[SCM] Samba Shared Repository - branch master updated

Günther Deschner gd at samba.org
Tue Jan 12 04:11:18 MST 2010


The branch, master has been updated
       via  a744dbc... s4-smbtorture: add RPC-SAMR-PASSWORDS-BADPWDCOUNT torture test.
       via  c9e84ad... s4-smbtorture: allow test_SamLogon to test interactive samlogon in RPC-SAMR family of tests.
      from  d75d14f... s3-lanman: Allow a level2 descriptor for a level1 NetShareGetInfo

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit a744dbcf2b29040d7d630201cef9f64edafd7eec
Author: Günther Deschner <gd at samba.org>
Date:   Mon Jan 11 21:18:51 2010 +0100

    s4-smbtorture: add RPC-SAMR-PASSWORDS-BADPWDCOUNT torture test.
    
    This test checks the behavior (since w2k3 sp1) of the badPwdCount samr attribute
    in relation to password history and successfull and unsucessful netlogon
    samlogons.
    
    Michael, please check. This should help verifiying Bug #4347.
    
    Guenther

commit c9e84ad3970cd3360313c1582d806c0393ce6228
Author: Günther Deschner <gd at samba.org>
Date:   Tue Jan 12 11:48:23 2010 +0100

    s4-smbtorture: allow test_SamLogon to test interactive samlogon in RPC-SAMR family of tests.
    
    Guenther

-----------------------------------------------------------------------

Summary of changes:
 source4/torture/rpc/rpc.c  |    1 +
 source4/torture/rpc/samr.c |  595 +++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 560 insertions(+), 36 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/torture/rpc/rpc.c b/source4/torture/rpc/rpc.c
index 3362bad..2ab0d12 100644
--- a/source4/torture/rpc/rpc.c
+++ b/source4/torture/rpc/rpc.c
@@ -462,6 +462,7 @@ NTSTATUS torture_rpc_init(void)
 	torture_suite_add_suite(suite, torture_rpc_samr_accessmask(suite));
 	torture_suite_add_suite(suite, torture_rpc_samr_workstation_auth(suite));
 	torture_suite_add_suite(suite, torture_rpc_samr_passwords_pwdlastset(suite));
+	torture_suite_add_suite(suite, torture_rpc_samr_passwords_badpwdcount(suite));
 	torture_suite_add_suite(suite, torture_rpc_samr_user_privileges(suite));
 	torture_suite_add_suite(suite, torture_rpc_samr_large_dc(suite));
 	torture_suite_add_suite(suite, torture_rpc_epmapper(suite));
diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c
index b5aa761..20d4803 100644
--- a/source4/torture/rpc/samr.c
+++ b/source4/torture/rpc/samr.c
@@ -4,7 +4,7 @@
 
    Copyright (C) Andrew Tridgell 2003
    Copyright (C) Andrew Bartlett <abartlet at samba.org> 2003
-   Copyright (C) Guenther Deschner 2008,2009
+   Copyright (C) Guenther Deschner 2008-2010
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -33,6 +33,10 @@
 #include "libcli/security/security.h"
 #include "torture/rpc/rpc.h"
 #include "param/param.h"
+#include "auth/gensec/gensec.h"
+#include "auth/gensec/gensec_proto.h"
+#include "../libcli/auth/schannel.h"
+#include "auth/gensec/schannel_state.h"
 
 #include <unistd.h>
 
@@ -46,6 +50,7 @@
 enum torture_samr_choice {
 	TORTURE_SAMR_PASSWORDS,
 	TORTURE_SAMR_PASSWORDS_PWDLASTSET,
+	TORTURE_SAMR_PASSWORDS_BADPWDCOUNT,
 	TORTURE_SAMR_USER_ATTRIBUTES,
 	TORTURE_SAMR_USER_PRIVILEGES,
 	TORTURE_SAMR_OTHER,
@@ -2730,17 +2735,24 @@ static bool test_QueryUserInfo_pwdlastset(struct dcerpc_pipe *p,
 static bool test_SamLogon(struct torture_context *tctx,
 			  struct dcerpc_pipe *p,
 			  struct cli_credentials *test_credentials,
-			  NTSTATUS expected_result)
+			  NTSTATUS expected_result,
+			  bool interactive)
 {
 	NTSTATUS status;
 	struct netr_LogonSamLogonEx r;
 	union netr_LogonLevel logon;
 	union netr_Validation validation;
 	uint8_t authoritative;
+	struct netr_IdentityInfo identity;
 	struct netr_NetworkInfo ninfo;
+	struct netr_PasswordInfo pinfo;
 	DATA_BLOB names_blob, chal, lm_resp, nt_resp;
 	int flags = CLI_CRED_NTLM_AUTH;
 	uint32_t samlogon_flags = 0;
+	struct netlogon_creds_CredentialState *creds;
+	struct netr_Authenticator a;
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_schannel_creds(p->conn->security_state.generic_state, tctx, &creds), "");
 
 	if (lp_client_lanman_auth(tctx->lp_ctx)) {
 		flags |= CLI_CRED_LANMAN_AUTH;
@@ -2751,50 +2763,74 @@ static bool test_SamLogon(struct torture_context *tctx,
 	}
 
 	cli_credentials_get_ntlm_username_domain(test_credentials, tctx,
-						 &ninfo.identity_info.account_name.string,
-						 &ninfo.identity_info.domain_name.string);
+						 &identity.account_name.string,
+						 &identity.domain_name.string);
 
-	generate_random_buffer(ninfo.challenge,
-			       sizeof(ninfo.challenge));
-	chal = data_blob_const(ninfo.challenge,
-			       sizeof(ninfo.challenge));
+	identity.parameter_control =
+		MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
+		MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
+	identity.logon_id_low = 0;
+	identity.logon_id_high = 0;
+	identity.workstation.string = cli_credentials_get_workstation(test_credentials);
 
-	names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(test_credentials),
-						cli_credentials_get_domain(test_credentials));
+	if (interactive) {
+		netlogon_creds_client_authenticator(creds, &a);
 
-	status = cli_credentials_get_ntlm_response(test_credentials, tctx,
-						   &flags,
-						   chal,
-						   names_blob,
-						   &lm_resp, &nt_resp,
-						   NULL, NULL);
-	torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed");
+		if (!E_deshash(cli_credentials_get_password(test_credentials), pinfo.lmpassword.hash)) {
+			ZERO_STRUCT(pinfo.lmpassword.hash);
+		}
+		E_md4hash(cli_credentials_get_password(test_credentials), pinfo.ntpassword.hash);
 
-	ninfo.lm.data = lm_resp.data;
-	ninfo.lm.length = lm_resp.length;
+		if (creds->negotiate_flags & NETLOGON_NEG_ARCFOUR) {
+			netlogon_creds_arcfour_crypt(creds, pinfo.lmpassword.hash, 16);
+			netlogon_creds_arcfour_crypt(creds, pinfo.ntpassword.hash, 16);
+		} else {
+			netlogon_creds_des_encrypt(creds, &pinfo.lmpassword);
+			netlogon_creds_des_encrypt(creds, &pinfo.ntpassword);
+		}
 
-	ninfo.nt.data = nt_resp.data;
-	ninfo.nt.length = nt_resp.length;
+		pinfo.identity_info = identity;
+		logon.password = &pinfo;
 
-	ninfo.identity_info.parameter_control =
-		MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
-		MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
-	ninfo.identity_info.logon_id_low = 0;
-	ninfo.identity_info.logon_id_high = 0;
-	ninfo.identity_info.workstation.string = cli_credentials_get_workstation(test_credentials);
+		r.in.logon_level = NetlogonInteractiveInformation;
+	} else {
+		generate_random_buffer(ninfo.challenge,
+				       sizeof(ninfo.challenge));
+		chal = data_blob_const(ninfo.challenge,
+				       sizeof(ninfo.challenge));
+
+		names_blob = NTLMv2_generate_names_blob(tctx, cli_credentials_get_workstation(test_credentials),
+							cli_credentials_get_domain(test_credentials));
+
+		status = cli_credentials_get_ntlm_response(test_credentials, tctx,
+							   &flags,
+							   chal,
+							   names_blob,
+							   &lm_resp, &nt_resp,
+							   NULL, NULL);
+		torture_assert_ntstatus_ok(tctx, status, "cli_credentials_get_ntlm_response failed");
+
+		ninfo.lm.data = lm_resp.data;
+		ninfo.lm.length = lm_resp.length;
 
-	logon.network = &ninfo;
+		ninfo.nt.data = nt_resp.data;
+		ninfo.nt.length = nt_resp.length;
+
+		ninfo.identity_info = identity;
+		logon.network = &ninfo;
+
+		r.in.logon_level = NetlogonNetworkInformation;
+	}
 
 	r.in.server_name = talloc_asprintf(tctx, "\\\\%s", dcerpc_server_name(p));
 	r.in.computer_name = cli_credentials_get_workstation(test_credentials);
-	r.in.logon_level = NetlogonNetworkInformation;
 	r.in.logon = &logon;
 	r.in.flags = &samlogon_flags;
 	r.out.flags = &samlogon_flags;
 	r.out.validation = &validation;
 	r.out.authoritative = &authoritative;
 
-	torture_comment(tctx, "Testing LogonSamLogon with name %s\n", ninfo.identity_info.account_name.string);
+	torture_comment(tctx, "Testing LogonSamLogon with name %s\n", identity.account_name.string);
 
 	r.in.validation_level = 6;
 
@@ -2818,7 +2854,8 @@ static bool test_SamLogon_with_creds(struct torture_context *tctx,
 				     struct cli_credentials *machine_creds,
 				     const char *acct_name,
 				     char *password,
-				     NTSTATUS expected_samlogon_result)
+				     NTSTATUS expected_samlogon_result,
+				     bool interactive)
 {
 	bool ret = true;
 	struct cli_credentials *test_credentials;
@@ -2834,11 +2871,11 @@ static bool test_SamLogon_with_creds(struct torture_context *tctx,
 	cli_credentials_set_password(test_credentials,
 				     password, CRED_SPECIFIED);
 
-	torture_comment(tctx, "testing samlogon as %s password: %s\n",
-		acct_name, password);
+	torture_comment(tctx, "testing samlogon (%s) as %s password: %s\n",
+		interactive ? "interactive" : "network", acct_name, password);
 
 	if (!test_SamLogon(tctx, p, test_credentials,
-			   expected_samlogon_result)) {
+			    expected_samlogon_result, interactive)) {
 		torture_warning(tctx, "new password did not work\n");
 		ret = false;
 	}
@@ -2904,7 +2941,8 @@ static bool test_SetPassword_level(struct dcerpc_pipe *p,
 				      machine_creds,
 				      acct_name,
 				      *password,
-				      expected_samlogon_result)) {
+				      expected_samlogon_result,
+				      false)) {
 		ret = false;
 	}
 
@@ -3337,6 +3375,428 @@ static bool test_SetPassword_pwdlastset(struct dcerpc_pipe *p,
 	return ret;
 }
 
+static bool test_QueryUserInfo_badpwdcount(struct dcerpc_pipe *p,
+					   struct torture_context *tctx,
+					   struct policy_handle *handle,
+					   uint32_t *badpwdcount)
+{
+	union samr_UserInfo *info;
+	struct samr_QueryUserInfo r;
+
+	r.in.user_handle = handle;
+	r.in.level = 3;
+	r.out.info = &info;
+
+	torture_comment(tctx, "Testing QueryUserInfo level %d", r.in.level);
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_samr_QueryUserInfo(p, tctx, &r),
+		"failed to query userinfo");
+
+	*badpwdcount = info->info3.bad_password_count;
+
+	torture_comment(tctx, " (bad password count: %d)\n", *badpwdcount);
+
+	return true;
+}
+
+static bool test_reset_badpwdcount(struct dcerpc_pipe *p,
+				   struct torture_context *tctx,
+				   struct policy_handle *user_handle,
+				   uint32_t acct_flags,
+				   char **password)
+{
+	struct samr_SetUserInfo r;
+	union samr_UserInfo user_info;
+
+	torture_assert(tctx, test_SetUserPass(p, tctx, user_handle, password),
+		"failed to set password");
+
+	torture_comment(tctx, "Testing SetUserInfo level 16 (enable account)\n");
+
+	user_info.info16.acct_flags = acct_flags;
+	user_info.info16.acct_flags &= ~ACB_DISABLED;
+
+	r.in.user_handle = user_handle;
+	r.in.level = 16;
+	r.in.info = &user_info;
+
+	torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo(p, tctx, &r),
+		"failed to enable user");
+
+	torture_assert(tctx, test_SetUserPass(p, tctx, user_handle, password),
+		"failed to set password");
+
+	return true;
+}
+
+static bool test_Password_badpwdcount(struct dcerpc_pipe *p,
+				      struct dcerpc_pipe *np,
+				      struct torture_context *tctx,
+				      uint32_t acct_flags,
+				      const char *acct_name,
+				      struct policy_handle *domain_handle,
+				      struct policy_handle *user_handle,
+				      char **password,
+				      struct cli_credentials *machine_credentials,
+				      const char *comment,
+				      bool disable,
+				      bool interactive,
+				      NTSTATUS expected_success_status,
+				      struct samr_DomInfo1 *info1,
+				      struct samr_DomInfo12 *info12)
+{
+	union samr_DomainInfo info;
+	char **passwords;
+	int i;
+	uint32_t badpwdcount, tmp;
+	uint32_t password_history_length = 12;
+	uint32_t lockout_threshold = 15;
+
+	torture_comment(tctx, "\nTesting bad pwd count with: %s\n", comment);
+
+	torture_assert(tctx, password_history_length < lockout_threshold,
+		"password history length needs to be smaller than account lockout threshold for this test");
+
+
+	/* set policies */
+
+	info.info1 = *info1;
+
+	info.info1.password_history_length = password_history_length;
+
+	{
+		struct samr_SetDomainInfo r;
+
+		r.in.domain_handle = domain_handle;
+		r.in.level = DomainPasswordInformation;
+		r.in.info = &info;
+
+		torture_assert_ntstatus_ok(tctx,
+			dcerpc_samr_SetDomainInfo(p, tctx, &r),
+			"failed to set domain info level 1");
+	}
+
+	info.info12 = *info12;
+
+	info.info12.lockout_threshold = lockout_threshold;
+
+	{
+		struct samr_SetDomainInfo r;
+
+		r.in.domain_handle = domain_handle;
+		r.in.level = DomainLockoutInformation;
+		r.in.info = &info;
+
+		torture_assert_ntstatus_ok(tctx,
+			dcerpc_samr_SetDomainInfo(p, tctx, &r),
+			"failed to set domain info level 12");
+	}
+
+	/* reset bad pwd count */
+
+	torture_assert(tctx,
+		test_reset_badpwdcount(p, tctx, user_handle, acct_flags, password), "");
+
+
+	/* enable or disable account */
+	{
+		struct samr_SetUserInfo r;
+		union samr_UserInfo user_info;
+
+		torture_comment(tctx, "Testing SetUserInfo level 16 (%s account)\n",
+			disable ? "disable" : "enable");
+
+		user_info.info16.acct_flags = acct_flags;
+		if (disable) {
+			user_info.info16.acct_flags |= ACB_DISABLED;
+		} else {
+			user_info.info16.acct_flags &= ~ACB_DISABLED;
+		}
+
+		r.in.user_handle = user_handle;
+		r.in.level = 16;
+		r.in.info = &user_info;
+
+		torture_assert_ntstatus_ok(tctx, dcerpc_samr_SetUserInfo(p, tctx, &r),
+			"failed to enable user");
+	}
+
+
+	/* setup password history */
+
+	passwords = talloc_array(tctx, char *, password_history_length);
+
+	for (i=0; i < password_history_length; i++) {
+
+		torture_assert(tctx, test_SetUserPass(p, tctx, user_handle, password),
+			"failed to set password");
+		passwords[i] = talloc_strdup(tctx, *password);
+
+		if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+					      acct_name, passwords[i],
+					      expected_success_status, interactive)) {
+			torture_fail(tctx, "failed to auth with latest password");
+		}
+
+		torture_assert(tctx,
+			test_QueryUserInfo_badpwdcount(p, tctx, user_handle, &badpwdcount), "");
+
+		torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0");
+	}
+
+
+	/* test with wrong password */
+
+	if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+				      acct_name, "random_crap",
+				      NT_STATUS_WRONG_PASSWORD, interactive)) {
+		torture_fail(tctx, "succeeded to authenticate with wrong password");
+	}
+
+	torture_assert(tctx,
+		test_QueryUserInfo_badpwdcount(p, tctx, user_handle, &badpwdcount), "");
+
+	torture_assert_int_equal(tctx, badpwdcount, 1, "expected badpwdcount to be 1");
+
+
+	/* test with latest good password */
+
+	if (!test_SamLogon_with_creds(tctx, np, machine_credentials, acct_name,
+				      passwords[password_history_length-1],
+				      expected_success_status, interactive)) {
+		torture_fail(tctx, "succeeded to authenticate with wrong password");
+	}
+
+	torture_assert(tctx,
+		test_QueryUserInfo_badpwdcount(p, tctx, user_handle, &badpwdcount), "");
+
+	if (disable) {
+		torture_assert_int_equal(tctx, badpwdcount, 1, "expected badpwdcount to be 1");
+	} else {
+		/* only enabled accounts get the bad pwd count reset upon
+		 * successful logon */
+		torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0");
+	}
+
+	tmp = badpwdcount;
+
+
+	/* test password history */
+
+	for (i=0; i < password_history_length; i++) {
+
+		torture_comment(tctx, "Testing bad password count behavior with "
+				      "password #%d of #%d\n", i, password_history_length);
+
+		/* - network samlogon will succeed auth and not
+		 *   increase badpwdcount for 2 last entries
+		 * - interactive samlogon only for the last one */
+
+		if (i == password_history_length - 1 ||
+		    (i == password_history_length - 2 && !interactive)) {
+
+			if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+						      acct_name, passwords[i],
+						      expected_success_status, interactive)) {
+				torture_fail(tctx, talloc_asprintf(tctx, "succeeded to authenticate with old password (#%d of #%d in history)", i, password_history_length));
+			}
+
+			torture_assert(tctx,
+				test_QueryUserInfo_badpwdcount(p, tctx, user_handle, &badpwdcount), "");
+
+			if (disable) {
+				/* torture_comment(tctx, "expecting bad pwd count to *NOT INCREASE* for pwd history entry %d\n", i); */
+				torture_assert_int_equal(tctx, badpwdcount, tmp, "unexpected badpwdcount");
+			} else {
+				/* torture_comment(tctx, "expecting bad pwd count to be 0 for pwd history entry %d\n", i); */
+				torture_assert_int_equal(tctx, badpwdcount, 0, "expected badpwdcount to be 0");
+			}
+
+			tmp = badpwdcount;
+
+			continue;
+		}
+
+		if (!test_SamLogon_with_creds(tctx, np, machine_credentials,
+					      acct_name, passwords[i],
+					      NT_STATUS_WRONG_PASSWORD, interactive)) {
+			torture_fail(tctx, talloc_asprintf(tctx, "succeeded to authenticate with old password (#%d of #%d in history)", i, password_history_length));
+		}
+
+		torture_assert(tctx,
+			test_QueryUserInfo_badpwdcount(p, tctx, user_handle, &badpwdcount), "");
+
+		/* - network samlogon will fail auth but not increase
+		 *   badpwdcount for 3rd last entry
+		 * - interactive samlogon for 3rd and 2nd last entry */
+
+		if (i == password_history_length - 3 ||
+		    (i == password_history_length - 2 && interactive)) {
+			/* torture_comment(tctx, "expecting bad pwd count to *NOT INCREASE * by one for pwd history entry %d\n", i); */
+			torture_assert_int_equal(tctx, badpwdcount, tmp, "unexpected badpwdcount");
+		} else {
+			/* torture_comment(tctx, "expecting bad pwd count to increase by one for pwd history entry %d\n", i); */
+			torture_assert_int_equal(tctx, badpwdcount, tmp + 1, "unexpected badpwdcount");
+		}
+
+		tmp = badpwdcount;
+	}
+
+	return true;
+}
+
+static bool test_Password_badpwdcount_wrap(struct dcerpc_pipe *p,
+					   struct torture_context *tctx,
+					   uint32_t acct_flags,
+					   const char *acct_name,
+					   struct policy_handle *domain_handle,
+					   struct policy_handle *user_handle,
+					   char **password,
+					   struct cli_credentials *machine_credentials)
+{
+	union samr_DomainInfo *q_info, s_info;
+	struct samr_DomInfo1 info1, _info1;
+	struct samr_DomInfo12 info12, _info12;
+	bool ret = true;
+	struct dcerpc_binding *b;
+	struct dcerpc_pipe *np;
+	int i;
+
+	struct {


-- 
Samba Shared Repository


More information about the samba-cvs mailing list