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