2 Unix SMB/CIFS implementation.
4 Winbind ADS backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
8 Copyright (C) Gerald (Jerry) Carter 2004
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 3 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, see <http://www.gnu.org/licenses/>.
26 #include "rpc_client/rpc_client.h"
27 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
28 #include "../libds/common/flags.h"
30 #include "../libcli/ldap/ldap_ndr.h"
31 #include "../libcli/security/security.h"
32 #include "../libds/common/flag_mapping.h"
33 #include "libsmb/samlogon_cache.h"
39 #define DBGC_CLASS DBGC_WINBIND
41 extern struct winbindd_methods reconnect_methods;
42 extern struct winbindd_methods msrpc_methods;
44 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
47 * Check if cached connection can be reused. If the connection cannot
48 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
50 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
53 ADS_STRUCT *ads = *adsp;
57 time_t now = time(NULL);
59 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
61 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
62 "is now %d)\n", (uint32_t)expire - (uint32_t)now,
63 (uint32_t) expire, (uint32_t) now));
65 if ( ads->config.realm && (expire > now)) {
68 /* we own this ADS_STRUCT so make sure it goes away */
69 DEBUG(7,("Deleting expired krb5 credential cache\n"));
72 ads_kdestroy(WINBIND_CCACHE_NAME);
79 * @brief Establish a connection to a DC
81 * @param[out] adsp ADS_STRUCT that will be created
82 * @param[in] target_realm Realm of domain to connect to
83 * @param[in] target_dom_name 'workgroup' name of domain to connect to
84 * @param[in] ldap_server DNS name of server to connect to
85 * @param[in] password Our machine acount secret
86 * @param[in] auth_realm Realm of local domain for creating krb token
87 * @param[in] renewable Renewable ticket time
91 static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
92 const char *target_realm,
93 const char *target_dom_name,
94 const char *ldap_server,
101 struct sockaddr_storage dc_ss;
104 if (auth_realm == NULL) {
105 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
108 /* we don't want this to affect the users ccache */
109 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
111 ads = ads_init(target_realm, target_dom_name, ldap_server);
113 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
114 return ADS_ERROR(LDAP_NO_MEMORY);
117 SAFE_FREE(ads->auth.password);
118 SAFE_FREE(ads->auth.realm);
120 ads->auth.renewable = renewable;
121 ads->auth.password = password;
123 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
125 ads->auth.realm = SMB_STRDUP(auth_realm);
126 if (!strupper_m(ads->auth.realm)) {
128 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
131 /* Setup the server affinity cache. We don't reaally care
132 about the name. Just setup affinity and the KRB5_CONFIG
134 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
136 status = ads_connect(ads);
137 if (!ADS_ERR_OK(status)) {
138 DEBUG(1,("ads_connect for domain %s failed: %s\n",
139 target_dom_name, ads_errstr(status)));
144 /* set the flag that says we don't own the memory even
145 though we do so that ads_destroy() won't destroy the
146 structure we pass back by reference */
148 ads->is_mine = False;
155 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
157 char *ldap_server, *realm, *password;
158 struct winbindd_domain *wb_dom;
161 ads_cached_connection_reuse(adsp);
167 * At this point we only have the NetBIOS domain name.
168 * Check if we can get server nam and realm from SAF cache
169 * and the domain list.
171 ldap_server = saf_fetch(talloc_tos(), dom_name);
172 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
173 ldap_server ? ldap_server : ""));
175 wb_dom = find_domain_from_name(dom_name);
176 if (wb_dom == NULL) {
177 DEBUG(10, ("could not find domain '%s'\n", dom_name));
178 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
181 DEBUG(10, ("find_domain_from_name found realm '%s' for "
182 " domain '%s'\n", wb_dom->alt_name, dom_name));
184 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
185 TALLOC_FREE(ldap_server);
186 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
190 SMB_ASSERT(wb_dom->alt_name != NULL);
191 realm = SMB_STRDUP(wb_dom->alt_name);
193 struct winbindd_domain *our_domain = wb_dom;
195 /* always give preference to the alt_name in our
196 primary domain if possible */
198 if (!wb_dom->primary) {
199 our_domain = find_our_domain();
202 if (our_domain->alt_name != NULL) {
203 realm = SMB_STRDUP(our_domain->alt_name);
205 realm = SMB_STRDUP(lp_realm());
209 status = ads_cached_connection_connect(
210 adsp, /* Returns ads struct. */
211 wb_dom->alt_name, /* realm to connect to. */
212 dom_name, /* 'workgroup' name for ads_init */
213 ldap_server, /* DNS name to connect to. */
214 password, /* password for auth realm. */
215 realm, /* realm used for krb5 ticket. */
216 0); /* renewable ticket time. */
219 TALLOC_FREE(ldap_server);
225 return our ads connections structure for a domain. We keep the connection
226 open to make things faster
228 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
231 char *password, *realm;
233 DEBUG(10,("ads_cached_connection\n"));
234 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
236 if (domain->private_data) {
237 return (ADS_STRUCT *)domain->private_data;
240 /* the machine acct password might have change - fetch it every time */
242 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
247 SMB_ASSERT(domain->alt_name != NULL);
248 realm = SMB_STRDUP(domain->alt_name);
251 struct winbindd_domain *our_domain = domain;
254 /* always give preference to the alt_name in our
255 primary domain if possible */
257 if ( !domain->primary )
258 our_domain = find_our_domain();
260 if (our_domain->alt_name != NULL) {
261 realm = SMB_STRDUP( our_domain->alt_name );
264 realm = SMB_STRDUP( lp_realm() );
267 status = ads_cached_connection_connect(
268 (ADS_STRUCT **)&domain->private_data,
272 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
275 if (!ADS_ERR_OK(status)) {
276 /* if we get ECONNREFUSED then it might be a NT4
277 server, fall back to MSRPC */
278 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
279 status.err.rc == ECONNREFUSED) {
280 /* 'reconnect_methods' is the MS-RPC backend. */
281 DEBUG(1,("Trying MSRPC methods\n"));
282 domain->backend = &reconnect_methods;
287 return (ADS_STRUCT *)domain->private_data;
290 /* Query display info for a realm. This is the basic user list fn */
291 static NTSTATUS query_user_list(struct winbindd_domain *domain,
295 ADS_STRUCT *ads = NULL;
296 const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
298 uint32_t *rids = NULL;
300 LDAPMessage *res = NULL;
301 LDAPMessage *msg = NULL;
302 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
304 DEBUG(3,("ads: query_user_list\n"));
306 if ( !winbindd_can_contact_domain( domain ) ) {
307 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
312 ads = ads_cached_connection(domain);
315 domain->last_status = NT_STATUS_SERVER_DISABLED;
319 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
320 if (!ADS_ERR_OK(rc)) {
321 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
322 status = ads_ntstatus(rc);
325 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
329 count = ads_count_replies(ads, res);
331 DEBUG(1,("query_user_list: No users found\n"));
335 rids = talloc_zero_array(mem_ctx, uint32_t, count);
337 status = NT_STATUS_NO_MEMORY;
343 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
344 struct dom_sid user_sid;
348 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
350 DBG_INFO("Object lacks sAMAccountType attribute\n");
353 if (ds_atype_map(atype) != SID_NAME_USER) {
354 DBG_INFO("Not a user account? atype=0x%x\n", atype);
358 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
359 char *dn = ads_get_dn(ads, talloc_tos(), msg);
360 DBG_INFO("No sid for %s !?\n", dn);
365 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
366 fstring sidstr, domstr;
367 DBG_WARNING("Got sid %s in domain %s\n",
368 sid_to_fstring(sidstr, &user_sid),
369 sid_to_fstring(domstr, &domain->sid));
373 sid_split_rid(&user_sid, &rids[count]);
377 rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
382 status = NT_STATUS_OK;
384 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
390 /* list all domain groups */
391 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
393 uint32_t *num_entries,
394 struct wb_acct_info **info)
396 ADS_STRUCT *ads = NULL;
397 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
398 "name", "objectSid", NULL};
401 LDAPMessage *res = NULL;
402 LDAPMessage *msg = NULL;
403 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
405 bool enum_dom_local_groups = False;
409 DEBUG(3,("ads: enum_dom_groups\n"));
411 if ( !winbindd_can_contact_domain( domain ) ) {
412 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
417 /* only grab domain local groups for our domain */
418 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
419 enum_dom_local_groups = True;
422 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
425 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
426 * default value, it MUST be absent. In case of extensible matching the
427 * "dnattr" boolean defaults to FALSE and so it must be only be present
430 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
431 * filter using bitwise matching rule then the buggy AD fails to decode
432 * the extensible match. As a workaround set it to TRUE and thereby add
433 * the dnAttributes "dn" field to cope with those older AD versions.
434 * It should not harm and won't put any additional load on the AD since
435 * none of the dn components have a bitmask-attribute.
437 * Thanks to Ralf Haferkamp for input and testing - Guenther */
439 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
440 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
441 ADS_LDAP_MATCHING_RULE_BIT_AND,
442 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
444 if (filter == NULL) {
445 status = NT_STATUS_NO_MEMORY;
449 ads = ads_cached_connection(domain);
452 domain->last_status = NT_STATUS_SERVER_DISABLED;
456 rc = ads_search_retry(ads, &res, filter, attrs);
457 if (!ADS_ERR_OK(rc)) {
458 status = ads_ntstatus(rc);
459 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
462 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
466 count = ads_count_replies(ads, res);
468 DEBUG(1,("enum_dom_groups: No groups found\n"));
472 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
474 status = NT_STATUS_NO_MEMORY;
480 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
485 name = ads_pull_username(ads, mem_ctx, msg);
486 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
487 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
488 DEBUG(1,("No sid for %s !?\n", name));
492 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
493 DEBUG(1,("No rid for %s !?\n", name));
497 fstrcpy((*info)[i].acct_name, name);
498 fstrcpy((*info)[i].acct_desc, gecos);
499 (*info)[i].rid = rid;
505 status = NT_STATUS_OK;
507 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
511 ads_msgfree(ads, res);
516 /* list all domain local groups */
517 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
519 uint32_t *num_entries,
520 struct wb_acct_info **info)
523 * This is a stub function only as we returned the domain
524 * local groups in enum_dom_groups() if the domain->native field
525 * was true. This is a simple performance optimization when
528 * if we ever need to enumerate domain local groups separately,
529 * then this optimization in enum_dom_groups() will need
537 /* convert a single name to a sid in a domain - use rpc methods */
538 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
540 const char *domain_name,
544 enum lsa_SidType *type)
546 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
550 /* convert a domain SID to a user or group name - use rpc methods */
551 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
553 const struct dom_sid *sid,
556 enum lsa_SidType *type)
558 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
559 domain_name, name, type);
562 /* convert a list of rids to names - use rpc methods */
563 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
565 const struct dom_sid *sid,
570 enum lsa_SidType **types)
572 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
574 domain_name, names, types);
577 /* Lookup aliases a user is member of - use rpc methods */
578 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
580 uint32_t num_sids, const struct dom_sid *sids,
581 uint32_t *num_aliases, uint32_t **alias_rids)
583 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
584 num_aliases, alias_rids);
587 static NTSTATUS add_primary_group_members(
588 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
589 char ***all_members, size_t *num_all_members)
592 NTSTATUS status = NT_STATUS_NO_MEMORY;
594 const char *attrs[] = { "dn", NULL };
595 LDAPMessage *res = NULL;
601 filter = talloc_asprintf(
602 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
604 if (filter == NULL) {
608 args.control = ADS_EXTENDED_DN_OID;
609 args.val = ADS_EXTENDED_DN_HEX_STRING;
610 args.critical = True;
612 rc = ads_do_search_all_args(ads, ads->config.bind_path,
613 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
616 if (!ADS_ERR_OK(rc)) {
617 status = ads_ntstatus(rc);
618 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
622 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
626 num_members = ads_count_replies(ads, res);
628 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
629 (uintmax_t)num_members));
631 if (num_members == 0) {
632 status = NT_STATUS_OK;
636 members = talloc_realloc(mem_ctx, *all_members, char *,
637 *num_all_members + num_members);
638 if (members == NULL) {
639 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
642 *all_members = members;
644 for (msg = ads_first_entry(ads, res); msg != NULL;
645 msg = ads_next_entry(ads, msg)) {
648 dn = ads_get_dn(ads, members, msg);
650 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
654 members[*num_all_members] = dn;
655 *num_all_members += 1;
658 status = NT_STATUS_OK;
661 ads_msgfree(ads, res);
668 find the members of a group, given a group rid and domain
670 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
672 const struct dom_sid *group_sid,
673 enum lsa_SidType type,
675 struct dom_sid **sid_mem, char ***names,
676 uint32_t **name_types)
679 ADS_STRUCT *ads = NULL;
681 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
683 char **members = NULL;
685 size_t num_members = 0;
687 struct dom_sid *sid_mem_nocache = NULL;
688 char **names_nocache = NULL;
689 enum lsa_SidType *name_types_nocache = NULL;
690 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
691 uint32_t num_nocache = 0;
692 TALLOC_CTX *tmp_ctx = NULL;
695 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
696 sid_string_dbg(group_sid)));
700 tmp_ctx = talloc_new(mem_ctx);
702 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
703 status = NT_STATUS_NO_MEMORY;
707 if (!sid_peek_rid(group_sid, &rid)) {
708 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
709 status = NT_STATUS_INVALID_PARAMETER;
713 if ( !winbindd_can_contact_domain( domain ) ) {
714 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
719 ads = ads_cached_connection(domain);
722 domain->last_status = NT_STATUS_SERVER_DISABLED;
726 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
727 status = NT_STATUS_NO_MEMORY;
731 /* search for all members of the group */
732 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
733 TALLOC_FREE(sidbinstr);
734 if (ldap_exp == NULL) {
735 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
736 status = NT_STATUS_NO_MEMORY;
740 args.control = ADS_EXTENDED_DN_OID;
741 args.val = ADS_EXTENDED_DN_HEX_STRING;
742 args.critical = True;
744 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
745 ldap_exp, &args, "member", &members, &num_members);
747 if (!ADS_ERR_OK(rc)) {
748 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
749 status = NT_STATUS_UNSUCCESSFUL;
753 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
755 status = add_primary_group_members(ads, mem_ctx, rid,
756 &members, &num_members);
757 if (!NT_STATUS_IS_OK(status)) {
758 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
759 __func__, nt_errstr(status)));
763 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
764 __func__, (int)num_members));
766 /* Now that we have a list of sids, we need to get the
767 * lists of names and name_types belonging to these sids.
768 * even though conceptually not quite clean, we use the
769 * RPC call lsa_lookup_sids for this since it can handle a
770 * list of sids. ldap calls can just resolve one sid at a time.
772 * At this stage, the sids are still hidden in the exetended dn
773 * member output format. We actually do a little better than
774 * stated above: In extracting the sids from the member strings,
775 * we try to resolve as many sids as possible from the
776 * cache. Only the rest is passed to the lsa_lookup_sids call. */
779 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
780 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
781 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
782 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
784 if ((members == NULL) || (*sid_mem == NULL) ||
785 (*names == NULL) || (*name_types == NULL) ||
786 (sid_mem_nocache == NULL))
788 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
789 status = NT_STATUS_NO_MEMORY;
796 (*name_types) = NULL;
799 for (i=0; i<num_members; i++) {
800 enum lsa_SidType name_type;
801 char *name, *domain_name;
804 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
806 if (!ADS_ERR_OK(rc)) {
807 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
808 NT_STATUS_NOT_FOUND)) {
809 /* Group members can be objects, like Exchange
810 * Public Folders, that don't have a SID. Skip
815 status = ads_ntstatus(rc);
819 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
821 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
822 "cache\n", sid_string_dbg(&sid)));
823 sid_copy(&(*sid_mem)[*num_names], &sid);
824 (*names)[*num_names] = fill_domain_username_talloc(
830 (*name_types)[*num_names] = name_type;
834 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
835 "cache\n", sid_string_dbg(&sid)));
836 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
841 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
842 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
844 /* handle sids not resolved from cache by lsa_lookup_sids */
845 if (num_nocache > 0) {
847 status = winbindd_lookup_sids(tmp_ctx,
853 &name_types_nocache);
855 if (!(NT_STATUS_IS_OK(status) ||
856 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
857 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
859 DEBUG(1, ("lsa_lookupsids call failed with %s "
860 "- retrying...\n", nt_errstr(status)));
862 status = winbindd_lookup_sids(tmp_ctx,
868 &name_types_nocache);
871 if (NT_STATUS_IS_OK(status) ||
872 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
874 /* Copy the entries over from the "_nocache" arrays
875 * to the result arrays, skipping the gaps the
876 * lookup_sids call left. */
877 for (i=0; i < num_nocache; i++) {
878 if (((names_nocache)[i] != NULL) &&
879 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
881 sid_copy(&(*sid_mem)[*num_names],
882 &sid_mem_nocache[i]);
883 (*names)[*num_names] =
884 fill_domain_username_talloc(
889 (*name_types)[*num_names] = name_types_nocache[i];
894 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
895 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
896 "not map any SIDs at all.\n"));
897 /* Don't handle this as an error here.
898 * There is nothing left to do with respect to the
899 * overall result... */
901 else if (!NT_STATUS_IS_OK(status)) {
902 DEBUG(10, ("lookup_groupmem: Error looking up %d "
903 "sids via rpc_lsa_lookup_sids: %s\n",
904 (int)num_members, nt_errstr(status)));
909 status = NT_STATUS_OK;
910 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
911 sid_string_dbg(group_sid)));
915 TALLOC_FREE(tmp_ctx);
920 /* find the sequence number for a domain */
921 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
923 ADS_STRUCT *ads = NULL;
926 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
928 if ( !winbindd_can_contact_domain( domain ) ) {
929 DEBUG(10,("sequence: No incoming trust for domain %s\n",
935 *seq = DOM_SEQUENCE_NONE;
937 ads = ads_cached_connection(domain);
940 domain->last_status = NT_STATUS_SERVER_DISABLED;
941 return NT_STATUS_UNSUCCESSFUL;
944 rc = ads_USN(ads, seq);
946 if (!ADS_ERR_OK(rc)) {
948 /* its a dead connection, destroy it */
950 if (domain->private_data) {
951 ads = (ADS_STRUCT *)domain->private_data;
954 ads_kdestroy(WINBIND_CCACHE_NAME);
955 domain->private_data = NULL;
958 return ads_ntstatus(rc);
961 /* find the lockout policy of a domain - use rpc methods */
962 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
964 struct samr_DomInfo12 *policy)
966 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
969 /* find the password policy of a domain - use rpc methods */
970 static NTSTATUS password_policy(struct winbindd_domain *domain,
972 struct samr_DomInfo1 *policy)
974 return msrpc_methods.password_policy(domain, mem_ctx, policy);
977 /* get a list of trusted domains */
978 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
980 struct netr_DomainTrustList *trusts)
982 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
986 struct rpc_pipe_client *cli;
988 struct dcerpc_binding_handle *b;
990 DEBUG(3,("ads: trusted_domains\n"));
992 ZERO_STRUCTP(trusts);
994 /* If this is our primary domain or a root in our forest,
995 query for all trusts. If not, then just look for domain
996 trusts in the target forest */
998 if (domain->primary || domain_is_forest_root(domain)) {
999 flags = NETR_TRUST_FLAG_OUTBOUND |
1000 NETR_TRUST_FLAG_INBOUND |
1001 NETR_TRUST_FLAG_IN_FOREST;
1003 flags = NETR_TRUST_FLAG_IN_FOREST;
1006 result = cm_connect_netlogon(domain, &cli);
1008 if (!NT_STATUS_IS_OK(result)) {
1009 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1010 "for PIPE_NETLOGON (%s)\n",
1011 domain->name, nt_errstr(result)));
1012 return NT_STATUS_UNSUCCESSFUL;
1015 b = cli->binding_handle;
1017 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1022 if (!NT_STATUS_IS_OK(result)) {
1026 if (!W_ERROR_IS_OK(werr)) {
1027 return werror_to_ntstatus(werr);
1029 if (trusts->count == 0) {
1030 return NT_STATUS_OK;
1033 /* Copy across names and sids */
1036 for (i = 0; i < trusts->count; i++) {
1037 struct netr_DomainTrust *trust = &trusts->array[i];
1038 struct winbindd_domain d;
1043 * drop external trusts if this is not our primary
1044 * domain. This means that the returned number of
1045 * domains may be less that the ones actually trusted
1049 if ((trust->trust_attributes
1050 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1053 DEBUG(10,("trusted_domains: Skipping external trusted "
1054 "domain %s because it is outside of our "
1056 trust->netbios_name));
1060 /* add to the trusted domain cache */
1062 d.name = discard_const_p(char, trust->netbios_name);
1063 d.alt_name = discard_const_p(char, trust->dns_name);
1066 sid_copy(&d.sid, trust->sid);
1068 sid_copy(&d.sid, &global_sid_NULL);
1071 if ( domain->primary ) {
1072 DEBUG(10,("trusted_domains(ads): Searching "
1073 "trusted domain list of %s and storing "
1074 "trust flags for domain %s\n",
1075 domain->name, d.alt_name));
1077 d.domain_flags = trust->trust_flags;
1078 d.domain_type = trust->trust_type;
1079 d.domain_trust_attribs = trust->trust_attributes;
1081 wcache_tdc_add_domain( &d );
1083 } else if (domain_is_forest_root(domain)) {
1084 /* Check if we already have this record. If
1085 * we are following our forest root that is not
1086 * our primary domain, we want to keep trust
1087 * flags from the perspective of our primary
1088 * domain not our forest root. */
1089 struct winbindd_tdc_domain *exist = NULL;
1091 exist = wcache_tdc_fetch_domain(
1092 talloc_tos(), trust->netbios_name);
1094 DEBUG(10,("trusted_domains(ads): Searching "
1095 "trusted domain list of %s and "
1096 "storing trust flags for domain "
1097 "%s\n", domain->name, d.alt_name));
1098 d.domain_flags = trust->trust_flags;
1099 d.domain_type = trust->trust_type;
1100 d.domain_trust_attribs =
1101 trust->trust_attributes;
1103 wcache_tdc_add_domain( &d );
1108 /* This gets a little tricky. If we are
1109 following a transitive forest trust, then
1110 innerit the flags, type, and attribs from
1111 the domain we queried to make sure we don't
1112 record the view of the trust from the wrong
1113 side. Always view it from the side of our
1114 primary domain. --jerry */
1115 struct winbindd_tdc_domain *parent = NULL;
1117 DEBUG(10,("trusted_domains(ads): Searching "
1118 "trusted domain list of %s and inheriting "
1119 "trust flags for domain %s\n",
1120 domain->name, d.alt_name));
1122 parent = wcache_tdc_fetch_domain(talloc_tos(),
1125 d.domain_flags = parent->trust_flags;
1126 d.domain_type = parent->trust_type;
1127 d.domain_trust_attribs = parent->trust_attribs;
1129 d.domain_flags = domain->domain_flags;
1130 d.domain_type = domain->domain_type;
1131 d.domain_trust_attribs =
1132 domain->domain_trust_attribs;
1134 TALLOC_FREE(parent);
1137 * We need to pass the modified properties
1140 trust->trust_flags = d.domain_flags;
1141 trust->trust_type = d.domain_type;
1142 trust->trust_attributes = d.domain_trust_attribs;
1144 wcache_tdc_add_domain( &d );
1151 /* the ADS backend methods are exposed via this structure */
1152 struct winbindd_methods ads_methods = {