summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/librpc/idl/samr.idl4
-rw-r--r--source4/torture/rpc/samr.c235
2 files changed, 195 insertions, 44 deletions
diff --git a/source4/librpc/idl/samr.idl b/source4/librpc/idl/samr.idl
index 42a549cc5c..f40f71df3e 100644
--- a/source4/librpc/idl/samr.idl
+++ b/source4/librpc/idl/samr.idl
@@ -678,10 +678,12 @@
const int SAMR_FIELD_PROFILE_PATH = 0x00000200;
const int SAMR_FIELD_WORKSTATION = 0x00000400;
const int SAMR_FIELD_LOGON_HOURS = 0x00002000;
+ const int SAMR_FIELD_ACCT_FLAGS = 0x00100000;
const int SAMR_FIELD_CALLBACK = 0x00200000;
const int SAMR_FIELD_COUNTRY_CODE = 0x00400000;
const int SAMR_FIELD_CODE_PAGE = 0x00800000;
- const int SAMR_FIELD_PASSWORD = 0x03000000; /* 2 bits!? */
+ const int SAMR_FIELD_PASSWORD = 0x01000000; /* either of these */
+ const int SAMR_FIELD_PASSWORD2 = 0x02000000; /* two bits seems to work */
typedef struct {
NTTIME last_logon;
diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c
index 7e7d2498da..9c63e654a3 100644
--- a/source4/torture/rpc/samr.c
+++ b/source4/torture/rpc/samr.c
@@ -159,7 +159,7 @@ static BOOL test_QuerySecurity(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
static BOOL test_SetUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
- struct policy_handle *handle)
+ struct policy_handle *handle, uint32_t base_acct_flags)
{
NTSTATUS status;
struct samr_SetUserInfo s;
@@ -169,6 +169,12 @@ static BOOL test_SetUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
union samr_UserInfo u;
BOOL ret = True;
+ uint32_t user_extra_flags = 0;
+ if (base_acct_flags == ACB_NORMAL) {
+ /* Don't know what this is, but it is always here for users - you can't get rid of it */
+ user_extra_flags = 0x20000;
+ }
+
s.in.user_handle = handle;
s.in.info = &u;
@@ -198,8 +204,8 @@ static BOOL test_SetUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
#define INT_EQUAL(i1, i2, field) \
if (i1 != i2) { \
- printf("Failed to set %s to %u (line %d)\n", \
- #field, i2, __LINE__); \
+ printf("Failed to set %s to 0x%x - got 0x%x (line %d)\n", \
+ #field, i2, i1, __LINE__); \
ret = False; \
break; \
}
@@ -228,7 +234,7 @@ static BOOL test_SetUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
STRING_EQUAL(u.info ## lvl2.field2.name, value, field2); \
} while (0)
-#define TEST_USERINFO_INT(lvl1, field1, lvl2, field2, value, fpval) do { \
+#define TEST_USERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, exp_value, fpval) do { \
printf("field test %d/%s vs %d/%s\n", lvl1, #field1, lvl2, #field2); \
q.in.level = lvl1; \
TESTCALL(QueryUserInfo, q) \
@@ -250,13 +256,17 @@ static BOOL test_SetUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
u.info ## lvl1.field1 = 0; \
TESTCALL(QueryUserInfo, q); \
u = *q.out.info; \
- INT_EQUAL(u.info ## lvl1.field1, value, field1); \
+ INT_EQUAL(u.info ## lvl1.field1, exp_value, field1); \
q.in.level = lvl2; \
TESTCALL(QueryUserInfo, q) \
u = *q.out.info; \
- INT_EQUAL(u.info ## lvl2.field2, value, field1); \
+ INT_EQUAL(u.info ## lvl2.field2, exp_value, field1); \
} while (0)
+#define TEST_USERINFO_INT(lvl1, field1, lvl2, field2, value, fpval) do { \
+ TEST_USERINFO_INT_EXP(lvl1, field1, lvl2, field2, value, value, fpval); \
+ } while (0)
+
q0.in.level = 12;
do { TESTCALL(QueryUserInfo, q0) } while (0);
@@ -317,6 +327,35 @@ static BOOL test_SetUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
TEST_USERINFO_INT(21, logon_hours.bitmap[3], 21, logon_hours.bitmap[3], 4,
SAMR_FIELD_LOGON_HOURS);
+ TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ),
+ (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ | user_extra_flags),
+ 0);
+ TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags,
+ (base_acct_flags | ACB_DISABLED),
+ (base_acct_flags | ACB_DISABLED | user_extra_flags),
+ 0);
+
+ /* Setting PWNOEXP clears the magic 0x20000 flag */
+ TEST_USERINFO_INT_EXP(16, acct_flags, 5, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_PWNOEXP),
+ (base_acct_flags | ACB_DISABLED | ACB_PWNOEXP),
+ 0);
+ TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ),
+ (base_acct_flags | ACB_DISABLED | ACB_HOMDIRREQ | user_extra_flags),
+ 0);
+
+ /* The 'autolock' flag doesn't stick - check this */
+ TEST_USERINFO_INT_EXP(16, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED | ACB_AUTOLOCK),
+ (base_acct_flags | ACB_DISABLED | user_extra_flags),
+ 0);
+ TEST_USERINFO_INT_EXP(21, acct_flags, 21, acct_flags,
+ (base_acct_flags | ACB_DISABLED),
+ (base_acct_flags | ACB_DISABLED | user_extra_flags),
+ SAMR_FIELD_ACCT_FLAGS);
+
#if 0
/* these fail with win2003 - it appears you can't set the primary gid?
the set succeeds, but the gid isn't changed. Very weird! */
@@ -331,9 +370,9 @@ static BOOL test_SetUserInfo(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
/*
generate a random password for password change tests
*/
-static char *samr_rand_pass(TALLOC_CTX *mem_ctx)
+static char *samr_rand_pass(TALLOC_CTX *mem_ctx, int min_len)
{
- size_t len = 8 + (random() % 6);
+ size_t len = MAX(8, min_len) + (random() % 6);
char *s = generate_random_str(mem_ctx, len);
printf("Generated password '%s'\n", s);
return s;
@@ -347,7 +386,16 @@ static BOOL test_SetUserPass(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
union samr_UserInfo u;
BOOL ret = True;
DATA_BLOB session_key;
- char *newpass = samr_rand_pass(mem_ctx);
+ char *newpass;
+ struct samr_GetUserPwInfo pwp;
+ int policy_min_pw_len = 0;
+ pwp.in.user_handle = handle;
+
+ status = dcerpc_samr_GetUserPwInfo(p, mem_ctx, &pwp);
+ if (NT_STATUS_IS_OK(status)) {
+ policy_min_pw_len = pwp.out.info.min_password_len;
+ }
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
s.in.user_handle = handle;
s.in.info = &u;
@@ -382,14 +430,24 @@ static BOOL test_SetUserPass(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
static BOOL test_SetUserPass_23(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
- struct policy_handle *handle, char **password)
+ struct policy_handle *handle, uint32 fields_present,
+ char **password)
{
NTSTATUS status;
struct samr_SetUserInfo s;
union samr_UserInfo u;
BOOL ret = True;
DATA_BLOB session_key;
- char *newpass = samr_rand_pass(mem_ctx);
+ char *newpass;
+ struct samr_GetUserPwInfo pwp;
+ int policy_min_pw_len = 0;
+ pwp.in.user_handle = handle;
+
+ status = dcerpc_samr_GetUserPwInfo(p, mem_ctx, &pwp);
+ if (NT_STATUS_IS_OK(status)) {
+ policy_min_pw_len = pwp.out.info.min_password_len;
+ }
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
s.in.user_handle = handle;
s.in.info = &u;
@@ -397,7 +455,7 @@ static BOOL test_SetUserPass_23(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
ZERO_STRUCT(u);
- u.info23.info.fields_present = SAMR_FIELD_PASSWORD;
+ u.info23.info.fields_present = fields_present;
encode_pw_buffer(u.info23.password.data, newpass, STR_UNICODE);
@@ -435,8 +493,17 @@ static BOOL test_SetUserPassEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
DATA_BLOB session_key;
DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
uint8_t confounder[16];
- char *newpass = samr_rand_pass(mem_ctx);
+ char *newpass;
struct MD5Context ctx;
+ struct samr_GetUserPwInfo pwp;
+ int policy_min_pw_len = 0;
+ pwp.in.user_handle = handle;
+
+ status = dcerpc_samr_GetUserPwInfo(p, mem_ctx, &pwp);
+ if (NT_STATUS_IS_OK(status)) {
+ policy_min_pw_len = pwp.out.info.min_password_len;
+ }
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
s.in.user_handle = handle;
s.in.info = &u;
@@ -477,7 +544,8 @@ static BOOL test_SetUserPassEx(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
}
static BOOL test_SetUserPass_25(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
- struct policy_handle *handle, char **password)
+ struct policy_handle *handle, uint32 fields_present,
+ char **password)
{
NTSTATUS status;
struct samr_SetUserInfo s;
@@ -485,9 +553,18 @@ static BOOL test_SetUserPass_25(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
BOOL ret = True;
DATA_BLOB session_key;
DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
- uint8_t confounder[16];
- char *newpass = samr_rand_pass(mem_ctx);
struct MD5Context ctx;
+ uint8_t confounder[16];
+ char *newpass;
+ struct samr_GetUserPwInfo pwp;
+ int policy_min_pw_len = 0;
+ pwp.in.user_handle = handle;
+
+ status = dcerpc_samr_GetUserPwInfo(p, mem_ctx, &pwp);
+ if (NT_STATUS_IS_OK(status)) {
+ policy_min_pw_len = pwp.out.info.min_password_len;
+ }
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
s.in.user_handle = handle;
s.in.info = &u;
@@ -495,7 +572,7 @@ static BOOL test_SetUserPass_25(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
ZERO_STRUCT(u);
- u.info25.info.fields_present = SAMR_FIELD_PASSWORD;
+ u.info25.info.fields_present = fields_present;
encode_pw_buffer(u.info25.password.data, newpass, STR_UNICODE);
@@ -798,14 +875,24 @@ static BOOL test_ChangePasswordUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
struct policy_handle user_handle;
char *oldpass = *password;
- char *newpass = samr_rand_pass(mem_ctx);
uint8_t old_nt_hash[16], new_nt_hash[16];
uint8_t old_lm_hash[16], new_lm_hash[16];
+ char *newpass;
+ struct samr_GetUserPwInfo pwp;
+ int policy_min_pw_len = 0;
+
status = test_OpenUser_byname(p, mem_ctx, handle, TEST_ACCOUNT_NAME, &user_handle);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
+ pwp.in.user_handle = &user_handle;
+
+ status = dcerpc_samr_GetUserPwInfo(p, mem_ctx, &pwp);
+ if (NT_STATUS_IS_OK(status)) {
+ policy_min_pw_len = pwp.out.info.min_password_len;
+ }
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
printf("Testing ChangePasswordUser\n");
@@ -859,11 +946,25 @@ static BOOL test_OemChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_c
struct samr_CryptPassword lm_pass;
struct samr_AsciiName server, account;
char *oldpass = *password;
- char *newpass = samr_rand_pass(mem_ctx);
+ char *newpass;
uint8_t old_lm_hash[16], new_lm_hash[16];
+ struct samr_GetDomPwInfo dom_pw_info;
+ int policy_min_pw_len = 0;
+
+ struct samr_Name domain_name;
+ domain_name.name = "";
+ dom_pw_info.in.name = &domain_name;
+
printf("Testing OemChangePasswordUser2\n");
+ 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_len;
+ }
+
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
+
server.name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
account.name = TEST_ACCOUNT_NAME;
@@ -901,12 +1002,26 @@ 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 = *password;
- char *newpass = samr_rand_pass(mem_ctx);
+ 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 samr_Name domain_name;
+ domain_name.name = "";
+ dom_pw_info.in.name = &domain_name;
+
printf("Testing ChangePasswordUser2\n");
+ 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_len;
+ }
+
+ newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
+
server.name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
init_samr_Name(&account, TEST_ACCOUNT_NAME);
@@ -945,7 +1060,9 @@ static BOOL test_ChangePasswordUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
static BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
- struct policy_handle *handle, char **password)
+ struct policy_handle *handle,
+ int policy_min_pw_len,
+ char **password)
{
NTSTATUS status;
struct samr_ChangePasswordUser3 r;
@@ -954,7 +1071,7 @@ static BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
struct samr_CryptPassword nt_pass, lm_pass;
struct samr_Password nt_verifier, lm_verifier;
char *oldpass = *password;
- char *newpass = samr_rand_pass(mem_ctx);
+ char *newpass = samr_rand_pass(mem_ctx, policy_min_pw_len);
uint8_t old_nt_hash[16], new_nt_hash[16];
uint8_t old_lm_hash[16], new_lm_hash[16];
@@ -987,7 +1104,18 @@ static BOOL test_ChangePasswordUser3(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
r.in.password3 = NULL;
status = dcerpc_samr_ChangePasswordUser3(p, mem_ctx, &r);
- if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)
+ && !policy_min_pw_len) {
+ if (r.out.dominfo) {
+ policy_min_pw_len = r.out.dominfo->min_password_len;
+ }
+ if (policy_min_pw_len) /* try again with the right min password length */ {
+ ret = test_ChangePasswordUser3(p, mem_ctx, handle, policy_min_pw_len, password);
+ } else {
+ printf("ChangePasswordUser3 failed - %s\n", nt_errstr(status));
+ ret = False;
+ }
+ } else if (!NT_STATUS_IS_OK(status)) {
printf("ChangePasswordUser3 failed - %s\n", nt_errstr(status));
ret = False;
} else {
@@ -1133,7 +1261,7 @@ static BOOL test_TestPrivateFunctionsUser(struct dcerpc_pipe *p, TALLOC_CTX *mem
static BOOL test_user_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
- struct policy_handle *handle)
+ struct policy_handle *handle, uint32_t base_acct_flags)
{
BOOL ret = True;
@@ -1149,7 +1277,7 @@ static BOOL test_user_ops(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
ret = False;
}
- if (!test_SetUserInfo(p, mem_ctx, handle)) {
+ if (!test_SetUserInfo(p, mem_ctx, handle, base_acct_flags)) {
ret = False;
}
@@ -1391,7 +1519,13 @@ static BOOL test_ChangePassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
ret = False;
}
- if (!test_ChangePasswordUser3(p, mem_ctx, domain_handle, password)) {
+ /* we change passwords twice - this has the effect of verifying
+ they were changed correctly for the final call */
+ if (!test_ChangePasswordUser3(p, mem_ctx, domain_handle, 0, password)) {
+ ret = False;
+ }
+
+ if (!test_ChangePasswordUser3(p, mem_ctx, domain_handle, 0, password)) {
ret = False;
}
@@ -1407,6 +1541,14 @@ static BOOL test_CreateUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
uint32_t rid;
char *password = NULL;
+ int i;
+ const uint32 password_fields[] = {
+ SAMR_FIELD_PASSWORD,
+ SAMR_FIELD_PASSWORD2,
+ SAMR_FIELD_PASSWORD | SAMR_FIELD_PASSWORD2,
+ 0
+ };
+
/* This call creates a 'normal' account - check that it really does */
const uint32_t acct_flags = ACB_NORMAL;
struct samr_Name name;
@@ -1458,7 +1600,7 @@ static BOOL test_CreateUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
}
}
- if (!test_user_ops(p, mem_ctx, user_handle)) {
+ if (!test_user_ops(p, mem_ctx, user_handle, acct_flags)) {
ret = False;
}
@@ -1466,21 +1608,29 @@ static BOOL test_CreateUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
ret = False;
}
- if (!test_SetUserPass_23(p, mem_ctx, user_handle, &password)) {
- ret = False;
- }
-
- if (!test_SetUserPassEx(p, mem_ctx, user_handle, &password)) {
- ret = False;
- }
+ for (i = 0; password_fields[i]; i++) {
+ if (!test_SetUserPass_23(p, mem_ctx, user_handle, password_fields[i], &password)) {
+ ret = False;
+ }
+
+ /* check it was set right */
+ if (!test_ChangePasswordUser3(p, mem_ctx, domain_handle, 0, &password)) {
+ ret = False;
+ }
+ }
- if (!test_SetUserPass_25(p, mem_ctx, user_handle, &password)) {
- ret = False;
- }
+ for (i = 0; password_fields[i]; i++) {
+ if (!test_SetUserPass_25(p, mem_ctx, user_handle, password_fields[i], &password)) {
+ ret = False;
+ }
+
+ /* check it was set right */
+ if (!test_ChangePasswordUser3(p, mem_ctx, domain_handle, 0, &password)) {
+ ret = False;
+ }
+ }
- /* we change passwords twice - this has the effect of verifying
- they were changed correctly */
- if (!test_ChangePassword(p, mem_ctx, domain_handle, &password)) {
+ if (!test_SetUserPassEx(p, mem_ctx, user_handle, &password)) {
ret = False;
}
@@ -1488,7 +1638,6 @@ static BOOL test_CreateUser(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
ret = False;
}
-
return ret;
}
@@ -1563,7 +1712,7 @@ static BOOL test_CreateUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
r.out.access_granted = &access_granted;
r.out.rid = &rid;
- printf("Testing CreateUser2(%s)\n", r.in.account_name->name);
+ printf("Testing CreateUser2(%s, 0x%x)\n", r.in.account_name->name, acct_flags);
status = dcerpc_samr_CreateUser2(p, mem_ctx, &r);
@@ -1602,7 +1751,7 @@ static BOOL test_CreateUser2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx,
}
}
- if (!test_user_ops(p, mem_ctx, &user_handle)) {
+ if (!test_user_ops(p, mem_ctx, &user_handle, acct_flags)) {
ret = False;
}