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 if (!NT_STATUS_IS_OK(result))
305 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
306 got_user_pol = False;
308 user_info->group_rid = ctr->info.id21->group_rid;
309 user_info->acct_name = unistr2_tdup(mem_ctx,
310 &ctr->info.id21->uni_user_name);
311 user_info->full_name = unistr2_tdup(mem_ctx,
312 &ctr->info.id21->uni_full_name);
315 /* Clean up policy handles */
317 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
320 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
325 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
326 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
329 uint32 *num_groups, uint32 **user_gids)
332 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
333 POLICY_HND dom_pol, user_pol;
334 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
335 BOOL got_dom_pol = False, got_user_pol = False;
336 DOM_GID *user_groups;
341 /* First try cached universal groups from logon */
342 *user_gids = uni_group_cache_fetch(&domain->sid, user_rid, mem_ctx, num_groups);
343 if((*num_groups > 0) && *user_gids) {
351 if (!(hnd = cm_get_sam_handle(domain->name)))
354 /* Get domain handle */
355 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
356 des_access, &domain->sid, &dom_pol);
358 if (!NT_STATUS_IS_OK(result))
363 /* Get user handle */
364 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
365 des_access, user_rid, &user_pol);
367 if (!NT_STATUS_IS_OK(result))
372 /* Query user rids */
373 result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
374 num_groups, &user_groups);
376 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
379 (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
380 for (i=0;i<(*num_groups);i++) {
381 (*user_gids)[i] = user_groups[i].g_rid;
385 /* Clean up policy handles */
387 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
390 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
396 /* Lookup group membership given a rid. */
397 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
399 uint32 group_rid, uint32 *num_names,
400 uint32 **rid_mem, char ***names,
404 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
405 uint32 i, total_names = 0;
406 POLICY_HND dom_pol, group_pol;
407 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
408 BOOL got_dom_pol = False, got_group_pol = False;
414 if (!(hnd = cm_get_sam_handle(domain->name)))
417 /* Get domain handle */
419 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
420 des_access, &domain->sid, &dom_pol);
422 if (!NT_STATUS_IS_OK(result))
427 /* Get group handle */
429 result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
430 des_access, group_rid, &group_pol);
432 if (!NT_STATUS_IS_OK(result))
435 got_group_pol = True;
437 /* Step #1: Get a list of user rids that are the members of the
440 result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
441 &group_pol, num_names, rid_mem,
444 if (!NT_STATUS_IS_OK(result))
447 /* Step #2: Convert list of rids into list of usernames. Do this
448 in bunches of ~1000 to avoid crashing NT4. It looks like there
449 is a buffer overflow or something like that lurking around
452 #define MAX_LOOKUP_RIDS 900
454 *names = talloc_zero(mem_ctx, *num_names * sizeof(char *));
455 *name_types = talloc_zero(mem_ctx, *num_names * sizeof(uint32));
457 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
458 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
459 uint32 tmp_num_names = 0;
460 char **tmp_names = NULL;
461 uint32 *tmp_types = NULL;
463 /* Lookup a chunk of rids */
465 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
466 &dom_pol, 1000, /* flags */
470 &tmp_names, &tmp_types);
472 if (!NT_STATUS_IS_OK(result))
475 /* Copy result into array. The talloc system will take
476 care of freeing the temporary arrays later on. */
478 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
481 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
484 total_names += tmp_num_names;
487 *num_names = total_names;
491 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
494 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
499 /* find the sequence number for a domain */
500 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
505 uint16 switch_value = 2;
507 uint32 seqnum = DOM_SEQUENCE_NONE;
509 BOOL got_dom_pol = False;
510 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
512 *seq = DOM_SEQUENCE_NONE;
514 if (!(mem_ctx = talloc_init_named("sequence_number[rpc]")))
515 return NT_STATUS_NO_MEMORY;
519 if (!(hnd = cm_get_sam_handle(domain->name)))
522 /* Get domain handle */
524 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
525 des_access, &domain->sid, &dom_pol);
527 if (!NT_STATUS_IS_OK(result))
532 /* Query domain info */
534 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
537 if (NT_STATUS_IS_OK(result)) {
538 seqnum = ctr.info.inf2.seq_num;
539 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
541 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
542 (unsigned)seqnum, domain->name ));
548 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
550 talloc_destroy(mem_ctx);
557 /* get a list of trusted domains */
558 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
565 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
567 uint32 pref_num_domains = 5;
571 if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
574 result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
575 &hnd->pol, &enum_ctx, &pref_num_domains,
576 num_domains, names, dom_sids);
581 /* find the domain sid for a domain */
582 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
584 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
589 if (!(mem_ctx = talloc_init_named("domain_sid[rpc]")))
590 return NT_STATUS_NO_MEMORY;
593 if (!(hnd = cm_get_lsa_handle(domain->name)))
596 status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
597 &hnd->pol, 0x05, level5_dom, sid);
600 talloc_destroy(mem_ctx);
604 /* the rpc backend methods are exposed via this structure */
605 struct winbindd_methods msrpc_methods = {