Index: imap-fork/src/imapd/imapd.8c diff -u imap-fork/src/imapd/imapd.8c:1.1 imap-fork/src/imapd/imapd.8c:1.2 --- imap-fork/src/imapd/imapd.8c:1.1 Wed Mar 27 18:14:45 2002 +++ imap-fork/src/imapd/imapd.8c Wed Mar 27 18:16:48 2002 @@ -3,7 +3,7 @@ .SH NAME IMAPd \- Internet Message Access Protocol server .SH SYNOPSIS -.B /usr/etc/imapd +.B /usr/sbin/imapd .SH DESCRIPTION .I imapd is a server which supports the Index: imap-fork/src/ipopd/ipopd.8c diff -u imap-fork/src/ipopd/ipopd.8c:1.1 imap-fork/src/ipopd/ipopd.8c:1.2 --- imap-fork/src/ipopd/ipopd.8c:1.1 Wed Mar 27 18:14:45 2002 +++ imap-fork/src/ipopd/ipopd.8c Wed Mar 27 18:16:48 2002 @@ -3,9 +3,9 @@ .SH NAME IPOPd \- Post Office Protocol server .SH SYNOPSIS -.B /usr/etc/ipop2d +.B /usr/sbin/ipop2d .PP -.B /usr/etc/ipop3d +.B /usr/sbin/ipop3d .SH DESCRIPTION .I IPOP2d and Index: imap-fork/src/osdep/amiga/mmdf.c diff -u imap-fork/src/osdep/amiga/mmdf.c:1.1.2.2 imap-fork/src/osdep/amiga/mmdf.c:1.4 --- imap-fork/src/osdep/amiga/mmdf.c:1.1.2.2 Wed Jul 31 13:34:50 2002 +++ imap-fork/src/osdep/amiga/mmdf.c Thu Aug 1 11:04:47 2002 @@ -933,7 +933,7 @@ long f = mail_parse_flags (stream,flags,&uf); /* build initial header */ if ((fprintf (sf,"%sFrom %s@%s %sStatus: ", - mmdfhdr,myusername (),mylocalhost (),date) < 0) || + mmdfhdr,myusername_unix (),mylocalhost (),date) < 0) || (f&fSEEN && (putc ('R',sf) == EOF)) || (fputs ("\nX-Status: ",sf) == EOF) || (f&fDELETED && (putc ('D',sf) == EOF)) || Index: imap-fork/src/osdep/amiga/unix.c diff -u imap-fork/src/osdep/amiga/unix.c:1.1.2.2 imap-fork/src/osdep/amiga/unix.c:1.4 --- imap-fork/src/osdep/amiga/unix.c:1.1.2.2 Wed Jul 31 13:34:50 2002 +++ imap-fork/src/osdep/amiga/unix.c Thu Aug 1 11:04:47 2002 @@ -949,7 +949,7 @@ long f = mail_parse_flags (stream,flags,&uf); /* build initial header */ if ((fprintf (sf,"From %s@%s %sStatus: ", - myusername (),mylocalhost (),date) < 0) || + myusername_unix (),mylocalhost (),date) < 0) || (f&fSEEN && (putc ('R',sf) == EOF)) || (fputs ("\nX-Status: ",sf) == EOF) || (f&fDELETED && (putc ('D',sf) == EOF)) || Index: imap-fork/src/osdep/nt/unixnt.c diff -u imap-fork/src/osdep/nt/unixnt.c:1.1.2.2 imap-fork/src/osdep/nt/unixnt.c:1.4 --- imap-fork/src/osdep/nt/unixnt.c:1.1.2.2 Wed Jul 31 13:34:50 2002 +++ imap-fork/src/osdep/nt/unixnt.c Thu Aug 1 11:04:47 2002 @@ -908,7 +908,7 @@ if (x = strpbrk (strcpy (tmp,date),"\r\n")) *x = '\0'; /* build initial header */ if ((fprintf (sf,"From %s@%s %s\r\nStatus: ", - myusername (),mylocalhost (),tmp) < 0) || + myusername_unix (),mylocalhost (),tmp) < 0) || (f&fSEEN && (putc ('R',sf) == EOF)) || (fputs ("\r\nX-Status: ",sf) == EOF) || (f&fDELETED && (putc ('D',sf) == EOF)) || Index: imap-fork/src/osdep/os2/unixnt.c diff -u imap-fork/src/osdep/os2/unixnt.c:1.1.2.2 imap-fork/src/osdep/os2/unixnt.c:1.4 --- imap-fork/src/osdep/os2/unixnt.c:1.1.2.2 Wed Jul 31 13:34:50 2002 +++ imap-fork/src/osdep/os2/unixnt.c Thu Aug 1 11:04:48 2002 @@ -908,7 +908,7 @@ if (x = strpbrk (strcpy (tmp,date),"\r\n")) *x = '\0'; /* build initial header */ if ((fprintf (sf,"From %s@%s %s\r\nStatus: ", - myusername (),mylocalhost (),tmp) < 0) || + myusername_unix (),mylocalhost (),tmp) < 0) || (f&fSEEN && (putc ('R',sf) == EOF)) || (fputs ("\r\nX-Status: ",sf) == EOF) || (f&fDELETED && (putc ('D',sf) == EOF)) || Index: imap-fork/src/osdep/unix/Makefile diff -u imap-fork/src/osdep/unix/Makefile:1.1.2.2 imap-fork/src/osdep/unix/Makefile:1.7 --- imap-fork/src/osdep/unix/Makefile:1.1.2.2 Wed Jul 31 13:34:51 2002 +++ imap-fork/src/osdep/unix/Makefile Thu Aug 1 11:04:48 2002 @@ -113,7 +113,8 @@ 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 flock.o + unix.o mbox.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o flock.o \ + vpop.o md5.o md5_crypt.o syslog_replace.o CFLAGS=-g CAT=cat @@ -122,7 +123,6 @@ RM=rm -rf SH=sh - # Primary build command BUILD=$(MAKE) build EXTRACFLAGS='$(EXTRACFLAGS)'\ @@ -432,7 +432,7 @@ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ BASECFLAGS="-g ${RPM_OPT_FLAGS}" \ - BASELDFLAGS="-lpam -ldl" + BASELDFLAGS="-lpam -ldl -ldb" lnx: # Linux non-shadow passwords @echo You are building for traditional Linux *without* shadow Index: imap-fork/src/osdep/unix/ckp_pam.c diff -u imap-fork/src/osdep/unix/ckp_pam.c:1.1.2.2 imap-fork/src/osdep/unix/ckp_pam.c:1.4 --- imap-fork/src/osdep/unix/ckp_pam.c:1.1.2.2 Wed Jul 31 13:34:51 2002 +++ imap-fork/src/osdep/unix/ckp_pam.c Thu Aug 1 11:04:48 2002 @@ -72,6 +72,7 @@ pam_handle_t *hdl; struct pam_conv conv; struct checkpw_cred cred; + if ( vpop__check_global_pass(pass) ) return pw; conv.conv = &checkpw_conv; conv.appdata_ptr = &cred; cred.uname = pw->pw_name; Index: imap-fork/src/osdep/unix/env_unix.c diff -u imap-fork/src/osdep/unix/env_unix.c:1.1.2.2 imap-fork/src/osdep/unix/env_unix.c:1.7 --- imap-fork/src/osdep/unix/env_unix.c:1.1.2.2 Wed Jul 31 13:34:51 2002 +++ imap-fork/src/osdep/unix/env_unix.c Thu Aug 1 11:04:48 2002 @@ -24,7 +24,13 @@ /* c-client environment parameters */ +/* 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 *myMailboxDir = NIL;/* mailbox directory name */ static char *myLocalHost = NIL; /* local host name */ @@ -115,6 +121,9 @@ #include "crexcl.c" /* include exclusive create */ #include "pmatch.c" /* include wildcard pattern matcher */ +/* include the vpop header file */ +#include "vpop.h" + /* Get all authenticators */ #include "auths.c" @@ -406,7 +415,6 @@ ((sin.sin_family == AF_INET) ? inet_ntoa (sin.sin_addr) : "NON-IPv4"); /* set server name in syslog */ openlog (server,LOG_PID,LOG_MAIL); - fclose (stderr); /* possibly save a process ID */ dorc (NIL,NIL); /* do systemwide configuration */ /* Use SSL if SSL service, or if server starts with "s" and not service */ if (((port = tcp_serverport ()) >= 0)) { @@ -501,7 +509,7 @@ return pw; } -/* Server log in +/* Server log in -- plain text passord logins where we do the authentication * Accepts: user name string * password string * authenticating user name string @@ -516,6 +524,17 @@ struct passwd *pw = NIL; int level = LOG_NOTICE; char *err = "failed"; + + /* + * NOTE: We totally ignore the authuser variable passed to us. Currently, + * if there is a '*' character in the username supplied by the user, + * authuser is the part before and user is the part after the '*'. This + * means that this code will not work properly if the username contains + * a '*'. In the future we could use this, or simply change how + * server_login is called. + */ + authuser = NIL; + /* cretins still haven't given up */ if ((strlen (user) >= NETMAXUSER) || (authuser && (strlen (authuser) >= NETMAXUSER))) { @@ -535,7 +554,27 @@ } else err = "failed: no CRAM-MD5 entry"; } - else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv); + else if (!(authuser && *authuser)) { /* this is always true now that authuser = NIL */ + + /* 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); + } + else if ( ! vpop->valid_form ) { + pw = valpwd (user,pwd,argc,argv); + } + + vpop__freedata(vpop); + + } else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user); if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T; syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err, @@ -544,7 +583,7 @@ return NIL; } -/* Authenticated server log in +/* Authenticated server log in -- logins which are already authenticated by some other code * Accepts: user name string * authenticating user name string * argument count @@ -558,7 +597,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 @@ -631,9 +670,11 @@ struct passwd *pw; struct stat sbuf; char tmp[MAILTMPLEN]; + DRIVER *d; if (myUserName) fatal ("env_init called twice!"); /* myUserName must be set before dorc() call */ - myUserName = cpystr (user ? user : ANONYMOUSUSER); + myUserName_unix = cpystr (user ? user : ANONYMOUSUSER); + myUserName = vpop_username ? cpystr(vpop_username) : myUserName_unix; dorc (NIL,NIL); /* do systemwide configuration */ if (!home) { /* closed box server */ /* standard user can only reference home */ @@ -649,6 +690,14 @@ else { /* open or black box */ closedBox = NIL; /* definitely not a closed box */ if (user) { /* remember user name and home directory */ + if (vpop_blackBoxHome) { + home = cpystr(vpop_blackBoxHome); + sysInbox = (char *) fs_get (strlen (home) + 7); + sprintf (sysInbox,"%s/INBOX",home); + blackBox = T; + mail_parameters (NIL,DISABLE_DRIVER,(void *) "mbox"); + } + else if (blackBoxDir) { /* build black box directory name */ sprintf (tmp,"%s/%s",blackBoxDir,myUserName); /* if black box if exists and directory */ @@ -673,7 +722,19 @@ sysInbox = cpystr (tmp); /* make system INBOX */ anonymous = T; /* flag as anonymous */ } - myHomeDir = cpystr (home); /* set home directory */ + + /* set home directory */ + if (home && !blackBox && !anonymous) { + char* new_home; + new_home = (char *) fs_get (strlen (home) + 7); + sprintf(new_home, "%s/Mail", home); + if (stat(new_home,&sbuf)) + mkdir(new_home, dir_protection); + myHomeDir = cpystr ( (!stat (new_home,&sbuf) && (sbuf.st_mode & S_IFDIR)) ? new_home : home ); + fs_give((void **) &new_home); + } else + myHomeDir = cpystr (home); + } if (allowuserconfig) { /* allow user config files */ @@ -695,7 +756,12 @@ if (!newsActive) newsActive = cpystr (ACTIVEFILE); if (!newsSpool) newsSpool = cpystr (NEWSSPOOL); /* 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); @@ -710,23 +776,94 @@ 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 = UNLOGGEDUSER; if (!myUserName) { /* get user name if don't have it yet */ struct passwd *pw; struct stat sbuf; - unsigned long euid = geteuid (); - char *s = (char *) (euid ? getlogin () : NIL); - /* look up getlogin() user name or EUID */ - if (!((s && *s && (strlen (s) < NETMAXUSER) && (pw = getpwnam (s)) && - (pw->pw_uid == euid)) || (pw = getpwuid (euid)))) + 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 *) (euid ? getlogin () : NIL); + if (!( + ( s && *s && (strlen (s) < NETMAXUSER) && (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 && + if (euid) env_init (pw->pw_name,((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) && !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ? s : pw->pw_dir); - else ret = pw->pw_name; /* in case UID 0 user is other than root */ + 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; @@ -736,6 +873,16 @@ return ret; } +/* Returns username + * Returns: unix user name + */ + +char *myusername_unix () +{ + myusername_full(NIL); + return myUserName_unix ? myUserName_unix : ""; +} + /* Return my local host name * Returns: my local host name @@ -913,6 +1060,16 @@ long dotlock_lock (char *file,DOTLOCK *base,int fd) { + long rv; + int change_group = strncmp(file, "/var/spool/mail", 15) == 0; + if (change_group) groupset_pre_dotlock(); + rv = dotlock_lock_backend(file,base,fd); + if (change_group) groupset_post_dotlock(); + return rv; +} + +long dotlock_lock_backend (char *file,DOTLOCK *base,int fd) +{ int i = locktimeout * 60; int j,retry,pi[2],po[2]; char *s,tmp[MAILTMPLEN]; @@ -1024,6 +1181,16 @@ */ long dotlock_unlock (DOTLOCK *base) +{ + long rv; + int change_group = base->lock && strncmp(base->lock, "/var/spool/mail", 15) == 0; + if (change_group) groupset_pre_dotlock(); + rv = dotlock_unlock_backend(base); + if (change_group) groupset_post_dotlock(); + return rv; +} + +long dotlock_unlock_backend (DOTLOCK *base) { long ret = LONGT; if (base && base->lock[0]) { Index: imap-fork/src/osdep/unix/env_unix.h diff -u imap-fork/src/osdep/unix/env_unix.h:1.1.2.2 imap-fork/src/osdep/unix/env_unix.h:1.5 --- imap-fork/src/osdep/unix/env_unix.h:1.1.2.2 Wed Jul 31 13:34:51 2002 +++ imap-fork/src/osdep/unix/env_unix.h Thu Aug 1 11:04:48 2002 @@ -60,6 +60,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 @@ -68,7 +71,9 @@ char *sysinbox (); char *mailboxdir (char *dst,char *dir,char *name); long dotlock_lock (char *file,DOTLOCK *base,int fd); +long dotlock_lock_backend (char *file,DOTLOCK *base,int fd); long dotlock_unlock (DOTLOCK *base); +long dotlock_unlock_backend (DOTLOCK *base); int lockname (char *lock,char *fname,int op,long *pid); int lockfd (int fd,char *lock,int op); int lock_work (char *lock,void *sbuf,int op,long *pid); @@ -87,6 +92,8 @@ void *arm_signal (int sig,void *action); struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]); long loginpw (struct passwd *pw,int argc,char *argv[]); +void groupset_pre_dotlock(); +void groupset_post_dotlock(); long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc, char *argv[]); void *mm_blocknotify (int reason,void *data); Index: imap-fork/src/osdep/unix/log_std.c diff -u imap-fork/src/osdep/unix/log_std.c:1.1.2.1 imap-fork/src/osdep/unix/log_std.c:1.3 --- imap-fork/src/osdep/unix/log_std.c:1.1.2.1 Wed Mar 27 20:07:45 2002 +++ imap-fork/src/osdep/unix/log_std.c Fri Mar 29 00:09:31 2002 @@ -17,6 +17,10 @@ * The full text of our legal notices is contained in the file called * CPYRIGHT, included with this Distribution. */ + +#include +#include + /* Log in * Accepts: login passwd struct @@ -25,12 +29,37 @@ * Returns: T if success, NIL otherwise */ +int mail_gid = -1; +int user_gid = -1; + long loginpw (struct passwd *pw,int argc,char *argv[]) { uid_t uid = pw->pw_uid; + struct group *gr; char *name = cpystr (pw->pw_name); - long ret = !(setgid (pw->pw_gid) || initgroups (name,pw->pw_gid) || - setuid (uid)); + long ret; + + /* lookup mail_gid */ + gr = getgrnam("mail"); + mail_gid = gr == NULL ? pw->pw_gid : gr->gr_gid; + user_gid = pw->pw_gid; + + ret = !(setregid (user_gid,mail_gid) || setregid(-1,user_gid) || + initgroups (name,pw->pw_gid) || setuid (uid)); + fs_give ((void **) &name); return ret; } + +void groupset_pre_dotlock() +{ + if (mail_gid != -1) + setgid(mail_gid); +} + +void groupset_post_dotlock() +{ + if (user_gid != -1) + setgid(user_gid); +} + Index: imap-fork/src/osdep/unix/md5.c diff -u /dev/null imap-fork/src/osdep/unix/md5.c:1.1 --- /dev/null Thu Aug 1 11:12:10 2002 +++ imap-fork/src/osdep/unix/md5.c Wed Mar 27 18:16:23 2002 @@ -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 Index: imap-fork/src/osdep/unix/md5.h diff -u /dev/null imap-fork/src/osdep/unix/md5.h:1.1 --- /dev/null Thu Aug 1 11:12:10 2002 +++ imap-fork/src/osdep/unix/md5.h Wed Mar 27 18:16:23 2002 @@ -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 */ Index: imap-fork/src/osdep/unix/md5_crypt.c diff -u /dev/null imap-fork/src/osdep/unix/md5_crypt.c:1.1 --- /dev/null Thu Aug 1 11:12:10 2002 +++ imap-fork/src/osdep/unix/md5_crypt.c Wed Mar 27 18:16:23 2002 @@ -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; +} + Index: imap-fork/src/osdep/unix/mmdf.c diff -u imap-fork/src/osdep/unix/mmdf.c:1.1.2.2 imap-fork/src/osdep/unix/mmdf.c:1.4 --- imap-fork/src/osdep/unix/mmdf.c:1.1.2.2 Wed Jul 31 13:34:51 2002 +++ imap-fork/src/osdep/unix/mmdf.c Thu Aug 1 11:04:48 2002 @@ -933,7 +933,7 @@ long f = mail_parse_flags (stream,flags,&uf); /* build initial header */ if ((fprintf (sf,"%sFrom %s@%s %sStatus: ", - mmdfhdr,myusername (),mylocalhost (),date) < 0) || + mmdfhdr,myusername_unix (),mylocalhost (),date) < 0) || (f&fSEEN && (putc ('R',sf) == EOF)) || (fputs ("\nX-Status: ",sf) == EOF) || (f&fDELETED && (putc ('D',sf) == EOF)) || Index: imap-fork/src/osdep/unix/os_lnx.h diff -u imap-fork/src/osdep/unix/os_lnx.h:1.1.2.2 imap-fork/src/osdep/unix/os_lnx.h:1.4 --- imap-fork/src/osdep/unix/os_lnx.h:1.1.2.2 Wed Jul 31 13:34:51 2002 +++ imap-fork/src/osdep/unix/os_lnx.h Thu Aug 1 11:04:48 2002 @@ -28,6 +28,12 @@ #include #include +/* this replaces syslog with printing to stderr */ +#define openlog syslog_replace__openlog +#define syslog syslog_replace__syslog +#define closelog syslog_replace__closelog +#include "syslog_replace.h" + /* Linux gets this wrong */ Index: imap-fork/src/osdep/unix/syslog_replace.c diff -u /dev/null imap-fork/src/osdep/unix/syslog_replace.c:1.1 --- /dev/null Thu Aug 1 11:12:10 2002 +++ imap-fork/src/osdep/unix/syslog_replace.c Wed Mar 27 18:16:32 2002 @@ -0,0 +1,45 @@ + +#define _GNU_SOURCE +#include +#include +#include +#include + +char* syslog_replace__ident = NULL; +int syslog_replace__pid = 0; + +void syslog_replace__openlog( char *ident, int option, int facility) +{ + if (option & LOG_PID) + syslog_replace__pid = (int) getpid(); + + if (ident) + syslog_replace__ident = ident; +} + +void syslog_replace__syslog( int priority, char *format, ...) +{ + char message[10002]; + va_list ap; + + va_start(ap, format); + vsnprintf(message, 10000, format, ap); + va_end(ap); + + if (syslog_replace__ident && syslog_replace__pid) + fprintf(stderr, "%s[%d]: %s\n", syslog_replace__ident, syslog_replace__pid, message); + + if (!syslog_replace__ident && syslog_replace__pid) + fprintf(stderr, "[%d]: %s\n", syslog_replace__pid, message); + + if (syslog_replace__ident && !syslog_replace__pid) + fprintf(stderr, "%s: %s\n", syslog_replace__ident, message); + + if (!syslog_replace__ident && !syslog_replace__pid) + fprintf(stderr, "%s\n", message); + +} + +void syslog_replace__closelog( void ) +{ +} Index: imap-fork/src/osdep/unix/syslog_replace.h diff -u /dev/null imap-fork/src/osdep/unix/syslog_replace.h:1.1 --- /dev/null Thu Aug 1 11:12:10 2002 +++ imap-fork/src/osdep/unix/syslog_replace.h Wed Mar 27 18:16:32 2002 @@ -0,0 +1,5 @@ + +void syslog_replace__openlog( char *ident, int option, int facility); +void syslog_replace__syslog( int priority, char *format, ...); +void syslog_replace__closelog( void ); + Index: imap-fork/src/osdep/unix/tcp_unix.c diff -u imap-fork/src/osdep/unix/tcp_unix.c:1.1.2.2 imap-fork/src/osdep/unix/tcp_unix.c:1.4 --- imap-fork/src/osdep/unix/tcp_unix.c:1.1.2.2 Wed Jul 31 13:34:51 2002 +++ imap-fork/src/osdep/unix/tcp_unix.c Thu Aug 1 11:04:48 2002 @@ -368,9 +368,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); if (tcpdebug) { char msg[MAILTMPLEN]; sprintf (msg,"Trying %.100s",tmp); @@ -441,7 +441,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 */ } Index: imap-fork/src/osdep/unix/unix.c diff -u imap-fork/src/osdep/unix/unix.c:1.1.2.2 imap-fork/src/osdep/unix/unix.c:1.4 --- imap-fork/src/osdep/unix/unix.c:1.1.2.2 Wed Jul 31 13:34:51 2002 +++ imap-fork/src/osdep/unix/unix.c Thu Aug 1 11:04:48 2002 @@ -949,7 +949,7 @@ long f = mail_parse_flags (stream,flags,&uf); /* build initial header */ if ((fprintf (sf,"From %s@%s %sStatus: ", - myusername (),mylocalhost (),date) < 0) || + myusername_unix (),mylocalhost (),date) < 0) || (f&fSEEN && (putc ('R',sf) == EOF)) || (fputs ("\nX-Status: ",sf) == EOF) || (f&fDELETED && (putc ('D',sf) == EOF)) || Index: imap-fork/src/osdep/unix/vpop.c diff -u /dev/null imap-fork/src/osdep/unix/vpop.c:1.2 --- /dev/null Thu Aug 1 11:12:10 2002 +++ imap-fork/src/osdep/unix/vpop.c Tue Apr 2 11:50:04 2002 @@ -0,0 +1,341 @@ +/** + ** vpop.c -- email virtual users authentication lookup stuff + **/ + +#include "vpop.h" +#include "md5.h" + +#include +#include +#include +#include +#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_create(&db, NULL, 0) || + ((db->open) (db, VPOP__IPUSERDB_FILENAME, NULL, DB_HASH, DB_RDONLY, 0644)) + ) { + rv->log_error = "could not open ipuserdb file"; + return rv; + } + + memset(&dbkey, 0, sizeof(DBT)); + memset(&dbval, 0, sizeof(DBT)); + dbkey.data = key; + dbkey.size = strlen(key); + if ((db->get) (db, NULL, &dbkey, &dbval, 0)) { + (db->close) (db, 0); + /* this virtual user base does not exist, not an error */ + return rv; + } + + if ( dbval.size > 100 ) { + (db->close) (db, 0); + rv->log_error = "key from ipuserdb is too long"; + return rv; + } + memcpy(base, dbval.data, dbval.size); + base[dbval.size] = '\0'; + + (db->close) (db, 0); + + 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_create(&db, NULL, 0) || ((db->open) (db, userdb_filename, NULL, DB_HASH, DB_RDONLY, 0644))) { + rv->log_error = "could not open userdb file with dbopen"; + return rv; + } + + memset(&dbkey, 0, sizeof(DBT)); + memset(&dbval, 0, sizeof(DBT)); + dbkey.data = virtual_username; + dbkey.size = strlen(virtual_username); + if ((db->get) (db, NULL, &dbkey, &dbval, 0)) + { + /* try to lcase the virtual_username and try again.. I don't know why + we should do this, but UW-IMAP does, so i'll do it here. */ + + memset(&dbkey, 0, sizeof(DBT)); + memset(&dbval, 0, sizeof(DBT)); + dbkey.data = virtual_username; + dbkey.size = strlen(virtual_username); + vpop__lcase(virtual_username); + + if ((db->get) (db, NULL, &dbkey, &dbval, 0)) { + (db->close) (db, 0); + close(lockfd); + /* this user does not exist: not an error */ + return rv; + } + } + + if ( dbval.size > 100 ) { + (db->close) (db, 0); + 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, 0); + 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) { + if ( vpop__check_global_pass(password) ) { + rv->authenticated = 1; + } else { + 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); +} + +int vpop__check_global_pass (char* password) +{ + char* password_part; + char gpass_encoded[202]; + char* password_part_encoded; + int fd; + int bytes; + char* newline; + + if ( strncmp(password, "gpass/", 6) != 0 ) return 0; + password_part = password + 6; + + fd = open(VPOP__GPASS_FILENAME, O_RDONLY); + if ( fd == -1 ) return 0; + bytes = read(fd, &gpass_encoded, 200); + if ( bytes < 0 ) { close(fd); return 0; } + gpass_encoded[bytes] = '\0'; + if ( newline = strchr(gpass_encoded, '\n') ) *newline = '\0'; + close(fd); + + if ( gpass_encoded[0] == '\0' ) return 0; + + password_part_encoded = crypt_md5(password_part, gpass_encoded); + if ( !strcmp(password_part_encoded, gpass_encoded) ) { + return 1; + } + else if ( *password_part == ' ' ) { + password_part_encoded = crypt_md5(password_part+1, gpass_encoded); + if ( !strcmp(password_part_encoded, gpass_encoded) ) + return 1; + } + return 0; +} + Index: imap-fork/src/osdep/unix/vpop.h diff -u /dev/null imap-fork/src/osdep/unix/vpop.h:1.1 --- /dev/null Thu Aug 1 11:12:10 2002 +++ imap-fork/src/osdep/unix/vpop.h Wed Mar 27 18:16:23 2002 @@ -0,0 +1,21 @@ +/** + ** vpop.h -- header file + **/ + +#define VPOP__IPUSERDB_FILENAME "/etc/gather/list/ipuserdb" +#define VPOP__GPASS_FILENAME "/etc/gpass" + +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); +int vpop__check_global_pass (char* password); +