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.realm = SMB_STRDUP(auth_realm);
124 if (!strupper_m(ads->auth.realm)) {
126 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
129 /* Setup the server affinity cache. We don't reaally care
130 about the name. Just setup affinity and the KRB5_CONFIG
132 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
134 status = ads_connect(ads);
135 if (!ADS_ERR_OK(status)) {
136 DEBUG(1,("ads_connect for domain %s failed: %s\n",
137 target_dom_name, ads_errstr(status)));
142 /* set the flag that says we don't own the memory even
143 though we do so that ads_destroy() won't destroy the
144 structure we pass back by reference */
146 ads->is_mine = False;
153 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
155 char *ldap_server, *realm, *password;
156 struct winbindd_domain *wb_dom;
159 ads_cached_connection_reuse(adsp);
165 * At this point we only have the NetBIOS domain name.
166 * Check if we can get server nam and realm from SAF cache
167 * and the domain list.
169 ldap_server = saf_fetch(talloc_tos(), dom_name);
170 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
171 ldap_server ? ldap_server : ""));
173 wb_dom = find_domain_from_name(dom_name);
174 if (wb_dom == NULL) {
175 DEBUG(10, ("could not find domain '%s'\n", dom_name));
176 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
179 DEBUG(10, ("find_domain_from_name found realm '%s' for "
180 " domain '%s'\n", wb_dom->alt_name, dom_name));
182 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
183 TALLOC_FREE(ldap_server);
184 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
188 SMB_ASSERT(wb_dom->alt_name != NULL);
189 realm = SMB_STRDUP(wb_dom->alt_name);
191 struct winbindd_domain *our_domain = wb_dom;
193 /* always give preference to the alt_name in our
194 primary domain if possible */
196 if (!wb_dom->primary) {
197 our_domain = find_our_domain();
200 if (our_domain->alt_name != NULL) {
201 realm = SMB_STRDUP(our_domain->alt_name);
203 realm = SMB_STRDUP(lp_realm());
207 status = ads_cached_connection_connect(
208 adsp, /* Returns ads struct. */
209 wb_dom->alt_name, /* realm to connect to. */
210 dom_name, /* 'workgroup' name for ads_init */
211 ldap_server, /* DNS name to connect to. */
212 password, /* password for auth realm. */
213 realm, /* realm used for krb5 ticket. */
214 0); /* renewable ticket time. */
217 TALLOC_FREE(ldap_server);
223 return our ads connections structure for a domain. We keep the connection
224 open to make things faster
226 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
229 char *password, *realm;
231 DEBUG(10,("ads_cached_connection\n"));
232 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
234 if (domain->private_data) {
235 return (ADS_STRUCT *)domain->private_data;
238 /* the machine acct password might have change - fetch it every time */
240 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
245 SMB_ASSERT(domain->alt_name != NULL);
246 realm = SMB_STRDUP(domain->alt_name);
249 struct winbindd_domain *our_domain = domain;
252 /* always give preference to the alt_name in our
253 primary domain if possible */
255 if ( !domain->primary )
256 our_domain = find_our_domain();
258 if (our_domain->alt_name != NULL) {
259 realm = SMB_STRDUP( our_domain->alt_name );
262 realm = SMB_STRDUP( lp_realm() );
265 status = ads_cached_connection_connect(
266 (ADS_STRUCT **)&domain->private_data,
270 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
273 if (!ADS_ERR_OK(status)) {
274 /* if we get ECONNREFUSED then it might be a NT4
275 server, fall back to MSRPC */
276 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
277 status.err.rc == ECONNREFUSED) {
278 /* 'reconnect_methods' is the MS-RPC backend. */
279 DEBUG(1,("Trying MSRPC methods\n"));
280 domain->backend = &reconnect_methods;
285 return (ADS_STRUCT *)domain->private_data;
288 /* Query display info for a realm. This is the basic user list fn */
289 static NTSTATUS query_user_list(struct winbindd_domain *domain,
291 uint32_t *num_entries,
292 struct wbint_userinfo **pinfo)
294 ADS_STRUCT *ads = NULL;
295 const char *attrs[] = { "*", NULL };
298 LDAPMessage *res = NULL;
299 LDAPMessage *msg = NULL;
300 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 (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
337 status = NT_STATUS_NO_MEMORY;
343 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
344 struct wbint_userinfo *info = &((*pinfo)[count]);
349 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
351 DBG_INFO("Object lacks sAMAccountType attribute\n");
354 if (ds_atype_map(atype) != SID_NAME_USER) {
355 DBG_INFO("Not a user account? atype=0x%x\n", atype);
359 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
360 info->full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
361 if (info->full_name == NULL) {
362 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
364 info->homedir = NULL;
366 info->primary_gid = (gid_t)-1;
368 if (!ads_pull_sid(ads, msg, "objectSid",
370 DEBUG(1, ("No sid for %s !?\n", info->acct_name));
374 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
375 DEBUG(1, ("No primary group for %s !?\n",
379 sid_compose(&info->group_sid, &domain->sid, group);
384 (*num_entries) = count;
385 ads_msgfree(ads, res);
387 for (i=0; i<count; i++) {
388 struct wbint_userinfo *info = &((*pinfo)[i]);
389 const char *gecos = NULL;
390 gid_t primary_gid = (gid_t)-1;
392 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
393 &info->homedir, &info->shell,
394 &gecos, &primary_gid);
395 if (!NT_STATUS_IS_OK(status)) {
397 * Deliberately ignore this error, there might be more
404 info->full_name = gecos;
406 info->primary_gid = primary_gid;
409 status = NT_STATUS_OK;
411 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
417 /* list all domain groups */
418 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
420 uint32_t *num_entries,
421 struct wb_acct_info **info)
423 ADS_STRUCT *ads = NULL;
424 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
425 "name", "objectSid", NULL};
428 LDAPMessage *res = NULL;
429 LDAPMessage *msg = NULL;
430 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
432 bool enum_dom_local_groups = False;
436 DEBUG(3,("ads: enum_dom_groups\n"));
438 if ( !winbindd_can_contact_domain( domain ) ) {
439 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
444 /* only grab domain local groups for our domain */
445 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
446 enum_dom_local_groups = True;
449 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
452 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
453 * default value, it MUST be absent. In case of extensible matching the
454 * "dnattr" boolean defaults to FALSE and so it must be only be present
457 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
458 * filter using bitwise matching rule then the buggy AD fails to decode
459 * the extensible match. As a workaround set it to TRUE and thereby add
460 * the dnAttributes "dn" field to cope with those older AD versions.
461 * It should not harm and won't put any additional load on the AD since
462 * none of the dn components have a bitmask-attribute.
464 * Thanks to Ralf Haferkamp for input and testing - Guenther */
466 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
467 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
468 ADS_LDAP_MATCHING_RULE_BIT_AND,
469 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
471 if (filter == NULL) {
472 status = NT_STATUS_NO_MEMORY;
476 ads = ads_cached_connection(domain);
479 domain->last_status = NT_STATUS_SERVER_DISABLED;
483 rc = ads_search_retry(ads, &res, filter, attrs);
484 if (!ADS_ERR_OK(rc)) {
485 status = ads_ntstatus(rc);
486 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
489 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
493 count = ads_count_replies(ads, res);
495 DEBUG(1,("enum_dom_groups: No groups found\n"));
499 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
501 status = NT_STATUS_NO_MEMORY;
507 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
512 name = ads_pull_username(ads, mem_ctx, msg);
513 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
514 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
515 DEBUG(1,("No sid for %s !?\n", name));
519 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
520 DEBUG(1,("No rid for %s !?\n", name));
524 fstrcpy((*info)[i].acct_name, name);
525 fstrcpy((*info)[i].acct_desc, gecos);
526 (*info)[i].rid = rid;
532 status = NT_STATUS_OK;
534 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
538 ads_msgfree(ads, res);
543 /* list all domain local groups */
544 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
546 uint32_t *num_entries,
547 struct wb_acct_info **info)
550 * This is a stub function only as we returned the domain
551 * local groups in enum_dom_groups() if the domain->native field
552 * was true. This is a simple performance optimization when
555 * if we ever need to enumerate domain local groups separately,
556 * then this optimization in enum_dom_groups() will need
564 /* convert a single name to a sid in a domain - use rpc methods */
565 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
567 const char *domain_name,
571 enum lsa_SidType *type)
573 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
577 /* convert a domain SID to a user or group name - use rpc methods */
578 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
580 const struct dom_sid *sid,
583 enum lsa_SidType *type)
585 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
586 domain_name, name, type);
589 /* convert a list of rids to names - use rpc methods */
590 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
592 const struct dom_sid *sid,
597 enum lsa_SidType **types)
599 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
601 domain_name, names, types);
604 /* Lookup aliases a user is member of - use rpc methods */
605 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
607 uint32_t num_sids, const struct dom_sid *sids,
608 uint32_t *num_aliases, uint32_t **alias_rids)
610 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
611 num_aliases, alias_rids);
614 static NTSTATUS add_primary_group_members(
615 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
616 char ***all_members, size_t *num_all_members)
619 NTSTATUS status = NT_STATUS_NO_MEMORY;
621 const char *attrs[] = { "dn", NULL };
622 LDAPMessage *res = NULL;
628 filter = talloc_asprintf(
629 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
631 if (filter == NULL) {
635 args.control = ADS_EXTENDED_DN_OID;
636 args.val = ADS_EXTENDED_DN_HEX_STRING;
637 args.critical = True;
639 rc = ads_do_search_all_args(ads, ads->config.bind_path,
640 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
643 if (!ADS_ERR_OK(rc)) {
644 status = ads_ntstatus(rc);
645 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
649 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
653 num_members = ads_count_replies(ads, res);
655 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
656 (uintmax_t)num_members));
658 if (num_members == 0) {
659 status = NT_STATUS_OK;
663 members = talloc_realloc(mem_ctx, *all_members, char *,
664 *num_all_members + num_members);
665 if (members == NULL) {
666 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
669 *all_members = members;
671 for (msg = ads_first_entry(ads, res); msg != NULL;
672 msg = ads_next_entry(ads, msg)) {
675 dn = ads_get_dn(ads, members, msg);
677 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
681 members[*num_all_members] = dn;
682 *num_all_members += 1;
685 status = NT_STATUS_OK;
688 ads_msgfree(ads, res);
695 find the members of a group, given a group rid and domain
697 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
699 const struct dom_sid *group_sid,
700 enum lsa_SidType type,
702 struct dom_sid **sid_mem, char ***names,
703 uint32_t **name_types)
706 ADS_STRUCT *ads = NULL;
708 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
710 char **members = NULL;
712 size_t num_members = 0;
714 struct dom_sid *sid_mem_nocache = NULL;
715 char **names_nocache = NULL;
716 enum lsa_SidType *name_types_nocache = NULL;
717 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
718 uint32_t num_nocache = 0;
719 TALLOC_CTX *tmp_ctx = NULL;
722 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
723 sid_string_dbg(group_sid)));
727 tmp_ctx = talloc_new(mem_ctx);
729 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
730 status = NT_STATUS_NO_MEMORY;
734 if (!sid_peek_rid(group_sid, &rid)) {
735 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
736 status = NT_STATUS_INVALID_PARAMETER;
740 if ( !winbindd_can_contact_domain( domain ) ) {
741 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
746 ads = ads_cached_connection(domain);
749 domain->last_status = NT_STATUS_SERVER_DISABLED;
753 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
754 status = NT_STATUS_NO_MEMORY;
758 /* search for all members of the group */
759 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
760 TALLOC_FREE(sidbinstr);
761 if (ldap_exp == NULL) {
762 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
763 status = NT_STATUS_NO_MEMORY;
767 args.control = ADS_EXTENDED_DN_OID;
768 args.val = ADS_EXTENDED_DN_HEX_STRING;
769 args.critical = True;
771 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
772 ldap_exp, &args, "member", &members, &num_members);
774 if (!ADS_ERR_OK(rc)) {
775 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
776 status = NT_STATUS_UNSUCCESSFUL;
780 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
782 status = add_primary_group_members(ads, mem_ctx, rid,
783 &members, &num_members);
784 if (!NT_STATUS_IS_OK(status)) {
785 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
786 __func__, nt_errstr(status)));
790 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
791 __func__, (int)num_members));
793 /* Now that we have a list of sids, we need to get the
794 * lists of names and name_types belonging to these sids.
795 * even though conceptually not quite clean, we use the
796 * RPC call lsa_lookup_sids for this since it can handle a
797 * list of sids. ldap calls can just resolve one sid at a time.
799 * At this stage, the sids are still hidden in the exetended dn
800 * member output format. We actually do a little better than
801 * stated above: In extracting the sids from the member strings,
802 * we try to resolve as many sids as possible from the
803 * cache. Only the rest is passed to the lsa_lookup_sids call. */
806 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
807 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
808 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
809 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
811 if ((members == NULL) || (*sid_mem == NULL) ||
812 (*names == NULL) || (*name_types == NULL) ||
813 (sid_mem_nocache == NULL))
815 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
816 status = NT_STATUS_NO_MEMORY;
823 (*name_types) = NULL;
826 for (i=0; i<num_members; i++) {
827 enum lsa_SidType name_type;
828 char *name, *domain_name;
831 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
833 if (!ADS_ERR_OK(rc)) {
834 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
835 NT_STATUS_NOT_FOUND)) {
836 /* Group members can be objects, like Exchange
837 * Public Folders, that don't have a SID. Skip
842 status = ads_ntstatus(rc);
846 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
848 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
849 "cache\n", sid_string_dbg(&sid)));
850 sid_copy(&(*sid_mem)[*num_names], &sid);
851 (*names)[*num_names] = fill_domain_username_talloc(
857 (*name_types)[*num_names] = name_type;
861 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
862 "cache\n", sid_string_dbg(&sid)));
863 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
868 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
869 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
871 /* handle sids not resolved from cache by lsa_lookup_sids */
872 if (num_nocache > 0) {
874 status = winbindd_lookup_sids(tmp_ctx,
880 &name_types_nocache);
882 if (!(NT_STATUS_IS_OK(status) ||
883 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
884 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
886 DEBUG(1, ("lsa_lookupsids call failed with %s "
887 "- retrying...\n", nt_errstr(status)));
889 status = winbindd_lookup_sids(tmp_ctx,
895 &name_types_nocache);
898 if (NT_STATUS_IS_OK(status) ||
899 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
901 /* Copy the entries over from the "_nocache" arrays
902 * to the result arrays, skipping the gaps the
903 * lookup_sids call left. */
904 for (i=0; i < num_nocache; i++) {
905 if (((names_nocache)[i] != NULL) &&
906 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
908 sid_copy(&(*sid_mem)[*num_names],
909 &sid_mem_nocache[i]);
910 (*names)[*num_names] =
911 fill_domain_username_talloc(
916 (*name_types)[*num_names] = name_types_nocache[i];
921 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
922 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
923 "not map any SIDs at all.\n"));
924 /* Don't handle this as an error here.
925 * There is nothing left to do with respect to the
926 * overall result... */
928 else if (!NT_STATUS_IS_OK(status)) {
929 DEBUG(10, ("lookup_groupmem: Error looking up %d "
930 "sids via rpc_lsa_lookup_sids: %s\n",
931 (int)num_members, nt_errstr(status)));
936 status = NT_STATUS_OK;
937 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
938 sid_string_dbg(group_sid)));
942 TALLOC_FREE(tmp_ctx);
947 /* find the sequence number for a domain */
948 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
950 ADS_STRUCT *ads = NULL;
953 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
955 if ( !winbindd_can_contact_domain( domain ) ) {
956 DEBUG(10,("sequence: No incoming trust for domain %s\n",
962 *seq = DOM_SEQUENCE_NONE;
964 ads = ads_cached_connection(domain);
967 domain->last_status = NT_STATUS_SERVER_DISABLED;
968 return NT_STATUS_UNSUCCESSFUL;
971 rc = ads_USN(ads, seq);
973 if (!ADS_ERR_OK(rc)) {
975 /* its a dead connection, destroy it */
977 if (domain->private_data) {
978 ads = (ADS_STRUCT *)domain->private_data;
981 ads_kdestroy(WINBIND_CCACHE_NAME);
982 domain->private_data = NULL;
985 return ads_ntstatus(rc);
988 /* find the lockout policy of a domain - use rpc methods */
989 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
991 struct samr_DomInfo12 *policy)
993 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
996 /* find the password policy of a domain - use rpc methods */
997 static NTSTATUS password_policy(struct winbindd_domain *domain,
999 struct samr_DomInfo1 *policy)
1001 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1004 /* get a list of trusted domains */
1005 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1006 TALLOC_CTX *mem_ctx,
1007 struct netr_DomainTrustList *trusts)
1009 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1013 struct rpc_pipe_client *cli;
1015 struct dcerpc_binding_handle *b;
1017 DEBUG(3,("ads: trusted_domains\n"));
1019 ZERO_STRUCTP(trusts);
1021 /* If this is our primary domain or a root in our forest,
1022 query for all trusts. If not, then just look for domain
1023 trusts in the target forest */
1025 if (domain->primary || domain_is_forest_root(domain)) {
1026 flags = NETR_TRUST_FLAG_OUTBOUND |
1027 NETR_TRUST_FLAG_INBOUND |
1028 NETR_TRUST_FLAG_IN_FOREST;
1030 flags = NETR_TRUST_FLAG_IN_FOREST;
1033 result = cm_connect_netlogon(domain, &cli);
1035 if (!NT_STATUS_IS_OK(result)) {
1036 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1037 "for PIPE_NETLOGON (%s)\n",
1038 domain->name, nt_errstr(result)));
1039 return NT_STATUS_UNSUCCESSFUL;
1042 b = cli->binding_handle;
1044 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1049 if (!NT_STATUS_IS_OK(result)) {
1053 if (!W_ERROR_IS_OK(werr)) {
1054 return werror_to_ntstatus(werr);
1056 if (trusts->count == 0) {
1057 return NT_STATUS_OK;
1060 /* Copy across names and sids */
1063 for (i = 0; i < trusts->count; i++) {
1064 struct netr_DomainTrust *trust = &trusts->array[i];
1065 struct winbindd_domain d;
1070 * drop external trusts if this is not our primary
1071 * domain. This means that the returned number of
1072 * domains may be less that the ones actually trusted
1076 if ((trust->trust_attributes
1077 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1080 DEBUG(10,("trusted_domains: Skipping external trusted "
1081 "domain %s because it is outside of our "
1083 trust->netbios_name));
1087 /* add to the trusted domain cache */
1089 d.name = discard_const_p(char, trust->netbios_name);
1090 d.alt_name = discard_const_p(char, trust->dns_name);
1093 sid_copy(&d.sid, trust->sid);
1095 sid_copy(&d.sid, &global_sid_NULL);
1098 if ( domain->primary ) {
1099 DEBUG(10,("trusted_domains(ads): Searching "
1100 "trusted domain list of %s and storing "
1101 "trust flags for domain %s\n",
1102 domain->name, d.alt_name));
1104 d.domain_flags = trust->trust_flags;
1105 d.domain_type = trust->trust_type;
1106 d.domain_trust_attribs = trust->trust_attributes;
1108 wcache_tdc_add_domain( &d );
1110 } else if (domain_is_forest_root(domain)) {
1111 /* Check if we already have this record. If
1112 * we are following our forest root that is not
1113 * our primary domain, we want to keep trust
1114 * flags from the perspective of our primary
1115 * domain not our forest root. */
1116 struct winbindd_tdc_domain *exist = NULL;
1118 exist = wcache_tdc_fetch_domain(
1119 talloc_tos(), trust->netbios_name);
1121 DEBUG(10,("trusted_domains(ads): Searching "
1122 "trusted domain list of %s and "
1123 "storing trust flags for domain "
1124 "%s\n", domain->name, d.alt_name));
1125 d.domain_flags = trust->trust_flags;
1126 d.domain_type = trust->trust_type;
1127 d.domain_trust_attribs =
1128 trust->trust_attributes;
1130 wcache_tdc_add_domain( &d );
1135 /* This gets a little tricky. If we are
1136 following a transitive forest trust, then
1137 innerit the flags, type, and attribs from
1138 the domain we queried to make sure we don't
1139 record the view of the trust from the wrong
1140 side. Always view it from the side of our
1141 primary domain. --jerry */
1142 struct winbindd_tdc_domain *parent = NULL;
1144 DEBUG(10,("trusted_domains(ads): Searching "
1145 "trusted domain list of %s and inheriting "
1146 "trust flags for domain %s\n",
1147 domain->name, d.alt_name));
1149 parent = wcache_tdc_fetch_domain(talloc_tos(),
1152 d.domain_flags = parent->trust_flags;
1153 d.domain_type = parent->trust_type;
1154 d.domain_trust_attribs = parent->trust_attribs;
1156 d.domain_flags = domain->domain_flags;
1157 d.domain_type = domain->domain_type;
1158 d.domain_trust_attribs =
1159 domain->domain_trust_attribs;
1161 TALLOC_FREE(parent);
1163 wcache_tdc_add_domain( &d );
1170 /* the ADS backend methods are exposed via this structure */
1171 struct winbindd_methods ads_methods = {