x
[heimdal.git] / appl / popper / pop_init.c
bloba2924877ddcc80f2f63eeafc3a117cc1b64a35fc
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 char *server;
62 if (memcmp (buf, "\x00\x00\x00\x13", 4) != 0)
63 return -1;
64 len = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]);
66 if (krb5_net_read(p->context, &s, buf, len) != len)
67 return -1;
68 if (len != sizeof(KRB5_SENDAUTH_VERSION)
69 || memcmp (buf, KRB5_SENDAUTH_VERSION, len) != 0)
70 return -1;
72 ret = krb5_recvauth (p->context,
73 &auth_context,
74 &s,
75 "KPOPV1.0",
76 NULL, /* let rd_req figure out what server to use */
77 KRB5_RECVAUTH_IGNORE_VERSION,
78 NULL,
79 &ticket);
80 if (ret) {
81 pop_log(p, POP_PRIORITY, "krb5_recvauth: %s",
82 krb5_get_err_text(p->context, ret));
83 return -1;
87 ret = krb5_unparse_name(p->context, ticket->server, &server);
88 if(ret) {
89 pop_log(p, POP_PRIORITY, "krb5_unparse_name: %s",
90 krb5_get_err_text(p->context, ret));
91 ret = -1;
92 goto out;
94 /* does this make sense? */
95 if(strncmp(server, "pop/", 4) != 0) {
96 pop_log(p, POP_PRIORITY,
97 "Got ticket for service `%s'", server);
98 ret = -1;
99 goto out;
100 } else if(p->debug)
101 pop_log(p, POP_DEBUG,
102 "Accepted ticket for service `%s'", server);
103 free(server);
104 out:
105 krb5_auth_con_free (p->context, auth_context);
106 krb5_copy_principal (p->context, ticket->client, &p->principal);
107 krb5_free_ticket (p->context, ticket);
109 return ret;
111 #endif
113 static int
114 krb_authenticate(POP *p, struct sockaddr *addr)
116 #if defined(KRB5)
117 u_char buf[BUFSIZ];
119 if (pop_net_read (p, 0, buf, 4) != 4) {
120 pop_msg(p, POP_FAILURE, "Reading four bytes: %s",
121 strerror(errno));
122 exit (1);
124 if (krb5_authenticate (p, 0, buf, addr) == 0){
125 pop_write_addr(p, addr);
126 p->version = 5;
127 return POP_SUCCESS;
129 #endif
130 exit (1);
132 return(POP_SUCCESS);
135 static int
136 plain_authenticate (POP *p, struct sockaddr *addr)
138 return(POP_SUCCESS);
141 static int kerberos_flag;
142 static char *auth_str;
143 static int debug_flag;
144 static int interactive_flag;
145 static char *port_str;
146 static char *trace_file;
147 static int timeout;
148 static int help_flag;
149 static int version_flag;
151 static struct getargs args[] = {
152 #if defined(KRB5)
153 { "kerberos", 'k', arg_flag, &kerberos_flag, "use kerberos" },
154 #endif
155 { "auth-mode", 'a', arg_string, &auth_str, "required authentication",
156 "plaintext"
157 #ifdef OTP
158 "|otp"
159 #endif
160 #ifdef SASL
161 "|sasl"
162 #endif
164 { "debug", 'd', arg_flag, &debug_flag },
165 { "interactive", 'i', arg_flag, &interactive_flag, "create new socket" },
166 { "port", 'p', arg_string, &port_str, "port to listen to", "port" },
167 { "trace-file", 't', arg_string, &trace_file, "trace all command to file", "file" },
168 { "timeout", 'T', arg_integer, &timeout, "timeout", "seconds" },
169 { "address-log", 0, arg_string, &addr_log, "enable address log", "file" },
170 { "help", 'h', arg_flag, &help_flag },
171 { "version", 'v', arg_flag, &version_flag }
174 static int num_args = sizeof(args) / sizeof(args[0]);
177 * init: Start a Post Office Protocol session
180 static int
181 pop_getportbyname(POP *p, const char *service,
182 const char *proto, short def)
184 #ifdef KRB5
185 return krb5_getportbyname(p->context, service, proto, def);
186 #else
187 return htons(default);
188 #endif
192 pop_init(POP *p,int argcount,char **argmessage)
194 struct sockaddr_storage cs_ss;
195 struct sockaddr *cs = (struct sockaddr *)&cs_ss;
196 socklen_t len;
197 char * trace_file_name = "/tmp/popper-trace";
198 int portnum = 0;
199 int optind = 0;
200 int error;
202 /* Initialize the POP parameter block */
203 memset (p, 0, sizeof(POP));
205 setprogname(argmessage[0]);
207 /* Save my name in a global variable */
208 p->myname = (char*)getprogname();
210 /* Get the name of our host */
211 gethostname(p->myhost,MaxHostNameLen);
213 #ifdef KRB5
215 krb5_error_code ret;
217 ret = krb5_init_context (&p->context);
218 if (ret)
219 errx (1, "krb5_init_context failed: %d", ret);
221 krb5_openlog(p->context, p->myname, &p->logf);
222 krb5_set_warn_dest(p->context, p->logf);
224 #else
225 /* Open the log file */
226 roken_openlog(p->myname,POP_LOGOPTS,POP_FACILITY);
227 #endif
229 p->auth_level = AUTH_NONE;
231 if(getarg(args, num_args, argcount, argmessage, &optind)){
232 arg_printusage(args, num_args, NULL, "");
233 exit(1);
235 if(help_flag){
236 arg_printusage(args, num_args, NULL, "");
237 exit(0);
239 if(version_flag){
240 print_version(NULL);
241 exit(0);
244 argcount -= optind;
245 argmessage += optind;
247 if (argcount != 0) {
248 arg_printusage(args, num_args, NULL, "");
249 exit(1);
252 if(auth_str){
253 if (strcasecmp (auth_str, "plaintext") == 0 ||
254 strcasecmp (auth_str, "none") == 0)
255 p->auth_level = AUTH_NONE;
256 else if(strcasecmp(auth_str, "otp") == 0) {
257 #ifdef OTP
258 p->auth_level = AUTH_OTP;
259 #else
260 pop_log (p, POP_PRIORITY, "support for OTP not enabled");
261 exit(1);
262 #endif
263 } else if(strcasecmp(auth_str, "sasl") == 0) {
264 #ifdef SASL
265 p->auth_level = AUTH_SASL;
266 #else
267 pop_log (p, POP_PRIORITY, "support for SASL not enabled");
268 exit(1);
269 #endif
270 } else {
271 pop_log (p, POP_PRIORITY, "bad value for -a: %s", auth_str);
272 exit(1);
275 /* Debugging requested */
276 p->debug = debug_flag;
278 if(port_str)
279 portnum = htons(atoi(port_str));
280 if(trace_file){
281 p->debug++;
282 if ((p->trace = fopen(trace_file, "a+")) == NULL) {
283 pop_log(p, POP_PRIORITY,
284 "Unable to open trace file \"%s\", err = %d",
285 optarg,errno);
286 exit (1);
288 trace_file_name = trace_file;
291 #if defined(KRB5)
292 p->kerberosp = kerberos_flag;
293 #endif
295 if(timeout)
296 pop_timeout = timeout;
298 /* Fake inetd */
299 if (interactive_flag) {
300 if (portnum == 0)
301 portnum = p->kerberosp ?
302 pop_getportbyname(p, "kpop", "tcp", 1109) :
303 pop_getportbyname(p, "pop", "tcp", 110);
304 mini_inetd (portnum);
307 /* Get the address and socket of the client to whom I am speaking */
308 len = sizeof(cs_ss);
309 if (getpeername(STDIN_FILENO, cs, &len) < 0) {
310 pop_log(p,POP_PRIORITY,
311 "Unable to obtain socket and address of client, err = %d",errno);
312 exit (1);
315 /* Save the dotted decimal form of the client's IP address
316 in the POP parameter block */
317 inet_ntop (cs->sa_family, socket_get_address (cs),
318 p->ipaddr, sizeof(p->ipaddr));
320 /* Save the client's port */
321 p->ipport = ntohs(socket_get_port (cs));
323 /* Get the canonical name of the host to whom I am speaking */
324 error = getnameinfo_verified (cs, len, p->client, sizeof(p->client),
325 NULL, 0, 0);
326 if (error) {
327 pop_log (p, POP_PRIORITY,
328 "getnameinfo: %s", gai_strerror (error));
329 strlcpy (p->client, p->ipaddr, sizeof(p->client));
332 /* Create input file stream for TCP/IP communication */
333 if ((p->input = fdopen(STDIN_FILENO,"r")) == NULL){
334 pop_log(p,POP_PRIORITY,
335 "Unable to open communication stream for input, err = %d",errno);
336 exit (1);
339 /* Create output file stream for TCP/IP communication */
340 if ((p->output = fdopen(STDOUT_FILENO,"w")) == NULL){
341 pop_log(p,POP_PRIORITY,
342 "Unable to open communication stream for output, err = %d",errno);
343 exit (1);
346 pop_log(p,POP_PRIORITY,
347 "(v%s) Servicing request from \"%s\" at %s\n",
348 VERSION,p->client,p->ipaddr);
350 #ifdef DEBUG
351 if (p->trace)
352 pop_log(p,POP_PRIORITY,
353 "Tracing session and debugging information in file \"%s\"",
354 trace_file_name);
355 else if (p->debug)
356 pop_log(p,POP_PRIORITY,"Debugging turned on");
357 #endif /* DEBUG */
360 if(p->kerberosp)
361 return krb_authenticate(p, cs);
362 else
363 return plain_authenticate(p, cs);