2 Unix SMB/CIFS implementation.
4 Winbind rpc backend functions
6 Copyright (C) Tim Potter 2000-2001,2003
7 Copyright (C) Andrew Tridgell 2001
8 Copyright (C) Volker Lendecke 2005
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 #define DBGC_CLASS DBGC_WINBIND
32 /* Query display info for a domain. This returns enough information plus a
33 bit extra to give an overview of domain users for the User Manager
35 static NTSTATUS query_user_list(struct winbindd_domain *domain,
38 WINBIND_USERINFO **info)
42 unsigned int i, start_idx;
44 struct rpc_pipe_client *cli;
46 DEBUG(3,("rpc: query_user_list\n"));
51 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
52 if (!NT_STATUS_IS_OK(result))
60 uint32 num_dom_users, j;
61 uint32 max_entries, max_size;
67 ctr.sam.info1 = &info1;
69 if (!(ctx2 = talloc_init("winbindd enum_users")))
70 return NT_STATUS_NO_MEMORY;
72 /* this next bit is copied from net_user_list_internal() */
74 get_query_dispinfo_params(loop_count, &max_entries,
77 result = rpccli_samr_query_dispinfo(cli, mem_ctx, &dom_pol,
80 max_entries, max_size,
85 *num_entries += num_dom_users;
87 *info = TALLOC_REALLOC_ARRAY(mem_ctx, *info, WINBIND_USERINFO,
92 return NT_STATUS_NO_MEMORY;
95 for (j = 0; j < num_dom_users; i++, j++) {
96 fstring username, fullname;
97 uint32 rid = ctr.sam.info1->sam[j].rid_user;
99 unistr2_to_ascii( username, &(&ctr.sam.info1->str[j])->uni_acct_name, sizeof(username)-1);
100 unistr2_to_ascii( fullname, &(&ctr.sam.info1->str[j])->uni_full_name, sizeof(fullname)-1);
102 (*info)[i].acct_name = talloc_strdup(mem_ctx, username );
103 (*info)[i].full_name = talloc_strdup(mem_ctx, fullname );
104 (*info)[i].homedir = NULL;
105 (*info)[i].shell = NULL;
106 sid_compose(&(*info)[i].user_sid, &domain->sid, rid);
108 /* For the moment we set the primary group for
109 every user to be the Domain Users group.
110 There are serious problems with determining
111 the actual primary group for large domains.
112 This should really be made into a 'winbind
113 force group' smb.conf parameter or
114 something like that. */
116 sid_compose(&(*info)[i].group_sid, &domain->sid,
117 DOMAIN_GROUP_RID_USERS);
120 talloc_destroy(ctx2);
122 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
127 /* list all domain groups */
128 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
131 struct acct_info **info)
136 struct rpc_pipe_client *cli;
141 DEBUG(3,("rpc: enum_dom_groups\n"));
143 status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
144 if (!NT_STATUS_IS_OK(status))
148 struct acct_info *info2 = NULL;
150 TALLOC_CTX *mem_ctx2;
152 mem_ctx2 = talloc_init("enum_dom_groups[rpc]");
154 /* start is updated by this call. */
155 status = rpccli_samr_enum_dom_groups(cli, mem_ctx2, &dom_pol,
157 0xFFFF, /* buffer size? */
160 if (!NT_STATUS_IS_OK(status) &&
161 !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
162 talloc_destroy(mem_ctx2);
166 (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
168 (*num_entries) + count);
170 talloc_destroy(mem_ctx2);
171 status = NT_STATUS_NO_MEMORY;
175 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
176 (*num_entries) += count;
177 talloc_destroy(mem_ctx2);
178 } while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES));
183 /* List all domain groups */
185 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
188 struct acct_info **info)
192 struct rpc_pipe_client *cli;
197 DEBUG(3,("rpc: enum_local_groups\n"));
199 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
200 if (!NT_STATUS_IS_OK(result))
204 struct acct_info *info2 = NULL;
205 uint32 count = 0, start = *num_entries;
206 TALLOC_CTX *mem_ctx2;
208 mem_ctx2 = talloc_init("enum_dom_local_groups[rpc]");
210 result = rpccli_samr_enum_als_groups( cli, mem_ctx2, &dom_pol,
211 &start, 0xFFFF, &info2,
214 if (!NT_STATUS_IS_OK(result) &&
215 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES) )
217 talloc_destroy(mem_ctx2);
221 (*info) = TALLOC_REALLOC_ARRAY(mem_ctx, *info,
223 (*num_entries) + count);
225 talloc_destroy(mem_ctx2);
226 return NT_STATUS_NO_MEMORY;
229 memcpy(&(*info)[*num_entries], info2, count*sizeof(*info2));
230 (*num_entries) += count;
231 talloc_destroy(mem_ctx2);
233 } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
238 /* convert a single name to a sid in a domain */
239 NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
241 const char *domain_name,
244 enum lsa_SidType *type)
247 DOM_SID *sids = NULL;
248 enum lsa_SidType *types = NULL;
249 const char *full_name;
250 struct rpc_pipe_client *cli;
251 POLICY_HND lsa_policy;
253 if(name == NULL || *name=='\0') {
254 DEBUG(3,("rpc: name_to_sid name=%s\n", domain_name));
255 full_name = talloc_asprintf(mem_ctx, "%s", domain_name);
257 DEBUG(3,("rpc: name_to_sid name=%s\\%s\n", domain_name, name));
258 full_name = talloc_asprintf(mem_ctx, "%s\\%s", domain_name, name);
261 DEBUG(0, ("talloc_asprintf failed!\n"));
262 return NT_STATUS_NO_MEMORY;
265 DEBUG(3,("name_to_sid [rpc] %s for domain %s\n", full_name?full_name:"", domain_name ));
267 result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
268 if (!NT_STATUS_IS_OK(result))
271 result = rpccli_lsa_lookup_names(cli, mem_ctx, &lsa_policy, 1,
272 &full_name, NULL, &sids, &types);
274 if (!NT_STATUS_IS_OK(result))
277 /* Return rid and type if lookup successful */
279 sid_copy(sid, &sids[0]);
286 convert a domain SID to a user or group name
288 NTSTATUS msrpc_sid_to_name(struct winbindd_domain *domain,
293 enum lsa_SidType *type)
297 enum lsa_SidType *types;
299 struct rpc_pipe_client *cli;
300 POLICY_HND lsa_policy;
302 DEBUG(3,("sid_to_name [rpc] %s for domain %s\n", sid_string_static(sid),
305 result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
306 if (!NT_STATUS_IS_OK(result))
309 result = rpccli_lsa_lookup_sids(cli, mem_ctx, &lsa_policy,
310 1, sid, &domains, &names, &types);
311 if (!NT_STATUS_IS_OK(result))
314 *type = (enum lsa_SidType)types[0];
315 *domain_name = domains[0];
317 DEBUG(5,("Mapped sid to [%s]\\[%s]\n", domains[0], *name));
321 NTSTATUS msrpc_rids_to_names(struct winbindd_domain *domain,
328 enum lsa_SidType **types)
332 struct rpc_pipe_client *cli;
333 POLICY_HND lsa_policy;
337 DEBUG(3, ("rids_to_names [rpc] for domain %s\n", domain->name ));
339 sids = TALLOC_ARRAY(mem_ctx, DOM_SID, num_rids);
341 return NT_STATUS_NO_MEMORY;
344 for (i=0; i<num_rids; i++) {
345 if (!sid_compose(&sids[i], sid, rids[i])) {
346 return NT_STATUS_INTERNAL_ERROR;
350 result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
351 if (!NT_STATUS_IS_OK(result)) {
355 result = rpccli_lsa_lookup_sids(cli, mem_ctx, &lsa_policy,
356 num_rids, sids, &domains,
358 if (!NT_STATUS_IS_OK(result) &&
359 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
363 for (i=0; i<num_rids; i++) {
364 if ((*types)[i] != SID_NAME_UNKNOWN) {
365 *domain_name = domains[i];
373 /* Lookup user information from a rid or username. */
374 static NTSTATUS query_user(struct winbindd_domain *domain,
376 const DOM_SID *user_sid,
377 WINBIND_USERINFO *user_info)
379 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
380 POLICY_HND dom_pol, user_pol;
381 SAM_USERINFO_CTR *ctr;
384 NET_USER_INFO_3 *user;
385 struct rpc_pipe_client *cli;
387 DEBUG(3,("rpc: query_user rid=%s\n",
388 sid_to_string(sid_string, user_sid)));
390 if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
391 return NT_STATUS_UNSUCCESSFUL;
393 /* try netsamlogon cache first */
395 if ( (user = netsamlogon_cache_get( mem_ctx, user_sid )) != NULL )
398 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
399 sid_string_static(user_sid)));
401 sid_compose(&user_info->user_sid, &domain->sid, user_rid);
402 sid_compose(&user_info->group_sid, &domain->sid,
405 user_info->acct_name = unistr2_tdup(mem_ctx,
406 &user->uni_user_name);
407 user_info->full_name = unistr2_tdup(mem_ctx,
408 &user->uni_full_name);
410 user_info->homedir = NULL;
411 user_info->shell = NULL;
418 /* no cache; hit the wire */
420 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
421 if (!NT_STATUS_IS_OK(result))
424 /* Get user handle */
425 result = rpccli_samr_open_user(cli, mem_ctx, &dom_pol,
426 SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid,
429 if (!NT_STATUS_IS_OK(result))
433 result = rpccli_samr_query_userinfo(cli, mem_ctx, &user_pol,
436 rpccli_samr_close(cli, mem_ctx, &user_pol);
438 if (!NT_STATUS_IS_OK(result))
441 sid_compose(&user_info->user_sid, &domain->sid, user_rid);
442 sid_compose(&user_info->group_sid, &domain->sid,
443 ctr->info.id21->group_rid);
444 user_info->acct_name = unistr2_tdup(mem_ctx,
445 &ctr->info.id21->uni_user_name);
446 user_info->full_name = unistr2_tdup(mem_ctx,
447 &ctr->info.id21->uni_full_name);
448 user_info->homedir = NULL;
449 user_info->shell = NULL;
454 /* Lookup groups a user is a member of. I wish Unix had a call like this! */
455 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
457 const DOM_SID *user_sid,
458 uint32 *num_groups, DOM_SID **user_grpsids)
460 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
461 POLICY_HND dom_pol, user_pol;
462 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
463 DOM_GID *user_groups;
467 struct rpc_pipe_client *cli;
469 DEBUG(3,("rpc: lookup_usergroups sid=%s\n",
470 sid_to_string(sid_string, user_sid)));
472 if (!sid_peek_check_rid(&domain->sid, user_sid, &user_rid))
473 return NT_STATUS_UNSUCCESSFUL;
476 *user_grpsids = NULL;
478 /* so lets see if we have a cached user_info_3 */
479 result = lookup_usergroups_cached(domain, mem_ctx, user_sid,
480 num_groups, user_grpsids);
482 if (NT_STATUS_IS_OK(result)) {
486 /* no cache; hit the wire */
488 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
489 if (!NT_STATUS_IS_OK(result))
492 /* Get user handle */
493 result = rpccli_samr_open_user(cli, mem_ctx, &dom_pol,
494 des_access, user_rid, &user_pol);
496 if (!NT_STATUS_IS_OK(result))
499 /* Query user rids */
500 result = rpccli_samr_query_usergroups(cli, mem_ctx, &user_pol,
501 num_groups, &user_groups);
503 rpccli_samr_close(cli, mem_ctx, &user_pol);
505 if (!NT_STATUS_IS_OK(result) || (*num_groups) == 0)
508 (*user_grpsids) = TALLOC_ARRAY(mem_ctx, DOM_SID, *num_groups);
509 if (!(*user_grpsids))
510 return NT_STATUS_NO_MEMORY;
512 for (i=0;i<(*num_groups);i++) {
513 sid_copy(&((*user_grpsids)[i]), &domain->sid);
514 sid_append_rid(&((*user_grpsids)[i]),
515 user_groups[i].g_rid);
521 NTSTATUS msrpc_lookup_useraliases(struct winbindd_domain *domain,
523 uint32 num_sids, const DOM_SID *sids,
524 uint32 *num_aliases, uint32 **alias_rids)
526 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
528 DOM_SID2 *query_sids;
529 uint32 num_query_sids = 0;
531 struct rpc_pipe_client *cli;
532 uint32 *alias_rids_query, num_aliases_query;
533 int rangesize = MAX_SAM_ENTRIES_W2K;
534 uint32 total_sids = 0;
540 DEBUG(3,("rpc: lookup_useraliases\n"));
542 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
543 if (!NT_STATUS_IS_OK(result))
549 num_query_sids = MIN(num_sids - total_sids, rangesize);
551 DEBUG(10,("rpc: lookup_useraliases: entering query %d for %d sids\n",
552 num_queries, num_query_sids));
555 query_sids = TALLOC_ARRAY(mem_ctx, DOM_SID2, num_query_sids);
556 if (query_sids == NULL) {
557 return NT_STATUS_NO_MEMORY;
560 for (i=0; i<num_query_sids; i++) {
561 sid_copy(&query_sids[i].sid, &sids[total_sids++]);
562 query_sids[i].num_auths = query_sids[i].sid.num_auths;
567 result = rpccli_samr_query_useraliases(cli, mem_ctx, &dom_pol,
568 num_query_sids, query_sids,
572 if (!NT_STATUS_IS_OK(result)) {
575 TALLOC_FREE(query_sids);
581 for (i=0; i<num_aliases_query; i++) {
582 size_t na = *num_aliases;
583 add_rid_to_array_unique(mem_ctx, alias_rids_query[i],
588 TALLOC_FREE(query_sids);
592 } while (total_sids < num_sids);
595 DEBUG(10,("rpc: lookup_useraliases: got %d aliases in %d queries "
596 "(rangesize: %d)\n", *num_aliases, num_queries, rangesize));
602 /* Lookup group membership given a rid. */
603 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
605 const DOM_SID *group_sid, uint32 *num_names,
606 DOM_SID **sid_mem, char ***names,
609 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
610 uint32 i, total_names = 0;
611 POLICY_HND dom_pol, group_pol;
612 uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
613 uint32 *rid_mem = NULL;
617 struct rpc_pipe_client *cli;
618 unsigned int orig_timeout;
620 DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name,
621 sid_to_string(sid_string, group_sid)));
623 if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid))
624 return NT_STATUS_UNSUCCESSFUL;
628 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
629 if (!NT_STATUS_IS_OK(result))
632 result = rpccli_samr_open_group(cli, mem_ctx, &dom_pol,
633 des_access, group_rid, &group_pol);
635 if (!NT_STATUS_IS_OK(result))
638 /* Step #1: Get a list of user rids that are the members of the
641 /* This call can take a long time - allow the server to time out.
642 35 seconds should do it. */
644 orig_timeout = cli_set_timeout(cli->cli, 35000);
646 result = rpccli_samr_query_groupmem(cli, mem_ctx,
647 &group_pol, num_names, &rid_mem,
650 /* And restore our original timeout. */
651 cli_set_timeout(cli->cli, orig_timeout);
653 rpccli_samr_close(cli, mem_ctx, &group_pol);
655 if (!NT_STATUS_IS_OK(result))
665 /* Step #2: Convert list of rids into list of usernames. Do this
666 in bunches of ~1000 to avoid crashing NT4. It looks like there
667 is a buffer overflow or something like that lurking around
670 #define MAX_LOOKUP_RIDS 900
672 *names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_names);
673 *name_types = TALLOC_ZERO_ARRAY(mem_ctx, uint32, *num_names);
674 *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_names);
676 for (j=0;j<(*num_names);j++)
677 sid_compose(&(*sid_mem)[j], &domain->sid, rid_mem[j]);
679 if (*num_names>0 && (!*names || !*name_types))
680 return NT_STATUS_NO_MEMORY;
682 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
683 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
684 uint32 tmp_num_names = 0;
685 char **tmp_names = NULL;
686 uint32 *tmp_types = NULL;
688 /* Lookup a chunk of rids */
690 result = rpccli_samr_lookup_rids(cli, mem_ctx,
695 &tmp_names, &tmp_types);
697 /* see if we have a real error (and yes the
698 STATUS_SOME_UNMAPPED is the one returned from 2k) */
700 if (!NT_STATUS_IS_OK(result) &&
701 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
704 /* Copy result into array. The talloc system will take
705 care of freeing the temporary arrays later on. */
707 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
710 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
713 total_names += tmp_num_names;
716 *num_names = total_names;
725 static int get_ldap_seq(const char *server, int port, uint32 *seq)
729 const char *attrs[] = {"highestCommittedUSN", NULL};
730 LDAPMessage *res = NULL;
731 char **values = NULL;
734 *seq = DOM_SEQUENCE_NONE;
737 * Parameterised (5) second timeout on open. This is needed as the
738 * search timeout doesn't seem to apply to doing an open as well. JRA.
741 ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout());
745 /* Timeout if no response within 20 seconds. */
749 if (ldap_search_st(ldp, "", LDAP_SCOPE_BASE, "(objectclass=*)",
750 CONST_DISCARD(char **, attrs), 0, &to, &res))
753 if (ldap_count_entries(ldp, res) != 1)
756 values = ldap_get_values(ldp, res, "highestCommittedUSN");
757 if (!values || !values[0])
760 *seq = atoi(values[0]);
766 ldap_value_free(values);
774 /**********************************************************************
775 Get the sequence number for a Windows AD native mode domain using
777 **********************************************************************/
779 static int get_ldap_sequence_number(struct winbindd_domain *domain, uint32 *seq)
784 fstrcpy( ipstr, inet_ntoa(domain->dcaddr.sin_addr));
785 if ((ret = get_ldap_seq( ipstr, LDAP_PORT, seq)) == 0) {
786 DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence "
787 "number for Domain (%s) from DC (%s)\n",
788 domain->name, ipstr));
793 #endif /* HAVE_LDAP */
795 /* find the sequence number for a domain */
796 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
802 BOOL got_seq_num = False;
803 struct rpc_pipe_client *cli;
805 DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
807 *seq = DOM_SEQUENCE_NONE;
809 if (!(mem_ctx = talloc_init("sequence_number[rpc]")))
810 return NT_STATUS_NO_MEMORY;
813 if ( domain->native_mode )
817 DEBUG(8,("using get_ldap_seq() to retrieve the "
818 "sequence number\n"));
820 res = get_ldap_sequence_number( domain, seq );
823 result = NT_STATUS_OK;
824 DEBUG(10,("domain_sequence_number: LDAP for "
826 domain->name, *seq));
830 DEBUG(10,("domain_sequence_number: failed to get LDAP "
831 "sequence number for domain %s\n",
834 #endif /* HAVE_LDAP */
836 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
837 if (!NT_STATUS_IS_OK(result)) {
841 /* Query domain info */
843 result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 8, &ctr);
845 if (NT_STATUS_IS_OK(result)) {
846 *seq = ctr.info.inf8.seq_num.low;
851 /* retry with info-level 2 in case the dc does not support info-level 8
852 * (like all older samba2 and samba3 dc's - Guenther */
854 result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 2, &ctr);
856 if (NT_STATUS_IS_OK(result)) {
857 *seq = ctr.info.inf2.seq_num.low;
863 DEBUG(10,("domain_sequence_number: for domain %s is %u\n",
864 domain->name, (unsigned)*seq));
866 DEBUG(10,("domain_sequence_number: failed to get sequence "
867 "number (%u) for domain %s\n",
868 (unsigned)*seq, domain->name ));
873 talloc_destroy(mem_ctx);
878 /* get a list of trusted domains */
879 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
886 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
888 struct rpc_pipe_client *cli;
889 POLICY_HND lsa_policy;
891 DEBUG(3,("rpc: trusted_domains\n"));
898 result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
899 if (!NT_STATUS_IS_OK(result))
902 result = STATUS_MORE_ENTRIES;
904 while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
905 uint32 start_idx, num;
910 result = rpccli_lsa_enum_trust_dom(cli, mem_ctx,
911 &lsa_policy, &enum_ctx,
915 if (!NT_STATUS_IS_OK(result) &&
916 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
919 start_idx = *num_domains;
921 *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
922 char *, *num_domains);
923 *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
924 DOM_SID, *num_domains);
925 *alt_names = TALLOC_REALLOC_ARRAY(mem_ctx, *alt_names,
926 char *, *num_domains);
927 if ((*names == NULL) || (*dom_sids == NULL) ||
928 (*alt_names == NULL))
929 return NT_STATUS_NO_MEMORY;
931 for (i=0; i<num; i++) {
932 (*names)[start_idx+i] = tmp_names[i];
933 (*dom_sids)[start_idx+i] = tmp_sids[i];
934 (*alt_names)[start_idx+i] = talloc_strdup(mem_ctx, "");
940 /* find the lockout policy for a domain */
941 NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain,
943 SAM_UNK_INFO_12 *lockout_policy)
946 struct rpc_pipe_client *cli;
950 DEBUG(10,("rpc: fetch lockout policy for %s\n", domain->name));
952 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
953 if (!NT_STATUS_IS_OK(result)) {
957 result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 12, &ctr);
958 if (!NT_STATUS_IS_OK(result)) {
962 *lockout_policy = ctr.info.inf12;
964 DEBUG(10,("msrpc_lockout_policy: bad_attempt_lockout %d\n",
965 ctr.info.inf12.bad_attempt_lockout));
972 /* find the password policy for a domain */
973 NTSTATUS msrpc_password_policy(struct winbindd_domain *domain,
975 SAM_UNK_INFO_1 *password_policy)
978 struct rpc_pipe_client *cli;
982 DEBUG(10,("rpc: fetch password policy for %s\n", domain->name));
984 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
985 if (!NT_STATUS_IS_OK(result)) {
989 result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 1, &ctr);
990 if (!NT_STATUS_IS_OK(result)) {
994 *password_policy = ctr.info.inf1;
996 DEBUG(10,("msrpc_password_policy: min_length_password %d\n",
997 ctr.info.inf1.min_length_password));
1005 /* the rpc backend methods are exposed via this structure */
1006 struct winbindd_methods msrpc_methods = {
1013 msrpc_rids_to_names,
1016 msrpc_lookup_useraliases,
1019 msrpc_lockout_policy,
1020 msrpc_password_policy,