1 /* MODULE: auth_shadow */
2 
3 /* COPYRIGHT
4  * Copyright (c) 1997 Messaging Direct Ltd.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY MESSAGING DIRECT LTD. ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL MESSAGING DIRECT LTD. OR
20  * ITS EMPLOYEES OR AGENTS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27  * DAMAGE.
28  * END COPYRIGHT */
29 
30 #include <config.h>
31 
32 /* PUBLIC DEPENDENCIES */
33 #include "mechanisms.h"
34 #include <stdio.h>
35 
36 #ifdef AUTH_SHADOW
37 
38 #ifndef _XOPEN_SOURCE
39 #define _XOPEN_SOURCE
40 #endif
41 #define PWBUFSZ 256 /***SWB***/
42 
43 # include <unistd.h>
44 # include <stdlib.h>
45 # include <string.h>
46 # include <sys/types.h>
47 # include <time.h>
48 # include <pwd.h>
49 # include <errno.h>
50 # include <syslog.h>
51 
52 #ifdef HAVE_CRYPT_H
53 #include <crypt.h>
54 #endif
55 
56 # ifndef HAVE_GETSPNAM
57 
58 # ifdef WITH_DES
59 #  ifdef WITH_SSL_DES
60 #   include <openssl/des.h>
61 #  else
62 #   include <des.h>
63 #  endif /* WITH_SSL_DES */
64 # endif /* WITH_DES */
65 
66 # endif /* ! HAVE_GETSPNAM */
67 
68 # ifdef HAVE_GETUSERPW
69 #  include <userpw.h>
70 #  include <usersec.h>
71 # else /* ! HAVE_GETUSERPW */
72 #  include <shadow.h>
73 # endif /* ! HAVE_GETUSERPW */
74 
75 # ifdef HAVE_CRYPT_H
76 #  include <crypt.h>
77 # endif
78 
79 # include "auth_shadow.h"
80 # include "globals.h"
81 /* END PUBLIC DEPENDENCIES */
82 
83 /* FUNCTION: auth_shadow */
84 
85 /* SYNOPSIS
86  * Authenticate against the system shadow password database. Where
87  * possible (and if enabled by the command line arguments), enforce
88  * time-of-day and other login restrictions.
89  */
90 
91 char *					/* R: allocated response string */
auth_shadow(const char * login,const char * password,const char * service,const char * realm)92 auth_shadow (
93   /* PARAMETERS */
94   const char *login,			/* I: plaintext authenticator */
95   const char *password,			/* I: plaintext password */
96   const char *service __attribute__((unused)),
97   const char *realm __attribute__((unused))
98   /* END PARAMETERS */
99   )
100 {
101 
102 /************************************************************************
103  *									*
104  * This is gross. Everyone wants to do this differently, thus we have   *
105  * to #ifdef the whole mess for each system type.                       *
106  *									*
107  ***********************************************************************/
108 
109 # ifdef HAVE_GETSPNAM
110 
111  /***************
112  * getspnam_r() *
113  ***************/
114 
115     /* VARIABLES */
116     long today;				/* the current time */
117     char *cpw;				/* pointer to crypt() result */
118     struct passwd	*pw;		/* return from getpwnam_r() */
119     struct spwd   	*sp;		/* return from getspnam_r() */
120     int errnum;
121 #  ifdef _REENTRANT
122     struct passwd pwbuf;
123     char pwdata[PWBUFSZ];		/* pwbuf indirect data goes in here */
124 
125     struct spwd spbuf;
126     char spdata[PWBUFSZ];		/* spbuf indirect data goes in here */
127 
128     struct crypt_data cdata;
129 #  endif /* _REENTRANT */
130     /* END VARIABLES */
131 
132 #  define RETURN(x) return strdup(x)
133 
134     /*
135      * "Magic" password field entries for SunOS/SysV
136      *
137      * "*LK*" is defined at in the shadow(4) man page, but of course any string
138      * inserted in front of the password will prevent the strings from matching
139      *
140      * *NP* is documented in getspnam(3) and indicates the caller had
141      * insufficient permission to read the shadow password database
142      * (generally this is a NIS error).
143      */
144 
145 #  define SHADOW_PW_LOCKED "*LK*"	/* account locked (not used by us) */
146 #  define SHADOW_PW_EPERM  "*NP*"	/* insufficient database perms */
147 
148 #  ifdef _REENTRANT
149 #    ifdef GETXXNAM_R_5ARG
150 	(void) getpwnam_r(login, &pwbuf, pwdata, sizeof(pwdata), &pw);
151 #    else
152     pw = getpwnam_r(login, &pwbuf, pwdata, sizeof(pwdata));
153 #    endif /* GETXXNAM_R_5ARG */
154 #  else
155     pw = getpwnam(login);
156 #  endif /* _REENTRANT */
157     errnum = errno;
158     endpwent();
159 
160     if (pw == NULL) {
161 	if (errnum != 0) {
162 	    char *errstr;
163 
164 	    if (flags & VERBOSE) {
165 		syslog(LOG_DEBUG, "DEBUG: auth_shadow: getpwnam(%s) failure: %m", login);
166 	    }
167 	    if (asprintf(&errstr, "NO Username lookup failure: %s", strerror(errno)) == -1) {
168 		/* XXX the hidden strdup() will likely fail and return NULL here.... */
169 		RETURN("NO Username lookup failure: unknown error (ENOMEM formatting strerror())");
170 	    }
171 	    return errstr;
172 	} else {
173 	    if (flags & VERBOSE) {
174 		syslog(LOG_DEBUG, "DEBUG: auth_shadow: getpwnam(%s): invalid username", login);
175 	    }
176 	    RETURN("NO Invalid username");
177 	}
178     }
179 
180     today = (long)time(NULL)/(24L*60*60);
181 
182 #  ifdef _REENTRANT
183 #    ifdef GETXXNAM_R_5ARG
184 	(void) getspnam_r(login, &spbuf, spdata, sizeof(spdata), &sp);
185 #    else
186     sp = getspnam_r(login, &spbuf, spdata, sizeof(spdata));
187 #    endif /* GETXXNAM_R_5ARG */
188 #  else
189     sp = getspnam(login);
190 #  endif /* _REENTRANT */
191     errnum = errno;
192     endspent();
193 
194     if (sp == NULL) {
195 	if (errnum != 0) {
196 	    char *errstr;
197 
198 	    if (flags & VERBOSE) {
199 		syslog(LOG_DEBUG, "DEBUG: auth_shadow: getspnam(%s) failure: %m", login);
200 	    }
201 	    if (asprintf(&errstr, "NO Username shadow lookup failure: %s", strerror(errno)) == -1) {
202 		/* XXX the hidden strdup() will likely fail and return NULL here.... */
203 		RETURN("NO Username shadow lookup failure: unknown error (ENOMEM formatting strerror())");
204 	    }
205 	    return errstr;
206 	} else {
207 	    if (flags & VERBOSE) {
208 		syslog(LOG_DEBUG, "DEBUG: auth_shadow: getspnam(%s): invalid shadow username", login);
209 	    }
210 	    RETURN("NO Invalid shadow username");
211 	}
212     }
213 
214     if (!strcmp(sp->sp_pwdp, SHADOW_PW_EPERM)) {
215 	if (flags & VERBOSE) {
216 	    syslog(LOG_DEBUG, "DEBUG: auth_shadow: sp->sp_pwdp == SHADOW_PW_EPERM");
217 	}
218 	RETURN("NO Insufficient permission to access NIS authentication database (saslauthd)");
219     }
220 
221 #  ifdef _REENTRANT
222     cdata.initialized = 0;
223     cpw = crypt_r(password, sp->sp_pwdp, &cdata);
224 #  else
225     cpw = crypt(password, sp->sp_pwdp);
226 #  endif /* _REENTRANT */
227     if (!cpw || strcmp(sp->sp_pwdp, (const char *)cpw)) {
228 	if (flags & VERBOSE) {
229 	    /*
230 	     * This _should_ reveal the SHADOW_PW_LOCKED prefix to an
231 	     * administrator trying to debug the situation, though maybe we
232 	     * should do the check here and be less obtuse about it....
233 	     */
234 	    syslog(LOG_DEBUG, "DEBUG: auth_shadow: pw mismatch: '%s' != '%s'",
235 		   sp->sp_pwdp, cpw);
236 	}
237 	RETURN("NO Incorrect password");
238     }
239 
240     /*
241      * The following fields will be set to -1 if:
242      *
243      *	1) They are not specified in the shadow database, or
244      *	2) The database is being served up by NIS.
245      */
246 
247     if ((sp->sp_expire != -1) && (today > sp->sp_expire)) {
248 	if (flags & VERBOSE) {
249 	    syslog(LOG_DEBUG, "DEBUG: auth_shadow: account expired: %ld > %ld",
250 		   today, sp->sp_expire);
251 	}
252 	RETURN("NO Account expired");
253     }
254 
255     /* Remaining tests are relative to the last change date for the password */
256 
257     if (sp->sp_lstchg != -1) {
258 
259 	if ((sp->sp_max != -1) && ((sp->sp_lstchg + sp->sp_max) < today)) {
260 	    if (flags & VERBOSE) {
261 		syslog(LOG_DEBUG,
262 		       "DEBUG: auth_shadow: password expired: %ld + %ld < %ld",
263 		       sp->sp_lstchg, sp->sp_max, today);
264 	    }
265 	    RETURN("NO Password expired");
266 	}
267     }
268     if (flags & VERBOSE) {
269 	syslog(LOG_DEBUG, "DEBUG: auth_shadow: OK: %s", login);
270     }
271     RETURN("OK");
272 
273 
274 # elif defined(HAVE_GETUSERPW)
275 
276 /*************
277  * AIX 4.1.4 *
278  ************/
279     /* VARIABLES */
280     struct userpw *upw;				/* return from getuserpw() */
281     /* END VARIABLES */
282 
283 #  define RETURN(x) { endpwdb(); return strdup(x); }
284 
285     if (setpwdb(S_READ) == -1) {
286 	syslog(LOG_ERR, "setpwdb: %m");
287 	RETURN("NO setpwdb() internal failure (saslauthd)");
288     }
289 
290     upw = getuserpw(login);
291 
292     if (upw == 0) {
293 	if (flags & VERBOSE) {
294 	    syslog(LOG_DEBUG, "auth_shadow: getuserpw(%s) failed: %m",
295 		   login);
296 	}
297 	RETURN("NO Invalid username");
298     }
299 
300     if (!(cpw = crypt(password, upw->upw_passwd)) || (strcmp(upw->upw_passwd, (const char *)cpw) != 0)) {
301 	if (flags & VERBOSE) {
302 	    syslog(LOG_DEBUG, "auth_shadow: pw mismatch: %s != %s",
303 		   password, upw->upw_passwd);
304 	}
305 	RETURN("NO Incorrect password");
306     }
307 
308     RETURN("OK");
309 
310 # else /* HAVE_GETUSERPW */
311 
312 #  error "unknown shadow authentication type"
313 
314 # endif /* ! HAVE_GETUSERPW */
315 }
316 
317 #else /* !AUTH_SHADOW */
318 
319 char *
auth_shadow(const char * login,const char * passwd,const char * service,const char * realm)320 auth_shadow (
321   const char *login __attribute__((unused)),
322   const char *passwd __attribute__((unused)),
323   const char *service __attribute__((unused)),
324   const char *realm __attribute__((unused))
325   )
326 {
327     return NULL;
328 }
329 
330 #endif /* !AUTH_SHADOW */
331 
332 /* END FUNCTION: auth_shadow */
333 
334 /* END MODULE: auth_shadow */
335