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