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;
49 if (!(hnd = cm_get_sam_handle(domain->name)))
52 /* Get domain handle */
54 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
55 des_access, &domain->sid, &dom_pol);
57 if (!NT_STATUS_IS_OK(result))
66 uint32 count = 0, start=i;
70 ctr.sam.info1 = &info1;
72 ctx2 = talloc_init_named("winbindd dispinfo");
74 result = NT_STATUS_NO_MEMORY;
78 /* Query display info level 1 */
79 result = cli_samr_query_dispinfo(hnd->cli, ctx2,
81 &count, 0xFFFF, &ctr);
83 if (!NT_STATUS_IS_OK(result) &&
84 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) break;
86 (*num_entries) += count;
88 /* now map the result into the WINBIND_USERINFO structure */
89 (*info) = talloc_realloc(mem_ctx, *info,
90 (*num_entries)*sizeof(WINBIND_USERINFO));
92 result = NT_STATUS_NO_MEMORY;
97 for (j=0;j<count;i++, j++) {
98 (*info)[i].acct_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_acct_name);
99 (*info)[i].full_name = unistr2_tdup(mem_ctx, &info1.str[j].uni_full_name);
100 (*info)[i].user_rid = info1.sam[j].rid_user;
101 /* For the moment we set the primary group for
102 every user to be the Domain Users group.
103 There are serious problems with determining
104 the actual primary group for large domains.
105 This should really be made into a 'winbind
106 force group' smb.conf parameter or
107 something like that. */
108 (*info)[i].group_rid = DOMAIN_GROUP_RID_USERS;
111 talloc_destroy(ctx2);
112 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
117 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
122 /* list all domain groups */
123 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
126 struct acct_info **info)
128 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
136 if (!(hnd = cm_get_sam_handle(domain->name))) {
137 return NT_STATUS_UNSUCCESSFUL;
140 status = cli_samr_open_domain(hnd->cli, mem_ctx,
141 &hnd->pol, des_access, &domain->sid, &dom_pol);
142 if (!NT_STATUS_IS_OK(status)) {
147 struct acct_info *info2 = NULL;
148 uint32 count = 0, start = *num_entries;
149 TALLOC_CTX *mem_ctx2;
151 mem_ctx2 = talloc_init_named("enum_dom_groups[rpc]");
153 status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx2, &dom_pol,
155 0xFFFF, /* buffer size? */
158 if (!NT_STATUS_IS_OK(status) &&
159 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
160 talloc_destroy(mem_ctx2);
164 (*info) = talloc_realloc(mem_ctx, *info,
165 sizeof(**info) * ((*num_entries) + count));
167 talloc_destroy(mem_ctx2);
168 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
169 return NT_STATUS_NO_MEMORY;
172 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
173 (*num_entries) += count;
174 talloc_destroy(mem_ctx2);
175 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
177 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
182 /* convert a single name to a sid in a domain */
183 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
186 enum SID_NAME_USE *type)
191 DOM_SID *sids = NULL;
192 uint32 *types = NULL;
193 const char *full_name;
195 if (!(mem_ctx = talloc_init_named("name_to_sid[rpc] for [%s]\\[%s]", domain->name, name))) {
196 DEBUG(0, ("talloc_init failed!\n"));
197 return NT_STATUS_NO_MEMORY;
200 if (!(hnd = cm_get_lsa_handle(domain->name))) {
201 talloc_destroy(mem_ctx);
202 return NT_STATUS_UNSUCCESSFUL;
205 full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain->name, name);
208 DEBUG(0, ("talloc_asprintf failed!\n"));
209 talloc_destroy(mem_ctx);
210 return NT_STATUS_NO_MEMORY;
213 status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1,
214 &full_name, &sids, &types);
216 /* Return rid and type if lookup successful */
218 if (NT_STATUS_IS_OK(status)) {
219 sid_copy(sid, &sids[0]);
223 talloc_destroy(mem_ctx);
228 convert a domain SID to a user or group name
230 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
234 enum SID_NAME_USE *type)
242 if (!(hnd = cm_get_lsa_handle(domain->name)))
243 return NT_STATUS_UNSUCCESSFUL;
245 status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
246 1, sid, &domains, &names, &types);
248 if (NT_STATUS_IS_OK(status)) {
251 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
254 if (strcasecmp(domain->name, domains[0]) != 0) {
255 DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain->name, domains[0]));
256 return NT_STATUS_UNSUCCESSFUL;
262 /* Lookup user information from a rid or username. */
263 static NTSTATUS query_user(struct winbindd_domain *domain,
266 WINBIND_USERINFO *user_info)
270 POLICY_HND dom_pol, user_pol;
271 BOOL got_dom_pol = False, got_user_pol = False;
272 SAM_USERINFO_CTR *ctr;
275 if (!(hnd = cm_get_sam_handle(domain->name)))
278 /* Get domain handle */
280 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
281 SEC_RIGHTS_MAXIMUM_ALLOWED,
282 &domain->sid, &dom_pol);
284 if (!NT_STATUS_IS_OK(result))
289 /* Get user handle */
290 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
291 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
293 if (!NT_STATUS_IS_OK(result))
299 result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
302 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
303 got_user_pol = False;
305 user_info->group_rid = ctr->info.id21->group_rid;
306 user_info->acct_name = unistr2_tdup(mem_ctx,
307 &ctr->info.id21->uni_user_name);
308 user_info->full_name = unistr2_tdup(mem_ctx,
309 &ctr->info.id21->uni_full_name);
312 /* Clean up policy handles */
314 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
317 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
322 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
323 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
326 uint32 *num_groups, uint32 **user_gids)
329 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
330 POLICY_HND dom_pol, user_pol;
331 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
332 BOOL got_dom_pol = False, got_user_pol = False;
333 DOM_GID *user_groups;
338 /* First try cached universal groups from logon */
339 *user_gids = uni_group_cache_fetch(&domain->sid, user_rid, mem_ctx, num_groups);
340 if((*num_groups > 0) && *user_gids) {
348 if (!(hnd = cm_get_sam_handle(domain->name)))
351 /* Get domain handle */
352 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
353 des_access, &domain->sid, &dom_pol);
355 if (!NT_STATUS_IS_OK(result))
360 /* Get user handle */
361 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
362 des_access, user_rid, &user_pol);
364 if (!NT_STATUS_IS_OK(result))
369 /* Query user rids */
370 result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
371 num_groups, &user_groups);
373 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
376 (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
377 for (i=0;i<(*num_groups);i++) {
378 (*user_gids)[i] = user_groups[i].g_rid;
382 /* Clean up policy handles */
384 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
387 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
393 /* Lookup group membership given a rid. */
394 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
396 uint32 group_rid, uint32 *num_names,
397 uint32 **rid_mem, char ***names,
401 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
402 uint32 i, total_names = 0;
403 POLICY_HND dom_pol, group_pol;
404 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
405 BOOL got_dom_pol = False, got_group_pol = False;
411 if (!(hnd = cm_get_sam_handle(domain->name)))
414 /* Get domain handle */
416 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
417 des_access, &domain->sid, &dom_pol);
419 if (!NT_STATUS_IS_OK(result))
424 /* Get group handle */
426 result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
427 des_access, group_rid, &group_pol);
429 if (!NT_STATUS_IS_OK(result))
432 got_group_pol = True;
434 /* Step #1: Get a list of user rids that are the members of the
437 result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
438 &group_pol, num_names, rid_mem,
441 if (!NT_STATUS_IS_OK(result))
444 /* Step #2: Convert list of rids into list of usernames. Do this
445 in bunches of ~1000 to avoid crashing NT4. It looks like there
446 is a buffer overflow or something like that lurking around
449 #define MAX_LOOKUP_RIDS 900
451 *names = talloc_zero(mem_ctx, *num_names * sizeof(char *));
452 *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32));
454 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
455 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
456 uint32 tmp_num_names = 0;
457 char **tmp_names = NULL;
458 uint32 *tmp_types = NULL;
460 /* Lookup a chunk of rids */
462 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
463 &dom_pol, 1000, /* flags */
467 &tmp_names, &tmp_types);
469 if (!NT_STATUS_IS_OK(result))
472 /* Copy result into array. The talloc system will take
473 care of freeing the temporary arrays later on. */
475 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
478 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
481 total_names += tmp_num_names;
484 *num_names = total_names;
488 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
491 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
496 /* find the sequence number for a domain */
497 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
502 uint16 switch_value = 2;
504 uint32 seqnum = DOM_SEQUENCE_NONE;
506 BOOL got_dom_pol = False;
507 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
509 *seq = DOM_SEQUENCE_NONE;
511 if (!(mem_ctx = talloc_init_named("sequence_number[rpc]")))
512 return NT_STATUS_NO_MEMORY;
516 if (!(hnd = cm_get_sam_handle(domain->name)))
519 /* Get domain handle */
521 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
522 des_access, &domain->sid, &dom_pol);
524 if (!NT_STATUS_IS_OK(result))
529 /* Query domain info */
531 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
534 if (NT_STATUS_IS_OK(result)) {
535 seqnum = ctr.info.inf2.seq_num;
536 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
538 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
539 (unsigned)seqnum, domain->name ));
545 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
547 talloc_destroy(mem_ctx);
554 /* get a list of trusted domains */
555 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
562 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
564 uint32 pref_num_domains = 5;
568 if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
571 result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
572 &hnd->pol, &enum_ctx, &pref_num_domains,
573 num_domains, names, dom_sids);
578 /* find the domain sid for a domain */
579 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
581 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
586 if (!(mem_ctx = talloc_init_named("domain_sid[rpc]")))
587 return NT_STATUS_NO_MEMORY;
590 if (!(hnd = cm_get_lsa_handle(domain->name)))
593 status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
594 &hnd->pol, 0x05, level5_dom, sid);
597 talloc_destroy(mem_ctx);
601 /* the rpc backend methods are exposed via this structure */
602 struct winbindd_methods msrpc_methods = {