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;
413 TALLOC_FREE(tmp_ctx);
417 if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
418 TALLOC_FREE(tmp_ctx);
423 * winbind_lookup_rids allocates its own array. We've been given the
424 * array, so copy it over
427 for (i=0; i<num_rids; i++) {
428 if (my_names[i] == NULL) {
429 TALLOC_FREE(tmp_ctx);
432 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
433 TALLOC_FREE(tmp_ctx);
436 types[i] = my_types[i];
438 TALLOC_FREE(tmp_ctx);
442 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
443 int num_rids, uint32_t *rids,
444 const char **domain_name,
445 const char ***names, enum lsa_SidType **types)
449 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
450 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
452 if ((*names == NULL) || (*types == NULL)) {
456 if (sid_check_is_domain(domain_sid)) {
459 if (*domain_name == NULL) {
460 *domain_name = talloc_strdup(
461 mem_ctx, get_global_sam_name());
464 if (*domain_name == NULL) {
468 become_root_uid_only();
469 result = pdb_lookup_rids(domain_sid, num_rids, rids,
471 unbecome_root_uid_only();
473 return (NT_STATUS_IS_OK(result) ||
474 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
475 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
478 if (sid_check_is_builtin(domain_sid)) {
480 if (*domain_name == NULL) {
481 *domain_name = talloc_strdup(
482 mem_ctx, builtin_domain_name());
485 if (*domain_name == NULL) {
489 for (i=0; i<num_rids; i++) {
490 if (lookup_builtin_rid(*names, rids[i],
492 if ((*names)[i] == NULL) {
495 (*types)[i] = SID_NAME_ALIAS;
497 (*types)[i] = SID_NAME_UNKNOWN;
503 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
504 for (i=0; i<num_rids; i++) {
506 sid_copy(&sid, domain_sid);
507 sid_append_rid(&sid, rids[i]);
508 if (lookup_wellknown_sid(mem_ctx, &sid,
509 domain_name, &(*names)[i])) {
510 if ((*names)[i] == NULL) {
513 (*types)[i] = SID_NAME_WKN_GRP;
515 (*types)[i] = SID_NAME_UNKNOWN;
521 if (sid_check_is_unix_users(domain_sid)) {
522 if (*domain_name == NULL) {
523 *domain_name = talloc_strdup(
524 mem_ctx, unix_users_domain_name());
526 for (i=0; i<num_rids; i++) {
527 (*names)[i] = talloc_strdup(
528 (*names), uidtoname(rids[i]));
529 (*types)[i] = SID_NAME_USER;
534 if (sid_check_is_unix_groups(domain_sid)) {
535 if (*domain_name == NULL) {
536 *domain_name = talloc_strdup(
537 mem_ctx, unix_groups_domain_name());
539 for (i=0; i<num_rids; i++) {
540 (*names)[i] = talloc_strdup(
541 (*names), gidtoname(rids[i]));
542 (*types)[i] = SID_NAME_DOM_GRP;
547 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
548 domain_name, *names, *types);
552 * Is the SID a domain as such? If yes, lookup its name.
555 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
559 enum lsa_SidType type;
561 if (sid_check_is_domain(sid)) {
562 *name = talloc_strdup(mem_ctx, get_global_sam_name());
566 if (sid_check_is_builtin(sid)) {
567 *name = talloc_strdup(mem_ctx, builtin_domain_name());
571 if (sid_check_is_wellknown_domain(sid, &tmp)) {
572 *name = talloc_strdup(mem_ctx, tmp);
576 if (sid->num_auths != 4) {
577 /* This can't be a domain */
582 uint32 i, num_domains;
583 struct trustdom_info **domains;
585 /* This is relatively expensive, but it happens only on DCs
586 * and for SIDs that have 4 sub-authorities and thus look like
589 if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
595 for (i=0; i<num_domains; i++) {
596 if (sid_equal(sid, &domains[i]->sid)) {
597 *name = talloc_strdup(mem_ctx,
605 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
606 (type == SID_NAME_DOMAIN)) {
615 * This tries to implement the rather weird rules for the lsa_lookup level
618 * This is as close as we can get to what W2k3 does. With this we survive the
619 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
620 * different, but I assume that's just being too liberal. For example, W2k3
621 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
622 * whereas NT4 does the same as level 1 (I think). I did not fully test that
623 * with NT4, this is what w2k3 does.
625 * Level 1: Ask everywhere
626 * Level 2: Ask domain and trusted domains, no builtin and wkn
627 * Level 3: Only ask domain
628 * Level 4: W2k3ad: Only ask AD trusts
629 * Level 5: Don't lookup anything
633 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
642 ret = (!sid_check_is_builtin(sid) &&
643 !sid_check_is_wellknown_domain(sid, NULL));
648 ret = sid_check_is_domain(sid);
655 DEBUG(10, ("%s SID %s in level %d\n",
656 ret ? "Accepting" : "Rejecting",
657 sid_string_static(sid), level));
662 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
663 * references to domains, it is explicitly made for this.
665 * This attempts to be as efficient as possible: It collects all SIDs
666 * belonging to a domain and hands them in bulk to the appropriate lookup
667 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
668 * *hugely* from this. Winbind is going to be extended with a lookup_rids
669 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
673 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
674 const DOM_SID **sids, int level,
675 struct lsa_dom_info **ret_domains,
676 struct lsa_name_info **ret_names)
679 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
680 struct lsa_name_info *name_infos;
681 struct lsa_dom_info *dom_infos;
685 if (!(tmp_ctx = talloc_new(mem_ctx))) {
686 DEBUG(0, ("talloc_new failed\n"));
687 return NT_STATUS_NO_MEMORY;
690 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
691 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
693 if ((name_infos == NULL) || (dom_infos == NULL)) {
694 result = NT_STATUS_NO_MEMORY;
698 /* First build up the data structures:
700 * dom_infos is a list of domains referenced in the list of
701 * SIDs. Later we will walk the list of domains and look up the RIDs
704 * name_infos is a shadow-copy of the SIDs array to collect the real
707 * dom_info->idxs is an index into the name_infos array. The
708 * difficulty we have here is that we need to keep the SIDs the client
709 * asked for in the same order for the reply
712 for (i=0; i<num_sids; i++) {
715 const char *domain_name = NULL;
717 sid_copy(&sid, sids[i]);
718 name_infos[i].type = SID_NAME_USE_NONE;
720 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
721 /* We can't push that through the normal lookup
722 * process, as this would reference illegal
725 * For example S-1-5-32 would end up referencing
726 * domain S-1-5- with RID 32 which is clearly wrong.
728 if (domain_name == NULL) {
729 result = NT_STATUS_NO_MEMORY;
733 name_infos[i].rid = 0;
734 name_infos[i].type = SID_NAME_DOMAIN;
735 name_infos[i].name = NULL;
737 if (sid_check_is_builtin(&sid)) {
738 /* Yes, W2k3 returns "BUILTIN" both as domain
740 name_infos[i].name = talloc_strdup(
741 name_infos, builtin_domain_name());
742 if (name_infos[i].name == NULL) {
743 result = NT_STATUS_NO_MEMORY;
748 /* This is a normal SID with rid component */
749 if (!sid_split_rid(&sid, &rid)) {
750 result = NT_STATUS_INVALID_PARAMETER;
755 if (!check_dom_sid_to_level(&sid, level)) {
756 name_infos[i].rid = 0;
757 name_infos[i].type = SID_NAME_UNKNOWN;
758 name_infos[i].name = NULL;
762 for (j=0; j<MAX_REF_DOMAINS; j++) {
763 if (!dom_infos[j].valid) {
766 if (sid_equal(&sid, &dom_infos[j].sid)) {
771 if (j == MAX_REF_DOMAINS) {
772 /* TODO: What's the right error message here? */
773 result = NT_STATUS_NONE_MAPPED;
777 if (!dom_infos[j].valid) {
778 /* We found a domain not yet referenced, create a new
780 dom_infos[j].valid = True;
781 sid_copy(&dom_infos[j].sid, &sid);
783 if (domain_name != NULL) {
784 /* This name was being found above in the case
785 * when we found a domain SID */
787 talloc_strdup(dom_infos, domain_name);
788 if (dom_infos[j].name == NULL) {
789 result = NT_STATUS_NO_MEMORY;
793 /* lookup_rids will take care of this */
794 dom_infos[j].name = NULL;
798 name_infos[i].dom_idx = j;
800 if (name_infos[i].type == SID_NAME_USE_NONE) {
801 name_infos[i].rid = rid;
803 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
804 &dom_infos[j].num_idxs);
806 if (dom_infos[j].idxs == NULL) {
807 result = NT_STATUS_NO_MEMORY;
813 /* Iterate over the domains found */
815 for (i=0; i<MAX_REF_DOMAINS; i++) {
817 const char *domain_name = NULL;
819 enum lsa_SidType *types;
820 struct lsa_dom_info *dom = &dom_infos[i];
823 /* No domains left, we're done */
827 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
828 result = NT_STATUS_NO_MEMORY;
832 for (j=0; j<dom->num_idxs; j++) {
833 rids[j] = name_infos[dom->idxs[j]].rid;
836 if (!lookup_rids(tmp_ctx, &dom->sid,
837 dom->num_idxs, rids, &domain_name,
839 result = NT_STATUS_NO_MEMORY;
843 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
844 result = NT_STATUS_NO_MEMORY;
848 for (j=0; j<dom->num_idxs; j++) {
849 int idx = dom->idxs[j];
850 name_infos[idx].type = types[j];
851 if (types[j] != SID_NAME_UNKNOWN) {
852 name_infos[idx].name =
853 talloc_strdup(name_infos, names[j]);
854 if (name_infos[idx].name == NULL) {
855 result = NT_STATUS_NO_MEMORY;
859 name_infos[idx].name = NULL;
864 *ret_domains = dom_infos;
865 *ret_names = name_infos;
869 TALLOC_FREE(dom_infos);
870 TALLOC_FREE(name_infos);
871 TALLOC_FREE(tmp_ctx);
875 /*****************************************************************
876 *THE CANONICAL* convert SID to name function.
877 *****************************************************************/
879 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
880 const char **ret_domain, const char **ret_name,
881 enum lsa_SidType *ret_type)
883 struct lsa_dom_info *domain;
884 struct lsa_name_info *name;
888 if (!(tmp_ctx = talloc_new(mem_ctx))) {
889 DEBUG(0, ("talloc_new failed\n"));
893 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
898 if (name->type == SID_NAME_UNKNOWN) {
902 if ((ret_domain != NULL) &&
903 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
907 if ((ret_name != NULL) &&
908 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
912 if (ret_type != NULL) {
913 *ret_type = name->type;
920 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
921 sid_string_static(sid), domain->name,
922 name->name, name->type));
924 DEBUG(10, ("failed to lookup sid %s\n",
925 sid_string_static(sid)));
927 TALLOC_FREE(tmp_ctx);
931 /*****************************************************************
932 Id mapping cache. This is to avoid Winbind mappings already
933 seen by smbd to be queried too frequently, keeping winbindd
934 busy, and blocking smbd while winbindd is busy with other
935 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
936 modified to use linked lists by jra.
937 *****************************************************************/
939 #define MAX_UID_SID_CACHE_SIZE 100
940 #define TURNOVER_UID_SID_CACHE_SIZE 10
941 #define MAX_GID_SID_CACHE_SIZE 100
942 #define TURNOVER_GID_SID_CACHE_SIZE 10
944 static size_t n_uid_sid_cache = 0;
945 static size_t n_gid_sid_cache = 0;
947 static struct uid_sid_cache {
948 struct uid_sid_cache *next, *prev;
951 enum lsa_SidType sidtype;
952 } *uid_sid_cache_head;
954 static struct gid_sid_cache {
955 struct gid_sid_cache *next, *prev;
958 enum lsa_SidType sidtype;
959 } *gid_sid_cache_head;
961 /*****************************************************************
962 Find a SID given a uid.
963 *****************************************************************/
965 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
967 struct uid_sid_cache *pc;
969 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
970 if (pc->uid == uid) {
972 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
973 (unsigned int)uid, sid_string_static(psid)));
974 DLIST_PROMOTE(uid_sid_cache_head, pc);
981 /*****************************************************************
982 Find a uid given a SID.
983 *****************************************************************/
985 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
987 struct uid_sid_cache *pc;
989 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
990 if (sid_compare(&pc->sid, psid) == 0) {
992 DEBUG(3,("fetch uid from cache %u -> %s\n",
993 (unsigned int)*puid, sid_string_static(psid)));
994 DLIST_PROMOTE(uid_sid_cache_head, pc);
1001 /*****************************************************************
1002 Store uid to SID mapping in cache.
1003 *****************************************************************/
1005 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1007 struct uid_sid_cache *pc;
1009 /* do not store SIDs in the "Unix Group" domain */
1011 if ( sid_check_is_in_unix_users( psid ) )
1014 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1015 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1016 struct uid_sid_cache *pc_next;
1019 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1021 for(; pc; pc = pc_next) {
1023 DLIST_REMOVE(uid_sid_cache_head,pc);
1029 pc = SMB_MALLOC_P(struct uid_sid_cache);
1033 sid_copy(&pc->sid, psid);
1034 DLIST_ADD(uid_sid_cache_head, pc);
1038 /*****************************************************************
1039 Find a SID given a gid.
1040 *****************************************************************/
1042 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1044 struct gid_sid_cache *pc;
1046 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1047 if (pc->gid == gid) {
1049 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1050 (unsigned int)gid, sid_string_static(psid)));
1051 DLIST_PROMOTE(gid_sid_cache_head, pc);
1058 /*****************************************************************
1059 Find a gid given a SID.
1060 *****************************************************************/
1062 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1064 struct gid_sid_cache *pc;
1066 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1067 if (sid_compare(&pc->sid, psid) == 0) {
1069 DEBUG(3,("fetch gid from cache %u -> %s\n",
1070 (unsigned int)*pgid, sid_string_static(psid)));
1071 DLIST_PROMOTE(gid_sid_cache_head, pc);
1078 /*****************************************************************
1079 Store gid to SID mapping in cache.
1080 *****************************************************************/
1082 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1084 struct gid_sid_cache *pc;
1086 /* do not store SIDs in the "Unix Group" domain */
1088 if ( sid_check_is_in_unix_groups( psid ) )
1091 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1092 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1093 struct gid_sid_cache *pc_next;
1096 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1098 for(; pc; pc = pc_next) {
1100 DLIST_REMOVE(gid_sid_cache_head,pc);
1106 pc = SMB_MALLOC_P(struct gid_sid_cache);
1110 sid_copy(&pc->sid, psid);
1111 DLIST_ADD(gid_sid_cache_head, pc);
1113 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1114 sid_string_static(psid)));
1119 /*****************************************************************
1120 *THE LEGACY* convert uid_t to SID function.
1121 *****************************************************************/
1123 void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1130 become_root_uid_only();
1131 ret = pdb_uid_to_rid(uid, &rid);
1132 unbecome_root_uid_only();
1135 /* This is a mapped user */
1136 sid_copy(psid, get_global_sam_sid());
1137 sid_append_rid(psid, rid);
1141 /* This is an unmapped user */
1143 uid_to_unix_users_sid(uid, psid);
1146 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1147 sid_string_static(psid)));
1149 store_uid_sid_cache(psid, uid);
1153 /*****************************************************************
1154 *THE LEGACY* convert gid_t to SID function.
1155 *****************************************************************/
1157 void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1163 become_root_uid_only();
1164 ret = pdb_gid_to_sid(gid, psid);
1165 unbecome_root_uid_only();
1168 /* This is a mapped group */
1172 /* This is an unmapped group */
1174 gid_to_unix_groups_sid(gid, psid);
1177 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1178 sid_string_static(psid)));
1180 store_gid_sid_cache(psid, gid);
1184 /*****************************************************************
1185 *THE LEGACY* convert SID to uid function.
1186 *****************************************************************/
1188 BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1190 enum lsa_SidType type;
1193 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1199 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1203 become_root_uid_only();
1204 ret = pdb_sid_to_id(psid, &id, &type);
1205 unbecome_root_uid_only();
1208 if (type != SID_NAME_USER) {
1209 DEBUG(5, ("sid %s is a %s, expected a user\n",
1210 sid_string_static(psid),
1211 sid_type_lookup(type)));
1218 /* This was ours, but it was not mapped. Fail */
1221 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1225 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
1226 (unsigned int)*puid ));
1228 store_uid_sid_cache(psid, *puid);
1232 /*****************************************************************
1233 *THE LEGACY* convert SID to gid function.
1234 Group mapping is used for gids that maps to Wellknown SIDs
1235 *****************************************************************/
1237 BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1242 enum lsa_SidType type;
1244 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1250 if ((sid_check_is_in_builtin(psid) ||
1251 sid_check_is_in_wellknown_domain(psid))) {
1254 become_root_uid_only();
1255 ret = pdb_getgrsid(&map, *psid);
1256 unbecome_root_uid_only();
1262 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1266 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1269 become_root_uid_only();
1270 ret = pdb_sid_to_id(psid, &id, &type);
1271 unbecome_root_uid_only();
1274 if ((type != SID_NAME_DOM_GRP) &&
1275 (type != SID_NAME_ALIAS)) {
1276 DEBUG(5, ("LEGACY: sid %s is a %s, expected a group\n",
1277 sid_string_static(psid),
1278 sid_type_lookup(type)));
1285 /* This was ours, but it was not mapped. Fail */
1288 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1292 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
1293 (unsigned int)*pgid ));
1295 store_gid_sid_cache(psid, *pgid);
1300 /*****************************************************************
1301 *THE CANONICAL* convert uid_t to SID function.
1302 *****************************************************************/
1304 void uid_to_sid(DOM_SID *psid, uid_t uid)
1308 if (fetch_sid_from_uid_cache(psid, uid))
1311 if (!winbind_uid_to_sid(psid, uid)) {
1312 if (!winbind_ping()) {
1313 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1314 legacy_uid_to_sid(psid, uid);
1318 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1323 DEBUG(10,("uid %u -> sid %s\n",
1324 (unsigned int)uid, sid_string_static(psid)));
1326 store_uid_sid_cache(psid, uid);
1330 /*****************************************************************
1331 *THE CANONICAL* convert gid_t to SID function.
1332 *****************************************************************/
1334 void gid_to_sid(DOM_SID *psid, gid_t gid)
1338 if (fetch_sid_from_gid_cache(psid, gid))
1341 if (!winbind_gid_to_sid(psid, gid)) {
1342 if (!winbind_ping()) {
1343 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1344 legacy_gid_to_sid(psid, gid);
1348 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1353 DEBUG(10,("gid %u -> sid %s\n",
1354 (unsigned int)gid, sid_string_static(psid)));
1356 store_gid_sid_cache(psid, gid);
1360 /*****************************************************************
1361 *THE CANONICAL* convert SID to uid function.
1362 *****************************************************************/
1364 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1368 if (fetch_uid_from_cache(puid, psid))
1371 if (fetch_gid_from_cache(&gid, psid)) {
1375 if (!winbind_sid_to_uid(puid, psid)) {
1376 if (!winbind_ping()) {
1377 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1378 return legacy_sid_to_uid(psid, puid);
1381 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1382 sid_string_static(psid)));
1386 /* TODO: Here would be the place to allocate both a gid and a uid for
1387 * the SID in question */
1389 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1390 (unsigned int)*puid ));
1392 store_uid_sid_cache(psid, *puid);
1396 /*****************************************************************
1397 *THE CANONICAL* convert SID to gid function.
1398 Group mapping is used for gids that maps to Wellknown SIDs
1399 *****************************************************************/
1401 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1405 if (fetch_gid_from_cache(pgid, psid))
1408 if (fetch_uid_from_cache(&uid, psid))
1411 /* Ask winbindd if it can map this sid to a gid.
1412 * (Idmap will check it is a valid SID and of the right type) */
1414 if ( !winbind_sid_to_gid(pgid, psid) ) {
1415 if (!winbind_ping()) {
1416 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1417 return legacy_sid_to_gid(psid, pgid);
1420 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1421 sid_string_static(psid)));
1425 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1426 (unsigned int)*pgid ));
1428 store_gid_sid_cache(psid, *pgid);