diff options
-rw-r--r-- | source4/rpc_server/samr/dcesrv_samr.c | 32 | ||||
-rw-r--r-- | source4/torture/rpc/samr.c | 102 |
2 files changed, 100 insertions, 34 deletions
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c index cedf4059e2..f1c4ac24c9 100644 --- a/source4/rpc_server/samr/dcesrv_samr.c +++ b/source4/rpc_server/samr/dcesrv_samr.c @@ -1428,9 +1428,9 @@ static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, struct dcesrv_handle *h; struct samr_domain_state *d_state; struct ldb_message **res; - int count, i, first; + int count, num_filtered_entries, i, first; struct samr_SamEntry *entries; - const char * const attrs[3] = { "objectSid", "sAMAccountName", NULL }; + const char * const attrs[] = { "objectSid", "sAMAccountName", "userAccountControl", NULL }; *r->out.resume_handle = 0; r->out.sam = NULL; @@ -1456,27 +1456,31 @@ static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, if (!entries) { return NT_STATUS_NO_MEMORY; } + num_filtered_entries = 0; for (i=0;i<count;i++) { - entries[i].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0); - entries[i].name.string = samdb_result_string(res[i], "sAMAccountName", ""); + /* Check if a mask has been requested */ + if (r->in.acct_flags + && ((samdb_result_acct_flags(res[i], + "userAccountControl") & r->in.acct_flags) == 0)) { + continue; + } + entries[num_filtered_entries].idx = samdb_result_rid_from_sid(mem_ctx, res[i], "objectSid", 0); + entries[num_filtered_entries].name.string = samdb_result_string(res[i], "sAMAccountName", ""); + num_filtered_entries++; } /* sort the results by rid */ - qsort(entries, count, sizeof(struct samr_SamEntry), + qsort(entries, num_filtered_entries, sizeof(struct samr_SamEntry), (comparison_fn_t)compare_SamEntry); /* find the first entry to return */ for (first=0; - first<count && entries[first].idx <= *r->in.resume_handle; + first<num_filtered_entries && entries[first].idx <= *r->in.resume_handle; first++) ; - if (first == count) { - return NT_STATUS_OK; - } - /* return the rest, limit by max_size. Note that we use the w2k3 element size value of 54 */ - r->out.num_entries = count - first; + r->out.num_entries = num_filtered_entries - first; r->out.num_entries = MIN(r->out.num_entries, 1+(r->in.max_size/SAMR_ENUM_USERS_MULTIPLIER)); @@ -1488,7 +1492,11 @@ static NTSTATUS dcesrv_samr_EnumDomainUsers(struct dcesrv_call_state *dce_call, r->out.sam->entries = entries+first; r->out.sam->count = r->out.num_entries; - if (r->out.num_entries < count - first) { + if (first == num_filtered_entries) { + return NT_STATUS_OK; + } + + if (r->out.num_entries < num_filtered_entries - first) { *r->out.resume_handle = entries[first+r->out.num_entries-1].idx; return STATUS_MORE_ENTRIES; } diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c index 20a79a7d4f..58488b7717 100644 --- a/source4/torture/rpc/samr.c +++ b/source4/torture/rpc/samr.c @@ -2861,42 +2861,100 @@ static BOOL test_OpenAlias(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, return ret; } -static BOOL test_EnumDomainUsers(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, - struct policy_handle *handle) +static BOOL check_mask(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, + struct policy_handle *handle, uint32_t rid, + uint32_t acct_flag_mask) { NTSTATUS status; - struct samr_EnumDomainUsers r; - uint32_t resume_handle=0; - int i; + struct samr_OpenUser r; + struct samr_QueryUserInfo q; + struct policy_handle user_handle; BOOL ret = True; - struct samr_LookupNames n; - struct samr_LookupRids lr ; - printf("Testing EnumDomainUsers\n"); + printf("Testing OpenUser(%u)\n", rid); r.in.domain_handle = handle; - r.in.resume_handle = &resume_handle; - r.in.acct_flags = 0; - r.in.max_size = (uint32_t)-1; - r.out.resume_handle = &resume_handle; + r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + r.in.rid = rid; + r.out.user_handle = &user_handle; - status = dcerpc_samr_EnumDomainUsers(p, mem_ctx, &r); + status = dcerpc_samr_OpenUser(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { - printf("EnumDomainUsers failed - %s\n", nt_errstr(status)); + printf("OpenUser(%u) failed - %s\n", rid, nt_errstr(status)); return False; } + + q.in.user_handle = &user_handle; + q.in.level = 16; - if (!r.out.sam) { - return False; + status = dcerpc_samr_QueryUserInfo(p, mem_ctx, &q); + if (!NT_STATUS_IS_OK(status)) { + printf("QueryUserInfo level 16 failed - %s\n", + nt_errstr(status)); + ret = False; + } else { + if ((acct_flag_mask & q.out.info->info16.acct_flags) == 0) { + printf("Server failed to filter for 0x%x, allowed 0x%x (%d) on EnumDomainUsers\n", + acct_flag_mask, q.out.info->info16.acct_flags, rid); + ret = False; + } } - - if (r.out.sam->count == 0) { - return True; + + if (!test_samr_handle_Close(p, mem_ctx, &user_handle)) { + ret = False; } - for (i=0;i<r.out.sam->count;i++) { - if (!test_OpenUser(p, mem_ctx, handle, r.out.sam->entries[i].idx)) { - ret = False; + return ret; +} + +static BOOL test_EnumDomainUsers(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, + struct policy_handle *handle) +{ + NTSTATUS status = STATUS_MORE_ENTRIES; + struct samr_EnumDomainUsers r; + uint32_t mask, resume_handle=0; + int i, mask_idx; + BOOL ret = True; + struct samr_LookupNames n; + struct samr_LookupRids lr ; + uint32_t masks[] = {ACB_NORMAL, ACB_DOMTRUST, ACB_WSTRUST, + ACB_DISABLED, ACB_NORMAL | ACB_DISABLED, + ACB_SVRTRUST | ACB_DOMTRUST | ACB_WSTRUST, + ACB_PWNOEXP, 0}; + + printf("Testing EnumDomainUsers\n"); + + for (mask_idx=0;mask_idx<ARRAY_SIZE(masks);mask_idx++) { + r.in.domain_handle = handle; + r.in.resume_handle = &resume_handle; + r.in.acct_flags = mask = masks[mask_idx]; + r.in.max_size = (uint32_t)-1; + r.out.resume_handle = &resume_handle; + + status = dcerpc_samr_EnumDomainUsers(p, mem_ctx, &r); + if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) && + !NT_STATUS_IS_OK(status)) { + printf("EnumDomainUsers failed - %s\n", nt_errstr(status)); + return False; + } + + if (!r.out.sam) { + printf("EnumDomainUsers failed: r.out.sam unexpectedly NULL\n"); + return False; + } + + if (r.out.sam->count == 0) { + continue; + } + + for (i=0;i<r.out.sam->count;i++) { + if (mask) { + if (!check_mask(p, mem_ctx, handle, r.out.sam->entries[i].idx, mask)) { + ret = False; + } + } else if (!test_OpenUser(p, mem_ctx, handle, r.out.sam->entries[i].idx)) { + ret = False; + } } } |