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#ifdef __GNUC__ 31#ident "$Id: auth_shadow.c,v 1.12 2009/08/14 14:58:38 mel Exp $" 32#endif 33 34/* PUBLIC DEPENDENCIES */ 35#include "mechanisms.h" 36 37#ifdef AUTH_SHADOW 38 39#define PWBUFSZ 256 /***SWB***/ 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 <errno.h> 48# include <syslog.h> 49 50#ifdef HAVE_CRYPT_H 51#include <crypt.h> 52#endif 53 54# ifndef HAVE_GETSPNAM 55 56# ifdef WITH_DES 57# ifdef WITH_SSL_DES 58# include <openssl/des.h> 59# else 60# include <des.h> 61# endif /* WITH_SSL_DES */ 62# endif /* WITH_DES */ 63 64# endif /* ! HAVE_GETSPNAM */ 65 66# ifdef HAVE_GETUSERPW 67# include <userpw.h> 68# include <usersec.h> 69# else /* ! HAVE_GETUSERPW */ 70# include <shadow.h> 71# endif /* ! HAVE_GETUSERPW */ 72 73# include "auth_shadow.h" 74# include "globals.h" 75/* END PUBLIC DEPENDENCIES */ 76 77/* FUNCTION: auth_shadow */ 78 79/* SYNOPSIS 80 * Authenticate against the system shadow password database. Where 81 * possible (and if enabled by the command line arguments), enforce 82 * time-of-day and other login restrictions. 83 */ 84 85char * /* R: allocated response string */ 86auth_shadow ( 87 /* PARAMETERS */ 88 const char *login, /* I: plaintext authenticator */ 89 const char *password, /* I: plaintext password */ 90 const char *service __attribute__((unused)), 91 const char *realm __attribute__((unused)) 92 /* END PARAMETERS */ 93 ) 94{ 95 96/************************************************************************ 97 * * 98 * This is gross. Everyone wants to do this differently, thus we have * 99 * to #ifdef the whole mess for each system type. * 100 * * 101 ***********************************************************************/ 102 103# ifdef HAVE_GETSPNAM 104 105 /*************** 106 * getspnam_r() * 107 ***************/ 108 109 /* VARIABLES */ 110 long today; /* the current time */ 111 char *cpw; /* pointer to crypt() result */ 112 struct passwd *pw; /* return from getpwnam_r() */ 113 struct spwd *sp; /* return from getspnam_r() */ 114 int errnum; 115# ifdef _REENTRANT 116 struct passwd pwbuf; 117 char pwdata[PWBUFSZ]; /* pwbuf indirect data goes in here */ 118 119 struct spwd spbuf; 120 char spdata[PWBUFSZ]; /* spbuf indirect data goes in here */ 121# endif /* _REENTRANT */ 122 /* END VARIABLES */ 123 124# define RETURN(x) return strdup(x) 125 126 /* 127 * "Magic" password field entries for SunOS/SysV 128 * 129 * "*LK*" is defined at in the shadow(4) man page, but of course any string 130 * inserted in front of the password will prevent the strings from matching 131 * 132 * *NP* is documented in getspnam(3) and indicates the caller had 133 * insufficient permission to read the shadow password database 134 * (generally this is a NIS error). 135 */ 136 137# define SHADOW_PW_LOCKED "*LK*" /* account locked (not used by us) */ 138# define SHADOW_PW_EPERM "*NP*" /* insufficient database perms */ 139 140# ifdef _REENTRANT 141# ifdef GETXXNAM_R_5ARG 142 (void) getpwnam_r(login, &pwbuf, pwdata, sizeof(pwdata), &pw); 143# else 144 pw = getpwnam_r(login, &pwbuf, pwdata, sizeof(pwdata)); 145# endif /* GETXXNAM_R_5ARG */ 146# else 147 pw = getpwnam(login); 148# endif /* _REENTRANT */ 149 errnum = errno; 150 endpwent(); 151 152 if (pw == NULL) { 153 if (errnum != 0) { 154 char *errstr; 155 156 if (flags & VERBOSE) { 157 syslog(LOG_DEBUG, "DEBUG: auth_shadow: getpwnam(%s) failure: %m", login); 158 } 159 if (asprintf(&errstr, "NO Username lookup failure: %s", strerror(errno)) == -1) { 160 /* XXX the hidden strdup() will likely fail and return NULL here.... */ 161 RETURN("NO Username lookup failure: unknown error (ENOMEM formatting strerror())"); 162 } 163 return errstr; 164 } else { 165 if (flags & VERBOSE) { 166 syslog(LOG_DEBUG, "DEBUG: auth_shadow: getpwnam(%s): invalid username", login); 167 } 168 RETURN("NO Invalid username"); 169 } 170 } 171 172 today = (long)time(NULL)/(24L*60*60); 173 174# ifdef _REENTRANT 175# ifdef GETXXNAM_R_5ARG 176 (void) getspnam_r(login, &spbuf, spdata, sizeof(spdata), &sp); 177# else 178 sp = getspnam_r(login, &spbuf, spdata, sizeof(spdata)); 179# endif /* GETXXNAM_R_5ARG */ 180# else 181 sp = getspnam(login); 182# endif /* _REENTRANT */ 183 errnum = errno; 184 endspent(); 185 186 if (sp == NULL) { 187 if (errnum != 0) { 188 char *errstr; 189 190 if (flags & VERBOSE) { 191 syslog(LOG_DEBUG, "DEBUG: auth_shadow: getspnam(%s) failure: %m", login); 192 } 193 if (asprintf(&errstr, "NO Username shadow lookup failure: %s", strerror(errno)) == -1) { 194 /* XXX the hidden strdup() will likely fail and return NULL here.... */ 195 RETURN("NO Username shadow lookup failure: unknown error (ENOMEM formatting strerror())"); 196 } 197 return errstr; 198 } else { 199 if (flags & VERBOSE) { 200 syslog(LOG_DEBUG, "DEBUG: auth_shadow: getspnam(%s): invalid shadow username", login); 201 } 202 RETURN("NO Invalid shadow username"); 203 } 204 } 205 206 if (!strcmp(sp->sp_pwdp, SHADOW_PW_EPERM)) { 207 if (flags & VERBOSE) { 208 syslog(LOG_DEBUG, "DEBUG: auth_shadow: sp->sp_pwdp == SHADOW_PW_EPERM"); 209 } 210 RETURN("NO Insufficient permission to access NIS authentication database (saslauthd)"); 211 } 212 213 cpw = strdup((const char *)crypt(password, sp->sp_pwdp)); 214 if (strcmp(sp->sp_pwdp, cpw)) { 215 if (flags & VERBOSE) { 216 /* 217 * This _should_ reveal the SHADOW_PW_LOCKED prefix to an 218 * administrator trying to debug the situation, though maybe we 219 * should do the check here and be less obtuse about it.... 220 */ 221 syslog(LOG_DEBUG, "DEBUG: auth_shadow: pw mismatch: '%s' != '%s'", 222 sp->sp_pwdp, cpw); 223 } 224 free(cpw); 225 RETURN("NO Incorrect password"); 226 } 227 free(cpw); 228 229 /* 230 * The following fields will be set to -1 if: 231 * 232 * 1) They are not specified in the shadow database, or 233 * 2) The database is being served up by NIS. 234 */ 235 236 if ((sp->sp_expire != -1) && (today > sp->sp_expire)) { 237 if (flags & VERBOSE) { 238 syslog(LOG_DEBUG, "DEBUG: auth_shadow: account expired: %dl > %dl", 239 today, sp->sp_expire); 240 } 241 RETURN("NO Account expired"); 242 } 243 244 /* Remaining tests are relative to the last change date for the password */ 245 246 if (sp->sp_lstchg != -1) { 247 248 if ((sp->sp_max != -1) && ((sp->sp_lstchg + sp->sp_max) < today)) { 249 if (flags & VERBOSE) { 250 syslog(LOG_DEBUG, 251 "DEBUG: auth_shadow: password expired: %ld + %ld < %ld", 252 sp->sp_lstchg, sp->sp_max, today); 253 } 254 RETURN("NO Password expired"); 255 } 256 } 257 if (flags & VERBOSE) { 258 syslog(LOG_DEBUG, "DEBUG: auth_shadow: OK: %s", login); 259 } 260 RETURN("OK"); 261 262 263# elif defined(HAVE_GETUSERPW) 264 265/************* 266 * AIX 4.1.4 * 267 ************/ 268 /* VARIABLES */ 269 struct userpw *upw; /* return from getuserpw() */ 270 /* END VARIABLES */ 271 272# define RETURN(x) { endpwdb(); return strdup(x); } 273 274 if (setpwdb(S_READ) == -1) { 275 syslog(LOG_ERR, "setpwdb: %m"); 276 RETURN("NO setpwdb() internal failure (saslauthd)"); 277 } 278 279 upw = getuserpw(login); 280 281 if (upw == 0) { 282 if (flags & VERBOSE) { 283 syslog(LOG_DEBUG, "auth_shadow: getuserpw(%s) failed: %m", 284 login); 285 } 286 RETURN("NO Invalid username"); 287 } 288 289 if (strcmp(upw->upw_passwd, crypt(password, upw->upw_passwd)) != 0) { 290 if (flags & VERBOSE) { 291 syslog(LOG_DEBUG, "auth_shadow: pw mismatch: %s != %s", 292 password, upw->upw_passwd); 293 } 294 RETURN("NO Incorrect password"); 295 } 296 297 RETURN("OK"); 298 299# else /* HAVE_GETUSERPW */ 300 301# error "unknown shadow authentication type" 302 303# endif /* ! HAVE_GETUSERPW */ 304} 305 306#else /* !AUTH_SHADOW */ 307 308char * 309auth_shadow ( 310 const char *login __attribute__((unused)), 311 const char *passwd __attribute__((unused)), 312 const char *service __attribute__((unused)), 313 const char *realm __attribute__((unused)) 314 ) 315{ 316 return NULL; 317} 318 319#endif /* !AUTH_SHADOW */ 320 321/* END FUNCTION: auth_shadow */ 322 323/* END MODULE: auth_shadow */ 324