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,
112 uint32 *start_ndx, uint32 *num_entries,
113 struct acct_info **info)
115 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
122 if (!(hnd = cm_get_sam_handle(domain->name))) {
123 return NT_STATUS_UNSUCCESSFUL;
126 status = cli_samr_open_domain(hnd->cli, mem_ctx,
127 &hnd->pol, des_access, &domain->sid, &dom_pol);
128 if (!NT_STATUS_IS_OK(status)) {
132 status = cli_samr_enum_dom_groups(hnd->cli, mem_ctx, &dom_pol,
134 0x8000, /* buffer size? */
137 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
142 /* convert a single name to a sid in a domain */
143 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
146 enum SID_NAME_USE *type)
151 DOM_SID *sids = NULL;
152 uint32 *types = NULL;
155 if (!(mem_ctx = talloc_init()))
156 return NT_STATUS_NO_MEMORY;
158 if (!(hnd = cm_get_lsa_handle(domain->name)))
159 return NT_STATUS_UNSUCCESSFUL;
161 status = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, 1, &name,
162 &sids, &types, &num_sids);
164 /* Return rid and type if lookup successful */
165 if (NT_STATUS_IS_OK(status)) {
166 sid_copy(sid, &sids[0]);
170 talloc_destroy(mem_ctx);
175 convert a domain SID to a user or group name
177 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
181 enum SID_NAME_USE *type)
189 if (!(hnd = cm_get_lsa_handle(domain->name)))
190 return NT_STATUS_UNSUCCESSFUL;
192 status = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol,
193 1, sid, &names, &types,
196 if (NT_STATUS_IS_OK(status)) {
199 DEBUG(5,("Mapped sid to %s\n", *name));
205 /* Lookup user information from a rid or username. */
206 static NTSTATUS query_user(struct winbindd_domain *domain,
209 WINBIND_USERINFO *user_info)
213 POLICY_HND dom_pol, user_pol;
214 BOOL got_dom_pol = False, got_user_pol = False;
215 SAM_USERINFO_CTR *ctr;
218 if (!(hnd = cm_get_sam_handle(domain->name)))
221 /* Get domain handle */
223 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
224 SEC_RIGHTS_MAXIMUM_ALLOWED,
225 &domain->sid, &dom_pol);
227 if (!NT_STATUS_IS_OK(result))
232 /* Get user handle */
233 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
234 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
236 if (!NT_STATUS_IS_OK(result))
240 result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol,
243 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
245 user_info->group_rid = ctr->info.id21->group_rid;
246 user_info->acct_name = unistr2_tdup(mem_ctx,
247 &ctr->info.id21->uni_user_name);
248 user_info->full_name = unistr2_tdup(mem_ctx,
249 &ctr->info.id21->uni_full_name);
252 /* Clean up policy handles */
254 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
257 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
262 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
263 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
266 uint32 *num_groups, uint32 **user_gids)
269 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
270 POLICY_HND dom_pol, user_pol;
271 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
272 BOOL got_dom_pol = False, got_user_pol = False;
273 DOM_GID *user_groups;
279 if (!(hnd = cm_get_sam_handle(domain->name)))
282 /* Get domain handle */
283 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
284 des_access, &domain->sid, &dom_pol);
286 if (!NT_STATUS_IS_OK(result))
291 /* Get user handle */
292 result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol,
293 des_access, user_rid, &user_pol);
295 if (!NT_STATUS_IS_OK(result))
300 /* Query user rids */
301 result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol,
302 num_groups, &user_groups);
304 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
307 (*user_gids) = talloc(mem_ctx, sizeof(uint32) * (*num_groups));
308 for (i=0;i<(*num_groups);i++) {
309 (*user_gids)[i] = user_groups[i].g_rid;
313 /* Clean up policy handles */
315 cli_samr_close(hnd->cli, mem_ctx, &user_pol);
318 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
324 /* Lookup group membership given a rid. */
325 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
327 uint32 group_rid, uint32 *num_names,
328 uint32 **rid_mem, char ***names,
332 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
333 uint32 i, total_names = 0;
334 POLICY_HND dom_pol, group_pol;
335 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
336 BOOL got_dom_pol = False, got_group_pol = False;
342 if (!(hnd = cm_get_sam_handle(domain->name)))
345 /* Get domain handle */
347 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
348 des_access, &domain->sid, &dom_pol);
350 if (!NT_STATUS_IS_OK(result))
355 /* Get group handle */
357 result = cli_samr_open_group(hnd->cli, mem_ctx, &dom_pol,
358 des_access, group_rid, &group_pol);
360 if (!NT_STATUS_IS_OK(result))
363 got_group_pol = True;
365 /* Step #1: Get a list of user rids that are the members of the
368 result = cli_samr_query_groupmem(hnd->cli, mem_ctx,
369 &group_pol, num_names, rid_mem,
372 if (!NT_STATUS_IS_OK(result))
375 /* Step #2: Convert list of rids into list of usernames. Do this
376 in bunches of ~1000 to avoid crashing NT4. It looks like there
377 is a buffer overflow or something like that lurking around
380 #define MAX_LOOKUP_RIDS 900
382 *names = talloc(mem_ctx, *num_names * sizeof(char *));
383 *name_types = talloc(mem_ctx, *num_names * sizeof(uint32));
385 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
386 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
387 uint32 tmp_num_names = 0;
388 char **tmp_names = NULL;
389 uint32 *tmp_types = NULL;
391 /* Lookup a chunk of rids */
393 result = cli_samr_lookup_rids(hnd->cli, mem_ctx,
394 &dom_pol, 1000, /* flags */
398 &tmp_names, &tmp_types);
400 if (!NT_STATUS_IS_OK(result))
403 /* Copy result into array. The talloc system will take
404 care of freeing the temporary arrays later on. */
406 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
409 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
412 total_names += tmp_num_names;
415 *num_names = total_names;
419 cli_samr_close(hnd->cli, mem_ctx, &group_pol);
422 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
427 /* find the sequence number for a domain */
428 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
433 uint16 switch_value = 2;
435 uint32 seqnum = DOM_SEQUENCE_NONE;
437 BOOL got_dom_pol = False;
438 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
440 *seq = DOM_SEQUENCE_NONE;
442 if (!(mem_ctx = talloc_init()))
443 return NT_STATUS_NO_MEMORY;
447 if (!(hnd = cm_get_sam_handle(domain->name)))
450 /* Get domain handle */
452 result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol,
453 des_access, &domain->sid, &dom_pol);
455 if (!NT_STATUS_IS_OK(result))
460 /* Query domain info */
462 result = cli_samr_query_dom_info(hnd->cli, mem_ctx, &dom_pol,
465 if (NT_STATUS_IS_OK(result)) {
466 seqnum = ctr.info.inf2.seq_num;
467 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain->name, (unsigned)seqnum ));
469 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
470 (unsigned)seqnum, domain->name ));
476 cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
478 talloc_destroy(mem_ctx);
485 /* get a list of trusted domains */
486 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
493 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
498 if (!(hnd = cm_get_lsa_handle(lp_workgroup())))
501 result = cli_lsa_enum_trust_dom(hnd->cli, mem_ctx,
502 &hnd->pol, &enum_ctx, num_domains,
508 /* find the domain sid for a domain */
509 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
511 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
516 if (!(mem_ctx = talloc_init()))
517 return NT_STATUS_NO_MEMORY;
520 if (!(hnd = cm_get_lsa_handle(domain->name)))
523 status = cli_lsa_query_info_policy(hnd->cli, mem_ctx,
524 &hnd->pol, 0x05, level5_dom, sid);
527 talloc_destroy(mem_ctx);
531 /* the rpc backend methods are exposed via this structure */
532 struct winbindd_methods msrpc_methods = {