Delta from 1.12 to 1.13 from Linux-PAM pam_unix_passwd.c made to work with our changes. Not sure this is actually relevant, as other changes seem to have been made upstream. This patch was specifically reverted in upstream CVS revision 1.18 as introducing a "race". Index: Linux-PAM/modules/pam_unix/pam_unix_passwd.c =================================================================== --- Linux-PAM/modules/pam_unix/pam_unix_passwd.c.orig +++ Linux-PAM/modules/pam_unix/pam_unix_passwd.c @@ -749,8 +749,7 @@ char *towhat, unsigned int ctrl, int remember) { struct passwd *pwd = NULL; - int retval = 0; - int unlocked = 0; + int retval = 0, i = 0; char *master = NULL; D(("called")); @@ -770,12 +769,6 @@ int status; enum clnt_stat err; - /* Unlock passwd file to avoid deadlock */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif - unlocked = 1; - /* Initialize password information */ yppwd.newpw.pw_passwd = pwd->pw_passwd; yppwd.newpw.pw_name = pwd->pw_name; @@ -833,29 +826,28 @@ } if (_unix_comesfromsource(pamh, forwho, 1, 0)) { -#ifdef USE_LCKPWDF - if(unlocked) { - int i = 0; - /* 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. */ - while((retval = lckpwdf()) != 0 && i < 100) { - usleep(1000); - i++; - } - if(retval != 0) { - return PAM_AUTHTOK_LOCK_BUSY; - } - } -#endif /* first, save old password */ if (save_old_password(pamh, forwho, fromwhat, remember)) { retval = PAM_AUTHTOK_ERR; goto done; } + +#ifdef USE_LCKPWDF + /* These values for the number of attempts and the sleep time + are, of course, completely arbitrary. + My reading of the PAM docs is that, once pam_chauthtok() has been + called with PAM_UPDATE_AUTHTOK, we are obliged to take any + reasonable steps to make sure the token is updated; so retrying + for 1/10 sec. isn't overdoing it. */ + while((retval = lckpwdf()) != 0 && i < 100) { + usleep(1000); + i++; + } + if(retval != 0) { + retval = PAM_AUTHTOK_LOCK_BUSY; + goto done; + } +#endif if (on(UNIX_SHADOW, ctrl) || _unix_shadowed(pwd)) { retval = _update_shadow(pamh, forwho, towhat); #ifdef WITH_SELINUX @@ -1024,7 +1016,7 @@ int argc, const char **argv) { unsigned int ctrl, lctrl; - int retval, i; + int retval; int remember = -1; /* */ @@ -1255,30 +1247,11 @@ pass_new = pass_old = NULL; /* tidy up */ return retval; } -#ifdef USE_LCKPWDF - /* These values for the number of attempts and the sleep time - are, of course, completely arbitrary. - My reading of the PAM docs is that, once pam_chauthtok() has been - called with PAM_UPDATE_AUTHTOK, we are obliged to take any - reasonable steps to make sure the token is updated; so retrying - for 1/10 sec. isn't overdoing it. */ - i=0; - while((retval = lckpwdf()) != 0 && i < 100) { - usleep(1000); - i++; - } - if(retval != 0) { - return PAM_AUTHTOK_LOCK_BUSY; - } -#endif if (pass_old) { retval = _unix_verify_password(pamh, user, pass_old, ctrl); if (retval != PAM_SUCCESS) { pam_syslog(pamh, LOG_NOTICE, "user password changed by another process"); -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } } @@ -1286,9 +1259,6 @@ 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 return retval; } @@ -1297,9 +1267,6 @@ pam_syslog(pamh, LOG_NOTICE, "new password not acceptable 2"); pass_new = pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return retval; } @@ -1341,9 +1308,6 @@ pam_syslog(pamh, LOG_CRIT, "out of memory for password"); pass_new = pass_old = NULL; /* tidy up */ -#ifdef USE_LCKPWDF - ulckpwdf(); -#endif return PAM_BUF_ERR; } /* copy first 8 bytes of password */