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