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.
26 /* Query display info for a domain. This returns enough information plus a
27 bit extra to give an overview of domain users for the User Manager
29 static NTSTATUS query_user_list(struct winbindd_domain *domain,
32 WINBIND_USERINFO **info)
35 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
37 BOOL got_dom_pol = False;
38 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
46 if (!(hnd = cm_get_sam_handle(domain->name)))
49 /* Get domain handle */
51 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
52 des_access, &domain->sid, &dom_pol);
54 if (!NT_STATUS_IS_OK(result))
63 uint32 count = 0, start=i;
67 ctr.sam.info1 = &info1;
69 ctx2 = talloc_init_named("winbindd dispinfo");
71 result = NT_STATUS_NO_MEMORY;
75 /* Query display info level 1 */
76 result = cli_samr_query_dispinfo(hnd->cli, ctx2,
78 &count, 0xFFFF, &ctr);
80 if (!NT_STATUS_IS_OK(result) &&
81 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) break;
83 (*num_entries) += count;
85 /* now map the result into the WINBIND_USERINFO structure */
86 (*info) = talloc_realloc(mem_ctx, *info,
87 (*num_entries)*sizeof(WINBIND_USERINFO));
89 result = NT_STATUS_NO_MEMORY;
94 for (j=0;j<count;i++, j++) {
95 (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_acct_name);
96 (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_full_name);
97 (*info)[i].user_rid = info1.sam[j].rid_user;
98 /* For the moment we set the primary group for
99 every user to be the Domain Users group.
100 There are serious problems with determining
101 the actual primary group for large domains.
102 This should really be made into a 'winbind
103 force group' smb.conf parameter or
104 something like that. */
105 (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS;
108 talloc_destroy(ctx2);
109 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
114 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
119 /* list all domain groups */
120 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
123 struct acct_info **info)
125 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
133 if (!(hnd = cm_get_sam_handle(domain->name))) {
134 return NT_STATUS_UNSUCCESSFUL;
137 status = cli_samr_open_domain(hnd->cli, mem_ctx,
138 &hnd->pol, des_access, &domain->sid, &dom_pol);
139 if (!NT_STATUS_IS_OK(status)) {
144 struct acct_info *info2 = NULL;
145 uint32 count = 0, start = *num_entries;
146 TALLOC_CTX *mem_ctx2;
148 mem_ctx2 = talloc_init_named("enum_dom_groups[rpc]");
150 status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
152 0xFFFF, /* buffer size? */
155 if (!NT_STATUS_IS_OK(status) &&
156 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
157 talloc_destroy(mem_ctx2);
161 (*info) = talloc_realloc(mem_ctx, *info,
162 sizeof(**info) * ((*num_entries) + count));
164 talloc_destroy(mem_ctx2);
165 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
166 return NT_STATUS_NO_MEMORY;
169 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
170 (*num_entries) += count;
171 talloc_destroy(mem_ctx2);
172 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
174 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
179 /* convert a single name to a sid in a domain */
180 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
183 enum SID_NAME_USE *type)
188 DOM_SID *sids = NULL;
189 uint32 *types = NULL;
190 const char *full_name;
192 if (!(mem_ctx = talloc_init_named("name_to_sid[rpc] for [%s]\\[%s]", domain->name, name))) {
193 DEBUG(0, ("talloc_init failed!\n"));
194 return NT_STATUS_NO_MEMORY;
197 if (!(hnd = cm_get_lsa_handle(domain->name))) {
198 talloc_destroy(mem_ctx);
199 return NT_STATUS_UNSUCCESSFUL;
202 full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain->name, name);
205 DEBUG(0, ("talloc_asprintf failed!\n"));
206 talloc_destroy(mem_ctx);
207 return NT_STATUS_NO_MEMORY;
210 status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1,
211 &full_name, &sids, &types);
213 /* Return rid and type if lookup successful */
215 if (NT_STATUS_IS_OK(status)) {
216 sid_copy(sid, &sids[0]);
220 talloc_destroy(mem_ctx);
225 convert a domain SID to a user or group name
227 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
231 enum SID_NAME_USE *type)
239 if (!(hnd = cm_get_lsa_handle(domain->name)))
240 return NT_STATUS_UNSUCCESSFUL;
242 status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
243 1, sid, &domains, &names, &types);
245 if (NT_STATUS_IS_OK(status)) {
248 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
251 if (strcasecmp(domain->name, domains[0]) != 0) {
252 DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain->name, domains[0]));
253 return NT_STATUS_UNSUCCESSFUL;
259 /* Lookup user information from a rid or username. */
260 static NTSTATUS query_user(struct winbindd_domain *domain,
263 WINBIND_USERINFO *user_info)
267 POLICY_HND dom_pol, user_pol;
268 BOOL got_dom_pol = False, got_user_pol = False;
269 SAM_USERINFO_CTR *ctr;
272 if (!(hnd = cm_get_sam_handle(domain->name)))
275 /* Get domain handle */
277 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
278 SEC_RIGHTS_MAXIMUM_ALLOWED,
279 &domain->sid, &dom_pol);
281 if (!NT_STATUS_IS_OK(result))
286 /* Get user handle */
287 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
288 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
290 if (!NT_STATUS_IS_OK(result))
296 result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
299 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
300 got_user_pol = False;
302 user_info->group_rid = ctr->info.id21->group_rid;
303 user_info->acct_name = unistr2_tdup(mem_ctx,
304 &ctr->info.id21->uni_user_name);
305 user_info->full_name = unistr2_tdup(mem_ctx,
306 &ctr->info.id21->uni_full_name);
309 /* Clean up policy handles */
311 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
314 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
319 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
320 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
323 uint32 *num_groups, uint32 **user_gids)
326 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
327 POLICY_HND dom_pol, user_pol;
328 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
329 BOOL got_dom_pol = False, got_user_pol = False;
330 DOM_GID *user_groups;
335 /* First try cached universal groups from logon */
336 *user_gids = uni_group_cache_fetch(&domain->sid, user_rid, mem_ctx, num_groups);
337 if((*num_groups > 0) && *user_gids) {
345 if (!(hnd = cm_get_sam_handle(domain->name)))
348 /* Get domain handle */
349 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
350 des_access, &domain->sid, &dom_pol);
352 if (!NT_STATUS_IS_OK(result))
357 /* Get user handle */
358 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
359 des_access, user_rid, &user_pol);
361 if (!NT_STATUS_IS_OK(result))
366 /* Query user rids */
367 result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
368 num_groups, &user_groups);
370 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
373 (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
374 for (i=0;i<(*num_groups);i++) {
375 (*user_gids)[i] = user_groups[i].g_rid;
379 /* Clean up policy handles */
381 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
384 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
390 /* Lookup group membership given a rid. */
391 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
393 uint32 group_rid, uint32 *num_names,
394 uint32 **rid_mem, char ***names,
398 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
399 uint32 i, total_names = 0;
400 POLICY_HND dom_pol, group_pol;
401 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
402 BOOL got_dom_pol = False, got_group_pol = False;
408 if (!(hnd = cm_get_sam_handle(domain->name)))
411 /* Get domain handle */
413 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
414 des_access, &domain->sid, &dom_pol);
416 if (!NT_STATUS_IS_OK(result))
421 /* Get group handle */
423 result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
424 des_access, group_rid, &group_pol);
426 if (!NT_STATUS_IS_OK(result))
429 got_group_pol = True;
431 /* Step #1: Get a list of user rids that are the members of the
434 result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
435 &group_pol, num_names, rid_mem,
438 if (!NT_STATUS_IS_OK(result))
441 /* Step #2: Convert list of rids into list of usernames. Do this
442 in bunches of ~1000 to avoid crashing NT4. It looks like there
443 is a buffer overflow or something like that lurking around
446 #define MAX_LOOKUP_RIDS 900
448 *names = talloc_zero(mem_ctx, *num_names * sizeof(char *));
449 *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32));
451 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
452 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
453 uint32 tmp_num_names = 0;
454 char **tmp_names = NULL;
455 uint32 *tmp_types = NULL;
457 /* Lookup a chunk of rids */
459 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
460 &dom_pol, 1000, /* flags */
464 &tmp_names, &tmp_types);
466 if (!NT_STATUS_IS_OK(result))
469 /* Copy result into array. The talloc system will take
470 care of freeing the temporary arrays later on. */
472 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
475 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
478 total_names += tmp_num_names;
481 *num_names = total_names;
485 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
488 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
493 /* find the sequence number for a domain */
494 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
499 uint16 switch_value = 2;
501 uint32 seqnum = DOM_SEQUENCE_NONE;
503 BOOL got_dom_pol = False;
504 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
506 *seq = DOM_SEQUENCE_NONE;
508 if (!(mem_ctx = talloc_init_named("sequence_number[rpc]")))
509 return NT_STATUS_NO_MEMORY;
513 if (!(hnd = cm_get_sam_handle(domain->name)))
516 /* Get domain handle */
518 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
519 des_access, &domain->sid, &dom_pol);
521 if (!NT_STATUS_IS_OK(result))
526 /* Query domain info */
528 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
531 if (NT_STATUS_IS_OK(result)) {
532 seqnum = ctr.info.inf2.seq_num;
533 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
535 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
536 (unsigned)seqnum, domain->name ));
542 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
544 talloc_destroy(mem_ctx);
551 /* get a list of trusted domains */
552 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
559 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
561 uint32 pref_num_domains = 5;
565 if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
568 result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
569 &hnd->pol, &enum_ctx, &pref_num_domains,
570 num_domains, names, dom_sids);
575 /* find the domain sid for a domain */
576 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
578 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
583 if (!(mem_ctx = talloc_init_named("domain_sid[rpc]")))
584 return NT_STATUS_NO_MEMORY;
587 if (!(hnd = cm_get_lsa_handle(domain->name)))
590 status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
591 &hnd->pol, 0x05, level5_dom, sid);
594 talloc_destroy(mem_ctx);
598 /* the rpc backend methods are exposed via this structure */
599 struct winbindd_methods msrpc_methods = {