Samba 3: added Samba 3.0.24 sources
[tomato.git] / release / src / router / samba3 / source / passdb / lookup_sid.c
blob7082cd3abd40ba2c9bef7c541964e00766eb6fec
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_uid_only();
425 result = pdb_lookup_rids(domain_sid, num_rids, rids,
426 *names, *types);
427 unbecome_root_uid_only();
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;
1072 BOOL ret;
1074 ZERO_STRUCTP(psid);
1076 if (fetch_sid_from_uid_cache(psid, uid))
1077 return;
1079 if ((lp_winbind_trusted_domains_only() ||
1080 (lp_idmap_uid(&low, &high) && (uid >= low) && (uid <= high))) &&
1081 winbind_uid_to_sid(psid, uid)) {
1083 DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
1084 (unsigned int)uid, sid_string_static(psid)));
1085 goto done;
1088 become_root_uid_only();
1089 ret = pdb_uid_to_rid(uid, &rid);
1090 unbecome_root_uid_only();
1092 if (ret) {
1093 /* This is a mapped user */
1094 sid_copy(psid, get_global_sam_sid());
1095 sid_append_rid(psid, rid);
1096 goto done;
1099 /* This is an unmapped user */
1101 uid_to_unix_users_sid(uid, psid);
1103 done:
1104 DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid,
1105 sid_string_static(psid)));
1107 store_uid_sid_cache(psid, uid);
1108 return;
1111 /*****************************************************************
1112 *THE CANONICAL* convert gid_t to SID function.
1113 *****************************************************************/
1115 void gid_to_sid(DOM_SID *psid, gid_t gid)
1117 BOOL ret;
1118 gid_t low, high;
1120 ZERO_STRUCTP(psid);
1122 if (fetch_sid_from_gid_cache(psid, gid))
1123 return;
1125 if ((lp_winbind_trusted_domains_only() ||
1126 (lp_idmap_gid(&low, &high) && (gid >= low) && (gid <= high))) &&
1127 winbind_gid_to_sid(psid, gid)) {
1129 DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
1130 (unsigned int)gid, sid_string_static(psid)));
1131 goto done;
1134 become_root_uid_only();
1135 ret = pdb_gid_to_sid(gid, psid);
1136 unbecome_root_uid_only();
1138 if (ret) {
1139 /* This is a mapped group */
1140 goto done;
1143 /* This is an unmapped group */
1145 gid_to_unix_groups_sid(gid, psid);
1147 done:
1148 DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid,
1149 sid_string_static(psid)));
1151 store_gid_sid_cache(psid, gid);
1152 return;
1155 /*****************************************************************
1156 *THE CANONICAL* convert SID to uid function.
1157 *****************************************************************/
1159 BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1161 enum SID_NAME_USE type;
1162 uint32 rid;
1163 gid_t gid;
1165 if (fetch_uid_from_cache(puid, psid))
1166 return True;
1168 if (fetch_gid_from_cache(&gid, psid)) {
1169 return False;
1172 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1173 uid_t uid = rid;
1174 *puid = uid;
1175 goto done;
1178 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1179 union unid_t id;
1180 BOOL ret;
1182 become_root_uid_only();
1183 ret = pdb_sid_to_id(psid, &id, &type);
1184 unbecome_root_uid_only();
1186 if (ret) {
1187 if (type != SID_NAME_USER) {
1188 DEBUG(5, ("sid %s is a %s, expected a user\n",
1189 sid_string_static(psid),
1190 sid_type_lookup(type)));
1191 return False;
1193 *puid = id.uid;
1194 goto done;
1197 /* This was ours, but it was not mapped. Fail */
1199 return False;
1202 if (winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1204 if (type != SID_NAME_USER) {
1205 DEBUG(10, ("sid_to_uid: sid %s is a %s\n",
1206 sid_string_static(psid),
1207 sid_type_lookup(type)));
1208 return False;
1211 if (!winbind_sid_to_uid(puid, psid)) {
1212 DEBUG(5, ("sid_to_uid: winbind failed to allocate a "
1213 "new uid for sid %s\n",
1214 sid_string_static(psid)));
1215 return False;
1217 goto done;
1220 /* TODO: Here would be the place to allocate both a gid and a uid for
1221 * the SID in question */
1223 return False;
1225 done:
1226 DEBUG(10,("sid_to_uid: %s -> %u\n", sid_string_static(psid),
1227 (unsigned int)*puid ));
1229 store_uid_sid_cache(psid, *puid);
1230 return True;
1233 /*****************************************************************
1234 *THE CANONICAL* convert SID to gid function.
1235 Group mapping is used for gids that maps to Wellknown SIDs
1236 *****************************************************************/
1238 BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1240 uint32 rid;
1241 GROUP_MAP map;
1242 union unid_t id;
1243 enum SID_NAME_USE type;
1244 uid_t uid;
1246 if (fetch_gid_from_cache(pgid, psid))
1247 return True;
1249 if (fetch_uid_from_cache(&uid, psid))
1250 return False;
1252 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1253 gid_t gid = rid;
1254 *pgid = gid;
1255 goto done;
1258 if ((sid_check_is_in_builtin(psid) ||
1259 sid_check_is_in_wellknown_domain(psid))) {
1260 BOOL ret;
1262 become_root_uid_only();
1263 ret = pdb_getgrsid(&map, *psid);
1264 unbecome_root_uid_only();
1266 if (ret) {
1267 *pgid = map.gid;
1268 goto done;
1270 return False;
1273 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1274 BOOL ret;
1276 become_root_uid_only();
1277 ret = pdb_sid_to_id(psid, &id, &type);
1278 unbecome_root_uid_only();
1280 if (ret) {
1281 if ((type != SID_NAME_DOM_GRP) &&
1282 (type != SID_NAME_ALIAS)) {
1283 DEBUG(5, ("sid %s is a %s, expected a group\n",
1284 sid_string_static(psid),
1285 sid_type_lookup(type)));
1286 return False;
1288 *pgid = id.gid;
1289 goto done;
1292 /* This was ours, but it was not mapped. Fail */
1294 return False;
1297 if (!winbind_lookup_sid(NULL, psid, NULL, NULL, &type)) {
1298 DEBUG(11,("sid_to_gid: no one knows the SID %s (tried local, "
1299 "then winbind)\n", sid_string_static(psid)));
1301 return False;
1304 /* winbindd knows it; Ensure this is a group sid */
1306 if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
1307 (type != SID_NAME_WKN_GRP)) {
1308 DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is "
1309 "a %s\n", sid_type_lookup(type)));
1310 return False;
1313 /* winbindd knows it and it is a type of group; sid_to_gid must succeed
1314 or we are dead in the water */
1316 if ( !winbind_sid_to_gid(pgid, psid) ) {
1317 DEBUG(10,("sid_to_gid: winbind failed to allocate a new gid "
1318 "for sid %s\n", sid_string_static(psid)));
1319 return False;
1322 done:
1323 DEBUG(10,("sid_to_gid: %s -> %u\n", sid_string_static(psid),
1324 (unsigned int)*pgid ));
1326 store_gid_sid_cache(psid, *pgid);
1328 return True;