diff -crN ../vpopmail-5.2.1_unpatched/Makefile.am ./Makefile.am *** ../vpopmail-5.2.1_unpatched/Makefile.am 2003-02-06 20:11:25.000000000 +0100 --- ./Makefile.am 2003-02-06 20:23:33.000000000 +0100 *************** *** 23,29 **** vdominfo_SOURCES = vdominfo.c vdominfo_LDADD = libvpopmail.a @auth_libs@ ! vchkpw_SOURCES = vchkpw.c vchkpw_LDADD = libvpopmail.a @auth_libs@ vdelivermail_SOURCES = vdelivermail.c maildirquota.c --- 23,29 ---- vdominfo_SOURCES = vdominfo.c vdominfo_LDADD = libvpopmail.a @auth_libs@ ! vchkpw_SOURCES = vchkpw.c functions.c vchkpw_LDADD = libvpopmail.a @auth_libs@ vdelivermail_SOURCES = vdelivermail.c maildirquota.c diff -crN ../vpopmail-5.2.1_unpatched/Makefile.in ./Makefile.in *** ../vpopmail-5.2.1_unpatched/Makefile.in 2003-02-06 20:11:25.000000000 +0100 --- ./Makefile.in 2003-02-06 20:28:19.000000000 +0100 *************** *** 92,98 **** vdominfo_SOURCES = vdominfo.c vdominfo_LDADD = libvpopmail.a @auth_libs@ ! vchkpw_SOURCES = vchkpw.c vchkpw_LDADD = libvpopmail.a @auth_libs@ vdelivermail_SOURCES = vdelivermail.c maildirquota.c --- 92,98 ---- vdominfo_SOURCES = vdominfo.c vdominfo_LDADD = libvpopmail.a @auth_libs@ ! vchkpw_SOURCES = vchkpw.c functions.c vchkpw_LDADD = libvpopmail.a @auth_libs@ vdelivermail_SOURCES = vdelivermail.c maildirquota.c *************** *** 166,172 **** AR = ar PROGRAMS = $(vpopmailbin_PROGRAMS) ! vchkpw_OBJECTS = vchkpw.o vchkpw_DEPENDENCIES = libvpopmail.a vchkpw_LDFLAGS = vdelivermail_OBJECTS = vdelivermail.o maildirquota.o --- 166,172 ---- AR = ar PROGRAMS = $(vpopmailbin_PROGRAMS) ! vchkpw_OBJECTS = vchkpw.o functions.o vchkpw_DEPENDENCIES = libvpopmail.a vchkpw_LDFLAGS = vdelivermail_OBJECTS = vdelivermail.o maildirquota.o diff -crN ../vpopmail-5.2.1_unpatched/functions.c ./functions.c *** ../vpopmail-5.2.1_unpatched/functions.c 1970-01-01 01:00:00.000000000 +0100 --- ./functions.c 2003-02-06 20:23:58.000000000 +0100 *************** *** 0 **** --- 1,458 ---- + #include + #include + #include + #include + #include + + #include "md5.h" + #include "functions.h" + + #ifndef VPOPMAIL + char *dec2hex(unsigned char *digest) + { + static char ascii[33]; + char *hex="0123456789abcdef"; + int i,j,k; + + memset(ascii,0,sizeof(ascii)); + + for (i=0; i < 16; i++) + { + j = digest[i]/16; + k = digest[i]%16; + ascii[i*2] = hex[j]; + ascii[(i*2)+1] = hex[k]; + } + + return ascii; + } + #endif + + void HMAC_MD5(text, text_len, key, key_len, digest) + unsigned char *text; /* pointer to data stream */ + int text_len; /* length of data stream */ + unsigned char *key; /* pointer to authentication key */ + int key_len; /* length of authentication key */ + unsigned char *digest; /* caller digest to be filled in */ + + { + MD5_CTX context; + unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[65]; /* outer padding - key XORd with opad */ + unsigned char tk[16]; + int i; + + /* sanity check parameters */ + if (!text || !key || !digest ) + /* most heinous, probably should log something */ + return; + + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) + { + + MD5_CTX tctx; + + MD5Init(&tctx); + MD5Update(&tctx, key, key_len); + MD5Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + + /* start out by storing key in pads */ + + bzero( k_ipad, sizeof k_ipad); + bzero( k_opad, sizeof k_opad); + bcopy( key, k_ipad, key_len); + bcopy( key, k_opad, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + /* + * perform inner MD5 + */ + MD5Init(&context); /* init context for 1st pass */ + MD5Update(&context, k_ipad, 64); /* start with inner pad */ + MD5Update(&context, text, text_len); /* then text of datagram */ + MD5Final(digest, &context); /* finish up 1st pass */ + /* + * perform outer MD5 + */ + MD5Init(&context); /* init context for 2nd pass */ + MD5Update(&context, k_opad, 64); /* start with outer pad */ + MD5Update(&context, digest, 16); /* then results of 1st hash */ + MD5Final(digest, &context); /* finish up 2nd pass */ + } + + + int WordCount(char *str) + { + int cnt=0; + char inword=1, *tmp=str, found=0; + + if(!str || !*str) + return 0; + + while(isspace(*tmp)) // skipping first spaces + tmp++; + + while(*tmp) + { + if( isspace(*tmp) ) + { + if(inword) + { + inword = 0; + cnt++; + found = 1; + } + } + else inword = 1; + + tmp++; + } + + if( (found && inword) || (cnt == 0 && inword) ) + cnt++; + + return cnt; + } + + int GetWordN(char *Word, char *str, int n, int Max) + { + int cnt=0; + char *tmp = str, inword=1; + + if(!str || !*str || n < 1 || WordCount(str) < n) + return 0; + + while(isspace(*tmp)) // skipping first spaces + tmp++; + + if(n > 1) + while(*tmp) + { + if( isspace(*tmp) ) + { + if(inword) + { + inword = 0; + + if(++cnt == n-1) + break; + } + } + else inword = 1; + + tmp++; + } + + cnt = 0; + + while(isspace(*tmp)) + tmp++; + + while(*tmp) + { + if(isspace(*tmp)) + break; + + *Word++ = *tmp++; + + if(++cnt >= Max) + break; + } + + *Word = 0; + DelGarbage(Word); + return cnt; + } + + + int GetLineFD(int fd, char *str, int MAX) + { + char c; + int key, got=0; + + while( (key = read(fd, &c, 1)) > 0 && MAX-- > 0) + { + if(c == '\n' || c == '\f') + break; + + *str++ = c; + got++; + } + + if(MAX < 1) // so we reach length limit, going to end of line (or file) + { + while((key = read(fd, &c, 1)) > 0) + { + if( !(c == '\n' || c == '\f') ) + continue; + break; + } + } + + *str = 0; + + return (got == 0 ? (key < 1 ? -1 : 0) : got); + } + + + + + int CheckCommands(char *command) + { + char *CommandsAllowed[] = { "imap", "pop3", "auth", "" }; + int i; + + if(command[4] && !isspace(command[4]) ) + return(0); + + for(i = 0; i < 3; i++) + if( !strncasecmp(CommandsAllowed[i], command, 4) ) + return(1); + + return(0); + } + + void DelGarbage(char *str) + { + char *pnt = str; + int j=0; + unsigned char buff[512]; + + if(!str || !*str) + return; + + while( *pnt ) + { + if( !isBAD(*pnt) && j < 512) + buff[j++] = *pnt; + + pnt++; + } + + buff[j] = 0; + strcpy(str, buff); + } + + int isBAD(unsigned char chr) + { + char bad = 0; + + bad = ( isspace(chr) || isEOL(chr) || (!isLetter(chr) ) ); + + if( bad ) + bad = ( !ispunct(chr) && !isdigit(chr) ); + + return (bad); + } + + int isEOL(unsigned char chr) + { + return( (chr == '\r' || chr == '\n' || chr == '\f') ? 1 : 0); + } + + int isLetter(char chr) + { + return ( (chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z') ); + } + + void DelSpaces(char *str) + { + int len; + + if(!str) + return; + + len = strlen(str); + + while( *str && isspace(*str) && len > 0 ) + { + memmove(str, str+1, len+1); + len--; + continue; + } + + while(len > 0 && isspace(*(str+(len-1)))) + len--; + + *(str+len) = 0; + } + + + void CleanIP(char *str) + { + int len; + + if(!str || !*str) + return; + + len = strlen(str); + + while(*str) + { + if( !isdigit(*str) && *str != '.' && len > 0 ) + { + memmove(str, str+1, len); + len--; + continue; + } + str++; + } + } + + + static unsigned char dtable[256]; + + void b64_decode(char *in, char *out) + { + int i, j; + + for (i = 0; i < 255; i++) + { + dtable[i] = 0x80; + } + + for (i = 'A'; i <= 'Z'; i++) + { + dtable[i] = 0 + (i - 'A'); + } + + for (i = 'a'; i <= 'z'; i++) + { + dtable[i] = 26 + (i - 'a'); + } + + for (i = '0'; i <= '9'; i++) + { + dtable[i] = 52 + (i - '0'); + } + + dtable['+'] = 62; + dtable['/'] = 63; + dtable['='] = 0; + + while(*in) + { + unsigned char a[4], b[4], o[3]; + + for(i = 0; i < 4; i++) + { + int c = *in++; + + if(c <= ' ') + continue; + + if (dtable[c] & 0x80) + { + i--; + continue; + } + + a[i] = (unsigned char) c; + b[i] = (unsigned char) dtable[c]; + } + o[0] = (b[0] << 2) | (b[1] >> 4); + o[1] = (b[1] << 4) | (b[2] >> 2); + o[2] = (b[2] << 6) | b[3]; + + i = ( (a[2] == '=') ? 1 : (a[3] == '=' ? 2 : 3) ); + + for(j=0; j < i; j++) + *out++ = o[j]; + + if (i < 3) + break; + } + *out = 0; + } + + + void b64_encode(char *in, char *out) + { + int i; + + /* Fill dtable with character encodings. */ + + for (i = 0; i < 26; i++) + { + dtable[i] = 'A' + i; + dtable[26 + i] = 'a' + i; + } + + for(i = 0; i < 10; i++) + dtable[52 + i] = '0' + i; + + dtable[62] = '+'; + dtable[63] = '/'; + + while (*in) + { + unsigned char igroup[3], ogroup[4]; + int c, n; + + igroup[0] = igroup[1] = igroup[2] = 0; + + for (n = 0; n < 3 && *in; n++) + { + c = *in++; + igroup[n] = (unsigned char) c; + } + + if(n > 0) + { + ogroup[0] = dtable[igroup[0] >> 2]; + ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)]; + ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)]; + ogroup[3] = dtable[igroup[2] & 0x3F]; + + /* Replace characters in output stream with "=" pad + characters if fewer than three characters were + read from the end of the input stream. */ + + if(n < 3) + { + ogroup[3] = '='; + if (n < 2) + ogroup[2] = '='; + } + for (i = 0; i < 4; i++) + *out++ = ogroup[i]; + } + } + + *out = 0; + } + + char *md5(char *string) + { + MD5_CTX buff; + char digest[17]; + + MD5Init(&buff); + MD5Update(&buff, string, strlen(string)); + MD5Final(digest, &buff); + + return(dec2hex(digest)); + } + diff -crN ../vpopmail-5.2.1_unpatched/functions.h ./functions.h *** ../vpopmail-5.2.1_unpatched/functions.h 1970-01-01 01:00:00.000000000 +0100 --- ./functions.h 2003-02-06 20:23:58.000000000 +0100 *************** *** 0 **** --- 1,18 ---- + char *md5(char *); + void HMAC_MD5(unsigned char *text, int text_len, unsigned char *key, int key_len, unsigned char *digest); + + char *dec2hex(unsigned char *); + + int WordCount(char *); + int GetWordN(char *, char *, int, int); + int CheckCommands(char *); + void DelGarbage(char *); + void DelSpaces(char *); + int isBAD(unsigned char); + int isEOL(unsigned char); + int isLetter(char chr); + void CleanIP(char *); + int GetLineFD(int, char *, int); + + void b64_decode(char *, char *); + void b64_encode(char *, char *); diff -crN ../vpopmail-5.2.1_unpatched/readme ./readme *** ../vpopmail-5.2.1_unpatched/readme 1970-01-01 01:00:00.000000000 +0100 --- ./readme 2003-02-06 20:23:58.000000000 +0100 *************** *** 0 **** --- 1,5 ---- + here is my corrections to use vchkpw with qmail & courier-imap + to make them possible to use APOP, CRAM-MD5 authentication schemas. + + in case of courier, you should change authentication module authvchkpw + to vchkpw. diff -crN ../vpopmail-5.2.1_unpatched/vchkpw.c ./vchkpw.c *** ../vpopmail-5.2.1_unpatched/vchkpw.c 2003-02-06 20:11:25.000000000 +0100 --- ./vchkpw.c 2003-02-06 20:23:58.000000000 +0100 *************** *** 29,39 **** --- 29,42 ---- #include #include #include + #include #include #include "config.h" #include "vpopmail.h" #include "vlog.h" #include "vauth.h" + #include "md5.h" + #include "functions.h" #ifdef HAS_SHADOW #include *************** *** 45,50 **** --- 48,59 ---- #define VCHKPW_SHELL "SHELL=NOLOGIN" #define VCHKPW_VPOPUSER "VPOPUSER=" + /* uncomment the next line for some debugging */ + /* #define DEBUG 0 */ + + /* to eliminate problem with functions' dec2hex */ + #define VPOPMAIL 1 + /* For tracking ip of client asking for pop service */ char *IpAddr; *************** *** 56,73 **** char ThePass[AUTH_SIZE]; char TheCrypted[AUTH_SIZE]; char TheDomain[AUTH_SIZE]; /* log line buffer */ #define LOG_LINE_SIZE 500 char LogLine[LOG_LINE_SIZE]; /* environment variable buffers */ ! #define MAX_ENV_BUF 100 static char envbuf1[MAX_ENV_BUF]; static char envbuf2[MAX_ENV_BUF]; static char envbuf3[MAX_ENV_BUF]; static char envbuf4[MAX_ENV_BUF]; /* shared data */ uid_t pw_uid; gid_t pw_gid; --- 65,103 ---- char ThePass[AUTH_SIZE]; char TheCrypted[AUTH_SIZE]; char TheDomain[AUTH_SIZE]; + /* additional string from qmail-popup or qmail-smtpd */ + char APOPStamp[AUTH_SIZE]; + + /* keys for protocols */ + char IsAPOP = 0, IsCRAM=0, Unsupported = 0; /* my for APOP & IMAP Auth */ + char IsOneLine = 0; + char *protocol="Undefined", IsCOURIER=0; + char *LocalPort; + char IsIMAP=0, IsSMTP=0, IsPOP3=0; + char IsSSL=0; + int PortNumber; + + /* functions to support courier */ + void authmod_fail_completely(); + void authexit(int); + /* log line buffer */ #define LOG_LINE_SIZE 500 char LogLine[LOG_LINE_SIZE]; /* environment variable buffers */ ! #define MAX_ENV_BUF 128 static char envbuf1[MAX_ENV_BUF]; static char envbuf2[MAX_ENV_BUF]; static char envbuf3[MAX_ENV_BUF]; static char envbuf4[MAX_ENV_BUF]; + /* additional environment for courier */ + static char envbuf5[MAX_ENV_BUF]; + static char envbuf6[MAX_ENV_BUF]; + static char envbuf7[MAX_ENV_BUF]; + /* shared data */ uid_t pw_uid; gid_t pw_gid; *************** *** 79,103 **** void login_virtual_user(); void login_system_user(); void read_user_pass(); - void vlog(int verror, char *TheUser, char *TheDomain, char *ThePass, char *TheName, char *IpAddr, char *LogLine); void vchkpw_exit(int err); void run_command(char *prog); int main( int argc, char **argv) { - if ( (IpAddr = getenv("TCPREMOTEIP")) == NULL) IpAddr=""; /* read in the user name and password from file descriptor 3 */ read_user_pass(); if ( parse_email( TheName, TheUser, TheDomain, AUTH_SIZE) != 0 ) { snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: invalid user/domain characters %s:%s", TheName, IpAddr); ! vlog(VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(20); ! } /* check if this virtual domain is in the system * we look in /var/qmail/users/cdb file --- 109,156 ---- void login_virtual_user(); void login_system_user(); void read_user_pass(); void vchkpw_exit(int err); void run_command(char *prog); + void vlog(int verror, char *TheUser, char *TheDomain, char *ThePass, + char *TheName, char *IpAddr, char *LogLine); int main( int argc, char **argv) { + if ( (IpAddr = getenv("TCPREMOTEIP")) == NULL) { + IpAddr=""; + } else { + CleanIP(IpAddr); /* to be sure IP is in IPv4 format */ + } /* courier uses IPv6 format, so we removing it */ + + if ( (LocalPort = getenv("TCPLOCALPORT")) == NULL) LocalPort=""; + PortNumber = atoi(LocalPort); + + if(PortNumber == 25 || PortNumber == 465) { + IsSMTP = 1; + } else if(PortNumber == 110 || PortNumber == 995) { + IsPOP3 = 1; + } else if(PortNumber == 143 || PortNumber == 993) { + IsIMAP = 1; + } + + if(PortNumber == 465 || PortNumber == 993 || PortNumber == 995) { + IsSSL = 1; + } /* read in the user name and password from file descriptor 3 */ read_user_pass(); + /* parse the name into a user@domain if there */ + if ( parse_email( TheName, TheUser, TheDomain, AUTH_SIZE) != 0 ) { snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: %s: invalid user/domain characters %s:%s", protocol, ! TheName, IpAddr); ! vlog(VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(20); ! } /* check if this virtual domain is in the system * we look in /var/qmail/users/cdb file *************** *** 106,217 **** */ if ( (vpw = vauth_getpw(TheUser, TheDomain)) != NULL ) { ! vget_assign(TheDomain,NULL,0,&pw_uid,&pw_gid); login_virtual_user(); /* if it is not in the virtual domains * then check the user in /etc/passwd */ #ifdef ENABLE_PASSWD ! } else if ( ENABLE_PASSWD == 1 ) { ! login_system_user(); #endif } else { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: vpopmail user not found %s@%s:%s", ! TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_LOGON, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(3); ! } ! vclose(); /* The user is authenticated, now setup the environment * for qmail-pop3d */ ! /* Set the programs effective group id */ ! if ( setgid(pw_gid) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: setgid %lu failed errno %d %s@%s:%s", ! (long unsigned)pw_gid, errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(4); ! } ! /* Set the programs effective user id */ ! if ( setuid(pw_uid) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: setuid %lu failed errno %d %s@%s:%s", ! (long unsigned)pw_uid, errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(5); } ! /* Change to the users Maildir directory */ ! if (chdir(pw_dir) == -1) { ! if ( vpw!=NULL) { ! if ( vmake_maildir(TheDomain, vpw->pw_dir )!= VA_SUCCESS ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: autocreate dir errno %d %s %s@%s:%s", ! errno, pw_dir, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(6); } - chdir(pw_dir); - } else { - snprintf(LogLine, LOG_LINE_SIZE, - "vchkpw: chdir failed errno %d %s %s@%s:%s", - errno, pw_dir, TheUser, TheDomain, IpAddr); - vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, - TheName, IpAddr, LogLine); - vchkpw_exit(6); - } - } ! /* The the VCHKPW_USER variable */ ! strncpy(envbuf1,VCHKPW_USER,MAX_ENV_BUF); ! strncat(envbuf1,TheUser,MAX_ENV_BUF); ! if ( putenv(envbuf1) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(USER) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(7); ! } ! /* Now HOME */ ! strncpy(envbuf2,VCHKPW_HOME,MAX_ENV_BUF); ! strncat(envbuf2,pw_dir,MAX_ENV_BUF); ! if ( putenv(envbuf2) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(HOME) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(8); ! } ! /* Now SHELL */ ! strncpy(envbuf3,VCHKPW_SHELL,MAX_ENV_BUF); ! if ( putenv(envbuf3) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(SHELL) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(9); ! } ! /* Now VPOPUSER */ ! strncpy(envbuf4,VCHKPW_VPOPUSER,MAX_ENV_BUF); ! strncat(envbuf4,TheName,MAX_ENV_BUF); ! if ( putenv(envbuf4) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(VPOPUSER) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(10); ! } /* close the log connection */ --- 159,337 ---- */ if ( (vpw = vauth_getpw(TheUser, TheDomain)) != NULL ) { ! vget_assign(TheDomain, NULL, 0, &pw_uid, &pw_gid); login_virtual_user(); /* if it is not in the virtual domains * then check the user in /etc/passwd */ #ifdef ENABLE_PASSWD ! } else if( ENABLE_PASSWD == 1 ) { ! login_system_user(); #endif } else { ! /* here is addition to log protocol */ ! snprintf(LogLine, LOG_LINE_SIZE, ! "%s: User not found %s@%s:%s", ! protocol, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_LOGON, TheUser, TheDomain, ! ThePass, TheName, IpAddr, LogLine); ! ! vchkpw_exit(3); ! } ! vclose(); /* The user is authenticated, now setup the environment * for qmail-pop3d */ ! if(!IsSMTP && !IsCOURIER) { ! /* Set the programs effective group id */ ! if ( setgid(pw_gid) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: %s: setgid %lu failed errno %d %s@%s:%s", protocol, ! (long unsigned) pw_gid, errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(4); ! } ! /* Set the programs effective user id */ ! if ( setuid(pw_uid) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: %s: setuid %lu failed errno %d %s@%s:%s", protocol, ! (long unsigned) pw_uid, errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ! ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(5); ! } } ! ! /* in case of SMTP-auth there are no need to change dir */ ! if( !IsSMTP ) { ! /* Change to the users Maildir directory */ ! ! /* there could be some problem, ! * but i guess in case of maildir absence and SMTP-AUTH ! * vdelivermail will create it ! */ ! ! if(chdir(pw_dir) == -1) { ! if( vpw != NULL ) { ! if ( vmake_maildir(TheDomain, vpw->pw_dir ) != VA_SUCCESS ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: %s: autocreate dir errno %d %s %s@%s:%s", ! protocol, errno, pw_dir, TheUser, ! TheDomain, IpAddr); ! ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(6); ! } ! chdir(pw_dir); // after successful creation of new dir ! } else { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: %s: chdir failed errno %d %s %s@%s:%s", ! protocol, errno, pw_dir, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(6); ! } } ! /* The the VCHKPW_USER variable */ ! strncpy(envbuf1, VCHKPW_USER, MAX_ENV_BUF); ! strncat(envbuf1, TheUser, MAX_ENV_BUF); ! if ( putenv(envbuf1) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(USER) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(7); ! } ! /* Now HOME */ ! strncpy(envbuf2, VCHKPW_HOME, MAX_ENV_BUF); ! strncat(envbuf2, pw_dir, MAX_ENV_BUF); ! if ( putenv(envbuf1) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(HOME) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(8); ! } ! /* Now SHELL */ ! strncpy(envbuf3,VCHKPW_SHELL,MAX_ENV_BUF); ! if ( putenv(envbuf3) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(SHELL) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(9); ! } ! /* Now VPOPUSER */ ! strncpy(envbuf4,VCHKPW_VPOPUSER,MAX_ENV_BUF); ! strncat(envbuf4,TheName,MAX_ENV_BUF); ! if( putenv(envbuf4) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(VPOPUSER) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(10); ! } ! ! if(IsCOURIER) { ! /* Next 3 shell variables for compatibilty with Courier ! * if vchkpw used for authentication with Courier-POP3, IMAP ! */ ! ! strncpy(envbuf5, "AUTHENTICATED=", MAX_ENV_BUF); ! strncat(envbuf5, TheUser, MAX_ENV_BUF); ! strcat(envbuf5, "@"); ! strcat(envbuf5, TheDomain); ! ! if( putenv(envbuf5) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(AUTHENTICATED) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(10); ! } ! ! strncpy(envbuf6, "AUTHFULLNAME=", MAX_ENV_BUF); ! strncat(envbuf6, TheUser, MAX_ENV_BUF); ! ! if ( putenv(envbuf6) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(AUTHFULLNAME) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ! ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(10); ! } ! ! strncpy(envbuf7, "AUTHADDR=", MAX_ENV_BUF); ! strncat(envbuf7, IpAddr, MAX_ENV_BUF); ! ! if( putenv(envbuf7) == -1 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: putenv(AUTHADDR) failed errno %d %s@%s:%s", ! errno, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ! ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(10); ! } ! } /* if IsCourier */ ! } /* if( !IsSMTP )*/ /* close the log connection */ *************** *** 220,413 **** } /* And now a simple way to kick off the next program */ ! execvp(argv[1],argv+1); /* all done, time to release resources and go away */ exit(0); - } /* clean a buffer for syslog */ char *sysc(char *mess) { char *ripper; ! for(ripper=mess;*ripper!=0;++ripper) { ! if ( *ripper=='%' ) { ! *ripper = '#'; ! } } ! return(mess); } void read_user_pass() { ! int i,j,l; /* Read the user and password from file descriptor 3 * use TheDomain variable as temporary storage of the * full incoming line */ ! memset(TheDomain,0,AUTH_SIZE); ! for(i=0;i 0 ) { ! openlog(LOG_NAME,LOG_PID,LOG_MAIL); ! } ! ! if ( TheName[0] == 0 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: null user name given %s:%s", TheName, IpAddr); ! vlog(VLOG_ERROR_LOGON, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(12); ! } ! if ( ThePass[0] == 0 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: null password given %s:%s", TheName, IpAddr); ! vlog(VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(13); } } void login_virtual_user() { /* If thier directory path is empty make them a new one */ if ( vpw->pw_dir == NULL || vpw->pw_dir[0]==0 ) { ! if ( make_user_dir(vpw->pw_name, TheDomain, pw_uid, pw_gid)==NULL){ ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: dir auto create failed %s@%s:%s", ! TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(14); } } - #ifdef ENABLE_LEARN_PASSWORDS /* check for a valid vpopmail passwd field */ ! if ( vpw->pw_passwd==NULL||vpw->pw_passwd[0]==0) { ! mkpasswd3(ThePass,TheCrypted, AUTH_SIZE); ! vpw->pw_passwd = TheCrypted; ! vpw->pw_clear_passwd = ThePass; ! vauth_setpw(vpw, TheDomain); ! #ifdef POP_FETCH ! if ( pop_init(vpw, "") { ! while (pop_loop) == 1 ); } #endif - } - #else - if ( vpw->pw_passwd==NULL||vpw->pw_passwd[0]==0) { - snprintf(LogLine, LOG_LINE_SIZE, - "vchkpw: user has no password %s@%s:%s", - TheUser, TheDomain, IpAddr); - vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, - IpAddr, LogLine); - vchkpw_exit(15); - } - #endif ! /* Encrypt the clear text password using the crypted ! * password as the salt then ! * check if it matches the encrypted password ! * If it does not match, log errors if requested ! * and exit */ ! if ( strcmp(crypt(ThePass,vpw->pw_passwd),vpw->pw_passwd) != 0 ) { ! if ( ENABLE_LOGGING==1||ENABLE_LOGGING==2){ ! snprintf(LogLine, LOG_LINE_SIZE, "vchkpw: password fail %s@%s:%s", ! TheUser, TheDomain, IpAddr); ! } else if ( ENABLE_LOGGING==3||ENABLE_LOGGING==4){ ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: password fail %s %s@%s:%s", ! ThePass, TheUser, TheDomain, IpAddr); ! } else { ! LogLine[0] = 0; } ! vlog( VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(3); } #ifdef ENABLE_LEARN_PASSWORDS #ifdef CLEAR_PASS ! /* User with pw_clear_passwd unset but pw_passwd set ! * should have the pw_clear_passwd field filled in ! */ ! if ( vpw->pw_clear_passwd==NULL||vpw->pw_clear_passwd[0]==0) { ! vpw->pw_clear_passwd = ThePass; ! vauth_setpw(vpw, TheDomain); ! } #endif #endif - /* They are authenticated now, check for restrictions * Check if they are allowed pop access */ ! if ( vpw->pw_gid & NO_POP ) { snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: pop access denied %s@%s:%s", ! TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_ACCESS, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(0); } /* They are authenticated, log the success if configured */ ! snprintf(LogLine, LOG_LINE_SIZE, "vchkpw: login success %s@%s:%s", ! TheUser, TheDomain, IpAddr); vlog(VLOG_AUTH, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); - /* If authentication logging is enabled * update the authentication time on the account */ #ifdef ENABLE_AUTH_LOGGING ! vset_lastauth(TheUser,TheDomain,IpAddr); #endif #ifdef POP_AUTH_OPEN_RELAY /* Check if we should open up relay for this account */ ! if ( (vpw->pw_gid & NO_RELAY) == 0 ) { open_smtp_relay(); } #endif /* Save the directory pointer */ pw_dir = vpw->pw_dir; - } #ifdef ENABLE_PASSWD --- 340,761 ---- } /* And now a simple way to kick off the next program */ ! execvp(argv[1], argv+1); /* all done, time to release resources and go away */ exit(0); } /* clean a buffer for syslog */ + char *sysc(char *mess) { char *ripper; ! for(ripper=mess; *ripper; ++ripper) { ! if ( *ripper == '%' ) { ! *ripper = '#'; } ! } ! return(mess); ! } ! ! ! /* function to read parameters from calling module ! * this is replacement for old function read_user_pass() ! * i guess its more ... reliable ! */ ! ! int GetString(char *str, int MAX, int NonCritical) ! { ! unsigned char c; ! int cnt = 0, i; ! ! while((i = read(3, &c, 1)) > 0 && cnt < MAX) { ! if(c == '\0') ! break; ! ! *(str + cnt++) = c; ! } ! ! if(!NonCritical && i == -1 && cnt == 0) { ! printf("vchkpw: what the hell are you doing running vchkpw on the command line!! It's only for talking with Courier & Qmail mail-servers.\n"); ! vchkpw_exit(11); ! } ! ! *(str+cnt) = '\0'; ! ! return( cnt ); } + void read_user_pass() { ! int result=0, cnt; ! ! /* additions */ ! char tmp[2]="\0\0", suppl[256]; /* Read the user and password from file descriptor 3 * use TheDomain variable as temporary storage of the * full incoming line */ ! ! memset(TheDomain, 0, AUTH_SIZE); ! memset(TheName, 0, AUTH_SIZE); ! memset(ThePass, 0, AUTH_SIZE); ! ! memset(APOPStamp, 0, AUTH_SIZE); ! memset(tmp, 0, 2); ! ! /* read the first argument */ ! GetString(TheName, AUTH_SIZE, 0); ! ! #ifdef DEBUG ! snprintf(LogLine, LOG_LINE_SIZE, ! "debug: First stage: '%s'", TheName); ! syslog(LOG_NOTICE, sysc(LogLine)); ! #endif ! ! /* checking for auth, pop3, imap in first word */ ! if( CheckCommands(TheName) ) { ! /* if we get authentication request from (maybe) imap client ! * so there have to be 4 words ! */ ! char Command[32]; ! int len = strlen(TheName); ! ! cnt = WordCount(TheName); ! ! /* making a copy of first string */ ! memmove(suppl, TheName, len+1); ! ! if(cnt > 2 && len > 6) { ! /* if string seems to be correct ! * something like auth login user pass ! * check from where we got request: from IMAP or from POP3 AUTH ! */ ! ! /* in case it's impossible to guess from port number */ ! if(!IsIMAP) IsIMAP = !strncasecmp(TheName, "imap", 4) ? 1 : 0; ! IsCOURIER = IsIMAP ? 1 : (!strncasecmp(TheName, "pop3", 4) ? 1 : -0); ! ! /* I guess IMAP server transform this into "imap login", ! * not "auth login" and courier pop3 makes it "pop3 login ..." ! */ ! ! IsOneLine = 1; ! GetWordN(Command, suppl, 2, 32); ! ! /* so, if login user/pass in cleartext */ ! if( !strncasecmp(Command, "login", 5) && len > 11) { ! GetWordN(TheName, suppl, 3, AUTH_SIZE); ! GetWordN(ThePass, suppl, 4, AUTH_SIZE); ! } else if( !strncasecmp(Command, "cram-md5", 8) && len > 30 ) { ! /* if CRAM-MD5 auth */ ! GetWordN(TheName, suppl, 3, AUTH_SIZE); ! b64_decode(TheName, ThePass); ! ! GetWordN(TheName, suppl, 4, AUTH_SIZE); ! b64_decode(TheName, suppl); ! ! GetWordN(TheName, suppl, 1, AUTH_SIZE); ! GetWordN(APOPStamp, suppl, 2, AUTH_SIZE); ! ! IsCRAM = 1; ! } else { ! /* currently unsupported schema were used, or just bad input */ ! Unsupported = 1; ! vchkpw_exit(1); ! } } + } + + if( !IsOneLine ) { + /* if not all parameters were passed in one line + * so taking them, second line should be Password (plain or APOP) + * if the following line empty -- malformed input, result < 1 + */ + + if( (result = GetString(ThePass, AUTH_SIZE, 0)) < 1) { + printf("vchkpw: Error in getting user/pass combination\n"); + vchkpw_exit(11); + } + + DelGarbage(TheName); + DelGarbage(ThePass); + + /* here we are getting third parameter, APOP stamp */ + + GetString(APOPStamp, AUTH_SIZE, 0); + /* stamp, from qmail, + * something like <6039.999784691@domain.com> + * to build apop hash + * md5(stamp+pass) -- pass in clear-text + */ + + GetString(tmp, 2, 1); /* additional byte from patched qmail */ } + + /* for developers */ + #ifdef DEBUG + snprintf(LogLine, LOG_LINE_SIZE, + "vchkpw debug: Given name: '%s'", TheName); + syslog(LOG_NOTICE, sysc(LogLine)); + + snprintf(LogLine, LOG_LINE_SIZE, + "vchkpw debug: Given password: '%s'", ThePass); + syslog(LOG_NOTICE, sysc(LogLine)); + + snprintf(LogLine, LOG_LINE_SIZE, + "vchkpw debug: Given stamp: '%s'", APOPStamp); + syslog(LOG_NOTICE, sysc(LogLine)); + #endif + /* close the user/pass file descriptor */ close(3); ! /* making decision which protocol used */ ! ! /* could be send only by patched qmail-popup */ ! IsAPOP = (tmp[0] == 'y') ? 1 : 0; ! ! /* "c" could be only from qmail-smtpd ! * but IsCRAM also could be set from "auth cram-md5 ..." ! */ ! ! if(!IsCRAM) /* if not already setted up */ ! IsCRAM = (tmp[0] == 'c') ? 1 : 0; /* from qmail-smtpd */ ! if(IsSMTP || tmp[0] == 'c' || tmp[0] == 's') { ! /* a little strange. but IsSMTP already could be recognized ! * from port-number ! */ ! protocol = IsSSL ? "SMTP-SSL" : "SMTP"; ! IsSMTP = 1; ! } else if(IsIMAP == 1) { ! protocol = IsSSL ? "IMAP-SSL" : "IMAP"; ! } else { ! protocol = IsSSL ? "POP3-SSL" : "POP3"; } /* open the log if configured */ if ( ENABLE_LOGGING > 0 ) { ! openlog(LOG_NAME, LOG_PID, LOG_MAIL); ! if( !*TheName ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "%s: no user name given %s:%s", protocol, TheName, IpAddr); ! vlog(VLOG_ERROR_LOGON, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(12); ! } ! if ( (!ThePass || !*ThePass) && !IsCOURIER ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "%s: empty password given %s:%s", protocol, TheName, IpAddr); ! vlog(VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); ! vchkpw_exit(13); ! } } } + void login_virtual_user() { + /* some kind of protection, assume auth already failed */ + char ErrAUTH=1, Impossible = 0; + /* If thier directory path is empty make them a new one */ if ( vpw->pw_dir == NULL || vpw->pw_dir[0]==0 ) { ! if ( make_user_dir(vpw->pw_name, TheDomain, pw_uid, pw_gid) == NULL) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: %s: dir auto create failed %s@%s:%s", ! protocol, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, ! TheName, IpAddr, LogLine); vchkpw_exit(14); } } /* check for a valid vpopmail passwd field */ ! if ( vpw->pw_passwd == NULL || vpw->pw_passwd[0] == 0) { ! #ifdef ENABLE_LEARN_PASSWORDS ! ! /* its useless business to learn passwords ! * when APOP or CRAM-MD5 methods used :) ! */ ! ! if(!IsAPOP && !IsCRAM) { ! mkpasswd3(ThePass, TheCrypted, AUTH_SIZE); ! vpw->pw_passwd = TheCrypted; ! vpw->pw_clear_passwd = ThePass; ! vauth_setpw(vpw, TheDomain); } + + #ifdef POP_FETCH + if ( pop_init(vpw, "") { + while (pop_loop) == 1 ); + } #endif ! #else // if learn-password disabled ! ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: %s: user has no password %s@%s:%s", ! protocol, TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_INTERNAL, TheUser, TheDomain, ThePass, TheName, ! IpAddr, LogLine); ! vchkpw_exit(15); ! #endif ! } ! ! /* if user were added with already hashed password, ! * so we will not make checks for cram & apop ! * ### hashed ### could be added by mkpassword */ ! ! if( !strcasecmp(vpw->pw_clear_passwd, "### hashed ###") ! || !vpw->pw_clear_passwd ! || strlen(vpw->pw_clear_passwd) < 1 ) Impossible = 1; ! ! /* "Impossible" only interesting in case of APOP or CRAM ! * as we dont use cleartext password from database to ! * check sended cleartext pass ! */ ! ! if(IsCRAM) { ! unsigned char tmp[17]; ! ! HMAC_MD5(ThePass, strlen(ThePass), vpw->pw_clear_passwd, ! strlen(vpw->pw_clear_passwd), (unsigned char *) &tmp); ! ! if ( !Impossible && !strcmp(dec2hex(tmp), APOPStamp) ) ErrAUTH=0; ! } else if(!IsAPOP) { ! /* if password send in cleartext */ ! ! if( !strcmp(crypt(ThePass, vpw->pw_passwd), vpw->pw_passwd)) ! ErrAUTH = 0; ! } else { ! /* checking APOP */ ! char *temp; ! ! if((temp = malloc(strlen(APOPStamp) + ! strlen(vpw->pw_clear_passwd) + 1)) == NULL) { ! ! if ( ENABLE_LOGGING > 0 ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw %s: memory allocation problems, exiting", ! protocol); ! vlog( VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, TheName, ! IpAddr, LogLine); ! } ! vchkpw_exit(11); } ! ! strcpy(temp, APOPStamp); ! strcat(temp, vpw->pw_clear_passwd); ! ! if(!Impossible && !strcmp(md5(temp), ThePass)) ! ErrAUTH = 0; ! ! free(temp); ! } ! ! if( ErrAUTH ) { ! if ( ENABLE_LOGGING == 1 || ENABLE_LOGGING == 2 ) { ! snprintf(LogLine, LOG_LINE_SIZE, "%s: Password fail for %s@%s:%s", ! protocol, TheUser, TheDomain, IpAddr); ! } else if (ENABLE_LOGGING == 3 || ENABLE_LOGGING == 4) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "%s: Password fail (pass: '%s' for %s@%s:%s. Auth: %s", ! protocol, ThePass, TheUser, TheDomain, IpAddr, ! IsAPOP ? "APOP" : (IsCRAM ? "CRAM-MD5" : "Plain")); ! } ! vlog( VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(3); } #ifdef ENABLE_LEARN_PASSWORDS #ifdef CLEAR_PASS ! ! /* User with pw_clear_passwd unset but pw_passwd set ! * should have the pw_clear_passwd field filled in ! */ ! ! if ( !IsCRAM && !IsAPOP && Impossible ) { ! vpw->pw_clear_passwd = ThePass; ! vauth_setpw(vpw, TheDomain); ! } #endif #endif /* They are authenticated now, check for restrictions * Check if they are allowed pop access */ ! ! /* if auth were done just for smtp-sessions ! * i guess there is no need to make these checks ! */ ! if(!IsSMTP) { ! if( (vpw->pw_gid & NO_POP) && !IsIMAP ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: POP3 access denied for %s@%s:%s", ! TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_ACCESS, TheUser, TheDomain, ! ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(-1); ! } ! ! if( IsIMAP && (vpw->pw_gid & NO_IMAP ) ) { ! snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: IMAP access denied for %s@%s:%s", ! TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_ACCESS, TheUser, TheDomain, ! ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(-1); ! } ! } else if( vpw->pw_gid & NO_SMTP ) { ! ! /* but if this is for SMTP ... ! * and user disabled from sending ! */ snprintf(LogLine, LOG_LINE_SIZE, ! "vchkpw: SMTP access denied for %s@%s:%s", ! TheUser, TheDomain, IpAddr); ! vlog(VLOG_ERROR_ACCESS, TheUser, TheDomain, ! ThePass, TheName, IpAddr, LogLine); ! vchkpw_exit(-1); } /* They are authenticated, log the success if configured */ ! snprintf(LogLine, LOG_LINE_SIZE, "%s ok, Auth: %s, User: %s@%s:%s", ! protocol, IsAPOP ? "APOP" : (IsCRAM ? "CRAM-MD5" : "Plain"), ! TheUser, TheDomain, IpAddr); vlog(VLOG_AUTH, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); /* If authentication logging is enabled * update the authentication time on the account */ + #ifdef ENABLE_AUTH_LOGGING ! vset_lastauth(TheUser, TheDomain, IpAddr); #endif #ifdef POP_AUTH_OPEN_RELAY + /* Check if we should open up relay for this account */ ! ! /* if we are checking for SMTP there is no need to open relay */ ! if ( (vpw->pw_gid & NO_RELAY) == 0 && !IsSMTP ) { open_smtp_relay(); } #endif /* Save the directory pointer */ pw_dir = vpw->pw_dir; } #ifdef ENABLE_PASSWD *************** *** 415,434 **** { struct passwd *pw; #ifdef HAS_SHADOW ! struct spwd *spw; #endif if ((pw=getpwnam(TheUser)) == NULL ) { snprintf(LogLine, LOG_LINE_SIZE, "vchkpw: system user not found %s:%s", ! TheUser, IpAddr); ! vlog(VLOG_ERROR_LOGON, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(21); } #ifdef HAS_SHADOW if ((spw = getspnam(TheUser)) == NULL) { snprintf(LogLine, LOG_LINE_SIZE, "vchkpw: system user shadow entry not found %s:%s", ! TheName, IpAddr); ! vlog(VLOG_ERROR_LOGON, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(22); } --- 763,785 ---- { struct passwd *pw; #ifdef HAS_SHADOW ! struct spwd *spw; #endif + if ((pw=getpwnam(TheUser)) == NULL ) { snprintf(LogLine, LOG_LINE_SIZE, "vchkpw: system user not found %s:%s", ! TheUser, IpAddr); ! vlog(VLOG_ERROR_LOGON, TheUser, TheDomain, ThePass, TheName, IpAddr, ! LogLine); vchkpw_exit(21); } #ifdef HAS_SHADOW if ((spw = getspnam(TheUser)) == NULL) { snprintf(LogLine, LOG_LINE_SIZE, "vchkpw: system user shadow entry not found %s:%s", ! TheName, IpAddr); ! vlog(VLOG_ERROR_LOGON, TheUser, TheDomain, ThePass, TheName, IpAddr, ! LogLine); vchkpw_exit(22); } *************** *** 442,479 **** } else if (ENABLE_LOGGING==3||ENABLE_LOGGING==4) { snprintf(LogLine, LOG_LINE_SIZE, "vchkpw: system password fail %s %s:%s", ! ThePass, TheName, IpAddr); } else { LogLine[0] = 0; } ! vlog(VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine); vchkpw_exit(23); } pw_uid = pw->pw_uid; pw_gid = pw->pw_gid; pw_dir = pw->pw_dir; #ifdef POP_AUTH_OPEN_RELAY ! open_smtp_relay(); #endif } #endif void vchkpw_exit(int err) { if ( ENABLE_LOGGING > 0 ) { closelog(); } vclose(); exit(err); } ! /* log messages and figure out what type they are and where they should go depending on configure options */ ! /* any one of the pointers can be null, i.e. the information is not available */ ! /* messages are autmatically cleaned for syslog if it is necessary */ ! void vlog(int verror, char *TheUser, char *TheDomain, char *ThePass, char *TheName, char *IpAddr, char *LogLine) { /* always log to syslog if enabled */ ! if ( (verror == VLOG_ERROR_PASSWD) && ( ENABLE_LOGGING==1 || ENABLE_LOGGING==2 || ENABLE_LOGGING==3 || ENABLE_LOGGING==4 ) ) { syslog(LOG_NOTICE,sysc(LogLine)); } else if ( verror == VLOG_ERROR_INTERNAL ) { syslog(LOG_NOTICE,sysc(LogLine)); --- 793,846 ---- } else if (ENABLE_LOGGING==3||ENABLE_LOGGING==4) { snprintf(LogLine, LOG_LINE_SIZE, "vchkpw: system password fail %s %s:%s", ! ThePass, TheName, IpAddr); } else { LogLine[0] = 0; } ! vlog(VLOG_ERROR_PASSWD, TheUser, TheDomain, ThePass, TheName, IpAddr, ! LogLine); vchkpw_exit(23); } pw_uid = pw->pw_uid; pw_gid = pw->pw_gid; pw_dir = pw->pw_dir; #ifdef POP_AUTH_OPEN_RELAY ! if(!IsSMTP) ! open_smtp_relay(); #endif } #endif + void vchkpw_exit(int err) { if ( ENABLE_LOGGING > 0 ) { closelog(); } + vclose(); + + if( IsCOURIER ) + authmod_fail_completely(); + exit(err); } ! ! /* log messages and figure out what type they are and where they should go ! * depending on configure options any one of the pointers can be null, i.e. ! * the information is not available messages are autmatically cleaned for ! * syslog if it is necessary ! */ ! ! void vlog(int verror, char *TheUser, char *TheDomain, char *ThePass, ! char *TheName, char *IpAddr, char *LogLine) { ! /* always log to syslog if enabled */ ! if ( (verror == VLOG_ERROR_PASSWD) ! && ( ENABLE_LOGGING==1 || ENABLE_LOGGING==2 || ENABLE_LOGGING==3 ! || ENABLE_LOGGING==4 ) ) { syslog(LOG_NOTICE,sysc(LogLine)); } else if ( verror == VLOG_ERROR_INTERNAL ) { syslog(LOG_NOTICE,sysc(LogLine)); *************** *** 481,495 **** syslog(LOG_NOTICE,sysc(LogLine)); } else if ( verror == VLOG_ERROR_ACCESS ) { syslog(LOG_NOTICE,sysc(LogLine)); ! } else if ( verror == VLOG_AUTH && ( ENABLE_LOGGING == 1 || ENABLE_LOGGING == 4 ) ) { syslog(LOG_NOTICE,sysc(LogLine)); } #ifdef ENABLE_MYSQL_LOGGING ! /* always log to mysql if mysql logging is enabled and it is not internal error */ if ( (ENABLE_MYSQL_LOGGING > 0) && (verror != VLOG_ERROR_INTERNAL) ) { ! if ( (logmysql(verror, TheUser, TheDomain, ThePass, TheName, IpAddr, LogLine) ) != 0 ) { syslog(LOG_NOTICE,"vchkpw: can't write MySQL logs"); } } #endif } --- 848,916 ---- syslog(LOG_NOTICE,sysc(LogLine)); } else if ( verror == VLOG_ERROR_ACCESS ) { syslog(LOG_NOTICE,sysc(LogLine)); ! } else if ( verror == VLOG_AUTH ! && ( ENABLE_LOGGING == 1 || ENABLE_LOGGING == 4 ) ) { syslog(LOG_NOTICE,sysc(LogLine)); } #ifdef ENABLE_MYSQL_LOGGING ! /* always log to mysql if mysql logging is enabled and it is not internal ! * error ! */ if ( (ENABLE_MYSQL_LOGGING > 0) && (verror != VLOG_ERROR_INTERNAL) ) { ! if ( (logmysql(verror, TheUser, TheDomain, ThePass, TheName, IpAddr, ! LogLine) ) != 0 ) { syslog(LOG_NOTICE,"vchkpw: can't write MySQL logs"); } } #endif } + + + + + /* additional two functions to be compatible with courier */ + + void authmod_fail_completely() + { + char **argv; + int argc, n; + const char *p=getenv("AUTHARGC"); + char buf[20]; + char *msg = "That method of authentication currently unavailable\r\n"; + + if (!p || sscanf(p, "%d", &argc) <= 0 || argc <= 0) { + write(2, "AUTHFAILURE\r\n", 13); + authexit(1); + } + + if( (argv = (char **) malloc((argc+1) * sizeof(char *)) ) == 0) { + perror("malloc"); + authexit(1); + } + + for(n = 0; n < argc; n++) { + sprintf(buf, "AUTHARGV%d", n); + if(( argv[n] = getenv(buf)) == 0) + authexit(1); + } + argv[n] = 0; + + if( !(p=getenv("AUTHUSER") ) ) + authexit(1); + + if(Unsupported) { + write(2, msg, strlen(msg)); + authexit(1); + } + + execv(p, argv); + perror(p); + + authexit(1); + } + + + void authexit(int n) + { + exit(n); + } diff -crN ../vpopmail-5.2.1_unpatched/vpopmail.h ./vpopmail.h *** ../vpopmail-5.2.1_unpatched/vpopmail.h 2003-02-06 20:11:25.000000000 +0100 --- ./vpopmail.h 2003-02-06 20:23:58.000000000 +0100 *************** *** 94,99 **** --- 94,100 ---- #define V_USER1 0x100 #define V_USER2 0x200 #define V_USER3 0x400 + #define NO_SMTP 0x800 #define QA_ADMIN 0x1000 extern int OptimizeAddDomain;