/* MODULE: auth_shadow */ /* COPYRIGHT * Copyright (c) 1997 Messaging Direct Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY MESSAGING DIRECT LTD. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MESSAGING DIRECT LTD. OR * ITS EMPLOYEES OR AGENTS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * END COPYRIGHT */ #ifdef __GNUC__ #ident "$Id: auth_shadow.c,v 1.1 2004/03/31 18:08:42 dasenbro Exp $" #endif /* PUBLIC DEPENDENCIES */ #include "mechanisms.h" #ifdef AUTH_SHADOW # include <unistd.h> # include <stdlib.h> # include <string.h> # include <sys/types.h> # include <time.h> # include <pwd.h> # include <syslog.h> # ifndef HAVE_GETSPNAM # ifdef WITH_DES # ifdef WITH_SSL_DES # include <openssl/des.h> # else # include <des.h> # endif /* WITH_SSL_DES */ # endif /* WITH_DES */ #endif /* ! HAVE_GETSPNAM */ # ifdef HAVE_GETUSERPW # include <userpw.h> # include <usersec.h> # else /* ! HAVE_GETUSERPW */ # include <shadow.h> # endif /* ! HAVE_GETUSERPW */ # include "auth_shadow.h" # include "globals.h" /* END PUBLIC DEPENDENCIES */ /* FUNCTION: auth_shadow */ /* SYNOPSIS * Authenticate against the system shadow password database. Where * possible (and if enabled by the command line arguments), enforce * time-of-day and other login restrictions. */ char * /* R: allocated response string */ auth_shadow ( /* PARAMETERS */ const char *login, /* I: plaintext authenticator */ const char *password, /* I: plaintext password */ const char *service __attribute__((unused)), const char *realm __attribute__((unused)) /* END PARAMETERS */ ) { /************************************************************************ * * * This is gross. Everyone wants to do this differently, thus we have * * to #ifdef the whole mess for each system type. * * * ***********************************************************************/ # ifdef HAVE_GETSPNAM /************** * getspnam() * *************/ /* VARIABLES */ struct passwd *pw; /* return from getpwent() */ struct spwd *sp; /* return from getspnam() */ long today; /* the current time */ char *cpw; /* pointer to crypt() result */ /* END VARIABLES */ # define RETURN(x) return strdup(x) /* * "Magic" password field entries for SunOS. * * *LK* is hinted at in the shadow(4) man page, but the * only definition for it (that I could find) is in the passmgmt(1M) * man page. * * *NP* is documented in getspnam(3) and indicates the caller had * insufficient permission to read the shadow password database * (generally this is a NIS error). */ # define SHADOW_PW_LOCKED "*LK*" /* account locked (not used by us) */ # define SHADOW_PW_EPERM "*NP*" /* insufficient database perms */ pw = getpwnam(login); endpwent(); if (pw == NULL) { if (flags & VERBOSE) { syslog(LOG_DEBUG, "DEBUG: auth_shadow: getpwnam(%s) returned NULL", login); } RETURN("NO"); } today = (long)time(NULL)/(24L*60*60); sp = getspnam(login); endspent(); if (sp == NULL) { if (flags & VERBOSE) { syslog(LOG_DEBUG, "DEBUG: auth_shadow: getspnam(%s) returned NULL", login); } RETURN("NO"); } if (!strcmp(sp->sp_pwdp, SHADOW_PW_EPERM)) { if (flags & VERBOSE) { syslog(LOG_DEBUG, "DEBUG: auth_shadow: sp->sp_pwdp == SHADOW_PW_EPERM"); } RETURN("NO Insufficient permission to access NIS authentication database (saslauthd)"); } /* * Note: no check for SHADOW_PW_LOCKED. Returning a "locked" notification * would allow login-id namespace probes, and violates our policy of * not returning any information about a login until we have validated * the password. */ cpw = strdup((const char *)crypt(password, sp->sp_pwdp)); if (strcmp(sp->sp_pwdp, cpw)) { if (flags & VERBOSE) { syslog(LOG_DEBUG, "DEBUG: auth_shadow: pw mismatch: '%s' != '%s'", sp->sp_pwdp, cpw); } free(cpw); RETURN("NO"); } free(cpw); /* * The following fields will be set to -1 if: * * 1) They are not specified in the shadow database, or * 2) The database is being served up by NIS. */ if ((sp->sp_expire != -1) && (today > sp->sp_expire)) { if (flags & VERBOSE) { syslog(LOG_DEBUG, "DEBUG: auth_shadow: account expired: %dl > %dl", today, sp->sp_expire); } RETURN("NO Account expired"); } /* Remaining tests are relative to the last change date for the password */ if (sp->sp_lstchg != -1) { if ((sp->sp_max != -1) && ((sp->sp_lstchg + sp->sp_max) < today)) { if (flags & VERBOSE) { syslog(LOG_DEBUG, "DEBUG: auth_shadow: password expired: %ld + %ld < %ld", sp->sp_lstchg, sp->sp_max, today); } RETURN("NO Password expired"); } } if (flags & VERBOSE) { syslog(LOG_DEBUG, "DEBUG: auth_shadow: OK: %s", login); } RETURN("OK"); # elif defined(HAVE_GETUSERPW) /************* * AIX 4.1.4 * ************/ /* VARIABLES */ struct userpw *upw; /* return from getuserpw() */ /* END VARIABLES */ # define RETURN(x) { endpwdb(); return strdup(x); } if (setpwdb(S_READ) == -1) { syslog(LOG_ERR, "setpwdb: %m"); RETURN("NO setpwdb() internal failure (saslauthd)"); } upw = getuserpw(login); if (upw == 0) { if (flags & VERBOSE) { syslog(LOG_DEBUG, "auth_shadow: getuserpw(%s) == 0", login); } RETURN("NO"); } if (strcmp(upw->upw_passwd, crypt(password, upw->upw_passwd)) != 0) { if (flags & VERBOSE) { syslog(LOG_DEBUG, "auth_shadow: pw mismatch: %s != %s", password, upw->upw_passwd); } RETURN("NO"); } RETURN("OK"); # else /* HAVE_GETUSERPW */ # error "unknown shadow authentication type" # endif /* ! HAVE_GETUSERPW */ } #else /* !AUTH_SHADOW */ char * auth_shadow ( const char *login __attribute__((unused)), const char *passwd __attribute__((unused)), const char *service __attribute__((unused)), const char *realm __attribute__((unused)) ) { return NULL; } #endif /* !AUTH_SHADOW */ /* END FUNCTION: auth_shadow */ /* END MODULE: auth_shadow */