tests: Expected failures in reparse point tests should not be errors
[Samba.git] / source3 / passdb / lookup_sid.c
blob426ea3f81bda52675af4ef59d63993d1c3e76bb1
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"
23 #include "passdb.h"
24 #include "lib/util_unixsids.h"
25 #include "../librpc/gen_ndr/ndr_security.h"
26 #include "secrets.h"
27 #include "../lib/util/memcache.h"
28 #include "idmap_cache.h"
29 #include "../libcli/security/security.h"
30 #include "lib/winbind_util.h"
31 #include "../librpc/gen_ndr/idmap.h"
32 #include "lib/util/bitmap.h"
34 static bool lookup_unix_user_name(const char *name, struct dom_sid *sid)
36 struct passwd *pwd;
37 bool ret;
39 pwd = Get_Pwnam_alloc(talloc_tos(), name);
40 if (pwd == NULL) {
41 return False;
45 * For 64-bit uid's we have enough space in the whole SID,
46 * should they become necessary
48 ret = sid_compose(sid, &global_sid_Unix_Users, pwd->pw_uid);
49 TALLOC_FREE(pwd);
50 return ret;
53 static bool lookup_unix_group_name(const char *name, struct dom_sid *sid)
55 struct group *grp;
57 grp = getgrnam(name);
58 if (grp == NULL) {
59 return False;
63 * For 64-bit gid's we have enough space in the whole SID,
64 * should they become necessary
66 return sid_compose(sid, &global_sid_Unix_Groups, grp->gr_gid);
69 /*****************************************************************
70 Dissect a user-provided name into domain, name, sid and type.
72 If an explicit domain name was given in the form domain\user, it
73 has to try that. If no explicit domain name was given, we have
74 to do guesswork.
75 *****************************************************************/
77 bool lookup_name(TALLOC_CTX *mem_ctx,
78 const char *full_name, int flags,
79 const char **ret_domain, const char **ret_name,
80 struct dom_sid *ret_sid, enum lsa_SidType *ret_type)
82 char *p;
83 const char *tmp;
84 const char *domain = NULL;
85 const char *name = NULL;
86 uint32_t rid;
87 struct dom_sid sid;
88 enum lsa_SidType type;
89 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
91 if (tmp_ctx == NULL) {
92 DEBUG(0, ("talloc_new failed\n"));
93 return false;
96 p = strchr_m(full_name, '\\');
98 if (p != NULL) {
99 domain = talloc_strndup(tmp_ctx, full_name,
100 PTR_DIFF(p, full_name));
101 name = talloc_strdup(tmp_ctx, p+1);
102 } else {
103 char *q = strchr_m(full_name, '@');
105 /* Set the domain for UPNs */
106 if (q != NULL) {
107 name = talloc_strndup(tmp_ctx,
108 full_name,
109 PTR_DIFF(q, full_name));
110 domain = talloc_strdup(tmp_ctx, q + 1);
111 } else {
112 domain = talloc_strdup(tmp_ctx, "");
113 name = talloc_strdup(tmp_ctx, full_name);
117 if ((domain == NULL) || (name == NULL)) {
118 DEBUG(0, ("talloc failed\n"));
119 TALLOC_FREE(tmp_ctx);
120 return false;
123 DEBUG(10,("lookup_name: %s => domain=[%s], name=[%s]\n",
124 full_name, domain, name));
125 DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags));
127 if ((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) {
128 bool check_global_sam = false;
130 check_global_sam = strequal(domain, get_global_sam_name());
132 /* If we are running on a DC that has PASSDB module with domain
133 * information, check if DNS forest name is matching the domain
134 * name. This is the case of IPA domain controller when
135 * trusted AD DC looks up users found in a Global Catalog of
136 * the forest root domain. */
137 if (!check_global_sam && (IS_DC)) {
138 struct pdb_domain_info *dom_info = NULL;
139 dom_info = pdb_get_domain_info(tmp_ctx);
141 if ((dom_info != NULL) && (dom_info->dns_forest != NULL)) {
142 check_global_sam = strequal(domain, dom_info->dns_forest);
145 TALLOC_FREE(dom_info);
148 if (check_global_sam) {
149 /* It's our own domain, lookup the name in passdb */
150 if (lookup_global_sam_name(name, flags, &rid, &type)) {
151 sid_compose(&sid, get_global_sam_sid(), rid);
152 goto ok;
154 TALLOC_FREE(tmp_ctx);
155 return false;
159 if ((flags & LOOKUP_NAME_BUILTIN) &&
160 strequal(domain, builtin_domain_name()))
162 if (strlen(name) == 0) {
163 /* Swap domain and name */
164 tmp = name; name = domain; domain = tmp;
165 sid_copy(&sid, &global_sid_Builtin);
166 type = SID_NAME_DOMAIN;
167 goto ok;
170 /* Explicit request for a name in BUILTIN */
171 if (lookup_builtin_name(name, &rid)) {
172 sid_compose(&sid, &global_sid_Builtin, rid);
173 type = SID_NAME_ALIAS;
174 goto ok;
176 TALLOC_FREE(tmp_ctx);
177 return false;
180 /* Try the explicit winbind lookup first, don't let it guess the
181 * domain yet at this point yet. This comes later. */
183 if ((domain[0] != '\0') &&
184 (flags & ~(LOOKUP_NAME_DOMAIN|LOOKUP_NAME_ISOLATED)) &&
185 (winbind_lookup_name(domain, name, &sid, &type))) {
186 goto ok;
189 if (((flags & (LOOKUP_NAME_NO_NSS|LOOKUP_NAME_GROUP)) == 0)
190 && strequal(domain, unix_users_domain_name())) {
191 if (lookup_unix_user_name(name, &sid)) {
192 type = SID_NAME_USER;
193 goto ok;
195 TALLOC_FREE(tmp_ctx);
196 return false;
199 if (((flags & LOOKUP_NAME_NO_NSS) == 0)
200 && strequal(domain, unix_groups_domain_name())) {
201 if (lookup_unix_group_name(name, &sid)) {
202 type = SID_NAME_DOM_GRP;
203 goto ok;
205 TALLOC_FREE(tmp_ctx);
206 return false;
210 * Finally check for a well known domain name ("NT Authority"),
211 * this is being taken care of in lookup_wellknown_name().
213 if ((domain[0] != '\0') &&
214 (flags & LOOKUP_NAME_WKN) &&
215 lookup_wellknown_name(tmp_ctx, name, &sid, &domain))
217 type = SID_NAME_WKN_GRP;
218 goto ok;
222 * If we're told not to look up 'isolated' names then we're
223 * done.
225 if (!(flags & LOOKUP_NAME_ISOLATED)) {
226 TALLOC_FREE(tmp_ctx);
227 return false;
231 * No domain names beyond this point
233 if (domain[0] != '\0') {
234 TALLOC_FREE(tmp_ctx);
235 return false;
238 /* Now the guesswork begins, we haven't been given an explicit
239 * domain. Try the sequence as documented on
240 * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
241 * November 27, 2005 */
243 /* 1. well-known names */
246 * Check for well known names without a domain name.
247 * e.g. \Creator Owner.
250 if ((flags & LOOKUP_NAME_WKN) &&
251 lookup_wellknown_name(tmp_ctx, name, &sid, &domain))
253 type = SID_NAME_WKN_GRP;
254 goto ok;
257 /* 2. Builtin domain as such */
259 if ((flags & (LOOKUP_NAME_BUILTIN|LOOKUP_NAME_REMOTE)) &&
260 strequal(name, builtin_domain_name()))
262 /* Swap domain and name */
263 tmp = name; name = domain; domain = tmp;
264 sid_copy(&sid, &global_sid_Builtin);
265 type = SID_NAME_DOMAIN;
266 goto ok;
269 /* 3. Account domain */
271 if ((flags & LOOKUP_NAME_DOMAIN) &&
272 strequal(name, get_global_sam_name()))
274 if (!secrets_fetch_domain_sid(name, &sid)) {
275 DEBUG(3, ("Could not fetch my SID\n"));
276 TALLOC_FREE(tmp_ctx);
277 return false;
279 /* Swap domain and name */
280 tmp = name; name = domain; domain = tmp;
281 type = SID_NAME_DOMAIN;
282 goto ok;
285 /* 4. Primary domain */
287 if ((flags & LOOKUP_NAME_DOMAIN) && !IS_DC &&
288 strequal(name, lp_workgroup()))
290 if (!secrets_fetch_domain_sid(name, &sid)) {
291 DEBUG(3, ("Could not fetch the domain SID\n"));
292 TALLOC_FREE(tmp_ctx);
293 return false;
295 /* Swap domain and name */
296 tmp = name; name = domain; domain = tmp;
297 type = SID_NAME_DOMAIN;
298 goto ok;
301 /* 5. Trusted domains as such, to me it looks as if members don't do
302 this, tested an XP workstation in a NT domain -- vl */
304 if ((flags & LOOKUP_NAME_REMOTE) && IS_DC &&
305 (pdb_get_trusteddom_pw(name, NULL, &sid, NULL)))
307 /* Swap domain and name */
308 tmp = name; name = domain; domain = tmp;
309 type = SID_NAME_DOMAIN;
310 goto ok;
313 /* 6. Builtin aliases */
315 if ((flags & LOOKUP_NAME_BUILTIN) &&
316 lookup_builtin_name(name, &rid))
318 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
319 sid_compose(&sid, &global_sid_Builtin, rid);
320 type = SID_NAME_ALIAS;
321 goto ok;
324 /* 7. Local systems' SAM (DCs don't have a local SAM) */
325 /* 8. Primary SAM (On members, this is the domain) */
327 /* Both cases are done by looking at our passdb */
329 if ((flags & LOOKUP_NAME_DOMAIN) &&
330 lookup_global_sam_name(name, flags, &rid, &type))
332 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
333 sid_compose(&sid, get_global_sam_sid(), rid);
334 goto ok;
337 /* Now our local possibilities are exhausted. */
339 if (!(flags & LOOKUP_NAME_REMOTE)) {
340 TALLOC_FREE(tmp_ctx);
341 return false;
344 /* If we are not a DC, we have to ask in our primary domain. Let
345 * winbind do that. */
347 if (!IS_DC &&
348 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
349 domain = talloc_strdup(tmp_ctx, lp_workgroup());
350 goto ok;
353 /* 9. Trusted domains */
355 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
356 * that (yet), but give it a chance. */
358 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
359 struct dom_sid dom_sid;
360 enum lsa_SidType domain_type;
362 if (type == SID_NAME_DOMAIN) {
363 /* Swap name and type */
364 tmp = name; name = domain; domain = tmp;
365 goto ok;
368 /* Here we have to cope with a little deficiency in the
369 * winbind API: We have to ask it again for the name of the
370 * domain it figured out itself. Maybe fix that later... */
372 sid_copy(&dom_sid, &sid);
373 sid_split_rid(&dom_sid, NULL);
375 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
376 &domain_type) ||
377 (domain_type != SID_NAME_DOMAIN)) {
378 DEBUG(2, ("winbind could not find the domain's name "
379 "it just looked up for us\n"));
380 TALLOC_FREE(tmp_ctx);
381 return false;
383 goto ok;
386 /* 10. Don't translate */
388 /* 11. Ok, windows would end here. Samba has two more options:
389 Unmapped users and unmapped groups */
391 if (((flags & (LOOKUP_NAME_NO_NSS|LOOKUP_NAME_GROUP)) == 0)
392 && lookup_unix_user_name(name, &sid)) {
393 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
394 type = SID_NAME_USER;
395 goto ok;
398 if (((flags & LOOKUP_NAME_NO_NSS) == 0)
399 && lookup_unix_group_name(name, &sid)) {
400 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
401 type = SID_NAME_DOM_GRP;
402 goto ok;
406 * Ok, all possibilities tried. Fail.
409 TALLOC_FREE(tmp_ctx);
410 return false;
413 if ((domain == NULL) || (name == NULL)) {
414 DEBUG(0, ("talloc failed\n"));
415 TALLOC_FREE(tmp_ctx);
416 return false;
420 * Hand over the results to the talloc context we've been given.
423 if ((ret_name != NULL) &&
424 !(*ret_name = talloc_strdup(mem_ctx, name))) {
425 DEBUG(0, ("talloc failed\n"));
426 TALLOC_FREE(tmp_ctx);
427 return false;
430 if (ret_domain != NULL) {
431 char *tmp_dom;
432 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
433 DEBUG(0, ("talloc failed\n"));
434 TALLOC_FREE(tmp_ctx);
435 return false;
437 if (!strupper_m(tmp_dom)) {
438 TALLOC_FREE(tmp_ctx);
439 return false;
441 *ret_domain = tmp_dom;
444 if (ret_sid != NULL) {
445 sid_copy(ret_sid, &sid);
448 if (ret_type != NULL) {
449 *ret_type = type;
452 TALLOC_FREE(tmp_ctx);
453 return true;
456 /************************************************************************
457 Names from smb.conf can be unqualified. eg. valid users = foo
458 These names should never map to a remote name. Try global_sam_name()\foo,
459 and then "Unix Users"\foo (or "Unix Groups"\foo).
460 ************************************************************************/
462 bool lookup_name_smbconf(TALLOC_CTX *mem_ctx,
463 const char *full_name, int flags,
464 const char **ret_domain, const char **ret_name,
465 struct dom_sid *ret_sid, enum lsa_SidType *ret_type)
467 char *qualified_name = NULL;
468 const char *p = strchr_m(full_name, *lp_winbind_separator());
469 bool is_qualified = p != NULL || strchr_m(full_name, '@') != NULL;
471 /* For DOMAIN\user or user@REALM directly call lookup_name(). */
472 if (is_qualified) {
474 /* The name is already qualified with a domain. */
476 if (p != NULL && *lp_winbind_separator() != '\\') {
477 /* lookup_name() needs '\\' as a separator */
479 qualified_name = talloc_strdup(mem_ctx, full_name);
480 if (qualified_name == NULL) {
481 return false;
483 qualified_name[p - full_name] = '\\';
484 full_name = qualified_name;
487 return lookup_name(mem_ctx, full_name, flags,
488 ret_domain, ret_name,
489 ret_sid, ret_type);
492 /* Try with winbind default domain name. */
493 if (lp_winbind_use_default_domain()) {
494 bool ok;
496 qualified_name = talloc_asprintf(mem_ctx,
497 "%s\\%s",
498 lp_workgroup(),
499 full_name);
500 if (qualified_name == NULL) {
501 return false;
504 ok = lookup_name(mem_ctx,
505 qualified_name,
506 flags,
507 ret_domain,
508 ret_name,
509 ret_sid,
510 ret_type);
511 if (ok) {
512 return true;
516 /* Try with our own SAM name. */
517 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
518 get_global_sam_name(),
519 full_name );
520 if (!qualified_name) {
521 return false;
524 if (lookup_name(mem_ctx, qualified_name, flags,
525 ret_domain, ret_name,
526 ret_sid, ret_type)) {
527 return true;
530 /* Finally try with "Unix Users" or "Unix Group" */
531 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
532 flags & LOOKUP_NAME_GROUP ?
533 unix_groups_domain_name() :
534 unix_users_domain_name(),
535 full_name );
536 if (!qualified_name) {
537 return false;
540 return lookup_name(mem_ctx, qualified_name, flags,
541 ret_domain, ret_name,
542 ret_sid, ret_type);
545 static bool wb_lookup_rids(TALLOC_CTX *mem_ctx,
546 const struct dom_sid *domain_sid,
547 int num_rids, uint32_t *rids,
548 const char **domain_name,
549 const char **names, enum lsa_SidType *types)
551 int i;
552 const char **my_names;
553 enum lsa_SidType *my_types;
554 TALLOC_CTX *tmp_ctx;
556 if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
557 return false;
560 if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
561 domain_name, &my_names, &my_types)) {
562 *domain_name = "";
563 for (i=0; i<num_rids; i++) {
564 names[i] = "";
565 types[i] = SID_NAME_UNKNOWN;
567 TALLOC_FREE(tmp_ctx);
568 return true;
571 if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
572 TALLOC_FREE(tmp_ctx);
573 return false;
577 * winbind_lookup_rids allocates its own array. We've been given the
578 * array, so copy it over
581 for (i=0; i<num_rids; i++) {
582 if (my_names[i] == NULL) {
583 TALLOC_FREE(tmp_ctx);
584 return false;
586 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
587 TALLOC_FREE(tmp_ctx);
588 return false;
590 types[i] = my_types[i];
592 TALLOC_FREE(tmp_ctx);
593 return true;
596 static bool lookup_rids(TALLOC_CTX *mem_ctx, const struct dom_sid *domain_sid,
597 int num_rids, uint32_t *rids,
598 const char **domain_name,
599 const char ***names, enum lsa_SidType **types)
601 int i;
602 struct dom_sid_buf buf;
604 DEBUG(10, ("lookup_rids called for domain sid '%s'\n",
605 dom_sid_str_buf(domain_sid, &buf)));
607 if (num_rids) {
608 *names = talloc_zero_array(mem_ctx, const char *, num_rids);
609 *types = talloc_array(mem_ctx, enum lsa_SidType, num_rids);
611 if ((*names == NULL) || (*types == NULL)) {
612 return false;
615 for (i = 0; i < num_rids; i++)
616 (*types)[i] = SID_NAME_UNKNOWN;
617 } else {
618 *names = NULL;
619 *types = NULL;
622 if (sid_check_is_our_sam(domain_sid)) {
623 NTSTATUS result;
625 if (*domain_name == NULL) {
626 *domain_name = talloc_strdup(
627 mem_ctx, get_global_sam_name());
630 if (*domain_name == NULL) {
631 return false;
634 become_root();
635 result = pdb_lookup_rids(domain_sid, num_rids, rids,
636 *names, *types);
637 unbecome_root();
639 return (NT_STATUS_IS_OK(result) ||
640 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
641 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
644 if (sid_check_is_builtin(domain_sid)) {
646 if (*domain_name == NULL) {
647 *domain_name = talloc_strdup(
648 mem_ctx, builtin_domain_name());
651 if (*domain_name == NULL) {
652 return false;
655 for (i=0; i<num_rids; i++) {
656 if (lookup_builtin_rid(*names, rids[i],
657 &(*names)[i])) {
658 if ((*names)[i] == NULL) {
659 return false;
661 (*types)[i] = SID_NAME_ALIAS;
662 } else {
663 (*types)[i] = SID_NAME_UNKNOWN;
666 return true;
669 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
670 for (i=0; i<num_rids; i++) {
671 struct dom_sid sid;
672 sid_compose(&sid, domain_sid, rids[i]);
673 if (lookup_wellknown_sid(mem_ctx, &sid,
674 domain_name, &(*names)[i])) {
675 if ((*names)[i] == NULL) {
676 return false;
678 (*types)[i] = SID_NAME_WKN_GRP;
679 } else {
680 (*types)[i] = SID_NAME_UNKNOWN;
683 return true;
686 if (sid_check_is_unix_users(domain_sid)) {
687 if (*domain_name == NULL) {
688 *domain_name = talloc_strdup(
689 mem_ctx, unix_users_domain_name());
690 if (*domain_name == NULL) {
691 return false;
694 for (i=0; i<num_rids; i++) {
695 (*names)[i] = talloc_strdup(
696 (*names), uidtoname(rids[i]));
697 if ((*names)[i] == NULL) {
698 return false;
700 (*types)[i] = SID_NAME_USER;
702 return true;
705 if (sid_check_is_unix_groups(domain_sid)) {
706 if (*domain_name == NULL) {
707 *domain_name = talloc_strdup(
708 mem_ctx, unix_groups_domain_name());
709 if (*domain_name == NULL) {
710 return false;
713 for (i=0; i<num_rids; i++) {
714 (*names)[i] = talloc_strdup(
715 (*names), gidtoname(rids[i]));
716 if ((*names)[i] == NULL) {
717 return false;
719 (*types)[i] = SID_NAME_DOM_GRP;
721 return true;
724 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
725 domain_name, *names, *types);
729 * Is the SID a domain as such? If yes, lookup its name.
732 static bool lookup_as_domain(const struct dom_sid *sid, TALLOC_CTX *mem_ctx,
733 const char **name)
735 const char *tmp;
736 enum lsa_SidType type;
738 if (sid_check_is_our_sam(sid)) {
739 *name = talloc_strdup(mem_ctx, get_global_sam_name());
740 return true;
743 if (sid_check_is_builtin(sid)) {
744 *name = talloc_strdup(mem_ctx, builtin_domain_name());
745 return true;
748 if (sid_check_is_wellknown_domain(sid, &tmp)) {
749 *name = talloc_strdup(mem_ctx, tmp);
750 return true;
753 if (sid_check_is_unix_users(sid)) {
754 *name = talloc_strdup(mem_ctx, unix_users_domain_name());
755 return true;
758 if (sid_check_is_unix_groups(sid)) {
759 *name = talloc_strdup(mem_ctx, unix_groups_domain_name());
760 return true;
763 if (sid->num_auths != 4) {
764 /* This can't be a domain */
765 return false;
768 if (IS_DC) {
769 uint32_t i, num_domains;
770 struct trustdom_info **domains;
772 /* This is relatively expensive, but it happens only on DCs
773 * and for SIDs that have 4 sub-authorities and thus look like
774 * domains */
776 if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
777 &num_domains,
778 &domains))) {
779 return false;
782 for (i=0; i<num_domains; i++) {
783 if (dom_sid_equal(sid, &domains[i]->sid)) {
784 *name = talloc_strdup(mem_ctx,
785 domains[i]->name);
786 return true;
789 return false;
792 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
793 (type == SID_NAME_DOMAIN)) {
794 *name = tmp;
795 return true;
798 return false;
802 * This tries to implement the rather weird rules for the lsa_lookup level
803 * parameter.
805 * This is as close as we can get to what W2k3 does. With this we survive the
806 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
807 * different, but I assume that's just being too liberal. For example, W2k3
808 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
809 * whereas NT4 does the same as level 1 (I think). I did not fully test that
810 * with NT4, this is what w2k3 does.
812 * Level 1: Ask everywhere
813 * Level 2: Ask domain and trusted domains, no builtin and wkn
814 * Level 3: Only ask domain
815 * Level 4: W2k3ad: Only ask AD trusts
816 * Level 5: Only ask transitive forest trusts
817 * Level 6: Like 4
820 static bool check_dom_sid_to_level(const struct dom_sid *sid, int level)
822 struct dom_sid_buf buf;
823 int ret = false;
825 switch(level) {
826 case 1:
827 ret = true;
828 break;
829 case 2:
830 ret = (!sid_check_is_builtin(sid) &&
831 !sid_check_is_wellknown_domain(sid, NULL));
832 break;
833 case 3:
834 case 4:
835 case 6:
836 ret = sid_check_is_our_sam(sid);
837 break;
838 case 5:
839 ret = false;
840 break;
843 DEBUG(10, ("%s SID %s in level %d\n",
844 ret ? "Accepting" : "Rejecting",
845 dom_sid_str_buf(sid, &buf),
846 level));
847 return ret;
851 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
852 * references to domains, it is explicitly made for this.
854 * This attempts to be as efficient as possible: It collects all SIDs
855 * belonging to a domain and hands them in bulk to the appropriate lookup
856 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
857 * *hugely* from this.
860 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
861 const struct dom_sid **sids, int level,
862 struct lsa_dom_info **ret_domains,
863 struct lsa_name_info **ret_names)
865 TALLOC_CTX *tmp_ctx;
866 NTSTATUS result;
867 struct lsa_name_info *name_infos;
868 struct lsa_dom_info *dom_infos = NULL;
870 int i, j;
872 if (!(tmp_ctx = talloc_new(mem_ctx))) {
873 DEBUG(0, ("talloc_new failed\n"));
874 return NT_STATUS_NO_MEMORY;
877 if (num_sids) {
878 name_infos = talloc_array(mem_ctx, struct lsa_name_info, num_sids);
879 if (name_infos == NULL) {
880 result = NT_STATUS_NO_MEMORY;
881 goto fail;
883 } else {
884 name_infos = NULL;
887 dom_infos = talloc_zero_array(mem_ctx, struct lsa_dom_info,
888 LSA_REF_DOMAIN_LIST_MULTIPLIER);
889 if (dom_infos == NULL) {
890 result = NT_STATUS_NO_MEMORY;
891 goto fail;
894 /* First build up the data structures:
896 * dom_infos is a list of domains referenced in the list of
897 * SIDs. Later we will walk the list of domains and look up the RIDs
898 * in bulk.
900 * name_infos is a shadow-copy of the SIDs array to collect the real
901 * data.
903 * dom_info->idxs is an index into the name_infos array. The
904 * difficulty we have here is that we need to keep the SIDs the client
905 * asked for in the same order for the reply
908 for (i=0; i<num_sids; i++) {
909 struct dom_sid sid;
910 uint32_t rid = 0;
911 const char *domain_name = NULL;
913 sid_copy(&sid, sids[i]);
914 name_infos[i].type = SID_NAME_USE_NONE;
916 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
917 /* We can't push that through the normal lookup
918 * process, as this would reference illegal
919 * domains.
921 * For example S-1-5-32 would end up referencing
922 * domain S-1-5- with RID 32 which is clearly wrong.
924 if (domain_name == NULL) {
925 result = NT_STATUS_NO_MEMORY;
926 goto fail;
929 name_infos[i].rid = 0;
930 name_infos[i].type = SID_NAME_DOMAIN;
931 name_infos[i].name = NULL;
933 if (sid_check_is_builtin(&sid)) {
934 /* Yes, W2k3 returns "BUILTIN" both as domain
935 * and name here */
936 name_infos[i].name = talloc_strdup(
937 name_infos, builtin_domain_name());
938 if (name_infos[i].name == NULL) {
939 result = NT_STATUS_NO_MEMORY;
940 goto fail;
943 } else {
944 /* This is a normal SID with rid component */
945 if (!sid_split_rid(&sid, &rid)) {
946 result = NT_STATUS_INVALID_SID;
947 goto fail;
951 if (!check_dom_sid_to_level(&sid, level)) {
952 name_infos[i].rid = 0;
953 name_infos[i].type = SID_NAME_UNKNOWN;
954 name_infos[i].name = NULL;
955 continue;
958 for (j=0; j<LSA_REF_DOMAIN_LIST_MULTIPLIER; j++) {
959 if (!dom_infos[j].valid) {
960 break;
962 if (dom_sid_equal(&sid, &dom_infos[j].sid)) {
963 break;
967 if (j == LSA_REF_DOMAIN_LIST_MULTIPLIER) {
968 /* TODO: What's the right error message here? */
969 result = NT_STATUS_NONE_MAPPED;
970 goto fail;
973 if (!dom_infos[j].valid) {
974 /* We found a domain not yet referenced, create a new
975 * ref. */
976 dom_infos[j].valid = true;
977 sid_copy(&dom_infos[j].sid, &sid);
979 if (domain_name != NULL) {
980 /* This name was being found above in the case
981 * when we found a domain SID */
982 dom_infos[j].name =
983 talloc_strdup(dom_infos, domain_name);
984 if (dom_infos[j].name == NULL) {
985 result = NT_STATUS_NO_MEMORY;
986 goto fail;
988 } else {
989 /* lookup_rids will take care of this */
990 dom_infos[j].name = NULL;
994 name_infos[i].dom_idx = j;
996 if (name_infos[i].type == SID_NAME_USE_NONE) {
997 name_infos[i].rid = rid;
999 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
1000 &dom_infos[j].num_idxs);
1002 if (dom_infos[j].idxs == NULL) {
1003 result = NT_STATUS_NO_MEMORY;
1004 goto fail;
1009 /* Iterate over the domains found */
1011 for (i=0; i<LSA_REF_DOMAIN_LIST_MULTIPLIER; i++) {
1012 uint32_t *rids;
1013 const char *domain_name = NULL;
1014 const char **names;
1015 enum lsa_SidType *types;
1016 struct lsa_dom_info *dom = &dom_infos[i];
1018 if (!dom->valid) {
1019 /* No domains left, we're done */
1020 break;
1023 if (dom->num_idxs == 0) {
1025 * This happens only if the only sid related to
1026 * this domain is the domain sid itself, which
1027 * is mapped to SID_NAME_DOMAIN above.
1029 continue;
1032 if (!(rids = talloc_array(tmp_ctx, uint32_t, dom->num_idxs))) {
1033 result = NT_STATUS_NO_MEMORY;
1034 goto fail;
1037 for (j=0; j<dom->num_idxs; j++) {
1038 rids[j] = name_infos[dom->idxs[j]].rid;
1041 if (!lookup_rids(tmp_ctx, &dom->sid,
1042 dom->num_idxs, rids, &domain_name,
1043 &names, &types)) {
1044 result = NT_STATUS_NO_MEMORY;
1045 goto fail;
1048 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
1049 result = NT_STATUS_NO_MEMORY;
1050 goto fail;
1053 for (j=0; j<dom->num_idxs; j++) {
1054 int idx = dom->idxs[j];
1055 name_infos[idx].type = types[j];
1056 if (types[j] != SID_NAME_UNKNOWN) {
1057 name_infos[idx].name =
1058 talloc_strdup(name_infos, names[j]);
1059 if (name_infos[idx].name == NULL) {
1060 result = NT_STATUS_NO_MEMORY;
1061 goto fail;
1063 } else {
1064 name_infos[idx].name = NULL;
1069 *ret_domains = dom_infos;
1070 *ret_names = name_infos;
1071 TALLOC_FREE(tmp_ctx);
1072 return NT_STATUS_OK;
1074 fail:
1075 TALLOC_FREE(dom_infos);
1076 TALLOC_FREE(name_infos);
1077 TALLOC_FREE(tmp_ctx);
1078 return result;
1081 /*****************************************************************
1082 *THE CANONICAL* convert SID to name function.
1083 *****************************************************************/
1085 bool lookup_sid(TALLOC_CTX *mem_ctx, const struct dom_sid *sid,
1086 const char **ret_domain, const char **ret_name,
1087 enum lsa_SidType *ret_type)
1089 struct lsa_dom_info *domain;
1090 struct lsa_name_info *name;
1091 struct dom_sid_buf buf;
1092 TALLOC_CTX *tmp_ctx;
1093 bool ret = false;
1095 DEBUG(10, ("lookup_sid called for SID '%s'\n",
1096 dom_sid_str_buf(sid, &buf)));
1098 if (!(tmp_ctx = talloc_new(mem_ctx))) {
1099 DEBUG(0, ("talloc_new failed\n"));
1100 return false;
1103 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
1104 &domain, &name))) {
1105 goto done;
1108 if (name->type == SID_NAME_UNKNOWN) {
1109 goto done;
1112 if ((ret_domain != NULL) &&
1113 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
1114 goto done;
1117 if ((ret_name != NULL) &&
1118 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
1119 goto done;
1122 if (ret_type != NULL) {
1123 *ret_type = name->type;
1126 ret = true;
1128 done:
1129 if (ret) {
1130 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
1131 dom_sid_str_buf(sid, &buf),
1132 domain->name, name->name, name->type));
1133 } else {
1134 DEBUG(10, ("failed to lookup sid %s\n",
1135 dom_sid_str_buf(sid, &buf)));
1137 TALLOC_FREE(tmp_ctx);
1138 return ret;
1141 /*****************************************************************
1142 *THE LEGACY* convert SID to id function.
1143 *****************************************************************/
1145 static bool legacy_sid_to_unixid(const struct dom_sid *psid, struct unixid *id)
1147 bool ret;
1149 become_root();
1150 ret = pdb_sid_to_id(psid, id);
1151 unbecome_root();
1153 if (!ret) {
1154 struct dom_sid_buf buf;
1155 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1156 dom_sid_str_buf(psid, &buf)));
1157 return false;
1160 return true;
1163 static bool legacy_sid_to_gid(const struct dom_sid *psid, gid_t *pgid)
1165 struct unixid id;
1166 if (!legacy_sid_to_unixid(psid, &id)) {
1167 return false;
1169 if (id.type == ID_TYPE_GID || id.type == ID_TYPE_BOTH) {
1170 *pgid = id.id;
1171 return true;
1173 return false;
1176 static bool legacy_sid_to_uid(const struct dom_sid *psid, uid_t *puid)
1178 struct unixid id;
1179 if (!legacy_sid_to_unixid(psid, &id)) {
1180 return false;
1182 if (id.type == ID_TYPE_UID || id.type == ID_TYPE_BOTH) {
1183 *puid = id.id;
1184 return true;
1186 return false;
1189 void xid_to_sid(struct dom_sid *psid, const struct unixid *xid)
1191 bool expired = true;
1192 bool ret;
1193 struct dom_sid_buf buf;
1195 SMB_ASSERT(xid->type == ID_TYPE_UID || xid->type == ID_TYPE_GID);
1197 *psid = (struct dom_sid) {0};
1199 ret = idmap_cache_find_xid2sid(xid, psid, &expired);
1200 if (ret && !expired) {
1201 DBG_DEBUG("%cID %"PRIu32" -> %s from cache\n",
1202 xid->type == ID_TYPE_UID ? 'U' : 'G',
1203 xid->id,
1204 dom_sid_str_buf(psid, &buf));
1205 goto done;
1208 ret = winbind_xid_to_sid(psid, xid);
1209 if (ret) {
1211 * winbind can return an explicit negative mapping
1212 * here. It's up to winbind to prime the cache either
1213 * positively or negatively, don't mess with the cache
1214 * here.
1216 DBG_DEBUG("%cID %"PRIu32" -> %s from cache\n",
1217 xid->type == ID_TYPE_UID ? 'U' : 'G',
1218 xid->id,
1219 dom_sid_str_buf(psid, &buf));
1220 goto done;
1225 * Make a copy, pdb_id_to_sid might want to turn
1226 * xid->type into ID_TYPE_BOTH, which we ignore here.
1228 struct unixid rw_xid = *xid;
1230 become_root();
1231 ret = pdb_id_to_sid(&rw_xid, psid);
1232 unbecome_root();
1235 if (ret) {
1236 DBG_DEBUG("%cID %"PRIu32" -> %s from passdb\n",
1237 xid->type == ID_TYPE_UID ? 'U' : 'G',
1238 xid->id,
1239 dom_sid_str_buf(psid, &buf));
1240 goto done;
1243 done:
1244 if (is_null_sid(psid)) {
1246 * Nobody found anything: Return S-1-22-xx-yy. Don't
1247 * store that in caches, this is up to the layers
1248 * beneath us.
1250 if (xid->type == ID_TYPE_UID) {
1251 uid_to_unix_users_sid(xid->id, psid);
1252 } else {
1253 gid_to_unix_groups_sid(xid->id, psid);
1256 DBG_DEBUG("%cID %"PRIu32" -> %s fallback\n",
1257 xid->type == ID_TYPE_UID ? 'U' : 'G',
1258 xid->id,
1259 dom_sid_str_buf(psid, &buf));
1263 void uid_to_sid(struct dom_sid *psid, uid_t uid)
1265 struct unixid xid = { .type = ID_TYPE_UID, .id = uid};
1266 xid_to_sid(psid, &xid);
1269 void gid_to_sid(struct dom_sid *psid, gid_t gid)
1271 struct unixid xid = { .type = ID_TYPE_GID, .id = gid};
1272 xid_to_sid(psid, &xid);
1275 bool sids_to_unixids(const struct dom_sid *sids, uint32_t num_sids,
1276 struct unixid *ids)
1278 struct wbcDomainSid *wbc_sids = NULL;
1279 struct wbcUnixId *wbc_ids = NULL;
1280 struct bitmap *found = NULL;
1281 uint32_t i, num_not_cached;
1282 uint32_t wbc_ids_size = 0;
1283 wbcErr err;
1284 bool ret = false;
1286 wbc_sids = talloc_array(talloc_tos(), struct wbcDomainSid, num_sids);
1287 if (wbc_sids == NULL) {
1288 return false;
1290 found = bitmap_talloc(wbc_sids, num_sids);
1291 if (found == NULL) {
1292 goto fail;
1296 * We go through the requested SID array three times.
1297 * First time to look for global_sid_Unix_Users
1298 * and global_sid_Unix_Groups SIDS, and to look
1299 * for mappings cached in the idmap_cache.
1301 * Use bitmap_set() to mark an ids[] array entry as
1302 * being mapped.
1305 num_not_cached = 0;
1307 for (i=0; i<num_sids; i++) {
1308 bool expired;
1309 uint32_t rid;
1311 if (sid_peek_check_rid(&global_sid_Unix_Users,
1312 &sids[i], &rid)) {
1313 ids[i].type = ID_TYPE_UID;
1314 ids[i].id = rid;
1315 bitmap_set(found, i);
1316 continue;
1318 if (sid_peek_check_rid(&global_sid_Unix_Groups,
1319 &sids[i], &rid)) {
1320 ids[i].type = ID_TYPE_GID;
1321 ids[i].id = rid;
1322 bitmap_set(found, i);
1323 continue;
1325 if (idmap_cache_find_sid2unixid(&sids[i], &ids[i], &expired)
1326 && !expired)
1328 bitmap_set(found, i);
1329 continue;
1331 ids[i].type = ID_TYPE_NOT_SPECIFIED;
1332 memcpy(&wbc_sids[num_not_cached], &sids[i],
1333 ndr_size_dom_sid(&sids[i], 0));
1334 num_not_cached += 1;
1336 if (num_not_cached == 0) {
1337 goto done;
1341 * For the ones that we couldn't map in the loop above, query winbindd
1342 * via wbcSidsToUnixIds().
1345 wbc_ids_size = num_not_cached;
1346 wbc_ids = talloc_array(talloc_tos(), struct wbcUnixId, wbc_ids_size);
1347 if (wbc_ids == NULL) {
1348 goto fail;
1350 for (i=0; i<wbc_ids_size; i++) {
1351 wbc_ids[i].type = WBC_ID_TYPE_NOT_SPECIFIED;
1352 wbc_ids[i].id.gid = (uint32_t)-1;
1354 err = wbcSidsToUnixIds(wbc_sids, wbc_ids_size, wbc_ids);
1355 if (!WBC_ERROR_IS_OK(err)) {
1356 DEBUG(10, ("wbcSidsToUnixIds returned %s\n",
1357 wbcErrorString(err)));
1361 * Second time through the SID array, replace
1362 * the ids[] entries that wbcSidsToUnixIds() was able to
1363 * map.
1365 * Use bitmap_set() to mark an ids[] array entry as
1366 * being mapped.
1369 num_not_cached = 0;
1371 for (i=0; i<num_sids; i++) {
1372 if (bitmap_query(found, i)) {
1373 continue;
1376 SMB_ASSERT(num_not_cached < wbc_ids_size);
1378 switch (wbc_ids[num_not_cached].type) {
1379 case WBC_ID_TYPE_UID:
1380 ids[i].type = ID_TYPE_UID;
1381 ids[i].id = wbc_ids[num_not_cached].id.uid;
1382 bitmap_set(found, i);
1383 break;
1384 case WBC_ID_TYPE_GID:
1385 ids[i].type = ID_TYPE_GID;
1386 ids[i].id = wbc_ids[num_not_cached].id.gid;
1387 bitmap_set(found, i);
1388 break;
1389 case WBC_ID_TYPE_BOTH:
1390 ids[i].type = ID_TYPE_BOTH;
1391 ids[i].id = wbc_ids[num_not_cached].id.uid;
1392 bitmap_set(found, i);
1393 break;
1394 case WBC_ID_TYPE_NOT_SPECIFIED:
1396 * wbcSidsToUnixIds() wasn't able to map this
1397 * so we still need to check legacy_sid_to_XXX()
1398 * below. Don't mark the bitmap entry
1399 * as being found so the final loop knows
1400 * to try and map this entry.
1402 ids[i].type = ID_TYPE_NOT_SPECIFIED;
1403 ids[i].id = (uint32_t)-1;
1404 break;
1405 default:
1407 * A successful return from wbcSidsToUnixIds()
1408 * cannot return anything other than the values
1409 * checked for above. Ensure this is so.
1411 smb_panic(__location__);
1412 break;
1414 num_not_cached += 1;
1418 * Third and final time through the SID array,
1419 * try legacy_sid_to_gid()/legacy_sid_to_uid()
1420 * for entries we haven't already been able to
1421 * map.
1423 * Use bitmap_set() to mark an ids[] array entry as
1424 * being mapped.
1427 for (i=0; i<num_sids; i++) {
1428 if (bitmap_query(found, i)) {
1429 continue;
1431 if (legacy_sid_to_gid(&sids[i], &ids[i].id)) {
1432 ids[i].type = ID_TYPE_GID;
1433 bitmap_set(found, i);
1434 continue;
1436 if (legacy_sid_to_uid(&sids[i], &ids[i].id)) {
1437 ids[i].type = ID_TYPE_UID;
1438 bitmap_set(found, i);
1439 continue;
1442 done:
1444 * Pass through the return array for consistency.
1445 * Any ids[].id mapped to (uint32_t)-1 must be returned
1446 * as ID_TYPE_NOT_SPECIFIED.
1448 for (i=0; i<num_sids; i++) {
1449 switch(ids[i].type) {
1450 case ID_TYPE_GID:
1451 case ID_TYPE_UID:
1452 case ID_TYPE_BOTH:
1453 if (ids[i].id == (uint32_t)-1) {
1454 ids[i].type = ID_TYPE_NOT_SPECIFIED;
1456 break;
1457 case ID_TYPE_NOT_SPECIFIED:
1458 break;
1459 case ID_TYPE_WB_REQUIRE_TYPE:
1461 * these are internal between winbindd
1462 * parent and child.
1464 smb_panic(__location__);
1465 break;
1469 ret = true;
1470 fail:
1471 TALLOC_FREE(wbc_ids);
1472 TALLOC_FREE(wbc_sids);
1473 return ret;
1476 /*****************************************************************
1477 *THE CANONICAL* convert SID to uid function.
1478 *****************************************************************/
1480 bool sid_to_uid(const struct dom_sid *psid, uid_t *puid)
1482 bool expired = true;
1483 bool ret;
1484 uint32_t rid;
1485 struct dom_sid_buf buf;
1487 /* Optimize for the Unix Users Domain
1488 * as the conversion is straightforward */
1489 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1490 uid_t uid = rid;
1491 *puid = uid;
1493 /* return here, don't cache */
1494 DEBUG(10,("sid %s -> uid %u\n",
1495 dom_sid_str_buf(psid, &buf),
1496 (unsigned int)*puid ));
1497 return true;
1500 if (sid_check_is_in_unix_groups(psid)) {
1501 DBG_DEBUG("SID %s is a group, failing\n",
1502 dom_sid_str_buf(psid, &buf));
1503 return false;
1506 /* Check the winbindd cache directly. */
1507 ret = idmap_cache_find_sid2uid(psid, puid, &expired);
1509 if (ret && !expired && (*puid == (uid_t)-1)) {
1511 * Negative cache entry, we already asked.
1512 * do legacy.
1514 return legacy_sid_to_uid(psid, puid);
1517 if (!ret || expired) {
1518 /* Not in cache. Ask winbindd. */
1519 if (!winbind_sid_to_uid(puid, psid)) {
1520 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1521 dom_sid_str_buf(psid, &buf)));
1522 /* winbind failed. do legacy */
1523 return legacy_sid_to_uid(psid, puid);
1527 /* TODO: Here would be the place to allocate both a gid and a uid for
1528 * the SID in question */
1530 DEBUG(10,("sid %s -> uid %u\n",
1531 dom_sid_str_buf(psid, &buf),
1532 (unsigned int)*puid ));
1534 return true;
1537 /*****************************************************************
1538 *THE CANONICAL* convert SID to gid function.
1539 Group mapping is used for gids that maps to Wellknown SIDs
1540 *****************************************************************/
1542 bool sid_to_gid(const struct dom_sid *psid, gid_t *pgid)
1544 bool expired = true;
1545 bool ret;
1546 uint32_t rid;
1547 struct dom_sid_buf buf;
1549 /* Optimize for the Unix Groups Domain
1550 * as the conversion is straightforward */
1551 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1552 gid_t gid = rid;
1553 *pgid = gid;
1555 /* return here, don't cache */
1556 DEBUG(10,("sid %s -> gid %u\n",
1557 dom_sid_str_buf(psid, &buf),
1558 (unsigned int)*pgid ));
1559 return true;
1562 if (sid_check_is_in_unix_users(psid)) {
1563 DBG_DEBUG("SID %s is a user, failing\n",
1564 dom_sid_str_buf(psid, &buf));
1565 return false;
1568 /* Check the winbindd cache directly. */
1569 ret = idmap_cache_find_sid2gid(psid, pgid, &expired);
1571 if (ret && !expired && (*pgid == (gid_t)-1)) {
1573 * Negative cache entry, we already asked.
1574 * do legacy.
1576 return legacy_sid_to_gid(psid, pgid);
1579 if (!ret || expired) {
1580 /* Not in cache or negative. Ask winbindd. */
1581 /* Ask winbindd if it can map this sid to a gid.
1582 * (Idmap will check it is a valid SID and of the right type) */
1584 if ( !winbind_sid_to_gid(pgid, psid) ) {
1586 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1587 dom_sid_str_buf(psid, &buf)));
1588 /* winbind failed. do legacy */
1589 return legacy_sid_to_gid(psid, pgid);
1593 DEBUG(10,("sid %s -> gid %u\n",
1594 dom_sid_str_buf(psid, &buf),
1595 (unsigned int)*pgid ));
1597 return true;
1601 * @brief This function gets the primary group SID mapping the primary
1602 * GID of the user as obtained by an actual getpwnam() call.
1603 * This is necessary to avoid issues with arbitrary group SIDs
1604 * stored in passdb. We try as hard as we can to get the SID
1605 * corresponding to the GID, including trying group mapping.
1606 * If nothing else works, we will force "Domain Users" as the
1607 * primary group.
1608 * This is needed because we must always be able to lookup the
1609 * primary group SID, so we cannot settle for an arbitrary SID.
1611 * This call can be expensive. Use with moderation.
1612 * If you have a "samu" struct around use pdb_get_group_sid()
1613 * instead as it does properly cache results.
1615 * @param mem_ctx[in] The memory context iused to allocate the result.
1616 * @param username[in] The user's name
1617 * @param _pwd[in|out] If available, pass in user's passwd struct.
1618 * It will contain a tallocated passwd if NULL was
1619 * passed in.
1620 * @param _group_sid[out] The user's Primary Group SID
1622 * @return NTSTATUS error code.
1624 NTSTATUS get_primary_group_sid(TALLOC_CTX *mem_ctx,
1625 const char *username,
1626 struct passwd **_pwd,
1627 struct dom_sid **_group_sid)
1629 TALLOC_CTX *tmp_ctx;
1630 bool need_lookup_sid = false;
1631 struct dom_sid *group_sid;
1632 struct passwd *pwd = *_pwd;
1634 tmp_ctx = talloc_new(mem_ctx);
1635 if (!tmp_ctx) {
1636 return NT_STATUS_NO_MEMORY;
1639 if (!pwd) {
1640 pwd = Get_Pwnam_alloc(mem_ctx, username);
1641 if (!pwd) {
1642 DEBUG(0, ("Failed to find a Unix account for %s\n",
1643 username));
1644 TALLOC_FREE(tmp_ctx);
1645 return NT_STATUS_NO_SUCH_USER;
1649 group_sid = talloc_zero(mem_ctx, struct dom_sid);
1650 if (!group_sid) {
1651 TALLOC_FREE(tmp_ctx);
1652 return NT_STATUS_NO_MEMORY;
1655 gid_to_sid(group_sid, pwd->pw_gid);
1656 if (!is_null_sid(group_sid)) {
1657 struct dom_sid domain_sid;
1658 uint32_t rid;
1660 /* We need a sid within our domain */
1661 sid_copy(&domain_sid, group_sid);
1662 sid_split_rid(&domain_sid, &rid);
1663 if (dom_sid_equal(&domain_sid, get_global_sam_sid())) {
1665 * As shortcut for the expensive lookup_sid call
1666 * compare the domain sid part
1668 switch (rid) {
1669 case DOMAIN_RID_ADMINS:
1670 case DOMAIN_RID_USERS:
1671 goto done;
1672 default:
1673 need_lookup_sid = true;
1674 break;
1676 } else {
1677 /* Try group mapping */
1678 struct unixid id;
1680 id.id = pwd->pw_gid;
1681 id.type = ID_TYPE_GID;
1683 ZERO_STRUCTP(group_sid);
1684 if (pdb_id_to_sid(&id, group_sid)) {
1685 need_lookup_sid = true;
1690 /* We must verify that this is a valid SID that resolves to a
1691 * group of the correct type */
1692 if (need_lookup_sid) {
1693 enum lsa_SidType type = SID_NAME_UNKNOWN;
1694 bool lookup_ret;
1695 struct dom_sid_buf buf;
1697 DEBUG(10, ("do lookup_sid(%s) for group of user %s\n",
1698 dom_sid_str_buf(group_sid, &buf),
1699 username));
1701 /* Now check that it's actually a domain group and
1702 * not something else */
1703 lookup_ret = lookup_sid(tmp_ctx, group_sid,
1704 NULL, NULL, &type);
1706 if (lookup_ret && (type == SID_NAME_DOM_GRP)) {
1707 goto done;
1710 DEBUG(3, ("Primary group %s for user %s is"
1711 " a %s and not a domain group\n",
1712 dom_sid_str_buf(group_sid, &buf),
1713 username,
1714 sid_type_lookup(type)));
1717 /* Everything else, failed.
1718 * Just set it to the 'Domain Users' RID of 513 which will
1719 always resolve to a name */
1720 DEBUG(3, ("Forcing Primary Group to 'Domain Users' for %s\n",
1721 username));
1723 sid_compose(group_sid, get_global_sam_sid(), DOMAIN_RID_USERS);
1725 done:
1726 *_pwd = talloc_move(mem_ctx, &pwd);
1727 *_group_sid = talloc_move(mem_ctx, &group_sid);
1728 TALLOC_FREE(tmp_ctx);
1729 return NT_STATUS_OK;