split user and dir, use rk_getpwnam_r
[heimdal.git] / appl / popper / pop_init.c
blobcfcff9e19f73c64d990f193eb9f347d1467a1413
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(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 #else
19 #error must define KRB5
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 KRB5
53 static int
54 krb5_authenticate (POP *p, int s, u_char *buf, struct sockaddr *addr)
56 krb5_error_code ret;
57 krb5_auth_context auth_context = NULL;
58 uint32_t len;
59 krb5_ticket *ticket;
60 const char *estr;
61 char *server;
63 if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0)
64 return -1;
65 len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
67 if (krb5_net_read(p->context, &s, buf, len) != len)
68 return -1;
69 if (len != sizeof(KRB5_SENDAUTH_VERSION)
70 || memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0)
71 return -1;
73 ret = krb5_recvauth (p->context,
74 &auth_context,
75 &s,
76 "KPOPV1.0",
77 NULL, /* let rd_req figure out what server to use */
78 KRB5_RECVAUTH_IGNORE_VERSION,
79 NULL,
80 &ticket);
81 if (ret) {
82 estr = krb5_get_error_message(p->context, ret);
83 pop_log(p, POP_PRIORITY, "krb5_recvauth: %s", estr);
84 krb5_free_error_message(p->context, estr);
85 return -1;
89 ret = krb5_unparse_name(p->context, ticket->server, &server);
90 if(ret) {
91 estr = krb5_get_error_message(p->context, ret);
92 pop_log(p, POP_PRIORITY, "krb5_unparse_name: %s", estr);
93 krb5_free_error_message(p->context, estr);
94 ret = -1;
95 goto out;
97 /* does this make sense? */
98 if(strncmp(server, "pop/", 4) != 0) {
99 pop_log(p, POP_PRIORITY,
100 "Got ticket for service `%s'", server);
101 ret = -1;
102 goto out;
103 } else if(p->debug)
104 pop_log(p, POP_DEBUG,
105 "Accepted ticket for service `%s'", server);
106 free(server);
107 out:
108 krb5_auth_con_free (p->context, auth_context);
109 krb5_copy_principal (p->context, ticket->client, &p->principal);
110 krb5_free_ticket (p->context, ticket);
112 return ret;
114 #endif
116 static int
117 krb_authenticate(POP *p, struct sockaddr *addr)
119 #if defined(KRB5)
120 u_char buf[BUFSIZ];
122 if (pop_net_read (p, 0, buf, 4) != 4) {
123 pop_msg(p, POP_FAILURE, "Reading four bytes: %s",
124 strerror(errno));
125 exit (1);
127 if (krb5_authenticate (p, 0, buf, addr) == 0){
128 pop_write_addr(p, addr);
129 p->version = 5;
130 return POP_SUCCESS;
132 #endif
133 exit (1);
135 return(POP_SUCCESS);
138 static int
139 plain_authenticate (POP *p, struct sockaddr *addr)
141 return(POP_SUCCESS);
144 static int kerberos_flag;
145 static char *auth_str;
146 static int debug_flag;
147 static int interactive_flag;
148 static char *port_str;
149 static char *trace_file;
150 static int timeout;
151 static int help_flag;
152 static int version_flag;
154 static struct getargs args[] = {
155 #if defined(KRB5)
156 { "kerberos", 'k', arg_flag, &kerberos_flag, "use kerberos" },
157 #endif
158 { "auth-mode", 'a', arg_string, &auth_str, "required authentication",
159 "plaintext"
160 #ifdef OTP
161 "|otp"
162 #endif
163 #ifdef SASL
164 "|sasl"
165 #endif
167 { "debug", 'd', arg_flag, &debug_flag },
168 { "interactive", 'i', arg_flag, &interactive_flag, "create new socket" },
169 { "port", 'p', arg_string, &port_str, "port to listen to", "port" },
170 { "trace-file", 't', arg_string, &trace_file, "trace all command to file", "file" },
171 { "timeout", 'T', arg_integer, &timeout, "timeout", "seconds" },
172 { "address-log", 0, arg_string, &addr_log, "enable address log", "file" },
173 { "help", 'h', arg_flag, &help_flag },
174 { "version", 'v', arg_flag, &version_flag }
177 static int num_args = sizeof(args) / sizeof(args[0]);
180 * init: Start a Post Office Protocol session
183 static int
184 pop_getportbyname(POP *p, const char *service,
185 const char *proto, short def)
187 #ifdef KRB5
188 return krb5_getportbyname(p->context, service, proto, def);
189 #else
190 return htons(default);
191 #endif
195 pop_init(POP *p,int argcount,char **argmessage)
197 struct sockaddr_storage cs_ss;
198 struct sockaddr *cs = (struct sockaddr *)&cs_ss;
199 socklen_t len;
200 char * trace_file_name = "/tmp/popper-trace";
201 int portnum = 0;
202 int optind = 0;
203 int error;
205 /* Initialize the POP parameter block */
206 memset (p, 0, sizeof(POP));
208 setprogname(argmessage[0]);
210 /* Save my name in a global variable */
211 p->myname = (char*)getprogname();
213 /* Get the name of our host */
214 gethostname(p->myhost,MaxHostNameLen);
216 #ifdef KRB5
218 krb5_error_code ret;
220 ret = krb5_init_context (&p->context);
221 if (ret)
222 errx (1, "krb5_init_context failed: %d", ret);
224 krb5_openlog(p->context, p->myname, &p->logf);
225 krb5_set_warn_dest(p->context, p->logf);
227 #else
228 /* Open the log file */
229 roken_openlog(p->myname,POP_LOGOPTS,POP_FACILITY);
230 #endif
232 p->auth_level = AUTH_NONE;
234 if(getarg(args, num_args, argcount, argmessage, &optind)){
235 arg_printusage(args, num_args, NULL, "");
236 exit(1);
238 if(help_flag){
239 arg_printusage(args, num_args, NULL, "");
240 exit(0);
242 if(version_flag){
243 print_version(NULL);
244 exit(0);
247 argcount -= optind;
248 argmessage += optind;
250 if (argcount != 0) {
251 arg_printusage(args, num_args, NULL, "");
252 exit(1);
255 if(auth_str){
256 if (strcasecmp (auth_str, "plaintext") == 0 ||
257 strcasecmp (auth_str, "none") == 0)
258 p->auth_level = AUTH_NONE;
259 else if(strcasecmp(auth_str, "otp") == 0) {
260 #ifdef OTP
261 p->auth_level = AUTH_OTP;
262 #else
263 pop_log (p, POP_PRIORITY, "support for OTP not enabled");
264 exit(1);
265 #endif
266 } else if(strcasecmp(auth_str, "sasl") == 0) {
267 #ifdef SASL
268 p->auth_level = AUTH_SASL;
269 #else
270 pop_log (p, POP_PRIORITY, "support for SASL not enabled");
271 exit(1);
272 #endif
273 } else {
274 pop_log (p, POP_PRIORITY, "bad value for -a: %s", auth_str);
275 exit(1);
278 /* Debugging requested */
279 p->debug = debug_flag;
281 if(port_str)
282 portnum = htons(atoi(port_str));
283 if(trace_file){
284 p->debug++;
285 if ((p->trace = fopen(trace_file, "a+")) == NULL) {
286 pop_log(p, POP_PRIORITY,
287 "Unable to open trace file \"%s\", err = %d",
288 optarg,errno);
289 exit (1);
291 trace_file_name = trace_file;
294 #if defined(KRB5)
295 p->kerberosp = kerberos_flag;
296 #endif
298 if(timeout)
299 pop_timeout = timeout;
301 /* Fake inetd */
302 if (interactive_flag) {
303 if (portnum == 0)
304 portnum = p->kerberosp ?
305 pop_getportbyname(p, "kpop", "tcp", 1109) :
306 pop_getportbyname(p, "pop", "tcp", 110);
307 mini_inetd (portnum, NULL);
310 /* Get the address and socket of the client to whom I am speaking */
311 len = sizeof(cs_ss);
312 if (getpeername(STDIN_FILENO, cs, &len) < 0) {
313 pop_log(p,POP_PRIORITY,
314 "Unable to obtain socket and address of client, err = %d",errno);
315 exit (1);
318 /* Save the dotted decimal form of the client's IP address
319 in the POP parameter block */
320 inet_ntop (cs->sa_family, socket_get_address (cs),
321 p->ipaddr, sizeof(p->ipaddr));
323 /* Save the client's port */
324 p->ipport = ntohs(socket_get_port (cs));
326 /* Get the canonical name of the host to whom I am speaking */
327 error = getnameinfo_verified (cs, len, p->client, sizeof(p->client),
328 NULL, 0, 0);
329 if (error) {
330 pop_log (p, POP_PRIORITY,
331 "getnameinfo: %s", gai_strerror (error));
332 strlcpy (p->client, p->ipaddr, sizeof(p->client));
335 /* Create input file stream for TCP/IP communication */
336 if ((p->input = fdopen(STDIN_FILENO,"r")) == NULL){
337 pop_log(p,POP_PRIORITY,
338 "Unable to open communication stream for input, err = %d",errno);
339 exit (1);
342 /* Create output file stream for TCP/IP communication */
343 if ((p->output = fdopen(STDOUT_FILENO,"w")) == NULL){
344 pop_log(p,POP_PRIORITY,
345 "Unable to open communication stream for output, err = %d",errno);
346 exit (1);
349 pop_log(p,POP_PRIORITY,
350 "(v%s) Servicing request from \"%s\" at %s\n",
351 VERSION,p->client,p->ipaddr);
353 #ifdef DEBUG
354 if (p->trace)
355 pop_log(p,POP_PRIORITY,
356 "Tracing session and debugging information in file \"%s\"",
357 trace_file_name);
358 else if (p->debug)
359 pop_log(p,POP_PRIORITY,"Debugging turned on");
360 #endif /* DEBUG */
363 if(p->kerberosp)
364 return krb_authenticate(p, cs);
365 else
366 return plain_authenticate(p, cs);