r17709: Fix cut-n-paste error with the name of gid_to_unix_group_sid().
[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 SID_NAME_USE *ret_type)
37 {
38         char *p;
39         const char *tmp;
40         const char *domain = NULL;
41         const char *name = NULL;
42         uint32 rid;
43         DOM_SID sid;
44         enum SID_NAME_USE type;
45         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
46
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 SID_NAME_USE 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 SID_NAME_USE *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 SID_NAME_USE *types)
397 {
398         int i;
399         const char **my_names;
400         enum SID_NAME_USE *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 SID_NAME_USE **types)
439 {
440         int i;
441
442         *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
443         *types = TALLOC_ARRAY(mem_ctx, enum SID_NAME_USE, 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();
462                 result = pdb_lookup_rids(domain_sid, num_rids, rids,
463                                          *names, *types);
464                 unbecome_root();
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 SID_NAME_USE 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 SID_NAME_USE *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 SID_NAME_USE *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 SID_NAME_USE 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 SID_NAME_USE 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         if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1003                 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1004                 struct uid_sid_cache *pc_next;
1005                 size_t i;
1006
1007                 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1008                         ;
1009                 for(; pc; pc = pc_next) {
1010                         pc_next = pc->next;
1011                         DLIST_REMOVE(uid_sid_cache_head,pc);
1012                         SAFE_FREE(pc);
1013                         n_uid_sid_cache--;
1014                 }
1015         }
1016
1017         pc = SMB_MALLOC_P(struct uid_sid_cache);
1018         if (!pc)
1019                 return;
1020         pc->uid = uid;
1021         sid_copy(&pc->sid, psid);
1022         DLIST_ADD(uid_sid_cache_head, pc);
1023         n_uid_sid_cache++;
1024 }
1025
1026 /*****************************************************************
1027   Find a SID given a gid.
1028 *****************************************************************/  
1029
1030 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1031 {
1032         struct gid_sid_cache *pc;
1033
1034         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1035                 if (pc->gid == gid) {
1036                         *psid = pc->sid;
1037                         DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1038                                  (unsigned int)gid, sid_string_static(psid)));
1039                         DLIST_PROMOTE(gid_sid_cache_head, pc);
1040                         return True;
1041                 }
1042         }
1043         return False;
1044 }
1045
1046 /*****************************************************************
1047   Find a gid given a SID.
1048 *****************************************************************/  
1049
1050 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1051 {
1052         struct gid_sid_cache *pc;
1053
1054         for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1055                 if (sid_compare(&pc->sid, psid) == 0) {
1056                         *pgid = pc->gid;
1057                         DEBUG(3,("fetch gid from cache %u -> %s\n",
1058                                  (unsigned int)*pgid, sid_string_static(psid)));
1059                         DLIST_PROMOTE(gid_sid_cache_head, pc);
1060                         return True;
1061                 }
1062         }
1063         return False;
1064 }
1065
1066 /*****************************************************************
1067  Store gid to SID mapping in cache.
1068 *****************************************************************/  
1069
1070 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1071 {
1072         struct gid_sid_cache *pc;
1073
1074         if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1075                 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1076                 struct gid_sid_cache *pc_next;
1077                 size_t i;
1078
1079                 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1080                         ;
1081                 for(; pc; pc = pc_next) {
1082                         pc_next = pc->next;
1083                         DLIST_REMOVE(gid_sid_cache_head,pc);
1084                         SAFE_FREE(pc);
1085                         n_gid_sid_cache--;
1086                 }
1087         }
1088
1089         pc = SMB_MALLOC_P(struct gid_sid_cache);
1090         if (!pc)
1091                 return;
1092         pc->gid = gid;
1093         sid_copy(&pc->sid, psid);
1094         DLIST_ADD(gid_sid_cache_head, pc);
1095
1096         DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1097                 sid_string_static(psid)));
1098
1099         n_gid_sid_cache++;
1100 }
1101
1102 /*****************************************************************
1103  *THE CANONICAL* convert uid_t to SID function.
1104 *****************************************************************/  
1105
1106 void uid_to_sid(DOM_SID *psid, uid_t uid)
1107 {
1108         uid_t low, high;
1109         uint32 rid;
1110
1111         ZERO_STRUCTP(psid);
1112
1113         if (fetch_sid_from_uid_cache(psid, uid))
1114                 return;
1115
1116         if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) &&
1117             winbind_uid_to_sid(psid, uid)) {
1118
1119                 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
1120                           (unsigned int)uid, sid_string_static(psid)));
1121                 goto done;
1122         }
1123
1124         if (pdb_uid_to_rid(uid, &rid)) {
1125                 /* This is a mapped user */
1126                 sid_copy(psid, get_global_sam_sid());
1127                 sid_append_rid(psid, rid);
1128                 goto done;
1129         }
1130
1131         /* This is an unmapped user */
1132
1133         uid_to_unix_users_sid(uid, psid);
1134
1135  done:
1136         DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
1137                   sid_string_static(psid)));
1138
1139         store_uid_sid_cache(psid, uid);
1140         return;
1141 }
1142
1143 /*****************************************************************
1144  *THE CANONICAL* convert gid_t to SID function.
1145 *****************************************************************/  
1146
1147 void gid_to_sid(DOM_SID *psid, gid_t gid)
1148 {
1149         gid_t low, high;
1150
1151         ZERO_STRUCTP(psid);
1152
1153         if (fetch_sid_from_gid_cache(psid, gid))
1154                 return;
1155
1156         if (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high) &&
1157             winbind_gid_to_sid(psid, gid)) {
1158
1159                 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
1160                           (unsigned int)gid, sid_string_static(psid)));
1161                 goto done;
1162         }
1163
1164         if (pdb_gid_to_sid(gid, psid)) {
1165                 /* This is a mapped group */
1166                 goto done;
1167         }
1168         
1169         /* This is an unmapped group */
1170
1171         gid_to_unix_groups_sid(gid, psid);
1172
1173  done:
1174         DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
1175                   sid_string_static(psid)));
1176
1177         store_gid_sid_cache(psid, gid);
1178         return;
1179 }
1180
1181 /*****************************************************************
1182  *THE CANONICAL* convert SID to uid function.
1183 *****************************************************************/  
1184
1185 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1186 {
1187         enum SID_NAME_USE type;
1188         uint32 rid;
1189         gid_t gid;
1190
1191         if (fetch_uid_from_cache(puid, psid))
1192                 return True;
1193
1194         if (fetch_gid_from_cache(&gid, psid)) {
1195                 return False;
1196         }
1197
1198         if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1199                 uid_t uid = rid;
1200                 *puid = uid;
1201                 goto done;
1202         }
1203
1204         if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1205                 union unid_t id;
1206
1207                 if (pdb_sid_to_id(psid, &id, &type)) {
1208                         if (type != SID_NAME_USER) {
1209                                 DEBUG(5, ("sid %s is a %s, expected a user\n",
1210                                           sid_string_static(psid),
1211                                           sid_type_lookup(type)));
1212                                 return False;
1213                         }
1214                         *puid = id.uid;
1215                         goto done;
1216                 }
1217
1218                 /* This was ours, but it was not mapped.  Fail */
1219
1220                 return False;
1221         }
1222
1223         if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1224
1225                 if (type != SID_NAME_USER) {
1226                         DEBUG(10, ("sid_to_uid: sid %s is a %s\n",
1227                                    sid_string_static(psid),
1228                                    sid_type_lookup(type)));
1229                         return False;
1230                 }
1231
1232                 if (!winbind_sid_to_uid(puid, psid)) {
1233                         DEBUG(5, ("sid_to_uid: winbind failed to allocate a "
1234                                   "new uid for sid %s\n",
1235                                   sid_string_static(psid)));
1236                         return False;
1237                 }
1238                 goto done;
1239         }
1240
1241         /* TODO: Here would be the place to allocate both a gid and a uid for
1242          * the SID in question */
1243
1244         return False;
1245
1246  done:
1247         DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
1248                 (unsigned int)*puid ));
1249
1250         store_uid_sid_cache(psid, *puid);
1251         return True;
1252 }
1253
1254 /*****************************************************************
1255  *THE CANONICAL* convert SID to gid function.
1256  Group mapping is used for gids that maps to Wellknown SIDs
1257 *****************************************************************/  
1258
1259 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1260 {
1261         uint32 rid;
1262         GROUP_MAP map;
1263         union unid_t id;
1264         enum SID_NAME_USE type;
1265         uid_t uid;
1266
1267         if (fetch_gid_from_cache(pgid, psid))
1268                 return True;
1269
1270         if (fetch_uid_from_cache(&uid, psid))
1271                 return False;
1272
1273         if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1274                 gid_t gid = rid;
1275                 *pgid = gid;
1276                 goto done;
1277         }
1278
1279         if ((sid_check_is_in_builtin(psid) ||
1280              sid_check_is_in_wellknown_domain(psid))) {
1281                 if (pdb_getgrsid(&map, *psid)) {
1282                         *pgid = map.gid;
1283                         goto done;
1284                 }
1285                 return False;
1286         }
1287
1288         if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1289                 if (pdb_sid_to_id(psid, &id, &type)) {
1290                         if ((type != SID_NAME_DOM_GRP) &&
1291                             (type != SID_NAME_ALIAS)) {
1292                                 DEBUG(5, ("sid %s is a %s, expected a group\n",
1293                                           sid_string_static(psid),
1294                                           sid_type_lookup(type)));
1295                                 return False;
1296                         }
1297                         *pgid = id.gid;
1298                         goto done;
1299                 }
1300
1301                 /* This was ours, but it was not mapped.  Fail */
1302
1303                 return False;
1304         }
1305         
1306         if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1307                 DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, "
1308                           "then winbind)\n", sid_string_static(psid)));
1309                 
1310                 return False;
1311         }
1312
1313         /* winbindd knows it; Ensure this is a group sid */
1314
1315         if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
1316             (type != SID_NAME_WKN_GRP)) {
1317                 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is "
1318                           "a %s\n", sid_type_lookup(type)));
1319                 return False;
1320         }
1321         
1322         /* winbindd knows it and it is a type of group; sid_to_gid must succeed
1323            or we are dead in the water */
1324
1325         if ( !winbind_sid_to_gid(pgid, psid) ) {
1326                 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid "
1327                           "for sid %s\n", sid_string_static(psid)));
1328                 return False;
1329         }
1330
1331  done:
1332         DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
1333                   (unsigned int)*pgid ));
1334
1335         store_gid_sid_cache(psid, *pgid);
1336         
1337         return True;
1338 }
1339