aa883d3cf105780bb7f1551e6d33d70787fcd39a
[ira/wip.git] / source3 / rpc_client / cli_lsarpc.c
1 /*
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4    Copyright (C) Tim Potter                        2000-2001,
5    Copyright (C) Andrew Tridgell              1992-1997,2000,
6    Copyright (C) Rafal Szczesniak                       2002
7    Copyright (C) Jeremy Allison                         2005.
8    Copyright (C) Michael Adam                           2007.
9    Copyright (C) Guenther Deschner                      2008.
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "includes.h"
26
27 /** @defgroup lsa LSA - Local Security Architecture
28  *  @ingroup rpc_client
29  *
30  * @{
31  **/
32
33 /**
34  * @file cli_lsarpc.c
35  *
36  * RPC client routines for the LSA RPC pipe.  LSA means "local
37  * security authority", which is half of a password database.
38  **/
39
40 /** Open a LSA policy handle
41  *
42  * @param cli Handle on an initialised SMB connection */
43
44 NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli,
45                                 TALLOC_CTX *mem_ctx,
46                                 bool sec_qos, uint32 des_access,
47                                 struct policy_handle *pol)
48 {
49         struct lsa_ObjectAttribute attr;
50         struct lsa_QosInfo qos;
51         uint16_t system_name = '\\';
52
53         ZERO_STRUCT(attr);
54
55         attr.len        = 0x18;
56
57         if (sec_qos) {
58                 qos.len                 = 0xc;
59                 qos.impersonation_level = 2;
60                 qos.context_mode        = 1;
61                 qos.effective_only      = 0;
62
63                 attr.sec_qos            = &qos;
64         }
65
66         return rpccli_lsa_OpenPolicy(cli, mem_ctx,
67                                      &system_name,
68                                      &attr,
69                                      des_access,
70                                      pol);
71 }
72
73 /** Open a LSA policy handle
74   *
75   * @param cli Handle on an initialised SMB connection
76   */
77
78 NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli,
79                                  TALLOC_CTX *mem_ctx, bool sec_qos,
80                                  uint32 des_access, struct policy_handle *pol)
81 {
82         struct lsa_ObjectAttribute attr;
83         struct lsa_QosInfo qos;
84
85         ZERO_STRUCT(attr);
86
87         attr.len        = 0x18;
88
89         if (sec_qos) {
90                 qos.len                 = 0xc;
91                 qos.impersonation_level = 2;
92                 qos.context_mode        = 1;
93                 qos.effective_only      = 0;
94
95                 attr.sec_qos            = &qos;
96         }
97
98         return rpccli_lsa_OpenPolicy2(cli, mem_ctx,
99                                       cli->srv_name_slash,
100                                       &attr,
101                                       des_access,
102                                       pol);
103 }
104
105 /* Lookup a list of sids
106  *
107  * internal version withOUT memory allocation of the target arrays.
108  * this assumes suffciently sized arrays to store domains, names and types. */
109
110 static NTSTATUS rpccli_lsa_lookup_sids_noalloc(struct rpc_pipe_client *cli,
111                                                TALLOC_CTX *mem_ctx,
112                                                struct policy_handle *pol,
113                                                int num_sids,
114                                                const DOM_SID *sids,
115                                                char **domains,
116                                                char **names,
117                                                enum lsa_SidType *types,
118                                                bool use_lookupsids3)
119 {
120         NTSTATUS result = NT_STATUS_OK;
121         TALLOC_CTX *tmp_ctx = NULL;
122         int i;
123         struct lsa_SidArray sid_array;
124         struct lsa_RefDomainList *ref_domains = NULL;
125         struct lsa_TransNameArray lsa_names;
126         uint32_t count = 0;
127         uint16_t level = 1;
128
129         ZERO_STRUCT(lsa_names);
130
131         tmp_ctx = talloc_new(mem_ctx);
132         if (!tmp_ctx) {
133                 DEBUG(0, ("rpccli_lsa_lookup_sids_noalloc: out of memory!\n"));
134                 result = NT_STATUS_UNSUCCESSFUL;
135                 goto done;
136         }
137
138         sid_array.num_sids = num_sids;
139         sid_array.sids = TALLOC_ARRAY(mem_ctx, struct lsa_SidPtr, num_sids);
140         if (!sid_array.sids) {
141                 return NT_STATUS_NO_MEMORY;
142         }
143
144         for (i = 0; i<num_sids; i++) {
145                 sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sids[i]);
146                 if (!sid_array.sids[i].sid) {
147                         return NT_STATUS_NO_MEMORY;
148                 }
149         }
150
151         if (use_lookupsids3) {
152                 struct lsa_TransNameArray2 lsa_names2;
153                 uint32_t n;
154
155                 result = rpccli_lsa_LookupSids3(cli, mem_ctx,
156                                                 &sid_array,
157                                                 &ref_domains,
158                                                 &lsa_names2,
159                                                 level,
160                                                 &count,
161                                                 0,
162                                                 0);
163
164                 if (!NT_STATUS_IS_ERR(result)) {
165                         lsa_names.count = lsa_names2.count;
166                         lsa_names.names = talloc_array(mem_ctx, struct lsa_TranslatedName, lsa_names.count);
167                         if (!lsa_names.names) {
168                                 return NT_STATUS_NO_MEMORY;
169                         }
170                         for (n=0; n < lsa_names.count; n++) {
171                                 lsa_names.names[n].sid_type     = lsa_names2.names[n].sid_type;
172                                 lsa_names.names[n].name         = lsa_names2.names[n].name;
173                                 lsa_names.names[n].sid_index    = lsa_names2.names[n].sid_index;
174                         }
175                 }
176
177         } else {
178                 result = rpccli_lsa_LookupSids(cli, mem_ctx,
179                                                pol,
180                                                &sid_array,
181                                                &ref_domains,
182                                                &lsa_names,
183                                                level,
184                                                &count);
185         }
186
187         DEBUG(10, ("LSA_LOOKUPSIDS returned '%s', mapped count = %d'\n",
188                    nt_errstr(result), count));
189
190         if (!NT_STATUS_IS_OK(result) &&
191             !NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
192             !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
193         {
194                 /* An actual error occured */
195                 goto done;
196         }
197
198         /* Return output parameters */
199
200         if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
201             (count == 0))
202         {
203                 for (i = 0; i < num_sids; i++) {
204                         (names)[i] = NULL;
205                         (domains)[i] = NULL;
206                         (types)[i] = SID_NAME_UNKNOWN;
207                 }
208                 result = NT_STATUS_NONE_MAPPED;
209                 goto done;
210         }
211
212         for (i = 0; i < num_sids; i++) {
213                 const char *name, *dom_name;
214                 uint32_t dom_idx = lsa_names.names[i].sid_index;
215
216                 /* Translate optimised name through domain index array */
217
218                 if (dom_idx != 0xffffffff) {
219
220                         dom_name = ref_domains->domains[dom_idx].name.string;
221                         name = lsa_names.names[i].name.string;
222
223                         if (name) {
224                                 (names)[i] = talloc_strdup(mem_ctx, name);
225                                 if ((names)[i] == NULL) {
226                                         DEBUG(0, ("cli_lsa_lookup_sids_noalloc(): out of memory\n"));
227                                         result = NT_STATUS_UNSUCCESSFUL;
228                                         goto done;
229                                 }
230                         } else {
231                                 (names)[i] = NULL;
232                         }
233                         (domains)[i] = talloc_strdup(mem_ctx, dom_name);
234                         (types)[i] = lsa_names.names[i].sid_type;
235                         if (((domains)[i] == NULL)) {
236                                 DEBUG(0, ("cli_lsa_lookup_sids_noalloc(): out of memory\n"));
237                                 result = NT_STATUS_UNSUCCESSFUL;
238                                 goto done;
239                         }
240
241                 } else {
242                         (names)[i] = NULL;
243                         (domains)[i] = NULL;
244                         (types)[i] = SID_NAME_UNKNOWN;
245                 }
246         }
247
248 done:
249         TALLOC_FREE(tmp_ctx);
250         return result;
251 }
252
253 /* Lookup a list of sids
254  *
255  * do it the right way: there is a limit (of 20480 for w2k3) entries
256  * returned by this call. when the sids list contains more entries,
257  * empty lists are returned. This version of lsa_lookup_sids passes
258  * the list of sids in hunks of LOOKUP_SIDS_HUNK_SIZE to the lsa call. */
259
260 /* This constant defines the limit of how many sids to look up
261  * in one call (maximum). the limit from the server side is
262  * at 20480 for win2k3, but we keep it at a save 1000 for now. */
263 #define LOOKUP_SIDS_HUNK_SIZE 1000
264
265 static NTSTATUS rpccli_lsa_lookup_sids_generic(struct rpc_pipe_client *cli,
266                                                TALLOC_CTX *mem_ctx,
267                                                struct policy_handle *pol,
268                                                int num_sids,
269                                                const DOM_SID *sids,
270                                                char ***pdomains,
271                                                char ***pnames,
272                                                enum lsa_SidType **ptypes,
273                                                bool use_lookupsids3)
274 {
275         NTSTATUS result = NT_STATUS_OK;
276         int sids_left = 0;
277         int sids_processed = 0;
278         const DOM_SID *hunk_sids = sids;
279         char **hunk_domains;
280         char **hunk_names;
281         enum lsa_SidType *hunk_types;
282         char **domains = NULL;
283         char **names = NULL;
284         enum lsa_SidType *types = NULL;
285
286         if (num_sids) {
287                 if (!(domains = TALLOC_ARRAY(mem_ctx, char *, num_sids))) {
288                         DEBUG(0, ("rpccli_lsa_lookup_sids(): out of memory\n"));
289                         result = NT_STATUS_NO_MEMORY;
290                         goto fail;
291                 }
292
293                 if (!(names = TALLOC_ARRAY(mem_ctx, char *, num_sids))) {
294                         DEBUG(0, ("rpccli_lsa_lookup_sids(): out of memory\n"));
295                         result = NT_STATUS_NO_MEMORY;
296                         goto fail;
297                 }
298
299                 if (!(types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_sids))) {
300                         DEBUG(0, ("rpccli_lsa_lookup_sids(): out of memory\n"));
301                         result = NT_STATUS_NO_MEMORY;
302                         goto fail;
303                 }
304         }
305
306         sids_left = num_sids;
307         hunk_domains = domains;
308         hunk_names = names;
309         hunk_types = types;
310
311         while (sids_left > 0) {
312                 int hunk_num_sids;
313                 NTSTATUS hunk_result = NT_STATUS_OK;
314
315                 hunk_num_sids = ((sids_left > LOOKUP_SIDS_HUNK_SIZE)
316                                 ? LOOKUP_SIDS_HUNK_SIZE
317                                 : sids_left);
318
319                 DEBUG(10, ("rpccli_lsa_lookup_sids: processing items "
320                            "%d -- %d of %d.\n",
321                            sids_processed,
322                            sids_processed + hunk_num_sids - 1,
323                            num_sids));
324
325                 hunk_result = rpccli_lsa_lookup_sids_noalloc(cli,
326                                                              mem_ctx,
327                                                              pol,
328                                                              hunk_num_sids,
329                                                              hunk_sids,
330                                                              hunk_domains,
331                                                              hunk_names,
332                                                              hunk_types,
333                                                              use_lookupsids3);
334
335                 if (!NT_STATUS_IS_OK(hunk_result) &&
336                     !NT_STATUS_EQUAL(hunk_result, STATUS_SOME_UNMAPPED) &&
337                     !NT_STATUS_EQUAL(hunk_result, NT_STATUS_NONE_MAPPED))
338                 {
339                         /* An actual error occured */
340                         result = hunk_result;
341                         goto fail;
342                 }
343
344                 /* adapt overall result */
345                 if (( NT_STATUS_IS_OK(result) &&
346                      !NT_STATUS_IS_OK(hunk_result))
347                     ||
348                     ( NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
349                      !NT_STATUS_EQUAL(hunk_result, NT_STATUS_NONE_MAPPED)))
350                 {
351                         result = STATUS_SOME_UNMAPPED;
352                 }
353
354                 sids_left -= hunk_num_sids;
355                 sids_processed += hunk_num_sids; /* only used in DEBUG */
356                 hunk_sids += hunk_num_sids;
357                 hunk_domains += hunk_num_sids;
358                 hunk_names += hunk_num_sids;
359                 hunk_types += hunk_num_sids;
360         }
361
362         *pdomains = domains;
363         *pnames = names;
364         *ptypes = types;
365         return result;
366
367 fail:
368         TALLOC_FREE(domains);
369         TALLOC_FREE(names);
370         TALLOC_FREE(types);
371         return result;
372 }
373
374 NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli,
375                                 TALLOC_CTX *mem_ctx,
376                                 struct policy_handle *pol,
377                                 int num_sids,
378                                 const DOM_SID *sids,
379                                 char ***pdomains,
380                                 char ***pnames,
381                                 enum lsa_SidType **ptypes)
382 {
383         return rpccli_lsa_lookup_sids_generic(cli, mem_ctx, pol, num_sids, sids,
384                                               pdomains, pnames, ptypes, false);
385 }
386
387 NTSTATUS rpccli_lsa_lookup_sids3(struct rpc_pipe_client *cli,
388                                  TALLOC_CTX *mem_ctx,
389                                  struct policy_handle *pol,
390                                  int num_sids,
391                                  const DOM_SID *sids,
392                                  char ***pdomains,
393                                  char ***pnames,
394                                  enum lsa_SidType **ptypes)
395 {
396         return rpccli_lsa_lookup_sids_generic(cli, mem_ctx, pol, num_sids, sids,
397                                               pdomains, pnames, ptypes, true);
398 }
399
400 /** Lookup a list of names */
401
402 static NTSTATUS rpccli_lsa_lookup_names_generic(struct rpc_pipe_client *cli,
403                                                 TALLOC_CTX *mem_ctx,
404                                                 struct policy_handle *pol, int num_names,
405                                                 const char **names,
406                                                 const char ***dom_names,
407                                                 int level,
408                                                 DOM_SID **sids,
409                                                 enum lsa_SidType **types,
410                                                 bool use_lookupnames4)
411 {
412         NTSTATUS result;
413         int i;
414         struct lsa_String *lsa_names = NULL;
415         struct lsa_RefDomainList *domains = NULL;
416         struct lsa_TransSidArray sid_array;
417         struct lsa_TransSidArray3 sid_array3;
418         uint32_t count = 0;
419
420         ZERO_STRUCT(sid_array);
421         ZERO_STRUCT(sid_array3);
422
423         lsa_names = TALLOC_ARRAY(mem_ctx, struct lsa_String, num_names);
424         if (!lsa_names) {
425                 return NT_STATUS_NO_MEMORY;
426         }
427
428         for (i=0; i<num_names; i++) {
429                 init_lsa_String(&lsa_names[i], names[i]);
430         }
431
432         if (use_lookupnames4) {
433                 result = rpccli_lsa_LookupNames4(cli, mem_ctx,
434                                                  num_names,
435                                                  lsa_names,
436                                                  &domains,
437                                                  &sid_array3,
438                                                  level,
439                                                  &count,
440                                                  0,
441                                                  0);
442         } else {
443                 result = rpccli_lsa_LookupNames(cli, mem_ctx,
444                                                 pol,
445                                                 num_names,
446                                                 lsa_names,
447                                                 &domains,
448                                                 &sid_array,
449                                                 level,
450                                                 &count);
451         }
452
453         if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) !=
454             NT_STATUS_V(STATUS_SOME_UNMAPPED)) {
455
456                 /* An actual error occured */
457
458                 goto done;
459         }
460
461         /* Return output parameters */
462
463         if (count == 0) {
464                 result = NT_STATUS_NONE_MAPPED;
465                 goto done;
466         }
467
468         if (num_names) {
469                 if (!((*sids = TALLOC_ARRAY(mem_ctx, DOM_SID, num_names)))) {
470                         DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
471                         result = NT_STATUS_NO_MEMORY;
472                         goto done;
473                 }
474
475                 if (!((*types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_names)))) {
476                         DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
477                         result = NT_STATUS_NO_MEMORY;
478                         goto done;
479                 }
480
481                 if (dom_names != NULL) {
482                         *dom_names = TALLOC_ARRAY(mem_ctx, const char *, num_names);
483                         if (*dom_names == NULL) {
484                                 DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
485                                 result = NT_STATUS_NO_MEMORY;
486                                 goto done;
487                         }
488                 }
489         } else {
490                 *sids = NULL;
491                 *types = NULL;
492                 if (dom_names != NULL) {
493                         *dom_names = NULL;
494                 }
495         }
496
497         for (i = 0; i < num_names; i++) {
498                 uint32_t dom_idx;
499                 DOM_SID *sid = &(*sids)[i];
500
501                 if (use_lookupnames4) {
502                         dom_idx         = sid_array3.sids[i].sid_index;
503                         (*types)[i]     = sid_array3.sids[i].sid_type;
504                 } else {
505                         dom_idx         = sid_array.sids[i].sid_index;
506                         (*types)[i]     = sid_array.sids[i].sid_type;
507                 }
508
509                 /* Translate optimised sid through domain index array */
510
511                 if (dom_idx == 0xffffffff) {
512                         /* Nothing to do, this is unknown */
513                         ZERO_STRUCTP(sid);
514                         (*types)[i] = SID_NAME_UNKNOWN;
515                         continue;
516                 }
517
518                 if (use_lookupnames4) {
519                         sid_copy(sid, sid_array3.sids[i].sid);
520                 } else {
521                         sid_copy(sid, domains->domains[dom_idx].sid);
522
523                         if (sid_array.sids[i].rid != 0xffffffff) {
524                                 sid_append_rid(sid, sid_array.sids[i].rid);
525                         }
526                 }
527
528                 if (dom_names == NULL) {
529                         continue;
530                 }
531
532                 (*dom_names)[i] = domains->domains[dom_idx].name.string;
533         }
534
535  done:
536
537         return result;
538 }
539
540 NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli,
541                                  TALLOC_CTX *mem_ctx,
542                                  struct policy_handle *pol, int num_names,
543                                  const char **names,
544                                  const char ***dom_names,
545                                  int level,
546                                  DOM_SID **sids,
547                                  enum lsa_SidType **types)
548 {
549         return rpccli_lsa_lookup_names_generic(cli, mem_ctx, pol, num_names,
550                                                names, dom_names, level, sids,
551                                                types, false);
552 }
553
554 NTSTATUS rpccli_lsa_lookup_names4(struct rpc_pipe_client *cli,
555                                   TALLOC_CTX *mem_ctx,
556                                   struct policy_handle *pol, int num_names,
557                                   const char **names,
558                                   const char ***dom_names,
559                                   int level,
560                                   DOM_SID **sids,
561                                   enum lsa_SidType **types)
562 {
563         return rpccli_lsa_lookup_names_generic(cli, mem_ctx, pol, num_names,
564                                                names, dom_names, level, sids,
565                                                types, true);
566 }