diff -rNu3 imap-4.6_vpop_orig/src/osdep/amiga/mmdf.c imap-4.6_vpop_my/src/osdep/amiga/mmdf.c --- imap-4.6_vpop_orig/src/osdep/amiga/mmdf.c Wed Sep 22 13:05:05 1999 +++ imap-4.6_vpop_my/src/osdep/amiga/mmdf.c Tue Nov 9 23:05:06 1999 @@ -861,7 +861,7 @@ return NIL; } fstat (fd,&sbuf); /* get current file size */ - sprintf (buf,"%sFrom %s@%s ",mmdfhdr,myusername (),mylocalhost ()); + sprintf (buf,"%sFrom %s@%s ",mmdfhdr,myusername_unix (),mylocalhost ()); /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); diff -rNu3 imap-4.6_vpop_orig/src/osdep/amiga/unix.c imap-4.6_vpop_my/src/osdep/amiga/unix.c --- imap-4.6_vpop_orig/src/osdep/amiga/unix.c Wed Sep 22 13:05:07 1999 +++ imap-4.6_vpop_my/src/osdep/amiga/unix.c Tue Nov 9 23:05:06 1999 @@ -890,7 +890,7 @@ return NIL; } fstat (fd,&sbuf); /* get current file size */ - sprintf (buf,"From %s@%s ",myusername (),mylocalhost ()); + sprintf (buf,"From %s@%s ",myusername_unix (),mylocalhost ()); /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); diff -rNu3 imap-4.6_vpop_orig/src/osdep/nt/unixnt.c imap-4.6_vpop_my/src/osdep/nt/unixnt.c --- imap-4.6_vpop_orig/src/osdep/nt/unixnt.c Wed Sep 22 13:06:21 1999 +++ imap-4.6_vpop_my/src/osdep/nt/unixnt.c Tue Nov 9 23:05:06 1999 @@ -836,7 +836,7 @@ return NIL; } fstat (fd,&sbuf); /* get current file size */ - sprintf (buf,"From %s@%s ",myusername (),mylocalhost ()); + sprintf (buf,"From %s@%s ",myusername_unix (),mylocalhost ()); /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); diff -rNu3 imap-4.6_vpop_orig/src/osdep/os2/unixnt.c imap-4.6_vpop_my/src/osdep/os2/unixnt.c --- imap-4.6_vpop_orig/src/osdep/os2/unixnt.c Wed Sep 22 13:06:21 1999 +++ imap-4.6_vpop_my/src/osdep/os2/unixnt.c Tue Nov 9 23:05:06 1999 @@ -836,7 +836,7 @@ return NIL; } fstat (fd,&sbuf); /* get current file size */ - sprintf (buf,"From %s@%s ",myusername (),mylocalhost ()); + sprintf (buf,"From %s@%s ",myusername_unix (),mylocalhost ()); /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/Makefile imap-4.6_vpop_my/src/osdep/unix/Makefile --- imap-4.6_vpop_orig/src/osdep/unix/Makefile Tue Nov 9 23:04:40 1999 +++ imap-4.6_vpop_my/src/osdep/unix/Makefile Tue Nov 9 23:05:06 1999 @@ -103,14 +103,14 @@ BINARIES=mail.o misc.o newsrc.o smanager.o osdep.o utf8.o siglocal.o \ dummy.o pseudo.o netmsg.o flstring.o fdstring.o \ rfc822.o nntp.o smtp.o imap4r1.o pop3.o \ - unix.o mbox.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o + unix.o mbox.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o \ + vpop.o md5.o md5_crypt.o CFLAGS=$(BASECFLAGS) $(EXTRACFLAGS) MAKE=make MV=mv RM=rm -rf SH=sh - # Primary build command BUILDOPTIONS= EXTRACFLAGS="$(EXTRACFLAGS)"\ @@ -352,7 +352,7 @@ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g -fno-omit-frame-pointer $(RPM_OPT_FLAGS)" \ - BASELDFLAGS="-lpam -ldl" + BASELDFLAGS="-lpam -ldl -ldb" lnx: # Linux non-shadow passwords @echo You are building for traditional Linux *without* shadow diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/env_unix.c imap-4.6_vpop_my/src/osdep/unix/env_unix.c --- imap-4.6_vpop_orig/src/osdep/unix/env_unix.c Tue Nov 9 23:04:40 1999 +++ imap-4.6_vpop_my/src/osdep/unix/env_unix.c Tue Nov 9 23:05:06 1999 @@ -37,6 +37,9 @@ #include #include "write.c" /* include safe writing routines */ +/* include the vpop header file */ +#include "vpop.h" + /* Get all authenticators */ #include "auths.c" @@ -46,7 +49,13 @@ static const char *anonymous_user = "nobody"; static const char *unlogged_user = "root"; +/* state variables for a vpop login */ +static char *vpop_virtualUsername = NIL; +static char *vpop_blackBoxHome = NIL; +static char *vpop_username = NIL; + static char *myUserName = NIL; /* user name */ +static char *myUserName_unix = NIL; /* UNIX user name (becuase myUserName could be vpop user) */ static char *myHomeDir = NIL; /* home directory name */ static char *myLocalHost = NIL; /* local host name */ static char *myNewsrc = NIL; /* newsrc file name */ @@ -419,7 +428,7 @@ } -/* Server log in +/* Server log in -- plain text passord logins where we do the authentication * Accepts: user name string * password string * argument count @@ -431,17 +440,44 @@ { char *s,usr[MAILTMPLEN]; struct passwd *pw; - /* cretins still haven't given up */ - if (strlen (user) >= MAILTMPLEN) - syslog (LOG_ALERT|LOG_AUTH,"System break-in attempt, host=%.80s", - tcp_clienthost ()); - /* validate with case-independence */ - else if ((logtry > 0) && ((pw = getpwnam (strcpy (usr,user))) || - (pw = getpwnam (lcase (usr)))) && - ((pw = checkpw (pw,pwd,argc,argv)) || - ((*pwd == ' ') && (pw = getpwnam (usr)) && - (pw = checkpw (pw,pwd + 1,argc,argv))))) - return pw_login (pw,pw->pw_name,pw->pw_dir,argc,argv); + + /* check for username too long */ + if (strlen (user) >= MAILTMPLEN) { + syslog (LOG_ALERT|LOG_AUTH,"System break-in attempt, host=%.80s", tcp_clienthost ()); + } + else if (! logtry>0 ) { + ; /* drop down for failure */ + } + else { + /* check for a vpop user */ + vpop__data* vpop; + vpop = vpop__userauthen(user, pwd, NULL); + + if ( vpop->log_error ) + syslog (LOG_INFO,"Vpop auth error user=%.80s host=%.80s: %s",user,tcp_clienthost (), vpop->log_error); + + if ( vpop->authenticated &&(pw = getpwnam(vpop->unix_username)) ) { + vpop_virtualUsername = cpystr(vpop->virtual_username); + vpop_blackBoxHome = cpystr(vpop->black_box_home); + vpop_username = cpystr(user); + vpop__freedata(vpop); + return pw_login (pw,pw->pw_name,pw->pw_dir,argc,argv); + } + vpop__freedata(vpop); + + if ( ! vpop->valid_form ) /* don't allow unix users which look like vpop users */ + /* check for a UNIX user using Mark's WEIRD logic */ + if ( ((pw = getpwnam (strcpy (usr,user))) || + (pw = getpwnam (lcase (usr)))) && + ((pw = checkpw (pw,pwd,argc,argv)) || + ((*pwd == ' ') && (pw = getpwnam (usr)) && + (pw = checkpw (pw,pwd + 1,argc,argv)))) + ) { + return pw_login (pw,pw->pw_name,pw->pw_dir,argc,argv); + } + } + + /* note an authentication failure */ s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts"; /* note the failure in the syslog */ syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ()); @@ -449,7 +485,7 @@ return NIL; } -/* Authenticated server log in +/* Authenticated server log in -- logins which are already authenticated by some other code * Accepts: user name string * argument count * argument vector @@ -463,7 +499,7 @@ } -/* Log in as anonymous daemon +/* Log in as anonymous daemon -- login as anonymous user * Accepts: argument count * argument vector * Returns: T if successful, NIL if error @@ -514,11 +550,19 @@ DRIVER *d; if (myUserName) fatal ("env_init called twice!"); /* myUserName must be set before dorc() call */ - myUserName = cpystr ((char *) (user ? user : anonymous_user)); + myUserName_unix = cpystr ((char *) (user ? user : anonymous_user)); + myUserName = vpop_username ? cpystr(vpop_username) : myUserName_unix; /* do systemwide configuration */ dorc ("/etc/c-client.cf",NIL); if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME); if (user) { /* remember user name and home directory */ + if (vpop_blackBoxHome) { + myHomeDir = cpystr(vpop_blackBoxHome); + sprintf(tmp,"%s/INBOX",myHomeDir); + sysInbox = cpystr(tmp); + blackBox = T; + } + else if (blackBoxDir) { /* build black box directory name */ sprintf (tmp,"%s/%s",blackBoxDir,myUserName); /* if black box if exists and directory */ @@ -533,7 +577,10 @@ nslist[0] = &nshome,nslist[1] = &nsblackother,nslist[2] = &nsshared; else { /* not a black box */ nslist[0] = &nshome,nslist[1] = &nsunixother,nslist[2] = &nsshared; - myHomeDir = cpystr (home);/* use real home directory */ + sprintf(tmp, "%s/Mail", home); + if (stat(tmp,&sbuf)) + mkdir(tmp, dir_protection); + myHomeDir = cpystr ( (!stat (tmp,&sbuf) && (sbuf.st_mode & S_IFDIR)) ? tmp : home ); /* make sure user rc files don't try this */ blackBoxDir = blackBoxDefaultHome = ""; } @@ -578,17 +625,89 @@ char *myusername_full (unsigned long *flags) { + return myusername_full_backend(flags, NIL, NIL); +} + +/* Return my user name, setting username if not set + * Accepts: username to log in as if no user is currently logged in + * Returns: my user name + */ + +char *myusername_dologin (char* user, char** error) +{ + return myusername_full_backend(NIL, user, error); +} + +/* + * myusername_full_backend -- backend for myusername_full and myusername_login + */ + +char *myusername_full_backend (unsigned long *flags, char* new_username, char** error) +{ char *ret = (char *) unlogged_user; if (!myUserName) { /* get user name if don't have it yet */ struct passwd *pw; - unsigned long euid = geteuid (); - char *s = (char *) getlogin (); - /* look up getlogin() user name or EUID */ - if (!((s && *s && (pw = getpwnam (s)) && (pw->pw_uid == euid)) || - (pw = getpwuid (euid)))) fatal ("Unable to look up user name"); + unsigned long euid; + char *s; + int check_unix_auth = 1; + + /* try to grab new_username from the env if not provided */ + if (!new_username) new_username = getenv("CCLIENT_USERNAME"); + + /* look up getlogin() user name or EUID */ + euid = geteuid (); + s = (char *) getlogin (); + if (!( + ( s && *s && (pw=getpwnam(s)) && (pw->pw_uid==euid) ) || + ( (pw=getpwuid(euid)) && (s=pw->pw_name) ) + )) + fatal ("Unable to look up user name"); + + /* if we have new_username, try to check that with vpop */ + if ( new_username && *new_username ) { + vpop__data* vpop; + vpop = vpop__userauthen(new_username, NULL, s); + + if ( vpop->log_error ) + syslog (LOG_INFO,"Vpop auth error user=%.80s: %s", s, vpop->log_error); + + if ( vpop->unix_username && strcmp(vpop->unix_username, s) ) { + if (!error) fatal("username error: vpop unix_username differs with real unix_username"); + *error = "username error: vpop unix_username differs with real unix_username"; + vpop__freedata(vpop); + return ""; + } + + if ( vpop->valid_user ) { + vpop_virtualUsername = cpystr(vpop->virtual_username); + vpop_blackBoxHome = cpystr(vpop->black_box_home); + vpop_username = cpystr(new_username); + env_init(pw->pw_name,pw->pw_dir); + check_unix_auth = 0; + } + else if ( vpop->valid_form ) { + if (!error) fatal("username error: invaid vpop username"); + *error = "username error: invaid vpop username"; + vpop__freedata(vpop); + return ""; + } + else { + if ( strcmp(new_username,s) ) { + if (!error) fatal("username error: new_username is not vpop or unix_username"); + *error = "username error: new_username is not vpop or unix_username"; + vpop__freedata(vpop); + return ""; + } + } + vpop__freedata(vpop); + } + + /* just log in the default unix user */ + if ( check_unix_auth ) { /* init environment if not root */ - if (euid) env_init (pw->pw_name,((s=getenv("HOME")) && *s) ? s:pw->pw_dir); - else ret = pw->pw_name; /* in case UID 0 user is other than root */ + if (euid) env_init (pw->pw_name,((s=getenv("HOME")) && *s) ? s:pw->pw_dir); + else ret = pw->pw_name; /* in case UID 0 user is other than root */ + } } if (myUserName) { /* logged in? */ if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN; @@ -596,6 +715,16 @@ } else if (flags) *flags = MU_NOTLOGGEDIN; return ret; +} + +/* Returns username + * Returns: unix user name + */ + +char *myusername_unix () +{ + myusername_full(NIL); + return myUserName_unix ? myUserName_unix : ""; } diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/env_unix.c.orig imap-4.6_vpop_my/src/osdep/unix/env_unix.c.orig --- imap-4.6_vpop_orig/src/osdep/unix/env_unix.c.orig Sun Oct 10 13:33:56 1999 +++ imap-4.6_vpop_my/src/osdep/unix/env_unix.c.orig Tue Nov 9 23:05:06 1999 @@ -511,6 +511,7 @@ struct passwd *pw; struct stat sbuf; char *s,tmp[MAILTMPLEN]; + DRIVER *d; if (myUserName) fatal ("env_init called twice!"); /* myUserName must be set before dorc() call */ myUserName = cpystr ((char *) (user ? user : anonymous_user)); @@ -557,7 +558,12 @@ if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared"))) sharedHome = cpystr (pw->pw_dir); /* force default prototype to be set */ - if (!createProto) createProto = &CREATEPROTO; + /* this hard-wires in a createProto of the INBOX format */ + if (!createProto) { + createProto = ((d = mail_valid (NIL,"INBOX",NIL)) && + strcmp (d->name,"dummy")) ? + ((*d->open) (NIL)) : &CREATEPROTO; + } if (!appendProto) appendProto = &EMPTYPROTO; /* re-do open action to get flags */ (*createProto->dtb->open) (NIL); diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/env_unix.h imap-4.6_vpop_my/src/osdep/unix/env_unix.h --- imap-4.6_vpop_orig/src/osdep/unix/env_unix.h Tue Jun 15 02:11:59 1999 +++ imap-4.6_vpop_my/src/osdep/unix/env_unix.h Tue Nov 9 23:05:06 1999 @@ -50,6 +50,9 @@ void rfc822_fixed_date (char *date); long env_init (char *user,char *home); char *myusername_full (unsigned long *flags); +char *myusername_dologin (char* user, char** error); +char *myusername_full_backend (unsigned long *flags, char* new_username, char** error); +char *myusername_unix (); #define MU_LOGGEDIN 0 #define MU_NOTLOGGEDIN 1 #define MU_ANONYMOUS 2 diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/md5.c imap-4.6_vpop_my/src/osdep/unix/md5.c --- imap-4.6_vpop_orig/src/osdep/unix/md5.c Wed Dec 31 19:00:00 1969 +++ imap-4.6_vpop_my/src/osdep/unix/md5.c Tue Nov 9 23:05:06 1999 @@ -0,0 +1,254 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + */ + +#include +#include "md5.h" + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +void byteReverse(unsigned char *buf, unsigned longs); + +#ifndef ASM_MD5 +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(unsigned char *buf, unsigned longs) +{ + uint32 t; + do { + t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301U; + ctx->buf[1] = 0xefcdab89U; + ctx->buf[2] = 0x98badcfeU; + ctx->buf[3] = 0x10325476U; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, unsigned const char *buf, unsigned len) +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *) ctx->in)[14] = ctx->bits[0]; + ((uint32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +#ifndef ASM_MD5 + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(uint32 buf[4], uint32 const in[16]) +{ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478U, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756U, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070dbU, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceeeU, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0fafU, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62aU, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613U, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501U, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8U, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7afU, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1U, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7beU, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122U, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193U, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438eU, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821U, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562U, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340U, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51U, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aaU, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105dU, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453U, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681U, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8U, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6U, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6U, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87U, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14edU, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905U, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8U, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9U, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8aU, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942U, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681U, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122U, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380cU, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44U, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9U, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60U, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70U, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6U, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127faU, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085U, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05U, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039U, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5U, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8U, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665U, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244U, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97U, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7U, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039U, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3U, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92U, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47dU, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1U, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4fU, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0U, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314U, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1U, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82U, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235U, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bbU, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391U, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#endif diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/md5.h imap-4.6_vpop_my/src/osdep/unix/md5.h --- imap-4.6_vpop_orig/src/osdep/unix/md5.h Wed Dec 31 19:00:00 1969 +++ imap-4.6_vpop_my/src/osdep/unix/md5.h Tue Nov 9 23:05:06 1999 @@ -0,0 +1,30 @@ +#ifndef MD5_H +#define MD5_H + +#ifdef __alpha +typedef unsigned int uint32; +#else +typedef unsigned long uint32; +#endif + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; + +void MD5Init(struct MD5Context *); +void MD5Update(struct MD5Context *, unsigned const char *, unsigned); +void MD5Final(unsigned char digest[16], struct MD5Context *); +void MD5Transform(uint32 buf[4], uint32 const in[16]); +int i64c(int i); + +char *crypt_md5(const char *pw, const char *salt); + +/* +* This is needed to make RSAREF happy on some MS-DOS compilers. +*/ + +typedef struct MD5Context MD5_CTX; + +#endif /* MD5_H */ diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/md5_crypt.c imap-4.6_vpop_my/src/osdep/unix/md5_crypt.c --- imap-4.6_vpop_orig/src/osdep/unix/md5_crypt.c Wed Dec 31 19:00:00 1969 +++ imap-4.6_vpop_my/src/osdep/unix/md5_crypt.c Tue Nov 9 23:05:06 1999 @@ -0,0 +1,159 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * Origin: Id: crypt.c,v 1.3 1995/05/30 05:42:22 rgrimes Exp + * + */ + +#include +#include "md5.h" + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void +to64(char *s, unsigned long v, int n) +{ + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +/* + * i64c - convert an integer to a radix 64 character + */ +int i64c(int i) +{ + if (i < 0) + return ('.'); + else if (i > 63) + return ('z'); + if (i == 0) + return ('.'); + if (i == 1) + return ('/'); + if (i >= 2 && i <= 11) + return ('0' - 2 + i); + if (i >= 12 && i <= 37) + return ('A' - 12 + i); + if (i >= 38 && i <= 63) + return ('a' - 38 + i); + return ('\0'); +} + +/* + * UNIX password + * + * Use MD5 for what it is best at... + */ + +char * crypt_md5(const char *pw, const char *salt) +{ + const char *magic = "$1$"; + /* This string is magic for this algorithm. Having + * it this way, we can get get better later on */ + static char passwd[120], *p; + static const char *sp,*ep; + unsigned char final[16]; + int sl,pl,i,j; + MD5_CTX ctx,ctx1; + unsigned long l; + + /* Refine the Salt first */ + sp = salt; + + /* If it starts with the magic string, then skip that */ + if(!strncmp(sp,magic,strlen(magic))) + sp += strlen(magic); + + /* It stops at the first '$', max 8 chars */ + for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + MD5Init(&ctx); + + /* The password first, since that is what is most unknown */ + MD5Update(&ctx,(unsigned const char *)pw,strlen(pw)); + + /* Then our magic string */ + MD5Update(&ctx,(unsigned const char *)magic,strlen(magic)); + + /* Then the raw salt */ + MD5Update(&ctx,(unsigned const char *)sp,sl); + + /* Then just as many characters of the MD5(pw,salt,pw) */ + MD5Init(&ctx1); + MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw)); + MD5Update(&ctx1,(unsigned const char *)sp,sl); + MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw)); + MD5Final(final,&ctx1); + for(pl = strlen(pw); pl > 0; pl -= 16) + MD5Update(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl); + + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); + + /* Then something really weird... */ + for (j=0,i = strlen(pw); i ; i >>= 1) + if(i&1) + MD5Update(&ctx, (unsigned const char *)final+j, 1); + else + MD5Update(&ctx, (unsigned const char *)pw+j, 1); + + /* Now make the output string */ + strcpy(passwd,magic); + strncat(passwd,sp,sl); + strcat(passwd,"$"); + + MD5Final(final,&ctx); + + /* + * and now, just to make sure things don't run too fast + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for(i=0;i<1000;i++) { + MD5Init(&ctx1); + if(i & 1) + MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw)); + else + MD5Update(&ctx1,(unsigned const char *)final,16); + + if(i % 3) + MD5Update(&ctx1,(unsigned const char *)sp,sl); + + if(i % 7) + MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw)); + + if(i & 1) + MD5Update(&ctx1,(unsigned const char *)final,16); + else + MD5Update(&ctx1,(unsigned const char *)pw,strlen(pw)); + MD5Final(final,&ctx1); + } + + p = passwd + strlen(passwd); + + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; + l = final[11] ; to64(p,l,2); p += 2; + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); + + return passwd; +} + diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/mmdf.c imap-4.6_vpop_my/src/osdep/unix/mmdf.c --- imap-4.6_vpop_orig/src/osdep/unix/mmdf.c Wed Sep 22 13:05:05 1999 +++ imap-4.6_vpop_my/src/osdep/unix/mmdf.c Tue Nov 9 23:05:06 1999 @@ -861,7 +861,7 @@ return NIL; } fstat (fd,&sbuf); /* get current file size */ - sprintf (buf,"%sFrom %s@%s ",mmdfhdr,myusername (),mylocalhost ()); + sprintf (buf,"%sFrom %s@%s ",mmdfhdr,myusername_unix (),mylocalhost ()); /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/tcp_unix.c imap-4.6_vpop_my/src/osdep/unix/tcp_unix.c --- imap-4.6_vpop_orig/src/osdep/unix/tcp_unix.c Wed Oct 6 15:06:16 1999 +++ imap-4.6_vpop_my/src/osdep/unix/tcp_unix.c Tue Nov 9 23:05:06 1999 @@ -384,9 +384,9 @@ } if (*service == '*') /* build ssh command */ sprintf (tmp,sshcommand,sshpath,host, - mb->user[0] ? mb->user : myusername (),service + 1); + mb->user[0] ? mb->user : myusername_unix (),service + 1); else sprintf (tmp,rshcommand,rshpath,host, - mb->user[0] ? mb->user : myusername (),service); + mb->user[0] ? mb->user : myusername_unix (),service); tmo.tv_usec = 0; /* initialize usec timeout */ FD_ZERO (&fds); /* initialize selection vector */ @@ -444,7 +444,7 @@ } (*bn) (BLOCK_NONE,NIL); /* return user name */ - strcpy (usrbuf,mb->user[0] ? mb->user : myusername ()); + strcpy (usrbuf,mb->user[0] ? mb->user : myusername_unix ()); return stream; /* return success */ } diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/unix.c imap-4.6_vpop_my/src/osdep/unix/unix.c --- imap-4.6_vpop_orig/src/osdep/unix/unix.c Wed Sep 22 13:05:07 1999 +++ imap-4.6_vpop_my/src/osdep/unix/unix.c Tue Nov 9 23:05:06 1999 @@ -890,7 +890,7 @@ return NIL; } fstat (fd,&sbuf); /* get current file size */ - sprintf (buf,"From %s@%s ",myusername (),mylocalhost ()); + sprintf (buf,"From %s@%s ",myusername_unix (),mylocalhost ()); /* user wants to suppress time zones? */ if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) { time_t when = mail_longdate (&elt); diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/vpop.c imap-4.6_vpop_my/src/osdep/unix/vpop.c --- imap-4.6_vpop_orig/src/osdep/unix/vpop.c Wed Dec 31 19:00:00 1969 +++ imap-4.6_vpop_my/src/osdep/unix/vpop.c Tue Nov 9 23:12:54 1999 @@ -0,0 +1,289 @@ +/** + ** vpop.c -- email virtual users authentication lookup stuff + **/ + +#include "vpop.h" +#include "md5.h" + +#include +#include +#include +#include +#include "/usr/include/db1/db.h" +/* #include */ +#include +#include +#include +#include + +char *vpop__lcase (char *s) { + char *t; + for (t = s; *t; t++) if (!(*t & 0x80) && isupper (*t)) *t = tolower (*t); + return s; +} + +vpop__data* vpop__userauthen (char* username, char* password, char* default_base_username) +{ + vpop__data* rv; + char* tmpchar; + + DB *db; + DBT dbkey, dbval; + + int prefixlen; + char virtual_username_buf[102]; + char* virtual_username; + char* base_username = NULL; + + char* key; + char base[102]; + char* unix_username; + + char userdb_filename[122]; + int lockfd; + char user_crypt[102]; + char* user_relfilename = NULL; + + char* password_encoded; + + /* + * Copy the username and prepare the return structure + */ + + rv = (vpop__data*) malloc(sizeof(vpop__data)); + rv->valid_form = 0; + rv->valid_user = 0; + rv->unix_username = NULL; + rv->virtual_username = NULL; + rv->black_box_home = NULL; + rv->authenticated = 0; + rv->log_error = NULL; + + /* + * See if we have a special dummy black box dir url in the form + * "vpop_fake_blackbox/UNIXUSERNAME/VIRTUALUSERNAME/BLACKBOXDIR" + */ + + if ( !strncmp(username, "vpop_fake_blackbox/", 19) ) { + + if ( strlen(username+19) > 100 ) { + rv->log_error = "virtual username too long"; + return rv; + } + + rv->valid_form = 1; + + strcpy(virtual_username_buf, username+19); + unix_username = virtual_username_buf; + if ( tmpchar = strchr(unix_username, '/') ) { + *tmpchar = '\0'; + virtual_username = tmpchar+1; + if ( tmpchar = strchr(virtual_username, '/') ) { + *tmpchar = '\0'; + + rv->valid_user = 1; + + rv->unix_username = (char*) malloc(strlen(unix_username)+2); + strcpy(rv->unix_username, unix_username); + + rv->virtual_username = (char*) malloc(strlen(virtual_username)+2); + strcpy(rv->virtual_username, virtual_username); + + rv->black_box_home = (char*) malloc(strlen(tmpchar+1)+2); + strcpy(rv->black_box_home, tmpchar+1); + } + } + + return rv; + } + + /* + * Extract the virtual_username and perhaps base_username from the + * provided username. + */ + + prefixlen = 0; + if ( !strncasecmp(username, "vpop/", 5) ) { prefixlen = 5; } + else if ( !strncasecmp(username, "vpop\\", 5) ) { prefixlen = 5; } + else if ( !strncasecmp(username, "v/", 2) ) { prefixlen = 2; } + else if ( !strncasecmp(username, "v\\", 2) ) { prefixlen = 2; } + else if ( !strncasecmp(username, "+", 1) ) { prefixlen = 1; } + + if ( prefixlen == 0 ) return rv; + + if ( strlen(username+prefixlen) > 100 ) { + rv->log_error = "virtual username too long"; + return rv; + } + + strcpy(virtual_username_buf, username+prefixlen); + virtual_username = virtual_username_buf; + if ( tmpchar = strchr(virtual_username, '/') ) { + *tmpchar = '\0'; + base_username = virtual_username; + virtual_username = tmpchar+1; + } + + if ( !strlen(virtual_username) ) return rv; + if ( base_username && !strlen(base_username) ) return rv; + + rv->valid_form = 1; + + /* + * Lookup base and unix_username in the IPUSERDB_FILENAME using + * the baseusername or getenv("TCPLOCALIP") as the key + */ + + key = base_username ? base_username : + ( default_base_username ? default_base_username : getenv("TCPLOCALIP") ); + + if ( !key || !strlen(key) ) { + rv->log_error = "no base_username or TCPLOCALIP"; + return rv; + } + + if (!(db = dbopen(VPOP__IPUSERDB_FILENAME, O_RDONLY, 0644, DB_HASH, NULL))) { + rv->log_error = "could not open ipuserdb file"; + return rv; + } + + dbkey.data = key; + dbkey.size = strlen(key); + if ((db->get) (db, &dbkey, &dbval, 0)) { + (db->close) (db); + /* this virtual user base does not exist, not an error */ + return rv; + } + + if ( dbval.size > 100 ) { + (db->close) (db); + rv->log_error = "key from ipuserdb is too long"; + return rv; + } + memcpy(base, dbval.data, dbval.size); + base[dbval.size] = '\0'; + + (db->close) (db); + + if ( !(tmpchar = strrchr(base, ':')) ) { + rv->log_error = "key from ipuserdb in wrong format"; + return rv; + } + *tmpchar = '\0'; + unix_username = tmpchar + 1; + + /* + * Lookup user_crypt and user_relfilename from the userdb + */ + + strcpy(userdb_filename, base); + strcat(userdb_filename, "/usrconf/vpop.db"); /* assert: userdb_filename 20 longer than base */ + + lockfd = open(userdb_filename, O_RDONLY); + if ( lockfd == -1 ) { + rv->log_error = "could not open userdb file with open"; + return rv; + } + + if( flock(lockfd, LOCK_SH) == -1 ) { + rv->log_error = "could not flock userdb file"; + return rv; + } + + if (!(db = dbopen(userdb_filename, O_RDONLY, 0644, DB_HASH, NULL))) { + rv->log_error = "could not open userdb file with dbopen"; + return rv; + } + + dbkey.data = virtual_username; + dbkey.size = strlen(virtual_username); + if ((db->get) (db, &dbkey, &dbval, 0)) { + /* try to lcase the virtual_username and try again.. I don't konw why + we should do this, but UW-IMAP does, so i'll do it here. */ + vpop__lcase(virtual_username); + if ((db->get) (db, &dbkey, &dbval, 0)) { + (db->close) (db); + close(lockfd); + /* this user does not exist: not an error */ + return rv; + } + } + + if ( dbval.size > 100 ) { + (db->close) (db); + close(lockfd); + rv->log_error = "key from userdb is too long"; + return rv; + } + memcpy(user_crypt, dbval.data, dbval.size); + user_crypt[dbval.size] = '\0'; + + (db->close) (db); + close(lockfd); + + if ( tmpchar = strchr(user_crypt, ':') ) { + *tmpchar = '\0'; + user_relfilename = tmpchar+1; + if ( tmpchar = strchr(user_relfilename, ':') ) { + *tmpchar = '\0'; + } + if ( user_relfilename[0] == '\0' ) { + user_relfilename = NULL; + } + } + + /* + * The user is valid, so set some information in the data structure + */ + + rv->valid_user = 1; + + rv->unix_username = (char*) malloc(strlen(unix_username)+2); + strcpy(rv->unix_username, unix_username); + + rv->virtual_username = (char*) malloc(strlen(virtual_username)+2); + strcpy(rv->virtual_username, virtual_username); + + rv->black_box_home = (char*) malloc( 2 + + strlen(base) + + strlen("/email/") + + strlen(user_relfilename ? user_relfilename : virtual_username) + ); + + strcpy(rv->black_box_home, base); + strcat(rv->black_box_home, "/email/"); + strcat(rv->black_box_home, user_relfilename ? user_relfilename : virtual_username); + + /* + * Check the user's password + */ + + /* NOTE: We deal with passwords that might have a leading space slapped on because + Mark Crispin's UW-IMAP code does the same. Perhaps a broken client? */ + + if (password) { + password_encoded = crypt_md5(password, user_crypt); + if ( !strcmp(password_encoded, user_crypt) ) { + rv->authenticated = 1; + } + else if ( *password == ' ' ) { + password_encoded = crypt_md5(password+1, user_crypt); + if ( !strcmp(password_encoded, user_crypt) ) + rv->authenticated = 1; + } + } + + /* + * Return the structure + */ + + return rv; +} + +void vpop__freedata (vpop__data* rv) +{ + if (rv->unix_username) free(rv->unix_username); + if (rv->virtual_username) free(rv->virtual_username); + if (rv->black_box_home) free(rv->black_box_home); + free(rv); +} diff -rNu3 imap-4.6_vpop_orig/src/osdep/unix/vpop.h imap-4.6_vpop_my/src/osdep/unix/vpop.h --- imap-4.6_vpop_orig/src/osdep/unix/vpop.h Wed Dec 31 19:00:00 1969 +++ imap-4.6_vpop_my/src/osdep/unix/vpop.h Tue Nov 9 23:05:06 1999 @@ -0,0 +1,19 @@ +/** + ** vpop.h -- header file + **/ + +#define VPOP__IPUSERDB_FILENAME "/etc/gather/list/ipuserdb" + +typedef struct { + int valid_form; + int valid_user; + char* unix_username; + char* virtual_username; + char* black_box_home; + int authenticated; + char* log_error; +} vpop__data; + +vpop__data* vpop__userauthen (char* username, char* password, char* default_base_username); +void vpop__freedata (vpop__data* rv); +