source: branches/samba-3.0/source/passdb/lookup_sid.c

Last change on this file was 124, checked in by Paul Smedley, 17 years ago

Update source to 3.0.28a

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