diff options
Diffstat (limited to 'sqmail-4.3.07/src/qmail-authuser.c')
-rwxr-xr-x | sqmail-4.3.07/src/qmail-authuser.c | 446 |
1 files changed, 0 insertions, 446 deletions
diff --git a/sqmail-4.3.07/src/qmail-authuser.c b/sqmail-4.3.07/src/qmail-authuser.c deleted file mode 100755 index ff0891b..0000000 --- a/sqmail-4.3.07/src/qmail-authuser.c +++ /dev/null @@ -1,446 +0,0 @@ -#include <stdio.h> -#include <unistd.h> -#include "global.h" -#include "stralloc.h" -#include "buffer.h" -#include "auto_qmail.h" -#include "case.h" -#include "control.h" -#include "constmap.h" -#include "str.h" -#include "fmt.h" -#include "fd.h" -#include "open.h" -#include "byte.h" -#include "scan.h" -#include "md5.h" -#include "hmac_md5.h" -#include "sha1.h" -#include "sha256.h" -#include "pathexec.h" -#include "prot.h" -#include "wait.h" -#include "sig.h" -#include "error.h" -#include "env.h" -#include "qmail.h" -#define FDAUTH 3 -#define FDGOSSIP 1 -#define SOCKET_CALL "-s" -#define DOVECOT_SERVICE "-x" - -extern char *crypt(); -#include <pwd.h> -static struct passwd *pw; - -#include "hasspnam.h" -#ifdef HASGETSPNAM -#include <shadow.h> -static struct spwd *spw; -#endif - -#include "hasuserpw.h" -#ifdef HASUSERPW -#include <userpw.h> -static struct userpw *upw; -#endif - -/** - @file qmail-authuser.c - @brief user authentication for qmail-smtpd/qmail-pop3d,bincimapd - @return 0: ok - 1: credentials failure - 2: qmail-authuser is misused - 110: can't read controls - 111: temporary problem checking the password -*/ - -char authbuf[BUFSIZE_AUTH]; -buffer ba = BUFFER_INIT(write,FDAUTH,authbuf,sizeof(authbuf)); - -struct constmap mapauthuser; -stralloc authfile = {0}; -stralloc disabled = {0}; -stralloc user = {0}; // user w/o domain appended -stralloc homedir = {0}; -stralloc shell = {0}; - -/** - @brief Supported storage methods: - (1) authuser:[=]plainpasswd, - (2) authuser:%hashpasswd, - (3) authuser:?, authuser:!, *:?, *:! (! -> +environment) - (4) x:+ -> checkvpw; x = { user@domain, @domain, @ } vmailmgr - (5) x:& -> vchkpw; x = { user@domain, @domain, @ } vpopmail - (6) x:= -> qmail-client; x = { user@domain, @domain, @ } dovecot - Supported auth methods: - user/login/plain: (1,2,3,4,5,6), - cram-md5/apop: (1,5) -**/ - -void exit(int fail) -{ - int i; - - for (i = 0; i < sizeof(authbuf); ++i) authbuf[i] = 0; - _exit(fail); -} - -int dig_ascii(char *digascii,const char *digest,const int len) -{ - static const char hextab[] = "0123456789abcdef"; - int j; - - for (j = 0; j < len; j++) { - digascii[2 * j] = hextab[digest[j] >> 4]; - digascii[2 * j + 1] = hextab[digest[j] & 0x0f]; - } - digascii[2 * len] = '\0'; - - return (2*j); // 2*len -} - -int auth_sha1(char *pwdhash,char *response) -{ - unsigned char digest[20]; - unsigned char digascii[41]; - - sha1_hash(digest,response,str_len(response)); - dig_ascii(digascii,digest,20); - - return str_diffn(digascii,pwdhash,40); -} - -int auth_sha256(char *pwdhash,char *response) -{ - unsigned char digest[32]; - unsigned char digascii[65]; - - sha256_hash(digest,response,str_len(response)); - dig_ascii(digascii,digest,32); - - return str_diffn(digascii,pwdhash,64); -} - -int auth_md5(char *pwdhash,char *response) -{ - MD5_CTX ctx; - unsigned char digest[16]; - unsigned char digascii[33]; - - MD5Init(&ctx); - MD5Update(&ctx,response,str_len(response)); - MD5Final(digest,&ctx); - dig_ascii(digascii,digest,16); - - return str_diffn(digascii,pwdhash,32); -} - -int auth_hash(char *password,char *response) -{ - switch (str_len(password)) { - case 32: return auth_md5(password,response); - case 40: return auth_sha1(password,response); - case 64: return auth_sha256(password,response); - default: return -1; - } -} - -int auth_unix(char *user,char* response) -{ - char *encrypted = 0; - char *stored = 0; - int r = -1; - - pw = getpwnam(user); - if (pw) { - stored = pw->pw_passwd; - if (!stralloc_copys(&homedir,pw->pw_dir)) exit(111); - if (!stralloc_copys(&shell,pw->pw_shell)) exit(111); - } else { - if (errno == ETXTBSY) exit(111); - exit(1); - } - - if (response) { -#ifdef HASUSERPW - upw = getuserpw(user); - if (upw) - stored = upw->upw_passwd; - else - if (errno == ETXTBSY) exit(111); -#elif HASGETSPNAM - spw = getspnam(user); - if (spw) - stored = spw->sp_pwdp; - else - if (errno == ETXTBSY) exit(111); -#endif - if (!stored || !*stored) exit(111); - encrypted = crypt(response,stored); - if (!encrypted) exit(111); // no password given (tx. M.B.) - r = str_diff(encrypted,stored); - } - - if (r == 0 || !response) { - if (prot_gid((int) pw->pw_gid) == -1) exit(1); - if (prot_uid((int) pw->pw_uid) == -1) exit(1); - if (chdir(pw->pw_dir) == -1) exit(111); - } - - return r; -} - -int auth_apop(unsigned char *password,unsigned char *response,unsigned char *challenge) -{ - MD5_CTX context; - unsigned char digest[16]; - unsigned char digascii[33]; - - MD5Init(&context); - MD5Update(&context,challenge,str_len(challenge)); - MD5Update(&context,password,str_len(password)); - MD5Final(digest,&context); - dig_ascii(digascii,digest,16); - - return (str_diff(digascii,response)); -} - -int auth_cram(unsigned char *password,unsigned char *response,unsigned char *challenge) -{ - unsigned char digest[16]; - unsigned char digascii[33]; - - hmac_md5(challenge,str_len(challenge),password,str_len(password),digest); - dig_ascii(digascii,digest,16); - - return (str_diff(digascii,response) && str_diff(password,response)); // cram or plain -} - -int auth_dovecot(char *user,char *response,char *socket,char *service) -{ - int wstat; - int child; - char *wrapper[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - int i = 0; - - close(FDGOSSIP); /* gossiping doveadm */ - - switch (child = fork()) { - case -1: - exit(111); - case 0: - wrapper[i] = "doveadm"; - wrapper[++i] = "auth"; - wrapper[++i] = "test"; - if (socket) { - wrapper[++i] = "-a"; - wrapper[++i] = socket; - } - if (service) { - wrapper[++i] = "-x"; - wrapper[++i] = service; - } - wrapper[++i] = user; - wrapper[++i] = response; - wrapper[++i] = 0; - - execvp(wrapper[0],wrapper); - exit(111); - } - - if (wait_pid(&wstat,child) == -1) exit(111); - if (wait_crashed(wstat)) exit(111); - return wait_exitcode(wstat); -} - -int auth_wrapper(char *pam,char *arg1,char *arg2,char *auth,int len) -{ - int wstat; - int child; - int pi[2]; - char *wrapper[4] = {0, 0, 0, 0}; - - if (pipe(pi) == -1) exit(111); - if (pi[0] != FDAUTH) exit(111); - - switch (child = fork()) { - case -1: - exit(111); - case 0: - close(pi[1]); - if (fd_copy(FDAUTH,pi[0]) == -1) exit(111); - wrapper[0] = pam; - wrapper[1] = arg1; - wrapper[2] = arg2; - wrapper[3] = 0; - sig_pipedefault(); - - execvp(wrapper[0],wrapper); - exit(111); - } - close(pi[0]); - - buffer_init(&ba,write,pi[1],authbuf,sizeof(authbuf)); - if (buffer_put(&ba,auth,len) == -1) exit(111); - if (buffer_flush(&ba) == -1) exit(111); - close(pi[1]); - - if (wait_pid(&wstat,child) == -1) exit(111); - if (wait_crashed(wstat)) exit(111); - return wait_exitcode(wstat); -} - -int main(int argc,char **argv) -{ - char *authuser; - char *authpass; - char *response = 0; - char *challenge = 0; - char *domain = 0; - char *authsocket = 0; - char *service = 0; - char *program = 0; - char *maildirname = 0; - int rc = -1; /* initialise: -1; ok: 0; !ok: > 0 */ - int authlen = 0; - int buflen = 0; - int domlen = 0; - int i = 0; - int r; - - if (!argv[1]) exit(2); - - if (!case_diffs(argv[1],SOCKET_CALL)) { // dovecot socket - if (!argv[3]) exit(2); - authsocket = argv[2]; - if (!case_diffs(argv[3],DOVECOT_SERVICE)) { // ++ dovecot service - service = argv[4]; - if (!argv[5]) exit(2); - } - } else if (!case_diffs(argv[1],DOVECOT_SERVICE)) { // dovecot service - if (!argv[3]) exit(2); - service = argv[2]; - if (!case_diffs(argv[3],SOCKET_CALL)) { // ++ dovecot socket - if (!argv[5]) exit(2); - authsocket = argv[4]; - } - } else if (argv[2]) { // pop or imap user with mailbox - if (case_starts(argv[2],"mail") || case_starts(argv[2],"mbox")) { - program = argv[1]; - maildirname = argv[2]; - } - } - env_unset("USER"); - - /* Read input on FDAUTH */ - - for (;;) { - do - r = read(FDAUTH,authbuf + buflen,sizeof(authbuf) - buflen); - while ((r == -1) && (errno == EINTR)); - if (r == -1) exit(111); - if (r == 0) break; - buflen += r; - if (buflen >= sizeof(authbuf)) exit(2); - } - close(FDAUTH); - - authuser = authbuf + i; /* username */ - if (i == buflen) exit(2); - while (authbuf[i++]) /* response */ - if (i == buflen) exit(2); - response = authbuf + i; - if (i == buflen) exit(2); - while (authbuf[i++]) /* challenge */ - if (i == buflen) exit(2); - challenge = authbuf + i; - - authlen = str_len(authuser); - if (!stralloc_copyb(&user,authuser,authlen)) exit(111); - - if ((i = byte_rchr(authuser,authlen,'@'))) /* @domain */ - if (i < authlen && authuser[i] == '@') { - domain = authuser + i; - domlen = str_len(domain); - case_lowerb(domain,domlen); - user.len = 0; - if (!stralloc_copyb(&user,authuser,i)) exit(111); - } - if (!stralloc_0(&user)) exit(111); - if (!env_put("USER",authuser)) exit(111); - - /* Read control file users/authuser and go for checks */ - - if (chdir(auto_qmail) == -1) exit(110); - - switch (control_readfile(&authfile,"users/authuser",0)) { - case -1: exit(110); - case 0: if (!constmap_init(&mapauthuser,"",0,1)) exit(111); - case 1: if (!constmap_init(&mapauthuser,authfile.s,authfile.len,1)) exit(111); - } - - /* Check for disabled authuser/domains */ - - if (!stralloc_copys(&disabled,"!")) exit(111); - if (!stralloc_catb(&disabled,authuser,authlen)) exit(111); - if (constmap(&mapauthuser,disabled.s,disabled.len)) exit(1); - - if (domlen) { - disabled.len = 0; - if (!stralloc_copys(&disabled,"!")) exit(111); - if (!stralloc_catb(&disabled,domain,domlen)) exit(111); - if (constmap(&mapauthuser,disabled.s,disabled.len)) exit(1); - } - - /* Virtual and system user accounts */ - - authpass = constmap(&mapauthuser,authuser,authlen); - - if (!authpass && domlen) - authpass = constmap(&mapauthuser,domain,domlen); // 1. authuser accounts - if (!authpass) - authpass = constmap(&mapauthuser,"*",1); // 2. system accounts - if (!authpass) - authpass = constmap(&mapauthuser,"@",1); // 3. virtual user accounts - - if (!authpass) exit(1); - - if (str_len(authpass) == 1) { // external IdP - switch (authpass[0]) { - case '?': rc = auth_unix(user.s,response); break; - case '+': if (maildirname) - rc = auth_wrapper("checkvpw",program,maildirname,authbuf,buflen); - else - rc = auth_wrapper("checkvpw","true","Maildir",authbuf,buflen); // Pseudo arg - break; - case '&': rc = auth_wrapper("vchkpw",program,maildirname,authbuf,buflen); - break; - case '=': rc = auth_dovecot(authuser,response,authsocket,service); - break; - default: rc = 2; - break; - } - } else { // authuser file - switch (authpass[0]) { - case '%': rc = auth_hash(authpass + 1,response); - break; - default: if (maildirname) { - if ((rc = auth_cram(authpass,response,challenge) == 0)) break; // IMAP C/R - if ((rc = auth_apop(authpass,response,challenge)) == 0) { - auth_unix(user.s,0); // Unix environment only - } - } else rc = auth_cram(authpass,response,challenge); - break; - } - } - - if (rc) exit(rc); - - for (i = 0; i < sizeof(authbuf); ++i) authbuf[i] = 0; - - if (authsocket && service) pathexec(argv + 5); - else if (authsocket || service) pathexec(argv + 3); - else pathexec(argv + 1); - exit(111); -} |