ntlm_auth: Fix another typo in the test.
[Samba.git] / source / passdb / lookup_sid.c
blob9f66eb934e46622337a1c1259bd9b5eedef5608f
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 DEBUG(10, ("lookup_rids called for domain sid '%s'\n",
468 sid_string_dbg(domain_sid)));
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);
474 if ((*names == NULL) || (*types == NULL)) {
475 return false;
477 } else {
478 *names = NULL;
479 *types = NULL;
482 if (sid_check_is_domain(domain_sid)) {
483 NTSTATUS result;
485 if (*domain_name == NULL) {
486 *domain_name = talloc_strdup(
487 mem_ctx, get_global_sam_name());
490 if (*domain_name == NULL) {
491 return false;
494 become_root();
495 result = pdb_lookup_rids(domain_sid, num_rids, rids,
496 *names, *types);
497 unbecome_root();
499 return (NT_STATUS_IS_OK(result) ||
500 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
501 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
504 if (sid_check_is_builtin(domain_sid)) {
506 if (*domain_name == NULL) {
507 *domain_name = talloc_strdup(
508 mem_ctx, builtin_domain_name());
511 if (*domain_name == NULL) {
512 return false;
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;
521 (*types)[i] = SID_NAME_ALIAS;
522 } else {
523 (*types)[i] = SID_NAME_UNKNOWN;
526 return true;
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;
539 (*types)[i] = SID_NAME_WKN_GRP;
540 } else {
541 (*types)[i] = SID_NAME_UNKNOWN;
544 return true;
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());
552 for (i=0; i<num_rids; i++) {
553 (*names)[i] = talloc_strdup(
554 (*names), uidtoname(rids[i]));
555 (*types)[i] = SID_NAME_USER;
557 return true;
560 if (sid_check_is_unix_groups(domain_sid)) {
561 if (*domain_name == NULL) {
562 *domain_name = talloc_strdup(
563 mem_ctx, unix_groups_domain_name());
565 for (i=0; i<num_rids; i++) {
566 (*names)[i] = talloc_strdup(
567 (*names), gidtoname(rids[i]));
568 (*types)[i] = SID_NAME_DOM_GRP;
570 return true;
573 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
574 domain_name, *names, *types);
578 * Is the SID a domain as such? If yes, lookup its name.
581 static bool lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
582 const char **name)
584 const char *tmp;
585 enum lsa_SidType type;
587 if (sid_check_is_domain(sid)) {
588 *name = talloc_strdup(mem_ctx, get_global_sam_name());
589 return true;
592 if (sid_check_is_builtin(sid)) {
593 *name = talloc_strdup(mem_ctx, builtin_domain_name());
594 return true;
597 if (sid_check_is_wellknown_domain(sid, &tmp)) {
598 *name = talloc_strdup(mem_ctx, tmp);
599 return true;
602 if (sid_check_is_unix_users(sid)) {
603 *name = talloc_strdup(mem_ctx, unix_users_domain_name());
604 return true;
607 if (sid_check_is_unix_groups(sid)) {
608 *name = talloc_strdup(mem_ctx, unix_groups_domain_name());
609 return true;
612 if (sid->num_auths != 4) {
613 /* This can't be a domain */
614 return false;
617 if (IS_DC) {
618 uint32 i, num_domains;
619 struct trustdom_info **domains;
621 /* This is relatively expensive, but it happens only on DCs
622 * and for SIDs that have 4 sub-authorities and thus look like
623 * domains */
625 if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
626 &num_domains,
627 &domains))) {
628 return false;
631 for (i=0; i<num_domains; i++) {
632 if (sid_equal(sid, &domains[i]->sid)) {
633 *name = talloc_strdup(mem_ctx,
634 domains[i]->name);
635 return true;
638 return false;
641 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
642 (type == SID_NAME_DOMAIN)) {
643 *name = tmp;
644 return true;
647 return false;
651 * This tries to implement the rather weird rules for the lsa_lookup level
652 * parameter.
654 * This is as close as we can get to what W2k3 does. With this we survive the
655 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
656 * different, but I assume that's just being too liberal. For example, W2k3
657 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
658 * whereas NT4 does the same as level 1 (I think). I did not fully test that
659 * with NT4, this is what w2k3 does.
661 * Level 1: Ask everywhere
662 * Level 2: Ask domain and trusted domains, no builtin and wkn
663 * Level 3: Only ask domain
664 * Level 4: W2k3ad: Only ask AD trusts
665 * Level 5: Only ask transitive forest trusts
666 * Level 6: Like 4
669 static bool check_dom_sid_to_level(const DOM_SID *sid, int level)
671 int ret = false;
673 switch(level) {
674 case 1:
675 ret = true;
676 break;
677 case 2:
678 ret = (!sid_check_is_builtin(sid) &&
679 !sid_check_is_wellknown_domain(sid, NULL));
680 break;
681 case 3:
682 case 4:
683 case 6:
684 ret = sid_check_is_domain(sid);
685 break;
686 case 5:
687 ret = false;
688 break;
691 DEBUG(10, ("%s SID %s in level %d\n",
692 ret ? "Accepting" : "Rejecting",
693 sid_string_dbg(sid), level));
694 return ret;
698 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
699 * references to domains, it is explicitly made for this.
701 * This attempts to be as efficient as possible: It collects all SIDs
702 * belonging to a domain and hands them in bulk to the appropriate lookup
703 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
704 * *hugely* from this. Winbind is going to be extended with a lookup_rids
705 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
706 * appropriate DC.
709 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
710 const DOM_SID **sids, int level,
711 struct lsa_dom_info **ret_domains,
712 struct lsa_name_info **ret_names)
714 TALLOC_CTX *tmp_ctx;
715 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
716 struct lsa_name_info *name_infos;
717 struct lsa_dom_info *dom_infos = NULL;
719 int i, j;
721 if (!(tmp_ctx = talloc_new(mem_ctx))) {
722 DEBUG(0, ("talloc_new failed\n"));
723 return NT_STATUS_NO_MEMORY;
726 if (num_sids) {
727 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
728 if (name_infos == NULL) {
729 result = NT_STATUS_NO_MEMORY;
730 goto fail;
732 } else {
733 name_infos = NULL;
736 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
737 MAX_REF_DOMAINS);
738 if (dom_infos == NULL) {
739 result = NT_STATUS_NO_MEMORY;
740 goto fail;
743 /* First build up the data structures:
745 * dom_infos is a list of domains referenced in the list of
746 * SIDs. Later we will walk the list of domains and look up the RIDs
747 * in bulk.
749 * name_infos is a shadow-copy of the SIDs array to collect the real
750 * data.
752 * dom_info->idxs is an index into the name_infos array. The
753 * difficulty we have here is that we need to keep the SIDs the client
754 * asked for in the same order for the reply
757 for (i=0; i<num_sids; i++) {
758 DOM_SID sid;
759 uint32 rid;
760 const char *domain_name = NULL;
762 sid_copy(&sid, sids[i]);
763 name_infos[i].type = SID_NAME_USE_NONE;
765 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
766 /* We can't push that through the normal lookup
767 * process, as this would reference illegal
768 * domains.
770 * For example S-1-5-32 would end up referencing
771 * domain S-1-5- with RID 32 which is clearly wrong.
773 if (domain_name == NULL) {
774 result = NT_STATUS_NO_MEMORY;
775 goto fail;
778 name_infos[i].rid = 0;
779 name_infos[i].type = SID_NAME_DOMAIN;
780 name_infos[i].name = NULL;
782 if (sid_check_is_builtin(&sid)) {
783 /* Yes, W2k3 returns "BUILTIN" both as domain
784 * and name here */
785 name_infos[i].name = talloc_strdup(
786 name_infos, builtin_domain_name());
787 if (name_infos[i].name == NULL) {
788 result = NT_STATUS_NO_MEMORY;
789 goto fail;
792 } else {
793 /* This is a normal SID with rid component */
794 if (!sid_split_rid(&sid, &rid)) {
795 result = NT_STATUS_INVALID_PARAMETER;
796 goto fail;
800 if (!check_dom_sid_to_level(&sid, level)) {
801 name_infos[i].rid = 0;
802 name_infos[i].type = SID_NAME_UNKNOWN;
803 name_infos[i].name = NULL;
804 continue;
807 for (j=0; j<MAX_REF_DOMAINS; j++) {
808 if (!dom_infos[j].valid) {
809 break;
811 if (sid_equal(&sid, &dom_infos[j].sid)) {
812 break;
816 if (j == MAX_REF_DOMAINS) {
817 /* TODO: What's the right error message here? */
818 result = NT_STATUS_NONE_MAPPED;
819 goto fail;
822 if (!dom_infos[j].valid) {
823 /* We found a domain not yet referenced, create a new
824 * ref. */
825 dom_infos[j].valid = true;
826 sid_copy(&dom_infos[j].sid, &sid);
828 if (domain_name != NULL) {
829 /* This name was being found above in the case
830 * when we found a domain SID */
831 dom_infos[j].name =
832 talloc_strdup(dom_infos, domain_name);
833 if (dom_infos[j].name == NULL) {
834 result = NT_STATUS_NO_MEMORY;
835 goto fail;
837 } else {
838 /* lookup_rids will take care of this */
839 dom_infos[j].name = NULL;
843 name_infos[i].dom_idx = j;
845 if (name_infos[i].type == SID_NAME_USE_NONE) {
846 name_infos[i].rid = rid;
848 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
849 &dom_infos[j].num_idxs);
851 if (dom_infos[j].idxs == NULL) {
852 result = NT_STATUS_NO_MEMORY;
853 goto fail;
858 /* Iterate over the domains found */
860 for (i=0; i<MAX_REF_DOMAINS; i++) {
861 uint32_t *rids;
862 const char *domain_name = NULL;
863 const char **names;
864 enum lsa_SidType *types;
865 struct lsa_dom_info *dom = &dom_infos[i];
867 if (!dom->valid) {
868 /* No domains left, we're done */
869 break;
872 if (dom->num_idxs) {
873 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
874 result = NT_STATUS_NO_MEMORY;
875 goto fail;
877 } else {
878 rids = NULL;
881 for (j=0; j<dom->num_idxs; j++) {
882 rids[j] = name_infos[dom->idxs[j]].rid;
885 if (!lookup_rids(tmp_ctx, &dom->sid,
886 dom->num_idxs, rids, &domain_name,
887 &names, &types)) {
888 result = NT_STATUS_NO_MEMORY;
889 goto fail;
892 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
893 result = NT_STATUS_NO_MEMORY;
894 goto fail;
897 for (j=0; j<dom->num_idxs; j++) {
898 int idx = dom->idxs[j];
899 name_infos[idx].type = types[j];
900 if (types[j] != SID_NAME_UNKNOWN) {
901 name_infos[idx].name =
902 talloc_strdup(name_infos, names[j]);
903 if (name_infos[idx].name == NULL) {
904 result = NT_STATUS_NO_MEMORY;
905 goto fail;
907 } else {
908 name_infos[idx].name = NULL;
913 *ret_domains = dom_infos;
914 *ret_names = name_infos;
915 TALLOC_FREE(tmp_ctx);
916 return NT_STATUS_OK;
918 fail:
919 TALLOC_FREE(dom_infos);
920 TALLOC_FREE(name_infos);
921 TALLOC_FREE(tmp_ctx);
922 return result;
925 /*****************************************************************
926 *THE CANONICAL* convert SID to name function.
927 *****************************************************************/
929 bool lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
930 const char **ret_domain, const char **ret_name,
931 enum lsa_SidType *ret_type)
933 struct lsa_dom_info *domain;
934 struct lsa_name_info *name;
935 TALLOC_CTX *tmp_ctx;
936 bool ret = false;
938 DEBUG(10, ("lookup_sid called for SID '%s'\n", sid_string_dbg(sid)));
940 if (!(tmp_ctx = talloc_new(mem_ctx))) {
941 DEBUG(0, ("talloc_new failed\n"));
942 return false;
945 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
946 &domain, &name))) {
947 goto done;
950 if (name->type == SID_NAME_UNKNOWN) {
951 goto done;
954 if ((ret_domain != NULL) &&
955 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
956 goto done;
959 if ((ret_name != NULL) &&
960 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
961 goto done;
964 if (ret_type != NULL) {
965 *ret_type = name->type;
968 ret = true;
970 done:
971 if (ret) {
972 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n", sid_string_dbg(sid),
973 domain->name, name->name, name->type));
974 } else {
975 DEBUG(10, ("failed to lookup sid %s\n", sid_string_dbg(sid)));
977 TALLOC_FREE(tmp_ctx);
978 return ret;
981 /*****************************************************************
982 Id mapping cache. This is to avoid Winbind mappings already
983 seen by smbd to be queried too frequently, keeping winbindd
984 busy, and blocking smbd while winbindd is busy with other
985 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
986 modified to use linked lists by jra.
987 *****************************************************************/
989 /*****************************************************************
990 Find a SID given a uid.
991 *****************************************************************/
993 static bool fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
995 DATA_BLOB cache_value;
997 if (!memcache_lookup(NULL, UID_SID_CACHE,
998 data_blob_const(&uid, sizeof(uid)),
999 &cache_value)) {
1000 return false;
1003 SMB_ASSERT(cache_value.length == sizeof(*psid));
1004 memcpy(psid, cache_value.data, sizeof(*psid));
1006 return true;
1009 /*****************************************************************
1010 Find a uid given a SID.
1011 *****************************************************************/
1013 static bool fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
1015 DATA_BLOB cache_value;
1017 if (!memcache_lookup(NULL, SID_UID_CACHE,
1018 data_blob_const(psid, sizeof(*psid)),
1019 &cache_value)) {
1020 return false;
1023 SMB_ASSERT(cache_value.length == sizeof(*puid));
1024 memcpy(puid, cache_value.data, sizeof(*puid));
1026 return true;
1029 /*****************************************************************
1030 Store uid to SID mapping in cache.
1031 *****************************************************************/
1033 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1035 memcache_add(NULL, SID_UID_CACHE,
1036 data_blob_const(psid, sizeof(*psid)),
1037 data_blob_const(&uid, sizeof(uid)));
1038 memcache_add(NULL, UID_SID_CACHE,
1039 data_blob_const(&uid, sizeof(uid)),
1040 data_blob_const(psid, sizeof(*psid)));
1043 /*****************************************************************
1044 Find a SID given a gid.
1045 *****************************************************************/
1047 static bool fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1049 DATA_BLOB cache_value;
1051 if (!memcache_lookup(NULL, GID_SID_CACHE,
1052 data_blob_const(&gid, sizeof(gid)),
1053 &cache_value)) {
1054 return false;
1057 SMB_ASSERT(cache_value.length == sizeof(*psid));
1058 memcpy(psid, cache_value.data, sizeof(*psid));
1060 return true;
1063 /*****************************************************************
1064 Find a gid given a SID.
1065 *****************************************************************/
1067 static bool fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1069 DATA_BLOB cache_value;
1071 if (!memcache_lookup(NULL, SID_UID_CACHE,
1072 data_blob_const(psid, sizeof(*psid)),
1073 &cache_value)) {
1074 return false;
1077 SMB_ASSERT(cache_value.length == sizeof(*pgid));
1078 memcpy(pgid, cache_value.data, sizeof(*pgid));
1080 return true;
1083 /*****************************************************************
1084 Store gid to SID mapping in cache.
1085 *****************************************************************/
1087 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1089 memcache_add(NULL, SID_GID_CACHE,
1090 data_blob_const(psid, sizeof(*psid)),
1091 data_blob_const(&gid, sizeof(gid)));
1092 memcache_add(NULL, GID_SID_CACHE,
1093 data_blob_const(&gid, sizeof(gid)),
1094 data_blob_const(psid, sizeof(*psid)));
1097 /*****************************************************************
1098 *THE LEGACY* convert uid_t to SID function.
1099 *****************************************************************/
1101 static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1103 uint32 rid;
1104 bool ret;
1106 ZERO_STRUCTP(psid);
1108 become_root();
1109 ret = pdb_uid_to_rid(uid, &rid);
1110 unbecome_root();
1112 if (ret) {
1113 /* This is a mapped user */
1114 sid_copy(psid, get_global_sam_sid());
1115 sid_append_rid(psid, rid);
1116 goto done;
1119 /* This is an unmapped user */
1121 uid_to_unix_users_sid(uid, psid);
1123 done:
1124 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1125 sid_string_dbg(psid)));
1127 store_uid_sid_cache(psid, uid);
1128 return;
1131 /*****************************************************************
1132 *THE LEGACY* convert gid_t to SID function.
1133 *****************************************************************/
1135 static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1137 bool ret;
1139 ZERO_STRUCTP(psid);
1141 become_root();
1142 ret = pdb_gid_to_sid(gid, psid);
1143 unbecome_root();
1145 if (ret) {
1146 /* This is a mapped group */
1147 goto done;
1150 /* This is an unmapped group */
1152 gid_to_unix_groups_sid(gid, psid);
1154 done:
1155 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1156 sid_string_dbg(psid)));
1158 store_gid_sid_cache(psid, gid);
1159 return;
1162 /*****************************************************************
1163 *THE LEGACY* convert SID to uid function.
1164 *****************************************************************/
1166 static bool legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1168 enum lsa_SidType type;
1169 uint32 rid;
1171 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1172 union unid_t id;
1173 bool ret;
1175 become_root();
1176 ret = pdb_sid_to_id(psid, &id, &type);
1177 unbecome_root();
1179 if (ret) {
1180 if (type != SID_NAME_USER) {
1181 DEBUG(5, ("sid %s is a %s, expected a user\n",
1182 sid_string_dbg(psid),
1183 sid_type_lookup(type)));
1184 return false;
1186 *puid = id.uid;
1187 goto done;
1190 /* This was ours, but it was not mapped. Fail */
1193 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1194 sid_string_dbg(psid)));
1195 return false;
1197 done:
1198 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_dbg(psid),
1199 (unsigned int)*puid ));
1201 store_uid_sid_cache(psid, *puid);
1202 return true;
1205 /*****************************************************************
1206 *THE LEGACY* convert SID to gid function.
1207 Group mapping is used for gids that maps to Wellknown SIDs
1208 *****************************************************************/
1210 static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1212 uint32 rid;
1213 GROUP_MAP map;
1214 union unid_t id;
1215 enum lsa_SidType type;
1217 if ((sid_check_is_in_builtin(psid) ||
1218 sid_check_is_in_wellknown_domain(psid))) {
1219 bool ret;
1221 become_root();
1222 ret = pdb_getgrsid(&map, *psid);
1223 unbecome_root();
1225 if (ret) {
1226 *pgid = map.gid;
1227 goto done;
1229 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1230 sid_string_dbg(psid)));
1231 return false;
1234 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1235 bool ret;
1237 become_root();
1238 ret = pdb_sid_to_id(psid, &id, &type);
1239 unbecome_root();
1241 if (ret) {
1242 if ((type != SID_NAME_DOM_GRP) &&
1243 (type != SID_NAME_ALIAS)) {
1244 DEBUG(5, ("LEGACY: sid %s is a %s, expected "
1245 "a group\n", sid_string_dbg(psid),
1246 sid_type_lookup(type)));
1247 return false;
1249 *pgid = id.gid;
1250 goto done;
1253 /* This was ours, but it was not mapped. Fail */
1256 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1257 sid_string_dbg(psid)));
1258 return false;
1260 done:
1261 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_dbg(psid),
1262 (unsigned int)*pgid ));
1264 store_gid_sid_cache(psid, *pgid);
1266 return true;
1269 /*****************************************************************
1270 *THE CANONICAL* convert uid_t to SID function.
1271 *****************************************************************/
1273 void uid_to_sid(DOM_SID *psid, uid_t uid)
1275 ZERO_STRUCTP(psid);
1277 if (fetch_sid_from_uid_cache(psid, uid))
1278 return;
1280 if (!winbind_uid_to_sid(psid, uid)) {
1281 if (!winbind_ping()) {
1282 legacy_uid_to_sid(psid, uid);
1283 return;
1286 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1287 uid));
1288 return;
1291 DEBUG(10,("uid %u -> sid %s\n", (unsigned int)uid,
1292 sid_string_dbg(psid)));
1294 store_uid_sid_cache(psid, uid);
1295 return;
1298 /*****************************************************************
1299 *THE CANONICAL* convert gid_t to SID function.
1300 *****************************************************************/
1302 void gid_to_sid(DOM_SID *psid, gid_t gid)
1304 ZERO_STRUCTP(psid);
1306 if (fetch_sid_from_gid_cache(psid, gid))
1307 return;
1309 if (!winbind_gid_to_sid(psid, gid)) {
1310 if (!winbind_ping()) {
1311 legacy_gid_to_sid(psid, gid);
1312 return;
1315 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1316 gid));
1317 return;
1320 DEBUG(10,("gid %u -> sid %s\n", (unsigned int)gid,
1321 sid_string_dbg(psid)));
1323 store_gid_sid_cache(psid, gid);
1324 return;
1327 /*****************************************************************
1328 *THE CANONICAL* convert SID to uid function.
1329 *****************************************************************/
1331 bool sid_to_uid(const DOM_SID *psid, uid_t *puid)
1333 uint32 rid;
1334 gid_t gid;
1336 if (fetch_uid_from_cache(puid, psid))
1337 return true;
1339 if (fetch_gid_from_cache(&gid, psid)) {
1340 return false;
1343 /* Optimize for the Unix Users Domain
1344 * as the conversion is straightforward */
1345 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1346 uid_t uid = rid;
1347 *puid = uid;
1349 /* return here, don't cache */
1350 DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1351 (unsigned int)*puid ));
1352 return true;
1355 if (!winbind_sid_to_uid(puid, psid)) {
1356 if (!winbind_ping()) {
1357 return legacy_sid_to_uid(psid, puid);
1360 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1361 sid_string_dbg(psid)));
1362 return false;
1365 /* TODO: Here would be the place to allocate both a gid and a uid for
1366 * the SID in question */
1368 DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1369 (unsigned int)*puid ));
1371 store_uid_sid_cache(psid, *puid);
1372 return true;
1375 /*****************************************************************
1376 *THE CANONICAL* convert SID to gid function.
1377 Group mapping is used for gids that maps to Wellknown SIDs
1378 *****************************************************************/
1380 bool sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1382 uint32 rid;
1383 uid_t uid;
1385 if (fetch_gid_from_cache(pgid, psid))
1386 return true;
1388 if (fetch_uid_from_cache(&uid, psid))
1389 return false;
1391 /* Optimize for the Unix Groups Domain
1392 * as the conversion is straightforward */
1393 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1394 gid_t gid = rid;
1395 *pgid = gid;
1397 /* return here, don't cache */
1398 DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1399 (unsigned int)*pgid ));
1400 return true;
1403 /* Ask winbindd if it can map this sid to a gid.
1404 * (Idmap will check it is a valid SID and of the right type) */
1406 if ( !winbind_sid_to_gid(pgid, psid) ) {
1407 if (!winbind_ping()) {
1408 return legacy_sid_to_gid(psid, pgid);
1411 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1412 sid_string_dbg(psid)));
1413 return false;
1416 DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1417 (unsigned int)*pgid ));
1419 store_gid_sid_cache(psid, *pgid);
1421 return true;