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