r18527: Janitor for Jeremy ;-)
[sfrench/samba-autobuild/.git] / source / 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                 for (i=0; i<num_rids; i++) {
410                         types[i] = SID_NAME_UNKNOWN;
411                 }
412                 return True;
413         }
414
415         /*
416          * winbind_lookup_rids allocates its own array. We've been given the
417          * array, so copy it over
418          */
419
420         for (i=0; i<num_rids; i++) {
421                 if (my_names[i] == NULL) {
422                         TALLOC_FREE(tmp_ctx);
423                         return False;
424                 }
425                 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
426                         TALLOC_FREE(tmp_ctx);
427                         return False;
428                 }
429                 types[i] = my_types[i];
430         }
431         TALLOC_FREE(tmp_ctx);
432         return True;
433 }
434
435 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
436                         int num_rids, uint32_t *rids,
437                         const char **domain_name,
438                         const char ***names, enum lsa_SidType **types)
439 {
440         int i;
441
442         *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
443         *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
444
445         if ((*names == NULL) || (*types == NULL)) {
446                 return False;
447         }
448
449         if (sid_check_is_domain(domain_sid)) {
450                 NTSTATUS result;
451
452                 if (*domain_name == NULL) {
453                         *domain_name = talloc_strdup(
454                                 mem_ctx, get_global_sam_name());
455                 }
456
457                 if (*domain_name == NULL) {
458                         return False;
459                 }
460
461                 become_root_uid_only();
462                 result = pdb_lookup_rids(domain_sid, num_rids, rids,
463                                          *names, *types);
464                 unbecome_root_uid_only();
465
466                 return (NT_STATUS_IS_OK(result) ||
467                         NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
468                         NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
469         }
470
471         if (sid_check_is_builtin(domain_sid)) {
472
473                 if (*domain_name == NULL) {
474                         *domain_name = talloc_strdup(
475                                 mem_ctx, builtin_domain_name());
476                 }
477
478                 if (*domain_name == NULL) {
479                         return False;
480                 }
481
482                 for (i=0; i<num_rids; i++) {
483                         if (lookup_builtin_rid(*names, rids[i],
484                                                &(*names)[i])) {
485                                 if ((*names)[i] == NULL) {
486                                         return False;
487                                 }
488                                 (*types)[i] = SID_NAME_ALIAS;
489                         } else {
490                                 (*types)[i] = SID_NAME_UNKNOWN;
491                         }
492                 }
493                 return True;
494         }
495
496         if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
497                 for (i=0; i<num_rids; i++) {
498                         DOM_SID sid;
499                         sid_copy(&sid, domain_sid);
500                         sid_append_rid(&sid, rids[i]);
501                         if (lookup_wellknown_sid(mem_ctx, &sid,
502                                                  domain_name, &(*names)[i])) {
503                                 if ((*names)[i] == NULL) {
504                                         return False;
505                                 }
506                                 (*types)[i] = SID_NAME_WKN_GRP;
507                         } else {
508                                 (*types)[i] = SID_NAME_UNKNOWN;
509                         }
510                 }
511                 return True;
512         }
513
514         if (sid_check_is_unix_users(domain_sid)) {
515                 if (*domain_name == NULL) {
516                         *domain_name = talloc_strdup(
517                                 mem_ctx, unix_users_domain_name());
518                 }
519                 for (i=0; i<num_rids; i++) {
520                         (*names)[i] = talloc_strdup(
521                                 (*names), uidtoname(rids[i]));
522                         (*types)[i] = SID_NAME_USER;
523                 }
524                 return True;
525         }
526
527         if (sid_check_is_unix_groups(domain_sid)) {
528                 if (*domain_name == NULL) {
529                         *domain_name = talloc_strdup(
530                                 mem_ctx, unix_groups_domain_name());
531                 }
532                 for (i=0; i<num_rids; i++) {
533                         (*names)[i] = talloc_strdup(
534                                 (*names), gidtoname(rids[i]));
535                         (*types)[i] = SID_NAME_DOM_GRP;
536                 }
537                 return True;
538         }
539
540         return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
541                               domain_name, *names, *types);
542 }
543
544 /*
545  * Is the SID a domain as such? If yes, lookup its name.
546  */
547
548 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
549                              const char **name)
550 {
551         const char *tmp;
552         enum lsa_SidType type;
553
554         if (sid_check_is_domain(sid)) {
555                 *name = talloc_strdup(mem_ctx, get_global_sam_name());
556                 return True;
557         }
558
559         if (sid_check_is_builtin(sid)) {
560                 *name = talloc_strdup(mem_ctx, builtin_domain_name());
561                 return True;
562         }
563
564         if (sid_check_is_wellknown_domain(sid, &tmp)) {
565                 *name = talloc_strdup(mem_ctx, tmp);
566                 return True;
567         }
568
569         if (sid->num_auths != 4) {
570                 /* This can't be a domain */
571                 return False;
572         }
573
574         if (IS_DC) {
575                 uint32 i, num_domains;
576                 struct trustdom_info **domains;
577
578                 /* This is relatively expensive, but it happens only on DCs
579                  * and for SIDs that have 4 sub-authorities and thus look like
580                  * domains */
581
582                 if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx,
583                                                              &num_domains,
584                                                              &domains))) {
585                         return False;
586                 }
587
588                 for (i=0; i<num_domains; i++) {
589                         if (sid_equal(sid, &domains[i]->sid)) {
590                                 *name = talloc_strdup(mem_ctx,
591                                                       domains[i]->name);
592                                 return True;
593                         }
594                 }
595                 return False;
596         }
597
598         if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
599             (type == SID_NAME_DOMAIN)) {
600                 *name = tmp;
601                 return True;
602         }
603
604         return False;
605 }
606
607 /*
608  * This tries to implement the rather weird rules for the lsa_lookup level
609  * parameter.
610  *
611  * This is as close as we can get to what W2k3 does. With this we survive the
612  * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
613  * different, but I assume that's just being too liberal. For example, W2k3
614  * replies to everything else but the levels 1-6 with INVALID_PARAMETER
615  * whereas NT4 does the same as level 1 (I think). I did not fully test that
616  * with NT4, this is what w2k3 does.
617  *
618  * Level 1: Ask everywhere
619  * Level 2: Ask domain and trusted domains, no builtin and wkn
620  * Level 3: Only ask domain
621  * Level 4: W2k3ad: Only ask AD trusts
622  * Level 5: Don't lookup anything
623  * Level 6: Like 4
624  */
625
626 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
627 {
628         int ret = False;
629
630         switch(level) {
631         case 1:
632                 ret = True;
633                 break;
634         case 2:
635                 ret = (!sid_check_is_builtin(sid) &&
636                        !sid_check_is_wellknown_domain(sid, NULL));
637                 break;
638         case 3:
639         case 4:
640         case 6:
641                 ret = sid_check_is_domain(sid);
642                 break;
643         case 5:
644                 ret = False;
645                 break;
646         }
647
648         DEBUG(10, ("%s SID %s in level %d\n",
649                    ret ? "Accepting" : "Rejecting",
650                    sid_string_static(sid), level));
651         return ret;
652 }
653
654 /*
655  * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
656  * references to domains, it is explicitly made for this.
657  *
658  * This attempts to be as efficient as possible: It collects all SIDs
659  * belonging to a domain and hands them in bulk to the appropriate lookup
660  * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
661  * *hugely* from this. Winbind is going to be extended with a lookup_rids
662  * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
663  * appropriate DC.
664  */
665
666 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
667                      const DOM_SID **sids, int level,
668                      struct lsa_dom_info **ret_domains,
669                      struct lsa_name_info **ret_names)
670 {
671         TALLOC_CTX *tmp_ctx;
672         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
673         struct lsa_name_info *name_infos;
674         struct lsa_dom_info *dom_infos;
675
676         int i, j;
677
678         if (!(tmp_ctx = talloc_new(mem_ctx))) {
679                 DEBUG(0, ("talloc_new failed\n"));
680                 return NT_STATUS_NO_MEMORY;
681         }
682
683         name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
684         dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
685                                       MAX_REF_DOMAINS);
686         if ((name_infos == NULL) || (dom_infos == NULL)) {
687                 result = NT_STATUS_NO_MEMORY;
688                 goto fail;
689         }
690
691         /* First build up the data structures:
692          * 
693          * dom_infos is a list of domains referenced in the list of
694          * SIDs. Later we will walk the list of domains and look up the RIDs
695          * in bulk.
696          *
697          * name_infos is a shadow-copy of the SIDs array to collect the real
698          * data.
699          *
700          * dom_info->idxs is an index into the name_infos array. The
701          * difficulty we have here is that we need to keep the SIDs the client
702          * asked for in the same order for the reply
703          */
704
705         for (i=0; i<num_sids; i++) {
706                 DOM_SID sid;
707                 uint32 rid;
708                 const char *domain_name = NULL;
709
710                 sid_copy(&sid, sids[i]);
711                 name_infos[i].type = SID_NAME_USE_NONE;
712
713                 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
714                         /* We can't push that through the normal lookup
715                          * process, as this would reference illegal
716                          * domains.
717                          *
718                          * For example S-1-5-32 would end up referencing
719                          * domain S-1-5- with RID 32 which is clearly wrong.
720                          */
721                         if (domain_name == NULL) {
722                                 result = NT_STATUS_NO_MEMORY;
723                                 goto fail;
724                         }
725                                 
726                         name_infos[i].rid = 0;
727                         name_infos[i].type = SID_NAME_DOMAIN;
728                         name_infos[i].name = NULL;
729
730                         if (sid_check_is_builtin(&sid)) {
731                                 /* Yes, W2k3 returns "BUILTIN" both as domain
732                                  * and name here */
733                                 name_infos[i].name = talloc_strdup(
734                                         name_infos, builtin_domain_name());
735                                 if (name_infos[i].name == NULL) {
736                                         result = NT_STATUS_NO_MEMORY;
737                                         goto fail;
738                                 }
739                         }
740                 } else {
741                         /* This is a normal SID with rid component */
742                         if (!sid_split_rid(&sid, &rid)) {
743                                 result = NT_STATUS_INVALID_PARAMETER;
744                                 goto fail;
745                         }
746                 }
747
748                 if (!check_dom_sid_to_level(&sid, level)) {
749                         name_infos[i].rid = 0;
750                         name_infos[i].type = SID_NAME_UNKNOWN;
751                         name_infos[i].name = NULL;
752                         continue;
753                 }
754
755                 for (j=0; j<MAX_REF_DOMAINS; j++) {
756                         if (!dom_infos[j].valid) {
757                                 break;
758                         }
759                         if (sid_equal(&sid, &dom_infos[j].sid)) {
760                                 break;
761                         }
762                 }
763
764                 if (j == MAX_REF_DOMAINS) {
765                         /* TODO: What's the right error message here? */
766                         result = NT_STATUS_NONE_MAPPED;
767                         goto fail;
768                 }
769
770                 if (!dom_infos[j].valid) {
771                         /* We found a domain not yet referenced, create a new
772                          * ref. */
773                         dom_infos[j].valid = True;
774                         sid_copy(&dom_infos[j].sid, &sid);
775
776                         if (domain_name != NULL) {
777                                 /* This name was being found above in the case
778                                  * when we found a domain SID */
779                                 dom_infos[j].name =
780                                         talloc_strdup(dom_infos, domain_name);
781                                 if (dom_infos[j].name == NULL) {
782                                         result = NT_STATUS_NO_MEMORY;
783                                         goto fail;
784                                 }
785                         } else {
786                                 /* lookup_rids will take care of this */
787                                 dom_infos[j].name = NULL;
788                         }
789                 }
790
791                 name_infos[i].dom_idx = j;
792
793                 if (name_infos[i].type == SID_NAME_USE_NONE) {
794                         name_infos[i].rid = rid;
795
796                         ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
797                                      &dom_infos[j].num_idxs);
798
799                         if (dom_infos[j].idxs == NULL) {
800                                 result = NT_STATUS_NO_MEMORY;
801                                 goto fail;
802                         }
803                 }
804         }
805
806         /* Iterate over the domains found */
807
808         for (i=0; i<MAX_REF_DOMAINS; i++) {
809                 uint32_t *rids;
810                 const char *domain_name = NULL;
811                 const char **names;
812                 enum lsa_SidType *types;
813                 struct lsa_dom_info *dom = &dom_infos[i];
814
815                 if (!dom->valid) {
816                         /* No domains left, we're done */
817                         break;
818                 }
819
820                 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
821                         result = NT_STATUS_NO_MEMORY;
822                         goto fail;
823                 }
824
825                 for (j=0; j<dom->num_idxs; j++) {
826                         rids[j] = name_infos[dom->idxs[j]].rid;
827                 }
828
829                 if (!lookup_rids(tmp_ctx, &dom->sid,
830                                  dom->num_idxs, rids, &domain_name,
831                                  &names, &types)) {
832                         result = NT_STATUS_NO_MEMORY;
833                         goto fail;
834                 }
835
836                 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
837                         result = NT_STATUS_NO_MEMORY;
838                         goto fail;
839                 }
840                         
841                 for (j=0; j<dom->num_idxs; j++) {
842                         int idx = dom->idxs[j];
843                         name_infos[idx].type = types[j];
844                         if (types[j] != SID_NAME_UNKNOWN) {
845                                 name_infos[idx].name =
846                                         talloc_strdup(name_infos, names[j]);
847                                 if (name_infos[idx].name == NULL) {
848                                         result = NT_STATUS_NO_MEMORY;
849                                         goto fail;
850                                 }
851                         } else {
852                                 name_infos[idx].name = NULL;
853                         }
854                 }
855         }
856
857         *ret_domains = dom_infos;
858         *ret_names = name_infos;
859         return NT_STATUS_OK;
860
861  fail:
862         TALLOC_FREE(dom_infos);
863         TALLOC_FREE(name_infos);
864         TALLOC_FREE(tmp_ctx);
865         return result;
866 }
867
868 /*****************************************************************
869  *THE CANONICAL* convert SID to name function.
870 *****************************************************************/  
871
872 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
873                 const char **ret_domain, const char **ret_name,
874                 enum lsa_SidType *ret_type)
875 {
876         struct lsa_dom_info *domain;
877         struct lsa_name_info *name;
878         TALLOC_CTX *tmp_ctx;
879         BOOL ret = False;
880
881         if (!(tmp_ctx = talloc_new(mem_ctx))) {
882                 DEBUG(0, ("talloc_new failed\n"));
883                 return False;
884         }
885
886         if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
887                                          &domain, &name))) {
888                 goto done;
889         }
890
891         if (name->type == SID_NAME_UNKNOWN) {
892                 goto done;
893         }
894
895         if ((ret_domain != NULL) &&
896             !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
897                 goto done;
898         }
899
900         if ((ret_name != NULL) && 
901             !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
902                 goto done;
903         }
904
905         if (ret_type != NULL) {
906                 *ret_type = name->type;
907         }
908
909         ret = True;
910
911  done:
912         if (ret) {
913                 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
914                            sid_string_static(sid), domain->name,
915                            name->name, name->type));
916         } else {
917                 DEBUG(10, ("failed to lookup sid %s\n",
918                            sid_string_static(sid)));
919         }
920         TALLOC_FREE(tmp_ctx);
921         return ret;
922 }
923
924 /*****************************************************************
925  Id mapping cache.  This is to avoid Winbind mappings already
926  seen by smbd to be queried too frequently, keeping winbindd
927  busy, and blocking smbd while winbindd is busy with other
928  stuff. Written by Michael Steffens <michael.steffens@hp.com>,
929  modified to use linked lists by jra.
930 *****************************************************************/  
931
932 #define MAX_UID_SID_CACHE_SIZE 100
933 #define TURNOVER_UID_SID_CACHE_SIZE 10
934 #define MAX_GID_SID_CACHE_SIZE 100
935 #define TURNOVER_GID_SID_CACHE_SIZE 10
936
937 static size_t n_uid_sid_cache = 0;
938 static size_t n_gid_sid_cache = 0;
939
940 static struct uid_sid_cache {
941         struct uid_sid_cache *next, *prev;
942         uid_t uid;
943         DOM_SID sid;
944         enum lsa_SidType sidtype;
945 } *uid_sid_cache_head;
946
947 static struct gid_sid_cache {
948         struct gid_sid_cache *next, *prev;
949         gid_t gid;
950         DOM_SID sid;
951         enum lsa_SidType sidtype;
952 } *gid_sid_cache_head;
953
954 /*****************************************************************
955   Find a SID given a uid.
956 *****************************************************************/  
957
958 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
959 {
960         struct uid_sid_cache *pc;
961
962         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
963                 if (pc->uid == uid) {
964                         *psid = pc->sid;
965                         DEBUG(3,("fetch sid from uid cache %u -> %s\n",
966                                  (unsigned int)uid, sid_string_static(psid)));
967                         DLIST_PROMOTE(uid_sid_cache_head, pc);
968                         return True;
969                 }
970         }
971         return False;
972 }
973
974 /*****************************************************************
975   Find a uid given a SID.
976 *****************************************************************/  
977
978 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
979 {
980         struct uid_sid_cache *pc;
981
982         for (pc = uid_sid_cache_head; pc; pc = pc->next) {
983                 if (sid_compare(&pc->sid, psid) == 0) {
984                         *puid = pc->uid;
985                         DEBUG(3,("fetch uid from cache %u -> %s\n",
986                                  (unsigned int)*puid, sid_string_static(psid)));
987                         DLIST_PROMOTE(uid_sid_cache_head, pc);
988                         return True;
989                 }
990         }
991         return False;
992 }
993
994 /*****************************************************************
995  Store uid to SID mapping in cache.
996 *****************************************************************/  
997
998 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
999 {
1000         struct uid_sid_cache *pc;
1001
1002         /* do not store SIDs in the "Unix Group" domain */
1003         
1004         if ( sid_check_is_in_unix_users( psid ) )
1005                 return;
1006
1007         if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1008                 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1009                 struct uid_sid_cache *pc_next;
1010                 size_t i;
1011
1012                 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1013                         ;
1014                 for(; pc; pc = pc_next) {
1015                         pc_next = pc->next;
1016                         DLIST_REMOVE(uid_sid_cache_head,pc);
1017                         SAFE_FREE(pc);
1018                         n_uid_sid_cache--;
1019                 }
1020         }
1021
1022         pc = SMB_MALLOC_P(struct uid_sid_cache);
1023         if (!pc)
1024                 return;
1025         pc->uid = uid;
1026         sid_copy(&pc->sid, psid);
1027         DLIST_ADD(uid_sid_cache_head, pc);
1028         n_uid_sid_cache++;
1029 }
1030
1031 /*****************************************************************
1032   Find a SID given a gid.
1033 *****************************************************************/  
1034
1035 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1036 {
1037         struct gid_sid_cache *pc;
1038
1039         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1040                 if (pc->gid == gid) {
1041                         *psid = pc->sid;
1042                         DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1043                                  (unsigned int)gid, sid_string_static(psid)));
1044                         DLIST_PROMOTE(gid_sid_cache_head, pc);
1045                         return True;
1046                 }
1047         }
1048         return False;
1049 }
1050
1051 /*****************************************************************
1052   Find a gid given a SID.
1053 *****************************************************************/  
1054
1055 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1056 {
1057         struct gid_sid_cache *pc;
1058
1059         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1060                 if (sid_compare(&pc->sid, psid) == 0) {
1061                         *pgid = pc->gid;
1062                         DEBUG(3,("fetch gid from cache %u -> %s\n",
1063                                  (unsigned int)*pgid, sid_string_static(psid)));
1064                         DLIST_PROMOTE(gid_sid_cache_head, pc);
1065                         return True;
1066                 }
1067         }
1068         return False;
1069 }
1070
1071 /*****************************************************************
1072  Store gid to SID mapping in cache.
1073 *****************************************************************/  
1074
1075 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1076 {
1077         struct gid_sid_cache *pc;
1078         
1079         /* do not store SIDs in the "Unix Group" domain */
1080         
1081         if ( sid_check_is_in_unix_groups( psid ) )
1082                 return;
1083
1084         if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1085                 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1086                 struct gid_sid_cache *pc_next;
1087                 size_t i;
1088
1089                 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1090                         ;
1091                 for(; pc; pc = pc_next) {
1092                         pc_next = pc->next;
1093                         DLIST_REMOVE(gid_sid_cache_head,pc);
1094                         SAFE_FREE(pc);
1095                         n_gid_sid_cache--;
1096                 }
1097         }
1098
1099         pc = SMB_MALLOC_P(struct gid_sid_cache);
1100         if (!pc)
1101                 return;
1102         pc->gid = gid;
1103         sid_copy(&pc->sid, psid);
1104         DLIST_ADD(gid_sid_cache_head, pc);
1105
1106         DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1107                 sid_string_static(psid)));
1108
1109         n_gid_sid_cache++;
1110 }
1111
1112 /*****************************************************************
1113  *THE CANONICAL* convert uid_t to SID function.
1114 *****************************************************************/  
1115
1116 void uid_to_sid(DOM_SID *psid, uid_t uid)
1117 {
1118         uid_t low, high;
1119         uint32 rid;
1120         BOOL ret;
1121
1122         ZERO_STRUCTP(psid);
1123
1124         if (fetch_sid_from_uid_cache(psid, uid))
1125                 return;
1126
1127         if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) &&
1128             winbind_uid_to_sid(psid, uid)) {
1129
1130                 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
1131                           (unsigned int)uid, sid_string_static(psid)));
1132                 goto done;
1133         }
1134
1135         become_root_uid_only();
1136         ret = pdb_uid_to_rid(uid, &rid);
1137         unbecome_root_uid_only();
1138
1139         if (ret) {
1140                 /* This is a mapped user */
1141                 sid_copy(psid, get_global_sam_sid());
1142                 sid_append_rid(psid, rid);
1143                 goto done;
1144         }
1145
1146         /* This is an unmapped user */
1147
1148         uid_to_unix_users_sid(uid, psid);
1149
1150  done:
1151         DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
1152                   sid_string_static(psid)));
1153
1154         store_uid_sid_cache(psid, uid);
1155         return;
1156 }
1157
1158 /*****************************************************************
1159  *THE CANONICAL* convert gid_t to SID function.
1160 *****************************************************************/  
1161
1162 void gid_to_sid(DOM_SID *psid, gid_t gid)
1163 {
1164         BOOL ret;
1165         gid_t low, high;
1166
1167         ZERO_STRUCTP(psid);
1168
1169         if (fetch_sid_from_gid_cache(psid, gid))
1170                 return;
1171
1172         if (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high) &&
1173             winbind_gid_to_sid(psid, gid)) {
1174
1175                 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
1176                           (unsigned int)gid, sid_string_static(psid)));
1177                 goto done;
1178         }
1179
1180         become_root_uid_only();
1181         ret = pdb_gid_to_sid(gid, psid);
1182         unbecome_root_uid_only();
1183
1184         if (ret) {
1185                 /* This is a mapped group */
1186                 goto done;
1187         }
1188         
1189         /* This is an unmapped group */
1190
1191         gid_to_unix_groups_sid(gid, psid);
1192
1193  done:
1194         DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
1195                   sid_string_static(psid)));
1196
1197         store_gid_sid_cache(psid, gid);
1198         return;
1199 }
1200
1201 /*****************************************************************
1202  *THE CANONICAL* convert SID to uid function.
1203 *****************************************************************/  
1204
1205 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1206 {
1207         enum lsa_SidType type;
1208         uint32 rid;
1209         gid_t gid;
1210
1211         if (fetch_uid_from_cache(puid, psid))
1212                 return True;
1213
1214         if (fetch_gid_from_cache(&gid, psid)) {
1215                 return False;
1216         }
1217
1218         if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1219                 uid_t uid = rid;
1220                 *puid = uid;
1221                 goto done;
1222         }
1223
1224         if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1225                 union unid_t id;
1226                 BOOL ret;
1227
1228                 become_root_uid_only();
1229                 ret = pdb_sid_to_id(psid, &id, &type);
1230                 unbecome_root_uid_only();
1231
1232                 if (ret) {
1233                         if (type != SID_NAME_USER) {
1234                                 DEBUG(5, ("sid %s is a %s, expected a user\n",
1235                                           sid_string_static(psid),
1236                                           sid_type_lookup(type)));
1237                                 return False;
1238                         }
1239                         *puid = id.uid;
1240                         goto done;
1241                 }
1242
1243                 /* This was ours, but it was not mapped.  Fail */
1244
1245                 return False;
1246         }
1247
1248         if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1249
1250                 if (type != SID_NAME_USER) {
1251                         DEBUG(10, ("sid_to_uid: sid %s is a %s\n",
1252                                    sid_string_static(psid),
1253                                    sid_type_lookup(type)));
1254                         return False;
1255                 }
1256
1257                 if (!winbind_sid_to_uid(puid, psid)) {
1258                         DEBUG(5, ("sid_to_uid: winbind failed to allocate a "
1259                                   "new uid for sid %s\n",
1260                                   sid_string_static(psid)));
1261                         return False;
1262                 }
1263                 goto done;
1264         }
1265
1266         /* TODO: Here would be the place to allocate both a gid and a uid for
1267          * the SID in question */
1268
1269         return False;
1270
1271  done:
1272         DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
1273                 (unsigned int)*puid ));
1274
1275         store_uid_sid_cache(psid, *puid);
1276         return True;
1277 }
1278
1279 /*****************************************************************
1280  *THE CANONICAL* convert SID to gid function.
1281  Group mapping is used for gids that maps to Wellknown SIDs
1282 *****************************************************************/  
1283
1284 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1285 {
1286         uint32 rid;
1287         GROUP_MAP map;
1288         union unid_t id;
1289         enum lsa_SidType type;
1290         uid_t uid;
1291
1292         if (fetch_gid_from_cache(pgid, psid))
1293                 return True;
1294
1295         if (fetch_uid_from_cache(&uid, psid))
1296                 return False;
1297
1298         if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1299                 gid_t gid = rid;
1300                 *pgid = gid;
1301                 goto done;
1302         }
1303
1304         if ((sid_check_is_in_builtin(psid) ||
1305              sid_check_is_in_wellknown_domain(psid))) {
1306                 BOOL ret;
1307
1308                 become_root_uid_only();
1309                 ret = pdb_getgrsid(&map, *psid);
1310                 unbecome_root_uid_only();
1311
1312                 if (ret) {
1313                         *pgid = map.gid;
1314                         goto done;
1315                 }
1316                 return False;
1317         }
1318
1319         if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1320                 BOOL ret;
1321
1322                 become_root_uid_only();
1323                 ret = pdb_sid_to_id(psid, &id, &type);
1324                 unbecome_root_uid_only();
1325
1326                 if (ret) {
1327                         if ((type != SID_NAME_DOM_GRP) &&
1328                             (type != SID_NAME_ALIAS)) {
1329                                 DEBUG(5, ("sid %s is a %s, expected a group\n",
1330                                           sid_string_static(psid),
1331                                           sid_type_lookup(type)));
1332                                 return False;
1333                         }
1334                         *pgid = id.gid;
1335                         goto done;
1336                 }
1337
1338                 /* This was ours, but it was not mapped.  Fail */
1339
1340                 return False;
1341         }
1342         
1343         if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1344                 DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, "
1345                           "then winbind)\n", sid_string_static(psid)));
1346                 
1347                 return False;
1348         }
1349
1350         /* winbindd knows it; Ensure this is a group sid */
1351
1352         if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
1353             (type != SID_NAME_WKN_GRP)) {
1354                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is "
1355                           "a %s\n", sid_type_lookup(type)));
1356                 return False;
1357         }
1358         
1359         /* winbindd knows it and it is a type of group; sid_to_gid must succeed
1360            or we are dead in the water */
1361
1362         if ( !winbind_sid_to_gid(pgid, psid) ) {
1363                 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid "
1364                           "for sid %s\n", sid_string_static(psid)));
1365                 return False;
1366         }
1367
1368  done:
1369         DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
1370                   (unsigned int)*pgid ));
1371
1372         store_gid_sid_cache(psid, *pgid);
1373         
1374         return True;
1375 }
1376