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)
committerGünther Deschner <gd@samba.org>
Thu, 22 Feb 2007 13:35:01 +0000 (13:35 +0000)
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
source/nsswitch/pam_winbind.h
source/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;