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 | |
38 | static unsigned ndaemons; |
39 | |
40 | struct authstaticinfolist { |
41 | struct authstaticinfolist *next; |
42 | struct authstaticinfo *info; |
43 | lt_dlhandle h; |
44 | }; |
45 | |
46 | static struct authstaticinfolist *modulelist=NULL; |
47 | |
48 | static int mksocket() |
49 | { |
50 | int fd=socket(PF_UNIX, SOCK_STREAM, 0); |
51 | struct 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 | |
72 | static 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 | |
156 | static 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 | |
234 | static char buf[BUFSIZ]; |
235 | static char *readptr; |
236 | static int readleft; |
237 | static char *writeptr; |
238 | static int writeleft; |
239 | |
240 | static int getauthc(int fd) |
241 | { |
242 | fd_set fds; |
243 | struct 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 | |
267 | static int writeauth(int fd, const char *p, unsigned pl) |
268 | { |
269 | fd_set fds; |
270 | struct 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 | |
291 | static 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 | |
303 | static int writeauthbuf(int fd, const char *p, unsigned pl) |
304 | { |
305 | unsigned 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 | |
330 | static 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 | |
340 | static 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 */ |
365 | static 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 | |
413 | static 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 | |
492 | static void pre(int fd, char *prebuf) |
493 | { |
494 | char *p=strchr(prebuf, ' '); |
495 | char *service; |
496 | struct 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 | |
539 | struct enumerate_info { |
540 | int fd; |
541 | char *buf_ptr; |
542 | size_t buf_left; |
543 | char buffer[BUFSIZ]; |
544 | int enumerate_ok; |
545 | }; |
546 | |
547 | static 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 | |
555 | static 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 | |
574 | static 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 | |
611 | static 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 | |
643 | static void dopasswd(int, const char *, const char *, const char *, |
644 | const char *); |
645 | |
646 | static 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 | |
688 | static void dopasswd(int fd, |
689 | const char *service, |
690 | const char *userid, |
691 | const char *opwd, |
692 | const char *npwd) |
693 | { |
694 | struct 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 | |
722 | static 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 | |
775 | static 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 | |
788 | static void doauth(int fd) |
789 | { |
790 | char buf[BUFSIZ]; |
791 | int i, ch; |
792 | char *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 | |
847 | static int sighup_pipe= -1; |
848 | |
8d138742 |
849 | static 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 | |
859 | static int sigterm_received=0; |
860 | |
8d138742 |
861 | static 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 | |
876 | static int startchildren(int *pipefd) |
877 | { |
878 | unsigned i; |
879 | pid_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 | |
904 | static int killchildren(int *pipefd) |
905 | { |
906 | int 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 | |
920 | int 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 | |
1036 | int 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 | } |