2 Unix SMB/CIFS implementation.
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.
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
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)
40 const char *domain = NULL;
41 const char *name = NULL;
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"));
52 p = strchr_m(full_name, '\\');
55 domain = talloc_strndup(tmp_ctx, full_name,
56 PTR_DIFF(p, full_name));
57 name = talloc_strdup(tmp_ctx, p+1);
59 domain = talloc_strdup(tmp_ctx, "");
60 name = talloc_strdup(tmp_ctx, full_name);
63 DEBUG(10,("lookup_name: %s => %s (domain), %s (name)\n",
64 full_name, domain, name));
66 if ((domain == NULL) || (name == NULL)) {
67 DEBUG(0, ("talloc failed\n"));
72 if (strequal(domain, get_global_sam_name())) {
74 /* It's our own domain, lookup the name in passdb */
75 if (lookup_global_sam_name(name, flags, &rid, &type)) {
76 sid_copy(&sid, get_global_sam_sid());
77 sid_append_rid(&sid, rid);
84 if (strequal(domain, builtin_domain_name())) {
86 /* Explicit request for a name in BUILTIN */
87 if (lookup_builtin_name(name, &rid)) {
88 sid_copy(&sid, &global_sid_Builtin);
89 sid_append_rid(&sid, rid);
90 type = SID_NAME_ALIAS;
97 /* Try the explicit winbind lookup first, don't let it guess the
98 * domain yet at this point yet. This comes later. */
100 if ((domain[0] != '\0') &&
101 (winbind_lookup_name(domain, name, &sid, &type))) {
105 if (strequal(domain, unix_users_domain_name())) {
106 if (lookup_unix_user_name(name, &sid)) {
107 type = SID_NAME_USER;
110 TALLOC_FREE(tmp_ctx);
114 if (strequal(domain, unix_groups_domain_name())) {
115 if (lookup_unix_group_name(name, &sid)) {
116 type = SID_NAME_DOM_GRP;
119 TALLOC_FREE(tmp_ctx);
123 if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
124 TALLOC_FREE(tmp_ctx);
128 /* Now the guesswork begins, we haven't been given an explicit
129 * domain. Try the sequence as documented on
130 * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
131 * November 27, 2005 */
133 /* 1. well-known names */
135 if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
136 type = SID_NAME_WKN_GRP;
140 /* 2. Builtin domain as such */
142 if (strequal(name, builtin_domain_name())) {
143 /* Swap domain and name */
144 tmp = name; name = domain; domain = tmp;
145 sid_copy(&sid, &global_sid_Builtin);
146 type = SID_NAME_DOMAIN;
150 /* 3. Account domain */
152 if (strequal(name, get_global_sam_name())) {
153 if (!secrets_fetch_domain_sid(name, &sid)) {
154 DEBUG(3, ("Could not fetch my SID\n"));
155 TALLOC_FREE(tmp_ctx);
158 /* Swap domain and name */
159 tmp = name; name = domain; domain = tmp;
160 type = SID_NAME_DOMAIN;
164 /* 4. Primary domain */
166 if (!IS_DC && strequal(name, lp_workgroup())) {
167 if (!secrets_fetch_domain_sid(name, &sid)) {
168 DEBUG(3, ("Could not fetch the domain SID\n"));
169 TALLOC_FREE(tmp_ctx);
172 /* Swap domain and name */
173 tmp = name; name = domain; domain = tmp;
174 type = SID_NAME_DOMAIN;
178 /* 5. Trusted domains as such, to me it looks as if members don't do
179 this, tested an XP workstation in a NT domain -- vl */
181 if (IS_DC && (pdb_get_trusteddom_pw(name, NULL, &sid, NULL))) {
182 /* Swap domain and name */
183 tmp = name; name = domain; domain = tmp;
184 type = SID_NAME_DOMAIN;
188 /* 6. Builtin aliases */
190 if (lookup_builtin_name(name, &rid)) {
191 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
192 sid_copy(&sid, &global_sid_Builtin);
193 sid_append_rid(&sid, rid);
194 type = SID_NAME_ALIAS;
198 /* 7. Local systems' SAM (DCs don't have a local SAM) */
199 /* 8. Primary SAM (On members, this is the domain) */
201 /* Both cases are done by looking at our passdb */
203 if (lookup_global_sam_name(name, flags, &rid, &type)) {
204 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
205 sid_copy(&sid, get_global_sam_sid());
206 sid_append_rid(&sid, rid);
210 /* Now our local possibilities are exhausted. */
212 if (!(flags & LOOKUP_NAME_REMOTE)) {
213 TALLOC_FREE(tmp_ctx);
217 /* If we are not a DC, we have to ask in our primary domain. Let
218 * winbind do that. */
221 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
222 domain = talloc_strdup(tmp_ctx, lp_workgroup());
226 /* 9. Trusted domains */
228 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
229 * that (yet), but give it a chance. */
231 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
234 enum lsa_SidType domain_type;
236 if (type == SID_NAME_DOMAIN) {
237 /* Swap name and type */
238 tmp = name; name = domain; domain = tmp;
242 /* Here we have to cope with a little deficiency in the
243 * winbind API: We have to ask it again for the name of the
244 * domain it figured out itself. Maybe fix that later... */
246 sid_copy(&dom_sid, &sid);
247 sid_split_rid(&dom_sid, &tmp_rid);
249 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
251 (domain_type != SID_NAME_DOMAIN)) {
252 DEBUG(2, ("winbind could not find the domain's name "
253 "it just looked up for us\n"));
254 TALLOC_FREE(tmp_ctx);
260 /* 10. Don't translate */
262 /* 11. Ok, windows would end here. Samba has two more options:
263 Unmapped users and unmapped groups */
265 if (lookup_unix_user_name(name, &sid)) {
266 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
267 type = SID_NAME_USER;
271 if (lookup_unix_group_name(name, &sid)) {
272 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
273 type = SID_NAME_DOM_GRP;
278 * Ok, all possibilities tried. Fail.
281 TALLOC_FREE(tmp_ctx);
285 if ((domain == NULL) || (name == NULL)) {
286 DEBUG(0, ("talloc failed\n"));
287 TALLOC_FREE(tmp_ctx);
292 * Hand over the results to the talloc context we've been given.
295 if ((ret_name != NULL) &&
296 !(*ret_name = talloc_strdup(mem_ctx, name))) {
297 DEBUG(0, ("talloc failed\n"));
298 TALLOC_FREE(tmp_ctx);
302 if (ret_domain != NULL) {
304 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
305 DEBUG(0, ("talloc failed\n"));
306 TALLOC_FREE(tmp_ctx);
310 *ret_domain = tmp_dom;
313 if (ret_sid != NULL) {
314 sid_copy(ret_sid, &sid);
317 if (ret_type != NULL) {
321 TALLOC_FREE(tmp_ctx);
325 /************************************************************************
326 Names from smb.conf can be unqualified. eg. valid users = foo
327 These names should never map to a remote name. Try global_sam_name()\foo,
328 and then "Unix Users"\foo (or "Unix Groups"\foo).
329 ************************************************************************/
331 BOOL lookup_name_smbconf(TALLOC_CTX *mem_ctx,
332 const char *full_name, int flags,
333 const char **ret_domain, const char **ret_name,
334 DOM_SID *ret_sid, enum lsa_SidType *ret_type)
336 char *qualified_name;
339 /* NB. No winbindd_separator here as lookup_name needs \\' */
340 if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
342 /* The name is already qualified with a domain. */
344 if (*lp_winbind_separator() != '\\') {
347 /* lookup_name() needs '\\' as a separator */
349 tmp = talloc_strdup(mem_ctx, full_name);
353 tmp[p - full_name] = '\\';
357 return lookup_name(mem_ctx, full_name, flags,
358 ret_domain, ret_name,
362 /* Try with our own SAM name. */
363 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
364 get_global_sam_name(),
366 if (!qualified_name) {
370 if (lookup_name(mem_ctx, qualified_name, flags,
371 ret_domain, ret_name,
372 ret_sid, ret_type)) {
376 /* Finally try with "Unix Users" or "Unix Group" */
377 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
378 flags & LOOKUP_NAME_GROUP ?
379 unix_groups_domain_name() :
380 unix_users_domain_name(),
382 if (!qualified_name) {
386 return lookup_name(mem_ctx, qualified_name, flags,
387 ret_domain, ret_name,
391 static BOOL wb_lookup_rids(TALLOC_CTX *mem_ctx,
392 const DOM_SID *domain_sid,
393 int num_rids, uint32 *rids,
394 const char **domain_name,
395 const char **names, enum lsa_SidType *types)
398 const char **my_names;
399 enum lsa_SidType *my_types;
402 if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
406 if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
407 domain_name, &my_names, &my_types)) {
409 for (i=0; i<num_rids; i++) {
411 types[i] = SID_NAME_UNKNOWN;
417 * winbind_lookup_rids allocates its own array. We've been given the
418 * array, so copy it over
421 for (i=0; i<num_rids; i++) {
422 if (my_names[i] == NULL) {
423 TALLOC_FREE(tmp_ctx);
426 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
427 TALLOC_FREE(tmp_ctx);
430 types[i] = my_types[i];
432 TALLOC_FREE(tmp_ctx);
436 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
437 int num_rids, uint32_t *rids,
438 const char **domain_name,
439 const char ***names, enum lsa_SidType **types)
443 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
444 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
446 if ((*names == NULL) || (*types == NULL)) {
450 if (sid_check_is_domain(domain_sid)) {
453 if (*domain_name == NULL) {
454 *domain_name = talloc_strdup(
455 mem_ctx, get_global_sam_name());
458 if (*domain_name == NULL) {
462 become_root_uid_only();
463 result = pdb_lookup_rids(domain_sid, num_rids, rids,
465 unbecome_root_uid_only();
467 return (NT_STATUS_IS_OK(result) ||
468 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
469 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
472 if (sid_check_is_builtin(domain_sid)) {
474 if (*domain_name == NULL) {
475 *domain_name = talloc_strdup(
476 mem_ctx, builtin_domain_name());
479 if (*domain_name == NULL) {
483 for (i=0; i<num_rids; i++) {
484 if (lookup_builtin_rid(*names, rids[i],
486 if ((*names)[i] == NULL) {
489 (*types)[i] = SID_NAME_ALIAS;
491 (*types)[i] = SID_NAME_UNKNOWN;
497 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
498 for (i=0; i<num_rids; i++) {
500 sid_copy(&sid, domain_sid);
501 sid_append_rid(&sid, rids[i]);
502 if (lookup_wellknown_sid(mem_ctx, &sid,
503 domain_name, &(*names)[i])) {
504 if ((*names)[i] == NULL) {
507 (*types)[i] = SID_NAME_WKN_GRP;
509 (*types)[i] = SID_NAME_UNKNOWN;
515 if (sid_check_is_unix_users(domain_sid)) {
516 if (*domain_name == NULL) {
517 *domain_name = talloc_strdup(
518 mem_ctx, unix_users_domain_name());
520 for (i=0; i<num_rids; i++) {
521 (*names)[i] = talloc_strdup(
522 (*names), uidtoname(rids[i]));
523 (*types)[i] = SID_NAME_USER;
528 if (sid_check_is_unix_groups(domain_sid)) {
529 if (*domain_name == NULL) {
530 *domain_name = talloc_strdup(
531 mem_ctx, unix_groups_domain_name());
533 for (i=0; i<num_rids; i++) {
534 (*names)[i] = talloc_strdup(
535 (*names), gidtoname(rids[i]));
536 (*types)[i] = SID_NAME_DOM_GRP;
541 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
542 domain_name, *names, *types);
546 * Is the SID a domain as such? If yes, lookup its name.
549 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
553 enum lsa_SidType type;
555 if (sid_check_is_domain(sid)) {
556 *name = talloc_strdup(mem_ctx, get_global_sam_name());
560 if (sid_check_is_builtin(sid)) {
561 *name = talloc_strdup(mem_ctx, builtin_domain_name());
565 if (sid_check_is_wellknown_domain(sid, &tmp)) {
566 *name = talloc_strdup(mem_ctx, tmp);
570 if (sid->num_auths != 4) {
571 /* This can't be a domain */
576 uint32 i, num_domains;
577 struct trustdom_info **domains;
579 /* This is relatively expensive, but it happens only on DCs
580 * and for SIDs that have 4 sub-authorities and thus look like
583 if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
589 for (i=0; i<num_domains; i++) {
590 if (sid_equal(sid, &domains[i]->sid)) {
591 *name = talloc_strdup(mem_ctx,
599 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
600 (type == SID_NAME_DOMAIN)) {
609 * This tries to implement the rather weird rules for the lsa_lookup level
612 * This is as close as we can get to what W2k3 does. With this we survive the
613 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
614 * different, but I assume that's just being too liberal. For example, W2k3
615 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
616 * whereas NT4 does the same as level 1 (I think). I did not fully test that
617 * with NT4, this is what w2k3 does.
619 * Level 1: Ask everywhere
620 * Level 2: Ask domain and trusted domains, no builtin and wkn
621 * Level 3: Only ask domain
622 * Level 4: W2k3ad: Only ask AD trusts
623 * Level 5: Don't lookup anything
627 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
636 ret = (!sid_check_is_builtin(sid) &&
637 !sid_check_is_wellknown_domain(sid, NULL));
642 ret = sid_check_is_domain(sid);
649 DEBUG(10, ("%s SID %s in level %d\n",
650 ret ? "Accepting" : "Rejecting",
651 sid_string_static(sid), level));
656 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
657 * references to domains, it is explicitly made for this.
659 * This attempts to be as efficient as possible: It collects all SIDs
660 * belonging to a domain and hands them in bulk to the appropriate lookup
661 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
662 * *hugely* from this. Winbind is going to be extended with a lookup_rids
663 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
667 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
668 const DOM_SID **sids, int level,
669 struct lsa_dom_info **ret_domains,
670 struct lsa_name_info **ret_names)
673 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
674 struct lsa_name_info *name_infos;
675 struct lsa_dom_info *dom_infos;
679 if (!(tmp_ctx = talloc_new(mem_ctx))) {
680 DEBUG(0, ("talloc_new failed\n"));
681 return NT_STATUS_NO_MEMORY;
684 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
685 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
687 if ((name_infos == NULL) || (dom_infos == NULL)) {
688 result = NT_STATUS_NO_MEMORY;
692 /* First build up the data structures:
694 * dom_infos is a list of domains referenced in the list of
695 * SIDs. Later we will walk the list of domains and look up the RIDs
698 * name_infos is a shadow-copy of the SIDs array to collect the real
701 * dom_info->idxs is an index into the name_infos array. The
702 * difficulty we have here is that we need to keep the SIDs the client
703 * asked for in the same order for the reply
706 for (i=0; i<num_sids; i++) {
709 const char *domain_name = NULL;
711 sid_copy(&sid, sids[i]);
712 name_infos[i].type = SID_NAME_USE_NONE;
714 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
715 /* We can't push that through the normal lookup
716 * process, as this would reference illegal
719 * For example S-1-5-32 would end up referencing
720 * domain S-1-5- with RID 32 which is clearly wrong.
722 if (domain_name == NULL) {
723 result = NT_STATUS_NO_MEMORY;
727 name_infos[i].rid = 0;
728 name_infos[i].type = SID_NAME_DOMAIN;
729 name_infos[i].name = NULL;
731 if (sid_check_is_builtin(&sid)) {
732 /* Yes, W2k3 returns "BUILTIN" both as domain
734 name_infos[i].name = talloc_strdup(
735 name_infos, builtin_domain_name());
736 if (name_infos[i].name == NULL) {
737 result = NT_STATUS_NO_MEMORY;
742 /* This is a normal SID with rid component */
743 if (!sid_split_rid(&sid, &rid)) {
744 result = NT_STATUS_INVALID_PARAMETER;
749 if (!check_dom_sid_to_level(&sid, level)) {
750 name_infos[i].rid = 0;
751 name_infos[i].type = SID_NAME_UNKNOWN;
752 name_infos[i].name = NULL;
756 for (j=0; j<MAX_REF_DOMAINS; j++) {
757 if (!dom_infos[j].valid) {
760 if (sid_equal(&sid, &dom_infos[j].sid)) {
765 if (j == MAX_REF_DOMAINS) {
766 /* TODO: What's the right error message here? */
767 result = NT_STATUS_NONE_MAPPED;
771 if (!dom_infos[j].valid) {
772 /* We found a domain not yet referenced, create a new
774 dom_infos[j].valid = True;
775 sid_copy(&dom_infos[j].sid, &sid);
777 if (domain_name != NULL) {
778 /* This name was being found above in the case
779 * when we found a domain SID */
781 talloc_strdup(dom_infos, domain_name);
782 if (dom_infos[j].name == NULL) {
783 result = NT_STATUS_NO_MEMORY;
787 /* lookup_rids will take care of this */
788 dom_infos[j].name = NULL;
792 name_infos[i].dom_idx = j;
794 if (name_infos[i].type == SID_NAME_USE_NONE) {
795 name_infos[i].rid = rid;
797 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
798 &dom_infos[j].num_idxs);
800 if (dom_infos[j].idxs == NULL) {
801 result = NT_STATUS_NO_MEMORY;
807 /* Iterate over the domains found */
809 for (i=0; i<MAX_REF_DOMAINS; i++) {
811 const char *domain_name = NULL;
813 enum lsa_SidType *types;
814 struct lsa_dom_info *dom = &dom_infos[i];
817 /* No domains left, we're done */
821 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
822 result = NT_STATUS_NO_MEMORY;
826 for (j=0; j<dom->num_idxs; j++) {
827 rids[j] = name_infos[dom->idxs[j]].rid;
830 if (!lookup_rids(tmp_ctx, &dom->sid,
831 dom->num_idxs, rids, &domain_name,
833 result = NT_STATUS_NO_MEMORY;
837 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
838 result = NT_STATUS_NO_MEMORY;
842 for (j=0; j<dom->num_idxs; j++) {
843 int idx = dom->idxs[j];
844 name_infos[idx].type = types[j];
845 if (types[j] != SID_NAME_UNKNOWN) {
846 name_infos[idx].name =
847 talloc_strdup(name_infos, names[j]);
848 if (name_infos[idx].name == NULL) {
849 result = NT_STATUS_NO_MEMORY;
853 name_infos[idx].name = NULL;
858 *ret_domains = dom_infos;
859 *ret_names = name_infos;
863 TALLOC_FREE(dom_infos);
864 TALLOC_FREE(name_infos);
865 TALLOC_FREE(tmp_ctx);
869 /*****************************************************************
870 *THE CANONICAL* convert SID to name function.
871 *****************************************************************/
873 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
874 const char **ret_domain, const char **ret_name,
875 enum lsa_SidType *ret_type)
877 struct lsa_dom_info *domain;
878 struct lsa_name_info *name;
882 if (!(tmp_ctx = talloc_new(mem_ctx))) {
883 DEBUG(0, ("talloc_new failed\n"));
887 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
892 if (name->type == SID_NAME_UNKNOWN) {
896 if ((ret_domain != NULL) &&
897 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
901 if ((ret_name != NULL) &&
902 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
906 if (ret_type != NULL) {
907 *ret_type = name->type;
914 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
915 sid_string_static(sid), domain->name,
916 name->name, name->type));
918 DEBUG(10, ("failed to lookup sid %s\n",
919 sid_string_static(sid)));
921 TALLOC_FREE(tmp_ctx);
925 /*****************************************************************
926 Id mapping cache. This is to avoid Winbind mappings already
927 seen by smbd to be queried too frequently, keeping winbindd
928 busy, and blocking smbd while winbindd is busy with other
929 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
930 modified to use linked lists by jra.
931 *****************************************************************/
933 #define MAX_UID_SID_CACHE_SIZE 100
934 #define TURNOVER_UID_SID_CACHE_SIZE 10
935 #define MAX_GID_SID_CACHE_SIZE 100
936 #define TURNOVER_GID_SID_CACHE_SIZE 10
938 static size_t n_uid_sid_cache = 0;
939 static size_t n_gid_sid_cache = 0;
941 static struct uid_sid_cache {
942 struct uid_sid_cache *next, *prev;
945 enum lsa_SidType sidtype;
946 } *uid_sid_cache_head;
948 static struct gid_sid_cache {
949 struct gid_sid_cache *next, *prev;
952 enum lsa_SidType sidtype;
953 } *gid_sid_cache_head;
955 /*****************************************************************
956 Find a SID given a uid.
957 *****************************************************************/
959 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
961 struct uid_sid_cache *pc;
963 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
964 if (pc->uid == uid) {
966 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
967 (unsigned int)uid, sid_string_static(psid)));
968 DLIST_PROMOTE(uid_sid_cache_head, pc);
975 /*****************************************************************
976 Find a uid given a SID.
977 *****************************************************************/
979 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
981 struct uid_sid_cache *pc;
983 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
984 if (sid_compare(&pc->sid, psid) == 0) {
986 DEBUG(3,("fetch uid from cache %u -> %s\n",
987 (unsigned int)*puid, sid_string_static(psid)));
988 DLIST_PROMOTE(uid_sid_cache_head, pc);
995 /*****************************************************************
996 Store uid to SID mapping in cache.
997 *****************************************************************/
999 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1001 struct uid_sid_cache *pc;
1003 /* do not store SIDs in the "Unix Group" domain */
1005 if ( sid_check_is_in_unix_users( psid ) )
1008 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1009 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1010 struct uid_sid_cache *pc_next;
1013 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1015 for(; pc; pc = pc_next) {
1017 DLIST_REMOVE(uid_sid_cache_head,pc);
1023 pc = SMB_MALLOC_P(struct uid_sid_cache);
1027 sid_copy(&pc->sid, psid);
1028 DLIST_ADD(uid_sid_cache_head, pc);
1032 /*****************************************************************
1033 Find a SID given a gid.
1034 *****************************************************************/
1036 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1038 struct gid_sid_cache *pc;
1040 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1041 if (pc->gid == gid) {
1043 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1044 (unsigned int)gid, sid_string_static(psid)));
1045 DLIST_PROMOTE(gid_sid_cache_head, pc);
1052 /*****************************************************************
1053 Find a gid given a SID.
1054 *****************************************************************/
1056 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1058 struct gid_sid_cache *pc;
1060 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1061 if (sid_compare(&pc->sid, psid) == 0) {
1063 DEBUG(3,("fetch gid from cache %u -> %s\n",
1064 (unsigned int)*pgid, sid_string_static(psid)));
1065 DLIST_PROMOTE(gid_sid_cache_head, pc);
1072 /*****************************************************************
1073 Store gid to SID mapping in cache.
1074 *****************************************************************/
1076 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1078 struct gid_sid_cache *pc;
1080 /* do not store SIDs in the "Unix Group" domain */
1082 if ( sid_check_is_in_unix_groups( psid ) )
1085 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1086 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1087 struct gid_sid_cache *pc_next;
1090 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1092 for(; pc; pc = pc_next) {
1094 DLIST_REMOVE(gid_sid_cache_head,pc);
1100 pc = SMB_MALLOC_P(struct gid_sid_cache);
1104 sid_copy(&pc->sid, psid);
1105 DLIST_ADD(gid_sid_cache_head, pc);
1107 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1108 sid_string_static(psid)));
1113 /*****************************************************************
1114 *THE LEGACY* convert uid_t to SID function.
1115 *****************************************************************/
1117 void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1124 become_root_uid_only();
1125 ret = pdb_uid_to_rid(uid, &rid);
1126 unbecome_root_uid_only();
1129 /* This is a mapped user */
1130 sid_copy(psid, get_global_sam_sid());
1131 sid_append_rid(psid, rid);
1135 /* This is an unmapped user */
1137 uid_to_unix_users_sid(uid, psid);
1140 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1141 sid_string_static(psid)));
1143 store_uid_sid_cache(psid, uid);
1147 /*****************************************************************
1148 *THE LEGACY* convert gid_t to SID function.
1149 *****************************************************************/
1151 void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1157 become_root_uid_only();
1158 ret = pdb_gid_to_sid(gid, psid);
1159 unbecome_root_uid_only();
1162 /* This is a mapped group */
1166 /* This is an unmapped group */
1168 gid_to_unix_groups_sid(gid, psid);
1171 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1172 sid_string_static(psid)));
1174 store_gid_sid_cache(psid, gid);
1178 /*****************************************************************
1179 *THE LEGACY* convert SID to uid function.
1180 *****************************************************************/
1182 BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1184 enum lsa_SidType type;
1187 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1193 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1197 become_root_uid_only();
1198 ret = pdb_sid_to_id(psid, &id, &type);
1199 unbecome_root_uid_only();
1202 if (type != SID_NAME_USER) {
1203 DEBUG(5, ("sid %s is a %s, expected a user\n",
1204 sid_string_static(psid),
1205 sid_type_lookup(type)));
1212 /* This was ours, but it was not mapped. Fail */
1215 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1219 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
1220 (unsigned int)*puid ));
1222 store_uid_sid_cache(psid, *puid);
1226 /*****************************************************************
1227 *THE LEGACY* convert SID to gid function.
1228 Group mapping is used for gids that maps to Wellknown SIDs
1229 *****************************************************************/
1231 BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1236 enum lsa_SidType type;
1238 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1244 if ((sid_check_is_in_builtin(psid) ||
1245 sid_check_is_in_wellknown_domain(psid))) {
1248 become_root_uid_only();
1249 ret = pdb_getgrsid(&map, *psid);
1250 unbecome_root_uid_only();
1256 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1260 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1263 become_root_uid_only();
1264 ret = pdb_sid_to_id(psid, &id, &type);
1265 unbecome_root_uid_only();
1268 if ((type != SID_NAME_DOM_GRP) &&
1269 (type != SID_NAME_ALIAS)) {
1270 DEBUG(5, ("LEGACY: sid %s is a %s, expected a group\n",
1271 sid_string_static(psid),
1272 sid_type_lookup(type)));
1279 /* This was ours, but it was not mapped. Fail */
1282 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1286 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
1287 (unsigned int)*pgid ));
1289 store_gid_sid_cache(psid, *pgid);
1294 /*****************************************************************
1295 *THE CANONICAL* convert uid_t to SID function.
1296 *****************************************************************/
1298 void uid_to_sid(DOM_SID *psid, uid_t uid)
1302 if (fetch_sid_from_uid_cache(psid, uid))
1305 if (!winbind_uid_to_sid(psid, uid)) {
1306 if (!winbind_ping()) {
1307 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1308 legacy_uid_to_sid(psid, uid);
1312 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1317 DEBUG(10,("uid %u -> sid %s\n",
1318 (unsigned int)uid, sid_string_static(psid)));
1320 store_uid_sid_cache(psid, uid);
1324 /*****************************************************************
1325 *THE CANONICAL* convert gid_t to SID function.
1326 *****************************************************************/
1328 void gid_to_sid(DOM_SID *psid, gid_t gid)
1332 if (fetch_sid_from_gid_cache(psid, gid))
1335 if (!winbind_gid_to_sid(psid, gid)) {
1336 if (!winbind_ping()) {
1337 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1338 legacy_gid_to_sid(psid, gid);
1342 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1347 DEBUG(10,("gid %u -> sid %s\n",
1348 (unsigned int)gid, sid_string_static(psid)));
1350 store_gid_sid_cache(psid, gid);
1354 /*****************************************************************
1355 *THE CANONICAL* convert SID to uid function.
1356 *****************************************************************/
1358 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1362 if (fetch_uid_from_cache(puid, psid))
1365 if (fetch_gid_from_cache(&gid, psid)) {
1369 if (!winbind_sid_to_uid(puid, psid)) {
1370 if (!winbind_ping()) {
1371 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1372 return legacy_sid_to_uid(psid, puid);
1375 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1376 sid_string_static(psid)));
1380 /* TODO: Here would be the place to allocate both a gid and a uid for
1381 * the SID in question */
1383 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1384 (unsigned int)*puid ));
1386 store_uid_sid_cache(psid, *puid);
1390 /*****************************************************************
1391 *THE CANONICAL* convert SID to gid function.
1392 Group mapping is used for gids that maps to Wellknown SIDs
1393 *****************************************************************/
1395 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1399 if (fetch_gid_from_cache(pgid, psid))
1402 if (fetch_uid_from_cache(&uid, psid))
1405 /* Ask winbindd if it can map this sid to a gid.
1406 * (Idmap will check it is a valid SID and of the right type) */
1408 if ( !winbind_sid_to_gid(pgid, psid) ) {
1409 if (!winbind_ping()) {
1410 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1411 return legacy_sid_to_gid(psid, pgid);
1414 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1415 sid_string_static(psid)));
1419 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1420 (unsigned int)*pgid ));
1422 store_gid_sid_cache(psid, *pgid);