2 Unix SMB/CIFS implementation.
4 Winbind rpc backend functions
6 Copyright (C) Tim Potter 2000-2001
7 Copyright (C) Andrew Tridgell 2001
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #define DBGC_CLASS DBGC_WINBIND
29 /* Query display info for a domain. This returns enough information plus a
30 bit extra to give an overview of domain users for the User Manager
32 static NTSTATUS query_user_list(struct winbindd_domain *domain,
35 WINBIND_USERINFO **info)
38 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
40 BOOL got_dom_pol = False;
41 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
42 int i, loop_count = 0;
45 DEBUG(3,("rpc: query_user_list\n"));
54 if (!(hnd = cm_get_sam_handle(domain->name)))
57 /* Get domain handle */
59 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
60 des_access, &domain->sid, &dom_pol);
62 } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
64 if (!NT_STATUS_IS_OK(result))
73 uint32 count = 0, start=i, max_entries, max_size;
77 ctr.sam.info1 = &info1;
79 ctx2 = talloc_init("winbindd dispinfo");
81 result = NT_STATUS_NO_MEMORY;
85 get_query_dispinfo_params(
86 loop_count, &max_entries, &max_size);
88 /* Query display info level 1 */
89 result = cli_samr_query_dispinfo(
90 hnd->cli, ctx2, &dom_pol, &start, 1, &count,
91 max_entries, max_size, &ctr);
95 if (!NT_STATUS_IS_OK(result) &&
96 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) break;
98 (*num_entries) += count;
100 /* now map the result into the WINBIND_USERINFO structure */
101 (*info) = talloc_realloc(mem_ctx, *info,
102 (*num_entries)*sizeof(WINBIND_USERINFO));
104 result = NT_STATUS_NO_MEMORY;
105 talloc_destroy(ctx2);
109 for (j=0;j<count;i++, j++) {
110 (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_acct_name);
111 (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_full_name);
112 (*info)[i].user_rid = info1.sam[j].rid_user;
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 (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS;
123 talloc_destroy(ctx2);
124 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
129 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
134 /* list all domain groups */
135 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
138 struct acct_info **info)
140 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
150 DEBUG(3,("rpc: enum_dom_groups\n"));
154 if (!(hnd = cm_get_sam_handle(domain->name)))
155 return NT_STATUS_UNSUCCESSFUL;
157 status = cli_samr_open_domain(hnd->cli, mem_ctx,
158 &hnd->pol, des_access, &domain->sid, &dom_pol);
159 } while (!NT_STATUS_IS_OK(status) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
161 if (!NT_STATUS_IS_OK(status))
165 struct acct_info *info2 = NULL;
167 TALLOC_CTX *mem_ctx2;
169 mem_ctx2 = talloc_init("enum_dom_groups[rpc]");
171 /* start is updated by this call. */
172 status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
174 0xFFFF, /* buffer size? */
177 if (!NT_STATUS_IS_OK(status) &&
178 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
179 talloc_destroy(mem_ctx2);
183 (*info) = talloc_realloc(mem_ctx, *info,
184 sizeof(**info) * ((*num_entries) + count));
186 talloc_destroy(mem_ctx2);
187 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
188 return NT_STATUS_NO_MEMORY;
191 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
192 (*num_entries) += count;
193 talloc_destroy(mem_ctx2);
194 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
196 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
201 /* List all domain groups */
203 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
206 struct acct_info **info)
208 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
219 if ( !(hnd = cm_get_sam_handle(domain->name)) )
220 return NT_STATUS_UNSUCCESSFUL;
222 result = cli_samr_open_domain( hnd->cli, mem_ctx, &hnd->pol,
223 des_access, &domain->sid, &dom_pol);
224 } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
226 if ( !NT_STATUS_IS_OK(result))
230 struct acct_info *info2 = NULL;
231 uint32 count = 0, start = *num_entries;
232 TALLOC_CTX *mem_ctx2;
234 mem_ctx2 = talloc_init("enum_dom_local_groups[rpc]");
236 result = cli_samr_enum_als_groups( hnd->cli, mem_ctx2, &dom_pol,
237 &start, 0xFFFF, &info2, &count);
239 if ( !NT_STATUS_IS_OK(result)
240 && !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES) )
242 talloc_destroy(mem_ctx2);
246 (*info) = talloc_realloc(mem_ctx, *info,
247 sizeof(**info) * ((*num_entries) + count));
249 talloc_destroy(mem_ctx2);
250 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
251 return NT_STATUS_NO_MEMORY;
254 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
255 (*num_entries) += count;
256 talloc_destroy(mem_ctx2);
257 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
259 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
264 /* convert a single name to a sid in a domain */
265 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
268 enum SID_NAME_USE *type)
273 DOM_SID *sids = NULL;
274 uint32 *types = NULL;
275 const char *full_name;
278 DEBUG(3,("rpc: name_to_sid name=%s\n", name));
280 if (!(mem_ctx = talloc_init("name_to_sid[rpc] for [%s]\\[%s]", domain->name, name))) {
281 DEBUG(0, ("talloc_init failed!\n"));
282 return NT_STATUS_NO_MEMORY;
285 full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain->name, name);
288 DEBUG(0, ("talloc_asprintf failed!\n"));
289 talloc_destroy(mem_ctx);
290 return NT_STATUS_NO_MEMORY;
295 if (!(hnd = cm_get_lsa_handle(domain->name))) {
296 talloc_destroy(mem_ctx);
297 return NT_STATUS_UNSUCCESSFUL;
300 status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1,
301 &full_name, &sids, &types);
302 } while (!NT_STATUS_IS_OK(status) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
304 /* Return rid and type if lookup successful */
306 if (NT_STATUS_IS_OK(status)) {
307 sid_copy(sid, &sids[0]);
311 talloc_destroy(mem_ctx);
316 convert a domain SID to a user or group name
318 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
322 enum SID_NAME_USE *type)
331 DEBUG(3,("rpc: sid_to_name\n"));
335 if (!(hnd = cm_get_lsa_handle(domain->name)))
336 return NT_STATUS_UNSUCCESSFUL;
338 status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
339 1, sid, &domains, &names, &types);
340 } while (!NT_STATUS_IS_OK(status) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
342 if (NT_STATUS_IS_OK(status)) {
345 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
348 if (strcasecmp(domain->name, domains[0]) != 0) {
349 DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain->name, domains[0]));
350 return NT_STATUS_UNSUCCESSFUL;
356 /* Lookup user information from a rid or username. */
357 static NTSTATUS query_user(struct winbindd_domain *domain,
360 WINBIND_USERINFO *user_info)
364 POLICY_HND dom_pol, user_pol;
365 BOOL got_dom_pol = False, got_user_pol = False;
366 SAM_USERINFO_CTR *ctr;
369 DEBUG(3,("rpc: query_user rid=%u\n", user_rid));
374 if (!(hnd = cm_get_sam_handle(domain->name)))
377 /* Get domain handle */
379 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
380 SEC_RIGHTS_MAXIMUM_ALLOWED,
381 &domain->sid, &dom_pol);
382 } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
384 if (!NT_STATUS_IS_OK(result))
389 /* Get user handle */
390 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
391 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
393 if (!NT_STATUS_IS_OK(result))
399 result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
402 if (!NT_STATUS_IS_OK(result))
405 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
406 got_user_pol = False;
408 user_info->user_rid = user_rid;
409 user_info->group_rid = ctr->info.id21->group_rid;
410 user_info->acct_name = unistr2_tdup(mem_ctx,
411 &ctr->info.id21->uni_user_name);
412 user_info->full_name = unistr2_tdup(mem_ctx,
413 &ctr->info.id21->uni_full_name);
416 /* Clean up policy handles */
418 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
421 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
426 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
427 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
430 uint32 *num_groups, uint32 **user_gids)
433 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
434 POLICY_HND dom_pol, user_pol;
435 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
436 BOOL got_dom_pol = False, got_user_pol = False;
437 DOM_GID *user_groups;
441 DEBUG(3,("rpc: lookup_usergroups rid=%u\n", user_rid));
445 /* First try cached universal groups from logon */
446 *user_gids = uni_group_cache_fetch(&domain->sid, user_rid, mem_ctx, num_groups);
447 if((*num_groups > 0) && *user_gids) {
457 if (!(hnd = cm_get_sam_handle(domain->name)))
460 /* Get domain handle */
461 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
462 des_access, &domain->sid, &dom_pol);
463 } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
465 if (!NT_STATUS_IS_OK(result))
470 /* Get user handle */
471 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
472 des_access, user_rid, &user_pol);
474 if (!NT_STATUS_IS_OK(result))
479 /* Query user rids */
480 result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
481 num_groups, &user_groups);
483 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
486 (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
487 for (i=0;i<(*num_groups);i++) {
488 (*user_gids)[i] = user_groups[i].g_rid;
492 /* Clean up policy handles */
494 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
497 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
503 /* Lookup group membership given a rid. */
504 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
506 uint32 group_rid, uint32 *num_names,
507 uint32 **rid_mem, char ***names,
511 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
512 uint32 i, total_names = 0;
513 POLICY_HND dom_pol, group_pol;
514 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
515 BOOL got_dom_pol = False, got_group_pol = False;
518 DEBUG(10,("rpc: lookup_groupmem %s rid=%u\n", domain->name, group_rid));
525 if (!(hnd = cm_get_sam_handle(domain->name)))
528 /* Get domain handle */
530 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
531 des_access, &domain->sid, &dom_pol);
532 } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
534 if (!NT_STATUS_IS_OK(result))
539 /* Get group handle */
541 result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
542 des_access, group_rid, &group_pol);
544 if (!NT_STATUS_IS_OK(result))
547 got_group_pol = True;
549 /* Step #1: Get a list of user rids that are the members of the
552 result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
553 &group_pol, num_names, rid_mem,
556 if (!NT_STATUS_IS_OK(result))
559 /* Step #2: Convert list of rids into list of usernames. Do this
560 in bunches of ~1000 to avoid crashing NT4. It looks like there
561 is a buffer overflow or something like that lurking around
564 #define MAX_LOOKUP_RIDS 900
566 *names = talloc_zero(mem_ctx, *num_names * sizeof(char *));
567 *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32));
569 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
570 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
571 uint32 tmp_num_names = 0;
572 char **tmp_names = NULL;
573 uint32 *tmp_types = NULL;
575 /* Lookup a chunk of rids */
577 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
578 &dom_pol, 1000, /* flags */
582 &tmp_names, &tmp_types);
584 if (!NT_STATUS_IS_OK(result))
587 /* Copy result into array. The talloc system will take
588 care of freeing the temporary arrays later on. */
590 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
593 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
596 total_names += tmp_num_names;
599 *num_names = total_names;
603 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
606 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
611 /* find the sequence number for a domain */
612 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
617 uint16 switch_value = 2;
619 uint32 seqnum = DOM_SEQUENCE_NONE;
621 BOOL got_dom_pol = False;
622 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
625 DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
627 *seq = DOM_SEQUENCE_NONE;
629 if (!(mem_ctx = talloc_init("sequence_number[rpc]")))
630 return NT_STATUS_NO_MEMORY;
635 if (!(hnd = cm_get_sam_handle(domain->name)))
638 /* Get domain handle */
639 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
640 des_access, &domain->sid, &dom_pol);
641 } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
643 if (!NT_STATUS_IS_OK(result))
648 /* Query domain info */
650 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
653 if (NT_STATUS_IS_OK(result)) {
654 seqnum = ctr.info.inf2.seq_num;
655 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
657 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
658 (unsigned)seqnum, domain->name ));
664 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
666 talloc_destroy(mem_ctx);
673 /* get a list of trusted domains */
674 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
682 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
686 DEBUG(3,("rpc: trusted_domains\n"));
693 if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
696 result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
697 &hnd->pol, &enum_ctx,
698 num_domains, names, dom_sids);
699 } while (!NT_STATUS_IS_OK(result) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
705 /* find the domain sid for a domain */
706 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
708 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
714 DEBUG(3,("rpc: domain_sid\n"));
716 if (!(mem_ctx = talloc_init("domain_sid[rpc]")))
717 return NT_STATUS_NO_MEMORY;
722 if (!(hnd = cm_get_lsa_handle(domain->name)))
725 status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
726 &hnd->pol, 0x05, level5_dom, sid);
727 } while (!NT_STATUS_IS_OK(status) && (retry++ < 1) && hnd && hnd->cli && hnd->cli->fd == -1);
730 talloc_destroy(mem_ctx);
734 /* find alternate names list for the domain - none for rpc */
735 static NTSTATUS alternate_name(struct winbindd_domain *domain)
741 /* the rpc backend methods are exposed via this structure */
742 struct winbindd_methods msrpc_methods = {