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