s3-lsa: allow to lookup BUILTIN\ in lsa_LookupNames.
[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                 if (strlen(name) == 0) {
90                         /* Swap domain and name */
91                         tmp = name; name = domain; domain = tmp;
92                         sid_copy(&sid, &global_sid_Builtin);
93                         type = SID_NAME_DOMAIN;
94                         goto ok;
95                 }
96
97                 /* Explicit request for a name in BUILTIN */
98                 if (lookup_builtin_name(name, &rid)) {
99                         sid_copy(&sid, &global_sid_Builtin);
100                         sid_append_rid(&sid, rid);
101                         type = SID_NAME_ALIAS;
102                         goto ok;
103                 }
104                 TALLOC_FREE(tmp_ctx);
105                 return false;
106         }
107
108         /* Try the explicit winbind lookup first, don't let it guess the
109          * domain yet at this point yet. This comes later. */
110
111         if ((domain[0] != '\0') &&
112             (flags & ~(LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED)) &&
113             (winbind_lookup_name(domain, name, &sid, &type))) {
114                         goto ok;
115         }
116
117         if (((flags & LOOKUP_NAME_NO_NSS) == 0)
118             && strequal(domain, unix_users_domain_name())) {
119                 if (lookup_unix_user_name(name, &sid)) {
120                         type = SID_NAME_USER;
121                         goto ok;
122                 }
123                 TALLOC_FREE(tmp_ctx);
124                 return false;
125         }
126
127         if (((flags & LOOKUP_NAME_NO_NSS) == 0)
128             && strequal(domain, unix_groups_domain_name())) {
129                 if (lookup_unix_group_name(name, &sid)) {
130                         type = SID_NAME_DOM_GRP;
131                         goto ok;
132                 }
133                 TALLOC_FREE(tmp_ctx);
134                 return false;
135         }
136
137         if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
138                 TALLOC_FREE(tmp_ctx);
139                 return false;
140         }
141
142         /* Now the guesswork begins, we haven't been given an explicit
143          * domain. Try the sequence as documented on
144          * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
145          * November 27, 2005 */
146
147         /* 1. well-known names */
148
149         if ((flags & LOOKUP_NAME_WKN) &&
150             lookup_wellknown_name(tmp_ctx, name, &sid, &domain))
151         {
152                 type = SID_NAME_WKN_GRP;
153                 goto ok;
154         }
155
156         /* 2. Builtin domain as such */
157
158         if ((flags & (LOOKUP_NAME_BUILTIN|LOOKUP_NAME_REMOTE)) &&
159             strequal(name, builtin_domain_name()))
160         {
161                 /* Swap domain and name */
162                 tmp = name; name = domain; domain = tmp;
163                 sid_copy(&sid, &global_sid_Builtin);
164                 type = SID_NAME_DOMAIN;
165                 goto ok;
166         }
167
168         /* 3. Account domain */
169
170         if ((flags & LOOKUP_NAME_DOMAIN) &&
171             strequal(name, get_global_sam_name()))
172         {
173                 if (!secrets_fetch_domain_sid(name, &sid)) {
174                         DEBUG(3, ("Could not fetch my SID\n"));
175                         TALLOC_FREE(tmp_ctx);
176                         return false;
177                 }
178                 /* Swap domain and name */
179                 tmp = name; name = domain; domain = tmp;
180                 type = SID_NAME_DOMAIN;
181                 goto ok;
182         }
183
184         /* 4. Primary domain */
185
186         if ((flags & LOOKUP_NAME_DOMAIN) && !IS_DC &&
187             strequal(name, lp_workgroup()))
188         {
189                 if (!secrets_fetch_domain_sid(name, &sid)) {
190                         DEBUG(3, ("Could not fetch the domain SID\n"));
191                         TALLOC_FREE(tmp_ctx);
192                         return false;
193                 }
194                 /* Swap domain and name */
195                 tmp = name; name = domain; domain = tmp;
196                 type = SID_NAME_DOMAIN;
197                 goto ok;
198         }
199
200         /* 5. Trusted domains as such, to me it looks as if members don't do
201               this, tested an XP workstation in a NT domain -- vl */
202
203         if ((flags & LOOKUP_NAME_REMOTE) && IS_DC &&
204             (pdb_get_trusteddom_pw(name, NULL, &sid, NULL)))
205         {
206                 /* Swap domain and name */
207                 tmp = name; name = domain; domain = tmp;
208                 type = SID_NAME_DOMAIN;
209                 goto ok;
210         }
211
212         /* 6. Builtin aliases */        
213
214         if ((flags & LOOKUP_NAME_BUILTIN) &&
215             lookup_builtin_name(name, &rid))
216         {
217                 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
218                 sid_copy(&sid, &global_sid_Builtin);
219                 sid_append_rid(&sid, rid);
220                 type = SID_NAME_ALIAS;
221                 goto ok;
222         }
223
224         /* 7. Local systems' SAM (DCs don't have a local SAM) */
225         /* 8. Primary SAM (On members, this is the domain) */
226
227         /* Both cases are done by looking at our passdb */
228
229         if ((flags & LOOKUP_NAME_DOMAIN) &&
230             lookup_global_sam_name(name, flags, &rid, &type))
231         {
232                 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
233                 sid_copy(&sid, get_global_sam_sid());
234                 sid_append_rid(&sid, rid);
235                 goto ok;
236         }
237
238         /* Now our local possibilities are exhausted. */
239
240         if (!(flags & LOOKUP_NAME_REMOTE)) {
241                 TALLOC_FREE(tmp_ctx);
242                 return false;
243         }
244
245         /* If we are not a DC, we have to ask in our primary domain. Let
246          * winbind do that. */
247
248         if (!IS_DC &&
249             (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
250                 domain = talloc_strdup(tmp_ctx, lp_workgroup());
251                 goto ok;
252         }
253
254         /* 9. Trusted domains */
255
256         /* If we're a DC we have to ask all trusted DC's. Winbind does not do
257          * that (yet), but give it a chance. */
258
259         if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
260                 DOM_SID dom_sid;
261                 uint32 tmp_rid;
262                 enum lsa_SidType domain_type;
263                 
264                 if (type == SID_NAME_DOMAIN) {
265                         /* Swap name and type */
266                         tmp = name; name = domain; domain = tmp;
267                         goto ok;
268                 }
269
270                 /* Here we have to cope with a little deficiency in the
271                  * winbind API: We have to ask it again for the name of the
272                  * domain it figured out itself. Maybe fix that later... */
273
274                 sid_copy(&dom_sid, &sid);
275                 sid_split_rid(&dom_sid, &tmp_rid);
276
277                 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
278                                         &domain_type) ||
279                     (domain_type != SID_NAME_DOMAIN)) {
280                         DEBUG(2, ("winbind could not find the domain's name "
281                                   "it just looked up for us\n"));
282                         TALLOC_FREE(tmp_ctx);
283                         return false;
284                 }
285                 goto ok;
286         }
287
288         /* 10. Don't translate */
289
290         /* 11. Ok, windows would end here. Samba has two more options:
291                Unmapped users and unmapped groups */
292
293         if (((flags & LOOKUP_NAME_NO_NSS) == 0)
294             && lookup_unix_user_name(name, &sid)) {
295                 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
296                 type = SID_NAME_USER;
297                 goto ok;
298         }
299
300         if (((flags & LOOKUP_NAME_NO_NSS) == 0)
301             && lookup_unix_group_name(name, &sid)) {
302                 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
303                 type = SID_NAME_DOM_GRP;
304                 goto ok;
305         }
306
307         /*
308          * Ok, all possibilities tried. Fail.
309          */
310
311         TALLOC_FREE(tmp_ctx);
312         return false;
313
314  ok:
315         if ((domain == NULL) || (name == NULL)) {
316                 DEBUG(0, ("talloc failed\n"));
317                 TALLOC_FREE(tmp_ctx);
318                 return false;
319         }
320
321         /*
322          * Hand over the results to the talloc context we've been given.
323          */
324
325         if ((ret_name != NULL) &&
326             !(*ret_name = talloc_strdup(mem_ctx, name))) {
327                 DEBUG(0, ("talloc failed\n"));
328                 TALLOC_FREE(tmp_ctx);
329                 return false;
330         }
331
332         if (ret_domain != NULL) {
333                 char *tmp_dom;
334                 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
335                         DEBUG(0, ("talloc failed\n"));
336                         TALLOC_FREE(tmp_ctx);
337                         return false;
338                 }
339                 strupper_m(tmp_dom);
340                 *ret_domain = tmp_dom;
341         }
342
343         if (ret_sid != NULL) {
344                 sid_copy(ret_sid, &sid);
345         }
346
347         if (ret_type != NULL) {
348                 *ret_type = type;
349         }
350
351         TALLOC_FREE(tmp_ctx);
352         return true;
353 }
354
355 /************************************************************************
356  Names from smb.conf can be unqualified. eg. valid users = foo
357  These names should never map to a remote name. Try global_sam_name()\foo,
358  and then "Unix Users"\foo (or "Unix Groups"\foo).
359 ************************************************************************/
360
361 bool lookup_name_smbconf(TALLOC_CTX *mem_ctx,
362                  const char *full_name, int flags,
363                  const char **ret_domain, const char **ret_name,
364                  DOM_SID *ret_sid, enum lsa_SidType *ret_type)
365 {
366         char *qualified_name;
367         const char *p;
368
369         /* NB. No winbindd_separator here as lookup_name needs \\' */
370         if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
371
372                 /* The name is already qualified with a domain. */
373
374                 if (*lp_winbind_separator() != '\\') {
375                         char *tmp;
376
377                         /* lookup_name() needs '\\' as a separator */
378
379                         tmp = talloc_strdup(mem_ctx, full_name);
380                         if (!tmp) {
381                                 return false;
382                         }
383                         tmp[p - full_name] = '\\';
384                         full_name = tmp;
385                 }
386
387                 return lookup_name(mem_ctx, full_name, flags,
388                                 ret_domain, ret_name,
389                                 ret_sid, ret_type);
390         }
391
392         /* Try with our own SAM name. */
393         qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
394                                 get_global_sam_name(),
395                                 full_name );
396         if (!qualified_name) {
397                 return false;
398         }
399
400         if (lookup_name(mem_ctx, qualified_name, flags,
401                                 ret_domain, ret_name,
402                                 ret_sid, ret_type)) {
403                 return true;
404         }
405         
406         /* Finally try with "Unix Users" or "Unix Group" */
407         qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
408                                 flags & LOOKUP_NAME_GROUP ?
409                                         unix_groups_domain_name() :
410                                         unix_users_domain_name(),
411                                 full_name );
412         if (!qualified_name) {
413                 return false;
414         }
415
416         return lookup_name(mem_ctx, qualified_name, flags,
417                                 ret_domain, ret_name,
418                                 ret_sid, ret_type);
419 }
420
421 static bool wb_lookup_rids(TALLOC_CTX *mem_ctx,
422                            const DOM_SID *domain_sid,
423                            int num_rids, uint32 *rids,
424                            const char **domain_name,
425                            const char **names, enum lsa_SidType *types)
426 {
427         int i;
428         const char **my_names;
429         enum lsa_SidType *my_types;
430         TALLOC_CTX *tmp_ctx;
431
432         if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
433                 return false;
434         }
435
436         if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
437                                  domain_name, &my_names, &my_types)) {
438                 *domain_name = "";
439                 for (i=0; i<num_rids; i++) {
440                         names[i] = "";
441                         types[i] = SID_NAME_UNKNOWN;
442                 }
443                 TALLOC_FREE(tmp_ctx);
444                 return true;
445         }
446
447         if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
448                 TALLOC_FREE(tmp_ctx);
449                 return false;
450         }
451
452         /*
453          * winbind_lookup_rids allocates its own array. We've been given the
454          * array, so copy it over
455          */
456
457         for (i=0; i<num_rids; i++) {
458                 if (my_names[i] == NULL) {
459                         TALLOC_FREE(tmp_ctx);
460                         return false;
461                 }
462                 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
463                         TALLOC_FREE(tmp_ctx);
464                         return false;
465                 }
466                 types[i] = my_types[i];
467         }
468         TALLOC_FREE(tmp_ctx);
469         return true;
470 }
471
472 static bool lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
473                         int num_rids, uint32_t *rids,
474                         const char **domain_name,
475                         const char ***names, enum lsa_SidType **types)
476 {
477         int i;
478
479         DEBUG(10, ("lookup_rids called for domain sid '%s'\n",
480                    sid_string_dbg(domain_sid)));
481
482         if (num_rids) {
483                 *names = TALLOC_ZERO_ARRAY(mem_ctx, const char *, num_rids);
484                 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
485
486                 if ((*names == NULL) || (*types == NULL)) {
487                         return false;
488                 }
489
490                 for (i = 0; i < num_rids; i++)
491                         (*types)[i] = SID_NAME_UNKNOWN;
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                                       LSA_REF_DOMAIN_LIST_MULTIPLIER);
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_SID;
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<LSA_REF_DOMAIN_LIST_MULTIPLIER; 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 == LSA_REF_DOMAIN_LIST_MULTIPLIER) {
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<LSA_REF_DOMAIN_LIST_MULTIPLIER; 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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, NULL, 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_GID_CACHE,
1101                              data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 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, NULL, 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, NULL, 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 && is_null_sid(psid)) {
1315                 /*
1316                  * Negative cache entry, we already asked.
1317                  * do legacy.
1318                  */
1319                 legacy_uid_to_sid(psid, uid);
1320                 return;
1321         }
1322
1323         if (!ret || expired) {
1324                 /* Not in cache. Ask winbindd. */
1325                 if (!winbind_uid_to_sid(psid, uid)) {
1326                         /*
1327                          * We shouldn't return the NULL SID
1328                          * here if winbind was running and
1329                          * couldn't map, as winbind will have
1330                          * added a negative entry that will
1331                          * cause us to go though the
1332                          * legacy_uid_to_sid()
1333                          * function anyway in the case above
1334                          * the next time we ask.
1335                          */
1336                         DEBUG(5, ("uid_to_sid: winbind failed to find a sid "
1337                                   "for uid %u\n", (unsigned int)uid));
1338
1339                         legacy_uid_to_sid(psid, uid);
1340                         return;
1341                 }
1342         }
1343
1344         DEBUG(10,("uid %u -> sid %s\n", (unsigned int)uid,
1345                   sid_string_dbg(psid)));
1346
1347         store_uid_sid_cache(psid, uid);
1348         return;
1349 }
1350
1351 /*****************************************************************
1352  *THE CANONICAL* convert gid_t to SID function.
1353 *****************************************************************/  
1354
1355 void gid_to_sid(DOM_SID *psid, gid_t gid)
1356 {
1357         bool expired = true;
1358         bool ret;
1359         ZERO_STRUCTP(psid);
1360
1361         if (fetch_sid_from_gid_cache(psid, gid))
1362                 return;
1363
1364         /* Check the winbindd cache directly. */
1365         ret = idmap_cache_find_gid2sid(gid, psid, &expired);
1366
1367         if (ret && !expired && is_null_sid(psid)) {
1368                 /*
1369                  * Negative cache entry, we already asked.
1370                  * do legacy.
1371                  */
1372                 legacy_gid_to_sid(psid, gid);
1373                 return;
1374         }
1375
1376         if (!ret || expired) {
1377                 /* Not in cache. Ask winbindd. */
1378                 if (!winbind_gid_to_sid(psid, gid)) {
1379                         /*
1380                          * We shouldn't return the NULL SID
1381                          * here if winbind was running and
1382                          * couldn't map, as winbind will have
1383                          * added a negative entry that will
1384                          * cause us to go though the
1385                          * legacy_gid_to_sid()
1386                          * function anyway in the case above
1387                          * the next time we ask.
1388                          */
1389                         DEBUG(5, ("gid_to_sid: winbind failed to find a sid "
1390                                   "for gid %u\n", (unsigned int)gid));
1391
1392                         legacy_gid_to_sid(psid, gid);
1393                         return;
1394                 }
1395         }
1396
1397         DEBUG(10,("gid %u -> sid %s\n", (unsigned int)gid,
1398                   sid_string_dbg(psid)));
1399
1400         store_gid_sid_cache(psid, gid);
1401         return;
1402 }
1403
1404 /*****************************************************************
1405  *THE CANONICAL* convert SID to uid function.
1406 *****************************************************************/  
1407
1408 bool sid_to_uid(const DOM_SID *psid, uid_t *puid)
1409 {
1410         bool expired = true;
1411         bool ret;
1412         uint32 rid;
1413         gid_t gid;
1414
1415         if (fetch_uid_from_cache(puid, psid))
1416                 return true;
1417
1418         if (fetch_gid_from_cache(&gid, psid)) {
1419                 return false;
1420         }
1421
1422         /* Optimize for the Unix Users Domain
1423          * as the conversion is straightforward */
1424         if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1425                 uid_t uid = rid;
1426                 *puid = uid;
1427
1428                 /* return here, don't cache */
1429                 DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1430                         (unsigned int)*puid ));
1431                 return true;
1432         }
1433
1434         /* Check the winbindd cache directly. */
1435         ret = idmap_cache_find_sid2uid(psid, puid, &expired);
1436
1437         if (ret && !expired && (*puid == (uid_t)-1)) {
1438                 /*
1439                  * Negative cache entry, we already asked.
1440                  * do legacy.
1441                  */
1442                 return legacy_sid_to_uid(psid, puid);
1443         }
1444
1445         if (!ret || expired) {
1446                 /* Not in cache. Ask winbindd. */
1447                 if (!winbind_sid_to_uid(puid, psid)) {
1448                         DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1449                                   sid_string_dbg(psid)));
1450                         /* winbind failed. do legacy */
1451                         return legacy_sid_to_uid(psid, puid);
1452                 }
1453         }
1454
1455         /* TODO: Here would be the place to allocate both a gid and a uid for
1456          * the SID in question */
1457
1458         DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1459                 (unsigned int)*puid ));
1460
1461         store_uid_sid_cache(psid, *puid);
1462         return true;
1463 }
1464
1465 /*****************************************************************
1466  *THE CANONICAL* convert SID to gid function.
1467  Group mapping is used for gids that maps to Wellknown SIDs
1468 *****************************************************************/  
1469
1470 bool sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1471 {
1472         bool expired = true;
1473         bool ret;
1474         uint32 rid;
1475         uid_t uid;
1476
1477         if (fetch_gid_from_cache(pgid, psid))
1478                 return true;
1479
1480         if (fetch_uid_from_cache(&uid, psid))
1481                 return false;
1482
1483         /* Optimize for the Unix Groups Domain
1484          * as the conversion is straightforward */
1485         if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1486                 gid_t gid = rid;
1487                 *pgid = gid;
1488
1489                 /* return here, don't cache */
1490                 DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1491                         (unsigned int)*pgid ));
1492                 return true;
1493         }
1494
1495         /* Check the winbindd cache directly. */
1496         ret = idmap_cache_find_sid2gid(psid, pgid, &expired);
1497
1498         if (ret && !expired && (*pgid == (gid_t)-1)) {
1499                 /*
1500                  * Negative cache entry, we already asked.
1501                  * do legacy.
1502                  */
1503                 return legacy_sid_to_gid(psid, pgid);
1504         }
1505
1506         if (!ret || expired) {
1507                 /* Not in cache or negative. Ask winbindd. */
1508                 /* Ask winbindd if it can map this sid to a gid.
1509                  * (Idmap will check it is a valid SID and of the right type) */
1510
1511                 if ( !winbind_sid_to_gid(pgid, psid) ) {
1512
1513                         DEBUG(10,("winbind failed to find a gid for sid %s\n",
1514                                   sid_string_dbg(psid)));
1515                         /* winbind failed. do legacy */
1516                         return legacy_sid_to_gid(psid, pgid);
1517                 }
1518         }
1519
1520         DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1521                   (unsigned int)*pgid ));
1522
1523         store_gid_sid_cache(psid, *pgid);
1524         return true;
1525 }