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)
450 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
451 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
453 if ((*names == NULL) || (*types == NULL)) {
461 if (sid_check_is_domain(domain_sid)) {
464 if (*domain_name == NULL) {
465 *domain_name = talloc_strdup(
466 mem_ctx, get_global_sam_name());
469 if (*domain_name == NULL) {
474 result = pdb_lookup_rids(domain_sid, num_rids, rids,
478 return (NT_STATUS_IS_OK(result) ||
479 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
480 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
483 if (sid_check_is_builtin(domain_sid)) {
485 if (*domain_name == NULL) {
486 *domain_name = talloc_strdup(
487 mem_ctx, builtin_domain_name());
490 if (*domain_name == NULL) {
494 for (i=0; i<num_rids; i++) {
495 if (lookup_builtin_rid(*names, rids[i],
497 if ((*names)[i] == NULL) {
500 (*types)[i] = SID_NAME_ALIAS;
502 (*types)[i] = SID_NAME_UNKNOWN;
508 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
509 for (i=0; i<num_rids; i++) {
511 sid_copy(&sid, domain_sid);
512 sid_append_rid(&sid, rids[i]);
513 if (lookup_wellknown_sid(mem_ctx, &sid,
514 domain_name, &(*names)[i])) {
515 if ((*names)[i] == NULL) {
518 (*types)[i] = SID_NAME_WKN_GRP;
520 (*types)[i] = SID_NAME_UNKNOWN;
526 if (sid_check_is_unix_users(domain_sid)) {
527 if (*domain_name == NULL) {
528 *domain_name = talloc_strdup(
529 mem_ctx, unix_users_domain_name());
531 for (i=0; i<num_rids; i++) {
532 (*names)[i] = talloc_strdup(
533 (*names), uidtoname(rids[i]));
534 (*types)[i] = SID_NAME_USER;
539 if (sid_check_is_unix_groups(domain_sid)) {
540 if (*domain_name == NULL) {
541 *domain_name = talloc_strdup(
542 mem_ctx, unix_groups_domain_name());
544 for (i=0; i<num_rids; i++) {
545 (*names)[i] = talloc_strdup(
546 (*names), gidtoname(rids[i]));
547 (*types)[i] = SID_NAME_DOM_GRP;
552 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
553 domain_name, *names, *types);
557 * Is the SID a domain as such? If yes, lookup its name.
560 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
564 enum lsa_SidType type;
566 if (sid_check_is_domain(sid)) {
567 *name = talloc_strdup(mem_ctx, get_global_sam_name());
571 if (sid_check_is_builtin(sid)) {
572 *name = talloc_strdup(mem_ctx, builtin_domain_name());
576 if (sid_check_is_wellknown_domain(sid, &tmp)) {
577 *name = talloc_strdup(mem_ctx, tmp);
581 if (sid->num_auths != 4) {
582 /* This can't be a domain */
587 uint32 i, num_domains;
588 struct trustdom_info **domains;
590 /* This is relatively expensive, but it happens only on DCs
591 * and for SIDs that have 4 sub-authorities and thus look like
594 if (!NT_STATUS_IS_OK(pdb_enum_trusteddoms(mem_ctx,
600 for (i=0; i<num_domains; i++) {
601 if (sid_equal(sid, &domains[i]->sid)) {
602 *name = talloc_strdup(mem_ctx,
610 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
611 (type == SID_NAME_DOMAIN)) {
620 * This tries to implement the rather weird rules for the lsa_lookup level
623 * This is as close as we can get to what W2k3 does. With this we survive the
624 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
625 * different, but I assume that's just being too liberal. For example, W2k3
626 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
627 * whereas NT4 does the same as level 1 (I think). I did not fully test that
628 * with NT4, this is what w2k3 does.
630 * Level 1: Ask everywhere
631 * Level 2: Ask domain and trusted domains, no builtin and wkn
632 * Level 3: Only ask domain
633 * Level 4: W2k3ad: Only ask AD trusts
634 * Level 5: Don't lookup anything
638 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
647 ret = (!sid_check_is_builtin(sid) &&
648 !sid_check_is_wellknown_domain(sid, NULL));
653 ret = sid_check_is_domain(sid);
660 DEBUG(10, ("%s SID %s in level %d\n",
661 ret ? "Accepting" : "Rejecting",
662 sid_string_static(sid), level));
667 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
668 * references to domains, it is explicitly made for this.
670 * This attempts to be as efficient as possible: It collects all SIDs
671 * belonging to a domain and hands them in bulk to the appropriate lookup
672 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
673 * *hugely* from this. Winbind is going to be extended with a lookup_rids
674 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
678 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
679 const DOM_SID **sids, int level,
680 struct lsa_dom_info **ret_domains,
681 struct lsa_name_info **ret_names)
684 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
685 struct lsa_name_info *name_infos;
686 struct lsa_dom_info *dom_infos;
690 if (!(tmp_ctx = talloc_new(mem_ctx))) {
691 DEBUG(0, ("talloc_new failed\n"));
692 return NT_STATUS_NO_MEMORY;
696 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
697 if (name_infos == NULL) {
698 result = NT_STATUS_NO_MEMORY;
705 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
707 if (dom_infos == NULL) {
708 result = NT_STATUS_NO_MEMORY;
712 /* First build up the data structures:
714 * dom_infos is a list of domains referenced in the list of
715 * SIDs. Later we will walk the list of domains and look up the RIDs
718 * name_infos is a shadow-copy of the SIDs array to collect the real
721 * dom_info->idxs is an index into the name_infos array. The
722 * difficulty we have here is that we need to keep the SIDs the client
723 * asked for in the same order for the reply
726 for (i=0; i<num_sids; i++) {
729 const char *domain_name = NULL;
731 sid_copy(&sid, sids[i]);
732 name_infos[i].type = SID_NAME_USE_NONE;
734 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
735 /* We can't push that through the normal lookup
736 * process, as this would reference illegal
739 * For example S-1-5-32 would end up referencing
740 * domain S-1-5- with RID 32 which is clearly wrong.
742 if (domain_name == NULL) {
743 result = NT_STATUS_NO_MEMORY;
747 name_infos[i].rid = 0;
748 name_infos[i].type = SID_NAME_DOMAIN;
749 name_infos[i].name = NULL;
751 if (sid_check_is_builtin(&sid)) {
752 /* Yes, W2k3 returns "BUILTIN" both as domain
754 name_infos[i].name = talloc_strdup(
755 name_infos, builtin_domain_name());
756 if (name_infos[i].name == NULL) {
757 result = NT_STATUS_NO_MEMORY;
762 /* This is a normal SID with rid component */
763 if (!sid_split_rid(&sid, &rid)) {
764 result = NT_STATUS_INVALID_PARAMETER;
769 if (!check_dom_sid_to_level(&sid, level)) {
770 name_infos[i].rid = 0;
771 name_infos[i].type = SID_NAME_UNKNOWN;
772 name_infos[i].name = NULL;
776 for (j=0; j<MAX_REF_DOMAINS; j++) {
777 if (!dom_infos[j].valid) {
780 if (sid_equal(&sid, &dom_infos[j].sid)) {
785 if (j == MAX_REF_DOMAINS) {
786 /* TODO: What's the right error message here? */
787 result = NT_STATUS_NONE_MAPPED;
791 if (!dom_infos[j].valid) {
792 /* We found a domain not yet referenced, create a new
794 dom_infos[j].valid = True;
795 sid_copy(&dom_infos[j].sid, &sid);
797 if (domain_name != NULL) {
798 /* This name was being found above in the case
799 * when we found a domain SID */
801 talloc_strdup(dom_infos, domain_name);
802 if (dom_infos[j].name == NULL) {
803 result = NT_STATUS_NO_MEMORY;
807 /* lookup_rids will take care of this */
808 dom_infos[j].name = NULL;
812 name_infos[i].dom_idx = j;
814 if (name_infos[i].type == SID_NAME_USE_NONE) {
815 name_infos[i].rid = rid;
817 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
818 &dom_infos[j].num_idxs);
820 if (dom_infos[j].idxs == NULL) {
821 result = NT_STATUS_NO_MEMORY;
827 /* Iterate over the domains found */
829 for (i=0; i<MAX_REF_DOMAINS; i++) {
831 const char *domain_name = NULL;
833 enum lsa_SidType *types;
834 struct lsa_dom_info *dom = &dom_infos[i];
837 /* No domains left, we're done */
842 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
843 result = NT_STATUS_NO_MEMORY;
850 for (j=0; j<dom->num_idxs; j++) {
851 rids[j] = name_infos[dom->idxs[j]].rid;
854 if (!lookup_rids(tmp_ctx, &dom->sid,
855 dom->num_idxs, rids, &domain_name,
857 result = NT_STATUS_NO_MEMORY;
861 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
862 result = NT_STATUS_NO_MEMORY;
866 for (j=0; j<dom->num_idxs; j++) {
867 int idx = dom->idxs[j];
868 name_infos[idx].type = types[j];
869 if (types[j] != SID_NAME_UNKNOWN) {
870 name_infos[idx].name =
871 talloc_strdup(name_infos, names[j]);
872 if (name_infos[idx].name == NULL) {
873 result = NT_STATUS_NO_MEMORY;
877 name_infos[idx].name = NULL;
882 *ret_domains = dom_infos;
883 *ret_names = name_infos;
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 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 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 BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1208 enum lsa_SidType type;
1211 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1217 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1222 ret = pdb_sid_to_id(psid, &id, &type);
1226 if (type != SID_NAME_USER) {
1227 DEBUG(5, ("sid %s is a %s, expected a user\n",
1228 sid_string_static(psid),
1229 sid_type_lookup(type)));
1236 /* This was ours, but it was not mapped. Fail */
1239 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1243 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
1244 (unsigned int)*puid ));
1246 store_uid_sid_cache(psid, *puid);
1250 /*****************************************************************
1251 *THE LEGACY* convert SID to gid function.
1252 Group mapping is used for gids that maps to Wellknown SIDs
1253 *****************************************************************/
1255 BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1260 enum lsa_SidType type;
1262 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1268 if ((sid_check_is_in_builtin(psid) ||
1269 sid_check_is_in_wellknown_domain(psid))) {
1273 ret = pdb_getgrsid(&map, *psid);
1280 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1284 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1288 ret = pdb_sid_to_id(psid, &id, &type);
1292 if ((type != SID_NAME_DOM_GRP) &&
1293 (type != SID_NAME_ALIAS)) {
1294 DEBUG(5, ("LEGACY: sid %s is a %s, expected a group\n",
1295 sid_string_static(psid),
1296 sid_type_lookup(type)));
1303 /* This was ours, but it was not mapped. Fail */
1306 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1310 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
1311 (unsigned int)*pgid ));
1313 store_gid_sid_cache(psid, *pgid);
1318 /*****************************************************************
1319 *THE CANONICAL* convert uid_t to SID function.
1320 *****************************************************************/
1322 void uid_to_sid(DOM_SID *psid, uid_t uid)
1326 if (fetch_sid_from_uid_cache(psid, uid))
1329 if (!winbind_uid_to_sid(psid, uid)) {
1330 if (!winbind_ping()) {
1331 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1332 legacy_uid_to_sid(psid, uid);
1336 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1341 DEBUG(10,("uid %u -> sid %s\n",
1342 (unsigned int)uid, sid_string_static(psid)));
1344 store_uid_sid_cache(psid, uid);
1348 /*****************************************************************
1349 *THE CANONICAL* convert gid_t to SID function.
1350 *****************************************************************/
1352 void gid_to_sid(DOM_SID *psid, gid_t gid)
1356 if (fetch_sid_from_gid_cache(psid, gid))
1359 if (!winbind_gid_to_sid(psid, gid)) {
1360 if (!winbind_ping()) {
1361 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1362 legacy_gid_to_sid(psid, gid);
1366 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1371 DEBUG(10,("gid %u -> sid %s\n",
1372 (unsigned int)gid, sid_string_static(psid)));
1374 store_gid_sid_cache(psid, gid);
1378 /*****************************************************************
1379 *THE CANONICAL* convert SID to uid function.
1380 *****************************************************************/
1382 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1386 if (fetch_uid_from_cache(puid, psid))
1389 if (fetch_gid_from_cache(&gid, psid)) {
1393 if (!winbind_sid_to_uid(puid, psid)) {
1394 if (!winbind_ping()) {
1395 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1396 return legacy_sid_to_uid(psid, puid);
1399 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1400 sid_string_static(psid)));
1404 /* TODO: Here would be the place to allocate both a gid and a uid for
1405 * the SID in question */
1407 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1408 (unsigned int)*puid ));
1410 store_uid_sid_cache(psid, *puid);
1414 /*****************************************************************
1415 *THE CANONICAL* convert SID to gid function.
1416 Group mapping is used for gids that maps to Wellknown SIDs
1417 *****************************************************************/
1419 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 /* Ask winbindd if it can map this sid to a gid.
1430 * (Idmap will check it is a valid SID and of the right type) */
1432 if ( !winbind_sid_to_gid(pgid, psid) ) {
1433 if (!winbind_ping()) {
1434 DEBUG(2, ("WARNING: Winbindd not running, mapping ids with legacy code\n"));
1435 return legacy_sid_to_gid(psid, pgid);
1438 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1439 sid_string_static(psid)));
1443 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1444 (unsigned int)*pgid ));
1446 store_gid_sid_cache(psid, *pgid);