r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[Samba/bb.git] / source / passdb / lookup_sid.c
blob313a8c0a8b1600ef60f2e9f3fba2f27c5da24a79
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 DEBUG(10,("lookup_name: %s => %s (domain), %s (name)\n",
63 full_name, domain, name));
65 if ((domain == NULL) || (name == NULL)) {
66 DEBUG(0, ("talloc failed\n"));
67 TALLOC_FREE(tmp_ctx);
68 return False;
71 if (strequal(domain, get_global_sam_name())) {
73 /* It's our own domain, lookup the name in passdb */
74 if (lookup_global_sam_name(name, flags, &rid, &type)) {
75 sid_copy(&sid, get_global_sam_sid());
76 sid_append_rid(&sid, rid);
77 goto ok;
79 TALLOC_FREE(tmp_ctx);
80 return False;
83 if (strequal(domain, builtin_domain_name())) {
85 /* Explicit request for a name in BUILTIN */
86 if (lookup_builtin_name(name, &rid)) {
87 sid_copy(&sid, &global_sid_Builtin);
88 sid_append_rid(&sid, rid);
89 type = SID_NAME_ALIAS;
90 goto ok;
92 TALLOC_FREE(tmp_ctx);
93 return False;
96 /* Try the explicit winbind lookup first, don't let it guess the
97 * domain yet at this point yet. This comes later. */
99 if ((domain[0] != '\0') &&
100 (winbind_lookup_name(domain, name, &sid, &type))) {
101 goto ok;
104 if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_users_domain_name())) {
105 if (lookup_unix_user_name(name, &sid)) {
106 type = SID_NAME_USER;
107 goto ok;
109 TALLOC_FREE(tmp_ctx);
110 return False;
113 if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_groups_domain_name())) {
114 if (lookup_unix_group_name(name, &sid)) {
115 type = SID_NAME_DOM_GRP;
116 goto ok;
118 TALLOC_FREE(tmp_ctx);
119 return False;
122 if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
123 TALLOC_FREE(tmp_ctx);
124 return False;
127 /* Now the guesswork begins, we haven't been given an explicit
128 * domain. Try the sequence as documented on
129 * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
130 * November 27, 2005 */
132 /* 1. well-known names */
134 if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
135 type = SID_NAME_WKN_GRP;
136 goto ok;
139 /* 2. Builtin domain as such */
141 if (strequal(name, builtin_domain_name())) {
142 /* Swap domain and name */
143 tmp = name; name = domain; domain = tmp;
144 sid_copy(&sid, &global_sid_Builtin);
145 type = SID_NAME_DOMAIN;
146 goto ok;
149 /* 3. Account domain */
151 if (strequal(name, get_global_sam_name())) {
152 if (!secrets_fetch_domain_sid(name, &sid)) {
153 DEBUG(3, ("Could not fetch my SID\n"));
154 TALLOC_FREE(tmp_ctx);
155 return False;
157 /* Swap domain and name */
158 tmp = name; name = domain; domain = tmp;
159 type = SID_NAME_DOMAIN;
160 goto ok;
163 /* 4. Primary domain */
165 if (!IS_DC && strequal(name, lp_workgroup())) {
166 if (!secrets_fetch_domain_sid(name, &sid)) {
167 DEBUG(3, ("Could not fetch the domain SID\n"));
168 TALLOC_FREE(tmp_ctx);
169 return False;
171 /* Swap domain and name */
172 tmp = name; name = domain; domain = tmp;
173 type = SID_NAME_DOMAIN;
174 goto ok;
177 /* 5. Trusted domains as such, to me it looks as if members don't do
178 this, tested an XP workstation in a NT domain -- vl */
180 if (IS_DC && (pdb_get_trusteddom_pw(name, NULL, &sid, NULL))) {
181 /* Swap domain and name */
182 tmp = name; name = domain; domain = tmp;
183 type = SID_NAME_DOMAIN;
184 goto ok;
187 /* 6. Builtin aliases */
189 if (lookup_builtin_name(name, &rid)) {
190 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
191 sid_copy(&sid, &global_sid_Builtin);
192 sid_append_rid(&sid, rid);
193 type = SID_NAME_ALIAS;
194 goto ok;
197 /* 7. Local systems' SAM (DCs don't have a local SAM) */
198 /* 8. Primary SAM (On members, this is the domain) */
200 /* Both cases are done by looking at our passdb */
202 if (lookup_global_sam_name(name, flags, &rid, &type)) {
203 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
204 sid_copy(&sid, get_global_sam_sid());
205 sid_append_rid(&sid, rid);
206 goto ok;
209 /* Now our local possibilities are exhausted. */
211 if (!(flags & LOOKUP_NAME_REMOTE)) {
212 TALLOC_FREE(tmp_ctx);
213 return False;
216 /* If we are not a DC, we have to ask in our primary domain. Let
217 * winbind do that. */
219 if (!IS_DC &&
220 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
221 domain = talloc_strdup(tmp_ctx, lp_workgroup());
222 goto ok;
225 /* 9. Trusted domains */
227 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
228 * that (yet), but give it a chance. */
230 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
231 DOM_SID dom_sid;
232 uint32 tmp_rid;
233 enum lsa_SidType domain_type;
235 if (type == SID_NAME_DOMAIN) {
236 /* Swap name and type */
237 tmp = name; name = domain; domain = tmp;
238 goto ok;
241 /* Here we have to cope with a little deficiency in the
242 * winbind API: We have to ask it again for the name of the
243 * domain it figured out itself. Maybe fix that later... */
245 sid_copy(&dom_sid, &sid);
246 sid_split_rid(&dom_sid, &tmp_rid);
248 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
249 &domain_type) ||
250 (domain_type != SID_NAME_DOMAIN)) {
251 DEBUG(2, ("winbind could not find the domain's name "
252 "it just looked up for us\n"));
253 TALLOC_FREE(tmp_ctx);
254 return False;
256 goto ok;
259 /* 10. Don't translate */
261 /* 11. Ok, windows would end here. Samba has two more options:
262 Unmapped users and unmapped groups */
264 if (!(flags & LOOKUP_NAME_EXPLICIT) && lookup_unix_user_name(name, &sid)) {
265 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
266 type = SID_NAME_USER;
267 goto ok;
270 if (!(flags & LOOKUP_NAME_EXPLICIT) && lookup_unix_group_name(name, &sid)) {
271 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
272 type = SID_NAME_DOM_GRP;
273 goto ok;
277 * Ok, all possibilities tried. Fail.
280 TALLOC_FREE(tmp_ctx);
281 return False;
284 if ((domain == NULL) || (name == NULL)) {
285 DEBUG(0, ("talloc failed\n"));
286 TALLOC_FREE(tmp_ctx);
287 return False;
291 * Hand over the results to the talloc context we've been given.
294 if ((ret_name != NULL) &&
295 !(*ret_name = talloc_strdup(mem_ctx, name))) {
296 DEBUG(0, ("talloc failed\n"));
297 TALLOC_FREE(tmp_ctx);
298 return False;
301 if (ret_domain != NULL) {
302 char *tmp_dom;
303 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
304 DEBUG(0, ("talloc failed\n"));
305 TALLOC_FREE(tmp_ctx);
306 return False;
308 strupper_m(tmp_dom);
309 *ret_domain = tmp_dom;
312 if (ret_sid != NULL) {
313 sid_copy(ret_sid, &sid);
316 if (ret_type != NULL) {
317 *ret_type = type;
320 TALLOC_FREE(tmp_ctx);
321 return True;
324 /************************************************************************
325 Names from smb.conf can be unqualified. eg. valid users = foo
326 These names should never map to a remote name. Try global_sam_name()\foo,
327 and then "Unix Users"\foo (or "Unix Groups"\foo).
328 ************************************************************************/
330 BOOL lookup_name_smbconf(TALLOC_CTX *mem_ctx,
331 const char *full_name, int flags,
332 const char **ret_domain, const char **ret_name,
333 DOM_SID *ret_sid, enum lsa_SidType *ret_type)
335 char *qualified_name;
336 const char *p;
338 /* NB. No winbindd_separator here as lookup_name needs \\' */
339 if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
341 /* The name is already qualified with a domain. */
343 if (*lp_winbind_separator() != '\\') {
344 char *tmp;
346 /* lookup_name() needs '\\' as a separator */
348 tmp = talloc_strdup(mem_ctx, full_name);
349 if (!tmp) {
350 return False;
352 tmp[p - full_name] = '\\';
353 full_name = tmp;
356 return lookup_name(mem_ctx, full_name, flags,
357 ret_domain, ret_name,
358 ret_sid, ret_type);
361 /* Try with our own SAM name. */
362 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
363 get_global_sam_name(),
364 full_name );
365 if (!qualified_name) {
366 return False;
369 if (lookup_name(mem_ctx, qualified_name, flags,
370 ret_domain, ret_name,
371 ret_sid, ret_type)) {
372 return True;
375 /* Finally try with "Unix Users" or "Unix Group" */
376 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
377 flags & LOOKUP_NAME_GROUP ?
378 unix_groups_domain_name() :
379 unix_users_domain_name(),
380 full_name );
381 if (!qualified_name) {
382 return False;
385 return lookup_name(mem_ctx, qualified_name, flags,
386 ret_domain, ret_name,
387 ret_sid, ret_type);
390 static BOOL wb_lookup_rids(TALLOC_CTX *mem_ctx,
391 const DOM_SID *domain_sid,
392 int num_rids, uint32 *rids,
393 const char **domain_name,
394 const char **names, enum lsa_SidType *types)
396 int i;
397 const char **my_names;
398 enum lsa_SidType *my_types;
399 TALLOC_CTX *tmp_ctx;
401 if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
402 return False;
405 if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
406 domain_name, &my_names, &my_types)) {
407 *domain_name = "";
408 for (i=0; i<num_rids; i++) {
409 names[i] = "";
410 types[i] = SID_NAME_UNKNOWN;
412 TALLOC_FREE(tmp_ctx);
413 return True;
416 if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
417 TALLOC_FREE(tmp_ctx);
418 return False;
422 * winbind_lookup_rids allocates its own array. We've been given the
423 * array, so copy it over
426 for (i=0; i<num_rids; i++) {
427 if (my_names[i] == NULL) {
428 TALLOC_FREE(tmp_ctx);
429 return False;
431 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
432 TALLOC_FREE(tmp_ctx);
433 return False;
435 types[i] = my_types[i];
437 TALLOC_FREE(tmp_ctx);
438 return True;
441 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
442 int num_rids, uint32_t *rids,
443 const char **domain_name,
444 const char ***names, enum lsa_SidType **types)
446 int i;
448 if (num_rids) {
449 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
450 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
452 if ((*names == NULL) || (*types == NULL)) {
453 return False;
455 } else {
456 *names = NULL;
457 *types = NULL;
460 if (sid_check_is_domain(domain_sid)) {
461 NTSTATUS result;
463 if (*domain_name == NULL) {
464 *domain_name = talloc_strdup(
465 mem_ctx, get_global_sam_name());
468 if (*domain_name == NULL) {
469 return False;
472 become_root();
473 result = pdb_lookup_rids(domain_sid, num_rids, rids,
474 *names, *types);
475 unbecome_root();
477 return (NT_STATUS_IS_OK(result) ||
478 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
479 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
482 if (sid_check_is_builtin(domain_sid)) {
484 if (*domain_name == NULL) {
485 *domain_name = talloc_strdup(
486 mem_ctx, builtin_domain_name());
489 if (*domain_name == NULL) {
490 return False;
493 for (i=0; i<num_rids; i++) {
494 if (lookup_builtin_rid(*names, rids[i],
495 &(*names)[i])) {
496 if ((*names)[i] == NULL) {
497 return False;
499 (*types)[i] = SID_NAME_ALIAS;
500 } else {
501 (*types)[i] = SID_NAME_UNKNOWN;
504 return True;
507 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
508 for (i=0; i<num_rids; i++) {
509 DOM_SID sid;
510 sid_copy(&sid, domain_sid);
511 sid_append_rid(&sid, rids[i]);
512 if (lookup_wellknown_sid(mem_ctx, &sid,
513 domain_name, &(*names)[i])) {
514 if ((*names)[i] == NULL) {
515 return False;
517 (*types)[i] = SID_NAME_WKN_GRP;
518 } else {
519 (*types)[i] = SID_NAME_UNKNOWN;
522 return True;
525 if (sid_check_is_unix_users(domain_sid)) {
526 if (*domain_name == NULL) {
527 *domain_name = talloc_strdup(
528 mem_ctx, unix_users_domain_name());
530 for (i=0; i<num_rids; i++) {
531 (*names)[i] = talloc_strdup(
532 (*names), uidtoname(rids[i]));
533 (*types)[i] = SID_NAME_USER;
535 return True;
538 if (sid_check_is_unix_groups(domain_sid)) {
539 if (*domain_name == NULL) {
540 *domain_name = talloc_strdup(
541 mem_ctx, unix_groups_domain_name());
543 for (i=0; i<num_rids; i++) {
544 (*names)[i] = talloc_strdup(
545 (*names), gidtoname(rids[i]));
546 (*types)[i] = SID_NAME_DOM_GRP;
548 return True;
551 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
552 domain_name, *names, *types);
556 * Is the SID a domain as such? If yes, lookup its name.
559 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
560 const char **name)
562 const char *tmp;
563 enum lsa_SidType type;
565 if (sid_check_is_domain(sid)) {
566 *name = talloc_strdup(mem_ctx, get_global_sam_name());
567 return True;
570 if (sid_check_is_builtin(sid)) {
571 *name = talloc_strdup(mem_ctx, builtin_domain_name());
572 return True;
575 if (sid_check_is_wellknown_domain(sid, &tmp)) {
576 *name = talloc_strdup(mem_ctx, tmp);
577 return True;
580 if (sid->num_auths != 4) {
581 /* This can't be a domain */
582 return False;
585 if (IS_DC) {
586 uint32 i, num_domains;
587 struct trustdom_info **domains;
589 /* This is relatively expensive, but it happens only on DCs
590 * and for SIDs that have 4 sub-authorities and thus look like
591 * domains */
593 if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
594 &num_domains,
595 &domains))) {
596 return False;
599 for (i=0; i<num_domains; i++) {
600 if (sid_equal(sid, &domains[i]->sid)) {
601 *name = talloc_strdup(mem_ctx,
602 domains[i]->name);
603 return True;
606 return False;
609 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
610 (type == SID_NAME_DOMAIN)) {
611 *name = tmp;
612 return True;
615 return False;
619 * This tries to implement the rather weird rules for the lsa_lookup level
620 * parameter.
622 * This is as close as we can get to what W2k3 does. With this we survive the
623 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
624 * different, but I assume that's just being too liberal. For example, W2k3
625 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
626 * whereas NT4 does the same as level 1 (I think). I did not fully test that
627 * with NT4, this is what w2k3 does.
629 * Level 1: Ask everywhere
630 * Level 2: Ask domain and trusted domains, no builtin and wkn
631 * Level 3: Only ask domain
632 * Level 4: W2k3ad: Only ask AD trusts
633 * Level 5: Only ask transitive forest trusts
634 * Level 6: Like 4
637 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
639 int ret = False;
641 switch(level) {
642 case 1:
643 ret = True;
644 break;
645 case 2:
646 ret = (!sid_check_is_builtin(sid) &&
647 !sid_check_is_wellknown_domain(sid, NULL));
648 break;
649 case 3:
650 case 4:
651 case 6:
652 ret = sid_check_is_domain(sid);
653 break;
654 case 5:
655 ret = False;
656 break;
659 DEBUG(10, ("%s SID %s in level %d\n",
660 ret ? "Accepting" : "Rejecting",
661 sid_string_static(sid), level));
662 return ret;
666 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
667 * references to domains, it is explicitly made for this.
669 * This attempts to be as efficient as possible: It collects all SIDs
670 * belonging to a domain and hands them in bulk to the appropriate lookup
671 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
672 * *hugely* from this. Winbind is going to be extended with a lookup_rids
673 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
674 * appropriate DC.
677 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
678 const DOM_SID **sids, int level,
679 struct lsa_dom_info **ret_domains,
680 struct lsa_name_info **ret_names)
682 TALLOC_CTX *tmp_ctx;
683 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
684 struct lsa_name_info *name_infos;
685 struct lsa_dom_info *dom_infos = NULL;
687 int i, j;
689 if (!(tmp_ctx = talloc_new(mem_ctx))) {
690 DEBUG(0, ("talloc_new failed\n"));
691 return NT_STATUS_NO_MEMORY;
694 if (num_sids) {
695 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
696 if (name_infos == NULL) {
697 result = NT_STATUS_NO_MEMORY;
698 goto fail;
700 } else {
701 name_infos = NULL;
704 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
705 MAX_REF_DOMAINS);
706 if (dom_infos == NULL) {
707 result = NT_STATUS_NO_MEMORY;
708 goto fail;
711 /* First build up the data structures:
713 * dom_infos is a list of domains referenced in the list of
714 * SIDs. Later we will walk the list of domains and look up the RIDs
715 * in bulk.
717 * name_infos is a shadow-copy of the SIDs array to collect the real
718 * data.
720 * dom_info->idxs is an index into the name_infos array. The
721 * difficulty we have here is that we need to keep the SIDs the client
722 * asked for in the same order for the reply
725 for (i=0; i<num_sids; i++) {
726 DOM_SID sid;
727 uint32 rid;
728 const char *domain_name = NULL;
730 sid_copy(&sid, sids[i]);
731 name_infos[i].type = SID_NAME_USE_NONE;
733 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
734 /* We can't push that through the normal lookup
735 * process, as this would reference illegal
736 * domains.
738 * For example S-1-5-32 would end up referencing
739 * domain S-1-5- with RID 32 which is clearly wrong.
741 if (domain_name == NULL) {
742 result = NT_STATUS_NO_MEMORY;
743 goto fail;
746 name_infos[i].rid = 0;
747 name_infos[i].type = SID_NAME_DOMAIN;
748 name_infos[i].name = NULL;
750 if (sid_check_is_builtin(&sid)) {
751 /* Yes, W2k3 returns "BUILTIN" both as domain
752 * and name here */
753 name_infos[i].name = talloc_strdup(
754 name_infos, builtin_domain_name());
755 if (name_infos[i].name == NULL) {
756 result = NT_STATUS_NO_MEMORY;
757 goto fail;
760 } else {
761 /* This is a normal SID with rid component */
762 if (!sid_split_rid(&sid, &rid)) {
763 result = NT_STATUS_INVALID_PARAMETER;
764 goto fail;
768 if (!check_dom_sid_to_level(&sid, level)) {
769 name_infos[i].rid = 0;
770 name_infos[i].type = SID_NAME_UNKNOWN;
771 name_infos[i].name = NULL;
772 continue;
775 for (j=0; j<MAX_REF_DOMAINS; j++) {
776 if (!dom_infos[j].valid) {
777 break;
779 if (sid_equal(&sid, &dom_infos[j].sid)) {
780 break;
784 if (j == MAX_REF_DOMAINS) {
785 /* TODO: What's the right error message here? */
786 result = NT_STATUS_NONE_MAPPED;
787 goto fail;
790 if (!dom_infos[j].valid) {
791 /* We found a domain not yet referenced, create a new
792 * ref. */
793 dom_infos[j].valid = True;
794 sid_copy(&dom_infos[j].sid, &sid);
796 if (domain_name != NULL) {
797 /* This name was being found above in the case
798 * when we found a domain SID */
799 dom_infos[j].name =
800 talloc_strdup(dom_infos, domain_name);
801 if (dom_infos[j].name == NULL) {
802 result = NT_STATUS_NO_MEMORY;
803 goto fail;
805 } else {
806 /* lookup_rids will take care of this */
807 dom_infos[j].name = NULL;
811 name_infos[i].dom_idx = j;
813 if (name_infos[i].type == SID_NAME_USE_NONE) {
814 name_infos[i].rid = rid;
816 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
817 &dom_infos[j].num_idxs);
819 if (dom_infos[j].idxs == NULL) {
820 result = NT_STATUS_NO_MEMORY;
821 goto fail;
826 /* Iterate over the domains found */
828 for (i=0; i<MAX_REF_DOMAINS; i++) {
829 uint32_t *rids;
830 const char *domain_name = NULL;
831 const char **names;
832 enum lsa_SidType *types;
833 struct lsa_dom_info *dom = &dom_infos[i];
835 if (!dom->valid) {
836 /* No domains left, we're done */
837 break;
840 if (dom->num_idxs) {
841 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
842 result = NT_STATUS_NO_MEMORY;
843 goto fail;
845 } else {
846 rids = NULL;
849 for (j=0; j<dom->num_idxs; j++) {
850 rids[j] = name_infos[dom->idxs[j]].rid;
853 if (!lookup_rids(tmp_ctx, &dom->sid,
854 dom->num_idxs, rids, &domain_name,
855 &names, &types)) {
856 result = NT_STATUS_NO_MEMORY;
857 goto fail;
860 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
861 result = NT_STATUS_NO_MEMORY;
862 goto fail;
865 for (j=0; j<dom->num_idxs; j++) {
866 int idx = dom->idxs[j];
867 name_infos[idx].type = types[j];
868 if (types[j] != SID_NAME_UNKNOWN) {
869 name_infos[idx].name =
870 talloc_strdup(name_infos, names[j]);
871 if (name_infos[idx].name == NULL) {
872 result = NT_STATUS_NO_MEMORY;
873 goto fail;
875 } else {
876 name_infos[idx].name = NULL;
881 *ret_domains = dom_infos;
882 *ret_names = name_infos;
883 return NT_STATUS_OK;
885 fail:
886 TALLOC_FREE(dom_infos);
887 TALLOC_FREE(name_infos);
888 TALLOC_FREE(tmp_ctx);
889 return result;
892 /*****************************************************************
893 *THE CANONICAL* convert SID to name function.
894 *****************************************************************/
896 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
897 const char **ret_domain, const char **ret_name,
898 enum lsa_SidType *ret_type)
900 struct lsa_dom_info *domain;
901 struct lsa_name_info *name;
902 TALLOC_CTX *tmp_ctx;
903 BOOL ret = False;
905 if (!(tmp_ctx = talloc_new(mem_ctx))) {
906 DEBUG(0, ("talloc_new failed\n"));
907 return False;
910 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
911 &domain, &name))) {
912 goto done;
915 if (name->type == SID_NAME_UNKNOWN) {
916 goto done;
919 if ((ret_domain != NULL) &&
920 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
921 goto done;
924 if ((ret_name != NULL) &&
925 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
926 goto done;
929 if (ret_type != NULL) {
930 *ret_type = name->type;
933 ret = True;
935 done:
936 if (ret) {
937 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
938 sid_string_static(sid), domain->name,
939 name->name, name->type));
940 } else {
941 DEBUG(10, ("failed to lookup sid %s\n",
942 sid_string_static(sid)));
944 TALLOC_FREE(tmp_ctx);
945 return ret;
948 /*****************************************************************
949 Id mapping cache. This is to avoid Winbind mappings already
950 seen by smbd to be queried too frequently, keeping winbindd
951 busy, and blocking smbd while winbindd is busy with other
952 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
953 modified to use linked lists by jra.
954 *****************************************************************/
956 #define MAX_UID_SID_CACHE_SIZE 100
957 #define TURNOVER_UID_SID_CACHE_SIZE 10
958 #define MAX_GID_SID_CACHE_SIZE 100
959 #define TURNOVER_GID_SID_CACHE_SIZE 10
961 static size_t n_uid_sid_cache = 0;
962 static size_t n_gid_sid_cache = 0;
964 static struct uid_sid_cache {
965 struct uid_sid_cache *next, *prev;
966 uid_t uid;
967 DOM_SID sid;
968 enum lsa_SidType sidtype;
969 } *uid_sid_cache_head;
971 static struct gid_sid_cache {
972 struct gid_sid_cache *next, *prev;
973 gid_t gid;
974 DOM_SID sid;
975 enum lsa_SidType sidtype;
976 } *gid_sid_cache_head;
978 /*****************************************************************
979 Find a SID given a uid.
980 *****************************************************************/
982 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
984 struct uid_sid_cache *pc;
986 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
987 if (pc->uid == uid) {
988 *psid = pc->sid;
989 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
990 (unsigned int)uid, sid_string_static(psid)));
991 DLIST_PROMOTE(uid_sid_cache_head, pc);
992 return True;
995 return False;
998 /*****************************************************************
999 Find a uid given a SID.
1000 *****************************************************************/
1002 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
1004 struct uid_sid_cache *pc;
1006 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
1007 if (sid_compare(&pc->sid, psid) == 0) {
1008 *puid = pc->uid;
1009 DEBUG(3,("fetch uid from cache %u -> %s\n",
1010 (unsigned int)*puid, sid_string_static(psid)));
1011 DLIST_PROMOTE(uid_sid_cache_head, pc);
1012 return True;
1015 return False;
1018 /*****************************************************************
1019 Store uid to SID mapping in cache.
1020 *****************************************************************/
1022 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1024 struct uid_sid_cache *pc;
1026 /* do not store SIDs in the "Unix Group" domain */
1028 if ( sid_check_is_in_unix_users( psid ) )
1029 return;
1031 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1032 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1033 struct uid_sid_cache *pc_next;
1034 size_t i;
1036 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1038 for(; pc; pc = pc_next) {
1039 pc_next = pc->next;
1040 DLIST_REMOVE(uid_sid_cache_head,pc);
1041 SAFE_FREE(pc);
1042 n_uid_sid_cache--;
1046 pc = SMB_MALLOC_P(struct uid_sid_cache);
1047 if (!pc)
1048 return;
1049 pc->uid = uid;
1050 sid_copy(&pc->sid, psid);
1051 DLIST_ADD(uid_sid_cache_head, pc);
1052 n_uid_sid_cache++;
1055 /*****************************************************************
1056 Find a SID given a gid.
1057 *****************************************************************/
1059 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1061 struct gid_sid_cache *pc;
1063 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1064 if (pc->gid == gid) {
1065 *psid = pc->sid;
1066 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1067 (unsigned int)gid, sid_string_static(psid)));
1068 DLIST_PROMOTE(gid_sid_cache_head, pc);
1069 return True;
1072 return False;
1075 /*****************************************************************
1076 Find a gid given a SID.
1077 *****************************************************************/
1079 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1081 struct gid_sid_cache *pc;
1083 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1084 if (sid_compare(&pc->sid, psid) == 0) {
1085 *pgid = pc->gid;
1086 DEBUG(3,("fetch gid from cache %u -> %s\n",
1087 (unsigned int)*pgid, sid_string_static(psid)));
1088 DLIST_PROMOTE(gid_sid_cache_head, pc);
1089 return True;
1092 return False;
1095 /*****************************************************************
1096 Store gid to SID mapping in cache.
1097 *****************************************************************/
1099 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1101 struct gid_sid_cache *pc;
1103 /* do not store SIDs in the "Unix Group" domain */
1105 if ( sid_check_is_in_unix_groups( psid ) )
1106 return;
1108 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1109 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1110 struct gid_sid_cache *pc_next;
1111 size_t i;
1113 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1115 for(; pc; pc = pc_next) {
1116 pc_next = pc->next;
1117 DLIST_REMOVE(gid_sid_cache_head,pc);
1118 SAFE_FREE(pc);
1119 n_gid_sid_cache--;
1123 pc = SMB_MALLOC_P(struct gid_sid_cache);
1124 if (!pc)
1125 return;
1126 pc->gid = gid;
1127 sid_copy(&pc->sid, psid);
1128 DLIST_ADD(gid_sid_cache_head, pc);
1130 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1131 sid_string_static(psid)));
1133 n_gid_sid_cache++;
1136 /*****************************************************************
1137 *THE LEGACY* convert uid_t to SID function.
1138 *****************************************************************/
1140 static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1142 uint32 rid;
1143 BOOL ret;
1145 ZERO_STRUCTP(psid);
1147 become_root();
1148 ret = pdb_uid_to_rid(uid, &rid);
1149 unbecome_root();
1151 if (ret) {
1152 /* This is a mapped user */
1153 sid_copy(psid, get_global_sam_sid());
1154 sid_append_rid(psid, rid);
1155 goto done;
1158 /* This is an unmapped user */
1160 uid_to_unix_users_sid(uid, psid);
1162 done:
1163 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1164 sid_string_static(psid)));
1166 store_uid_sid_cache(psid, uid);
1167 return;
1170 /*****************************************************************
1171 *THE LEGACY* convert gid_t to SID function.
1172 *****************************************************************/
1174 static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1176 BOOL ret;
1178 ZERO_STRUCTP(psid);
1180 become_root();
1181 ret = pdb_gid_to_sid(gid, psid);
1182 unbecome_root();
1184 if (ret) {
1185 /* This is a mapped group */
1186 goto done;
1189 /* This is an unmapped group */
1191 gid_to_unix_groups_sid(gid, psid);
1193 done:
1194 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1195 sid_string_static(psid)));
1197 store_gid_sid_cache(psid, gid);
1198 return;
1201 /*****************************************************************
1202 *THE LEGACY* convert SID to uid function.
1203 *****************************************************************/
1205 static BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1207 enum lsa_SidType type;
1208 uint32 rid;
1210 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1211 union unid_t id;
1212 BOOL ret;
1214 become_root();
1215 ret = pdb_sid_to_id(psid, &id, &type);
1216 unbecome_root();
1218 if (ret) {
1219 if (type != SID_NAME_USER) {
1220 DEBUG(5, ("sid %s is a %s, expected a user\n",
1221 sid_string_static(psid),
1222 sid_type_lookup(type)));
1223 return False;
1225 *puid = id.uid;
1226 goto done;
1229 /* This was ours, but it was not mapped. Fail */
1232 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1233 return False;
1235 done:
1236 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
1237 (unsigned int)*puid ));
1239 store_uid_sid_cache(psid, *puid);
1240 return True;
1243 /*****************************************************************
1244 *THE LEGACY* convert SID to gid function.
1245 Group mapping is used for gids that maps to Wellknown SIDs
1246 *****************************************************************/
1248 static BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1250 uint32 rid;
1251 GROUP_MAP map;
1252 union unid_t id;
1253 enum lsa_SidType type;
1255 if ((sid_check_is_in_builtin(psid) ||
1256 sid_check_is_in_wellknown_domain(psid))) {
1257 BOOL ret;
1259 become_root();
1260 ret = pdb_getgrsid(&map, *psid);
1261 unbecome_root();
1263 if (ret) {
1264 *pgid = map.gid;
1265 goto done;
1267 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1268 return False;
1271 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1272 BOOL ret;
1274 become_root();
1275 ret = pdb_sid_to_id(psid, &id, &type);
1276 unbecome_root();
1278 if (ret) {
1279 if ((type != SID_NAME_DOM_GRP) &&
1280 (type != SID_NAME_ALIAS)) {
1281 DEBUG(5, ("LEGACY: sid %s is a %s, expected a group\n",
1282 sid_string_static(psid),
1283 sid_type_lookup(type)));
1284 return False;
1286 *pgid = id.gid;
1287 goto done;
1290 /* This was ours, but it was not mapped. Fail */
1293 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1294 return False;
1296 done:
1297 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
1298 (unsigned int)*pgid ));
1300 store_gid_sid_cache(psid, *pgid);
1302 return True;
1305 /*****************************************************************
1306 *THE CANONICAL* convert uid_t to SID function.
1307 *****************************************************************/
1309 void uid_to_sid(DOM_SID *psid, uid_t uid)
1311 ZERO_STRUCTP(psid);
1313 if (fetch_sid_from_uid_cache(psid, uid))
1314 return;
1316 if (!winbind_uid_to_sid(psid, uid)) {
1317 if (!winbind_ping()) {
1318 legacy_uid_to_sid(psid, uid);
1319 return;
1322 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1323 uid));
1324 return;
1327 DEBUG(10,("uid %u -> sid %s\n",
1328 (unsigned int)uid, sid_string_static(psid)));
1330 store_uid_sid_cache(psid, uid);
1331 return;
1334 /*****************************************************************
1335 *THE CANONICAL* convert gid_t to SID function.
1336 *****************************************************************/
1338 void gid_to_sid(DOM_SID *psid, gid_t gid)
1340 ZERO_STRUCTP(psid);
1342 if (fetch_sid_from_gid_cache(psid, gid))
1343 return;
1345 if (!winbind_gid_to_sid(psid, gid)) {
1346 if (!winbind_ping()) {
1347 legacy_gid_to_sid(psid, gid);
1348 return;
1351 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1352 gid));
1353 return;
1356 DEBUG(10,("gid %u -> sid %s\n",
1357 (unsigned int)gid, sid_string_static(psid)));
1359 store_gid_sid_cache(psid, gid);
1360 return;
1363 /*****************************************************************
1364 *THE CANONICAL* convert SID to uid function.
1365 *****************************************************************/
1367 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1369 uint32 rid;
1370 gid_t gid;
1372 if (fetch_uid_from_cache(puid, psid))
1373 return True;
1375 if (fetch_gid_from_cache(&gid, psid)) {
1376 return False;
1379 /* Optimize for the Unix Users Domain
1380 * as the conversion is straightforward */
1381 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1382 uid_t uid = rid;
1383 *puid = uid;
1385 /* return here, don't cache */
1386 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1387 (unsigned int)*puid ));
1388 return True;
1391 if (!winbind_sid_to_uid(puid, psid)) {
1392 if (!winbind_ping()) {
1393 return legacy_sid_to_uid(psid, puid);
1396 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1397 sid_string_static(psid)));
1398 return False;
1401 /* TODO: Here would be the place to allocate both a gid and a uid for
1402 * the SID in question */
1404 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1405 (unsigned int)*puid ));
1407 store_uid_sid_cache(psid, *puid);
1408 return True;
1411 /*****************************************************************
1412 *THE CANONICAL* convert SID to gid function.
1413 Group mapping is used for gids that maps to Wellknown SIDs
1414 *****************************************************************/
1416 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1418 uint32 rid;
1419 uid_t uid;
1421 if (fetch_gid_from_cache(pgid, psid))
1422 return True;
1424 if (fetch_uid_from_cache(&uid, psid))
1425 return False;
1427 /* Optimize for the Unix Groups Domain
1428 * as the conversion is straightforward */
1429 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1430 gid_t gid = rid;
1431 *pgid = gid;
1433 /* return here, don't cache */
1434 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1435 (unsigned int)*pgid ));
1436 return True;
1439 /* Ask winbindd if it can map this sid to a gid.
1440 * (Idmap will check it is a valid SID and of the right type) */
1442 if ( !winbind_sid_to_gid(pgid, psid) ) {
1443 if (!winbind_ping()) {
1444 return legacy_sid_to_gid(psid, pgid);
1447 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1448 sid_string_static(psid)));
1449 return False;
1452 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1453 (unsigned int)*pgid ));
1455 store_gid_sid_cache(psid, *pgid);
1457 return True;