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,
293 ADS_STRUCT *ads = NULL;
294 const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
296 uint32_t *rids = NULL;
298 LDAPMessage *res = NULL;
299 LDAPMessage *msg = NULL;
300 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
302 DEBUG(3,("ads: query_user_list\n"));
304 if ( !winbindd_can_contact_domain( domain ) ) {
305 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
310 ads = ads_cached_connection(domain);
313 domain->last_status = NT_STATUS_SERVER_DISABLED;
317 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
318 if (!ADS_ERR_OK(rc)) {
319 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
320 status = ads_ntstatus(rc);
323 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
327 count = ads_count_replies(ads, res);
329 DEBUG(1,("query_user_list: No users found\n"));
333 rids = talloc_zero_array(mem_ctx, uint32_t, count);
335 status = NT_STATUS_NO_MEMORY;
341 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
342 struct dom_sid user_sid;
346 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
348 DBG_INFO("Object lacks sAMAccountType attribute\n");
351 if (ds_atype_map(atype) != SID_NAME_USER) {
352 DBG_INFO("Not a user account? atype=0x%x\n", atype);
356 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
357 char *dn = ads_get_dn(ads, talloc_tos(), msg);
358 DBG_INFO("No sid for %s !?\n", dn);
363 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
364 fstring sidstr, domstr;
365 DBG_WARNING("Got sid %s in domain %s\n",
366 sid_to_fstring(sidstr, &user_sid),
367 sid_to_fstring(domstr, &domain->sid));
371 sid_split_rid(&user_sid, &rids[count]);
375 rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
380 status = NT_STATUS_OK;
382 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
388 /* list all domain groups */
389 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
391 uint32_t *num_entries,
392 struct wb_acct_info **info)
394 ADS_STRUCT *ads = NULL;
395 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
396 "name", "objectSid", NULL};
399 LDAPMessage *res = NULL;
400 LDAPMessage *msg = NULL;
401 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
403 bool enum_dom_local_groups = False;
407 DEBUG(3,("ads: enum_dom_groups\n"));
409 if ( !winbindd_can_contact_domain( domain ) ) {
410 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
415 /* only grab domain local groups for our domain */
416 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
417 enum_dom_local_groups = True;
420 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
423 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
424 * default value, it MUST be absent. In case of extensible matching the
425 * "dnattr" boolean defaults to FALSE and so it must be only be present
428 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
429 * filter using bitwise matching rule then the buggy AD fails to decode
430 * the extensible match. As a workaround set it to TRUE and thereby add
431 * the dnAttributes "dn" field to cope with those older AD versions.
432 * It should not harm and won't put any additional load on the AD since
433 * none of the dn components have a bitmask-attribute.
435 * Thanks to Ralf Haferkamp for input and testing - Guenther */
437 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
438 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
439 ADS_LDAP_MATCHING_RULE_BIT_AND,
440 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
442 if (filter == NULL) {
443 status = NT_STATUS_NO_MEMORY;
447 ads = ads_cached_connection(domain);
450 domain->last_status = NT_STATUS_SERVER_DISABLED;
454 rc = ads_search_retry(ads, &res, filter, attrs);
455 if (!ADS_ERR_OK(rc)) {
456 status = ads_ntstatus(rc);
457 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
460 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
464 count = ads_count_replies(ads, res);
466 DEBUG(1,("enum_dom_groups: No groups found\n"));
470 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
472 status = NT_STATUS_NO_MEMORY;
478 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
483 name = ads_pull_username(ads, mem_ctx, msg);
484 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
485 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
486 DEBUG(1,("No sid for %s !?\n", name));
490 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
491 DEBUG(1,("No rid for %s !?\n", name));
495 fstrcpy((*info)[i].acct_name, name);
496 fstrcpy((*info)[i].acct_desc, gecos);
497 (*info)[i].rid = rid;
503 status = NT_STATUS_OK;
505 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
509 ads_msgfree(ads, res);
514 /* list all domain local groups */
515 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
517 uint32_t *num_entries,
518 struct wb_acct_info **info)
521 * This is a stub function only as we returned the domain
522 * local groups in enum_dom_groups() if the domain->native field
523 * was true. This is a simple performance optimization when
526 * if we ever need to enumerate domain local groups separately,
527 * then this optimization in enum_dom_groups() will need
535 /* convert a single name to a sid in a domain - use rpc methods */
536 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
538 const char *domain_name,
542 enum lsa_SidType *type)
544 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
548 /* convert a domain SID to a user or group name - use rpc methods */
549 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
551 const struct dom_sid *sid,
554 enum lsa_SidType *type)
556 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
557 domain_name, name, type);
560 /* convert a list of rids to names - use rpc methods */
561 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
563 const struct dom_sid *sid,
568 enum lsa_SidType **types)
570 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
572 domain_name, names, types);
575 /* Lookup aliases a user is member of - use rpc methods */
576 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
578 uint32_t num_sids, const struct dom_sid *sids,
579 uint32_t *num_aliases, uint32_t **alias_rids)
581 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
582 num_aliases, alias_rids);
585 static NTSTATUS add_primary_group_members(
586 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
587 char ***all_members, size_t *num_all_members)
590 NTSTATUS status = NT_STATUS_NO_MEMORY;
592 const char *attrs[] = { "dn", NULL };
593 LDAPMessage *res = NULL;
599 filter = talloc_asprintf(
600 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
602 if (filter == NULL) {
606 args.control = ADS_EXTENDED_DN_OID;
607 args.val = ADS_EXTENDED_DN_HEX_STRING;
608 args.critical = True;
610 rc = ads_do_search_all_args(ads, ads->config.bind_path,
611 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
614 if (!ADS_ERR_OK(rc)) {
615 status = ads_ntstatus(rc);
616 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
620 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
624 num_members = ads_count_replies(ads, res);
626 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
627 (uintmax_t)num_members));
629 if (num_members == 0) {
630 status = NT_STATUS_OK;
634 members = talloc_realloc(mem_ctx, *all_members, char *,
635 *num_all_members + num_members);
636 if (members == NULL) {
637 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
640 *all_members = members;
642 for (msg = ads_first_entry(ads, res); msg != NULL;
643 msg = ads_next_entry(ads, msg)) {
646 dn = ads_get_dn(ads, members, msg);
648 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
652 members[*num_all_members] = dn;
653 *num_all_members += 1;
656 status = NT_STATUS_OK;
659 ads_msgfree(ads, res);
666 find the members of a group, given a group rid and domain
668 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
670 const struct dom_sid *group_sid,
671 enum lsa_SidType type,
673 struct dom_sid **sid_mem, char ***names,
674 uint32_t **name_types)
677 ADS_STRUCT *ads = NULL;
679 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
681 char **members = NULL;
683 size_t num_members = 0;
685 struct dom_sid *sid_mem_nocache = NULL;
686 char **names_nocache = NULL;
687 enum lsa_SidType *name_types_nocache = NULL;
688 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
689 uint32_t num_nocache = 0;
690 TALLOC_CTX *tmp_ctx = NULL;
693 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
694 sid_string_dbg(group_sid)));
698 tmp_ctx = talloc_new(mem_ctx);
700 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
701 status = NT_STATUS_NO_MEMORY;
705 if (!sid_peek_rid(group_sid, &rid)) {
706 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
707 status = NT_STATUS_INVALID_PARAMETER;
711 if ( !winbindd_can_contact_domain( domain ) ) {
712 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
717 ads = ads_cached_connection(domain);
720 domain->last_status = NT_STATUS_SERVER_DISABLED;
724 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
725 status = NT_STATUS_NO_MEMORY;
729 /* search for all members of the group */
730 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
731 TALLOC_FREE(sidbinstr);
732 if (ldap_exp == NULL) {
733 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
734 status = NT_STATUS_NO_MEMORY;
738 args.control = ADS_EXTENDED_DN_OID;
739 args.val = ADS_EXTENDED_DN_HEX_STRING;
740 args.critical = True;
742 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
743 ldap_exp, &args, "member", &members, &num_members);
745 if (!ADS_ERR_OK(rc)) {
746 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
747 status = NT_STATUS_UNSUCCESSFUL;
751 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
753 status = add_primary_group_members(ads, mem_ctx, rid,
754 &members, &num_members);
755 if (!NT_STATUS_IS_OK(status)) {
756 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
757 __func__, nt_errstr(status)));
761 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
762 __func__, (int)num_members));
764 /* Now that we have a list of sids, we need to get the
765 * lists of names and name_types belonging to these sids.
766 * even though conceptually not quite clean, we use the
767 * RPC call lsa_lookup_sids for this since it can handle a
768 * list of sids. ldap calls can just resolve one sid at a time.
770 * At this stage, the sids are still hidden in the exetended dn
771 * member output format. We actually do a little better than
772 * stated above: In extracting the sids from the member strings,
773 * we try to resolve as many sids as possible from the
774 * cache. Only the rest is passed to the lsa_lookup_sids call. */
777 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
778 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
779 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
780 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
782 if ((members == NULL) || (*sid_mem == NULL) ||
783 (*names == NULL) || (*name_types == NULL) ||
784 (sid_mem_nocache == NULL))
786 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
787 status = NT_STATUS_NO_MEMORY;
794 (*name_types) = NULL;
797 for (i=0; i<num_members; i++) {
798 enum lsa_SidType name_type;
799 char *name, *domain_name;
802 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
804 if (!ADS_ERR_OK(rc)) {
805 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
806 NT_STATUS_NOT_FOUND)) {
807 /* Group members can be objects, like Exchange
808 * Public Folders, that don't have a SID. Skip
813 status = ads_ntstatus(rc);
817 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
819 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
820 "cache\n", sid_string_dbg(&sid)));
821 sid_copy(&(*sid_mem)[*num_names], &sid);
822 (*names)[*num_names] = fill_domain_username_talloc(
828 (*name_types)[*num_names] = name_type;
832 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
833 "cache\n", sid_string_dbg(&sid)));
834 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
839 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
840 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
842 /* handle sids not resolved from cache by lsa_lookup_sids */
843 if (num_nocache > 0) {
845 status = winbindd_lookup_sids(tmp_ctx,
851 &name_types_nocache);
853 if (!(NT_STATUS_IS_OK(status) ||
854 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
855 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
857 DEBUG(1, ("lsa_lookupsids call failed with %s "
858 "- retrying...\n", nt_errstr(status)));
860 status = winbindd_lookup_sids(tmp_ctx,
866 &name_types_nocache);
869 if (NT_STATUS_IS_OK(status) ||
870 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
872 /* Copy the entries over from the "_nocache" arrays
873 * to the result arrays, skipping the gaps the
874 * lookup_sids call left. */
875 for (i=0; i < num_nocache; i++) {
876 if (((names_nocache)[i] != NULL) &&
877 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
879 sid_copy(&(*sid_mem)[*num_names],
880 &sid_mem_nocache[i]);
881 (*names)[*num_names] =
882 fill_domain_username_talloc(
887 (*name_types)[*num_names] = name_types_nocache[i];
892 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
893 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
894 "not map any SIDs at all.\n"));
895 /* Don't handle this as an error here.
896 * There is nothing left to do with respect to the
897 * overall result... */
899 else if (!NT_STATUS_IS_OK(status)) {
900 DEBUG(10, ("lookup_groupmem: Error looking up %d "
901 "sids via rpc_lsa_lookup_sids: %s\n",
902 (int)num_members, nt_errstr(status)));
907 status = NT_STATUS_OK;
908 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
909 sid_string_dbg(group_sid)));
913 TALLOC_FREE(tmp_ctx);
918 /* find the sequence number for a domain */
919 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
921 ADS_STRUCT *ads = NULL;
924 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
926 if ( !winbindd_can_contact_domain( domain ) ) {
927 DEBUG(10,("sequence: No incoming trust for domain %s\n",
933 *seq = DOM_SEQUENCE_NONE;
935 ads = ads_cached_connection(domain);
938 domain->last_status = NT_STATUS_SERVER_DISABLED;
939 return NT_STATUS_UNSUCCESSFUL;
942 rc = ads_USN(ads, seq);
944 if (!ADS_ERR_OK(rc)) {
946 /* its a dead connection, destroy it */
948 if (domain->private_data) {
949 ads = (ADS_STRUCT *)domain->private_data;
952 ads_kdestroy(WINBIND_CCACHE_NAME);
953 domain->private_data = NULL;
956 return ads_ntstatus(rc);
959 /* find the lockout policy of a domain - use rpc methods */
960 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
962 struct samr_DomInfo12 *policy)
964 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
967 /* find the password policy of a domain - use rpc methods */
968 static NTSTATUS password_policy(struct winbindd_domain *domain,
970 struct samr_DomInfo1 *policy)
972 return msrpc_methods.password_policy(domain, mem_ctx, policy);
975 /* get a list of trusted domains */
976 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
978 struct netr_DomainTrustList *trusts)
980 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
984 struct rpc_pipe_client *cli;
986 struct dcerpc_binding_handle *b;
988 DEBUG(3,("ads: trusted_domains\n"));
990 ZERO_STRUCTP(trusts);
992 /* If this is our primary domain or a root in our forest,
993 query for all trusts. If not, then just look for domain
994 trusts in the target forest */
996 if (domain->primary || domain_is_forest_root(domain)) {
997 flags = NETR_TRUST_FLAG_OUTBOUND |
998 NETR_TRUST_FLAG_INBOUND |
999 NETR_TRUST_FLAG_IN_FOREST;
1001 flags = NETR_TRUST_FLAG_IN_FOREST;
1004 result = cm_connect_netlogon(domain, &cli);
1006 if (!NT_STATUS_IS_OK(result)) {
1007 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1008 "for PIPE_NETLOGON (%s)\n",
1009 domain->name, nt_errstr(result)));
1010 return NT_STATUS_UNSUCCESSFUL;
1013 b = cli->binding_handle;
1015 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1020 if (!NT_STATUS_IS_OK(result)) {
1024 if (!W_ERROR_IS_OK(werr)) {
1025 return werror_to_ntstatus(werr);
1027 if (trusts->count == 0) {
1028 return NT_STATUS_OK;
1031 /* Copy across names and sids */
1034 for (i = 0; i < trusts->count; i++) {
1035 struct netr_DomainTrust *trust = &trusts->array[i];
1036 struct winbindd_domain d;
1041 * drop external trusts if this is not our primary
1042 * domain. This means that the returned number of
1043 * domains may be less that the ones actually trusted
1047 if ((trust->trust_attributes
1048 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1051 DEBUG(10,("trusted_domains: Skipping external trusted "
1052 "domain %s because it is outside of our "
1054 trust->netbios_name));
1058 /* add to the trusted domain cache */
1060 d.name = discard_const_p(char, trust->netbios_name);
1061 d.alt_name = discard_const_p(char, trust->dns_name);
1064 sid_copy(&d.sid, trust->sid);
1066 sid_copy(&d.sid, &global_sid_NULL);
1069 if ( domain->primary ) {
1070 DEBUG(10,("trusted_domains(ads): Searching "
1071 "trusted domain list of %s and storing "
1072 "trust flags for domain %s\n",
1073 domain->name, d.alt_name));
1075 d.domain_flags = trust->trust_flags;
1076 d.domain_type = trust->trust_type;
1077 d.domain_trust_attribs = trust->trust_attributes;
1079 wcache_tdc_add_domain( &d );
1081 } else if (domain_is_forest_root(domain)) {
1082 /* Check if we already have this record. If
1083 * we are following our forest root that is not
1084 * our primary domain, we want to keep trust
1085 * flags from the perspective of our primary
1086 * domain not our forest root. */
1087 struct winbindd_tdc_domain *exist = NULL;
1089 exist = wcache_tdc_fetch_domain(
1090 talloc_tos(), trust->netbios_name);
1092 DEBUG(10,("trusted_domains(ads): Searching "
1093 "trusted domain list of %s and "
1094 "storing trust flags for domain "
1095 "%s\n", domain->name, d.alt_name));
1096 d.domain_flags = trust->trust_flags;
1097 d.domain_type = trust->trust_type;
1098 d.domain_trust_attribs =
1099 trust->trust_attributes;
1101 wcache_tdc_add_domain( &d );
1106 /* This gets a little tricky. If we are
1107 following a transitive forest trust, then
1108 innerit the flags, type, and attribs from
1109 the domain we queried to make sure we don't
1110 record the view of the trust from the wrong
1111 side. Always view it from the side of our
1112 primary domain. --jerry */
1113 struct winbindd_tdc_domain *parent = NULL;
1115 DEBUG(10,("trusted_domains(ads): Searching "
1116 "trusted domain list of %s and inheriting "
1117 "trust flags for domain %s\n",
1118 domain->name, d.alt_name));
1120 parent = wcache_tdc_fetch_domain(talloc_tos(),
1123 d.domain_flags = parent->trust_flags;
1124 d.domain_type = parent->trust_type;
1125 d.domain_trust_attribs = parent->trust_attribs;
1127 d.domain_flags = domain->domain_flags;
1128 d.domain_type = domain->domain_type;
1129 d.domain_trust_attribs =
1130 domain->domain_trust_attribs;
1132 TALLOC_FREE(parent);
1134 wcache_tdc_add_domain( &d );
1141 /* the ADS backend methods are exposed via this structure */
1142 struct winbindd_methods ads_methods = {