From 87d30dc32d06ce20e091b9d482af126780a9e4b7 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Tue, 22 May 2007 11:30:35 +0000 Subject: r23070: The lsa rpc lookup sids call has a maximum number of SIDS to be looked up at one time. This limit is at 20480 for w2k3. Our rpccli_lsa_lookup_sids function ignores this limit, so when we give the server too long a list of SIDs, then we will get nothing back. Since typically rpccli_lsa_lookup_sids is given one SID (or a small number of SIDS), this did not do harm up to now. But since I want to use lsa_lookup_sids in a subsequent modification to winbindd_ads.c:lookup_groupmem to get rid of a vast number of dn_lookup calls to the server, I had to make sure we do it correctly. I have added a function rpccli_lsa_lookup_sids_all function that has the same prototype but internally splits the list of SIDs up into hunks of a (conservative, hard coded) 1000 SIDs each for a first go. If this approach is agreed upon, the new function could replace the original rpccli_lsa_lookup_sids function. Michael (This used to be commit 66ff0bc6c39f86a9830dc508cd891e33638b475d) --- source3/rpc_client/cli_lsarpc.c | 201 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/source3/rpc_client/cli_lsarpc.c b/source3/rpc_client/cli_lsarpc.c index 00b91e4a3c..d0214eb5ff 100644 --- a/source3/rpc_client/cli_lsarpc.c +++ b/source3/rpc_client/cli_lsarpc.c @@ -127,6 +127,97 @@ NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli, return result; } +/* Lookup a list of sids + * + * internal version withOUT memory allocation. + * this assumes suffciently sized arrays to store + * domains, names and types */ + +static NTSTATUS rpccli_lsa_lookup_sids_noalloc(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + POLICY_HND *pol, + int num_sids, + const DOM_SID *sids, + char **domains, + char **names, + enum lsa_SidType *types) +{ + prs_struct qbuf, rbuf; + LSA_Q_LOOKUP_SIDS q; + LSA_R_LOOKUP_SIDS r; + DOM_R_REF ref; + LSA_TRANS_NAME_ENUM t_names; + NTSTATUS result = NT_STATUS_OK; + int i; + + ZERO_STRUCT(q); + ZERO_STRUCT(r); + + init_q_lookup_sids(mem_ctx, &q, pol, num_sids, sids, 1); + + ZERO_STRUCT(ref); + ZERO_STRUCT(t_names); + + r.dom_ref = &ref; + r.names = &t_names; + + CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_LOOKUPSIDS, + q, r, + qbuf, rbuf, + lsa_io_q_lookup_sids, + lsa_io_r_lookup_sids, + NT_STATUS_UNSUCCESSFUL ); + + if (!NT_STATUS_IS_OK(r.status) && + !NT_STATUS_EQUAL(r.status, STATUS_SOME_UNMAPPED)) + { + /* An actual error occured */ + result = r.status; + goto done; + } + + /* Return output parameters */ + + if (r.mapped_count == 0) { + result = NT_STATUS_NONE_MAPPED; + goto done; + } + + for (i = 0; i < num_sids; i++) { + fstring name, dom_name; + uint32 dom_idx = t_names.name[i].domain_idx; + + /* Translate optimised name through domain index array */ + + if (dom_idx != 0xffffffff) { + + rpcstr_pull_unistr2_fstring( + dom_name, &ref.ref_dom[dom_idx].uni_dom_name); + rpcstr_pull_unistr2_fstring( + name, &t_names.uni_name[i]); + + (names)[i] = talloc_strdup(mem_ctx, name); + (domains)[i] = talloc_strdup(mem_ctx, dom_name); + (types)[i] = (enum lsa_SidType)t_names.name[i].sid_name_use; + + if (((names)[i] == NULL) || ((domains)[i] == NULL)) { + DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n")); + result = NT_STATUS_UNSUCCESSFUL; + goto done; + } + + } else { + (names)[i] = NULL; + (domains)[i] = NULL; + (types)[i] = SID_NAME_UNKNOWN; + } + } + + done: + + return result; +} + /** Lookup a list of sids */ NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli, @@ -238,6 +329,116 @@ NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli, return result; } +/* Lookup a list of sids + * + * do it the right way: there is a limit (of 20480 for w2k3) entries + * returned by this call. when the sids list contains more entries, + * empty lists are returned. This version of lsa_lookup_sids passes + * the list of sids in hunks of LOOKUP_SIDS_HUNK_SIZE to the lsa call. */ + +/* This constant defines the limit of how many sids to look up + * in one call (maximum). the limit from the server side is + * at 20480 for win2k3, but we keep it at a save 1000 for now. */ +#define LOOKUP_SIDS_HUNK_SIZE 1000 + +NTSTATUS rpccli_lsa_lookup_sids_all(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + POLICY_HND *pol, + int num_sids, + const DOM_SID *sids, + char ***domains, + char ***names, + enum lsa_SidType **types) +{ + NTSTATUS result = NT_STATUS_OK; + int sids_left = 0; + int sids_processed = 0; + const DOM_SID *hunk_sids = sids; + char **hunk_domains = NULL; + char **hunk_names = NULL; + enum lsa_SidType *hunk_types = NULL; + + if (num_sids) { + if (!((*domains) = TALLOC_ARRAY(mem_ctx, char *, num_sids))) { + DEBUG(0, ("rpccli_lsa_lookup_sids_all(): out of memory\n")); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + if (!((*names) = TALLOC_ARRAY(mem_ctx, char *, num_sids))) { + DEBUG(0, ("rpccli_lsa_lookup_sids_all(): out of memory\n")); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + if (!((*types) = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_sids))) { + DEBUG(0, ("rpccli_lsa_lookup_sids_all(): out of memory\n")); + result = NT_STATUS_NO_MEMORY; + goto done; + } + } else { + (*domains) = NULL; + (*names) = NULL; + (*types) = NULL; + } + + sids_left = num_sids; + hunk_domains = *domains; + hunk_names = *names; + hunk_types = *types; + + while (sids_left > 0) { + int hunk_num_sids; + NTSTATUS hunk_result = NT_STATUS_OK; + + hunk_num_sids = ((sids_left > LOOKUP_SIDS_HUNK_SIZE) + ? LOOKUP_SIDS_HUNK_SIZE + : sids_left); + + DEBUG(10, ("rpccli_lsa_lookup_sids_all: processing items " + "%d -- %d of %d.\n", + sids_processed, + sids_processed + hunk_num_sids - 1, + num_sids)); + + hunk_result = rpccli_lsa_lookup_sids_noalloc(cli, mem_ctx, + pol, + hunk_num_sids, + hunk_sids, + hunk_domains, + hunk_names, + hunk_types); + + if (!NT_STATUS_IS_OK(hunk_result) && + !NT_STATUS_EQUAL(hunk_result, STATUS_SOME_UNMAPPED) && + !NT_STATUS_EQUAL(hunk_result, NT_STATUS_NONE_MAPPED)) + { + /* An actual error occured */ + goto done; + } + + /* adapt overall result */ + if (( NT_STATUS_IS_OK(result) && + !NT_STATUS_IS_OK(hunk_result)) + || + ( NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) && + !NT_STATUS_EQUAL(hunk_result, NT_STATUS_NONE_MAPPED))) + { + result = STATUS_SOME_UNMAPPED; + } + + sids_left -= hunk_num_sids; + sids_processed += hunk_num_sids; /* only used in DEBUG */ + hunk_sids += hunk_num_sids; + hunk_domains += hunk_num_sids; + hunk_names += hunk_num_sids; + hunk_types += hunk_num_sids; + } + +done: + return result; +} + /** Lookup a list of names */ NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli, -- cgit