source: trunk-3.0/source/passdb/lookup_sid.c@ 101

Last change on this file since 101 was 39, checked in by Paul Smedley, 18 years ago

Upgrade source to 3.0.25a

File size: 36.0 KB
Line 
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
7
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.
12
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.
17
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.
21*/
22
23#include "includes.h"
24
25/*****************************************************************
26 Dissect a user-provided name into domain, name, sid and type.
27
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*****************************************************************/
32
33BOOL 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)
37{
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 lsa_SidType type;
45 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
46
47 if (tmp_ctx == NULL) {
48 DEBUG(0, ("talloc_new failed\n"));
49 return False;
50 }
51
52 p = strchr_m(full_name, '\\');
53
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);
61 }
62
63 DEBUG(10,("lookup_name: %s => %s (domain), %s (name)\n",
64 full_name, domain, name));
65
66 if ((domain == NULL) || (name == NULL)) {
67 DEBUG(0, ("talloc failed\n"));
68 TALLOC_FREE(tmp_ctx);
69 return False;
70 }
71
72 if (strequal(domain, get_global_sam_name())) {
73
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);
78 goto ok;
79 }
80 TALLOC_FREE(tmp_ctx);
81 return False;
82 }
83
84 if (strequal(domain, builtin_domain_name())) {
85
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;
91 goto ok;
92 }
93 TALLOC_FREE(tmp_ctx);
94 return False;
95 }
96
97 /* Try the explicit winbind lookup first, don't let it guess the
98 * domain yet at this point yet. This comes later. */
99
100 if ((domain[0] != '\0') &&
101 (winbind_lookup_name(domain, name, &sid, &type))) {
102 goto ok;
103 }
104
105 if (strequal(domain, unix_users_domain_name())) {
106 if (lookup_unix_user_name(name, &sid)) {
107 type = SID_NAME_USER;
108 goto ok;
109 }
110 TALLOC_FREE(tmp_ctx);
111 return False;
112 }
113
114 if (strequal(domain, unix_groups_domain_name())) {
115 if (lookup_unix_group_name(name, &sid)) {
116 type = SID_NAME_DOM_GRP;
117 goto ok;
118 }
119 TALLOC_FREE(tmp_ctx);
120 return False;
121 }
122
123 if ((domain[0] == '\0') && (!(flags & LOOKUP_NAME_ISOLATED))) {
124 TALLOC_FREE(tmp_ctx);
125 return False;
126 }
127
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 */
132
133 /* 1. well-known names */
134
135 if (lookup_wellknown_name(tmp_ctx, name, &sid, &domain)) {
136 type = SID_NAME_WKN_GRP;
137 goto ok;
138 }
139
140 /* 2. Builtin domain as such */
141
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;
147 goto ok;
148 }
149
150 /* 3. Account domain */
151
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);
156 return False;
157 }
158 /* Swap domain and name */
159 tmp = name; name = domain; domain = tmp;
160 type = SID_NAME_DOMAIN;
161 goto ok;
162 }
163
164 /* 4. Primary domain */
165
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);
170 return False;
171 }
172 /* Swap domain and name */
173 tmp = name; name = domain; domain = tmp;
174 type = SID_NAME_DOMAIN;
175 goto ok;
176 }
177
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 */
180
181 if (IS_DC && (secrets_fetch_trusted_domain_password(name, NULL,
182 &sid, NULL))) {
183 /* Swap domain and name */
184 tmp = name; name = domain; domain = tmp;
185 type = SID_NAME_DOMAIN;
186 goto ok;
187 }
188
189 /* 6. Builtin aliases */
190
191 if (lookup_builtin_name(name, &rid)) {
192 domain = talloc_strdup(tmp_ctx, builtin_domain_name());
193 sid_copy(&sid, &global_sid_Builtin);
194 sid_append_rid(&sid, rid);
195 type = SID_NAME_ALIAS;
196 goto ok;
197 }
198
199 /* 7. Local systems' SAM (DCs don't have a local SAM) */
200 /* 8. Primary SAM (On members, this is the domain) */
201
202 /* Both cases are done by looking at our passdb */
203
204 if (lookup_global_sam_name(name, flags, &rid, &type)) {
205 domain = talloc_strdup(tmp_ctx, get_global_sam_name());
206 sid_copy(&sid, get_global_sam_sid());
207 sid_append_rid(&sid, rid);
208 goto ok;
209 }
210
211 /* Now our local possibilities are exhausted. */
212
213 if (!(flags & LOOKUP_NAME_REMOTE)) {
214 TALLOC_FREE(tmp_ctx);
215 return False;
216 }
217
218 /* If we are not a DC, we have to ask in our primary domain. Let
219 * winbind do that. */
220
221 if (!IS_DC &&
222 (winbind_lookup_name(lp_workgroup(), name, &sid, &type))) {
223 domain = talloc_strdup(tmp_ctx, lp_workgroup());
224 goto ok;
225 }
226
227 /* 9. Trusted domains */
228
229 /* If we're a DC we have to ask all trusted DC's. Winbind does not do
230 * that (yet), but give it a chance. */
231
232 if (IS_DC && winbind_lookup_name("", name, &sid, &type)) {
233 DOM_SID dom_sid;
234 uint32 tmp_rid;
235 enum lsa_SidType domain_type;
236
237 if (type == SID_NAME_DOMAIN) {
238 /* Swap name and type */
239 tmp = name; name = domain; domain = tmp;
240 goto ok;
241 }
242
243 /* Here we have to cope with a little deficiency in the
244 * winbind API: We have to ask it again for the name of the
245 * domain it figured out itself. Maybe fix that later... */
246
247 sid_copy(&dom_sid, &sid);
248 sid_split_rid(&dom_sid, &tmp_rid);
249
250 if (!winbind_lookup_sid(tmp_ctx, &dom_sid, &domain, NULL,
251 &domain_type) ||
252 (domain_type != SID_NAME_DOMAIN)) {
253 DEBUG(2, ("winbind could not find the domain's name "
254 "it just looked up for us\n"));
255 TALLOC_FREE(tmp_ctx);
256 return False;
257 }
258 goto ok;
259 }
260
261 /* 10. Don't translate */
262
263 /* 11. Ok, windows would end here. Samba has two more options:
264 Unmapped users and unmapped groups */
265
266 if (lookup_unix_user_name(name, &sid)) {
267 domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
268 type = SID_NAME_USER;
269 goto ok;
270 }
271
272 if (lookup_unix_group_name(name, &sid)) {
273 domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
274 type = SID_NAME_DOM_GRP;
275 goto ok;
276 }
277
278 /*
279 * Ok, all possibilities tried. Fail.
280 */
281
282 TALLOC_FREE(tmp_ctx);
283 return False;
284
285 ok:
286 if ((domain == NULL) || (name == NULL)) {
287 DEBUG(0, ("talloc failed\n"));
288 TALLOC_FREE(tmp_ctx);
289 return False;
290 }
291
292 /*
293 * Hand over the results to the talloc context we've been given.
294 */
295
296 if ((ret_name != NULL) &&
297 !(*ret_name = talloc_strdup(mem_ctx, name))) {
298 DEBUG(0, ("talloc failed\n"));
299 TALLOC_FREE(tmp_ctx);
300 return False;
301 }
302
303 if (ret_domain != NULL) {
304 char *tmp_dom;
305 if (!(tmp_dom = talloc_strdup(mem_ctx, domain))) {
306 DEBUG(0, ("talloc failed\n"));
307 TALLOC_FREE(tmp_ctx);
308 return False;
309 }
310 strupper_m(tmp_dom);
311 *ret_domain = tmp_dom;
312 }
313
314 if (ret_sid != NULL) {
315 sid_copy(ret_sid, &sid);
316 }
317
318 if (ret_type != NULL) {
319 *ret_type = type;
320 }
321
322 TALLOC_FREE(tmp_ctx);
323 return True;
324}
325
326/************************************************************************
327 Names from smb.conf can be unqualified. eg. valid users = foo
328 These names should never map to a remote name. Try global_sam_name()\foo,
329 and then "Unix Users"\foo (or "Unix Groups"\foo).
330************************************************************************/
331
332BOOL lookup_name_smbconf(TALLOC_CTX *mem_ctx,
333 const char *full_name, int flags,
334 const char **ret_domain, const char **ret_name,
335 DOM_SID *ret_sid, enum lsa_SidType *ret_type)
336{
337 char *qualified_name;
338 const char *p;
339
340 /* NB. No winbindd_separator here as lookup_name needs \\' */
341 if ((p = strchr_m(full_name, *lp_winbind_separator())) != NULL) {
342
343 /* The name is already qualified with a domain. */
344
345 if (*lp_winbind_separator() != '\\') {
346 char *tmp;
347
348 /* lookup_name() needs '\\' as a separator */
349
350 tmp = talloc_strdup(mem_ctx, full_name);
351 if (!tmp) {
352 return False;
353 }
354 tmp[p - full_name] = '\\';
355 full_name = tmp;
356 }
357
358 return lookup_name(mem_ctx, full_name, flags,
359 ret_domain, ret_name,
360 ret_sid, ret_type);
361 }
362
363 /* Try with our own SAM name. */
364 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
365 get_global_sam_name(),
366 full_name );
367 if (!qualified_name) {
368 return False;
369 }
370
371 if (lookup_name(mem_ctx, qualified_name, flags,
372 ret_domain, ret_name,
373 ret_sid, ret_type)) {
374 return True;
375 }
376
377 /* Finally try with "Unix Users" or "Unix Group" */
378 qualified_name = talloc_asprintf(mem_ctx, "%s\\%s",
379 flags & LOOKUP_NAME_GROUP ?
380 unix_groups_domain_name() :
381 unix_users_domain_name(),
382 full_name );
383 if (!qualified_name) {
384 return False;
385 }
386
387 return lookup_name(mem_ctx, qualified_name, flags,
388 ret_domain, ret_name,
389 ret_sid, ret_type);
390}
391
392static BOOL wb_lookup_rids(TALLOC_CTX *mem_ctx,
393 const DOM_SID *domain_sid,
394 int num_rids, uint32 *rids,
395 const char **domain_name,
396 const char **names, enum lsa_SidType *types)
397{
398 int i;
399 const char **my_names;
400 enum lsa_SidType *my_types;
401 TALLOC_CTX *tmp_ctx;
402
403 if (!(tmp_ctx = talloc_init("wb_lookup_rids"))) {
404 return False;
405 }
406
407 if (!winbind_lookup_rids(tmp_ctx, domain_sid, num_rids, rids,
408 domain_name, &my_names, &my_types)) {
409 *domain_name = "";
410 for (i=0; i<num_rids; i++) {
411 names[i] = "";
412 types[i] = SID_NAME_UNKNOWN;
413 }
414 TALLOC_FREE(tmp_ctx);
415 return True;
416 }
417
418 if (!(*domain_name = talloc_strdup(mem_ctx, *domain_name))) {
419 TALLOC_FREE(tmp_ctx);
420 return False;
421 }
422
423 /*
424 * winbind_lookup_rids allocates its own array. We've been given the
425 * array, so copy it over
426 */
427
428 for (i=0; i<num_rids; i++) {
429 if (my_names[i] == NULL) {
430 TALLOC_FREE(tmp_ctx);
431 return False;
432 }
433 if (!(names[i] = talloc_strdup(names, my_names[i]))) {
434 TALLOC_FREE(tmp_ctx);
435 return False;
436 }
437 types[i] = my_types[i];
438 }
439 TALLOC_FREE(tmp_ctx);
440 return True;
441}
442
443static BOOL lookup_rids(TALLOC_CTX *mem_ctx, const DOM_SID *domain_sid,
444 int num_rids, uint32_t *rids,
445 const char **domain_name,
446 const char ***names, enum lsa_SidType **types)
447{
448 int i;
449
450 if (num_rids) {
451 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
452 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
453
454 if ((*names == NULL) || (*types == NULL)) {
455 return False;
456 }
457 } else {
458 *names = NULL;
459 *types = NULL;
460 }
461
462 if (sid_check_is_domain(domain_sid)) {
463 NTSTATUS result;
464
465 if (*domain_name == NULL) {
466 *domain_name = talloc_strdup(
467 mem_ctx, get_global_sam_name());
468 }
469
470 if (*domain_name == NULL) {
471 return False;
472 }
473
474 become_root();
475 result = pdb_lookup_rids(domain_sid, num_rids, rids,
476 *names, *types);
477 unbecome_root();
478
479 return (NT_STATUS_IS_OK(result) ||
480 NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) ||
481 NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED));
482 }
483
484 if (sid_check_is_builtin(domain_sid)) {
485
486 if (*domain_name == NULL) {
487 *domain_name = talloc_strdup(
488 mem_ctx, builtin_domain_name());
489 }
490
491 if (*domain_name == NULL) {
492 return False;
493 }
494
495 for (i=0; i<num_rids; i++) {
496 if (lookup_builtin_rid(*names, rids[i],
497 &(*names)[i])) {
498 if ((*names)[i] == NULL) {
499 return False;
500 }
501 (*types)[i] = SID_NAME_ALIAS;
502 } else {
503 (*types)[i] = SID_NAME_UNKNOWN;
504 }
505 }
506 return True;
507 }
508
509 if (sid_check_is_wellknown_domain(domain_sid, NULL)) {
510 for (i=0; i<num_rids; i++) {
511 DOM_SID sid;
512 sid_copy(&sid, domain_sid);
513 sid_append_rid(&sid, rids[i]);
514 if (lookup_wellknown_sid(mem_ctx, &sid,
515 domain_name, &(*names)[i])) {
516 if ((*names)[i] == NULL) {
517 return False;
518 }
519 (*types)[i] = SID_NAME_WKN_GRP;
520 } else {
521 (*types)[i] = SID_NAME_UNKNOWN;
522 }
523 }
524 return True;
525 }
526
527 if (sid_check_is_unix_users(domain_sid)) {
528 if (*domain_name == NULL) {
529 *domain_name = talloc_strdup(
530 mem_ctx, unix_users_domain_name());
531 }
532 for (i=0; i<num_rids; i++) {
533 (*names)[i] = talloc_strdup(
534 (*names), uidtoname(rids[i]));
535 (*types)[i] = SID_NAME_USER;
536 }
537 return True;
538 }
539
540 if (sid_check_is_unix_groups(domain_sid)) {
541 if (*domain_name == NULL) {
542 *domain_name = talloc_strdup(
543 mem_ctx, unix_groups_domain_name());
544 }
545 for (i=0; i<num_rids; i++) {
546 (*names)[i] = talloc_strdup(
547 (*names), gidtoname(rids[i]));
548 (*types)[i] = SID_NAME_DOM_GRP;
549 }
550 return True;
551 }
552
553 return wb_lookup_rids(mem_ctx, domain_sid, num_rids, rids,
554 domain_name, *names, *types);
555}
556
557/*
558 * Is the SID a domain as such? If yes, lookup its name.
559 */
560
561static BOOL lookup_as_domain(const DOM_SID *sid, TALLOC_CTX *mem_ctx,
562 const char **name)
563{
564 const char *tmp;
565 enum lsa_SidType type;
566
567 if (sid_check_is_domain(sid)) {
568 *name = talloc_strdup(mem_ctx, get_global_sam_name());
569 return True;
570 }
571
572 if (sid_check_is_builtin(sid)) {
573 *name = talloc_strdup(mem_ctx, builtin_domain_name());
574 return True;
575 }
576
577 if (sid_check_is_wellknown_domain(sid, &tmp)) {
578 *name = talloc_strdup(mem_ctx, tmp);
579 return True;
580 }
581
582 if (sid->num_auths != 4) {
583 /* This can't be a domain */
584 return False;
585 }
586
587 if (IS_DC) {
588 uint32 i, num_domains;
589 struct trustdom_info **domains;
590
591 /* This is relatively expensive, but it happens only on DCs
592 * and for SIDs that have 4 sub-authorities and thus look like
593 * domains */
594
595 if (!NT_STATUS_IS_OK(secrets_trusted_domains(mem_ctx,
596 &num_domains,
597 &domains))) {
598 return False;
599 }
600
601 for (i=0; i<num_domains; i++) {
602 if (sid_equal(sid, &domains[i]->sid)) {
603 *name = talloc_strdup(mem_ctx,
604 domains[i]->name);
605 return True;
606 }
607 }
608 return False;
609 }
610
611 if (winbind_lookup_sid(mem_ctx, sid, &tmp, NULL, &type) &&
612 (type == SID_NAME_DOMAIN)) {
613 *name = tmp;
614 return True;
615 }
616
617 return False;
618}
619
620/*
621 * This tries to implement the rather weird rules for the lsa_lookup level
622 * parameter.
623 *
624 * This is as close as we can get to what W2k3 does. With this we survive the
625 * RPC-LSALOOKUP samba4 test as of 2006-01-08. NT4 as a PDC is a bit more
626 * different, but I assume that's just being too liberal. For example, W2k3
627 * replies to everything else but the levels 1-6 with INVALID_PARAMETER
628 * whereas NT4 does the same as level 1 (I think). I did not fully test that
629 * with NT4, this is what w2k3 does.
630 *
631 * Level 1: Ask everywhere
632 * Level 2: Ask domain and trusted domains, no builtin and wkn
633 * Level 3: Only ask domain
634 * Level 4: W2k3ad: Only ask AD trusts
635 * Level 5: Don't lookup anything
636 * Level 6: Like 4
637 */
638
639static BOOL check_dom_sid_to_level(const DOM_SID *sid, int level)
640{
641 int ret = False;
642
643 switch(level) {
644 case 1:
645 ret = True;
646 break;
647 case 2:
648 ret = (!sid_check_is_builtin(sid) &&
649 !sid_check_is_wellknown_domain(sid, NULL));
650 break;
651 case 3:
652 case 4:
653 case 6:
654 ret = sid_check_is_domain(sid);
655 break;
656 case 5:
657 ret = False;
658 break;
659 }
660
661 DEBUG(10, ("%s SID %s in level %d\n",
662 ret ? "Accepting" : "Rejecting",
663 sid_string_static(sid), level));
664 return ret;
665}
666
667/*
668 * Lookup a bunch of SIDs. This is modeled after lsa_lookup_sids with
669 * references to domains, it is explicitly made for this.
670 *
671 * This attempts to be as efficient as possible: It collects all SIDs
672 * belonging to a domain and hands them in bulk to the appropriate lookup
673 * function. In particular pdb_lookup_rids with ldapsam_trusted benefits
674 * *hugely* from this. Winbind is going to be extended with a lookup_rids
675 * interface as well, so on a DC we can do a bulk lsa_lookuprids to the
676 * appropriate DC.
677 */
678
679NTSTATUS lookup_sids(TALLOC_CTX *mem_ctx, int num_sids,
680 const DOM_SID **sids, int level,
681 struct lsa_dom_info **ret_domains,
682 struct lsa_name_info **ret_names)
683{
684 TALLOC_CTX *tmp_ctx;
685 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
686 struct lsa_name_info *name_infos;
687 struct lsa_dom_info *dom_infos = NULL;
688
689 int i, j;
690
691 if (!(tmp_ctx = talloc_new(mem_ctx))) {
692 DEBUG(0, ("talloc_new failed\n"));
693 return NT_STATUS_NO_MEMORY;
694 }
695
696 if (num_sids) {
697 name_infos = TALLOC_ARRAY(mem_ctx, struct lsa_name_info, num_sids);
698 if (name_infos == NULL) {
699 result = NT_STATUS_NO_MEMORY;
700 goto fail;
701 }
702 } else {
703 name_infos = NULL;
704 }
705
706 dom_infos = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_dom_info,
707 MAX_REF_DOMAINS);
708 if (dom_infos == NULL) {
709 result = NT_STATUS_NO_MEMORY;
710 goto fail;
711 }
712
713 /* First build up the data structures:
714 *
715 * dom_infos is a list of domains referenced in the list of
716 * SIDs. Later we will walk the list of domains and look up the RIDs
717 * in bulk.
718 *
719 * name_infos is a shadow-copy of the SIDs array to collect the real
720 * data.
721 *
722 * dom_info->idxs is an index into the name_infos array. The
723 * difficulty we have here is that we need to keep the SIDs the client
724 * asked for in the same order for the reply
725 */
726
727 for (i=0; i<num_sids; i++) {
728 DOM_SID sid;
729 uint32 rid;
730 const char *domain_name = NULL;
731
732 sid_copy(&sid, sids[i]);
733 name_infos[i].type = SID_NAME_USE_NONE;
734
735 if (lookup_as_domain(&sid, name_infos, &domain_name)) {
736 /* We can't push that through the normal lookup
737 * process, as this would reference illegal
738 * domains.
739 *
740 * For example S-1-5-32 would end up referencing
741 * domain S-1-5- with RID 32 which is clearly wrong.
742 */
743 if (domain_name == NULL) {
744 result = NT_STATUS_NO_MEMORY;
745 goto fail;
746 }
747
748 name_infos[i].rid = 0;
749 name_infos[i].type = SID_NAME_DOMAIN;
750 name_infos[i].name = NULL;
751
752 if (sid_check_is_builtin(&sid)) {
753 /* Yes, W2k3 returns "BUILTIN" both as domain
754 * and name here */
755 name_infos[i].name = talloc_strdup(
756 name_infos, builtin_domain_name());
757 if (name_infos[i].name == NULL) {
758 result = NT_STATUS_NO_MEMORY;
759 goto fail;
760 }
761 }
762 } else {
763 /* This is a normal SID with rid component */
764 if (!sid_split_rid(&sid, &rid)) {
765 result = NT_STATUS_INVALID_PARAMETER;
766 goto fail;
767 }
768 }
769
770 if (!check_dom_sid_to_level(&sid, level)) {
771 name_infos[i].rid = 0;
772 name_infos[i].type = SID_NAME_UNKNOWN;
773 name_infos[i].name = NULL;
774 continue;
775 }
776
777 for (j=0; j<MAX_REF_DOMAINS; j++) {
778 if (!dom_infos[j].valid) {
779 break;
780 }
781 if (sid_equal(&sid, &dom_infos[j].sid)) {
782 break;
783 }
784 }
785
786 if (j == MAX_REF_DOMAINS) {
787 /* TODO: What's the right error message here? */
788 result = NT_STATUS_NONE_MAPPED;
789 goto fail;
790 }
791
792 if (!dom_infos[j].valid) {
793 /* We found a domain not yet referenced, create a new
794 * ref. */
795 dom_infos[j].valid = True;
796 sid_copy(&dom_infos[j].sid, &sid);
797
798 if (domain_name != NULL) {
799 /* This name was being found above in the case
800 * when we found a domain SID */
801 dom_infos[j].name =
802 talloc_strdup(dom_infos, domain_name);
803 if (dom_infos[j].name == NULL) {
804 result = NT_STATUS_NO_MEMORY;
805 goto fail;
806 }
807 } else {
808 /* lookup_rids will take care of this */
809 dom_infos[j].name = NULL;
810 }
811 }
812
813 name_infos[i].dom_idx = j;
814
815 if (name_infos[i].type == SID_NAME_USE_NONE) {
816 name_infos[i].rid = rid;
817
818 ADD_TO_ARRAY(dom_infos, int, i, &dom_infos[j].idxs,
819 &dom_infos[j].num_idxs);
820
821 if (dom_infos[j].idxs == NULL) {
822 result = NT_STATUS_NO_MEMORY;
823 goto fail;
824 }
825 }
826 }
827
828 /* Iterate over the domains found */
829
830 for (i=0; i<MAX_REF_DOMAINS; i++) {
831 uint32_t *rids;
832 const char *domain_name = NULL;
833 const char **names;
834 enum lsa_SidType *types;
835 struct lsa_dom_info *dom = &dom_infos[i];
836
837 if (!dom->valid) {
838 /* No domains left, we're done */
839 break;
840 }
841
842 if (dom->num_idxs) {
843 if (!(rids = TALLOC_ARRAY(tmp_ctx, uint32, dom->num_idxs))) {
844 result = NT_STATUS_NO_MEMORY;
845 goto fail;
846 }
847 } else {
848 rids = NULL;
849 }
850
851 for (j=0; j<dom->num_idxs; j++) {
852 rids[j] = name_infos[dom->idxs[j]].rid;
853 }
854
855 if (!lookup_rids(tmp_ctx, &dom->sid,
856 dom->num_idxs, rids, &domain_name,
857 &names, &types)) {
858 result = NT_STATUS_NO_MEMORY;
859 goto fail;
860 }
861
862 if (!(dom->name = talloc_strdup(dom_infos, domain_name))) {
863 result = NT_STATUS_NO_MEMORY;
864 goto fail;
865 }
866
867 for (j=0; j<dom->num_idxs; j++) {
868 int idx = dom->idxs[j];
869 name_infos[idx].type = types[j];
870 if (types[j] != SID_NAME_UNKNOWN) {
871 name_infos[idx].name =
872 talloc_strdup(name_infos, names[j]);
873 if (name_infos[idx].name == NULL) {
874 result = NT_STATUS_NO_MEMORY;
875 goto fail;
876 }
877 } else {
878 name_infos[idx].name = NULL;
879 }
880 }
881 }
882
883 *ret_domains = dom_infos;
884 *ret_names = name_infos;
885 return NT_STATUS_OK;
886
887 fail:
888 TALLOC_FREE(dom_infos);
889 TALLOC_FREE(name_infos);
890 TALLOC_FREE(tmp_ctx);
891 return result;
892}
893
894/*****************************************************************
895 *THE CANONICAL* convert SID to name function.
896*****************************************************************/
897
898BOOL lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
899 const char **ret_domain, const char **ret_name,
900 enum lsa_SidType *ret_type)
901{
902 struct lsa_dom_info *domain;
903 struct lsa_name_info *name;
904 TALLOC_CTX *tmp_ctx;
905 BOOL ret = False;
906
907 if (!(tmp_ctx = talloc_new(mem_ctx))) {
908 DEBUG(0, ("talloc_new failed\n"));
909 return False;
910 }
911
912 if (!NT_STATUS_IS_OK(lookup_sids(tmp_ctx, 1, &sid, 1,
913 &domain, &name))) {
914 goto done;
915 }
916
917 if (name->type == SID_NAME_UNKNOWN) {
918 goto done;
919 }
920
921 if ((ret_domain != NULL) &&
922 !(*ret_domain = talloc_strdup(mem_ctx, domain->name))) {
923 goto done;
924 }
925
926 if ((ret_name != NULL) &&
927 !(*ret_name = talloc_strdup(mem_ctx, name->name))) {
928 goto done;
929 }
930
931 if (ret_type != NULL) {
932 *ret_type = name->type;
933 }
934
935 ret = True;
936
937 done:
938 if (ret) {
939 DEBUG(10, ("Sid %s -> %s\\%s(%d)\n",
940 sid_string_static(sid), domain->name,
941 name->name, name->type));
942 } else {
943 DEBUG(10, ("failed to lookup sid %s\n",
944 sid_string_static(sid)));
945 }
946 TALLOC_FREE(tmp_ctx);
947 return ret;
948}
949
950/*****************************************************************
951 Id mapping cache. This is to avoid Winbind mappings already
952 seen by smbd to be queried too frequently, keeping winbindd
953 busy, and blocking smbd while winbindd is busy with other
954 stuff. Written by Michael Steffens <michael.steffens@hp.com>,
955 modified to use linked lists by jra.
956*****************************************************************/
957
958#define MAX_UID_SID_CACHE_SIZE 100
959#define TURNOVER_UID_SID_CACHE_SIZE 10
960#define MAX_GID_SID_CACHE_SIZE 100
961#define TURNOVER_GID_SID_CACHE_SIZE 10
962
963static size_t n_uid_sid_cache = 0;
964static size_t n_gid_sid_cache = 0;
965
966static struct uid_sid_cache {
967 struct uid_sid_cache *next, *prev;
968 uid_t uid;
969 DOM_SID sid;
970 enum lsa_SidType sidtype;
971} *uid_sid_cache_head;
972
973static struct gid_sid_cache {
974 struct gid_sid_cache *next, *prev;
975 gid_t gid;
976 DOM_SID sid;
977 enum lsa_SidType sidtype;
978} *gid_sid_cache_head;
979
980/*****************************************************************
981 Find a SID given a uid.
982*****************************************************************/
983
984static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
985{
986 struct uid_sid_cache *pc;
987
988 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
989 if (pc->uid == uid) {
990 *psid = pc->sid;
991 DEBUG(3,("fetch sid from uid cache %u -> %s\n",
992 (unsigned int)uid, sid_string_static(psid)));
993 DLIST_PROMOTE(uid_sid_cache_head, pc);
994 return True;
995 }
996 }
997 return False;
998}
999
1000/*****************************************************************
1001 Find a uid given a SID.
1002*****************************************************************/
1003
1004static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
1005{
1006 struct uid_sid_cache *pc;
1007
1008 for (pc = uid_sid_cache_head; pc; pc = pc->next) {
1009 if (sid_compare(&pc->sid, psid) == 0) {
1010 *puid = pc->uid;
1011 DEBUG(3,("fetch uid from cache %u -> %s\n",
1012 (unsigned int)*puid, sid_string_static(psid)));
1013 DLIST_PROMOTE(uid_sid_cache_head, pc);
1014 return True;
1015 }
1016 }
1017 return False;
1018}
1019
1020/*****************************************************************
1021 Store uid to SID mapping in cache.
1022*****************************************************************/
1023
1024void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
1025{
1026 struct uid_sid_cache *pc;
1027
1028 /* do not store SIDs in the "Unix Group" domain */
1029
1030 if ( sid_check_is_in_unix_users( psid ) )
1031 return;
1032
1033 if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
1034 /* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
1035 struct uid_sid_cache *pc_next;
1036 size_t i;
1037
1038 for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
1039 ;
1040 for(; pc; pc = pc_next) {
1041 pc_next = pc->next;
1042 DLIST_REMOVE(uid_sid_cache_head,pc);
1043 SAFE_FREE(pc);
1044 n_uid_sid_cache--;
1045 }
1046 }
1047
1048 pc = SMB_MALLOC_P(struct uid_sid_cache);
1049 if (!pc)
1050 return;
1051 pc->uid = uid;
1052 sid_copy(&pc->sid, psid);
1053 DLIST_ADD(uid_sid_cache_head, pc);
1054 n_uid_sid_cache++;
1055}
1056
1057/*****************************************************************
1058 Find a SID given a gid.
1059*****************************************************************/
1060
1061static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
1062{
1063 struct gid_sid_cache *pc;
1064
1065 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1066 if (pc->gid == gid) {
1067 *psid = pc->sid;
1068 DEBUG(3,("fetch sid from gid cache %u -> %s\n",
1069 (unsigned int)gid, sid_string_static(psid)));
1070 DLIST_PROMOTE(gid_sid_cache_head, pc);
1071 return True;
1072 }
1073 }
1074 return False;
1075}
1076
1077/*****************************************************************
1078 Find a gid given a SID.
1079*****************************************************************/
1080
1081static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
1082{
1083 struct gid_sid_cache *pc;
1084
1085 for (pc = gid_sid_cache_head; pc; pc = pc->next) {
1086 if (sid_compare(&pc->sid, psid) == 0) {
1087 *pgid = pc->gid;
1088 DEBUG(3,("fetch gid from cache %u -> %s\n",
1089 (unsigned int)*pgid, sid_string_static(psid)));
1090 DLIST_PROMOTE(gid_sid_cache_head, pc);
1091 return True;
1092 }
1093 }
1094 return False;
1095}
1096
1097/*****************************************************************
1098 Store gid to SID mapping in cache.
1099*****************************************************************/
1100
1101void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
1102{
1103 struct gid_sid_cache *pc;
1104
1105 /* do not store SIDs in the "Unix Group" domain */
1106
1107 if ( sid_check_is_in_unix_groups( psid ) )
1108 return;
1109
1110 if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
1111 /* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
1112 struct gid_sid_cache *pc_next;
1113 size_t i;
1114
1115 for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
1116 ;
1117 for(; pc; pc = pc_next) {
1118 pc_next = pc->next;
1119 DLIST_REMOVE(gid_sid_cache_head,pc);
1120 SAFE_FREE(pc);
1121 n_gid_sid_cache--;
1122 }
1123 }
1124
1125 pc = SMB_MALLOC_P(struct gid_sid_cache);
1126 if (!pc)
1127 return;
1128 pc->gid = gid;
1129 sid_copy(&pc->sid, psid);
1130 DLIST_ADD(gid_sid_cache_head, pc);
1131
1132 DEBUG(3,("store_gid_sid_cache: gid %u in cache -> %s\n", (unsigned int)gid,
1133 sid_string_static(psid)));
1134
1135 n_gid_sid_cache++;
1136}
1137
1138/*****************************************************************
1139 *THE LEGACY* convert uid_t to SID function.
1140*****************************************************************/
1141
1142static void legacy_uid_to_sid(DOM_SID *psid, uid_t uid)
1143{
1144 uint32 rid;
1145 BOOL ret;
1146
1147 ZERO_STRUCTP(psid);
1148
1149 become_root();
1150 ret = pdb_uid_to_rid(uid, &rid);
1151 unbecome_root();
1152
1153 if (ret) {
1154 /* This is a mapped user */
1155 sid_copy(psid, get_global_sam_sid());
1156 sid_append_rid(psid, rid);
1157 goto done;
1158 }
1159
1160 /* This is an unmapped user */
1161
1162 uid_to_unix_users_sid(uid, psid);
1163
1164 done:
1165 DEBUG(10,("LEGACY: uid %u -> sid %s\n", (unsigned int)uid,
1166 sid_string_static(psid)));
1167
1168 store_uid_sid_cache(psid, uid);
1169 return;
1170}
1171
1172/*****************************************************************
1173 *THE LEGACY* convert gid_t to SID function.
1174*****************************************************************/
1175
1176static void legacy_gid_to_sid(DOM_SID *psid, gid_t gid)
1177{
1178 BOOL ret;
1179
1180 ZERO_STRUCTP(psid);
1181
1182 become_root();
1183 ret = pdb_gid_to_sid(gid, psid);
1184 unbecome_root();
1185
1186 if (ret) {
1187 /* This is a mapped group */
1188 goto done;
1189 }
1190
1191 /* This is an unmapped group */
1192
1193 gid_to_unix_groups_sid(gid, psid);
1194
1195 done:
1196 DEBUG(10,("LEGACY: gid %u -> sid %s\n", (unsigned int)gid,
1197 sid_string_static(psid)));
1198
1199 store_gid_sid_cache(psid, gid);
1200 return;
1201}
1202
1203/*****************************************************************
1204 *THE LEGACY* convert SID to uid function.
1205*****************************************************************/
1206
1207static BOOL legacy_sid_to_uid(const DOM_SID *psid, uid_t *puid)
1208{
1209 enum lsa_SidType type;
1210 uint32 rid;
1211
1212 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1213 union unid_t id;
1214 BOOL ret;
1215
1216 become_root();
1217 ret = pdb_sid_to_id(psid, &id, &type);
1218 unbecome_root();
1219
1220 if (ret) {
1221 if (type != SID_NAME_USER) {
1222 DEBUG(5, ("sid %s is a %s, expected a user\n",
1223 sid_string_static(psid),
1224 sid_type_lookup(type)));
1225 return False;
1226 }
1227 *puid = id.uid;
1228 goto done;
1229 }
1230
1231 /* This was ours, but it was not mapped. Fail */
1232 }
1233
1234 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1235 return False;
1236
1237done:
1238 DEBUG(10,("LEGACY: sid %s -> uid %u\n", sid_string_static(psid),
1239 (unsigned int)*puid ));
1240
1241 store_uid_sid_cache(psid, *puid);
1242 return True;
1243}
1244
1245/*****************************************************************
1246 *THE LEGACY* convert SID to gid function.
1247 Group mapping is used for gids that maps to Wellknown SIDs
1248*****************************************************************/
1249
1250static BOOL legacy_sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1251{
1252 uint32 rid;
1253 GROUP_MAP map;
1254 union unid_t id;
1255 enum lsa_SidType type;
1256
1257 if ((sid_check_is_in_builtin(psid) ||
1258 sid_check_is_in_wellknown_domain(psid))) {
1259 BOOL ret;
1260
1261 become_root();
1262 ret = pdb_getgrsid(&map, *psid);
1263 unbecome_root();
1264
1265 if (ret) {
1266 *pgid = map.gid;
1267 goto done;
1268 }
1269 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1270 return False;
1271 }
1272
1273 if (sid_peek_check_rid(get_global_sam_sid(), psid, &rid)) {
1274 BOOL ret;
1275
1276 become_root();
1277 ret = pdb_sid_to_id(psid, &id, &type);
1278 unbecome_root();
1279
1280 if (ret) {
1281 if ((type != SID_NAME_DOM_GRP) &&
1282 (type != SID_NAME_ALIAS)) {
1283 DEBUG(5, ("LEGACY: sid %s is a %s, expected a group\n",
1284 sid_string_static(psid),
1285 sid_type_lookup(type)));
1286 return False;
1287 }
1288 *pgid = id.gid;
1289 goto done;
1290 }
1291
1292 /* This was ours, but it was not mapped. Fail */
1293 }
1294
1295 DEBUG(10,("LEGACY: mapping failed for sid %s\n", sid_string_static(psid)));
1296 return False;
1297
1298 done:
1299 DEBUG(10,("LEGACY: sid %s -> gid %u\n", sid_string_static(psid),
1300 (unsigned int)*pgid ));
1301
1302 store_gid_sid_cache(psid, *pgid);
1303
1304 return True;
1305}
1306
1307/*****************************************************************
1308 *THE CANONICAL* convert uid_t to SID function.
1309*****************************************************************/
1310
1311void uid_to_sid(DOM_SID *psid, uid_t uid)
1312{
1313 ZERO_STRUCTP(psid);
1314
1315 if (fetch_sid_from_uid_cache(psid, uid))
1316 return;
1317
1318 if (!winbind_uid_to_sid(psid, uid)) {
1319 if (!winbind_ping()) {
1320 legacy_uid_to_sid(psid, uid);
1321 return;
1322 }
1323
1324 DEBUG(5, ("uid_to_sid: winbind failed to find a sid for uid %u\n",
1325 uid));
1326 return;
1327 }
1328
1329 DEBUG(10,("uid %u -> sid %s\n",
1330 (unsigned int)uid, sid_string_static(psid)));
1331
1332 store_uid_sid_cache(psid, uid);
1333 return;
1334}
1335
1336/*****************************************************************
1337 *THE CANONICAL* convert gid_t to SID function.
1338*****************************************************************/
1339
1340void gid_to_sid(DOM_SID *psid, gid_t gid)
1341{
1342 ZERO_STRUCTP(psid);
1343
1344 if (fetch_sid_from_gid_cache(psid, gid))
1345 return;
1346
1347 if (!winbind_gid_to_sid(psid, gid)) {
1348 if (!winbind_ping()) {
1349 legacy_gid_to_sid(psid, gid);
1350 return;
1351 }
1352
1353 DEBUG(5, ("gid_to_sid: winbind failed to find a sid for gid %u\n",
1354 gid));
1355 return;
1356 }
1357
1358 DEBUG(10,("gid %u -> sid %s\n",
1359 (unsigned int)gid, sid_string_static(psid)));
1360
1361 store_gid_sid_cache(psid, gid);
1362 return;
1363}
1364
1365/*****************************************************************
1366 *THE CANONICAL* convert SID to uid function.
1367*****************************************************************/
1368
1369BOOL sid_to_uid(const DOM_SID *psid, uid_t *puid)
1370{
1371 uint32 rid;
1372 gid_t gid;
1373
1374 if (fetch_uid_from_cache(puid, psid))
1375 return True;
1376
1377 if (fetch_gid_from_cache(&gid, psid)) {
1378 return False;
1379 }
1380
1381 /* Optimize for the Unix Users Domain
1382 * as the conversion is straightforward */
1383 if (sid_peek_check_rid(&global_sid_Unix_Users, psid, &rid)) {
1384 uid_t uid = rid;
1385 *puid = uid;
1386
1387 /* return here, don't cache */
1388 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1389 (unsigned int)*puid ));
1390 return True;
1391 }
1392
1393 if (!winbind_sid_to_uid(puid, psid)) {
1394 if (!winbind_ping()) {
1395 return legacy_sid_to_uid(psid, puid);
1396 }
1397
1398 DEBUG(5, ("winbind failed to find a uid for sid %s\n",
1399 sid_string_static(psid)));
1400 return False;
1401 }
1402
1403 /* TODO: Here would be the place to allocate both a gid and a uid for
1404 * the SID in question */
1405
1406 DEBUG(10,("sid %s -> uid %u\n", sid_string_static(psid),
1407 (unsigned int)*puid ));
1408
1409 store_uid_sid_cache(psid, *puid);
1410 return True;
1411}
1412
1413/*****************************************************************
1414 *THE CANONICAL* convert SID to gid function.
1415 Group mapping is used for gids that maps to Wellknown SIDs
1416*****************************************************************/
1417
1418BOOL sid_to_gid(const DOM_SID *psid, gid_t *pgid)
1419{
1420 uint32 rid;
1421 uid_t uid;
1422
1423 if (fetch_gid_from_cache(pgid, psid))
1424 return True;
1425
1426 if (fetch_uid_from_cache(&uid, psid))
1427 return False;
1428
1429 /* Optimize for the Unix Groups Domain
1430 * as the conversion is straightforward */
1431 if (sid_peek_check_rid(&global_sid_Unix_Groups, psid, &rid)) {
1432 gid_t gid = rid;
1433 *pgid = gid;
1434
1435 /* return here, don't cache */
1436 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1437 (unsigned int)*pgid ));
1438 return True;
1439 }
1440
1441 /* Ask winbindd if it can map this sid to a gid.
1442 * (Idmap will check it is a valid SID and of the right type) */
1443
1444 if ( !winbind_sid_to_gid(pgid, psid) ) {
1445 if (!winbind_ping()) {
1446 return legacy_sid_to_gid(psid, pgid);
1447 }
1448
1449 DEBUG(10,("winbind failed to find a gid for sid %s\n",
1450 sid_string_static(psid)));
1451 return False;
1452 }
1453
1454 DEBUG(10,("sid %s -> gid %u\n", sid_string_static(psid),
1455 (unsigned int)*pgid ));
1456
1457 store_gid_sid_cache(psid, *pgid);
1458
1459 return True;
1460}
1461
Note: See TracBrowser for help on using the repository browser.