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