r17402: Added lookup_name_smbconf() to be called when looking
[nivanova/samba-autobuild/.git] / source3 / passdb / lookup_sid.c
1 /* 
2    Unix SMB/CIFS implementation.
3    uid/user handling
4    Copyright (C) Andrew Tridgell         1992-1998
5    Copyright (C) Gerald (Jerry) Carter   2003
6    Copyright (C) Volker Lendecke         2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /*****************************************************************
26  Dissect a user-provided name into domain, name, sid and type.
27
28  If an explicit domain name was given in the form domain\user, it
29  has to try that. If no explicit domain name was given, we have
30  to do guesswork.
31 *****************************************************************/  
32
33 BOOL lookup_name(TALLOC_CTX *mem_ctx,
34                  const char *full_name, int flags,
35                  const char **ret_domain, const char **ret_name,
36                  DOM_SID *ret_sid, enum SID_NAME_USE *ret_type)
37 {
38         char *p;
39         const char *tmp;
40         const char *domain = NULL;
41         const char *name = NULL;
42         uint32 rid;
43         DOM_SID sid;
44         enum SID_NAME_USE type;
45         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
46         struct group *grp;
47
48         if (tmp_ctx == NULL) {
49                 DEBUG(0, ("talloc_new failed\n"));
50                 return False;
51         }
52
53         p = strchr_m(full_name, '\\');
54
55         if (p != NULL) {
56                 domain = talloc_strndup(tmp_ctx, full_name,
57                                         PTR_DIFF(p, full_name));
58                 name = talloc_strdup(tmp_ctx, p+1);
59         } else {
60                 domain = talloc_strdup(tmp_ctx, "");
61                 name = talloc_strdup(tmp_ctx, full_name);
62         }
63
64         if ((domain == NULL) || (name == NULL)) {
65                 DEBUG(0, ("talloc failed\n"));
66                 TALLOC_FREE(tmp_ctx);
67                 return False;
68         }
69
70         if (strequal(domain, get_global_sam_name())) {
71
72                 /* It's our own domain, lookup the name in passdb */
73                 if (lookup_global_sam_name(name, flags, &rid, &type)) {
74                         sid_copy(&sid, get_global_sam_sid());
75                         sid_append_rid(&sid, rid);
76                         goto ok;
77                 }
78                 TALLOC_FREE(tmp_ctx);
79                 return False;
80         }
81
82         if (strequal(domain, builtin_domain_name())) {
83
84                 /* Explicit request for a name in BUILTIN */
85                 if (lookup_builtin_name(name, &rid)) {
86                         sid_copy(&sid, &global_sid_Builtin);
87                         sid_append_rid(&sid, rid);
88                         type = SID_NAME_ALIAS;
89                         goto ok;
90                 }
91                 TALLOC_FREE(tmp_ctx);
92                 return False;
93         }
94
95         /* Try the explicit winbind lookup first, don't let it guess the
96          * domain yet at this point yet. This comes later. */
97
98         if ((domain[0] != '\0') &&
99             (winbind_lookup_name(domain, name, &sid, &type))) {
100                         goto ok;
101         }
102
103         if (strequal(domain, unix_users_domain_name())) {
104                 if (lookup_unix_user_name(name, &sid)) {
105                         type = SID_NAME_USER;
106                         goto ok;
107                 }
108                 TALLOC_FREE(tmp_ctx);
109                 return False;
110         }
111
112         if (strequal(domain, unix_groups_domain_name())) {
113                 if (lookup_unix_group_name(name, &sid)) {
114                         type = SID_NAME_DOM_GRP;
115                         goto ok;
116                 }
117                 TALLOC_FREE(tmp_ctx);
118                 return False;
119         }
120
121         if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
122                 TALLOC_FREE(tmp_ctx);
123                 return False;
124         }
125
126         /*
127          * Nasty hack necessary for too common scenarios:
128          *
129          * For 'valid users = +users' we know "users" is most probably not
130          * BUILTIN\users but the unix group users. This hack requires the
131          * admin to explicitly qualify BUILTIN if BUILTIN\users is meant.
132          *
133          * Please note that LOOKUP_NAME_GROUP can not be requested via for
134          * example lsa_lookupnames, it only comes into this routine via
135          * the expansion of group names coming in from smb.conf
136          */
137
138         if ((flags & LOOKUP_NAME_GROUP) && ((grp = getgrnam(name)) != NULL)) {
139
140                 GROUP_MAP map;
141
142                 if (pdb_getgrgid(&map, grp->gr_gid)) {
143                         /* The hack gets worse. Handle the case where we have
144                          * 'force group = +unixgroup' but "unixgroup" has a
145                          * group mapping */
146
147                         if (sid_check_is_in_builtin(&map.sid)) {
148                                 domain = talloc_strdup(
149                                         tmp_ctx, builtin_domain_name());
150                         } else {
151                                 domain = talloc_strdup(
152                                         tmp_ctx, get_global_sam_name());
153                         }
154
155                         sid_copy(&sid, &map.sid);
156                         type = map.sid_name_use;
157                         goto ok;
158                 }
159
160                 /* If we are using the smbpasswd backend, we need to use the
161                  * algorithmic mapping for the unix group we find. This is
162                  * necessary because when creating the NT token from the unix
163                  * gid list we got from initgroups() we use gid_to_sid() that
164                  * uses algorithmic mapping if pdb_rid_algorithm() is true. */
165
166                 if (pdb_rid_algorithm() &&
167                     (grp->gr_gid < max_algorithmic_gid())) {
168                         domain = talloc_strdup(tmp_ctx, get_global_sam_name());
169                         sid_compose(&sid, get_global_sam_sid(),
170                                     pdb_gid_to_group_rid(grp->gr_gid));
171                         type = SID_NAME_DOM_GRP;
172                         goto ok;
173                 }
174                 
175                 if (lookup_unix_group_name(name, &sid)) {
176                         domain = talloc_strdup(tmp_ctx,
177                                                unix_groups_domain_name());
178                         type = SID_NAME_DOM_GRP;
179                         goto ok;
180                 }
181         }
182
183         /* Now the guesswork begins, we haven't been given an explicit
184          * domain. Try the sequence as documented on
185          * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
186          * November 27, 2005 */
187
188         /* 1. well-known names */
189
190         if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
191                 type = SID_NAME_WKN_GRP;
192                 goto ok;
193         }
194
195         /* 2. Builtin domain as such */
196
197         if (strequal(name, builtin_domain_name())) {
198                 /* Swap domain and name */
199                 tmp = name; name = domain; domain = tmp;
200                 sid_copy(&sid, &global_sid_Builtin);
201                 type = SID_NAME_DOMAIN;
202                 goto ok;
203         }
204
205         /* 3. Account domain */
206
207         if (strequal(name, get_global_sam_name())) {
208                 if (!secrets_fetch_domain_sid(name, &sid)) {
209                         DEBUG(3, ("Could not fetch my SID\n"));
210                         TALLOC_FREE(tmp_ctx);
211                         return False;
212                 }
213                 /* Swap domain and name */
214                 tmp = name; name = domain; domain = tmp;
215                 type = SID_NAME_DOMAIN;
216                 goto ok;
217         }
218
219         /* 4. Primary domain */
220
221         if (!IS_DC && strequal(name, lp_workgroup())) {
222                 if (!secrets_fetch_domain_sid(name, &sid)) {
223                         DEBUG(3, ("Could not fetch the domain SID\n"));
224                         TALLOC_FREE(tmp_ctx);
225                         return False;
226                 }
227                 /* Swap domain and name */
228                 tmp = name; name = domain; domain = tmp;
229                 type = SID_NAME_DOMAIN;
230                 goto ok;
231         }
232
233         /* 5. Trusted domains as such, to me it looks as if members don't do
234               this, tested an XP workstation in a NT domain -- vl */
235
236         if (IS_DC && (secrets_fetch_trusted_domain_password(name, NULL,
237                                                             &sid, NULL))) {
238                 /* Swap domain and name */
239                 tmp = name; name = domain; domain = tmp;
240                 type = SID_NAME_DOMAIN;
241                 goto ok;
242         }
243
244         /* 6. Builtin aliases */        
245
246         if (lookup_builtin_name(name, &rid)) {
247                 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
248                 sid_copy(&sid, &global_sid_Builtin);
249                 sid_append_rid(&sid, rid);
250                 type = SID_NAME_ALIAS;
251                 goto ok;
252         }
253
254         /* 7. Local systems' SAM (DCs don't have a local SAM) */
255         /* 8. Primary SAM (On members, this is the domain) */
256
257         /* Both cases are done by looking at our passdb */
258
259         if (lookup_global_sam_name(name, flags, &rid, &type)) {
260                 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
261                 sid_copy(&sid, get_global_sam_sid());
262                 sid_append_rid(&sid, rid);
263                 goto ok;
264         }
265
266         /* Now our local possibilities are exhausted. */
267
268         if (!(flags & LOOKUP_NAME_REMOTE)) {
269                 TALLOC_FREE(tmp_ctx);
270                 return False;
271         }
272
273         /* If we are not a DC, we have to ask in our primary domain. Let
274          * winbind do that. */
275
276         if (!IS_DC &&
277             (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
278                 domain = talloc_strdup(tmp_ctx, lp_workgroup());
279                 goto ok;
280         }
281
282         /* 9. Trusted domains */
283
284         /* If we're a DC we have to ask all trusted DC's. Winbind does not do
285          * that (yet), but give it a chance. */
286
287         if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
288                 DOM_SID dom_sid;
289                 uint32 tmp_rid;
290                 enum SID_NAME_USE domain_type;
291                 
292                 if (type == SID_NAME_DOMAIN) {
293                         /* Swap name and type */
294                         tmp = name; name = domain; domain = tmp;
295                         goto ok;
296                 }
297
298                 /* Here we have to cope with a little deficiency in the
299                  * winbind API: We have to ask it again for the name of the
300                  * domain it figured out itself. Maybe fix that later... */
301
302                 sid_copy(&dom_sid, &sid);
303                 sid_split_rid(&dom_sid, &tmp_rid);
304
305                 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
306                                         &domain_type) ||
307                     (domain_type != SID_NAME_DOMAIN)) {
308                         DEBUG(2, ("winbind could not find the domain's name "
309                                   "it just looked up for us\n"));
310                         TALLOC_FREE(tmp_ctx);
311                         return False;
312                 }
313                 goto ok;
314         }
315
316         /* 10. Don't translate */
317
318         /* 11. Ok, windows would end here. Samba has two more options:
319                Unmapped users and unmapped groups */
320
321         if (lookup_unix_user_name(name, &sid)) {
322                 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
323                 type = SID_NAME_USER;
324                 goto ok;
325         }
326
327         if (lookup_unix_group_name(name, &sid)) {
328                 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
329                 type = SID_NAME_DOM_GRP;
330                 goto ok;
331         }
332
333         /*
334          * Ok, all possibilities tried. Fail.
335          */
336
337         TALLOC_FREE(tmp_ctx);
338         return False;
339
340  ok:
341         if ((domain == NULL) || (name == NULL)) {
342                 DEBUG(0, ("talloc failed\n"));
343                 TALLOC_FREE(tmp_ctx);
344                 return False;
345         }
346
347         /*
348          * Hand over the results to the talloc context we've been given.
349          */
350
351         if ((ret_name != NULL) &&
352             !(*ret_name = talloc_strdup(mem_ctx, name))) {
353                 DEBUG(0, ("talloc failed\n"));
354                 TALLOC_FREE(tmp_ctx);
355                 return False;
356         }
357
358         if (ret_domain != NULL) {
359                 char *tmp_dom;
360                 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
361                         DEBUG(0, ("talloc failed\n"));
362                         TALLOC_FREE(tmp_ctx);
363                         return False;
364                 }
365                 strupper_m(tmp_dom);
366                 *ret_domain = tmp_dom;
367         }
368
369         if (ret_sid != NULL) {
370                 sid_copy(ret_sid, &sid);
371         }
372
373         if (ret_type != NULL) {
374                 *ret_type = type;
375         }
376
377         TALLOC_FREE(tmp_ctx);
378         return True;
379 }
380
381 /************************************************************************
382  Names from smb.conf can be unqualified. eg. valid users = foo
383  These names should never map to a remote name. Try lp_workgroup()\foo,
384  and then "Unix Users"\foo (or "Unix Groups"\foo).
385 ************************************************************************/
386
387 BOOL lookup_name_smbconf(TALLOC_CTX *mem_ctx,
388                  const char *full_name, int flags,
389                  const char **ret_domain, const char **ret_name,
390                  DOM_SID *ret_sid, enum SID_NAME_USE *ret_type)
391 {
392         char *qualified_name;
393
394         /* NB. No winbindd_separator here as lookup_name needs \\' */
395         if (strchr_m(full_name, '\\')) {
396                 /* The name is already qualified with a domain. */
397                 return lookup_name(mem_ctx, full_name, flags,
398                                 ret_domain, ret_name,
399                                 ret_sid, ret_type);
400         }
401
402         /* Try with our own domain name. */
403         qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
404                                 lp_workgroup(),
405                                 full_name );
406         if (!qualified_name) {
407                 return False;
408         }
409
410         if (lookup_name(mem_ctx, qualified_name, flags,
411                                 ret_domain, ret_name,
412                                 ret_sid, ret_type)) {
413                 return True;
414         }
415         
416         /* Finally try with "Unix Users" or "Unix Group" */
417         qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
418                                 flags & LOOKUP_NAME_GROUP ?
419                                         unix_groups_domain_name() :
420                                         unix_users_domain_name(),
421                                 full_name );
422         if (!qualified_name) {
423                 return False;
424         }
425
426         return lookup_name(mem_ctx, qualified_name, flags,
427                                 ret_domain, ret_name,
428                                 ret_sid, ret_type);
429 }
430
431 static BOOL wb_lookup_rids(TALLOC_CTX *mem_ctx,
432                            const DOM_SID *domain_sid,
433                            int num_rids, uint32 *rids,
434                            const char **domain_name,
435                            const char **names, enum SID_NAME_USE *types)
436 {
437         int i;
438         const char **my_names;
439         enum SID_NAME_USE *my_types;
440         TALLOC_CTX *tmp_ctx;
441
442         if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
443                 return False;
444         }
445
446         if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
447                                  domain_name, &my_names, &my_types)) {
448                 for (i=0; i<num_rids; i++) {
449                         types[i] = SID_NAME_UNKNOWN;
450                 }
451                 return True;
452         }
453
454         /*
455          * winbind_lookup_rids allocates its own array. We've been given the
456          * array, so copy it over
457          */
458
459         for (i=0; i<num_rids; i++) {
460                 if (my_names[i] == NULL) {
461                         TALLOC_FREE(tmp_ctx);
462                         return False;
463                 }
464                 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
465                         TALLOC_FREE(tmp_ctx);
466                         return False;
467                 }
468                 types[i] = my_types[i];
469         }
470         TALLOC_FREE(tmp_ctx);
471         return True;
472 }
473
474 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
475                         int num_rids, uint32_t *rids,
476                         const char **domain_name,
477                         const char ***names, enum SID_NAME_USE **types)
478 {
479         int i;
480
481         *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
482         *types = TALLOC_ARRAY(mem_ctx, enum SID_NAME_USE, num_rids);
483
484         if ((*names == NULL) || (*types == NULL)) {
485                 return False;
486         }
487
488         if (sid_check_is_domain(domain_sid)) {
489                 NTSTATUS result;
490
491                 if (*domain_name == NULL) {
492                         *domain_name = talloc_strdup(
493                                 mem_ctx, get_global_sam_name());
494                 }
495
496                 if (*domain_name == NULL) {
497                         return False;
498                 }
499
500                 become_root();
501                 result = pdb_lookup_rids(domain_sid, num_rids, rids,
502                                          *names, *types);
503                 unbecome_root();
504
505                 return (NT_STATUS_IS_OK(result) ||
506                         NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
507                         NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
508         }
509
510         if (sid_check_is_builtin(domain_sid)) {
511
512                 if (*domain_name == NULL) {
513                         *domain_name = talloc_strdup(
514                                 mem_ctx, builtin_domain_name());
515                 }
516
517                 if (*domain_name == NULL) {
518                         return False;
519                 }
520
521                 for (i=0; i<num_rids; i++) {
522                         if (lookup_builtin_rid(*names, rids[i],
523                                                &(*names)[i])) {
524                                 if ((*names)[i] == NULL) {
525                                         return False;
526                                 }
527                                 (*types)[i] = SID_NAME_ALIAS;
528                         } else {
529                                 (*types)[i] = SID_NAME_UNKNOWN;
530                         }
531                 }
532                 return True;
533         }
534
535         if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
536                 for (i=0; i<num_rids; i++) {
537                         DOM_SID sid;
538                         sid_copy(&sid, domain_sid);
539                         sid_append_rid(&sid, rids[i]);
540                         if (lookup_wellknown_sid(mem_ctx, &sid,
541                                                  domain_name, &(*names)[i])) {
542                                 if ((*names)[i] == NULL) {
543                                         return False;
544                                 }
545                                 (*types)[i] = SID_NAME_WKN_GRP;
546                         } else {
547                                 (*types)[i] = SID_NAME_UNKNOWN;
548                         }
549                 }
550                 return True;
551         }
552
553         if (sid_check_is_unix_users(domain_sid)) {
554                 if (*domain_name == NULL) {
555                         *domain_name = talloc_strdup(
556                                 mem_ctx, unix_users_domain_name());
557                 }
558                 for (i=0; i<num_rids; i++) {
559                         (*names)[i] = talloc_strdup(
560                                 (*names), uidtoname(rids[i]));
561                         (*types)[i] = SID_NAME_USER;
562                 }
563                 return True;
564         }
565
566         if (sid_check_is_unix_groups(domain_sid)) {
567                 if (*domain_name == NULL) {
568                         *domain_name = talloc_strdup(
569                                 mem_ctx, unix_groups_domain_name());
570                 }
571                 for (i=0; i<num_rids; i++) {
572                         (*names)[i] = talloc_strdup(
573                                 (*names), gidtoname(rids[i]));
574                         (*types)[i] = SID_NAME_DOM_GRP;
575                 }
576                 return True;
577         }
578
579         return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
580                               domain_name, *names, *types);
581 }
582
583 /*
584  * Is the SID a domain as such? If yes, lookup its name.
585  */
586
587 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
588                              const char **name)
589 {
590         const char *tmp;
591         enum SID_NAME_USE type;
592
593         if (sid_check_is_domain(sid)) {
594                 *name = talloc_strdup(mem_ctx, get_global_sam_name());
595                 return True;
596         }
597
598         if (sid_check_is_builtin(sid)) {
599                 *name = talloc_strdup(mem_ctx, builtin_domain_name());
600                 return True;
601         }
602
603         if (sid_check_is_wellknown_domain(sid, &tmp)) {
604                 *name = talloc_strdup(mem_ctx, tmp);
605                 return True;
606         }
607
608         if (sid->num_auths != 4) {
609                 /* This can't be a domain */
610                 return False;
611         }
612
613         if (IS_DC) {
614                 uint32 i, num_domains;
615                 struct trustdom_info **domains;
616
617                 /* This is relatively expensive, but it happens only on DCs
618                  * and for SIDs that have 4 sub-authorities and thus look like
619                  * domains */
620
621                 if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx,
622                                                              &num_domains,
623                                                              &domains))) {
624                         return False;
625                 }
626
627                 for (i=0; i<num_domains; i++) {
628                         if (sid_equal(sid, &domains[i]->sid)) {
629                                 *name = talloc_strdup(mem_ctx,
630                                                       domains[i]->name);
631                                 return True;
632                         }
633                 }
634                 return False;
635         }
636
637         if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
638             (type == SID_NAME_DOMAIN)) {
639                 *name = tmp;
640                 return True;
641         }
642
643         return False;
644 }
645
646 /*
647  * This tries to implement the rather weird rules for the lsa_lookup level
648  * parameter.
649  *
650  * This is as close as we can get to what W2k3 does. With this we survive the
651  * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
652  * different, but I assume that's just being too liberal. For example, W2k3
653  * replies to everything else but the levels 1-6 with INVALID_PARAMETER
654  * whereas NT4 does the same as level 1 (I think). I did not fully test that
655  * with NT4, this is what w2k3 does.
656  *
657  * Level 1: Ask everywhere
658  * Level 2: Ask domain and trusted domains, no builtin and wkn
659  * Level 3: Only ask domain
660  * Level 4: W2k3ad: Only ask AD trusts
661  * Level 5: Don't lookup anything
662  * Level 6: Like 4
663  */
664
665 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
666 {
667         int ret = False;
668
669         switch(level) {
670         case 1:
671                 ret = True;
672                 break;
673         case 2:
674                 ret = (!sid_check_is_builtin(sid) &&
675                        !sid_check_is_wellknown_domain(sid, NULL));
676                 break;
677         case 3:
678         case 4:
679         case 6:
680                 ret = sid_check_is_domain(sid);
681                 break;
682         case 5:
683                 ret = False;
684                 break;
685         }
686
687         DEBUG(10, ("%s SID %s in level %d\n",
688                    ret ? "Accepting" : "Rejecting",
689                    sid_string_static(sid), level));
690         return ret;
691 }
692
693 /*
694  * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
695  * references to domains, it is explicitly made for this.
696  *
697  * This attempts to be as efficient as possible: It collects all SIDs
698  * belonging to a domain and hands them in bulk to the appropriate lookup
699  * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
700  * *hugely* from this. Winbind is going to be extended with a lookup_rids
701  * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
702  * appropriate DC.
703  */
704
705 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
706                      const DOM_SID **sids, int level,
707                      struct lsa_dom_info **ret_domains,
708                      struct lsa_name_info **ret_names)
709 {
710         TALLOC_CTX *tmp_ctx;
711         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
712         struct lsa_name_info *name_infos;
713         struct lsa_dom_info *dom_infos;
714
715         int i, j;
716
717         if (!(tmp_ctx = talloc_new(mem_ctx))) {
718                 DEBUG(0, ("talloc_new failed\n"));
719                 return NT_STATUS_NO_MEMORY;
720         }
721
722         name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
723         dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
724                                       MAX_REF_DOMAINS);
725         if ((name_infos == NULL) || (dom_infos == NULL)) {
726                 result = NT_STATUS_NO_MEMORY;
727                 goto fail;
728         }
729
730         /* First build up the data structures:
731          * 
732          * dom_infos is a list of domains referenced in the list of
733          * SIDs. Later we will walk the list of domains and look up the RIDs
734          * in bulk.
735          *
736          * name_infos is a shadow-copy of the SIDs array to collect the real
737          * data.
738          *
739          * dom_info->idxs is an index into the name_infos array. The
740          * difficulty we have here is that we need to keep the SIDs the client
741          * asked for in the same order for the reply
742          */
743
744         for (i=0; i<num_sids; i++) {
745                 DOM_SID sid;
746                 uint32 rid;
747                 const char *domain_name = NULL;
748
749                 sid_copy(&sid, sids[i]);
750                 name_infos[i].type = SID_NAME_USE_NONE;
751
752                 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
753                         /* We can't push that through the normal lookup
754                          * process, as this would reference illegal
755                          * domains.
756                          *
757                          * For example S-1-5-32 would end up referencing
758                          * domain S-1-5- with RID 32 which is clearly wrong.
759                          */
760                         if (domain_name == NULL) {
761                                 result = NT_STATUS_NO_MEMORY;
762                                 goto fail;
763                         }
764                                 
765                         name_infos[i].rid = 0;
766                         name_infos[i].type = SID_NAME_DOMAIN;
767                         name_infos[i].name = NULL;
768
769                         if (sid_check_is_builtin(&sid)) {
770                                 /* Yes, W2k3 returns "BUILTIN" both as domain
771                                  * and name here */
772                                 name_infos[i].name = talloc_strdup(
773                                         name_infos, builtin_domain_name());
774                                 if (name_infos[i].name == NULL) {
775                                         result = NT_STATUS_NO_MEMORY;
776                                         goto fail;
777                                 }
778                         }
779                 } else {
780                         /* This is a normal SID with rid component */
781                         if (!sid_split_rid(&sid, &rid)) {
782                                 result = NT_STATUS_INVALID_PARAMETER;
783                                 goto fail;
784                         }
785                 }
786
787                 if (!check_dom_sid_to_level(&sid, level)) {
788                         name_infos[i].rid = 0;
789                         name_infos[i].type = SID_NAME_UNKNOWN;
790                         name_infos[i].name = NULL;
791                         continue;
792                 }
793
794                 for (j=0; j<MAX_REF_DOMAINS; j++) {
795                         if (!dom_infos[j].valid) {
796                                 break;
797                         }
798                         if (sid_equal(&sid, &dom_infos[j].sid)) {
799                                 break;
800                         }
801                 }
802
803                 if (j == MAX_REF_DOMAINS) {
804                         /* TODO: What's the right error message here? */
805                         result = NT_STATUS_NONE_MAPPED;
806                         goto fail;
807                 }
808
809                 if (!dom_infos[j].valid) {
810                         /* We found a domain not yet referenced, create a new
811                          * ref. */
812                         dom_infos[j].valid = True;
813                         sid_copy(&dom_infos[j].sid, &sid);
814
815                         if (domain_name != NULL) {
816                                 /* This name was being found above in the case
817                                  * when we found a domain SID */
818                                 dom_infos[j].name =
819                                         talloc_strdup(dom_infos, domain_name);
820                                 if (dom_infos[j].name == NULL) {
821                                         result = NT_STATUS_NO_MEMORY;
822                                         goto fail;
823                                 }
824                         } else {
825                                 /* lookup_rids will take care of this */
826                                 dom_infos[j].name = NULL;
827                         }
828                 }
829
830                 name_infos[i].dom_idx = j;
831
832                 if (name_infos[i].type == SID_NAME_USE_NONE) {
833                         name_infos[i].rid = rid;
834
835                         ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
836                                      &dom_infos[j].num_idxs);
837
838                         if (dom_infos[j].idxs == NULL) {
839                                 result = NT_STATUS_NO_MEMORY;
840                                 goto fail;
841                         }
842                 }
843         }
844
845         /* Iterate over the domains found */
846
847         for (i=0; i<MAX_REF_DOMAINS; i++) {
848                 uint32_t *rids;
849                 const char *domain_name = NULL;
850                 const char **names;
851                 enum SID_NAME_USE *types;
852                 struct lsa_dom_info *dom = &dom_infos[i];
853
854                 if (!dom->valid) {
855                         /* No domains left, we're done */
856                         break;
857                 }
858
859                 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
860                         result = NT_STATUS_NO_MEMORY;
861                         goto fail;
862                 }
863
864                 for (j=0; j<dom->num_idxs; j++) {
865                         rids[j] = name_infos[dom->idxs[j]].rid;
866                 }
867
868                 if (!lookup_rids(tmp_ctx, &dom->sid,
869                                  dom->num_idxs, rids, &domain_name,
870                                  &names, &types)) {
871                         result = NT_STATUS_NO_MEMORY;
872                         goto fail;
873                 }
874
875                 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
876                         result = NT_STATUS_NO_MEMORY;
877                         goto fail;
878                 }
879                         
880                 for (j=0; j<dom->num_idxs; j++) {
881                         int idx = dom->idxs[j];
882                         name_infos[idx].type = types[j];
883                         if (types[j] != SID_NAME_UNKNOWN) {
884                                 name_infos[idx].name =
885                                         talloc_strdup(name_infos, names[j]);
886                                 if (name_infos[idx].name == NULL) {
887                                         result = NT_STATUS_NO_MEMORY;
888                                         goto fail;
889                                 }
890                         } else {
891                                 name_infos[idx].name = NULL;
892                         }
893                 }
894         }
895
896         *ret_domains = dom_infos;
897         *ret_names = name_infos;
898         return NT_STATUS_OK;
899
900  fail:
901         TALLOC_FREE(dom_infos);
902         TALLOC_FREE(name_infos);
903         TALLOC_FREE(tmp_ctx);
904         return result;
905 }
906
907 /*****************************************************************
908  *THE CANONICAL* convert SID to name function.
909 *****************************************************************/  
910
911 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
912                 const char **ret_domain, const char **ret_name,
913                 enum SID_NAME_USE *ret_type)
914 {
915         struct lsa_dom_info *domain;
916         struct lsa_name_info *name;
917         TALLOC_CTX *tmp_ctx;
918         BOOL ret = False;
919
920         if (!(tmp_ctx = talloc_new(mem_ctx))) {
921                 DEBUG(0, ("talloc_new failed\n"));
922                 return False;
923         }
924
925         if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
926                                          &domain, &name))) {
927                 goto done;
928         }
929
930         if (name->type == SID_NAME_UNKNOWN) {
931                 goto done;
932         }
933
934         if ((ret_domain != NULL) &&
935             !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
936                 goto done;
937         }
938
939         if ((ret_name != NULL) && 
940             !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
941                 goto done;
942         }
943
944         if (ret_type != NULL) {
945                 *ret_type = name->type;
946         }
947
948         ret = True;
949
950  done:
951         if (ret) {
952                 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
953                            sid_string_static(sid), domain->name,
954                            name->name, name->type));
955         } else {
956                 DEBUG(10, ("failed to lookup sid %s\n",
957                            sid_string_static(sid)));
958         }
959         TALLOC_FREE(tmp_ctx);
960         return ret;
961 }
962
963 /*****************************************************************
964  Id mapping cache.  This is to avoid Winbind mappings already
965  seen by smbd to be queried too frequently, keeping winbindd
966  busy, and blocking smbd while winbindd is busy with other
967  stuff. Written by Michael Steffens <michael.steffens@hp.com>,
968  modified to use linked lists by jra.
969 *****************************************************************/  
970
971 #define MAX_UID_SID_CACHE_SIZE 100
972 #define TURNOVER_UID_SID_CACHE_SIZE 10
973 #define MAX_GID_SID_CACHE_SIZE 100
974 #define TURNOVER_GID_SID_CACHE_SIZE 10
975
976 static size_t n_uid_sid_cache = 0;
977 static size_t n_gid_sid_cache = 0;
978
979 static struct uid_sid_cache {
980         struct uid_sid_cache *next, *prev;
981         uid_t uid;
982         DOM_SID sid;
983         enum SID_NAME_USE sidtype;
984 } *uid_sid_cache_head;
985
986 static struct gid_sid_cache {
987         struct gid_sid_cache *next, *prev;
988         gid_t gid;
989         DOM_SID sid;
990         enum SID_NAME_USE sidtype;
991 } *gid_sid_cache_head;
992
993 /*****************************************************************
994   Find a SID given a uid.
995 *****************************************************************/  
996
997 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
998 {
999         struct uid_sid_cache *pc;
1000
1001         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
1002                 if (pc->uid == uid) {
1003                         *psid = pc->sid;
1004                         DEBUG(3,("fetch sid from uid cache %u -> %s\n",
1005                                  (unsigned int)uid, sid_string_static(psid)));
1006                         DLIST_PROMOTE(uid_sid_cache_head, pc);
1007                         return True;
1008                 }
1009         }
1010         return False;
1011 }
1012
1013 /*****************************************************************
1014   Find a uid given a SID.
1015 *****************************************************************/  
1016
1017 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
1018 {
1019         struct uid_sid_cache *pc;
1020
1021         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
1022                 if (sid_compare(&pc->sid, psid) == 0) {
1023                         *puid = pc->uid;
1024                         DEBUG(3,("fetch uid from cache %u -> %s\n",
1025                                  (unsigned int)*puid, sid_string_static(psid)));
1026                         DLIST_PROMOTE(uid_sid_cache_head, pc);
1027                         return True;
1028                 }
1029         }
1030         return False;
1031 }
1032
1033 /*****************************************************************
1034  Store uid to SID mapping in cache.
1035 *****************************************************************/  
1036
1037 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1038 {
1039         struct uid_sid_cache *pc;
1040
1041         if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1042                 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1043                 struct uid_sid_cache *pc_next;
1044                 size_t i;
1045
1046                 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1047                         ;
1048                 for(; pc; pc = pc_next) {
1049                         pc_next = pc->next;
1050                         DLIST_REMOVE(uid_sid_cache_head,pc);
1051                         SAFE_FREE(pc);
1052                         n_uid_sid_cache--;
1053                 }
1054         }
1055
1056         pc = SMB_MALLOC_P(struct uid_sid_cache);
1057         if (!pc)
1058                 return;
1059         pc->uid = uid;
1060         sid_copy(&pc->sid, psid);
1061         DLIST_ADD(uid_sid_cache_head, pc);
1062         n_uid_sid_cache++;
1063 }
1064
1065 /*****************************************************************
1066   Find a SID given a gid.
1067 *****************************************************************/  
1068
1069 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1070 {
1071         struct gid_sid_cache *pc;
1072
1073         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1074                 if (pc->gid == gid) {
1075                         *psid = pc->sid;
1076                         DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1077                                  (unsigned int)gid, sid_string_static(psid)));
1078                         DLIST_PROMOTE(gid_sid_cache_head, pc);
1079                         return True;
1080                 }
1081         }
1082         return False;
1083 }
1084
1085 /*****************************************************************
1086   Find a gid given a SID.
1087 *****************************************************************/  
1088
1089 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1090 {
1091         struct gid_sid_cache *pc;
1092
1093         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1094                 if (sid_compare(&pc->sid, psid) == 0) {
1095                         *pgid = pc->gid;
1096                         DEBUG(3,("fetch gid from cache %u -> %s\n",
1097                                  (unsigned int)*pgid, sid_string_static(psid)));
1098                         DLIST_PROMOTE(gid_sid_cache_head, pc);
1099                         return True;
1100                 }
1101         }
1102         return False;
1103 }
1104
1105 /*****************************************************************
1106  Store gid to SID mapping in cache.
1107 *****************************************************************/  
1108
1109 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1110 {
1111         struct gid_sid_cache *pc;
1112
1113         if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1114                 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1115                 struct gid_sid_cache *pc_next;
1116                 size_t i;
1117
1118                 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1119                         ;
1120                 for(; pc; pc = pc_next) {
1121                         pc_next = pc->next;
1122                         DLIST_REMOVE(gid_sid_cache_head,pc);
1123                         SAFE_FREE(pc);
1124                         n_gid_sid_cache--;
1125                 }
1126         }
1127
1128         pc = SMB_MALLOC_P(struct gid_sid_cache);
1129         if (!pc)
1130                 return;
1131         pc->gid = gid;
1132         sid_copy(&pc->sid, psid);
1133         DLIST_ADD(gid_sid_cache_head, pc);
1134
1135         DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1136                 sid_string_static(psid)));
1137
1138         n_gid_sid_cache++;
1139 }
1140
1141 /*****************************************************************
1142  *THE CANONICAL* convert uid_t to SID function.
1143 *****************************************************************/  
1144
1145 void uid_to_sid(DOM_SID *psid, uid_t uid)
1146 {
1147         uid_t low, high;
1148         uint32 rid;
1149
1150         ZERO_STRUCTP(psid);
1151
1152         if (fetch_sid_from_uid_cache(psid, uid))
1153                 return;
1154
1155         if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) &&
1156             winbind_uid_to_sid(psid, uid)) {
1157
1158                 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
1159                           (unsigned int)uid, sid_string_static(psid)));
1160                 goto done;
1161         }
1162
1163         if (pdb_uid_to_rid(uid, &rid)) {
1164                 /* This is a mapped user */
1165                 sid_copy(psid, get_global_sam_sid());
1166                 sid_append_rid(psid, rid);
1167                 goto done;
1168         }
1169
1170         if (pdb_rid_algorithm() && (uid < max_algorithmic_uid())) {
1171                 sid_copy(psid, get_global_sam_sid());
1172                 sid_append_rid(psid, algorithmic_pdb_uid_to_user_rid(uid));
1173                 goto done;
1174         } else {
1175                 uid_to_unix_users_sid(uid, psid);
1176                 goto done;
1177         }
1178
1179  done:
1180         DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
1181                   sid_string_static(psid)));
1182
1183         store_uid_sid_cache(psid, uid);
1184         return;
1185 }
1186
1187 /*****************************************************************
1188  *THE CANONICAL* convert gid_t to SID function.
1189 *****************************************************************/  
1190
1191 void gid_to_sid(DOM_SID *psid, gid_t gid)
1192 {
1193         gid_t low, high;
1194
1195         ZERO_STRUCTP(psid);
1196
1197         if (fetch_sid_from_gid_cache(psid, gid))
1198                 return;
1199
1200         if (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high) &&
1201             winbind_gid_to_sid(psid, gid)) {
1202
1203                 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
1204                           (unsigned int)gid, sid_string_static(psid)));
1205                 goto done;
1206         }
1207
1208         if (pdb_gid_to_sid(gid, psid)) {
1209                 /* This is a mapped group */
1210                 goto done;
1211         }
1212
1213         if (pdb_rid_algorithm() && (gid < max_algorithmic_gid())) {
1214                 sid_copy(psid, get_global_sam_sid());
1215                 sid_append_rid(psid, pdb_gid_to_group_rid(gid));
1216                 goto done;
1217         } else {
1218                 sid_copy(psid, &global_sid_Unix_Groups);
1219                 sid_append_rid(psid, gid);
1220                 goto done;
1221         }
1222
1223  done:
1224         DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
1225                   sid_string_static(psid)));
1226
1227         store_gid_sid_cache(psid, gid);
1228         return;
1229 }
1230
1231 /*****************************************************************
1232  *THE CANONICAL* convert SID to uid function.
1233 *****************************************************************/  
1234
1235 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1236 {
1237         enum SID_NAME_USE type;
1238         uint32 rid;
1239         gid_t gid;
1240
1241         if (fetch_uid_from_cache(puid, psid))
1242                 return True;
1243
1244         if (fetch_gid_from_cache(&gid, psid)) {
1245                 return False;
1246         }
1247
1248         if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1249                 uid_t uid = rid;
1250                 *puid = uid;
1251                 goto done;
1252         }
1253
1254         if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1255                 union unid_t id;
1256
1257                 if (pdb_sid_to_id(psid, &id, &type)) {
1258                         if (type != SID_NAME_USER) {
1259                                 DEBUG(5, ("sid %s is a %s, expected a user\n",
1260                                           sid_string_static(psid),
1261                                           sid_type_lookup(type)));
1262                                 return False;
1263                         }
1264                         *puid = id.uid;
1265                         goto done;
1266                 }
1267                 if (pdb_rid_algorithm() &&
1268                     algorithmic_pdb_rid_is_user(rid)) {
1269                         *puid = algorithmic_pdb_user_rid_to_uid(rid);
1270                         goto done;
1271                 }
1272
1273                 /* This was ours, but it was neither mapped nor
1274                  * algorithmic. Fail */
1275                 return False;
1276         }
1277
1278         if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1279
1280                 if (type != SID_NAME_USER) {
1281                         DEBUG(10, ("sid_to_uid: sid %s is a %s\n",
1282                                    sid_string_static(psid),
1283                                    sid_type_lookup(type)));
1284                         return False;
1285                 }
1286
1287                 if (!winbind_sid_to_uid(puid, psid)) {
1288                         DEBUG(5, ("sid_to_uid: winbind failed to allocate a "
1289                                   "new uid for sid %s\n",
1290                                   sid_string_static(psid)));
1291                         return False;
1292                 }
1293                 goto done;
1294         }
1295
1296         /* TODO: Here would be the place to allocate both a gid and a uid for
1297          * the SID in question */
1298
1299         return False;
1300
1301  done:
1302         DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
1303                 (unsigned int)*puid ));
1304
1305         store_uid_sid_cache(psid, *puid);
1306         return True;
1307 }
1308
1309 /*****************************************************************
1310  *THE CANONICAL* convert SID to gid function.
1311  Group mapping is used for gids that maps to Wellknown SIDs
1312 *****************************************************************/  
1313
1314 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1315 {
1316         uint32 rid;
1317         GROUP_MAP map;
1318         union unid_t id;
1319         enum SID_NAME_USE type;
1320         uid_t uid;
1321
1322         if (fetch_gid_from_cache(pgid, psid))
1323                 return True;
1324
1325         if (fetch_uid_from_cache(&uid, psid))
1326                 return False;
1327
1328         if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1329                 gid_t gid = rid;
1330                 *pgid = gid;
1331                 goto done;
1332         }
1333
1334         if ((sid_check_is_in_builtin(psid) ||
1335              sid_check_is_in_wellknown_domain(psid))) {
1336                 if (pdb_getgrsid(&map, *psid)) {
1337                         *pgid = map.gid;
1338                         goto done;
1339                 }
1340                 return False;
1341         }
1342
1343         if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1344                 if (pdb_sid_to_id(psid, &id, &type)) {
1345                         if ((type != SID_NAME_DOM_GRP) &&
1346                             (type != SID_NAME_ALIAS)) {
1347                                 DEBUG(5, ("sid %s is a %s, expected a group\n",
1348                                           sid_string_static(psid),
1349                                           sid_type_lookup(type)));
1350                                 return False;
1351                         }
1352                         *pgid = id.gid;
1353                         goto done;
1354                 }
1355                 if (pdb_rid_algorithm() &&
1356                     !algorithmic_pdb_rid_is_user(rid)) {
1357                         /* This must be a group, presented as alias */
1358                         *pgid = pdb_group_rid_to_gid(rid);
1359                         goto done;
1360                 }
1361                 /* This was ours, but it was neither mapped nor
1362                  * algorithmic. Fail. */
1363                 return False;
1364         }
1365         
1366         if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1367                 DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, "
1368                           "then winbind)\n", sid_string_static(psid)));
1369                 
1370                 return False;
1371         }
1372
1373         /* winbindd knows it; Ensure this is a group sid */
1374
1375         if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
1376             (type != SID_NAME_WKN_GRP)) {
1377                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is "
1378                           "a %s\n", sid_type_lookup(type)));
1379                 return False;
1380         }
1381         
1382         /* winbindd knows it and it is a type of group; sid_to_gid must succeed
1383            or we are dead in the water */
1384
1385         if ( !winbind_sid_to_gid(pgid, psid) ) {
1386                 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid "
1387                           "for sid %s\n", sid_string_static(psid)));
1388                 return False;
1389         }
1390
1391  done:
1392         DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
1393                   (unsigned int)*pgid ));
1394
1395         store_gid_sid_cache(psid, *pgid);
1396         
1397         return True;
1398 }
1399