r21500: Fix inappropriate creation of a krb5 ticket refreshing event when a user
authorGünther Deschner <gd@samba.org>
Thu, 22 Feb 2007 13:35:01 +0000 (13:35 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:18:08 +0000 (12:18 -0500)
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
(This used to be commit c3005c48cd86bc1dd17fab80da05c2d34071b872)

source3/nsswitch/pam_winbind.c
source3/nsswitch/pam_winbind.h
source3/nsswitch/winbindd_pam.c

index d2979ed71cac46c30f816c6dcf351dc50fc53bd2..ac87fcf32eeb8b5a28cea7ae07a31b4e2610a621 100644 (file)
@@ -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);
index 05fc2e128e6c7fe8ae34d2406586bc0b2da56c4e..73da2826cabb3d133b5ee3e636830176b431b485 100644 (file)
@@ -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"
index 98f76bea9239d55f7815125fab734cebdb9d5814..69e004ec71890770ef8e192e7e90c73d80cc1dcd 100644 (file)
@@ -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;