summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2007-08-22 04:28:15 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 15:02:23 -0500
commitd7f84b51f96c2e1b48a38de823329f2e4ea86e55 (patch)
tree7c542a304bf3da5d2eaad177b8ac400ee6d5da44
parentbd93ed4680b3a86348b0d84a93d20f3daafbe8ad (diff)
downloadsamba-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)
-rw-r--r--source4/dsdb/samdb/samdb.c16
-rw-r--r--source4/rpc_server/dcerpc_server.c4
-rw-r--r--source4/rpc_server/netlogon/dcerpc_netlogon.c2
-rw-r--r--source4/rpc_server/samr/samr_password.c45
-rw-r--r--source4/torture/rpc/samr.c237
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);