r15837: starting sync up for 3.0.23rc1 (in sync with SAMBA_3_0 r15822)
[Samba.git] / source / passdb / lookup_sid.c
blob751fa597c04e179491758c85bfce2efd2a733c42
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
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 /*****************************************************************
26 Dissect a user-provided name into domain, name, sid and type.
28 If an explicit domain name was given in the form domain\user, it
29 has to try that. If no explicit domain name was given, we have
30 to do guesswork.
31 *****************************************************************/
33 BOOL lookup_name(TALLOC_CTX *mem_ctx,
34 const char *full_name, int flags,
35 const char **ret_domain, const char **ret_name,
36 DOM_SID *ret_sid, enum SID_NAME_USE *ret_type)
38 char *p;
39 const char *tmp;
40 const char *domain = NULL;
41 const char *name = NULL;
42 uint32 rid;
43 DOM_SID sid;
44 enum SID_NAME_USE type;
45 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
47 if (tmp_ctx == NULL) {
48 DEBUG(0, ("talloc_new failed\n"));
49 return False;
52 p = strchr_m(full_name, '\\');
54 if (p != NULL) {
55 domain = talloc_strndup(tmp_ctx, full_name,
56 PTR_DIFF(p, full_name));
57 name = talloc_strdup(tmp_ctx, p+1);
58 } else {
59 domain = talloc_strdup(tmp_ctx, "");
60 name = talloc_strdup(tmp_ctx, full_name);
63 if ((domain == NULL) || (name == NULL)) {
64 DEBUG(0, ("talloc failed\n"));
65 return False;
68 if (strequal(domain, get_global_sam_name())) {
70 /* It's our own domain, lookup the name in passdb */
71 if (lookup_global_sam_name(name, flags, &rid, &type)) {
72 sid_copy(&sid, get_global_sam_sid());
73 sid_append_rid(&sid, rid);
74 goto ok;
76 goto failed;
79 if (strequal(domain, builtin_domain_name())) {
81 /* Explicit request for a name in BUILTIN */
82 if (lookup_builtin_name(name, &rid)) {
83 sid_copy(&sid, &global_sid_Builtin);
84 sid_append_rid(&sid, rid);
85 type = SID_NAME_ALIAS;
86 goto ok;
88 goto failed;
91 /* Try the explicit winbind lookup first, don't let it guess the
92 * domain yet at this point yet. This comes later. */
94 if ((domain[0] != '\0') &&
95 (winbind_lookup_name(domain, name, &sid, &type))) {
96 goto ok;
99 if (strequal(domain, unix_users_domain_name())) {
100 if (lookup_unix_user_name(name, &sid)) {
101 type = SID_NAME_USER;
102 goto ok;
104 goto failed;
107 if (strequal(domain, unix_groups_domain_name())) {
108 if (lookup_unix_group_name(name, &sid)) {
109 type = SID_NAME_DOM_GRP;
110 goto ok;
112 goto failed;
115 if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
116 goto failed;
120 * Nasty hack necessary for too common scenarios:
122 * For 'valid users = +users' we know "users" is most probably not
123 * BUILTIN\users but the unix group users. This hack requires the
124 * admin to explicitly qualify BUILTIN if BUILTIN\users is meant.
126 * Please note that LOOKUP_NAME_GROUP can not be requested via for
127 * example lsa_lookupnames, it only comes into this routine via
128 * the expansion of group names coming in from smb.conf
131 if (flags & LOOKUP_NAME_GROUP) {
132 struct group *grp;
134 /* If we are using the smbpasswd backend, we need to use the
135 * algorithmic mapping for the unix group we find. This is
136 * necessary because when creating the NT token from the unix
137 * gid list we got from initgroups() we use gid_to_sid() that
138 * uses algorithmic mapping if pdb_rid_algorithm() is true. */
140 if (pdb_rid_algorithm() && ((grp = getgrnam(name)) != NULL) &&
141 (grp->gr_gid < max_algorithmic_gid())) {
142 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
143 sid_compose(&sid, get_global_sam_sid(),
144 pdb_gid_to_group_rid(grp->gr_gid));
145 type = SID_NAME_DOM_GRP;
146 goto ok;
149 if (lookup_unix_group_name(name, &sid)) {
150 domain = talloc_strdup(tmp_ctx,
151 unix_groups_domain_name());
152 type = SID_NAME_DOM_GRP;
153 goto ok;
157 /* Now the guesswork begins, we haven't been given an explicit
158 * domain. Try the sequence as documented on
159 * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
160 * November 27, 2005 */
162 /* 1. well-known names */
164 if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
165 type = SID_NAME_WKN_GRP;
166 goto ok;
169 /* 2. Builtin domain as such */
171 if (strequal(name, builtin_domain_name())) {
172 /* Swap domain and name */
173 tmp = name; name = domain; domain = tmp;
174 sid_copy(&sid, &global_sid_Builtin);
175 type = SID_NAME_DOMAIN;
176 goto ok;
179 /* 3. Account domain */
181 if (strequal(name, get_global_sam_name())) {
182 if (!secrets_fetch_domain_sid(name, &sid)) {
183 DEBUG(3, ("Could not fetch my SID\n"));
184 goto failed;
186 /* Swap domain and name */
187 tmp = name; name = domain; domain = tmp;
188 type = SID_NAME_DOMAIN;
189 goto ok;
192 /* 4. Primary domain */
194 if (!IS_DC && strequal(name, lp_workgroup())) {
195 if (!secrets_fetch_domain_sid(name, &sid)) {
196 DEBUG(3, ("Could not fetch the domain SID\n"));
197 goto failed;
199 /* Swap domain and name */
200 tmp = name; name = domain; domain = tmp;
201 type = SID_NAME_DOMAIN;
202 goto ok;
205 /* 5. Trusted domains as such, to me it looks as if members don't do
206 this, tested an XP workstation in a NT domain -- vl */
208 if (IS_DC && (secrets_fetch_trusted_domain_password(name, NULL,
209 &sid, NULL))) {
210 /* Swap domain and name */
211 tmp = name; name = domain; domain = tmp;
212 type = SID_NAME_DOMAIN;
213 goto ok;
216 /* 6. Builtin aliases */
218 if (lookup_builtin_name(name, &rid)) {
219 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
220 sid_copy(&sid, &global_sid_Builtin);
221 sid_append_rid(&sid, rid);
222 type = SID_NAME_ALIAS;
223 goto ok;
226 /* 7. Local systems' SAM (DCs don't have a local SAM) */
227 /* 8. Primary SAM (On members, this is the domain) */
229 /* Both cases are done by looking at our passdb */
231 if (lookup_global_sam_name(name, flags, &rid, &type)) {
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;
238 /* Now our local possibilities are exhausted. */
240 if (!(flags & LOOKUP_NAME_REMOTE)) {
241 goto failed;
244 /* If we are not a DC, we have to ask in our primary domain. Let
245 * winbind do that. */
247 if (!IS_DC &&
248 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
249 domain = talloc_strdup(tmp_ctx, lp_workgroup());
250 goto ok;
253 /* 9. Trusted domains */
255 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
256 * that (yet), but give it a chance. */
258 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
259 DOM_SID dom_sid;
260 uint32 tmp_rid;
261 enum SID_NAME_USE domain_type;
263 if (type == SID_NAME_DOMAIN) {
264 /* Swap name and type */
265 tmp = name; name = domain; domain = tmp;
266 goto ok;
269 /* Here we have to cope with a little deficiency in the
270 * winbind API: We have to ask it again for the name of the
271 * domain it figured out itself. Maybe fix that later... */
273 sid_copy(&dom_sid, &sid);
274 sid_split_rid(&dom_sid, &tmp_rid);
276 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
277 &domain_type) ||
278 (domain_type != SID_NAME_DOMAIN)) {
279 DEBUG(2, ("winbind could not find the domain's name "
280 "it just looked up for us\n"));
281 goto failed;
283 goto ok;
286 /* 10. Don't translate */
288 /* 11. Ok, windows would end here. Samba has two more options:
289 Unmapped users and unmapped groups */
291 if (lookup_unix_user_name(name, &sid)) {
292 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
293 type = SID_NAME_USER;
294 goto ok;
297 if (lookup_unix_group_name(name, &sid)) {
298 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
299 type = SID_NAME_DOM_GRP;
300 goto ok;
303 failed:
304 TALLOC_FREE(tmp_ctx);
305 return False;
308 if ((domain == NULL) || (name == NULL)) {
309 DEBUG(0, ("talloc failed\n"));
310 TALLOC_FREE(tmp_ctx);
311 return False;
314 if (ret_name != NULL) {
315 *ret_name = talloc_steal(mem_ctx, name);
318 if (ret_domain != NULL) {
319 char *tmp_dom = talloc_strdup(tmp_ctx, domain);
320 strupper_m(tmp_dom);
321 *ret_domain = talloc_steal(mem_ctx, tmp_dom);
324 if (ret_sid != NULL) {
325 sid_copy(ret_sid, &sid);
328 if (ret_type != NULL) {
329 *ret_type = type;
332 TALLOC_FREE(tmp_ctx);
333 return True;
336 static BOOL winbind_lookup_rids(TALLOC_CTX *mem_ctx,
337 const DOM_SID *domain_sid,
338 int num_rids, uint32 *rids,
339 const char **domain_name,
340 const char **names, uint32 *types)
342 /* Unless the winbind interface is upgraded, fall back to ask for
343 * individual sids. I imagine introducing a lookuprids operation that
344 * directly proxies to lsa_lookupsids to the correct DC. -- vl */
346 int i;
347 for (i=0; i<num_rids; i++) {
348 DOM_SID sid;
350 sid_copy(&sid, domain_sid);
351 sid_append_rid(&sid, rids[i]);
353 if (winbind_lookup_sid(mem_ctx, &sid,
354 *domain_name == NULL ?
355 domain_name : NULL,
356 &names[i], &types[i])) {
357 if ((names[i] == NULL) || ((*domain_name) == NULL)) {
358 return False;
360 } else {
361 types[i] = SID_NAME_UNKNOWN;
364 return True;
367 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
368 int num_rids, uint32_t *rids,
369 const char **domain_name,
370 const char ***names, enum SID_NAME_USE **types)
372 int i;
374 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
375 *types = TALLOC_ARRAY(mem_ctx, enum SID_NAME_USE, num_rids);
377 if ((*names == NULL) || (*types == NULL)) {
378 return False;
381 if (sid_check_is_domain(domain_sid)) {
382 NTSTATUS result;
384 if (*domain_name == NULL) {
385 *domain_name = talloc_strdup(
386 mem_ctx, get_global_sam_name());
389 if (*domain_name == NULL) {
390 return False;
393 become_root();
394 result = pdb_lookup_rids(domain_sid, num_rids, rids,
395 *names, *types);
396 unbecome_root();
398 return (NT_STATUS_IS_OK(result) ||
399 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
400 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
403 if (sid_check_is_builtin(domain_sid)) {
405 if (*domain_name == NULL) {
406 *domain_name = talloc_strdup(
407 mem_ctx, builtin_domain_name());
410 if (*domain_name == NULL) {
411 return False;
414 for (i=0; i<num_rids; i++) {
415 if (lookup_builtin_rid(*names, rids[i],
416 &(*names)[i])) {
417 if ((*names)[i] == NULL) {
418 return False;
420 (*types)[i] = SID_NAME_ALIAS;
421 } else {
422 (*types)[i] = SID_NAME_UNKNOWN;
425 return True;
428 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
429 for (i=0; i<num_rids; i++) {
430 DOM_SID sid;
431 sid_copy(&sid, domain_sid);
432 sid_append_rid(&sid, rids[i]);
433 if (lookup_wellknown_sid(mem_ctx, &sid,
434 domain_name, &(*names)[i])) {
435 if ((*names)[i] == NULL) {
436 return False;
438 (*types)[i] = SID_NAME_WKN_GRP;
439 } else {
440 (*types)[i] = SID_NAME_UNKNOWN;
443 return True;
446 if (sid_check_is_unix_users(domain_sid)) {
447 if (*domain_name == NULL) {
448 *domain_name = talloc_strdup(
449 mem_ctx, unix_users_domain_name());
451 for (i=0; i<num_rids; i++) {
452 (*names)[i] = talloc_strdup(
453 (*names), uidtoname(rids[i]));
454 (*types)[i] = SID_NAME_USER;
456 return True;
459 if (sid_check_is_unix_groups(domain_sid)) {
460 if (*domain_name == NULL) {
461 *domain_name = talloc_strdup(
462 mem_ctx, unix_groups_domain_name());
464 for (i=0; i<num_rids; i++) {
465 (*names)[i] = talloc_strdup(
466 (*names), gidtoname(rids[i]));
467 (*types)[i] = SID_NAME_DOM_GRP;
469 return True;
472 return winbind_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
473 domain_name, *names, *types);
477 * Is the SID a domain as such? If yes, lookup its name.
480 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
481 const char **name)
483 const char *tmp;
484 enum SID_NAME_USE type;
486 if (sid_check_is_domain(sid)) {
487 *name = talloc_strdup(mem_ctx, get_global_sam_name());
488 return True;
491 if (sid_check_is_builtin(sid)) {
492 *name = talloc_strdup(mem_ctx, builtin_domain_name());
493 return True;
496 if (sid_check_is_wellknown_domain(sid, &tmp)) {
497 *name = talloc_strdup(mem_ctx, tmp);
498 return True;
501 if (sid->num_auths != 4) {
502 /* This can't be a domain */
503 return False;
506 if (IS_DC) {
507 uint32 i, num_domains;
508 struct trustdom_info **domains;
510 /* This is relatively expensive, but it happens only on DCs
511 * and for SIDs that have 4 sub-authorities and thus look like
512 * domains */
514 if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx,
515 &num_domains,
516 &domains))) {
517 return False;
520 for (i=0; i<num_domains; i++) {
521 if (sid_equal(sid, &domains[i]->sid)) {
522 *name = talloc_strdup(mem_ctx,
523 domains[i]->name);
524 return True;
527 return False;
530 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
531 (type == SID_NAME_DOMAIN)) {
532 *name = tmp;
533 return True;
536 return False;
540 * This tries to implement the rather weird rules for the lsa_lookup level
541 * parameter.
543 * This is as close as we can get to what W2k3 does. With this we survive the
544 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
545 * different, but I assume that's just being too liberal. For example, W2k3
546 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
547 * whereas NT4 does the same as level 1 (I think). I did not fully test that
548 * with NT4, this is what w2k3 does.
550 * Level 1: Ask everywhere
551 * Level 2: Ask domain and trusted domains, no builtin and wkn
552 * Level 3: Only ask domain
553 * Level 4: W2k3ad: Only ask AD trusts
554 * Level 5: Don't lookup anything
555 * Level 6: Like 4
558 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
560 int ret = False;
562 switch(level) {
563 case 1:
564 ret = True;
565 break;
566 case 2:
567 ret = (!sid_check_is_builtin(sid) &&
568 !sid_check_is_wellknown_domain(sid, NULL));
569 break;
570 case 3:
571 case 4:
572 case 6:
573 ret = sid_check_is_domain(sid);
574 break;
575 case 5:
576 ret = False;
577 break;
580 DEBUG(10, ("%s SID %s in level %d\n",
581 ret ? "Accepting" : "Rejecting",
582 sid_string_static(sid), level));
583 return ret;
587 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
588 * references to domains, it is explicitly made for this.
590 * This attempts to be as efficient as possible: It collects all SIDs
591 * belonging to a domain and hands them in bulk to the appropriate lookup
592 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
593 * *hugely* from this. Winbind is going to be extended with a lookup_rids
594 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
595 * appropriate DC.
598 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
599 const DOM_SID **sids, int level,
600 struct lsa_dom_info **ret_domains,
601 struct lsa_name_info **ret_names)
603 TALLOC_CTX *tmp_ctx;
604 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
605 struct lsa_name_info *name_infos;
606 struct lsa_dom_info *dom_infos;
608 int i, j;
610 tmp_ctx = talloc_new(mem_ctx);
611 if (tmp_ctx == NULL) {
612 DEBUG(0, ("talloc_new failed\n"));
613 return NT_STATUS_NO_MEMORY;
616 name_infos = TALLOC_ARRAY(tmp_ctx, struct lsa_name_info, num_sids);
617 dom_infos = TALLOC_ZERO_ARRAY(tmp_ctx, struct lsa_dom_info,
618 MAX_REF_DOMAINS);
619 if ((name_infos == NULL) || (dom_infos == NULL)) {
620 result = NT_STATUS_NO_MEMORY;
621 goto done;
624 /* First build up the data structures:
626 * dom_infos is a list of domains referenced in the list of
627 * SIDs. Later we will walk the list of domains and look up the RIDs
628 * in bulk.
630 * name_infos is a shadow-copy of the SIDs array to collect the real
631 * data.
633 * dom_info->idxs is an index into the name_infos array. The
634 * difficulty we have here is that we need to keep the SIDs the client
635 * asked for in the same order for the reply
638 for (i=0; i<num_sids; i++) {
639 DOM_SID sid;
640 uint32 rid;
641 const char *domain_name = NULL;
643 sid_copy(&sid, sids[i]);
644 name_infos[i].type = SID_NAME_USE_NONE;
646 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
647 /* We can't push that through the normal lookup
648 * process, as this would reference illegal
649 * domains.
651 * For example S-1-5-32 would end up referencing
652 * domain S-1-5- with RID 32 which is clearly wrong.
654 if (domain_name == NULL) {
655 result = NT_STATUS_NO_MEMORY;
656 goto done;
659 name_infos[i].rid = 0;
660 name_infos[i].type = SID_NAME_DOMAIN;
661 name_infos[i].name = NULL;
663 if (sid_check_is_builtin(&sid)) {
664 /* Yes, W2k3 returns "BUILTIN" both as domain
665 * and name here */
666 name_infos[i].name = talloc_strdup(
667 name_infos, builtin_domain_name());
668 if (name_infos[i].name == NULL) {
669 result = NT_STATUS_NO_MEMORY;
670 goto done;
673 } else {
674 /* This is a normal SID with rid component */
675 if (!sid_split_rid(&sid, &rid)) {
676 result = NT_STATUS_INVALID_PARAMETER;
677 goto done;
681 if (!check_dom_sid_to_level(&sid, level)) {
682 name_infos[i].rid = 0;
683 name_infos[i].type = SID_NAME_UNKNOWN;
684 name_infos[i].name = NULL;
685 continue;
688 for (j=0; j<MAX_REF_DOMAINS; j++) {
689 if (!dom_infos[j].valid) {
690 break;
692 if (sid_equal(&sid, &dom_infos[j].sid)) {
693 break;
697 if (j == MAX_REF_DOMAINS) {
698 /* TODO: What's the right error message here? */
699 result = NT_STATUS_NONE_MAPPED;
700 goto done;
703 if (!dom_infos[j].valid) {
704 /* We found a domain not yet referenced, create a new
705 * ref. */
706 dom_infos[j].valid = True;
707 sid_copy(&dom_infos[j].sid, &sid);
709 if (domain_name != NULL) {
710 /* This name was being found above in the case
711 * when we found a domain SID */
712 dom_infos[j].name =
713 talloc_steal(dom_infos, domain_name);
714 } else {
715 /* lookup_rids will take care of this */
716 dom_infos[j].name = NULL;
720 name_infos[i].dom_idx = j;
722 if (name_infos[i].type == SID_NAME_USE_NONE) {
723 name_infos[i].rid = rid;
725 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
726 &dom_infos[j].num_idxs);
728 if (dom_infos[j].idxs == NULL) {
729 result = NT_STATUS_NO_MEMORY;
730 goto done;
735 /* Iterate over the domains found */
737 for (i=0; i<MAX_REF_DOMAINS; i++) {
738 uint32_t *rids;
739 const char **names;
740 enum SID_NAME_USE *types;
741 struct lsa_dom_info *dom = &dom_infos[i];
743 if (!dom->valid) {
744 /* No domains left, we're done */
745 break;
748 rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs);
750 if (rids == NULL) {
751 result = NT_STATUS_NO_MEMORY;
752 goto done;
755 for (j=0; j<dom->num_idxs; j++) {
756 rids[j] = name_infos[dom->idxs[j]].rid;
759 if (!lookup_rids(tmp_ctx, &dom->sid,
760 dom->num_idxs, rids, &dom->name,
761 &names, &types)) {
762 result = NT_STATUS_NO_MEMORY;
763 goto done;
766 talloc_steal(dom_infos, dom->name);
768 for (j=0; j<dom->num_idxs; j++) {
769 int idx = dom->idxs[j];
770 name_infos[idx].type = types[j];
771 if (types[j] != SID_NAME_UNKNOWN) {
772 name_infos[idx].name =
773 talloc_steal(name_infos, names[j]);
774 } else {
775 name_infos[idx].name = NULL;
780 *ret_domains = talloc_steal(mem_ctx, dom_infos);
781 *ret_names = talloc_steal(mem_ctx, name_infos);
782 result = NT_STATUS_OK;
784 done:
785 TALLOC_FREE(tmp_ctx);
786 return result;
789 /*****************************************************************
790 *THE CANONICAL* convert SID to name function.
791 *****************************************************************/
793 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
794 const char **ret_domain, const char **ret_name,
795 enum SID_NAME_USE *ret_type)
797 struct lsa_dom_info *domain;
798 struct lsa_name_info *name;
799 TALLOC_CTX *tmp_ctx;
800 BOOL ret = False;
802 tmp_ctx = talloc_new(mem_ctx);
804 if (tmp_ctx == NULL) {
805 DEBUG(0, ("talloc_new failed\n"));
806 return False;
809 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
810 &domain, &name))) {
811 goto done;
814 if (name->type == SID_NAME_UNKNOWN) {
815 goto done;
818 if (ret_domain != NULL) {
819 *ret_domain = talloc_steal(mem_ctx, domain->name);
822 if (ret_name != NULL) {
823 *ret_name = talloc_steal(mem_ctx, name->name);
826 if (ret_type != NULL) {
827 *ret_type = name->type;
830 ret = True;
832 done:
833 if (ret) {
834 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
835 sid_string_static(sid), domain->name,
836 name->name, name->type));
837 } else {
838 DEBUG(10, ("failed to lookup sid %s\n",
839 sid_string_static(sid)));
841 TALLOC_FREE(tmp_ctx);
842 return ret;
845 /*****************************************************************
846 Id mapping cache. This is to avoid Winbind mappings already
847 seen by smbd to be queried too frequently, keeping winbindd
848 busy, and blocking smbd while winbindd is busy with other
849 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
850 modified to use linked lists by jra.
851 *****************************************************************/
853 #define MAX_UID_SID_CACHE_SIZE 100
854 #define TURNOVER_UID_SID_CACHE_SIZE 10
855 #define MAX_GID_SID_CACHE_SIZE 100
856 #define TURNOVER_GID_SID_CACHE_SIZE 10
858 static size_t n_uid_sid_cache = 0;
859 static size_t n_gid_sid_cache = 0;
861 static struct uid_sid_cache {
862 struct uid_sid_cache *next, *prev;
863 uid_t uid;
864 DOM_SID sid;
865 enum SID_NAME_USE sidtype;
866 } *uid_sid_cache_head;
868 static struct gid_sid_cache {
869 struct gid_sid_cache *next, *prev;
870 gid_t gid;
871 DOM_SID sid;
872 enum SID_NAME_USE sidtype;
873 } *gid_sid_cache_head;
875 /*****************************************************************
876 Find a SID given a uid.
877 *****************************************************************/
879 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
881 struct uid_sid_cache *pc;
883 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
884 if (pc->uid == uid) {
885 *psid = pc->sid;
886 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
887 (unsigned int)uid, sid_string_static(psid)));
888 DLIST_PROMOTE(uid_sid_cache_head, pc);
889 return True;
892 return False;
895 /*****************************************************************
896 Find a uid given a SID.
897 *****************************************************************/
899 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
901 struct uid_sid_cache *pc;
903 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
904 if (sid_compare(&pc->sid, psid) == 0) {
905 *puid = pc->uid;
906 DEBUG(3,("fetch uid from cache %u -> %s\n",
907 (unsigned int)*puid, sid_string_static(psid)));
908 DLIST_PROMOTE(uid_sid_cache_head, pc);
909 return True;
912 return False;
915 /*****************************************************************
916 Store uid to SID mapping in cache.
917 *****************************************************************/
919 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
921 struct uid_sid_cache *pc;
923 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
924 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
925 struct uid_sid_cache *pc_next;
926 size_t i;
928 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
930 for(; pc; pc = pc_next) {
931 pc_next = pc->next;
932 DLIST_REMOVE(uid_sid_cache_head,pc);
933 SAFE_FREE(pc);
934 n_uid_sid_cache--;
938 pc = SMB_MALLOC_P(struct uid_sid_cache);
939 if (!pc)
940 return;
941 pc->uid = uid;
942 sid_copy(&pc->sid, psid);
943 DLIST_ADD(uid_sid_cache_head, pc);
944 n_uid_sid_cache++;
947 /*****************************************************************
948 Find a SID given a gid.
949 *****************************************************************/
951 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
953 struct gid_sid_cache *pc;
955 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
956 if (pc->gid == gid) {
957 *psid = pc->sid;
958 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
959 (unsigned int)gid, sid_string_static(psid)));
960 DLIST_PROMOTE(gid_sid_cache_head, pc);
961 return True;
964 return False;
967 /*****************************************************************
968 Find a gid given a SID.
969 *****************************************************************/
971 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
973 struct gid_sid_cache *pc;
975 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
976 if (sid_compare(&pc->sid, psid) == 0) {
977 *pgid = pc->gid;
978 DEBUG(3,("fetch gid from cache %u -> %s\n",
979 (unsigned int)*pgid, sid_string_static(psid)));
980 DLIST_PROMOTE(gid_sid_cache_head, pc);
981 return True;
984 return False;
987 /*****************************************************************
988 Store gid to SID mapping in cache.
989 *****************************************************************/
991 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
993 struct gid_sid_cache *pc;
995 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
996 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
997 struct gid_sid_cache *pc_next;
998 size_t i;
1000 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1002 for(; pc; pc = pc_next) {
1003 pc_next = pc->next;
1004 DLIST_REMOVE(gid_sid_cache_head,pc);
1005 SAFE_FREE(pc);
1006 n_gid_sid_cache--;
1010 pc = SMB_MALLOC_P(struct gid_sid_cache);
1011 if (!pc)
1012 return;
1013 pc->gid = gid;
1014 sid_copy(&pc->sid, psid);
1015 DLIST_ADD(gid_sid_cache_head, pc);
1016 n_gid_sid_cache++;
1019 /*****************************************************************
1020 *THE CANONICAL* convert uid_t to SID function.
1021 *****************************************************************/
1023 void uid_to_sid(DOM_SID *psid, uid_t uid)
1025 uid_t low, high;
1026 uint32 rid;
1028 ZERO_STRUCTP(psid);
1030 if (fetch_sid_from_uid_cache(psid, uid))
1031 return;
1033 if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) &&
1034 winbind_uid_to_sid(psid, uid)) {
1036 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
1037 (unsigned int)uid, sid_string_static(psid)));
1038 goto done;
1041 if (pdb_uid_to_rid(uid, &rid)) {
1042 /* This is a mapped user */
1043 sid_copy(psid, get_global_sam_sid());
1044 sid_append_rid(psid, rid);
1045 goto done;
1048 if (pdb_rid_algorithm() && (uid < max_algorithmic_uid())) {
1049 sid_copy(psid, get_global_sam_sid());
1050 sid_append_rid(psid, algorithmic_pdb_uid_to_user_rid(uid));
1051 goto done;
1052 } else {
1053 sid_copy(psid, &global_sid_Unix_Users);
1054 sid_append_rid(psid, uid);
1055 goto done;
1058 done:
1059 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
1060 sid_string_static(psid)));
1062 store_uid_sid_cache(psid, uid);
1063 return;
1066 /*****************************************************************
1067 *THE CANONICAL* convert gid_t to SID function.
1068 *****************************************************************/
1070 void gid_to_sid(DOM_SID *psid, gid_t gid)
1072 gid_t low, high;
1074 ZERO_STRUCTP(psid);
1076 if (fetch_sid_from_gid_cache(psid, gid))
1077 return;
1079 if (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high) &&
1080 winbind_gid_to_sid(psid, gid)) {
1082 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
1083 (unsigned int)gid, sid_string_static(psid)));
1084 goto done;
1087 if (pdb_gid_to_sid(gid, psid)) {
1088 /* This is a mapped group */
1089 goto done;
1092 if (pdb_rid_algorithm() && (gid < max_algorithmic_gid())) {
1093 sid_copy(psid, get_global_sam_sid());
1094 sid_append_rid(psid, pdb_gid_to_group_rid(gid));
1095 goto done;
1096 } else {
1097 sid_copy(psid, &global_sid_Unix_Groups);
1098 sid_append_rid(psid, gid);
1099 goto done;
1102 done:
1103 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
1104 sid_string_static(psid)));
1106 store_gid_sid_cache(psid, gid);
1107 return;
1110 /*****************************************************************
1111 *THE CANONICAL* convert SID to uid function.
1112 *****************************************************************/
1114 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1116 enum SID_NAME_USE type;
1117 uint32 rid;
1118 gid_t gid;
1120 if (fetch_uid_from_cache(puid, psid))
1121 return True;
1123 if (fetch_gid_from_cache(&gid, psid)) {
1124 return False;
1127 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1128 uid_t uid = rid;
1129 *puid = uid;
1130 goto done;
1133 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1134 union unid_t id;
1136 if (pdb_sid_to_id(psid, &id, &type)) {
1137 if (type != SID_NAME_USER) {
1138 DEBUG(5, ("sid %s is a %s, expected a user\n",
1139 sid_string_static(psid),
1140 sid_type_lookup(type)));
1141 return False;
1143 *puid = id.uid;
1144 goto done;
1146 if (pdb_rid_algorithm() &&
1147 algorithmic_pdb_rid_is_user(rid)) {
1148 *puid = algorithmic_pdb_user_rid_to_uid(rid);
1149 goto done;
1152 /* This was ours, but it was neither mapped nor
1153 * algorithmic. Fail */
1154 return False;
1157 if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1159 if (type != SID_NAME_USER) {
1160 DEBUG(10, ("sid_to_uid: sid %s is a %s\n",
1161 sid_string_static(psid),
1162 sid_type_lookup(type)));
1163 return False;
1166 if (!winbind_sid_to_uid(puid, psid)) {
1167 DEBUG(5, ("sid_to_uid: winbind failed to allocate a "
1168 "new uid for sid %s\n",
1169 sid_string_static(psid)));
1170 return False;
1172 goto done;
1175 /* TODO: Here would be the place to allocate both a gid and a uid for
1176 * the SID in question */
1178 return False;
1180 done:
1181 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
1182 (unsigned int)*puid ));
1184 store_uid_sid_cache(psid, *puid);
1185 return True;
1188 /*****************************************************************
1189 *THE CANONICAL* convert SID to gid function.
1190 Group mapping is used for gids that maps to Wellknown SIDs
1191 *****************************************************************/
1193 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1195 uint32 rid;
1196 GROUP_MAP map;
1197 union unid_t id;
1198 enum SID_NAME_USE type;
1199 uid_t uid;
1201 if (fetch_gid_from_cache(pgid, psid))
1202 return True;
1204 if (fetch_uid_from_cache(&uid, psid))
1205 return False;
1207 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1208 gid_t gid = rid;
1209 *pgid = gid;
1210 goto done;
1213 if ((sid_check_is_in_builtin(psid) ||
1214 sid_check_is_in_wellknown_domain(psid))) {
1215 if (pdb_getgrsid(&map, *psid)) {
1216 *pgid = map.gid;
1217 goto done;
1219 return False;
1222 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1223 if (pdb_sid_to_id(psid, &id, &type)) {
1224 if ((type != SID_NAME_DOM_GRP) &&
1225 (type != SID_NAME_ALIAS)) {
1226 DEBUG(5, ("sid %s is a %s, expected a group\n",
1227 sid_string_static(psid),
1228 sid_type_lookup(type)));
1229 return False;
1231 *pgid = id.gid;
1232 goto done;
1234 if (pdb_rid_algorithm() &&
1235 !algorithmic_pdb_rid_is_user(rid)) {
1236 /* This must be a group, presented as alias */
1237 *pgid = pdb_group_rid_to_gid(rid);
1238 goto done;
1240 /* This was ours, but it was neither mapped nor
1241 * algorithmic. Fail. */
1242 return False;
1245 if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1246 DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, "
1247 "then winbind)\n", sid_string_static(psid)));
1249 return False;
1252 /* winbindd knows it; Ensure this is a group sid */
1254 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
1255 (type != SID_NAME_WKN_GRP)) {
1256 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is "
1257 "a %s\n", sid_type_lookup(type)));
1258 return False;
1261 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
1262 or we are dead in the water */
1264 if ( !winbind_sid_to_gid(pgid, psid) ) {
1265 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid "
1266 "for sid %s\n", sid_string_static(psid)));
1267 return False;
1270 done:
1271 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
1272 (unsigned int)*pgid ));
1274 store_gid_sid_cache(psid, *pgid);
1276 return True;