r23070: The lsa rpc lookup sids call has a maximum number of SIDS to be
authorMichael Adam <obnox@samba.org>
Tue, 22 May 2007 11:30:35 +0000 (11:30 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:22:18 +0000 (12:22 -0500)
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

index 00b91e4a3c297654e7e7d624f0e39d77449427d5..d0214eb5ff33c17d8966c892d0d5f2feca3539db 100644 (file)
@@ -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,