/************************************************************************ * Modify to taste in order to comply with your authentication * * (e.g. Radius or shadow passwd) and mailbox conventions * * * * You have the liberty to redefine the identity typedef in * * any way you see fit, so that it can hold state information * * you need to authenticate your users * * * * Copyright (c) 1996-1997, S.R. van den Berg, The Netherlands * * #include "../README" or "README" * ************************************************************************/ #ifdef RCS static /*const*/char rcsid[]= "$Id: authenticate.c,v 1.19 1998/05/13 16:57:39 srb Exp $"; #endif #ifdef INET6 #include #include #include #endif #ifdef PROCMAIL #include "includes.h" #include "robust.h" #include "shell.h" #include "misc.h" #else #include "config.h" #define _XOPEN_SOURCE #include #include #include #include #include #ifdef SHADOW_PASSWD #include #endif #endif /* PROCMAIL */ #include "authenticate.h" #define VIRTUALSERVER /**/ #define SENDMAILLIB "/etc/mail" #define VIRTUALHOSTDB "vpop.db" #define VIRTUALUSER "vpop" #ifndef MAILSPOOLDIR #define MAILSPOOLDIR "/var/spool/mail/" /* watch the trailing / */ #endif #ifndef MAILSPOOLHASH #define MAILSPOOLHASH 0 /* 2 would deliver to /var/spool/mail/b/a/bar */ #endif /*#define MAILSPOOLHOME "/.mail" /* watch the leading / */ /* delivers to $HOME/.mail */ #ifdef VIRTUALSERVER #include #include #include "sdb.h" #include "simplecrypt.h" const char virtualhostdb[]=SENDMAILLIB"/"VIRTUALHOSTDB, virtualuser[]=VIRTUALUSER; #endif /* VIRTUALSERVER */ #define STRLEN(x) (sizeof(x)-1) struct auth_identity { const struct passwd*pw; char*mbox,*usersecret; int sock; }; char*auth_logname; static auth_identity authi; /* reuse copy, only one active */ static void castlower(str)register char*str; /* and I'll take the low road */ { for(;*str;str++) if((unsigned)*str-'A'<='Z'-'A') /* uppercase character? */ *str+='a'-'A'; /* cast it to lowercase */ } static void getlogname(user,sock)const char*user;const int sock; { #ifdef INET6 static char hbuf[NI_MAXHOST]; struct sockaddr_storage sockname; #ifdef NI_WITHSCOPEID const int niflags = NI_NAMEREQD | NI_WITHSCOPEID; #else const int niflags = NI_NAMEREQD; #endif #else struct sockaddr_in sockname; #endif int namelen=sizeof sockname;const char*retval=""; if(!getsockname(sock,(struct sockaddr*)&sockname,&namelen)) { #ifdef INET6 if (getnameinfo((struct sockaddr *)&sockname, namelen, hbuf, sizeof(hbuf), NULL, 0, niflags) == 0) { retval = hbuf; } #else const struct hostent*hent= gethostbyaddr((void*)&sockname.sin_addr.s_addr,sizeof sockname.sin_addr, sockname.sin_family); if(hent) retval=hent->h_name; #endif } if(auth_logname= /* memory leak when out of memory */ realloc(auth_logname,(namelen=strlen(retval))+1+strlen(user)+1)) { strcpy(auth_logname,retval)[namelen]='/'; strcpy(auth_logname+namelen+1,user); } } static const struct passwd*cgetpwnam(user,sock)const char*user; const int sock; { #ifdef VIRTUALSERVER DB_ENV dbenv;DB*db; memset(&dbenv,0,sizeof dbenv); if(!db_appinit(0,0,&dbenv,0)) { if(!db_open(virtualhostdb,DB_HASH,DB_RDONLY,0666,&dbenv,(void*)0,&db)) { getlogname(user,sock); if(auth_logname) { DBT k,d;unsigned foundentry=1; memset(&k,0,sizeof k);memset(&d,0,sizeof d); k.size=strlen(k.data=auth_logname); if(db->get(db,0,&k,&d,0)) { k.size=strlen(strcpy(auth_logname,user)); foundentry=!db->get(db,0,&k,&d,0)<<1; /* fallback check */ } if(foundentry&&(authi.usersecret=malloc(d.size+1))) { scmorph(&k,&d);memcpy(authi.usersecret,d.data,d.size); authi.usersecret[d.size]='\0';memset(d.data,0,d.size); if(foundentry&2) goto freesec; else if(*authi.usersecret) /* no empty secrets allowed */ user=virtualuser; else freesec: { free(authi.usersecret);authi.usersecret=0; goto novirt; } } else novirt: strcpy(auth_logname,user); } db->close(db,0); } /* memory leak when out of memory */ else if(auth_logname=realloc(auth_logname,strlen(user)+1)) strcpy(auth_logname,user); /* DB doesn't exist */ db_appexit(&dbenv); } else /* DB subsystem problem */ { if(auth_logname=realloc(auth_logname,strlen(user)+1)) strcpy(auth_logname,user); } #endif return getpwnam(user); /* this should be selfexplanatory :-) */ } static const struct passwd*cgetpwuid(uid,sock)const uid_t uid;const int sock; { const struct passwd*pass; pass=getpwuid(uid); #ifdef VIRTUALSERVER ;{ const char*logname=pass->pw_name; if(pass&&!auth_logname&&(auth_logname=malloc(strlen(logname)))) strcpy(auth_logname,logname); } #endif return pass; } /*const*/auth_identity*auth_finduser(user,sock)char*const user;const int sock; { if(authi.usersecret) free(authi.usersecret),authi.usersecret=0; if(!(authi.pw=cgetpwnam(user,sock))) /* /etc/passwd user lookup */ { char*p; if(p=strchr(user,'@')) /* does the username contain an @? */ *p='\0'; /* clueless user using the mailaddress */ castlower(user); /* make it all lowercase (luser problem no. 1) */ if(!(authi.pw=cgetpwnam(user,sock))) /* ok, be nice and try again */ return 0; /* sorry, no such user on this planet */ } authi.sock=sock; /* save the filedescriptor for virtual server separation */ if(authi.mbox) /* any old mailbox reference left? */ free(authi.mbox),authi.mbox=0; /* clear the reference */ return &authi; /* user found */ } /*const*/auth_identity*auth_finduid(uid,sock)const uid_t uid;const int sock; { if(!(authi.pw=cgetpwuid(uid,sock))) /* /etc/passwd user lookup */ return 0; /* nada */ authi.sock=sock; /* save filedescriptor for later perusal */ if(authi.usersecret) free(authi.usersecret),authi.usersecret=0; if(authi.mbox) /* old mailbox reference? */ free(authi.mbox),authi.mbox=0; /* nix old mailbox reference */ return &authi; /* user found */ } #ifndef PROCMAIL int auth_checkpassword(pass,pw,allowemptypw)const auth_identity*const pass; const char*const pw;const int allowemptypw; { const char*rpw; rpw=pass->pw->pw_passwd; /* get the regular (encrypted) password */ #ifdef SHADOW_PASSWD ;{ struct spwd*spwd; if(spwd=getspnam(pass->pw->pw_name)) /* any shadow password? */ rpw=spwd->sp_pwdp; /* override the regular one */ } #endif if(!*rpw) /* empty password found */ return allowemptypw; /* should we allow this? */ return !strcmp(rpw,crypt(pw,rpw)); /* compare the passwords */ } const char*auth_getsecret(pass)const auth_identity*const pass; { return authi.usersecret; } int auth_checkvalidshell(pass)const auth_identity*const pass; { } #else /* PROCMAIL */ auth_identity*auth_newid P((void)) { auth_identity*pass; /* create a new auth_identity placeholder */ (pass=malloc(sizeof*pass))->pw=0;pass->mbox=0;return pass; } void auth_copyid(newpass,oldpass)auth_identity*newpass; const auth_identity*oldpass; { struct passwd*np;const struct passwd*op; if(newpass->mbox) free(newpass->mbox),newpass->mbox=0; newpass->sock=oldpass->sock; if(!(np=(struct passwd*)newpass->pw)) { np=(struct passwd*)(newpass->pw=malloc(sizeof*np)); np->pw_name=np->pw_dir=np->pw_shell=0; } np->pw_uid=(op=oldpass->pw)->pw_uid;np->pw_gid=op->pw_gid; np->pw_name=cstr(np->pw_name,op->pw_name); np->pw_dir=cstr(np->pw_dir,op->pw_dir); np->pw_shell=cstr(np->pw_shell,op->pw_shell); } void auth_freeid(pass)auth_identity*pass; { struct passwd*p; if(p=(struct passwd*)pass->pw) free(p->pw_name),free(p->pw_dir),free(p->pw_shell),free(p); if(pass->mbox) free(pass->mbox); free(pass); } int auth_filledid(pass)const auth_identity*pass; { return !!pass->pw; } #endif /* PROCMAIL */ const char*auth_mailboxname(pass)auth_identity*const pass; { if(!pass->mbox) #ifdef MAILSPOOLHOME { static const char mailfile[]=MAILSPOOLHOME;size_t i; if(!(pass->mbox=malloc((i=strlen(pass->pw->pw_dir))+STRLEN(mailfile)+1))) return ""; strcpy(pass->mbox,pass->pw->pw_dir); strcpy(pass->mbox+i,mailfile); #else { static const char mailspooldir[]=MAILSPOOLDIR;size_t servernlen; #ifdef VIRTUALSERVER char*logname=auth_logname; #else char*logname=pass->pw->pw_name; #endif if(!logname||!(pass->mbox=malloc(STRLEN(mailspooldir)+ MAILSPOOLHASH*2+strlen(logname)+1))) return ""; strcpy(pass->mbox,mailspooldir); ;{ char*p,*n;size_t i;int c; for(p=pass->mbox+STRLEN(mailspooldir),n=logname,i=MAILSPOOLHASH; i--; *p++='/') { if(*n) c= *n++; *p++=c; } strcpy(p,logname); } #endif /* MAILSPOOLHOME */ } return pass->mbox; } uid_t auth_whatuid(pass)const auth_identity*const pass; { return pass->pw->pw_uid; } uid_t auth_whatgid(pass)const auth_identity*const pass; { return pass->pw->pw_gid; } const char*auth_homedir(pass)const auth_identity*const pass; { return pass->pw->pw_dir; } const char*auth_shell(pass)const auth_identity*const pass; { return pass->pw->pw_shell; } const char*auth_username(pass)const auth_identity*const pass; { return auth_logname?auth_logname:pass->pw->pw_name; } void auth_end P((void)) { if(authi.mbox) free(authi.mbox),authi.mbox=0; /* discard the mailbox reference */ endpwent(); #ifdef SHADOW_PASSWD endspent(); #endif }