+ /* pwdlastset must be 0 afterwards, except for a level 21, 23 and 25
+ * set without the SAMR_FIELD_EXPIRED_FLAG */
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ if ((pwdlastset_new != 0) &&
+ !(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG)) {
+ torture_comment(tctx, "not considering a non-0 "
+ "pwdLastSet as a an error as the "
+ "SAMR_FIELD_EXPIRED_FLAG has not "
+ "been set\n");
+ break;
+ }
+ default:
+ if (pwdlastset_new != 0) {
+ torture_warning(tctx, "pwdLastSet test failed: "
+ "expected pwdLastSet 0 but got %lld\n",
+ pwdlastset_old);
+ ret = false;
+ }
+ break;
+ }
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ if (((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)) &&
+ (pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_warning(tctx, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ default:
+ if ((pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_warning(tctx, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ }
+
+ usleep(delay);
+
+ /* set #2 */
+
+ /* set a password, pwdlastset needs to get updated (increased
+ * value), password_expired value used here is 0 */
+
+ if (!test_SetPassword_level(p, np, tctx, handle,
+ levels[l],
+ fields_present[f],
+ 0,
+ &matched_expected_error,
+ set_levels[s],
+ acct_name,
+ password,
+ machine_credentials,
+ query_levels[q],
+ &pwdlastset_new,
+ expected_samlogon_result)) {
+ ret = false;
+ }
+
+ /* when a password has been changed, pwdlastset must not be 0 afterwards
+ * and must be larger then the old value */
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+
+ /* SAMR_FIELD_EXPIRED_FLAG has not been set and no
+ * password has been changed, old and new pwdlastset
+ * need to be the same value */
+
+ if (!(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG) &&
+ !((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)))
+ {
+ torture_assert_int_equal(tctx, pwdlastset_old,
+ pwdlastset_new, "pwdlastset must be equal");
+ break;
+ }
+ default:
+ if (pwdlastset_old >= pwdlastset_new) {
+ torture_warning(tctx, "pwdLastSet test failed: "
+ "expected last pwdlastset (%lld) < new pwdlastset (%lld)\n",
+ pwdlastset_old, pwdlastset_new);
+ ret = false;
+ }
+ if (pwdlastset_new == 0) {
+ torture_warning(tctx, "pwdLastSet test failed: "
+ "expected non-0 pwdlastset, got: %lld\n",
+ pwdlastset_new);
+ ret = false;
+ }
+ }
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ if (((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)) &&
+ (pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_warning(tctx, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ default:
+ if ((pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_warning(tctx, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ }
+
+ pwdlastset_old = pwdlastset_new;
+
+ usleep(delay);
+
+ /* set #2b */
+
+ /* set a password, pwdlastset needs to get updated (increased
+ * value), password_expired value used here is 0 */
+
+ if (!test_SetPassword_level(p, np, tctx, handle,
+ levels[l],
+ fields_present[f],
+ 0,
+ &matched_expected_error,
+ set_levels[s],
+ acct_name,
+ password,
+ machine_credentials,
+ query_levels[q],
+ &pwdlastset_new,
+ expected_samlogon_result)) {
+ ret = false;
+ }
+
+ /* when a password has been changed, pwdlastset must not be 0 afterwards
+ * and must be larger then the old value */
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+
+ /* if no password has been changed, old and new pwdlastset
+ * need to be the same value */
+
+ if (!((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)))
+ {
+ torture_assert_int_equal(tctx, pwdlastset_old,
+ pwdlastset_new, "pwdlastset must be equal");
+ break;
+ }
+ default:
+ if (pwdlastset_old >= pwdlastset_new) {
+ torture_warning(tctx, "pwdLastSet test failed: "
+ "expected last pwdlastset (%lld) < new pwdlastset (%lld)\n",
+ pwdlastset_old, pwdlastset_new);
+ ret = false;
+ }
+ if (pwdlastset_new == 0) {
+ torture_warning(tctx, "pwdLastSet test failed: "
+ "expected non-0 pwdlastset, got: %lld\n",
+ pwdlastset_new);
+ ret = false;
+ }
+ }
+
+ /* set #3 */
+
+ /* set a password and force password change (pwdlastset 0) by
+ * setting the password expired flag to a non-0 value */
+
+ if (!test_SetPassword_level(p, np, tctx, handle,
+ levels[l],
+ fields_present[f],
+ nonzeros[z],
+ &matched_expected_error,
+ set_levels[s],
+ acct_name,
+ password,
+ machine_credentials,
+ query_levels[q],
+ &pwdlastset_new,
+ expected_samlogon_result)) {
+ ret = false;
+ }
+
+ /* pwdlastset must be 0 afterwards, except for a level 21, 23 and 25
+ * set without the SAMR_FIELD_EXPIRED_FLAG */
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ if ((pwdlastset_new != 0) &&
+ !(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG)) {
+ torture_comment(tctx, "not considering a non-0 "
+ "pwdLastSet as a an error as the "
+ "SAMR_FIELD_EXPIRED_FLAG has not "
+ "been set\n");
+ break;
+ }
+
+ /* SAMR_FIELD_EXPIRED_FLAG has not been set and no
+ * password has been changed, old and new pwdlastset
+ * need to be the same value */
+
+ if (!(fields_present[f] & SAMR_FIELD_EXPIRED_FLAG) &&
+ !((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)))
+ {
+ torture_assert_int_equal(tctx, pwdlastset_old,
+ pwdlastset_new, "pwdlastset must be equal");
+ break;
+ }
+ default:
+
+ if (pwdlastset_old == pwdlastset_new) {
+ torture_warning(tctx, "pwdLastSet test failed: "
+ "expected last pwdlastset (%lld) != new pwdlastset (%lld)\n",
+ pwdlastset_old, pwdlastset_new);
+ ret = false;
+ }
+
+ if (pwdlastset_new != 0) {
+ torture_warning(tctx, "pwdLastSet test failed: "
+ "expected pwdLastSet 0, got %lld\n",
+ pwdlastset_old);
+ ret = false;
+ }
+ break;
+ }
+
+ switch (levels[l]) {
+ case 21:
+ case 23:
+ case 25:
+ if (((fields_present[f] & SAMR_FIELD_NT_PASSWORD_PRESENT) ||
+ (fields_present[f] & SAMR_FIELD_LM_PASSWORD_PRESENT)) &&
+ (pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_warning(tctx, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ default:
+ if ((pwdlastset_old > 0) && (pwdlastset_new > 0) &&
+ (pwdlastset_old >= pwdlastset_new)) {
+ torture_warning(tctx, "pwdlastset not increasing\n");
+ ret = false;
+ }
+ break;
+ }
+
+ /* if the level we are testing does not have a fields_present
+ * field, skip all fields present tests by setting f to to
+ * arraysize */
+ switch (levels[l]) {
+ case 18:
+ case 24:
+ case 26:
+ f = ARRAY_SIZE(fields_present);
+ break;
+ }
+
+#ifdef TEST_QUERY_LEVELS
+ }
+#endif
+#ifdef TEST_SET_LEVELS
+ }
+#endif
+ } /* fields present */
+ } /* nonzeros */
+ } /* levels */
+
+#undef TEST_SET_LEVELS
+#undef TEST_QUERY_LEVELS
+
+ talloc_free(np);
+
+ return ret;
+}
+
+static bool test_DeleteUser_with_privs(struct dcerpc_pipe *p,
+ struct dcerpc_pipe *lp,
+ struct torture_context *tctx,
+ struct policy_handle *domain_handle,
+ struct policy_handle *lsa_handle,
+ struct policy_handle *user_handle,
+ const struct dom_sid *domain_sid,
+ uint32_t rid,
+ struct cli_credentials *machine_credentials)
+{
+ NTSTATUS status;
+ bool ret = true;
+
+ struct policy_handle lsa_acct_handle;
+ struct dom_sid *user_sid;
+
+ user_sid = dom_sid_add_rid(tctx, domain_sid, rid);
+
+ {
+ struct lsa_EnumAccountRights r;
+ struct lsa_RightSet rights;
+
+ torture_comment(tctx, "Testing LSA EnumAccountRights\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.out.rights = &rights;
+
+ status = dcerpc_lsa_EnumAccountRights(lp, tctx, &r);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "Expected enum rights for account to fail");
+ }
+
+ {
+ struct lsa_RightSet rights;
+ struct lsa_StringLarge names[2];
+ struct lsa_AddAccountRights r;
+
+ torture_comment(tctx, "Testing LSA AddAccountRights\n");
+
+ init_lsa_StringLarge(&names[0], "SeMachineAccountPrivilege");
+ init_lsa_StringLarge(&names[1], NULL);
+
+ rights.count = 1;
+ rights.names = names;
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.in.rights = &rights;
+
+ status = dcerpc_lsa_AddAccountRights(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to add privileges");
+ }
+
+ {
+ struct lsa_EnumAccounts r;
+ uint32_t resume_handle = 0;
+ struct lsa_SidArray lsa_sid_array;
+ int i;
+ bool found_sid = false;
+
+ torture_comment(tctx, "Testing LSA EnumAccounts\n");
+
+ r.in.handle = lsa_handle;
+ r.in.num_entries = 0x1000;
+ r.in.resume_handle = &resume_handle;
+ r.out.sids = &lsa_sid_array;
+ r.out.resume_handle = &resume_handle;
+
+ status = dcerpc_lsa_EnumAccounts(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to enum accounts");
+
+ for (i=0; i < lsa_sid_array.num_sids; i++) {
+ if (dom_sid_equal(user_sid, lsa_sid_array.sids[i].sid)) {
+ found_sid = true;
+ }
+ }
+
+ torture_assert(tctx, found_sid,
+ "failed to list privileged account");
+ }
+
+ {
+ struct lsa_EnumAccountRights r;
+ struct lsa_RightSet user_rights;
+
+ torture_comment(tctx, "Testing LSA EnumAccountRights\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.out.rights = &user_rights;
+
+ status = dcerpc_lsa_EnumAccountRights(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to enum rights for account");
+
+ if (user_rights.count < 1) {
+ torture_warning(tctx, "failed to find newly added rights");
+ return false;
+ }
+ }
+
+ {
+ struct lsa_OpenAccount r;
+
+ torture_comment(tctx, "Testing LSA OpenAccount\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.acct_handle = &lsa_acct_handle;
+
+ status = dcerpc_lsa_OpenAccount(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to open lsa account");
+ }
+
+ {
+ struct lsa_GetSystemAccessAccount r;
+ uint32_t access_mask;
+
+ torture_comment(tctx, "Testing LSA GetSystemAccessAccount\n");
+
+ r.in.handle = &lsa_acct_handle;
+ r.out.access_mask = &access_mask;
+
+ status = dcerpc_lsa_GetSystemAccessAccount(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to get lsa system access account");
+ }
+
+ {
+ struct lsa_Close r;
+
+ torture_comment(tctx, "Testing LSA Close\n");
+
+ r.in.handle = &lsa_acct_handle;
+ r.out.handle = &lsa_acct_handle;
+
+ status = dcerpc_lsa_Close(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to close lsa");
+ }
+
+ {
+ struct samr_DeleteUser r;
+
+ torture_comment(tctx, "Testing SAMR DeleteUser\n");
+
+ r.in.user_handle = user_handle;
+ r.out.user_handle = user_handle;
+
+ status = dcerpc_samr_DeleteUser(p, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status, "Delete User failed");
+ }
+
+ {
+ struct lsa_EnumAccounts r;
+ uint32_t resume_handle = 0;
+ struct lsa_SidArray lsa_sid_array;
+ int i;
+ bool found_sid = false;
+
+ torture_comment(tctx, "Testing LSA EnumAccounts\n");
+
+ r.in.handle = lsa_handle;
+ r.in.num_entries = 0x1000;
+ r.in.resume_handle = &resume_handle;
+ r.out.sids = &lsa_sid_array;
+ r.out.resume_handle = &resume_handle;
+
+ status = dcerpc_lsa_EnumAccounts(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to enum accounts");
+
+ for (i=0; i < lsa_sid_array.num_sids; i++) {
+ if (dom_sid_equal(user_sid, lsa_sid_array.sids[i].sid)) {
+ found_sid = true;
+ }
+ }
+
+ torture_assert(tctx, found_sid,
+ "failed to list privileged account");
+ }
+
+ {
+ struct lsa_EnumAccountRights r;
+ struct lsa_RightSet user_rights;
+
+ torture_comment(tctx, "Testing LSA EnumAccountRights\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.out.rights = &user_rights;
+
+ status = dcerpc_lsa_EnumAccountRights(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to enum rights for account");
+
+ if (user_rights.count < 1) {
+ torture_warning(tctx, "failed to find newly added rights");
+ return false;
+ }
+ }
+
+ {
+ struct lsa_OpenAccount r;
+
+ torture_comment(tctx, "Testing LSA OpenAccount\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.out.acct_handle = &lsa_acct_handle;
+
+ status = dcerpc_lsa_OpenAccount(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to open lsa account");
+ }
+
+ {
+ struct lsa_GetSystemAccessAccount r;
+ uint32_t access_mask;
+
+ torture_comment(tctx, "Testing LSA GetSystemAccessAccount\n");
+
+ r.in.handle = &lsa_acct_handle;
+ r.out.access_mask = &access_mask;
+
+ status = dcerpc_lsa_GetSystemAccessAccount(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to get lsa system access account");
+ }
+
+ {
+ struct lsa_DeleteObject r;
+
+ torture_comment(tctx, "Testing LSA DeleteObject\n");
+
+ r.in.handle = &lsa_acct_handle;
+ r.out.handle = &lsa_acct_handle;
+
+ status = dcerpc_lsa_DeleteObject(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to delete object");
+ }
+
+ {
+ struct lsa_EnumAccounts r;
+ uint32_t resume_handle = 0;
+ struct lsa_SidArray lsa_sid_array;
+ int i;
+ bool found_sid = false;
+
+ torture_comment(tctx, "Testing LSA EnumAccounts\n");
+
+ r.in.handle = lsa_handle;
+ r.in.num_entries = 0x1000;
+ r.in.resume_handle = &resume_handle;
+ r.out.sids = &lsa_sid_array;
+ r.out.resume_handle = &resume_handle;
+
+ status = dcerpc_lsa_EnumAccounts(lp, tctx, &r);
+ torture_assert_ntstatus_ok(tctx, status,
+ "Failed to enum accounts");
+
+ for (i=0; i < lsa_sid_array.num_sids; i++) {
+ if (dom_sid_equal(user_sid, lsa_sid_array.sids[i].sid)) {
+ found_sid = true;
+ }
+ }
+
+ torture_assert(tctx, !found_sid,
+ "should not have listed privileged account");
+ }
+
+ {
+ struct lsa_EnumAccountRights r;
+ struct lsa_RightSet user_rights;
+
+ torture_comment(tctx, "Testing LSA EnumAccountRights\n");
+
+ r.in.handle = lsa_handle;
+ r.in.sid = user_sid;
+ r.out.rights = &user_rights;
+
+ status = dcerpc_lsa_EnumAccountRights(lp, tctx, &r);
+ torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ "Failed to enum rights for account");
+ }
+
+ return ret;
+}
+
+static bool test_user_ops(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *user_handle,
+ struct policy_handle *domain_handle,
+ const struct dom_sid *domain_sid,
+ uint32_t base_acct_flags,
+ const char *base_acct_name, enum torture_samr_choice which_ops,
+ struct cli_credentials *machine_credentials)
+{
+ char *password = NULL;
+ struct samr_QueryUserInfo q;
+ union samr_UserInfo *info;
+ NTSTATUS status;
+
+ bool ret = true;
+ int i;
+ uint32_t rid;
+ const uint32_t password_fields[] = {
+ SAMR_FIELD_NT_PASSWORD_PRESENT,
+ SAMR_FIELD_LM_PASSWORD_PRESENT,
+ SAMR_FIELD_NT_PASSWORD_PRESENT | SAMR_FIELD_LM_PASSWORD_PRESENT,
+ 0
+ };
+
+ status = test_LookupName(p, tctx, domain_handle, base_acct_name, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = false;
+ }
+
+ switch (which_ops) {
+ case TORTURE_SAMR_USER_ATTRIBUTES:
+ if (!test_QuerySecurity(p, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_QueryUserInfo(p, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_QueryUserInfo2(p, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_SetUserInfo(p, tctx, user_handle, base_acct_flags,
+ base_acct_name)) {
+ ret = false;
+ }
+
+ if (!test_GetUserPwInfo(p, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_TestPrivateFunctionsUser(p, tctx, user_handle)) {
+ ret = false;
+ }
+
+ if (!test_SetUserPass(p, tctx, user_handle, &password)) {
+ ret = false;
+ }
+ break;
+ case TORTURE_SAMR_PASSWORDS:
+ if (base_acct_flags & (ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST)) {
+ char simple_pass[9];
+ char *v = generate_random_str(tctx, 1);
+
+ ZERO_STRUCT(simple_pass);
+ memset(simple_pass, *v, sizeof(simple_pass) - 1);
+
+ torture_comment(tctx, "Testing machine account password policy rules\n");
+
+ /* Workstation trust accounts don't seem to need to honour password quality policy */
+ if (!test_SetUserPassEx(p, tctx, user_handle, true, &password)) {
+ ret = false;
+ }
+
+ if (!test_ChangePasswordUser2(p, tctx, base_acct_name, &password, simple_pass, false)) {
+ ret = false;
+ }
+
+ /* reset again, to allow another 'user' password change */
+ if (!test_SetUserPassEx(p, tctx, user_handle, true, &password)) {
+ ret = false;
+ }
+
+ /* Try a 'short' password */
+ if (!test_ChangePasswordUser2(p, tctx, base_acct_name, &password, samr_rand_pass(tctx, 4), false)) {
+ ret = false;
+ }
+
+ /* Try a compleatly random password */
+ if (!test_ChangePasswordRandomBytes(p, tctx, base_acct_name, user_handle, &password)) {
+ ret = false;
+ }
+ }
+
+ for (i = 0; password_fields[i]; i++) {
+ if (!test_SetUserPass_23(p, tctx, user_handle, password_fields[i], &password)) {
+ ret = false;
+ }
+
+ /* check it was set right */
+ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) {
+ ret = false;
+ }
+ }
+
+ for (i = 0; password_fields[i]; i++) {
+ if (!test_SetUserPass_25(p, tctx, user_handle, password_fields[i], &password)) {
+ ret = false;
+ }
+
+ /* check it was set right */
+ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) {
+ ret = false;
+ }
+ }
+
+ if (!test_SetUserPassEx(p, tctx, user_handle, false, &password)) {
+ ret = false;
+ }
+
+ if (!test_ChangePassword(p, tctx, base_acct_name, domain_handle, &password)) {
+ ret = false;
+ }
+
+ if (torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping Set Password level 18 and 21 against Samba4\n");
+ } else {
+
+ if (!test_SetUserPass_18(p, tctx, user_handle, &password)) {
+ ret = false;
+ }
+
+ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) {
+ ret = false;
+ }
+
+ for (i = 0; password_fields[i]; i++) {
+
+ if (password_fields[i] == SAMR_FIELD_LM_PASSWORD_PRESENT) {
+ /* we need to skip as that would break
+ * the ChangePasswordUser3 verify */
+ continue;
+ }
+
+ if (!test_SetUserPass_21(p, tctx, user_handle, password_fields[i], &password)) {
+ ret = false;
+ }
+
+ /* check it was set right */
+ if (!test_ChangePasswordUser3(p, tctx, base_acct_name, 0, &password, NULL, 0, false)) {
+ ret = false;
+ }
+ }
+ }
+
+ q.in.user_handle = user_handle;
+ q.in.level = 5;
+ q.out.info = &info;
+
+ status = dcerpc_samr_QueryUserInfo(p, tctx, &q);
+ if (!NT_STATUS_IS_OK(status)) {
+ torture_warning(tctx, "QueryUserInfo level %u failed - %s\n",
+ q.in.level, nt_errstr(status));
+ ret = false;
+ } else {
+ uint32_t expected_flags = (base_acct_flags | ACB_PWNOTREQ | ACB_DISABLED);
+ if ((info->info5.acct_flags) != expected_flags) {
+ torture_warning(tctx, "QuerUserInfo level 5 failed, it returned 0x%08x when we expected flags of 0x%08x\n",
+ info->info5.acct_flags,
+ expected_flags);
+ /* FIXME: GD */
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ ret = false;
+ }
+ }
+ if (info->info5.rid != rid) {
+ torture_warning(tctx, "QuerUserInfo level 5 failed, it returned %u when we expected rid of %u\n",
+ info->info5.rid, rid);
+
+ }
+ }
+
+ break;
+
+ case TORTURE_SAMR_PASSWORDS_PWDLASTSET:
+
+ /* test last password change timestamp behaviour */
+ if (!test_SetPassword_pwdlastset(p, tctx, base_acct_flags,
+ base_acct_name,
+ user_handle, &password,
+ machine_credentials)) {
+ ret = false;
+ }
+
+ if (ret == true) {
+ torture_comment(tctx, "pwdLastSet test succeeded\n");
+ } else {
+ torture_warning(tctx, "pwdLastSet test failed\n");
+ }
+
+ break;
+
+ case TORTURE_SAMR_USER_PRIVILEGES: {
+
+ struct dcerpc_pipe *lp;
+ struct policy_handle *lsa_handle;
+
+ status = torture_rpc_connection(tctx, &lp, &ndr_table_lsarpc);
+ torture_assert_ntstatus_ok(tctx, status, "Failed to open LSA pipe");
+
+ if (!test_lsa_OpenPolicy2(lp, tctx, &lsa_handle)) {
+ ret = false;
+ }
+
+ if (!test_DeleteUser_with_privs(p, lp, tctx,
+ domain_handle, lsa_handle, user_handle,
+ domain_sid, rid,
+ machine_credentials)) {
+ ret = false;
+ }
+
+ if (!test_lsa_Close(lp, tctx, lsa_handle)) {
+ ret = false;
+ }
+
+ if (!ret) {
+ torture_warning(tctx, "privileged user delete test failed\n");
+ }
+
+ break;
+ }
+ case TORTURE_SAMR_OTHER:
+ /* We just need the account to exist */
+ break;
+ }
+ return ret;
+}
+
+static bool test_alias_ops(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *alias_handle,
+ const struct dom_sid *domain_sid)
+{
+ bool ret = true;
+
+ if (!torture_setting_bool(tctx, "samba3", false)) {
+ if (!test_QuerySecurity(p, tctx, alias_handle)) {
+ ret = false;
+ }
+ }
+
+ if (!test_QueryAliasInfo(p, tctx, alias_handle)) {
+ ret = false;
+ }
+
+ if (!test_SetAliasInfo(p, tctx, alias_handle)) {
+ ret = false;
+ }
+
+ if (!test_AddMemberToAlias(p, tctx, alias_handle, domain_sid)) {
+ ret = false;
+ }
+
+ if (torture_setting_bool(tctx, "samba3", false) ||
+ torture_setting_bool(tctx, "samba4", false)) {
+ torture_comment(tctx, "skipping MultipleMembers Alias tests against Samba\n");
+ return ret;
+ }
+
+ if (!test_AddMultipleMembersToAlias(p, tctx, alias_handle)) {
+ ret = false;
+ }
+
+ return ret;
+}
+
+
+static bool test_DeleteUser(struct dcerpc_pipe *p, struct torture_context *tctx,
+ struct policy_handle *user_handle)
+{
+ struct samr_DeleteUser d;
+ NTSTATUS status;
+ torture_comment(tctx, "Testing DeleteUser\n");
+
+ d.in.user_handle = user_handle;
+ d.out.user_handle = user_handle;
+
+ status = dcerpc_samr_DeleteUser(p, tctx, &d);
+ torture_assert_ntstatus_ok(tctx, status, "DeleteUser");
+
+ return true;
+}
+
+bool test_DeleteUser_byname(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle, const char *name)
+{
+ NTSTATUS status;
+ struct samr_DeleteUser d;
+ struct policy_handle user_handle;
+ uint32_t rid;
+
+ status = test_LookupName(p, tctx, handle, name, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ status = test_OpenUser_byname(p, tctx, handle, name, &user_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ d.in.user_handle = &user_handle;
+ d.out.user_handle = &user_handle;
+ status = dcerpc_samr_DeleteUser(p, tctx, &d);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ return true;
+
+failed:
+ torture_warning(tctx, "DeleteUser_byname(%s) failed - %s\n", name, nt_errstr(status));
+ return false;
+}
+
+
+static bool test_DeleteGroup_byname(struct dcerpc_pipe *p,
+ struct torture_context *tctx,
+ struct policy_handle *handle, const char *name)
+{
+ NTSTATUS status;
+ struct samr_OpenGroup r;
+ struct samr_DeleteDomainGroup d;
+ struct policy_handle group_handle;
+ uint32_t rid;
+
+ status = test_LookupName(p, tctx, handle, name, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+
+ r.in.domain_handle = handle;
+ r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+ r.in.rid = rid;
+ r.out.group_handle = &group_handle;
+ status = dcerpc_samr_OpenGroup(p, tctx, &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;