source: vendor/3.5.0/source3/winbindd/winbindd_rpc.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 31.9 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Winbind rpc backend functions
5
6 Copyright (C) Tim Potter 2000-2001,2003
7 Copyright (C) Andrew Tridgell 2001
8 Copyright (C) Volker Lendecke 2005
9 Copyright (C) Guenther Deschner 2008 (pidl conversion)
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "includes.h"
26#include "winbindd.h"
27#include "../librpc/gen_ndr/cli_samr.h"
28#include "../librpc/gen_ndr/cli_lsa.h"
29
30#undef DBGC_CLASS
31#define DBGC_CLASS DBGC_WINBIND
32
33
34/* Query display info for a domain. This returns enough information plus a
35 bit extra to give an overview of domain users for the User Manager
36 application. */
37static NTSTATUS query_user_list(struct winbindd_domain *domain,
38 TALLOC_CTX *mem_ctx,
39 uint32 *num_entries,
40 struct wbint_userinfo **info)
41{
42 NTSTATUS result;
43 struct policy_handle dom_pol;
44 unsigned int i, start_idx;
45 uint32 loop_count;
46 struct rpc_pipe_client *cli;
47
48 DEBUG(3,("rpc: query_user_list\n"));
49
50 *num_entries = 0;
51 *info = NULL;
52
53 if ( !winbindd_can_contact_domain( domain ) ) {
54 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
55 domain->name));
56 return NT_STATUS_OK;
57 }
58
59 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
60 if (!NT_STATUS_IS_OK(result))
61 return result;
62
63 i = start_idx = 0;
64 loop_count = 0;
65
66 do {
67 uint32 num_dom_users, j;
68 uint32 max_entries, max_size;
69 uint32_t total_size, returned_size;
70
71 union samr_DispInfo disp_info;
72
73 /* this next bit is copied from net_user_list_internal() */
74
75 get_query_dispinfo_params(loop_count, &max_entries,
76 &max_size);
77
78 result = rpccli_samr_QueryDisplayInfo(cli, mem_ctx,
79 &dom_pol,
80 1,
81 start_idx,
82 max_entries,
83 max_size,
84 &total_size,
85 &returned_size,
86 &disp_info);
87 num_dom_users = disp_info.info1.count;
88 start_idx += disp_info.info1.count;
89 loop_count++;
90
91 *num_entries += num_dom_users;
92
93 *info = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
94 struct wbint_userinfo,
95 *num_entries);
96
97 if (!(*info)) {
98 return NT_STATUS_NO_MEMORY;
99 }
100
101 for (j = 0; j < num_dom_users; i++, j++) {
102
103 uint32_t rid = disp_info.info1.entries[j].rid;
104
105 (*info)[i].acct_name = talloc_strdup(mem_ctx,
106 disp_info.info1.entries[j].account_name.string);
107 (*info)[i].full_name = talloc_strdup(mem_ctx,
108 disp_info.info1.entries[j].full_name.string);
109 (*info)[i].homedir = NULL;
110 (*info)[i].shell = NULL;
111 sid_compose(&(*info)[i].user_sid, &domain->sid, rid);
112
113 /* For the moment we set the primary group for
114 every user to be the Domain Users group.
115 There are serious problems with determining
116 the actual primary group for large domains.
117 This should really be made into a 'winbind
118 force group' smb.conf parameter or
119 something like that. */
120
121 sid_compose(&(*info)[i].group_sid, &domain->sid,
122 DOMAIN_GROUP_RID_USERS);
123 }
124
125 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
126
127 return result;
128}
129
130/* list all domain groups */
131static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
132 TALLOC_CTX *mem_ctx,
133 uint32 *num_entries,
134 struct acct_info **info)
135{
136 struct policy_handle dom_pol;
137 NTSTATUS status;
138 uint32 start = 0;
139 struct rpc_pipe_client *cli;
140
141 *num_entries = 0;
142 *info = NULL;
143
144 DEBUG(3,("rpc: enum_dom_groups\n"));
145
146 if ( !winbindd_can_contact_domain( domain ) ) {
147 DEBUG(10,("enum_domain_groups: No incoming trust for domain %s\n",
148 domain->name));
149 return NT_STATUS_OK;
150 }
151
152 status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
153 if (!NT_STATUS_IS_OK(status))
154 return status;
155
156 do {
157 struct samr_SamArray *sam_array = NULL;
158 uint32 count = 0;
159 TALLOC_CTX *mem_ctx2;
160 int g;
161
162 mem_ctx2 = talloc_init("enum_dom_groups[rpc]");
163
164 /* start is updated by this call. */
165 status = rpccli_samr_EnumDomainGroups(cli, mem_ctx2,
166 &dom_pol,
167 &start,
168 &sam_array,
169 0xFFFF, /* buffer size? */
170 &count);
171
172 if (!NT_STATUS_IS_OK(status) &&
173 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
174 talloc_destroy(mem_ctx2);
175 break;
176 }
177
178 (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
179 struct acct_info,
180 (*num_entries) + count);
181 if (! *info) {
182 talloc_destroy(mem_ctx2);
183 return NT_STATUS_NO_MEMORY;
184 }
185
186 for (g=0; g < count; g++) {
187
188 fstrcpy((*info)[*num_entries + g].acct_name,
189 sam_array->entries[g].name.string);
190 (*info)[*num_entries + g].rid = sam_array->entries[g].idx;
191 }
192
193 (*num_entries) += count;
194 talloc_destroy(mem_ctx2);
195 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
196
197 return status;
198}
199
200/* List all domain groups */
201
202static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
203 TALLOC_CTX *mem_ctx,
204 uint32 *num_entries,
205 struct acct_info **info)
206{
207 struct policy_handle dom_pol;
208 NTSTATUS result;
209 struct rpc_pipe_client *cli;
210
211 *num_entries = 0;
212 *info = NULL;
213
214 DEBUG(3,("rpc: enum_local_groups\n"));
215
216 if ( !winbindd_can_contact_domain( domain ) ) {
217 DEBUG(10,("enum_local_groups: No incoming trust for domain %s\n",
218 domain->name));
219 return NT_STATUS_OK;
220 }
221
222 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
223 if (!NT_STATUS_IS_OK(result))
224 return result;
225
226 do {
227 struct samr_SamArray *sam_array = NULL;
228 uint32 count = 0, start = *num_entries;
229 TALLOC_CTX *mem_ctx2;
230 int g;
231
232 mem_ctx2 = talloc_init("enum_dom_local_groups[rpc]");
233
234 result = rpccli_samr_EnumDomainAliases(cli, mem_ctx2,
235 &dom_pol,
236 &start,
237 &sam_array,
238 0xFFFF, /* buffer size? */
239 &count);
240 if (!NT_STATUS_IS_OK(result) &&
241 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES) )
242 {
243 talloc_destroy(mem_ctx2);
244 return result;
245 }
246
247 (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
248 struct acct_info,
249 (*num_entries) + count);
250 if (! *info) {
251 talloc_destroy(mem_ctx2);
252 return NT_STATUS_NO_MEMORY;
253 }
254
255 for (g=0; g < count; g++) {
256
257 fstrcpy((*info)[*num_entries + g].acct_name,
258 sam_array->entries[g].name.string);
259 (*info)[*num_entries + g].rid = sam_array->entries[g].idx;
260 }
261
262 (*num_entries) += count;
263 talloc_destroy(mem_ctx2);
264
265 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
266
267 return result;
268}
269
270/* convert a single name to a sid in a domain */
271static NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
272 TALLOC_CTX *mem_ctx,
273 const char *domain_name,
274 const char *name,
275 uint32_t flags,
276 DOM_SID *sid,
277 enum lsa_SidType *type)
278{
279 NTSTATUS result;
280 DOM_SID *sids = NULL;
281 enum lsa_SidType *types = NULL;
282 char *full_name = NULL;
283 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
284 char *mapped_name = NULL;
285
286 if (name == NULL || *name=='\0') {
287 full_name = talloc_asprintf(mem_ctx, "%s", domain_name);
288 } else if (domain_name == NULL || *domain_name == '\0') {
289 full_name = talloc_asprintf(mem_ctx, "%s", name);
290 } else {
291 full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain_name, name);
292 }
293 if (!full_name) {
294 DEBUG(0, ("talloc_asprintf failed!\n"));
295 return NT_STATUS_NO_MEMORY;
296 }
297
298 DEBUG(3,("rpc: name_to_sid name=%s\n", full_name));
299
300 name_map_status = normalize_name_unmap(mem_ctx, full_name,
301 &mapped_name);
302
303 /* Reset the full_name pointer if we mapped anytthing */
304
305 if (NT_STATUS_IS_OK(name_map_status) ||
306 NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
307 {
308 full_name = mapped_name;
309 }
310
311 DEBUG(3,("name_to_sid [rpc] %s for domain %s\n",
312 full_name?full_name:"", domain_name ));
313
314 result = winbindd_lookup_names(mem_ctx, domain, 1,
315 (const char **)&full_name, NULL,
316 &sids, &types);
317 if (!NT_STATUS_IS_OK(result))
318 return result;
319
320 /* Return rid and type if lookup successful */
321
322 sid_copy(sid, &sids[0]);
323 *type = types[0];
324
325 return NT_STATUS_OK;
326}
327
328/*
329 convert a domain SID to a user or group name
330*/
331static NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain,
332 TALLOC_CTX *mem_ctx,
333 const DOM_SID *sid,
334 char **domain_name,
335 char **name,
336 enum lsa_SidType *type)
337{
338 char **domains;
339 char **names;
340 enum lsa_SidType *types = NULL;
341 NTSTATUS result;
342 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
343 char *mapped_name = NULL;
344
345 DEBUG(3,("sid_to_name [rpc] %s for domain %s\n", sid_string_dbg(sid),
346 domain->name ));
347
348 result = winbindd_lookup_sids(mem_ctx,
349 domain,
350 1,
351 sid,
352 &domains,
353 &names,
354 &types);
355 if (!NT_STATUS_IS_OK(result)) {
356 DEBUG(2,("msrpc_sid_to_name: failed to lookup sids: %s\n",
357 nt_errstr(result)));
358 return result;
359 }
360
361
362 *type = (enum lsa_SidType)types[0];
363 *domain_name = domains[0];
364 *name = names[0];
365
366 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
367
368 name_map_status = normalize_name_map(mem_ctx, domain, *name,
369 &mapped_name);
370 if (NT_STATUS_IS_OK(name_map_status) ||
371 NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
372 {
373 *name = mapped_name;
374 DEBUG(5,("returning mapped name -- %s\n", *name));
375 }
376
377 return NT_STATUS_OK;
378}
379
380static NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain,
381 TALLOC_CTX *mem_ctx,
382 const DOM_SID *sid,
383 uint32 *rids,
384 size_t num_rids,
385 char **domain_name,
386 char ***names,
387 enum lsa_SidType **types)
388{
389 char **domains;
390 NTSTATUS result;
391 DOM_SID *sids;
392 size_t i;
393 char **ret_names;
394
395 DEBUG(3, ("rids_to_names [rpc] for domain %s\n", domain->name ));
396
397 if (num_rids) {
398 sids = TALLOC_ARRAY(mem_ctx, DOM_SID, num_rids);
399 if (sids == NULL) {
400 return NT_STATUS_NO_MEMORY;
401 }
402 } else {
403 sids = NULL;
404 }
405
406 for (i=0; i<num_rids; i++) {
407 if (!sid_compose(&sids[i], sid, rids[i])) {
408 return NT_STATUS_INTERNAL_ERROR;
409 }
410 }
411
412 result = winbindd_lookup_sids(mem_ctx,
413 domain,
414 num_rids,
415 sids,
416 &domains,
417 names,
418 types);
419
420 if (!NT_STATUS_IS_OK(result) &&
421 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
422 return result;
423 }
424
425 ret_names = *names;
426 for (i=0; i<num_rids; i++) {
427 NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
428 char *mapped_name = NULL;
429
430 if ((*types)[i] != SID_NAME_UNKNOWN) {
431 name_map_status = normalize_name_map(mem_ctx,
432 domain,
433 ret_names[i],
434 &mapped_name);
435 if (NT_STATUS_IS_OK(name_map_status) ||
436 NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
437 {
438 ret_names[i] = mapped_name;
439 }
440
441 *domain_name = domains[i];
442 }
443 }
444
445 return result;
446}
447
448/* Lookup user information from a rid or username. */
449static NTSTATUS query_user(struct winbindd_domain *domain,
450 TALLOC_CTX *mem_ctx,
451 const DOM_SID *user_sid,
452 struct wbint_userinfo *user_info)
453{
454 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
455 struct policy_handle dom_pol, user_pol;
456 union samr_UserInfo *info = NULL;
457 uint32 user_rid;
458 struct netr_SamInfo3 *user;
459 struct rpc_pipe_client *cli;
460
461 DEBUG(3,("rpc: query_user sid=%s\n", sid_string_dbg(user_sid)));
462
463 if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
464 return NT_STATUS_UNSUCCESSFUL;
465
466 user_info->homedir = NULL;
467 user_info->shell = NULL;
468 user_info->primary_gid = (gid_t)-1;
469
470 /* try netsamlogon cache first */
471
472 if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL )
473 {
474
475 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
476 sid_string_dbg(user_sid)));
477
478 sid_compose(&user_info->user_sid, &domain->sid, user->base.rid);
479 sid_compose(&user_info->group_sid, &domain->sid,
480 user->base.primary_gid);
481
482 user_info->acct_name = talloc_strdup(mem_ctx,
483 user->base.account_name.string);
484 user_info->full_name = talloc_strdup(mem_ctx,
485 user->base.full_name.string);
486
487 TALLOC_FREE(user);
488
489 return NT_STATUS_OK;
490 }
491
492 if ( !winbindd_can_contact_domain( domain ) ) {
493 DEBUG(10,("query_user: No incoming trust for domain %s\n",
494 domain->name));
495 return NT_STATUS_OK;
496 }
497
498 /* no cache; hit the wire */
499
500 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
501 if (!NT_STATUS_IS_OK(result))
502 return result;
503
504 /* Get user handle */
505 result = rpccli_samr_OpenUser(cli, mem_ctx,
506 &dom_pol,
507 SEC_FLAG_MAXIMUM_ALLOWED,
508 user_rid,
509 &user_pol);
510
511 if (!NT_STATUS_IS_OK(result))
512 return result;
513
514 /* Get user info */
515 result = rpccli_samr_QueryUserInfo(cli, mem_ctx,
516 &user_pol,
517 0x15,
518 &info);
519
520 rpccli_samr_Close(cli, mem_ctx, &user_pol);
521
522 if (!NT_STATUS_IS_OK(result))
523 return result;
524
525 sid_compose(&user_info->user_sid, &domain->sid, user_rid);
526 sid_compose(&user_info->group_sid, &domain->sid,
527 info->info21.primary_gid);
528 user_info->acct_name = talloc_strdup(mem_ctx,
529 info->info21.account_name.string);
530 user_info->full_name = talloc_strdup(mem_ctx,
531 info->info21.full_name.string);
532 user_info->homedir = NULL;
533 user_info->shell = NULL;
534 user_info->primary_gid = (gid_t)-1;
535
536 return NT_STATUS_OK;
537}
538
539/* Lookup groups a user is a member of. I wish Unix had a call like this! */
540static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
541 TALLOC_CTX *mem_ctx,
542 const DOM_SID *user_sid,
543 uint32 *num_groups, DOM_SID **user_grpsids)
544{
545 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
546 struct policy_handle dom_pol, user_pol;
547 uint32 des_access = SEC_FLAG_MAXIMUM_ALLOWED;
548 struct samr_RidWithAttributeArray *rid_array = NULL;
549 unsigned int i;
550 uint32 user_rid;
551 struct rpc_pipe_client *cli;
552
553 DEBUG(3,("rpc: lookup_usergroups sid=%s\n", sid_string_dbg(user_sid)));
554
555 if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
556 return NT_STATUS_UNSUCCESSFUL;
557
558 *num_groups = 0;
559 *user_grpsids = NULL;
560
561 /* so lets see if we have a cached user_info_3 */
562 result = lookup_usergroups_cached(domain, mem_ctx, user_sid,
563 num_groups, user_grpsids);
564
565 if (NT_STATUS_IS_OK(result)) {
566 return NT_STATUS_OK;
567 }
568
569 if ( !winbindd_can_contact_domain( domain ) ) {
570 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
571 domain->name));
572
573 /* Tell the cache manager not to remember this one */
574
575 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
576 }
577
578 /* no cache; hit the wire */
579
580 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
581 if (!NT_STATUS_IS_OK(result))
582 return result;
583
584 /* Get user handle */
585 result = rpccli_samr_OpenUser(cli, mem_ctx,
586 &dom_pol,
587 des_access,
588 user_rid,
589 &user_pol);
590
591 if (!NT_STATUS_IS_OK(result))
592 return result;
593
594 /* Query user rids */
595 result = rpccli_samr_GetGroupsForUser(cli, mem_ctx,
596 &user_pol,
597 &rid_array);
598 *num_groups = rid_array->count;
599
600 rpccli_samr_Close(cli, mem_ctx, &user_pol);
601
602 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
603 return result;
604
605 (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
606 if (!(*user_grpsids))
607 return NT_STATUS_NO_MEMORY;
608
609 for (i=0;i<(*num_groups);i++) {
610 sid_copy(&((*user_grpsids)[i]), &domain->sid);
611 sid_append_rid(&((*user_grpsids)[i]),
612 rid_array->rids[i].rid);
613 }
614
615 return NT_STATUS_OK;
616}
617
618#define MAX_SAM_ENTRIES_W2K 0x400 /* 1024 */
619
620static NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
621 TALLOC_CTX *mem_ctx,
622 uint32 num_sids, const DOM_SID *sids,
623 uint32 *num_aliases,
624 uint32 **alias_rids)
625{
626 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
627 struct policy_handle dom_pol;
628 uint32 num_query_sids = 0;
629 int i;
630 struct rpc_pipe_client *cli;
631 struct samr_Ids alias_rids_query;
632 int rangesize = MAX_SAM_ENTRIES_W2K;
633 uint32 total_sids = 0;
634 int num_queries = 1;
635
636 *num_aliases = 0;
637 *alias_rids = NULL;
638
639 DEBUG(3,("rpc: lookup_useraliases\n"));
640
641 if ( !winbindd_can_contact_domain( domain ) ) {
642 DEBUG(10,("msrpc_lookup_useraliases: No incoming trust for domain %s\n",
643 domain->name));
644 return NT_STATUS_OK;
645 }
646
647 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
648 if (!NT_STATUS_IS_OK(result))
649 return result;
650
651 do {
652 /* prepare query */
653 struct lsa_SidArray sid_array;
654
655 ZERO_STRUCT(sid_array);
656
657 num_query_sids = MIN(num_sids - total_sids, rangesize);
658
659 DEBUG(10,("rpc: lookup_useraliases: entering query %d for %d sids\n",
660 num_queries, num_query_sids));
661
662 if (num_query_sids) {
663 sid_array.sids = TALLOC_ZERO_ARRAY(mem_ctx, struct lsa_SidPtr, num_query_sids);
664 if (sid_array.sids == NULL) {
665 return NT_STATUS_NO_MEMORY;
666 }
667 } else {
668 sid_array.sids = NULL;
669 }
670
671 for (i=0; i<num_query_sids; i++) {
672 sid_array.sids[i].sid = sid_dup_talloc(mem_ctx, &sids[total_sids++]);
673 if (!sid_array.sids[i].sid) {
674 TALLOC_FREE(sid_array.sids);
675 return NT_STATUS_NO_MEMORY;
676 }
677 }
678 sid_array.num_sids = num_query_sids;
679
680 /* do request */
681 result = rpccli_samr_GetAliasMembership(cli, mem_ctx,
682 &dom_pol,
683 &sid_array,
684 &alias_rids_query);
685
686 if (!NT_STATUS_IS_OK(result)) {
687 *num_aliases = 0;
688 *alias_rids = NULL;
689 TALLOC_FREE(sid_array.sids);
690 goto done;
691 }
692
693 /* process output */
694
695 for (i=0; i<alias_rids_query.count; i++) {
696 size_t na = *num_aliases;
697 if (!add_rid_to_array_unique(mem_ctx, alias_rids_query.ids[i],
698 alias_rids, &na)) {
699 return NT_STATUS_NO_MEMORY;
700 }
701 *num_aliases = na;
702 }
703
704 TALLOC_FREE(sid_array.sids);
705
706 num_queries++;
707
708 } while (total_sids < num_sids);
709
710 done:
711 DEBUG(10,("rpc: lookup_useraliases: got %d aliases in %d queries "
712 "(rangesize: %d)\n", *num_aliases, num_queries, rangesize));
713
714 return result;
715}
716
717
718/* Lookup group membership given a rid. */
719static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
720 TALLOC_CTX *mem_ctx,
721 const DOM_SID *group_sid,
722 enum lsa_SidType type,
723 uint32 *num_names,
724 DOM_SID **sid_mem, char ***names,
725 uint32 **name_types)
726{
727 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
728 uint32 i, total_names = 0;
729 struct policy_handle dom_pol, group_pol;
730 uint32 des_access = SEC_FLAG_MAXIMUM_ALLOWED;
731 uint32 *rid_mem = NULL;
732 uint32 group_rid;
733 unsigned int j, r;
734 struct rpc_pipe_client *cli;
735 unsigned int orig_timeout;
736 struct samr_RidTypeArray *rids = NULL;
737
738 DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name,
739 sid_string_dbg(group_sid)));
740
741 if ( !winbindd_can_contact_domain( domain ) ) {
742 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
743 domain->name));
744 return NT_STATUS_OK;
745 }
746
747 if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid))
748 return NT_STATUS_UNSUCCESSFUL;
749
750 *num_names = 0;
751
752 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
753 if (!NT_STATUS_IS_OK(result))
754 return result;
755
756 result = rpccli_samr_OpenGroup(cli, mem_ctx,
757 &dom_pol,
758 des_access,
759 group_rid,
760 &group_pol);
761
762 if (!NT_STATUS_IS_OK(result))
763 return result;
764
765 /* Step #1: Get a list of user rids that are the members of the
766 group. */
767
768 /* This call can take a long time - allow the server to time out.
769 35 seconds should do it. */
770
771 orig_timeout = rpccli_set_timeout(cli, 35000);
772
773 result = rpccli_samr_QueryGroupMember(cli, mem_ctx,
774 &group_pol,
775 &rids);
776
777 /* And restore our original timeout. */
778 rpccli_set_timeout(cli, orig_timeout);
779
780 rpccli_samr_Close(cli, mem_ctx, &group_pol);
781
782 if (!NT_STATUS_IS_OK(result))
783 return result;
784
785 if (!rids || !rids->count) {
786 names = NULL;
787 name_types = NULL;
788 sid_mem = NULL;
789 return NT_STATUS_OK;
790 }
791
792 *num_names = rids->count;
793 rid_mem = rids->rids;
794
795 /* Step #2: Convert list of rids into list of usernames. Do this
796 in bunches of ~1000 to avoid crashing NT4. It looks like there
797 is a buffer overflow or something like that lurking around
798 somewhere. */
799
800#define MAX_LOOKUP_RIDS 900
801
802 *names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_names);
803 *name_types = TALLOC_ZERO_ARRAY(mem_ctx, uint32, *num_names);
804 *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_names);
805
806 for (j=0;j<(*num_names);j++)
807 sid_compose(&(*sid_mem)[j], &domain->sid, rid_mem[j]);
808
809 if (*num_names>0 && (!*names || !*name_types))
810 return NT_STATUS_NO_MEMORY;
811
812 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
813 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
814 struct lsa_Strings tmp_names;
815 struct samr_Ids tmp_types;
816
817 /* Lookup a chunk of rids */
818
819 result = rpccli_samr_LookupRids(cli, mem_ctx,
820 &dom_pol,
821 num_lookup_rids,
822 &rid_mem[i],
823 &tmp_names,
824 &tmp_types);
825
826 /* see if we have a real error (and yes the
827 STATUS_SOME_UNMAPPED is the one returned from 2k) */
828
829 if (!NT_STATUS_IS_OK(result) &&
830 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
831 return result;
832
833 /* Copy result into array. The talloc system will take
834 care of freeing the temporary arrays later on. */
835
836 if (tmp_names.count != tmp_types.count) {
837 return NT_STATUS_UNSUCCESSFUL;
838 }
839
840 for (r=0; r<tmp_names.count; r++) {
841 if (tmp_types.ids[r] == SID_NAME_UNKNOWN) {
842 continue;
843 }
844 (*names)[total_names] = fill_domain_username_talloc(
845 mem_ctx, domain->name,
846 tmp_names.names[r].string, true);
847 (*name_types)[total_names] = tmp_types.ids[r];
848 total_names += 1;
849 }
850 }
851
852 *num_names = total_names;
853
854 return NT_STATUS_OK;
855}
856
857#ifdef HAVE_LDAP
858
859#include <ldap.h>
860
861static int get_ldap_seq(const char *server, int port, uint32 *seq)
862{
863 int ret = -1;
864 struct timeval to;
865 const char *attrs[] = {"highestCommittedUSN", NULL};
866 LDAPMessage *res = NULL;
867 char **values = NULL;
868 LDAP *ldp = NULL;
869
870 *seq = DOM_SEQUENCE_NONE;
871
872 /*
873 * Parameterised (5) second timeout on open. This is needed as the
874 * search timeout doesn't seem to apply to doing an open as well. JRA.
875 */
876
877 ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout());
878 if (ldp == NULL)
879 return -1;
880
881 /* Timeout if no response within 20 seconds. */
882 to.tv_sec = 10;
883 to.tv_usec = 0;
884
885 if (ldap_search_st(ldp, "", LDAP_SCOPE_BASE, "(objectclass=*)",
886 CONST_DISCARD(char **, attrs), 0, &to, &res))
887 goto done;
888
889 if (ldap_count_entries(ldp, res) != 1)
890 goto done;
891
892 values = ldap_get_values(ldp, res, "highestCommittedUSN");
893 if (!values || !values[0])
894 goto done;
895
896 *seq = atoi(values[0]);
897 ret = 0;
898
899 done:
900
901 if (values)
902 ldap_value_free(values);
903 if (res)
904 ldap_msgfree(res);
905 if (ldp)
906 ldap_unbind(ldp);
907 return ret;
908}
909
910/**********************************************************************
911 Get the sequence number for a Windows AD native mode domain using
912 LDAP queries.
913**********************************************************************/
914
915static int get_ldap_sequence_number(struct winbindd_domain *domain, uint32 *seq)
916{
917 int ret = -1;
918 char addr[INET6_ADDRSTRLEN];
919
920 print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
921 if ((ret = get_ldap_seq(addr, LDAP_PORT, seq)) == 0) {
922 DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence "
923 "number for Domain (%s) from DC (%s)\n",
924 domain->name, addr));
925 }
926 return ret;
927}
928
929#endif /* HAVE_LDAP */
930
931/* find the sequence number for a domain */
932static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
933{
934 TALLOC_CTX *mem_ctx;
935 union samr_DomainInfo *info = NULL;
936 NTSTATUS result;
937 struct policy_handle dom_pol;
938 bool got_seq_num = False;
939 struct rpc_pipe_client *cli;
940
941 DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
942
943 if ( !winbindd_can_contact_domain( domain ) ) {
944 DEBUG(10,("sequence_number: No incoming trust for domain %s\n",
945 domain->name));
946 *seq = time(NULL);
947 return NT_STATUS_OK;
948 }
949
950 *seq = DOM_SEQUENCE_NONE;
951
952 if (!(mem_ctx = talloc_init("sequence_number[rpc]")))
953 return NT_STATUS_NO_MEMORY;
954
955#ifdef HAVE_LDAP
956 if ( domain->active_directory )
957 {
958 int res;
959
960 DEBUG(8,("using get_ldap_seq() to retrieve the "
961 "sequence number\n"));
962
963 res = get_ldap_sequence_number( domain, seq );
964 if (res == 0)
965 {
966 result = NT_STATUS_OK;
967 DEBUG(10,("domain_sequence_number: LDAP for "
968 "domain %s is %u\n",
969 domain->name, *seq));
970 goto done;
971 }
972
973 DEBUG(10,("domain_sequence_number: failed to get LDAP "
974 "sequence number for domain %s\n",
975 domain->name ));
976 }
977#endif /* HAVE_LDAP */
978
979 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
980 if (!NT_STATUS_IS_OK(result)) {
981 goto done;
982 }
983
984 /* Query domain info */
985
986 result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
987 &dom_pol,
988 8,
989 &info);
990
991 if (NT_STATUS_IS_OK(result)) {
992 *seq = info->info8.sequence_num;
993 got_seq_num = True;
994 goto seq_num;
995 }
996
997 /* retry with info-level 2 in case the dc does not support info-level 8
998 * (like all older samba2 and samba3 dc's) - Guenther */
999
1000 result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
1001 &dom_pol,
1002 2,
1003 &info);
1004
1005 if (NT_STATUS_IS_OK(result)) {
1006 *seq = info->general.sequence_num;
1007 got_seq_num = True;
1008 }
1009
1010 seq_num:
1011 if (got_seq_num) {
1012 DEBUG(10,("domain_sequence_number: for domain %s is %u\n",
1013 domain->name, (unsigned)*seq));
1014 } else {
1015 DEBUG(10,("domain_sequence_number: failed to get sequence "
1016 "number (%u) for domain %s\n",
1017 (unsigned)*seq, domain->name ));
1018 }
1019
1020 done:
1021
1022 talloc_destroy(mem_ctx);
1023
1024 return result;
1025}
1026
1027/* get a list of trusted domains */
1028static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1029 TALLOC_CTX *mem_ctx,
1030 struct netr_DomainTrustList *trusts)
1031{
1032 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1033 uint32 enum_ctx = 0;
1034 struct rpc_pipe_client *cli;
1035 struct policy_handle lsa_policy;
1036
1037 DEBUG(3,("rpc: trusted_domains\n"));
1038
1039 ZERO_STRUCTP(trusts);
1040
1041 result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
1042 if (!NT_STATUS_IS_OK(result))
1043 return result;
1044
1045 result = STATUS_MORE_ENTRIES;
1046
1047 while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
1048 uint32 start_idx;
1049 int i;
1050 struct lsa_DomainList dom_list;
1051
1052 result = rpccli_lsa_EnumTrustDom(cli, mem_ctx,
1053 &lsa_policy,
1054 &enum_ctx,
1055 &dom_list,
1056 (uint32_t)-1);
1057
1058 if (!NT_STATUS_IS_OK(result) &&
1059 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
1060 break;
1061
1062 start_idx = trusts->count;
1063 trusts->count += dom_list.count;
1064
1065 trusts->array = talloc_realloc(
1066 mem_ctx, trusts->array, struct netr_DomainTrust,
1067 trusts->count);
1068 if (trusts->array == NULL) {
1069 return NT_STATUS_NO_MEMORY;
1070 }
1071
1072 for (i=0; i<dom_list.count; i++) {
1073 struct netr_DomainTrust *trust = &trusts->array[i];
1074 struct dom_sid *sid;
1075
1076 ZERO_STRUCTP(trust);
1077
1078 trust->netbios_name = talloc_move(
1079 trusts->array,
1080 &dom_list.domains[i].name.string);
1081 trust->dns_name = NULL;
1082
1083 sid = talloc(trusts->array, struct dom_sid);
1084 if (sid == NULL) {
1085 return NT_STATUS_NO_MEMORY;
1086 }
1087 sid_copy(sid, dom_list.domains[i].sid);
1088 trust->sid = sid;
1089 }
1090 }
1091 return result;
1092}
1093
1094/* find the lockout policy for a domain */
1095static NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain,
1096 TALLOC_CTX *mem_ctx,
1097 struct samr_DomInfo12 *lockout_policy)
1098{
1099 NTSTATUS result;
1100 struct rpc_pipe_client *cli;
1101 struct policy_handle dom_pol;
1102 union samr_DomainInfo *info = NULL;
1103
1104 DEBUG(10,("rpc: fetch lockout policy for %s\n", domain->name));
1105
1106 if ( !winbindd_can_contact_domain( domain ) ) {
1107 DEBUG(10,("msrpc_lockout_policy: No incoming trust for domain %s\n",
1108 domain->name));
1109 return NT_STATUS_NOT_SUPPORTED;
1110 }
1111
1112 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
1113 if (!NT_STATUS_IS_OK(result)) {
1114 goto done;
1115 }
1116
1117 result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
1118 &dom_pol,
1119 12,
1120 &info);
1121 if (!NT_STATUS_IS_OK(result)) {
1122 goto done;
1123 }
1124
1125 *lockout_policy = info->info12;
1126
1127 DEBUG(10,("msrpc_lockout_policy: lockout_threshold %d\n",
1128 info->info12.lockout_threshold));
1129
1130 done:
1131
1132 return result;
1133}
1134
1135/* find the password policy for a domain */
1136static NTSTATUS msrpc_password_policy(struct winbindd_domain *domain,
1137 TALLOC_CTX *mem_ctx,
1138 struct samr_DomInfo1 *password_policy)
1139{
1140 NTSTATUS result;
1141 struct rpc_pipe_client *cli;
1142 struct policy_handle dom_pol;
1143 union samr_DomainInfo *info = NULL;
1144
1145 DEBUG(10,("rpc: fetch password policy for %s\n", domain->name));
1146
1147 if ( !winbindd_can_contact_domain( domain ) ) {
1148 DEBUG(10,("msrpc_password_policy: No incoming trust for domain %s\n",
1149 domain->name));
1150 return NT_STATUS_NOT_SUPPORTED;
1151 }
1152
1153 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
1154 if (!NT_STATUS_IS_OK(result)) {
1155 goto done;
1156 }
1157
1158 result = rpccli_samr_QueryDomainInfo(cli, mem_ctx,
1159 &dom_pol,
1160 1,
1161 &info);
1162 if (!NT_STATUS_IS_OK(result)) {
1163 goto done;
1164 }
1165
1166 *password_policy = info->info1;
1167
1168 DEBUG(10,("msrpc_password_policy: min_length_password %d\n",
1169 info->info1.min_password_length));
1170
1171 done:
1172
1173 return result;
1174}
1175
1176typedef NTSTATUS (*lookup_sids_fn_t)(struct rpc_pipe_client *cli,
1177 TALLOC_CTX *mem_ctx,
1178 struct policy_handle *pol,
1179 int num_sids,
1180 const DOM_SID *sids,
1181 char ***pdomains,
1182 char ***pnames,
1183 enum lsa_SidType **ptypes);
1184
1185NTSTATUS winbindd_lookup_sids(TALLOC_CTX *mem_ctx,
1186 struct winbindd_domain *domain,
1187 uint32_t num_sids,
1188 const struct dom_sid *sids,
1189 char ***domains,
1190 char ***names,
1191 enum lsa_SidType **types)
1192{
1193 NTSTATUS status;
1194 struct rpc_pipe_client *cli = NULL;
1195 struct policy_handle lsa_policy;
1196 unsigned int orig_timeout;
1197 lookup_sids_fn_t lookup_sids_fn = rpccli_lsa_lookup_sids;
1198
1199 if (domain->can_do_ncacn_ip_tcp) {
1200 status = cm_connect_lsa_tcp(domain, mem_ctx, &cli);
1201 if (NT_STATUS_IS_OK(status)) {
1202 lookup_sids_fn = rpccli_lsa_lookup_sids3;
1203 goto lookup;
1204 }
1205 domain->can_do_ncacn_ip_tcp = false;
1206 }
1207 status = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
1208
1209 if (!NT_STATUS_IS_OK(status)) {
1210 return status;
1211 }
1212
1213 lookup:
1214 /*
1215 * This call can take a long time
1216 * allow the server to time out.
1217 * 35 seconds should do it.
1218 */
1219 orig_timeout = rpccli_set_timeout(cli, 35000);
1220
1221 status = lookup_sids_fn(cli,
1222 mem_ctx,
1223 &lsa_policy,
1224 num_sids,
1225 sids,
1226 domains,
1227 names,
1228 types);
1229
1230 /* And restore our original timeout. */
1231 rpccli_set_timeout(cli, orig_timeout);
1232
1233 if (!NT_STATUS_IS_OK(status)) {
1234 return status;
1235 }
1236
1237 return status;
1238}
1239
1240typedef NTSTATUS (*lookup_names_fn_t)(struct rpc_pipe_client *cli,
1241 TALLOC_CTX *mem_ctx,
1242 struct policy_handle *pol,
1243 int num_names,
1244 const char **names,
1245 const char ***dom_names,
1246 int level,
1247 struct dom_sid **sids,
1248 enum lsa_SidType **types);
1249
1250NTSTATUS winbindd_lookup_names(TALLOC_CTX *mem_ctx,
1251 struct winbindd_domain *domain,
1252 uint32_t num_names,
1253 const char **names,
1254 const char ***domains,
1255 struct dom_sid **sids,
1256 enum lsa_SidType **types)
1257{
1258 NTSTATUS status;
1259 struct rpc_pipe_client *cli = NULL;
1260 struct policy_handle lsa_policy;
1261 unsigned int orig_timeout = 0;
1262 lookup_names_fn_t lookup_names_fn = rpccli_lsa_lookup_names;
1263
1264 if (domain->can_do_ncacn_ip_tcp) {
1265 status = cm_connect_lsa_tcp(domain, mem_ctx, &cli);
1266 if (NT_STATUS_IS_OK(status)) {
1267 lookup_names_fn = rpccli_lsa_lookup_names4;
1268 goto lookup;
1269 }
1270 domain->can_do_ncacn_ip_tcp = false;
1271 }
1272 status = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
1273
1274 if (!NT_STATUS_IS_OK(status)) {
1275 return status;
1276 }
1277
1278 lookup:
1279
1280 /*
1281 * This call can take a long time
1282 * allow the server to time out.
1283 * 35 seconds should do it.
1284 */
1285 orig_timeout = rpccli_set_timeout(cli, 35000);
1286
1287 status = lookup_names_fn(cli,
1288 mem_ctx,
1289 &lsa_policy,
1290 num_names,
1291 (const char **) names,
1292 domains,
1293 1,
1294 sids,
1295 types);
1296
1297 /* And restore our original timeout. */
1298 rpccli_set_timeout(cli, orig_timeout);
1299
1300 if (!NT_STATUS_IS_OK(status)) {
1301 return status;
1302 }
1303
1304 return status;
1305}
1306
1307/* the rpc backend methods are exposed via this structure */
1308struct winbindd_methods msrpc_methods = {
1309 False,
1310 query_user_list,
1311 enum_dom_groups,
1312 enum_local_groups,
1313 msrpc_name_to_sid,
1314 msrpc_sid_to_name,
1315 msrpc_rids_to_names,
1316 query_user,
1317 lookup_usergroups,
1318 msrpc_lookup_useraliases,
1319 lookup_groupmem,
1320 sequence_number,
1321 msrpc_lockout_policy,
1322 msrpc_password_policy,
1323 trusted_domains,
1324};
Note: See TracBrowser for help on using the repository browser.