r17973: emrge the SID cache fixes for 3.0.23c
[Samba.git] / source / passdb / lookup_sid.c
blobdca7f47d8b50f35cd217cb19c49a5745403ac63e
1 /*
2 Unix SMB/CIFS implementation.
3 uid/user handling
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.
23 #include "includes.h"
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
30 to do guesswork.
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 SID_NAME_USE *ret_type)
38 char *p;
39 const char *tmp;
40 const char *domain = NULL;
41 const char *name = NULL;
42 uint32 rid;
43 DOM_SID sid;
44 enum SID_NAME_USE type;
45 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
47 if (tmp_ctx == NULL) {
48 DEBUG(0, ("talloc_new failed\n"));
49 return False;
52 p = strchr_m(full_name, '\\');
54 if (p != NULL) {
55 domain = talloc_strndup(tmp_ctx, full_name,
56 PTR_DIFF(p, full_name));
57 name = talloc_strdup(tmp_ctx, p+1);
58 } else {
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"));
68 return False;
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);
77 goto ok;
79 goto failed;
82 if (strequal(domain, builtin_domain_name())) {
84 /* Explicit request for a name in BUILTIN */
85 if (lookup_builtin_name(name, &rid)) {
86 sid_copy(&sid, &global_sid_Builtin);
87 sid_append_rid(&sid, rid);
88 type = SID_NAME_ALIAS;
89 goto ok;
91 goto failed;
94 /* Try the explicit winbind lookup first, don't let it guess the
95 * domain yet at this point yet. This comes later. */
97 if ((domain[0] != '\0') &&
98 (winbind_lookup_name(domain, name, &sid, &type))) {
99 goto ok;
102 if (strequal(domain, unix_users_domain_name())) {
103 if (lookup_unix_user_name(name, &sid)) {
104 type = SID_NAME_USER;
105 goto ok;
107 goto failed;
110 if (strequal(domain, unix_groups_domain_name())) {
111 if (lookup_unix_group_name(name, &sid)) {
112 type = SID_NAME_DOM_GRP;
113 goto ok;
115 goto failed;
118 if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
119 goto failed;
122 /* Now the guesswork begins, we haven't been given an explicit
123 * domain. Try the sequence as documented on
124 * http://msdn.microsoft.com/library/en-us/secmgmt/security/lsalookupnames.asp
125 * November 27, 2005 */
127 /* 1. well-known names */
129 if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
130 type = SID_NAME_WKN_GRP;
131 goto ok;
134 /* 2. Builtin domain as such */
136 if (strequal(name, builtin_domain_name())) {
137 /* Swap domain and name */
138 tmp = name; name = domain; domain = tmp;
139 sid_copy(&sid, &global_sid_Builtin);
140 type = SID_NAME_DOMAIN;
141 goto ok;
144 /* 3. Account domain */
146 if (strequal(name, get_global_sam_name())) {
147 if (!secrets_fetch_domain_sid(name, &sid)) {
148 DEBUG(3, ("Could not fetch my SID\n"));
149 goto failed;
151 /* Swap domain and name */
152 tmp = name; name = domain; domain = tmp;
153 type = SID_NAME_DOMAIN;
154 goto ok;
157 /* 4. Primary domain */
159 if (!IS_DC && strequal(name, lp_workgroup())) {
160 if (!secrets_fetch_domain_sid(name, &sid)) {
161 DEBUG(3, ("Could not fetch the domain SID\n"));
162 goto failed;
164 /* Swap domain and name */
165 tmp = name; name = domain; domain = tmp;
166 type = SID_NAME_DOMAIN;
167 goto ok;
170 /* 5. Trusted domains as such, to me it looks as if members don't do
171 this, tested an XP workstation in a NT domain -- vl */
173 if (IS_DC && (secrets_fetch_trusted_domain_password(name, NULL,
174 &sid, NULL))) {
175 /* Swap domain and name */
176 tmp = name; name = domain; domain = tmp;
177 type = SID_NAME_DOMAIN;
178 goto ok;
181 /* 6. Builtin aliases */
183 if (lookup_builtin_name(name, &rid)) {
184 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
185 sid_copy(&sid, &global_sid_Builtin);
186 sid_append_rid(&sid, rid);
187 type = SID_NAME_ALIAS;
188 goto ok;
191 /* 7. Local systems' SAM (DCs don't have a local SAM) */
192 /* 8. Primary SAM (On members, this is the domain) */
194 /* Both cases are done by looking at our passdb */
196 if (lookup_global_sam_name(name, flags, &rid, &type)) {
197 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
198 sid_copy(&sid, get_global_sam_sid());
199 sid_append_rid(&sid, rid);
200 goto ok;
203 /* Now our local possibilities are exhausted. */
205 if (!(flags & LOOKUP_NAME_REMOTE)) {
206 goto failed;
209 /* If we are not a DC, we have to ask in our primary domain. Let
210 * winbind do that. */
212 if (!IS_DC &&
213 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
214 domain = talloc_strdup(tmp_ctx, lp_workgroup());
215 goto ok;
218 /* 9. Trusted domains */
220 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
221 * that (yet), but give it a chance. */
223 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
224 DOM_SID dom_sid;
225 uint32 tmp_rid;
226 enum SID_NAME_USE domain_type;
228 if (type == SID_NAME_DOMAIN) {
229 /* Swap name and type */
230 tmp = name; name = domain; domain = tmp;
231 goto ok;
234 /* Here we have to cope with a little deficiency in the
235 * winbind API: We have to ask it again for the name of the
236 * domain it figured out itself. Maybe fix that later... */
238 sid_copy(&dom_sid, &sid);
239 sid_split_rid(&dom_sid, &tmp_rid);
241 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
242 &domain_type) ||
243 (domain_type != SID_NAME_DOMAIN)) {
244 DEBUG(2, ("winbind could not find the domain's name "
245 "it just looked up for us\n"));
246 goto failed;
248 goto ok;
251 /* 10. Don't translate */
253 /* 11. Ok, windows would end here. Samba has two more options:
254 Unmapped users and unmapped groups */
256 if (lookup_unix_user_name(name, &sid)) {
257 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
258 type = SID_NAME_USER;
259 goto ok;
262 if (lookup_unix_group_name(name, &sid)) {
263 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
264 type = SID_NAME_DOM_GRP;
265 goto ok;
268 failed:
269 TALLOC_FREE(tmp_ctx);
270 return False;
273 if ((domain == NULL) || (name == NULL)) {
274 DEBUG(0, ("talloc failed\n"));
275 TALLOC_FREE(tmp_ctx);
276 return False;
279 if (ret_name != NULL) {
280 *ret_name = talloc_steal(mem_ctx, name);
283 if (ret_domain != NULL) {
284 char *tmp_dom = talloc_strdup(tmp_ctx, domain);
285 strupper_m(tmp_dom);
286 *ret_domain = talloc_steal(mem_ctx, tmp_dom);
289 if (ret_sid != NULL) {
290 sid_copy(ret_sid, &sid);
293 if (ret_type != NULL) {
294 *ret_type = type;
297 TALLOC_FREE(tmp_ctx);
298 return True;
301 /************************************************************************
302 Names from smb.conf can be unqualified. eg. valid users = foo
303 These names should never map to a remote name. Try global_sam_name()\foo,
304 and then "Unix Users"\foo (or "Unix Groups"\foo).
305 ************************************************************************/
307 BOOL lookup_name_smbconf(TALLOC_CTX *mem_ctx,
308 const char *full_name, int flags,
309 const char **ret_domain, const char **ret_name,
310 DOM_SID *ret_sid, enum SID_NAME_USE *ret_type)
312 char *qualified_name;
313 const char *p;
315 /* NB. No winbindd_separator here as lookup_name needs \\' */
316 if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
318 /* The name is already qualified with a domain. */
320 if (*lp_winbind_separator() != '\\') {
321 char *tmp;
323 /* lookup_name() needs '\\' as a separator */
325 tmp = talloc_strdup(mem_ctx, full_name);
326 if (!tmp) {
327 return False;
329 tmp[p - full_name] = '\\';
330 full_name = tmp;
333 return lookup_name(mem_ctx, full_name, flags,
334 ret_domain, ret_name,
335 ret_sid, ret_type);
338 /* Try with our own SAM name. */
339 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
340 get_global_sam_name(),
341 full_name );
342 if (!qualified_name) {
343 return False;
346 if (lookup_name(mem_ctx, qualified_name, flags,
347 ret_domain, ret_name,
348 ret_sid, ret_type)) {
349 return True;
352 /* Finally try with "Unix Users" or "Unix Group" */
353 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
354 flags & LOOKUP_NAME_GROUP ?
355 unix_groups_domain_name() :
356 unix_users_domain_name(),
357 full_name );
358 if (!qualified_name) {
359 return False;
362 return lookup_name(mem_ctx, qualified_name, flags,
363 ret_domain, ret_name,
364 ret_sid, ret_type);
367 static BOOL winbind_lookup_rids(TALLOC_CTX *mem_ctx,
368 const DOM_SID *domain_sid,
369 int num_rids, uint32 *rids,
370 const char **domain_name,
371 const char **names, uint32 *types)
373 /* Unless the winbind interface is upgraded, fall back to ask for
374 * individual sids. I imagine introducing a lookuprids operation that
375 * directly proxies to lsa_lookupsids to the correct DC. -- vl */
377 int i;
378 for (i=0; i<num_rids; i++) {
379 DOM_SID sid;
381 sid_copy(&sid, domain_sid);
382 sid_append_rid(&sid, rids[i]);
384 if (winbind_lookup_sid(mem_ctx, &sid,
385 *domain_name == NULL ?
386 domain_name : NULL,
387 &names[i], &types[i])) {
388 if ((names[i] == NULL) || ((*domain_name) == NULL)) {
389 return False;
391 } else {
392 types[i] = SID_NAME_UNKNOWN;
395 return True;
398 static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
399 int num_rids, uint32_t *rids,
400 const char **domain_name,
401 const char ***names, enum SID_NAME_USE **types)
403 int i;
405 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
406 *types = TALLOC_ARRAY(mem_ctx, enum SID_NAME_USE, num_rids);
408 if ((*names == NULL) || (*types == NULL)) {
409 return False;
412 if (sid_check_is_domain(domain_sid)) {
413 NTSTATUS result;
415 if (*domain_name == NULL) {
416 *domain_name = talloc_strdup(
417 mem_ctx, get_global_sam_name());
420 if (*domain_name == NULL) {
421 return False;
424 become_root();
425 result = pdb_lookup_rids(domain_sid, num_rids, rids,
426 *names, *types);
427 unbecome_root();
429 return (NT_STATUS_IS_OK(result) ||
430 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
431 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
434 if (sid_check_is_builtin(domain_sid)) {
436 if (*domain_name == NULL) {
437 *domain_name = talloc_strdup(
438 mem_ctx, builtin_domain_name());
441 if (*domain_name == NULL) {
442 return False;
445 for (i=0; i<num_rids; i++) {
446 if (lookup_builtin_rid(*names, rids[i],
447 &(*names)[i])) {
448 if ((*names)[i] == NULL) {
449 return False;
451 (*types)[i] = SID_NAME_ALIAS;
452 } else {
453 (*types)[i] = SID_NAME_UNKNOWN;
456 return True;
459 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
460 for (i=0; i<num_rids; i++) {
461 DOM_SID sid;
462 sid_copy(&sid, domain_sid);
463 sid_append_rid(&sid, rids[i]);
464 if (lookup_wellknown_sid(mem_ctx, &sid,
465 domain_name, &(*names)[i])) {
466 if ((*names)[i] == NULL) {
467 return False;
469 (*types)[i] = SID_NAME_WKN_GRP;
470 } else {
471 (*types)[i] = SID_NAME_UNKNOWN;
474 return True;
477 if (sid_check_is_unix_users(domain_sid)) {
478 if (*domain_name == NULL) {
479 *domain_name = talloc_strdup(
480 mem_ctx, unix_users_domain_name());
482 for (i=0; i<num_rids; i++) {
483 (*names)[i] = talloc_strdup(
484 (*names), uidtoname(rids[i]));
485 (*types)[i] = SID_NAME_USER;
487 return True;
490 if (sid_check_is_unix_groups(domain_sid)) {
491 if (*domain_name == NULL) {
492 *domain_name = talloc_strdup(
493 mem_ctx, unix_groups_domain_name());
495 for (i=0; i<num_rids; i++) {
496 (*names)[i] = talloc_strdup(
497 (*names), gidtoname(rids[i]));
498 (*types)[i] = SID_NAME_DOM_GRP;
500 return True;
503 return winbind_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
504 domain_name, *names, *types);
508 * Is the SID a domain as such? If yes, lookup its name.
511 static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
512 const char **name)
514 const char *tmp;
515 enum SID_NAME_USE type;
517 if (sid_check_is_domain(sid)) {
518 *name = talloc_strdup(mem_ctx, get_global_sam_name());
519 return True;
522 if (sid_check_is_builtin(sid)) {
523 *name = talloc_strdup(mem_ctx, builtin_domain_name());
524 return True;
527 if (sid_check_is_wellknown_domain(sid, &tmp)) {
528 *name = talloc_strdup(mem_ctx, tmp);
529 return True;
532 if (sid->num_auths != 4) {
533 /* This can't be a domain */
534 return False;
537 if (IS_DC) {
538 uint32 i, num_domains;
539 struct trustdom_info **domains;
541 /* This is relatively expensive, but it happens only on DCs
542 * and for SIDs that have 4 sub-authorities and thus look like
543 * domains */
545 if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx,
546 &num_domains,
547 &domains))) {
548 return False;
551 for (i=0; i<num_domains; i++) {
552 if (sid_equal(sid, &domains[i]->sid)) {
553 *name = talloc_strdup(mem_ctx,
554 domains[i]->name);
555 return True;
558 return False;
561 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
562 (type == SID_NAME_DOMAIN)) {
563 *name = tmp;
564 return True;
567 return False;
571 * This tries to implement the rather weird rules for the lsa_lookup level
572 * parameter.
574 * This is as close as we can get to what W2k3 does. With this we survive the
575 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
576 * different, but I assume that's just being too liberal. For example, W2k3
577 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
578 * whereas NT4 does the same as level 1 (I think). I did not fully test that
579 * with NT4, this is what w2k3 does.
581 * Level 1: Ask everywhere
582 * Level 2: Ask domain and trusted domains, no builtin and wkn
583 * Level 3: Only ask domain
584 * Level 4: W2k3ad: Only ask AD trusts
585 * Level 5: Don't lookup anything
586 * Level 6: Like 4
589 static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
591 int ret = False;
593 switch(level) {
594 case 1:
595 ret = True;
596 break;
597 case 2:
598 ret = (!sid_check_is_builtin(sid) &&
599 !sid_check_is_wellknown_domain(sid, NULL));
600 break;
601 case 3:
602 case 4:
603 case 6:
604 ret = sid_check_is_domain(sid);
605 break;
606 case 5:
607 ret = False;
608 break;
611 DEBUG(10, ("%s SID %s in level %d\n",
612 ret ? "Accepting" : "Rejecting",
613 sid_string_static(sid), level));
614 return ret;
618 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
619 * references to domains, it is explicitly made for this.
621 * This attempts to be as efficient as possible: It collects all SIDs
622 * belonging to a domain and hands them in bulk to the appropriate lookup
623 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
624 * *hugely* from this. Winbind is going to be extended with a lookup_rids
625 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
626 * appropriate DC.
629 NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
630 const DOM_SID **sids, int level,
631 struct lsa_dom_info **ret_domains,
632 struct lsa_name_info **ret_names)
634 TALLOC_CTX *tmp_ctx;
635 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
636 struct lsa_name_info *name_infos;
637 struct lsa_dom_info *dom_infos;
639 int i, j;
641 tmp_ctx = talloc_new(mem_ctx);
642 if (tmp_ctx == NULL) {
643 DEBUG(0, ("talloc_new failed\n"));
644 return NT_STATUS_NO_MEMORY;
647 name_infos = TALLOC_ARRAY(tmp_ctx, struct lsa_name_info, num_sids);
648 dom_infos = TALLOC_ZERO_ARRAY(tmp_ctx, struct lsa_dom_info,
649 MAX_REF_DOMAINS);
650 if ((name_infos == NULL) || (dom_infos == NULL)) {
651 result = NT_STATUS_NO_MEMORY;
652 goto done;
655 /* First build up the data structures:
657 * dom_infos is a list of domains referenced in the list of
658 * SIDs. Later we will walk the list of domains and look up the RIDs
659 * in bulk.
661 * name_infos is a shadow-copy of the SIDs array to collect the real
662 * data.
664 * dom_info->idxs is an index into the name_infos array. The
665 * difficulty we have here is that we need to keep the SIDs the client
666 * asked for in the same order for the reply
669 for (i=0; i<num_sids; i++) {
670 DOM_SID sid;
671 uint32 rid;
672 const char *domain_name = NULL;
674 sid_copy(&sid, sids[i]);
675 name_infos[i].type = SID_NAME_USE_NONE;
677 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
678 /* We can't push that through the normal lookup
679 * process, as this would reference illegal
680 * domains.
682 * For example S-1-5-32 would end up referencing
683 * domain S-1-5- with RID 32 which is clearly wrong.
685 if (domain_name == NULL) {
686 result = NT_STATUS_NO_MEMORY;
687 goto done;
690 name_infos[i].rid = 0;
691 name_infos[i].type = SID_NAME_DOMAIN;
692 name_infos[i].name = NULL;
694 if (sid_check_is_builtin(&sid)) {
695 /* Yes, W2k3 returns "BUILTIN" both as domain
696 * and name here */
697 name_infos[i].name = talloc_strdup(
698 name_infos, builtin_domain_name());
699 if (name_infos[i].name == NULL) {
700 result = NT_STATUS_NO_MEMORY;
701 goto done;
704 } else {
705 /* This is a normal SID with rid component */
706 if (!sid_split_rid(&sid, &rid)) {
707 result = NT_STATUS_INVALID_PARAMETER;
708 goto done;
712 if (!check_dom_sid_to_level(&sid, level)) {
713 name_infos[i].rid = 0;
714 name_infos[i].type = SID_NAME_UNKNOWN;
715 name_infos[i].name = NULL;
716 continue;
719 for (j=0; j<MAX_REF_DOMAINS; j++) {
720 if (!dom_infos[j].valid) {
721 break;
723 if (sid_equal(&sid, &dom_infos[j].sid)) {
724 break;
728 if (j == MAX_REF_DOMAINS) {
729 /* TODO: What's the right error message here? */
730 result = NT_STATUS_NONE_MAPPED;
731 goto done;
734 if (!dom_infos[j].valid) {
735 /* We found a domain not yet referenced, create a new
736 * ref. */
737 dom_infos[j].valid = True;
738 sid_copy(&dom_infos[j].sid, &sid);
740 if (domain_name != NULL) {
741 /* This name was being found above in the case
742 * when we found a domain SID */
743 dom_infos[j].name =
744 talloc_steal(dom_infos, domain_name);
745 } else {
746 /* lookup_rids will take care of this */
747 dom_infos[j].name = NULL;
751 name_infos[i].dom_idx = j;
753 if (name_infos[i].type == SID_NAME_USE_NONE) {
754 name_infos[i].rid = rid;
756 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
757 &dom_infos[j].num_idxs);
759 if (dom_infos[j].idxs == NULL) {
760 result = NT_STATUS_NO_MEMORY;
761 goto done;
766 /* Iterate over the domains found */
768 for (i=0; i<MAX_REF_DOMAINS; i++) {
769 uint32_t *rids;
770 const char **names;
771 enum SID_NAME_USE *types;
772 struct lsa_dom_info *dom = &dom_infos[i];
774 if (!dom->valid) {
775 /* No domains left, we're done */
776 break;
779 rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs);
781 if (rids == NULL) {
782 result = NT_STATUS_NO_MEMORY;
783 goto done;
786 for (j=0; j<dom->num_idxs; j++) {
787 rids[j] = name_infos[dom->idxs[j]].rid;
790 if (!lookup_rids(tmp_ctx, &dom->sid,
791 dom->num_idxs, rids, &dom->name,
792 &names, &types)) {
793 result = NT_STATUS_NO_MEMORY;
794 goto done;
797 talloc_steal(dom_infos, dom->name);
799 for (j=0; j<dom->num_idxs; j++) {
800 int idx = dom->idxs[j];
801 name_infos[idx].type = types[j];
802 if (types[j] != SID_NAME_UNKNOWN) {
803 name_infos[idx].name =
804 talloc_steal(name_infos, names[j]);
805 } else {
806 name_infos[idx].name = NULL;
811 *ret_domains = talloc_steal(mem_ctx, dom_infos);
812 *ret_names = talloc_steal(mem_ctx, name_infos);
813 result = NT_STATUS_OK;
815 done:
816 TALLOC_FREE(tmp_ctx);
817 return result;
820 /*****************************************************************
821 *THE CANONICAL* convert SID to name function.
822 *****************************************************************/
824 BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
825 const char **ret_domain, const char **ret_name,
826 enum SID_NAME_USE *ret_type)
828 struct lsa_dom_info *domain;
829 struct lsa_name_info *name;
830 TALLOC_CTX *tmp_ctx;
831 BOOL ret = False;
833 tmp_ctx = talloc_new(mem_ctx);
835 if (tmp_ctx == NULL) {
836 DEBUG(0, ("talloc_new failed\n"));
837 return False;
840 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
841 &domain, &name))) {
842 goto done;
845 if (name->type == SID_NAME_UNKNOWN) {
846 goto done;
849 if (ret_domain != NULL) {
850 *ret_domain = talloc_steal(mem_ctx, domain->name);
853 if (ret_name != NULL) {
854 *ret_name = talloc_steal(mem_ctx, name->name);
857 if (ret_type != NULL) {
858 *ret_type = name->type;
861 ret = True;
863 done:
864 if (ret) {
865 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
866 sid_string_static(sid), domain->name,
867 name->name, name->type));
868 } else {
869 DEBUG(10, ("failed to lookup sid %s\n",
870 sid_string_static(sid)));
872 TALLOC_FREE(tmp_ctx);
873 return ret;
876 /*****************************************************************
877 Id mapping cache. This is to avoid Winbind mappings already
878 seen by smbd to be queried too frequently, keeping winbindd
879 busy, and blocking smbd while winbindd is busy with other
880 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
881 modified to use linked lists by jra.
882 *****************************************************************/
884 #define MAX_UID_SID_CACHE_SIZE 100
885 #define TURNOVER_UID_SID_CACHE_SIZE 10
886 #define MAX_GID_SID_CACHE_SIZE 100
887 #define TURNOVER_GID_SID_CACHE_SIZE 10
889 static size_t n_uid_sid_cache = 0;
890 static size_t n_gid_sid_cache = 0;
892 static struct uid_sid_cache {
893 struct uid_sid_cache *next, *prev;
894 uid_t uid;
895 DOM_SID sid;
896 enum SID_NAME_USE sidtype;
897 } *uid_sid_cache_head;
899 static struct gid_sid_cache {
900 struct gid_sid_cache *next, *prev;
901 gid_t gid;
902 DOM_SID sid;
903 enum SID_NAME_USE sidtype;
904 } *gid_sid_cache_head;
906 /*****************************************************************
907 Find a SID given a uid.
908 *****************************************************************/
910 static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
912 struct uid_sid_cache *pc;
914 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
915 if (pc->uid == uid) {
916 *psid = pc->sid;
917 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
918 (unsigned int)uid, sid_string_static(psid)));
919 DLIST_PROMOTE(uid_sid_cache_head, pc);
920 return True;
923 return False;
926 /*****************************************************************
927 Find a uid given a SID.
928 *****************************************************************/
930 static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
932 struct uid_sid_cache *pc;
934 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
935 if (sid_compare(&pc->sid, psid) == 0) {
936 *puid = pc->uid;
937 DEBUG(3,("fetch uid from cache %u -> %s\n",
938 (unsigned int)*puid, sid_string_static(psid)));
939 DLIST_PROMOTE(uid_sid_cache_head, pc);
940 return True;
943 return False;
946 /*****************************************************************
947 Store uid to SID mapping in cache.
948 *****************************************************************/
950 void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
952 struct uid_sid_cache *pc;
954 /* do not store SIDs in the "Unix Group" domain */
956 if ( sid_check_is_in_unix_users( psid ) )
957 return;
959 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
960 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
961 struct uid_sid_cache *pc_next;
962 size_t i;
964 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
966 for(; pc; pc = pc_next) {
967 pc_next = pc->next;
968 DLIST_REMOVE(uid_sid_cache_head,pc);
969 SAFE_FREE(pc);
970 n_uid_sid_cache--;
974 pc = SMB_MALLOC_P(struct uid_sid_cache);
975 if (!pc)
976 return;
977 pc->uid = uid;
978 sid_copy(&pc->sid, psid);
979 DLIST_ADD(uid_sid_cache_head, pc);
980 n_uid_sid_cache++;
983 /*****************************************************************
984 Find a SID given a gid.
985 *****************************************************************/
987 static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
989 struct gid_sid_cache *pc;
991 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
992 if (pc->gid == gid) {
993 *psid = pc->sid;
994 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
995 (unsigned int)gid, sid_string_static(psid)));
996 DLIST_PROMOTE(gid_sid_cache_head, pc);
997 return True;
1000 return False;
1003 /*****************************************************************
1004 Find a gid given a SID.
1005 *****************************************************************/
1007 static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1009 struct gid_sid_cache *pc;
1011 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1012 if (sid_compare(&pc->sid, psid) == 0) {
1013 *pgid = pc->gid;
1014 DEBUG(3,("fetch gid from cache %u -> %s\n",
1015 (unsigned int)*pgid, sid_string_static(psid)));
1016 DLIST_PROMOTE(gid_sid_cache_head, pc);
1017 return True;
1020 return False;
1023 /*****************************************************************
1024 Store gid to SID mapping in cache.
1025 *****************************************************************/
1027 void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1029 struct gid_sid_cache *pc;
1031 /* do not store SIDs in the "Unix Group" domain */
1033 if ( sid_check_is_in_unix_groups( psid ) )
1034 return;
1036 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1037 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1038 struct gid_sid_cache *pc_next;
1039 size_t i;
1041 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1043 for(; pc; pc = pc_next) {
1044 pc_next = pc->next;
1045 DLIST_REMOVE(gid_sid_cache_head,pc);
1046 SAFE_FREE(pc);
1047 n_gid_sid_cache--;
1051 pc = SMB_MALLOC_P(struct gid_sid_cache);
1052 if (!pc)
1053 return;
1054 pc->gid = gid;
1055 sid_copy(&pc->sid, psid);
1056 DLIST_ADD(gid_sid_cache_head, pc);
1058 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1059 sid_string_static(psid)));
1061 n_gid_sid_cache++;
1064 /*****************************************************************
1065 *THE CANONICAL* convert uid_t to SID function.
1066 *****************************************************************/
1068 void uid_to_sid(DOM_SID *psid, uid_t uid)
1070 uid_t low, high;
1071 uint32 rid;
1073 ZERO_STRUCTP(psid);
1075 if (fetch_sid_from_uid_cache(psid, uid))
1076 return;
1078 if (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high) &&
1079 winbind_uid_to_sid(psid, uid)) {
1081 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
1082 (unsigned int)uid, sid_string_static(psid)));
1083 goto done;
1086 if (pdb_uid_to_rid(uid, &rid)) {
1087 /* This is a mapped user */
1088 sid_copy(psid, get_global_sam_sid());
1089 sid_append_rid(psid, rid);
1090 goto done;
1093 /* This is an unmapped user */
1095 uid_to_unix_users_sid(uid, psid);
1097 done:
1098 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
1099 sid_string_static(psid)));
1101 store_uid_sid_cache(psid, uid);
1102 return;
1105 /*****************************************************************
1106 *THE CANONICAL* convert gid_t to SID function.
1107 *****************************************************************/
1109 void gid_to_sid(DOM_SID *psid, gid_t gid)
1111 gid_t low, high;
1113 ZERO_STRUCTP(psid);
1115 if (fetch_sid_from_gid_cache(psid, gid))
1116 return;
1118 if (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high) &&
1119 winbind_gid_to_sid(psid, gid)) {
1121 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
1122 (unsigned int)gid, sid_string_static(psid)));
1123 goto done;
1126 if (pdb_gid_to_sid(gid, psid)) {
1127 /* This is a mapped group */
1128 goto done;
1131 /* This is an unmapped group */
1133 gid_to_unix_groups_sid(gid, psid);
1135 done:
1136 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
1137 sid_string_static(psid)));
1139 store_gid_sid_cache(psid, gid);
1140 return;
1143 /*****************************************************************
1144 *THE CANONICAL* convert SID to uid function.
1145 *****************************************************************/
1147 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1149 enum SID_NAME_USE type;
1150 uint32 rid;
1151 gid_t gid;
1153 if (fetch_uid_from_cache(puid, psid))
1154 return True;
1156 if (fetch_gid_from_cache(&gid, psid)) {
1157 return False;
1160 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1161 uid_t uid = rid;
1162 *puid = uid;
1163 goto done;
1166 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1167 union unid_t id;
1169 if (pdb_sid_to_id(psid, &id, &type)) {
1170 if (type != SID_NAME_USER) {
1171 DEBUG(5, ("sid %s is a %s, expected a user\n",
1172 sid_string_static(psid),
1173 sid_type_lookup(type)));
1174 return False;
1176 *puid = id.uid;
1177 goto done;
1180 /* This was ours, but it was not mapped. Fail */
1182 return False;
1185 if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1187 if (type != SID_NAME_USER) {
1188 DEBUG(10, ("sid_to_uid: sid %s is a %s\n",
1189 sid_string_static(psid),
1190 sid_type_lookup(type)));
1191 return False;
1194 if (!winbind_sid_to_uid(puid, psid)) {
1195 DEBUG(5, ("sid_to_uid: winbind failed to allocate a "
1196 "new uid for sid %s\n",
1197 sid_string_static(psid)));
1198 return False;
1200 goto done;
1203 /* TODO: Here would be the place to allocate both a gid and a uid for
1204 * the SID in question */
1206 return False;
1208 done:
1209 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
1210 (unsigned int)*puid ));
1212 store_uid_sid_cache(psid, *puid);
1213 return True;
1216 /*****************************************************************
1217 *THE CANONICAL* convert SID to gid function.
1218 Group mapping is used for gids that maps to Wellknown SIDs
1219 *****************************************************************/
1221 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1223 uint32 rid;
1224 GROUP_MAP map;
1225 union unid_t id;
1226 enum SID_NAME_USE type;
1227 uid_t uid;
1229 if (fetch_gid_from_cache(pgid, psid))
1230 return True;
1232 if (fetch_uid_from_cache(&uid, psid))
1233 return False;
1235 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1236 gid_t gid = rid;
1237 *pgid = gid;
1238 goto done;
1241 if ((sid_check_is_in_builtin(psid) ||
1242 sid_check_is_in_wellknown_domain(psid))) {
1243 if (pdb_getgrsid(&map, *psid)) {
1244 *pgid = map.gid;
1245 goto done;
1247 return False;
1250 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1251 if (pdb_sid_to_id(psid, &id, &type)) {
1252 if ((type != SID_NAME_DOM_GRP) &&
1253 (type != SID_NAME_ALIAS)) {
1254 DEBUG(5, ("sid %s is a %s, expected a group\n",
1255 sid_string_static(psid),
1256 sid_type_lookup(type)));
1257 return False;
1259 *pgid = id.gid;
1260 goto done;
1263 /* This was ours, but it was not mapped. Fail */
1265 return False;
1268 if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1269 DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, "
1270 "then winbind)\n", sid_string_static(psid)));
1272 return False;
1275 /* winbindd knows it; Ensure this is a group sid */
1277 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
1278 (type != SID_NAME_WKN_GRP)) {
1279 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is "
1280 "a %s\n", sid_type_lookup(type)));
1281 return False;
1284 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
1285 or we are dead in the water */
1287 if ( !winbind_sid_to_gid(pgid, psid) ) {
1288 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid "
1289 "for sid %s\n", sid_string_static(psid)));
1290 return False;
1293 done:
1294 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
1295 (unsigned int)*pgid ));
1297 store_gid_sid_cache(psid, *pgid);
1299 return True;