Merge branch 'master' of git://git.samba.org/samba
[bbaumbach/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
1191         if (sid_check_is_in_our_domain(psid)) {
1192                 union unid_t id;
1193                 bool ret;
1194
1195                 become_root();
1196                 ret = pdb_sid_to_id(psid, &id, &type);
1197                 unbecome_root();
1198
1199                 if (ret) {
1200                         if (type != SID_NAME_USER) {
1201                                 DEBUG(5, ("sid %s is a %s, expected a user\n",
1202                                           sid_string_dbg(psid),
1203                                           sid_type_lookup(type)));
1204                                 return false;
1205                         }
1206                         *puid = id.uid;
1207                         goto done;
1208                 }
1209
1210                 /* This was ours, but it was not mapped.  Fail */
1211         }
1212
1213         DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1214                   sid_string_dbg(psid)));
1215         return false;
1216
1217 done:
1218         DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_dbg(psid),
1219                   (unsigned int)*puid ));
1220
1221         store_uid_sid_cache(psid, *puid);
1222         return true;
1223 }
1224
1225 /*****************************************************************
1226  *THE LEGACY* convert SID to gid function.
1227  Group mapping is used for gids that maps to Wellknown SIDs
1228 *****************************************************************/  
1229
1230 static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1231 {
1232         GROUP_MAP map;
1233         union unid_t id;
1234         enum lsa_SidType type;
1235
1236         if ((sid_check_is_in_builtin(psid) ||
1237              sid_check_is_in_wellknown_domain(psid))) {
1238                 bool ret;
1239
1240                 become_root();
1241                 ret = pdb_getgrsid(&map, *psid);
1242                 unbecome_root();
1243
1244                 if (ret) {
1245                         *pgid = map.gid;
1246                         goto done;
1247                 }
1248                 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1249                           sid_string_dbg(psid)));
1250                 return false;
1251         }
1252
1253         if (sid_check_is_in_our_domain(psid)) {
1254                 bool ret;
1255
1256                 become_root();
1257                 ret = pdb_sid_to_id(psid, &id, &type);
1258                 unbecome_root();
1259
1260                 if (ret) {
1261                         if ((type != SID_NAME_DOM_GRP) &&
1262                             (type != SID_NAME_ALIAS)) {
1263                                 DEBUG(5, ("LEGACY: sid %s is a %s, expected "
1264                                           "a group\n", sid_string_dbg(psid),
1265                                           sid_type_lookup(type)));
1266                                 return false;
1267                         }
1268                         *pgid = id.gid;
1269                         goto done;
1270                 }
1271         
1272                 /* This was ours, but it was not mapped.  Fail */
1273         }
1274
1275         DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1276                   sid_string_dbg(psid)));
1277         return false;
1278         
1279  done:
1280         DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_dbg(psid),
1281                   (unsigned int)*pgid ));
1282
1283         store_gid_sid_cache(psid, *pgid);
1284
1285         return true;
1286 }
1287
1288 /*****************************************************************
1289  *THE CANONICAL* convert uid_t to SID function.
1290 *****************************************************************/  
1291
1292 void uid_to_sid(DOM_SID *psid, uid_t uid)
1293 {
1294         bool expired = true;
1295         bool ret;
1296         ZERO_STRUCTP(psid);
1297
1298         if (fetch_sid_from_uid_cache(psid, uid))
1299                 return;
1300
1301         /* Check the winbindd cache directly. */
1302         ret = idmap_cache_find_uid2sid(uid, psid, &expired);
1303
1304         if (ret && !expired && is_null_sid(psid)) {
1305                 /*
1306                  * Negative cache entry, we already asked.
1307                  * do legacy.
1308                  */
1309                 legacy_uid_to_sid(psid, uid);
1310                 return;
1311         }
1312
1313         if (!ret || expired) {
1314                 /* Not in cache. Ask winbindd. */
1315                 if (!winbind_uid_to_sid(psid, uid)) {
1316                         /*
1317                          * We shouldn't return the NULL SID
1318                          * here if winbind was running and
1319                          * couldn't map, as winbind will have
1320                          * added a negative entry that will
1321                          * cause us to go though the
1322                          * legacy_uid_to_sid()
1323                          * function anyway in the case above
1324                          * the next time we ask.
1325                          */
1326                         DEBUG(5, ("uid_to_sid: winbind failed to find a sid "
1327                                   "for uid %u\n", (unsigned int)uid));
1328
1329                         legacy_uid_to_sid(psid, uid);
1330                         return;
1331                 }
1332         }
1333
1334         DEBUG(10,("uid %u -> sid %s\n", (unsigned int)uid,
1335                   sid_string_dbg(psid)));
1336
1337         store_uid_sid_cache(psid, uid);
1338         return;
1339 }
1340
1341 /*****************************************************************
1342  *THE CANONICAL* convert gid_t to SID function.
1343 *****************************************************************/  
1344
1345 void gid_to_sid(DOM_SID *psid, gid_t gid)
1346 {
1347         bool expired = true;
1348         bool ret;
1349         ZERO_STRUCTP(psid);
1350
1351         if (fetch_sid_from_gid_cache(psid, gid))
1352                 return;
1353
1354         /* Check the winbindd cache directly. */
1355         ret = idmap_cache_find_gid2sid(gid, psid, &expired);
1356
1357         if (ret && !expired && is_null_sid(psid)) {
1358                 /*
1359                  * Negative cache entry, we already asked.
1360                  * do legacy.
1361                  */
1362                 legacy_gid_to_sid(psid, gid);
1363                 return;
1364         }
1365
1366         if (!ret || expired) {
1367                 /* Not in cache. Ask winbindd. */
1368                 if (!winbind_gid_to_sid(psid, gid)) {
1369                         /*
1370                          * We shouldn't return the NULL SID
1371                          * here if winbind was running and
1372                          * couldn't map, as winbind will have
1373                          * added a negative entry that will
1374                          * cause us to go though the
1375                          * legacy_gid_to_sid()
1376                          * function anyway in the case above
1377                          * the next time we ask.
1378                          */
1379                         DEBUG(5, ("gid_to_sid: winbind failed to find a sid "
1380                                   "for gid %u\n", (unsigned int)gid));
1381
1382                         legacy_gid_to_sid(psid, gid);
1383                         return;
1384                 }
1385         }
1386
1387         DEBUG(10,("gid %u -> sid %s\n", (unsigned int)gid,
1388                   sid_string_dbg(psid)));
1389
1390         store_gid_sid_cache(psid, gid);
1391         return;
1392 }
1393
1394 /*****************************************************************
1395  *THE CANONICAL* convert SID to uid function.
1396 *****************************************************************/  
1397
1398 bool sid_to_uid(const DOM_SID *psid, uid_t *puid)
1399 {
1400         bool expired = true;
1401         bool ret;
1402         uint32 rid;
1403         gid_t gid;
1404
1405         if (fetch_uid_from_cache(puid, psid))
1406                 return true;
1407
1408         if (fetch_gid_from_cache(&gid, psid)) {
1409                 return false;
1410         }
1411
1412         /* Optimize for the Unix Users Domain
1413          * as the conversion is straightforward */
1414         if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1415                 uid_t uid = rid;
1416                 *puid = uid;
1417
1418                 /* return here, don't cache */
1419                 DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1420                         (unsigned int)*puid ));
1421                 return true;
1422         }
1423
1424         /* Check the winbindd cache directly. */
1425         ret = idmap_cache_find_sid2uid(psid, puid, &expired);
1426
1427         if (ret && !expired && (*puid == (uid_t)-1)) {
1428                 /*
1429                  * Negative cache entry, we already asked.
1430                  * do legacy.
1431                  */
1432                 return legacy_sid_to_uid(psid, puid);
1433         }
1434
1435         if (!ret || expired) {
1436                 /* Not in cache. Ask winbindd. */
1437                 if (!winbind_sid_to_uid(puid, psid)) {
1438                         DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1439                                   sid_string_dbg(psid)));
1440                         /* winbind failed. do legacy */
1441                         return legacy_sid_to_uid(psid, puid);
1442                 }
1443         }
1444
1445         /* TODO: Here would be the place to allocate both a gid and a uid for
1446          * the SID in question */
1447
1448         DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1449                 (unsigned int)*puid ));
1450
1451         store_uid_sid_cache(psid, *puid);
1452         return true;
1453 }
1454
1455 /*****************************************************************
1456  *THE CANONICAL* convert SID to gid function.
1457  Group mapping is used for gids that maps to Wellknown SIDs
1458 *****************************************************************/  
1459
1460 bool sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1461 {
1462         bool expired = true;
1463         bool ret;
1464         uint32 rid;
1465         uid_t uid;
1466
1467         if (fetch_gid_from_cache(pgid, psid))
1468                 return true;
1469
1470         if (fetch_uid_from_cache(&uid, psid))
1471                 return false;
1472
1473         /* Optimize for the Unix Groups Domain
1474          * as the conversion is straightforward */
1475         if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1476                 gid_t gid = rid;
1477                 *pgid = gid;
1478
1479                 /* return here, don't cache */
1480                 DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1481                         (unsigned int)*pgid ));
1482                 return true;
1483         }
1484
1485         /* Check the winbindd cache directly. */
1486         ret = idmap_cache_find_sid2gid(psid, pgid, &expired);
1487
1488         if (ret && !expired && (*pgid == (gid_t)-1)) {
1489                 /*
1490                  * Negative cache entry, we already asked.
1491                  * do legacy.
1492                  */
1493                 return legacy_sid_to_gid(psid, pgid);
1494         }
1495
1496         if (!ret || expired) {
1497                 /* Not in cache or negative. Ask winbindd. */
1498                 /* Ask winbindd if it can map this sid to a gid.
1499                  * (Idmap will check it is a valid SID and of the right type) */
1500
1501                 if ( !winbind_sid_to_gid(pgid, psid) ) {
1502
1503                         DEBUG(10,("winbind failed to find a gid for sid %s\n",
1504                                   sid_string_dbg(psid)));
1505                         /* winbind failed. do legacy */
1506                         return legacy_sid_to_gid(psid, pgid);
1507                 }
1508         }
1509
1510         DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1511                   (unsigned int)*pgid ));
1512
1513         store_gid_sid_cache(psid, *pgid);
1514         return true;
1515 }