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