r25196: Thanks to id10ts on IRC for finding some typos in my well-known names
[samba.git] / source4 / rpc_server / lsa / lsa_lookup.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the lsarpc pipe
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2007
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "rpc_server/lsa/lsa.h"
24
25 static const struct {
26         const char *domain;
27         const char *name;
28         const char *sid;
29         int rtype;
30 } well_known[] = {
31         {
32                 .name = "EVERYONE",
33                 .sid = SID_WORLD,
34                 .rtype = SID_NAME_WKN_GRP,
35         },
36         {
37                 .name = "CREATOR OWNER",
38                 .sid = SID_CREATOR_OWNER,
39                 .rtype = SID_NAME_WKN_GRP,
40         },
41         {
42                 .name = "CREATOR GROUP",
43                 .sid = SID_CREATOR_GROUP,
44                 .rtype = SID_NAME_WKN_GRP,
45         },
46         {
47                 .domain = "NT AUTHORITY",
48                 .name = "Dialup",
49                 .sid = SID_NT_DIALUP,
50                 .rtype = SID_NAME_WKN_GRP,
51         },
52         {
53                 .domain = "NT AUTHORITY",
54                 .name = "Network",
55                 .sid = SID_NT_NETWORK,
56                 .rtype = SID_NAME_WKN_GRP,
57         },
58         {
59                 .domain = "NT AUTHORITY",
60                 .name = "Batch",
61                 .sid = SID_NT_BATCH,
62                 .rtype = SID_NAME_WKN_GRP,
63         },
64         {
65                 .domain = "NT AUTHORITY",
66                 .name = "Interactive",
67                 .sid = SID_NT_INTERACTIVE,
68                 .rtype = SID_NAME_WKN_GRP,
69         },
70         {
71                 .domain = "NT AUTHORITY",
72                 .name = "Service",
73                 .sid = SID_NT_SERVICE,
74                 .rtype = SID_NAME_WKN_GRP,
75         },
76         {
77                 .domain = "NT AUTHORITY",
78                 .name = "ANONYMOUS LOGON",
79                 .sid = SID_NT_ANONYMOUS,
80                 .rtype = SID_NAME_WKN_GRP,
81         },
82         {
83                 .domain = "NT AUTHORITY",
84                 .name = "Proxy",
85                 .sid = SID_NT_PROXY,
86                 .rtype = SID_NAME_WKN_GRP,
87         },
88         {
89                 .domain = "NT AUTHORITY",
90                 .name = "ServerLogon",
91                 .sid = SID_NT_ENTERPRISE_DCS,
92                 .rtype = SID_NAME_WKN_GRP,
93         },
94         {
95                 .domain = "NT AUTHORITY",
96                 .name = "Self",
97                 .sid = SID_NT_SELF,
98                 .rtype = SID_NAME_WKN_GRP,
99         },
100         {
101                 .domain = "NT AUTHORITY",
102                 .name = "Authenticated Users",
103                 .sid = SID_NT_AUTHENTICATED_USERS,
104                 .rtype = SID_NAME_WKN_GRP,
105         },
106         {
107                 .domain = "NT AUTHORITY",
108                 .name = "Restricted",
109                 .sid = SID_NT_RESTRICTED,
110                 .rtype = SID_NAME_WKN_GRP,
111         },
112         {
113                 .domain = "NT AUTHORITY",
114                 .name = "Termainal Server User",
115                 .sid = SID_NT_TERMINAL_SERVER_USERS,
116                 .rtype = SID_NAME_WKN_GRP,
117         },
118         {
119                 .domain = "NT AUTHORITY",
120                 .name = "Remote Interactive Logon",
121                 .sid = SID_NT_REMOTE_INTERACTIVE,
122                 .rtype = SID_NAME_WKN_GRP,
123         },
124         {
125                 .domain = "NT AUTHORITY",
126                 .name = "This Organization",
127                 .sid = SID_NT_THIS_ORGANISATION,
128                 .rtype = SID_NAME_WKN_GRP,
129         },
130         {
131                 .domain = "NT AUTHORITY",
132                 .name = "SYSTEM",
133                 .sid = SID_NT_SYSTEM,
134                 .rtype = SID_NAME_WKN_GRP,
135         },
136         {
137                 .domain = "NT AUTHORITY",
138                 .name = "Local Service",
139                 .sid = SID_NT_LOCAL_SERVICE,
140                 .rtype = SID_NAME_WKN_GRP,
141         },
142         {
143                 .domain = "NT AUTHORITY",
144                 .name = "Network Service",
145                 .sid = SID_NT_NETWORK_SERVICE,
146                 .rtype = SID_NAME_WKN_GRP,
147         },
148         {
149                 .sid = NULL,
150         }
151 };
152
153 static NTSTATUS lookup_well_known_names(TALLOC_CTX *mem_ctx, const char *domain,
154                                         const char *name, const char **authority_name, 
155                                         struct dom_sid **sid, uint32_t *rtype) 
156 {
157         int i;
158         for (i=0; well_known[i].sid; i++) {
159                 if (domain) {
160                         if (strcasecmp_m(domain, well_known[i].domain) == 0
161                             && strcasecmp_m(name, well_known[i].name) == 0) {
162                                 *authority_name = well_known[i].domain;
163                                 *sid = dom_sid_parse_talloc(mem_ctx, well_known[i].sid);
164                                 *rtype = well_known[i].rtype;
165                                 return NT_STATUS_OK;
166                         }
167                 } else {
168                         if (strcasecmp_m(name, well_known[i].name) == 0) {
169                                 *authority_name = well_known[i].domain;
170                                 *sid = dom_sid_parse_talloc(mem_ctx, well_known[i].sid);
171                                 *rtype = well_known[i].rtype;
172                                 return NT_STATUS_OK;
173                         }
174                 }
175         }
176         return NT_STATUS_NOT_FOUND;     
177 }
178
179 static NTSTATUS lookup_well_known_sids(TALLOC_CTX *mem_ctx, 
180                                        const char *sid_str, const char **authority_name, 
181                                        const char **name, uint32_t *rtype) 
182 {
183         int i;
184         for (i=0; well_known[i].sid; i++) {
185                 if (strcasecmp_m(sid_str, well_known[i].sid) == 0) {
186                         *authority_name = well_known[i].domain;
187                         *name = well_known[i].name;
188                         *rtype = well_known[i].rtype;
189                         return NT_STATUS_OK;
190                 }
191         }
192         return NT_STATUS_NOT_FOUND;     
193 }
194
195 /*
196   lookup a SID for 1 name
197 */
198 static NTSTATUS dcesrv_lsa_lookup_name(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
199                                 const char *name, const char **authority_name, 
200                                 struct dom_sid **sid, enum lsa_SidType *rtype)
201 {
202         int ret, atype, i;
203         struct ldb_message **res;
204         const char * const attrs[] = { "objectSid", "sAMAccountType", NULL};
205         const char *p;
206         const char *domain;
207         const char *username;
208         struct ldb_dn *domain_dn;
209         struct dom_sid *domain_sid;
210         NTSTATUS status;
211
212         p = strchr_m(name, '\\');
213         if (p != NULL) {
214                 domain = talloc_strndup(mem_ctx, name, p-name);
215                 if (!domain) {
216                         return NT_STATUS_NO_MEMORY;
217                 }
218                 username = p + 1;
219         } else if (strchr_m(name, '@')) {
220                 status = crack_name_to_nt4_name(mem_ctx, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username);
221                 if (!NT_STATUS_IS_OK(status)) {
222                         return status;
223                 }
224         } else {
225                 domain = NULL;
226                 username = name;
227         }
228         
229         if (!domain) {
230                 /* Look up table of well known names */
231                 status = lookup_well_known_names(mem_ctx, NULL, username, authority_name, sid, rtype);
232                 if (NT_STATUS_IS_OK(status)) {
233                         return NT_STATUS_OK;
234                 }
235
236                 if (strcasecmp_m(username, NAME_NT_AUTHORITY) == 0) { 
237                         *authority_name = NAME_NT_AUTHORITY;
238                         *sid =  dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
239                         *rtype = SID_NAME_DOMAIN;
240                         return NT_STATUS_OK;
241                 }
242                 if (strcasecmp_m(username, NAME_BUILTIN) == 0) { 
243                         *authority_name = NAME_BUILTIN;
244                         *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN);
245                         *rtype = SID_NAME_DOMAIN;
246                         return NT_STATUS_OK;
247                 }
248                 if (strcasecmp_m(username, state->domain_dns) == 0) { 
249                         *authority_name = state->domain_name;
250                         *sid =  state->domain_sid;
251                         *rtype = SID_NAME_DOMAIN;
252                         return NT_STATUS_OK;
253                 }
254                 if (strcasecmp_m(username, state->domain_name) == 0) { 
255                         *authority_name = state->domain_name;
256                         *sid =  state->domain_sid;
257                         *rtype = SID_NAME_DOMAIN;
258                         return NT_STATUS_OK;
259                 }
260                 
261                 /* Perhaps this is a well known user? */
262                 name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_NT_AUTHORITY, username);
263                 if (!name) {
264                         return NT_STATUS_NO_MEMORY;
265                 }
266                 status = dcesrv_lsa_lookup_name(state, mem_ctx, name, authority_name, sid, rtype);
267                 if (NT_STATUS_IS_OK(status)) {
268                         return status;
269                 }
270
271                 /* Perhaps this is a BUILTIN user? */
272                 name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_BUILTIN, username);
273                 if (!name) {
274                         return NT_STATUS_NO_MEMORY;
275                 }
276                 status = dcesrv_lsa_lookup_name(state, mem_ctx, name, authority_name, sid, rtype);
277                 if (NT_STATUS_IS_OK(status)) {
278                         return status;
279                 }
280
281                 /* OK, I give up - perhaps we need to assume the user is in our domain? */
282                 name = talloc_asprintf(mem_ctx, "%s\\%s", state->domain_name, username);
283                 if (!name) {
284                         return NT_STATUS_NO_MEMORY;
285                 }
286                 status = dcesrv_lsa_lookup_name(state, mem_ctx, name, authority_name, sid, rtype);
287                 if (NT_STATUS_IS_OK(status)) {
288                         return status;
289                 }
290
291                 return STATUS_SOME_UNMAPPED;
292         } else if (strcasecmp_m(domain, NAME_NT_AUTHORITY) == 0) {
293                 if (!*username) {
294                         *authority_name = NAME_NT_AUTHORITY;
295                         *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
296                         *rtype = SID_NAME_DOMAIN;
297                         return NT_STATUS_OK;
298                 }
299
300                 /* Look up table of well known names */
301                 return lookup_well_known_names(mem_ctx, domain, username, authority_name, 
302                                                sid, rtype);
303         } else if (strcasecmp_m(domain, NAME_BUILTIN) == 0) {
304                 *authority_name = NAME_BUILTIN;
305                 domain_dn = state->builtin_dn;
306         } else if (strcasecmp_m(domain, state->domain_dns) == 0) { 
307                 *authority_name = state->domain_name;
308                 domain_dn = state->domain_dn;
309         } else if (strcasecmp_m(domain, state->domain_name) == 0) { 
310                 *authority_name = state->domain_name;
311                 domain_dn = state->domain_dn;
312         } else {
313                 /* Not local, need to ask winbind in future */
314                 return STATUS_SOME_UNMAPPED;
315         }
316
317         ret = gendb_search_dn(state->sam_ldb, mem_ctx, domain_dn, &res, attrs);
318         if (ret == 1) {
319                 domain_sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
320                 if (domain_sid == NULL) {
321                         return NT_STATUS_INVALID_SID;
322                 }
323         } else {
324                 return NT_STATUS_INVALID_SID;
325         }
326
327         if (!*username) {
328                 *sid = domain_sid;
329                 *rtype = SID_NAME_DOMAIN;
330                 return NT_STATUS_OK;
331         }
332         
333         ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, 
334                            "(&(sAMAccountName=%s)(objectSid=*))", 
335                            ldb_binary_encode_string(mem_ctx, username));
336         if (ret == -1) {
337                 return NT_STATUS_INVALID_SID;
338         }
339
340         for (i=0; i < ret; i++) {
341                 *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
342                 if (*sid == NULL) {
343                         return NT_STATUS_INVALID_SID;
344                 }
345
346                 /* Check that this is in the domain */
347                 if (!dom_sid_in_domain(domain_sid, *sid)) {
348                         continue;
349                 }
350
351                 atype = samdb_result_uint(res[i], "sAMAccountType", 0);
352                         
353                 *rtype = samdb_atype_map(atype);
354                 if (*rtype == SID_NAME_UNKNOWN) {
355                         return STATUS_SOME_UNMAPPED;
356                 }
357
358                 return NT_STATUS_OK;
359         }
360
361         /* need to add a call into sidmap to check for a allocated sid */
362
363         return NT_STATUS_INVALID_SID;
364 }
365
366
367 /*
368   add to the lsa_RefDomainList for LookupSids and LookupNames
369 */
370 static NTSTATUS dcesrv_lsa_authority_list(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, 
371                                           enum lsa_SidType rtype,
372                                           const char *authority_name,
373                                           struct dom_sid *sid, 
374                                           struct lsa_RefDomainList *domains,
375                                           uint32_t *sid_index)
376 {
377         struct dom_sid *authority_sid;
378         int i;
379
380         if (rtype != SID_NAME_DOMAIN) {
381                 authority_sid = dom_sid_dup(mem_ctx, sid);
382                 if (authority_sid == NULL) {
383                         return NT_STATUS_NO_MEMORY;
384                 }
385                 authority_sid->num_auths--;
386         } else {
387                 authority_sid = sid;
388         }
389
390         /* see if we've already done this authority name */
391         for (i=0;i<domains->count;i++) {
392                 if (strcasecmp_m(authority_name, domains->domains[i].name.string) == 0) {
393                         *sid_index = i;
394                         return NT_STATUS_OK;
395                 }
396         }
397
398         domains->domains = talloc_realloc(domains, 
399                                           domains->domains,
400                                           struct lsa_DomainInfo,
401                                           domains->count+1);
402         if (domains->domains == NULL) {
403                 return NT_STATUS_NO_MEMORY;
404         }
405         domains->domains[i].name.string = authority_name;
406         domains->domains[i].sid         = authority_sid;
407         domains->count++;
408         domains->max_size = LSA_REF_DOMAIN_LIST_MULTIPLIER * domains->count;
409         *sid_index = i;
410         
411         return NT_STATUS_OK;
412 }
413
414 /*
415   lookup a name for 1 SID
416 */
417 static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
418                                       struct dom_sid *sid, const char *sid_str,
419                                       const char **authority_name, 
420                                       const char **name, enum lsa_SidType *rtype)
421 {
422         NTSTATUS status;
423         int ret;
424         uint32_t atype;
425         struct ldb_message **res;
426         struct ldb_dn *domain_dn;
427         const char * const attrs[] = { "sAMAccountName", "sAMAccountType", "cn", NULL};
428
429         status = lookup_well_known_sids(mem_ctx, sid_str, authority_name, name, rtype);
430         if (NT_STATUS_IS_OK(status)) {
431                 return status;
432         }
433
434         if (dom_sid_in_domain(state->domain_sid, sid)) {
435                 *authority_name = state->domain_name;
436                 domain_dn = state->domain_dn;
437         } else if (dom_sid_in_domain(state->builtin_sid, sid)) {
438                 *authority_name = NAME_BUILTIN;
439                 domain_dn = state->builtin_dn;
440         } else {
441                 /* Not well known, our domain or built in */
442
443                 /* In future, we must look at SID histories, and at trusted domains via winbind */
444
445                 return NT_STATUS_NOT_FOUND;
446         }
447
448         ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, 
449                            "objectSid=%s", ldap_encode_ndr_dom_sid(mem_ctx, sid));
450         if (ret == 1) {
451                 *name = ldb_msg_find_attr_as_string(res[0], "sAMAccountName", NULL);
452                 if (!*name) {
453                         *name = ldb_msg_find_attr_as_string(res[0], "cn", NULL);
454                         if (!*name) {
455                                 *name = talloc_strdup(mem_ctx, sid_str);
456                                 NT_STATUS_HAVE_NO_MEMORY(*name);
457                         }
458                 }
459
460                 atype = samdb_result_uint(res[0], "sAMAccountType", 0);
461
462                 *rtype = samdb_atype_map(atype);
463
464                 return NT_STATUS_OK;
465         }
466
467         /* need to re-add a call into sidmap to check for a allocated sid */
468         /* status = sidmap_allocated_sid_lookup(state->sidmap, mem_ctx, sid, name, rtype); */
469
470         return NT_STATUS_NOT_FOUND;
471 }
472
473
474 /*
475   lsa_LookupSids2
476 */
477 NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call,
478                                 TALLOC_CTX *mem_ctx,
479                                 struct lsa_LookupSids2 *r)
480 {
481         struct lsa_policy_state *state;
482         int i;
483         NTSTATUS status = NT_STATUS_OK;
484
485         r->out.domains = NULL;
486
487         status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state);
488         if (!NT_STATUS_IS_OK(status)) {
489                 return status;
490         }
491
492         r->out.domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
493         if (r->out.domains == NULL) {
494                 return NT_STATUS_NO_MEMORY;
495         }
496
497         r->out.names = talloc_zero(mem_ctx,  struct lsa_TransNameArray2);
498         if (r->out.names == NULL) {
499                 return NT_STATUS_NO_MEMORY;
500         }
501
502         *r->out.count = 0;
503
504         r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName2, 
505                                              r->in.sids->num_sids);
506         if (r->out.names->names == NULL) {
507                 return NT_STATUS_NO_MEMORY;
508         }
509
510         for (i=0;i<r->in.sids->num_sids;i++) {
511                 struct dom_sid *sid = r->in.sids->sids[i].sid;
512                 char *sid_str = dom_sid_string(mem_ctx, sid);
513                 const char *name, *authority_name;
514                 enum lsa_SidType rtype;
515                 uint32_t sid_index;
516                 NTSTATUS status2;
517
518                 r->out.names->count++;
519
520                 r->out.names->names[i].sid_type    = SID_NAME_UNKNOWN;
521                 r->out.names->names[i].name.string = sid_str;
522                 r->out.names->names[i].sid_index   = 0xFFFFFFFF;
523                 r->out.names->names[i].unknown     = 0;
524
525                 if (sid_str == NULL) {
526                         r->out.names->names[i].name.string = "(SIDERROR)";
527                         status = STATUS_SOME_UNMAPPED;
528                         continue;
529                 }
530
531                 status2 = dcesrv_lsa_lookup_sid(state, mem_ctx, sid, sid_str, 
532                                                 &authority_name, &name, &rtype);
533                 if (!NT_STATUS_IS_OK(status2)) {
534                         status = STATUS_SOME_UNMAPPED;
535                         continue;
536                 }
537
538                 /* set up the authority table */
539                 status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, 
540                                                     authority_name, sid, 
541                                                     r->out.domains, &sid_index);
542                 if (!NT_STATUS_IS_OK(status2)) {
543                         return status2;
544                 }
545
546                 r->out.names->names[i].sid_type    = rtype;
547                 r->out.names->names[i].name.string = name;
548                 r->out.names->names[i].sid_index   = sid_index;
549                 r->out.names->names[i].unknown     = 0;
550
551                 (*r->out.count)++;
552         }
553         
554         if (*r->out.count == 0) {
555                 return NT_STATUS_NONE_MAPPED;
556         }
557         if (*r->out.count != r->in.sids->num_sids) {
558                 return STATUS_SOME_UNMAPPED;
559         }
560
561         return NT_STATUS_OK;
562 }
563
564
565 /*
566   lsa_LookupSids3
567
568   Identical to LookupSids2, but doesn't take a policy handle
569   
570 */
571 NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call,
572                                 TALLOC_CTX *mem_ctx,
573                                 struct lsa_LookupSids3 *r)
574 {
575         struct lsa_LookupSids2 r2;
576         struct lsa_OpenPolicy2 pol;
577         NTSTATUS status;
578         struct dcesrv_handle *h;
579
580         /* No policy handle on the wire, so make one up here */
581         r2.in.handle = talloc(mem_ctx, struct policy_handle);
582         if (!r2.in.handle) {
583                 return NT_STATUS_NO_MEMORY;
584         }
585
586         pol.out.handle = r2.in.handle;
587         pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
588         pol.in.attr = NULL;
589         pol.in.system_name = NULL;
590         status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol);
591         if (!NT_STATUS_IS_OK(status)) {
592                 return status;
593         }
594
595         /* ensure this handle goes away at the end of this call */
596         DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY);
597         talloc_steal(mem_ctx, h);
598
599         r2.in.sids     = r->in.sids;
600         r2.in.names    = r->in.names;
601         r2.in.level    = r->in.level;
602         r2.in.count    = r->in.count;
603         r2.in.unknown1 = r->in.unknown1;
604         r2.in.unknown2 = r->in.unknown2;
605         r2.out.count   = r->out.count;
606         r2.out.names   = r->out.names;
607
608         status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2);
609         if (dce_call->fault_code != 0) {
610                 return status;
611         }
612
613         r->out.domains = r2.out.domains;
614         r->out.names   = r2.out.names;
615         r->out.count   = r2.out.count;
616
617         return status;
618 }
619
620
621 /* 
622   lsa_LookupSids 
623 */
624 NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
625                                struct lsa_LookupSids *r)
626 {
627         struct lsa_LookupSids2 r2;
628         NTSTATUS status;
629         int i;
630
631         r2.in.handle   = r->in.handle;
632         r2.in.sids     = r->in.sids;
633         r2.in.names    = NULL;
634         r2.in.level    = r->in.level;
635         r2.in.count    = r->in.count;
636         r2.in.unknown1 = 0;
637         r2.in.unknown2 = 0;
638         r2.out.count   = r->out.count;
639         r2.out.names   = NULL;
640
641         status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2);
642         if (dce_call->fault_code != 0) {
643                 return status;
644         }
645
646         r->out.domains = r2.out.domains;
647         if (!r2.out.names) {
648                 r->out.names = NULL;
649                 return status;
650         }
651
652         r->out.names = talloc(mem_ctx, struct lsa_TransNameArray);
653         if (r->out.names == NULL) {
654                 return NT_STATUS_NO_MEMORY;
655         }
656         r->out.names->count = r2.out.names->count;
657         r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName, 
658                                              r->out.names->count);
659         if (r->out.names->names == NULL) {
660                 return NT_STATUS_NO_MEMORY;
661         }
662         for (i=0;i<r->out.names->count;i++) {
663                 r->out.names->names[i].sid_type    = r2.out.names->names[i].sid_type;
664                 r->out.names->names[i].name.string = r2.out.names->names[i].name.string;
665                 r->out.names->names[i].sid_index   = r2.out.names->names[i].sid_index;
666         }
667
668         return status;
669 }
670
671
672 /*
673   lsa_LookupNames3
674 */
675 NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call,
676                                  TALLOC_CTX *mem_ctx,
677                                  struct lsa_LookupNames3 *r)
678 {
679         struct lsa_policy_state *policy_state;
680         struct dcesrv_handle *policy_handle;
681         int i;
682
683         DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
684
685         policy_state = policy_handle->data;
686
687         r->out.domains = NULL;
688
689         r->out.domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
690         if (r->out.domains == NULL) {
691                 return NT_STATUS_NO_MEMORY;
692         }
693
694         r->out.sids = talloc_zero(mem_ctx,  struct lsa_TransSidArray3);
695         if (r->out.sids == NULL) {
696                 return NT_STATUS_NO_MEMORY;
697         }
698
699         *r->out.count = 0;
700
701         r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid3, 
702                                            r->in.num_names);
703         if (r->out.sids->sids == NULL) {
704                 return NT_STATUS_NO_MEMORY;
705         }
706
707         for (i=0;i<r->in.num_names;i++) {
708                 const char *name = r->in.names[i].string;
709                 const char *authority_name;
710                 struct dom_sid *sid;
711                 uint32_t sid_index;
712                 enum lsa_SidType rtype;
713                 NTSTATUS status2;
714
715                 r->out.sids->count++;
716
717                 r->out.sids->sids[i].sid_type    = SID_NAME_UNKNOWN;
718                 r->out.sids->sids[i].sid         = NULL;
719                 r->out.sids->sids[i].sid_index   = 0xFFFFFFFF;
720                 r->out.sids->sids[i].unknown     = 0;
721
722                 status2 = dcesrv_lsa_lookup_name(policy_state, mem_ctx, name, &authority_name, &sid, &rtype);
723                 if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) {
724                         continue;
725                 }
726
727                 status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, rtype, authority_name, 
728                                                     sid, r->out.domains, &sid_index);
729                 if (!NT_STATUS_IS_OK(status2)) {
730                         return status2;
731                 }
732
733                 r->out.sids->sids[i].sid_type    = rtype;
734                 r->out.sids->sids[i].sid         = sid;
735                 r->out.sids->sids[i].sid_index   = sid_index;
736                 r->out.sids->sids[i].unknown     = 0;
737
738                 (*r->out.count)++;
739         }
740         
741         if (*r->out.count == 0) {
742                 return NT_STATUS_NONE_MAPPED;
743         }
744         if (*r->out.count != r->in.num_names) {
745                 return STATUS_SOME_UNMAPPED;
746         }
747
748         return NT_STATUS_OK;
749 }
750
751 /* 
752   lsa_LookupNames4
753
754   Identical to LookupNames3, but doesn't take a policy handle
755   
756 */
757 NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
758                                  struct lsa_LookupNames4 *r)
759 {
760         struct lsa_LookupNames3 r2;
761         struct lsa_OpenPolicy2 pol;
762         NTSTATUS status;
763         struct dcesrv_handle *h;
764
765         /* No policy handle on the wire, so make one up here */
766         r2.in.handle = talloc(mem_ctx, struct policy_handle);
767         if (!r2.in.handle) {
768                 return NT_STATUS_NO_MEMORY;
769         }
770
771         pol.out.handle = r2.in.handle;
772         pol.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
773         pol.in.attr = NULL;
774         pol.in.system_name = NULL;
775         status = dcesrv_lsa_OpenPolicy2(dce_call, mem_ctx, &pol);
776         if (!NT_STATUS_IS_OK(status)) {
777                 return status;
778         }
779
780         /* ensure this handle goes away at the end of this call */
781         DCESRV_PULL_HANDLE(h, r2.in.handle, LSA_HANDLE_POLICY);
782         talloc_steal(mem_ctx, h);
783
784         r2.in.num_names = r->in.num_names;
785         r2.in.names = r->in.names;
786         r2.in.sids = r->in.sids;
787         r2.in.count = r->in.count;
788         r2.in.unknown1 = r->in.unknown1;
789         r2.in.unknown2 = r->in.unknown2;
790         r2.out.domains = r->out.domains;
791         r2.out.sids = r->out.sids;
792         r2.out.count = r->out.count;
793         
794         status = dcesrv_lsa_LookupNames3(dce_call, mem_ctx, &r2);
795         if (dce_call->fault_code != 0) {
796                 return status;
797         }
798         
799         r->out.domains = r2.out.domains;
800         r->out.sids = r2.out.sids;
801         r->out.count = r2.out.count;
802         return status;
803 }
804
805 /*
806   lsa_LookupNames2
807 */
808 NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call,
809                                  TALLOC_CTX *mem_ctx,
810                                  struct lsa_LookupNames2 *r)
811 {
812         struct lsa_policy_state *state;
813         struct dcesrv_handle *h;
814         int i;
815
816         r->out.domains = NULL;
817
818         DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY);
819
820         state = h->data;
821
822         r->out.domains = talloc_zero(mem_ctx,  struct lsa_RefDomainList);
823         if (r->out.domains == NULL) {
824                 return NT_STATUS_NO_MEMORY;
825         }
826
827         r->out.sids = talloc_zero(mem_ctx,  struct lsa_TransSidArray2);
828         if (r->out.sids == NULL) {
829                 return NT_STATUS_NO_MEMORY;
830         }
831
832         *r->out.count = 0;
833
834         r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid2, 
835                                            r->in.num_names);
836         if (r->out.sids->sids == NULL) {
837                 return NT_STATUS_NO_MEMORY;
838         }
839
840         for (i=0;i<r->in.num_names;i++) {
841                 const char *name = r->in.names[i].string;
842                 const char *authority_name;
843                 struct dom_sid *sid;
844                 uint32_t rtype, sid_index;
845                 NTSTATUS status2;
846
847                 r->out.sids->count++;
848
849                 r->out.sids->sids[i].sid_type    = SID_NAME_UNKNOWN;
850                 r->out.sids->sids[i].rid         = 0xFFFFFFFF;
851                 r->out.sids->sids[i].sid_index   = 0xFFFFFFFF;
852                 r->out.sids->sids[i].unknown     = 0;
853
854                 status2 = dcesrv_lsa_lookup_name(state, mem_ctx, name, 
855                                                  &authority_name, &sid, &rtype);
856                 if (!NT_STATUS_IS_OK(status2)) {
857                         continue;
858                 }
859
860                 status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, authority_name, 
861                                                     sid, r->out.domains, &sid_index);
862                 if (!NT_STATUS_IS_OK(status2)) {
863                         return status2;
864                 }
865
866                 r->out.sids->sids[i].sid_type    = rtype;
867                 r->out.sids->sids[i].rid         = sid->sub_auths[sid->num_auths-1];
868                 r->out.sids->sids[i].sid_index   = sid_index;
869                 r->out.sids->sids[i].unknown     = 0;
870
871                 (*r->out.count)++;
872         }
873         
874         if (*r->out.count == 0) {
875                 return NT_STATUS_NONE_MAPPED;
876         }
877         if (*r->out.count != r->in.num_names) {
878                 return STATUS_SOME_UNMAPPED;
879         }
880
881         return NT_STATUS_OK;
882 }
883
884 /* 
885   lsa_LookupNames 
886 */
887 NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
888                        struct lsa_LookupNames *r)
889 {
890         struct lsa_LookupNames2 r2;
891         NTSTATUS status;
892         int i;
893
894         r2.in.handle    = r->in.handle;
895         r2.in.num_names = r->in.num_names;
896         r2.in.names     = r->in.names;
897         r2.in.sids      = NULL;
898         r2.in.level     = r->in.level;
899         r2.in.count     = r->in.count;
900         r2.in.unknown1  = 0;
901         r2.in.unknown2  = 0;
902         r2.out.count    = r->out.count;
903
904         status = dcesrv_lsa_LookupNames2(dce_call, mem_ctx, &r2);
905         if (dce_call->fault_code != 0) {
906                 return status;
907         }
908
909         r->out.domains = r2.out.domains;
910         r->out.sids = talloc(mem_ctx, struct lsa_TransSidArray);
911         if (r->out.sids == NULL) {
912                 return NT_STATUS_NO_MEMORY;
913         }
914         r->out.sids->count = r2.out.sids->count;
915         r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid, 
916                                            r->out.sids->count);
917         if (r->out.sids->sids == NULL) {
918                 return NT_STATUS_NO_MEMORY;
919         }
920         for (i=0;i<r->out.sids->count;i++) {
921                 r->out.sids->sids[i].sid_type    = r2.out.sids->sids[i].sid_type;
922                 r->out.sids->sids[i].rid         = r2.out.sids->sids[i].rid;
923                 r->out.sids->sids[i].sid_index   = r2.out.sids->sids[i].sid_index;
924         }
925
926         return status;
927 }
928