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
15static /*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
54struct auth_identity
55{ const struct passwd*pw;
56  char*mbox;
57  int sock;
58};
59
60static auth_identity authi;		      /* reuse copy, only one active */
61
62static 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
68static const struct passwd*cgetpwnam(user,sock)const char*const user;
69 const int sock;
70{ return getpwnam(user);	       /* this should be selfexplanatory :-) */
71}
72
73static const struct passwd*cgetpwuid(uid,sock)const uid_t uid;const int sock;
74{ return getpwuid(uid);					       /* no comment */
75}
76
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
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
102int 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
117const 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 */
121auth_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
126void 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
146static 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
167void 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
177int auth_filledid(pass)const auth_identity*pass;
178{ return !!pass->pw;
179}
180#endif /* PROCMAIL */
181
182const 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
212uid_t auth_whatuid(pass)const auth_identity*const pass;
213{ return pass->pw->pw_uid;
214}
215
216uid_t auth_whatgid(pass)const auth_identity*const pass;
217{ return pass->pw->pw_gid;
218}
219
220const char*auth_homedir(pass)const auth_identity*const pass;
221{ return pass->pw->pw_dir;
222}
223
224const char*auth_shell(pass)const auth_identity*const pass;
225{ return pass->pw->pw_shell;
226}
227
228const char*auth_username(pass)const auth_identity*const pass;
229{ return pass->pw->pw_name;
230}
231
232void 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