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 SID_NAME_USE *type)
247 DOM_SID *sids = NULL;
248 enum SID_NAME_USE *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 SID_NAME_USE *type)
297 enum SID_NAME_USE *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 SID_NAME_USE)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 SID_NAME_USE **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;
619 DEBUG(10,("rpc: lookup_groupmem %s sid=%s\n", domain->name,
620 sid_to_string(sid_string, group_sid)));
622 if (!sid_peek_check_rid(&domain->sid, group_sid, &group_rid))
623 return NT_STATUS_UNSUCCESSFUL;
627 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
628 if (!NT_STATUS_IS_OK(result))
631 result = rpccli_samr_open_group(cli, mem_ctx, &dom_pol,
632 des_access, group_rid, &group_pol);
634 if (!NT_STATUS_IS_OK(result))
637 /* Step #1: Get a list of user rids that are the members of the
640 result = rpccli_samr_query_groupmem(cli, mem_ctx,
641 &group_pol, num_names, &rid_mem,
644 rpccli_samr_close(cli, mem_ctx, &group_pol);
646 if (!NT_STATUS_IS_OK(result))
656 /* Step #2: Convert list of rids into list of usernames. Do this
657 in bunches of ~1000 to avoid crashing NT4. It looks like there
658 is a buffer overflow or something like that lurking around
661 #define MAX_LOOKUP_RIDS 900
663 *names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_names);
664 *name_types = TALLOC_ZERO_ARRAY(mem_ctx, uint32, *num_names);
665 *sid_mem = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_names);
667 for (j=0;j<(*num_names);j++)
668 sid_compose(&(*sid_mem)[j], &domain->sid, rid_mem[j]);
670 if (*num_names>0 && (!*names || !*name_types))
671 return NT_STATUS_NO_MEMORY;
673 for (i = 0; i < *num_names; i += MAX_LOOKUP_RIDS) {
674 int num_lookup_rids = MIN(*num_names - i, MAX_LOOKUP_RIDS);
675 uint32 tmp_num_names = 0;
676 char **tmp_names = NULL;
677 uint32 *tmp_types = NULL;
679 /* Lookup a chunk of rids */
681 result = rpccli_samr_lookup_rids(cli, mem_ctx,
686 &tmp_names, &tmp_types);
688 /* see if we have a real error (and yes the
689 STATUS_SOME_UNMAPPED is the one returned from 2k) */
691 if (!NT_STATUS_IS_OK(result) &&
692 !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
695 /* Copy result into array. The talloc system will take
696 care of freeing the temporary arrays later on. */
698 memcpy(&(*names)[i], tmp_names, sizeof(char *) *
701 memcpy(&(*name_types)[i], tmp_types, sizeof(uint32) *
704 total_names += tmp_num_names;
707 *num_names = total_names;
716 static int get_ldap_seq(const char *server, int port, uint32 *seq)
720 const char *attrs[] = {"highestCommittedUSN", NULL};
721 LDAPMessage *res = NULL;
722 char **values = NULL;
725 *seq = DOM_SEQUENCE_NONE;
728 * Parameterised (5) second timeout on open. This is needed as the
729 * search timeout doesn't seem to apply to doing an open as well. JRA.
732 ldp = ldap_open_with_timeout(server, port, lp_ldap_timeout());
736 /* Timeout if no response within 20 seconds. */
740 if (ldap_search_st(ldp, "", LDAP_SCOPE_BASE, "(objectclass=*)",
741 CONST_DISCARD(char **, attrs), 0, &to, &res))
744 if (ldap_count_entries(ldp, res) != 1)
747 values = ldap_get_values(ldp, res, "highestCommittedUSN");
748 if (!values || !values[0])
751 *seq = atoi(values[0]);
757 ldap_value_free(values);
765 /**********************************************************************
766 Get the sequence number for a Windows AD native mode domain using
768 **********************************************************************/
770 static int get_ldap_sequence_number( const char* domain, uint32 *seq)
773 int i, port = LDAP_PORT;
774 struct ip_service *ip_list = NULL;
777 if ( !NT_STATUS_IS_OK(get_sorted_dc_list(domain, &ip_list, &count,
779 DEBUG(3, ("Could not look up dc's for domain %s\n", domain));
783 /* Finally return first DC that we can contact */
785 for (i = 0; i < count; i++) {
788 /* since the is an LDAP lookup, default to the LDAP_PORT is
790 port = (ip_list[i].port!= PORT_NONE) ?
791 ip_list[i].port : LDAP_PORT;
793 fstrcpy( ipstr, inet_ntoa(ip_list[i].ip) );
795 if (is_zero_ip(ip_list[i].ip))
798 if ( (ret = get_ldap_seq( ipstr, port, seq)) == 0 )
801 /* add to failed connection cache */
802 add_failed_connection_entry( domain, ipstr,
803 NT_STATUS_UNSUCCESSFUL );
808 DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence "
809 "number for Domain (%s) from DC (%s:%d)\n",
810 domain, inet_ntoa(ip_list[i].ip), port));
818 #endif /* HAVE_LDAP */
820 /* find the sequence number for a domain */
821 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
827 BOOL got_seq_num = False;
828 struct rpc_pipe_client *cli;
830 DEBUG(10,("rpc: fetch sequence_number for %s\n", domain->name));
832 *seq = DOM_SEQUENCE_NONE;
834 if (!(mem_ctx = talloc_init("sequence_number[rpc]")))
835 return NT_STATUS_NO_MEMORY;
838 if ( domain->native_mode )
842 DEBUG(8,("using get_ldap_seq() to retrieve the "
843 "sequence number\n"));
845 res = get_ldap_sequence_number( domain->name, seq );
848 result = NT_STATUS_OK;
849 DEBUG(10,("domain_sequence_number: LDAP for "
851 domain->name, *seq));
855 DEBUG(10,("domain_sequence_number: failed to get LDAP "
856 "sequence number for domain %s\n",
859 #endif /* HAVE_LDAP */
861 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
862 if (!NT_STATUS_IS_OK(result)) {
866 /* Query domain info */
868 result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 8, &ctr);
870 if (NT_STATUS_IS_OK(result)) {
871 *seq = ctr.info.inf8.seq_num;
876 /* retry with info-level 2 in case the dc does not support info-level 8
877 * (like all older samba2 and samba3 dc's - Guenther */
879 result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 2, &ctr);
881 if (NT_STATUS_IS_OK(result)) {
882 *seq = ctr.info.inf2.seq_num;
888 DEBUG(10,("domain_sequence_number: for domain %s is %u\n",
889 domain->name, (unsigned)*seq));
891 DEBUG(10,("domain_sequence_number: failed to get sequence "
892 "number (%u) for domain %s\n",
893 (unsigned)*seq, domain->name ));
898 talloc_destroy(mem_ctx);
903 /* get a list of trusted domains */
904 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
911 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
913 struct rpc_pipe_client *cli;
914 POLICY_HND lsa_policy;
916 DEBUG(3,("rpc: trusted_domains\n"));
923 result = cm_connect_lsa(domain, mem_ctx, &cli, &lsa_policy);
924 if (!NT_STATUS_IS_OK(result))
927 result = STATUS_MORE_ENTRIES;
929 while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) {
930 uint32 start_idx, num;
935 result = rpccli_lsa_enum_trust_dom(cli, mem_ctx,
936 &lsa_policy, &enum_ctx,
940 if (!NT_STATUS_IS_OK(result) &&
941 !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
944 start_idx = *num_domains;
946 *names = TALLOC_REALLOC_ARRAY(mem_ctx, *names,
947 char *, *num_domains);
948 *dom_sids = TALLOC_REALLOC_ARRAY(mem_ctx, *dom_sids,
949 DOM_SID, *num_domains);
950 *alt_names = TALLOC_REALLOC_ARRAY(mem_ctx, *alt_names,
951 char *, *num_domains);
952 if ((*names == NULL) || (*dom_sids == NULL) ||
953 (*alt_names == NULL))
954 return NT_STATUS_NO_MEMORY;
956 for (i=0; i<num; i++) {
957 (*names)[start_idx+i] = tmp_names[i];
958 (*dom_sids)[start_idx+i] = tmp_sids[i];
959 (*alt_names)[start_idx+i] = talloc_strdup(mem_ctx, "");
965 /* find the lockout policy for a domain */
966 NTSTATUS msrpc_lockout_policy(struct winbindd_domain *domain,
968 SAM_UNK_INFO_12 *lockout_policy)
971 struct rpc_pipe_client *cli;
975 DEBUG(10,("rpc: fetch lockout policy for %s\n", domain->name));
977 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
978 if (!NT_STATUS_IS_OK(result)) {
982 result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 12, &ctr);
983 if (!NT_STATUS_IS_OK(result)) {
987 *lockout_policy = ctr.info.inf12;
989 DEBUG(10,("msrpc_lockout_policy: bad_attempt_lockout %d\n",
990 ctr.info.inf12.bad_attempt_lockout));
997 /* find the password policy for a domain */
998 NTSTATUS msrpc_password_policy(struct winbindd_domain *domain,
1000 SAM_UNK_INFO_1 *password_policy)
1003 struct rpc_pipe_client *cli;
1007 DEBUG(10,("rpc: fetch password policy for %s\n", domain->name));
1009 result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
1010 if (!NT_STATUS_IS_OK(result)) {
1014 result = rpccli_samr_query_dom_info(cli, mem_ctx, &dom_pol, 1, &ctr);
1015 if (!NT_STATUS_IS_OK(result)) {
1019 *password_policy = ctr.info.inf1;
1021 DEBUG(10,("msrpc_password_policy: min_length_password %d\n",
1022 ctr.info.inf1.min_length_password));
1030 /* the rpc backend methods are exposed via this structure */
1031 struct winbindd_methods msrpc_methods = {
1038 msrpc_rids_to_names,
1041 msrpc_lookup_useraliases,
1044 msrpc_lockout_policy,
1045 msrpc_password_policy,