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)) {
409 for (i=0; i<num_rids; i++) {
410 types[i] = SID_NAME_UNKNOWN;
416 * winbind_lookup_rids allocates its own array. We've been given the
417 * array, so copy it over
420 for (i=0; i<num_rids; i++) {
421 if (my_names[i] == NULL) {
422 TALLOC_FREE(tmp_ctx);
425 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
426 TALLOC_FREE(tmp_ctx);
429 types[i] = my_types[i];
431 TALLOC_FREE(tmp_ctx);
435 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
436 int num_rids, uint32_t *rids,
437 const char **domain_name,
438 const char ***names, enum lsa_SidType **types)
442 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
443 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
445 if ((*names == NULL) || (*types == NULL)) {
449 if (sid_check_is_domain(domain_sid)) {
452 if (*domain_name == NULL) {
453 *domain_name = talloc_strdup(
454 mem_ctx, get_global_sam_name());
457 if (*domain_name == NULL) {
462 result = pdb_lookup_rids(domain_sid, num_rids, rids,
466 return (NT_STATUS_IS_OK(result) ||
467 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
468 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
471 if (sid_check_is_builtin(domain_sid)) {
473 if (*domain_name == NULL) {
474 *domain_name = talloc_strdup(
475 mem_ctx, builtin_domain_name());
478 if (*domain_name == NULL) {
482 for (i=0; i<num_rids; i++) {
483 if (lookup_builtin_rid(*names, rids[i],
485 if ((*names)[i] == NULL) {
488 (*types)[i] = SID_NAME_ALIAS;
490 (*types)[i] = SID_NAME_UNKNOWN;
496 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
497 for (i=0; i<num_rids; i++) {
499 sid_copy(&sid, domain_sid);
500 sid_append_rid(&sid, rids[i]);
501 if (lookup_wellknown_sid(mem_ctx, &sid,
502 domain_name, &(*names)[i])) {
503 if ((*names)[i] == NULL) {
506 (*types)[i] = SID_NAME_WKN_GRP;
508 (*types)[i] = SID_NAME_UNKNOWN;
514 if (sid_check_is_unix_users(domain_sid)) {
515 if (*domain_name == NULL) {
516 *domain_name = talloc_strdup(
517 mem_ctx, unix_users_domain_name());
519 for (i=0; i<num_rids; i++) {
520 (*names)[i] = talloc_strdup(
521 (*names), uidtoname(rids[i]));
522 (*types)[i] = SID_NAME_USER;
527 if (sid_check_is_unix_groups(domain_sid)) {
528 if (*domain_name == NULL) {
529 *domain_name = talloc_strdup(
530 mem_ctx, unix_groups_domain_name());
532 for (i=0; i<num_rids; i++) {
533 (*names)[i] = talloc_strdup(
534 (*names), gidtoname(rids[i]));
535 (*types)[i] = SID_NAME_DOM_GRP;
540 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
541 domain_name, *names, *types);
545 * Is the SID a domain as such? If yes, lookup its name.
548 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
552 enum lsa_SidType type;
554 if (sid_check_is_domain(sid)) {
555 *name = talloc_strdup(mem_ctx, get_global_sam_name());
559 if (sid_check_is_builtin(sid)) {
560 *name = talloc_strdup(mem_ctx, builtin_domain_name());
564 if (sid_check_is_wellknown_domain(sid, &tmp)) {
565 *name = talloc_strdup(mem_ctx, tmp);
569 if (sid->num_auths != 4) {
570 /* This can't be a domain */
575 uint32 i, num_domains;
576 struct trustdom_info **domains;
578 /* This is relatively expensive, but it happens only on DCs
579 * and for SIDs that have 4 sub-authorities and thus look like
582 if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx,
588 for (i=0; i<num_domains; i++) {
589 if (sid_equal(sid, &domains[i]->sid)) {
590 *name = talloc_strdup(mem_ctx,
598 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
599 (type == SID_NAME_DOMAIN)) {
608 * This tries to implement the rather weird rules for the lsa_lookup level
611 * This is as close as we can get to what W2k3 does. With this we survive the
612 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
613 * different, but I assume that's just being too liberal. For example, W2k3
614 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
615 * whereas NT4 does the same as level 1 (I think). I did not fully test that
616 * with NT4, this is what w2k3 does.
618 * Level 1: Ask everywhere
619 * Level 2: Ask domain and trusted domains, no builtin and wkn
620 * Level 3: Only ask domain
621 * Level 4: W2k3ad: Only ask AD trusts
622 * Level 5: Don't lookup anything
626 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
635 ret = (!sid_check_is_builtin(sid) &&
636 !sid_check_is_wellknown_domain(sid, NULL));
641 ret = sid_check_is_domain(sid);
648 DEBUG(10, ("%s SID %s in level %d\n",
649 ret ? "Accepting" : "Rejecting",
650 sid_string_static(sid), level));
655 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
656 * references to domains, it is explicitly made for this.
658 * This attempts to be as efficient as possible: It collects all SIDs
659 * belonging to a domain and hands them in bulk to the appropriate lookup
660 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
661 * *hugely* from this. Winbind is going to be extended with a lookup_rids
662 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
666 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
667 const DOM_SID **sids, int level,
668 struct lsa_dom_info **ret_domains,
669 struct lsa_name_info **ret_names)
672 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
673 struct lsa_name_info *name_infos;
674 struct lsa_dom_info *dom_infos;
678 if (!(tmp_ctx = talloc_new(mem_ctx))) {
679 DEBUG(0, ("talloc_new failed\n"));
680 return NT_STATUS_NO_MEMORY;
683 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
684 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
686 if ((name_infos == NULL) || (dom_infos == NULL)) {
687 result = NT_STATUS_NO_MEMORY;
691 /* First build up the data structures:
693 * dom_infos is a list of domains referenced in the list of
694 * SIDs. Later we will walk the list of domains and look up the RIDs
697 * name_infos is a shadow-copy of the SIDs array to collect the real
700 * dom_info->idxs is an index into the name_infos array. The
701 * difficulty we have here is that we need to keep the SIDs the client
702 * asked for in the same order for the reply
705 for (i=0; i<num_sids; i++) {
708 const char *domain_name = NULL;
710 sid_copy(&sid, sids[i]);
711 name_infos[i].type = SID_NAME_USE_NONE;
713 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
714 /* We can't push that through the normal lookup
715 * process, as this would reference illegal
718 * For example S-1-5-32 would end up referencing
719 * domain S-1-5- with RID 32 which is clearly wrong.
721 if (domain_name == NULL) {
722 result = NT_STATUS_NO_MEMORY;
726 name_infos[i].rid = 0;
727 name_infos[i].type = SID_NAME_DOMAIN;
728 name_infos[i].name = NULL;
730 if (sid_check_is_builtin(&sid)) {
731 /* Yes, W2k3 returns "BUILTIN" both as domain
733 name_infos[i].name = talloc_strdup(
734 name_infos, builtin_domain_name());
735 if (name_infos[i].name == NULL) {
736 result = NT_STATUS_NO_MEMORY;
741 /* This is a normal SID with rid component */
742 if (!sid_split_rid(&sid, &rid)) {
743 result = NT_STATUS_INVALID_PARAMETER;
748 if (!check_dom_sid_to_level(&sid, level)) {
749 name_infos[i].rid = 0;
750 name_infos[i].type = SID_NAME_UNKNOWN;
751 name_infos[i].name = NULL;
755 for (j=0; j<MAX_REF_DOMAINS; j++) {
756 if (!dom_infos[j].valid) {
759 if (sid_equal(&sid, &dom_infos[j].sid)) {
764 if (j == MAX_REF_DOMAINS) {
765 /* TODO: What's the right error message here? */
766 result = NT_STATUS_NONE_MAPPED;
770 if (!dom_infos[j].valid) {
771 /* We found a domain not yet referenced, create a new
773 dom_infos[j].valid = True;
774 sid_copy(&dom_infos[j].sid, &sid);
776 if (domain_name != NULL) {
777 /* This name was being found above in the case
778 * when we found a domain SID */
780 talloc_strdup(dom_infos, domain_name);
781 if (dom_infos[j].name == NULL) {
782 result = NT_STATUS_NO_MEMORY;
786 /* lookup_rids will take care of this */
787 dom_infos[j].name = NULL;
791 name_infos[i].dom_idx = j;
793 if (name_infos[i].type == SID_NAME_USE_NONE) {
794 name_infos[i].rid = rid;
796 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
797 &dom_infos[j].num_idxs);
799 if (dom_infos[j].idxs == NULL) {
800 result = NT_STATUS_NO_MEMORY;
806 /* Iterate over the domains found */
808 for (i=0; i<MAX_REF_DOMAINS; i++) {
810 const char *domain_name = NULL;
812 enum lsa_SidType *types;
813 struct lsa_dom_info *dom = &dom_infos[i];
816 /* No domains left, we're done */
820 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
821 result = NT_STATUS_NO_MEMORY;
825 for (j=0; j<dom->num_idxs; j++) {
826 rids[j] = name_infos[dom->idxs[j]].rid;
829 if (!lookup_rids(tmp_ctx, &dom->sid,
830 dom->num_idxs, rids, &domain_name,
832 result = NT_STATUS_NO_MEMORY;
836 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
837 result = NT_STATUS_NO_MEMORY;
841 for (j=0; j<dom->num_idxs; j++) {
842 int idx = dom->idxs[j];
843 name_infos[idx].type = types[j];
844 if (types[j] != SID_NAME_UNKNOWN) {
845 name_infos[idx].name =
846 talloc_strdup(name_infos, names[j]);
847 if (name_infos[idx].name == NULL) {
848 result = NT_STATUS_NO_MEMORY;
852 name_infos[idx].name = NULL;
857 *ret_domains = dom_infos;
858 *ret_names = name_infos;
862 TALLOC_FREE(dom_infos);
863 TALLOC_FREE(name_infos);
864 TALLOC_FREE(tmp_ctx);
868 /*****************************************************************
869 *THE CANONICAL* convert SID to name function.
870 *****************************************************************/
872 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
873 const char **ret_domain, const char **ret_name,
874 enum lsa_SidType *ret_type)
876 struct lsa_dom_info *domain;
877 struct lsa_name_info *name;
881 if (!(tmp_ctx = talloc_new(mem_ctx))) {
882 DEBUG(0, ("talloc_new failed\n"));
886 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
891 if (name->type == SID_NAME_UNKNOWN) {
895 if ((ret_domain != NULL) &&
896 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
900 if ((ret_name != NULL) &&
901 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
905 if (ret_type != NULL) {
906 *ret_type = name->type;
913 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
914 sid_string_static(sid), domain->name,
915 name->name, name->type));
917 DEBUG(10, ("failed to lookup sid %s\n",
918 sid_string_static(sid)));
920 TALLOC_FREE(tmp_ctx);
924 /*****************************************************************
925 Id mapping cache. This is to avoid Winbind mappings already
926 seen by smbd to be queried too frequently, keeping winbindd
927 busy, and blocking smbd while winbindd is busy with other
928 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
929 modified to use linked lists by jra.
930 *****************************************************************/
932 #define MAX_UID_SID_CACHE_SIZE 100
933 #define TURNOVER_UID_SID_CACHE_SIZE 10
934 #define MAX_GID_SID_CACHE_SIZE 100
935 #define TURNOVER_GID_SID_CACHE_SIZE 10
937 static size_t n_uid_sid_cache = 0;
938 static size_t n_gid_sid_cache = 0;
940 static struct uid_sid_cache {
941 struct uid_sid_cache *next, *prev;
944 enum lsa_SidType sidtype;
945 } *uid_sid_cache_head;
947 static struct gid_sid_cache {
948 struct gid_sid_cache *next, *prev;
951 enum lsa_SidType sidtype;
952 } *gid_sid_cache_head;
954 /*****************************************************************
955 Find a SID given a uid.
956 *****************************************************************/
958 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
960 struct uid_sid_cache *pc;
962 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
963 if (pc->uid == uid) {
965 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
966 (unsigned int)uid, sid_string_static(psid)));
967 DLIST_PROMOTE(uid_sid_cache_head, pc);
974 /*****************************************************************
975 Find a uid given a SID.
976 *****************************************************************/
978 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
980 struct uid_sid_cache *pc;
982 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
983 if (sid_compare(&pc->sid, psid) == 0) {
985 DEBUG(3,("fetch uid from cache %u -> %s\n",
986 (unsigned int)*puid, sid_string_static(psid)));
987 DLIST_PROMOTE(uid_sid_cache_head, pc);
994 /*****************************************************************
995 Store uid to SID mapping in cache.
996 *****************************************************************/
998 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1000 struct uid_sid_cache *pc;
1002 /* do not store SIDs in the "Unix Group" domain */
1004 if ( sid_check_is_in_unix_users( psid ) )
1007 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1008 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1009 struct uid_sid_cache *pc_next;
1012 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1014 for(; pc; pc = pc_next) {
1016 DLIST_REMOVE(uid_sid_cache_head,pc);
1022 pc = SMB_MALLOC_P(struct uid_sid_cache);
1026 sid_copy(&pc->sid, psid);
1027 DLIST_ADD(uid_sid_cache_head, pc);
1031 /*****************************************************************
1032 Find a SID given a gid.
1033 *****************************************************************/
1035 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1037 struct gid_sid_cache *pc;
1039 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1040 if (pc->gid == gid) {
1042 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1043 (unsigned int)gid, sid_string_static(psid)));
1044 DLIST_PROMOTE(gid_sid_cache_head, pc);
1051 /*****************************************************************
1052 Find a gid given a SID.
1053 *****************************************************************/
1055 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1057 struct gid_sid_cache *pc;
1059 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1060 if (sid_compare(&pc->sid, psid) == 0) {
1062 DEBUG(3,("fetch gid from cache %u -> %s\n",
1063 (unsigned int)*pgid, sid_string_static(psid)));
1064 DLIST_PROMOTE(gid_sid_cache_head, pc);
1071 /*****************************************************************
1072 Store gid to SID mapping in cache.
1073 *****************************************************************/
1075 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1077 struct gid_sid_cache *pc;
1079 /* do not store SIDs in the "Unix Group" domain */
1081 if ( sid_check_is_in_unix_groups( psid ) )
1084 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1085 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1086 struct gid_sid_cache *pc_next;
1089 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1091 for(; pc; pc = pc_next) {
1093 DLIST_REMOVE(gid_sid_cache_head,pc);
1099 pc = SMB_MALLOC_P(struct gid_sid_cache);
1103 sid_copy(&pc->sid, psid);
1104 DLIST_ADD(gid_sid_cache_head, pc);
1106 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1107 sid_string_static(psid)));
1112 /*****************************************************************
1113 *THE CANONICAL* convert uid_t to SID function.
1114 *****************************************************************/
1116 void uid_to_sid(DOM_SID *psid, uid_t uid)
1124 if (fetch_sid_from_uid_cache(psid, uid))
1127 if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) &&
1128 winbind_uid_to_sid(psid, uid)) {
1130 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
1131 (unsigned int)uid, sid_string_static(psid)));
1136 ret = pdb_uid_to_rid(uid, &rid);
1140 /* This is a mapped user */
1141 sid_copy(psid, get_global_sam_sid());
1142 sid_append_rid(psid, rid);
1146 /* This is an unmapped user */
1148 uid_to_unix_users_sid(uid, psid);
1151 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
1152 sid_string_static(psid)));
1154 store_uid_sid_cache(psid, uid);
1158 /*****************************************************************
1159 *THE CANONICAL* convert gid_t to SID function.
1160 *****************************************************************/
1162 void gid_to_sid(DOM_SID *psid, gid_t gid)
1169 if (fetch_sid_from_gid_cache(psid, gid))
1172 if (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high) &&
1173 winbind_gid_to_sid(psid, gid)) {
1175 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
1176 (unsigned int)gid, sid_string_static(psid)));
1181 ret = pdb_gid_to_sid(gid, psid);
1185 /* This is a mapped group */
1189 /* This is an unmapped group */
1191 gid_to_unix_groups_sid(gid, psid);
1194 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
1195 sid_string_static(psid)));
1197 store_gid_sid_cache(psid, gid);
1201 /*****************************************************************
1202 *THE CANONICAL* convert SID to uid function.
1203 *****************************************************************/
1205 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1207 enum lsa_SidType type;
1211 if (fetch_uid_from_cache(puid, psid))
1214 if (fetch_gid_from_cache(&gid, psid)) {
1218 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1224 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1229 ret = pdb_sid_to_id(psid, &id, &type);
1233 if (type != SID_NAME_USER) {
1234 DEBUG(5, ("sid %s is a %s, expected a user\n",
1235 sid_string_static(psid),
1236 sid_type_lookup(type)));
1243 /* This was ours, but it was not mapped. Fail */
1248 if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1250 if (type != SID_NAME_USER) {
1251 DEBUG(10, ("sid_to_uid: sid %s is a %s\n",
1252 sid_string_static(psid),
1253 sid_type_lookup(type)));
1257 if (!winbind_sid_to_uid(puid, psid)) {
1258 DEBUG(5, ("sid_to_uid: winbind failed to allocate a "
1259 "new uid for sid %s\n",
1260 sid_string_static(psid)));
1266 /* TODO: Here would be the place to allocate both a gid and a uid for
1267 * the SID in question */
1272 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
1273 (unsigned int)*puid ));
1275 store_uid_sid_cache(psid, *puid);
1279 /*****************************************************************
1280 *THE CANONICAL* convert SID to gid function.
1281 Group mapping is used for gids that maps to Wellknown SIDs
1282 *****************************************************************/
1284 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1289 enum lsa_SidType type;
1292 if (fetch_gid_from_cache(pgid, psid))
1295 if (fetch_uid_from_cache(&uid, psid))
1298 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1304 if ((sid_check_is_in_builtin(psid) ||
1305 sid_check_is_in_wellknown_domain(psid))) {
1309 ret = pdb_getgrsid(&map, *psid);
1319 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1323 ret = pdb_sid_to_id(psid, &id, &type);
1327 if ((type != SID_NAME_DOM_GRP) &&
1328 (type != SID_NAME_ALIAS)) {
1329 DEBUG(5, ("sid %s is a %s, expected a group\n",
1330 sid_string_static(psid),
1331 sid_type_lookup(type)));
1338 /* This was ours, but it was not mapped. Fail */
1343 if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1344 DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, "
1345 "then winbind)\n", sid_string_static(psid)));
1350 /* winbindd knows it; Ensure this is a group sid */
1352 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
1353 (type != SID_NAME_WKN_GRP)) {
1354 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is "
1355 "a %s\n", sid_type_lookup(type)));
1359 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
1360 or we are dead in the water */
1362 if ( !winbind_sid_to_gid(pgid, psid) ) {
1363 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid "
1364 "for sid %s\n", sid_string_static(psid)));
1369 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
1370 (unsigned int)*pgid ));
1372 store_gid_sid_cache(psid, *pgid);