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.
26 /*******************************************************************
27 Duplicate a UNISTR2 string into a UNIX codepage null terminated char*
28 using a talloc context
29 ********************************************************************/
31 static char *unistr2_tdup(TALLOC_CTX
*ctx
, const UNISTR2
*str
)
34 int maxlen
= (str
->uni_str_len
+1)*4;
37 s
= (char *)talloc(ctx
, maxlen
); /* convervative */
40 unistr2_to_unix(s
, str
, maxlen
);
44 /* Query display info for a domain. This returns enough information plus a
45 bit extra to give an overview of domain users for the User Manager
47 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
50 WINBIND_USERINFO
**info
)
53 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
55 BOOL got_dom_pol
= False
;
56 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
64 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
67 /* Get domain handle */
69 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
70 des_access
, &domain
->sid
, &dom_pol
);
72 if (!NT_STATUS_IS_OK(result
))
81 uint32 count
= 0, start
=i
;
85 ctr
.sam
.info1
= &info1
;
87 ctx2
= talloc_init_named("winbindd dispinfo");
89 result
= NT_STATUS_NO_MEMORY
;
93 /* Query display info level 1 */
94 result
= cli_samr_query_dispinfo(hnd
->cli
, ctx2
,
96 &count
, 0xFFFF, &ctr
);
98 if (!NT_STATUS_IS_OK(result
) &&
99 !NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
)) break;
101 (*num_entries
) += count
;
103 /* now map the result into the WINBIND_USERINFO structure */
104 (*info
) = talloc_realloc(mem_ctx
, *info
,
105 (*num_entries
)*sizeof(WINBIND_USERINFO
));
107 result
= NT_STATUS_NO_MEMORY
;
108 talloc_destroy(ctx2
);
112 for (j
=0;j
<count
;i
++, j
++) {
113 /* unistr2_tdup converts to UNIX charset. */
114 (*info
)[i
].acct_name
= unistr2_tdup(mem_ctx
, &info1
.str
[j
].uni_acct_name
);
115 (*info
)[i
].full_name
= unistr2_tdup(mem_ctx
, &info1
.str
[j
].uni_full_name
);
116 (*info
)[i
].user_rid
= info1
.sam
[j
].rid_user
;
117 /* For the moment we set the primary group for
118 every user to be the Domain Users group.
119 There are serious problems with determining
120 the actual primary group for large domains.
121 This should really be made into a 'winbind
122 force group' smb.conf parameter or
123 something like that. */
124 (*info
)[i
].group_rid
= DOMAIN_GROUP_RID_USERS
;
127 talloc_destroy(ctx2
);
128 } while (NT_STATUS_EQUAL(result
, STATUS_MORE_ENTRIES
));
133 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
138 /* list all domain groups */
139 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
142 struct acct_info
**info
)
144 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
152 if (!(hnd
= cm_get_sam_handle(domain
->name
))) {
153 return NT_STATUS_UNSUCCESSFUL
;
156 status
= cli_samr_open_domain(hnd
->cli
, mem_ctx
,
157 &hnd
->pol
, des_access
, &domain
->sid
, &dom_pol
);
158 if (!NT_STATUS_IS_OK(status
)) {
163 struct acct_info
*info2
= NULL
;
164 uint32 count
= 0, start
= *num_entries
;
165 TALLOC_CTX
*mem_ctx2
;
167 mem_ctx2
= talloc_init_named("enum_dom_groups[rpc]");
169 status
= cli_samr_enum_dom_groups(hnd
->cli
, mem_ctx2
, &dom_pol
,
171 0xFFFF, /* buffer size? */
174 if (!NT_STATUS_IS_OK(status
) &&
175 !NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
)) {
176 talloc_destroy(mem_ctx2
);
180 (*info
) = talloc_realloc(mem_ctx
, *info
,
181 sizeof(**info
) * ((*num_entries
) + count
));
183 talloc_destroy(mem_ctx2
);
184 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
185 return NT_STATUS_NO_MEMORY
;
188 memcpy(&(*info
)[*num_entries
], info2
, count
*sizeof(*info2
));
189 (*num_entries
) += count
;
190 talloc_destroy(mem_ctx2
);
191 } while (NT_STATUS_EQUAL(status
, STATUS_MORE_ENTRIES
));
193 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
198 /* convert a single name to a sid in a domain */
199 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
202 enum SID_NAME_USE
*type
)
207 DOM_SID
*sids
= NULL
;
208 uint32
*types
= NULL
;
209 const char *full_name
;
211 if (!(mem_ctx
= talloc_init_named("name_to_sid[rpc] for [%s]\\[%s]", domain
->name
, name
))) {
212 DEBUG(0, ("talloc_init failed!\n"));
213 return NT_STATUS_NO_MEMORY
;
216 if (!(hnd
= cm_get_lsa_handle(domain
->name
))) {
217 talloc_destroy(mem_ctx
);
218 return NT_STATUS_UNSUCCESSFUL
;
221 full_name
= talloc_asprintf(mem_ctx
, "%s\\%s", domain
->name
, name
);
224 DEBUG(0, ("talloc_asprintf failed!\n"));
225 talloc_destroy(mem_ctx
);
226 return NT_STATUS_NO_MEMORY
;
229 status
= cli_lsa_lookup_names(hnd
->cli
, mem_ctx
, &hnd
->pol
, 1,
230 &full_name
, &sids
, &types
);
232 /* Return rid and type if lookup successful */
234 if (NT_STATUS_IS_OK(status
)) {
235 sid_copy(sid
, &sids
[0]);
239 talloc_destroy(mem_ctx
);
244 convert a domain SID to a user or group name
246 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
250 enum SID_NAME_USE
*type
)
258 if (!(hnd
= cm_get_lsa_handle(domain
->name
)))
259 return NT_STATUS_UNSUCCESSFUL
;
261 status
= cli_lsa_lookup_sids(hnd
->cli
, mem_ctx
, &hnd
->pol
,
262 1, sid
, &domains
, &names
, &types
);
264 if (NT_STATUS_IS_OK(status
)) {
267 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains
[0], *name
));
270 if (strcasecmp(domain
->name
, domains
[0]) != 0) {
271 DEBUG(1, ("domain name from domain param and PDC lookup return differ! (%s vs %s)\n", domain
->name
, domains
[0]));
272 return NT_STATUS_UNSUCCESSFUL
;
278 /* Lookup user information from a rid or username. */
279 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
282 WINBIND_USERINFO
*user_info
)
286 POLICY_HND dom_pol
, user_pol
;
287 BOOL got_dom_pol
= False
, got_user_pol
= False
;
288 SAM_USERINFO_CTR
*ctr
;
291 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
294 /* Get domain handle */
296 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
297 SEC_RIGHTS_MAXIMUM_ALLOWED
,
298 &domain
->sid
, &dom_pol
);
300 if (!NT_STATUS_IS_OK(result
))
305 /* Get user handle */
306 result
= cli_samr_open_user(hnd
->cli
, mem_ctx
, &dom_pol
,
307 SEC_RIGHTS_MAXIMUM_ALLOWED
, user_rid
, &user_pol
);
309 if (!NT_STATUS_IS_OK(result
))
315 result
= cli_samr_query_userinfo(hnd
->cli
, mem_ctx
, &user_pol
,
318 cli_samr_close(hnd
->cli
, mem_ctx
, &user_pol
);
319 got_user_pol
= False
;
321 user_info
->group_rid
= ctr
->info
.id21
->group_rid
;
322 user_info
->acct_name
= unistr2_tdup(mem_ctx
,
323 &ctr
->info
.id21
->uni_user_name
);
324 user_info
->full_name
= unistr2_tdup(mem_ctx
,
325 &ctr
->info
.id21
->uni_full_name
);
328 /* Clean up policy handles */
330 cli_samr_close(hnd
->cli
, mem_ctx
, &user_pol
);
333 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
338 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
339 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
342 uint32
*num_groups
, uint32
**user_gids
)
345 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
346 POLICY_HND dom_pol
, user_pol
;
347 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
348 BOOL got_dom_pol
= False
, got_user_pol
= False
;
349 DOM_GID
*user_groups
;
356 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
359 /* Get domain handle */
360 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
361 des_access
, &domain
->sid
, &dom_pol
);
363 if (!NT_STATUS_IS_OK(result
))
368 /* Get user handle */
369 result
= cli_samr_open_user(hnd
->cli
, mem_ctx
, &dom_pol
,
370 des_access
, user_rid
, &user_pol
);
372 if (!NT_STATUS_IS_OK(result
))
377 /* Query user rids */
378 result
= cli_samr_query_usergroups(hnd
->cli
, mem_ctx
, &user_pol
,
379 num_groups
, &user_groups
);
381 if (!NT_STATUS_IS_OK(result
) || (*num_groups
) == 0)
384 (*user_gids
) = talloc(mem_ctx
, sizeof(uint32
) * (*num_groups
));
385 for (i
=0;i
<(*num_groups
);i
++) {
386 (*user_gids
)[i
] = user_groups
[i
].g_rid
;
390 /* Clean up policy handles */
392 cli_samr_close(hnd
->cli
, mem_ctx
, &user_pol
);
395 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
401 /* Lookup group membership given a rid. */
402 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
404 uint32 group_rid
, uint32
*num_names
,
405 uint32
**rid_mem
, char ***names
,
409 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
410 uint32 i
, total_names
= 0;
411 POLICY_HND dom_pol
, group_pol
;
412 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
413 BOOL got_dom_pol
= False
, got_group_pol
= False
;
419 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
422 /* Get domain handle */
424 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
425 des_access
, &domain
->sid
, &dom_pol
);
427 if (!NT_STATUS_IS_OK(result
))
432 /* Get group handle */
434 result
= cli_samr_open_group(hnd
->cli
, mem_ctx
, &dom_pol
,
435 des_access
, group_rid
, &group_pol
);
437 if (!NT_STATUS_IS_OK(result
))
440 got_group_pol
= True
;
442 /* Step #1: Get a list of user rids that are the members of the
445 result
= cli_samr_query_groupmem(hnd
->cli
, mem_ctx
,
446 &group_pol
, num_names
, rid_mem
,
449 if (!NT_STATUS_IS_OK(result
))
452 /* Step #2: Convert list of rids into list of usernames. Do this
453 in bunches of ~1000 to avoid crashing NT4. It looks like there
454 is a buffer overflow or something like that lurking around
457 #define MAX_LOOKUP_RIDS 900
459 *names
= talloc_zero(mem_ctx
, *num_names
* sizeof(char *));
460 *name_types
= talloc_zero(mem_ctx
, *num_names
* sizeof(uint32
));
462 for (i
= 0; i
< *num_names
; i
+= MAX_LOOKUP_RIDS
) {
463 int num_lookup_rids
= MIN(*num_names
- i
, MAX_LOOKUP_RIDS
);
464 uint32 tmp_num_names
= 0;
465 char **tmp_names
= NULL
;
466 uint32
*tmp_types
= NULL
;
468 /* Lookup a chunk of rids */
470 result
= cli_samr_lookup_rids(hnd
->cli
, mem_ctx
,
471 &dom_pol
, 1000, /* flags */
475 &tmp_names
, &tmp_types
);
477 if (!NT_STATUS_IS_OK(result
))
480 /* Copy result into array. The talloc system will take
481 care of freeing the temporary arrays later on. */
483 memcpy(&(*names
)[i
], tmp_names
, sizeof(char *) *
486 memcpy(&(*name_types
)[i
], tmp_types
, sizeof(uint32
) *
489 total_names
+= tmp_num_names
;
492 *num_names
= total_names
;
496 cli_samr_close(hnd
->cli
, mem_ctx
, &group_pol
);
499 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
504 /* find the sequence number for a domain */
505 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
510 uint16 switch_value
= 2;
512 uint32 seqnum
= DOM_SEQUENCE_NONE
;
514 BOOL got_dom_pol
= False
;
515 uint32 des_access
= SEC_RIGHTS_MAXIMUM_ALLOWED
;
517 *seq
= DOM_SEQUENCE_NONE
;
519 if (!(mem_ctx
= talloc_init_named("sequence_number[rpc]")))
520 return NT_STATUS_NO_MEMORY
;
524 if (!(hnd
= cm_get_sam_handle(domain
->name
)))
527 /* Get domain handle */
529 result
= cli_samr_open_domain(hnd
->cli
, mem_ctx
, &hnd
->pol
,
530 des_access
, &domain
->sid
, &dom_pol
);
532 if (!NT_STATUS_IS_OK(result
))
537 /* Query domain info */
539 result
= cli_samr_query_dom_info(hnd
->cli
, mem_ctx
, &dom_pol
,
542 if (NT_STATUS_IS_OK(result
)) {
543 seqnum
= ctr
.info
.inf2
.seq_num
;
544 DEBUG(10,("domain_sequence_number: for domain %s is %u\n", domain
->name
, (unsigned)seqnum
));
546 DEBUG(10,("domain_sequence_number: failed to get sequence number (%u) for domain %s\n",
547 (unsigned)seqnum
, domain
->name
));
553 cli_samr_close(hnd
->cli
, mem_ctx
, &dom_pol
);
555 talloc_destroy(mem_ctx
);
562 /* get a list of trusted domains */
563 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
570 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
575 if (!(hnd
= cm_get_lsa_handle(lp_workgroup())))
578 result
= cli_lsa_enum_trust_dom(hnd
->cli
, mem_ctx
,
579 &hnd
->pol
, &enum_ctx
, num_domains
,
585 /* find the domain sid for a domain */
586 static NTSTATUS
domain_sid(struct winbindd_domain
*domain
, DOM_SID
*sid
)
588 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
593 if (!(mem_ctx
= talloc_init_named("domain_sid[rpc]")))
594 return NT_STATUS_NO_MEMORY
;
597 if (!(hnd
= cm_get_lsa_handle(domain
->name
)))
600 status
= cli_lsa_query_info_policy(hnd
->cli
, mem_ctx
,
601 &hnd
->pol
, 0x05, level5_dom
, sid
);
604 talloc_destroy(mem_ctx
);
608 /* the rpc backend methods are exposed via this structure */
609 struct winbindd_methods msrpc_methods
= {