2 ** Copyright 2000-2008 Double Precision, Inc. See COPYING for
3 ** distribution information.
6 #include "courier_auth_config.h"
9 #include <sys/socket.h>
20 #include "numlib/numlib.h"
21 #include "liblock/config.h"
22 #include "liblock/liblock.h"
24 #include "authdaemonrc.h"
25 #include "courierauthdebug.h"
26 #include "pkglibdir.h"
27 #include "authstaticlist.h"
28 #include "libhmac/hmac.h"
32 static const char rcsid
[]="$Id: authdaemond.c,v 1.34 2008/07/10 02:43:55 mrsam Exp $";
38 #include "authstaticlist.h"
40 static unsigned ndaemons
;
42 struct authstaticinfolist
{
43 struct authstaticinfolist
*next
;
44 struct authstaticinfo
*info
;
48 static struct authstaticinfolist
*modulelist
=NULL
;
52 int fd
=socket(PF_UNIX
, SOCK_STREAM
, 0);
53 struct sockaddr_un skun
;
55 if (fd
< 0) return (-1);
56 skun
.sun_family
=AF_UNIX
;
57 strcpy(skun
.sun_path
, AUTHDAEMONSOCK
);
58 strcat(skun
.sun_path
, ".tmp");
59 unlink(skun
.sun_path
);
60 if (bind(fd
, (const struct sockaddr
*)&skun
, sizeof(skun
)) ||
61 listen(fd
, SOMAXCONN
) ||
62 chmod(skun
.sun_path
, 0777) ||
63 rename(skun
.sun_path
, AUTHDAEMONSOCK
) ||
64 fcntl(fd
, F_SETFL
, O_NONBLOCK
) < 0)
66 perror(AUTHDAEMONSOCK
);
74 static int initmodules(const char *p
)
78 struct authstaticinfolist
**modptr
= &modulelist
;
79 struct authstaticinfolist
*m
;
85 fprintf(stderr
, "ERR: Configuration error - missing 'daemons' setting, using %u\n",
89 while ((m
=modulelist
) != NULL
)
92 fprintf(stderr
, "INFO: Uninstalling %s\n",
103 struct authstaticinfo
*a
;
105 if (isspace((int)(unsigned char)*p
))
111 for (i
=0; p
[i
] && !isspace((int)(unsigned char)p
[i
]); ++i
)
115 strncat(buf
, p
, i
>40 ? 40:i
);
117 fprintf(stderr
, "INFO: Installing %s\n", buf
);
123 fprintf(stderr
, "INFO: %s\n", lt_dlerror());
127 sprintf(buf2
, "courier_%s_init", buf
+3);
129 pt
=lt_dlsym(h
, buf2
);
133 "ERR: Can't locate init function %s.\n",
135 fprintf(stderr
, "ERR: %s\n", lt_dlerror());
139 a
= (*(struct authstaticinfo
*(*)(void))pt
)();
141 if ((m
=malloc(sizeof(*modulelist
))) == NULL
)
152 fprintf(stderr
, "INFO: Installation complete: %s\n",
158 static int readconfig()
165 if ((fp
=fopen(AUTHDAEMONRC
, "r")) == NULL
)
167 perror(AUTHDAEMONRC
);
171 while (fgets(buf
, sizeof(buf
), fp
))
173 char *p
=strchr(buf
, '\n'), *q
;
179 while ((c
=getc(fp
)) >= 0 && c
!= '\n')
183 if ((p
=strchr(buf
, '#')) != 0) *p
=0;
186 if (!isspace((int)(unsigned char)*p
))
188 if (*p
== 0) continue;
190 if ((p
=strchr(buf
, '=')) == 0)
192 fprintf(stderr
, "ERR: Bad line in %s: %s\n",
200 while (*p
&& isspace((int)(unsigned char)*p
))
208 if (strcmp(buf
, "authmodulelist") == 0)
221 if (strcmp(buf
, "daemons") == 0)
229 fprintf(stderr
, "INFO: modules=\"%s\", daemons=%u\n",
230 modlist
? modlist
:"(none)",
233 return (initmodules(modlist
));
236 static char buf
[BUFSIZ
];
237 static char *readptr
;
239 static char *writeptr
;
240 static int writeleft
;
242 static int getauthc(int fd
)
248 return ( (int)(unsigned char)*readptr
++ );
255 if (select(fd
+1, &fds
, 0, 0, &tv
) <= 0 ||
258 readleft
=read(fd
, buf
, sizeof(buf
));
266 return ( (int)(unsigned char)*readptr
++ );
269 static int writeauth(int fd
, const char *p
, unsigned pl
)
282 if (select(fd
+1, 0, &fds
, 0, &tv
) <= 0 ||
286 if (n
<= 0) return (-1);
293 static int writeauthflush(int fd
)
297 if (writeauth(fd
, buf
, writeptr
- buf
))
301 writeleft
=sizeof(buf
);
305 static int writeauthbuf(int fd
, const char *p
, unsigned pl
)
313 memcpy(writeptr
, p
, pl
);
319 if (writeauthflush(fd
)) return (-1);
322 if (n
> writeleft
) n
=writeleft
;
323 memcpy(writeptr
, p
, n
);
332 static int writeenvval(int fd
, const char *env
, const char *val
)
334 if (writeauthbuf(fd
, env
, strlen(env
)) ||
335 writeauthbuf(fd
, "=", 1) ||
336 writeauthbuf(fd
, val
, strlen(val
)) ||
337 writeauthbuf(fd
, "\n", 1))
342 static const char *findopt(const char *options
, const char *keyword
)
344 size_t keyword_l
=strlen(keyword
);
348 if (strncmp(options
, keyword
, keyword_l
) == 0)
350 switch (options
[keyword_l
])
353 return options
+ keyword_l
+ 1;
355 return options
+ keyword_l
;
358 options
=strchr(options
, ',');
365 /* Returns a malloc'd string containing the merge of the options string
366 and any default options which apply, or NULL if no options at all */
367 static char *mergeoptions(const char *options
)
369 char *defoptions
= getenv("DEFAULTOPTIONS");
372 if (options
&& *options
&& defoptions
&& *defoptions
)
374 char *result
= malloc(strlen(options
) +
375 strlen(defoptions
) + 2);
381 strcpy(result
, options
);
383 defoptions
= strdup(defoptions
);
391 for (p
= strtok(defoptions
, ","); p
; p
= strtok(0, ","))
393 char *q
= strchr(p
, '=');
395 if (findopt(result
, p
)) continue;
403 else if (options
&& *options
)
405 return strdup(options
);
407 else if (defoptions
&& *defoptions
)
409 return strdup(defoptions
);
415 static int printauth(struct authinfo
*authinfo
, void *vp
)
418 char buf2
[NUMBUFSIZE
];
422 writeleft
=sizeof(buf
);
424 courier_authdebug_authinfo("Authenticated: ", authinfo
,
425 authinfo
->clearpasswd
,
428 if (authinfo
->sysusername
)
429 if (writeenvval(fd
, "USERNAME", authinfo
->sysusername
))
431 if (authinfo
->sysuserid
)
432 if (writeenvval(fd
, "UID", libmail_str_uid_t(*authinfo
->sysuserid
,
435 if (writeenvval(fd
, "GID", libmail_str_uid_t(authinfo
->sysgroupid
, buf2
)))
438 if (writeenvval(fd
, "HOME", authinfo
->homedir
))
440 if (authinfo
->address
)
441 if (writeenvval(fd
, "ADDRESS", authinfo
->address
))
443 if (authinfo
->fullname
)
446 * Only the first field of the comma-seperated GECOS field is the
453 fullname
=strdup(authinfo
->fullname
);
461 while (*p
!= ',' && *p
!= '\0')
464 retval
= writeenvval(fd
, "NAME", fullname
);
469 if (authinfo
->maildir
)
470 if (writeenvval(fd
, "MAILDIR", authinfo
->maildir
))
473 if (writeenvval(fd
, "QUOTA", authinfo
->quota
))
475 if (authinfo
->passwd
)
476 if (writeenvval(fd
, "PASSWD", authinfo
->passwd
))
478 if (authinfo
->clearpasswd
)
479 if (writeenvval(fd
, "PASSWD2", authinfo
->clearpasswd
))
481 fullopt
= mergeoptions(authinfo
->options
);
484 int rc
= writeenvval(fd
, "OPTIONS", fullopt
);
489 if (writeauthbuf(fd
, ".\n", 2) || writeauthflush(fd
))
494 static void pre(int fd
, char *prebuf
)
496 char *p
=strchr(prebuf
, ' ');
498 struct authstaticinfolist
*l
;
502 while (*p
== ' ') ++p
;
507 while (*p
== ' ') ++p
;
509 DPRINTF("received userid lookup request: %s", p
);
511 for (l
=modulelist
; l
; l
=l
->next
)
513 struct authstaticinfo
*auth
=l
->info
;
514 const char *modname
= auth
->auth_name
;
517 if (strcmp(prebuf
, ".") && strcmp(prebuf
, modname
))
520 DPRINTF("%s: trying this module", modname
);
523 rc
=(*auth
->auth_prefunc
)(p
, service
,
531 DPRINTF("%s: TEMPFAIL - no more modules will be tried",
533 return; /* Temporary error */
535 DPRINTF("%s: REJECT - try next module", modname
);
537 writeauth(fd
, "FAIL\n", 5);
538 DPRINTF("FAIL, all modules rejected");
541 struct enumerate_info
{
549 static void enumflush(struct enumerate_info
*ei
)
551 if (ei
->buf_ptr
> ei
->buffer
)
552 writeauth(ei
->fd
, ei
->buffer
, ei
->buf_ptr
- ei
->buffer
);
553 ei
->buf_ptr
=ei
->buffer
;
554 ei
->buf_left
=sizeof(ei
->buffer
);
557 static void enumwrite(struct enumerate_info
*ei
, const char *s
)
563 if (ei
->buf_left
== 0)
567 if (l
> ei
->buf_left
)
569 memcpy(ei
->buf_ptr
, s
, l
);
576 static void enum_cb(const char *name
,
584 struct enumerate_info
*ei
=(struct enumerate_info
*)void_arg
;
585 char buf
[NUMBUFSIZE
];
596 enumwrite(ei
, libmail_str_uid_t(uid
, buf
));
598 enumwrite(ei
, libmail_str_gid_t(gid
, buf
));
600 enumwrite(ei
, homedir
);
602 enumwrite(ei
, maildir
? maildir
: "");
604 fullopt
= mergeoptions(options
);
607 enumwrite(ei
, fullopt
);
613 static void enumerate(int fd
)
615 struct enumerate_info ei
;
616 struct authstaticinfolist
*l
;
621 for (l
=modulelist
; l
; l
=l
->next
)
623 struct authstaticinfo
*auth
=l
->info
;
625 if (auth
->auth_enumerate
== NULL
)
628 enumwrite(&ei
, "# ");
629 enumwrite(&ei
, auth
->auth_name
);
630 enumwrite(&ei
, "\n\n");
632 (*auth
->auth_enumerate
)(enum_cb
, &ei
);
633 if (!ei
.enumerate_ok
)
636 DPRINTF("enumeration terminated prematurely in module %s",
641 enumwrite(&ei
, ".\n");
645 static void dopasswd(int, const char *, const char *, const char *,
648 static void passwd(int fd
, char *prebuf
)
656 for (p
=prebuf
; *p
; p
++)
660 if ((int)(unsigned char)*p
< ' ')
662 writeauth(fd
, "FAIL\n", 5);
669 if ((p
=strchr(service
, '\t')) != 0)
673 if ((p
=strchr(p
, '\t')) != 0)
677 if ((p
=strchr(p
, '\t')) != 0)
681 if ((p
=strchr(p
, '\t')) != 0)
683 dopasswd(fd
, service
, userid
, opwd
, npwd
);
690 static void dopasswd(int fd
,
696 struct authstaticinfolist
*l
;
699 for (l
=modulelist
; l
; l
=l
->next
)
701 struct authstaticinfo
*auth
=l
->info
;
704 int (*f
)(const char *, const char *, const char *,
706 auth
->auth_changepwd
;
711 rc
= (*f
)(service
, userid
, opwd
, npwd
);
715 writeauth(fd
, "OK\n", 3);
721 writeauth(fd
, "FAIL\n", 5);
724 static void auth(int fd
, char *p
)
729 struct authstaticinfolist
*l
;
732 if ((p
=strchr(p
, '\n')) == 0) return;
735 if ((p
=strchr(p
, '\n')) == 0) return;
738 pp
=malloc(strlen(p
)+1);
741 perror("CRIT: malloc() failed");
745 DPRINTF("received auth request, service=%s, authtype=%s", service
, authtype
);
746 for (l
=modulelist
; l
; l
=l
->next
)
748 struct authstaticinfo
*auth
=l
->info
;
749 const char *modname
= auth
->auth_name
;
752 DPRINTF("%s: trying this module", modname
);
754 rc
=(*auth
->auth_func
)(service
, authtype
,
766 DPRINTF("%s: TEMPFAIL - no more modules will be tried", modname
);
768 return; /* Temporary error */
770 DPRINTF("%s: REJECT - try next module", modname
);
772 DPRINTF("FAIL, all modules rejected");
773 writeauth(fd
, "FAIL\n", 5);
777 static void idlefunc()
779 struct authstaticinfolist
*l
;
781 for (l
=modulelist
; l
; l
=l
->next
)
783 struct authstaticinfo
*auth
=l
->info
;
786 (*auth
->auth_idle
)();
790 static void doauth(int fd
)
797 for (i
=0; (ch
=getauthc(fd
)) != '\n'; i
++)
799 if (ch
< 0 || i
>= sizeof(buf
)-2)
810 while (*p
== ' ') ++p
;
815 if (strcmp(buf
, "PRE") == 0)
821 if (strcmp(buf
, "PASSWD") == 0)
827 if (strcmp(buf
, "AUTH") == 0)
832 if (i
< 0 || i
>= sizeof(buf
)) return;
843 if (strcmp(buf
, "ENUMERATE") == 0)
849 static int sighup_pipe
= -1;
851 static RETSIGTYPE
sighup(int n
)
853 if (sighup_pipe
>= 0)
858 signal(SIGHUP
, sighup
);
859 #if RETSIGTYPE != void
864 static int sigterm_received
=0;
866 static RETSIGTYPE
sigterm(int n
)
869 if (sighup_pipe
>= 0)
880 #if RETSIGTYPE != void
885 static int startchildren(int *pipefd
)
890 signal(SIGCHLD
, sighup
);
891 for (i
=0; i
<ndaemons
; i
++)
896 perror("CRIT: fork() failed");
904 signal(SIGHUP
, SIG_DFL
);
905 signal(SIGTERM
, SIG_DFL
);
906 signal(SIGCHLD
, SIG_DFL
);
913 static int killchildren(int *pipefd
)
917 while (wait(&waitstat
) >= 0 || errno
!= ECHILD
)
922 perror("CRIT: pipe() failed");
936 for (fd
=3; fd
<256; fd
++)
947 fprintf(stderr
, "ERR: lt_dlinit() failed: %s\n",
952 if (lt_dlsetsearchpath(PKGLIBDIR
))
954 fprintf(stderr
, "ERR: lt_dlsetsearchpath() failed: %s\n",
969 perror(AUTHDAEMONSOCK
);
975 signal(SIGPIPE
, SIG_IGN
);
976 signal(SIGHUP
, sighup
);
977 signal(SIGTERM
, sigterm
);
980 if (open("/dev/null", O_RDWR
) != 0)
986 sighup_pipe
= pipefd
[1];
988 do_child
=startchildren(pipefd
);
992 struct sockaddr saddr
;
998 FD_SET(pipefd
[0], &fds
);
1006 if (select( (s
> pipefd
[0] ? s
:pipefd
[0])+1,
1007 &fds
, 0, 0, &tv
) < 0)
1009 if (FD_ISSET(pipefd
[0], &fds
))
1013 return (0); /* Parent died */
1014 fprintf(stderr
, "INFO: stopping authdaemond children\n");
1015 while (killchildren(pipefd
))
1017 if (sigterm_received
)
1019 fprintf(stderr
, "INFO: restarting authdaemond children\n");
1021 sighup_pipe
=pipefd
[1];
1022 do_child
=startchildren(pipefd
);
1026 if (!FD_ISSET(s
, &fds
))
1032 saddr_len
=sizeof(saddr
);
1033 if ((fd
=accept(s
, &saddr
, &saddr_len
)) < 0)
1035 if (fcntl(fd
, F_SETFL
, 0) < 0)
1037 perror("CRIT: fcntl() failed");
1045 int main(int argc
, char **argv
)
1047 courier_authdebug_login_init();
1051 fprintf(stderr
, "Error: authdaemond no longer handles its own daemonizing.\n"
1052 "Use new startup script.\n");