1 /************************************************************************
2  *	Modify to taste in order to comply with your authentication	*
3  *	(e.g. Radius or shadow passwd) and mailbox conventions		*
4  *									*
5  *	You have the liberty to redefine the identity typedef in	*
6  *	any way you see fit, so that it can hold state information	*
7  *	you need to authenticate your users				*
8  *									*
9  *	Copyright (c) 1996-1997, S.R. van den Berg, The Netherlands	*
10  *	Copyright (c) 1999-2001, Philip Guenther, The United States	*
11  *						of America		*
12  *	#include "../README" or "README"				*
13  ************************************************************************/
14 #ifdef RCS
15 static /*const*/char rcsid[]=
16  "$Id: authenticate.c,v 1.10 2001/06/27 17:07:19 guenther Exp $";
17 #endif
18 
19 #ifdef PROCMAIL
20 #include "includes.h"
21 #include "robust.h"
22 #include "shell.h"
23 #include "misc.h"
24 #else
25 #include "config.h"
26 
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <pwd.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #define bbzero(s,l)	memset(s,'\0',l)
33 
34 #ifdef SHADOW_PASSWD
35 #include <shadow.h>
36 #endif
37 #endif /* PROCMAIL */
38 
39 #include "authenticate.h"
40 
41 #ifndef MAILSPOOLDIR
42 #define MAILSPOOLDIR	"/var/spool/mail/"	     /* watch the trailing / */
43 #endif
44 #ifndef MAILSPOOLSUFFIX
45 #define MAILSPOOLSUFFIX ""	      /* suffix to force maildir or MH style */
46 #endif
47 #ifndef MAILSPOOLHASH
48 #define MAILSPOOLHASH	0      /* 2 would deliver to /var/spool/mail/b/a/bar */
49 #endif
50 /*#define MAILSPOOLHOME "/.mail"		      /* watch the leading / */
51 						  /* delivers to $HOME/.mail */
52 #define STRLEN(x)	(sizeof(x)-1)
53 
54 struct auth_identity
55 { const struct passwd*pw;
56   char*mbox;
57   int sock;
58 };
59 
60 static auth_identity authi;		      /* reuse copy, only one active */
61 
castlower(str)62 static void castlower(str)register char*str;   /* and I'll take the low road */
63 { for(;*str;str++)
64      if((unsigned)*str-'A'<='Z'-'A')		     /* uppercase character? */
65 	*str+='a'-'A';				     /* cast it to lowercase */
66 }
67 
cgetpwnam(user,sock)68 static const struct passwd*cgetpwnam(user,sock)const char*const user;
69  const int sock;
70 { return getpwnam(user);	       /* this should be selfexplanatory :-) */
71 }
72 
cgetpwuid(uid,sock)73 static const struct passwd*cgetpwuid(uid,sock)const uid_t uid;const int sock;
74 { return getpwuid(uid);					       /* no comment */
75 }
76 
auth_finduser(user,sock)77 /*const*/auth_identity*auth_finduser(user,sock)char*const user;const int sock;
78 { if(!(authi.pw=cgetpwnam(user,sock)))		  /* /etc/passwd user lookup */
79    { char*p;
80      if(p=strchr(user,'@'))		  /* does the username contain an @? */
81 	*p='\0';		      /* clueless user using the mailaddress */
82      castlower(user);	      /* make it all lowercase (luser problem no. 1) */
83      if(!(authi.pw=cgetpwnam(user,sock)))	/* ok, be nice and try again */
84 	return 0;		       /* sorry, no such user on this planet */
85    }
86   authi.sock=sock;  /* save the filedescriptor for virtual server separation */
87   if(authi.mbox)			  /* any old mailbox reference left? */
88      free(authi.mbox),authi.mbox=0;		      /* clear the reference */
89   return &authi;					       /* user found */
90 }
91 
auth_finduid(uid,sock)92 /*const*/auth_identity*auth_finduid(uid,sock)const uid_t uid;const int sock;
93 { if(!(authi.pw=cgetpwuid(uid,sock)))		  /* /etc/passwd user lookup */
94      return 0;							     /* nada */
95   authi.sock=sock;		    /* save filedescriptor for later perusal */
96   if(authi.mbox)				   /* old mailbox reference? */
97      free(authi.mbox),authi.mbox=0;		/* nix old mailbox reference */
98   return &authi;					       /* user found */
99 }
100 
101 #ifndef PROCMAIL
auth_checkpassword(pass,pw,allowemptypw)102 int auth_checkpassword(pass,pw,allowemptypw)const auth_identity*const pass;
103  const char*const pw;const int allowemptypw;
104 { const char*rpw;
105   rpw=pass->pw->pw_passwd;	     /* get the regular (encrypted) password */
106 #ifdef SHADOW_PASSWD
107   ;{ struct spwd*spwd;
108      if(spwd=getspnam(pass->pw->pw_name))	     /* any shadow password? */
109 	rpw=spwd->sp_pwdp;			 /* override the regular one */
110    }
111 #endif
112   if(!*rpw)					     /* empty password found */
113      return allowemptypw;			    /* should we allow this? */
114   return !strcmp(rpw,crypt(pw,rpw));		    /* compare the passwords */
115 }
116 
auth_getsecret(pass)117 const char*auth_getsecret(pass)const auth_identity*const pass;
118 { return 0;	       /* no standard way to get a secret, add function here */
119 }
120 #else /* PROCMAIL */
auth_newid(void)121 auth_identity*auth_newid P((void))
122 { auth_identity*pass;		   /* create a new auth_identity placeholder */
123   (pass=malloc(sizeof*pass))->pw=0;pass->mbox=0;return pass;
124 }
125 
auth_copyid(newpass,oldpass)126 void auth_copyid(newpass,oldpass)auth_identity*newpass;
127  const auth_identity*oldpass;
128 { struct passwd*np;const struct passwd*op;
129   if(newpass->mbox)
130      free(newpass->mbox),newpass->mbox=0;
131   newpass->sock=oldpass->sock;
132   if(!(np=(struct passwd*)newpass->pw))
133    { np=(struct passwd*)(newpass->pw=malloc(sizeof*np));
134      bbzero(np,sizeof*np);
135    }
136   np->pw_uid=(op=oldpass->pw)->pw_uid;np->pw_gid=op->pw_gid;
137   np->pw_name=cstr(np->pw_name,op->pw_name);
138   np->pw_dir=cstr(np->pw_dir,op->pw_dir);
139   np->pw_shell=cstr(np->pw_shell,op->pw_shell);
140 #ifndef NOpw_passwd
141   if(op->pw_passwd)
142      bbzero(op->pw_passwd,strlen(op->pw_passwd));
143 #endif
144 }
145 
auth_zeroout(pass)146 static void auth_zeroout(pass)auth_identity*pass;
147 { struct passwd*p;
148   if(p=(struct passwd*)pass->pw)
149    { bbzero(p->pw_name,strlen(p->pw_name));
150 #ifndef NOpw_passwd
151      if(p->pw_passwd)bbzero(p->pw_passwd,strlen(p->pw_passwd));
152 #endif
153 #ifndef NOpw_class
154      if(p->pw_class)bbzero(p->pw_class,strlen(p->pw_class));
155 #endif
156 #ifndef NOpw_gecos
157      if(p->pw_gecos)bbzero(p->pw_gecos,strlen(p->pw_gecos));
158 #endif
159      bbzero(p->pw_dir,strlen(p->pw_dir));
160      bbzero(p->pw_shell,strlen(p->pw_shell));
161      bbzero(p,sizeof(*p));
162    }
163   if(pass->mbox)
164      bbzero(pass->mbox,strlen(pass->mbox));
165 }
166 
auth_freeid(pass)167 void auth_freeid(pass)auth_identity*pass;
168 { struct passwd*p;
169   auth_zeroout(pass);
170   if(p=(struct passwd*)pass->pw)
171      free(p->pw_name),free(p->pw_dir),free(p->pw_shell),free(p);
172   if(pass->mbox)
173      free(pass->mbox);
174   free(pass);
175 }
176 
auth_filledid(pass)177 int auth_filledid(pass)const auth_identity*pass;
178 { return !!pass->pw;
179 }
180 #endif /* PROCMAIL */
181 
auth_mailboxname(pass)182 const char*auth_mailboxname(pass)auth_identity*const pass;
183 { if(!pass->mbox)
184 #ifdef MAILSPOOLHOME
185    { static const char mailfile[]=MAILSPOOLHOME;size_t i;
186      if(!(pass->mbox=malloc((i=strlen(pass->pw->pw_dir))+STRLEN(mailfile)+1)))
187 	return "";
188      strcpy(pass->mbox,pass->pw->pw_dir);
189      strcpy(pass->mbox+i,mailfile);
190 #else
191    { static const char mailspooldir[]=MAILSPOOLDIR;
192      if(!(pass->mbox=malloc(STRLEN(mailspooldir)+MAILSPOOLHASH*2+
193       strlen(pass->pw->pw_name)+1+STRLEN(MAILSPOOLSUFFIX))))
194 	return "";
195      strcpy(pass->mbox,mailspooldir);
196      ;{ char*p,*n;size_t i;int c;
197 	for(p=pass->mbox+STRLEN(mailspooldir),n=pass->pw->pw_name,
198 	 i=MAILSPOOLHASH;i--;*p++='/')
199 	 { if(*n)
200 	      c= *n++;
201 	   *p++=c;
202 	 }
203 	strcpy(p,pass->pw->pw_name);
204 	if(STRLEN(MAILSPOOLSUFFIX))
205 	   strcat(p,MAILSPOOLSUFFIX);
206       }
207 #endif /* MAILSPOOLHOME */
208    }
209   return pass->mbox;
210 }
211 
auth_whatuid(pass)212 uid_t auth_whatuid(pass)const auth_identity*const pass;
213 { return pass->pw->pw_uid;
214 }
215 
auth_whatgid(pass)216 uid_t auth_whatgid(pass)const auth_identity*const pass;
217 { return pass->pw->pw_gid;
218 }
219 
auth_homedir(pass)220 const char*auth_homedir(pass)const auth_identity*const pass;
221 { return pass->pw->pw_dir;
222 }
223 
auth_shell(pass)224 const char*auth_shell(pass)const auth_identity*const pass;
225 { return pass->pw->pw_shell;
226 }
227 
auth_username(pass)228 const char*auth_username(pass)const auth_identity*const pass;
229 { return pass->pw->pw_name;
230 }
231 
auth_end(void)232 void auth_end P((void))
233 { auth_zeroout(&authi);
234   if(authi.mbox)
235      free(authi.mbox),authi.mbox=0;	    /* discard the mailbox reference */
236   endpwent();
237 #ifdef SHADOW_PASSWD
238   endspent();
239 #endif
240 }
241