From 29f99826c8010a0d05ac25fc53a0ba99b2c76bd4 Mon Sep 17 00:00:00 2001 From: Günther Deschner Date: Thu, 22 Feb 2007 13:35:01 +0000 Subject: r21500: 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 --- source/nsswitch/pam_winbind.c | 62 ++++++++++++++++++++++++++++++++++++++---- source/nsswitch/pam_winbind.h | 1 + source/nsswitch/winbindd_pam.c | 11 ++++++++ 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/source/nsswitch/pam_winbind.c b/source/nsswitch/pam_winbind.c index d2979ed71ca..ac87fcf32ee 100644 --- a/source/nsswitch/pam_winbind.c +++ b/source/nsswitch/pam_winbind.c @@ -198,6 +198,7 @@ static void _pam_log_state(const pam_handle_t *pamh, int ctrl) _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 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, 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 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, 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,6 +1863,49 @@ out: 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 @@ -1948,9 +2003,6 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, 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,9 +2094,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, goto out; } - /* just in case we need krb5 creds after a password change over msrpc */ - - if (ctrl & WINBIND_KRB5_AUTH) { + if (_pam_require_krb5_auth_after_chauthtok(pamh, ctrl, user)) { 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); diff --git a/source/nsswitch/pam_winbind.h b/source/nsswitch/pam_winbind.h index 05fc2e128e6..73da2826cab 100644 --- a/source/nsswitch/pam_winbind.h +++ b/source/nsswitch/pam_winbind.h @@ -99,6 +99,7 @@ do { \ #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" diff --git a/source/nsswitch/winbindd_pam.c b/source/nsswitch/winbindd_pam.c index 98f76bea923..69e004ec718 100644 --- a/source/nsswitch/winbindd_pam.c +++ b/source/nsswitch/winbindd_pam.c @@ -671,6 +671,17 @@ static NTSTATUS winbindd_raw_kerberos_login(struct winbindd_domain *domain, 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; -- cgit