File: authenticate.c

package info (click to toggle)
cucipop 1.31-15.8
  • links: PTS
  • area: non-free
  • in suites: woody
  • size: 296 kB
  • ctags: 394
  • sloc: ansic: 2,380; sh: 176; makefile: 100
file content (305 lines) | stat: -rw-r--r-- 9,257 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/************************************************************************
 *	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 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	/**/

#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 <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;
{ struct sockaddr_in sockname;int namelen=sizeof sockname;const char*retval="";
  if(!getsockname(sock,(struct sockaddr*)&sockname,&namelen))
   { const struct hostent*hent=
      gethostbyaddr((void*)&sockname.sin_addr.s_addr,sizeof sockname.sin_addr,
       sockname.sin_family);
     if(hent)
	retval=hent->h_name;
   }
  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
}