Author: gd Date: 2007-02-22 13:35:01 +0000 (Thu, 22 Feb 2007) New Revision: 21500
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=21500 Log: Fix inappropriate creation of a krb5 ticket refreshing event when a user changed a password via pam_chauthtok. Only do this if a) a user logs on using an expired password (or a password that needs to be changed immediately) or b) the user itself changes his password. Also make sure to delete the in-memory krb5 credential cache (when a user did not request a FILE based cred cache). Finally honor the krb5 settings in the first pam authentication in the chauthtok block (PAM_PRELIM_CHECK). This circumvents confusion when NTLM samlogon authentication is still possible with the old password after the password has been already changed (on w2k3 sp1 dcs). Guenther Modified: branches/SAMBA_3_0/source/nsswitch/pam_winbind.c branches/SAMBA_3_0/source/nsswitch/pam_winbind.h branches/SAMBA_3_0/source/nsswitch/winbindd_pam.c branches/SAMBA_3_0_25/source/nsswitch/pam_winbind.c branches/SAMBA_3_0_25/source/nsswitch/pam_winbind.h branches/SAMBA_3_0_25/source/nsswitch/winbindd_pam.c Changeset: Modified: branches/SAMBA_3_0/source/nsswitch/pam_winbind.c =================================================================== --- branches/SAMBA_3_0/source/nsswitch/pam_winbind.c 2007-02-22 13:15:49 UTC (rev 21499) +++ branches/SAMBA_3_0/source/nsswitch/pam_winbind.c 2007-02-22 13:35:01 UTC (rev 21500) @@ -198,6 +198,7 @@ _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_LOGONSERVER); _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_PROFILEPATH); _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_NEW_AUTHTOK_REQD); /* Use atoi to get PAM result code */ + _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH); _PAM_LOG_STATE_DATA_POINTER(pamh, ctrl, PAM_WINBIND_PWD_LAST_SET); } @@ -1564,6 +1565,8 @@ if (retval == PAM_NEW_AUTHTOK_REQD || retval == PAM_AUTHTOK_EXPIRED) { + char *new_authtok_required_during_auth = NULL; + if (!asprintf(&new_authtok_required, "%d", retval)) { retval = PAM_BUF_ERR; goto out; @@ -1572,6 +1575,15 @@ pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, new_authtok_required, _pam_winbind_cleanup_func); retval = PAM_SUCCESS; + + if (!asprintf(&new_authtok_required_during_auth, "%d", True)) { + retval = PAM_BUF_ERR; + goto out; + } + + pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, + new_authtok_required_during_auth, _pam_winbind_cleanup_func); + goto out; } @@ -1851,8 +1863,51 @@ return retval; } +/** + * evaluate whether we need to re-authenticate with kerberos after a password change + * + * @param pamh PAM handle + * @param ctrl PAM winbind options. + * @param user The username + * + * @return boolean Returns True if required, False if not. + */ +static BOOL _pam_require_krb5_auth_after_chauthtok(pam_handle_t *pamh, int ctrl, const char *user) +{ + /* Make sure that we only do this if + * a) the chauthtok got initiated during a logon attempt (authenticate->acct_mgmt->chauthtok) + * b) any later password change via the "passwd" command if done by the user itself + */ + + char *new_authtok_reqd_during_auth = NULL; + struct passwd *pwd = NULL; + + if (!(ctrl & WINBIND_KRB5_AUTH)) { + return False; + } + + _pam_get_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, &new_authtok_reqd_during_auth); + pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, NULL, NULL); + + if (new_authtok_reqd_during_auth) { + return True; + } + + pwd = getpwnam(user); + if (!pwd) { + return False; + } + + if (getuid() == pwd->pw_uid) { + return True; + } + + return False; +} + + PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, int argc, const char **argv) @@ -1948,9 +2003,6 @@ goto out; } - /* We don't need krb5 env set for password change test. */ - ctrl &= ~WINBIND_KRB5_AUTH; - /* verify that this is the password for this user */ ret = winbind_auth_request(pamh, ctrl, user, pass_old, @@ -2042,10 +2094,8 @@ goto out; } - /* just in case we need krb5 creds after a password change over msrpc */ + if (_pam_require_krb5_auth_after_chauthtok(pamh, ctrl, user)) { - if (ctrl & WINBIND_KRB5_AUTH) { - const char *member = get_member_from_config(pamh, argc, argv, ctrl, d); const char *cctype = get_krb5_cc_type_from_config(pamh, argc, argv, ctrl, d); Modified: branches/SAMBA_3_0/source/nsswitch/pam_winbind.h =================================================================== --- branches/SAMBA_3_0/source/nsswitch/pam_winbind.h 2007-02-22 13:15:49 UTC (rev 21499) +++ branches/SAMBA_3_0/source/nsswitch/pam_winbind.h 2007-02-22 13:35:01 UTC (rev 21500) @@ -99,6 +99,7 @@ #define off(x, y) (!(x & y)) #define PAM_WINBIND_NEW_AUTHTOK_REQD "PAM_WINBIND_NEW_AUTHTOK_REQD" +#define PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH "PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH" #define PAM_WINBIND_HOMEDIR "PAM_WINBIND_HOMEDIR" #define PAM_WINBIND_LOGONSCRIPT "PAM_WINBIND_LOGONSCRIPT" #define PAM_WINBIND_LOGONSERVER "PAM_WINBIND_LOGONSERVER" Modified: branches/SAMBA_3_0/source/nsswitch/winbindd_pam.c =================================================================== --- branches/SAMBA_3_0/source/nsswitch/winbindd_pam.c 2007-02-22 13:15:49 UTC (rev 21499) +++ branches/SAMBA_3_0/source/nsswitch/winbindd_pam.c 2007-02-22 13:35:01 UTC (rev 21500) @@ -671,6 +671,17 @@ DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n", nt_errstr(result))); } + } else { + + /* need to delete the memory cred cache, it is not used anymore */ + + krb5_ret = ads_kdestroy(cc); + if (krb5_ret) { + DEBUG(3,("winbindd_raw_kerberos_login: " + "could not destroy krb5 credential cache: " + "%s\n", error_message(krb5_ret))); + } + } result = NT_STATUS_OK; Modified: branches/SAMBA_3_0_25/source/nsswitch/pam_winbind.c =================================================================== --- branches/SAMBA_3_0_25/source/nsswitch/pam_winbind.c 2007-02-22 13:15:49 UTC (rev 21499) +++ branches/SAMBA_3_0_25/source/nsswitch/pam_winbind.c 2007-02-22 13:35:01 UTC (rev 21500) @@ -198,6 +198,7 @@ _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_LOGONSERVER); _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_PROFILEPATH); _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_NEW_AUTHTOK_REQD); /* Use atoi to get PAM result code */ + _PAM_LOG_STATE_DATA_STRING(pamh, ctrl, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH); _PAM_LOG_STATE_DATA_POINTER(pamh, ctrl, PAM_WINBIND_PWD_LAST_SET); } @@ -1564,6 +1565,8 @@ if (retval == PAM_NEW_AUTHTOK_REQD || retval == PAM_AUTHTOK_EXPIRED) { + char *new_authtok_required_during_auth = NULL; + if (!asprintf(&new_authtok_required, "%d", retval)) { retval = PAM_BUF_ERR; goto out; @@ -1572,6 +1575,15 @@ pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD, new_authtok_required, _pam_winbind_cleanup_func); retval = PAM_SUCCESS; + + if (!asprintf(&new_authtok_required_during_auth, "%d", True)) { + retval = PAM_BUF_ERR; + goto out; + } + + pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, + new_authtok_required_during_auth, _pam_winbind_cleanup_func); + goto out; } @@ -1851,8 +1863,51 @@ return retval; } +/** + * evaluate whether we need to re-authenticate with kerberos after a password change + * + * @param pamh PAM handle + * @param ctrl PAM winbind options. + * @param user The username + * + * @return boolean Returns True if required, False if not. + */ +static BOOL _pam_require_krb5_auth_after_chauthtok(pam_handle_t *pamh, int ctrl, const char *user) +{ + /* Make sure that we only do this if + * a) the chauthtok got initiated during a logon attempt (authenticate->acct_mgmt->chauthtok) + * b) any later password change via the "passwd" command if done by the user itself + */ + + char *new_authtok_reqd_during_auth = NULL; + struct passwd *pwd = NULL; + + if (!(ctrl & WINBIND_KRB5_AUTH)) { + return False; + } + + _pam_get_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, &new_authtok_reqd_during_auth); + pam_set_data(pamh, PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH, NULL, NULL); + + if (new_authtok_reqd_during_auth) { + return True; + } + + pwd = getpwnam(user); + if (!pwd) { + return False; + } + + if (getuid() == pwd->pw_uid) { + return True; + } + + return False; +} + + PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags, int argc, const char **argv) @@ -1948,9 +2003,6 @@ goto out; } - /* We don't need krb5 env set for password change test. */ - ctrl &= ~WINBIND_KRB5_AUTH; - /* verify that this is the password for this user */ ret = winbind_auth_request(pamh, ctrl, user, pass_old, @@ -2042,10 +2094,8 @@ goto out; } - /* just in case we need krb5 creds after a password change over msrpc */ + if (_pam_require_krb5_auth_after_chauthtok(pamh, ctrl, user)) { - if (ctrl & WINBIND_KRB5_AUTH) { - const char *member = get_member_from_config(pamh, argc, argv, ctrl, d); const char *cctype = get_krb5_cc_type_from_config(pamh, argc, argv, ctrl, d); Modified: branches/SAMBA_3_0_25/source/nsswitch/pam_winbind.h =================================================================== --- branches/SAMBA_3_0_25/source/nsswitch/pam_winbind.h 2007-02-22 13:15:49 UTC (rev 21499) +++ branches/SAMBA_3_0_25/source/nsswitch/pam_winbind.h 2007-02-22 13:35:01 UTC (rev 21500) @@ -99,6 +99,7 @@ #define off(x, y) (!(x & y)) #define PAM_WINBIND_NEW_AUTHTOK_REQD "PAM_WINBIND_NEW_AUTHTOK_REQD" +#define PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH "PAM_WINBIND_NEW_AUTHTOK_REQD_DURING_AUTH" #define PAM_WINBIND_HOMEDIR "PAM_WINBIND_HOMEDIR" #define PAM_WINBIND_LOGONSCRIPT "PAM_WINBIND_LOGONSCRIPT" #define PAM_WINBIND_LOGONSERVER "PAM_WINBIND_LOGONSERVER" Modified: branches/SAMBA_3_0_25/source/nsswitch/winbindd_pam.c =================================================================== --- branches/SAMBA_3_0_25/source/nsswitch/winbindd_pam.c 2007-02-22 13:15:49 UTC (rev 21499) +++ branches/SAMBA_3_0_25/source/nsswitch/winbindd_pam.c 2007-02-22 13:35:01 UTC (rev 21500) @@ -671,6 +671,17 @@ DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n", nt_errstr(result))); } + } else { + + /* need to delete the memory cred cache, it is not used anymore */ + + krb5_ret = ads_kdestroy(cc); + if (krb5_ret) { + DEBUG(3,("winbindd_raw_kerberos_login: " + "could not destroy krb5 credential cache: " + "%s\n", error_message(krb5_ret))); + } + } result = NT_STATUS_OK;