s3:trusts_util: also pass the previous_nt_hash to netlogon_creds_cli_auth()
authorStefan Metzmacher <metze@samba.org>
Wed, 21 Jun 2017 19:30:39 +0000 (21:30 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 13 Jul 2017 18:01:29 +0000 (20:01 +0200)
Even in the case where only the password is known to the server, we should
try to leave a valid authentication behind.

We have better ways to indentify which password worked than only using
the current one.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=12782

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(cherry picked from commit d60404b032eca5384d889352f52b9b129861b4af)

source3/libsmb/trusts_util.c

index 5bc8005e596c5ffadeba79d2f85bb4788e750650..ff7f256eb775bec7f24edd5f19b0b35c0b4bfb27 100644 (file)
@@ -115,9 +115,12 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
        struct trust_pw_change_state *state;
        struct cli_credentials *creds = NULL;
        const struct samr_Password *current_nt_hash = NULL;
+       const struct samr_Password *previous_nt_hash = NULL;
        uint8_t num_nt_hashes = 0;
-       const struct samr_Password *nt_hashes[1] = { NULL, };
+       uint8_t idx = 0;
+       const struct samr_Password *nt_hashes[1+1] = { NULL, };
        uint8_t idx_nt_hashes = 0;
+       uint8_t idx_current = UINT8_MAX;
        enum netr_SchannelType sec_channel_type = SEC_CHAN_NULL;
        time_t pass_last_set_time;
        uint32_t old_version = 0;
@@ -181,6 +184,7 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
                TALLOC_FREE(frame);
                return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
        }
+       previous_nt_hash = cli_credentials_get_old_nt_hash(creds, frame);
 
        old_version = cli_credentials_get_kvno(creds);
        pass_last_set_time = cli_credentials_get_password_last_changed_time(creds);
@@ -266,15 +270,19 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
                return status;
        }
 
-       nt_hashes[0] = current_nt_hash;
-       num_nt_hashes = 1;
+       idx_current = idx;
+       nt_hashes[idx++] = current_nt_hash;
+       if (previous_nt_hash != NULL) {
+               nt_hashes[idx++] = previous_nt_hash;
+       }
+       num_nt_hashes = idx;
+
+       DEBUG(0,("%s : %s(%s): Verifying passwords remotely %s.\n",
+                current_timestring(talloc_tos(), false),
+                __func__, domain, context_name));
 
        /*
-        * We could use cli_credentials_get_old_nt_hash(creds, frame) to
-        * set previous_nt_hash.
-        *
-        * But we want to check if the dc has our current password and only do
-        * a change if that's the case. So we keep previous_nt_hash = NULL.
+        * Check which password the dc knows about.
         *
         * TODO:
         * If the previous password is the only password in common with the dc,
@@ -287,12 +295,21 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
                                         nt_hashes,
                                         &idx_nt_hashes);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for old password - %s!\n",
-                         context_name, nt_errstr(status)));
+               DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for old passwords (%u) - %s!\n",
+                         context_name, num_nt_hashes, nt_errstr(status)));
                TALLOC_FREE(frame);
                return status;
        }
 
+       if (idx_nt_hashes != idx_current) {
+               DEBUG(0,("%s : %s(%s): Verified older password remotely "
+                        "skip changing %s\n",
+                        current_timestring(talloc_tos(), false),
+                        __func__, domain, context_name));
+               TALLOC_FREE(frame);
+               return NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE;
+       }
+
        DEBUG(0,("%s : %s(%s): Verified old password remotely using %s\n",
                 current_timestring(talloc_tos(), false),
                 __func__, domain, context_name));
@@ -380,8 +397,10 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
        /*
         * Now we verify the new password.
         */
-       nt_hashes[0] = current_nt_hash;
-       num_nt_hashes = 1;
+       idx = 0;
+       idx_current = idx;
+       nt_hashes[idx++] = current_nt_hash;
+       num_nt_hashes = idx;
        status = netlogon_creds_cli_auth(context, b,
                                         num_nt_hashes,
                                         nt_hashes,