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;

Reply via email to