1 /*
2 ** Copyright 2000-2018 Double Precision, Inc.  See COPYING for
3 ** distribution information.
4 */
5 
6 #include	"courier_auth_config.h"
7 #include	<sys/types.h>
8 #include	<sys/stat.h>
9 #include	<sys/socket.h>
10 #include	<sys/un.h>
11 #include	<sys/time.h>
12 #include	<sys/wait.h>
13 #include	<unistd.h>
14 #include	<stdlib.h>
15 #include	<stdio.h>
16 #include	<errno.h>
17 #include	<signal.h>
18 #include	<fcntl.h>
19 #include	<ctype.h>
20 #include	"numlib/numlib.h"
21 #include	"liblock/liblock.h"
22 #include	"auth.h"
23 #include	"authdaemonrc.h"
24 #include	"courierauthdebug.h"
25 #include	"pkglibdir.h"
26 #include	"courierauth.h"
27 #include	"courierauthstaticlist.h"
28 #include        "libhmac/hmac.h"
29 #include	"authdaemond.h"
30 #include	<ltdl.h>
31 
32 
33 #ifndef	SOMAXCONN
34 #define	SOMAXCONN	5
35 #endif
36 
37 #include	"courierauthstaticlist.h"
38 
39 static unsigned ndaemons;
40 
41 struct authstaticinfolist {
42 	struct authstaticinfolist *next;
43 	struct authstaticinfo *info;
44 	lt_dlhandle h;
45 };
46 
47 static struct authstaticinfolist *modulelist=NULL;
48 
49 char tcpremoteip[40];
50 
mksocket()51 static int mksocket()
52 {
53 int	fd=socket(PF_UNIX, SOCK_STREAM, 0);
54 struct	sockaddr_un skun;
55 
56 	if (fd < 0)	return (-1);
57 	skun.sun_family=AF_UNIX;
58 	memcpy(skun.sun_path, AUTHDAEMONSOCK, sizeof(AUTHDAEMONSOCK)-1);
59 	memcpy(&skun.sun_path[0]+sizeof(AUTHDAEMONSOCK)-1, ".tmp", 5);
60 	unlink(skun.sun_path);
61 	if (bind(fd, (const struct sockaddr *)&skun, sizeof(skun)) ||
62 	    listen(fd, SOMAXCONN) ||
63 	    chmod(skun.sun_path, 0777) ||
64 	    rename(skun.sun_path, AUTHDAEMONSOCK) ||
65 	    fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 ||
66 	    fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
67 	{
68 		perror(AUTHDAEMONSOCK);
69 		close(fd);
70 		return (-1);
71 	}
72 	return (fd);
73 }
74 
75 
initmodules(const char * p)76 static int initmodules(const char *p)
77 {
78 	char buf[100];
79 	char buf2[100];
80 	struct authstaticinfolist **modptr= &modulelist;
81 	struct authstaticinfolist *m;
82 
83 	if (ndaemons <= 0)
84 	{
85 		ndaemons=1;
86 
87 		fprintf(stderr, "ERR: Configuration error - missing 'daemons' setting, using %u\n",
88 			ndaemons);
89 	}
90 
91 	while ((m=modulelist) != NULL)
92 	{
93 		modulelist=m->next;
94 		fprintf(stderr, "INFO: Uninstalling %s\n",
95 			m->info->auth_name);
96 		lt_dlclose(m->h);
97 		free(m);
98 	}
99 
100 	while (p && *p)
101 	{
102 		size_t i;
103 		lt_dlhandle h;
104 		lt_ptr pt;
105 		struct authstaticinfo *a;
106 
107 		if (isspace((int)(unsigned char)*p))
108 		{
109 			++p;
110 			continue;
111 		}
112 
113 		for (i=0; p[i] && !isspace((int)(unsigned char)p[i]); ++i)
114 			;
115 
116 		strcpy(buf, "lib");
117 		strncat(buf, p, i>40 ? 40:i);
118 		strcpy(buf2, buf);
119 		strcat(buf2, COURIERDLEXT);
120 
121 		fprintf(stderr, "INFO: Installing %s\n", buf2);
122 		p += i;
123 		h=lt_dlopen(buf2);
124 
125 		if (h == NULL)
126 		{
127 			fprintf(stderr, "INFO: %s\n", lt_dlerror());
128 			continue;
129 		}
130 
131 		buf2[snprintf(buf2, sizeof(buf2)-1, "courier_%s_init",
132 			      buf+3)]=0;
133 
134 		pt=lt_dlsym(h, buf2);
135 		if (pt == NULL)
136 		{
137 			fprintf(stderr,
138 				"ERR: Can't locate init function %s.\n",
139 				buf2);
140 			fprintf(stderr, "ERR: %s\n", lt_dlerror());
141 			continue;
142 		}
143 
144 		a= (*(struct authstaticinfo *(*)(void))pt)();
145 
146 		if ((m=malloc(sizeof(*modulelist))) == NULL)
147 		{
148 			perror("ERR");
149 			lt_dlclose(h);
150 			continue;
151 		}
152 		*modptr=m;
153 		m->next=NULL;
154 		m->info=a;
155 		m->h=h;
156 		modptr= &m->next;
157 		fprintf(stderr, "INFO: Installation complete: %s\n",
158 			a->auth_name);
159 	}
160 	return (0);
161 }
162 
readconfig()163 static int readconfig()
164 {
165 	char	buf[BUFSIZ];
166 	FILE	*fp;
167 	char	*modlist=0;
168 	unsigned daemons=0;
169 
170 	if ((fp=fopen(AUTHDAEMONRC, "r")) == NULL)
171 	{
172 		perror(AUTHDAEMONRC);
173 		return (-1);
174 	}
175 
176 	while (fgets(buf, sizeof(buf), fp))
177 	{
178 	char	*p=strchr(buf, '\n'), *q;
179 
180 		if (!p)
181 		{
182 		int	c;
183 
184 			while ((c=getc(fp)) >= 0 && c != '\n')
185 				;
186 		}
187 		else	*p=0;
188 		if ((p=strchr(buf, '#')) != 0)	*p=0;
189 
190 		for (p=buf; *p; p++)
191 			if (!isspace((int)(unsigned char)*p))
192 				break;
193 		if (*p == 0)	continue;
194 
195 		if ((p=strchr(buf, '=')) == 0)
196 		{
197 			fprintf(stderr, "ERR: Bad line in %s: %s\n",
198 				AUTHDAEMONRC, buf);
199 			fclose(fp);
200 			if (modlist)
201 				free(modlist);
202 			return (-1);
203 		}
204 		*p++=0;
205 		while (*p && isspace((int)(unsigned char)*p))
206 			++p;
207 		if (*p == '"')
208 		{
209 			++p;
210 			q=strchr(p, '"');
211 			if (q)	*q=0;
212 		}
213 		if (strcmp(buf, "authmodulelist") == 0)
214 		{
215 			if (modlist)
216 				free(modlist);
217 			modlist=strdup(p);
218 			if (!modlist)
219 			{
220 				perror("malloc");
221 				fclose(fp);
222 				return (-1);
223 			}
224 			continue;
225 		}
226 		if (strcmp(buf, "daemons") == 0)
227 		{
228 			daemons=atoi(p);
229 			continue;
230 		}
231 	}
232 	fclose(fp);
233 
234 	fprintf(stderr, "INFO: modules=\"%s\", daemons=%u\n",
235 		modlist ? modlist:"(none)",
236 		daemons);
237 	ndaemons=daemons;
238 	return (initmodules(modlist));
239 }
240 
241 static char buf[BUFSIZ];
242 static char *readptr;
243 static int readleft;
244 static char *writeptr;
245 static int writeleft;
246 
getauthc(int fd)247 static int getauthc(int fd)
248 {
249 fd_set	fds;
250 struct	timeval	tv;
251 
252 	if (readleft--)
253 		return ( (int)(unsigned char)*readptr++ );
254 
255 	readleft=0;
256 	FD_ZERO(&fds);
257 	FD_SET(fd, &fds);
258 	tv.tv_sec=10;
259 	tv.tv_usec=0;
260 	if (select(fd+1, &fds, 0, 0, &tv) <= 0 ||
261 		!FD_ISSET(fd, &fds))
262 		return (EOF);
263 	readleft=read(fd, buf, sizeof(buf));
264 	readptr=buf;
265 	if (readleft <= 0)
266 	{
267 		readleft=0;
268 		return (EOF);
269 	}
270 	--readleft;
271 	return ( (int)(unsigned char)*readptr++ );
272 }
273 
writeauth(int fd,const char * p,unsigned pl)274 static int writeauth(int fd, const char *p, unsigned pl)
275 {
276 fd_set	fds;
277 struct	timeval	tv;
278 
279 	while (pl)
280 	{
281 	int	n;
282 
283 		FD_ZERO(&fds);
284 		FD_SET(fd, &fds);
285 		tv.tv_sec=30;
286 		tv.tv_usec=0;
287 		if (select(fd+1, 0, &fds, 0, &tv) <= 0 ||
288 			!FD_ISSET(fd, &fds))
289 			return (-1);
290 		n=write(fd, p, pl);
291 		if (n <= 0)	return (-1);
292 		p += n;
293 		pl -= n;
294 	}
295 	return (0);
296 }
297 
writeauthflush(int fd)298 static int writeauthflush(int fd)
299 {
300 	if (writeptr > buf)
301 	{
302 		if (writeauth(fd, buf, writeptr - buf))
303 			return (-1);
304 	}
305 	writeptr=buf;
306 	writeleft=sizeof(buf);
307 	return (0);
308 }
309 
writeauthbuf(int fd,const char * p,unsigned pl)310 static int writeauthbuf(int fd, const char *p, unsigned pl)
311 {
312 unsigned n;
313 
314 	while (pl)
315 	{
316 		if (pl < writeleft)
317 		{
318 			memcpy(writeptr, p, pl);
319 			writeptr += pl;
320 			writeleft -= pl;
321 			return (0);
322 		}
323 
324 		if (writeauthflush(fd))	return (-1);
325 
326 		n=pl;
327 		if (n > writeleft)	n=writeleft;
328 		memcpy(writeptr, p, n);
329 		p += n;
330 		writeptr += n;
331 		writeleft -= n;
332 		pl -= n;
333 	}
334 	return (0);
335 }
336 
writeenvval(int fd,const char * env,const char * val)337 static int writeenvval(int fd, const char *env, const char *val)
338 {
339 	if (writeauthbuf(fd, env, strlen(env)) ||
340 		writeauthbuf(fd, "=", 1) ||
341 		writeauthbuf(fd, val, strlen(val)) ||
342 		writeauthbuf(fd, "\n", 1))
343 		return (-1);
344 	return (0);
345 }
346 
findopt(const char * options,const char * keyword)347 static const char *findopt(const char *options, const char *keyword)
348 {
349 	size_t keyword_l=strlen(keyword);
350 
351 	while (options)
352 	{
353 		if (strncmp(options, keyword, keyword_l) == 0)
354 		{
355 			switch (options[keyword_l])
356 			{
357 			case '=':
358 				return options + keyword_l + 1;
359 			case ',': case '\0':
360 				return options + keyword_l;
361 			}
362 		}
363 		options=strchr(options, ',');
364 		if (options)
365 			++options;
366 	}
367 	return NULL;
368 }
369 
370 /* Returns a malloc'd string containing the merge of the options string
371    and any default options which apply, or NULL if no options at all */
mergeoptions(const char * options)372 static char *mergeoptions(const char *options)
373 {
374 	char	*defoptions = getenv("DEFAULTOPTIONS");
375 	char	*p;
376 
377 	if (options && *options && defoptions && *defoptions)
378 	{
379 		char *result = malloc(strlen(options) +
380 				 strlen(defoptions) + 2);
381 		if (!result)
382 		{
383 			perror("malloc");
384 			return NULL;
385 		}
386 		strcpy(result, options);
387 
388 		defoptions = strdup(defoptions);
389 		if (!defoptions)
390 		{
391 			perror("malloc");
392 			free(result);
393 			return NULL;
394 		}
395 
396 		for (p = strtok(defoptions, ","); p; p = strtok(0, ","))
397 		{
398 			char *q = strchr(p, '=');
399 			if (q) *q = '\0';
400 			if (findopt(result, p)) continue;
401 			if (q) *q = '=';
402 			strcat(result, ",");
403 			strcat(result, p);
404 		}
405 		free(defoptions);
406 		return result;
407 	}
408 	else if (options && *options)
409 	{
410 		return strdup(options);
411 	}
412 	else if (defoptions && *defoptions)
413 	{
414 		return strdup(defoptions);
415 	}
416 	else
417 		return 0;
418 }
419 
printauth(struct authinfo * authinfo,void * vp)420 static int printauth(struct authinfo *authinfo, void *vp)
421 {
422 	int	fd= *(int *)vp;
423 	char	buf2[NUMBUFSIZE];
424 	char	*fullopt;
425 
426 	writeptr=buf;
427 	writeleft=sizeof(buf);
428 
429 	courier_authdebug_authinfo("Authenticated: ", authinfo,
430 				   authinfo->clearpasswd,
431 				   authinfo->passwd);
432 
433 	if (authinfo->sysusername)
434 		if (writeenvval(fd, "USERNAME", authinfo->sysusername))
435 			return (1);
436 	if (authinfo->sysuserid)
437 		if (writeenvval(fd, "UID", libmail_str_uid_t(*authinfo->sysuserid,
438 			buf2)))
439 			return (1);
440 	if (writeenvval(fd, "GID", libmail_str_uid_t(authinfo->sysgroupid, buf2)))
441 			return (1);
442 
443 	if (writeenvval(fd, "HOME", authinfo->homedir))
444 			return (1);
445 	if (authinfo->address)
446 		if (writeenvval(fd, "ADDRESS", authinfo->address))
447 			return (1);
448 	if (authinfo->fullname)
449 	{
450 		/*
451 		 * Only the first field of the comma-seperated GECOS field is the
452 		 * full username.
453 		 */
454 	 	char *fullname;
455 		char *p;
456 		int retval;
457 
458 		fullname=strdup(authinfo->fullname);
459 		if(fullname == NULL)
460 		{
461 			perror("strdup");
462 			return (1);
463 		}
464 
465 		p = fullname;
466 		while (*p != ',' && *p != '\0')
467 			p++;
468 		*p=0;
469 		retval = writeenvval(fd, "NAME", fullname);
470 		free(fullname);
471 		if(retval)
472 			return (1);
473 	}
474 	if (authinfo->maildir)
475 		if (writeenvval(fd, "MAILDIR", authinfo->maildir))
476 			return (1);
477 	if (authinfo->quota)
478 		if (writeenvval(fd, "QUOTA", authinfo->quota))
479 			return (1);
480 	if (authinfo->passwd)
481 		if (writeenvval(fd, "PASSWD", authinfo->passwd))
482 			return (1);
483 	if (authinfo->clearpasswd)
484 		if (writeenvval(fd, "PASSWD2", authinfo->clearpasswd))
485 			return (1);
486 	fullopt = mergeoptions(authinfo->options);
487 	if (fullopt)
488 	{
489 		int rc = writeenvval(fd, "OPTIONS", fullopt);
490 		free(fullopt);
491 		if (rc)
492 			return (1);
493 	}
494 	if (writeauthbuf(fd, ".\n", 2) || writeauthflush(fd))
495 		return (1);
496 	return (0);
497 }
498 
pre(int fd,char * prebuf)499 static void pre(int fd, char *prebuf)
500 {
501 char	*p=strchr(prebuf, ' ');
502 char	*service;
503 struct authstaticinfolist *l;
504 
505 	if (!p)	return;
506 	*p++=0;
507 	while (*p == ' ')	++p;
508 	service=p;
509 	p=strchr(p, ' ');
510 	if (!p) return;
511         *p++=0;
512         while (*p == ' ')     ++p;
513 
514 	DPRINTF("received userid lookup request: %s", p);
515 
516 	for (l=modulelist; l; l=l->next)
517 	{
518 		struct authstaticinfo *auth=l->info;
519 		const char	*modname = auth->auth_name;
520 		int rc;
521 
522 		if (strcmp(prebuf, ".") && strcmp(prebuf, modname))
523 			continue;
524 
525 		DPRINTF("%s: trying this module", modname);
526 
527 
528 		rc=(*auth->auth_prefunc)(p, service,
529 					 &printauth, &fd);
530 
531 		if (rc == 0)
532 			return;
533 
534 		if (rc > 0)
535 		{
536 			DPRINTF("%s: TEMPFAIL - no more modules will be tried",
537 				modname);
538 			return;	/* Temporary error */
539 		}
540 		DPRINTF("%s: REJECT - try next module", modname);
541 	}
542 	writeauth(fd, "FAIL\n", 5);
543 	DPRINTF("FAIL, all modules rejected");
544 }
545 
546 struct enumerate_info {
547 	int fd;
548 	char *buf_ptr;
549 	size_t buf_left;
550 	char buffer[BUFSIZ];
551 	int enumerate_ok;
552 };
553 
enumflush(struct enumerate_info * ei)554 static void enumflush(struct enumerate_info *ei)
555 {
556 	if (ei->buf_ptr > ei->buffer)
557 		writeauth(ei->fd, ei->buffer, ei->buf_ptr - ei->buffer);
558 	ei->buf_ptr=ei->buffer;
559 	ei->buf_left=sizeof(ei->buffer);
560 }
561 
enumwrite(struct enumerate_info * ei,const char * s)562 static void enumwrite(struct enumerate_info *ei, const char *s)
563 {
564 	while (s && *s)
565 	{
566 		size_t l;
567 
568 		if (ei->buf_left == 0)
569 			enumflush(ei);
570 
571 		l=strlen(s);
572 		if (l > ei->buf_left)
573 			l=ei->buf_left;
574 		memcpy(ei->buf_ptr, s, l);
575 		ei->buf_ptr += l;
576 		ei->buf_left -= l;
577 		s += l;
578 	}
579 }
580 
enum_cb(const char * name,uid_t uid,gid_t gid,const char * homedir,const char * maildir,const char * options,void * void_arg)581 static void enum_cb(const char *name,
582 		    uid_t uid,
583 		    gid_t gid,
584 		    const char *homedir,
585 		    const char *maildir,
586 		    const char *options,
587 		    void *void_arg)
588 {
589 	struct enumerate_info *ei=(struct enumerate_info *)void_arg;
590 	char buf[NUMBUFSIZE];
591 	char *fullopt;
592 
593 	if (name == NULL)
594 	{
595 		ei->enumerate_ok=1;
596 		return;
597 	}
598 
599 	enumwrite(ei, name);
600 	enumwrite(ei, "\t");
601 	enumwrite(ei, libmail_str_uid_t(uid, buf));
602 	enumwrite(ei, "\t");
603 	enumwrite(ei, libmail_str_gid_t(gid, buf));
604 	enumwrite(ei, "\t");
605 	enumwrite(ei, homedir);
606 	enumwrite(ei, "\t");
607 	enumwrite(ei, maildir ? maildir : "");
608 	enumwrite(ei, "\t");
609 	fullopt = mergeoptions(options);
610 	if (fullopt)
611 	{
612 		enumwrite(ei, fullopt);
613 		free (fullopt);
614 	}
615 	enumwrite(ei, "\n");
616 }
617 
enumerate(int fd)618 static void enumerate(int fd)
619 {
620 	struct enumerate_info ei;
621 	struct authstaticinfolist *l;
622 
623 	ei.fd=fd;
624 	ei.buf_ptr=ei.buffer;
625 	ei.buf_left=0;
626 
627 	for (l=modulelist; l; l=l->next)
628 	{
629 		struct authstaticinfo *auth=l->info;
630 
631 		if (auth->auth_enumerate == NULL)
632 			continue;
633 
634 		enumwrite(&ei, "# ");
635 		enumwrite(&ei, auth->auth_name);
636 		enumwrite(&ei, "\n\n");
637 		ei.enumerate_ok=0;
638 		(*auth->auth_enumerate)(enum_cb, &ei);
639 		if (!ei.enumerate_ok)
640 		{
641 			enumflush(&ei);
642 			DPRINTF("enumeration terminated prematurely in module %s",
643 				auth->auth_name);
644 			return;
645 		}
646 	}
647 	enumwrite(&ei, ".\n");
648 	enumflush(&ei);
649 }
650 
651 static void dopasswd(int, const char *, const char *, const char *,
652 		     const char *);
653 
passwd(int fd,char * prebuf)654 static void passwd(int fd, char *prebuf)
655 {
656 	char *p;
657 	const char *service;
658 	const char *userid;
659 	const char *opwd;
660 	const char *npwd;
661 
662 	for (p=prebuf; *p; p++)
663 	{
664 		if (*p == '\t')
665 			continue;
666 		if ((int)(unsigned char)*p < ' ')
667 		{
668 			writeauth(fd, "FAIL\n", 5);
669 			return;
670 		}
671 	}
672 
673 	service=prebuf;
674 
675 	if ((p=strchr(service, '\t')) != 0)
676 	{
677 		*p++=0;
678 		userid=p;
679 		if ((p=strchr(p, '\t')) != 0)
680 		{
681 			*p++=0;
682 			opwd=p;
683 			if ((p=strchr(p, '\t')) != 0)
684 			{
685 				*p++=0;
686 				npwd=p;
687 				if ((p=strchr(p, '\t')) != 0)
688 					*p=0;
689 				dopasswd(fd, service, userid, opwd, npwd);
690 				return;
691 			}
692 		}
693 	}
694 }
695 
dopasswd(int fd,const char * service,const char * userid,const char * opwd,const char * npwd)696 static void dopasswd(int fd,
697 		     const char *service,
698 		     const char *userid,
699 		     const char *opwd,
700 		     const char *npwd)
701 {
702 struct authstaticinfolist *l;
703 
704 
705 	for (l=modulelist; l; l=l->next)
706 	{
707 		struct authstaticinfo *auth=l->info;
708 		int	rc;
709 
710 		int (*f)(const char *, const char *, const char *,
711 			 const char *)=
712 			auth->auth_changepwd;
713 
714 		if (!f)
715 			continue;
716 
717 		rc= (*f)(service, userid, opwd, npwd);
718 
719 		if (rc == 0)
720 		{
721 			writeauth(fd, "OK\n", 3);
722 			return;
723 		}
724 		if (rc > 0)
725 			break;
726 	}
727 	writeauth(fd, "FAIL\n", 5);
728 }
729 
auth(int fd,char * p)730 static void auth(int fd, char *p)
731 {
732 	char *service;
733 	char *authtype;
734 	char	*pp;
735 	struct authstaticinfolist *l;
736 
737 	service=p;
738 	if ((p=strchr(p, '\n')) == 0)	return;
739 	*p++=0;
740 	authtype=p;
741 	if ((p=strchr(p, '\n')) == 0)	return;
742 	*p++=0;
743 
744 	pp=malloc(strlen(p)+1);
745 	if (!pp)
746 	{
747 		perror("CRIT: malloc() failed");
748 		return;
749 	}
750 
751 	DPRINTF("received auth request, service=%s, authtype=%s", service, authtype);
752 	for (l=modulelist; l; l=l->next)
753 	{
754 		struct authstaticinfo *auth=l->info;
755 		const char	*modname = auth->auth_name;
756 		int rc;
757 
758 		DPRINTF("%s: trying this module", modname);
759 
760 		rc=(*auth->auth_func)(service, authtype,
761 				      strcpy(pp, p),
762 				      &printauth, &fd);
763 
764 		if (rc == 0)
765 		{
766 			free(pp);
767 			return;
768 		}
769 
770 		if (rc > 0)
771 		{
772 			DPRINTF("%s: TEMPFAIL - no more modules will be tried", modname);
773 			free(pp);
774 			return;	/* Temporary error */
775 		}
776 		DPRINTF("%s: REJECT - try next module", modname);
777 	}
778 	DPRINTF("FAIL, all modules rejected");
779 	writeauth(fd, "FAIL\n", 5);
780 	free(pp);
781 }
782 
idlefunc()783 static void idlefunc()
784 {
785 	struct authstaticinfolist *l;
786 
787 	for (l=modulelist; l; l=l->next)
788 	{
789 		struct authstaticinfo *auth=l->info;
790 
791 		if (auth->auth_idle)
792 			(*auth->auth_idle)();
793 	}
794 }
795 
doauth(int fd)796 static void doauth(int fd)
797 {
798 char	buf[BUFSIZ];
799 int	i, ch;
800 char	*p;
801 
802 	readleft=0;
803 	tcpremoteip[0]=0;
804 
805 	while (1)
806 	{
807 		for (i=0; (ch=getauthc(fd)) != '\n'; i++)
808 		{
809 			if (ch < 0 || i >= sizeof(buf)-2)
810 				return;
811 			buf[i]=ch;
812 		}
813 		buf[i]=0;
814 
815 		for (p=buf; *p; p++)
816 		{
817 			if (*p == ' ' || *p == '=')
818 				break;
819 		}
820 
821 		if (!*p)
822 			break;
823 
824 		if (*p == ' ')
825 		{
826 			*p++=0;
827 			while (*p == ' ')	++p;
828 			break;
829 		}
830 
831 		*p++=0;
832 
833 		if (strcmp(buf, "TCPREMOTEIP") == 0)
834 		{
835 			tcpremoteip[sizeof(tcpremoteip)-1]=0;
836 			strncpy(tcpremoteip, p, sizeof(tcpremoteip)-1);
837 		}
838 	}
839 
840 	if (strcmp(buf, "PRE") == 0)
841 	{
842 		pre(fd, p);
843 		return;
844 	}
845 
846 	if (strcmp(buf, "PASSWD") == 0)
847 	{
848 		passwd(fd, p);
849 		return;
850 	}
851 
852 	if (strcmp(buf, "AUTH") == 0)
853 	{
854 	int j;
855 
856 		i=atoi(p);
857 		if (i < 0 || i >= sizeof(buf))	return;
858 		for (j=0; j<i; j++)
859 		{
860 			ch=getauthc(fd);
861 			if (ch < 0)	return;
862 			buf[j]=ch;
863 		}
864 		buf[j]=0;
865 		auth(fd, buf);
866 	}
867 
868 	if (strcmp(buf, "ENUMERATE") == 0)
869 	{
870 		enumerate(fd);
871 	}
872 }
873 
874 static int sighup_pipe= -1;
875 
sighup(int n)876 static void sighup(int n)
877 {
878 	if (sighup_pipe >= 0)
879 	{
880 		close(sighup_pipe);
881 		sighup_pipe= -1;
882 	}
883 	signal(SIGHUP, sighup);
884 }
885 
886 static int sigterm_received=0;
887 
sigterm(int n)888 static void sigterm(int n)
889 {
890 	sigterm_received=1;
891 	if (sighup_pipe >= 0)
892 	{
893 		close(sighup_pipe);
894 		sighup_pipe= -1;
895 	}
896 	else
897 	{
898 		kill(0, SIGTERM);
899 		_exit(0);
900 	}
901 }
902 
startchildren(int * pipefd)903 static int startchildren(int *pipefd)
904 {
905 unsigned i;
906 pid_t	p;
907 
908 	signal(SIGCHLD, sighup);
909 	for (i=0; i<ndaemons; i++)
910 	{
911 		p=fork();
912 		while (p == -1)
913 		{
914 			perror("CRIT: fork() failed");
915 			sleep(5);
916 			p=fork();
917 		}
918 		if (p == 0)
919 		{
920 			sighup_pipe= -1;
921 			close(pipefd[1]);
922 			signal(SIGHUP, SIG_DFL);
923 			signal(SIGTERM, SIG_DFL);
924 			signal(SIGCHLD, SIG_DFL);
925 			return (1);
926 		}
927 	}
928 	return (0);
929 }
930 
killchildren(int * pipefd)931 static int killchildren(int *pipefd)
932 {
933 int	waitstat;
934 
935 	while (wait(&waitstat) >= 0 || errno != ECHILD)
936 		;
937 
938 	if (pipe(pipefd))
939 	{
940 		perror("CRIT: pipe() failed");
941 		return (-1);
942 	}
943 
944 	return (0);
945 }
946 
start()947 int start()
948 {
949 	int	s;
950 	int	fd;
951 	int	pipefd[2];
952 	int	do_child;
953 
954 	for (fd=3; fd<256; fd++)
955 		close(fd);
956 
957 	if (pipe(pipefd))
958 	{
959 		perror("pipe");
960 		return (1);
961 	}
962 
963 	if (lt_dlinit())
964 	{
965 		fprintf(stderr, "ERR: lt_dlinit() failed: %s\n",
966 			lt_dlerror());
967 		exit(1);
968 	}
969 
970 	if (lt_dlsetsearchpath(PKGLIBDIR))
971 	{
972 		fprintf(stderr, "ERR: lt_dlsetsearchpath() failed: %s\n",
973 			lt_dlerror());
974 		exit(1);
975 	}
976 
977 	if (readconfig())
978 	{
979 		close(pipefd[0]);
980 		close(pipefd[1]);
981 		return (1);
982 	}
983 
984 	s=mksocket();
985 	if (s < 0)
986 	{
987 		perror(AUTHDAEMONSOCK);
988 		close(pipefd[0]);
989 		close(pipefd[1]);
990 		return (1);
991 	}
992 
993 	signal(SIGPIPE, SIG_IGN);
994 	signal(SIGHUP, sighup);
995 	signal(SIGTERM, sigterm);
996 
997 	close(0);
998 	if (open("/dev/null", O_RDWR) != 0)
999 	{
1000 		perror("open");
1001 		exit(1);
1002 	}
1003 	dup2(0, 1);
1004 	sighup_pipe= pipefd[1];
1005 
1006 	do_child=startchildren(pipefd);
1007 
1008 	for (;;)
1009 	{
1010 		struct sockaddr	saddr;
1011 		socklen_t saddr_len;
1012 		fd_set	fds;
1013 		struct timeval tv;
1014 
1015 		FD_ZERO(&fds);
1016 		FD_SET(pipefd[0], &fds);
1017 
1018 		if (do_child)
1019 			FD_SET(s, &fds);
1020 
1021 		tv.tv_sec=300;
1022 		tv.tv_usec=0;
1023 
1024 		if (select( (s > pipefd[0] ? s:pipefd[0])+1,
1025 			&fds, 0, 0, &tv) < 0)
1026 			continue;
1027 		if (FD_ISSET(pipefd[0], &fds))
1028 		{
1029 			close(pipefd[0]);
1030 			if (do_child)
1031 				return (0);	/* Parent died */
1032 			fprintf(stderr, "INFO: stopping authdaemond children\n");
1033 			while (killchildren(pipefd))
1034 				sleep(5);
1035 			if (sigterm_received)
1036 				return (0);
1037 			fprintf(stderr, "INFO: restarting authdaemond children\n");
1038 			readconfig();
1039 			sighup_pipe=pipefd[1];
1040 			do_child=startchildren(pipefd);
1041 			continue;
1042 		}
1043 
1044 		if (!FD_ISSET(s, &fds))
1045 		{
1046 			idlefunc();
1047 			continue;
1048 		}
1049 
1050 		saddr_len=sizeof(saddr);
1051 		if ((fd=accept(s, &saddr, &saddr_len)) < 0)
1052 			continue;
1053 		if (fcntl(fd, F_SETFL, 0) < 0 ||
1054 		    fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
1055 		{
1056 			perror("CRIT: fcntl() failed");
1057 		}
1058 		else
1059 			doauth(fd);
1060 		close(fd);
1061 	}
1062 }
1063