Properly destroy the pdb search object
[Samba.git] / source / passdb / lookup_sid.c
blob55dd654131cf7d5596379a40832f0fd809076cd8
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 3 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, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
24 /*****************************************************************
25 Dissect a user-provided name into domain, name, sid and type.
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 *****************************************************************/
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)
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);
46 if (tmp_ctx == NULL) {
47 DEBUG(0, ("talloc_new failed\n"));
48 return false;
51 p = strchr_m(full_name, '\\');
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);
62 if ((domain == NULL) || (name == NULL)) {
63 DEBUG(0, ("talloc failed\n"));
64 TALLOC_FREE(tmp_ctx);
65 return false;
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));
72 if ((flags & LOOKUP_NAME_DOMAIN) &&
73 strequal(domain, get_global_sam_name()))
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;
82 TALLOC_FREE(tmp_ctx);
83 return false;
86 if ((flags & LOOKUP_NAME_BUILTIN) &&
87 strequal(domain, builtin_domain_name()))
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;
96 TALLOC_FREE(tmp_ctx);
97 return false;
100 /* Try the explicit winbind lookup first, don't let it guess the
101 * domain yet at this point yet. This comes later. */
103 if ((domain[0] != '\0') &&
104 (flags & ~(LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED)) &&
105 (winbind_lookup_name(domain, name, &sid, &type))) {
106 goto ok;
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;
114 TALLOC_FREE(tmp_ctx);
115 return false;
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;
123 TALLOC_FREE(tmp_ctx);
124 return false;
127 if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
128 TALLOC_FREE(tmp_ctx);
129 return false;
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 */
137 /* 1. well-known names */
139 if ((flags & LOOKUP_NAME_WKN) &&
140 lookup_wellknown_name(tmp_ctx, name, &sid, &domain))
142 type = SID_NAME_WKN_GRP;
143 goto ok;
146 /* 2. Builtin domain as such */
148 if ((flags & (LOOKUP_NAME_BUILTIN|LOOKUP_NAME_REMOTE)) &&
149 strequal(name, builtin_domain_name()))
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;
158 /* 3. Account domain */
160 if ((flags & LOOKUP_NAME_DOMAIN) &&
161 strequal(name, get_global_sam_name()))
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;
168 /* Swap domain and name */
169 tmp = name; name = domain; domain = tmp;
170 type = SID_NAME_DOMAIN;
171 goto ok;
174 /* 4. Primary domain */
176 if ((flags & LOOKUP_NAME_DOMAIN) && !IS_DC &&
177 strequal(name, lp_workgroup()))
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;
184 /* Swap domain and name */
185 tmp = name; name = domain; domain = tmp;
186 type = SID_NAME_DOMAIN;
187 goto ok;
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 */
193 if ((flags & LOOKUP_NAME_REMOTE) && IS_DC &&
194 (pdb_get_trusteddom_pw(name, NULL, &sid, NULL)))
196 /* Swap domain and name */
197 tmp = name; name = domain; domain = tmp;
198 type = SID_NAME_DOMAIN;
199 goto ok;
202 /* 6. Builtin aliases */
204 if ((flags & LOOKUP_NAME_BUILTIN) &&
205 lookup_builtin_name(name, &rid))
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;
214 /* 7. Local systems' SAM (DCs don't have a local SAM) */
215 /* 8. Primary SAM (On members, this is the domain) */
217 /* Both cases are done by looking at our passdb */
219 if ((flags & LOOKUP_NAME_DOMAIN) &&
220 lookup_global_sam_name(name, flags, &rid, &type))
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;
228 /* Now our local possibilities are exhausted. */
230 if (!(flags & LOOKUP_NAME_REMOTE)) {
231 TALLOC_FREE(tmp_ctx);
232 return false;
235 /* If we are not a DC, we have to ask in our primary domain. Let
236 * winbind do that. */
238 if (!IS_DC &&
239 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
240 domain = talloc_strdup(tmp_ctx, lp_workgroup());
241 goto ok;
244 /* 9. Trusted domains */
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. */
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;
254 if (type == SID_NAME_DOMAIN) {
255 /* Swap name and type */
256 tmp = name; name = domain; domain = tmp;
257 goto ok;
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... */
264 sid_copy(&dom_sid, &sid);
265 sid_split_rid(&dom_sid, &tmp_rid);
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;
275 goto ok;
278 /* 10. Don't translate */
280 /* 11. Ok, windows would end here. Samba has two more options:
281 Unmapped users and unmapped groups */
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;
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;
296 * Ok, all possibilities tried. Fail.
299 TALLOC_FREE(tmp_ctx);
300 return false;
303 if ((domain == NULL) || (name == NULL)) {
304 DEBUG(0, ("talloc failed\n"));
305 TALLOC_FREE(tmp_ctx);
306 return false;
310 * Hand over the results to the talloc context we've been given.
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;
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;
327 strupper_m(tmp_dom);
328 *ret_domain = tmp_dom;
331 if (ret_sid != NULL) {
332 sid_copy(ret_sid, &sid);
335 if (ret_type != NULL) {
336 *ret_type = type;
339 TALLOC_FREE(tmp_ctx);
340 return true;
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 ************************************************************************/
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)
354 char *qualified_name;
355 const char *p;
357 /* NB. No winbindd_separator here as lookup_name needs \\' */
358 if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
360 /* The name is already qualified with a domain. */
362 if (*lp_winbind_separator() != '\\') {
363 char *tmp;
365 /* lookup_name() needs '\\' as a separator */
367 tmp = talloc_strdup(mem_ctx, full_name);
368 if (!tmp) {
369 return false;
371 tmp[p - full_name] = '\\';
372 full_name = tmp;
375 return lookup_name(mem_ctx, full_name, flags,
376 ret_domain, ret_name,
377 ret_sid, ret_type);
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;
388 if (lookup_name(mem_ctx, qualified_name, flags,
389 ret_domain, ret_name,
390 ret_sid, ret_type)) {
391 return true;
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;
404 return lookup_name(mem_ctx, qualified_name, flags,
405 ret_domain, ret_name,
406 ret_sid, ret_type);
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)
415 int i;
416 const char **my_names;
417 enum lsa_SidType *my_types;
418 TALLOC_CTX *tmp_ctx;
420 if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
421 return false;
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;
431 TALLOC_FREE(tmp_ctx);
432 return true;
435 if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
436 TALLOC_FREE(tmp_ctx);
437 return false;
441 * winbind_lookup_rids allocates its own array. We've been given the
442 * array, so copy it over
445 for (i=0; i<num_rids; i++) {
446 if (my_names[i] == NULL) {
447 TALLOC_FREE(tmp_ctx);
448 return false;
450 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
451 TALLOC_FREE(tmp_ctx);
452 return false;
454 types[i] = my_types[i];
456 TALLOC_FREE(tmp_ctx);
457 return true;
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)
465 int i;
467 if (num_rids) {
468 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
469 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
471 if ((*names == NULL) || (*types == NULL)) {
472 return false;
474 } else {
475 *names = NULL;
476 *types = NULL;
479 if (sid_check_is_domain(domain_sid)) {
480 NTSTATUS result;
482 if (*domain_name == NULL) {
483 *domain_name = talloc_strdup(
484 mem_ctx, get_global_sam_name());
487 if (*domain_name == NULL) {
488 return false;
491 become_root();
492 result = pdb_lookup_rids(domain_sid, num_rids, rids,
493 *names, *types);
494 unbecome_root();
496 return (NT_STATUS_IS_OK(result) ||
497 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
498 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
501 if (sid_check_is_builtin(domain_sid)) {
503 if (*domain_name == NULL) {
504 *domain_name = talloc_strdup(
505 mem_ctx, builtin_domain_name());
508 if (*domain_name == NULL) {
509 return false;
512 for (i=0; i<num_rids; i++) {
513 if (lookup_builtin_rid(*names, rids[i],
514 &(*names)[i])) {
515 if ((*names)[i] == NULL) {
516 return false;
518 (*types)[i] = SID_NAME_ALIAS;
519 } else {
520 (*types)[i] = SID_NAME_UNKNOWN;
523 return true;
526 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
527 for (i=0; i<num_rids; i++) {
528 DOM_SID sid;
529 sid_copy(&sid, domain_sid);
530 sid_append_rid(&sid, rids[i]);
531 if (lookup_wellknown_sid(mem_ctx, &sid,
532 domain_name, &(*names)[i])) {
533 if ((*names)[i] == NULL) {
534 return false;
536 (*types)[i] = SID_NAME_WKN_GRP;
537 } else {
538 (*types)[i] = SID_NAME_UNKNOWN;
541 return true;
544 if (sid_check_is_unix_users(domain_sid)) {
545 if (*domain_name == NULL) {
546 *domain_name = talloc_strdup(
547 mem_ctx, unix_users_domain_name());
549 for (i=0; i<num_rids; i++) {
550 (*names)[i] = talloc_strdup(
551 (*names), uidtoname(rids[i]));
552 (*types)[i] = SID_NAME_USER;
554 return true;
557 if (sid_check_is_unix_groups(domain_sid)) {
558 if (*domain_name == NULL) {
559 *domain_name = talloc_strdup(
560 mem_ctx, unix_groups_domain_name());
562 for (i=0; i<num_rids; i++) {
563 (*names)[i] = talloc_strdup(
564 (*names), gidtoname(rids[i]));
565 (*types)[i] = SID_NAME_DOM_GRP;
567 return true;
570 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
571 domain_name, *names, *types);
575 * Is the SID a domain as such? If yes, lookup its name.
578 static bool lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
579 const char **name)
581 const char *tmp;
582 enum lsa_SidType type;
584 if (sid_check_is_domain(sid)) {
585 *name = talloc_strdup(mem_ctx, get_global_sam_name());
586 return true;
589 if (sid_check_is_builtin(sid)) {
590 *name = talloc_strdup(mem_ctx, builtin_domain_name());
591 return true;
594 if (sid_check_is_wellknown_domain(sid, &tmp)) {
595 *name = talloc_strdup(mem_ctx, tmp);
596 return true;
599 if (sid->num_auths != 4) {
600 /* This can't be a domain */
601 return false;
604 if (IS_DC) {
605 uint32 i, num_domains;
606 struct trustdom_info **domains;
608 /* This is relatively expensive, but it happens only on DCs
609 * and for SIDs that have 4 sub-authorities and thus look like
610 * domains */
612 if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
613 &num_domains,
614 &domains))) {
615 return false;
618 for (i=0; i<num_domains; i++) {
619 if (sid_equal(sid, &domains[i]->sid)) {
620 *name = talloc_strdup(mem_ctx,
621 domains[i]->name);
622 return true;
625 return false;
628 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
629 (type == SID_NAME_DOMAIN)) {
630 *name = tmp;
631 return true;
634 return false;
638 * This tries to implement the rather weird rules for the lsa_lookup level
639 * parameter.
641 * This is as close as we can get to what W2k3 does. With this we survive the
642 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
643 * different, but I assume that's just being too liberal. For example, W2k3
644 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
645 * whereas NT4 does the same as level 1 (I think). I did not fully test that
646 * with NT4, this is what w2k3 does.
648 * Level 1: Ask everywhere
649 * Level 2: Ask domain and trusted domains, no builtin and wkn
650 * Level 3: Only ask domain
651 * Level 4: W2k3ad: Only ask AD trusts
652 * Level 5: Only ask transitive forest trusts
653 * Level 6: Like 4
656 static bool check_dom_sid_to_level(const DOM_SID *sid, int level)
658 int ret = false;
660 switch(level) {
661 case 1:
662 ret = true;
663 break;
664 case 2:
665 ret = (!sid_check_is_builtin(sid) &&
666 !sid_check_is_wellknown_domain(sid, NULL));
667 break;
668 case 3:
669 case 4:
670 case 6:
671 ret = sid_check_is_domain(sid);
672 break;
673 case 5:
674 ret = false;
675 break;
678 DEBUG(10, ("%s SID %s in level %d\n",
679 ret ? "Accepting" : "Rejecting",
680 sid_string_dbg(sid), level));
681 return ret;
685 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
686 * references to domains, it is explicitly made for this.
688 * This attempts to be as efficient as possible: It collects all SIDs
689 * belonging to a domain and hands them in bulk to the appropriate lookup
690 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
691 * *hugely* from this. Winbind is going to be extended with a lookup_rids
692 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
693 * appropriate DC.
696 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
697 const DOM_SID **sids, int level,
698 struct lsa_dom_info **ret_domains,
699 struct lsa_name_info **ret_names)
701 TALLOC_CTX *tmp_ctx;
702 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
703 struct lsa_name_info *name_infos;
704 struct lsa_dom_info *dom_infos = NULL;
706 int i, j;
708 if (!(tmp_ctx = talloc_new(mem_ctx))) {
709 DEBUG(0, ("talloc_new failed\n"));
710 return NT_STATUS_NO_MEMORY;
713 if (num_sids) {
714 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
715 if (name_infos == NULL) {
716 result = NT_STATUS_NO_MEMORY;
717 goto fail;
719 } else {
720 name_infos = NULL;
723 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
724 MAX_REF_DOMAINS);
725 if (dom_infos == NULL) {
726 result = NT_STATUS_NO_MEMORY;
727 goto fail;
730 /* First build up the data structures:
732 * dom_infos is a list of domains referenced in the list of
733 * SIDs. Later we will walk the list of domains and look up the RIDs
734 * in bulk.
736 * name_infos is a shadow-copy of the SIDs array to collect the real
737 * data.
739 * dom_info->idxs is an index into the name_infos array. The
740 * difficulty we have here is that we need to keep the SIDs the client
741 * asked for in the same order for the reply
744 for (i=0; i<num_sids; i++) {
745 DOM_SID sid;
746 uint32 rid;
747 const char *domain_name = NULL;
749 sid_copy(&sid, sids[i]);
750 name_infos[i].type = SID_NAME_USE_NONE;
752 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
753 /* We can't push that through the normal lookup
754 * process, as this would reference illegal
755 * domains.
757 * For example S-1-5-32 would end up referencing
758 * domain S-1-5- with RID 32 which is clearly wrong.
760 if (domain_name == NULL) {
761 result = NT_STATUS_NO_MEMORY;
762 goto fail;
765 name_infos[i].rid = 0;
766 name_infos[i].type = SID_NAME_DOMAIN;
767 name_infos[i].name = NULL;
769 if (sid_check_is_builtin(&sid)) {
770 /* Yes, W2k3 returns "BUILTIN" both as domain
771 * and name here */
772 name_infos[i].name = talloc_strdup(
773 name_infos, builtin_domain_name());
774 if (name_infos[i].name == NULL) {
775 result = NT_STATUS_NO_MEMORY;
776 goto fail;
779 } else {
780 /* This is a normal SID with rid component */
781 if (!sid_split_rid(&sid, &rid)) {
782 result = NT_STATUS_INVALID_PARAMETER;
783 goto fail;
787 if (!check_dom_sid_to_level(&sid, level)) {
788 name_infos[i].rid = 0;
789 name_infos[i].type = SID_NAME_UNKNOWN;
790 name_infos[i].name = NULL;
791 continue;
794 for (j=0; j<MAX_REF_DOMAINS; j++) {
795 if (!dom_infos[j].valid) {
796 break;
798 if (sid_equal(&sid, &dom_infos[j].sid)) {
799 break;
803 if (j == MAX_REF_DOMAINS) {
804 /* TODO: What's the right error message here? */
805 result = NT_STATUS_NONE_MAPPED;
806 goto fail;
809 if (!dom_infos[j].valid) {
810 /* We found a domain not yet referenced, create a new
811 * ref. */
812 dom_infos[j].valid = true;
813 sid_copy(&dom_infos[j].sid, &sid);
815 if (domain_name != NULL) {
816 /* This name was being found above in the case
817 * when we found a domain SID */
818 dom_infos[j].name =
819 talloc_strdup(dom_infos, domain_name);
820 if (dom_infos[j].name == NULL) {
821 result = NT_STATUS_NO_MEMORY;
822 goto fail;
824 } else {
825 /* lookup_rids will take care of this */
826 dom_infos[j].name = NULL;
830 name_infos[i].dom_idx = j;
832 if (name_infos[i].type == SID_NAME_USE_NONE) {
833 name_infos[i].rid = rid;
835 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
836 &dom_infos[j].num_idxs);
838 if (dom_infos[j].idxs == NULL) {
839 result = NT_STATUS_NO_MEMORY;
840 goto fail;
845 /* Iterate over the domains found */
847 for (i=0; i<MAX_REF_DOMAINS; i++) {
848 uint32_t *rids;
849 const char *domain_name = NULL;
850 const char **names;
851 enum lsa_SidType *types;
852 struct lsa_dom_info *dom = &dom_infos[i];
854 if (!dom->valid) {
855 /* No domains left, we're done */
856 break;
859 if (dom->num_idxs) {
860 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
861 result = NT_STATUS_NO_MEMORY;
862 goto fail;
864 } else {
865 rids = NULL;
868 for (j=0; j<dom->num_idxs; j++) {
869 rids[j] = name_infos[dom->idxs[j]].rid;
872 if (!lookup_rids(tmp_ctx, &dom->sid,
873 dom->num_idxs, rids, &domain_name,
874 &names, &types)) {
875 result = NT_STATUS_NO_MEMORY;
876 goto fail;
879 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
880 result = NT_STATUS_NO_MEMORY;
881 goto fail;
884 for (j=0; j<dom->num_idxs; j++) {
885 int idx = dom->idxs[j];
886 name_infos[idx].type = types[j];
887 if (types[j] != SID_NAME_UNKNOWN) {
888 name_infos[idx].name =
889 talloc_strdup(name_infos, names[j]);
890 if (name_infos[idx].name == NULL) {
891 result = NT_STATUS_NO_MEMORY;
892 goto fail;
894 } else {
895 name_infos[idx].name = NULL;
900 *ret_domains = dom_infos;
901 *ret_names = name_infos;
902 TALLOC_FREE(tmp_ctx);
903 return NT_STATUS_OK;
905 fail:
906 TALLOC_FREE(dom_infos);
907 TALLOC_FREE(name_infos);
908 TALLOC_FREE(tmp_ctx);
909 return result;
912 /*****************************************************************
913 *THE CANONICAL* convert SID to name function.
914 *****************************************************************/
916 bool lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
917 const char **ret_domain, const char **ret_name,
918 enum lsa_SidType *ret_type)
920 struct lsa_dom_info *domain;
921 struct lsa_name_info *name;
922 TALLOC_CTX *tmp_ctx;
923 bool ret = false;
925 if (!(tmp_ctx = talloc_new(mem_ctx))) {
926 DEBUG(0, ("talloc_new failed\n"));
927 return false;
930 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
931 &domain, &name))) {
932 goto done;
935 if (name->type == SID_NAME_UNKNOWN) {
936 goto done;
939 if ((ret_domain != NULL) &&
940 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
941 goto done;
944 if ((ret_name != NULL) &&
945 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
946 goto done;
949 if (ret_type != NULL) {
950 *ret_type = name->type;
953 ret = true;
955 done:
956 if (ret) {
957 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n", sid_string_dbg(sid),
958 domain->name, name->name, name->type));
959 } else {
960 DEBUG(10, ("failed to lookup sid %s\n", sid_string_dbg(sid)));
962 TALLOC_FREE(tmp_ctx);
963 return ret;
966 /*****************************************************************
967 Id mapping cache. This is to avoid Winbind mappings already
968 seen by smbd to be queried too frequently, keeping winbindd
969 busy, and blocking smbd while winbindd is busy with other
970 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
971 modified to use linked lists by jra.
972 *****************************************************************/
974 /*****************************************************************
975 Find a SID given a uid.
976 *****************************************************************/
978 static bool fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
980 DATA_BLOB cache_value;
982 if (!memcache_lookup(NULL, UID_SID_CACHE,
983 data_blob_const(&uid, sizeof(uid)),
984 &cache_value)) {
985 return false;
988 SMB_ASSERT(cache_value.length == sizeof(*psid));
989 memcpy(psid, cache_value.data, sizeof(*psid));
991 return true;
994 /*****************************************************************
995 Find a uid given a SID.
996 *****************************************************************/
998 static bool fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
1000 DATA_BLOB cache_value;
1002 if (!memcache_lookup(NULL, SID_UID_CACHE,
1003 data_blob_const(psid, sizeof(*psid)),
1004 &cache_value)) {
1005 return false;
1008 SMB_ASSERT(cache_value.length == sizeof(*puid));
1009 memcpy(puid, cache_value.data, sizeof(*puid));
1011 return true;
1014 /*****************************************************************
1015 Store uid to SID mapping in cache.
1016 *****************************************************************/
1018 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1020 memcache_add(NULL, SID_UID_CACHE,
1021 data_blob_const(psid, sizeof(*psid)),
1022 data_blob_const(&uid, sizeof(uid)));
1023 memcache_add(NULL, UID_SID_CACHE,
1024 data_blob_const(&uid, sizeof(uid)),
1025 data_blob_const(psid, sizeof(*psid)));
1028 /*****************************************************************
1029 Find a SID given a gid.
1030 *****************************************************************/
1032 static bool fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1034 DATA_BLOB cache_value;
1036 if (!memcache_lookup(NULL, GID_SID_CACHE,
1037 data_blob_const(&gid, sizeof(gid)),
1038 &cache_value)) {
1039 return false;
1042 SMB_ASSERT(cache_value.length == sizeof(*psid));
1043 memcpy(psid, cache_value.data, sizeof(*psid));
1045 return true;
1048 /*****************************************************************
1049 Find a gid given a SID.
1050 *****************************************************************/
1052 static bool fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1054 DATA_BLOB cache_value;
1056 if (!memcache_lookup(NULL, SID_UID_CACHE,
1057 data_blob_const(psid, sizeof(*psid)),
1058 &cache_value)) {
1059 return false;
1062 SMB_ASSERT(cache_value.length == sizeof(*pgid));
1063 memcpy(pgid, cache_value.data, sizeof(*pgid));
1065 return true;
1068 /*****************************************************************
1069 Store gid to SID mapping in cache.
1070 *****************************************************************/
1072 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1074 memcache_add(NULL, SID_GID_CACHE,
1075 data_blob_const(psid, sizeof(*psid)),
1076 data_blob_const(&gid, sizeof(gid)));
1077 memcache_add(NULL, GID_SID_CACHE,
1078 data_blob_const(&gid, sizeof(gid)),
1079 data_blob_const(psid, sizeof(*psid)));
1082 /*****************************************************************
1083 *THE LEGACY* convert uid_t to SID function.
1084 *****************************************************************/
1086 static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1088 uint32 rid;
1089 bool ret;
1091 ZERO_STRUCTP(psid);
1093 become_root();
1094 ret = pdb_uid_to_rid(uid, &rid);
1095 unbecome_root();
1097 if (ret) {
1098 /* This is a mapped user */
1099 sid_copy(psid, get_global_sam_sid());
1100 sid_append_rid(psid, rid);
1101 goto done;
1104 /* This is an unmapped user */
1106 uid_to_unix_users_sid(uid, psid);
1108 done:
1109 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1110 sid_string_dbg(psid)));
1112 store_uid_sid_cache(psid, uid);
1113 return;
1116 /*****************************************************************
1117 *THE LEGACY* convert gid_t to SID function.
1118 *****************************************************************/
1120 static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1122 bool ret;
1124 ZERO_STRUCTP(psid);
1126 become_root();
1127 ret = pdb_gid_to_sid(gid, psid);
1128 unbecome_root();
1130 if (ret) {
1131 /* This is a mapped group */
1132 goto done;
1135 /* This is an unmapped group */
1137 gid_to_unix_groups_sid(gid, psid);
1139 done:
1140 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1141 sid_string_dbg(psid)));
1143 store_gid_sid_cache(psid, gid);
1144 return;
1147 /*****************************************************************
1148 *THE LEGACY* convert SID to uid function.
1149 *****************************************************************/
1151 static bool legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1153 enum lsa_SidType type;
1154 uint32 rid;
1156 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1157 union unid_t id;
1158 bool ret;
1160 become_root();
1161 ret = pdb_sid_to_id(psid, &id, &type);
1162 unbecome_root();
1164 if (ret) {
1165 if (type != SID_NAME_USER) {
1166 DEBUG(5, ("sid %s is a %s, expected a user\n",
1167 sid_string_dbg(psid),
1168 sid_type_lookup(type)));
1169 return false;
1171 *puid = id.uid;
1172 goto done;
1175 /* This was ours, but it was not mapped. Fail */
1178 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1179 sid_string_dbg(psid)));
1180 return false;
1182 done:
1183 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_dbg(psid),
1184 (unsigned int)*puid ));
1186 store_uid_sid_cache(psid, *puid);
1187 return true;
1190 /*****************************************************************
1191 *THE LEGACY* convert SID to gid function.
1192 Group mapping is used for gids that maps to Wellknown SIDs
1193 *****************************************************************/
1195 static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1197 uint32 rid;
1198 GROUP_MAP map;
1199 union unid_t id;
1200 enum lsa_SidType type;
1202 if ((sid_check_is_in_builtin(psid) ||
1203 sid_check_is_in_wellknown_domain(psid))) {
1204 bool ret;
1206 become_root();
1207 ret = pdb_getgrsid(&map, *psid);
1208 unbecome_root();
1210 if (ret) {
1211 *pgid = map.gid;
1212 goto done;
1214 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1215 sid_string_dbg(psid)));
1216 return false;
1219 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1220 bool ret;
1222 become_root();
1223 ret = pdb_sid_to_id(psid, &id, &type);
1224 unbecome_root();
1226 if (ret) {
1227 if ((type != SID_NAME_DOM_GRP) &&
1228 (type != SID_NAME_ALIAS)) {
1229 DEBUG(5, ("LEGACY: sid %s is a %s, expected "
1230 "a group\n", sid_string_dbg(psid),
1231 sid_type_lookup(type)));
1232 return false;
1234 *pgid = id.gid;
1235 goto done;
1238 /* This was ours, but it was not mapped. Fail */
1241 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1242 sid_string_dbg(psid)));
1243 return false;
1245 done:
1246 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_dbg(psid),
1247 (unsigned int)*pgid ));
1249 store_gid_sid_cache(psid, *pgid);
1251 return true;
1254 /*****************************************************************
1255 *THE CANONICAL* convert uid_t to SID function.
1256 *****************************************************************/
1258 void uid_to_sid(DOM_SID *psid, uid_t uid)
1260 ZERO_STRUCTP(psid);
1262 if (fetch_sid_from_uid_cache(psid, uid))
1263 return;
1265 if (!winbind_uid_to_sid(psid, uid)) {
1266 if (!winbind_ping()) {
1267 legacy_uid_to_sid(psid, uid);
1268 return;
1271 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1272 uid));
1273 return;
1276 DEBUG(10,("uid %u -> sid %s\n", (unsigned int)uid,
1277 sid_string_dbg(psid)));
1279 store_uid_sid_cache(psid, uid);
1280 return;
1283 /*****************************************************************
1284 *THE CANONICAL* convert gid_t to SID function.
1285 *****************************************************************/
1287 void gid_to_sid(DOM_SID *psid, gid_t gid)
1289 ZERO_STRUCTP(psid);
1291 if (fetch_sid_from_gid_cache(psid, gid))
1292 return;
1294 if (!winbind_gid_to_sid(psid, gid)) {
1295 if (!winbind_ping()) {
1296 legacy_gid_to_sid(psid, gid);
1297 return;
1300 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1301 gid));
1302 return;
1305 DEBUG(10,("gid %u -> sid %s\n", (unsigned int)gid,
1306 sid_string_dbg(psid)));
1308 store_gid_sid_cache(psid, gid);
1309 return;
1312 /*****************************************************************
1313 *THE CANONICAL* convert SID to uid function.
1314 *****************************************************************/
1316 bool sid_to_uid(const DOM_SID *psid, uid_t *puid)
1318 uint32 rid;
1319 gid_t gid;
1321 if (fetch_uid_from_cache(puid, psid))
1322 return true;
1324 if (fetch_gid_from_cache(&gid, psid)) {
1325 return false;
1328 /* Optimize for the Unix Users Domain
1329 * as the conversion is straightforward */
1330 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1331 uid_t uid = rid;
1332 *puid = uid;
1334 /* return here, don't cache */
1335 DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1336 (unsigned int)*puid ));
1337 return true;
1340 if (!winbind_sid_to_uid(puid, psid)) {
1341 if (!winbind_ping()) {
1342 return legacy_sid_to_uid(psid, puid);
1345 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1346 sid_string_dbg(psid)));
1347 return false;
1350 /* TODO: Here would be the place to allocate both a gid and a uid for
1351 * the SID in question */
1353 DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1354 (unsigned int)*puid ));
1356 store_uid_sid_cache(psid, *puid);
1357 return true;
1360 /*****************************************************************
1361 *THE CANONICAL* convert SID to gid function.
1362 Group mapping is used for gids that maps to Wellknown SIDs
1363 *****************************************************************/
1365 bool sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1367 uint32 rid;
1368 uid_t uid;
1370 if (fetch_gid_from_cache(pgid, psid))
1371 return true;
1373 if (fetch_uid_from_cache(&uid, psid))
1374 return false;
1376 /* Optimize for the Unix Groups Domain
1377 * as the conversion is straightforward */
1378 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1379 gid_t gid = rid;
1380 *pgid = gid;
1382 /* return here, don't cache */
1383 DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1384 (unsigned int)*pgid ));
1385 return true;
1388 /* Ask winbindd if it can map this sid to a gid.
1389 * (Idmap will check it is a valid SID and of the right type) */
1391 if ( !winbind_sid_to_gid(pgid, psid) ) {
1392 if (!winbind_ping()) {
1393 return legacy_sid_to_gid(psid, pgid);
1396 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1397 sid_string_dbg(psid)));
1398 return false;
1401 DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1402 (unsigned int)*pgid ));
1404 store_gid_sid_cache(psid, *pgid);
1406 return true;