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