diff options
author | Andrew Bartlett <abartlet@samba.org> | 2007-08-22 04:28:15 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 15:02:23 -0500 |
commit | d7f84b51f96c2e1b48a38de823329f2e4ea86e55 (patch) | |
tree | 7c542a304bf3da5d2eaad177b8ac400ee6d5da44 /source4 | |
parent | bd93ed4680b3a86348b0d84a93d20f3daafbe8ad (diff) | |
download | samba-d7f84b51f96c2e1b48a38de823329f2e4ea86e55.tar.gz samba-d7f84b51f96c2e1b48a38de823329f2e4ea86e55.tar.bz2 samba-d7f84b51f96c2e1b48a38de823329f2e4ea86e55.zip |
r24611: Following up on the re-opening of bug 4817 is it pretty clear that
machine accounts are not subject to password policy in Win2k3 R2 (at
least in terms of password quality).
In testing this, I found that Win2k3 R2 has changed the way the old
ChangePassword RPC call is handled - the 'cross-checks' between new LM
and NT passwords are not required.
Andrew Bartlett
(This used to be commit 417ea885b41cc097a0bb3a10ffbffb31f234f25d)
Diffstat (limited to 'source4')
-rw-r--r-- | source4/dsdb/samdb/samdb.c | 16 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 4 | ||||
-rw-r--r-- | source4/rpc_server/netlogon/dcerpc_netlogon.c | 2 | ||||
-rw-r--r-- | source4/rpc_server/samr/samr_password.c | 45 | ||||
-rw-r--r-- | source4/torture/rpc/samr.c | 237 |
5 files changed, 213 insertions, 91 deletions
diff --git a/source4/dsdb/samdb/samdb.c b/source4/dsdb/samdb/samdb.c index 148be88532..7a20ea8665 100644 --- a/source4/dsdb/samdb/samdb.c +++ b/source4/dsdb/samdb/samdb.c @@ -1515,7 +1515,6 @@ _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ct struct samr_Password *lmNewHash, struct samr_Password *ntNewHash, BOOL user_change, - BOOL restrictions, enum samr_RejectReason *reject_reason, struct samr_DomInfo1 **_dominfo) { @@ -1536,6 +1535,7 @@ _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ct int sambaLMPwdHistory_len, sambaNTPwdHistory_len; struct dom_sid *domain_sid; struct ldb_message **res; + BOOL restrictions; int count; time_t now = time(NULL); NTTIME now_nt; @@ -1558,6 +1558,13 @@ _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ct ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd"); pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0); + /* Only non-trust accounts have restrictions (possibly this + * test is the wrong way around, but I like to be restrictive + * if possible */ + restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT + |UF_WORKSTATION_TRUST_ACCOUNT + |UF_SERVER_TRUST_ACCOUNT)); + if (domain_dn) { /* pull the domain parameters */ count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs); @@ -1605,7 +1612,8 @@ _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ct *_dominfo = dominfo; } - if (new_pass) { + if (restrictions && new_pass) { + /* check the various password restrictions */ if (restrictions && minPwdLength > strlen_m(new_pass)) { if (reject_reason) { @@ -1637,7 +1645,7 @@ _PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ct ntNewHash = &local_ntNewHash; } - if (restrictions && user_change) { + if (user_change) { /* are all password changes disallowed? */ if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) { if (reject_reason) { @@ -1745,7 +1753,6 @@ _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *me struct samr_Password *lmNewHash, struct samr_Password *ntNewHash, BOOL user_change, - BOOL restrictions, enum samr_RejectReason *reject_reason, struct samr_DomInfo1 **_dominfo) { @@ -1787,7 +1794,6 @@ _PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *me msg, new_pass, lmNewHash, ntNewHash, user_change, /* This is a password set, not change */ - restrictions, /* run restriction tests */ reject_reason, _dominfo); if (!NT_STATUS_IS_OK(nt_status)) { ldb_transaction_cancel(ctx); diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 35b37b3af6..7d257fac06 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -528,10 +528,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call) uint32_t context_id; const struct dcesrv_interface *iface; - if (call->pkt.u.bind.assoc_group_id != 0) { - return dcesrv_bind_nak(call, 0); - } - if (call->pkt.u.bind.num_contexts < 1 || call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) { return dcesrv_bind_nak(call, 0); diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index 5a2fd7a07f..2198dc5ebc 100644 --- a/source4/rpc_server/netlogon/dcerpc_netlogon.c +++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c @@ -312,7 +312,6 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet(struct dcesrv_call_state *dce_call NULL, /* Don't have plaintext */ NULL, &r->in.new_password, False, /* This is not considered a password change */ - False, /* don't restrict this password change (match w2k3) */ NULL, NULL); return nt_status; } @@ -360,7 +359,6 @@ static NTSTATUS dcesrv_netr_ServerPasswordSet2(struct dcesrv_call_state *dce_cal new_pass, /* we have plaintext */ NULL, NULL, False, /* This is not considered a password change */ - False, /* don't restrict this password change (match w2k3) */ NULL, NULL); return nt_status; } diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c index fac0015f0e..e3cb70ad17 100644 --- a/source4/rpc_server/samr/samr_password.c +++ b/source4/rpc_server/samr/samr_password.c @@ -62,12 +62,6 @@ NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALL present */ return NT_STATUS_INVALID_PARAMETER_MIX; } - if (!r->in.cross1_present || !r->in.nt_cross) { - return NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED; - } - if (!r->in.cross2_present || !r->in.lm_cross) { - return NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED; - } /* To change a password we need to open as system */ sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx)); @@ -112,18 +106,24 @@ NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALL return NT_STATUS_WRONG_PASSWORD; } - /* check the nt cross hash */ - D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash); - if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) { - ldb_transaction_cancel(sam_ctx); - return NT_STATUS_WRONG_PASSWORD; + /* The NT Cross is not required by Win2k3 R2, but if present + check the nt cross hash */ + if (r->in.cross1_present && r->in.nt_cross) { + D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash); + if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) { + ldb_transaction_cancel(sam_ctx); + return NT_STATUS_WRONG_PASSWORD; + } } - /* check the lm cross hash */ - D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash); - if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) { - ldb_transaction_cancel(sam_ctx); - return NT_STATUS_WRONG_PASSWORD; + /* The LM Cross is not required by Win2k3 R2, but if present + check the lm cross hash */ + if (r->in.cross2_present && r->in.lm_cross) { + D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash); + if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) { + ldb_transaction_cancel(sam_ctx); + return NT_STATUS_WRONG_PASSWORD; + } } msg = ldb_msg_new(mem_ctx); @@ -144,7 +144,6 @@ NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALL a_state->account_dn, a_state->domain_state->domain_dn, msg, NULL, &new_lmPwdHash, &new_ntPwdHash, True, /* this is a user password change */ - True, /* run restriction tests */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { @@ -196,7 +195,11 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, struct samr_Password lm_verifier; if (pwbuf == NULL) { - return NT_STATUS_WRONG_PASSWORD; + return NT_STATUS_INVALID_PARAMETER; + } + + if (r->in.hash == NULL) { + return NT_STATUS_INVALID_PARAMETER; } /* To change a password we need to open as system */ @@ -245,7 +248,7 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, } /* check LM verifier */ - if (lm_pwd == NULL || r->in.hash == NULL) { + if (lm_pwd == NULL) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } @@ -276,7 +279,6 @@ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, mod, new_pass, NULL, NULL, True, /* this is a user password change */ - True, /* run restriction tests */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { @@ -430,7 +432,6 @@ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, mod, new_pass, NULL, NULL, True, /* this is a user password change */ - True, /* run restriction tests */ &reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { @@ -539,7 +540,6 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call, msg, new_pass, NULL, NULL, False, /* This is a password set, not change */ - True, /* run restriction tests */ NULL, NULL); } @@ -593,7 +593,6 @@ NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call, msg, new_pass, NULL, NULL, False, /* This is a password set, not change */ - True, /* run restriction tests */ NULL, NULL); } diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c index 8e765fe027..a07a39e078 100644 --- a/source4/torture/rpc/samr.c +++ b/source4/torture/rpc/samr.c @@ -616,7 +616,8 @@ static BOOL test_SetUserPass_23(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, static BOOL test_SetUserPassEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *handle, char **password) + struct policy_handle *handle, bool makeshort, + char **password) { NTSTATUS status; struct samr_SetUserInfo s; @@ -635,7 +636,11 @@ static BOOL test_SetUserPassEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, if (NT_STATUS_IS_OK(status)) { policy_min_pw_len = pwp.out.info.min_password_length; } - newpass = samr_rand_pass(mem_ctx, policy_min_pw_len); + if (makeshort && policy_min_pw_len) { + newpass = samr_rand_pass_fixed_len(mem_ctx, policy_min_pw_len - 1); + } else { + newpass = samr_rand_pass(mem_ctx, policy_min_pw_len); + } s.in.user_handle = handle; s.in.info = &u; @@ -682,7 +687,7 @@ static BOOL test_SetUserPassEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, status = dcerpc_samr_SetUserInfo(p, mem_ctx, &s); if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { - printf("SetUserInfo level %u should have failed with WRONG_PASSWORD- %s\n", + printf("SetUserInfo level %u should have failed with WRONG_PASSWORD: %s\n", s.in.level, nt_errstr(status)); ret = False; } else { @@ -1110,6 +1115,8 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.user_handle = &user_handle; r.in.lm_present = 1; + /* Break the LM hash */ + hash1.hash[0]++; r.in.old_lm_crypted = &hash1; r.in.new_lm_crypted = &hash2; r.in.nt_present = 1; @@ -1117,38 +1124,43 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, 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; + 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_LM_CROSS_ENCRYPTION_REQUIRED)) { - printf("ChangePasswordUser failed: expected NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED, got %s\n", nt_errstr(status)); + if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { + printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the LM hash, got %s\n", nt_errstr(status)); ret = False; } - + /* Unbreak the LM hash */ + hash1.hash[0]--; + r.in.user_handle = &user_handle; r.in.lm_present = 1; r.in.old_lm_crypted = &hash1; r.in.new_lm_crypted = &hash2; + /* Break the NT hash */ + hash3.hash[0]--; 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.cross1_present = 1; + r.in.nt_cross = &hash5; 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)); + if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { + printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the NT hash, got %s\n", nt_errstr(status)); ret = False; } + /* Unbreak the NT hash */ + hash3.hash[0]--; + r.in.user_handle = &user_handle; r.in.lm_present = 1; - /* Break the LM hash */ - hash1.hash[0]++; r.in.old_lm_crypted = &hash1; r.in.new_lm_crypted = &hash2; r.in.nt_present = 1; @@ -1157,39 +1169,50 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.cross1_present = 1; r.in.nt_cross = &hash5; r.in.cross2_present = 1; + /* Break the LM cross */ + hash6.hash[0]++; r.in.lm_cross = &hash6; 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 broke the LM hash, got %s\n", nt_errstr(status)); + printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the LM cross-hash, got %s\n", nt_errstr(status)); ret = False; } - /* Unbreak the LM hash */ - hash1.hash[0]--; + /* Unbreak the LM cross */ + hash6.hash[0]--; r.in.user_handle = &user_handle; r.in.lm_present = 1; r.in.old_lm_crypted = &hash1; r.in.new_lm_crypted = &hash2; - /* Break the NT hash */ - hash3.hash[0]--; r.in.nt_present = 1; r.in.old_nt_crypted = &hash3; r.in.new_nt_crypted = &hash4; r.in.cross1_present = 1; + /* Break the NT cross */ + hash5.hash[0]++; r.in.nt_cross = &hash5; 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_WRONG_PASSWORD)) { - printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the NT hash, got %s\n", nt_errstr(status)); + printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the NT cross-hash, got %s\n", nt_errstr(status)); ret = False; } - /* Unbreak the NT hash */ - hash3.hash[0]--; + /* Unbreak the NT cross */ + hash5.hash[0]--; + + + /* Reset the hashes to not broken values */ + E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash); + E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash); + E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash); + E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash); + 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; @@ -1200,19 +1223,34 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.new_nt_crypted = &hash4; r.in.cross1_present = 1; r.in.nt_cross = &hash5; - r.in.cross2_present = 1; - /* Break the LM cross */ - hash6.hash[0]++; - r.in.lm_cross = &hash6; + 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_WRONG_PASSWORD)) { - printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the LM cross-hash, got %s\n", nt_errstr(status)); + if (NT_STATUS_IS_OK(status)) { + changed = True; + *password = newpass; + } else if (!NT_STATUS_EQUAL(NT_STATUS_PASSWORD_RESTRICTION, status)) { + printf("ChangePasswordUser failed: expected NT_STATUS_OK, or at least NT_STATUS_PASSWORD_RESTRICTION, got %s\n", nt_errstr(status)); ret = False; } - /* Unbreak the LM cross */ - hash6.hash[0]--; + oldpass = newpass; + newpass = samr_rand_pass(mem_ctx, policy_min_pw_len); + + E_md4hash(oldpass, old_nt_hash); + E_md4hash(newpass, new_nt_hash); + E_deshash(oldpass, old_lm_hash); + E_deshash(newpass, new_lm_hash); + + + /* Reset the hashes to not broken values */ + E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash); + E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash); + E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash); + E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash); + 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; @@ -1221,21 +1259,28 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.nt_present = 1; r.in.old_nt_crypted = &hash3; r.in.new_nt_crypted = &hash4; - r.in.cross1_present = 1; - /* Break the NT cross */ - hash5.hash[0]++; - r.in.nt_cross = &hash5; + 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_WRONG_PASSWORD)) { - printf("ChangePasswordUser failed: expected NT_STATUS_WRONG_PASSWORD because we broke the NT cross-hash, got %s\n", nt_errstr(status)); + if (NT_STATUS_IS_OK(status)) { + changed = True; + *password = newpass; + } else if (!NT_STATUS_EQUAL(NT_STATUS_PASSWORD_RESTRICTION, status)) { + printf("ChangePasswordUser failed: expected NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED, got %s\n", nt_errstr(status)); ret = False; } - /* Unbreak the NT cross */ - hash5.hash[0]--; + oldpass = newpass; + newpass = samr_rand_pass(mem_ctx, policy_min_pw_len); + + E_md4hash(oldpass, old_nt_hash); + E_md4hash(newpass, new_nt_hash); + E_deshash(oldpass, old_lm_hash); + E_deshash(newpass, new_lm_hash); + /* Reset the hashes to not broken values */ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash); @@ -1282,12 +1327,15 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, if (changed) { status = dcerpc_samr_ChangePasswordUser(p, mem_ctx, &r); - if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { + if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { + printf("ChangePasswordUser returned: %s perhaps min password age? (not fatal)\n", nt_errstr(status)); + } else 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; } @@ -1394,8 +1442,20 @@ static BOOL test_OemChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_c 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_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { + printf("ChangePasswordUser3 failed, should have returned INVALID_PARAMETER (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; + + status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &r); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { + printf("ChangePasswordUser3 failed, should have returned INVALID_PARAMETER for no supplied validation hash and invalid user - %s\n", nt_errstr(status)); ret = False; } @@ -1403,6 +1463,8 @@ static BOOL test_OemChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_c /* This shouldn't be a valid name */ account_bad.string = TEST_ACCOUNT_NAME "XX"; r.in.account = &account_bad; + r.in.password = &lm_pass; + r.in.hash = &lm_verifier; status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &r); @@ -1412,6 +1474,20 @@ static BOOL test_OemChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_c ret = False; } + /* This shouldn't be a valid name */ + account_bad.string = TEST_ACCOUNT_NAME "XX"; + r.in.account = &account_bad; + r.in.password = NULL; + r.in.hash = &lm_verifier; + + status = dcerpc_samr_OemChangePasswordUser2(p, mem_ctx, &r); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) { + printf("ChangePasswordUser3 failed, should have returned INVALID_PARAMETER for no supplied password and invalid user - %s\n", + nt_errstr(status)); + ret = False; + } + E_deshash(oldpass, old_lm_hash); E_deshash(newpass, new_lm_hash); @@ -1440,7 +1516,8 @@ static BOOL test_OemChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_c static BOOL test_ChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, const char *acct_name, - struct policy_handle *handle, char **password) + char **password, + char *newpass, bool allow_password_restriction) { NTSTATUS status; struct samr_ChangePasswordUser2 r; @@ -1449,20 +1526,17 @@ static BOOL test_ChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct samr_CryptPassword nt_pass, lm_pass; struct samr_Password nt_verifier, lm_verifier; char *oldpass; - char *newpass; uint8_t old_nt_hash[16], new_nt_hash[16]; uint8_t old_lm_hash[16], new_lm_hash[16]; struct samr_GetDomPwInfo dom_pw_info; - int policy_min_pw_len = 0; struct lsa_String domain_name; - domain_name.string = ""; dom_pw_info.in.domain_name = &domain_name; - printf("Testing ChangePasswordUser2\n"); + printf("Testing ChangePasswordUser2 on %s\n", acct_name); if (!*password) { printf("Failing ChangePasswordUser3 as old password was NULL. Previous test failed?\n"); @@ -1470,12 +1544,15 @@ static BOOL test_ChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } oldpass = *password; - status = dcerpc_samr_GetDomPwInfo(p, mem_ctx, &dom_pw_info); - if (NT_STATUS_IS_OK(status)) { - policy_min_pw_len = dom_pw_info.out.info.min_password_length; - } + if (!newpass) { + int policy_min_pw_len = 0; + status = dcerpc_samr_GetDomPwInfo(p, mem_ctx, &dom_pw_info); + if (NT_STATUS_IS_OK(status)) { + policy_min_pw_len = dom_pw_info.out.info.min_password_length; + } - newpass = samr_rand_pass(mem_ctx, policy_min_pw_len); + newpass = samr_rand_pass(mem_ctx, policy_min_pw_len); + } server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); init_lsa_String(&account, acct_name); @@ -1503,7 +1580,7 @@ static BOOL test_ChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, r.in.lm_verifier = &lm_verifier; status = dcerpc_samr_ChangePasswordUser2(p, mem_ctx, &r); - if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { + if (allow_password_restriction && NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { printf("ChangePasswordUser2 returned: %s perhaps min password age? (not fatal)\n", nt_errstr(status)); } else if (!NT_STATUS_IS_OK(status)) { printf("ChangePasswordUser2 failed - %s\n", nt_errstr(status)); @@ -1659,9 +1736,11 @@ BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, status = dcerpc_samr_ChangePasswordUser3(p, mem_ctx, &r); - if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) && - r.out.dominfo && r.out.reject && handle_reject_reason) { - + if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION) + && r.out.dominfo + && r.out.reject + && handle_reject_reason + && (!null_nttime(last_password_change) || !r.out.dominfo->min_password_age)) { if (r.out.dominfo->password_properties & DOMAIN_REFUSE_PASSWORD_CHANGE ) { if (r.out.reject && (r.out.reject->reason != SAMR_REJECT_OTHER)) { @@ -1724,6 +1803,14 @@ BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } + } else if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) { + if (r.out.reject && r.out.reject->reason != SAMR_REJECT_OTHER) { + printf("expected SAMR_REJECT_OTHER (%d), got %d\n", + SAMR_REJECT_OTHER, r.out.reject->reason); + return False; + } + /* Perhaps the server has a 'min password age' set? */ + } else if (!NT_STATUS_IS_OK(status)) { printf("ChangePasswordUser3 failed - %s\n", nt_errstr(status)); ret = False; @@ -1920,6 +2007,36 @@ static BOOL test_user_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } break; case TORTURE_SAMR_PASSWORDS: + if (base_acct_flags & (ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST)) { + char simple_pass[9]; + char *v = generate_random_str(mem_ctx, 1); + + ZERO_STRUCT(simple_pass); + memset(simple_pass, *v, sizeof(simple_pass) - 1); + + printf("Testing machine account password policy rules\n"); + + /* Workstation trust accounts don't seem to need to honour password quality policy */ + if (!test_SetUserPassEx(p, user_ctx, user_handle, true, &password)) { + ret = False; + } + + if (!test_ChangePasswordUser2(p, user_ctx, base_acct_name, &password, simple_pass, False)) { + ret = False; + } + + /* reset again, to allow another 'user' password change */ + if (!test_SetUserPassEx(p, user_ctx, user_handle, true, &password)) { + ret = False; + } + + /* Try a 'short' password */ + if (!test_ChangePasswordUser2(p, user_ctx, base_acct_name, &password, samr_rand_pass(mem_ctx, 4), False)) { + ret = False; + } + + } + for (i = 0; password_fields[i]; i++) { if (!test_SetUserPass_23(p, user_ctx, user_handle, password_fields[i], &password)) { ret = False; @@ -1942,13 +2059,14 @@ static BOOL test_user_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, } } - if (!test_SetUserPassEx(p, user_ctx, user_handle, &password)) { + if (!test_SetUserPassEx(p, user_ctx, user_handle, false, &password)) { ret = False; } if (!test_ChangePassword(p, user_ctx, base_acct_name, domain_handle, &password)) { ret = False; } + break; case TORTURE_SAMR_OTHER: /* We just need the account to exist */ @@ -2203,7 +2321,7 @@ static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, ret = False; } - if (!test_ChangePasswordUser2(p, mem_ctx, acct_name, domain_handle, password)) { + if (!test_ChangePasswordUser2(p, mem_ctx, acct_name, password, 0, True)) { ret = False; } @@ -2235,6 +2353,7 @@ static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct samr_SetDomainInfo s; uint16_t len_old, len; uint32_t pwd_prop_old; + int64_t min_pwd_age_old; NTSTATUS status; len = 5; @@ -2259,6 +2378,9 @@ static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, /* turn off password complexity checks for this test */ s.in.info->info1.password_properties &= ~DOMAIN_PASSWORD_COMPLEX; + min_pwd_age_old = s.in.info->info1.min_password_age; + s.in.info->info1.min_password_age = 0; + printf("testing samr_SetDomainInfo level 1\n"); status = dcerpc_samr_SetDomainInfo(p, mem_ctx, &s); if (!NT_STATUS_IS_OK(status)) { @@ -2273,6 +2395,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; + s.in.info->info1.min_password_age = min_pwd_age_old; printf("testing samr_SetDomainInfo level 1\n"); status = dcerpc_samr_SetDomainInfo(p, mem_ctx, &s); |