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