summaryrefslogtreecommitdiff
path: root/sqmail-4.3.07/src/qmail-authuser.c
diff options
context:
space:
mode:
Diffstat (limited to 'sqmail-4.3.07/src/qmail-authuser.c')
-rwxr-xr-xsqmail-4.3.07/src/qmail-authuser.c446
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);
-}