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 3 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, see <http://www.gnu.org/licenses/>.
24 /*****************************************************************
25 Dissect a user-provided name into domain, name, sid and type.
27 If an explicit domain name was given in the form domain\user, it
28 has to try that. If no explicit domain name was given, we have
30 *****************************************************************/
32 bool lookup_name(TALLOC_CTX *mem_ctx,
33 const char *full_name, int flags,
34 const char **ret_domain, const char **ret_name,
35 DOM_SID *ret_sid, enum lsa_SidType *ret_type)
39 const char *domain = NULL;
40 const char *name = NULL;
43 enum lsa_SidType type;
44 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
46 if (tmp_ctx == NULL) {
47 DEBUG(0, ("talloc_new failed\n"));
51 p = strchr_m(full_name, '\\');
54 domain = talloc_strndup(tmp_ctx, full_name,
55 PTR_DIFF(p, full_name));
56 name = talloc_strdup(tmp_ctx, p+1);
58 domain = talloc_strdup(tmp_ctx, "");
59 name = talloc_strdup(tmp_ctx, full_name);
62 DEBUG(10,("lookup_name: %s => %s (domain), %s (name)\n",
63 full_name, domain, name));
65 if ((domain == NULL) || (name == NULL)) {
66 DEBUG(0, ("talloc failed\n"));
71 if (strequal(domain, get_global_sam_name())) {
73 /* It's our own domain, lookup the name in passdb */
74 if (lookup_global_sam_name(name, flags, &rid, &type)) {
75 sid_copy(&sid, get_global_sam_sid());
76 sid_append_rid(&sid, rid);
83 if (strequal(domain, builtin_domain_name())) {
85 /* Explicit request for a name in BUILTIN */
86 if (lookup_builtin_name(name, &rid)) {
87 sid_copy(&sid, &global_sid_Builtin);
88 sid_append_rid(&sid, rid);
89 type = SID_NAME_ALIAS;
96 /* Try the explicit winbind lookup first, don't let it guess the
97 * domain yet at this point yet. This comes later. */
99 if ((domain[0] != '\0') &&
100 (winbind_lookup_name(domain, name, &sid, &type))) {
104 if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_users_domain_name())) {
105 if (lookup_unix_user_name(name, &sid)) {
106 type = SID_NAME_USER;
109 TALLOC_FREE(tmp_ctx);
113 if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_groups_domain_name())) {
114 if (lookup_unix_group_name(name, &sid)) {
115 type = SID_NAME_DOM_GRP;
118 TALLOC_FREE(tmp_ctx);
122 if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
123 TALLOC_FREE(tmp_ctx);
127 /* Now the guesswork begins, we haven't been given an explicit
128 * domain. Try the sequence as documented on
129 * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
130 * November 27, 2005 */
132 /* 1. well-known names */
134 if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
135 type = SID_NAME_WKN_GRP;
139 /* 2. Builtin domain as such */
141 if (strequal(name, builtin_domain_name())) {
142 /* Swap domain and name */
143 tmp = name; name = domain; domain = tmp;
144 sid_copy(&sid, &global_sid_Builtin);
145 type = SID_NAME_DOMAIN;
149 /* 3. Account domain */
151 if (strequal(name, get_global_sam_name())) {
152 if (!secrets_fetch_domain_sid(name, &sid)) {
153 DEBUG(3, ("Could not fetch my SID\n"));
154 TALLOC_FREE(tmp_ctx);
157 /* Swap domain and name */
158 tmp = name; name = domain; domain = tmp;
159 type = SID_NAME_DOMAIN;
163 /* 4. Primary domain */
165 if (!IS_DC && strequal(name, lp_workgroup())) {
166 if (!secrets_fetch_domain_sid(name, &sid)) {
167 DEBUG(3, ("Could not fetch the domain SID\n"));
168 TALLOC_FREE(tmp_ctx);
171 /* Swap domain and name */
172 tmp = name; name = domain; domain = tmp;
173 type = SID_NAME_DOMAIN;
177 /* 5. Trusted domains as such, to me it looks as if members don't do
178 this, tested an XP workstation in a NT domain -- vl */
180 if (IS_DC && (pdb_get_trusteddom_pw(name, NULL, &sid, NULL))) {
181 /* Swap domain and name */
182 tmp = name; name = domain; domain = tmp;
183 type = SID_NAME_DOMAIN;
187 /* 6. Builtin aliases */
189 if (lookup_builtin_name(name, &rid)) {
190 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
191 sid_copy(&sid, &global_sid_Builtin);
192 sid_append_rid(&sid, rid);
193 type = SID_NAME_ALIAS;
197 /* 7. Local systems' SAM (DCs don't have a local SAM) */
198 /* 8. Primary SAM (On members, this is the domain) */
200 /* Both cases are done by looking at our passdb */
202 if (lookup_global_sam_name(name, flags, &rid, &type)) {
203 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
204 sid_copy(&sid, get_global_sam_sid());
205 sid_append_rid(&sid, rid);
209 /* Now our local possibilities are exhausted. */
211 if (!(flags & LOOKUP_NAME_REMOTE)) {
212 TALLOC_FREE(tmp_ctx);
216 /* If we are not a DC, we have to ask in our primary domain. Let
217 * winbind do that. */
220 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
221 domain = talloc_strdup(tmp_ctx, lp_workgroup());
225 /* 9. Trusted domains */
227 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
228 * that (yet), but give it a chance. */
230 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
233 enum lsa_SidType domain_type;
235 if (type == SID_NAME_DOMAIN) {
236 /* Swap name and type */
237 tmp = name; name = domain; domain = tmp;
241 /* Here we have to cope with a little deficiency in the
242 * winbind API: We have to ask it again for the name of the
243 * domain it figured out itself. Maybe fix that later... */
245 sid_copy(&dom_sid, &sid);
246 sid_split_rid(&dom_sid, &tmp_rid);
248 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
250 (domain_type != SID_NAME_DOMAIN)) {
251 DEBUG(2, ("winbind could not find the domain's name "
252 "it just looked up for us\n"));
253 TALLOC_FREE(tmp_ctx);
259 /* 10. Don't translate */
261 /* 11. Ok, windows would end here. Samba has two more options:
262 Unmapped users and unmapped groups */
264 if (!(flags & LOOKUP_NAME_EXPLICIT) && lookup_unix_user_name(name, &sid)) {
265 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
266 type = SID_NAME_USER;
270 if (!(flags & LOOKUP_NAME_EXPLICIT) && lookup_unix_group_name(name, &sid)) {
271 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
272 type = SID_NAME_DOM_GRP;
277 * Ok, all possibilities tried. Fail.
280 TALLOC_FREE(tmp_ctx);
284 if ((domain == NULL) || (name == NULL)) {
285 DEBUG(0, ("talloc failed\n"));
286 TALLOC_FREE(tmp_ctx);
291 * Hand over the results to the talloc context we've been given.
294 if ((ret_name != NULL) &&
295 !(*ret_name = talloc_strdup(mem_ctx, name))) {
296 DEBUG(0, ("talloc failed\n"));
297 TALLOC_FREE(tmp_ctx);
301 if (ret_domain != NULL) {
303 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
304 DEBUG(0, ("talloc failed\n"));
305 TALLOC_FREE(tmp_ctx);
309 *ret_domain = tmp_dom;
312 if (ret_sid != NULL) {
313 sid_copy(ret_sid, &sid);
316 if (ret_type != NULL) {
320 TALLOC_FREE(tmp_ctx);
324 /************************************************************************
325 Names from smb.conf can be unqualified. eg. valid users = foo
326 These names should never map to a remote name. Try global_sam_name()\foo,
327 and then "Unix Users"\foo (or "Unix Groups"\foo).
328 ************************************************************************/
330 bool lookup_name_smbconf(TALLOC_CTX *mem_ctx,
331 const char *full_name, int flags,
332 const char **ret_domain, const char **ret_name,
333 DOM_SID *ret_sid, enum lsa_SidType *ret_type)
335 char *qualified_name;
338 /* NB. No winbindd_separator here as lookup_name needs \\' */
339 if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
341 /* The name is already qualified with a domain. */
343 if (*lp_winbind_separator() != '\\') {
346 /* lookup_name() needs '\\' as a separator */
348 tmp = talloc_strdup(mem_ctx, full_name);
352 tmp[p - full_name] = '\\';
356 return lookup_name(mem_ctx, full_name, flags,
357 ret_domain, ret_name,
361 /* Try with our own SAM name. */
362 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
363 get_global_sam_name(),
365 if (!qualified_name) {
369 if (lookup_name(mem_ctx, qualified_name, flags,
370 ret_domain, ret_name,
371 ret_sid, ret_type)) {
375 /* Finally try with "Unix Users" or "Unix Group" */
376 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
377 flags & LOOKUP_NAME_GROUP ?
378 unix_groups_domain_name() :
379 unix_users_domain_name(),
381 if (!qualified_name) {
385 return lookup_name(mem_ctx, qualified_name, flags,
386 ret_domain, ret_name,
390 static bool wb_lookup_rids(TALLOC_CTX *mem_ctx,
391 const DOM_SID *domain_sid,
392 int num_rids, uint32 *rids,
393 const char **domain_name,
394 const char **names, enum lsa_SidType *types)
397 const char **my_names;
398 enum lsa_SidType *my_types;
401 if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
405 if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
406 domain_name, &my_names, &my_types)) {
408 for (i=0; i<num_rids; i++) {
410 types[i] = SID_NAME_UNKNOWN;
412 TALLOC_FREE(tmp_ctx);
416 if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
417 TALLOC_FREE(tmp_ctx);
422 * winbind_lookup_rids allocates its own array. We've been given the
423 * array, so copy it over
426 for (i=0; i<num_rids; i++) {
427 if (my_names[i] == NULL) {
428 TALLOC_FREE(tmp_ctx);
431 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
432 TALLOC_FREE(tmp_ctx);
435 types[i] = my_types[i];
437 TALLOC_FREE(tmp_ctx);
441 static bool lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
442 int num_rids, uint32_t *rids,
443 const char **domain_name,
444 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)) {
460 if (sid_check_is_domain(domain_sid)) {
463 if (*domain_name == NULL) {
464 *domain_name = talloc_strdup(
465 mem_ctx, get_global_sam_name());
468 if (*domain_name == NULL) {
473 result = pdb_lookup_rids(domain_sid, num_rids, rids,
477 return (NT_STATUS_IS_OK(result) ||
478 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
479 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
482 if (sid_check_is_builtin(domain_sid)) {
484 if (*domain_name == NULL) {
485 *domain_name = talloc_strdup(
486 mem_ctx, builtin_domain_name());
489 if (*domain_name == NULL) {
493 for (i=0; i<num_rids; i++) {
494 if (lookup_builtin_rid(*names, rids[i],
496 if ((*names)[i] == NULL) {
499 (*types)[i] = SID_NAME_ALIAS;
501 (*types)[i] = SID_NAME_UNKNOWN;
507 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
508 for (i=0; i<num_rids; i++) {
510 sid_copy(&sid, domain_sid);
511 sid_append_rid(&sid, rids[i]);
512 if (lookup_wellknown_sid(mem_ctx, &sid,
513 domain_name, &(*names)[i])) {
514 if ((*names)[i] == NULL) {
517 (*types)[i] = SID_NAME_WKN_GRP;
519 (*types)[i] = SID_NAME_UNKNOWN;
525 if (sid_check_is_unix_users(domain_sid)) {
526 if (*domain_name == NULL) {
527 *domain_name = talloc_strdup(
528 mem_ctx, unix_users_domain_name());
530 for (i=0; i<num_rids; i++) {
531 (*names)[i] = talloc_strdup(
532 (*names), uidtoname(rids[i]));
533 (*types)[i] = SID_NAME_USER;
538 if (sid_check_is_unix_groups(domain_sid)) {
539 if (*domain_name == NULL) {
540 *domain_name = talloc_strdup(
541 mem_ctx, unix_groups_domain_name());
543 for (i=0; i<num_rids; i++) {
544 (*names)[i] = talloc_strdup(
545 (*names), gidtoname(rids[i]));
546 (*types)[i] = SID_NAME_DOM_GRP;
551 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
552 domain_name, *names, *types);
556 * Is the SID a domain as such? If yes, lookup its name.
559 static bool lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
563 enum lsa_SidType type;
565 if (sid_check_is_domain(sid)) {
566 *name = talloc_strdup(mem_ctx, get_global_sam_name());
570 if (sid_check_is_builtin(sid)) {
571 *name = talloc_strdup(mem_ctx, builtin_domain_name());
575 if (sid_check_is_wellknown_domain(sid, &tmp)) {
576 *name = talloc_strdup(mem_ctx, tmp);
580 if (sid->num_auths != 4) {
581 /* This can't be a domain */
586 uint32 i, num_domains;
587 struct trustdom_info **domains;
589 /* This is relatively expensive, but it happens only on DCs
590 * and for SIDs that have 4 sub-authorities and thus look like
593 if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
599 for (i=0; i<num_domains; i++) {
600 if (sid_equal(sid, &domains[i]->sid)) {
601 *name = talloc_strdup(mem_ctx,
609 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
610 (type == SID_NAME_DOMAIN)) {
619 * This tries to implement the rather weird rules for the lsa_lookup level
622 * This is as close as we can get to what W2k3 does. With this we survive the
623 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
624 * different, but I assume that's just being too liberal. For example, W2k3
625 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
626 * whereas NT4 does the same as level 1 (I think). I did not fully test that
627 * with NT4, this is what w2k3 does.
629 * Level 1: Ask everywhere
630 * Level 2: Ask domain and trusted domains, no builtin and wkn
631 * Level 3: Only ask domain
632 * Level 4: W2k3ad: Only ask AD trusts
633 * Level 5: Only ask transitive forest trusts
637 static bool check_dom_sid_to_level(const DOM_SID *sid, int level)
646 ret = (!sid_check_is_builtin(sid) &&
647 !sid_check_is_wellknown_domain(sid, NULL));
652 ret = sid_check_is_domain(sid);
659 DEBUG(10, ("%s SID %s in level %d\n",
660 ret ? "Accepting" : "Rejecting",
661 sid_string_dbg(sid), level));
666 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
667 * references to domains, it is explicitly made for this.
669 * This attempts to be as efficient as possible: It collects all SIDs
670 * belonging to a domain and hands them in bulk to the appropriate lookup
671 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
672 * *hugely* from this. Winbind is going to be extended with a lookup_rids
673 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
677 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
678 const DOM_SID **sids, int level,
679 struct lsa_dom_info **ret_domains,
680 struct lsa_name_info **ret_names)
683 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
684 struct lsa_name_info *name_infos;
685 struct lsa_dom_info *dom_infos = NULL;
689 if (!(tmp_ctx = talloc_new(mem_ctx))) {
690 DEBUG(0, ("talloc_new failed\n"));
691 return NT_STATUS_NO_MEMORY;
695 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
696 if (name_infos == NULL) {
697 result = NT_STATUS_NO_MEMORY;
704 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
706 if (dom_infos == NULL) {
707 result = NT_STATUS_NO_MEMORY;
711 /* First build up the data structures:
713 * dom_infos is a list of domains referenced in the list of
714 * SIDs. Later we will walk the list of domains and look up the RIDs
717 * name_infos is a shadow-copy of the SIDs array to collect the real
720 * dom_info->idxs is an index into the name_infos array. The
721 * difficulty we have here is that we need to keep the SIDs the client
722 * asked for in the same order for the reply
725 for (i=0; i<num_sids; i++) {
728 const char *domain_name = NULL;
730 sid_copy(&sid, sids[i]);
731 name_infos[i].type = SID_NAME_USE_NONE;
733 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
734 /* We can't push that through the normal lookup
735 * process, as this would reference illegal
738 * For example S-1-5-32 would end up referencing
739 * domain S-1-5- with RID 32 which is clearly wrong.
741 if (domain_name == NULL) {
742 result = NT_STATUS_NO_MEMORY;
746 name_infos[i].rid = 0;
747 name_infos[i].type = SID_NAME_DOMAIN;
748 name_infos[i].name = NULL;
750 if (sid_check_is_builtin(&sid)) {
751 /* Yes, W2k3 returns "BUILTIN" both as domain
753 name_infos[i].name = talloc_strdup(
754 name_infos, builtin_domain_name());
755 if (name_infos[i].name == NULL) {
756 result = NT_STATUS_NO_MEMORY;
761 /* This is a normal SID with rid component */
762 if (!sid_split_rid(&sid, &rid)) {
763 result = NT_STATUS_INVALID_PARAMETER;
768 if (!check_dom_sid_to_level(&sid, level)) {
769 name_infos[i].rid = 0;
770 name_infos[i].type = SID_NAME_UNKNOWN;
771 name_infos[i].name = NULL;
775 for (j=0; j<MAX_REF_DOMAINS; j++) {
776 if (!dom_infos[j].valid) {
779 if (sid_equal(&sid, &dom_infos[j].sid)) {
784 if (j == MAX_REF_DOMAINS) {
785 /* TODO: What's the right error message here? */
786 result = NT_STATUS_NONE_MAPPED;
790 if (!dom_infos[j].valid) {
791 /* We found a domain not yet referenced, create a new
793 dom_infos[j].valid = true;
794 sid_copy(&dom_infos[j].sid, &sid);
796 if (domain_name != NULL) {
797 /* This name was being found above in the case
798 * when we found a domain SID */
800 talloc_strdup(dom_infos, domain_name);
801 if (dom_infos[j].name == NULL) {
802 result = NT_STATUS_NO_MEMORY;
806 /* lookup_rids will take care of this */
807 dom_infos[j].name = NULL;
811 name_infos[i].dom_idx = j;
813 if (name_infos[i].type == SID_NAME_USE_NONE) {
814 name_infos[i].rid = rid;
816 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
817 &dom_infos[j].num_idxs);
819 if (dom_infos[j].idxs == NULL) {
820 result = NT_STATUS_NO_MEMORY;
826 /* Iterate over the domains found */
828 for (i=0; i<MAX_REF_DOMAINS; i++) {
830 const char *domain_name = NULL;
832 enum lsa_SidType *types;
833 struct lsa_dom_info *dom = &dom_infos[i];
836 /* No domains left, we're done */
841 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
842 result = NT_STATUS_NO_MEMORY;
849 for (j=0; j<dom->num_idxs; j++) {
850 rids[j] = name_infos[dom->idxs[j]].rid;
853 if (!lookup_rids(tmp_ctx, &dom->sid,
854 dom->num_idxs, rids, &domain_name,
856 result = NT_STATUS_NO_MEMORY;
860 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
861 result = NT_STATUS_NO_MEMORY;
865 for (j=0; j<dom->num_idxs; j++) {
866 int idx = dom->idxs[j];
867 name_infos[idx].type = types[j];
868 if (types[j] != SID_NAME_UNKNOWN) {
869 name_infos[idx].name =
870 talloc_strdup(name_infos, names[j]);
871 if (name_infos[idx].name == NULL) {
872 result = NT_STATUS_NO_MEMORY;
876 name_infos[idx].name = NULL;
881 *ret_domains = dom_infos;
882 *ret_names = name_infos;
883 TALLOC_FREE(tmp_ctx);
887 TALLOC_FREE(dom_infos);
888 TALLOC_FREE(name_infos);
889 TALLOC_FREE(tmp_ctx);
893 /*****************************************************************
894 *THE CANONICAL* convert SID to name function.
895 *****************************************************************/
897 bool lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
898 const char **ret_domain, const char **ret_name,
899 enum lsa_SidType *ret_type)
901 struct lsa_dom_info *domain;
902 struct lsa_name_info *name;
906 if (!(tmp_ctx = talloc_new(mem_ctx))) {
907 DEBUG(0, ("talloc_new failed\n"));
911 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
916 if (name->type == SID_NAME_UNKNOWN) {
920 if ((ret_domain != NULL) &&
921 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
925 if ((ret_name != NULL) &&
926 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
930 if (ret_type != NULL) {
931 *ret_type = name->type;
938 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n", sid_string_dbg(sid),
939 domain->name, name->name, name->type));
941 DEBUG(10, ("failed to lookup sid %s\n", sid_string_dbg(sid)));
943 TALLOC_FREE(tmp_ctx);
947 /*****************************************************************
948 Id mapping cache. This is to avoid Winbind mappings already
949 seen by smbd to be queried too frequently, keeping winbindd
950 busy, and blocking smbd while winbindd is busy with other
951 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
952 modified to use linked lists by jra.
953 *****************************************************************/
955 #define MAX_UID_SID_CACHE_SIZE 100
956 #define TURNOVER_UID_SID_CACHE_SIZE 10
957 #define MAX_GID_SID_CACHE_SIZE 100
958 #define TURNOVER_GID_SID_CACHE_SIZE 10
960 static size_t n_uid_sid_cache = 0;
961 static size_t n_gid_sid_cache = 0;
963 static struct uid_sid_cache {
964 struct uid_sid_cache *next, *prev;
967 enum lsa_SidType sidtype;
968 } *uid_sid_cache_head;
970 static struct gid_sid_cache {
971 struct gid_sid_cache *next, *prev;
974 enum lsa_SidType sidtype;
975 } *gid_sid_cache_head;
977 /*****************************************************************
978 Find a SID given a uid.
979 *****************************************************************/
981 static bool fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
983 struct uid_sid_cache *pc;
985 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
986 if (pc->uid == uid) {
988 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
989 (unsigned int)uid, sid_string_dbg(psid)));
990 DLIST_PROMOTE(uid_sid_cache_head, pc);
997 /*****************************************************************
998 Find a uid given a SID.
999 *****************************************************************/
1001 static bool fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
1003 struct uid_sid_cache *pc;
1005 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
1006 if (sid_compare(&pc->sid, psid) == 0) {
1008 DEBUG(3,("fetch uid from cache %u -> %s\n",
1009 (unsigned int)*puid, sid_string_dbg(psid)));
1010 DLIST_PROMOTE(uid_sid_cache_head, pc);
1017 /*****************************************************************
1018 Store uid to SID mapping in cache.
1019 *****************************************************************/
1021 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1023 struct uid_sid_cache *pc;
1025 /* do not store SIDs in the "Unix Group" domain */
1027 if ( sid_check_is_in_unix_users( psid ) )
1030 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1031 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1032 struct uid_sid_cache *pc_next;
1035 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1037 for(; pc; pc = pc_next) {
1039 DLIST_REMOVE(uid_sid_cache_head,pc);
1045 pc = SMB_MALLOC_P(struct uid_sid_cache);
1049 sid_copy(&pc->sid, psid);
1050 DLIST_ADD(uid_sid_cache_head, pc);
1054 /*****************************************************************
1055 Find a SID given a gid.
1056 *****************************************************************/
1058 static bool fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1060 struct gid_sid_cache *pc;
1062 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1063 if (pc->gid == gid) {
1065 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1066 (unsigned int)gid, sid_string_dbg(psid)));
1067 DLIST_PROMOTE(gid_sid_cache_head, pc);
1074 /*****************************************************************
1075 Find a gid given a SID.
1076 *****************************************************************/
1078 static bool fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1080 struct gid_sid_cache *pc;
1082 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1083 if (sid_compare(&pc->sid, psid) == 0) {
1085 DEBUG(3,("fetch gid from cache %u -> %s\n",
1086 (unsigned int)*pgid, sid_string_dbg(psid)));
1087 DLIST_PROMOTE(gid_sid_cache_head, pc);
1094 /*****************************************************************
1095 Store gid to SID mapping in cache.
1096 *****************************************************************/
1098 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1100 struct gid_sid_cache *pc;
1102 /* do not store SIDs in the "Unix Group" domain */
1104 if ( sid_check_is_in_unix_groups( psid ) )
1107 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1108 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1109 struct gid_sid_cache *pc_next;
1112 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1114 for(; pc; pc = pc_next) {
1116 DLIST_REMOVE(gid_sid_cache_head,pc);
1122 pc = SMB_MALLOC_P(struct gid_sid_cache);
1126 sid_copy(&pc->sid, psid);
1127 DLIST_ADD(gid_sid_cache_head, pc);
1129 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n",
1130 (unsigned int)gid, sid_string_dbg(psid)));
1135 /*****************************************************************
1136 *THE LEGACY* convert uid_t to SID function.
1137 *****************************************************************/
1139 static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1147 ret = pdb_uid_to_rid(uid, &rid);
1151 /* This is a mapped user */
1152 sid_copy(psid, get_global_sam_sid());
1153 sid_append_rid(psid, rid);
1157 /* This is an unmapped user */
1159 uid_to_unix_users_sid(uid, psid);
1162 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1163 sid_string_dbg(psid)));
1165 store_uid_sid_cache(psid, uid);
1169 /*****************************************************************
1170 *THE LEGACY* convert gid_t to SID function.
1171 *****************************************************************/
1173 static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1180 ret = pdb_gid_to_sid(gid, psid);
1184 /* This is a mapped group */
1188 /* This is an unmapped group */
1190 gid_to_unix_groups_sid(gid, psid);
1193 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1194 sid_string_dbg(psid)));
1196 store_gid_sid_cache(psid, gid);
1200 /*****************************************************************
1201 *THE LEGACY* convert SID to uid function.
1202 *****************************************************************/
1204 static bool legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1206 enum lsa_SidType type;
1209 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1214 ret = pdb_sid_to_id(psid, &id, &type);
1218 if (type != SID_NAME_USER) {
1219 DEBUG(5, ("sid %s is a %s, expected a user\n",
1220 sid_string_dbg(psid),
1221 sid_type_lookup(type)));
1228 /* This was ours, but it was not mapped. Fail */
1231 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1232 sid_string_dbg(psid)));
1236 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_dbg(psid),
1237 (unsigned int)*puid ));
1239 store_uid_sid_cache(psid, *puid);
1243 /*****************************************************************
1244 *THE LEGACY* convert SID to gid function.
1245 Group mapping is used for gids that maps to Wellknown SIDs
1246 *****************************************************************/
1248 static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1253 enum lsa_SidType type;
1255 if ((sid_check_is_in_builtin(psid) ||
1256 sid_check_is_in_wellknown_domain(psid))) {
1260 ret = pdb_getgrsid(&map, *psid);
1267 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1268 sid_string_dbg(psid)));
1272 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1276 ret = pdb_sid_to_id(psid, &id, &type);
1280 if ((type != SID_NAME_DOM_GRP) &&
1281 (type != SID_NAME_ALIAS)) {
1282 DEBUG(5, ("LEGACY: sid %s is a %s, expected "
1283 "a group\n", sid_string_dbg(psid),
1284 sid_type_lookup(type)));
1291 /* This was ours, but it was not mapped. Fail */
1294 DEBUG(10,("LEGACY: mapping failed for sid %s\n",
1295 sid_string_dbg(psid)));
1299 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_dbg(psid),
1300 (unsigned int)*pgid ));
1302 store_gid_sid_cache(psid, *pgid);
1307 /*****************************************************************
1308 *THE CANONICAL* convert uid_t to SID function.
1309 *****************************************************************/
1311 void uid_to_sid(DOM_SID *psid, uid_t uid)
1315 if (fetch_sid_from_uid_cache(psid, uid))
1318 if (!winbind_uid_to_sid(psid, uid)) {
1319 if (!winbind_ping()) {
1320 legacy_uid_to_sid(psid, uid);
1324 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1329 DEBUG(10,("uid %u -> sid %s\n", (unsigned int)uid,
1330 sid_string_dbg(psid)));
1332 store_uid_sid_cache(psid, uid);
1336 /*****************************************************************
1337 *THE CANONICAL* convert gid_t to SID function.
1338 *****************************************************************/
1340 void gid_to_sid(DOM_SID *psid, gid_t gid)
1344 if (fetch_sid_from_gid_cache(psid, gid))
1347 if (!winbind_gid_to_sid(psid, gid)) {
1348 if (!winbind_ping()) {
1349 legacy_gid_to_sid(psid, gid);
1353 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1358 DEBUG(10,("gid %u -> sid %s\n", (unsigned int)gid,
1359 sid_string_dbg(psid)));
1361 store_gid_sid_cache(psid, gid);
1365 /*****************************************************************
1366 *THE CANONICAL* convert SID to uid function.
1367 *****************************************************************/
1369 bool sid_to_uid(const DOM_SID *psid, uid_t *puid)
1374 if (fetch_uid_from_cache(puid, psid))
1377 if (fetch_gid_from_cache(&gid, psid)) {
1381 /* Optimize for the Unix Users Domain
1382 * as the conversion is straightforward */
1383 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1387 /* return here, don't cache */
1388 DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1389 (unsigned int)*puid ));
1393 if (!winbind_sid_to_uid(puid, psid)) {
1394 if (!winbind_ping()) {
1395 return legacy_sid_to_uid(psid, puid);
1398 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1399 sid_string_dbg(psid)));
1403 /* TODO: Here would be the place to allocate both a gid and a uid for
1404 * the SID in question */
1406 DEBUG(10,("sid %s -> uid %u\n", sid_string_dbg(psid),
1407 (unsigned int)*puid ));
1409 store_uid_sid_cache(psid, *puid);
1413 /*****************************************************************
1414 *THE CANONICAL* convert SID to gid function.
1415 Group mapping is used for gids that maps to Wellknown SIDs
1416 *****************************************************************/
1418 bool sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1423 if (fetch_gid_from_cache(pgid, psid))
1426 if (fetch_uid_from_cache(&uid, psid))
1429 /* Optimize for the Unix Groups Domain
1430 * as the conversion is straightforward */
1431 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1435 /* return here, don't cache */
1436 DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1437 (unsigned int)*pgid ));
1441 /* Ask winbindd if it can map this sid to a gid.
1442 * (Idmap will check it is a valid SID and of the right type) */
1444 if ( !winbind_sid_to_gid(pgid, psid) ) {
1445 if (!winbind_ping()) {
1446 return legacy_sid_to_gid(psid, pgid);
1449 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1450 sid_string_dbg(psid)));
1454 DEBUG(10,("sid %s -> gid %u\n", sid_string_dbg(psid),
1455 (unsigned int)*pgid ));
1457 store_gid_sid_cache(psid, *pgid);