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