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