/************************************************************************
* 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 <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif
#ifdef PROCMAIL
#include "includes.h"
#include "robust.h"
#include "shell.h"
#include "misc.h"
#else
#include "config.h"
#define _XOPEN_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <string.h>
#include <stdlib.h>
#ifdef SHADOW_PASSWD
#include <shadow.h>
#endif
#endif /* PROCMAIL */
#include "authenticate.h"
#define VIRTUALSERVER /**/
#ifndef SENDMAILLIB
#define SENDMAILLIB "/etc/mail"
#endif
#define VIRTUALHOSTDB "vpop.db"
#define VIRTUALUSER "vpop"
#ifndef MAILSPOOLDIR
#define MAILSPOOLDIR "/var/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 <netdb.h>
#include <netinet/in.h>
#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
}
syntax highlighted by Code2HTML, v. 0.9.1