updating default values for several parameters
[Samba.git] / source / passdb / lookup_sid.c
blobd1390fdadbbfc24d310dea1cec518733cfce87c9
1 /*
2 Unix SMB/CIFS implementation.
3 uid/user handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Gerald (Jerry) Carter 2003
6 Copyright (C) Volker Lendecke 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 /*****************************************************************
26 Dissect a user-provided name into domain, name, sid and type.
28 If an explicit domain name was given in the form domain\user, it
29 has to try that. If no explicit domain name was given, we have
30 to do guesswork.
31 *****************************************************************/
33 BOOL lookup_name(TALLOC_CTX *mem_ctx,
34 const char *full_name, int flags,
35 const char **ret_domain, const char **ret_name,
36 DOM_SID *ret_sid, enum lsa_SidType *ret_type)
38 char *p;
39 const char *tmp;
40 const char *domain = NULL;
41 const char *name = NULL;
42 uint32 rid;
43 DOM_SID sid;
44 enum lsa_SidType type;
45 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
47 if (tmp_ctx == NULL) {
48 DEBUG(0, ("talloc_new failed\n"));
49 return False;
52 p = strchr_m(full_name, '\\');
54 if (p != NULL) {
55 domain = talloc_strndup(tmp_ctx, full_name,
56 PTR_DIFF(p, full_name));
57 name = talloc_strdup(tmp_ctx, p+1);
58 } else {
59 domain = talloc_strdup(tmp_ctx, "");
60 name = talloc_strdup(tmp_ctx, full_name);
63 if ((domain == NULL) || (name == NULL)) {
64 DEBUG(0, ("talloc failed\n"));
65 TALLOC_FREE(tmp_ctx);
66 return False;
69 DEBUG(10,("lookup_name: %s => %s (domain), %s (name)\n",
70 full_name, domain, name));
71 DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags));
73 if ((flags & LOOKUP_NAME_DOMAIN) &&
74 strequal(domain, get_global_sam_name()))
77 /* It's our own domain, lookup the name in passdb */
78 if (lookup_global_sam_name(name, flags, &rid, &type)) {
79 sid_copy(&sid, get_global_sam_sid());
80 sid_append_rid(&sid, rid);
81 goto ok;
83 TALLOC_FREE(tmp_ctx);
84 return False;
87 if ((flags & LOOKUP_NAME_BUILTIN) &&
88 strequal(domain, builtin_domain_name()))
90 /* Explicit request for a name in BUILTIN */
91 if (lookup_builtin_name(name, &rid)) {
92 sid_copy(&sid, &global_sid_Builtin);
93 sid_append_rid(&sid, rid);
94 type = SID_NAME_ALIAS;
95 goto ok;
97 TALLOC_FREE(tmp_ctx);
98 return False;
101 /* Try the explicit winbind lookup first, don't let it guess the
102 * domain yet at this point yet. This comes later. */
104 if ((domain[0] != '\0') &&
105 (flags & ~(LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED)) &&
106 (winbind_lookup_name(domain, name, &sid, &type))) {
107 goto ok;
110 if (strequal(domain, unix_users_domain_name())) {
111 if (lookup_unix_user_name(name, &sid)) {
112 type = SID_NAME_USER;
113 goto ok;
115 TALLOC_FREE(tmp_ctx);
116 return False;
119 if (strequal(domain, unix_groups_domain_name())) {
120 if (lookup_unix_group_name(name, &sid)) {
121 type = SID_NAME_DOM_GRP;
122 goto ok;
124 TALLOC_FREE(tmp_ctx);
125 return False;
128 if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
129 TALLOC_FREE(tmp_ctx);
130 return False;
133 /* Now the guesswork begins, we haven't been given an explicit
134 * domain. Try the sequence as documented on
135 * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
136 * November 27, 2005 */
138 /* 1. well-known names */
140 if ((flags & LOOKUP_NAME_WKN) &&
141 lookup_wellknown_name(tmp_ctx, name, &sid, &domain))
143 type = SID_NAME_WKN_GRP;
144 goto ok;
147 /* 2. Builtin domain as such */
149 if ((flags & (LOOKUP_NAME_BUILTIN|LOOKUP_NAME_REMOTE)) &&
150 strequal(name, builtin_domain_name()))
152 /* Swap domain and name */
153 tmp = name; name = domain; domain = tmp;
154 sid_copy(&sid, &global_sid_Builtin);
155 type = SID_NAME_DOMAIN;
156 goto ok;
159 /* 3. Account domain */
161 if ((flags & LOOKUP_NAME_DOMAIN) &&
162 strequal(name, get_global_sam_name()))
164 if (!secrets_fetch_domain_sid(name, &sid)) {
165 DEBUG(3, ("Could not fetch my SID\n"));
166 TALLOC_FREE(tmp_ctx);
167 return False;
169 /* Swap domain and name */
170 tmp = name; name = domain; domain = tmp;
171 type = SID_NAME_DOMAIN;
172 goto ok;
175 /* 4. Primary domain */
177 if ((flags & LOOKUP_NAME_DOMAIN) && !IS_DC &&
178 strequal(name, lp_workgroup()))
180 if (!secrets_fetch_domain_sid(name, &sid)) {
181 DEBUG(3, ("Could not fetch the domain SID\n"));
182 TALLOC_FREE(tmp_ctx);
183 return False;
185 /* Swap domain and name */
186 tmp = name; name = domain; domain = tmp;
187 type = SID_NAME_DOMAIN;
188 goto ok;
191 /* 5. Trusted domains as such, to me it looks as if members don't do
192 this, tested an XP workstation in a NT domain -- vl */
194 if ((flags & LOOKUP_NAME_REMOTE) && IS_DC &&
195 (secrets_fetch_trusted_domain_password(name, NULL, &sid, NULL)))
197 /* Swap domain and name */
198 tmp = name; name = domain; domain = tmp;
199 type = SID_NAME_DOMAIN;
200 goto ok;
203 /* 6. Builtin aliases */
205 if ((flags & LOOKUP_NAME_BUILTIN) &&
206 lookup_builtin_name(name, &rid))
208 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
209 sid_copy(&sid, &global_sid_Builtin);
210 sid_append_rid(&sid, rid);
211 type = SID_NAME_ALIAS;
212 goto ok;
215 /* 7. Local systems' SAM (DCs don't have a local SAM) */
216 /* 8. Primary SAM (On members, this is the domain) */
218 /* Both cases are done by looking at our passdb */
220 if ((flags & LOOKUP_NAME_DOMAIN) &&
221 lookup_global_sam_name(name, flags, &rid, &type))
223 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
224 sid_copy(&sid, get_global_sam_sid());
225 sid_append_rid(&sid, rid);
226 goto ok;
229 /* Now our local possibilities are exhausted. */
231 if (!(flags & LOOKUP_NAME_REMOTE)) {
232 TALLOC_FREE(tmp_ctx);
233 return False;
236 /* If we are not a DC, we have to ask in our primary domain. Let
237 * winbind do that. */
239 if (!IS_DC &&
240 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
241 domain = talloc_strdup(tmp_ctx, lp_workgroup());
242 goto ok;
245 /* 9. Trusted domains */
247 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
248 * that (yet), but give it a chance. */
250 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
251 DOM_SID dom_sid;
252 uint32 tmp_rid;
253 enum lsa_SidType domain_type;
255 if (type == SID_NAME_DOMAIN) {
256 /* Swap name and type */
257 tmp = name; name = domain; domain = tmp;
258 goto ok;
261 /* Here we have to cope with a little deficiency in the
262 * winbind API: We have to ask it again for the name of the
263 * domain it figured out itself. Maybe fix that later... */
265 sid_copy(&dom_sid, &sid);
266 sid_split_rid(&dom_sid, &tmp_rid);
268 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
269 &domain_type) ||
270 (domain_type != SID_NAME_DOMAIN)) {
271 DEBUG(2, ("winbind could not find the domain's name "
272 "it just looked up for us\n"));
273 TALLOC_FREE(tmp_ctx);
274 return False;
276 goto ok;
279 /* 10. Don't translate */
281 /* 11. Ok, windows would end here. Samba has two more options:
282 Unmapped users and unmapped groups */
284 if (lookup_unix_user_name(name, &sid)) {
285 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
286 type = SID_NAME_USER;
287 goto ok;
290 if (lookup_unix_group_name(name, &sid)) {
291 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
292 type = SID_NAME_DOM_GRP;
293 goto ok;
297 * Ok, all possibilities tried. Fail.
300 TALLOC_FREE(tmp_ctx);
301 return False;
304 if ((domain == NULL) || (name == NULL)) {
305 DEBUG(0, ("talloc failed\n"));
306 TALLOC_FREE(tmp_ctx);
307 return False;
311 * Hand over the results to the talloc context we've been given.
314 if ((ret_name != NULL) &&
315 !(*ret_name = talloc_strdup(mem_ctx, name))) {
316 DEBUG(0, ("talloc failed\n"));
317 TALLOC_FREE(tmp_ctx);
318 return False;
321 if (ret_domain != NULL) {
322 char *tmp_dom;
323 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
324 DEBUG(0, ("talloc failed\n"));
325 TALLOC_FREE(tmp_ctx);
326 return False;
328 strupper_m(tmp_dom);
329 *ret_domain = tmp_dom;
332 if (ret_sid != NULL) {
333 sid_copy(ret_sid, &sid);
336 if (ret_type != NULL) {
337 *ret_type = type;
340 TALLOC_FREE(tmp_ctx);
341 return True;
344 /************************************************************************
345 Names from smb.conf can be unqualified. eg. valid users = foo
346 These names should never map to a remote name. Try global_sam_name()\foo,
347 and then "Unix Users"\foo (or "Unix Groups"\foo).
348 ************************************************************************/
350 BOOL lookup_name_smbconf(TALLOC_CTX *mem_ctx,
351 const char *full_name, int flags,
352 const char **ret_domain, const char **ret_name,
353 DOM_SID *ret_sid, enum lsa_SidType *ret_type)
355 char *qualified_name;
356 const char *p;
358 /* NB. No winbindd_separator here as lookup_name needs \\' */
359 if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
361 /* The name is already qualified with a domain. */
363 if (*lp_winbind_separator() != '\\') {
364 char *tmp;
366 /* lookup_name() needs '\\' as a separator */
368 tmp = talloc_strdup(mem_ctx, full_name);
369 if (!tmp) {
370 return False;
372 tmp[p - full_name] = '\\';
373 full_name = tmp;
376 return lookup_name(mem_ctx, full_name, flags,
377 ret_domain, ret_name,
378 ret_sid, ret_type);
381 /* Try with our own SAM name. */
382 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
383 get_global_sam_name(),
384 full_name );
385 if (!qualified_name) {
386 return False;
389 if (lookup_name(mem_ctx, qualified_name, flags,
390 ret_domain, ret_name,
391 ret_sid, ret_type)) {
392 return True;
395 /* Finally try with "Unix Users" or "Unix Group" */
396 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
397 flags & LOOKUP_NAME_GROUP ?
398 unix_groups_domain_name() :
399 unix_users_domain_name(),
400 full_name );
401 if (!qualified_name) {
402 return False;
405 return lookup_name(mem_ctx, qualified_name, flags,
406 ret_domain, ret_name,
407 ret_sid, ret_type);
410 static BOOL wb_lookup_rids(TALLOC_CTX *mem_ctx,
411 const DOM_SID *domain_sid,
412 int num_rids, uint32 *rids,
413 const char **domain_name,
414 const char **names, enum lsa_SidType *types)
416 int i;
417 const char **my_names;
418 enum lsa_SidType *my_types;
419 TALLOC_CTX *tmp_ctx;
421 if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
422 return False;
425 if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
426 domain_name, &my_names, &my_types)) {
427 *domain_name = "";
428 for (i=0; i<num_rids; i++) {
429 names[i] = "";
430 types[i] = SID_NAME_UNKNOWN;
432 TALLOC_FREE(tmp_ctx);
433 return True;
436 if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
437 TALLOC_FREE(tmp_ctx);
438 return False;
442 * winbind_lookup_rids allocates its own array. We've been given the
443 * array, so copy it over
446 for (i=0; i<num_rids; i++) {
447 if (my_names[i] == NULL) {
448 TALLOC_FREE(tmp_ctx);
449 return False;
451 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
452 TALLOC_FREE(tmp_ctx);
453 return False;
455 types[i] = my_types[i];
457 TALLOC_FREE(tmp_ctx);
458 return True;
461 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
462 int num_rids, uint32_t *rids,
463 const char **domain_name,
464 const char ***names, enum lsa_SidType **types)
466 int i;
468 if (num_rids) {
469 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
470 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
472 if ((*names == NULL) || (*types == NULL)) {
473 return False;
475 } else {
476 *names = NULL;
477 *types = NULL;
480 if (sid_check_is_domain(domain_sid)) {
481 NTSTATUS result;
483 if (*domain_name == NULL) {
484 *domain_name = talloc_strdup(
485 mem_ctx, get_global_sam_name());
488 if (*domain_name == NULL) {
489 return False;
492 become_root();
493 result = pdb_lookup_rids(domain_sid, num_rids, rids,
494 *names, *types);
495 unbecome_root();
497 return (NT_STATUS_IS_OK(result) ||
498 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
499 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
502 if (sid_check_is_builtin(domain_sid)) {
504 if (*domain_name == NULL) {
505 *domain_name = talloc_strdup(
506 mem_ctx, builtin_domain_name());
509 if (*domain_name == NULL) {
510 return False;
513 for (i=0; i<num_rids; i++) {
514 if (lookup_builtin_rid(*names, rids[i],
515 &(*names)[i])) {
516 if ((*names)[i] == NULL) {
517 return False;
519 (*types)[i] = SID_NAME_ALIAS;
520 } else {
521 (*types)[i] = SID_NAME_UNKNOWN;
524 return True;
527 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
528 for (i=0; i<num_rids; i++) {
529 DOM_SID sid;
530 sid_copy(&sid, domain_sid);
531 sid_append_rid(&sid, rids[i]);
532 if (lookup_wellknown_sid(mem_ctx, &sid,
533 domain_name, &(*names)[i])) {
534 if ((*names)[i] == NULL) {
535 return False;
537 (*types)[i] = SID_NAME_WKN_GRP;
538 } else {
539 (*types)[i] = SID_NAME_UNKNOWN;
542 return True;
545 if (sid_check_is_unix_users(domain_sid)) {
546 if (*domain_name == NULL) {
547 *domain_name = talloc_strdup(
548 mem_ctx, unix_users_domain_name());
550 for (i=0; i<num_rids; i++) {
551 (*names)[i] = talloc_strdup(
552 (*names), uidtoname(rids[i]));
553 (*types)[i] = SID_NAME_USER;
555 return True;
558 if (sid_check_is_unix_groups(domain_sid)) {
559 if (*domain_name == NULL) {
560 *domain_name = talloc_strdup(
561 mem_ctx, unix_groups_domain_name());
563 for (i=0; i<num_rids; i++) {
564 (*names)[i] = talloc_strdup(
565 (*names), gidtoname(rids[i]));
566 (*types)[i] = SID_NAME_DOM_GRP;
568 return True;
571 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
572 domain_name, *names, *types);
576 * Is the SID a domain as such? If yes, lookup its name.
579 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
580 const char **name)
582 const char *tmp;
583 enum lsa_SidType type;
585 if (sid_check_is_domain(sid)) {
586 *name = talloc_strdup(mem_ctx, get_global_sam_name());
587 return True;
590 if (sid_check_is_builtin(sid)) {
591 *name = talloc_strdup(mem_ctx, builtin_domain_name());
592 return True;
595 if (sid_check_is_wellknown_domain(sid, &tmp)) {
596 *name = talloc_strdup(mem_ctx, tmp);
597 return True;
600 if (sid->num_auths != 4) {
601 /* This can't be a domain */
602 return False;
605 if (IS_DC) {
606 uint32 i, num_domains;
607 struct trustdom_info **domains;
609 /* This is relatively expensive, but it happens only on DCs
610 * and for SIDs that have 4 sub-authorities and thus look like
611 * domains */
613 if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx,
614 &num_domains,
615 &domains))) {
616 return False;
619 for (i=0; i<num_domains; i++) {
620 if (sid_equal(sid, &domains[i]->sid)) {
621 *name = talloc_strdup(mem_ctx,
622 domains[i]->name);
623 return True;
626 return False;
629 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
630 (type == SID_NAME_DOMAIN)) {
631 *name = tmp;
632 return True;
635 return False;
639 * This tries to implement the rather weird rules for the lsa_lookup level
640 * parameter.
642 * This is as close as we can get to what W2k3 does. With this we survive the
643 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
644 * different, but I assume that's just being too liberal. For example, W2k3
645 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
646 * whereas NT4 does the same as level 1 (I think). I did not fully test that
647 * with NT4, this is what w2k3 does.
649 * Level 1: Ask everywhere
650 * Level 2: Ask domain and trusted domains, no builtin and wkn
651 * Level 3: Only ask domain
652 * Level 4: W2k3ad: Only ask AD trusts
653 * Level 5: Don't lookup anything
654 * Level 6: Like 4
657 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
659 int ret = False;
661 switch(level) {
662 case 1:
663 ret = True;
664 break;
665 case 2:
666 ret = (!sid_check_is_builtin(sid) &&
667 !sid_check_is_wellknown_domain(sid, NULL));
668 break;
669 case 3:
670 case 4:
671 case 6:
672 ret = sid_check_is_domain(sid);
673 break;
674 case 5:
675 ret = False;
676 break;
679 DEBUG(10, ("%s SID %s in level %d\n",
680 ret ? "Accepting" : "Rejecting",
681 sid_string_static(sid), level));
682 return ret;
686 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
687 * references to domains, it is explicitly made for this.
689 * This attempts to be as efficient as possible: It collects all SIDs
690 * belonging to a domain and hands them in bulk to the appropriate lookup
691 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
692 * *hugely* from this. Winbind is going to be extended with a lookup_rids
693 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
694 * appropriate DC.
697 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
698 const DOM_SID **sids, int level,
699 struct lsa_dom_info **ret_domains,
700 struct lsa_name_info **ret_names)
702 TALLOC_CTX *tmp_ctx;
703 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
704 struct lsa_name_info *name_infos;
705 struct lsa_dom_info *dom_infos = NULL;
707 int i, j;
709 if (!(tmp_ctx = talloc_new(mem_ctx))) {
710 DEBUG(0, ("talloc_new failed\n"));
711 return NT_STATUS_NO_MEMORY;
714 if (num_sids) {
715 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
716 if (name_infos == NULL) {
717 result = NT_STATUS_NO_MEMORY;
718 goto fail;
720 } else {
721 name_infos = NULL;
724 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
725 MAX_REF_DOMAINS);
726 if (dom_infos == NULL) {
727 result = NT_STATUS_NO_MEMORY;
728 goto fail;
731 /* First build up the data structures:
733 * dom_infos is a list of domains referenced in the list of
734 * SIDs. Later we will walk the list of domains and look up the RIDs
735 * in bulk.
737 * name_infos is a shadow-copy of the SIDs array to collect the real
738 * data.
740 * dom_info->idxs is an index into the name_infos array. The
741 * difficulty we have here is that we need to keep the SIDs the client
742 * asked for in the same order for the reply
745 for (i=0; i<num_sids; i++) {
746 DOM_SID sid;
747 uint32 rid;
748 const char *domain_name = NULL;
750 sid_copy(&sid, sids[i]);
751 name_infos[i].type = SID_NAME_USE_NONE;
753 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
754 /* We can't push that through the normal lookup
755 * process, as this would reference illegal
756 * domains.
758 * For example S-1-5-32 would end up referencing
759 * domain S-1-5- with RID 32 which is clearly wrong.
761 if (domain_name == NULL) {
762 result = NT_STATUS_NO_MEMORY;
763 goto fail;
766 name_infos[i].rid = 0;
767 name_infos[i].type = SID_NAME_DOMAIN;
768 name_infos[i].name = NULL;
770 if (sid_check_is_builtin(&sid)) {
771 /* Yes, W2k3 returns "BUILTIN" both as domain
772 * and name here */
773 name_infos[i].name = talloc_strdup(
774 name_infos, builtin_domain_name());
775 if (name_infos[i].name == NULL) {
776 result = NT_STATUS_NO_MEMORY;
777 goto fail;
780 } else {
781 /* This is a normal SID with rid component */
782 if (!sid_split_rid(&sid, &rid)) {
783 result = NT_STATUS_INVALID_PARAMETER;
784 goto fail;
788 if (!check_dom_sid_to_level(&sid, level)) {
789 name_infos[i].rid = 0;
790 name_infos[i].type = SID_NAME_UNKNOWN;
791 name_infos[i].name = NULL;
792 continue;
795 for (j=0; j<MAX_REF_DOMAINS; j++) {
796 if (!dom_infos[j].valid) {
797 break;
799 if (sid_equal(&sid, &dom_infos[j].sid)) {
800 break;
804 if (j == MAX_REF_DOMAINS) {
805 /* TODO: What's the right error message here? */
806 result = NT_STATUS_NONE_MAPPED;
807 goto fail;
810 if (!dom_infos[j].valid) {
811 /* We found a domain not yet referenced, create a new
812 * ref. */
813 dom_infos[j].valid = True;
814 sid_copy(&dom_infos[j].sid, &sid);
816 if (domain_name != NULL) {
817 /* This name was being found above in the case
818 * when we found a domain SID */
819 dom_infos[j].name =
820 talloc_strdup(dom_infos, domain_name);
821 if (dom_infos[j].name == NULL) {
822 result = NT_STATUS_NO_MEMORY;
823 goto fail;
825 } else {
826 /* lookup_rids will take care of this */
827 dom_infos[j].name = NULL;
831 name_infos[i].dom_idx = j;
833 if (name_infos[i].type == SID_NAME_USE_NONE) {
834 name_infos[i].rid = rid;
836 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
837 &dom_infos[j].num_idxs);
839 if (dom_infos[j].idxs == NULL) {
840 result = NT_STATUS_NO_MEMORY;
841 goto fail;
846 /* Iterate over the domains found */
848 for (i=0; i<MAX_REF_DOMAINS; i++) {
849 uint32_t *rids;
850 const char *domain_name = NULL;
851 const char **names;
852 enum lsa_SidType *types;
853 struct lsa_dom_info *dom = &dom_infos[i];
855 if (!dom->valid) {
856 /* No domains left, we're done */
857 break;
860 if (dom->num_idxs) {
861 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
862 result = NT_STATUS_NO_MEMORY;
863 goto fail;
865 } else {
866 rids = NULL;
869 for (j=0; j<dom->num_idxs; j++) {
870 rids[j] = name_infos[dom->idxs[j]].rid;
873 if (!lookup_rids(tmp_ctx, &dom->sid,
874 dom->num_idxs, rids, &domain_name,
875 &names, &types)) {
876 result = NT_STATUS_NO_MEMORY;
877 goto fail;
880 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
881 result = NT_STATUS_NO_MEMORY;
882 goto fail;
885 for (j=0; j<dom->num_idxs; j++) {
886 int idx = dom->idxs[j];
887 name_infos[idx].type = types[j];
888 if (types[j] != SID_NAME_UNKNOWN) {
889 name_infos[idx].name =
890 talloc_strdup(name_infos, names[j]);
891 if (name_infos[idx].name == NULL) {
892 result = NT_STATUS_NO_MEMORY;
893 goto fail;
895 } else {
896 name_infos[idx].name = NULL;
901 *ret_domains = dom_infos;
902 *ret_names = name_infos;
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",
958 sid_string_static(sid), domain->name,
959 name->name, name->type));
960 } else {
961 DEBUG(10, ("failed to lookup sid %s\n",
962 sid_string_static(sid)));
964 TALLOC_FREE(tmp_ctx);
965 return ret;
968 /*****************************************************************
969 Id mapping cache. This is to avoid Winbind mappings already
970 seen by smbd to be queried too frequently, keeping winbindd
971 busy, and blocking smbd while winbindd is busy with other
972 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
973 modified to use linked lists by jra.
974 *****************************************************************/
976 #define MAX_UID_SID_CACHE_SIZE 100
977 #define TURNOVER_UID_SID_CACHE_SIZE 10
978 #define MAX_GID_SID_CACHE_SIZE 100
979 #define TURNOVER_GID_SID_CACHE_SIZE 10
981 static size_t n_uid_sid_cache = 0;
982 static size_t n_gid_sid_cache = 0;
984 static struct uid_sid_cache {
985 struct uid_sid_cache *next, *prev;
986 uid_t uid;
987 DOM_SID sid;
988 enum lsa_SidType sidtype;
989 } *uid_sid_cache_head;
991 static struct gid_sid_cache {
992 struct gid_sid_cache *next, *prev;
993 gid_t gid;
994 DOM_SID sid;
995 enum lsa_SidType sidtype;
996 } *gid_sid_cache_head;
998 /*****************************************************************
999 Find a SID given a uid.
1000 *****************************************************************/
1002 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
1004 struct uid_sid_cache *pc;
1006 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
1007 if (pc->uid == uid) {
1008 *psid = pc->sid;
1009 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
1010 (unsigned int)uid, sid_string_static(psid)));
1011 DLIST_PROMOTE(uid_sid_cache_head, pc);
1012 return True;
1015 return False;
1018 /*****************************************************************
1019 Find a uid given a SID.
1020 *****************************************************************/
1022 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
1024 struct uid_sid_cache *pc;
1026 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
1027 if (sid_compare(&pc->sid, psid) == 0) {
1028 *puid = pc->uid;
1029 DEBUG(3,("fetch uid from cache %u -> %s\n",
1030 (unsigned int)*puid, sid_string_static(psid)));
1031 DLIST_PROMOTE(uid_sid_cache_head, pc);
1032 return True;
1035 return False;
1038 /*****************************************************************
1039 Store uid to SID mapping in cache.
1040 *****************************************************************/
1042 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1044 struct uid_sid_cache *pc;
1046 /* do not store SIDs in the "Unix Group" domain */
1048 if ( sid_check_is_in_unix_users( psid ) )
1049 return;
1051 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1052 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1053 struct uid_sid_cache *pc_next;
1054 size_t i;
1056 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1058 for(; pc; pc = pc_next) {
1059 pc_next = pc->next;
1060 DLIST_REMOVE(uid_sid_cache_head,pc);
1061 SAFE_FREE(pc);
1062 n_uid_sid_cache--;
1066 pc = SMB_MALLOC_P(struct uid_sid_cache);
1067 if (!pc)
1068 return;
1069 pc->uid = uid;
1070 sid_copy(&pc->sid, psid);
1071 DLIST_ADD(uid_sid_cache_head, pc);
1072 n_uid_sid_cache++;
1075 /*****************************************************************
1076 Find a SID given a gid.
1077 *****************************************************************/
1079 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1081 struct gid_sid_cache *pc;
1083 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1084 if (pc->gid == gid) {
1085 *psid = pc->sid;
1086 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1087 (unsigned int)gid, sid_string_static(psid)));
1088 DLIST_PROMOTE(gid_sid_cache_head, pc);
1089 return True;
1092 return False;
1095 /*****************************************************************
1096 Find a gid given a SID.
1097 *****************************************************************/
1099 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1101 struct gid_sid_cache *pc;
1103 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1104 if (sid_compare(&pc->sid, psid) == 0) {
1105 *pgid = pc->gid;
1106 DEBUG(3,("fetch gid from cache %u -> %s\n",
1107 (unsigned int)*pgid, sid_string_static(psid)));
1108 DLIST_PROMOTE(gid_sid_cache_head, pc);
1109 return True;
1112 return False;
1115 /*****************************************************************
1116 Store gid to SID mapping in cache.
1117 *****************************************************************/
1119 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1121 struct gid_sid_cache *pc;
1123 /* do not store SIDs in the "Unix Group" domain */
1125 if ( sid_check_is_in_unix_groups( psid ) )
1126 return;
1128 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1129 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1130 struct gid_sid_cache *pc_next;
1131 size_t i;
1133 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1135 for(; pc; pc = pc_next) {
1136 pc_next = pc->next;
1137 DLIST_REMOVE(gid_sid_cache_head,pc);
1138 SAFE_FREE(pc);
1139 n_gid_sid_cache--;
1143 pc = SMB_MALLOC_P(struct gid_sid_cache);
1144 if (!pc)
1145 return;
1146 pc->gid = gid;
1147 sid_copy(&pc->sid, psid);
1148 DLIST_ADD(gid_sid_cache_head, pc);
1150 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1151 sid_string_static(psid)));
1153 n_gid_sid_cache++;
1156 /*****************************************************************
1157 *THE LEGACY* convert uid_t to SID function.
1158 *****************************************************************/
1160 static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1162 uint32 rid;
1163 BOOL ret;
1165 ZERO_STRUCTP(psid);
1167 become_root();
1168 ret = pdb_uid_to_rid(uid, &rid);
1169 unbecome_root();
1171 if (ret) {
1172 /* This is a mapped user */
1173 sid_copy(psid, get_global_sam_sid());
1174 sid_append_rid(psid, rid);
1175 goto done;
1178 /* This is an unmapped user */
1180 uid_to_unix_users_sid(uid, psid);
1182 done:
1183 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1184 sid_string_static(psid)));
1186 store_uid_sid_cache(psid, uid);
1187 return;
1190 /*****************************************************************
1191 *THE LEGACY* convert gid_t to SID function.
1192 *****************************************************************/
1194 static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1196 BOOL ret;
1198 ZERO_STRUCTP(psid);
1200 become_root();
1201 ret = pdb_gid_to_sid(gid, psid);
1202 unbecome_root();
1204 if (ret) {
1205 /* This is a mapped group */
1206 goto done;
1209 /* This is an unmapped group */
1211 gid_to_unix_groups_sid(gid, psid);
1213 done:
1214 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1215 sid_string_static(psid)));
1217 store_gid_sid_cache(psid, gid);
1218 return;
1221 /*****************************************************************
1222 *THE LEGACY* convert SID to uid function.
1223 *****************************************************************/
1225 static BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1227 enum lsa_SidType type;
1228 uint32 rid;
1230 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1231 union unid_t id;
1232 BOOL ret;
1234 become_root();
1235 ret = pdb_sid_to_id(psid, &id, &type);
1236 unbecome_root();
1238 if (ret) {
1239 if (type != SID_NAME_USER) {
1240 DEBUG(5, ("sid %s is a %s, expected a user\n",
1241 sid_string_static(psid),
1242 sid_type_lookup(type)));
1243 return False;
1245 *puid = id.uid;
1246 goto done;
1249 /* This was ours, but it was not mapped. Fail */
1252 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1253 return False;
1255 done:
1256 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
1257 (unsigned int)*puid ));
1259 store_uid_sid_cache(psid, *puid);
1260 return True;
1263 /*****************************************************************
1264 *THE LEGACY* convert SID to gid function.
1265 Group mapping is used for gids that maps to Wellknown SIDs
1266 *****************************************************************/
1268 static BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1270 uint32 rid;
1271 GROUP_MAP map;
1272 union unid_t id;
1273 enum lsa_SidType type;
1275 if ((sid_check_is_in_builtin(psid) ||
1276 sid_check_is_in_wellknown_domain(psid))) {
1277 BOOL ret;
1279 become_root();
1280 ret = pdb_getgrsid(&map, *psid);
1281 unbecome_root();
1283 if (ret) {
1284 *pgid = map.gid;
1285 goto done;
1287 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1288 return False;
1291 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1292 BOOL ret;
1294 become_root();
1295 ret = pdb_sid_to_id(psid, &id, &type);
1296 unbecome_root();
1298 if (ret) {
1299 if ((type != SID_NAME_DOM_GRP) &&
1300 (type != SID_NAME_ALIAS)) {
1301 DEBUG(5, ("LEGACY: sid %s is a %s, expected a group\n",
1302 sid_string_static(psid),
1303 sid_type_lookup(type)));
1304 return False;
1306 *pgid = id.gid;
1307 goto done;
1310 /* This was ours, but it was not mapped. Fail */
1313 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1314 return False;
1316 done:
1317 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
1318 (unsigned int)*pgid ));
1320 store_gid_sid_cache(psid, *pgid);
1322 return True;
1325 /*****************************************************************
1326 *THE CANONICAL* convert uid_t to SID function.
1327 *****************************************************************/
1329 void uid_to_sid(DOM_SID *psid, uid_t uid)
1331 ZERO_STRUCTP(psid);
1333 if (fetch_sid_from_uid_cache(psid, uid))
1334 return;
1336 if (!winbind_uid_to_sid(psid, uid)) {
1337 if (!winbind_ping()) {
1338 legacy_uid_to_sid(psid, uid);
1339 return;
1342 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1343 uid));
1344 return;
1347 DEBUG(10,("uid %u -> sid %s\n",
1348 (unsigned int)uid, sid_string_static(psid)));
1350 store_uid_sid_cache(psid, uid);
1351 return;
1354 /*****************************************************************
1355 *THE CANONICAL* convert gid_t to SID function.
1356 *****************************************************************/
1358 void gid_to_sid(DOM_SID *psid, gid_t gid)
1360 ZERO_STRUCTP(psid);
1362 if (fetch_sid_from_gid_cache(psid, gid))
1363 return;
1365 if (!winbind_gid_to_sid(psid, gid)) {
1366 if (!winbind_ping()) {
1367 legacy_gid_to_sid(psid, gid);
1368 return;
1371 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1372 gid));
1373 return;
1376 DEBUG(10,("gid %u -> sid %s\n",
1377 (unsigned int)gid, sid_string_static(psid)));
1379 store_gid_sid_cache(psid, gid);
1380 return;
1383 /*****************************************************************
1384 *THE CANONICAL* convert SID to uid function.
1385 *****************************************************************/
1387 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1389 uint32 rid;
1390 gid_t gid;
1392 if (fetch_uid_from_cache(puid, psid))
1393 return True;
1395 if (fetch_gid_from_cache(&gid, psid)) {
1396 return False;
1399 /* Optimize for the Unix Users Domain
1400 * as the conversion is straightforward */
1401 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1402 uid_t uid = rid;
1403 *puid = uid;
1405 /* return here, don't cache */
1406 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1407 (unsigned int)*puid ));
1408 return True;
1411 if (!winbind_sid_to_uid(puid, psid)) {
1412 if (!winbind_ping()) {
1413 return legacy_sid_to_uid(psid, puid);
1416 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1417 sid_string_static(psid)));
1418 return False;
1421 /* TODO: Here would be the place to allocate both a gid and a uid for
1422 * the SID in question */
1424 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1425 (unsigned int)*puid ));
1427 store_uid_sid_cache(psid, *puid);
1428 return True;
1431 /*****************************************************************
1432 *THE CANONICAL* convert SID to gid function.
1433 Group mapping is used for gids that maps to Wellknown SIDs
1434 *****************************************************************/
1436 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1438 uint32 rid;
1439 uid_t uid;
1441 if (fetch_gid_from_cache(pgid, psid))
1442 return True;
1444 if (fetch_uid_from_cache(&uid, psid))
1445 return False;
1447 /* Optimize for the Unix Groups Domain
1448 * as the conversion is straightforward */
1449 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1450 gid_t gid = rid;
1451 *pgid = gid;
1453 /* return here, don't cache */
1454 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1455 (unsigned int)*pgid ));
1456 return True;
1459 /* Ask winbindd if it can map this sid to a gid.
1460 * (Idmap will check it is a valid SID and of the right type) */
1462 if ( !winbind_sid_to_gid(pgid, psid) ) {
1463 if (!winbind_ping()) {
1464 return legacy_sid_to_gid(psid, pgid);
1467 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1468 sid_string_static(psid)));
1469 return False;
1472 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1473 (unsigned int)*pgid ));
1475 store_gid_sid_cache(psid, *pgid);
1477 return True;