s3-winbind: Implemented samr backend function sam_query_user.
[Samba/gbeck.git] / source3 / winbindd / winbindd_samr.c
blob57a9d5829251e6fad6c010fadf282960afd2b6bc
1 /*
2 * Unix SMB/CIFS implementation.
4 * Winbind rpc backend functions
6 * Copyright (c) 2000-2003 Tim Potter
7 * Copyright (c) 2001 Andrew Tridgell
8 * Copyright (c) 2005 Volker Lendecke
9 * Copyright (c) 2008 Guenther Deschner (pidl conversion)
10 * Copyright (c) 2010 Andreas Schneider <asn@samba.org>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "includes.h"
27 #include "winbindd.h"
28 #include "../librpc/gen_ndr/cli_samr.h"
29 #include "rpc_client/cli_samr.h"
30 #include "../librpc/gen_ndr/srv_samr.h"
31 #include "../librpc/gen_ndr/cli_lsa.h"
32 #include "rpc_client/cli_lsarpc.h"
33 #include "../librpc/gen_ndr/srv_lsa.h"
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_WINBIND
38 static NTSTATUS open_internal_samr_pipe(TALLOC_CTX *mem_ctx,
39 struct rpc_pipe_client **samr_pipe)
41 static struct rpc_pipe_client *cli = NULL;
42 struct auth_serversupplied_info *server_info = NULL;
43 NTSTATUS status;
45 if (cli != NULL) {
46 goto done;
49 if (server_info == NULL) {
50 status = make_server_info_system(mem_ctx, &server_info);
51 if (!NT_STATUS_IS_OK(status)) {
52 DEBUG(0, ("open_samr_pipe: Could not create auth_serversupplied_info: %s\n",
53 nt_errstr(status)));
54 return status;
58 /* create a samr connection */
59 status = rpc_pipe_open_internal(talloc_autofree_context(),
60 &ndr_table_samr.syntax_id,
61 rpc_samr_dispatch,
62 server_info,
63 &cli);
64 if (!NT_STATUS_IS_OK(status)) {
65 DEBUG(0, ("open_samr_pipe: Could not connect to samr_pipe: %s\n",
66 nt_errstr(status)));
67 return status;
70 done:
71 if (samr_pipe) {
72 *samr_pipe = cli;
75 return NT_STATUS_OK;
78 static NTSTATUS open_internal_samr_conn(TALLOC_CTX *mem_ctx,
79 struct winbindd_domain *domain,
80 struct rpc_pipe_client **samr_pipe,
81 struct policy_handle *samr_domain_hnd)
83 NTSTATUS status;
84 struct policy_handle samr_connect_hnd;
86 status = open_internal_samr_pipe(mem_ctx, samr_pipe);
87 if (!NT_STATUS_IS_OK(status)) {
88 return status;
91 status = rpccli_samr_Connect2((*samr_pipe),
92 mem_ctx,
93 (*samr_pipe)->desthost,
94 SEC_FLAG_MAXIMUM_ALLOWED,
95 &samr_connect_hnd);
96 if (!NT_STATUS_IS_OK(status)) {
97 return status;
100 status = rpccli_samr_OpenDomain((*samr_pipe),
101 mem_ctx,
102 &samr_connect_hnd,
103 SEC_FLAG_MAXIMUM_ALLOWED,
104 &domain->sid,
105 samr_domain_hnd);
107 return status;
110 static NTSTATUS open_internal_lsa_pipe(TALLOC_CTX *mem_ctx,
111 struct rpc_pipe_client **lsa_pipe)
113 static struct rpc_pipe_client *cli = NULL;
114 struct auth_serversupplied_info *server_info = NULL;
115 NTSTATUS status;
117 if (cli != NULL) {
118 goto done;
121 if (server_info == NULL) {
122 status = make_server_info_system(mem_ctx, &server_info);
123 if (!NT_STATUS_IS_OK(status)) {
124 DEBUG(0, ("open_samr_pipe: Could not create auth_serversupplied_info: %s\n",
125 nt_errstr(status)));
126 return status;
130 /* create a samr connection */
131 status = rpc_pipe_open_internal(talloc_autofree_context(),
132 &ndr_table_lsarpc.syntax_id,
133 rpc_lsarpc_dispatch,
134 server_info,
135 &cli);
136 if (!NT_STATUS_IS_OK(status)) {
137 DEBUG(0, ("open_samr_pipe: Could not connect to samr_pipe: %s\n",
138 nt_errstr(status)));
139 return status;
142 done:
143 if (lsa_pipe) {
144 *lsa_pipe = cli;
147 return NT_STATUS_OK;
150 static NTSTATUS open_internal_lsa_conn(TALLOC_CTX *mem_ctx,
151 struct rpc_pipe_client **lsa_pipe,
152 struct policy_handle *lsa_hnd)
154 NTSTATUS status;
156 status = open_internal_lsa_pipe(mem_ctx, lsa_pipe);
157 if (!NT_STATUS_IS_OK(status)) {
158 return status;
161 status = rpccli_lsa_open_policy((*lsa_pipe),
162 mem_ctx,
163 true,
164 SEC_FLAG_MAXIMUM_ALLOWED,
165 lsa_hnd);
167 return status;
170 /*********************************************************************
171 SAM specific functions.
172 *********************************************************************/
174 /* List all domain groups */
175 static NTSTATUS sam_enum_dom_groups(struct winbindd_domain *domain,
176 TALLOC_CTX *mem_ctx,
177 uint32_t *pnum_info,
178 struct acct_info **pinfo)
180 struct rpc_pipe_client *samr_pipe;
181 struct policy_handle dom_pol;
182 struct acct_info *info = NULL;
183 TALLOC_CTX *tmp_ctx;
184 uint32_t start = 0;
185 uint32_t num_info = 0;
186 NTSTATUS status;
188 DEBUG(3,("samr: query_user_list\n"));
190 if (pnum_info) {
191 *pnum_info = 0;
194 tmp_ctx = talloc_stackframe();
195 if (tmp_ctx == NULL) {
196 return NT_STATUS_NO_MEMORY;
199 status = open_internal_samr_conn(tmp_ctx, domain, &samr_pipe, &dom_pol);
200 if (!NT_STATUS_IS_OK(status)) {
201 goto error;
204 do {
205 struct samr_SamArray *sam_array = NULL;
206 uint32_t count = 0;
207 uint32_t g;
209 /* start is updated by this call. */
210 status = rpccli_samr_EnumDomainGroups(samr_pipe,
211 tmp_ctx,
212 &dom_pol,
213 &start,
214 &sam_array,
215 0xFFFF, /* buffer size? */
216 &count);
217 if (!NT_STATUS_IS_OK(status)) {
218 if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
219 DEBUG(2,("query_user_list: failed to enum domain groups: %s\n",
220 nt_errstr(status)));
221 goto error;
225 info = TALLOC_REALLOC_ARRAY(tmp_ctx,
226 info,
227 struct acct_info,
228 num_info + count);
229 if (info == NULL) {
230 status = NT_STATUS_NO_MEMORY;
231 goto error;
234 for (g = 0; g < count; g++) {
235 fstrcpy(info[num_info + g].acct_name,
236 sam_array->entries[g].name.string);
238 info[num_info + g].rid = sam_array->entries[g].idx;
241 num_info += count;
242 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
244 if (pnum_info) {
245 *pnum_info = num_info;
248 if (pinfo) {
249 *pinfo = talloc_move(mem_ctx, &info);
252 error:
253 TALLOC_FREE(tmp_ctx);
254 return status;
257 /* Query display info for a domain */
258 static NTSTATUS sam_query_user_list(struct winbindd_domain *domain,
259 TALLOC_CTX *mem_ctx,
260 uint32_t *pnum_info,
261 struct wbint_userinfo **pinfo)
263 struct rpc_pipe_client *samr_pipe = NULL;
264 struct wbint_userinfo *info = NULL;
265 struct policy_handle dom_pol;
266 uint32_t num_info = 0;
267 uint32_t loop_count = 0;
268 uint32_t start_idx = 0;
269 uint32_t i = 0;
270 TALLOC_CTX *tmp_ctx;
271 NTSTATUS status;
273 DEBUG(3,("samr: query_user_list\n"));
275 if (pnum_info) {
276 *pnum_info = 0;
279 tmp_ctx = talloc_stackframe();
280 if (tmp_ctx == NULL) {
281 return NT_STATUS_NO_MEMORY;
284 status = open_internal_samr_conn(tmp_ctx, domain, &samr_pipe, &dom_pol);
285 if (!NT_STATUS_IS_OK(status)) {
286 goto error;
289 do {
290 uint32_t j;
291 uint32_t num_dom_users;
292 uint32_t max_entries, max_size;
293 uint32_t total_size, returned_size;
294 union samr_DispInfo disp_info;
296 get_query_dispinfo_params(loop_count,
297 &max_entries,
298 &max_size);
300 status = rpccli_samr_QueryDisplayInfo(samr_pipe,
301 tmp_ctx,
302 &dom_pol,
303 1, /* level */
304 start_idx,
305 max_entries,
306 max_size,
307 &total_size,
308 &returned_size,
309 &disp_info);
310 if (!NT_STATUS_IS_OK(status)) {
311 if (!NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
312 goto error;
316 /* increment required start query values */
317 start_idx += disp_info.info1.count;
318 loop_count++;
319 num_dom_users = disp_info.info1.count;
321 num_info += num_dom_users;
323 info = TALLOC_REALLOC_ARRAY(tmp_ctx,
324 info,
325 struct wbint_userinfo,
326 num_info);
327 if (info == NULL) {
328 status = NT_STATUS_NO_MEMORY;
329 goto error;
332 for (j = 0; j < num_dom_users; i++, j++) {
333 uint32_t rid = disp_info.info1.entries[j].rid;
334 struct samr_DispEntryGeneral *src;
335 struct wbint_userinfo *dst;
337 src = &(disp_info.info1.entries[j]);
338 dst = &(info[i]);
340 dst->acct_name = talloc_strdup(info,
341 src->account_name.string);
342 if (dst->acct_name == NULL) {
343 status = NT_STATUS_NO_MEMORY;
344 goto error;
347 dst->full_name = talloc_strdup(info, src->full_name.string);
348 if (dst->full_name == NULL) {
349 status = NT_STATUS_NO_MEMORY;
350 goto error;
353 dst->homedir = NULL;
354 dst->shell = NULL;
356 sid_compose(&dst->user_sid, &domain->sid, rid);
358 /* For the moment we set the primary group for
359 every user to be the Domain Users group.
360 There are serious problems with determining
361 the actual primary group for large domains.
362 This should really be made into a 'winbind
363 force group' smb.conf parameter or
364 something like that. */
365 sid_compose(&dst->group_sid, &domain->sid,
366 DOMAIN_RID_USERS);
368 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
370 if (pnum_info) {
371 *pnum_info = num_info;
374 if (pinfo) {
375 *pinfo = talloc_move(mem_ctx, &info);
378 error:
379 TALLOC_FREE(tmp_ctx);
380 return status;
383 /* Lookup user information from a rid or username. */
384 static NTSTATUS sam_query_user(struct winbindd_domain *domain,
385 TALLOC_CTX *mem_ctx,
386 const struct dom_sid *user_sid,
387 struct wbint_userinfo *user_info)
389 struct rpc_pipe_client *samr_pipe;
390 struct policy_handle dom_pol, user_pol;
391 union samr_UserInfo *info = NULL;
392 TALLOC_CTX *tmp_ctx;
393 uint32_t user_rid;
394 NTSTATUS status;
396 DEBUG(3,("samr: query_user\n"));
398 if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid)) {
399 return NT_STATUS_UNSUCCESSFUL;
402 if (user_info) {
403 user_info->homedir = NULL;
404 user_info->shell = NULL;
405 user_info->primary_gid = (gid_t) -1;
408 tmp_ctx = talloc_stackframe();
409 if (tmp_ctx == NULL) {
410 return NT_STATUS_NO_MEMORY;
413 status = open_internal_samr_conn(tmp_ctx, domain, &samr_pipe, &dom_pol);
414 if (!NT_STATUS_IS_OK(status)) {
415 goto error;
418 /* Get user handle */
419 status = rpccli_samr_OpenUser(samr_pipe,
420 tmp_ctx,
421 &dom_pol,
422 SEC_FLAG_MAXIMUM_ALLOWED,
423 user_rid,
424 &user_pol);
425 if (!NT_STATUS_IS_OK(status)) {
426 goto error;
429 /* Get user info */
430 status = rpccli_samr_QueryUserInfo(samr_pipe,
431 tmp_ctx,
432 &user_pol,
433 0x15,
434 &info);
436 rpccli_samr_Close(samr_pipe, tmp_ctx, &user_pol);
438 if (!NT_STATUS_IS_OK(status)) {
439 goto error;
442 sid_compose(&user_info->user_sid, &domain->sid, user_rid);
443 sid_compose(&user_info->group_sid, &domain->sid,
444 info->info21.primary_gid);
446 if (user_info) {
447 user_info->acct_name = talloc_strdup(mem_ctx,
448 info->info21.account_name.string);
449 if (user_info->acct_name == NULL) {
450 status = NT_STATUS_NO_MEMORY;
451 goto error;
454 user_info->full_name = talloc_strdup(mem_ctx,
455 info->info21.full_name.string);
456 if (user_info->acct_name == NULL) {
457 status = NT_STATUS_NO_MEMORY;
458 goto error;
461 user_info->homedir = NULL;
462 user_info->shell = NULL;
463 user_info->primary_gid = (gid_t)-1;
466 status = NT_STATUS_OK;
467 error:
468 TALLOC_FREE(tmp_ctx);
469 return status;
472 /* get a list of trusted domains - builtin domain */
473 static NTSTATUS sam_trusted_domains(struct winbindd_domain *domain,
474 TALLOC_CTX *mem_ctx,
475 struct netr_DomainTrustList *trusts)
477 /* TODO FIXME */
478 return NT_STATUS_NOT_IMPLEMENTED;
481 /* Lookup group membership given a rid. */
482 static NTSTATUS sam_lookup_groupmem(struct winbindd_domain *domain,
483 TALLOC_CTX *mem_ctx,
484 const struct dom_sid *group_sid,
485 enum lsa_SidType type,
486 uint32_t *num_names,
487 struct dom_sid **sid_mem,
488 char ***names,
489 uint32_t **name_types)
491 /* TODO FIXME */
492 return NT_STATUS_NOT_IMPLEMENTED;
495 /*********************************************************************
496 BUILTIN specific functions.
497 *********************************************************************/
499 /* List all domain groups */
500 static NTSTATUS builtin_enum_dom_groups(struct winbindd_domain *domain,
501 TALLOC_CTX *mem_ctx,
502 uint32 *num_entries,
503 struct acct_info **info)
505 /* BUILTIN doesn't have domain groups */
506 *num_entries = 0;
507 *info = NULL;
508 return NT_STATUS_OK;
511 /* Query display info for a domain */
512 static NTSTATUS builtin_query_user_list(struct winbindd_domain *domain,
513 TALLOC_CTX *mem_ctx,
514 uint32 *num_entries,
515 struct wbint_userinfo **info)
517 /* We don't have users */
518 *num_entries = 0;
519 *info = NULL;
520 return NT_STATUS_OK;
523 /* Lookup user information from a rid or username. */
524 static NTSTATUS builtin_query_user(struct winbindd_domain *domain,
525 TALLOC_CTX *mem_ctx,
526 const struct dom_sid *user_sid,
527 struct wbint_userinfo *user_info)
529 return NT_STATUS_NO_SUCH_USER;
532 /* get a list of trusted domains - builtin domain */
533 static NTSTATUS builtin_trusted_domains(struct winbindd_domain *domain,
534 TALLOC_CTX *mem_ctx,
535 struct netr_DomainTrustList *trusts)
537 ZERO_STRUCTP(trusts);
538 return NT_STATUS_OK;
541 /*********************************************************************
542 COMMON functions.
543 *********************************************************************/
545 /* List all local groups (aliases) */
546 static NTSTATUS common_enum_local_groups(struct winbindd_domain *domain,
547 TALLOC_CTX *mem_ctx,
548 uint32_t *num_entries,
549 struct acct_info **info)
551 /* TODO FIXME */
552 return NT_STATUS_NOT_IMPLEMENTED;
555 /* convert a single name to a sid in a domain */
556 static NTSTATUS common_name_to_sid(struct winbindd_domain *domain,
557 TALLOC_CTX *mem_ctx,
558 const char *domain_name,
559 const char *name,
560 uint32_t flags,
561 struct dom_sid *sid,
562 enum lsa_SidType *type)
564 /* TODO FIXME */
565 return NT_STATUS_NOT_IMPLEMENTED;
568 /* convert a domain SID to a user or group name */
569 static NTSTATUS common_sid_to_name(struct winbindd_domain *domain,
570 TALLOC_CTX *mem_ctx,
571 const struct dom_sid *sid,
572 char **domain_name,
573 char **name,
574 enum lsa_SidType *type)
576 /* TODO FIXME */
577 return NT_STATUS_NOT_IMPLEMENTED;
580 static NTSTATUS common_rids_to_names(struct winbindd_domain *domain,
581 TALLOC_CTX *mem_ctx,
582 const struct dom_sid *sid,
583 uint32 *rids,
584 size_t num_rids,
585 char **domain_name,
586 char ***names,
587 enum lsa_SidType **types)
589 /* TODO FIXME */
590 return NT_STATUS_NOT_IMPLEMENTED;
593 static NTSTATUS common_lockout_policy(struct winbindd_domain *domain,
594 TALLOC_CTX *mem_ctx,
595 struct samr_DomInfo12 *policy)
597 /* TODO FIXME */
598 return NT_STATUS_NOT_IMPLEMENTED;
601 static NTSTATUS common_password_policy(struct winbindd_domain *domain,
602 TALLOC_CTX *mem_ctx,
603 struct samr_DomInfo1 *policy)
605 /* TODO FIXME */
606 return NT_STATUS_NOT_IMPLEMENTED;
609 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
610 static NTSTATUS common_lookup_usergroups(struct winbindd_domain *domain,
611 TALLOC_CTX *mem_ctx,
612 const struct dom_sid *user_sid,
613 uint32_t *num_groups,
614 struct dom_sid **user_gids)
616 /* TODO FIXME */
617 return NT_STATUS_NOT_IMPLEMENTED;
620 static NTSTATUS common_lookup_useraliases(struct winbindd_domain *domain,
621 TALLOC_CTX *mem_ctx,
622 uint32_t num_sids,
623 const struct dom_sid *sids,
624 uint32_t *p_num_aliases,
625 uint32_t **rids)
627 /* TODO FIXME */
628 return NT_STATUS_NOT_IMPLEMENTED;
631 /* find the sequence number for a domain */
632 static NTSTATUS common_sequence_number(struct winbindd_domain *domain,
633 uint32_t *seq)
635 /* TODO FIXME */
636 return NT_STATUS_NOT_IMPLEMENTED;
639 #if 0
640 /* the rpc backend methods are exposed via this structure */
641 struct winbindd_methods builtin_passdb_methods = {
642 .consistent = false,
644 .query_user_list = builtin_query_user_list,
645 .enum_dom_groups = builtin_enum_dom_groups,
646 .enum_local_groups = common_enum_local_groups,
647 .name_to_sid = common_name_to_sid,
648 .sid_to_name = common_sid_to_name,
649 .rids_to_names = common_rids_to_names,
650 .query_user = builtin_query_user,
651 .lookup_usergroups = common_lookup_usergroups,
652 .lookup_useraliases = common_lookup_useraliases,
653 .lookup_groupmem = sam_lookup_groupmem,
654 .sequence_number = common_sequence_number,
655 .lockout_policy = common_lockout_policy,
656 .password_policy = common_password_policy,
657 .trusted_domains = builtin_trusted_domains
660 /* the rpc backend methods are exposed via this structure */
661 struct winbindd_methods sam_passdb_methods = {
662 .consistent = false,
664 .query_user_list = sam_query_user_list,
665 .enum_dom_groups = sam_enum_dom_groups,
666 .enum_local_groups = common_enum_local_groups,
667 .name_to_sid = common_name_to_sid,
668 .sid_to_name = common_sid_to_name,
669 .rids_to_names = common_rids_to_names,
670 .query_user = sam_query_user,
671 .lookup_usergroups = common_lookup_usergroups,
672 .lookup_useraliases = common_lookup_useraliases,
673 .lookup_groupmem = sam_lookup_groupmem,
674 .sequence_number = common_sequence_number,
675 .lockout_policy = common_lockout_policy,
676 .password_policy = common_password_policy,
677 .trusted_domains = sam_trusted_domains
679 #endif