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_named("enum_dom_groups[rpc]");
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;
180 const char *full_name;
182 if (!(mem_ctx = talloc_init_named("name_to_sid[rpc] for [%s]\\[%s]", domain->name, name))) {
183 DEBUG(0, ("talloc_init failed!\n"));
184 return NT_STATUS_NO_MEMORY;
187 if (!(hnd = cm_get_lsa_handle(domain->name))) {
188 talloc_destroy(mem_ctx);
189 return NT_STATUS_UNSUCCESSFUL;
192 full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain->name, name);
195 DEBUG(0, ("talloc_asprintf failed!\n"));
196 talloc_destroy(mem_ctx);
197 return NT_STATUS_NO_MEMORY;
200 status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1,
201 &full_name, &sids, &types, &num_sids);
203 /* Return rid and type if lookup successful */
204 if (NT_STATUS_IS_OK(status)) {
205 sid_copy(sid, &sids[0]);
209 talloc_destroy(mem_ctx);
214 convert a domain SID to a user or group name
216 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
220 enum SID_NAME_USE *type)
229 if (!(hnd = cm_get_lsa_handle(domain->name)))
230 return NT_STATUS_UNSUCCESSFUL;
232 status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
233 1, sid, &domains, &names, &types,
236 if (NT_STATUS_IS_OK(status)) {
239 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
242 if (strcasecmp(domain->name, domains[0]) != 0) {
243 DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain->name, domains[0]));
244 return NT_STATUS_UNSUCCESSFUL;
250 /* Lookup user information from a rid or username. */
251 static NTSTATUS query_user(struct winbindd_domain *domain,
254 WINBIND_USERINFO *user_info)
258 POLICY_HND dom_pol, user_pol;
259 BOOL got_dom_pol = False, got_user_pol = False;
260 SAM_USERINFO_CTR *ctr;
263 if (!(hnd = cm_get_sam_handle(domain->name)))
266 /* Get domain handle */
268 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
269 SEC_RIGHTS_MAXIMUM_ALLOWED,
270 &domain->sid, &dom_pol);
272 if (!NT_STATUS_IS_OK(result))
277 /* Get user handle */
278 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
279 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
281 if (!NT_STATUS_IS_OK(result))
285 result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
288 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
290 user_info->group_rid = ctr->info.id21->group_rid;
291 user_info->acct_name = unistr2_tdup(mem_ctx,
292 &ctr->info.id21->uni_user_name);
293 user_info->full_name = unistr2_tdup(mem_ctx,
294 &ctr->info.id21->uni_full_name);
297 /* Clean up policy handles */
299 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
302 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
307 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
308 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
311 uint32 *num_groups, uint32 **user_gids)
314 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
315 POLICY_HND dom_pol, user_pol;
316 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
317 BOOL got_dom_pol = False, got_user_pol = False;
318 DOM_GID *user_groups;
323 /* First try cached universal groups from logon */
324 *user_gids = uni_group_cache_fetch(&domain->sid, user_rid, mem_ctx, num_groups);
325 if((*num_groups > 0) && *user_gids) {
333 if (!(hnd = cm_get_sam_handle(domain->name)))
336 /* Get domain handle */
337 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
338 des_access, &domain->sid, &dom_pol);
340 if (!NT_STATUS_IS_OK(result))
345 /* Get user handle */
346 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
347 des_access, user_rid, &user_pol);
349 if (!NT_STATUS_IS_OK(result))
354 /* Query user rids */
355 result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
356 num_groups, &user_groups);
358 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
361 (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
362 for (i=0;i<(*num_groups);i++) {
363 (*user_gids)[i] = user_groups[i].g_rid;
367 /* Clean up policy handles */
369 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
372 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
378 /* Lookup group membership given a rid. */
379 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
381 uint32 group_rid, uint32 *num_names,
382 uint32 **rid_mem, char ***names,
386 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
387 uint32 i, total_names = 0;
388 POLICY_HND dom_pol, group_pol;
389 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
390 BOOL got_dom_pol = False, got_group_pol = False;
396 if (!(hnd = cm_get_sam_handle(domain->name)))
399 /* Get domain handle */
401 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
402 des_access, &domain->sid, &dom_pol);
404 if (!NT_STATUS_IS_OK(result))
409 /* Get group handle */
411 result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
412 des_access, group_rid, &group_pol);
414 if (!NT_STATUS_IS_OK(result))
417 got_group_pol = True;
419 /* Step #1: Get a list of user rids that are the members of the
422 result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
423 &group_pol, num_names, rid_mem,
426 if (!NT_STATUS_IS_OK(result))
429 /* Step #2: Convert list of rids into list of usernames. Do this
430 in bunches of ~1000 to avoid crashing NT4. It looks like there
431 is a buffer overflow or something like that lurking around
434 #define MAX_LOOKUP_RIDS 900
436 *names = talloc(mem_ctx, *num_names * sizeof(char *));
437 *name_types = talloc(mem_ctx, *num_names * sizeof(uint32));
439 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
440 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
441 uint32 tmp_num_names = 0;
442 char **tmp_names = NULL;
443 uint32 *tmp_types = NULL;
445 /* Lookup a chunk of rids */
447 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
448 &dom_pol, 1000, /* flags */
452 &tmp_names, &tmp_types);
454 if (!NT_STATUS_IS_OK(result))
457 /* Copy result into array. The talloc system will take
458 care of freeing the temporary arrays later on. */
460 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
463 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
466 total_names += tmp_num_names;
469 *num_names = total_names;
473 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
476 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
481 /* find the sequence number for a domain */
482 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
487 uint16 switch_value = 2;
489 uint32 seqnum = DOM_SEQUENCE_NONE;
491 BOOL got_dom_pol = False;
492 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
494 *seq = DOM_SEQUENCE_NONE;
496 if (!(mem_ctx = talloc_init_named("sequence_number[rpc]")))
497 return NT_STATUS_NO_MEMORY;
501 if (!(hnd = cm_get_sam_handle(domain->name)))
504 /* Get domain handle */
506 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
507 des_access, &domain->sid, &dom_pol);
509 if (!NT_STATUS_IS_OK(result))
514 /* Query domain info */
516 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
519 if (NT_STATUS_IS_OK(result)) {
520 seqnum = ctr.info.inf2.seq_num;
521 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
523 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
524 (unsigned)seqnum, domain->name ));
530 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
532 talloc_destroy(mem_ctx);
539 /* get a list of trusted domains */
540 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
547 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
552 if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
555 result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
556 &hnd->pol, &enum_ctx, num_domains,
562 /* find the domain sid for a domain */
563 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
565 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
570 if (!(mem_ctx = talloc_init_named("domain_sid[rpc]")))
571 return NT_STATUS_NO_MEMORY;
574 if (!(hnd = cm_get_lsa_handle(domain->name)))
577 status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
578 &hnd->pol, 0x05, level5_dom, sid);
581 talloc_destroy(mem_ctx);
585 /* the rpc backend methods are exposed via this structure */
586 struct winbindd_methods msrpc_methods = {