s3: Replace most calls to sid_append_rid() by sid_compose()
[sfrench/samba-autobuild/.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_compose(&sid, get_global_sam_sid(), rid);
79                         goto ok;
80                 }
81                 TALLOC_FREE(tmp_ctx);
82                 return false;
83         }
84
85         if ((flags & LOOKUP_NAME_BUILTIN) &&
86             strequal(domain, builtin_domain_name()))
87         {
88                 if (strlen(name) == 0) {
89                         /* Swap domain and name */
90                         tmp = name; name = domain; domain = tmp;
91                         sid_copy(&sid, &global_sid_Builtin);
92                         type = SID_NAME_DOMAIN;
93                         goto ok;
94                 }
95
96                 /* Explicit request for a name in BUILTIN */
97                 if (lookup_builtin_name(name, &rid)) {
98                         sid_compose(&sid, &global_sid_Builtin, rid);
99                         type = SID_NAME_ALIAS;
100                         goto ok;
101                 }
102                 TALLOC_FREE(tmp_ctx);
103                 return false;
104         }
105
106         /* Try the explicit winbind lookup first, don't let it guess the
107          * domain yet at this point yet. This comes later. */
108
109         if ((domain[0] != '\0') &&
110             (flags & ~(LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED)) &&
111             (winbind_lookup_name(domain, name, &sid, &type))) {
112                         goto ok;
113         }
114
115         if (((flags & LOOKUP_NAME_NO_NSS) == 0)
116             && strequal(domain, unix_users_domain_name())) {
117                 if (lookup_unix_user_name(name, &sid)) {
118                         type = SID_NAME_USER;
119                         goto ok;
120                 }
121                 TALLOC_FREE(tmp_ctx);
122                 return false;
123         }
124
125         if (((flags & LOOKUP_NAME_NO_NSS) == 0)
126             && strequal(domain, unix_groups_domain_name())) {
127                 if (lookup_unix_group_name(name, &sid)) {
128                         type = SID_NAME_DOM_GRP;
129                         goto ok;
130                 }
131                 TALLOC_FREE(tmp_ctx);
132                 return false;
133         }
134
135         if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
136                 TALLOC_FREE(tmp_ctx);
137                 return false;
138         }
139
140         /* Now the guesswork begins, we haven't been given an explicit
141          * domain. Try the sequence as documented on
142          * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
143          * November 27, 2005 */
144
145         /* 1. well-known names */
146
147         if ((flags & LOOKUP_NAME_WKN) &&
148             lookup_wellknown_name(tmp_ctx, name, &sid, &domain))
149         {
150                 type = SID_NAME_WKN_GRP;
151                 goto ok;
152         }
153
154         /* 2. Builtin domain as such */
155
156         if ((flags & (LOOKUP_NAME_BUILTIN|LOOKUP_NAME_REMOTE)) &&
157             strequal(name, builtin_domain_name()))
158         {
159                 /* Swap domain and name */
160                 tmp = name; name = domain; domain = tmp;
161                 sid_copy(&sid, &global_sid_Builtin);
162                 type = SID_NAME_DOMAIN;
163                 goto ok;
164         }
165
166         /* 3. Account domain */
167
168         if ((flags & LOOKUP_NAME_DOMAIN) &&
169             strequal(name, get_global_sam_name()))
170         {
171                 if (!secrets_fetch_domain_sid(name, &sid)) {
172                         DEBUG(3, ("Could not fetch my SID\n"));
173                         TALLOC_FREE(tmp_ctx);
174                         return false;
175                 }
176                 /* Swap domain and name */
177                 tmp = name; name = domain; domain = tmp;
178                 type = SID_NAME_DOMAIN;
179                 goto ok;
180         }
181
182         /* 4. Primary domain */
183
184         if ((flags & LOOKUP_NAME_DOMAIN) && !IS_DC &&
185             strequal(name, lp_workgroup()))
186         {
187                 if (!secrets_fetch_domain_sid(name, &sid)) {
188                         DEBUG(3, ("Could not fetch the domain SID\n"));
189                         TALLOC_FREE(tmp_ctx);
190                         return false;
191                 }
192                 /* Swap domain and name */
193                 tmp = name; name = domain; domain = tmp;
194                 type = SID_NAME_DOMAIN;
195                 goto ok;
196         }
197
198         /* 5. Trusted domains as such, to me it looks as if members don't do
199               this, tested an XP workstation in a NT domain -- vl */
200
201         if ((flags & LOOKUP_NAME_REMOTE) && IS_DC &&
202             (pdb_get_trusteddom_pw(name, NULL, &sid, NULL)))
203         {
204                 /* Swap domain and name */
205                 tmp = name; name = domain; domain = tmp;
206                 type = SID_NAME_DOMAIN;
207                 goto ok;
208         }
209
210         /* 6. Builtin aliases */        
211
212         if ((flags & LOOKUP_NAME_BUILTIN) &&
213             lookup_builtin_name(name, &rid))
214         {
215                 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
216                 sid_compose(&sid, &global_sid_Builtin, rid);
217                 type = SID_NAME_ALIAS;
218                 goto ok;
219         }
220
221         /* 7. Local systems' SAM (DCs don't have a local SAM) */
222         /* 8. Primary SAM (On members, this is the domain) */
223
224         /* Both cases are done by looking at our passdb */
225
226         if ((flags & LOOKUP_NAME_DOMAIN) &&
227             lookup_global_sam_name(name, flags, &rid, &type))
228         {
229                 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
230                 sid_compose(&sid, get_global_sam_sid(), rid);
231                 goto ok;
232         }
233
234         /* Now our local possibilities are exhausted. */
235
236         if (!(flags & LOOKUP_NAME_REMOTE)) {
237                 TALLOC_FREE(tmp_ctx);
238                 return false;
239         }
240
241         /* If we are not a DC, we have to ask in our primary domain. Let
242          * winbind do that. */
243
244         if (!IS_DC &&
245             (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
246                 domain = talloc_strdup(tmp_ctx, lp_workgroup());
247                 goto ok;
248         }
249
250         /* 9. Trusted domains */
251
252         /* If we're a DC we have to ask all trusted DC's. Winbind does not do
253          * that (yet), but give it a chance. */
254
255         if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
256                 DOM_SID dom_sid;
257                 uint32 tmp_rid;
258                 enum lsa_SidType domain_type;
259                 
260                 if (type == SID_NAME_DOMAIN) {
261                         /* Swap name and type */
262                         tmp = name; name = domain; domain = tmp;
263                         goto ok;
264                 }
265
266                 /* Here we have to cope with a little deficiency in the
267                  * winbind API: We have to ask it again for the name of the
268                  * domain it figured out itself. Maybe fix that later... */
269
270                 sid_copy(&dom_sid, &sid);
271                 sid_split_rid(&dom_sid, &tmp_rid);
272
273                 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
274                                         &domain_type) ||
275                     (domain_type != SID_NAME_DOMAIN)) {
276                         DEBUG(2, ("winbind could not find the domain's name "
277                                   "it just looked up for us\n"));
278                         TALLOC_FREE(tmp_ctx);
279                         return false;
280                 }
281                 goto ok;
282         }
283
284         /* 10. Don't translate */
285
286         /* 11. Ok, windows would end here. Samba has two more options:
287                Unmapped users and unmapped groups */
288
289         if (((flags & LOOKUP_NAME_NO_NSS) == 0)
290             && lookup_unix_user_name(name, &sid)) {
291                 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
292                 type = SID_NAME_USER;
293                 goto ok;
294         }
295
296         if (((flags & LOOKUP_NAME_NO_NSS) == 0)
297             && lookup_unix_group_name(name, &sid)) {
298                 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
299                 type = SID_NAME_DOM_GRP;
300                 goto ok;
301         }
302
303         /*
304          * Ok, all possibilities tried. Fail.
305          */
306
307         TALLOC_FREE(tmp_ctx);
308         return false;
309
310  ok:
311         if ((domain == NULL) || (name == NULL)) {
312                 DEBUG(0, ("talloc failed\n"));
313                 TALLOC_FREE(tmp_ctx);
314                 return false;
315         }
316
317         /*
318          * Hand over the results to the talloc context we've been given.
319          */
320
321         if ((ret_name != NULL) &&
322             !(*ret_name = talloc_strdup(mem_ctx, name))) {
323                 DEBUG(0, ("talloc failed\n"));
324                 TALLOC_FREE(tmp_ctx);
325                 return false;
326         }
327
328         if (ret_domain != NULL) {
329                 char *tmp_dom;
330                 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
331                         DEBUG(0, ("talloc failed\n"));
332                         TALLOC_FREE(tmp_ctx);
333                         return false;
334                 }
335                 strupper_m(tmp_dom);
336                 *ret_domain = tmp_dom;
337         }
338
339         if (ret_sid != NULL) {
340                 sid_copy(ret_sid, &sid);
341         }
342
343         if (ret_type != NULL) {
344                 *ret_type = type;
345         }
346
347         TALLOC_FREE(tmp_ctx);
348         return true;
349 }
350
351 /************************************************************************
352  Names from smb.conf can be unqualified. eg. valid users = foo
353  These names should never map to a remote name. Try global_sam_name()\foo,
354  and then "Unix Users"\foo (or "Unix Groups"\foo).
355 ************************************************************************/
356
357 bool lookup_name_smbconf(TALLOC_CTX *mem_ctx,
358                  const char *full_name, int flags,
359                  const char **ret_domain, const char **ret_name,
360                  DOM_SID *ret_sid, enum lsa_SidType *ret_type)
361 {
362         char *qualified_name;
363         const char *p;
364
365         /* NB. No winbindd_separator here as lookup_name needs \\' */
366         if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
367
368                 /* The name is already qualified with a domain. */
369
370                 if (*lp_winbind_separator() != '\\') {
371                         char *tmp;
372
373                         /* lookup_name() needs '\\' as a separator */
374
375                         tmp = talloc_strdup(mem_ctx, full_name);
376                         if (!tmp) {
377                                 return false;
378                         }
379                         tmp[p - full_name] = '\\';
380                         full_name = tmp;
381                 }
382
383                 return lookup_name(mem_ctx, full_name, flags,
384                                 ret_domain, ret_name,
385                                 ret_sid, ret_type);
386         }
387
388         /* Try with our own SAM name. */
389         qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
390                                 get_global_sam_name(),
391                                 full_name );
392         if (!qualified_name) {
393                 return false;
394         }
395
396         if (lookup_name(mem_ctx, qualified_name, flags,
397                                 ret_domain, ret_name,
398                                 ret_sid, ret_type)) {
399                 return true;
400         }
401         
402         /* Finally try with "Unix Users" or "Unix Group" */
403         qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
404                                 flags & LOOKUP_NAME_GROUP ?
405                                         unix_groups_domain_name() :
406                                         unix_users_domain_name(),
407                                 full_name );
408         if (!qualified_name) {
409                 return false;
410         }
411
412         return lookup_name(mem_ctx, qualified_name, flags,
413                                 ret_domain, ret_name,
414                                 ret_sid, ret_type);
415 }
416
417 static bool wb_lookup_rids(TALLOC_CTX *mem_ctx,
418                            const DOM_SID *domain_sid,
419                            int num_rids, uint32 *rids,
420                            const char **domain_name,
421                            const char **names, enum lsa_SidType *types)
422 {
423         int i;
424         const char **my_names;
425         enum lsa_SidType *my_types;
426         TALLOC_CTX *tmp_ctx;
427
428         if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
429                 return false;
430         }
431
432         if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
433                                  domain_name, &my_names, &my_types)) {
434                 *domain_name = "";
435                 for (i=0; i<num_rids; i++) {
436                         names[i] = "";
437                         types[i] = SID_NAME_UNKNOWN;
438                 }
439                 TALLOC_FREE(tmp_ctx);
440                 return true;
441         }
442
443         if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
444                 TALLOC_FREE(tmp_ctx);
445                 return false;
446         }
447
448         /*
449          * winbind_lookup_rids allocates its own array. We've been given the
450          * array, so copy it over
451          */
452
453         for (i=0; i<num_rids; i++) {
454                 if (my_names[i] == NULL) {
455                         TALLOC_FREE(tmp_ctx);
456                         return false;
457                 }
458                 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
459                         TALLOC_FREE(tmp_ctx);
460                         return false;
461                 }
462                 types[i] = my_types[i];
463         }
464         TALLOC_FREE(tmp_ctx);
465         return true;
466 }
467
468 static bool lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
469                         int num_rids, uint32_t *rids,
470                         const char **domain_name,
471                         const char ***names, enum lsa_SidType **types)
472 {
473         int i;
474
475         DEBUG(10, ("lookup_rids called for domain sid '%s'\n",
476                    sid_string_dbg(domain_sid)));
477
478         if (num_rids) {
479                 *names = TALLOC_ZERO_ARRAY(mem_ctx, const char *, num_rids);
480                 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
481
482                 if ((*names == NULL) || (*types == NULL)) {
483                         return false;
484                 }
485
486                 for (i = 0; i < num_rids; i++)
487                         (*types)[i] = SID_NAME_UNKNOWN;
488         } else {
489                 *names = NULL;
490                 *types = NULL;
491         }
492
493         if (sid_check_is_domain(domain_sid)) {
494                 NTSTATUS result;
495
496                 if (*domain_name == NULL) {
497                         *domain_name = talloc_strdup(
498                                 mem_ctx, get_global_sam_name());
499                 }
500
501                 if (*domain_name == NULL) {
502                         return false;
503                 }
504
505                 become_root();
506                 result = pdb_lookup_rids(domain_sid, num_rids, rids,
507                                          *names, *types);
508                 unbecome_root();
509
510                 return (NT_STATUS_IS_OK(result) ||
511                         NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
512                         NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
513         }
514
515         if (sid_check_is_builtin(domain_sid)) {
516
517                 if (*domain_name == NULL) {
518                         *domain_name = talloc_strdup(
519                                 mem_ctx, builtin_domain_name());
520                 }
521
522                 if (*domain_name == NULL) {
523                         return false;
524                 }
525
526                 for (i=0; i<num_rids; i++) {
527                         if (lookup_builtin_rid(*names, rids[i],
528                                                &(*names)[i])) {
529                                 if ((*names)[i] == NULL) {
530                                         return false;
531                                 }
532                                 (*types)[i] = SID_NAME_ALIAS;
533                         } else {
534                                 (*types)[i] = SID_NAME_UNKNOWN;
535                         }
536                 }
537                 return true;
538         }
539
540         if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
541                 for (i=0; i<num_rids; i++) {
542                         DOM_SID sid;
543                         sid_compose(&sid, domain_sid, rids[i]);
544                         if (lookup_wellknown_sid(mem_ctx, &sid,
545                                                  domain_name, &(*names)[i])) {
546                                 if ((*names)[i] == NULL) {
547                                         return false;
548                                 }
549                                 (*types)[i] = SID_NAME_WKN_GRP;
550                         } else {
551                                 (*types)[i] = SID_NAME_UNKNOWN;
552                         }
553                 }
554                 return true;
555         }
556
557         if (sid_check_is_unix_users(domain_sid)) {
558                 if (*domain_name == NULL) {
559                         *domain_name = talloc_strdup(
560                                 mem_ctx, unix_users_domain_name());
561                         if (*domain_name == NULL) {
562                                 return false;
563                         }
564                 }
565                 for (i=0; i<num_rids; i++) {
566                         (*names)[i] = talloc_strdup(
567                                 (*names), uidtoname(rids[i]));
568                         if ((*names)[i] == NULL) {
569                                 return false;
570                         }
571                         (*types)[i] = SID_NAME_USER;
572                 }
573                 return true;
574         }
575
576         if (sid_check_is_unix_groups(domain_sid)) {
577                 if (*domain_name == NULL) {
578                         *domain_name = talloc_strdup(
579                                 mem_ctx, unix_groups_domain_name());
580                         if (*domain_name == NULL) {
581                                 return false;
582                         }
583                 }
584                 for (i=0; i<num_rids; i++) {
585                         (*names)[i] = talloc_strdup(
586                                 (*names), gidtoname(rids[i]));
587                         if ((*names)[i] == NULL) {
588                                 return false;
589                         }
590                         (*types)[i] = SID_NAME_DOM_GRP;
591                 }
592                 return true;
593         }
594
595         return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
596                               domain_name, *names, *types);
597 }
598
599 /*
600  * Is the SID a domain as such? If yes, lookup its name.
601  */
602
603 static bool lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
604                              const char **name)
605 {
606         const char *tmp;
607         enum lsa_SidType type;
608
609         if (sid_check_is_domain(sid)) {
610                 *name = talloc_strdup(mem_ctx, get_global_sam_name());
611                 return true;
612         }
613
614         if (sid_check_is_builtin(sid)) {
615                 *name = talloc_strdup(mem_ctx, builtin_domain_name());
616                 return true;
617         }
618
619         if (sid_check_is_wellknown_domain(sid, &tmp)) {
620                 *name = talloc_strdup(mem_ctx, tmp);
621                 return true;
622         }
623
624         if (sid_check_is_unix_users(sid)) {
625                 *name = talloc_strdup(mem_ctx, unix_users_domain_name());
626                 return true;
627         }
628
629         if (sid_check_is_unix_groups(sid)) {
630                 *name = talloc_strdup(mem_ctx, unix_groups_domain_name());
631                 return true;
632         }
633
634         if (sid->num_auths != 4) {
635                 /* This can't be a domain */
636                 return false;
637         }
638
639         if (IS_DC) {
640                 uint32 i, num_domains;
641                 struct trustdom_info **domains;
642
643                 /* This is relatively expensive, but it happens only on DCs
644                  * and for SIDs that have 4 sub-authorities and thus look like
645                  * domains */
646
647                 if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
648                                                           &num_domains,
649                                                           &domains))) {
650                         return false;
651                 }
652
653                 for (i=0; i<num_domains; i++) {
654                         if (sid_equal(sid, &domains[i]->sid)) {
655                                 *name = talloc_strdup(mem_ctx,
656                                                       domains[i]->name);
657                                 return true;
658                         }
659                 }
660                 return false;
661         }
662
663         if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
664             (type == SID_NAME_DOMAIN)) {
665                 *name = tmp;
666                 return true;
667         }
668
669         return false;
670 }
671
672 /*
673  * This tries to implement the rather weird rules for the lsa_lookup level
674  * parameter.
675  *
676  * This is as close as we can get to what W2k3 does. With this we survive the
677  * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
678  * different, but I assume that's just being too liberal. For example, W2k3
679  * replies to everything else but the levels 1-6 with INVALID_PARAMETER
680  * whereas NT4 does the same as level 1 (I think). I did not fully test that
681  * with NT4, this is what w2k3 does.
682  *
683  * Level 1: Ask everywhere
684  * Level 2: Ask domain and trusted domains, no builtin and wkn
685  * Level 3: Only ask domain
686  * Level 4: W2k3ad: Only ask AD trusts
687  * Level 5: Only ask transitive forest trusts
688  * Level 6: Like 4
689  */
690
691 static bool check_dom_sid_to_level(const DOM_SID *sid, int level)
692 {
693         int ret = false;
694
695         switch(level) {
696         case 1:
697                 ret = true;
698                 break;
699         case 2:
700                 ret = (!sid_check_is_builtin(sid) &&
701                        !sid_check_is_wellknown_domain(sid, NULL));
702                 break;
703         case 3:
704         case 4:
705         case 6:
706                 ret = sid_check_is_domain(sid);
707                 break;
708         case 5:
709                 ret = false;
710                 break;
711         }
712
713         DEBUG(10, ("%s SID %s in level %d\n",
714                    ret ? "Accepting" : "Rejecting",
715                    sid_string_dbg(sid), level));
716         return ret;
717 }
718
719 /*
720  * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
721  * references to domains, it is explicitly made for this.
722  *
723  * This attempts to be as efficient as possible: It collects all SIDs
724  * belonging to a domain and hands them in bulk to the appropriate lookup
725  * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
726  * *hugely* from this. Winbind is going to be extended with a lookup_rids
727  * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
728  * appropriate DC.
729  */
730
731 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
732                      const DOM_SID **sids, int level,
733                      struct lsa_dom_info **ret_domains,
734                      struct lsa_name_info **ret_names)
735 {
736         TALLOC_CTX *tmp_ctx;
737         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
738         struct lsa_name_info *name_infos;
739         struct lsa_dom_info *dom_infos = NULL;
740
741         int i, j;
742
743         if (!(tmp_ctx = talloc_new(mem_ctx))) {
744                 DEBUG(0, ("talloc_new failed\n"));
745                 return NT_STATUS_NO_MEMORY;
746         }
747
748         if (num_sids) {
749                 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
750                 if (name_infos == NULL) {
751                         result = NT_STATUS_NO_MEMORY;
752                         goto fail;
753                 }
754         } else {
755                 name_infos = NULL;
756         }
757
758         dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
759                                       LSA_REF_DOMAIN_LIST_MULTIPLIER);
760         if (dom_infos == NULL) {
761                 result = NT_STATUS_NO_MEMORY;
762                 goto fail;
763         }
764
765         /* First build up the data structures:
766          * 
767          * dom_infos is a list of domains referenced in the list of
768          * SIDs. Later we will walk the list of domains and look up the RIDs
769          * in bulk.
770          *
771          * name_infos is a shadow-copy of the SIDs array to collect the real
772          * data.
773          *
774          * dom_info->idxs is an index into the name_infos array. The
775          * difficulty we have here is that we need to keep the SIDs the client
776          * asked for in the same order for the reply
777          */
778
779         for (i=0; i<num_sids; i++) {
780                 DOM_SID sid;
781                 uint32 rid;
782                 const char *domain_name = NULL;
783
784                 sid_copy(&sid, sids[i]);
785                 name_infos[i].type = SID_NAME_USE_NONE;
786
787                 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
788                         /* We can't push that through the normal lookup
789                          * process, as this would reference illegal
790                          * domains.
791                          *
792                          * For example S-1-5-32 would end up referencing
793                          * domain S-1-5- with RID 32 which is clearly wrong.
794                          */
795                         if (domain_name == NULL) {
796                                 result = NT_STATUS_NO_MEMORY;
797                                 goto fail;
798                         }
799                                 
800                         name_infos[i].rid = 0;
801                         name_infos[i].type = SID_NAME_DOMAIN;
802                         name_infos[i].name = NULL;
803
804                         if (sid_check_is_builtin(&sid)) {
805                                 /* Yes, W2k3 returns "BUILTIN" both as domain
806                                  * and name here */
807                                 name_infos[i].name = talloc_strdup(
808                                         name_infos, builtin_domain_name());
809                                 if (name_infos[i].name == NULL) {
810                                         result = NT_STATUS_NO_MEMORY;
811                                         goto fail;
812                                 }
813                         }
814                 } else {
815                         /* This is a normal SID with rid component */
816                         if (!sid_split_rid(&sid, &rid)) {
817                                 result = NT_STATUS_INVALID_SID;
818                                 goto fail;
819                         }
820                 }
821
822                 if (!check_dom_sid_to_level(&sid, level)) {
823                         name_infos[i].rid = 0;
824                         name_infos[i].type = SID_NAME_UNKNOWN;
825                         name_infos[i].name = NULL;
826                         continue;
827                 }
828
829                 for (j=0; j<LSA_REF_DOMAIN_LIST_MULTIPLIER; j++) {
830                         if (!dom_infos[j].valid) {
831                                 break;
832                         }
833                         if (sid_equal(&sid, &dom_infos[j].sid)) {
834                                 break;
835                         }
836                 }
837
838                 if (j == LSA_REF_DOMAIN_LIST_MULTIPLIER) {
839                         /* TODO: What's the right error message here? */
840                         result = NT_STATUS_NONE_MAPPED;
841                         goto fail;
842                 }
843
844                 if (!dom_infos[j].valid) {
845                         /* We found a domain not yet referenced, create a new
846                          * ref. */
847                         dom_infos[j].valid = true;
848                         sid_copy(&dom_infos[j].sid, &sid);
849
850                         if (domain_name != NULL) {
851                                 /* This name was being found above in the case
852                                  * when we found a domain SID */
853                                 dom_infos[j].name =
854                                         talloc_strdup(dom_infos, domain_name);
855                                 if (dom_infos[j].name == NULL) {
856                                         result = NT_STATUS_NO_MEMORY;
857                                         goto fail;
858                                 }
859                         } else {
860                                 /* lookup_rids will take care of this */
861                                 dom_infos[j].name = NULL;
862                         }
863                 }
864
865                 name_infos[i].dom_idx = j;
866
867                 if (name_infos[i].type == SID_NAME_USE_NONE) {
868                         name_infos[i].rid = rid;
869
870                         ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
871                                      &dom_infos[j].num_idxs);
872
873                         if (dom_infos[j].idxs == NULL) {
874                                 result = NT_STATUS_NO_MEMORY;
875                                 goto fail;
876                         }
877                 }
878         }
879
880         /* Iterate over the domains found */
881
882         for (i=0; i<LSA_REF_DOMAIN_LIST_MULTIPLIER; i++) {
883                 uint32_t *rids;
884                 const char *domain_name = NULL;
885                 const char **names;
886                 enum lsa_SidType *types;
887                 struct lsa_dom_info *dom = &dom_infos[i];
888
889                 if (!dom->valid) {
890                         /* No domains left, we're done */
891                         break;
892                 }
893
894                 if (dom->num_idxs) {
895                         if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
896                                 result = NT_STATUS_NO_MEMORY;
897                                 goto fail;
898                         }
899                 } else {
900                         rids = NULL;
901                 }
902
903                 for (j=0; j<dom->num_idxs; j++) {
904                         rids[j] = name_infos[dom->idxs[j]].rid;
905                 }
906
907                 if (!lookup_rids(tmp_ctx, &dom->sid,
908                                  dom->num_idxs, rids, &domain_name,
909                                  &names, &types)) {
910                         result = NT_STATUS_NO_MEMORY;
911                         goto fail;
912                 }
913
914                 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
915                         result = NT_STATUS_NO_MEMORY;
916                         goto fail;
917                 }
918                         
919                 for (j=0; j<dom->num_idxs; j++) {
920                         int idx = dom->idxs[j];
921                         name_infos[idx].type = types[j];
922                         if (types[j] != SID_NAME_UNKNOWN) {
923                                 name_infos[idx].name =
924                                         talloc_strdup(name_infos, names[j]);
925                                 if (name_infos[idx].name == NULL) {
926                                         result = NT_STATUS_NO_MEMORY;
927                                         goto fail;
928                                 }
929                         } else {
930                                 name_infos[idx].name = NULL;
931                         }
932                 }
933         }
934
935         *ret_domains = dom_infos;
936         *ret_names = name_infos;
937         TALLOC_FREE(tmp_ctx);
938         return NT_STATUS_OK;
939
940  fail:
941         TALLOC_FREE(dom_infos);
942         TALLOC_FREE(name_infos);
943         TALLOC_FREE(tmp_ctx);
944         return result;
945 }
946
947 /*****************************************************************
948  *THE CANONICAL* convert SID to name function.
949 *****************************************************************/  
950
951 bool lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
952                 const char **ret_domain, const char **ret_name,
953                 enum lsa_SidType *ret_type)
954 {
955         struct lsa_dom_info *domain;
956         struct lsa_name_info *name;
957         TALLOC_CTX *tmp_ctx;
958         bool ret = false;
959
960         DEBUG(10, ("lookup_sid called for SID '%s'\n", sid_string_dbg(sid)));
961
962         if (!(tmp_ctx = talloc_new(mem_ctx))) {
963                 DEBUG(0, ("talloc_new failed\n"));
964                 return false;
965         }
966
967         if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
968                                          &domain, &name))) {
969                 goto done;
970         }
971
972         if (name->type == SID_NAME_UNKNOWN) {
973                 goto done;
974         }
975
976         if ((ret_domain != NULL) &&
977             !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
978                 goto done;
979         }
980
981         if ((ret_name != NULL) && 
982             !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
983                 goto done;
984         }
985
986         if (ret_type != NULL) {
987                 *ret_type = name->type;
988         }
989
990         ret = true;
991
992  done:
993         if (ret) {
994                 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n", sid_string_dbg(sid),
995                            domain->name, name->name, name->type));
996         } else {
997                 DEBUG(10, ("failed to lookup sid %s\n", sid_string_dbg(sid)));
998         }
999         TALLOC_FREE(tmp_ctx);
1000         return ret;
1001 }
1002
1003 /*****************************************************************
1004  Id mapping cache.  This is to avoid Winbind mappings already
1005  seen by smbd to be queried too frequently, keeping winbindd
1006  busy, and blocking smbd while winbindd is busy with other
1007  stuff. Written by Michael Steffens <michael.steffens@hp.com>,
1008  modified to use linked lists by jra.
1009 *****************************************************************/  
1010
1011 /*****************************************************************
1012   Find a SID given a uid.
1013 *****************************************************************/
1014
1015 static bool fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
1016 {
1017         DATA_BLOB cache_value;
1018
1019         if (!memcache_lookup(NULL, UID_SID_CACHE,
1020                              data_blob_const(&uid, sizeof(uid)),
1021                              &cache_value)) {
1022                 return false;
1023         }
1024
1025         memcpy(psid, cache_value.data, MIN(sizeof(*psid), cache_value.length));
1026         SMB_ASSERT(cache_value.length >= offsetof(struct dom_sid, id_auth));
1027         SMB_ASSERT(cache_value.length == ndr_size_dom_sid(psid, NULL, 0));
1028
1029         return true;
1030 }
1031
1032 /*****************************************************************
1033   Find a uid given a SID.
1034 *****************************************************************/
1035
1036 static bool fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
1037 {
1038         DATA_BLOB cache_value;
1039
1040         if (!memcache_lookup(NULL, SID_UID_CACHE,
1041                              data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)),
1042                              &cache_value)) {
1043                 return false;
1044         }
1045
1046         SMB_ASSERT(cache_value.length == sizeof(*puid));
1047         memcpy(puid, cache_value.data, sizeof(*puid));
1048
1049         return true;
1050 }
1051
1052 /*****************************************************************
1053  Store uid to SID mapping in cache.
1054 *****************************************************************/
1055
1056 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1057 {
1058         memcache_add(NULL, SID_UID_CACHE,
1059                      data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)),
1060                      data_blob_const(&uid, sizeof(uid)));
1061         memcache_add(NULL, UID_SID_CACHE,
1062                      data_blob_const(&uid, sizeof(uid)),
1063                      data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)));
1064 }
1065
1066 /*****************************************************************
1067   Find a SID given a gid.
1068 *****************************************************************/
1069
1070 static bool fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1071 {
1072         DATA_BLOB cache_value;
1073
1074         if (!memcache_lookup(NULL, GID_SID_CACHE,
1075                              data_blob_const(&gid, sizeof(gid)),
1076                              &cache_value)) {
1077                 return false;
1078         }
1079
1080         memcpy(psid, cache_value.data, MIN(sizeof(*psid), cache_value.length));
1081         SMB_ASSERT(cache_value.length >= offsetof(struct dom_sid, id_auth));
1082         SMB_ASSERT(cache_value.length == ndr_size_dom_sid(psid, NULL, 0));
1083
1084         return true;
1085 }
1086
1087 /*****************************************************************
1088   Find a gid given a SID.
1089 *****************************************************************/
1090
1091 static bool fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1092 {
1093         DATA_BLOB cache_value;
1094
1095         if (!memcache_lookup(NULL, SID_GID_CACHE,
1096                              data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)),
1097                              &cache_value)) {
1098                 return false;
1099         }
1100
1101         SMB_ASSERT(cache_value.length == sizeof(*pgid));
1102         memcpy(pgid, cache_value.data, sizeof(*pgid));
1103
1104         return true;
1105 }
1106
1107 /*****************************************************************
1108  Store gid to SID mapping in cache.
1109 *****************************************************************/
1110
1111 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1112 {
1113         memcache_add(NULL, SID_GID_CACHE,
1114                      data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)),
1115                      data_blob_const(&gid, sizeof(gid)));
1116         memcache_add(NULL, GID_SID_CACHE,
1117                      data_blob_const(&gid, sizeof(gid)),
1118                      data_blob_const(psid, ndr_size_dom_sid(psid, NULL, 0)));
1119 }
1120
1121 /*****************************************************************
1122  *THE LEGACY* convert uid_t to SID function.
1123 *****************************************************************/  
1124
1125 static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1126 {
1127         bool ret;
1128
1129         ZERO_STRUCTP(psid);
1130
1131         become_root();
1132         ret = pdb_uid_to_sid(uid, psid);
1133         unbecome_root();
1134
1135         if (ret) {
1136                 /* This is a mapped user */
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 }