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
;
44 DEBUG(3,("rpc: query_user_list\n"));
51 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
54 /* Get domain handle */
56 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
57 des_access
, &domain
->sid
, &dom_pol
);
59 if (!NT_STATUS_IS_OK(result
))
68 uint32 count
= 0, start
=i
;
72 ctr
.sam
.info1
= &info1
;
74 ctx2
= talloc_init_named("winbindd dispinfo");
76 result
= NT_STATUS_NO_MEMORY
;
80 /* Query display info level 1 */
81 result
= cli_samr_query_dispinfo(hnd
->cli
, ctx2
,
83 &count
, 0xFFFF, &ctr
);
85 if (!NT_STATUS_IS_OK(result
) &&
86 !NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
)) break;
88 (*num_entries
) += count
;
90 /* now map the result into the WINBIND_USERINFO structure */
91 (*info
) = talloc_realloc(mem_ctx
, *info
,
92 (*num_entries
)*sizeof(WINBIND_USERINFO
));
94 result
= NT_STATUS_NO_MEMORY
;
99 for (j
=0;j
<count
;i
++, j
++) {
100 (*info
)[i
].acct_name
= unistr2_tdup(mem_ctx
, &info1
.str
[j
].uni_acct_name
);
101 (*info
)[i
].full_name
= unistr2_tdup(mem_ctx
, &info1
.str
[j
].uni_full_name
);
102 (*info
)[i
].user_rid
= info1
.sam
[j
].rid_user
;
103 /* For the moment we set the primary group for
104 every user to be the Domain Users group.
105 There are serious problems with determining
106 the actual primary group for large domains.
107 This should really be made into a 'winbind
108 force group' smb.conf parameter or
109 something like that. */
110 (*info
)[i
].group_rid
= DOMAIN_GROUP_RID_USERS
;
113 talloc_destroy(ctx2
);
114 } while (NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
));
119 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
124 /* list all domain groups */
125 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
128 struct acct_info
**info
)
130 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
138 DEBUG(3,("rpc: enum_dom_groups\n"));
140 if (!(hnd
= cm_get_sam_handle(domain
->name
))) {
141 return NT_STATUS_UNSUCCESSFUL
;
144 status
= cli_samr_open_domain(hnd
->cli
, mem_ctx
,
145 &hnd
->pol
, des_access
, &domain
->sid
, &dom_pol
);
146 if (!NT_STATUS_IS_OK(status
)) {
151 struct acct_info
*info2
= NULL
;
152 uint32 count
= 0, start
= *num_entries
;
153 TALLOC_CTX
*mem_ctx2
;
155 mem_ctx2
= talloc_init_named("enum_dom_groups[rpc]");
157 status
= cli_samr_enum_dom_groups(hnd
->cli
, mem_ctx2
, &dom_pol
,
159 0xFFFF, /* buffer size? */
162 if (!NT_STATUS_IS_OK(status
) &&
163 !NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) {
164 talloc_destroy(mem_ctx2
);
168 (*info
) = talloc_realloc(mem_ctx
, *info
,
169 sizeof(**info
) * ((*num_entries
) + count
));
171 talloc_destroy(mem_ctx2
);
172 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
173 return NT_STATUS_NO_MEMORY
;
176 memcpy(&(*info
)[*num_entries
], info2
, count
*sizeof(*info2
));
177 (*num_entries
) += count
;
178 talloc_destroy(mem_ctx2
);
179 } while (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
));
181 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
186 /* convert a single name to a sid in a domain */
187 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
190 enum SID_NAME_USE
*type
)
195 DOM_SID
*sids
= NULL
;
196 uint32
*types
= NULL
;
197 const char *full_name
;
199 DEBUG(3,("rpc: name_to_sid name=%s\n", name
));
201 if (!(mem_ctx
= talloc_init_named("name_to_sid[rpc] for [%s]\\[%s]", domain
->name
, name
))) {
202 DEBUG(0, ("talloc_init failed!\n"));
203 return NT_STATUS_NO_MEMORY
;
206 if (!(hnd
= cm_get_lsa_handle(domain
->name
))) {
207 talloc_destroy(mem_ctx
);
208 return NT_STATUS_UNSUCCESSFUL
;
211 full_name
= talloc_asprintf(mem_ctx
, "%s\\%s", domain
->name
, name
);
214 DEBUG(0, ("talloc_asprintf failed!\n"));
215 talloc_destroy(mem_ctx
);
216 return NT_STATUS_NO_MEMORY
;
219 status
= cli_lsa_lookup_names(hnd
->cli
, mem_ctx
, &hnd
->pol
, 1,
220 &full_name
, &sids
, &types
);
222 /* Return rid and type if lookup successful */
224 if (NT_STATUS_IS_OK(status
)) {
225 sid_copy(sid
, &sids
[0]);
229 talloc_destroy(mem_ctx
);
234 convert a domain SID to a user or group name
236 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
240 enum SID_NAME_USE
*type
)
248 DEBUG(3,("rpc: sid_to_name\n"));
250 if (!(hnd
= cm_get_lsa_handle(domain
->name
)))
251 return NT_STATUS_UNSUCCESSFUL
;
253 status
= cli_lsa_lookup_sids(hnd
->cli
, mem_ctx
, &hnd
->pol
,
254 1, sid
, &domains
, &names
, &types
);
256 if (NT_STATUS_IS_OK(status
)) {
259 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains
[0], *name
));
262 if (strcasecmp(domain
->name
, domains
[0]) != 0) {
263 DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain
->name
, domains
[0]));
264 return NT_STATUS_UNSUCCESSFUL
;
270 /* Lookup user information from a rid or username. */
271 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
274 WINBIND_USERINFO
*user_info
)
278 POLICY_HND dom_pol
, user_pol
;
279 BOOL got_dom_pol
= False
, got_user_pol
= False
;
280 SAM_USERINFO_CTR
*ctr
;
282 DEBUG(3,("rpc: query_user rid=%u\n", user_rid
));
285 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
288 /* Get domain handle */
290 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
291 SEC_RIGHTS_MAXIMUM_ALLOWED
,
292 &domain
->sid
, &dom_pol
);
294 if (!NT_STATUS_IS_OK(result
))
299 /* Get user handle */
300 result
= cli_samr_open_user(hnd
->cli
, mem_ctx
, &dom_pol
,
301 SEC_RIGHTS_MAXIMUM_ALLOWED
, user_rid
, &user_pol
);
303 if (!NT_STATUS_IS_OK(result
))
309 result
= cli_samr_query_userinfo(hnd
->cli
, mem_ctx
, &user_pol
,
312 if (!NT_STATUS_IS_OK(result
))
315 cli_samr_close(hnd
->cli
, mem_ctx
, &user_pol
);
316 got_user_pol
= False
;
318 user_info
->user_rid
= user_rid
;
319 user_info
->group_rid
= ctr
->info
.id21
->group_rid
;
320 user_info
->acct_name
= unistr2_tdup(mem_ctx
,
321 &ctr
->info
.id21
->uni_user_name
);
322 user_info
->full_name
= unistr2_tdup(mem_ctx
,
323 &ctr
->info
.id21
->uni_full_name
);
326 /* Clean up policy handles */
328 cli_samr_close(hnd
->cli
, mem_ctx
, &user_pol
);
331 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
336 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
337 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
340 uint32
*num_groups
, uint32
**user_gids
)
343 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
344 POLICY_HND dom_pol
, user_pol
;
345 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
346 BOOL got_dom_pol
= False
, got_user_pol
= False
;
347 DOM_GID
*user_groups
;
350 DEBUG(3,("rpc: lookup_usergroups rid=%u\n", user_rid
));
354 /* First try cached universal groups from logon */
355 *user_gids
= uni_group_cache_fetch(&domain
->sid
, user_rid
, mem_ctx
, num_groups
);
356 if((*num_groups
> 0) && *user_gids
) {
364 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
367 /* Get domain handle */
368 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
369 des_access
, &domain
->sid
, &dom_pol
);
371 if (!NT_STATUS_IS_OK(result
))
376 /* Get user handle */
377 result
= cli_samr_open_user(hnd
->cli
, mem_ctx
, &dom_pol
,
378 des_access
, user_rid
, &user_pol
);
380 if (!NT_STATUS_IS_OK(result
))
385 /* Query user rids */
386 result
= cli_samr_query_usergroups(hnd
->cli
, mem_ctx
, &user_pol
,
387 num_groups
, &user_groups
);
389 if (!NT_STATUS_IS_OK(result
) || (*num_groups
) == 0)
392 (*user_gids
) = talloc(mem_ctx
, sizeof(uint32
) * (*num_groups
));
393 for (i
=0;i
<(*num_groups
);i
++) {
394 (*user_gids
)[i
] = user_groups
[i
].g_rid
;
398 /* Clean up policy handles */
400 cli_samr_close(hnd
->cli
, mem_ctx
, &user_pol
);
403 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
409 /* Lookup group membership given a rid. */
410 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
412 uint32 group_rid
, uint32
*num_names
,
413 uint32
**rid_mem
, char ***names
,
417 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
418 uint32 i
, total_names
= 0;
419 POLICY_HND dom_pol
, group_pol
;
420 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
421 BOOL got_dom_pol
= False
, got_group_pol
= False
;
423 DEBUG(10,("rpc: lookup_groupmem %s rid=%u\n", domain
->name
, group_rid
));
429 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
432 /* Get domain handle */
434 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
435 des_access
, &domain
->sid
, &dom_pol
);
437 if (!NT_STATUS_IS_OK(result
))
442 /* Get group handle */
444 result
= cli_samr_open_group(hnd
->cli
, mem_ctx
, &dom_pol
,
445 des_access
, group_rid
, &group_pol
);
447 if (!NT_STATUS_IS_OK(result
))
450 got_group_pol
= True
;
452 /* Step #1: Get a list of user rids that are the members of the
455 result
= cli_samr_query_groupmem(hnd
->cli
, mem_ctx
,
456 &group_pol
, num_names
, rid_mem
,
459 if (!NT_STATUS_IS_OK(result
))
462 /* Step #2: Convert list of rids into list of usernames. Do this
463 in bunches of ~1000 to avoid crashing NT4. It looks like there
464 is a buffer overflow or something like that lurking around
467 #define MAX_LOOKUP_RIDS 900
469 *names
= talloc_zero(mem_ctx
, *num_names
* sizeof(char *));
470 *name_types
= talloc_zero(mem_ctx
, *num_names
* sizeof(uint32
));
472 for (i
= 0; i
< *num_names
; i
+= MAX_LOOKUP_RIDS
) {
473 int num_lookup_rids
= MIN(*num_names
- i
, MAX_LOOKUP_RIDS
);
474 uint32 tmp_num_names
= 0;
475 char **tmp_names
= NULL
;
476 uint32
*tmp_types
= NULL
;
478 /* Lookup a chunk of rids */
480 result
= cli_samr_lookup_rids(hnd
->cli
, mem_ctx
,
481 &dom_pol
, 1000, /* flags */
485 &tmp_names
, &tmp_types
);
487 if (!NT_STATUS_IS_OK(result
))
490 /* Copy result into array. The talloc system will take
491 care of freeing the temporary arrays later on. */
493 memcpy(&(*names
)[i
], tmp_names
, sizeof(char *) *
496 memcpy(&(*name_types
)[i
], tmp_types
, sizeof(uint32
) *
499 total_names
+= tmp_num_names
;
502 *num_names
= total_names
;
506 cli_samr_close(hnd
->cli
, mem_ctx
, &group_pol
);
509 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
514 /* find the sequence number for a domain */
515 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
520 uint16 switch_value
= 2;
522 uint32 seqnum
= DOM_SEQUENCE_NONE
;
524 BOOL got_dom_pol
= False
;
525 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
527 DEBUG(10,("rpc: fetch sequence_number for %s\n", domain
->name
));
529 *seq
= DOM_SEQUENCE_NONE
;
531 if (!(mem_ctx
= talloc_init_named("sequence_number[rpc]")))
532 return NT_STATUS_NO_MEMORY
;
536 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
539 /* Get domain handle */
541 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
542 des_access
, &domain
->sid
, &dom_pol
);
544 if (!NT_STATUS_IS_OK(result
))
549 /* Query domain info */
551 result
= cli_samr_query_dom_info(hnd
->cli
, mem_ctx
, &dom_pol
,
554 if (NT_STATUS_IS_OK(result
)) {
555 seqnum
= ctr
.info
.inf2
.seq_num
;
556 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain
->name
, (unsigned)seqnum
));
558 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
559 (unsigned)seqnum
, domain
->name
));
565 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
567 talloc_destroy(mem_ctx
);
574 /* get a list of trusted domains */
575 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
583 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
586 DEBUG(3,("rpc: trusted_domains\n"));
591 if (!(hnd
= cm_get_lsa_handle(lp_workgroup())))
594 result
= cli_lsa_enum_trust_dom(hnd
->cli
, mem_ctx
,
595 &hnd
->pol
, &enum_ctx
,
596 num_domains
, names
, dom_sids
);
601 /* find the domain sid for a domain */
602 static NTSTATUS
domain_sid(struct winbindd_domain
*domain
, DOM_SID
*sid
)
604 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
609 DEBUG(3,("rpc: domain_sid\n"));
611 if (!(mem_ctx
= talloc_init_named("domain_sid[rpc]")))
612 return NT_STATUS_NO_MEMORY
;
615 if (!(hnd
= cm_get_lsa_handle(domain
->name
)))
618 status
= cli_lsa_query_info_policy(hnd
->cli
, mem_ctx
,
619 &hnd
->pol
, 0x05, level5_dom
, sid
);
622 talloc_destroy(mem_ctx
);
626 /* find alternate names list for the domain - none for rpc */
627 static NTSTATUS
alternate_name(struct winbindd_domain
*domain
)
633 /* the rpc backend methods are exposed via this structure */
634 struct winbindd_methods msrpc_methods
= {