22575: Remove extra ;, From Dennis Davis.
[heimdal.git] / appl / popper / pop_init.c
blob7912481f9e8f235ac79fee7cb57c1b58fae53790
1 /*
2 * Copyright (c) 1989 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
7 #include <popper.h>
8 RCSID("$Id$");
11 #if defined(KRB4) || defined(KRB5)
13 static int
14 pop_net_read(POP *p, int fd, void *buf, size_t len)
16 #ifdef KRB5
17 return krb5_net_read(p->context, &fd, buf, len);
18 #elif defined(KRB4)
19 return krb_net_read(fd, buf, len);
20 #endif
22 #endif
24 static char *addr_log;
26 static void
27 pop_write_addr(POP *p, struct sockaddr *addr)
29 char ts[32];
30 char as[128];
31 time_t t;
32 FILE *f;
33 if(addr_log == NULL)
34 return;
35 t = time(NULL);
36 strftime(ts, sizeof(ts), "%Y%m%d%H%M%S", localtime(&t));
37 if(inet_ntop (addr->sa_family, socket_get_address(addr),
38 as, sizeof(as)) == NULL) {
39 pop_log(p, POP_PRIORITY, "failed to print address");
40 return;
43 f = fopen(addr_log, "a");
44 if(f == NULL) {
45 pop_log(p, POP_PRIORITY, "failed to open address log (%s)", addr_log);
46 return;
48 fprintf(f, "%s %s\n", as, ts);
49 fclose(f);
52 #ifdef KRB4
53 static int
54 krb4_authenticate (POP *p, int s, u_char *buf, struct sockaddr *addr)
56 Key_schedule schedule;
57 KTEXT_ST ticket;
58 char instance[INST_SZ];
59 char version[9];
60 int auth;
62 if (memcmp (buf, KRB_SENDAUTH_VERS, 4) != 0)
63 return -1;
64 if (pop_net_read (p, s, buf + 4,
65 KRB_SENDAUTH_VLEN - 4) != KRB_SENDAUTH_VLEN - 4)
66 return -1;
67 if (memcmp (buf, KRB_SENDAUTH_VERS, KRB_SENDAUTH_VLEN) != 0)
68 return -1;
70 k_getsockinst (0, instance, sizeof(instance));
71 auth = krb_recvauth(KOPT_IGNORE_PROTOCOL,
73 &ticket,
74 "pop",
75 instance,
76 (struct sockaddr_in *)addr,
77 (struct sockaddr_in *) NULL,
78 &p->kdata,
79 "",
80 schedule,
81 version);
83 if (auth != KSUCCESS) {
84 pop_msg(p, POP_FAILURE, "Kerberos authentication failure: %s",
85 krb_get_err_text(auth));
86 pop_log(p, POP_PRIORITY, "%s: (%s.%s@%s) %s", p->client,
87 p->kdata.pname, p->kdata.pinst, p->kdata.prealm,
88 krb_get_err_text(auth));
89 return -1;
92 #ifdef DEBUG
93 pop_log(p, POP_DEBUG, "%s.%s@%s (%s): ok", p->kdata.pname,
94 p->kdata.pinst, p->kdata.prealm, p->ipaddr);
95 #endif /* DEBUG */
96 return 0;
98 #endif /* KRB4 */
100 #ifdef KRB5
101 static int
102 krb5_authenticate (POP *p, int s, u_char *buf, struct sockaddr *addr)
104 krb5_error_code ret;
105 krb5_auth_context auth_context = NULL;
106 uint32_t len;
107 krb5_ticket *ticket;
108 char *server;
110 if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0)
111 return -1;
112 len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
114 if (krb5_net_read(p->context, &s, buf, len) != len)
115 return -1;
116 if (len != sizeof(KRB5_SENDAUTH_VERSION)
117 || memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0)
118 return -1;
120 ret = krb5_recvauth (p->context,
121 &auth_context,
123 "KPOPV1.0",
124 NULL, /* let rd_req figure out what server to use */
125 KRB5_RECVAUTH_IGNORE_VERSION,
126 NULL,
127 &ticket);
128 if (ret) {
129 pop_log(p, POP_PRIORITY, "krb5_recvauth: %s",
130 krb5_get_err_text(p->context, ret));
131 return -1;
135 ret = krb5_unparse_name(p->context, ticket->server, &server);
136 if(ret) {
137 pop_log(p, POP_PRIORITY, "krb5_unparse_name: %s",
138 krb5_get_err_text(p->context, ret));
139 ret = -1;
140 goto out;
142 /* does this make sense? */
143 if(strncmp(server, "pop/", 4) != 0) {
144 pop_log(p, POP_PRIORITY,
145 "Got ticket for service `%s'", server);
146 ret = -1;
147 goto out;
148 } else if(p->debug)
149 pop_log(p, POP_DEBUG,
150 "Accepted ticket for service `%s'", server);
151 free(server);
152 out:
153 krb5_auth_con_free (p->context, auth_context);
154 krb5_copy_principal (p->context, ticket->client, &p->principal);
155 krb5_free_ticket (p->context, ticket);
157 return ret;
159 #endif
161 static int
162 krb_authenticate(POP *p, struct sockaddr *addr)
164 #if defined(KRB4) || defined(KRB5)
165 u_char buf[BUFSIZ];
167 if (pop_net_read (p, 0, buf, 4) != 4) {
168 pop_msg(p, POP_FAILURE, "Reading four bytes: %s",
169 strerror(errno));
170 exit (1);
172 #ifdef KRB4
173 if (krb4_authenticate (p, 0, buf, addr) == 0){
174 pop_write_addr(p, addr);
175 p->version = 4;
176 return POP_SUCCESS;
178 #endif
179 #ifdef KRB5
180 if (krb5_authenticate (p, 0, buf, addr) == 0){
181 pop_write_addr(p, addr);
182 p->version = 5;
183 return POP_SUCCESS;
185 #endif
186 exit (1);
188 #endif /* defined(KRB4) || defined(KRB5) */
190 return(POP_SUCCESS);
193 static int
194 plain_authenticate (POP *p, struct sockaddr *addr)
196 return(POP_SUCCESS);
199 static int kerberos_flag;
200 static char *auth_str;
201 static int debug_flag;
202 static int interactive_flag;
203 static char *port_str;
204 static char *trace_file;
205 static int timeout;
206 static int help_flag;
207 static int version_flag;
209 static struct getargs args[] = {
210 #if defined(KRB4) || defined(KRB5)
211 { "kerberos", 'k', arg_flag, &kerberos_flag, "use kerberos" },
212 #endif
213 { "auth-mode", 'a', arg_string, &auth_str, "required authentication",
214 "plaintext"
215 #ifdef OTP
216 "|otp"
217 #endif
218 #ifdef SASL
219 "|sasl"
220 #endif
222 { "debug", 'd', arg_flag, &debug_flag },
223 { "interactive", 'i', arg_flag, &interactive_flag, "create new socket" },
224 { "port", 'p', arg_string, &port_str, "port to listen to", "port" },
225 { "trace-file", 't', arg_string, &trace_file, "trace all command to file", "file" },
226 { "timeout", 'T', arg_integer, &timeout, "timeout", "seconds" },
227 { "address-log", 0, arg_string, &addr_log, "enable address log", "file" },
228 { "help", 'h', arg_flag, &help_flag },
229 { "version", 'v', arg_flag, &version_flag }
232 static int num_args = sizeof(args) / sizeof(args[0]);
235 * init: Start a Post Office Protocol session
238 static int
239 pop_getportbyname(POP *p, const char *service,
240 const char *proto, short def)
242 #ifdef KRB5
243 return krb5_getportbyname(p->context, service, proto, def);
244 #elif defined(KRB4)
245 return k_getportbyname(service, proto, htons(def));
246 #else
247 return htons(default);
248 #endif
252 pop_init(POP *p,int argcount,char **argmessage)
254 struct sockaddr_storage cs_ss;
255 struct sockaddr *cs = (struct sockaddr *)&cs_ss;
256 socklen_t len;
257 char * trace_file_name = "/tmp/popper-trace";
258 int portnum = 0;
259 int optind = 0;
260 int error;
262 /* Initialize the POP parameter block */
263 memset (p, 0, sizeof(POP));
265 setprogname(argmessage[0]);
267 /* Save my name in a global variable */
268 p->myname = (char*)getprogname();
270 /* Get the name of our host */
271 gethostname(p->myhost,MaxHostNameLen);
273 #ifdef KRB5
275 krb5_error_code ret;
277 ret = krb5_init_context (&p->context);
278 if (ret)
279 errx (1, "krb5_init_context failed: %d", ret);
281 krb5_openlog(p->context, p->myname, &p->logf);
282 krb5_set_warn_dest(p->context, p->logf);
284 #else
285 /* Open the log file */
286 roken_openlog(p->myname,POP_LOGOPTS,POP_FACILITY);
287 #endif
289 p->auth_level = AUTH_NONE;
291 if(getarg(args, num_args, argcount, argmessage, &optind)){
292 arg_printusage(args, num_args, NULL, "");
293 exit(1);
295 if(help_flag){
296 arg_printusage(args, num_args, NULL, "");
297 exit(0);
299 if(version_flag){
300 print_version(NULL);
301 exit(0);
304 argcount -= optind;
305 argmessage += optind;
307 if (argcount != 0) {
308 arg_printusage(args, num_args, NULL, "");
309 exit(1);
312 if(auth_str){
313 if (strcasecmp (auth_str, "plaintext") == 0 ||
314 strcasecmp (auth_str, "none") == 0)
315 p->auth_level = AUTH_NONE;
316 else if(strcasecmp(auth_str, "otp") == 0) {
317 #ifdef OTP
318 p->auth_level = AUTH_OTP;
319 #else
320 pop_log (p, POP_PRIORITY, "support for OTP not enabled");
321 exit(1);
322 #endif
323 } else if(strcasecmp(auth_str, "sasl") == 0) {
324 #ifdef SASL
325 p->auth_level = AUTH_SASL;
326 #else
327 pop_log (p, POP_PRIORITY, "support for SASL not enabled");
328 exit(1);
329 #endif
330 } else {
331 pop_log (p, POP_PRIORITY, "bad value for -a: %s", auth_str);
332 exit(1);
335 /* Debugging requested */
336 p->debug = debug_flag;
338 if(port_str)
339 portnum = htons(atoi(port_str));
340 if(trace_file){
341 p->debug++;
342 if ((p->trace = fopen(trace_file, "a+")) == NULL) {
343 pop_log(p, POP_PRIORITY,
344 "Unable to open trace file \"%s\", err = %d",
345 optarg,errno);
346 exit (1);
348 trace_file_name = trace_file;
351 #if defined(KRB4) || defined(KRB5)
352 p->kerberosp = kerberos_flag;
353 #endif
355 if(timeout)
356 pop_timeout = timeout;
358 /* Fake inetd */
359 if (interactive_flag) {
360 if (portnum == 0)
361 portnum = p->kerberosp ?
362 pop_getportbyname(p, "kpop", "tcp", 1109) :
363 pop_getportbyname(p, "pop", "tcp", 110);
364 mini_inetd (portnum);
367 /* Get the address and socket of the client to whom I am speaking */
368 len = sizeof(cs_ss);
369 if (getpeername(STDIN_FILENO, cs, &len) < 0) {
370 pop_log(p,POP_PRIORITY,
371 "Unable to obtain socket and address of client, err = %d",errno);
372 exit (1);
375 /* Save the dotted decimal form of the client's IP address
376 in the POP parameter block */
377 inet_ntop (cs->sa_family, socket_get_address (cs),
378 p->ipaddr, sizeof(p->ipaddr));
380 /* Save the client's port */
381 p->ipport = ntohs(socket_get_port (cs));
383 /* Get the canonical name of the host to whom I am speaking */
384 error = getnameinfo_verified (cs, len, p->client, sizeof(p->client),
385 NULL, 0, 0);
386 if (error) {
387 pop_log (p, POP_PRIORITY,
388 "getnameinfo: %s", gai_strerror (error));
389 strlcpy (p->client, p->ipaddr, sizeof(p->client));
392 /* Create input file stream for TCP/IP communication */
393 if ((p->input = fdopen(STDIN_FILENO,"r")) == NULL){
394 pop_log(p,POP_PRIORITY,
395 "Unable to open communication stream for input, err = %d",errno);
396 exit (1);
399 /* Create output file stream for TCP/IP communication */
400 if ((p->output = fdopen(STDOUT_FILENO,"w")) == NULL){
401 pop_log(p,POP_PRIORITY,
402 "Unable to open communication stream for output, err = %d",errno);
403 exit (1);
406 pop_log(p,POP_PRIORITY,
407 "(v%s) Servicing request from \"%s\" at %s\n",
408 VERSION,p->client,p->ipaddr);
410 #ifdef DEBUG
411 if (p->trace)
412 pop_log(p,POP_PRIORITY,
413 "Tracing session and debugging information in file \"%s\"",
414 trace_file_name);
415 else if (p->debug)
416 pop_log(p,POP_PRIORITY,"Debugging turned on");
417 #endif /* DEBUG */
420 if(p->kerberosp)
421 return krb_authenticate(p, cs);
422 else
423 return plain_authenticate(p, cs);