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