1
0
mirror of https://github.com/samba-team/samba.git synced 2025-05-27 17:05:51 +03:00

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)
This commit is contained in:
Andrew Bartlett 2007-08-22 04:28:15 +00:00 committed by Gerald (Jerry) Carter
parent bd93ed4680
commit d7f84b51f9
5 changed files with 215 additions and 93 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 {
@ -1108,43 +1113,6 @@ 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;
/* Break the LM hash */
@ -1237,6 +1205,83 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
/* 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;
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_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;
}
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;
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_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;
}
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);
@ -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,8 @@ 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;
}
@ -1406,12 +1454,40 @@ 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_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;
}
/* 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);
if (!NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
printf("ChangePasswordUser3 failed, should have returned WRONG_PASSWORD for invalid user - %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;
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);