2 ** Copyright 2000-2006 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"
30 static const char rcsid
[]="$Id: authdaemond.c,v 1.33 2006/06/01 10:47:32 mrsam Exp $";
37 #include "libhmac/hmac.h"
41 #include "authstaticlist.h"
43 static unsigned ndaemons
;
45 struct authstaticinfolist
{
46 struct authstaticinfolist
*next
;
47 struct authstaticinfo
*info
;
51 static struct authstaticinfolist
*modulelist
=NULL
;
55 int fd
=socket(PF_UNIX
, SOCK_STREAM
, 0);
56 struct sockaddr_un skun
;
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)
69 perror(AUTHDAEMONSOCK
);
77 static int initmodules(const char *p
)
81 struct authstaticinfolist
**modptr
= &modulelist
;
82 struct authstaticinfolist
*m
;
88 fprintf(stderr
, "ERR: Configuration error - missing 'daemons' setting, using %u\n",
92 while ((m
=modulelist
) != NULL
)
95 fprintf(stderr
, "INFO: Uninstalling %s\n",
106 struct authstaticinfo
*a
;
108 if (isspace((int)(unsigned char)*p
))
114 for (i
=0; p
[i
] && !isspace((int)(unsigned char)p
[i
]); ++i
)
118 strncat(buf
, p
, i
>40 ? 40:i
);
120 fprintf(stderr
, "INFO: Installing %s\n", buf
);
126 fprintf(stderr
, "INFO: %s\n", lt_dlerror());
130 sprintf(buf2
, "courier_%s_init", buf
+3);
132 pt
=lt_dlsym(h
, buf2
);
136 "ERR: Can't locate init function %s.\n",
138 fprintf(stderr
, "ERR: %s\n", lt_dlerror());
142 a
= (*(struct authstaticinfo
*(*)(void))pt
)();
144 if ((m
=malloc(sizeof(*modulelist
))) == NULL
)
155 fprintf(stderr
, "INFO: Installation complete: %s\n",
161 static int readconfig()
168 if ((fp
=fopen(AUTHDAEMONRC
, "r")) == NULL
)
170 perror(AUTHDAEMONRC
);
174 while (fgets(buf
, sizeof(buf
), fp
))
176 char *p
=strchr(buf
, '\n'), *q
;
182 while ((c
=getc(fp
)) >= 0 && c
!= '\n')
186 if ((p
=strchr(buf
, '#')) != 0) *p
=0;
189 if (!isspace((int)(unsigned char)*p
))
191 if (*p
== 0) continue;
193 if ((p
=strchr(buf
, '=')) == 0)
195 fprintf(stderr
, "ERR: Bad line in %s: %s\n",
203 while (*p
&& isspace((int)(unsigned char)*p
))
211 if (strcmp(buf
, "authmodulelist") == 0)
224 if (strcmp(buf
, "daemons") == 0)
232 fprintf(stderr
, "INFO: modules=\"%s\", daemons=%u\n",
233 modlist
? modlist
:"(none)",
236 return (initmodules(modlist
));
239 static char buf
[BUFSIZ
];
240 static char *readptr
;
242 static char *writeptr
;
243 static int writeleft
;
245 static int getauthc(int fd
)
251 return ( (int)(unsigned char)*readptr
++ );
258 if (select(fd
+1, &fds
, 0, 0, &tv
) <= 0 ||
261 readleft
=read(fd
, buf
, sizeof(buf
));
269 return ( (int)(unsigned char)*readptr
++ );
272 static int writeauth(int fd
, const char *p
, unsigned pl
)
285 if (select(fd
+1, 0, &fds
, 0, &tv
) <= 0 ||
289 if (n
<= 0) return (-1);
296 static int writeauthflush(int fd
)
300 if (writeauth(fd
, buf
, writeptr
- buf
))
304 writeleft
=sizeof(buf
);
308 static int writeauthbuf(int fd
, const char *p
, unsigned pl
)
316 memcpy(writeptr
, p
, pl
);
322 if (writeauthflush(fd
)) return (-1);
325 if (n
> writeleft
) n
=writeleft
;
326 memcpy(writeptr
, p
, n
);
335 static int writeenvval(int fd
, const char *env
, const char *val
)
337 if (writeauthbuf(fd
, env
, strlen(env
)) ||
338 writeauthbuf(fd
, "=", 1) ||
339 writeauthbuf(fd
, val
, strlen(val
)) ||
340 writeauthbuf(fd
, "\n", 1))
345 static const char *findopt(const char *options
, const char *keyword
)
347 size_t keyword_l
=strlen(keyword
);
351 if (strncmp(options
, keyword
, keyword_l
) == 0)
353 switch (options
[keyword_l
])
356 return options
+ keyword_l
+ 1;
358 return options
+ keyword_l
;
361 options
=strchr(options
, ',');
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
)
372 char *defoptions
= getenv("DEFAULTOPTIONS");
375 if (options
&& *options
&& defoptions
&& *defoptions
)
377 char *result
= malloc(strlen(options
) +
378 strlen(defoptions
) + 2);
384 strcpy(result
, options
);
386 defoptions
= strdup(defoptions
);
394 for (p
= strtok(defoptions
, ","); p
; p
= strtok(0, ","))
396 char *q
= strchr(p
, '=');
398 if (findopt(result
, p
)) continue;
406 else if (options
&& *options
)
408 return strdup(options
);
410 else if (defoptions
&& *defoptions
)
412 return strdup(defoptions
);
418 static int printauth(struct authinfo
*authinfo
, void *vp
)
421 char buf2
[NUMBUFSIZE
];
425 writeleft
=sizeof(buf
);
427 courier_authdebug_authinfo("Authenticated: ", authinfo
,
428 authinfo
->clearpasswd
,
431 if (authinfo
->sysusername
)
432 if (writeenvval(fd
, "USERNAME", authinfo
->sysusername
))
434 if (authinfo
->sysuserid
)
435 if (writeenvval(fd
, "UID", libmail_str_uid_t(*authinfo
->sysuserid
,
438 if (writeenvval(fd
, "GID", libmail_str_uid_t(authinfo
->sysgroupid
, buf2
)))
441 if (writeenvval(fd
, "HOME", authinfo
->homedir
))
443 if (authinfo
->address
)
444 if (writeenvval(fd
, "ADDRESS", authinfo
->address
))
446 if (authinfo
->fullname
)
449 * Only the first field of the comma-seperated GECOS field is the
456 fullname
=strdup(authinfo
->fullname
);
464 while (*p
!= ',' && *p
!= '\0')
467 retval
= writeenvval(fd
, "NAME", fullname
);
472 if (authinfo
->maildir
)
473 if (writeenvval(fd
, "MAILDIR", authinfo
->maildir
))
476 if (writeenvval(fd
, "QUOTA", authinfo
->quota
))
478 if (authinfo
->passwd
)
479 if (writeenvval(fd
, "PASSWD", authinfo
->passwd
))
481 if (authinfo
->clearpasswd
)
482 if (writeenvval(fd
, "PASSWD2", authinfo
->clearpasswd
))
484 fullopt
= mergeoptions(authinfo
->options
);
487 int rc
= writeenvval(fd
, "OPTIONS", fullopt
);
492 if (writeauthbuf(fd
, ".\n", 2) || writeauthflush(fd
))
497 static void pre(int fd
, char *prebuf
)
499 char *p
=strchr(prebuf
, ' ');
501 struct authstaticinfolist
*l
;
505 while (*p
== ' ') ++p
;
510 while (*p
== ' ') ++p
;
512 DPRINTF("received userid lookup request: %s", p
);
514 for (l
=modulelist
; l
; l
=l
->next
)
516 struct authstaticinfo
*auth
=l
->info
;
517 const char *modname
= auth
->auth_name
;
520 if (strcmp(prebuf
, ".") && strcmp(prebuf
, modname
))
523 DPRINTF("%s: trying this module", modname
);
526 rc
=(*auth
->auth_prefunc
)(p
, service
,
534 DPRINTF("%s: TEMPFAIL - no more modules will be tried",
536 return; /* Temporary error */
538 DPRINTF("%s: REJECT - try next module", modname
);
540 writeauth(fd
, "FAIL\n", 5);
541 DPRINTF("FAIL, all modules rejected");
544 struct enumerate_info
{
552 static void enumflush(struct enumerate_info
*ei
)
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
);
560 static void enumwrite(struct enumerate_info
*ei
, const char *s
)
566 if (ei
->buf_left
== 0)
570 if (l
> ei
->buf_left
)
572 memcpy(ei
->buf_ptr
, s
, l
);
579 static void enum_cb(const char *name
,
587 struct enumerate_info
*ei
=(struct enumerate_info
*)void_arg
;
588 char buf
[NUMBUFSIZE
];
599 enumwrite(ei
, libmail_str_uid_t(uid
, buf
));
601 enumwrite(ei
, libmail_str_gid_t(gid
, buf
));
603 enumwrite(ei
, homedir
);
605 enumwrite(ei
, maildir
? maildir
: "");
607 fullopt
= mergeoptions(options
);
610 enumwrite(ei
, fullopt
);
616 static void enumerate(int fd
)
618 struct enumerate_info ei
;
619 struct authstaticinfolist
*l
;
624 for (l
=modulelist
; l
; l
=l
->next
)
626 struct authstaticinfo
*auth
=l
->info
;
628 if (auth
->auth_enumerate
== NULL
)
631 enumwrite(&ei
, "# ");
632 enumwrite(&ei
, auth
->auth_name
);
633 enumwrite(&ei
, "\n\n");
635 (*auth
->auth_enumerate
)(enum_cb
, &ei
);
636 if (!ei
.enumerate_ok
)
639 DPRINTF("enumeration terminated prematurely in module %s",
644 enumwrite(&ei
, ".\n");
648 static void dopasswd(int, const char *, const char *, const char *,
651 static void passwd(int fd
, char *prebuf
)
659 for (p
=prebuf
; *p
; p
++)
663 if ((int)(unsigned char)*p
< ' ')
665 writeauth(fd
, "FAIL\n", 5);
672 if ((p
=strchr(service
, '\t')) != 0)
676 if ((p
=strchr(p
, '\t')) != 0)
680 if ((p
=strchr(p
, '\t')) != 0)
684 if ((p
=strchr(p
, '\t')) != 0)
686 dopasswd(fd
, service
, userid
, opwd
, npwd
);
693 static void dopasswd(int fd
,
699 struct authstaticinfolist
*l
;
702 for (l
=modulelist
; l
; l
=l
->next
)
704 struct authstaticinfo
*auth
=l
->info
;
707 int (*f
)(const char *, const char *, const char *,
709 auth
->auth_changepwd
;
714 rc
= (*f
)(service
, userid
, opwd
, npwd
);
718 writeauth(fd
, "OK\n", 3);
724 writeauth(fd
, "FAIL\n", 5);
727 static void auth(int fd
, char *p
)
732 struct authstaticinfolist
*l
;
735 if ((p
=strchr(p
, '\n')) == 0) return;
738 if ((p
=strchr(p
, '\n')) == 0) return;
741 pp
=malloc(strlen(p
)+1);
744 perror("CRIT: malloc() failed");
748 DPRINTF("received auth request, service=%s, authtype=%s", service
, authtype
);
749 for (l
=modulelist
; l
; l
=l
->next
)
751 struct authstaticinfo
*auth
=l
->info
;
752 const char *modname
= auth
->auth_name
;
755 DPRINTF("%s: trying this module", modname
);
757 rc
=(*auth
->auth_func
)(service
, authtype
,
769 DPRINTF("%s: TEMPFAIL - no more modules will be tried", modname
);
771 return; /* Temporary error */
773 DPRINTF("%s: REJECT - try next module", modname
);
775 DPRINTF("FAIL, all modules rejected");
776 writeauth(fd
, "FAIL\n", 5);
780 static void idlefunc()
782 struct authstaticinfolist
*l
;
784 for (l
=modulelist
; l
; l
=l
->next
)
786 struct authstaticinfo
*auth
=l
->info
;
789 (*auth
->auth_idle
)();
793 static void doauth(int fd
)
800 for (i
=0; (ch
=getauthc(fd
)) != '\n'; i
++)
802 if (ch
< 0 || i
>= sizeof(buf
)-2)
813 while (*p
== ' ') ++p
;
818 if (strcmp(buf
, "PRE") == 0)
824 if (strcmp(buf
, "PASSWD") == 0)
830 if (strcmp(buf
, "AUTH") == 0)
835 if (i
< 0 || i
>= sizeof(buf
)) return;
846 if (strcmp(buf
, "ENUMERATE") == 0)
852 static int sighup_pipe
= -1;
854 static RETSIGTYPE
sighup(int n
)
856 if (sighup_pipe
>= 0)
861 signal(SIGHUP
, sighup
);
862 #if RETSIGTYPE != void
867 static int sigterm_received
=0;
869 static RETSIGTYPE
sigterm(int n
)
872 if (sighup_pipe
>= 0)
883 #if RETSIGTYPE != void
888 static int startchildren(int *pipefd
)
893 signal(SIGCHLD
, sighup
);
894 for (i
=0; i
<ndaemons
; i
++)
899 perror("CRIT: fork() failed");
907 signal(SIGHUP
, SIG_DFL
);
908 signal(SIGTERM
, SIG_DFL
);
909 signal(SIGCHLD
, SIG_DFL
);
916 static int killchildren(int *pipefd
)
920 while (wait(&waitstat
) >= 0 || errno
!= ECHILD
)
925 perror("CRIT: pipe() failed");
939 for (fd
=3; fd
<256; fd
++)
950 fprintf(stderr
, "ERR: lt_dlinit() failed: %s\n",
955 if (lt_dlsetsearchpath(PKGLIBDIR
))
957 fprintf(stderr
, "ERR: lt_dlsetsearchpath() failed: %s\n",
972 perror(AUTHDAEMONSOCK
);
978 signal(SIGPIPE
, SIG_IGN
);
979 signal(SIGHUP
, sighup
);
980 signal(SIGTERM
, sigterm
);
983 if (open("/dev/null", O_RDWR
) != 0)
989 sighup_pipe
= pipefd
[1];
991 do_child
=startchildren(pipefd
);
995 struct sockaddr saddr
;
1001 FD_SET(pipefd
[0], &fds
);
1009 if (select( (s
> pipefd
[0] ? s
:pipefd
[0])+1,
1010 &fds
, 0, 0, &tv
) < 0)
1012 if (FD_ISSET(pipefd
[0], &fds
))
1016 return (0); /* Parent died */
1017 fprintf(stderr
, "INFO: stopping authdaemond children\n");
1018 while (killchildren(pipefd
))
1020 if (sigterm_received
)
1022 fprintf(stderr
, "INFO: restarting authdaemond children\n");
1024 sighup_pipe
=pipefd
[1];
1025 do_child
=startchildren(pipefd
);
1029 if (!FD_ISSET(s
, &fds
))
1035 saddr_len
=sizeof(saddr
);
1036 if ((fd
=accept(s
, &saddr
, &saddr_len
)) < 0)
1038 if (fcntl(fd
, F_SETFL
, 0) < 0)
1040 perror("CRIT: fcntl() failed");
1048 int main(int argc
, char **argv
)
1050 courier_authdebug_login_init();
1054 fprintf(stderr
, "Error: authdaemond no longer handles its own daemonizing.\n"
1055 "Use new startup script.\n");