From 3e1dd63927b6d50aa21f32ffaa41b320026be6a1 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 6 Mar 2007 05:30:25 +0000 Subject: r21719: Try to cover more of the server-side password processing. Don't just exit the test with 'return True', actually process the result. Turn off password complexity checking for the password length test. Andrew Bartlett (This used to be commit 1a7635baa701c6268eebd84dd0dc187379c44e6e) --- source4/torture/rpc/samr.c | 165 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 149 insertions(+), 16 deletions(-) diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c index e76599b3e4..0367cc4dc8 100644 --- a/source4/torture/rpc/samr.c +++ b/source4/torture/rpc/samr.c @@ -1034,6 +1034,7 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, char *oldpass; uint8_t old_nt_hash[16], new_nt_hash[16]; uint8_t old_lm_hash[16], new_lm_hash[16]; + BOOL changed = True; char *newpass; struct samr_GetUserPwInfo pwp; @@ -1072,6 +1073,43 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash); E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash); + r.in.user_handle = &user_handle; + r.in.lm_present = 1; + r.in.old_lm_crypted = &hash1; + r.in.new_lm_crypted = &hash2; + r.in.nt_present = 1; + r.in.old_nt_crypted = &hash3; + r.in.new_nt_crypted = &hash4; + r.in.cross1_present = 1; + r.in.nt_cross = &hash5; + r.in.cross2_present = 0; + r.in.lm_cross = NULL; + + status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &r); + if (!NT_STATUS_EQUAL(status, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED)) { + printf("ChangePasswordUser failed: expected NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED, got %s\n", nt_errstr(status)); + ret = False; + } + + + r.in.user_handle = &user_handle; + r.in.lm_present = 1; + r.in.old_lm_crypted = &hash1; + r.in.new_lm_crypted = &hash2; + r.in.nt_present = 1; + r.in.old_nt_crypted = &hash3; + r.in.new_nt_crypted = &hash4; + r.in.cross1_present = 0; + r.in.nt_cross = NULL; + r.in.cross2_present = 1; + r.in.lm_cross = &hash6; + + status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &r); + if (!NT_STATUS_EQUAL(status, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED)) { + printf("ChangePasswordUser failed: expected NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED, got %s\n", nt_errstr(status)); + ret = False; + } + r.in.user_handle = &user_handle; r.in.lm_present = 1; r.in.old_lm_crypted = &hash1; @@ -1091,9 +1129,30 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, printf("ChangePasswordUser failed - %s\n", nt_errstr(status)); ret = False; } else { + changed = True; *password = newpass; } + r.in.user_handle = &user_handle; + r.in.lm_present = 1; + r.in.old_lm_crypted = &hash1; + r.in.new_lm_crypted = &hash2; + r.in.nt_present = 1; + r.in.old_nt_crypted = &hash3; + r.in.new_nt_crypted = &hash4; + r.in.cross1_present = 1; + r.in.nt_cross = &hash5; + r.in.cross2_present = 1; + r.in.lm_cross = &hash6; + + if (changed) { + status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &r); + if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { + printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we already changed the password, got %s\n", nt_errstr(status)); + ret = False; + } + } + if (!test_samr_handle_Close(p, mem_ctx, &user_handle)) { ret = False; } @@ -1167,6 +1226,45 @@ static BOOL test_OemChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_c ret = False; } + encode_pw_buffer(lm_pass.data, newpass, STR_ASCII); + /* Break the old password */ + old_lm_hash[0]++; + arcfour_crypt(lm_pass.data, old_lm_hash, 516); + /* unbreak it for the next operation */ + old_lm_hash[0]--; + E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash); + + r.in.server = &server; + r.in.account = &account; + r.in.password = &lm_pass; + r.in.hash = &lm_verifier; + + status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &r); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) + && !NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { + printf("ChangePasswordUser3 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalidly encrpted password - %s\n", + nt_errstr(status)); + ret = False; + } + + encode_pw_buffer(lm_pass.data, newpass, STR_ASCII); + arcfour_crypt(lm_pass.data, old_lm_hash, 516); + + r.in.server = &server; + r.in.account = &account; + r.in.password = &lm_pass; + r.in.hash = NULL; + + status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &r); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) + && !NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { + printf("ChangePasswordUser3 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for no supplied validation hash - %s\n", + nt_errstr(status)); + ret = False; + } + /* This shouldn't be a valid name */ account_bad.string = TEST_ACCOUNT_NAME "XX"; r.in.account = &account_bad; @@ -1305,11 +1403,13 @@ BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, printf("Testing ChangePasswordUser3\n"); if (newpass == NULL) { - if (policy_min_pw_len == 0) { - newpass = samr_rand_pass(mem_ctx, policy_min_pw_len); - } else { - newpass = samr_rand_pass_fixed_len(mem_ctx, policy_min_pw_len); - } + do { + if (policy_min_pw_len == 0) { + newpass = samr_rand_pass(mem_ctx, policy_min_pw_len); + } else { + newpass = samr_rand_pass_fixed_len(mem_ctx, policy_min_pw_len); + } + } while (check_password_quality(newpass) == False); } else { printf("Using password '%s'\n", newpass); } @@ -1357,6 +1457,35 @@ BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, ret = False; } + encode_pw_buffer(lm_pass.data, newpass, STR_UNICODE); + arcfour_crypt(lm_pass.data, old_nt_hash, 516); + E_old_pw_hash(new_nt_hash, old_lm_hash, lm_verifier.hash); + + encode_pw_buffer(nt_pass.data, newpass, STR_UNICODE); + /* Break the NT hash */ + old_nt_hash[0]++; + arcfour_crypt(nt_pass.data, old_nt_hash, 516); + /* Unbreak it again */ + old_nt_hash[0]--; + E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash); + + r.in.server = &server; + r.in.account = &account; + r.in.nt_password = &nt_pass; + r.in.nt_verifier = &nt_verifier; + r.in.lm_change = 1; + r.in.lm_password = &lm_pass; + r.in.lm_verifier = &lm_verifier; + r.in.password3 = NULL; + + status = dcerpc_samr_ChangePasswordUser3(p, mem_ctx, &r); + if (!NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) && + (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD))) { + printf("ChangePasswordUser3 failed, should have returned WRONG_PASSWORD (or at least 'PASSWORD_RESTRICTON') for invalidly encrpted password - %s\n", + nt_errstr(status)); + ret = False; + } + /* This shouldn't be a valid name */ init_lsa_String(&account_bad, talloc_asprintf(mem_ctx, "%sXX", account_string)); @@ -1434,14 +1563,6 @@ BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, return False; } - } else if (r.out.dominfo->password_properties & DOMAIN_PASSWORD_COMPLEX) { - - if (r.out.reject->reason != SAMR_REJECT_COMPLEXITY) { - printf("expected SAMR_REJECT_COMPLEXITY (%d), got %d\n", - SAMR_REJECT_COMPLEXITY, r.out.reject->reason); - return False; - } - } else if ((r.out.dominfo->password_history_length > 0) && strequal(oldpass, newpass)) { @@ -1450,6 +1571,14 @@ BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, SAMR_REJECT_IN_HISTORY, r.out.reject->reason); return False; } + } else if (r.out.dominfo->password_properties & DOMAIN_PASSWORD_COMPLEX) { + + if (r.out.reject->reason != SAMR_REJECT_COMPLEXITY) { + printf("expected SAMR_REJECT_COMPLEXITY (%d), got %d\n", + SAMR_REJECT_COMPLEXITY, r.out.reject->reason); + return False; + } + } if (r.out.reject->reason == SAMR_REJECT_TOO_SHORT) { @@ -1970,9 +2099,10 @@ static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct samr_QueryDomainInfo r; struct samr_SetDomainInfo s; uint16_t len_old, len; + uint32_t pwd_prop_old; NTSTATUS status; - len = 3; + len = 5; r.in.domain_handle = domain_handle; r.in.level = 1; @@ -1987,8 +2117,12 @@ static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, s.in.level = 1; s.in.info = r.out.info; + /* remember the old min length, so we can reset it */ len_old = s.in.info->info1.min_password_length; s.in.info->info1.min_password_length = len; + pwd_prop_old = s.in.info->info1.password_properties; + /* turn off password complexity checks for this test */ + s.in.info->info1.password_properties &= ~DOMAIN_PASSWORD_COMPLEX; printf("testing samr_SetDomainInfo level 1\n"); status = dcerpc_samr_SetDomainInfo(p, mem_ctx, &s); @@ -2003,6 +2137,7 @@ static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } s.in.info->info1.min_password_length = len_old; + s.in.info->info1.password_properties = pwd_prop_old; printf("testing samr_SetDomainInfo level 1\n"); status = dcerpc_samr_SetDomainInfo(p, mem_ctx, &s); @@ -2058,8 +2193,6 @@ static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } } - return True; - /* we change passwords twice - this has the effect of verifying they were changed correctly for the final call */ if (!test_ChangePasswordUser3(p, mem_ctx, acct_name, 0, password, NULL, 0, True)) { -- cgit