Commit | Line | Data |
---|---|---|
d9898ee8 | 1 | /* |
0e333c05 | 2 | ** Copyright 2000-2018 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" | |
0e333c05 | 26 | #include "courierauth.h" |
b0322a85 | 27 | #include "courierauthstaticlist.h" |
ac40fd9e | 28 | #include "libhmac/hmac.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)) || | |
0e333c05 CE |
59 | listen(fd, SOMAXCONN) || |
60 | chmod(skun.sun_path, 0777) || | |
61 | rename(skun.sun_path, AUTHDAEMONSOCK) || | |
62 | fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 || | |
63 | fcntl(fd, F_SETFL, O_NONBLOCK) < 0) | |
d9898ee8 | 64 | { |
65 | perror(AUTHDAEMONSOCK); | |
66 | close(fd); | |
67 | return (-1); | |
68 | } | |
69 | return (fd); | |
70 | } | |
71 | ||
72 | ||
73 | static int initmodules(const char *p) | |
74 | { | |
75 | char buf[100]; | |
76 | char buf2[100]; | |
77 | struct authstaticinfolist **modptr= &modulelist; | |
78 | struct authstaticinfolist *m; | |
79 | ||
80 | if (ndaemons <= 0) | |
81 | { | |
82 | ndaemons=1; | |
83 | ||
84 | fprintf(stderr, "ERR: Configuration error - missing 'daemons' setting, using %u\n", | |
85 | ndaemons); | |
86 | } | |
87 | ||
88 | while ((m=modulelist) != NULL) | |
89 | { | |
90 | modulelist=m->next; | |
91 | fprintf(stderr, "INFO: Uninstalling %s\n", | |
92 | m->info->auth_name); | |
93 | lt_dlclose(m->h); | |
94 | free(m); | |
95 | } | |
96 | ||
97 | while (p && *p) | |
98 | { | |
99 | size_t i; | |
100 | lt_dlhandle h; | |
101 | lt_ptr pt; | |
102 | struct authstaticinfo *a; | |
103 | ||
104 | if (isspace((int)(unsigned char)*p)) | |
105 | { | |
106 | ++p; | |
107 | continue; | |
108 | } | |
109 | ||
110 | for (i=0; p[i] && !isspace((int)(unsigned char)p[i]); ++i) | |
111 | ; | |
112 | ||
113 | strcpy(buf, "lib"); | |
114 | strncat(buf, p, i>40 ? 40:i); | |
115 | ||
116 | fprintf(stderr, "INFO: Installing %s\n", buf); | |
117 | p += i; | |
118 | h=lt_dlopenext(buf); | |
119 | ||
120 | if (h == NULL) | |
121 | { | |
122 | fprintf(stderr, "INFO: %s\n", lt_dlerror()); | |
123 | continue; | |
124 | } | |
125 | ||
126 | sprintf(buf2, "courier_%s_init", buf+3); | |
127 | ||
128 | pt=lt_dlsym(h, buf2); | |
129 | if (pt == NULL) | |
130 | { | |
131 | fprintf(stderr, | |
132 | "ERR: Can't locate init function %s.\n", | |
133 | buf2); | |
134 | fprintf(stderr, "ERR: %s\n", lt_dlerror()); | |
135 | continue; | |
136 | } | |
137 | ||
138 | a= (*(struct authstaticinfo *(*)(void))pt)(); | |
139 | ||
140 | if ((m=malloc(sizeof(*modulelist))) == NULL) | |
141 | { | |
142 | perror("ERR"); | |
143 | lt_dlclose(h); | |
144 | continue; | |
145 | } | |
146 | *modptr=m; | |
147 | m->next=NULL; | |
148 | m->info=a; | |
149 | m->h=h; | |
150 | modptr= &m->next; | |
151 | fprintf(stderr, "INFO: Installation complete: %s\n", | |
152 | a->auth_name); | |
153 | } | |
154 | return (0); | |
155 | } | |
156 | ||
157 | static int readconfig() | |
158 | { | |
159 | char buf[BUFSIZ]; | |
160 | FILE *fp; | |
161 | char *modlist=0; | |
162 | unsigned daemons=0; | |
163 | ||
164 | if ((fp=fopen(AUTHDAEMONRC, "r")) == NULL) | |
165 | { | |
166 | perror(AUTHDAEMONRC); | |
167 | return (-1); | |
168 | } | |
169 | ||
170 | while (fgets(buf, sizeof(buf), fp)) | |
171 | { | |
172 | char *p=strchr(buf, '\n'), *q; | |
173 | ||
174 | if (!p) | |
175 | { | |
176 | int c; | |
177 | ||
178 | while ((c=getc(fp)) >= 0 && c != '\n') | |
179 | ; | |
180 | } | |
181 | else *p=0; | |
182 | if ((p=strchr(buf, '#')) != 0) *p=0; | |
183 | ||
184 | for (p=buf; *p; p++) | |
185 | if (!isspace((int)(unsigned char)*p)) | |
186 | break; | |
187 | if (*p == 0) continue; | |
188 | ||
189 | if ((p=strchr(buf, '=')) == 0) | |
190 | { | |
191 | fprintf(stderr, "ERR: Bad line in %s: %s\n", | |
192 | AUTHDAEMONRC, buf); | |
193 | fclose(fp); | |
194 | if (modlist) | |
195 | free(modlist); | |
196 | return (-1); | |
197 | } | |
198 | *p++=0; | |
199 | while (*p && isspace((int)(unsigned char)*p)) | |
200 | ++p; | |
201 | if (*p == '"') | |
202 | { | |
203 | ++p; | |
204 | q=strchr(p, '"'); | |
205 | if (q) *q=0; | |
206 | } | |
207 | if (strcmp(buf, "authmodulelist") == 0) | |
208 | { | |
209 | if (modlist) | |
210 | free(modlist); | |
211 | modlist=strdup(p); | |
212 | if (!modlist) | |
213 | { | |
214 | perror("malloc"); | |
215 | fclose(fp); | |
216 | return (-1); | |
217 | } | |
218 | continue; | |
219 | } | |
220 | if (strcmp(buf, "daemons") == 0) | |
221 | { | |
222 | daemons=atoi(p); | |
223 | continue; | |
224 | } | |
225 | } | |
226 | fclose(fp); | |
227 | ||
228 | fprintf(stderr, "INFO: modules=\"%s\", daemons=%u\n", | |
229 | modlist ? modlist:"(none)", | |
230 | daemons); | |
231 | ndaemons=daemons; | |
232 | return (initmodules(modlist)); | |
233 | } | |
234 | ||
235 | static char buf[BUFSIZ]; | |
236 | static char *readptr; | |
237 | static int readleft; | |
238 | static char *writeptr; | |
239 | static int writeleft; | |
240 | ||
241 | static int getauthc(int fd) | |
242 | { | |
243 | fd_set fds; | |
244 | struct timeval tv; | |
245 | ||
246 | if (readleft--) | |
247 | return ( (int)(unsigned char)*readptr++ ); | |
248 | ||
249 | readleft=0; | |
250 | FD_ZERO(&fds); | |
251 | FD_SET(fd, &fds); | |
252 | tv.tv_sec=10; | |
253 | tv.tv_usec=0; | |
254 | if (select(fd+1, &fds, 0, 0, &tv) <= 0 || | |
255 | !FD_ISSET(fd, &fds)) | |
256 | return (EOF); | |
257 | readleft=read(fd, buf, sizeof(buf)); | |
258 | readptr=buf; | |
259 | if (readleft <= 0) | |
260 | { | |
261 | readleft=0; | |
262 | return (EOF); | |
263 | } | |
264 | --readleft; | |
265 | return ( (int)(unsigned char)*readptr++ ); | |
266 | } | |
267 | ||
268 | static int writeauth(int fd, const char *p, unsigned pl) | |
269 | { | |
270 | fd_set fds; | |
271 | struct timeval tv; | |
272 | ||
273 | while (pl) | |
274 | { | |
275 | int n; | |
276 | ||
277 | FD_ZERO(&fds); | |
278 | FD_SET(fd, &fds); | |
279 | tv.tv_sec=30; | |
280 | tv.tv_usec=0; | |
281 | if (select(fd+1, 0, &fds, 0, &tv) <= 0 || | |
282 | !FD_ISSET(fd, &fds)) | |
283 | return (-1); | |
284 | n=write(fd, p, pl); | |
285 | if (n <= 0) return (-1); | |
286 | p += n; | |
287 | pl -= n; | |
288 | } | |
289 | return (0); | |
290 | } | |
291 | ||
292 | static int writeauthflush(int fd) | |
293 | { | |
294 | if (writeptr > buf) | |
295 | { | |
296 | if (writeauth(fd, buf, writeptr - buf)) | |
297 | return (-1); | |
298 | } | |
299 | writeptr=buf; | |
300 | writeleft=sizeof(buf); | |
301 | return (0); | |
302 | } | |
303 | ||
304 | static int writeauthbuf(int fd, const char *p, unsigned pl) | |
305 | { | |
306 | unsigned n; | |
307 | ||
308 | while (pl) | |
309 | { | |
310 | if (pl < writeleft) | |
311 | { | |
312 | memcpy(writeptr, p, pl); | |
313 | writeptr += pl; | |
314 | writeleft -= pl; | |
315 | return (0); | |
316 | } | |
317 | ||
318 | if (writeauthflush(fd)) return (-1); | |
319 | ||
320 | n=pl; | |
321 | if (n > writeleft) n=writeleft; | |
322 | memcpy(writeptr, p, n); | |
323 | p += n; | |
324 | writeptr += n; | |
325 | writeleft -= n; | |
326 | pl -= n; | |
327 | } | |
328 | return (0); | |
329 | } | |
330 | ||
331 | static int writeenvval(int fd, const char *env, const char *val) | |
332 | { | |
333 | if (writeauthbuf(fd, env, strlen(env)) || | |
334 | writeauthbuf(fd, "=", 1) || | |
335 | writeauthbuf(fd, val, strlen(val)) || | |
336 | writeauthbuf(fd, "\n", 1)) | |
337 | return (-1); | |
338 | return (0); | |
339 | } | |
340 | ||
341 | static const char *findopt(const char *options, const char *keyword) | |
342 | { | |
343 | size_t keyword_l=strlen(keyword); | |
344 | ||
345 | while (options) | |
346 | { | |
347 | if (strncmp(options, keyword, keyword_l) == 0) | |
348 | { | |
349 | switch (options[keyword_l]) | |
350 | { | |
351 | case '=': | |
352 | return options + keyword_l + 1; | |
353 | case ',': case '\0': | |
354 | return options + keyword_l; | |
355 | } | |
356 | } | |
357 | options=strchr(options, ','); | |
358 | if (options) | |
359 | ++options; | |
360 | } | |
361 | return NULL; | |
362 | } | |
363 | ||
364 | /* Returns a malloc'd string containing the merge of the options string | |
365 | and any default options which apply, or NULL if no options at all */ | |
366 | static char *mergeoptions(const char *options) | |
367 | { | |
368 | char *defoptions = getenv("DEFAULTOPTIONS"); | |
369 | char *p; | |
370 | ||
371 | if (options && *options && defoptions && *defoptions) | |
372 | { | |
373 | char *result = malloc(strlen(options) + | |
374 | strlen(defoptions) + 2); | |
375 | if (!result) | |
376 | { | |
377 | perror("malloc"); | |
378 | return NULL; | |
379 | } | |
380 | strcpy(result, options); | |
381 | ||
382 | defoptions = strdup(defoptions); | |
383 | if (!defoptions) | |
384 | { | |
385 | perror("malloc"); | |
386 | free(result); | |
387 | return NULL; | |
388 | } | |
389 | ||
390 | for (p = strtok(defoptions, ","); p; p = strtok(0, ",")) | |
391 | { | |
392 | char *q = strchr(p, '='); | |
393 | if (q) *q = '\0'; | |
394 | if (findopt(result, p)) continue; | |
395 | if (q) *q = '='; | |
396 | strcat(result, ","); | |
397 | strcat(result, p); | |
398 | } | |
399 | free(defoptions); | |
400 | return result; | |
401 | } | |
402 | else if (options && *options) | |
403 | { | |
404 | return strdup(options); | |
405 | } | |
406 | else if (defoptions && *defoptions) | |
407 | { | |
408 | return strdup(defoptions); | |
409 | } | |
410 | else | |
411 | return 0; | |
412 | } | |
413 | ||
414 | static int printauth(struct authinfo *authinfo, void *vp) | |
415 | { | |
416 | int fd= *(int *)vp; | |
417 | char buf2[NUMBUFSIZE]; | |
418 | char *fullopt; | |
419 | ||
420 | writeptr=buf; | |
421 | writeleft=sizeof(buf); | |
422 | ||
423 | courier_authdebug_authinfo("Authenticated: ", authinfo, | |
424 | authinfo->clearpasswd, | |
425 | authinfo->passwd); | |
426 | ||
427 | if (authinfo->sysusername) | |
428 | if (writeenvval(fd, "USERNAME", authinfo->sysusername)) | |
429 | return (1); | |
430 | if (authinfo->sysuserid) | |
431 | if (writeenvval(fd, "UID", libmail_str_uid_t(*authinfo->sysuserid, | |
432 | buf2))) | |
433 | return (1); | |
434 | if (writeenvval(fd, "GID", libmail_str_uid_t(authinfo->sysgroupid, buf2))) | |
435 | return (1); | |
436 | ||
437 | if (writeenvval(fd, "HOME", authinfo->homedir)) | |
438 | return (1); | |
439 | if (authinfo->address) | |
440 | if (writeenvval(fd, "ADDRESS", authinfo->address)) | |
441 | return (1); | |
442 | if (authinfo->fullname) | |
443 | { | |
0e333c05 CE |
444 | /* |
445 | * Only the first field of the comma-seperated GECOS field is the | |
446 | * full username. | |
d9898ee8 | 447 | */ |
448 | char *fullname; | |
449 | char *p; | |
450 | int retval; | |
451 | ||
452 | fullname=strdup(authinfo->fullname); | |
453 | if(fullname == NULL) | |
454 | { | |
455 | perror("strdup"); | |
456 | return (1); | |
457 | } | |
458 | ||
459 | p = fullname; | |
460 | while (*p != ',' && *p != '\0') | |
461 | p++; | |
0e333c05 | 462 | *p=0; |
d9898ee8 | 463 | retval = writeenvval(fd, "NAME", fullname); |
464 | free(fullname); | |
465 | if(retval) | |
466 | return (1); | |
467 | } | |
468 | if (authinfo->maildir) | |
469 | if (writeenvval(fd, "MAILDIR", authinfo->maildir)) | |
470 | return (1); | |
471 | if (authinfo->quota) | |
472 | if (writeenvval(fd, "QUOTA", authinfo->quota)) | |
473 | return (1); | |
474 | if (authinfo->passwd) | |
475 | if (writeenvval(fd, "PASSWD", authinfo->passwd)) | |
476 | return (1); | |
477 | if (authinfo->clearpasswd) | |
478 | if (writeenvval(fd, "PASSWD2", authinfo->clearpasswd)) | |
479 | return (1); | |
480 | fullopt = mergeoptions(authinfo->options); | |
481 | if (fullopt) | |
482 | { | |
483 | int rc = writeenvval(fd, "OPTIONS", fullopt); | |
484 | free(fullopt); | |
485 | if (rc) | |
486 | return (1); | |
487 | } | |
488 | if (writeauthbuf(fd, ".\n", 2) || writeauthflush(fd)) | |
489 | return (1); | |
490 | return (0); | |
491 | } | |
492 | ||
493 | static void pre(int fd, char *prebuf) | |
494 | { | |
495 | char *p=strchr(prebuf, ' '); | |
496 | char *service; | |
497 | struct authstaticinfolist *l; | |
498 | ||
499 | if (!p) return; | |
500 | *p++=0; | |
501 | while (*p == ' ') ++p; | |
502 | service=p; | |
503 | p=strchr(p, ' '); | |
504 | if (!p) return; | |
505 | *p++=0; | |
506 | while (*p == ' ') ++p; | |
507 | ||
508 | DPRINTF("received userid lookup request: %s", p); | |
509 | ||
510 | for (l=modulelist; l; l=l->next) | |
511 | { | |
512 | struct authstaticinfo *auth=l->info; | |
513 | const char *modname = auth->auth_name; | |
514 | int rc; | |
515 | ||
516 | if (strcmp(prebuf, ".") && strcmp(prebuf, modname)) | |
517 | continue; | |
518 | ||
519 | DPRINTF("%s: trying this module", modname); | |
520 | ||
521 | ||
522 | rc=(*auth->auth_prefunc)(p, service, | |
523 | &printauth, &fd); | |
524 | ||
525 | if (rc == 0) | |
526 | return; | |
527 | ||
528 | if (rc > 0) | |
529 | { | |
530 | DPRINTF("%s: TEMPFAIL - no more modules will be tried", | |
531 | modname); | |
532 | return; /* Temporary error */ | |
533 | } | |
534 | DPRINTF("%s: REJECT - try next module", modname); | |
535 | } | |
536 | writeauth(fd, "FAIL\n", 5); | |
537 | DPRINTF("FAIL, all modules rejected"); | |
538 | } | |
539 | ||
540 | struct enumerate_info { | |
541 | int fd; | |
542 | char *buf_ptr; | |
543 | size_t buf_left; | |
544 | char buffer[BUFSIZ]; | |
545 | int enumerate_ok; | |
546 | }; | |
547 | ||
548 | static void enumflush(struct enumerate_info *ei) | |
549 | { | |
550 | if (ei->buf_ptr > ei->buffer) | |
551 | writeauth(ei->fd, ei->buffer, ei->buf_ptr - ei->buffer); | |
552 | ei->buf_ptr=ei->buffer; | |
553 | ei->buf_left=sizeof(ei->buffer); | |
554 | } | |
555 | ||
556 | static void enumwrite(struct enumerate_info *ei, const char *s) | |
557 | { | |
558 | while (s && *s) | |
559 | { | |
560 | size_t l; | |
561 | ||
562 | if (ei->buf_left == 0) | |
563 | enumflush(ei); | |
564 | ||
565 | l=strlen(s); | |
566 | if (l > ei->buf_left) | |
567 | l=ei->buf_left; | |
568 | memcpy(ei->buf_ptr, s, l); | |
569 | ei->buf_ptr += l; | |
570 | ei->buf_left -= l; | |
571 | s += l; | |
572 | } | |
573 | } | |
574 | ||
575 | static void enum_cb(const char *name, | |
576 | uid_t uid, | |
577 | gid_t gid, | |
578 | const char *homedir, | |
579 | const char *maildir, | |
580 | const char *options, | |
581 | void *void_arg) | |
582 | { | |
583 | struct enumerate_info *ei=(struct enumerate_info *)void_arg; | |
584 | char buf[NUMBUFSIZE]; | |
585 | char *fullopt; | |
586 | ||
587 | if (name == NULL) | |
588 | { | |
589 | ei->enumerate_ok=1; | |
590 | return; | |
591 | } | |
592 | ||
593 | enumwrite(ei, name); | |
594 | enumwrite(ei, "\t"); | |
595 | enumwrite(ei, libmail_str_uid_t(uid, buf)); | |
596 | enumwrite(ei, "\t"); | |
597 | enumwrite(ei, libmail_str_gid_t(gid, buf)); | |
598 | enumwrite(ei, "\t"); | |
599 | enumwrite(ei, homedir); | |
600 | enumwrite(ei, "\t"); | |
601 | enumwrite(ei, maildir ? maildir : ""); | |
602 | enumwrite(ei, "\t"); | |
603 | fullopt = mergeoptions(options); | |
604 | if (fullopt) | |
605 | { | |
606 | enumwrite(ei, fullopt); | |
607 | free (fullopt); | |
608 | } | |
609 | enumwrite(ei, "\n"); | |
610 | } | |
611 | ||
612 | static void enumerate(int fd) | |
613 | { | |
614 | struct enumerate_info ei; | |
615 | struct authstaticinfolist *l; | |
616 | ||
617 | ei.fd=fd; | |
0e333c05 | 618 | ei.buf_ptr=ei.buffer; |
d9898ee8 | 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 | ||
645 | static void dopasswd(int, const char *, const char *, const char *, | |
646 | const char *); | |
647 | ||
648 | static 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 | ||
690 | static void dopasswd(int fd, | |
691 | const char *service, | |
692 | const char *userid, | |
693 | const char *opwd, | |
694 | const char *npwd) | |
695 | { | |
696 | struct 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 | ||
724 | static 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 | ||
777 | static 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 | ||
790 | static void doauth(int fd) | |
791 | { | |
792 | char buf[BUFSIZ]; | |
793 | int i, ch; | |
794 | char *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 | ||
849 | static int sighup_pipe= -1; | |
850 | ||
8d138742 | 851 | static 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 | ||
861 | static int sigterm_received=0; | |
862 | ||
8d138742 | 863 | static 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 | ||
878 | static int startchildren(int *pipefd) | |
879 | { | |
880 | unsigned i; | |
881 | pid_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 | ||
906 | static int killchildren(int *pipefd) | |
907 | { | |
908 | int 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 | ||
922 | int 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; | |
0e333c05 CE |
1028 | if (fcntl(fd, F_SETFL, 0) < 0 || |
1029 | fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) | |
d9898ee8 | 1030 | { |
1031 | perror("CRIT: fcntl() failed"); | |
1032 | } | |
1033 | else | |
1034 | doauth(fd); | |
1035 | close(fd); | |
1036 | } | |
1037 | } |