1 #define PWBUFSZ 256 /***SWB***/
3 /* MODULE: auth_shadow */
6 * Copyright (c) 1997 Messaging Direct Ltd.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY MESSAGING DIRECT LTD. ``AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MESSAGING DIRECT LTD. OR
22 * ITS EMPLOYEES OR AGENTS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
28 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
33 #ident "$Id: auth_shadow.c,v 1.8 2006/04/19 19:36:25 murch Exp $"
36 /* PUBLIC DEPENDENCIES */
37 #include "mechanisms.h"
44 # include <sys/types.h>
48 # ifndef HAVE_GETSPNAM
52 # include <openssl/des.h>
55 # endif /* WITH_SSL_DES */
56 # endif /* WITH_DES */
58 #endif /* ! HAVE_GETSPNAM */
59 # ifdef HAVE_GETUSERPW
62 # else /* ! HAVE_GETUSERPW */
64 # endif /* ! HAVE_GETUSERPW */
66 # include "auth_shadow.h"
68 /* END PUBLIC DEPENDENCIES */
70 /* FUNCTION: auth_shadow */
73 * Authenticate against the system shadow password database. Where
74 * possible (and if enabled by the command line arguments), enforce
75 * time-of-day and other login restrictions.
78 char * /* R: allocated response string */
81 const char *login, /* I: plaintext authenticator */
82 const char *password, /* I: plaintext password */
83 const char *service __attribute__((unused)),
84 const char *realm __attribute__((unused))
89 /************************************************************************
91 * This is gross. Everyone wants to do this differently, thus we have *
92 * to #ifdef the whole mess for each system type. *
94 ***********************************************************************/
103 long today; /* the current time */
104 char *cpw; /* pointer to crypt() result */
105 struct passwd *pw; /* return from getpwnam_r() */
106 struct spwd *sp; /* return from getspnam_r() */
109 char pwdata[PWBUFSZ]; /* pwbuf indirect data goes in here */
112 char spdata[PWBUFSZ]; /* spbuf indirect data goes in here */
113 # endif /* _REENTRANT */
116 # define RETURN(x) return strdup(x)
119 * "Magic" password field entries for SunOS.
121 * *LK* is hinted at in the shadow(4) man page, but the
122 * only definition for it (that I could find) is in the passmgmt(1M)
125 * *NP* is documented in getspnam(3) and indicates the caller had
126 * insufficient permission to read the shadow password database
127 * (generally this is a NIS error).
130 # define SHADOW_PW_LOCKED "*LK*" /* account locked (not used by us) */
131 # define SHADOW_PW_EPERM "*NP*" /* insufficient database perms */
134 # ifdef GETXXNAM_R_5ARG
135 (void) getpwnam_r(login, &pwbuf, pwdata, sizeof(pwdata), &pw);
137 pw = getpwnam_r(login, &pwbuf, pwdata, sizeof(pwdata));
138 # endif /* GETXXNAM_R_5ARG */
140 pw = getpwnam(login);
141 # endif /* _REENTRANT */
144 if (flags & VERBOSE) {
145 syslog(LOG_DEBUG, "DEBUG: auth_shadow: getpwnam(%s) returned NULL", login);
150 today = (long)time(NULL)/(24L*60*60);
153 # ifdef GETXXNAM_R_5ARG
154 (void) getspnam_r(login, &spbuf, spdata, sizeof(spdata), &sp);
156 sp = getspnam_r(login, &spbuf, spdata, sizeof(spdata));
157 # endif /* GETXXNAM_R_5ARG */
159 sp = getspnam(login);
160 # endif /* _REENTRANT */
164 if (flags & VERBOSE) {
165 syslog(LOG_DEBUG, "DEBUG: auth_shadow: getspnam(%s) returned NULL", login);
170 if (!strcmp(sp->sp_pwdp, SHADOW_PW_EPERM)) {
171 if (flags & VERBOSE) {
172 syslog(LOG_DEBUG, "DEBUG: auth_shadow: sp->sp_pwdp == SHADOW_PW_EPERM");
174 RETURN("NO Insufficient permission to access NIS authentication database (saslauthd)");
178 * Note: no check for SHADOW_PW_LOCKED. Returning a "locked" notification
179 * would allow login-id namespace probes, and violates our policy of
180 * not returning any information about a login until we have validated
183 cpw = strdup((const char *)crypt(password, sp->sp_pwdp));
184 if (strcmp(sp->sp_pwdp, cpw)) {
185 if (flags & VERBOSE) {
186 syslog(LOG_DEBUG, "DEBUG: auth_shadow: pw mismatch: '%s' != '%s'",
195 * The following fields will be set to -1 if:
197 * 1) They are not specified in the shadow database, or
198 * 2) The database is being served up by NIS.
201 if ((sp->sp_expire != -1) && (today > sp->sp_expire)) {
202 if (flags & VERBOSE) {
203 syslog(LOG_DEBUG, "DEBUG: auth_shadow: account expired: %dl > %dl",
204 today, sp->sp_expire);
206 RETURN("NO Account expired");
209 /* Remaining tests are relative to the last change date for the password */
211 if (sp->sp_lstchg != -1) {
213 if ((sp->sp_max != -1) && ((sp->sp_lstchg + sp->sp_max) < today)) {
214 if (flags & VERBOSE) {
216 "DEBUG: auth_shadow: password expired: %ld + %ld < %ld",
217 sp->sp_lstchg, sp->sp_max, today);
219 RETURN("NO Password expired");
222 if (flags & VERBOSE) {
223 syslog(LOG_DEBUG, "DEBUG: auth_shadow: OK: %s", login);
228 # elif defined(HAVE_GETUSERPW)
234 struct userpw *upw; /* return from getuserpw() */
237 # define RETURN(x) { endpwdb(); return strdup(x); }
239 if (setpwdb(S_READ) == -1) {
240 syslog(LOG_ERR, "setpwdb: %m");
241 RETURN("NO setpwdb() internal failure (saslauthd)");
244 upw = getuserpw(login);
247 if (flags & VERBOSE) {
248 syslog(LOG_DEBUG, "auth_shadow: getuserpw(%s) == 0",
254 if (strcmp(upw->upw_passwd, crypt(password, upw->upw_passwd)) != 0) {
255 if (flags & VERBOSE) {
256 syslog(LOG_DEBUG, "auth_shadow: pw mismatch: %s != %s",
257 password, upw->upw_passwd);
264 # else /* HAVE_GETUSERPW */
266 # error "unknown shadow authentication type"
268 # endif /* ! HAVE_GETUSERPW */
271 #else /* !AUTH_SHADOW */
275 const char *login __attribute__((unused)),
276 const char *passwd __attribute__((unused)),
277 const char *service __attribute__((unused)),
278 const char *realm __attribute__((unused))
284 #endif /* !AUTH_SHADOW */
286 /* END FUNCTION: auth_shadow */
288 /* END MODULE: auth_shadow */