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 && (secrets_fetch_trusted_domain_password(name, NULL,
183 /* Swap domain and name */
184 tmp = name; name = domain; domain = tmp;
185 type = SID_NAME_DOMAIN;
189 /* 6. Builtin aliases */
191 if (lookup_builtin_name(name, &rid)) {
192 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
193 sid_copy(&sid, &global_sid_Builtin);
194 sid_append_rid(&sid, rid);
195 type = SID_NAME_ALIAS;
199 /* 7. Local systems' SAM (DCs don't have a local SAM) */
200 /* 8. Primary SAM (On members, this is the domain) */
202 /* Both cases are done by looking at our passdb */
204 if (lookup_global_sam_name(name, flags, &rid, &type)) {
205 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
206 sid_copy(&sid, get_global_sam_sid());
207 sid_append_rid(&sid, rid);
211 /* Now our local possibilities are exhausted. */
213 if (!(flags & LOOKUP_NAME_REMOTE)) {
214 TALLOC_FREE(tmp_ctx);
218 /* If we are not a DC, we have to ask in our primary domain. Let
219 * winbind do that. */
222 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
223 domain = talloc_strdup(tmp_ctx, lp_workgroup());
227 /* 9. Trusted domains */
229 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
230 * that (yet), but give it a chance. */
232 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
235 enum lsa_SidType domain_type;
237 if (type == SID_NAME_DOMAIN) {
238 /* Swap name and type */
239 tmp = name; name = domain; domain = tmp;
243 /* Here we have to cope with a little deficiency in the
244 * winbind API: We have to ask it again for the name of the
245 * domain it figured out itself. Maybe fix that later... */
247 sid_copy(&dom_sid, &sid);
248 sid_split_rid(&dom_sid, &tmp_rid);
250 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
252 (domain_type != SID_NAME_DOMAIN)) {
253 DEBUG(2, ("winbind could not find the domain's name "
254 "it just looked up for us\n"));
255 TALLOC_FREE(tmp_ctx);
261 /* 10. Don't translate */
263 /* 11. Ok, windows would end here. Samba has two more options:
264 Unmapped users and unmapped groups */
266 if (lookup_unix_user_name(name, &sid)) {
267 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
268 type = SID_NAME_USER;
272 if (lookup_unix_group_name(name, &sid)) {
273 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
274 type = SID_NAME_DOM_GRP;
279 * Ok, all possibilities tried. Fail.
282 TALLOC_FREE(tmp_ctx);
286 if ((domain == NULL) || (name == NULL)) {
287 DEBUG(0, ("talloc failed\n"));
288 TALLOC_FREE(tmp_ctx);
293 * Hand over the results to the talloc context we've been given.
296 if ((ret_name != NULL) &&
297 !(*ret_name = talloc_strdup(mem_ctx, name))) {
298 DEBUG(0, ("talloc failed\n"));
299 TALLOC_FREE(tmp_ctx);
303 if (ret_domain != NULL) {
305 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
306 DEBUG(0, ("talloc failed\n"));
307 TALLOC_FREE(tmp_ctx);
311 *ret_domain = tmp_dom;
314 if (ret_sid != NULL) {
315 sid_copy(ret_sid, &sid);
318 if (ret_type != NULL) {
322 TALLOC_FREE(tmp_ctx);
326 /************************************************************************
327 Names from smb.conf can be unqualified. eg. valid users = foo
328 These names should never map to a remote name. Try global_sam_name()\foo,
329 and then "Unix Users"\foo (or "Unix Groups"\foo).
330 ************************************************************************/
332 BOOL lookup_name_smbconf(TALLOC_CTX *mem_ctx,
333 const char *full_name, int flags,
334 const char **ret_domain, const char **ret_name,
335 DOM_SID *ret_sid, enum lsa_SidType *ret_type)
337 char *qualified_name;
340 /* NB. No winbindd_separator here as lookup_name needs \\' */
341 if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
343 /* The name is already qualified with a domain. */
345 if (*lp_winbind_separator() != '\\') {
348 /* lookup_name() needs '\\' as a separator */
350 tmp = talloc_strdup(mem_ctx, full_name);
354 tmp[p - full_name] = '\\';
358 return lookup_name(mem_ctx, full_name, flags,
359 ret_domain, ret_name,
363 /* Try with our own SAM name. */
364 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
365 get_global_sam_name(),
367 if (!qualified_name) {
371 if (lookup_name(mem_ctx, qualified_name, flags,
372 ret_domain, ret_name,
373 ret_sid, ret_type)) {
377 /* Finally try with "Unix Users" or "Unix Group" */
378 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
379 flags & LOOKUP_NAME_GROUP ?
380 unix_groups_domain_name() :
381 unix_users_domain_name(),
383 if (!qualified_name) {
387 return lookup_name(mem_ctx, qualified_name, flags,
388 ret_domain, ret_name,
392 static BOOL wb_lookup_rids(TALLOC_CTX *mem_ctx,
393 const DOM_SID *domain_sid,
394 int num_rids, uint32 *rids,
395 const char **domain_name,
396 const char **names, enum lsa_SidType *types)
399 const char **my_names;
400 enum lsa_SidType *my_types;
403 if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
407 if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
408 domain_name, &my_names, &my_types)) {
410 for (i=0; i<num_rids; i++) {
412 types[i] = SID_NAME_UNKNOWN;
418 * winbind_lookup_rids allocates its own array. We've been given the
419 * array, so copy it over
422 for (i=0; i<num_rids; i++) {
423 if (my_names[i] == NULL) {
424 TALLOC_FREE(tmp_ctx);
427 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
428 TALLOC_FREE(tmp_ctx);
431 types[i] = my_types[i];
433 TALLOC_FREE(tmp_ctx);
437 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
438 int num_rids, uint32_t *rids,
439 const char **domain_name,
440 const char ***names, enum lsa_SidType **types)
444 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
445 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
447 if ((*names == NULL) || (*types == NULL)) {
451 if (sid_check_is_domain(domain_sid)) {
454 if (*domain_name == NULL) {
455 *domain_name = talloc_strdup(
456 mem_ctx, get_global_sam_name());
459 if (*domain_name == NULL) {
463 become_root_uid_only();
464 result = pdb_lookup_rids(domain_sid, num_rids, rids,
466 unbecome_root_uid_only();
468 return (NT_STATUS_IS_OK(result) ||
469 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
470 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
473 if (sid_check_is_builtin(domain_sid)) {
475 if (*domain_name == NULL) {
476 *domain_name = talloc_strdup(
477 mem_ctx, builtin_domain_name());
480 if (*domain_name == NULL) {
484 for (i=0; i<num_rids; i++) {
485 if (lookup_builtin_rid(*names, rids[i],
487 if ((*names)[i] == NULL) {
490 (*types)[i] = SID_NAME_ALIAS;
492 (*types)[i] = SID_NAME_UNKNOWN;
498 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
499 for (i=0; i<num_rids; i++) {
501 sid_copy(&sid, domain_sid);
502 sid_append_rid(&sid, rids[i]);
503 if (lookup_wellknown_sid(mem_ctx, &sid,
504 domain_name, &(*names)[i])) {
505 if ((*names)[i] == NULL) {
508 (*types)[i] = SID_NAME_WKN_GRP;
510 (*types)[i] = SID_NAME_UNKNOWN;
516 if (sid_check_is_unix_users(domain_sid)) {
517 if (*domain_name == NULL) {
518 *domain_name = talloc_strdup(
519 mem_ctx, unix_users_domain_name());
521 for (i=0; i<num_rids; i++) {
522 (*names)[i] = talloc_strdup(
523 (*names), uidtoname(rids[i]));
524 (*types)[i] = SID_NAME_USER;
529 if (sid_check_is_unix_groups(domain_sid)) {
530 if (*domain_name == NULL) {
531 *domain_name = talloc_strdup(
532 mem_ctx, unix_groups_domain_name());
534 for (i=0; i<num_rids; i++) {
535 (*names)[i] = talloc_strdup(
536 (*names), gidtoname(rids[i]));
537 (*types)[i] = SID_NAME_DOM_GRP;
542 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
543 domain_name, *names, *types);
547 * Is the SID a domain as such? If yes, lookup its name.
550 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
554 enum lsa_SidType type;
556 if (sid_check_is_domain(sid)) {
557 *name = talloc_strdup(mem_ctx, get_global_sam_name());
561 if (sid_check_is_builtin(sid)) {
562 *name = talloc_strdup(mem_ctx, builtin_domain_name());
566 if (sid_check_is_wellknown_domain(sid, &tmp)) {
567 *name = talloc_strdup(mem_ctx, tmp);
571 if (sid->num_auths != 4) {
572 /* This can't be a domain */
577 uint32 i, num_domains;
578 struct trustdom_info **domains;
580 /* This is relatively expensive, but it happens only on DCs
581 * and for SIDs that have 4 sub-authorities and thus look like
584 if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx,
590 for (i=0; i<num_domains; i++) {
591 if (sid_equal(sid, &domains[i]->sid)) {
592 *name = talloc_strdup(mem_ctx,
600 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
601 (type == SID_NAME_DOMAIN)) {
610 * This tries to implement the rather weird rules for the lsa_lookup level
613 * This is as close as we can get to what W2k3 does. With this we survive the
614 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
615 * different, but I assume that's just being too liberal. For example, W2k3
616 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
617 * whereas NT4 does the same as level 1 (I think). I did not fully test that
618 * with NT4, this is what w2k3 does.
620 * Level 1: Ask everywhere
621 * Level 2: Ask domain and trusted domains, no builtin and wkn
622 * Level 3: Only ask domain
623 * Level 4: W2k3ad: Only ask AD trusts
624 * Level 5: Don't lookup anything
628 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
637 ret = (!sid_check_is_builtin(sid) &&
638 !sid_check_is_wellknown_domain(sid, NULL));
643 ret = sid_check_is_domain(sid);
650 DEBUG(10, ("%s SID %s in level %d\n",
651 ret ? "Accepting" : "Rejecting",
652 sid_string_static(sid), level));
657 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
658 * references to domains, it is explicitly made for this.
660 * This attempts to be as efficient as possible: It collects all SIDs
661 * belonging to a domain and hands them in bulk to the appropriate lookup
662 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
663 * *hugely* from this. Winbind is going to be extended with a lookup_rids
664 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
668 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
669 const DOM_SID **sids, int level,
670 struct lsa_dom_info **ret_domains,
671 struct lsa_name_info **ret_names)
674 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
675 struct lsa_name_info *name_infos;
676 struct lsa_dom_info *dom_infos;
680 if (!(tmp_ctx = talloc_new(mem_ctx))) {
681 DEBUG(0, ("talloc_new failed\n"));
682 return NT_STATUS_NO_MEMORY;
685 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
686 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
688 if ((name_infos == NULL) || (dom_infos == NULL)) {
689 result = NT_STATUS_NO_MEMORY;
693 /* First build up the data structures:
695 * dom_infos is a list of domains referenced in the list of
696 * SIDs. Later we will walk the list of domains and look up the RIDs
699 * name_infos is a shadow-copy of the SIDs array to collect the real
702 * dom_info->idxs is an index into the name_infos array. The
703 * difficulty we have here is that we need to keep the SIDs the client
704 * asked for in the same order for the reply
707 for (i=0; i<num_sids; i++) {
710 const char *domain_name = NULL;
712 sid_copy(&sid, sids[i]);
713 name_infos[i].type = SID_NAME_USE_NONE;
715 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
716 /* We can't push that through the normal lookup
717 * process, as this would reference illegal
720 * For example S-1-5-32 would end up referencing
721 * domain S-1-5- with RID 32 which is clearly wrong.
723 if (domain_name == NULL) {
724 result = NT_STATUS_NO_MEMORY;
728 name_infos[i].rid = 0;
729 name_infos[i].type = SID_NAME_DOMAIN;
730 name_infos[i].name = NULL;
732 if (sid_check_is_builtin(&sid)) {
733 /* Yes, W2k3 returns "BUILTIN" both as domain
735 name_infos[i].name = talloc_strdup(
736 name_infos, builtin_domain_name());
737 if (name_infos[i].name == NULL) {
738 result = NT_STATUS_NO_MEMORY;
743 /* This is a normal SID with rid component */
744 if (!sid_split_rid(&sid, &rid)) {
745 result = NT_STATUS_INVALID_PARAMETER;
750 if (!check_dom_sid_to_level(&sid, level)) {
751 name_infos[i].rid = 0;
752 name_infos[i].type = SID_NAME_UNKNOWN;
753 name_infos[i].name = NULL;
757 for (j=0; j<MAX_REF_DOMAINS; j++) {
758 if (!dom_infos[j].valid) {
761 if (sid_equal(&sid, &dom_infos[j].sid)) {
766 if (j == MAX_REF_DOMAINS) {
767 /* TODO: What's the right error message here? */
768 result = NT_STATUS_NONE_MAPPED;
772 if (!dom_infos[j].valid) {
773 /* We found a domain not yet referenced, create a new
775 dom_infos[j].valid = True;
776 sid_copy(&dom_infos[j].sid, &sid);
778 if (domain_name != NULL) {
779 /* This name was being found above in the case
780 * when we found a domain SID */
782 talloc_strdup(dom_infos, domain_name);
783 if (dom_infos[j].name == NULL) {
784 result = NT_STATUS_NO_MEMORY;
788 /* lookup_rids will take care of this */
789 dom_infos[j].name = NULL;
793 name_infos[i].dom_idx = j;
795 if (name_infos[i].type == SID_NAME_USE_NONE) {
796 name_infos[i].rid = rid;
798 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
799 &dom_infos[j].num_idxs);
801 if (dom_infos[j].idxs == NULL) {
802 result = NT_STATUS_NO_MEMORY;
808 /* Iterate over the domains found */
810 for (i=0; i<MAX_REF_DOMAINS; i++) {
812 const char *domain_name = NULL;
814 enum lsa_SidType *types;
815 struct lsa_dom_info *dom = &dom_infos[i];
818 /* No domains left, we're done */
822 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
823 result = NT_STATUS_NO_MEMORY;
827 for (j=0; j<dom->num_idxs; j++) {
828 rids[j] = name_infos[dom->idxs[j]].rid;
831 if (!lookup_rids(tmp_ctx, &dom->sid,
832 dom->num_idxs, rids, &domain_name,
834 result = NT_STATUS_NO_MEMORY;
838 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
839 result = NT_STATUS_NO_MEMORY;
843 for (j=0; j<dom->num_idxs; j++) {
844 int idx = dom->idxs[j];
845 name_infos[idx].type = types[j];
846 if (types[j] != SID_NAME_UNKNOWN) {
847 name_infos[idx].name =
848 talloc_strdup(name_infos, names[j]);
849 if (name_infos[idx].name == NULL) {
850 result = NT_STATUS_NO_MEMORY;
854 name_infos[idx].name = NULL;
859 *ret_domains = dom_infos;
860 *ret_names = name_infos;
864 TALLOC_FREE(dom_infos);
865 TALLOC_FREE(name_infos);
866 TALLOC_FREE(tmp_ctx);
870 /*****************************************************************
871 *THE CANONICAL* convert SID to name function.
872 *****************************************************************/
874 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
875 const char **ret_domain, const char **ret_name,
876 enum lsa_SidType *ret_type)
878 struct lsa_dom_info *domain;
879 struct lsa_name_info *name;
883 if (!(tmp_ctx = talloc_new(mem_ctx))) {
884 DEBUG(0, ("talloc_new failed\n"));
888 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
893 if (name->type == SID_NAME_UNKNOWN) {
897 if ((ret_domain != NULL) &&
898 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
902 if ((ret_name != NULL) &&
903 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
907 if (ret_type != NULL) {
908 *ret_type = name->type;
915 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
916 sid_string_static(sid), domain->name,
917 name->name, name->type));
919 DEBUG(10, ("failed to lookup sid %s\n",
920 sid_string_static(sid)));
922 TALLOC_FREE(tmp_ctx);
926 /*****************************************************************
927 Id mapping cache. This is to avoid Winbind mappings already
928 seen by smbd to be queried too frequently, keeping winbindd
929 busy, and blocking smbd while winbindd is busy with other
930 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
931 modified to use linked lists by jra.
932 *****************************************************************/
934 #define MAX_UID_SID_CACHE_SIZE 100
935 #define TURNOVER_UID_SID_CACHE_SIZE 10
936 #define MAX_GID_SID_CACHE_SIZE 100
937 #define TURNOVER_GID_SID_CACHE_SIZE 10
939 static size_t n_uid_sid_cache = 0;
940 static size_t n_gid_sid_cache = 0;
942 static struct uid_sid_cache {
943 struct uid_sid_cache *next, *prev;
946 enum lsa_SidType sidtype;
947 } *uid_sid_cache_head;
949 static struct gid_sid_cache {
950 struct gid_sid_cache *next, *prev;
953 enum lsa_SidType sidtype;
954 } *gid_sid_cache_head;
956 /*****************************************************************
957 Find a SID given a uid.
958 *****************************************************************/
960 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
962 struct uid_sid_cache *pc;
964 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
965 if (pc->uid == uid) {
967 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
968 (unsigned int)uid, sid_string_static(psid)));
969 DLIST_PROMOTE(uid_sid_cache_head, pc);
976 /*****************************************************************
977 Find a uid given a SID.
978 *****************************************************************/
980 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
982 struct uid_sid_cache *pc;
984 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
985 if (sid_compare(&pc->sid, psid) == 0) {
987 DEBUG(3,("fetch uid from cache %u -> %s\n",
988 (unsigned int)*puid, sid_string_static(psid)));
989 DLIST_PROMOTE(uid_sid_cache_head, pc);
996 /*****************************************************************
997 Store uid to SID mapping in cache.
998 *****************************************************************/
1000 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1002 struct uid_sid_cache *pc;
1004 /* do not store SIDs in the "Unix Group" domain */
1006 if ( sid_check_is_in_unix_users( psid ) )
1009 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1010 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1011 struct uid_sid_cache *pc_next;
1014 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1016 for(; pc; pc = pc_next) {
1018 DLIST_REMOVE(uid_sid_cache_head,pc);
1024 pc = SMB_MALLOC_P(struct uid_sid_cache);
1028 sid_copy(&pc->sid, psid);
1029 DLIST_ADD(uid_sid_cache_head, pc);
1033 /*****************************************************************
1034 Find a SID given a gid.
1035 *****************************************************************/
1037 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1039 struct gid_sid_cache *pc;
1041 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1042 if (pc->gid == gid) {
1044 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1045 (unsigned int)gid, sid_string_static(psid)));
1046 DLIST_PROMOTE(gid_sid_cache_head, pc);
1053 /*****************************************************************
1054 Find a gid given a SID.
1055 *****************************************************************/
1057 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1059 struct gid_sid_cache *pc;
1061 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1062 if (sid_compare(&pc->sid, psid) == 0) {
1064 DEBUG(3,("fetch gid from cache %u -> %s\n",
1065 (unsigned int)*pgid, sid_string_static(psid)));
1066 DLIST_PROMOTE(gid_sid_cache_head, pc);
1073 /*****************************************************************
1074 Store gid to SID mapping in cache.
1075 *****************************************************************/
1077 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1079 struct gid_sid_cache *pc;
1081 /* do not store SIDs in the "Unix Group" domain */
1083 if ( sid_check_is_in_unix_groups( psid ) )
1086 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1087 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1088 struct gid_sid_cache *pc_next;
1091 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1093 for(; pc; pc = pc_next) {
1095 DLIST_REMOVE(gid_sid_cache_head,pc);
1101 pc = SMB_MALLOC_P(struct gid_sid_cache);
1105 sid_copy(&pc->sid, psid);
1106 DLIST_ADD(gid_sid_cache_head, pc);
1108 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1109 sid_string_static(psid)));
1114 /*****************************************************************
1115 *THE LEGACY* convert uid_t to SID function.
1116 *****************************************************************/
1118 void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1125 become_root_uid_only();
1126 ret = pdb_uid_to_rid(uid, &rid);
1127 unbecome_root_uid_only();
1130 /* This is a mapped user */
1131 sid_copy(psid, get_global_sam_sid());
1132 sid_append_rid(psid, rid);
1136 /* This is an unmapped user */
1138 uid_to_unix_users_sid(uid, psid);
1141 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1142 sid_string_static(psid)));
1144 store_uid_sid_cache(psid, uid);
1148 /*****************************************************************
1149 *THE LEGACY* convert gid_t to SID function.
1150 *****************************************************************/
1152 void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1158 become_root_uid_only();
1159 ret = pdb_gid_to_sid(gid, psid);
1160 unbecome_root_uid_only();
1163 /* This is a mapped group */
1167 /* This is an unmapped group */
1169 gid_to_unix_groups_sid(gid, psid);
1172 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1173 sid_string_static(psid)));
1175 store_gid_sid_cache(psid, gid);
1179 /*****************************************************************
1180 *THE LEGACY* convert SID to uid function.
1181 *****************************************************************/
1183 BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1185 enum lsa_SidType type;
1188 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1194 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1198 become_root_uid_only();
1199 ret = pdb_sid_to_id(psid, &id, &type);
1200 unbecome_root_uid_only();
1203 if (type != SID_NAME_USER) {
1204 DEBUG(5, ("sid %s is a %s, expected a user\n",
1205 sid_string_static(psid),
1206 sid_type_lookup(type)));
1213 /* This was ours, but it was not mapped. Fail */
1216 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1220 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
1221 (unsigned int)*puid ));
1223 store_uid_sid_cache(psid, *puid);
1227 /*****************************************************************
1228 *THE LEGACY* convert SID to gid function.
1229 Group mapping is used for gids that maps to Wellknown SIDs
1230 *****************************************************************/
1232 BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1237 enum lsa_SidType type;
1239 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1245 if ((sid_check_is_in_builtin(psid) ||
1246 sid_check_is_in_wellknown_domain(psid))) {
1249 become_root_uid_only();
1250 ret = pdb_getgrsid(&map, *psid);
1251 unbecome_root_uid_only();
1257 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1261 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1264 become_root_uid_only();
1265 ret = pdb_sid_to_id(psid, &id, &type);
1266 unbecome_root_uid_only();
1269 if ((type != SID_NAME_DOM_GRP) &&
1270 (type != SID_NAME_ALIAS)) {
1271 DEBUG(5, ("LEGACY: sid %s is a %s, expected a group\n",
1272 sid_string_static(psid),
1273 sid_type_lookup(type)));
1280 /* This was ours, but it was not mapped. Fail */
1283 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1287 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
1288 (unsigned int)*pgid ));
1290 store_gid_sid_cache(psid, *pgid);
1295 /*****************************************************************
1296 *THE CANONICAL* convert uid_t to SID function.
1297 *****************************************************************/
1299 void uid_to_sid(DOM_SID *psid, uid_t uid)
1303 if (fetch_sid_from_uid_cache(psid, uid))
1306 if (!winbind_uid_to_sid(psid, uid)) {
1307 if (!winbind_ping()) {
1308 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1309 return 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 return legacy_gid_to_sid(psid, gid);
1341 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1346 DEBUG(10,("gid %u -> sid %s\n",
1347 (unsigned int)gid, sid_string_static(psid)));
1349 store_gid_sid_cache(psid, gid);
1353 /*****************************************************************
1354 *THE CANONICAL* convert SID to uid function.
1355 *****************************************************************/
1357 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1361 if (fetch_uid_from_cache(puid, psid))
1364 if (fetch_gid_from_cache(&gid, psid)) {
1368 if (!winbind_sid_to_uid(puid, psid)) {
1369 if (!winbind_ping()) {
1370 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1371 return legacy_sid_to_uid(psid, puid);
1374 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1375 sid_string_static(psid)));
1379 /* TODO: Here would be the place to allocate both a gid and a uid for
1380 * the SID in question */
1382 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1383 (unsigned int)*puid ));
1385 store_uid_sid_cache(psid, *puid);
1389 /*****************************************************************
1390 *THE CANONICAL* convert SID to gid function.
1391 Group mapping is used for gids that maps to Wellknown SIDs
1392 *****************************************************************/
1394 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1398 if (fetch_gid_from_cache(pgid, psid))
1401 if (fetch_uid_from_cache(&uid, psid))
1404 /* Ask winbindd if it can map this sid to a gid.
1405 * (Idmap will check it is a valid SID and of the right type) */
1407 if ( !winbind_sid_to_gid(pgid, psid) ) {
1408 if (!winbind_ping()) {
1409 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1410 return legacy_sid_to_gid(psid, pgid);
1413 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1414 sid_string_static(psid)));
1418 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1419 (unsigned int)*pgid ));
1421 store_gid_sid_cache(psid, *pgid);