d49fa47f57a3cf0b8f4abee6f466134e74202e9a
[samba.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                 ZERO_STRUCT(lsa_names2);
156
157                 result = rpccli_lsa_LookupSids3(cli, mem_ctx,
158                                                 &sid_array,
159                                                 &ref_domains,
160                                                 &lsa_names2,
161                                                 level,
162                                                 &count,
163                                                 0,
164                                                 0);
165
166                 if (!NT_STATUS_IS_ERR(result)) {
167                         lsa_names.count = lsa_names2.count;
168                         lsa_names.names = talloc_array(mem_ctx, struct lsa_TranslatedName, lsa_names.count);
169                         if (!lsa_names.names) {
170                                 return NT_STATUS_NO_MEMORY;
171                         }
172                         for (n=0; n < lsa_names.count; n++) {
173                                 lsa_names.names[n].sid_type     = lsa_names2.names[n].sid_type;
174                                 lsa_names.names[n].name         = lsa_names2.names[n].name;
175                                 lsa_names.names[n].sid_index    = lsa_names2.names[n].sid_index;
176                         }
177                 }
178
179         } else {
180                 result = rpccli_lsa_LookupSids(cli, mem_ctx,
181                                                pol,
182                                                &sid_array,
183                                                &ref_domains,
184                                                &lsa_names,
185                                                level,
186                                                &count);
187         }
188
189         DEBUG(10, ("LSA_LOOKUPSIDS returned '%s', mapped count = %d'\n",
190                    nt_errstr(result), count));
191
192         if (!NT_STATUS_IS_OK(result) &&
193             !NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
194             !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
195         {
196                 /* An actual error occured */
197                 goto done;
198         }
199
200         /* Return output parameters */
201
202         if (NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
203             (count == 0))
204         {
205                 for (i = 0; i < num_sids; i++) {
206                         (names)[i] = NULL;
207                         (domains)[i] = NULL;
208                         (types)[i] = SID_NAME_UNKNOWN;
209                 }
210                 result = NT_STATUS_NONE_MAPPED;
211                 goto done;
212         }
213
214         for (i = 0; i < num_sids; i++) {
215                 const char *name, *dom_name;
216                 uint32_t dom_idx = lsa_names.names[i].sid_index;
217
218                 /* Translate optimised name through domain index array */
219
220                 if (dom_idx != 0xffffffff) {
221
222                         dom_name = ref_domains->domains[dom_idx].name.string;
223                         name = lsa_names.names[i].name.string;
224
225                         if (name) {
226                                 (names)[i] = talloc_strdup(mem_ctx, name);
227                                 if ((names)[i] == NULL) {
228                                         DEBUG(0, ("cli_lsa_lookup_sids_noalloc(): out of memory\n"));
229                                         result = NT_STATUS_UNSUCCESSFUL;
230                                         goto done;
231                                 }
232                         } else {
233                                 (names)[i] = NULL;
234                         }
235                         (domains)[i] = talloc_strdup(mem_ctx, dom_name);
236                         (types)[i] = lsa_names.names[i].sid_type;
237                         if (((domains)[i] == NULL)) {
238                                 DEBUG(0, ("cli_lsa_lookup_sids_noalloc(): out of memory\n"));
239                                 result = NT_STATUS_UNSUCCESSFUL;
240                                 goto done;
241                         }
242
243                 } else {
244                         (names)[i] = NULL;
245                         (domains)[i] = NULL;
246                         (types)[i] = SID_NAME_UNKNOWN;
247                 }
248         }
249
250 done:
251         TALLOC_FREE(tmp_ctx);
252         return result;
253 }
254
255 /* Lookup a list of sids
256  *
257  * do it the right way: there is a limit (of 20480 for w2k3) entries
258  * returned by this call. when the sids list contains more entries,
259  * empty lists are returned. This version of lsa_lookup_sids passes
260  * the list of sids in hunks of LOOKUP_SIDS_HUNK_SIZE to the lsa call. */
261
262 /* This constant defines the limit of how many sids to look up
263  * in one call (maximum). the limit from the server side is
264  * at 20480 for win2k3, but we keep it at a save 1000 for now. */
265 #define LOOKUP_SIDS_HUNK_SIZE 1000
266
267 static NTSTATUS rpccli_lsa_lookup_sids_generic(struct rpc_pipe_client *cli,
268                                                TALLOC_CTX *mem_ctx,
269                                                struct policy_handle *pol,
270                                                int num_sids,
271                                                const DOM_SID *sids,
272                                                char ***pdomains,
273                                                char ***pnames,
274                                                enum lsa_SidType **ptypes,
275                                                bool use_lookupsids3)
276 {
277         NTSTATUS result = NT_STATUS_OK;
278         int sids_left = 0;
279         int sids_processed = 0;
280         const DOM_SID *hunk_sids = sids;
281         char **hunk_domains;
282         char **hunk_names;
283         enum lsa_SidType *hunk_types;
284         char **domains = NULL;
285         char **names = NULL;
286         enum lsa_SidType *types = NULL;
287
288         if (num_sids) {
289                 if (!(domains = TALLOC_ARRAY(mem_ctx, char *, num_sids))) {
290                         DEBUG(0, ("rpccli_lsa_lookup_sids(): out of memory\n"));
291                         result = NT_STATUS_NO_MEMORY;
292                         goto fail;
293                 }
294
295                 if (!(names = TALLOC_ARRAY(mem_ctx, char *, num_sids))) {
296                         DEBUG(0, ("rpccli_lsa_lookup_sids(): out of memory\n"));
297                         result = NT_STATUS_NO_MEMORY;
298                         goto fail;
299                 }
300
301                 if (!(types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_sids))) {
302                         DEBUG(0, ("rpccli_lsa_lookup_sids(): out of memory\n"));
303                         result = NT_STATUS_NO_MEMORY;
304                         goto fail;
305                 }
306         }
307
308         sids_left = num_sids;
309         hunk_domains = domains;
310         hunk_names = names;
311         hunk_types = types;
312
313         while (sids_left > 0) {
314                 int hunk_num_sids;
315                 NTSTATUS hunk_result = NT_STATUS_OK;
316
317                 hunk_num_sids = ((sids_left > LOOKUP_SIDS_HUNK_SIZE)
318                                 ? LOOKUP_SIDS_HUNK_SIZE
319                                 : sids_left);
320
321                 DEBUG(10, ("rpccli_lsa_lookup_sids: processing items "
322                            "%d -- %d of %d.\n",
323                            sids_processed,
324                            sids_processed + hunk_num_sids - 1,
325                            num_sids));
326
327                 hunk_result = rpccli_lsa_lookup_sids_noalloc(cli,
328                                                              mem_ctx,
329                                                              pol,
330                                                              hunk_num_sids,
331                                                              hunk_sids,
332                                                              hunk_domains,
333                                                              hunk_names,
334                                                              hunk_types,
335                                                              use_lookupsids3);
336
337                 if (!NT_STATUS_IS_OK(hunk_result) &&
338                     !NT_STATUS_EQUAL(hunk_result, STATUS_SOME_UNMAPPED) &&
339                     !NT_STATUS_EQUAL(hunk_result, NT_STATUS_NONE_MAPPED))
340                 {
341                         /* An actual error occured */
342                         result = hunk_result;
343                         goto fail;
344                 }
345
346                 /* adapt overall result */
347                 if (( NT_STATUS_IS_OK(result) &&
348                      !NT_STATUS_IS_OK(hunk_result))
349                     ||
350                     ( NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
351                      !NT_STATUS_EQUAL(hunk_result, NT_STATUS_NONE_MAPPED)))
352                 {
353                         result = STATUS_SOME_UNMAPPED;
354                 }
355
356                 sids_left -= hunk_num_sids;
357                 sids_processed += hunk_num_sids; /* only used in DEBUG */
358                 hunk_sids += hunk_num_sids;
359                 hunk_domains += hunk_num_sids;
360                 hunk_names += hunk_num_sids;
361                 hunk_types += hunk_num_sids;
362         }
363
364         *pdomains = domains;
365         *pnames = names;
366         *ptypes = types;
367         return result;
368
369 fail:
370         TALLOC_FREE(domains);
371         TALLOC_FREE(names);
372         TALLOC_FREE(types);
373         return result;
374 }
375
376 NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli,
377                                 TALLOC_CTX *mem_ctx,
378                                 struct policy_handle *pol,
379                                 int num_sids,
380                                 const DOM_SID *sids,
381                                 char ***pdomains,
382                                 char ***pnames,
383                                 enum lsa_SidType **ptypes)
384 {
385         return rpccli_lsa_lookup_sids_generic(cli, mem_ctx, pol, num_sids, sids,
386                                               pdomains, pnames, ptypes, false);
387 }
388
389 NTSTATUS rpccli_lsa_lookup_sids3(struct rpc_pipe_client *cli,
390                                  TALLOC_CTX *mem_ctx,
391                                  struct policy_handle *pol,
392                                  int num_sids,
393                                  const DOM_SID *sids,
394                                  char ***pdomains,
395                                  char ***pnames,
396                                  enum lsa_SidType **ptypes)
397 {
398         return rpccli_lsa_lookup_sids_generic(cli, mem_ctx, pol, num_sids, sids,
399                                               pdomains, pnames, ptypes, true);
400 }
401
402 /** Lookup a list of names */
403
404 static NTSTATUS rpccli_lsa_lookup_names_generic(struct rpc_pipe_client *cli,
405                                                 TALLOC_CTX *mem_ctx,
406                                                 struct policy_handle *pol, int num_names,
407                                                 const char **names,
408                                                 const char ***dom_names,
409                                                 int level,
410                                                 DOM_SID **sids,
411                                                 enum lsa_SidType **types,
412                                                 bool use_lookupnames4)
413 {
414         NTSTATUS result;
415         int i;
416         struct lsa_String *lsa_names = NULL;
417         struct lsa_RefDomainList *domains = NULL;
418         struct lsa_TransSidArray sid_array;
419         struct lsa_TransSidArray3 sid_array3;
420         uint32_t count = 0;
421
422         ZERO_STRUCT(sid_array);
423         ZERO_STRUCT(sid_array3);
424
425         lsa_names = TALLOC_ARRAY(mem_ctx, struct lsa_String, num_names);
426         if (!lsa_names) {
427                 return NT_STATUS_NO_MEMORY;
428         }
429
430         for (i=0; i<num_names; i++) {
431                 init_lsa_String(&lsa_names[i], names[i]);
432         }
433
434         if (use_lookupnames4) {
435                 result = rpccli_lsa_LookupNames4(cli, mem_ctx,
436                                                  num_names,
437                                                  lsa_names,
438                                                  &domains,
439                                                  &sid_array3,
440                                                  level,
441                                                  &count,
442                                                  0,
443                                                  0);
444         } else {
445                 result = rpccli_lsa_LookupNames(cli, mem_ctx,
446                                                 pol,
447                                                 num_names,
448                                                 lsa_names,
449                                                 &domains,
450                                                 &sid_array,
451                                                 level,
452                                                 &count);
453         }
454
455         if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) !=
456             NT_STATUS_V(STATUS_SOME_UNMAPPED)) {
457
458                 /* An actual error occured */
459
460                 goto done;
461         }
462
463         /* Return output parameters */
464
465         if (count == 0) {
466                 result = NT_STATUS_NONE_MAPPED;
467                 goto done;
468         }
469
470         if (num_names) {
471                 if (!((*sids = TALLOC_ARRAY(mem_ctx, DOM_SID, num_names)))) {
472                         DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
473                         result = NT_STATUS_NO_MEMORY;
474                         goto done;
475                 }
476
477                 if (!((*types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_names)))) {
478                         DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
479                         result = NT_STATUS_NO_MEMORY;
480                         goto done;
481                 }
482
483                 if (dom_names != NULL) {
484                         *dom_names = TALLOC_ARRAY(mem_ctx, const char *, num_names);
485                         if (*dom_names == NULL) {
486                                 DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
487                                 result = NT_STATUS_NO_MEMORY;
488                                 goto done;
489                         }
490                 }
491         } else {
492                 *sids = NULL;
493                 *types = NULL;
494                 if (dom_names != NULL) {
495                         *dom_names = NULL;
496                 }
497         }
498
499         for (i = 0; i < num_names; i++) {
500                 uint32_t dom_idx;
501                 DOM_SID *sid = &(*sids)[i];
502
503                 if (use_lookupnames4) {
504                         dom_idx         = sid_array3.sids[i].sid_index;
505                         (*types)[i]     = sid_array3.sids[i].sid_type;
506                 } else {
507                         dom_idx         = sid_array.sids[i].sid_index;
508                         (*types)[i]     = sid_array.sids[i].sid_type;
509                 }
510
511                 /* Translate optimised sid through domain index array */
512
513                 if (dom_idx == 0xffffffff) {
514                         /* Nothing to do, this is unknown */
515                         ZERO_STRUCTP(sid);
516                         (*types)[i] = SID_NAME_UNKNOWN;
517                         continue;
518                 }
519
520                 if (use_lookupnames4) {
521                         sid_copy(sid, sid_array3.sids[i].sid);
522                 } else {
523                         sid_copy(sid, domains->domains[dom_idx].sid);
524
525                         if (sid_array.sids[i].rid != 0xffffffff) {
526                                 sid_append_rid(sid, sid_array.sids[i].rid);
527                         }
528                 }
529
530                 if (dom_names == NULL) {
531                         continue;
532                 }
533
534                 (*dom_names)[i] = domains->domains[dom_idx].name.string;
535         }
536
537  done:
538
539         return result;
540 }
541
542 NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli,
543                                  TALLOC_CTX *mem_ctx,
544                                  struct policy_handle *pol, int num_names,
545                                  const char **names,
546                                  const char ***dom_names,
547                                  int level,
548                                  DOM_SID **sids,
549                                  enum lsa_SidType **types)
550 {
551         return rpccli_lsa_lookup_names_generic(cli, mem_ctx, pol, num_names,
552                                                names, dom_names, level, sids,
553                                                types, false);
554 }
555
556 NTSTATUS rpccli_lsa_lookup_names4(struct rpc_pipe_client *cli,
557                                   TALLOC_CTX *mem_ctx,
558                                   struct policy_handle *pol, int num_names,
559                                   const char **names,
560                                   const char ***dom_names,
561                                   int level,
562                                   DOM_SID **sids,
563                                   enum lsa_SidType **types)
564 {
565         return rpccli_lsa_lookup_names_generic(cli, mem_ctx, pol, num_names,
566                                                names, dom_names, level, sids,
567                                                types, true);
568 }