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)));
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)));
1177 /*****************************************************************
1178 *THE LEGACY* convert SID to uid function.
1179 *****************************************************************/
1181 BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1183 enum lsa_SidType type;
1186 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1192 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1196 become_root_uid_only();
1197 ret = pdb_sid_to_id(psid, &id, &type);
1198 unbecome_root_uid_only();
1201 if (type != SID_NAME_USER) {
1202 DEBUG(5, ("sid %s is a %s, expected a user\n",
1203 sid_string_static(psid),
1204 sid_type_lookup(type)));
1211 /* This was ours, but it was not mapped. Fail */
1219 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
1220 (unsigned int)*puid ));
1225 /*****************************************************************
1226 *THE LEGACY* convert SID to gid function.
1227 Group mapping is used for gids that maps to Wellknown SIDs
1228 *****************************************************************/
1230 BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1235 enum lsa_SidType type;
1237 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1243 if ((sid_check_is_in_builtin(psid) ||
1244 sid_check_is_in_wellknown_domain(psid))) {
1247 become_root_uid_only();
1248 ret = pdb_getgrsid(&map, *psid);
1249 unbecome_root_uid_only();
1258 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1261 become_root_uid_only();
1262 ret = pdb_sid_to_id(psid, &id, &type);
1263 unbecome_root_uid_only();
1266 if ((type != SID_NAME_DOM_GRP) &&
1267 (type != SID_NAME_ALIAS)) {
1268 DEBUG(5, ("sid %s is a %s, expected a group\n",
1269 sid_string_static(psid),
1270 sid_type_lookup(type)));
1277 /* This was ours, but it was not mapped. Fail */
1283 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
1284 (unsigned int)*pgid ));
1289 /*****************************************************************
1290 *THE CANONICAL* convert uid_t to SID function.
1291 *****************************************************************/
1293 void uid_to_sid(DOM_SID *psid, uid_t uid)
1297 if (fetch_sid_from_uid_cache(psid, uid))
1300 if (!winbind_uid_to_sid(psid, uid)) {
1301 if (!winbind_ping()) {
1302 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code"));
1303 return legacy_uid_to_sid(psid, uid);
1306 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1311 DEBUG(10,("uid %u -> sid %s\n",
1312 (unsigned int)uid, sid_string_static(psid)));
1314 store_uid_sid_cache(psid, uid);
1318 /*****************************************************************
1319 *THE CANONICAL* convert gid_t to SID function.
1320 *****************************************************************/
1322 void gid_to_sid(DOM_SID *psid, gid_t gid)
1326 if (fetch_sid_from_gid_cache(psid, gid))
1329 if (!winbind_gid_to_sid(psid, gid)) {
1330 if (!winbind_ping()) {
1331 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code"));
1332 return legacy_gid_to_sid(psid, gid);
1335 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1340 DEBUG(10,("gid %u -> sid %s\n",
1341 (unsigned int)gid, sid_string_static(psid)));
1343 store_gid_sid_cache(psid, gid);
1347 /*****************************************************************
1348 *THE CANONICAL* convert SID to uid function.
1349 *****************************************************************/
1351 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1355 if (fetch_uid_from_cache(puid, psid))
1358 if (fetch_gid_from_cache(&gid, psid)) {
1362 if (!winbind_sid_to_uid(puid, psid)) {
1363 if (!winbind_ping()) {
1364 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code"));
1365 return legacy_sid_to_uid(psid, puid);
1368 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1369 sid_string_static(psid)));
1373 /* TODO: Here would be the place to allocate both a gid and a uid for
1374 * the SID in question */
1376 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1377 (unsigned int)*puid ));
1379 store_uid_sid_cache(psid, *puid);
1383 /*****************************************************************
1384 *THE CANONICAL* convert SID to gid function.
1385 Group mapping is used for gids that maps to Wellknown SIDs
1386 *****************************************************************/
1388 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1392 if (fetch_gid_from_cache(pgid, psid))
1395 if (fetch_uid_from_cache(&uid, psid))
1398 /* Ask winbindd if it can map this sid to a gid.
1399 * (Idmap will check it is a valid SID and of the right type) */
1401 if ( !winbind_sid_to_gid(pgid, psid) ) {
1402 if (!winbind_ping()) {
1403 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code"));
1404 return legacy_sid_to_uid(psid, pgid);
1407 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1408 sid_string_static(psid)));
1412 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1413 (unsigned int)*pgid ));
1415 store_gid_sid_cache(psid, *pgid);