2 Unix SMB/Netbios 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;
48 if (!(hnd = cm_get_sam_handle(domain->name)))
51 /* Get domain handle */
53 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
54 des_access, &domain->sid, &dom_pol);
56 if (!NT_STATUS_IS_OK(result))
61 ctr.sam.info1 = &info1;
65 uint32 count = 0, start=i;
69 /* Query display info level 1 */
70 result = cli_samr_query_dispinfo(hnd->cli, mem_ctx,
72 &count, 0xFFFF, &ctr);
74 if (!NT_STATUS_IS_OK(result) &&
75 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) break;
77 (*num_entries) += count;
79 /* now map the result into the WINBIND_USERINFO structure */
80 (*info) = talloc_realloc(mem_ctx, *info,
81 (*num_entries)*sizeof(WINBIND_USERINFO));
83 return NT_STATUS_NO_MEMORY;
86 for (j=0;j<count;i++, j++) {
87 (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_acct_name);
88 (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_full_name);
89 (*info)[i].user_rid = info1.sam[j].rid_user;
90 /* For the moment we set the primary group for
91 every user to be the Domain Users group.
92 There are serious problems with determining
93 the actual primary group for large domains.
94 This should really be made into a 'winbind
95 force group' smb.conf parameter or
96 something like that. */
97 (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS;
99 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
104 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
109 /* list all domain groups */
110 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
113 struct acct_info **info)
115 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
123 if (!(hnd = cm_get_sam_handle(domain->name))) {
124 return NT_STATUS_UNSUCCESSFUL;
127 status = cli_samr_open_domain(hnd->cli, mem_ctx,
128 &hnd->pol, des_access, &domain->sid, &dom_pol);
129 if (!NT_STATUS_IS_OK(status)) {
134 struct acct_info *info2 = NULL;
135 uint32 count = 0, start = *num_entries;
136 TALLOC_CTX *mem_ctx2;
138 mem_ctx2 = talloc_init();
140 status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
142 0xFFFF, /* buffer size? */
145 if (!NT_STATUS_IS_OK(status) &&
146 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
147 talloc_destroy(mem_ctx2);
151 (*info) = talloc_realloc(mem_ctx, *info,
152 sizeof(**info) * ((*num_entries) + count));
154 talloc_destroy(mem_ctx2);
155 return NT_STATUS_NO_MEMORY;
158 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
159 (*num_entries) += count;
160 talloc_destroy(mem_ctx2);
161 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
163 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
168 /* convert a single name to a sid in a domain */
169 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
172 enum SID_NAME_USE *type)
177 DOM_SID *sids = NULL;
178 uint32 *types = NULL;
181 if (!(mem_ctx = talloc_init()))
182 return NT_STATUS_NO_MEMORY;
184 if (!(hnd = cm_get_lsa_handle(domain->name)))
185 return NT_STATUS_UNSUCCESSFUL;
187 status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1, &name,
188 &sids, &types, &num_sids);
190 /* Return rid and type if lookup successful */
191 if (NT_STATUS_IS_OK(status)) {
192 sid_copy(sid, &sids[0]);
196 talloc_destroy(mem_ctx);
201 convert a domain SID to a user or group name
203 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
207 enum SID_NAME_USE *type)
215 if (!(hnd = cm_get_lsa_handle(domain->name)))
216 return NT_STATUS_UNSUCCESSFUL;
218 status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
219 1, sid, &names, &types,
222 if (NT_STATUS_IS_OK(status)) {
225 DEBUG(5,("Mapped sid to %s\n", *name));
231 /* Lookup user information from a rid or username. */
232 static NTSTATUS query_user(struct winbindd_domain *domain,
235 WINBIND_USERINFO *user_info)
239 POLICY_HND dom_pol, user_pol;
240 BOOL got_dom_pol = False, got_user_pol = False;
241 SAM_USERINFO_CTR *ctr;
244 if (!(hnd = cm_get_sam_handle(domain->name)))
247 /* Get domain handle */
249 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
250 SEC_RIGHTS_MAXIMUM_ALLOWED,
251 &domain->sid, &dom_pol);
253 if (!NT_STATUS_IS_OK(result))
258 /* Get user handle */
259 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
260 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
262 if (!NT_STATUS_IS_OK(result))
266 result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
269 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
271 user_info->group_rid = ctr->info.id21->group_rid;
272 user_info->acct_name = unistr2_tdup(mem_ctx,
273 &ctr->info.id21->uni_user_name);
274 user_info->full_name = unistr2_tdup(mem_ctx,
275 &ctr->info.id21->uni_full_name);
278 /* Clean up policy handles */
280 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
283 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
288 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
289 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
292 uint32 *num_groups, uint32 **user_gids)
295 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
296 POLICY_HND dom_pol, user_pol;
297 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
298 BOOL got_dom_pol = False, got_user_pol = False;
299 DOM_GID *user_groups;
305 if (!(hnd = cm_get_sam_handle(domain->name)))
308 /* Get domain handle */
309 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
310 des_access, &domain->sid, &dom_pol);
312 if (!NT_STATUS_IS_OK(result))
317 /* Get user handle */
318 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
319 des_access, user_rid, &user_pol);
321 if (!NT_STATUS_IS_OK(result))
326 /* Query user rids */
327 result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
328 num_groups, &user_groups);
330 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
333 (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
334 for (i=0;i<(*num_groups);i++) {
335 (*user_gids)[i] = user_groups[i].g_rid;
339 /* Clean up policy handles */
341 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
344 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
350 /* Lookup group membership given a rid. */
351 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
353 uint32 group_rid, uint32 *num_names,
354 uint32 **rid_mem, char ***names,
358 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
359 uint32 i, total_names = 0;
360 POLICY_HND dom_pol, group_pol;
361 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
362 BOOL got_dom_pol = False, got_group_pol = False;
368 if (!(hnd = cm_get_sam_handle(domain->name)))
371 /* Get domain handle */
373 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
374 des_access, &domain->sid, &dom_pol);
376 if (!NT_STATUS_IS_OK(result))
381 /* Get group handle */
383 result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
384 des_access, group_rid, &group_pol);
386 if (!NT_STATUS_IS_OK(result))
389 got_group_pol = True;
391 /* Step #1: Get a list of user rids that are the members of the
394 result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
395 &group_pol, num_names, rid_mem,
398 if (!NT_STATUS_IS_OK(result))
401 /* Step #2: Convert list of rids into list of usernames. Do this
402 in bunches of ~1000 to avoid crashing NT4. It looks like there
403 is a buffer overflow or something like that lurking around
406 #define MAX_LOOKUP_RIDS 900
408 *names = talloc(mem_ctx, *num_names * sizeof(char *));
409 *name_types = talloc(mem_ctx, *num_names * sizeof(uint32));
411 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
412 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
413 uint32 tmp_num_names = 0;
414 char **tmp_names = NULL;
415 uint32 *tmp_types = NULL;
417 /* Lookup a chunk of rids */
419 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
420 &dom_pol, 1000, /* flags */
424 &tmp_names, &tmp_types);
426 if (!NT_STATUS_IS_OK(result))
429 /* Copy result into array. The talloc system will take
430 care of freeing the temporary arrays later on. */
432 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
435 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
438 total_names += tmp_num_names;
441 *num_names = total_names;
445 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
448 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
453 /* find the sequence number for a domain */
454 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
459 uint16 switch_value = 2;
461 uint32 seqnum = DOM_SEQUENCE_NONE;
463 BOOL got_dom_pol = False;
464 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
466 *seq = DOM_SEQUENCE_NONE;
468 if (!(mem_ctx = talloc_init()))
469 return NT_STATUS_NO_MEMORY;
473 if (!(hnd = cm_get_sam_handle(domain->name)))
476 /* Get domain handle */
478 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
479 des_access, &domain->sid, &dom_pol);
481 if (!NT_STATUS_IS_OK(result))
486 /* Query domain info */
488 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
491 if (NT_STATUS_IS_OK(result)) {
492 seqnum = ctr.info.inf2.seq_num;
493 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
495 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
496 (unsigned)seqnum, domain->name ));
502 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
504 talloc_destroy(mem_ctx);
511 /* get a list of trusted domains */
512 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
519 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
524 if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
527 result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
528 &hnd->pol, &enum_ctx, num_domains,
534 /* find the domain sid for a domain */
535 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
537 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
542 if (!(mem_ctx = talloc_init()))
543 return NT_STATUS_NO_MEMORY;
546 if (!(hnd = cm_get_lsa_handle(domain->name)))
549 status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
550 &hnd->pol, 0x05, level5_dom, sid);
553 talloc_destroy(mem_ctx);
557 /* the rpc backend methods are exposed via this structure */
558 struct winbindd_methods msrpc_methods = {