From c5d3ee3a3fa72d28f4850ac400f52782a0d8c08d Mon Sep 17 00:00:00 2001 From: Tomáš Mráz Date: Jan 08 2008 18:56:11 +0000 Subject: - support for sha256 and sha512 password hashes - account expiry checks moved to unix_chkpwd helper --- diff --git a/pam-0.99.7.1-unix-hpux-aging.patch b/pam-0.99.7.1-unix-hpux-aging.patch deleted file mode 100644 index 11d5274..0000000 --- a/pam-0.99.7.1-unix-hpux-aging.patch +++ /dev/null @@ -1,77 +0,0 @@ -o For non-extensible-style hashes, strip off anything after the 13th character - which would not be valid as part of a hash. On HP/UX, this clips off a comma - followed by encoded aging information. - - The real problem is a complete lack of any standard for storing password - aging information (actually, for anything having to do with password aging) - for users across operating systems, but there's nothing we can do about that - here. - ---- Linux-PAM-0.99.7.1/modules/pam_unix/support.c.unix-hpux-aging 2007-06-01 15:21:08.000000000 +0200 -+++ Linux-PAM-0.99.7.1/modules/pam_unix/support.c 2007-06-01 15:24:32.000000000 +0200 -@@ -573,6 +573,21 @@ - return retval; - } - -+static void strip_hpux_aging(char *p) -+{ -+ const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -+ "abcdefghijklmnopqrstuvwxyz" -+ "0123456789./"; -+ if ((*p != '$') && (strlen(p) > 13)) { -+ for (p += 13; *p != '\0'; p++) { -+ if (strchr(valid, *p) == NULL) { -+ *p = '\0'; -+ break; -+ } -+ } -+ } -+} -+ - int _unix_verify_password(pam_handle_t * pamh, const char *name - ,const char *p, unsigned int ctrl) - { -@@ -679,7 +694,9 @@ - } - } - } else { -- size_t salt_len = strlen(salt); -+ size_t salt_len; -+ strip_hpux_aging(salt); -+ salt_len = strlen(salt); - if (!salt_len) { - /* the stored password is NULL */ - if (off(UNIX__NONULL, ctrl)) {/* this means we've succeeded */ ---- Linux-PAM-0.99.7.1/modules/pam_unix/passverify.c.unix-hpux-aging 2007-06-01 15:21:08.000000000 +0200 -+++ Linux-PAM-0.99.7.1/modules/pam_unix/passverify.c 2007-06-01 15:26:26.000000000 +0200 -@@ -146,6 +146,22 @@ - return i; - } - -+static void -+strip_hpux_aging(char *p) -+{ -+ const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -+ "abcdefghijklmnopqrstuvwxyz" -+ "0123456789./"; -+ if ((*p != '$') && (strlen(p) > 13)) { -+ for (p += 13; *p != '\0'; p++) { -+ if (strchr(valid, *p) == NULL) { -+ *p = '\0'; -+ break; -+ } -+ } -+ } -+} -+ - int - _unix_verify_password(const char *name, const char *p, int nullok) - { -@@ -194,6 +210,7 @@ - return PAM_USER_UNKNOWN; - } - -+ strip_hpux_aging(salt); - salt_len = strlen(salt); - if (salt_len == 0) { - return (nullok == 0) ? PAM_AUTH_ERR : PAM_SUCCESS; diff --git a/pam-0.99.8.1-unix-blankpass.patch b/pam-0.99.8.1-unix-blankpass.patch deleted file mode 100644 index 9a1c054..0000000 --- a/pam-0.99.8.1-unix-blankpass.patch +++ /dev/null @@ -1,64 +0,0 @@ -diff -up Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.blankpass Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c ---- Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.blankpass 2007-09-18 13:50:40.000000000 +0200 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c 2007-09-18 13:50:40.000000000 +0200 -@@ -50,7 +50,7 @@ int main(int argc, char *argv[]) - char pass[MAXPASS + 1]; - char *option; - int npass, nullok; -- int force_failure = 0; -+ int blankpass = 0; - int retval = PAM_AUTH_ERR; - char *user; - char *passwords[] = { pass }; -@@ -115,6 +115,10 @@ int main(int argc, char *argv[]) - if (npass != 1) { /* is it a valid password? */ - _log_err(LOG_DEBUG, "no valid password supplied"); - } -+ -+ if (*pass == '\0') { -+ blankpass = 1; -+ } - - retval = _unix_verify_password(user, pass, nullok); - -@@ -122,8 +126,11 @@ int main(int argc, char *argv[]) - - /* return pass or fail */ - -- if ((retval != PAM_SUCCESS) || force_failure) { -- _log_err(LOG_NOTICE, "password check failed for user (%s)", user); -+ if (retval != PAM_SUCCESS) { -+ /* don't log if it is a test for blank password */ -+ if (!blankpass) { -+ _log_err(LOG_NOTICE, "password check failed for user (%s)", user); -+ } - return PAM_AUTH_ERR; - } else { - return PAM_SUCCESS; -diff -up Linux-PAM-0.99.8.1/modules/pam_unix/support.c.blankpass Linux-PAM-0.99.8.1/modules/pam_unix/support.c ---- Linux-PAM-0.99.8.1/modules/pam_unix/support.c.blankpass 2007-09-18 13:50:40.000000000 +0200 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/support.c 2007-09-18 17:56:57.000000000 +0200 -@@ -38,6 +38,9 @@ - - const char app_name[]="pam_unix"; - -+static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd, -+ unsigned int ctrl, const char *user); -+ - /* this is a front-end for module-application conversations */ - - int _make_remark(pam_handle_t * pamh, unsigned int ctrl, -@@ -442,6 +445,13 @@ _unix_blankpasswd (pam_handle_t *pamh, u - * ...and shadow password file entry for this user, - * if shadowing is enabled - */ -+ if (geteuid() || SELINUX_ENABLED) { -+ /* We do not have direct access to shadow. Run helper. */ -+ D(("running helper binary")); -+ if (_unix_run_helper_binary(pamh, "", ctrl, name) == PAM_SUCCESS) -+ return 1; -+ return 0; -+ } - spwdent = pam_modutil_getspnam(pamh, name); - } - if (spwdent) diff --git a/pam-0.99.8.1-unix-hpux-aging.patch b/pam-0.99.8.1-unix-hpux-aging.patch new file mode 100644 index 0000000..72966dc --- /dev/null +++ b/pam-0.99.8.1-unix-hpux-aging.patch @@ -0,0 +1,50 @@ +diff -up Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h.unix-hpux-aging Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h +--- Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h.unix-hpux-aging 2008-01-08 14:43:36.000000000 +0100 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h 2008-01-08 15:49:43.000000000 +0100 +@@ -13,7 +13,7 @@ + #define OLD_PASSWORDS_FILE "/etc/security/opasswd" + + int +-verify_pwd_hash(const char *p, const char *hash, unsigned int nullok); ++verify_pwd_hash(const char *p, char *hash, unsigned int nullok); + + int + is_pwd_shadowed(const struct passwd *pwd); +diff -up Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c.unix-hpux-aging Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c +--- Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c.unix-hpux-aging 2008-01-08 14:43:36.000000000 +0100 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c 2008-01-08 15:49:02.000000000 +0100 +@@ -44,14 +44,32 @@ + # include "./lckpwdf.-c" + #endif + ++static void ++strip_hpux_aging(char *p) ++{ ++ const char *valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++ "abcdefghijklmnopqrstuvwxyz" ++ "0123456789./"; ++ if ((*p != '$') && (strlen(p) > 13)) { ++ for (p += 13; *p != '\0'; p++) { ++ if (strchr(valid, *p) == NULL) { ++ *p = '\0'; ++ break; ++ } ++ } ++ } ++} ++ + int +-verify_pwd_hash(const char *p, const char *hash, unsigned int nullok) ++verify_pwd_hash(const char *p, char *hash, unsigned int nullok) + { +- size_t hash_len = strlen(hash); ++ size_t hash_len; + char *pp = NULL; + int retval; + D(("called")); + ++ strip_hpux_aging(hash); ++ hash_len = strlen(hash); + if (!hash_len) { + /* the stored password is NULL */ + if (nullok) { /* this means we've succeeded */ diff --git a/pam-0.99.8.1-unix-update-helper.patch b/pam-0.99.8.1-unix-update-helper.patch index 93baab4..c4e1b42 100644 --- a/pam-0.99.8.1-unix-update-helper.patch +++ b/pam-0.99.8.1-unix-update-helper.patch @@ -1,14 +1,51 @@ +diff -up Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_sess.c.update-helper Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_sess.c +--- Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_sess.c.update-helper 2006-06-17 18:44:58.000000000 +0200 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_sess.c 2008-01-07 16:39:07.000000000 +0100 +@@ -73,7 +73,7 @@ PAM_EXTERN int pam_sm_open_session(pam_h + + D(("called.")); + +- ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); ++ ctrl = _set_ctrl(pamh, flags, NULL, NULL, argc, argv); + + retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); + if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) { +@@ -107,7 +107,7 @@ PAM_EXTERN int pam_sm_close_session(pam_ + + D(("called.")); + +- ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); ++ ctrl = _set_ctrl(pamh, flags, NULL, NULL, argc, argv); + + retval = pam_get_item(pamh, PAM_USER, (void *) &user_name); + if (user_name == NULL || *user_name == '\0' || retval != PAM_SUCCESS) { diff -up Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c.update-helper Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c --- Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c.update-helper 2007-04-30 12:47:30.000000000 +0200 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c 2007-09-18 09:52:43.000000000 +0200 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c 2008-01-08 16:17:32.000000000 +0100 @@ -2,6 +2,7 @@ * Main coding by Elliot Lee , Red Hat Software. * Copyright (C) 1996. * Copyright (c) Jan R�korajski, 1999. -+ * Copyright (c) Red Hat, Inc., 2007. ++ * Copyright (c) Red Hat, Inc., 2007, 2008. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions +@@ -63,7 +64,6 @@ + #ifdef WITH_SELINUX + static int selinux_enabled=-1; + #include +-static security_context_t prev_context=NULL; + #define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : (selinux_enabled=is_selinux_enabled()>0)) + #endif + +@@ -84,6 +84,7 @@ static security_context_t prev_context=N + #include "yppasswd.h" + #include "md5.h" + #include "support.h" ++#include "passverify.h" + #include "bigcrypt.h" + + #if !((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)) @@ -92,15 +93,6 @@ extern int getrpcport(const char *host, #endif /* GNU libc 2.1 */ @@ -159,64 +196,7 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c.update-helper Lin retval = PAM_AUTH_ERR; } else { retval = WEXITSTATUS(retval); -@@ -315,8 +249,56 @@ static int _unix_run_shadow_binary(pam_h - - return retval; - } -+ -+static int selinux_confined(void) -+{ -+ static int confined = -1; -+ int fd; -+ char tempfile[]="/etc/.pwdXXXXXX"; -+ -+ if (confined != -1) -+ return confined; -+ -+ /* cannot be confined without SELinux enabled */ -+ if (!SELINUX_ENABLED){ -+ confined = 0; -+ return confined; -+ } -+ -+ /* let's try opening shadow read only */ -+ if ((fd=open("/etc/shadow", O_RDONLY)) != -1) { -+ close(fd); -+ confined = 0; -+ return confined; -+ } -+ -+ if (errno == EACCES) { -+ confined = 1; -+ return confined; -+ } -+ -+ /* shadow opening failed because of other reasons let's try -+ creating a file in /etc */ -+ if ((fd=mkstemp(tempfile)) != -1) { -+ unlink(tempfile); -+ close(fd); -+ confined = 0; -+ return confined; -+ } -+ -+ confined = 1; -+ return confined; -+} -+ -+#else -+static int selinux_confined(void) -+{ -+ return 0; -+} - #endif - -+#include "passupdate.c" -+ - static int check_old_password(const char *forwho, const char *newpass) - { - static char buf[16384]; -@@ -354,393 +336,6 @@ static int check_old_password(const char +@@ -354,393 +288,6 @@ static int check_old_password(const char return retval; } @@ -610,18 +590,22 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c.update-helper Lin static int _do_setpass(pam_handle_t* pamh, const char *forwho, const char *fromwhat, char *towhat, unsigned int ctrl, int remember) -@@ -769,7 +364,7 @@ static int _do_setpass(pam_handle_t* pam +@@ -768,9 +315,7 @@ static int _do_setpass(pam_handle_t* pam + enum clnt_stat err; /* Unlock passwd file to avoid deadlock */ - #ifdef USE_LCKPWDF +-#ifdef USE_LCKPWDF - ulckpwdf(); +-#endif + unlock_pwdf(); - #endif unlocked = 1; -@@ -832,33 +427,22 @@ static int _do_setpass(pam_handle_t* pam + /* Initialize password information */ +@@ -830,129 +375,63 @@ static int _do_setpass(pam_handle_t* pam + } + if (_unix_comesfromsource(pamh, forwho, 1, 0)) { - #ifdef USE_LCKPWDF +-#ifdef USE_LCKPWDF if(unlocked) { - int i = 0; - /* These values for the number of attempts and the sleep time @@ -639,72 +623,169 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c.update-helper Lin return PAM_AUTHTOK_LOCK_BUSY; } } - #endif +#ifdef WITH_SELINUX -+ if (selinux_confined()) ++ if (unix_selinux_confined()) + return _unix_run_update_binary(pamh, ctrl, forwho, fromwhat, towhat, remember); -+#endif + #endif /* first, save old password */ - if (save_old_password(pamh, forwho, fromwhat, remember)) { + if (save_old_password(forwho, fromwhat, remember)) { retval = PAM_AUTHTOK_ERR; goto done; } - if (on(UNIX_SHADOW, ctrl) || _unix_shadowed(pwd)) { - retval = _update_shadow(pamh, forwho, towhat); +- if (on(UNIX_SHADOW, ctrl) || _unix_shadowed(pwd)) { +- retval = _update_shadow(pamh, forwho, towhat); -#ifdef WITH_SELINUX - if (retval != PAM_SUCCESS && SELINUX_ENABLED) - retval = _unix_run_shadow_binary(pamh, ctrl, forwho, fromwhat, towhat); -#endif ++ if (on(UNIX_SHADOW, ctrl) || is_pwd_shadowed(pwd)) { ++ retval = unix_update_shadow(pamh, forwho, towhat); if (retval == PAM_SUCCESS) - if (!_unix_shadowed(pwd)) - retval = _update_passwd(pamh, forwho, "x"); -@@ -870,7 +454,7 @@ static int _do_setpass(pam_handle_t* pam +- if (!_unix_shadowed(pwd)) +- retval = _update_passwd(pamh, forwho, "x"); ++ if (!is_pwd_shadowed(pwd)) ++ retval = unix_update_passwd(pamh, forwho, "x"); + } else { +- retval = _update_passwd(pamh, forwho, towhat); ++ retval = unix_update_passwd(pamh, forwho, towhat); + } + } + done: - #ifdef USE_LCKPWDF +-#ifdef USE_LCKPWDF - ulckpwdf(); +-#endif + unlock_pwdf(); - #endif return retval; -@@ -891,13 +475,17 @@ static int _unix_verify_shadow(pam_handl - if (_unix_shadowed(pwd)) { - /* ...and shadow password file entry for this user, if shadowing - is enabled */ + } + + static int _unix_verify_shadow(pam_handle_t *pamh, const char *user, unsigned int ctrl) + { +- struct passwd *pwd = NULL; /* Password and shadow password */ +- struct spwd *spwdent = NULL; /* file entries for the user */ +- time_t curdays; +- int retval = PAM_SUCCESS; ++ struct passwd *pwent = NULL; /* Password and shadow password */ ++ struct spwd *spent = NULL; /* file entries for the user */ ++ int daysleft; ++ int retval; + +- /* UNIX passwords area */ +- pwd = getpwnam(user); /* Get password file entry... */ +- if (pwd == NULL) +- return PAM_AUTHINFO_UNAVAIL; /* We don't need to do the rest... */ +- +- if (_unix_shadowed(pwd)) { +- /* ...and shadow password file entry for this user, if shadowing +- is enabled */ - setspent(); - spwdent = getspnam(user); - endspent(); -- - #ifdef WITH_SELINUX ++ retval = get_account_info(pamh, user, &pwent, &spent); ++ if (retval == PAM_USER_UNKNOWN) { ++ return retval; ++ } + +-#ifdef WITH_SELINUX - if (spwdent == NULL && SELINUX_ENABLED ) - spwdent = _unix_run_verify_binary(pamh, ctrl, user); -+ if (selinux_confined()) -+ spwdent = _unix_run_verify_binary(pamh, ctrl, user); -+ else -+ { -+#endif -+ setspent(); -+ spwdent = getspnam(user); -+ endspent(); -+#ifdef WITH_SELINUX -+ } - #endif - if (spwdent == NULL) - return PAM_AUTHINFO_UNAVAIL; -@@ -1020,7 +608,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand +-#endif +- if (spwdent == NULL) +- return PAM_AUTHINFO_UNAVAIL; +- } else { +- if (strcmp(pwd->pw_passwd,"*NP*") == 0) { /* NIS+ */ +- uid_t save_uid; ++ if (retval == PAM_SUCCESS && spent == NULL) ++ return PAM_SUCCESS; + +- save_uid = geteuid(); +- seteuid (pwd->pw_uid); +- spwdent = getspnam( user ); +- seteuid (save_uid); +- +- if (spwdent == NULL) +- return PAM_AUTHINFO_UNAVAIL; +- } else +- spwdent = NULL; ++ if (retval == PAM_UNIX_RUN_HELPER) { ++ retval = _unix_run_verify_binary(pamh, ctrl, user, &daysleft); ++ if (retval == PAM_AUTH_ERR || retval == PAM_USER_UNKNOWN) ++ return retval; + } ++ else if (retval == PAM_SUCCESS) ++ retval = check_shadow_expiry(pamh, spent, &daysleft); ++ ++ if (on(UNIX__IAMROOT, ctrl) || retval == PAM_NEW_AUTHTOK_REQD) ++ return PAM_SUCCESS; + +- if (spwdent != NULL) { +- /* We have the user's information, now let's check if their account +- has expired (60 * 60 * 24 = number of seconds in a day) */ +- +- if (off(UNIX__IAMROOT, ctrl)) { +- /* Get the current number of days since 1970 */ +- curdays = time(NULL) / (60 * 60 * 24); +- if (curdays < spwdent->sp_lstchg) { +- pam_syslog(pamh, LOG_DEBUG, +- "account %s has password changed in future", +- user); +- curdays = spwdent->sp_lstchg; +- } +- if ((curdays - spwdent->sp_lstchg < spwdent->sp_min) +- && (spwdent->sp_min != -1)) +- /* +- * The last password change was too recent. +- */ +- retval = PAM_AUTHTOK_ERR; +- else if ((curdays - spwdent->sp_lstchg > spwdent->sp_max) +- && (curdays - spwdent->sp_lstchg > spwdent->sp_inact) +- && (curdays - spwdent->sp_lstchg > +- spwdent->sp_max + spwdent->sp_inact) +- && (spwdent->sp_max != -1) && (spwdent->sp_inact != -1) +- && (spwdent->sp_lstchg != 0)) +- /* +- * Their password change has been put off too long, +- */ +- retval = PAM_ACCT_EXPIRED; +- else if ((curdays > spwdent->sp_expire) && (spwdent->sp_expire != -1) +- && (spwdent->sp_lstchg != 0)) +- /* +- * OR their account has just plain expired +- */ +- retval = PAM_ACCT_EXPIRED; +- } +- } + return retval; + } + +@@ -1020,8 +499,9 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand int argc, const char **argv) { unsigned int ctrl, lctrl; - int retval, i; + int retval; int remember = -1; ++ int rounds = -1; /* */ -@@ -1240,49 +828,40 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand + const char *user; +@@ -1030,7 +510,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand + + D(("called.")); + +- ctrl = _set_ctrl(pamh, flags, &remember, argc, argv); ++ ctrl = _set_ctrl(pamh, flags, &remember, &rounds, argc, argv); + + /* + * First get the name of a user +@@ -1239,40 +719,23 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand + pass_new = pass_old = NULL; /* tidy up */ return retval; } - #ifdef USE_LCKPWDF +-#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 @@ -720,58 +801,102 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c.update-helper Lin + if (lock_pwdf() != PAM_SUCCESS) { return PAM_AUTHTOK_LOCK_BUSY; } - #endif +-#endif -- if (pass_old) { -+ if (!selinux_confined() && pass_old) { + if (pass_old) { retval = _unix_verify_password(pamh, user, pass_old, ctrl); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "user password changed by another process"); - #ifdef USE_LCKPWDF +-#ifdef USE_LCKPWDF - ulckpwdf(); +-#endif + unlock_pwdf(); - #endif return retval; } } -- retval = _unix_verify_shadow(pamh, user, ctrl); -- if (retval != PAM_SUCCESS) { -+ -+ if (!selinux_confined() && -+ (retval=_unix_verify_shadow(pamh, user, ctrl)) != PAM_SUCCESS) { - pam_syslog(pamh, LOG_NOTICE, "user not authenticated 2"); - #ifdef USE_LCKPWDF + retval = _unix_verify_shadow(pamh, user, ctrl); + if (retval != PAM_SUCCESS) { +- pam_syslog(pamh, LOG_NOTICE, "user not authenticated 2"); +-#ifdef USE_LCKPWDF - ulckpwdf(); +-#endif ++ pam_syslog(pamh, LOG_NOTICE, "user shadow entry expired"); + unlock_pwdf(); - #endif return retval; } -- retval = _pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new); -- if (retval != PAM_SUCCESS) { -+ -+ if (!selinux_confined() && -+ (retval=_pam_unix_approve_pass(pamh, ctrl, pass_old, pass_new)) != PAM_SUCCESS) { +@@ -1281,9 +744,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand pam_syslog(pamh, LOG_NOTICE, "new password not acceptable 2"); pass_new = pass_old = NULL; /* tidy up */ - #ifdef USE_LCKPWDF +-#ifdef USE_LCKPWDF - ulckpwdf(); +-#endif + unlock_pwdf(); - #endif return retval; } -@@ -1326,7 +905,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand - "out of memory for password"); - pass_new = pass_old = NULL; /* tidy up */ - #ifdef USE_LCKPWDF + +@@ -1296,51 +757,13 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand + * First we encrypt the new password. + */ + +- if (on(UNIX_MD5_PASS, ctrl)) { +- tpass = crypt_md5_wrapper(pass_new); +- } else { +- /* +- * Salt manipulation is stolen from Rick Faith's passwd +- * program. Sorry Rick :) -- alex +- */ +- +- time_t tm; +- char salt[3]; +- +- time(&tm); +- salt[0] = bin_to_ascii(tm & 0x3f); +- salt[1] = bin_to_ascii((tm >> 6) & 0x3f); +- 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 +- * Bug 521314.] +- */ +- char *temp = malloc(9); +- +- if (temp == NULL) { +- pam_syslog(pamh, LOG_CRIT, +- "out of memory for password"); +- pass_new = pass_old = NULL; /* tidy up */ +-#ifdef USE_LCKPWDF - ulckpwdf(); -+ unlock_pwdf(); - #endif - return PAM_BUF_ERR; - } -@@ -1349,7 +928,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand +-#endif +- return PAM_BUF_ERR; +- } +- /* copy first 8 bytes of password */ +- strncpy(temp, pass_new, 8); +- temp[8] = '\0'; +- +- /* no longer need cleartext */ +- tpass = bigcrypt(temp, salt); +- +- _pam_delete(temp); /* tidy up */ +- } else { +- tpass = bigcrypt(pass_new, salt); +- } ++ tpass = create_password_hash(pass_new, ctrl, rounds); ++ if (tpass == NULL) { ++ pam_syslog(pamh, LOG_CRIT, ++ "out of memory for password"); ++ pass_new = pass_old = NULL; /* tidy up */ ++ unlock_pwdf(); ++ return PAM_BUF_ERR; + } + + D(("password processed")); +@@ -1349,7 +772,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand retval = _do_setpass(pamh, user, pass_old, tpass, ctrl, remember); @@ -782,13 +907,36 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_passwd.c.update-helper Lin pass_old = pass_new = NULL; diff -up Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.update-helper Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c --- Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.update-helper 2007-03-12 15:35:14.000000000 +0100 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c 2007-09-18 10:15:54.000000000 +0200 -@@ -41,386 +41,9 @@ static int selinux_enabled=-1; ++++ Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c 2008-01-08 16:17:32.000000000 +0100 +@@ -13,7 +13,6 @@ - #include "md5.h" - #include "bigcrypt.h" -+#include "passverify.h" + #include "config.h" + +-#include + #include + #include + #include +@@ -25,401 +24,34 @@ + #include + #include + #include +-#ifdef WITH_SELINUX +-#include +-#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : (selinux_enabled=is_selinux_enabled()>0)) +-static security_context_t prev_context=NULL; +-static int selinux_enabled=-1; +-#else +-#define SELINUX_ENABLED 0 +-#endif +- +-#define MAXPASS 200 /* the maximum length of a password */ + #include + #include + +-#include "md5.h" +-#include "bigcrypt.h" +- -/* syslogging function for errors and other information */ - -static void _log_err(int err, const char *format,...) @@ -856,12 +1004,16 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.update-helper Linux-P - (void) sigaction(SIGINT, &action, NULL); - (void) sigaction(SIGQUIT, &action, NULL); -} -- ++#include "passverify.h" + -static int _verify_account(const char * const uname) --{ -- struct spwd *spent; -- struct passwd *pwent; -- ++static int _check_expiry(const char *uname) + { + struct spwd *spent; + struct passwd *pwent; ++ int retval; ++ int daysleft; + - pwent = getpwnam(uname); - if (!pwent) { - _log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname); @@ -983,9 +1135,19 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.update-helper Linux-P - if (pp && strcmp(pp, salt) == 0) { - retval = PAM_SUCCESS; - } -- } ++ retval = get_account_info(uname, &pwent, &spent); ++ if (retval != PAM_SUCCESS) { ++ helper_log_err(LOG_ALERT, "could not obtain user info (%s)", uname); ++ printf("-1\n"); ++ return retval; ++ } ++ ++ if (spent == NULL) { ++ printf("-1\n"); ++ return retval; + } - p = NULL; /* no longer needed here */ -- + - /* clean up */ - _pam_overwrite(pp); - _pam_drop(pp); @@ -1040,7 +1202,9 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.update-helper Linux-P - pass[npass] = '\0'; /* NUL terminate */ - retval = _unix_verify_password(forwho, pass, 0); - if (retval != PAM_SUCCESS) { -- return retval; ++ retval = check_shadow_expiry(spent, &daysleft); ++ printf("%d\n", daysleft); + return retval; - } - } - @@ -1167,20 +1331,44 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.update-helper Linux-P - unlink(SH_TMPFILE); - return PAM_AUTHTOK_ERR; - } --} -+const char app_name[] = "unix_chkpwd"; + } int main(int argc, char *argv[]) - { -@@ -430,6 +53,7 @@ int main(int argc, char *argv[]) - int force_failure = 0; +@@ -427,9 +59,10 @@ int main(int argc, char *argv[]) + char pass[MAXPASS + 1]; + char *option; + int npass, nullok; +- int force_failure = 0; ++ int blankpass = 0; int retval = PAM_AUTH_ERR; char *user; + char *passwords[] = { pass }; /* * Catch or ignore as many signal as possible. -@@ -476,49 +100,24 @@ int main(int argc, char *argv[]) +@@ -446,7 +79,7 @@ int main(int argc, char *argv[]) + */ + + if (isatty(STDIN_FILENO) || argc != 3 ) { +- _log_err(LOG_NOTICE ++ helper_log_err(LOG_NOTICE + ,"inappropriate use of Unix helper binary [UID=%d]" + ,getuid()); + fprintf(stderr +@@ -458,11 +91,9 @@ int main(int argc, char *argv[]) + + /* + * Determine what the current user's name is. +- * On a SELinux enabled system with a strict policy leaving the +- * existing check prevents shadow password authentication from working. + * We must thus skip the check if the real uid is 0. + */ +- if (SELINUX_ENABLED && getuid() == 0) { ++ if (getuid() == 0) { + user=argv[1]; + } + else { +@@ -476,63 +107,49 @@ int main(int argc, char *argv[]) option=argv[2]; @@ -1194,11 +1382,15 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.update-helper Linux-P - return _update_shadow(argv[1]); - } - ++ if (strcmp(option, "chkexpiry") == 0) ++ /* Check account information from the shadow file */ ++ return _check_expiry(argv[1]); /* read the nullok/nonull option */ - if (strncmp(option, "nullok", 8) == 0) +- if (strncmp(option, "nullok", 8) == 0) ++ else if (strcmp(option, "nullok") == 0) nullok = 1; - else -+ else if (strncmp(option, "nonull", 8) == 0) ++ else if (strcmp(option, "nonull") == 0) nullok = 0; + else + return PAM_SYSTEM_ERR; @@ -1227,59 +1419,193 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/unix_chkpwd.c.update-helper Linux-P - - pass[npass] = '\0'; /* NUL terminate */ - retval = _unix_verify_password(user, pass, nullok); -- -- } + if (npass != 1) { /* is it a valid password? */ -+ _log_err(LOG_DEBUG, "no valid password supplied"); ++ helper_log_err(LOG_DEBUG, "no password supplied"); ++ *pass = '\0'; ++ } + +- } ++ if (*pass == '\0') { ++ blankpass = 1; } -+ retval = _unix_verify_password(user, pass, nullok); ++ retval = helper_verify_password(user, pass, nullok); + memset(pass, '\0', MAXPASS); /* clear memory of the password */ /* return pass or fail */ -@@ -533,6 +132,7 @@ int main(int argc, char *argv[]) + +- if ((retval != PAM_SUCCESS) || force_failure) { +- _log_err(LOG_NOTICE, "password check failed for user (%s)", user); +- return PAM_AUTH_ERR; ++ if (retval != PAM_SUCCESS) { ++ if (!nullok || !blankpass) ++ /* no need to log blank pass test */ ++ helper_log_err(LOG_NOTICE, "password check failed for user (%s)", user); ++ return PAM_AUTH_ERR; + } else { +- return PAM_SUCCESS; ++ return PAM_SUCCESS; + } + } /* * Copyright (c) Andrew G. Morgan, 1996. All rights reserved -+ * Copyright (c) Red Hat, Inc., 2007. All rights reserved ++ * Copyright (c) Red Hat, Inc., 2007,2008. All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions +diff -up Linux-PAM-0.99.8.1/modules/pam_unix/support.h.update-helper Linux-PAM-0.99.8.1/modules/pam_unix/support.h +--- Linux-PAM-0.99.8.1/modules/pam_unix/support.h.update-helper 2007-01-23 10:30:23.000000000 +0100 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/support.h 2008-01-08 16:17:32.000000000 +0100 +@@ -1,5 +1,5 @@ + /* +- * $Id: pam-0.99.8.1-unix-update-helper.patch,v 1.3 2008/01/08 18:54:47 tmraz Exp $ ++ * $Id: pam-0.99.8.1-unix-update-helper.patch,v 1.3 2008/01/08 18:54:47 tmraz Exp $ + */ + + #ifndef _PAM_UNIX_SUPPORT_H +@@ -84,8 +84,12 @@ typedef struct { + #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_SHA256_PASS 23 /* new password hashes will use SHA256 */ ++#define UNIX_SHA512_PASS 24 /* new password hashes will use SHA512 */ ++#define UNIX_ALGO_ROUNDS 25 /* optional number of rounds for new ++ password hash algorithms */ + /* -------------- */ +-#define UNIX_CTRLS_ 23 /* number of ctrl arguments defined */ ++#define UNIX_CTRLS_ 26 /* number of ctrl arguments defined */ + + + static const UNIX_Ctrls unix_args[UNIX_CTRLS_] = +@@ -116,6 +120,9 @@ static const UNIX_Ctrls unix_args[UNIX_C + /* UNIX_REMEMBER_PASSWD */ {"remember=", _ALL_ON_, 02000000}, + /* UNIX_NOREAP */ {"noreap", _ALL_ON_, 04000000}, + /* UNIX_BROKEN_SHADOW */ {"broken_shadow", _ALL_ON_, 010000000}, ++/* UNIX_SHA256_PASS */ {"sha256", _ALL_ON_^(040420000), 020000000}, ++/* UNIX_SHA512_PASS */ {"sha512", _ALL_ON_^(020420000), 040000000}, ++/* UNIX_ALGO_ROUNDS */ {"rounds=", _ALL_ON_, 0100000000}, + }; + + #define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag) +@@ -131,8 +138,8 @@ static const UNIX_Ctrls unix_args[UNIX_C + + 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 _set_ctrl(pam_handle_t * pamh, int flags, int *remember, int *rounds, ++ int argc, const char **argv); + extern int _unix_getpwnam (pam_handle_t *pamh, + const char *name, int files, int nis, + struct passwd **ret); +@@ -149,7 +156,7 @@ extern int _unix_read_password(pam_handl + ,const char *prompt2 + ,const char *data_name + ,const void **pass); +-extern int _unix_shadowed(const struct passwd *pwd); + +-extern struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user); ++extern int _unix_run_verify_binary(pam_handle_t *pamh, ++ unsigned int ctrl, const char *user, int *daysleft); + #endif /* _PAM_UNIX_SUPPORT_H */ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h ---- /dev/null 2007-09-17 08:57:19.474470099 +0200 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h 2007-09-18 10:13:25.000000000 +0200 -@@ -0,0 +1,62 @@ +--- /dev/null 2008-01-05 20:21:31.621001512 +0100 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h 2008-01-08 16:17:32.000000000 +0100 +@@ -0,0 +1,124 @@ +/* -+ * This program is designed to run setuid(root) or with sufficient -+ * privilege to read all of the unix password databases. It is designed -+ * to provide a mechanism for the current user (defined by this -+ * process' uid) to verify their own password. -+ * -+ * The password is read from the standard input. The exit status of -+ * this program indicates whether the user is authenticated or not. -+ * -+ * Copyright information is located at the end of the file. -+ * ++ * Copyright information at end of file. + */ + ++#include ++#include ++#include ++ ++#define PAM_UNIX_RUN_HELPER PAM_CRED_INSUFFICIENT ++ +#define MAXPASS 200 /* the maximum length of a password */ + -+extern const char app_name[]; ++#define OLD_PASSWORDS_FILE "/etc/security/opasswd" + -+void _log_err(int err, const char *format,...); ++int ++verify_pwd_hash(const char *p, const char *hash, unsigned int nullok); + -+void setup_signals(void); ++int ++is_pwd_shadowed(const struct passwd *pwd); + -+int read_passwords(int fd, int npass, char **passwords); ++char * ++crypt_md5_wrapper(const char *pass_new); + -+int _unix_verify_password(const char *name, const char *p, int nullok); ++char * ++create_password_hash(const char *password, unsigned int ctrl, int rounds); + -+char *getuidname(uid_t uid); ++int ++unix_selinux_confined(void); + -+/* -+ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved -+ * Copyright (c) Red Hat, Inc. 2007. All rights reserved ++int ++lock_pwdf(void); ++ ++void ++unlock_pwdf(void); ++ ++int ++save_old_password(const char *forwho, const char *oldpass, ++ int howmany); ++ ++#ifdef HELPER_COMPILE ++void ++helper_log_err(int err, const char *format,...); ++ ++int ++helper_verify_password(const char *name, const char *p, int nullok); ++ ++void ++setup_signals(void); ++ ++char * ++getuidname(uid_t uid); ++ ++int ++read_passwords(int fd, int npass, char **passwords); ++ ++int ++get_account_info(const char *name, ++ struct passwd **pwd, struct spwd **spwdent); ++ ++int ++get_pwd_hash(const char *name, ++ struct passwd **pwd, char **hash); ++ ++int ++check_shadow_expiry(struct spwd *spent, int *daysleft); ++ ++int ++unix_update_passwd(const char *forwho, const char *towhat); ++ ++int ++unix_update_shadow(const char *forwho, char *towhat); ++#else ++int ++get_account_info(pam_handle_t *pamh, const char *name, ++ struct passwd **pwd, struct spwd **spwdent); ++ ++int ++get_pwd_hash(pam_handle_t *pamh, const char *name, ++ struct passwd **pwd, char **hash); ++ ++int ++check_shadow_expiry(pam_handle_t *pamh, struct spwd *spent, int *daysleft); ++ ++int ++unix_update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat); ++ ++int ++unix_update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat); ++#endif ++ ++/* ****************************************************************** * ++ * Copyright (c) Red Hat, Inc. 2007. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions @@ -1314,90 +1640,503 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passverify.h + */ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_acct.c.update-helper Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_acct.c --- Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_acct.c.update-helper 2006-06-27 10:38:14.000000000 +0200 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_acct.c 2007-09-18 13:02:52.000000000 +0200 -@@ -124,11 +124,11 @@ struct spwd *_unix_run_verify_binary(pam - } ++++ Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_acct.c 2008-01-08 16:17:32.000000000 +0100 +@@ -47,10 +47,6 @@ + #include /* for time() */ + #include + #include +-#ifdef WITH_SELINUX +-#include +-#define SELINUX_ENABLED is_selinux_enabled()>0 +-#endif - /* exec binary helper */ -- args[0] = x_strdup(CHKPWD_HELPER); -+ args[0] = x_strdup(UPDATE_HELPER); - args[1] = x_strdup(user); - args[2] = x_strdup("verify"); + #include -- execve(CHKPWD_HELPER, args, envp); -+ execve(UPDATE_HELPER, args, envp); +@@ -63,12 +59,10 @@ + #include - pam_syslog(pamh, LOG_ERR, "helper binary execve failed: %m"); - /* should not get here: exit with error */ -@@ -142,11 +142,11 @@ struct spwd *_unix_run_verify_binary(pam - int rc=0; - rc=waitpid(child, &retval, 0); /* wait for helper to complete */ - if (rc<0) { -- pam_syslog(pamh, LOG_ERR, "unix_chkpwd waitpid returned %d: %m", rc); -+ pam_syslog(pamh, LOG_ERR, "unix_update waitpid failed: %m"); + #include "support.h" ++#include "passverify.h" + +-#ifdef WITH_SELINUX +- +-struct spwd spwd; +- +-struct spwd *_unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, const char *user) ++int _unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl, ++ const char *user, int *daysleft) + { + int retval=0, child, fds[2]; + void (*sighandler)(int) = NULL; +@@ -78,7 +72,7 @@ struct spwd *_unix_run_verify_binary(pam + if (pipe(fds) != 0) { + D(("could not make pipe")); + pam_syslog(pamh, LOG_ERR, "Could not make pipe: %m"); +- return NULL; ++ return PAM_AUTH_ERR; + } + D(("called.")); + +@@ -117,7 +111,7 @@ struct spwd *_unix_run_verify_binary(pam + } + } + +- if (SELINUX_ENABLED && geteuid() == 0) { ++ if (geteuid() == 0) { + /* must set the real uid to 0 so the helper will not error + out if pam is called from setuid binary (su, sudo...) */ + setuid(0); +@@ -126,7 +120,7 @@ struct spwd *_unix_run_verify_binary(pam + /* exec binary helper */ + args[0] = x_strdup(CHKPWD_HELPER); + args[1] = x_strdup(user); +- args[2] = x_strdup("verify"); ++ args[2] = x_strdup("chkexpiry"); + + execve(CHKPWD_HELPER, args, envp); + +@@ -134,11 +128,12 @@ struct spwd *_unix_run_verify_binary(pam + /* should not get here: exit with error */ + close (fds[1]); + D(("helper binary is not available")); ++ printf("-1\n"); + exit(PAM_AUTHINFO_UNAVAIL); + } else { + close(fds[1]); + if (child > 0) { +- char buf[1024]; ++ char buf[32]; + int rc=0; + rc=waitpid(child, &retval, 0); /* wait for helper to complete */ + if (rc<0) { +@@ -146,22 +141,16 @@ struct spwd *_unix_run_verify_binary(pam retval = PAM_AUTH_ERR; } else { retval = WEXITSTATUS(retval); - if (retval != PAM_AUTHINFO_UNAVAIL) { -+ if (retval == PAM_SUCCESS) { - rc = pam_modutil_read(fds[0], buf, sizeof(buf) - 1); - if(rc > 0) { +- rc = pam_modutil_read(fds[0], buf, sizeof(buf) - 1); +- if(rc > 0) { ++ rc = pam_modutil_read(fds[0], buf, sizeof(buf) - 1); ++ if(rc > 0) { buf[rc] = '\0'; -@@ -157,15 +157,15 @@ struct spwd *_unix_run_verify_binary(pam - &spwd.sp_warn, /* days warning for expiration */ - &spwd.sp_inact, /* days before account inactive */ - &spwd.sp_expire) /* date when account expires */ != 6 ) retval = PAM_AUTH_ERR; -- } +- if (sscanf(buf,"%ld:%ld:%ld:%ld:%ld:%ld", +- &spwd.sp_lstchg, /* last password change */ +- &spwd.sp_min, /* days until change allowed. */ +- &spwd.sp_max, /* days before change required */ +- &spwd.sp_warn, /* days warning for expiration */ +- &spwd.sp_inact, /* days before account inactive */ +- &spwd.sp_expire) /* date when account expires */ != 6 ) retval = PAM_AUTH_ERR; ++ if (sscanf(buf,"%d", daysleft) != 1 ) ++ retval = PAM_AUTH_ERR; + } - else { - pam_syslog(pamh, LOG_ERR, " ERROR %d: %m", rc); retval = PAM_AUTH_ERR; -+ } else { -+ pam_syslog(pamh, LOG_ERR, "read failed: %m"); retval = PAM_AUTH_ERR; ++ else { ++ pam_syslog(pamh, LOG_ERR, "read unix_chkpwd output error %d: %m", rc); ++ retval = PAM_AUTH_ERR; } -+ } else { -+ pam_syslog(pamh, LOG_ERR, "unix_update returned error %d", retval); - } +- } } } else { -- pam_syslog(pamh, LOG_ERR, "Fork failed: %m"); -- D(("fork failed")); -+ pam_syslog(pamh, LOG_ERR, "fork failed: %m"); - retval = PAM_AUTH_ERR; - } - close(fds[0]); -@@ -247,15 +247,17 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_hand - setreuid( -1, save_euid ); - } + pam_syslog(pamh, LOG_ERR, "Fork failed: %m"); +@@ -174,15 +163,9 @@ struct spwd *_unix_run_verify_binary(pam + (void) signal(SIGCHLD, sighandler); /* restore old signal handler */ + } + D(("Returning %d",retval)); +- if (retval != PAM_SUCCESS) { +- return NULL; +- } +- return &spwd; ++ return retval; + } + +-#endif +- +- + /* + * PAM framework looks for this entry-point to pass control to the + * account management module. +@@ -195,14 +178,13 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_hand + const void *void_uname; + const char *uname; + int retval, daysleft; +- time_t curdays; + struct spwd *spent; + struct passwd *pwent; + char buf[256]; + + D(("called.")); + +- ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); ++ ctrl = _set_ctrl(pamh, flags, NULL, NULL, argc, argv); + + retval = pam_get_item(pamh, PAM_USER, &void_uname); + uname = void_uname; +@@ -214,134 +196,90 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_hand + return PAM_USER_UNKNOWN; + } +- pwent = pam_modutil_getpwnam(pamh, uname); +- if (!pwent) { ++ retval = get_account_info(pamh, uname, &pwent, &spent); ++ if (retval == PAM_USER_UNKNOWN) { + pam_syslog(pamh, LOG_ALERT, + "could not identify user (from getpwnam(%s))", + uname); +- return PAM_USER_UNKNOWN; ++ return retval; + } + +- if (!strcmp( pwent->pw_passwd, "*NP*" )) { /* NIS+ */ +- uid_t save_euid, save_uid; +- +- save_euid = geteuid(); +- save_uid = getuid(); +- if (save_uid == pwent->pw_uid) +- setreuid( save_euid, save_uid ); +- else { +- setreuid( 0, -1 ); +- if (setreuid( -1, pwent->pw_uid ) == -1) { +- setreuid( -1, 0 ); +- setreuid( 0, -1 ); +- if(setreuid( -1, pwent->pw_uid ) == -1) +- return PAM_CRED_INSUFFICIENT; +- } +- } +- spent = pam_modutil_getspnam (pamh, uname); +- if (save_uid == pwent->pw_uid) +- setreuid( save_uid, save_euid ); +- else { +- if (setreuid( -1, 0 ) == -1) +- setreuid( save_uid, -1 ); +- setreuid( -1, save_euid ); +- } +- - } else if (_unix_shadowed (pwent)) - spent = pam_modutil_getspnam (pamh, uname); - else -- return PAM_SUCCESS; -- -+ } else if (geteuid() != 0) { /* cannot read shadow when non root */ -+ return PAM_IGNORE; -+ } else if (_unix_shadowed (pwent)) { - #ifdef WITH_SELINUX ++ if (retval == PAM_SUCCESS && spent == NULL) + return PAM_SUCCESS; + +-#ifdef WITH_SELINUX - if (!spent && SELINUX_ENABLED ) - spent = _unix_run_verify_binary(pamh, ctrl, uname); -+ if (SELINUX_ENABLED) -+ spent = _unix_run_verify_binary(pamh, ctrl, uname); +-#endif +- +- if (!spent) ++ if (retval == PAM_UNIX_RUN_HELPER) { ++ retval = _unix_run_verify_binary(pamh, ctrl, uname, &daysleft); ++ if (retval == PAM_AUTHINFO_UNAVAIL && ++ on(UNIX_BROKEN_SHADOW, ctrl)) ++ return PAM_SUCCESS; ++ } else if (retval != PAM_SUCCESS) { + if (on(UNIX_BROKEN_SHADOW,ctrl)) + return PAM_SUCCESS; + else - #endif -+ spent = pam_modutil_getspnam (pamh, uname); ++ return retval; + } else -+ return PAM_SUCCESS; ++ retval = check_shadow_expiry(pamh, spent, &daysleft); - if (!spent) - if (on(UNIX_BROKEN_SHADOW,ctrl)) -diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c ---- /dev/null 2007-09-17 08:57:19.474470099 +0200 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c 2007-09-18 09:52:43.000000000 +0200 -@@ -0,0 +1,560 @@ +- 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)) { ++ switch (retval) { ++ case PAM_ACCT_EXPIRED: + pam_syslog(pamh, LOG_NOTICE, +- "account %s has expired (account expired)", +- uname); ++ "account %s has expired (account expired)", ++ uname); + _make_remark(pamh, ctrl, PAM_ERROR_MSG, +- _("Your account has expired; please contact your system administrator")); +- D(("account expired")); +- return PAM_ACCT_EXPIRED; +- } +- if (spent->sp_lstchg == 0) { +- pam_syslog(pamh, LOG_NOTICE, +- "expired password for user %s (root enforced)", +- uname); +- _make_remark(pamh, ctrl, PAM_ERROR_MSG, +- _("You are required to change your password immediately (root enforced)")); +- D(("need a new password")); +- return PAM_NEW_AUTHTOK_REQD; +- } +- if (curdays < spent->sp_lstchg) { +- pam_syslog(pamh, LOG_DEBUG, +- "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)) { ++ _("Your account has expired; please contact your system administrator")); ++ break; ++ case PAM_NEW_AUTHTOK_REQD: ++ if (daysleft == 0) { ++ pam_syslog(pamh, LOG_NOTICE, ++ "expired password for user %s (root enforced)", ++ uname); ++ _make_remark(pamh, ctrl, PAM_ERROR_MSG, ++ _("You are required to change your password immediately (root enforced)")); ++ } else { ++ pam_syslog(pamh, LOG_DEBUG, ++ "expired password for user %s (password aged)", ++ uname); ++ _make_remark(pamh, ctrl, PAM_ERROR_MSG, ++ _("You are required to change your password immediately (password aged)")); ++ } ++ break; ++ case PAM_AUTHTOK_EXPIRED: + pam_syslog(pamh, LOG_NOTICE, +- "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)) { +- pam_syslog(pamh, LOG_DEBUG, +- "expired password for user %s (password aged)", +- uname); ++ "account %s has expired (failed to change password)", ++ uname); + _make_remark(pamh, ctrl, PAM_ERROR_MSG, +- _("You are required to change your password immediately (password aged)")); +- D(("need a new password 2")); +- return PAM_NEW_AUTHTOK_REQD; +- } +- 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; +- pam_syslog(pamh, LOG_DEBUG, +- "password for user %s will expire in %d days", +- uname, daysleft); +-#ifdef HAVE_DNGETTEXT +- snprintf (buf, sizeof (buf), +- dngettext(PACKAGE, +- "Warning: your password will expire in %d day", +- "Warning: your password will expire in %d days", +- daysleft), +- daysleft); ++ _("Your account has expired; please contact your system administrator")); ++ break; ++ case PAM_SUCCESS: ++ if (daysleft >= 0) { ++ pam_syslog(pamh, LOG_DEBUG, ++ "password for user %s will expire in %d days", ++ uname, daysleft); ++#if defined HAVE_DNGETTEXT && defined ENABLE_NLS ++ snprintf (buf, sizeof (buf), ++ dngettext(PACKAGE, ++ "Warning: your password will expire in %d day", ++ "Warning: your password will expire in %d days", ++ daysleft), ++ daysleft); + #else +- if (daysleft == 1) +- snprintf(buf, sizeof (buf), +- _("Warning: your password will expire in %d day"), +- daysleft); +- else +- snprintf(buf, sizeof (buf), +- /* TRANSLATORS: only used if dngettext is not support +-ed */ +- _("Warning: your password will expire in %d days"), +- daysleft); ++ if (daysleft == 1) ++ snprintf(buf, sizeof (buf), ++ _("Warning: your password will expire in %d day"), ++ daysleft); ++ else ++ snprintf(buf, sizeof (buf), ++ /* TRANSLATORS: only used if dngettext is not supported */ ++ _("Warning: your password will expire in %d days"), ++ daysleft); + #endif +- _make_remark(pamh, ctrl, PAM_TEXT_INFO, buf); ++ _make_remark(pamh, ctrl, PAM_TEXT_INFO, buf); ++ } + } + + D(("all done")); + +- return PAM_SUCCESS; ++ return retval; + } + + +diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/unix_update.c +--- /dev/null 2008-01-05 20:21:31.621001512 +0100 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/unix_update.c 2008-01-08 16:17:32.000000000 +0100 +@@ -0,0 +1,194 @@ ++/* ++ * This program is designed to run setuid(root) or with sufficient ++ * privilege to read all of the unix password databases. It is designed ++ * to provide a mechanism for the current user (defined by this ++ * process' uid) to verify their own password. ++ * ++ * The password is read from the standard input. The exit status of ++ * this program indicates whether the user is authenticated or not. ++ * ++ * Copyright information is located at the end of the file. ++ * ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef WITH_SELINUX ++#include ++#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : (selinux_enabled=is_selinux_enabled()>0)) ++static int selinux_enabled=-1; ++#else ++#define SELINUX_ENABLED 0 ++#endif ++ ++#include ++#include ++ ++#include "passverify.h" ++ ++static int ++set_password(const char *forwho, const char *shadow, const char *remember) ++{ ++ struct passwd *pwd = NULL; ++ int retval; ++ char pass[MAXPASS + 1]; ++ char towhat[MAXPASS + 1]; ++ int npass = 0; ++ /* we don't care about number format errors because the helper ++ should be called internally only */ ++ int doshadow = atoi(shadow); ++ int nremember = atoi(remember); ++ char *passwords[] = { pass, towhat }; ++ ++ /* read the password from stdin (a pipe from the pam_unix module) */ ++ ++ npass = read_passwords(STDIN_FILENO, 2, passwords); ++ ++ if (npass != 2) { /* is it a valid password? */ ++ if (npass == 1) { ++ helper_log_err(LOG_DEBUG, "no new password supplied"); ++ memset(pass, '\0', MAXPASS); ++ } else { ++ helper_log_err(LOG_DEBUG, "no valid passwords supplied"); ++ } ++ return PAM_AUTHTOK_ERR; ++ } ++ ++ if (lock_pwdf() != PAM_SUCCESS) ++ return PAM_AUTHTOK_LOCK_BUSY; ++ ++ pwd = getpwnam(forwho); ++ ++ if (pwd == NULL) { ++ retval = PAM_USER_UNKNOWN; ++ goto done; ++ } ++ ++ /* does pass agree with the official one? ++ we always allow change from null pass */ ++ retval = helper_verify_password(forwho, pass, 1); ++ if (retval != PAM_SUCCESS) { ++ goto done; ++ } ++ ++ /* first, save old password */ ++ if (save_old_password(forwho, pass, nremember)) { ++ retval = PAM_AUTHTOK_ERR; ++ goto done; ++ } ++ ++ if (doshadow || is_pwd_shadowed(pwd)) { ++ retval = unix_update_shadow(forwho, towhat); ++ if (retval == PAM_SUCCESS) ++ if (!is_pwd_shadowed(pwd)) ++ retval = unix_update_passwd(forwho, "x"); ++ } else { ++ retval = unix_update_passwd(forwho, towhat); ++ } ++ ++done: ++ memset(pass, '\0', MAXPASS); ++ memset(towhat, '\0', MAXPASS); ++ ++ unlock_pwdf(); ++ ++ if (retval == PAM_SUCCESS) { ++ return PAM_SUCCESS; ++ } else { ++ return PAM_AUTHTOK_ERR; ++ } ++} ++ ++int main(int argc, char *argv[]) ++{ ++ char *option; ++ ++ /* ++ * Catch or ignore as many signal as possible. ++ */ ++ setup_signals(); ++ ++ /* ++ * we establish that this program is running with non-tty stdin. ++ * this is to discourage casual use. It does *NOT* prevent an ++ * intruder from repeatadly running this program to determine the ++ * password of the current user (brute force attack, but one for ++ * which the attacker must already have gained access to the user's ++ * account). ++ */ ++ ++ if (isatty(STDIN_FILENO) || argc != 5 ) { ++ helper_log_err(LOG_NOTICE ++ ,"inappropriate use of Unix helper binary [UID=%d]" ++ ,getuid()); ++ fprintf(stderr ++ ,"This binary is not designed for running in this way\n" ++ "-- the system administrator has been informed\n"); ++ sleep(10); /* this should discourage/annoy the user */ ++ return PAM_SYSTEM_ERR; ++ } ++ ++ /* We must be root to read/update shadow. ++ */ ++ if (geteuid() != 0) { ++ return PAM_CRED_INSUFFICIENT; ++ } ++ ++ option = argv[2]; ++ ++ if (strcmp(option, "update") == 0) { ++ /* Attempting to change the password */ ++ return set_password(argv[1], argv[3], argv[4]); ++ } ++ ++ return PAM_SYSTEM_ERR; ++} ++ +/* -+ * Main coding by Elliot Lee , Red Hat Software. -+ * Copyright (C) 1996. -+ * Copyright (c) Jan R�korajski, 1999. -+ * Copyright (c) Red Hat, Inc., 2007 ++ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved ++ * Copyright (c) Red Hat, Inc., 2007, 2008. All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions @@ -1430,121 +2169,508 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c +--- /dev/null 2008-01-05 20:21:31.621001512 +0100 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c 2008-01-08 16:17:32.000000000 +0100 +@@ -0,0 +1,1083 @@ ++/* ++ * Copyright information at end of file. ++ */ ++#include "config.h" ++#include ++#include ++#include "support.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "md5.h" ++#include "bigcrypt.h" ++#include "passverify.h" ++ ++#ifdef WITH_SELINUX ++#include ++#define SELINUX_ENABLED is_selinux_enabled()>0 ++#else ++#define SELINUX_ENABLED 0 ++#endif + -+/* this will be included from module and update helper */ ++#ifdef HELPER_COMPILE ++#define pam_modutil_getpwnam(h,n) getpwnam(n) ++#define pam_modutil_getspnam(h,n) getspnam(n) ++#define pam_syslog(h,a,b,c) helper_log_err(a,b,c) ++#else ++#include ++#include ++#endif + +#if defined(USE_LCKPWDF) && !defined(HAVE_LCKPWDF) +# include "./lckpwdf.-c" +#endif + -+/* passwd/salt conversion macros */ ++int ++verify_pwd_hash(const char *p, const char *hash, unsigned int nullok) ++{ ++ size_t hash_len = strlen(hash); ++ char *pp = NULL; ++ int retval; ++ D(("called")); ++ ++ if (!hash_len) { ++ /* the stored password is NULL */ ++ if (nullok) { /* 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 || *hash == '*' || *hash == '!') { ++ retval = PAM_AUTH_ERR; ++ } else { ++ if (!strncmp(hash, "$1$", 3)) { ++ pp = Goodcrypt_md5(p, hash); ++ if (pp && strcmp(pp, hash) != 0) { ++ _pam_delete(pp); ++ pp = Brokencrypt_md5(p, hash); ++ } ++ } else if (*hash != '$' && hash_len >= 13) { ++ pp = bigcrypt(p, hash); ++ if (pp && hash_len == 13 && strlen(pp) > hash_len) { ++ _pam_overwrite(pp + hash_len); ++ } ++ } else { ++ /* ++ * Ok, we don't know the crypt algorithm, but maybe ++ * libcrypt nows about it? We should try it. ++ */ ++ pp = x_strdup(crypt(p, hash)); ++ } ++ p = NULL; /* no longer needed here */ + -+#define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') -+#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') ++ /* the moment of truth -- do we agree with the password? */ ++ D(("comparing state of pp[%s] and salt[%s]", pp, salt)); + -+#define PW_TMPFILE "/etc/npasswd" -+#define SH_TMPFILE "/etc/nshadow" -+#define OPW_TMPFILE "/etc/security/nopasswd" -+#define OLD_PASSWORDS_FILE "/etc/security/opasswd" ++ if (pp && strcmp(pp, hash) == 0) { ++ retval = PAM_SUCCESS; ++ } else { ++ retval = PAM_AUTH_ERR; ++ } ++ } ++ ++ if (pp) ++ _pam_delete(pp); ++ D(("done [%d].", retval)); + -+/* -+ * i64c - convert an integer to a radix 64 character -+ */ -+static int i64c(int i) ++ return retval; ++} ++ ++int ++is_pwd_shadowed(const struct passwd *pwd) +{ -+ if (i < 0) -+ return ('.'); -+ else if (i > 63) -+ return ('z'); -+ if (i == 0) -+ return ('.'); -+ if (i == 1) -+ return ('/'); -+ if (i >= 2 && i <= 11) -+ return ('0' - 2 + i); -+ if (i >= 12 && i <= 37) -+ return ('A' - 12 + i); -+ if (i >= 38 && i <= 63) -+ return ('a' - 38 + i); -+ return ('\0'); ++ 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; +} + -+static char *crypt_md5_wrapper(const char *pass_new) ++#ifdef HELPER_COMPILE ++int ++get_account_info(const char *name, ++ struct passwd **pwd, struct spwd **spwdent) ++#else ++int ++get_account_info(pam_handle_t *pamh, const char *name, ++ struct passwd **pwd, struct spwd **spwdent) ++#endif +{ -+ /* -+ * Code lifted from Marek Michalkiewicz's shadow suite. (CG) -+ * removed use of static variables (AGM) -+ */ ++ /* UNIX passwords area */ ++ *pwd = pam_modutil_getpwnam(pamh, name); /* Get password file entry... */ ++ *spwdent = NULL; ++ ++ if (*pwd != NULL) { ++ if (strcmp((*pwd)->pw_passwd, "*NP*") == 0) ++ { /* NIS+ */ ++#ifdef HELPER_COMPILE ++ uid_t save_euid, save_uid; ++ ++ save_euid = geteuid(); ++ save_uid = getuid(); ++ if (save_uid == (*pwd)->pw_uid) ++ setreuid(save_euid, save_uid); ++ else { ++ setreuid(0, -1); ++ if (setreuid(-1, (*pwd)->pw_uid) == -1) { ++ setreuid(-1, 0); ++ setreuid(0, -1); ++ if(setreuid(-1, (*pwd)->pw_uid) == -1) ++ return PAM_CRED_INSUFFICIENT; ++ } ++ } ++ ++ *spwdent = pam_modutil_getspnam(pamh, name); ++ if (save_uid == (*pwd)->pw_uid) ++ setreuid(save_uid, save_euid); ++ else { ++ setreuid(-1, 0); ++ setreuid(save_uid, -1); ++ setreuid(-1, save_euid); ++ } + -+ struct timeval tv; -+ MD5_CTX ctx; -+ unsigned char result[16]; -+ char *cp = (char *) result; -+ unsigned char tmp[16]; -+ int i; -+ char *x = NULL; -+ -+ GoodMD5Init(&ctx); -+ gettimeofday(&tv, (struct timezone *) 0); -+ GoodMD5Update(&ctx, (void *) &tv, sizeof tv); -+ i = getpid(); -+ GoodMD5Update(&ctx, (void *) &i, sizeof i); -+ i = clock(); -+ GoodMD5Update(&ctx, (void *) &i, sizeof i); -+ GoodMD5Update(&ctx, result, sizeof result); -+ GoodMD5Final(tmp, &ctx); -+ strcpy(cp, "$1$"); /* magic for the MD5 */ -+ cp += strlen(cp); -+ for (i = 0; i < 8; i++) -+ *cp++ = i64c(tmp[i] & 077); -+ *cp = '\0'; -+ -+ /* no longer need cleartext */ -+ x = Goodcrypt_md5(pass_new, (const char *) result); -+ -+ return x; ++ if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL) ++ return PAM_AUTHINFO_UNAVAIL; ++#else ++ /* we must run helper for NIS+ passwords */ ++ return PAM_UNIX_RUN_HELPER; ++#endif ++ } else if (is_pwd_shadowed(*pwd)) { ++ /* ++ * ...and shadow password file entry for this user, ++ * if shadowing is enabled ++ */ ++#ifndef HELPER_COMPILE ++ if (geteuid() || SELINUX_ENABLED) ++ return PAM_UNIX_RUN_HELPER; ++#endif ++ *spwdent = pam_modutil_getspnam(pamh, name); ++ if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL) ++ return PAM_AUTHINFO_UNAVAIL; ++ } ++ } else { ++ return PAM_USER_UNKNOWN; ++ } ++ return PAM_SUCCESS; +} + -+#ifdef USE_LCKPWDF -+static int lock_pwdf(void) ++#ifdef HELPER_COMPILE ++int ++get_pwd_hash(const char *name, ++ struct passwd **pwd, char **hash) ++#else ++int ++get_pwd_hash(pam_handle_t *pamh, const char *name, ++ struct passwd **pwd, char **hash) ++#endif +{ -+ int i; + int retval; ++ struct spwd *spwdent = NULL; + -+#ifndef HELPER_COMPILE -+ if (selinux_confined()) { ++#ifdef HELPER_COMPILE ++ retval = get_account_info(name, pwd, &spwdent); ++#else ++ retval = get_account_info(pamh, name, pwd, &spwdent); ++#endif ++ if (retval != PAM_SUCCESS) { ++ return retval; ++ } ++ ++ if (spwdent) ++ *hash = x_strdup(spwdent->sp_pwdp); ++ else ++ *hash = x_strdup((*pwd)->pw_passwd); ++ if (*hash == NULL) ++ return PAM_BUF_ERR; ++ ++ return PAM_SUCCESS; ++} ++ ++#ifdef HELPER_COMPILE ++int ++check_shadow_expiry(struct spwd *spent, int *daysleft) ++#else ++int ++check_shadow_expiry(pam_handle_t *pamh, struct spwd *spent, int *daysleft) ++#endif ++{ ++ long int curdays; ++ *daysleft = -1; ++ curdays = (long int)(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)) { ++ D(("account expired")); ++ return PAM_ACCT_EXPIRED; ++ } ++ if (spent->sp_lstchg == 0) { ++ D(("need a new password")); ++ *daysleft = 0; ++ return PAM_NEW_AUTHTOK_REQD; ++ } ++ if (curdays < spent->sp_lstchg) { ++ pam_syslog(pamh, LOG_DEBUG, ++ "account %s has password changed in future", ++ spent->sp_namp); + 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)) { ++ *daysleft = (int)((spent->sp_lstchg + spent->sp_max) - curdays); ++ D(("authtok expired")); ++ return PAM_AUTHTOK_EXPIRED; ++ } ++ if ((curdays - spent->sp_lstchg > spent->sp_max) && (spent->sp_max != -1)) { ++ D(("need a new password 2")); ++ return PAM_NEW_AUTHTOK_REQD; ++ } ++ if ((curdays - spent->sp_lstchg > spent->sp_max - spent->sp_warn) ++ && (spent->sp_max != -1) && (spent->sp_warn != -1)) { ++ *daysleft = (int)((spent->sp_lstchg + spent->sp_max) - curdays); ++ D(("warn before expiry")); ++ } ++ return PAM_SUCCESS; ++ ++} ++ ++/* passwd/salt conversion macros */ ++ ++#define PW_TMPFILE "/etc/npasswd" ++#define SH_TMPFILE "/etc/nshadow" ++#define OPW_TMPFILE "/etc/security/nopasswd" ++ ++/* ++ * i64c - convert an integer to a radix 64 character ++ */ ++static int ++i64c(int i) ++{ ++ if (i < 0) ++ return ('.'); ++ else if (i > 63) ++ return ('z'); ++ if (i == 0) ++ return ('.'); ++ if (i == 1) ++ return ('/'); ++ if (i >= 2 && i <= 11) ++ return ('0' - 2 + i); ++ if (i >= 12 && i <= 37) ++ return ('A' - 12 + i); ++ if (i >= 38 && i <= 63) ++ return ('a' - 38 + i); ++ return ('\0'); ++} ++ ++static void ++crypt_make_salt(char *where, int length) ++{ ++ struct timeval tv; ++ MD5_CTX ctx; ++ unsigned char tmp[16]; ++ unsigned char *src = (unsigned char *)where; ++ int i; ++#ifdef PATH_RANDOMDEV ++ int fd; ++ int rv; ++ ++ if ((rv = fd = open (PATH_RANDOMDEV, O_RDONLY)) != -1) { ++ while ((rv = read(fd, where, length)) != length && errno == EINTR); ++ close (fd); ++ } ++ if (rv != length) { ++#endif ++ /* ++ * Code lifted from Marek Michalkiewicz's shadow suite. (CG) ++ * removed use of static variables (AGM) ++ * ++ * will work correctly only for length <= 16 */ ++ src = tmp; ++ GoodMD5Init(&ctx); ++ gettimeofday(&tv, (struct timezone *) 0); ++ GoodMD5Update(&ctx, (void *) &tv, sizeof tv); ++ i = getpid(); ++ GoodMD5Update(&ctx, (void *) &i, sizeof i); ++ i = clock(); ++ GoodMD5Update(&ctx, (void *) &i, sizeof i); ++ GoodMD5Update(&ctx, src, length); ++ GoodMD5Final(tmp, &ctx); ++#ifdef PATH_RANDOMDEV ++ } +#endif -+ /* 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++; ++ for (i = 0; i < length; i++) ++ *where++ = i64c(src[i] & 077); ++ *where = '\0'; ++} ++ ++char * ++crypt_md5_wrapper(const char *pass_new) ++{ ++ unsigned char result[16]; ++ char *cp = (char *) result; ++ ++ cp = stpcpy(cp, "$1$"); /* magic for the MD5 */ ++ crypt_make_salt(cp, 9); ++ ++ /* no longer need cleartext */ ++ cp = Goodcrypt_md5(pass_new, (const char *) result); ++ pass_new = NULL; ++ ++ return cp; ++} ++ ++char * ++create_password_hash(const char *password, unsigned int ctrl, int rounds) ++{ ++ const char *algoid; ++ char salt[64]; /* contains rounds number + max 16 bytes of salt + algo id */ ++ char *sp; ++ ++ if (on(UNIX_MD5_PASS, ctrl)) { ++ return crypt_md5_wrapper(password); ++ } ++ if (on(UNIX_SHA256_PASS, ctrl)) { ++ algoid = "$5$"; ++ } else if (on(UNIX_SHA512_PASS, ctrl)) { ++ algoid = "$6$"; ++ } else { /* must be crypt/bigcrypt */ ++ char tmppass[9]; ++ char *crypted; ++ ++ crypt_make_salt(salt, 2); ++ if (off(UNIX_BIGCRYPT, ctrl) && strlen(password) > 8) { ++ strncpy(tmppass, password, sizeof(tmppass)-1); ++ tmppass[sizeof(tmppass)-1] = '\0'; ++ password = tmppass; ++ } ++ crypted = bigcrypt(password, salt); ++ memset(tmppass, '\0', sizeof(tmppass)); ++ password = NULL; ++ return crypted; + } -+ if(retval != 0) { -+ return PAM_AUTHTOK_LOCK_BUSY; ++ ++ sp = stpcpy(salt, algoid); ++ if (on(UNIX_ALGO_ROUNDS, ctrl)) { ++ sp += snprintf(sp, sizeof(salt) - 3, "rounds=%u$", rounds); + } ++ crypt_make_salt(sp, 8); ++ /* For now be conservative so the resulting hashes ++ * are not too long. 8 bytes of salt prevents dictionary ++ * attacks well enough. */ ++ return x_strdup(crypt(password, salt)); ++} ++ ++#ifdef WITH_SELINUX ++int ++unix_selinux_confined(void) ++{ ++ static int confined = -1; ++ int fd; ++ char tempfile[]="/etc/.pwdXXXXXX"; ++ ++ if (confined != -1) ++ return confined; ++ ++ /* cannot be confined without SELinux enabled */ ++ if (!SELINUX_ENABLED){ ++ confined = 0; ++ return confined; ++ } ++ ++ /* let's try opening shadow read only */ ++ if ((fd=open("/etc/shadow", O_RDONLY)) != -1) { ++ close(fd); ++ confined = 0; ++ return confined; ++ } ++ ++ if (errno == EACCES) { ++ confined = 1; ++ return confined; ++ } ++ ++ /* shadow opening failed because of other reasons let's try ++ creating a file in /etc */ ++ if ((fd=mkstemp(tempfile)) != -1) { ++ unlink(tempfile); ++ close(fd); ++ confined = 0; ++ return confined; ++ } ++ ++ confined = 1; ++ return confined; ++} ++ ++#else ++int ++unix_selinux_confined(void) ++{ ++ return 0; ++} ++#endif ++ ++#ifdef USE_LCKPWDF ++int ++lock_pwdf(void) ++{ ++ int i; ++ int retval; ++ ++#ifndef HELPER_COMPILE ++ if (unix_selinux_confined()) { ++ return PAM_SUCCESS; ++ } ++#endif ++ /* 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; ++ } ++ return PAM_SUCCESS; ++} ++ ++void ++unlock_pwdf(void) ++{ ++#ifndef HELPER_COMPILE ++ if (unix_selinux_confined()) { ++ return; ++ } ++#endif ++ ulckpwdf(); ++} ++#else ++int ++lock_pwdf(void) ++{ + return PAM_SUCCESS; +} + -+static void unlock_pwdf(void) ++void ++unlock_pwdf(void) +{ -+#ifndef HELPER_COMPILE -+ if (selinux_confined()) { -+ return; -+ } -+#endif -+ ulckpwdf(); ++ return; +} +#endif + -+static int ++int +save_old_password(const char *forwho, const char *oldpass, + int howmany) +{ @@ -1558,6 +2684,7 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c + int found = 0; + struct passwd *pwd = NULL; + struct stat st; ++ security_context_t prev_context=NULL; + + if (howmany < 0) { + return PAM_SUCCESS; @@ -1702,11 +2829,11 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c +} + +#ifdef HELPER_COMPILE -+static int -+_update_passwd(const char *forwho, const char *towhat) ++int ++unix_update_passwd(const char *forwho, const char *towhat) +#else -+static int -+_update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat) ++int ++unix_update_passwd(pam_handle_t *pamh, const char *forwho, const char *towhat) +#endif +{ + struct passwd *tmpent = NULL; @@ -1714,6 +2841,7 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c + FILE *pwfile, *opwfile; + int err = 1; + int oldmask; ++ security_context_t prev_context=NULL; + + oldmask = umask(077); +#ifdef WITH_SELINUX @@ -1799,7 +2927,7 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c + if (!err) { + if (!rename(PW_TMPFILE, "/etc/passwd")) +#ifdef HELPER_COMPILE -+ _log_err( ++ helper_log_err( +#else + pam_syslog(pamh, +#endif @@ -1826,11 +2954,11 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c +} + +#ifdef HELPER_COMPILE -+static int -+_update_shadow(const char *forwho, char *towhat) ++int ++unix_update_shadow(const char *forwho, char *towhat) +#else -+static int -+_update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) ++int ++unix_update_shadow(pam_handle_t *pamh, const char *forwho, char *towhat) +#endif +{ + struct spwd *spwdent = NULL, *stmpent = NULL; @@ -1838,6 +2966,7 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c + FILE *pwfile, *opwfile; + int err = 1; + int oldmask; ++ security_context_t prev_context=NULL; + + spwdent = getspnam(forwho); + if (spwdent == NULL) { @@ -1926,7 +3055,7 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c + if (!err) { + if (!rename(SH_TMPFILE, "/etc/shadow")) +#ifdef HELPER_COMPILE -+ _log_err( ++ helper_log_err( +#else + pam_syslog(pamh, +#endif @@ -1953,554 +3082,148 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passupdate.c + return PAM_AUTHTOK_ERR; + } +} -diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/unix_update.c ---- /dev/null 2007-09-17 08:57:19.474470099 +0200 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/unix_update.c 2007-09-18 10:16:36.000000000 +0200 -@@ -0,0 +1,264 @@ -+/* -+ * This program is designed to run setuid(root) or with sufficient -+ * privilege to read all of the unix password databases. It is designed -+ * to provide a mechanism for the current user (defined by this -+ * process' uid) to verify their own password. -+ * -+ * The password is read from the standard input. The exit status of -+ * this program indicates whether the user is authenticated or not. -+ * -+ * Copyright information is located at the end of the file. -+ * -+ */ -+ -+#include "config.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef WITH_SELINUX -+#include -+#define SELINUX_ENABLED (selinux_enabled!=-1 ? selinux_enabled : (selinux_enabled=is_selinux_enabled()>0)) -+static security_context_t prev_context=NULL; -+static int selinux_enabled=-1; -+#else -+#define SELINUX_ENABLED 0 -+#endif -+ -+#define MAXPASS 200 /* the maximum length of a password */ -+ -+#include -+#include -+ -+#include "md5.h" -+#include "bigcrypt.h" -+#include "passverify.h" -+ -+#define _pam_delete(xx) \ -+{ \ -+ _pam_overwrite(xx); \ -+ _pam_drop(xx); \ -+} -+ -+const char app_name[] = "unix_update"; -+ -+static 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; -+} -+ -+#define HELPER_COMPILE -+#include "passupdate.c" -+ -+static int -+verify_account(const char * const uname) -+{ -+ struct spwd *spent; -+ struct passwd *pwent; -+ -+ pwent = getpwnam(uname); -+ if (!pwent) { -+ _log_err(LOG_ALERT, "could not identify user (from getpwnam(%s))", uname); -+ return PAM_USER_UNKNOWN; -+ } -+ -+ spent = getspnam( uname ); -+ if (!spent) { -+ _log_err(LOG_ALERT, "could not get username from shadow (%s))", uname); -+ return PAM_AUTHINFO_UNAVAIL; /* Couldn't get username from shadow */ -+ } -+ printf("%ld:%ld:%ld:%ld:%ld:%ld", -+ spent->sp_lstchg, /* last password change */ -+ spent->sp_min, /* days until change allowed. */ -+ spent->sp_max, /* days before change required */ -+ spent->sp_warn, /* days warning for expiration */ -+ spent->sp_inact, /* days before account inactive */ -+ spent->sp_expire); /* date when account expires */ -+ -+ return PAM_SUCCESS; -+} -+ -+static int -+set_password(const char *forwho, const char *shadow, const char *remember) -+{ -+ struct passwd *pwd = NULL; -+ int retval; -+ char pass[MAXPASS + 1]; -+ char towhat[MAXPASS + 1]; -+ int npass = 0; -+ /* we don't care about number format errors because the helper -+ should be called internally only */ -+ int doshadow = atoi(shadow); -+ int nremember = atoi(remember); -+ char *passwords[] = { pass, towhat }; -+ -+ /* read the password from stdin (a pipe from the pam_unix module) */ -+ -+ npass = read_passwords(STDIN_FILENO, 2, passwords); -+ -+ if (npass != 2) { /* is it a valid password? */ -+ if (npass == 1) { -+ _log_err(LOG_DEBUG, "no new password supplied"); -+ memset(pass, '\0', MAXPASS); -+ } else { -+ _log_err(LOG_DEBUG, "no valid passwords supplied"); -+ } -+ return PAM_AUTHTOK_ERR; -+ } -+ -+#ifdef USE_LCKPWDF -+ if (lock_pwdf() != PAM_SUCCESS) -+ return PAM_AUTHTOK_LOCK_BUSY; -+#endif -+ -+ pwd = getpwnam(forwho); -+ -+ if (pwd == NULL) { -+ retval = PAM_USER_UNKNOWN; -+ goto done; -+ } -+ -+ /* does pass agree with the official one? -+ we always allow change from null pass */ -+ retval = _unix_verify_password(forwho, pass, 1); -+ if (retval != PAM_SUCCESS) { -+ goto done; -+ } -+ -+ /* first, save old password */ -+ if (save_old_password(forwho, pass, nremember)) { -+ retval = PAM_AUTHTOK_ERR; -+ goto done; -+ } -+ -+ if (doshadow || _unix_shadowed(pwd)) { -+ retval = _update_shadow(forwho, towhat); -+ if (retval == PAM_SUCCESS) -+ if (!_unix_shadowed(pwd)) -+ retval = _update_passwd(forwho, "x"); -+ } else { -+ retval = _update_passwd(forwho, towhat); -+ } -+ -+done: -+ memset(pass, '\0', MAXPASS); -+ memset(towhat, '\0', MAXPASS); -+ -+#ifdef USE_LCKPWDF -+ unlock_pwdf(); -+#endif -+ -+ if (retval == PAM_SUCCESS) { -+ return PAM_SUCCESS; -+ } else { -+ return PAM_AUTHTOK_ERR; -+ } -+} -+ -+int main(int argc, char *argv[]) -+{ -+ char *option; -+ -+ /* -+ * Catch or ignore as many signal as possible. -+ */ -+ setup_signals(); -+ -+ /* -+ * we establish that this program is running with non-tty stdin. -+ * this is to discourage casual use. It does *NOT* prevent an -+ * intruder from repeatadly running this program to determine the -+ * password of the current user (brute force attack, but one for -+ * which the attacker must already have gained access to the user's -+ * account). -+ */ -+ -+ if (isatty(STDIN_FILENO) || argc < 3 ) { -+ _log_err(LOG_NOTICE -+ ,"inappropriate use of Unix helper binary [UID=%d]" -+ ,getuid()); -+ fprintf(stderr -+ ,"This binary is not designed for running in this way\n" -+ "-- the system administrator has been informed\n"); -+ sleep(10); /* this should discourage/annoy the user */ -+ return PAM_SYSTEM_ERR; -+ } -+ -+ /* We must be root to read/update shadow. -+ */ -+ if (geteuid() != 0) { -+ return PAM_AUTH_ERR; -+ } -+ -+ option = argv[2]; -+ -+ if (strncmp(option, "verify", 8) == 0) { -+ /* Get the account information from the shadow file */ -+ return verify_account(argv[1]); -+ } -+ -+ if (strncmp(option, "update", 8) == 0) { -+ if (argc == 5) -+ /* Attempting to change the password */ -+ return set_password(argv[1], argv[3], argv[4]); -+ } -+ -+ return PAM_SYSTEM_ERR; -+} -+ -+/* -+ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved -+ * Copyright (c) Red Hat, Inc., 2007. 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, and the entire permission notice in its entirety, -+ * including the disclaimer of warranties. -+ * 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. -+ * 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 -+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. -+ */ -diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c ---- /dev/null 2007-09-17 08:57:19.474470099 +0200 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c 2007-09-18 10:15:19.000000000 +0200 -@@ -0,0 +1,308 @@ -+/* -+ * This program is designed to run setuid(root) or with sufficient -+ * privilege to read all of the unix password databases. It is designed -+ * to provide a mechanism for the current user (defined by this -+ * process' uid) to verify their own password. -+ * -+ * The password is read from the standard input. The exit status of -+ * this program indicates whether the user is authenticated or not. -+ * -+ * Copyright information is located at the end of the file. -+ * -+ */ -+ -+#include "config.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include + -+#include -+#include ++#ifdef HELPER_COMPILE + -+#include "md5.h" -+#include "bigcrypt.h" ++int ++helper_verify_password(const char *name, const char *p, int nullok) ++{ ++ struct passwd *pwd = NULL; ++ char *salt = NULL; ++ int retval; + -+#include "passverify.h" ++ retval = get_pwd_hash(name, &pwd, &salt); ++ ++ if (pwd == NULL || salt == NULL) { ++ helper_log_err(LOG_WARNING, "check pass; user unknown"); ++ retval = PAM_USER_UNKNOWN; ++ } else { ++ retval = verify_pwd_hash(p, salt, nullok); ++ } ++ ++ if (salt) { ++ _pam_overwrite(salt); ++ _pam_drop(salt); ++ } ++ ++ p = NULL; /* no longer needed here */ + -+/* syslogging function for errors and other information */ ++ return retval; ++} + +void -+_log_err(int err, const char *format,...) ++helper_log_err(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); -+ openlog(app_name, LOG_CONS | LOG_PID, LOG_AUTHPRIV); ++ openlog(HELPER_COMPILE, LOG_CONS | LOG_PID, LOG_AUTHPRIV); + vsyslog(err, format, args); + va_end(args); + 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); ++ /* 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) { -+ _exit(sig); -+ } ++ if (sig > 0) { ++ _exit(sig); ++ } +} + +void +setup_signals(void) +{ -+ struct sigaction action; /* posix signal structure */ ++ struct sigaction action; /* posix signal structure */ + -+ /* -+ * Setup signal handlers -+ */ -+ (void) memset((void *) &action, 0, sizeof(action)); -+ action.sa_handler = su_sighandler; ++ /* ++ * Setup signal handlers ++ */ ++ (void) memset((void *) &action, 0, sizeof(action)); ++ action.sa_handler = su_sighandler; +#ifdef SA_RESETHAND -+ action.sa_flags = SA_RESETHAND; ++ action.sa_flags = SA_RESETHAND; +#endif -+ (void) sigaction(SIGILL, &action, NULL); -+ (void) sigaction(SIGTRAP, &action, NULL); -+ (void) sigaction(SIGBUS, &action, NULL); -+ (void) sigaction(SIGSEGV, &action, NULL); -+ action.sa_handler = SIG_IGN; -+ action.sa_flags = 0; -+ (void) sigaction(SIGTERM, &action, NULL); -+ (void) sigaction(SIGHUP, &action, NULL); -+ (void) sigaction(SIGINT, &action, NULL); -+ (void) sigaction(SIGQUIT, &action, NULL); ++ (void) sigaction(SIGILL, &action, NULL); ++ (void) sigaction(SIGTRAP, &action, NULL); ++ (void) sigaction(SIGBUS, &action, NULL); ++ (void) sigaction(SIGSEGV, &action, NULL); ++ action.sa_handler = SIG_IGN; ++ action.sa_flags = 0; ++ (void) sigaction(SIGTERM, &action, NULL); ++ (void) sigaction(SIGHUP, &action, NULL); ++ (void) sigaction(SIGINT, &action, NULL); ++ (void) sigaction(SIGQUIT, &action, NULL); +} + -+int -+read_passwords(int fd, int npass, char **passwords) ++char * ++getuidname(uid_t uid) +{ -+ int rbytes = 0; -+ int offset = 0; -+ int i = 0; -+ char *pptr; -+ while (npass > 0) { -+ rbytes = read(fd, passwords[i]+offset, MAXPASS-offset); -+ -+ if (rbytes < 0) { -+ if (errno == EINTR) continue; -+ break; -+ } -+ if (rbytes == 0) -+ break; -+ -+ while (npass > 0 && (pptr=memchr(passwords[i]+offset, '\0', rbytes)) -+ != NULL) { -+ rbytes -= pptr - (passwords[i]+offset) + 1; -+ i++; -+ offset = 0; -+ npass--; -+ if (rbytes > 0) { -+ if (npass > 0) -+ memcpy(passwords[i], pptr+1, rbytes); -+ memset(pptr+1, '\0', rbytes); -+ } -+ } -+ offset += rbytes; -+ } ++ struct passwd *pw; ++ static char username[256]; + -+ /* clear up */ -+ if (offset > 0 && npass > 0) { -+ memset(passwords[i], '\0', offset); -+ } ++ pw = getpwuid(uid); ++ if (pw == NULL) ++ return NULL; ++ ++ strncpy(username, pw->pw_name, sizeof(username)); ++ username[sizeof(username) - 1] = '\0'; + -+ return i; ++ return username; +} + +int -+_unix_verify_password(const char *name, const char *p, int nullok) ++read_passwords(int fd, int npass, char **passwords) +{ -+ struct passwd *pwd = NULL; -+ struct spwd *spwdent = NULL; -+ char *salt = NULL; -+ char *pp = NULL; -+ int retval = PAM_AUTH_ERR; -+ size_t salt_len; -+ -+ /* UNIX passwords area */ -+ setpwent(); -+ pwd = getpwnam(name); /* Get password file entry... */ -+ endpwent(); -+ if (pwd != NULL) { -+ if (_unix_shadowed(pwd)) { -+ /* -+ * ...and shadow password file entry for this user, -+ * if shadowing is enabled -+ */ -+ setspent(); -+ spwdent = getspnam(name); -+ endspent(); -+ if (spwdent != NULL) -+ salt = x_strdup(spwdent->sp_pwdp); -+ else -+ pwd = NULL; -+ } else { -+ if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */ -+ uid_t save_uid; -+ -+ save_uid = geteuid(); -+ seteuid(pwd->pw_uid); -+ spwdent = getspnam(name); -+ seteuid(save_uid); -+ -+ salt = x_strdup(spwdent->sp_pwdp); -+ } else { -+ salt = x_strdup(pwd->pw_passwd); -+ } -+ } -+ } -+ if (pwd == NULL || salt == NULL) { -+ _log_err(LOG_ALERT, "check pass; user unknown"); -+ p = NULL; -+ return PAM_USER_UNKNOWN; -+ } -+ -+ salt_len = strlen(salt); -+ if (salt_len == 0) { -+ return (nullok == 0) ? PAM_AUTH_ERR : PAM_SUCCESS; -+ } -+ if (p == NULL || strlen(p) == 0) { -+ _pam_overwrite(salt); -+ _pam_drop(salt); -+ return PAM_AUTHTOK_ERR; -+ } -+ -+ /* the moment of truth -- do we agree with the password? */ -+ retval = PAM_AUTH_ERR; -+ if (!strncmp(salt, "$1$", 3)) { -+ pp = Goodcrypt_md5(p, salt); -+ if (pp && strcmp(pp, salt) == 0) { -+ retval = PAM_SUCCESS; -+ } else { -+ _pam_overwrite(pp); -+ _pam_drop(pp); -+ pp = Brokencrypt_md5(p, salt); -+ if (pp && strcmp(pp, salt) == 0) -+ retval = PAM_SUCCESS; -+ } -+ } else if (*salt == '$') { -+ /* -+ * Ok, we don't know the crypt algorithm, but maybe -+ * libcrypt nows about it? We should try it. -+ */ -+ pp = x_strdup (crypt(p, salt)); -+ if (pp && strcmp(pp, salt) == 0) { -+ retval = PAM_SUCCESS; -+ } -+ } else if (*salt == '*' || *salt == '!' || salt_len < 13) { -+ retval = PAM_AUTH_ERR; -+ } else { -+ pp = bigcrypt(p, 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. -+ */ -+ if (pp && salt_len == 13 && strlen(pp) > salt_len) { -+ _pam_overwrite(pp+salt_len); -+ } -+ -+ if (pp && strcmp(pp, salt) == 0) { -+ retval = PAM_SUCCESS; -+ } -+ } -+ p = NULL; /* no longer needed here */ ++ int rbytes = 0; ++ int offset = 0; ++ int i = 0; ++ char *pptr; ++ while (npass > 0) { ++ rbytes = read(fd, passwords[i]+offset, MAXPASS-offset); ++ ++ if (rbytes < 0) { ++ if (errno == EINTR) continue; ++ break; ++ } ++ if (rbytes == 0) ++ break; ++ ++ while (npass > 0 && (pptr=memchr(passwords[i]+offset, '\0', rbytes)) ++ != NULL) { ++ rbytes -= pptr - (passwords[i]+offset) + 1; ++ i++; ++ offset = 0; ++ npass--; ++ if (rbytes > 0) { ++ if (npass > 0) ++ memcpy(passwords[i], pptr+1, rbytes); ++ memset(pptr+1, '\0', rbytes); ++ } ++ } ++ offset += rbytes; ++ } + -+ /* clean up */ -+ _pam_overwrite(pp); -+ _pam_drop(pp); ++ /* clear up */ ++ if (offset > 0 && npass > 0) { ++ memset(passwords[i], '\0', offset); ++ } + -+ return retval; ++ return i; +} + -+char * -+getuidname(uid_t uid) -+{ -+ struct passwd *pw; -+ static char username[256]; -+ -+ pw = getpwuid(uid); -+ if (pw == NULL) -+ return NULL; -+ -+ strncpy(username, pw->pw_name, sizeof(username)); -+ username[sizeof(username) - 1] = '\0'; -+ -+ return username; -+} -+/* -+ * Copyright (c) Andrew G. Morgan, 1996. All rights reserved -+ * Copyright (c) Red Hat, Inc. 2007. All rights reserved ++#endif ++/* ****************************************************************** * ++ * Copyright (c) Jan Rêkorajski 1999. ++ * Copyright (c) Andrew G. Morgan 1996-8. ++ * Copyright (c) Alex O. Yuriev, 1996. ++ * Copyright (c) Cristian Gafton 1996. ++ * Copyright (c) Red Hat, Inc. 1996, 2007, 2008. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions @@ -2535,48 +3258,418 @@ diff -up /dev/null Linux-PAM-0.99.8.1/modules/pam_unix/passverify.c + */ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/support.c.update-helper Linux-PAM-0.99.8.1/modules/pam_unix/support.c --- Linux-PAM-0.99.8.1/modules/pam_unix/support.c.update-helper 2007-02-06 17:06:45.000000000 +0100 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/support.c 2007-09-18 12:05:31.000000000 +0200 -@@ -36,6 +36,8 @@ - #define SELINUX_ENABLED 0 - #endif ++++ Linux-PAM-0.99.8.1/modules/pam_unix/support.c 2008-01-08 16:17:32.000000000 +0100 +@@ -26,9 +26,8 @@ + #include + #include -+const char app_name[]="pam_unix"; -+ - /* this is a front-end for module-application conversations */ +-#include "md5.h" + #include "support.h" +-#include "bigcrypt.h" ++#include "passverify.h" + #ifdef WITH_SELINUX + #include + #define SELINUX_ENABLED is_selinux_enabled()>0 +@@ -53,8 +52,8 @@ int _make_remark(pam_handle_t * pamh, un + * set the control flags for the UNIX module. + */ + +-int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int argc, +- const char **argv) ++int _set_ctrl(pam_handle_t *pamh, int flags, int *remember, int *rounds, ++ int argc, const char **argv) + { + unsigned int ctrl; - int _make_remark(pam_handle_t * pamh, unsigned int ctrl, -@@ -627,7 +629,7 @@ int _unix_verify_password(pam_handle_t * - setreuid( save_uid, -1 ); - setreuid( -1, save_euid ); +@@ -110,6 +109,16 @@ int _set_ctrl(pam_handle_t *pamh, int fl + *remember = 400; + } } ++ if (rounds != NULL) { ++ if (j == UNIX_ALGO_ROUNDS) { ++ *rounds = strtol(*argv + 7, NULL, 10); ++ if ((*rounds < 1000) || (*rounds == INT_MAX)) ++ /* don't care about bogus values */ ++ unset(UNIX_ALGO_ROUNDS, ctrl); ++ if (*rounds >= 10000000) ++ *rounds = 9999999; ++ } ++ } + } + + ++argv; /* step to next argument */ +@@ -377,95 +386,6 @@ int _unix_comesfromsource(pam_handle_t * + } + + /* +- * _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 (pam_handle_t *pamh, unsigned int ctrl, const char *name) +-{ +- struct passwd *pwd = NULL; +- struct spwd *spwdent = NULL; +- char *salt = NULL; +- int retval; +- +- D(("called")); +- +- /* +- * This function does not have to be too smart if something goes +- * wrong, return FALSE and let this case to be treated somewhere +- * else (CG) +- */ +- +- if (on(UNIX__NONULL, ctrl)) +- return 0; /* will fail but don't let on yet */ +- +- /* UNIX passwords area */ +- +- /* Get password file entry... */ +- pwd = pam_modutil_getpwnam (pamh, name); +- +- if (pwd != NULL) { +- if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) +- { /* NIS+ */ +- uid_t save_euid, save_uid; +- +- save_euid = geteuid(); +- save_uid = getuid(); +- if (save_uid == pwd->pw_uid) +- setreuid( save_euid, save_uid ); +- else { +- setreuid( 0, -1 ); +- if (setreuid( -1, pwd->pw_uid ) == -1) { +- setreuid( -1, 0 ); +- setreuid( 0, -1 ); +- if(setreuid( -1, pwd->pw_uid ) == -1) +- /* Will fail elsewhere. */ +- return 0; +- } +- } +- +- spwdent = pam_modutil_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( -1, save_euid ); +- } - } else if (_unix_shadowed(pwd)) { -+ } else if (_unix_shadowed(pwd) && !SELINUX_ENABLED) { - /* - * ...and shadow password file entry for this user, - * if shadowing is enabled -diff -up Linux-PAM-0.99.8.1/modules/pam_unix/Makefile.am.update-helper Linux-PAM-0.99.8.1/modules/pam_unix/Makefile.am ---- Linux-PAM-0.99.8.1/modules/pam_unix/Makefile.am.update-helper 2006-12-18 19:50:50.000000000 +0100 -+++ Linux-PAM-0.99.8.1/modules/pam_unix/Makefile.am 2007-09-18 12:54:44.000000000 +0200 -@@ -4,7 +4,7 @@ +- /* +- * ...and shadow password file entry for this user, +- * if shadowing is enabled +- */ +- spwdent = pam_modutil_getspnam(pamh, name); +- } +- if (spwdent) +- salt = x_strdup(spwdent->sp_pwdp); +- else +- salt = x_strdup(pwd->pw_passwd); +- } +- /* Does this user have a password? */ +- if (salt == NULL) { +- retval = 0; +- } else { +- if (strlen(salt) == 0) +- retval = 1; +- else +- retval = 0; +- } +- +- /* tidy up */ +- +- if (salt) +- _pam_delete(salt); +- +- return retval; +-} +- +-/* + * verify the password of a user + */ + +@@ -519,7 +439,7 @@ static int _unix_run_helper_binary(pam_h + } + } + +- if (SELINUX_ENABLED && geteuid() == 0) { ++ if (geteuid() == 0) { + /* must set the real uid to 0 so the helper will not error + out if pam is called from setuid binary (su, sudo...) */ + setuid(0); +@@ -573,13 +493,66 @@ static int _unix_run_helper_binary(pam_h + return retval; + } + ++/* ++ * _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 (pam_handle_t *pamh, unsigned int ctrl, const char *name) ++{ ++ struct passwd *pwd = NULL; ++ char *salt = NULL; ++ int retval; ++ ++ D(("called")); ++ ++ /* ++ * This function does not have to be too smart if something goes ++ * wrong, return FALSE and let this case to be treated somewhere ++ * else (CG) ++ */ ++ ++ if (on(UNIX__NONULL, ctrl)) ++ return 0; /* will fail but don't let on yet */ ++ ++ /* UNIX passwords area */ ++ ++ retval = get_pwd_hash(pamh, name, &pwd, &salt); ++ ++ if (retval == PAM_UNIX_RUN_HELPER) { ++ /* salt will not be set here so we can return immediately */ ++ if (_unix_run_helper_binary(pamh, NULL, ctrl, name) == PAM_SUCCESS) ++ return 1; ++ else ++ return 0; ++ } ++ ++ /* Does this user have a password? */ ++ if (salt == NULL) { ++ retval = 0; ++ } else { ++ if (strlen(salt) == 0) ++ retval = 1; ++ else ++ retval = 0; ++ } ++ ++ /* tidy up */ ++ ++ if (salt) ++ _pam_delete(salt); ++ ++ return retval; ++} ++ + int _unix_verify_password(pam_handle_t * pamh, const char *name + ,const char *p, unsigned int ctrl) + { + struct passwd *pwd = NULL; +- struct spwd *spwdent = NULL; + char *salt = NULL; +- char *pp = NULL; + char *data_name; + int retval; + +@@ -597,48 +570,7 @@ int _unix_verify_password(pam_handle_t * + + D(("locating user's record")); + +- /* UNIX passwords area */ +- pwd = pam_modutil_getpwnam (pamh, name); /* Get password file entry... */ +- +- if (pwd != NULL) { +- if (strcmp( pwd->pw_passwd, "*NP*" ) == 0) +- { /* NIS+ */ +- uid_t save_euid, save_uid; +- +- save_euid = geteuid(); +- save_uid = getuid(); +- if (save_uid == pwd->pw_uid) +- setreuid( save_euid, save_uid ); +- else { +- setreuid( 0, -1 ); +- if (setreuid( -1, pwd->pw_uid ) == -1) { +- setreuid( -1, 0 ); +- setreuid( 0, -1 ); +- if(setreuid( -1, pwd->pw_uid ) == -1) +- return PAM_CRED_INSUFFICIENT; +- } +- } +- +- spwdent = pam_modutil_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( -1, save_euid ); +- } +- } else if (_unix_shadowed(pwd)) { +- /* +- * ...and shadow password file entry for this user, +- * if shadowing is enabled +- */ +- spwdent = pam_modutil_getspnam (pamh, name); +- } +- if (spwdent) +- salt = x_strdup(spwdent->sp_pwdp); +- else +- salt = x_strdup(pwd->pw_passwd); +- } ++ retval = get_pwd_hash(pamh, name, &pwd, &salt); + + data_name = (char *) malloc(sizeof(FAIL_PREFIX) + strlen(name)); + if (data_name == NULL) { +@@ -648,29 +580,22 @@ int _unix_verify_password(pam_handle_t * + strcpy(data_name + sizeof(FAIL_PREFIX) - 1, name); + } + +- retval = PAM_SUCCESS; +- if (pwd == NULL || salt == NULL || !strcmp(salt, "x") || ((salt[0] == '#') && (salt[1] == '#') && !strcmp(salt + 2, name))) { +- +- if (pwd != NULL && (geteuid() || SELINUX_ENABLED)) { +- /* we are not root perhaps this is the reason? Run helper */ ++ if (retval != PAM_SUCCESS) { ++ if (retval == PAM_UNIX_RUN_HELPER) { + D(("running helper binary")); + retval = _unix_run_helper_binary(pamh, p, ctrl, 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. */ +- pam_syslog(pamh, LOG_ALERT, ++ pam_syslog(pamh, LOG_WARNING, + "check pass; user (%s) unknown", name); + } else { + name = NULL; + if (on(UNIX_DEBUG, ctrl) || pwd == NULL) { +- pam_syslog(pamh, LOG_ALERT, ++ pam_syslog(pamh, LOG_WARNING, + "check pass; user unknown"); + } else { + /* don't log failure as another pam module can succeed */ +@@ -679,48 +604,7 @@ int _unix_verify_password(pam_handle_t * + } + } + } else { +- size_t 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 { +- D(("user has empty password - access denied")); +- retval = PAM_AUTH_ERR; +- } +- } else if (!p || *salt == '*' || *salt == '!') { +- retval = PAM_AUTH_ERR; +- } else { +- if (!strncmp(salt, "$1$", 3)) { +- pp = Goodcrypt_md5(p, salt); +- if (pp && strcmp(pp, salt) != 0) { +- _pam_delete(pp); +- pp = Brokencrypt_md5(p, salt); +- } +- } else if (*salt != '$' && salt_len >= 13) { +- pp = bigcrypt(p, salt); +- if (pp && salt_len == 13 && strlen(pp) > salt_len) { +- _pam_overwrite(pp + salt_len); +- } +- } else { +- /* +- * Ok, we don't know the crypt algorithm, but maybe +- * libcrypt nows about it? We should try it. +- */ +- pp = x_strdup (crypt(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)); +- +- if (pp && strcmp(pp, salt) == 0) { +- retval = PAM_SUCCESS; +- } else { +- retval = PAM_AUTH_ERR; +- } +- } ++ retval = verify_pwd_hash(p, salt, off(UNIX__NONULL, ctrl)); + } + + if (retval == PAM_SUCCESS) { +@@ -809,8 +693,6 @@ cleanup: + _pam_delete(data_name); + if (salt) + _pam_delete(salt); +- if (pp) +- _pam_delete(pp); - CLEANFILES = *~ + D(("done [%d].", retval)); --EXTRA_DIST = README md5.c md5_crypt.c lckpwdf.-c $(MANS) CHANGELOG \ -+EXTRA_DIST = README md5.c md5_crypt.c lckpwdf.-c passupdate.c $(MANS) CHANGELOG \ - tst-pam_unix $(XMLS) +@@ -971,26 +853,12 @@ int _unix_read_password(pam_handle_t * p + return PAM_SUCCESS; + } - man_MANS = pam_unix.8 unix_chkpwd.8 -@@ -16,7 +16,8 @@ securelibdir = $(SECUREDIR) +-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. + * Copyright (c) Alex O. Yuriev, 1996. + * Copyright (c) Cristian Gafton 1996. ++ * Copyright (c) Red Hat, Inc. 2007. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +diff -up Linux-PAM-0.99.8.1/modules/pam_unix/Makefile.am.update-helper Linux-PAM-0.99.8.1/modules/pam_unix/Makefile.am +--- Linux-PAM-0.99.8.1/modules/pam_unix/Makefile.am.update-helper 2006-12-18 19:50:50.000000000 +0100 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/Makefile.am 2008-01-08 16:17:32.000000000 +0100 +@@ -16,7 +16,9 @@ securelibdir = $(SECUREDIR) secureconfdir = $(SCONFIGDIR) AM_CFLAGS = -I$(top_srcdir)/libpam/include -I$(top_srcdir)/libpamc/include \ - -DCHKPWD_HELPER=\"$(sbindir)/unix_chkpwd\" + -DCHKPWD_HELPER=\"$(sbindir)/unix_chkpwd\" \ -+ -DUPDATE_HELPER=\"$(sbindir)/unix_update\" ++ -DUPDATE_HELPER=\"$(sbindir)/unix_update\" \ ++ -DPATH_RANDOMDEV=\"/dev/urandom\" if HAVE_LIBSELINUX AM_CFLAGS += -D"WITH_SELINUX" -@@ -34,9 +35,9 @@ endif +@@ -25,33 +27,40 @@ if HAVE_LIBCRACK + AM_CFLAGS += -D"USE_CRACKLIB" + endif + +-pam_unix_la_LDFLAGS = -no-undefined -avoid-version -module \ +- @LIBCRACK@ @LIBNSL@ -L$(top_builddir)/libpam -lpam \ +- @LIBCRYPT@ @LIBSELINUX@ ++pam_unix_la_LDFLAGS = -no-undefined -avoid-version -module + if HAVE_VERSIONING + pam_unix_la_LDFLAGS += -Wl,--version-script=$(srcdir)/../modules.map + endif ++pam_unix_la_LIBADD = @LIBCRACK@ @LIBNSL@ -L$(top_builddir)/libpam -lpam \ ++ @LIBCRYPT@ @LIBSELINUX@ securelib_LTLIBRARIES = pam_unix.la @@ -2588,21 +3681,43 @@ diff -up Linux-PAM-0.99.8.1/modules/pam_unix/Makefile.am.update-helper Linux-PAM noinst_PROGRAMS = bigcrypt -@@ -48,11 +49,16 @@ bigcrypt_SOURCES = bigcrypt.c bigcrypt_m + pam_unix_la_SOURCES = bigcrypt.c pam_unix_acct.c \ + pam_unix_auth.c pam_unix_passwd.c pam_unix_sess.c support.c \ +- yppasswd_xdr.c md5_good.c md5_broken.c ++ passverify.c yppasswd_xdr.c md5_good.c md5_broken.c + + bigcrypt_SOURCES = bigcrypt.c bigcrypt_main.c bigcrypt_CFLAGS = $(AM_CFLAGS) - bigcrypt_LDFLAGS = @LIBCRYPT@ +-bigcrypt_LDFLAGS = @LIBCRYPT@ ++bigcrypt_LDADD = @LIBCRYPT@ -unix_chkpwd_SOURCES = unix_chkpwd.c md5_good.c md5_broken.c bigcrypt.c -+unix_chkpwd_SOURCES = unix_chkpwd.c passverify.c md5_good.c md5_broken.c bigcrypt.c - unix_chkpwd_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ - unix_chkpwd_LDFLAGS = @PIE_LDFLAGS@ -L$(top_builddir)/libpam -lpam \ - @LIBCRYPT@ @LIBSELINUX@ - -+unix_update_SOURCES = unix_update.c passverify.c md5_good.c md5_broken.c bigcrypt.c -+unix_update_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -+unix_update_LDFLAGS = @PIE_LDFLAGS@ -L$(top_builddir)/libpam -lpam \ -+ @LIBCRYPT@ @LIBSELINUX@ -+ +-unix_chkpwd_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ +-unix_chkpwd_LDFLAGS = @PIE_LDFLAGS@ -L$(top_builddir)/libpam -lpam \ +- @LIBCRYPT@ @LIBSELINUX@ ++unix_chkpwd_SOURCES = unix_chkpwd.c md5_good.c md5_broken.c bigcrypt.c \ ++ passverify.c ++unix_chkpwd_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"unix_chkpwd\" ++unix_chkpwd_LDFLAGS = @PIE_LDFLAGS@ ++unix_chkpwd_LDADD = @LIBCRYPT@ @LIBSELINUX@ ++ ++unix_update_SOURCES = unix_update.c md5_good.c md5_broken.c bigcrypt.c \ ++ passverify.c ++unix_update_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"unix_update\" ++unix_update_LDFLAGS = @PIE_LDFLAGS@ ++unix_update_LDADD = @LIBCRYPT@ @LIBSELINUX@ + if ENABLE_REGENERATE_MAN noinst_DATA = README - README: pam_unix.8.xml +diff -up Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_auth.c.update-helper Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_auth.c +--- Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_auth.c.update-helper 2006-12-20 15:52:55.000000000 +0100 ++++ Linux-PAM-0.99.8.1/modules/pam_unix/pam_unix_auth.c 2008-01-07 16:38:50.000000000 +0100 +@@ -111,7 +111,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_h + + D(("called.")); + +- ctrl = _set_ctrl(pamh, flags, NULL, argc, argv); ++ ctrl = _set_ctrl(pamh, flags, NULL, NULL, argc, argv); + + /* Get a few bytes so we can pass our return value to + pam_sm_setcred(). */ diff --git a/pam.spec b/pam.spec index e4e1c72..d529674 100644 --- a/pam.spec +++ b/pam.spec @@ -11,7 +11,7 @@ Summary: A security tool which provides authentication for applications Name: pam Version: 0.99.8.1 -Release: 13%{?dist} +Release: 14%{?dist} # The library is BSD licensed with option to relicense as GPLv2+ - this option is redundant # as the BSD license allows that anyway. pam_timestamp and pam_console modules are GPLv2+, # pam_rhosts_auth module is BSD with advertising @@ -32,8 +32,7 @@ Patch2: db-4.6.18-glibc.patch Patch4: pam-0.99.8.1-dbpam.patch Patch5: pam-0.99.8.1-audit-no-log.patch Patch24: pam-0.99.8.1-unix-update-helper.patch -Patch25: pam-0.99.7.1-unix-hpux-aging.patch -Patch26: pam-0.99.8.1-unix-blankpass.patch +Patch25: pam-0.99.8.1-unix-hpux-aging.patch Patch31: pam-0.99.3.0-cracklib-try-first-pass.patch Patch32: pam-0.99.3.0-tally-fail-close.patch Patch40: pam-0.99.7.1-namespace-temp-logon.patch @@ -107,7 +106,7 @@ popd %patch5 -p1 -b .no-log %patch24 -p1 -b .update-helper %patch25 -p1 -b .unix-hpux-aging -%patch26 -p1 -b .blankpass +#%patch26 -p1 -b .blankpass %patch31 -p1 -b .try-first-pass %patch32 -p1 -b .fail-close %patch40 -p1 -b .temp-logon @@ -414,6 +413,10 @@ fi %doc doc/adg/*.txt doc/adg/html %changelog +* Wed Jan 8 2008 Tomas Mraz 0.99.8.1-14 +- support for sha256 and sha512 password hashes +- account expiry checks moved to unix_chkpwd helper + * Wed Jan 2 2008 Tomas Mraz 0.99.8.1-13 - wildcard match support in pam_tty_audit (by Miloslav Trmač)