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_static(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",
939 sid_string_static(sid), domain->name,
940 name->name, name->type));
942 DEBUG(10, ("failed to lookup sid %s\n",
943 sid_string_static(sid)));
945 TALLOC_FREE(tmp_ctx);
949 /*****************************************************************
950 Id mapping cache. This is to avoid Winbind mappings already
951 seen by smbd to be queried too frequently, keeping winbindd
952 busy, and blocking smbd while winbindd is busy with other
953 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
954 modified to use linked lists by jra.
955 *****************************************************************/
957 #define MAX_UID_SID_CACHE_SIZE 100
958 #define TURNOVER_UID_SID_CACHE_SIZE 10
959 #define MAX_GID_SID_CACHE_SIZE 100
960 #define TURNOVER_GID_SID_CACHE_SIZE 10
962 static size_t n_uid_sid_cache = 0;
963 static size_t n_gid_sid_cache = 0;
965 static struct uid_sid_cache {
966 struct uid_sid_cache *next, *prev;
969 enum lsa_SidType sidtype;
970 } *uid_sid_cache_head;
972 static struct gid_sid_cache {
973 struct gid_sid_cache *next, *prev;
976 enum lsa_SidType sidtype;
977 } *gid_sid_cache_head;
979 /*****************************************************************
980 Find a SID given a uid.
981 *****************************************************************/
983 static bool fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
985 struct uid_sid_cache *pc;
987 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
988 if (pc->uid == uid) {
990 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
991 (unsigned int)uid, sid_string_static(psid)));
992 DLIST_PROMOTE(uid_sid_cache_head, pc);
999 /*****************************************************************
1000 Find a uid given a SID.
1001 *****************************************************************/
1003 static bool fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
1005 struct uid_sid_cache *pc;
1007 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
1008 if (sid_compare(&pc->sid, psid) == 0) {
1010 DEBUG(3,("fetch uid from cache %u -> %s\n",
1011 (unsigned int)*puid, sid_string_static(psid)));
1012 DLIST_PROMOTE(uid_sid_cache_head, pc);
1019 /*****************************************************************
1020 Store uid to SID mapping in cache.
1021 *****************************************************************/
1023 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1025 struct uid_sid_cache *pc;
1027 /* do not store SIDs in the "Unix Group" domain */
1029 if ( sid_check_is_in_unix_users( psid ) )
1032 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1033 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1034 struct uid_sid_cache *pc_next;
1037 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1039 for(; pc; pc = pc_next) {
1041 DLIST_REMOVE(uid_sid_cache_head,pc);
1047 pc = SMB_MALLOC_P(struct uid_sid_cache);
1051 sid_copy(&pc->sid, psid);
1052 DLIST_ADD(uid_sid_cache_head, pc);
1056 /*****************************************************************
1057 Find a SID given a gid.
1058 *****************************************************************/
1060 static bool fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1062 struct gid_sid_cache *pc;
1064 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1065 if (pc->gid == gid) {
1067 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1068 (unsigned int)gid, sid_string_static(psid)));
1069 DLIST_PROMOTE(gid_sid_cache_head, pc);
1076 /*****************************************************************
1077 Find a gid given a SID.
1078 *****************************************************************/
1080 static bool fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1082 struct gid_sid_cache *pc;
1084 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1085 if (sid_compare(&pc->sid, psid) == 0) {
1087 DEBUG(3,("fetch gid from cache %u -> %s\n",
1088 (unsigned int)*pgid, sid_string_static(psid)));
1089 DLIST_PROMOTE(gid_sid_cache_head, pc);
1096 /*****************************************************************
1097 Store gid to SID mapping in cache.
1098 *****************************************************************/
1100 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1102 struct gid_sid_cache *pc;
1104 /* do not store SIDs in the "Unix Group" domain */
1106 if ( sid_check_is_in_unix_groups( psid ) )
1109 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1110 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1111 struct gid_sid_cache *pc_next;
1114 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1116 for(; pc; pc = pc_next) {
1118 DLIST_REMOVE(gid_sid_cache_head,pc);
1124 pc = SMB_MALLOC_P(struct gid_sid_cache);
1128 sid_copy(&pc->sid, psid);
1129 DLIST_ADD(gid_sid_cache_head, pc);
1131 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1132 sid_string_static(psid)));
1137 /*****************************************************************
1138 *THE LEGACY* convert uid_t to SID function.
1139 *****************************************************************/
1141 static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1149 ret = pdb_uid_to_rid(uid, &rid);
1153 /* This is a mapped user */
1154 sid_copy(psid, get_global_sam_sid());
1155 sid_append_rid(psid, rid);
1159 /* This is an unmapped user */
1161 uid_to_unix_users_sid(uid, psid);
1164 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1165 sid_string_static(psid)));
1167 store_uid_sid_cache(psid, uid);
1171 /*****************************************************************
1172 *THE LEGACY* convert gid_t to SID function.
1173 *****************************************************************/
1175 static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1182 ret = pdb_gid_to_sid(gid, psid);
1186 /* This is a mapped group */
1190 /* This is an unmapped group */
1192 gid_to_unix_groups_sid(gid, psid);
1195 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1196 sid_string_static(psid)));
1198 store_gid_sid_cache(psid, gid);
1202 /*****************************************************************
1203 *THE LEGACY* convert SID to uid function.
1204 *****************************************************************/
1206 static bool legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1208 enum lsa_SidType type;
1211 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1216 ret = pdb_sid_to_id(psid, &id, &type);
1220 if (type != SID_NAME_USER) {
1221 DEBUG(5, ("sid %s is a %s, expected a user\n",
1222 sid_string_static(psid),
1223 sid_type_lookup(type)));
1230 /* This was ours, but it was not mapped. Fail */
1233 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1237 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
1238 (unsigned int)*puid ));
1240 store_uid_sid_cache(psid, *puid);
1244 /*****************************************************************
1245 *THE LEGACY* convert SID to gid function.
1246 Group mapping is used for gids that maps to Wellknown SIDs
1247 *****************************************************************/
1249 static bool legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1254 enum lsa_SidType type;
1256 if ((sid_check_is_in_builtin(psid) ||
1257 sid_check_is_in_wellknown_domain(psid))) {
1261 ret = pdb_getgrsid(&map, *psid);
1268 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(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 a group\n",
1283 sid_string_static(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", sid_string_static(psid)));
1298 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
1299 (unsigned int)*pgid ));
1301 store_gid_sid_cache(psid, *pgid);
1306 /*****************************************************************
1307 *THE CANONICAL* convert uid_t to SID function.
1308 *****************************************************************/
1310 void uid_to_sid(DOM_SID *psid, uid_t uid)
1314 if (fetch_sid_from_uid_cache(psid, uid))
1317 if (!winbind_uid_to_sid(psid, uid)) {
1318 if (!winbind_ping()) {
1319 legacy_uid_to_sid(psid, uid);
1323 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1328 DEBUG(10,("uid %u -> sid %s\n",
1329 (unsigned int)uid, sid_string_static(psid)));
1331 store_uid_sid_cache(psid, uid);
1335 /*****************************************************************
1336 *THE CANONICAL* convert gid_t to SID function.
1337 *****************************************************************/
1339 void gid_to_sid(DOM_SID *psid, gid_t gid)
1343 if (fetch_sid_from_gid_cache(psid, gid))
1346 if (!winbind_gid_to_sid(psid, gid)) {
1347 if (!winbind_ping()) {
1348 legacy_gid_to_sid(psid, gid);
1352 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1357 DEBUG(10,("gid %u -> sid %s\n",
1358 (unsigned int)gid, sid_string_static(psid)));
1360 store_gid_sid_cache(psid, gid);
1364 /*****************************************************************
1365 *THE CANONICAL* convert SID to uid function.
1366 *****************************************************************/
1368 bool sid_to_uid(const DOM_SID *psid, uid_t *puid)
1373 if (fetch_uid_from_cache(puid, psid))
1376 if (fetch_gid_from_cache(&gid, psid)) {
1380 /* Optimize for the Unix Users Domain
1381 * as the conversion is straightforward */
1382 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1386 /* return here, don't cache */
1387 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1388 (unsigned int)*puid ));
1392 if (!winbind_sid_to_uid(puid, psid)) {
1393 if (!winbind_ping()) {
1394 return legacy_sid_to_uid(psid, puid);
1397 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1398 sid_string_static(psid)));
1402 /* TODO: Here would be the place to allocate both a gid and a uid for
1403 * the SID in question */
1405 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1406 (unsigned int)*puid ));
1408 store_uid_sid_cache(psid, *puid);
1412 /*****************************************************************
1413 *THE CANONICAL* convert SID to gid function.
1414 Group mapping is used for gids that maps to Wellknown SIDs
1415 *****************************************************************/
1417 bool sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1422 if (fetch_gid_from_cache(pgid, psid))
1425 if (fetch_uid_from_cache(&uid, psid))
1428 /* Optimize for the Unix Groups Domain
1429 * as the conversion is straightforward */
1430 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1434 /* return here, don't cache */
1435 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1436 (unsigned int)*pgid ));
1440 /* Ask winbindd if it can map this sid to a gid.
1441 * (Idmap will check it is a valid SID and of the right type) */
1443 if ( !winbind_sid_to_gid(pgid, psid) ) {
1444 if (!winbind_ping()) {
1445 return legacy_sid_to_gid(psid, pgid);
1448 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1449 sid_string_static(psid)));
1453 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1454 (unsigned int)*pgid ));
1456 store_gid_sid_cache(psid, *pgid);