GSS_S_PROMPTING_NEEDED is a bit
[cyrus-sasl.git] / saslauthd / auth_shadow.c
1 #define PWBUFSZ 256 /***SWB***/
2
3 /* MODULE: auth_shadow */
4
5 /* COPYRIGHT
6  * Copyright (c) 1997 Messaging Direct Ltd.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
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.
17  *
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
29  * DAMAGE.
30  * END COPYRIGHT */
31
32 #ifdef __GNUC__
33 #ident "$Id: auth_shadow.c,v 1.8 2006/04/19 19:36:25 murch Exp $"
34 #endif
35
36 /* PUBLIC DEPENDENCIES */
37 #include "mechanisms.h"
38
39 #ifdef AUTH_SHADOW
40
41 # include <unistd.h>
42 # include <stdlib.h>
43 # include <string.h>
44 # include <sys/types.h>
45 # include <time.h>
46 # include <pwd.h>
47 # include <syslog.h>
48 # ifndef HAVE_GETSPNAM
49
50 # ifdef WITH_DES
51 #  ifdef WITH_SSL_DES
52 #   include <openssl/des.h>
53 #  else
54 #   include <des.h>
55 #  endif /* WITH_SSL_DES */
56 # endif /* WITH_DES */
57
58 #endif /* ! HAVE_GETSPNAM */
59 # ifdef HAVE_GETUSERPW
60 #  include <userpw.h>
61 #  include <usersec.h>
62 # else /* ! HAVE_GETUSERPW */
63 #  include <shadow.h>
64 # endif /* ! HAVE_GETUSERPW */
65
66 # include "auth_shadow.h"
67 # include "globals.h"
68 /* END PUBLIC DEPENDENCIES */
69 \f
70 /* FUNCTION: auth_shadow */
71
72 /* SYNOPSIS
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.
76  */
77
78 char *                                  /* R: allocated response string */
79 auth_shadow (
80   /* PARAMETERS */
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))
85   /* END PARAMETERS */
86   )
87 {
88
89 /************************************************************************
90  *                                                                      *
91  * This is gross. Everyone wants to do this differently, thus we have   *
92  * to #ifdef the whole mess for each system type.                       *
93  *                                                                      *
94  ***********************************************************************/
95
96 # ifdef HAVE_GETSPNAM
97
98  /***************
99  * getspnam_r() *
100  ***************/
101
102     /* VARIABLES */
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() */
107 #  ifdef _REENTRANT
108     struct passwd pwbuf;
109     char pwdata[PWBUFSZ];               /* pwbuf indirect data goes in here */
110
111     struct spwd spbuf;
112     char spdata[PWBUFSZ];               /* spbuf indirect data goes in here */
113 #  endif /* _REENTRANT */
114     /* END VARIABLES */
115
116 #  define RETURN(x) return strdup(x)
117
118     /*
119      * "Magic" password field entries for SunOS.
120      *
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)
123      * man page.
124      *
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).
128      */
129
130 #  define SHADOW_PW_LOCKED "*LK*"       /* account locked (not used by us) */
131 #  define SHADOW_PW_EPERM  "*NP*"       /* insufficient database perms */
132
133 #  ifdef _REENTRANT
134 #    ifdef GETXXNAM_R_5ARG
135         (void) getpwnam_r(login, &pwbuf, pwdata, sizeof(pwdata), &pw);
136 #    else
137     pw = getpwnam_r(login, &pwbuf, pwdata, sizeof(pwdata));
138 #    endif /* GETXXNAM_R_5ARG */
139 #  else
140     pw = getpwnam(login);
141 #  endif /* _REENTRANT */
142     endpwent();
143     if (pw == NULL) {
144         if (flags & VERBOSE) {
145             syslog(LOG_DEBUG, "DEBUG: auth_shadow: getpwnam(%s) returned NULL", login);
146         }
147         RETURN("NO");
148     }
149
150     today = (long)time(NULL)/(24L*60*60);
151
152 #  ifdef _REENTRANT
153 #    ifdef GETXXNAM_R_5ARG
154         (void) getspnam_r(login, &spbuf, spdata, sizeof(spdata), &sp);
155 #    else
156     sp = getspnam_r(login, &spbuf, spdata, sizeof(spdata));
157 #    endif /* GETXXNAM_R_5ARG */
158 #  else
159     sp = getspnam(login);
160 #  endif /* _REENTRANT */
161     endspent();
162
163     if (sp == NULL) {
164         if (flags & VERBOSE) {
165             syslog(LOG_DEBUG, "DEBUG: auth_shadow: getspnam(%s) returned NULL", login);
166         }
167         RETURN("NO");
168     }
169
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");
173         }
174         RETURN("NO Insufficient permission to access NIS authentication database (saslauthd)");
175     }
176
177     /*
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
181      * the password.
182      */
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'",
187                    sp->sp_pwdp, cpw);
188         }
189         free(cpw);
190         RETURN("NO");
191     }
192     free(cpw);
193
194     /*
195      * The following fields will be set to -1 if:
196      *
197      *  1) They are not specified in the shadow database, or
198      *  2) The database is being served up by NIS.
199      */
200
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);
205         }
206         RETURN("NO Account expired");
207     }
208
209     /* Remaining tests are relative to the last change date for the password */
210
211     if (sp->sp_lstchg != -1) {
212
213         if ((sp->sp_max != -1) && ((sp->sp_lstchg + sp->sp_max) < today)) {
214             if (flags & VERBOSE) {
215                 syslog(LOG_DEBUG,
216                        "DEBUG: auth_shadow: password expired: %ld + %ld < %ld",
217                        sp->sp_lstchg, sp->sp_max, today);
218             }
219             RETURN("NO Password expired");
220         }
221     }
222     if (flags & VERBOSE) {
223         syslog(LOG_DEBUG, "DEBUG: auth_shadow: OK: %s", login);
224     }
225     RETURN("OK");
226
227
228 # elif defined(HAVE_GETUSERPW)
229
230 /*************
231  * AIX 4.1.4 *
232  ************/
233     /* VARIABLES */
234     struct userpw *upw;                         /* return from getuserpw() */
235     /* END VARIABLES */
236
237 #  define RETURN(x) { endpwdb(); return strdup(x); }
238
239     if (setpwdb(S_READ) == -1) {
240         syslog(LOG_ERR, "setpwdb: %m");
241         RETURN("NO setpwdb() internal failure (saslauthd)");
242     }
243   
244     upw = getuserpw(login);
245   
246     if (upw == 0) {
247         if (flags & VERBOSE) {
248             syslog(LOG_DEBUG, "auth_shadow: getuserpw(%s) == 0",
249                    login);
250         }
251         RETURN("NO");
252     }
253   
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);
258         }
259         RETURN("NO");
260     }
261
262     RETURN("OK");
263   
264 # else /* HAVE_GETUSERPW */
265
266 #  error "unknown shadow authentication type"
267
268 # endif /* ! HAVE_GETUSERPW */
269 }
270
271 #else /* !AUTH_SHADOW */
272
273 char *
274 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))
279   )
280 {
281     return NULL;
282 }
283
284 #endif /* !AUTH_SHADOW */
285
286 /* END FUNCTION: auth_shadow */
287
288 /* END MODULE: auth_shadow */