diff -Nru imap-2000c.orig/Makefile imap-2000c-vpop.compile/Makefile --- imap-2000c.orig/Makefile Tue Jan 23 21:50:36 2001 +++ imap-2000c-vpop.compile/Makefile Mon Jul 16 15:29:42 2001 @@ -291,7 +291,20 @@ SPECIALS=GSSDIR=$(GSSDIR) # *** TEMPORARY FOR PINE BUILD *** - +# VPOP=´type´ +# Compiles with support for vpop. The type specifies which +# vpop implementation to use. Right now the only implementation is +# ´´extmakemap´´. +VPOP= +# ´extmakemap´ VPOP data +VPOP_EXTMAKEMAP_SRC=vpop_extmakemap.c + +ifeq ($(VPOP),extmakemap) + VPOP_SRC=$(VPOP_EXTMAKEMAP_SRC) +else + VPOP_SRC= +endif + # Normal commands CAT=cat @@ -304,7 +317,7 @@ SYSTEM=unix TOOLS=tools TOUCH=touch - +CP=cp -f # Primary build command @@ -421,6 +434,9 @@ an ua: @echo Applying $@ process to sources... +ifdef VPOP + $(CP) src/osdep/$(SYSTEM)/$(VPOP_SRC) src/osdep/$(SYSTEM)/vpop.c +endif $(TOOLS)/$@ "$(LN)" src/c-client c-client $(TOOLS)/$@ "$(LN)" src/ansilib c-client $(TOOLS)/$@ "$(LN)" src/charset c-client @@ -430,6 +446,7 @@ $(TOOLS)/$@ "$(LN)" src/ipopd ipopd $(TOOLS)/$@ "$(LN)" src/imapd imapd $(LN) $(TOOLS)/$@ . + build: OSTYPE rebuild rebuildclean bundled @@ -442,7 +459,7 @@ EXTRAAUTHENTICATORS='$(EXTRAAUTHENTICATORS)'\ SPECIALAUTHENTICATORS='$(SPECIALAUTHENTICATORS)'\ PASSWDTYPE=$(PASSWDTYPE)\ - $(SPECIALS) $(EXTRASPECIALS) + $(SPECIALS) $(EXTRASPECIALS) VPOP=$(VPOP) echo $(OS) > OSTYPE $(TOUCH) rebuild @@ -465,6 +482,7 @@ @echo Removing old processed sources and binaries... sh -c '$(RM) an ua OSTYPE c-client mtest imapd ipopd || true' $(CD) tools;$(MAKE) clean + sh -c '$(RM) src/osdep/$(SYSTEM)/vpop.c || true' # A monument to a hack of long ago and far away... diff -Nru imap-2000c.orig/docs/vpop.txt imap-2000c-vpop.compile/docs/vpop.txt --- imap-2000c.orig/docs/vpop.txt Wed Dec 31 21:00:00 1969 +++ imap-2000c-vpop.compile/docs/vpop.txt Mon Jul 16 15:01:52 2001 @@ -0,0 +1,156 @@ +Suport for virtual domains / virtual users in imap toolkit + +INSTALATION +----------- + +To compile vpop support with imapd, do: +$ make VPOP= + +where system is your default system +(e.g. lnp, slx, ...) + +and vpop_type is what vpop interface to use. +the only type right now is extmakemap. +For more info about extmakemap see the vpop_extmakemap.txt file. + +So, to compile in a Linux system with PAM support +the extmakemap vpop type, you should call: + +$ make lnp VPOP=extmakemap + +The vpop implementation was designed in a way to not interfere in a regular +imap toolkit compile. + +So if the VPOP= part is not specified, imapd will build the same +binnary as without the patch. + + + +IMPLEMENTATION (developers) +--------------------------- + +The vpop can work in two ways. + +First as an authenticator where it uses a built-in authentication scheme and allow +non-system users email accounts using only one valid system accounts. + +The other way is as an user translator. Which allows the translation of a +specified username to a valid system user account. (hint, hint: virtual domains). + +To do this, you have to create a file named vpop_.c . + +and it has to contain at least two functions: +vpop__userauthen (which does the authentication/translation) and +vpop__free (which frees the memory used by vpop objects). + +the following notes were adpated from an email from David Harris : + + +---- begin interface description ----- + +Here is the relevant data from vpop.h: + +vpop__data* vpop__userauthen (char* username, char* password, char* + default_base_username); + +typedef struct { + int valid_form; + int valid_user; + char* unix_username; + char* virtual_username; + char* black_box_home; + char* translated_user; + int authenticated; + char* log_error; +} vpop__data; + +The function vpop__userauthen is called whenever a user is trying to +authenticate with the system. It is called _before_ any unix usernames are +checked. Depending on the values in the returned vpop__data structure, the +username and password will or will not be checked as a valid UNIX username. + +Here are the details... + +vpop__useauthen is called with, of course, the username and the password of +the user trying to connect. However "default_base_username" is a little +weird. If c-client is trying to login a user and it is not running as root +it will provide the username of the current user in default_base_username +here. If c-client is running as root, and can switch to any user then this +will e NULL. (You will not get a non-NULL value from imapd but rather from +tools like dmail in the imap-utils package. These tools are used for things +like local delivery and are already running as the correct UNIX user.) + +vpop__userauthen then gets to control what c-client does by the structure it +returns... here are what the values mean + +* valid_form specifies if the username looks like a virtual username. If +this is returned as true, c-client does not try to check the username and +password as a UNIX user. If valid_form is false, vpop__userauthen should set +it false and just return there. + +* valid_user specifies if this username is a valid username. This can only +be true if valid_form is true. + +* unix_username specifies the UNIX username that we should switch uid/gid +to when accessing the mail of the virtual user. + +* virtual_username specifies the virtual username of the virtual e-mail +account. Does not have to be a valid login user or anything. Not currently +used for anything. :-) + +* black_box_home specifies the directory where the e-mail for this user +will be stored. unix_username should have write permission here. The user is +locked down into this directory and now allowed to get mail from anywhere +else in the system. + +* authenticated specifies if the password was correct. Even if the supplied +password was incorrect vpop__userauthen is required to set the +unix_username, virtual_username, and black_box_home values. This is because +sometimes this information is needed without password authentication outside +of imapd, such as when dmail is used to deliver to a virtual e-mail user. + +* log_error is a string to log as an error. If this is not NULL, it will be +written to the standard c-client error reporting device. Inside of imapd +this will work its way into syslog. + +* translated_user should return NULL, unless the vpop implementaion is +being used just for translating the given username in a local valid username. + +---- end interface description ----- + +So, when adding a new interface to vpop, all that have to be done is: +create a new interface file vpop_.c + +and edit Makefile and src/osdep/unix/Makefile accordling (please just note +how extmakemaker was done). + +If VPOP is note passed to make during build time, the built binaries a +are exactly the ones without the vpop patch. + + + + +AUTHORS: +-------- + +David Harris is the original author o vpop and +implemented it. However he no longer have time to mantain it. + +David mantains info about his original patch and a maillist at +http://www.davideous.com + +Raul Dias update the patch to the latest imap version +and implement a few new capabilities like translating user interface. + +If you find bugs or problems with this. You should blame me at + and not the University of Washington neither Mark +Crisping. + + + +LICENSE: +-------- + +This patch has the same license as UW-IMAP toolkit itself. + + diff -Nru imap-2000c.orig/docs/vpop_extmakemap.txt imap-2000c-vpop.compile/docs/vpop_extmakemap.txt --- imap-2000c.orig/docs/vpop_extmakemap.txt Wed Dec 31 21:00:00 1969 +++ imap-2000c-vpop.compile/docs/vpop_extmakemap.txt Mon Jul 16 14:57:56 2001 @@ -0,0 +1,43 @@ + + Virtual Pop External Makemap implementation. + +To compile just: + +$make VPOP=extmakemap + +where system the system you use to compile the regular imapd. +e.g: $ make lnp VPOP=extmakemap + +The external makemap implementation implements a Virtual domain +support to the imapd toolkit using sendmail's makemap. + +So, when a user tries to authenticate using a name@domain format +it will run (securily) the command "/usr/bin/makemap -u hash /etc/mail/virtusertable.db" +and lookup the table for the user@domain key. + +If found, it returns the corresponding username to c-client as if the user had specified it. + +If not found, it will search for a @domain key, which is sendmail's generic domain account. +If found will try to authenticate with its account. + +If both failed. extmakemap will strip the @domain part from the user name and give it back +to c-client. + +If the client specifies a user without a @domain part it will not try to do a makemap lookup. + +The downside about reading the output of makemap is that a fork is generated in order to run +the makemap process each time a @domain is specified. + +Another solution for this is to read the virtusertable.db file directly, the problem with this +is that sendmail can be compiled with either: db1, db2, db3, smdb or ndbm. + +In linux it is usually compiled with db2 in glibc2.1 distributions and are being replaced +by db3 in glibc2.2 distributions. + +This means that the imap toolkit would have to be compiled with those libs in order to +read the database file. And in a upgrade, that might change again. + +You can mail any vpop's extmakemap related subject to me. + +Raul Dias + diff -Nru imap-2000c.orig/src/osdep/unix/Makefile imap-2000c-vpop.compile/src/osdep/unix/Makefile --- imap-2000c.orig/src/osdep/unix/Makefile Thu Feb 1 16:15:58 2001 +++ imap-2000c-vpop.compile/src/osdep/unix/Makefile Mon Jul 16 14:04:33 2001 @@ -25,6 +25,31 @@ EXTRADRIVERS=mbox PASSWDTYPE=std +VPOP= +# ´extmakemap´ VPOP data +VPOP_EXTMAKEMAP_SRC=vpop_extmakemap.c +VPOP_EXTMAKEMAP_OBJ=vpop.o +VPOP_EXTMAKEMAP_CFLAGS= -DVPOP +VPOP_EXTMAKEMAP_LDFLAGS= +VPOP_EXTMAKEMAP_DEPENDENCY=vpop.h + +ifeq ($(VPOP),extmakemap) + VPOP_SRC=$(VPOP_EXTMAKEMAP_SRC) + VPOP_OBJ=$(VPOP_EXTMAKEMAP_OBJ) + VPOP_CFLAGS=$(VPOP_EXTMAKEMAP_CFLAGS) + VPOP_LDFLAGS=$(VPOP_EXTMAKEMAP_LDFLAGS) + VPOP_DEPENDENCY=$(VPOP_EXTMAKEMAP_DEPENDENCY) + VPOP_SRC_FINAL=vpop.c +else + VPOP_SRC= + VPOP_OBJ= + VPOP_CFLAGS= + VPOP_LDFLAGS= + VPOP_DEPENDENCY= + VPOP_SRC_FINAL= +endif + + # Extended flags needed for non-standard passwd types. You may need to modify. @@ -91,7 +116,9 @@ 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_OBJ) + CFLAGS=-g CAT=cat @@ -99,7 +126,7 @@ MV=mv RM=rm -rf SH=sh - +CP=cp -f # Primary build command @@ -388,8 +415,8 @@ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ - BASECFLAGS="-g -fno-omit-frame-pointer -O6" \ - BASELDFLAGS="-lpam -ldl" + BASECFLAGS="-g -fno-omit-frame-pointer -O6 $(VPOP_CFLAGS)" \ + BASELDFLAGS="-lpam -ldl $(VPOP_LDFLAGS)" lnx: # Linux non-shadow passwords @echo You are building for traditional Linux *without* shadow @@ -401,7 +428,7 @@ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ - BASECFLAGS="-g -O" + BASECFLAGS="-g -O $(VPOP_CFLAGS) " lyn: # LynxOS $(BUILD) `$(CAT) SPECIALS` OS=$@ \ @@ -569,8 +596,8 @@ SPOOLDIR=/var/spool \ ACTIVEFILE=/var/lib/news/active \ RSHPATH=/usr/bin/rsh \ - BASECFLAGS="-g -fno-omit-frame-pointer -O6" \ - BASELDFLAGS="-lcrypt" + BASECFLAGS="-g -fno-omit-frame-pointer -O6 $(VPOP_CFLAGS)" \ + BASELDFLAGS="-lcrypt $(VPOP_LDFLAGS)" sl4: # Secure Linux using libc4 @echo You are building for libc4 versions of Secure Linux @@ -765,7 +792,6 @@ unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h utf8.o: mail.h misc.h osdep.h utf8.h - # OS-dependent osdep.o:mail.h misc.h env.h fs.h ftl.h nl.h tcp.h \ @@ -777,7 +803,7 @@ pmatch.c scandir.c setpgrp.c strerror.c truncate.c write.c \ memmove.c memmove2.c memset.c \ tz_bsd.c tz_nul.c tz_sv4.c \ - write.c \ + write.c $(VPOP_SRC_FINAL)\ strerror.c strpbrk.c strstr.c strtok.c strtoul.c \ OSCFLAGS `$(CAT) CCTYPE` -c `$(CAT) CFLAGS` `$(CAT) OSCFLAGS` -c osdep.c diff -Nru imap-2000c.orig/src/osdep/unix/env_unix.c imap-2000c-vpop.compile/src/osdep/unix/env_unix.c --- imap-2000c.orig/src/osdep/unix/env_unix.c Thu Dec 21 04:12:13 2000 +++ imap-2000c-vpop.compile/src/osdep/unix/env_unix.c Mon Jul 16 15:35:34 2001 @@ -21,7 +21,12 @@ #include #include #include - + +#ifdef VPOP +/* include the vpop header file */ +#include "vpop.h" +#endif + /* c-client environment parameters */ /* don't change these */ @@ -79,7 +84,16 @@ static int logtry = 3; /* number of server login tries */ /* block notification */ static blocknotify_t mailblocknotify = mm_blocknotify; - + +#ifdef VPOP +/* state variables for a vpop login */ +static char *vpop_virtualUsername = NIL; +static char *vpop_blackBoxHome = NIL; +static char *vpop_username = NIL; + +static char *myUserName_unix = NIL; /* UNIX user name (becuase myUserName could be vpop user) */ +#endif + /* UNIX namespaces */ /* personal mh namespace */ @@ -457,39 +471,73 @@ usr,ausr,tcp_clienthost ()); } } +#ifdef VPOP + 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); + /* our authentication user and username is the same */ + return pw_login (pw,pw->pw_name,pw->pw_name,pw->pw_dir,argc,argv); + } + /* check for translated username */ + if ( (! vpop->valid_form) && (vpop->translated_user) ) + user = cpystr(vpop->translated_user); + /* don't allow unix users which look like vpop users */ + if ( ! vpop->valid_form ) { /* ordinary password authentication */ - else if ((authuser && *authuser) ? - (((pw = getpwnam (strcpy (ausr,authuser))) || - (pw = getpwnam (lcase (ausr)))) && - (checkpw (pw,pwd,argc,argv) || - ((*pwd == ' ') && checkpw (getpwnam (ausr),pwd+1,argc,argv))) && - ((pw = getpwnam (strcpy (usr,user))) || - (pw = getpwnam (lcase (usr))))) : - (((pw = getpwnam (strcpy (ausr,user))) || - (pw = getpwnam (lcase (ausr)))) && - ((pw = checkpw (pw,pwd,argc,argv)) || - ((*pwd == ' ') && - (pw = checkpw (getpwnam(ausr),pwd+1,argc,argv)))))) - logpw = pw; - - if (logtry <= 0) /* excessive login failures */ - syslog (LOG_NOTICE|LOG_AUTH, - "Login attempt after lockout user=%.80s host=%.80s", - user,tcp_clienthost ()); - else if (!logpw) /* login failed */ - syslog (LOG_NOTICE|LOG_AUTH,"%s user=%.80s host=%.80s", - (logtry-- > 0) ? "Login failure" : "Excessive login attempts", - user,tcp_clienthost ()); + if +#else + else if +#endif + ((authuser && *authuser) ? + (((pw = getpwnam (strcpy (ausr,authuser))) || + (pw = getpwnam (lcase (ausr)))) && + (checkpw (pw,pwd,argc,argv) || + ((*pwd == ' ') && checkpw (getpwnam (ausr),pwd+1,argc,argv))) && + ((pw = getpwnam (strcpy (usr,user))) || + (pw = getpwnam (lcase (usr))))) : + (((pw = getpwnam (strcpy (ausr,user))) || + (pw = getpwnam (lcase (ausr)))) && + ((pw = checkpw (pw,pwd,argc,argv)) || + ((*pwd == ' ') && + (pw = checkpw (getpwnam(ausr),pwd+1,argc,argv)))))) + logpw = pw; + + if (logtry <= 0) /* excessive login failures */ + syslog (LOG_NOTICE|LOG_AUTH, + "Login attempt after lockout user=%.80s host=%.80s", + user,tcp_clienthost ()); + else if (!logpw) /* login failed */ + syslog (LOG_NOTICE|LOG_AUTH,"%s user=%.80s host=%.80s", + (logtry-- > 0) ? "Login failure" : "Excessive login attempts", + user,tcp_clienthost ()); #ifndef PLAINTEXT_DISABLED /* validate with authentication ID */ - else if (pw_login (pw,ausr,pw->pw_name,pw->pw_dir,argc,argv)) return T; + else if (pw_login (pw,ausr,pw->pw_name,pw->pw_dir,argc,argv)) return T; #endif + +#ifdef VPOP + } + /* free vpop data */ + vpop__freedata(vpop); +#endif + sleep (3); /* slow down possible cracker */ + return NIL; +#ifdef VPOP + } +#endif } - sleep (3); /* slow down possible cracker */ - 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 @@ -584,9 +632,19 @@ struct passwd *pw; struct stat sbuf; char tmp[MAILTMPLEN]; +#ifdef VPOP + short vpop_home_flag = 0; + DRIVER *d; +#endif if (myUserName) fatal ("env_init called twice!"); /* myUserName must be set before dorc() call */ +#ifdef VPOP + myUserName_unix = cpystr (user ? user : (char *) anonymous_user); + myUserName = vpop_username ? cpystr(vpop_username) : myUserName_unix; +#else myUserName = cpystr (user ? user : (char *) anonymous_user); +#endif + if (closedBox) { /* closed box server */ /* standard user can only reference home */ if (user) nslist[0] = &nshome; @@ -605,19 +663,29 @@ dorc ("/etc/c-client.cf",NIL); if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME); if (user) { /* remember user name and home directory */ - if (blackBoxDir) { /* build black box directory name */ - sprintf (tmp,"%s/%s",blackBoxDir,myUserName); - /* if black box if exists and directory */ - if (home = (!stat (tmp,&sbuf) && (sbuf.st_mode & S_IFDIR)) ? - tmp : blackBoxDefaultHome) { - sysInbox = (char *) fs_get (strlen (home) + 7); - /* set system INBOX */ - sprintf (sysInbox,"%s/INBOX",home); - blackBox = T; /* mark that it's a black box */ - /* mbox meaningless if black box */ - mail_parameters (NIL,DISABLE_DRIVER,(void *) "mbox"); - } +#ifdef VPOP + if (vpop_blackBoxHome) { + myHomeDir = cpystr(vpop_blackBoxHome); + sprintf(tmp,"%s/INBOX",myHomeDir); + sysInbox = cpystr(tmp); + blackBox = T; } + else +#endif + if (blackBoxDir) { /* build black box directory name */ + sprintf (tmp,"%s/%s",blackBoxDir,myUserName); + /* if black box if exists and directory */ + if (home = (!stat (tmp,&sbuf) && (sbuf.st_mode & S_IFDIR)) ? + tmp : blackBoxDefaultHome) { + sysInbox = (char *) fs_get (strlen (home) + 7); + /* set system INBOX */ + sprintf (sysInbox,"%s/INBOX",home); + blackBox = T; /* mark that it's a black box */ + /* mbox meaningless if black box */ + mail_parameters (NIL,DISABLE_DRIVER,(void *) "mbox"); + } + } + if (blackBox) /* black box? */ nslist[0] = &nshome,nslist[1] = &nsblackother,nslist[2] = &nsshared; else { /* not a black box */ @@ -629,7 +697,15 @@ #else nslist[2] = &nsshared; /* what, me paranoid? */ #endif - /* make sure user rc files don't try this */ + +#ifdef VPOP + 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 ); + vpop_home_flag = 1; + /* make sure user rc files don't try this */ +#endif blackBoxDir = blackBoxDefaultHome = ""; } } @@ -642,9 +718,13 @@ if (!blackBoxDir) blackBoxDir = blackBoxDefaultHome = anonymousHome; } } - - /* use real home directory */ - myHomeDir = cpystr (home ? home : ANONYMOUSHOME); + + /* use real home directory */ +#ifdef VPOP + if (! vpop_home_flag) /* makes sure vpop hasn't done it before */ +#endif + myHomeDir = cpystr (home ? home : ANONYMOUSHOME); + dorc (strcat (strcpy (tmp,myHomeDir),"/.mminit"),T); dorc (strcat (strcpy (tmp,myHomeDir),"/.imaprc"),NIL); #ifndef DISABLE_AUTOMATIC_SHARED_NAMESPACES @@ -664,7 +744,16 @@ if (!newsActive) newsActive = cpystr (ACTIVEFILE); if (!newsSpool) newsSpool = cpystr (NEWSSPOOL); /* force default prototype to be set */ +#ifdef VPOP + /* 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; +#else if (!createProto) createProto = &CREATEPROTO; +#endif + if (!appendProto) appendProto = &EMPTYPROTO; /* re-do open action to get flags */ (*createProto->dtb->open) (NIL); @@ -679,6 +768,9 @@ char *myusername_full (unsigned long *flags) { +#ifdef VPOP + return myusername_full_backend(flags, NIL, NIL); +#else char *ret = (char *) unlogged_user; if (!myUserName) { /* get user name if don't have it yet */ struct passwd *pw; @@ -690,12 +782,113 @@ (pw->pw_uid == euid)) || (pw = getpwuid (euid)))) fatal ("Unable to look up user name"); /* init environment if not root */ - 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 */ + 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 */ + } + if (myUserName) { /* logged in? */ + if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN; + ret = myUserName; /* return user name */ + } + else if (flags) *flags = MU_NOTLOGGEDIN; + return ret; + +#endif +} + +#ifdef VPOP +/* 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; + struct stat sbuf; + 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 ( (! vpop->valid_form) && (vpop->translated_user) ) + new_username = cpystr(vpop->translated_user); + + 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 && + (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 */ + } } if (myUserName) { /* logged in? */ if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN; @@ -705,6 +898,17 @@ return ret; } +/* Returns username + * Returns: unix user name + */ + +char *myusername_unix () +{ + myusername_full(NIL); + return myUserName_unix ? myUserName_unix : ""; + +} +#endif /* Return my local host name * Returns: my local host name diff -Nru imap-2000c.orig/src/osdep/unix/env_unix.h imap-2000c-vpop.compile/src/osdep/unix/env_unix.h --- imap-2000c.orig/src/osdep/unix/env_unix.h Wed Dec 20 03:34:51 2000 +++ imap-2000c-vpop.compile/src/osdep/unix/env_unix.h Mon Jul 16 14:04:33 2001 @@ -35,6 +35,11 @@ void rfc822_fixed_date (char *date); long env_init (char *user,char *home); char *myusername_full (unsigned long *flags); +#ifdef VPOP +char *myusername_dologin (char* user, char** error); +char *myusername_full_backend (unsigned long *flags, char* new_username, char** error); +char *myusername_unix (); +#endif #define MU_LOGGEDIN 0 #define MU_NOTLOGGEDIN 1 #define MU_ANONYMOUS 2 diff -Nru imap-2000c.orig/src/osdep/unix/mmdf.c imap-2000c-vpop.compile/src/osdep/unix/mmdf.c --- imap-2000c.orig/src/osdep/unix/mmdf.c Tue Jan 16 19:42:29 2001 +++ imap-2000c-vpop.compile/src/osdep/unix/mmdf.c Mon Jul 16 15:27:37 2001 @@ -928,7 +928,13 @@ long f = mail_parse_flags (stream,flags,&uf); /* build initial header */ if ((fprintf (sf,"%sFrom %s@%s %sStatus: ", - mmdfhdr,myusername (),mylocalhost (),date) < 0) || + mmdfhdr, +#ifdef VPOP + myusername_unix(), +#else + myusername (), +#endif + mylocalhost (),date) < 0) || (f&fSEEN && (putc ('R',sf) == EOF)) || (fputs ("\nX-Status: ",sf) == EOF) || (f&fDELETED && (putc ('D',sf) == EOF)) || diff -Nru imap-2000c.orig/src/osdep/unix/tcp_unix.c imap-2000c-vpop.compile/src/osdep/unix/tcp_unix.c --- imap-2000c.orig/src/osdep/unix/tcp_unix.c Wed Nov 8 15:28:02 2000 +++ imap-2000c-vpop.compile/src/osdep/unix/tcp_unix.c Mon Jul 16 15:33:01 2001 @@ -356,9 +356,21 @@ if (*service == '*') /* build ssh command */ sprintf (tmp,sshcommand,sshpath,host, - mb->user[0] ? mb->user : myusername (),service + 1); + mb->user[0] ? mb->user : +#ifdef VPOP + myusername_unix (), +#else + myusername (), +#endif + service + 1); else sprintf (tmp,rshcommand,rshpath,host, - mb->user[0] ? mb->user : myusername (),service); + mb->user[0] ? mb->user : +#ifdef VPOP + myusername_unix(), +#else + myusername (), +#endif + service); for (i = 1,path = argv[0] = strtok (tmp," "); (i < MAXARGV) && (argv[i] = strtok (NIL," ")); i++); argv[i] = NIL; /* make sure argv tied off */ @@ -422,7 +434,12 @@ } (*bn) (BLOCK_NONE,NIL); /* return user name */ +#ifdef VPOP + strcpy (usrbuf,mb->user[0] ? mb->user : myusername_unix ()); +#else strcpy (usrbuf,mb->user[0] ? mb->user : myusername ()); +#endif + return stream; /* return success */ } diff -Nru imap-2000c.orig/src/osdep/unix/unix.c imap-2000c-vpop.compile/src/osdep/unix/unix.c --- imap-2000c.orig/src/osdep/unix/unix.c Tue Jan 16 19:42:18 2001 +++ imap-2000c-vpop.compile/src/osdep/unix/unix.c Mon Jul 16 15:21:01 2001 @@ -946,7 +946,12 @@ long f = mail_parse_flags (stream,flags,&uf); /* build initial header */ if ((fprintf (sf,"From %s@%s %sStatus: ", - myusername (),mylocalhost (),date) < 0) || +#ifdef VPOP + myusername_unix (), +#else + myusername (), +#endif + mylocalhost (),date) < 0) || (f&fSEEN && (putc ('R',sf) == EOF)) || (fputs ("\nX-Status: ",sf) == EOF) || (f&fDELETED && (putc ('D',sf) == EOF)) || diff -Nru imap-2000c.orig/src/osdep/unix/vpop.h imap-2000c-vpop.compile/src/osdep/unix/vpop.h --- imap-2000c.orig/src/osdep/unix/vpop.h Wed Dec 31 21:00:00 1969 +++ imap-2000c-vpop.compile/src/osdep/unix/vpop.h Mon Jul 16 14:04:33 2001 @@ -0,0 +1,20 @@ +/** + ** 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* translated_user; + 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); + diff -Nru imap-2000c.orig/src/osdep/unix/vpop_extmakemap.c imap-2000c-vpop.compile/src/osdep/unix/vpop_extmakemap.c --- imap-2000c.orig/src/osdep/unix/vpop_extmakemap.c Wed Dec 31 21:00:00 1969 +++ imap-2000c-vpop.compile/src/osdep/unix/vpop_extmakemap.c Mon Jul 16 14:04:33 2001 @@ -0,0 +1,176 @@ +/** + ** vpop.c -- email virtual users authentication lookup stuff + **/ + +#include "vpop.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "mail.h" +#include "misc.h" + +#define VPOP_MAX_SIZE 128 +#define VPOP_MAX_LINE 1024 +#define EXTERN_APP "/usr/bin/makemap" +#define EXTERN_APP_PARAM " -u hash /etc/mail/virtusertable" +#define MAKEMAP_FIELD_SEPARATOR "\t" + + +/* vpop__truncate + * truncates a string when a delimeter + * is found + */ +char* vpop__truncate ( char* string, char delimiter ) +{ + int i; + for (i = 0; i < strlen(string); i++) + if (string[i] == delimiter){ + string[i] = '\0'; + break; + } +} + +/* vpop__external_search + * searchs an external application for a realusername + * returns a pointer to the real username or NULL + * if not found + */ +char* vpop__external_search ( char* username, char* domain_name, vpop__data* rv ) +{ + FILE *extapp; + struct stat stat_app; + char line[VPOP_MAX_LINE]; + char possible_user[VPOP_MAX_SIZE]; + char original_user[VPOP_MAX_SIZE]; + int global_domain_flag = 0; + int user_match_flag = 0; + int size; + char* runapp; + char* key; + char* value; + char* user; + + strcpy(original_user, username); + size = strlen(username); + original_user[size] = '@'; + original_user[size + 1] = '\0'; + strcat(original_user, domain_name); + + if (stat(EXTERN_APP, &stat_app) == 0) + { + if ((S_ISREG(stat_app.st_mode) || S_ISLNK(stat_app.st_mode)) + &&( S_IXOTH & stat_app.st_mode)) + { + if ( (extapp = popen (EXTERN_APP EXTERN_APP_PARAM , "r")) != NULL ) + { + while ( (fgets (line, VPOP_MAX_LINE, extapp)) != NULL ) + { + key = strtok( line , MAKEMAP_FIELD_SEPARATOR ); + value = strtok( NULL , MAKEMAP_FIELD_SEPARATOR ); + vpop__truncate ( value, '\n' ); + + /* The global domain email */ + if ( ( *key == '@' ) && ( strcmp (++key, domain_name) == 0 ) ) + { + strcpy (possible_user, value); + global_domain_flag = 1; + } + else if ( strcmp (key, original_user) == 0 ) + { + strcpy (possible_user, value); + user_match_flag = 1; + break; + } + } + pclose (extapp); + if ( user_match_flag || global_domain_flag ) + { + user = cpystr(possible_user); + return user; + } + rv->log_error = "Did not found user in external application."; + }else + rv->log_error = "Could not execute " EXTERN_APP; + }else + rv->log_error = EXTERN_APP " is not executable."; + }else + rv->log_error = "Could not stat " EXTERN_APP; + return NULL; +} + + +/* Virtual pop authentication + * In this sample code the username is converted to + * lowercase and the domain part @domain is striped (if any). + * The real authentication will go to the c-client itself. + */ +vpop__data* vpop__userauthen (char* username, char* password, char* default_base_username) +{ + vpop__data* rv; + char* domain_p; + char* domain_name; + char* final_user; + char real_username[VPOP_MAX_SIZE]; + + /* + * Copy the username and prepare the return structure + * Returning rv like this we make c-client authenticate + * the user in the default way. + */ + + 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; + rv->translated_user = NULL; + + if (VPOP_MAX_SIZE < strlen(username)){ + rv->log_error = "username is too big."; + return rv; + } + + lcase(username); + vpop__truncate(username, ' '); + + /* Now we check if there is an ´@´ in the username + * and strip it + */ + if ((domain_p = strchr(username,'@')) != NULL) { + + /* separate the username from the domain name */ + strncpy( real_username, username, (domain_p - username)); + real_username[domain_p - username] = '\0'; + domain_name = cpystr(++domain_p); + + /* searchs for it is an external application */ + if ( ( final_user = vpop__external_search(real_username, domain_name, rv) ) == NULL ) + final_user = cpystr(real_username); + + }else + final_user = cpystr(username); + + rv->translated_user = final_user; + return rv; +} + +/* vpop__freedata + * clears the memory from a vpop__data structure + */ +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); + if (rv->translated_user) free(rv->translated_user); + free(rv); +} +