diff options
Diffstat (limited to 'Linux-PAM/modules/pam_unix')
-rw-r--r-- | Linux-PAM/modules/pam_unix/CHANGELOG | 2 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/Makefile | 38 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/README | 2 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/bigcrypt_main.c | 18 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/md5.c | 2 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/md5_crypt.c | 2 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/pam_unix_acct.c | 53 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/pam_unix_auth.c | 13 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/pam_unix_passwd.c | 329 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/pam_unix_sess.c | 21 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/support.c | 399 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/support.h | 21 | ||||
-rw-r--r-- | Linux-PAM/modules/pam_unix/unix_chkpwd.c | 53 |
13 files changed, 654 insertions, 299 deletions
diff --git a/Linux-PAM/modules/pam_unix/CHANGELOG b/Linux-PAM/modules/pam_unix/CHANGELOG index 206d30dd..509ce0a3 100644 --- a/Linux-PAM/modules/pam_unix/CHANGELOG +++ b/Linux-PAM/modules/pam_unix/CHANGELOG @@ -1,4 +1,4 @@ -$Id: CHANGELOG,v 1.1.1.1 2001/04/29 04:17:36 hartmans Exp $ +$Id: CHANGELOG,v 1.1.1.1 2000/06/20 22:12:01 agmorgan Exp $ * Mon Aug 16 1999 Jan Rêkorajski <baggins@pld.org.pl> - fixed reentrancy problems diff --git a/Linux-PAM/modules/pam_unix/Makefile b/Linux-PAM/modules/pam_unix/Makefile index 03374512..7f32e073 100644 --- a/Linux-PAM/modules/pam_unix/Makefile +++ b/Linux-PAM/modules/pam_unix/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1.1.1 2001/04/29 04:17:36 hartmans Exp $ +# $Id: Makefile,v 1.8 2004/11/08 08:58:37 kukuk Exp $ # # This Makefile controls a build process of the pam_unix modules # for Linux-PAM. You should not modify this Makefile. @@ -18,6 +18,19 @@ include ../../Make.Rules #USE_CRACKLIB=-D"USE_CRACKLIB" #endif +ifeq ($(shell if [ -f /usr/lib/cracklib_dict.hwm ]; then echo yes ; fi),yes) + CRACKLIB_DICTPATH=/usr/lib/cracklib_dict +else + CRACKLIB_DICTPATH=/usr/share/dict/cracklib_dict +endif +EXTRAS += -DCRACKLIB_DICTS=\"$(CRACKLIB_DICTPATH)\" + +ifeq ($(HAVE_LIBCRYPT),yes) + EXTRALS += -lcrypt +endif +ifeq ($(HAVE_LIBNSL),yes) + EXTRALS += -lnsl +endif # do you want to use lckpwdf? ifeq ($(WITH_LCKPWDF),yes) USE_LCKPWDF=-D"USE_LCKPWDF" @@ -37,12 +50,19 @@ endif CHKPWD=unix_chkpwd +BIGCRYPT=bigcrypt + EXTRAS += -DCHKPWD_HELPER=\"$(SUPLEMENTED)/$(CHKPWD)\" +LINK_PAMMODUTILS = -L../pammodutil -lpammodutil +INCLUDE_PAMMODUTILS = -I../pammodutil/include + ######################################################################## -CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) -LDLIBS = $(EXTRALS) +CFLAGS += $(USE_CRACKLIB) $(USE_LCKPWDF) $(NEED_LCKPWDF) $(EXTRAS) \ + $(INCLUDE_PAMMODUTILS) + +LDLIBS = $(EXTRALS) $(LINK_PAMMODUTILS) ifdef USE_CRACKLIB CRACKLIB = -lcrack @@ -69,7 +89,8 @@ endif ########################### don't edit below ####################### -all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) register +all: dirs info $(PLUS) $(LIBSHARED) $(LIBSTATIC) $(CHKPWD) $(BIGCRYPT) \ + register dynamic/%.o : %.c $(CC) $(CFLAGS) $(DYNAMIC) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ @@ -107,7 +128,7 @@ ifdef DYNAMIC $(LIBOBJD): $(LIBSRC) $(LIBSHARED): $(LIBOBJD) - $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT) + $(LD_D) -o $@ $(LIBOBJD) $(PLUS) $(CRACKLIB) $(LDLIBS) $(LIBNSL) $(LIBCRYPT) $(NEED_LINK_LIB_C) -L../../libpam -lpam endif ifdef STATIC @@ -120,7 +141,10 @@ endif $(CHKPWD): unix_chkpwd.o md5_good.o md5_broken.o \ md5_crypt_good.o md5_crypt_broken.o \ bigcrypt.o - $(CC) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT) + $(CC) $(CFLAGS) -o $(CHKPWD) $^ $(LDLIBS) $(LIBCRYPT) + +$(BIGCRYPT): bigcrypt_main.o bigcrypt.o + $(CC) -o $(BIGCRYPT) $^ $(LDLIBS) $(LIBCRYPT) unix_chkpwd.o: unix_chkpwd.c $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ @@ -158,7 +182,7 @@ remove: rm -f $(FAKEROOT)$(SUPLEMENTED)/$(CHKPWD) clean: - rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) *.o *.so core + rm -f $(LIBOBJD) $(LIBOBJS) $(CHKPWD) $(BIGCRYPT) *.o *.so core rm -f *~ *.a *.out *.bak rm -rf dynamic static diff --git a/Linux-PAM/modules/pam_unix/README b/Linux-PAM/modules/pam_unix/README index d6b1f395..afeee3da 100644 --- a/Linux-PAM/modules/pam_unix/README +++ b/Linux-PAM/modules/pam_unix/README @@ -31,5 +31,7 @@ The following options are recognized: nis - use NIS RPC for setting new password remember=X - remember X old passwords, they are kept in /etc/security/opasswd in MD5 crypted form + broken_shadow - ignore errors reading shadow information for + users in the account management module invalid arguments are logged to syslog. diff --git a/Linux-PAM/modules/pam_unix/bigcrypt_main.c b/Linux-PAM/modules/pam_unix/bigcrypt_main.c new file mode 100644 index 00000000..70819072 --- /dev/null +++ b/Linux-PAM/modules/pam_unix/bigcrypt_main.c @@ -0,0 +1,18 @@ +#include <stdio.h> +#include <string.h> + +extern const char *bigcrypt(const char *password, const char *salt); + +int +main(int argc, char **argv) +{ + if (argc < 3) { + fprintf(stderr, "Usage: %s password salt\n", + strchr(argv[0], '/') ? + (strchr(argv[0], '/') + 1) : + argv[0]); + return 0; + } + fprintf(stdout, "%s\n", bigcrypt(argv[1], argv[2])); + return 0; +} diff --git a/Linux-PAM/modules/pam_unix/md5.c b/Linux-PAM/modules/pam_unix/md5.c index 3fb50137..7ee9ed00 100644 --- a/Linux-PAM/modules/pam_unix/md5.c +++ b/Linux-PAM/modules/pam_unix/md5.c @@ -1,5 +1,5 @@ /* - * $Id: md5.c,v 1.1.1.1 2001/04/29 04:17:37 hartmans Exp $ + * $Id: md5.c,v 1.1.1.1 2000/06/20 22:12:03 agmorgan Exp $ * * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was diff --git a/Linux-PAM/modules/pam_unix/md5_crypt.c b/Linux-PAM/modules/pam_unix/md5_crypt.c index 8ae84588..8b7bc66b 100644 --- a/Linux-PAM/modules/pam_unix/md5_crypt.c +++ b/Linux-PAM/modules/pam_unix/md5_crypt.c @@ -1,5 +1,5 @@ /* - * $Id: md5_crypt.c,v 1.1.1.2 2002/09/15 20:09:01 hartmans Exp $ + * $Id: md5_crypt.c,v 1.2 2001/07/10 20:24:16 vorlon Exp $ * * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): diff --git a/Linux-PAM/modules/pam_unix/pam_unix_acct.c b/Linux-PAM/modules/pam_unix/pam_unix_acct.c index 178b6037..02e07ba6 100644 --- a/Linux-PAM/modules/pam_unix/pam_unix_acct.c +++ b/Linux-PAM/modules/pam_unix/pam_unix_acct.c @@ -53,6 +53,7 @@ #define PAM_SM_ACCOUNT #include <security/pam_modules.h> +#include <security/_pam_modutil.h> #ifndef LINUX_PAM #include <security/pam_appl.h> @@ -89,7 +90,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, return PAM_USER_UNKNOWN; } - pwent = getpwnam(uname); + pwent = _pammodutil_getpwnam(pamh, uname); if (!pwent) { _log_err(LOG_ALERT, pamh ,"could not identify user (from getpwnam(%s))" @@ -113,7 +114,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, return PAM_CRED_INSUFFICIENT; } } - spent = getspnam( uname ); + spent = _pammodutil_getspnam (pamh, uname); if (save_uid == pwent->pw_uid) setreuid( save_uid, save_euid ); else { @@ -122,19 +123,21 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, setreuid( -1, save_euid ); } - } else if (!strcmp( pwent->pw_passwd, "x" )) { - spent = getspnam(uname); - } else { + } else if (_unix_shadowed (pwent)) + spent = _pammodutil_getspnam (pamh, uname); + else return PAM_SUCCESS; - } + + if (!spent) + if (on(UNIX_BROKEN_SHADOW,ctrl)) + return PAM_SUCCESS; if (!spent) return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */ curdays = time(NULL) / (60 * 60 * 24); D(("today is %d, last change %d", curdays, spent->sp_lstchg)); - if ((curdays > spent->sp_expire) && (spent->sp_expire != -1) - && (spent->sp_lstchg != 0)) { + if ((curdays > spent->sp_expire) && (spent->sp_expire != -1)) { _log_err(LOG_NOTICE, pamh ,"account %s has expired (account expired)" ,uname); @@ -143,18 +146,6 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, D(("account expired")); return PAM_ACCT_EXPIRED; } - if ((curdays > (spent->sp_lstchg + spent->sp_max + spent->sp_inact)) - && (spent->sp_max != -1) && (spent->sp_inact != -1) - && (spent->sp_lstchg != 0)) { - _log_err(LOG_NOTICE, pamh - ,"account %s has expired (failed to change password)" - ,uname); - _make_remark(pamh, ctrl, PAM_ERROR_MSG, - "Your account has expired; please contact your system administrator"); - D(("account expired 2")); - return PAM_ACCT_EXPIRED; - } - D(("when was the last change")); if (spent->sp_lstchg == 0) { _log_err(LOG_NOTICE, pamh ,"expired password for user %s (root enforced)" @@ -164,7 +155,25 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, D(("need a new password")); return PAM_NEW_AUTHTOK_REQD; } - if (((spent->sp_lstchg + spent->sp_max) < curdays) && (spent->sp_max != -1)) { + if (curdays < spent->sp_lstchg) { + _log_err(LOG_DEBUG, pamh + ,"account %s has password changed in future" + ,uname); + return PAM_SUCCESS; + } + if ((curdays - spent->sp_lstchg > spent->sp_max) + && (curdays - spent->sp_lstchg > spent->sp_inact) + && (curdays - spent->sp_lstchg > spent->sp_max + spent->sp_inact) + && (spent->sp_max != -1) && (spent->sp_inact != -1)) { + _log_err(LOG_NOTICE, pamh + ,"account %s has expired (failed to change password)" + ,uname); + _make_remark(pamh, ctrl, PAM_ERROR_MSG, + "Your account has expired; please contact your system administrator"); + D(("account expired 2")); + return PAM_ACCT_EXPIRED; + } + if ((curdays - spent->sp_lstchg > spent->sp_max) && (spent->sp_max != -1)) { _log_err(LOG_DEBUG, pamh ,"expired password for user %s (password aged)" ,uname); @@ -173,7 +182,7 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags, D(("need a new password 2")); return PAM_NEW_AUTHTOK_REQD; } - if ((curdays > (spent->sp_lstchg + spent->sp_max - spent->sp_warn)) + if ((curdays - spent->sp_lstchg > spent->sp_max - spent->sp_warn) && (spent->sp_max != -1) && (spent->sp_warn != -1)) { daysleft = (spent->sp_lstchg + spent->sp_max) - curdays; _log_err(LOG_DEBUG, pamh diff --git a/Linux-PAM/modules/pam_unix/pam_unix_auth.c b/Linux-PAM/modules/pam_unix/pam_unix_auth.c index 67497e06..39e0cde5 100644 --- a/Linux-PAM/modules/pam_unix/pam_unix_auth.c +++ b/Linux-PAM/modules/pam_unix/pam_unix_auth.c @@ -15,13 +15,13 @@ * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. - * + * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) - * + * * THIS SOFTWARE IS PROVIDED ``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 @@ -88,7 +88,8 @@ do { \ *ret_data = retval; \ pam_set_data(pamh, "unix_setcred_return", \ (void *) ret_data, setcred_free); \ - } \ + } else if (ret_data) \ + free (ret_data); \ D(("done. [%s]", pam_strerror(pamh, retval))); \ return retval; \ } while (0) @@ -148,7 +149,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags /* if this user does not have a password... */ - if (_unix_blankpasswd(ctrl, name)) { + if (_unix_blankpasswd(pamh, ctrl, name)) { D(("user '%s' has blank passwd", name)); name = NULL; retval = PAM_SUCCESS; @@ -183,7 +184,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags } -/* +/* * The only thing _pam_set_credentials_unix() does is initialization of * UNIX group IDs. * @@ -203,7 +204,7 @@ PAM_EXTERN int pam_sm_setcred(pam_handle_t * pamh, int flags retval = PAM_SUCCESS; D(("recovering return code from auth call")); - /* We will only find something here if UNIX_LIKE_AUTH is set -- + /* We will only find something here if UNIX_LIKE_AUTH is set -- don't worry about an explicit check of argv. */ pam_get_data(pamh, "unix_setcred_return", (const void **) &pretval); if(pretval) { diff --git a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c index 6b51a6b2..2ea57cc6 100644 --- a/Linux-PAM/modules/pam_unix/pam_unix_passwd.c +++ b/Linux-PAM/modules/pam_unix/pam_unix_passwd.c @@ -1,5 +1,5 @@ /* - * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. + * Main coding by Elliot Lee <sopwith@redhat.com>, Red Hat Software. * Copyright (C) 1996. * Copyright (c) Jan Rêkorajski, 1999. * @@ -73,6 +73,8 @@ #include <security/pam_appl.h> #endif /* LINUX_PAM */ +#include <security/_pam_modutil.h> + #include "yppasswd.h" #include "md5.h" #include "support.h" @@ -88,7 +90,7 @@ extern int getrpcport(const char *host, unsigned long prognum, */ #ifdef NEED_LCKPWDF -#include "./lckpwdf.-c" +# include "./lckpwdf.-c" #endif extern char *bigcrypt(const char *key, const char *salt); @@ -114,7 +116,9 @@ extern char *bigcrypt(const char *key, const char *salt); #define MAX_PASSWD_TRIES 3 #define PW_TMPFILE "/etc/npasswd" #define SH_TMPFILE "/etc/nshadow" +#ifndef CRACKLIB_DICTS #define CRACKLIB_DICTS "/usr/share/dict/cracklib_dict" +#endif #define OPW_TMPFILE "/etc/security/nopasswd" #define OLD_PASSWORDS_FILE "/etc/security/opasswd" @@ -215,7 +219,7 @@ static int check_old_password(const char *forwho, const char *newpass) opwfile = fopen(OLD_PASSWORDS_FILE, "r"); if (opwfile == NULL) - return PAM_AUTHTOK_ERR; + return PAM_ABORT; while (fgets(buf, 16380, opwfile)) { if (!strncmp(buf, forwho, strlen(forwho))) { @@ -242,7 +246,8 @@ static int check_old_password(const char *forwho, const char *newpass) return retval; } -static int save_old_password(const char *forwho, const char *oldpass, +static int save_old_password(pam_handle_t *pamh, + const char *forwho, const char *oldpass, int howmany) { static char buf[16384]; @@ -254,6 +259,7 @@ static int save_old_password(const char *forwho, const char *oldpass, int oldmask; int found = 0; struct passwd *pwd = NULL; + struct stat st; if (howmany < 0) { return PAM_SUCCESS; @@ -276,8 +282,25 @@ static int save_old_password(const char *forwho, const char *oldpass, return PAM_AUTHTOK_ERR; } - chown(OPW_TMPFILE, 0, 0); - chmod(OPW_TMPFILE, 0600); + if (fstat (fileno (opwfile), &st) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + + if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + if (fchmod (fileno (pwfile), st.st_mode) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } while (fgets(buf, 16380, opwfile)) { if (!strncmp(buf, forwho, strlen(forwho))) { @@ -314,7 +337,7 @@ static int save_old_password(const char *forwho, const char *oldpass, fclose(opwfile); if (!found) { - pwd = getpwnam(forwho); + pwd = _pammodutil_getpwnam(pamh, forwho); if (pwd == NULL) { err = 1; } else { @@ -335,18 +358,20 @@ static int save_old_password(const char *forwho, const char *oldpass, } if (!err) { - rename(OPW_TMPFILE, OLD_PASSWORDS_FILE); - return PAM_SUCCESS; - } else { - unlink(OPW_TMPFILE); - return PAM_AUTHTOK_ERR; + if (!rename(OPW_TMPFILE, OLD_PASSWORDS_FILE)) { + return PAM_SUCCESS; + } } + + unlink(OPW_TMPFILE); + return PAM_AUTHTOK_ERR; } static int _update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat) { struct passwd *tmpent = NULL; + struct stat st; FILE *pwfile, *opwfile; int err = 1; int oldmask; @@ -364,9 +389,26 @@ static int _update_passwd(pam_handle_t *pamh, return PAM_AUTHTOK_ERR; } - chown(PW_TMPFILE, 0, 0); - chmod(PW_TMPFILE, 0644); - tmpent = fgetpwent(opwfile); + if (fstat (fileno (opwfile), &st) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + + if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + if (fchmod (fileno (pwfile), st.st_mode) == -1) + { + fclose (opwfile); + fclose (pwfile); + } + + tmpent = fgetpwent (opwfile); while (tmpent) { if (!strcmp(tmpent->pw_name, forwho)) { /* To shut gcc up */ @@ -375,7 +417,7 @@ static int _update_passwd(pam_handle_t *pamh, char *charp; } assigned_passwd; assigned_passwd.const_charp = towhat; - + tmpent->pw_passwd = assigned_passwd.charp; err = 0; } @@ -394,18 +436,20 @@ static int _update_passwd(pam_handle_t *pamh, } if (!err) { - rename(PW_TMPFILE, "/etc/passwd"); - _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); - return PAM_SUCCESS; - } else { - unlink(PW_TMPFILE); - return PAM_AUTHTOK_ERR; + if (!rename(PW_TMPFILE, "/etc/passwd")) { + _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); + return PAM_SUCCESS; + } } + + unlink(PW_TMPFILE); + return PAM_AUTHTOK_ERR; } -static int _update_shadow(const char *forwho, char *towhat) +static int _update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) { struct spwd *spwdent = NULL, *stmpent = NULL; + struct stat st; FILE *pwfile, *opwfile; int err = 1; int oldmask; @@ -427,8 +471,26 @@ static int _update_shadow(const char *forwho, char *towhat) return PAM_AUTHTOK_ERR; } - chown(SH_TMPFILE, 0, 0); - chmod(SH_TMPFILE, 0600); + if (fstat (fileno (opwfile), &st) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + + if (fchown (fileno (pwfile), st.st_uid, st.st_gid) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + if (fchmod (fileno (pwfile), st.st_mode) == -1) + { + fclose (opwfile); + fclose (pwfile); + return PAM_AUTHTOK_ERR; + } + stmpent = fgetspent(opwfile); while (stmpent) { @@ -455,12 +517,14 @@ static int _update_shadow(const char *forwho, char *towhat) } if (!err) { - rename(SH_TMPFILE, "/etc/shadow"); - return PAM_SUCCESS; - } else { - unlink(SH_TMPFILE); - return PAM_AUTHTOK_ERR; + if (!rename(SH_TMPFILE, "/etc/shadow")) { + _log_err(LOG_NOTICE, pamh, "password changed for %s", forwho); + return PAM_SUCCESS; + } } + + unlink(SH_TMPFILE); + return PAM_AUTHTOK_ERR; } static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, @@ -471,14 +535,28 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, D(("called")); - setpwent(); pwd = getpwnam(forwho); - endpwent(); - if (pwd == NULL) - return PAM_AUTHTOK_ERR; + if (pwd == NULL) { + retval = PAM_AUTHTOK_ERR; + goto done; + } - if (on(UNIX_NIS, ctrl)) { + if (_unix_comesfromsource(pamh, forwho, 1, 0)) { + /* first, save old password */ + if (save_old_password(pamh, forwho, fromwhat, remember)) { + retval = PAM_AUTHTOK_ERR; + goto done; + } + if (on(UNIX_SHADOW, ctrl) || _unix_shadowed(pwd)) { + retval = _update_shadow(pamh, forwho, towhat); + if (retval == PAM_SUCCESS) + if (!_unix_shadowed(pwd)) + retval = _update_passwd(pamh, forwho, "x"); + } else { + retval = _update_passwd(pamh, forwho, towhat); + } + } else if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) { struct timeval timeout; struct yppasswd yppwd; CLIENT *clnt; @@ -486,6 +564,10 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, int status; int err = 0; + /* Unlock passwd file to avoid deadlock */ +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif /* Make RPC call to NIS server */ if ((master = getNISserver(pamh)) == NULL) return PAM_TRY_AGAIN; @@ -498,7 +580,7 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, yppwd.newpw.pw_gecos = pwd->pw_gecos; yppwd.newpw.pw_dir = pwd->pw_dir; yppwd.newpw.pw_shell = pwd->pw_shell; - yppwd.oldpass = fromwhat; + yppwd.oldpass = fromwhat ? fromwhat : ""; yppwd.newpw.pw_passwd = towhat; D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho)); @@ -540,17 +622,11 @@ static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat, #endif return retval; } - /* first, save old password */ - if (save_old_password(forwho, fromwhat, remember)) { - return PAM_AUTHTOK_ERR; - } - if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) { - retval = _update_shadow(forwho, towhat); - if (retval == PAM_SUCCESS) - retval = _update_passwd(pamh, forwho, "x"); - } else { - retval = _update_passwd(pamh, forwho, towhat); - } + +done: +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif return retval; } @@ -563,13 +639,11 @@ static int _unix_verify_shadow(const char *user, unsigned int ctrl) int retval = PAM_SUCCESS; /* UNIX passwords area */ - setpwent(); pwd = getpwnam(user); /* Get password file entry... */ - endpwent(); if (pwd == NULL) return PAM_AUTHINFO_UNAVAIL; /* We don't need to do the rest... */ - if (strcmp(pwd->pw_passwd, "x") == 0) { + if (_unix_shadowed(pwd)) { /* ...and shadow password file entry for this user, if shadowing is enabled */ setspent(); @@ -579,7 +653,7 @@ static int _unix_verify_shadow(const char *user, unsigned int ctrl) if (spwdent == NULL) return PAM_AUTHINFO_UNAVAIL; } else { - if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */ + if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */ uid_t save_uid; save_uid = geteuid(); @@ -661,11 +735,17 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh #else if (strlen(pass_new) < 6) remark = "You must choose a longer password"; - D(("lenth check [%s]", remark)); + D(("length check [%s]", remark)); #endif - if (on(UNIX_REMEMBER_PASSWD, ctrl)) - if ((retval = check_old_password(user, pass_new)) != PAM_SUCCESS) + if (on(UNIX_REMEMBER_PASSWD, ctrl)) { + if ((retval = check_old_password(user, pass_new)) == PAM_AUTHTOK_ERR) remark = "Password has been already used. Choose another."; + if (retval == PAM_ABORT) { + _log_err(LOG_ERR, pamh, "can't open %s file to check old passwords", + OLD_PASSWORDS_FILE); + return retval; + } + } } if (remark) { _make_remark(pamh, ctrl, PAM_ERROR_MSG, remark); @@ -689,33 +769,12 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, D(("called.")); -#ifdef USE_LCKPWDF - /* our current locking system requires that we lock the - entire password database. This avoids both livelock - and deadlock. */ - /* These values for the number of attempts and the sleep time - are, of course, completely arbitrary. - My reading of the PAM docs is that, once pam_chauthtok() has been - called with PAM_UPDATE_AUTHTOK, we are obliged to take any - reasonable steps to make sure the token is updated; so retrying - for 1/10 sec. isn't overdoing it. - The other possibility is to call lckpwdf() on the first - pam_chauthtok() pass, and hold the lock until released in the - second pass--but is this guaranteed to work? -SRL */ - i=0; - while((retval = lckpwdf()) != 0 && i < 100) { - usleep(1000); - } - if(retval != 0) { - return PAM_AUTHTOK_LOCK_BUSY; - } -#endif ctrl = _set_ctrl(pamh, flags, &remember, argc, argv); /* * First get the name of a user */ - retval = pam_get_user(pamh, &user, "Username: "); + retval = pam_get_user(pamh, &user, NULL); if (retval == PAM_SUCCESS) { /* * Various libraries at various times have had bugs related to @@ -725,9 +784,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, */ if (user == NULL || !isalnum(*user)) { _log_err(LOG_ERR, pamh, "bad username [%s]", user); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS && on(UNIX_DEBUG, ctrl)) @@ -737,15 +793,42 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (on(UNIX_DEBUG, ctrl)) _log_err(LOG_DEBUG, pamh, "password - could not identify user"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } D(("Got username of %s", user)); /* + * Before we do anything else, check to make sure that the user's + * info is in one of the databases we can modify from this module, + * which currently is 'files' and 'nis'. We have to do this because + * getpwnam() doesn't tell you *where* the information it gives you + * came from, nor should it. That's our job. + */ + if (_unix_comesfromsource(pamh, user, 1, 1) == 0) { + _log_err(LOG_DEBUG, pamh, + "user \"%s\" does not exist in /etc/passwd or NIS", + user); + return PAM_USER_UNKNOWN; + } else { + struct passwd *pwd; + _unix_getpwnam(pamh, user, 1, 1, &pwd); + if (pwd == NULL) { + _log_err(LOG_DEBUG, pamh, + "user \"%s\" has corrupted passwd entry", + user); + return PAM_USER_UNKNOWN; + } + if (!_unix_shadowed(pwd) && + (strchr(pwd->pw_passwd, '*') != NULL)) { + _log_err(LOG_DEBUG, pamh, + "user \"%s\" does not have modifiable password", + user); + return PAM_USER_UNKNOWN; + } + } + + /* * This is not an AUTH module! */ if (on(UNIX__NONULL, ctrl)) @@ -760,10 +843,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, D(("prelim check")); - if (_unix_blankpasswd(ctrl, user)) { -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif + if (_unix_blankpasswd(pamh, ctrl, user)) { return PAM_SUCCESS; } else if (off(UNIX__IAMROOT, ctrl)) { @@ -773,9 +853,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (Announce == NULL) { _log_err(LOG_CRIT, pamh, "password - out of memory"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return PAM_BUF_ERR; } (void) strcpy(Announce, greeting); @@ -795,9 +872,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh ,"password - (old) token not obtained"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } /* verify that this is the password for this user */ @@ -812,9 +886,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (retval != PAM_SUCCESS) { D(("Authentication failed")); pass_old = NULL; -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old); @@ -867,19 +938,9 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, if (retval != PAM_SUCCESS) { _log_err(LOG_NOTICE, pamh, "user not authenticated"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - return retval; - } - retval = _unix_verify_shadow(user, ctrl); - if (retval != PAM_SUCCESS) { - _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } + D(("get new password now")); lctrl = ctrl; @@ -908,9 +969,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, ,"password - new password not obtained"); } pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } D(("returned to _unix_chauthtok")); @@ -931,11 +989,56 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, _log_err(LOG_NOTICE, pamh, "new password not acceptable"); pass_new = pass_old = NULL; /* tidy up */ + return retval; + } +#ifdef USE_LCKPWDF + /* These values for the number of attempts and the sleep time + are, of course, completely arbitrary. + My reading of the PAM docs is that, once pam_chauthtok() has been + called with PAM_UPDATE_AUTHTOK, we are obliged to take any + reasonable steps to make sure the token is updated; so retrying + for 1/10 sec. isn't overdoing it. */ + i=0; + while((retval = lckpwdf()) != 0 && i < 100) { + usleep(1000); + i++; + } + if(retval != 0) { + return PAM_AUTHTOK_LOCK_BUSY; + } +#endif + + if (pass_old) { + retval = _unix_verify_password(pamh, user, pass_old, ctrl); + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh, "user password changed by another process"); +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + } + + retval = _unix_verify_shadow(user, ctrl); + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh, "user not authenticated 2"); #ifdef USE_LCKPWDF ulckpwdf(); #endif return retval; } + + retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); + if (retval != PAM_SUCCESS) { + _log_err(LOG_NOTICE, pamh, + "new password not acceptable 2"); + pass_new = pass_old = NULL; /* tidy up */ +#ifdef USE_LCKPWDF + ulckpwdf(); +#endif + return retval; + } + /* * By reaching here we have approved the passwords and must now * rebuild the password database file. @@ -962,7 +1065,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, salt[2] = '\0'; if (off(UNIX_BIGCRYPT, ctrl) && strlen(pass_new) > 8) { - /* + /* * to avoid using the _extensions_ of the bigcrypt() * function we truncate the newly entered password * [Problems that followed from this are fixed as per @@ -998,6 +1101,8 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, remember); + /* _do_setpass has called ulckpwdf for us */ + _pam_delete(tpass); pass_old = pass_new = NULL; } else { /* something has broken with the module */ @@ -1008,9 +1113,6 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, D(("retval was %d", retval)); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } @@ -1027,4 +1129,3 @@ struct pam_module _pam_unix_passwd_modstruct = { pam_sm_chauthtok, }; #endif - diff --git a/Linux-PAM/modules/pam_unix/pam_unix_sess.c b/Linux-PAM/modules/pam_unix/pam_unix_sess.c index 0784bff8..a29a7085 100644 --- a/Linux-PAM/modules/pam_unix/pam_unix_sess.c +++ b/Linux-PAM/modules/pam_unix/pam_unix_sess.c @@ -1,5 +1,5 @@ /* - * $Id: pam_unix_sess.c,v 1.1.1.1 2001/04/29 04:17:39 hartmans Exp $ + * $Id: pam_unix_sess.c,v 1.5 2005/03/23 14:35:21 t8m Exp $ * * Copyright Alexander O. Yuriev, 1996. All rights reserved. * Copyright Jan Rêkorajski, 1999. All rights reserved. @@ -53,6 +53,7 @@ #include <security/_pam_macros.h> #include <security/pam_modules.h> +#include <security/_pam_modutil.h> #ifndef LINUX_PAM #include <security/pam_appl.h> @@ -71,27 +72,31 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t * pamh, int flags, char *user_name, *service; unsigned int ctrl; int retval; + const char *login_name; D(("called.")); ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); - if (user_name == NULL || retval != PAM_SUCCESS) { + if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "open_session - error recovering username"); return PAM_SESSION_ERR; /* How did we get authenticated with no username?! */ } retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service); - if (service == NULL || retval != PAM_SUCCESS) { + if (service == NULL || *service == '\0' || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "open_session - error recovering service"); return PAM_SESSION_ERR; } - _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)" - ,user_name - ,PAM_getlogin() == NULL ? "" : PAM_getlogin(), getuid()); + login_name = _pammodutil_getlogin(pamh); + if (login_name == NULL) { + login_name = ""; + } + _log_err(LOG_INFO, pamh, "session opened for user %s by %s(uid=%d)", + user_name, login_name, getuid()); return PAM_SUCCESS; } @@ -108,14 +113,14 @@ PAM_EXTERN int pam_sm_close_session(pam_handle_t * pamh, int flags, ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); - if (user_name == NULL || retval != PAM_SUCCESS) { + if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "close_session - error recovering username"); return PAM_SESSION_ERR; /* How did we get authenticated with no username?! */ } retval = pam_get_item(pamh, PAM_SERVICE, (void *) &service); - if (service == NULL || retval != PAM_SUCCESS) { + if (service == NULL || *service == '\0' || retval != PAM_SUCCESS) { _log_err(LOG_CRIT, pamh, "close_session - error recovering service"); return PAM_SESSION_ERR; diff --git a/Linux-PAM/modules/pam_unix/support.c b/Linux-PAM/modules/pam_unix/support.c index 15861af6..1584f2f1 100644 --- a/Linux-PAM/modules/pam_unix/support.c +++ b/Linux-PAM/modules/pam_unix/support.c @@ -1,5 +1,5 @@ /* - * $Id: support.c,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $ + * $Id: support.c,v 1.25 2005/01/10 09:45:37 kukuk Exp $ * * Copyright information at end of file. */ @@ -9,6 +9,7 @@ #include <stdlib.h> #include <unistd.h> #include <stdarg.h> +#include <stdio.h> #include <string.h> #include <malloc.h> #include <pwd.h> @@ -16,9 +17,13 @@ #include <limits.h> #include <utmp.h> #include <errno.h> +#include <signal.h> +#include <ctype.h> +#include <rpcsvc/ypclnt.h> #include <security/_pam_macros.h> #include <security/pam_modules.h> +#include <security/_pam_modutil.h> #include "md5.h" #include "support.h" @@ -106,36 +111,6 @@ int _make_remark(pam_handle_t * pamh, unsigned int ctrl return retval; } - /* - * Beacause getlogin() is braindead and sometimes it just - * doesn't work, we reimplement it here. - */ -char *PAM_getlogin(void) -{ - struct utmp *ut, line; - char *curr_tty, *retval; - static char curr_user[sizeof(ut->ut_user) + 4]; - - retval = NULL; - - curr_tty = ttyname(0); - if (curr_tty != NULL) { - D(("PAM_getlogin ttyname: %s", curr_tty)); - curr_tty += 5; - setutent(); - strncpy(line.ut_line, curr_tty, sizeof(line.ut_line)); - if ((ut = getutline(&line)) != NULL) { - strncpy(curr_user, ut->ut_user, sizeof(ut->ut_user)); - curr_user[sizeof(curr_user) - 1] = '\0'; - retval = curr_user; - } - endutent(); - } - D(("PAM_getlogin retval: %s", retval)); - - return retval; -} - /* * set the control flags for the UNIX module. */ @@ -163,10 +138,6 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc, D(("PRELIM_CHECK")); set(UNIX__PRELIM, ctrl); } - if (flags & PAM_DISALLOW_NULL_AUTHTOK) { - D(("DISALLOW_NULL_AUTHTOK")); - set(UNIX__NONULL, ctrl); - } if (flags & PAM_SILENT) { D(("SILENT")); set(UNIX__QUIET, ctrl); @@ -195,7 +166,7 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc, if (remember != NULL) { if (j == UNIX_REMEMBER_PASSWD) { *remember = strtol(*argv + 9, NULL, 10); - if ((*remember == LONG_MIN) || (*remember == LONG_MAX)) + if ((*remember == INT_MIN) || (*remember == INT_MAX)) *remember = -1; if (*remember > 400) *remember = 400; @@ -206,6 +177,11 @@ int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc, ++argv; /* step to next argument */ } + if (flags & PAM_DISALLOW_NULL_AUTHTOK) { + D(("DISALLOW_NULL_AUTHTOK")); + set(UNIX__NONULL, ctrl); + } + /* auditing is a more sensitive version of debug */ if (on(UNIX_AUDIT, ctrl)) { @@ -304,25 +280,178 @@ static void _cleanup_failures(pam_handle_t * pamh, void *fl, int err) } /* + * _unix_getpwnam() searches only /etc/passwd and NIS to find user information + */ +static void _unix_cleanup(pam_handle_t *pamh, void *data, int error_status) +{ + free(data); +} + +int _unix_getpwnam(pam_handle_t *pamh, const char *name, + int files, int nis, struct passwd **ret) +{ + FILE *passwd; + char buf[16384]; + int matched = 0, buflen; + char *slogin, *spasswd, *suid, *sgid, *sgecos, *shome, *sshell, *p; + + memset(buf, 0, sizeof(buf)); + + if (!matched && files) { + int userlen = strlen(name); + passwd = fopen("/etc/passwd", "r"); + if (passwd != NULL) { + while (fgets(buf, sizeof(buf), passwd) != NULL) { + if ((buf[userlen] == ':') && + (strncmp(name, buf, userlen) == 0)) { + p = buf + strlen(buf) - 1; + while (isspace(*p) && (p >= buf)) { + *p-- = '\0'; + } + matched = 1; + break; + } + } + fclose(passwd); + } + } + + if (!matched && nis) { + char *userinfo = NULL, *domain = NULL; + int len = 0, i; + len = yp_get_default_domain(&domain); + if (len == YPERR_SUCCESS) { + len = yp_bind(domain); + } + if (len == YPERR_SUCCESS) { + i = yp_match(domain, "passwd.byname", name, + strlen(name), &userinfo, &len); + yp_unbind(domain); + if ((i == YPERR_SUCCESS) && (len < sizeof(buf))) { + strncpy(buf, userinfo, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + matched = 1; + } + } + } + + if (matched && (ret != NULL)) { + *ret = NULL; + + slogin = buf; + + spasswd = strchr(slogin, ':'); + if (spasswd == NULL) { + return matched; + } + *spasswd++ = '\0'; + + suid = strchr(spasswd, ':'); + if (suid == NULL) { + return matched; + } + *suid++ = '\0'; + + sgid = strchr(suid, ':'); + if (sgid == NULL) { + return matched; + } + *sgid++ = '\0'; + + sgecos = strchr(sgid, ':'); + if (sgecos == NULL) { + return matched; + } + *sgecos++ = '\0'; + + shome = strchr(sgecos, ':'); + if (shome == NULL) { + return matched; + } + *shome++ = '\0'; + + sshell = strchr(shome, ':'); + if (sshell == NULL) { + return matched; + } + *sshell++ = '\0'; + + buflen = sizeof(struct passwd) + + strlen(slogin) + 1 + + strlen(spasswd) + 1 + + strlen(suid) + 1 + + strlen(sgid) + 1 + + strlen(sgecos) + 1 + + strlen(shome) + 1 + + strlen(sshell) + 1; + *ret = malloc(buflen); + if (*ret == NULL) { + return matched; + } + memset(*ret, '\0', buflen); + + (*ret)->pw_uid = strtol(suid, &p, 10); + if ((strlen(sgid) == 0) || (*p != '\0')) { + free(*ret); + *ret = NULL; + return matched; + } + + (*ret)->pw_gid = strtol(sgid, &p, 10); + if ((strlen(sgid) == 0) || (*p != '\0')) { + free(*ret); + *ret = NULL; + return matched; + } + + p = ((char*)(*ret)) + sizeof(struct passwd); + (*ret)->pw_name = strcpy(p, slogin); + p += strlen(p) + 1; + (*ret)->pw_passwd = strcpy(p, spasswd); + p += strlen(p) + 1; + (*ret)->pw_gecos = strcpy(p, sgecos); + p += strlen(p) + 1; + (*ret)->pw_dir = strcpy(p, shome); + p += strlen(p) + 1; + (*ret)->pw_shell = strcpy(p, sshell); + + snprintf(buf, sizeof(buf), "_pam_unix_getpwnam_%s", name); + + if (pam_set_data(pamh, buf, + *ret, _unix_cleanup) != PAM_SUCCESS) { + free(*ret); + *ret = NULL; + } + } + + return matched; +} + +/* + * _unix_comsefromsource() is a quick check to see if information about a given + * user comes from a particular source (just files and nis for now) + * + */ +int _unix_comesfromsource(pam_handle_t *pamh, + const char *name, int files, int nis) +{ + return _unix_getpwnam(pamh, name, files, nis, NULL); +} + +/* * _unix_blankpasswd() is a quick check for a blank password * * returns TRUE if user does not have a password * - to avoid prompting for one in such cases (CG) */ -int _unix_blankpasswd(unsigned int ctrl, const char *name) +int +_unix_blankpasswd (pam_handle_t *pamh, unsigned int ctrl, const char *name) { struct passwd *pwd = NULL; struct spwd *spwdent = NULL; char *salt = NULL; int retval; -#if HAVE_GETPWNAM_R - char *buf = NULL; - int bufsize = 0; - struct passwd pwd_buf; - - pwd = &pwd_buf; -#endif D(("called")); @@ -338,23 +467,7 @@ int _unix_blankpasswd(unsigned int ctrl, const char *name) /* UNIX passwords area */ /* Get password file entry... */ -#if HAVE_GETPWNAM_R - bufsize = 1024; - buf = malloc(bufsize); - - if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) { - pwd = NULL; - } - while (retval == ERANGE) { - bufsize += 1024; - buf = realloc(buf, bufsize); - if ((retval = getpwnam_r(name, pwd, buf, bufsize, &pwd))) { - pwd = NULL; - } - } -#else - pwd = getpwnam(name); -#endif + pwd = _pammodutil_getpwnam (pamh, name); if (pwd != NULL) { if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) @@ -372,28 +485,24 @@ int _unix_blankpasswd(unsigned int ctrl, const char *name) setreuid( 0, -1 ); if(setreuid( -1, pwd->pw_uid ) == -1) /* Will fail elsewhere. */ -#if HAVE_GETPWNAM_R - if (buf) - free(buf); -#endif return 0; } } - spwdent = getspnam( name ); + spwdent = _pammodutil_getspnam (pamh, name); if (save_uid == pwd->pw_uid) setreuid( save_uid, save_euid ); else { if (setreuid( -1, 0 ) == -1) - setreuid( save_uid, -1 ); + setreuid( save_uid, -1 ); setreuid( -1, save_euid ); } - } else if (strcmp(pwd->pw_passwd, "x") == 0) { + } else if (_unix_shadowed(pwd)) { /* * ...and shadow password file entry for this user, * if shadowing is enabled */ - spwdent = getspnam(name); + spwdent = _pammodutil_getspnam(pamh, name); } if (spwdent) salt = x_strdup(spwdent->sp_pwdp); @@ -415,11 +524,6 @@ int _unix_blankpasswd(unsigned int ctrl, const char *name) if (salt) _pam_delete(salt); -#if HAVE_GETPWNAM_R - if (buf) - free(buf); -#endif - return retval; } @@ -434,6 +538,7 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, unsigned int ctrl, const char *user) { int retval, child, fds[2]; + void (*sighandler)(int) = NULL; D(("called.")); /* create a pipe for the password */ @@ -442,6 +547,18 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, return PAM_AUTH_ERR; } + if (off(UNIX_NOREAP, ctrl)) { + /* + * This code arranges that the demise of the child does not cause + * the application to receive a signal it is not expecting - which + * may kill the application or worse. + * + * The "noreap" module argument is provided so that the admin can + * override this behavior. + */ + sighandler = signal(SIGCHLD, SIG_DFL); + } + /* fork */ child = fork(); if (child == 0) { @@ -486,6 +603,10 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, retval = PAM_AUTH_ERR; } + if (sighandler != NULL) { + (void) signal(SIGCHLD, sighandler); /* restore old signal handler */ + } + D(("returning %d", retval)); return retval; } @@ -514,7 +635,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name D(("locating user's record")); /* UNIX passwords area */ - pwd = getpwnam(name); /* Get password file entry... */ + pwd = _pammodutil_getpwnam (pamh, name); /* Get password file entry... */ if (pwd != NULL) { if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) @@ -535,7 +656,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name } } - spwdent = getspnam( name ); + spwdent = _pammodutil_getspnam (pamh, name); if (save_uid == pwd->pw_uid) setreuid( save_uid, save_euid ); else { @@ -543,12 +664,12 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name setreuid( save_uid, -1 ); setreuid( -1, save_euid ); } - } else if (strcmp(pwd->pw_passwd, "x") == 0) { + } else if (_unix_shadowed(pwd)) { /* * ...and shadow password file entry for this user, * if shadowing is enabled */ - spwdent = getspnam(name); + spwdent = _pammodutil_getspnam (pamh, name); } if (spwdent) salt = x_strdup(spwdent->sp_pwdp); @@ -565,7 +686,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name } retval = PAM_SUCCESS; - if (pwd == NULL || salt == NULL || !strcmp(salt, "x")) { + if (pwd == NULL || salt == NULL || !strcmp(salt, "x") || ((salt[0] == '#') && (salt[1] == '#') && !strcmp(salt + 2, name))) { if (geteuid()) { /* we are not root perhaps this is the reason? Run helper */ D(("running helper binary")); @@ -577,6 +698,11 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name } } else { D(("user's record unavailable")); + p = NULL; + if (pwd == NULL) + retval = PAM_USER_UNKNOWN; + else + retval = PAM_AUTHINFO_UNAVAIL; if (on(UNIX_AUDIT, ctrl)) { /* this might be a typo and the user has given a password instead of a username. Careful with this. */ @@ -584,54 +710,58 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name "check pass; user (%s) unknown", name); } else { name = NULL; - _log_err(LOG_ALERT, pamh, - "check pass; user unknown"); + if (on(UNIX_DEBUG, ctrl) || pwd == NULL) { + _log_err(LOG_ALERT, pamh, + "check pass; user unknown"); + } else { + /* don't log failure as another pam module can succeed */ + goto cleanup; + } } - p = NULL; - retval = PAM_AUTHINFO_UNAVAIL; } } else { - if (!strlen(salt)) { - /* the stored password is NULL */ - if (off(UNIX__NONULL, ctrl)) { /* this means we've succeeded */ - D(("user has empty password - access granted")); - retval = PAM_SUCCESS; - } else { - D(("user has empty password - access denied")); - retval = PAM_AUTH_ERR; - } - } else if (!p) { - retval = PAM_AUTH_ERR; + int salt_len = strlen(salt); + if (!salt_len) { + /* the stored password is NULL */ + if (off(UNIX__NONULL, ctrl)) {/* this means we've succeeded */ + D(("user has empty password - access granted")); + retval = PAM_SUCCESS; } else { - if (!strncmp(salt, "$1$", 3)) { - pp = Goodcrypt_md5(p, salt); - if (strcmp(pp, salt) != 0) { - _pam_delete(pp); - pp = Brokencrypt_md5(p, salt); - } - } else { - pp = bigcrypt(p, salt); - } - p = NULL; /* no longer needed here */ + D(("user has empty password - access denied")); + retval = PAM_AUTH_ERR; + } + } else if (!p || (*salt == '*') || (salt_len < 13)) { + retval = PAM_AUTH_ERR; + } else { + if (!strncmp(salt, "$1$", 3)) { + pp = Goodcrypt_md5(p, salt); + if (strcmp(pp, salt) != 0) { + _pam_delete(pp); + pp = Brokencrypt_md5(p, salt); + } + } else { + pp = bigcrypt(p, salt); + } + p = NULL; /* no longer needed here */ - /* the moment of truth -- do we agree with the password? */ - D(("comparing state of pp[%s] and salt[%s]", pp, salt)); + /* the moment of truth -- do we agree with the password? */ + D(("comparing state of pp[%s] and salt[%s]", pp, salt)); - /* - * Note, we are comparing the bigcrypt of the password with - * the contents of the password field. If the latter was - * encrypted with regular crypt (and not bigcrypt) it will - * have been truncated for storage relative to the output - * of bigcrypt here. As such we need to compare only the - * stored string with the subset of bigcrypt's result. - * Bug 521314: The strncmp comparison is for legacy support. - */ - if (strncmp(pp, salt, strlen(salt)) == 0) { - retval = PAM_SUCCESS; - } else { - retval = PAM_AUTH_ERR; - } + /* + * Note, we are comparing the bigcrypt of the password with + * the contents of the password field. If the latter was + * encrypted with regular crypt (and not bigcrypt) it will + * have been truncated for storage relative to the output + * of bigcrypt here. As such we need to compare only the + * stored string with the subset of bigcrypt's result. + * Bug 521314: The strncmp comparison is for legacy support. + */ + if (strncmp(pp, salt, salt_len) == 0) { + retval = PAM_SUCCESS; + } else { + retval = PAM_AUTH_ERR; } + } } if (retval == PAM_SUCCESS) { @@ -649,10 +779,17 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name if (new != NULL) { - new->user = x_strdup(name ? name : ""); + const char *login_name; + + login_name = _pammodutil_getlogin(pamh); + if (login_name == NULL) { + login_name = ""; + } + + new->user = x_strdup(name ? name : ""); new->uid = getuid(); new->euid = geteuid(); - new->name = x_strdup(PAM_getlogin()? PAM_getlogin() : ""); + new->name = x_strdup(login_name); /* any previous failures for this user ? */ pam_get_data(pamh, data_name, (const void **) &old); @@ -702,6 +839,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name } } +cleanup: if (data_name) _pam_delete(data_name); if (salt) @@ -762,7 +900,7 @@ int _unix_read_password(pam_handle_t * pamh return PAM_AUTHTOK_RECOVER_ERR; /* didn't work */ } else if (on(UNIX_USE_AUTHTOK, ctrl) && off(UNIX__OLD_PASSWD, ctrl)) { - return PAM_AUTHTOK_RECOVER_ERR; + return PAM_AUTHTOK_ERR; } } /* @@ -884,6 +1022,21 @@ int _unix_read_password(pam_handle_t * pamh return PAM_SUCCESS; } +int _unix_shadowed(const struct passwd *pwd) +{ + if (pwd != NULL) { + if (strcmp(pwd->pw_passwd, "x") == 0) { + return 1; + } + if ((pwd->pw_passwd[0] == '#') && + (pwd->pw_passwd[1] == '#') && + (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) { + return 1; + } + } + return 0; +} + /* ****************************************************************** * * Copyright (c) Jan Rêkorajski 1999. * Copyright (c) Andrew G. Morgan 1996-8. diff --git a/Linux-PAM/modules/pam_unix/support.h b/Linux-PAM/modules/pam_unix/support.h index 368a4e8f..39abadd5 100644 --- a/Linux-PAM/modules/pam_unix/support.h +++ b/Linux-PAM/modules/pam_unix/support.h @@ -1,10 +1,11 @@ /* - * $Id: support.h,v 1.1.1.1 2001/04/29 04:17:41 hartmans Exp $ + * $Id: support.h,v 1.8 2004/10/06 13:42:36 kukuk Exp $ */ #ifndef _PAM_UNIX_SUPPORT_H #define _PAM_UNIX_SUPPORT_H +#include <pwd.h> /* * here is the string to inform the user that the new passwords they @@ -80,8 +81,11 @@ typedef struct { #define UNIX_BIGCRYPT 18 /* use DEC-C2 crypt()^x function */ #define UNIX_LIKE_AUTH 19 /* need to auth for setcred to work */ #define UNIX_REMEMBER_PASSWD 20 /* Remember N previous passwords */ +#define UNIX_NOREAP 21 /* don't reap child process */ +#define UNIX_BROKEN_SHADOW 22 /* ignore errors reading password aging + * information during acct management */ /* -------------- */ -#define UNIX_CTRLS_ 21 /* number of ctrl arguments defined */ +#define UNIX_CTRLS_ 23 /* number of ctrl arguments defined */ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = @@ -110,6 +114,8 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = /* UNIX_BIGCRYPT */ {"bigcrypt", _ALL_ON_^(020000), 0400000}, /* UNIX_LIKE_AUTH */ {"likeauth", _ALL_ON_, 01000000}, /* UNIX_REMEMBER_PASSWD */ {"remember=", _ALL_ON_, 02000000}, +/* UNIX_NOREAP */ {"noreap", _ALL_ON_, 04000000}, +/* UNIX_BROKEN_SHADOW */ {"broken_shadow", _ALL_ON_, 010000000}, }; #define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) @@ -123,13 +129,18 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = _pam_drop(xx); \ } -extern char *PAM_getlogin(void); extern void _log_err(int err, pam_handle_t *pamh, const char *format,...); extern int _make_remark(pam_handle_t * pamh, unsigned int ctrl ,int type, const char *text); extern int _set_ctrl(pam_handle_t * pamh, int flags, int *remember, int argc, const char **argv); -extern int _unix_blankpasswd(unsigned int ctrl, const char *name); +extern int _unix_getpwnam (pam_handle_t *pamh, + const char *name, int files, int nis, + struct passwd **ret); +extern int _unix_comesfromsource (pam_handle_t *pamh, + const char *name, int files, int nis); +extern int _unix_blankpasswd(pam_handle_t *pamh,unsigned int ctrl, + const char *name); extern int _unix_verify_password(pam_handle_t * pamh, const char *name ,const char *p, unsigned int ctrl); extern int _unix_read_password(pam_handle_t * pamh @@ -139,6 +150,6 @@ extern int _unix_read_password(pam_handle_t * pamh ,const char *prompt2 ,const char *data_name ,const char **pass); +extern int _unix_shadowed(const struct passwd *pwd); #endif /* _PAM_UNIX_SUPPORT_H */ - diff --git a/Linux-PAM/modules/pam_unix/unix_chkpwd.c b/Linux-PAM/modules/pam_unix/unix_chkpwd.c index 6188435f..be32348f 100644 --- a/Linux-PAM/modules/pam_unix/unix_chkpwd.c +++ b/Linux-PAM/modules/pam_unix/unix_chkpwd.c @@ -1,5 +1,5 @@ /* - * $Id: unix_chkpwd.c,v 1.1.1.2 2002/09/15 20:09:02 hartmans Exp $ + * $Id: unix_chkpwd.c,v 1.11 2004/11/16 14:27:42 toady Exp $ * * This program is designed to run setuid(root) or with sufficient * privilege to read all of the unix password databases. It is designed @@ -57,8 +57,31 @@ static void _log_err(int err, const char *format,...) closelog(); } +static int _unix_shadowed(const struct passwd *pwd) +{ + char hashpass[1024]; + if (pwd != NULL) { + if (strcmp(pwd->pw_passwd, "x") == 0) { + return 1; + } + if (strlen(pwd->pw_name) < sizeof(hashpass) - 2) { + strcpy(hashpass, "##"); + strcpy(hashpass + 2, pwd->pw_name); + if (strcmp(pwd->pw_passwd, hashpass) == 0) { + return 1; + } + } + } + return 0; +} + static void su_sighandler(int sig) { +#ifndef SA_RESETHAND + /* emulate the behaviour of the SA_RESETHAND flag */ + if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV ) + signal(sig, SIG_DFL); +#endif if (sig > 0) { _log_err(LOG_NOTICE, "caught signal %d.", sig); exit(sig); @@ -74,7 +97,9 @@ static void setup_signals(void) */ (void) memset((void *) &action, 0, sizeof(action)); action.sa_handler = su_sighandler; +#ifdef SA_RESETHAND action.sa_flags = SA_RESETHAND; +#endif (void) sigaction(SIGILL, &action, NULL); (void) sigaction(SIGTRAP, &action, NULL); (void) sigaction(SIGBUS, &action, NULL); @@ -87,20 +112,21 @@ static void setup_signals(void) (void) sigaction(SIGQUIT, &action, NULL); } -static int _unix_verify_password(const char *name, const char *p, int opt) +static int _unix_verify_password(const char *name, const char *p, int nullok) { struct passwd *pwd = NULL; struct spwd *spwdent = NULL; char *salt = NULL; char *pp = NULL; int retval = UNIX_FAILED; + int salt_len; /* UNIX passwords area */ setpwent(); pwd = getpwnam(name); /* Get password file entry... */ endpwent(); if (pwd != NULL) { - if (strcmp(pwd->pw_passwd, "x") == 0) { + if (_unix_shadowed(pwd)) { /* * ...and shadow password file entry for this user, * if shadowing is enabled @@ -133,8 +159,11 @@ static int _unix_verify_password(const char *name, const char *p, int opt) return retval; } - if (strlen(salt) == 0) - return (opt == 0) ? UNIX_FAILED : UNIX_PASSED; + salt_len = strlen(salt); + if (salt_len == 0) + return (nullok == 0) ? UNIX_FAILED : UNIX_PASSED; + else if (p == NULL || strlen(p) == 0) + return UNIX_FAILED; /* the moment of truth -- do we agree with the password? */ retval = UNIX_FAILED; @@ -147,6 +176,8 @@ static int _unix_verify_password(const char *name, const char *p, int opt) if (strcmp(pp, salt) == 0) retval = UNIX_PASSED; } + } else if ((*salt == '*') || (salt_len < 13)) { + retval = UNIX_FAILED; } else { pp = bigcrypt(p, salt); /* @@ -158,7 +189,7 @@ static int _unix_verify_password(const char *name, const char *p, int opt) * stored string with the subset of bigcrypt's result. * Bug 521314: the strncmp comparison is for legacy support. */ - if (strncmp(pp, salt, strlen(salt)) == 0) { + if (strncmp(pp, salt, salt_len) == 0) { retval = UNIX_PASSED; } } @@ -197,7 +228,7 @@ int main(int argc, char *argv[]) { char pass[MAXPASS + 1]; char option[8]; - int npass, opt; + int npass, nullok; int force_failure = 0; int retval = UNIX_FAILED; char *user; @@ -250,9 +281,9 @@ int main(int argc, char *argv[]) } else { option[7] = '\0'; if (strncmp(option, "nullok", 8) == 0) - opt = 1; + nullok = 1; else - opt = 0; + nullok = 0; } /* read the password from stdin (a pipe from the pam_unix module) */ @@ -271,13 +302,13 @@ int main(int argc, char *argv[]) if (npass == 0) { /* the password is NULL */ - retval = _unix_verify_password(user, NULL, opt); + retval = _unix_verify_password(user, NULL, nullok); } else { /* does pass agree with the official one? */ pass[npass] = '\0'; /* NUL terminate */ - retval = _unix_verify_password(user, pass, opt); + retval = _unix_verify_password(user, pass, nullok); } } |