lib:torture: add torture_assert_u32_[not_]equal[_goto] macros
[Samba.git] / source3 / winbindd / winbindd_ads.c
blob20f47eb5954f67d569aaa250d75ac0524c50fc36
1 /*
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/>.
24 #include "includes.h"
25 #include "winbindd.h"
26 #include "winbindd_ads.h"
27 #include "libsmb/namequery.h"
28 #include "rpc_client/rpc_client.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../libds/common/flags.h"
31 #include "ads.h"
32 #include "../libcli/ldap/ldap_ndr.h"
33 #include "../libcli/security/security.h"
34 #include "../libds/common/flag_mapping.h"
35 #include "libsmb/samlogon_cache.h"
36 #include "passdb.h"
38 #ifdef HAVE_ADS
40 #undef DBGC_CLASS
41 #define DBGC_CLASS DBGC_WINBIND
43 extern struct winbindd_methods reconnect_methods;
44 extern struct winbindd_methods msrpc_methods;
46 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
48 /**
49 * Check if cached connection can be reused. If the connection cannot
50 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
52 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
55 ADS_STRUCT *ads = *adsp;
57 if (ads != NULL) {
58 time_t expire;
59 time_t now = time(NULL);
61 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
63 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
64 "is now %d)\n", (uint32_t)expire - (uint32_t)now,
65 (uint32_t) expire, (uint32_t) now));
67 if ( ads->config.realm && (expire > now)) {
68 return;
69 } else {
70 /* we own this ADS_STRUCT so make sure it goes away */
71 DEBUG(7,("Deleting expired krb5 credential cache\n"));
72 ads->is_mine = True;
73 ads_destroy( &ads );
74 ads_kdestroy(WINBIND_CCACHE_NAME);
75 *adsp = NULL;
80 /**
81 * @brief Establish a connection to a DC
83 * @param[out] adsp ADS_STRUCT that will be created
84 * @param[in] target_realm Realm of domain to connect to
85 * @param[in] target_dom_name 'workgroup' name of domain to connect to
86 * @param[in] ldap_server DNS name of server to connect to
87 * @param[in] password Our machine acount secret
88 * @param[in] auth_realm Realm of local domain for creating krb token
89 * @param[in] renewable Renewable ticket time
91 * @return ADS_STATUS
93 static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
94 const char *target_realm,
95 const char *target_dom_name,
96 const char *ldap_server,
97 char *password,
98 char *auth_realm,
99 time_t renewable)
101 ADS_STRUCT *ads;
102 ADS_STATUS status;
103 struct sockaddr_storage dc_ss;
104 fstring dc_name;
106 if (auth_realm == NULL) {
107 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
110 /* we don't want this to affect the users ccache */
111 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
113 ads = ads_init(target_realm,
114 target_dom_name,
115 ldap_server,
116 ADS_SASL_SEAL);
117 if (!ads) {
118 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
119 return ADS_ERROR(LDAP_NO_MEMORY);
122 SAFE_FREE(ads->auth.password);
123 SAFE_FREE(ads->auth.realm);
125 ads->auth.renewable = renewable;
126 ads->auth.password = password;
128 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
130 ads->auth.realm = SMB_STRDUP(auth_realm);
131 if (!strupper_m(ads->auth.realm)) {
132 ads_destroy(&ads);
133 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
136 /* Setup the server affinity cache. We don't reaally care
137 about the name. Just setup affinity and the KRB5_CONFIG
138 file. */
139 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
141 status = ads_connect(ads);
142 if (!ADS_ERR_OK(status)) {
143 DEBUG(1,("ads_connect for domain %s failed: %s\n",
144 target_dom_name, ads_errstr(status)));
145 ads_destroy(&ads);
146 return status;
149 /* set the flag that says we don't own the memory even
150 though we do so that ads_destroy() won't destroy the
151 structure we pass back by reference */
153 ads->is_mine = False;
155 *adsp = ads;
157 return status;
160 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
162 char *ldap_server, *realm, *password;
163 struct winbindd_domain *wb_dom;
164 ADS_STATUS status;
166 if (IS_AD_DC) {
168 * Make sure we never try to use LDAP against
169 * a trusted domain as AD DC.
171 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
174 ads_cached_connection_reuse(adsp);
175 if (*adsp != NULL) {
176 return ADS_SUCCESS;
180 * At this point we only have the NetBIOS domain name.
181 * Check if we can get server nam and realm from SAF cache
182 * and the domain list.
184 ldap_server = saf_fetch(talloc_tos(), dom_name);
185 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
186 ldap_server ? ldap_server : ""));
188 wb_dom = find_domain_from_name(dom_name);
189 if (wb_dom == NULL) {
190 DEBUG(10, ("could not find domain '%s'\n", dom_name));
191 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
194 DEBUG(10, ("find_domain_from_name found realm '%s' for "
195 " domain '%s'\n", wb_dom->alt_name, dom_name));
197 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
198 TALLOC_FREE(ldap_server);
199 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
202 if (IS_DC) {
203 SMB_ASSERT(wb_dom->alt_name != NULL);
204 realm = SMB_STRDUP(wb_dom->alt_name);
205 } else {
206 struct winbindd_domain *our_domain = wb_dom;
208 /* always give preference to the alt_name in our
209 primary domain if possible */
211 if (!wb_dom->primary) {
212 our_domain = find_our_domain();
215 if (our_domain->alt_name != NULL) {
216 realm = SMB_STRDUP(our_domain->alt_name);
217 } else {
218 realm = SMB_STRDUP(lp_realm());
222 status = ads_cached_connection_connect(
223 adsp, /* Returns ads struct. */
224 wb_dom->alt_name, /* realm to connect to. */
225 dom_name, /* 'workgroup' name for ads_init */
226 ldap_server, /* DNS name to connect to. */
227 password, /* password for auth realm. */
228 realm, /* realm used for krb5 ticket. */
229 0); /* renewable ticket time. */
231 SAFE_FREE(realm);
232 TALLOC_FREE(ldap_server);
234 return status;
238 return our ads connections structure for a domain. We keep the connection
239 open to make things faster
241 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
243 ADS_STATUS status;
244 char *password, *realm;
246 if (IS_AD_DC) {
248 * Make sure we never try to use LDAP against
249 * a trusted domain as AD DC.
251 return NULL;
254 DEBUG(10,("ads_cached_connection\n"));
255 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
257 if (domain->private_data) {
258 return (ADS_STRUCT *)domain->private_data;
261 /* the machine acct password might have change - fetch it every time */
263 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
264 return NULL;
267 if ( IS_DC ) {
268 SMB_ASSERT(domain->alt_name != NULL);
269 realm = SMB_STRDUP(domain->alt_name);
271 else {
272 struct winbindd_domain *our_domain = domain;
275 /* always give preference to the alt_name in our
276 primary domain if possible */
278 if ( !domain->primary )
279 our_domain = find_our_domain();
281 if (our_domain->alt_name != NULL) {
282 realm = SMB_STRDUP( our_domain->alt_name );
284 else
285 realm = SMB_STRDUP( lp_realm() );
288 status = ads_cached_connection_connect(
289 (ADS_STRUCT **)&domain->private_data,
290 domain->alt_name,
291 domain->name, NULL,
292 password, realm,
293 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
294 SAFE_FREE(realm);
296 if (!ADS_ERR_OK(status)) {
297 /* if we get ECONNREFUSED then it might be a NT4
298 server, fall back to MSRPC */
299 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
300 status.err.rc == ECONNREFUSED) {
301 /* 'reconnect_methods' is the MS-RPC backend. */
302 DEBUG(1,("Trying MSRPC methods\n"));
303 domain->backend = &reconnect_methods;
305 return NULL;
308 return (ADS_STRUCT *)domain->private_data;
311 /* Query display info for a realm. This is the basic user list fn */
312 static NTSTATUS query_user_list(struct winbindd_domain *domain,
313 TALLOC_CTX *mem_ctx,
314 uint32_t **prids)
316 ADS_STRUCT *ads = NULL;
317 const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
318 int count;
319 uint32_t *rids = NULL;
320 ADS_STATUS rc;
321 LDAPMessage *res = NULL;
322 LDAPMessage *msg = NULL;
323 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
325 DEBUG(3,("ads: query_user_list\n"));
327 if ( !winbindd_can_contact_domain( domain ) ) {
328 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
329 domain->name));
330 return NT_STATUS_OK;
333 ads = ads_cached_connection(domain);
335 if (!ads) {
336 domain->last_status = NT_STATUS_SERVER_DISABLED;
337 goto done;
340 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
341 if (!ADS_ERR_OK(rc)) {
342 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
343 status = ads_ntstatus(rc);
344 goto done;
345 } else if (!res) {
346 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
347 goto done;
350 count = ads_count_replies(ads, res);
351 if (count == 0) {
352 DEBUG(1,("query_user_list: No users found\n"));
353 goto done;
356 rids = talloc_zero_array(mem_ctx, uint32_t, count);
357 if (rids == NULL) {
358 status = NT_STATUS_NO_MEMORY;
359 goto done;
362 count = 0;
364 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
365 struct dom_sid user_sid;
366 uint32_t atype;
367 bool ok;
369 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
370 if (!ok) {
371 DBG_INFO("Object lacks sAMAccountType attribute\n");
372 continue;
374 if (ds_atype_map(atype) != SID_NAME_USER) {
375 DBG_INFO("Not a user account? atype=0x%x\n", atype);
376 continue;
379 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
380 char *dn = ads_get_dn(ads, talloc_tos(), msg);
381 DBG_INFO("No sid for %s !?\n", dn);
382 TALLOC_FREE(dn);
383 continue;
386 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
387 struct dom_sid_buf sidstr, domstr;
388 DBG_WARNING("Got sid %s in domain %s\n",
389 dom_sid_str_buf(&user_sid, &sidstr),
390 dom_sid_str_buf(&domain->sid, &domstr));
391 continue;
394 sid_split_rid(&user_sid, &rids[count]);
395 count += 1;
398 rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
399 if (prids != NULL) {
400 *prids = rids;
403 status = NT_STATUS_OK;
405 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
407 done:
408 return status;
411 /* list all domain groups */
412 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
413 TALLOC_CTX *mem_ctx,
414 uint32_t *num_entries,
415 struct wb_acct_info **info)
417 ADS_STRUCT *ads = NULL;
418 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
419 "name", "objectSid", NULL};
420 int i, count;
421 ADS_STATUS rc;
422 LDAPMessage *res = NULL;
423 LDAPMessage *msg = NULL;
424 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
425 const char *filter;
426 bool enum_dom_local_groups = False;
428 *num_entries = 0;
430 DEBUG(3,("ads: enum_dom_groups\n"));
432 if ( !winbindd_can_contact_domain( domain ) ) {
433 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
434 domain->name));
435 return NT_STATUS_OK;
438 /* only grab domain local groups for our domain */
439 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
440 enum_dom_local_groups = True;
443 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
444 * rollup-fixes:
446 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
447 * default value, it MUST be absent. In case of extensible matching the
448 * "dnattr" boolean defaults to FALSE and so it must be only be present
449 * when set to TRUE.
451 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
452 * filter using bitwise matching rule then the buggy AD fails to decode
453 * the extensible match. As a workaround set it to TRUE and thereby add
454 * the dnAttributes "dn" field to cope with those older AD versions.
455 * It should not harm and won't put any additional load on the AD since
456 * none of the dn components have a bitmask-attribute.
458 * Thanks to Ralf Haferkamp for input and testing - Guenther */
460 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
461 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
462 ADS_LDAP_MATCHING_RULE_BIT_AND,
463 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
465 if (filter == NULL) {
466 status = NT_STATUS_NO_MEMORY;
467 goto done;
470 ads = ads_cached_connection(domain);
472 if (!ads) {
473 domain->last_status = NT_STATUS_SERVER_DISABLED;
474 goto done;
477 rc = ads_search_retry(ads, &res, filter, attrs);
478 if (!ADS_ERR_OK(rc)) {
479 status = ads_ntstatus(rc);
480 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
481 goto done;
482 } else if (!res) {
483 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
484 goto done;
487 count = ads_count_replies(ads, res);
488 if (count == 0) {
489 DEBUG(1,("enum_dom_groups: No groups found\n"));
490 goto done;
493 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
494 if (!*info) {
495 status = NT_STATUS_NO_MEMORY;
496 goto done;
499 i = 0;
501 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
502 char *name, *gecos;
503 struct dom_sid sid;
504 uint32_t rid;
506 name = ads_pull_username(ads, (*info), msg);
507 gecos = ads_pull_string(ads, (*info), msg, "name");
508 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
509 DEBUG(1,("No sid for %s !?\n", name));
510 continue;
513 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
514 DEBUG(1,("No rid for %s !?\n", name));
515 continue;
518 (*info)[i].acct_name = name;
519 (*info)[i].acct_desc = gecos;
520 (*info)[i].rid = rid;
521 i++;
524 (*num_entries) = i;
526 status = NT_STATUS_OK;
528 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
530 done:
531 if (res)
532 ads_msgfree(ads, res);
534 return status;
537 /* list all domain local groups */
538 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
539 TALLOC_CTX *mem_ctx,
540 uint32_t *num_entries,
541 struct wb_acct_info **info)
544 * This is a stub function only as we returned the domain
545 * local groups in enum_dom_groups() if the domain->native field
546 * was true. This is a simple performance optimization when
547 * using LDAP.
549 * if we ever need to enumerate domain local groups separately,
550 * then this optimization in enum_dom_groups() will need
551 * to be split out
553 *num_entries = 0;
555 return NT_STATUS_OK;
558 /* convert a single name to a sid in a domain - use rpc methods */
559 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
560 TALLOC_CTX *mem_ctx,
561 const char *domain_name,
562 const char *name,
563 uint32_t flags,
564 const char **pdom_name,
565 struct dom_sid *sid,
566 enum lsa_SidType *type)
568 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
569 flags, pdom_name, sid, type);
572 /* convert a domain SID to a user or group name - use rpc methods */
573 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
574 TALLOC_CTX *mem_ctx,
575 const struct dom_sid *sid,
576 char **domain_name,
577 char **name,
578 enum lsa_SidType *type)
580 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
581 domain_name, name, type);
584 /* convert a list of rids to names - use rpc methods */
585 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
586 TALLOC_CTX *mem_ctx,
587 const struct dom_sid *sid,
588 uint32_t *rids,
589 size_t num_rids,
590 char **domain_name,
591 char ***names,
592 enum lsa_SidType **types)
594 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
595 rids, num_rids,
596 domain_name, names, types);
599 /* Lookup groups a user is a member of - alternate method, for when
600 tokenGroups are not available. */
601 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
602 TALLOC_CTX *mem_ctx,
603 const char *user_dn,
604 struct dom_sid *primary_group,
605 uint32_t *p_num_groups, struct dom_sid **user_sids)
607 ADS_STATUS rc;
608 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
609 int count;
610 LDAPMessage *res = NULL;
611 LDAPMessage *msg = NULL;
612 char *ldap_exp;
613 ADS_STRUCT *ads;
614 const char *group_attrs[] = {"objectSid", NULL};
615 char *escaped_dn;
616 uint32_t num_groups = 0;
618 DEBUG(3,("ads: lookup_usergroups_member\n"));
620 if ( !winbindd_can_contact_domain( domain ) ) {
621 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
622 domain->name));
623 return NT_STATUS_OK;
626 ads = ads_cached_connection(domain);
628 if (!ads) {
629 domain->last_status = NT_STATUS_SERVER_DISABLED;
630 goto done;
633 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
634 status = NT_STATUS_NO_MEMORY;
635 goto done;
638 ldap_exp = talloc_asprintf(mem_ctx,
639 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
640 escaped_dn,
641 ADS_LDAP_MATCHING_RULE_BIT_AND,
642 GROUP_TYPE_SECURITY_ENABLED);
643 if (!ldap_exp) {
644 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
645 TALLOC_FREE(escaped_dn);
646 status = NT_STATUS_NO_MEMORY;
647 goto done;
650 TALLOC_FREE(escaped_dn);
652 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
654 if (!ADS_ERR_OK(rc)) {
655 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
656 return ads_ntstatus(rc);
657 } else if (!res) {
658 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
659 return NT_STATUS_INTERNAL_ERROR;
663 count = ads_count_replies(ads, res);
665 *user_sids = NULL;
666 num_groups = 0;
668 /* always add the primary group to the sid array */
669 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
670 &num_groups);
671 if (!NT_STATUS_IS_OK(status)) {
672 goto done;
675 if (count > 0) {
676 for (msg = ads_first_entry(ads, res); msg;
677 msg = ads_next_entry(ads, msg)) {
678 struct dom_sid group_sid;
680 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
681 DEBUG(1,("No sid for this group ?!?\n"));
682 continue;
685 /* ignore Builtin groups from ADS - Guenther */
686 if (sid_check_is_in_builtin(&group_sid)) {
687 continue;
690 status = add_sid_to_array(mem_ctx, &group_sid,
691 user_sids, &num_groups);
692 if (!NT_STATUS_IS_OK(status)) {
693 goto done;
699 *p_num_groups = num_groups;
700 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
702 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
703 done:
704 if (res)
705 ads_msgfree(ads, res);
707 return status;
710 /* Lookup groups a user is a member of - alternate method, for when
711 tokenGroups are not available. */
712 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
713 TALLOC_CTX *mem_ctx,
714 const char *user_dn,
715 struct dom_sid *primary_group,
716 uint32_t *p_num_groups,
717 struct dom_sid **user_sids)
719 ADS_STATUS rc;
720 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
721 ADS_STRUCT *ads;
722 const char *attrs[] = {"memberOf", NULL};
723 uint32_t num_groups = 0;
724 struct dom_sid *group_sids = NULL;
725 size_t i;
726 char **strings = NULL;
727 size_t num_strings = 0, num_sids = 0;
730 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
732 if ( !winbindd_can_contact_domain( domain ) ) {
733 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
734 "domain %s\n", domain->name));
735 return NT_STATUS_OK;
738 ads = ads_cached_connection(domain);
740 if (!ads) {
741 domain->last_status = NT_STATUS_SERVER_DISABLED;
742 return NT_STATUS_UNSUCCESSFUL;
745 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
746 ADS_EXTENDED_DN_HEX_STRING,
747 &strings, &num_strings);
749 if (!ADS_ERR_OK(rc)) {
750 DEBUG(1,("lookup_usergroups_memberof ads_search "
751 "member=%s: %s\n", user_dn, ads_errstr(rc)));
752 return ads_ntstatus(rc);
755 *user_sids = NULL;
756 num_groups = 0;
758 /* always add the primary group to the sid array */
759 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
760 &num_groups);
761 if (!NT_STATUS_IS_OK(status)) {
762 goto done;
765 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
766 if (!group_sids) {
767 status = NT_STATUS_NO_MEMORY;
768 goto done;
771 for (i=0; i<num_strings; i++) {
772 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
773 ADS_EXTENDED_DN_HEX_STRING,
774 &(group_sids)[i]);
775 if (!ADS_ERR_OK(rc)) {
776 /* ignore members without SIDs */
777 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
778 NT_STATUS_NOT_FOUND)) {
779 continue;
781 else {
782 status = ads_ntstatus(rc);
783 goto done;
786 num_sids++;
789 if (i == 0) {
790 DEBUG(1,("No memberOf for this user?!?\n"));
791 status = NT_STATUS_NO_MEMORY;
792 goto done;
795 for (i=0; i<num_sids; i++) {
797 /* ignore Builtin groups from ADS - Guenther */
798 if (sid_check_is_in_builtin(&group_sids[i])) {
799 continue;
802 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
803 &num_groups);
804 if (!NT_STATUS_IS_OK(status)) {
805 goto done;
810 *p_num_groups = num_groups;
811 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
813 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
814 user_dn));
816 done:
817 TALLOC_FREE(strings);
818 TALLOC_FREE(group_sids);
820 return status;
824 /* Lookup groups a user is a member of. */
825 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
826 TALLOC_CTX *mem_ctx,
827 const struct dom_sid *sid,
828 uint32_t *p_num_groups, struct dom_sid **user_sids)
830 ADS_STRUCT *ads = NULL;
831 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
832 ADS_STATUS rc;
833 int count;
834 LDAPMessage *msg = NULL;
835 char *user_dn = NULL;
836 struct dom_sid *sids;
837 int i;
838 struct dom_sid primary_group;
839 uint32_t primary_group_rid;
840 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
841 uint32_t num_groups = 0;
842 struct dom_sid_buf buf;
844 DEBUG(3,("ads: lookup_usergroups\n"));
845 *p_num_groups = 0;
847 status = lookup_usergroups_cached(mem_ctx, sid,
848 p_num_groups, user_sids);
849 if (NT_STATUS_IS_OK(status)) {
850 return NT_STATUS_OK;
853 if ( !winbindd_can_contact_domain( domain ) ) {
854 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
855 domain->name));
857 /* Tell the cache manager not to remember this one */
859 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
862 ads = ads_cached_connection(domain);
864 if (!ads) {
865 domain->last_status = NT_STATUS_SERVER_DISABLED;
866 status = NT_STATUS_SERVER_DISABLED;
867 goto done;
870 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
872 if (!ADS_ERR_OK(rc)) {
873 status = ads_ntstatus(rc);
874 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
875 "%s\n",
876 dom_sid_str_buf(sid, &buf),
877 ads_errstr(rc)));
878 goto done;
881 count = ads_count_replies(ads, msg);
882 if (count != 1) {
883 status = NT_STATUS_UNSUCCESSFUL;
884 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
885 "invalid number of results (count=%d)\n",
886 dom_sid_str_buf(sid, &buf),
887 count));
888 goto done;
891 if (!msg) {
892 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
893 dom_sid_str_buf(sid, &buf)));
894 status = NT_STATUS_UNSUCCESSFUL;
895 goto done;
898 user_dn = ads_get_dn(ads, mem_ctx, msg);
899 if (user_dn == NULL) {
900 status = NT_STATUS_NO_MEMORY;
901 goto done;
904 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
905 DEBUG(1,("%s: No primary group for sid=%s !?\n",
906 domain->name,
907 dom_sid_str_buf(sid, &buf)));
908 goto done;
911 sid_compose(&primary_group, &domain->sid, primary_group_rid);
913 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
915 /* there must always be at least one group in the token,
916 unless we are talking to a buggy Win2k server */
918 /* actually this only happens when the machine account has no read
919 * permissions on the tokenGroup attribute - gd */
921 if (count == 0) {
923 /* no tokenGroups */
925 /* lookup what groups this user is a member of by DN search on
926 * "memberOf" */
928 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
929 &primary_group,
930 &num_groups, user_sids);
931 *p_num_groups = num_groups;
932 if (NT_STATUS_IS_OK(status)) {
933 goto done;
936 /* lookup what groups this user is a member of by DN search on
937 * "member" */
939 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
940 &primary_group,
941 &num_groups, user_sids);
942 *p_num_groups = num_groups;
943 goto done;
946 *user_sids = NULL;
947 num_groups = 0;
949 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
950 &num_groups);
951 if (!NT_STATUS_IS_OK(status)) {
952 goto done;
955 for (i=0;i<count;i++) {
957 /* ignore Builtin groups from ADS - Guenther */
958 if (sid_check_is_in_builtin(&sids[i])) {
959 continue;
962 status = add_sid_to_array_unique(mem_ctx, &sids[i],
963 user_sids, &num_groups);
964 if (!NT_STATUS_IS_OK(status)) {
965 goto done;
969 *p_num_groups = (uint32_t)num_groups;
970 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
972 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
973 dom_sid_str_buf(sid, &buf)));
974 done:
975 TALLOC_FREE(user_dn);
976 ads_msgfree(ads, msg);
977 return status;
980 /* Lookup aliases a user is member of - use rpc methods */
981 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
982 TALLOC_CTX *mem_ctx,
983 uint32_t num_sids, const struct dom_sid *sids,
984 uint32_t *num_aliases, uint32_t **alias_rids)
986 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
987 num_aliases, alias_rids);
990 static NTSTATUS add_primary_group_members(
991 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
992 char ***all_members, size_t *num_all_members)
994 char *filter;
995 NTSTATUS status = NT_STATUS_NO_MEMORY;
996 ADS_STATUS rc;
997 const char *attrs[] = { "dn", NULL };
998 LDAPMessage *res = NULL;
999 LDAPMessage *msg;
1000 char **members;
1001 size_t num_members;
1002 ads_control args;
1004 filter = talloc_asprintf(
1005 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1006 (unsigned)rid);
1007 if (filter == NULL) {
1008 goto done;
1011 args.control = ADS_EXTENDED_DN_OID;
1012 args.val = ADS_EXTENDED_DN_HEX_STRING;
1013 args.critical = True;
1015 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1016 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1017 &res);
1019 if (!ADS_ERR_OK(rc)) {
1020 status = ads_ntstatus(rc);
1021 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1022 goto done;
1024 if (res == NULL) {
1025 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1026 goto done;
1029 num_members = ads_count_replies(ads, res);
1031 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1032 (uintmax_t)num_members));
1034 if (num_members == 0) {
1035 status = NT_STATUS_OK;
1036 goto done;
1039 members = talloc_realloc(mem_ctx, *all_members, char *,
1040 *num_all_members + num_members);
1041 if (members == NULL) {
1042 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1043 goto done;
1045 *all_members = members;
1047 for (msg = ads_first_entry(ads, res); msg != NULL;
1048 msg = ads_next_entry(ads, msg)) {
1049 char *dn;
1051 dn = ads_get_dn(ads, members, msg);
1052 if (dn == NULL) {
1053 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1054 continue;
1057 members[*num_all_members] = dn;
1058 *num_all_members += 1;
1061 status = NT_STATUS_OK;
1062 done:
1063 if (res != NULL) {
1064 ads_msgfree(ads, res);
1066 TALLOC_FREE(filter);
1067 return status;
1071 find the members of a group, given a group rid and domain
1073 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1074 TALLOC_CTX *mem_ctx,
1075 const struct dom_sid *group_sid,
1076 enum lsa_SidType type,
1077 uint32_t *num_names,
1078 struct dom_sid **sid_mem, char ***names,
1079 uint32_t **name_types)
1081 ADS_STATUS rc;
1082 ADS_STRUCT *ads = NULL;
1083 char *ldap_exp;
1084 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1085 char *sidbinstr;
1086 char **members = NULL;
1087 size_t i;
1088 size_t num_members = 0;
1089 ads_control args;
1090 struct dom_sid *sid_mem_nocache = NULL;
1091 char **names_nocache = NULL;
1092 enum lsa_SidType *name_types_nocache = NULL;
1093 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1094 uint32_t num_nocache = 0;
1095 TALLOC_CTX *tmp_ctx = NULL;
1096 uint32_t rid;
1097 struct dom_sid_buf buf;
1099 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1100 dom_sid_str_buf(group_sid, &buf)));
1102 *num_names = 0;
1104 tmp_ctx = talloc_new(mem_ctx);
1105 if (!tmp_ctx) {
1106 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1107 status = NT_STATUS_NO_MEMORY;
1108 goto done;
1111 if (!sid_peek_rid(group_sid, &rid)) {
1112 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1113 status = NT_STATUS_INVALID_PARAMETER;
1114 goto done;
1117 if ( !winbindd_can_contact_domain( domain ) ) {
1118 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1119 domain->name));
1120 return NT_STATUS_OK;
1123 ads = ads_cached_connection(domain);
1125 if (!ads) {
1126 domain->last_status = NT_STATUS_SERVER_DISABLED;
1127 goto done;
1130 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1131 status = NT_STATUS_NO_MEMORY;
1132 goto done;
1135 /* search for all members of the group */
1136 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1137 TALLOC_FREE(sidbinstr);
1138 if (ldap_exp == NULL) {
1139 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1140 status = NT_STATUS_NO_MEMORY;
1141 goto done;
1144 args.control = ADS_EXTENDED_DN_OID;
1145 args.val = ADS_EXTENDED_DN_HEX_STRING;
1146 args.critical = True;
1148 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1149 ldap_exp, &args, "member", &members, &num_members);
1151 if (!ADS_ERR_OK(rc)) {
1152 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1153 status = NT_STATUS_UNSUCCESSFUL;
1154 goto done;
1157 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1159 status = add_primary_group_members(ads, mem_ctx, rid,
1160 &members, &num_members);
1161 if (!NT_STATUS_IS_OK(status)) {
1162 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1163 __func__, nt_errstr(status)));
1164 goto done;
1167 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1168 __func__, (int)num_members));
1170 /* Now that we have a list of sids, we need to get the
1171 * lists of names and name_types belonging to these sids.
1172 * even though conceptually not quite clean, we use the
1173 * RPC call lsa_lookup_sids for this since it can handle a
1174 * list of sids. ldap calls can just resolve one sid at a time.
1176 * At this stage, the sids are still hidden in the exetended dn
1177 * member output format. We actually do a little better than
1178 * stated above: In extracting the sids from the member strings,
1179 * we try to resolve as many sids as possible from the
1180 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1182 if (num_members) {
1183 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1184 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1185 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1186 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1188 if ((members == NULL) || (*sid_mem == NULL) ||
1189 (*names == NULL) || (*name_types == NULL) ||
1190 (sid_mem_nocache == NULL))
1192 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1193 status = NT_STATUS_NO_MEMORY;
1194 goto done;
1197 else {
1198 (*sid_mem) = NULL;
1199 (*names) = NULL;
1200 (*name_types) = NULL;
1203 for (i=0; i<num_members; i++) {
1204 enum lsa_SidType name_type;
1205 char *name, *domain_name;
1206 struct dom_sid sid;
1208 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1209 &sid);
1210 if (!ADS_ERR_OK(rc)) {
1211 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1212 NT_STATUS_NOT_FOUND)) {
1213 /* Group members can be objects, like Exchange
1214 * Public Folders, that don't have a SID. Skip
1215 * them. */
1216 continue;
1218 else {
1219 status = ads_ntstatus(rc);
1220 goto done;
1223 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1224 &name_type)) {
1225 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1226 "cache\n",
1227 dom_sid_str_buf(&sid, &buf)));
1228 sid_copy(&(*sid_mem)[*num_names], &sid);
1229 (*names)[*num_names] = fill_domain_username_talloc(
1230 *names,
1231 domain_name,
1232 name,
1233 true);
1235 (*name_types)[*num_names] = name_type;
1236 (*num_names)++;
1238 else {
1239 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1240 "cache\n",
1241 dom_sid_str_buf(&sid, &buf)));
1242 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1243 num_nocache++;
1247 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1248 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1250 /* handle sids not resolved from cache by lsa_lookup_sids */
1251 if (num_nocache > 0) {
1253 status = winbindd_lookup_sids(tmp_ctx,
1254 domain,
1255 num_nocache,
1256 sid_mem_nocache,
1257 &domains_nocache,
1258 &names_nocache,
1259 &name_types_nocache);
1261 if (!(NT_STATUS_IS_OK(status) ||
1262 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1263 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1265 DEBUG(1, ("lsa_lookupsids call failed with %s "
1266 "- retrying...\n", nt_errstr(status)));
1268 status = winbindd_lookup_sids(tmp_ctx,
1269 domain,
1270 num_nocache,
1271 sid_mem_nocache,
1272 &domains_nocache,
1273 &names_nocache,
1274 &name_types_nocache);
1277 if (NT_STATUS_IS_OK(status) ||
1278 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1280 /* Copy the entries over from the "_nocache" arrays
1281 * to the result arrays, skipping the gaps the
1282 * lookup_sids call left. */
1283 for (i=0; i < num_nocache; i++) {
1284 if (((names_nocache)[i] != NULL) &&
1285 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1287 sid_copy(&(*sid_mem)[*num_names],
1288 &sid_mem_nocache[i]);
1289 (*names)[*num_names] =
1290 fill_domain_username_talloc(
1291 *names,
1292 domains_nocache[i],
1293 names_nocache[i],
1294 true);
1295 (*name_types)[*num_names] = name_types_nocache[i];
1296 (*num_names)++;
1300 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1301 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1302 "not map any SIDs at all.\n"));
1303 /* Don't handle this as an error here.
1304 * There is nothing left to do with respect to the
1305 * overall result... */
1307 else if (!NT_STATUS_IS_OK(status)) {
1308 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1309 "sids via rpc_lsa_lookup_sids: %s\n",
1310 (int)num_members, nt_errstr(status)));
1311 goto done;
1315 status = NT_STATUS_OK;
1316 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1317 dom_sid_str_buf(group_sid, &buf)));
1319 done:
1321 TALLOC_FREE(tmp_ctx);
1323 return status;
1326 /* find the sequence number for a domain */
1327 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1329 ADS_STRUCT *ads = NULL;
1330 ADS_STATUS rc;
1332 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1334 if ( !winbindd_can_contact_domain( domain ) ) {
1335 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1336 domain->name));
1337 *seq = time(NULL);
1338 return NT_STATUS_OK;
1341 if (IS_AD_DC) {
1342 DEBUG(10,("sequence: Avoid LDAP connection for domain %s\n",
1343 domain->name));
1344 *seq = time(NULL);
1345 return NT_STATUS_OK;
1348 *seq = DOM_SEQUENCE_NONE;
1350 ads = ads_cached_connection(domain);
1352 if (!ads) {
1353 domain->last_status = NT_STATUS_SERVER_DISABLED;
1354 return NT_STATUS_UNSUCCESSFUL;
1357 rc = ads_USN(ads, seq);
1359 if (!ADS_ERR_OK(rc)) {
1361 /* its a dead connection, destroy it */
1363 if (domain->private_data) {
1364 ads = (ADS_STRUCT *)domain->private_data;
1365 ads->is_mine = True;
1366 ads_destroy(&ads);
1367 ads_kdestroy(WINBIND_CCACHE_NAME);
1368 domain->private_data = NULL;
1371 return ads_ntstatus(rc);
1374 /* find the lockout policy of a domain - use rpc methods */
1375 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1376 TALLOC_CTX *mem_ctx,
1377 struct samr_DomInfo12 *policy)
1379 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1382 /* find the password policy of a domain - use rpc methods */
1383 static NTSTATUS password_policy(struct winbindd_domain *domain,
1384 TALLOC_CTX *mem_ctx,
1385 struct samr_DomInfo1 *policy)
1387 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1390 /* get a list of trusted domains */
1391 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1392 TALLOC_CTX *mem_ctx,
1393 struct netr_DomainTrustList *trusts)
1395 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1396 WERROR werr;
1397 uint32_t i;
1398 uint32_t flags;
1399 struct rpc_pipe_client *cli;
1400 int ret_count;
1401 struct dcerpc_binding_handle *b;
1403 DEBUG(3,("ads: trusted_domains\n"));
1405 ZERO_STRUCTP(trusts);
1407 /* If this is our primary domain or a root in our forest,
1408 query for all trusts. If not, then just look for domain
1409 trusts in the target forest */
1411 if (domain->primary || domain_is_forest_root(domain)) {
1412 flags = NETR_TRUST_FLAG_OUTBOUND |
1413 NETR_TRUST_FLAG_INBOUND |
1414 NETR_TRUST_FLAG_IN_FOREST;
1415 } else {
1416 flags = NETR_TRUST_FLAG_IN_FOREST;
1419 result = cm_connect_netlogon(domain, &cli);
1421 if (!NT_STATUS_IS_OK(result)) {
1422 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1423 "for PIPE_NETLOGON (%s)\n",
1424 domain->name, nt_errstr(result)));
1425 return NT_STATUS_UNSUCCESSFUL;
1428 b = cli->binding_handle;
1430 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1431 cli->desthost,
1432 flags,
1433 trusts,
1434 &werr);
1435 if (!NT_STATUS_IS_OK(result)) {
1436 return result;
1439 if (!W_ERROR_IS_OK(werr)) {
1440 return werror_to_ntstatus(werr);
1442 if (trusts->count == 0) {
1443 return NT_STATUS_OK;
1446 /* Copy across names and sids */
1448 ret_count = 0;
1449 for (i = 0; i < trusts->count; i++) {
1450 struct netr_DomainTrust *trust = &trusts->array[i];
1451 struct winbindd_domain d;
1453 ZERO_STRUCT(d);
1456 * drop external trusts if this is not our primary
1457 * domain. This means that the returned number of
1458 * domains may be less that the ones actually trusted
1459 * by the DC.
1462 if ((trust->trust_attributes
1463 & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1464 !domain->primary )
1466 DEBUG(10,("trusted_domains: Skipping external trusted "
1467 "domain %s because it is outside of our "
1468 "primary domain\n",
1469 trust->netbios_name));
1470 continue;
1473 /* add to the trusted domain cache */
1475 d.name = discard_const_p(char, trust->netbios_name);
1476 d.alt_name = discard_const_p(char, trust->dns_name);
1478 if (trust->sid) {
1479 sid_copy(&d.sid, trust->sid);
1480 } else {
1481 sid_copy(&d.sid, &global_sid_NULL);
1484 if ( domain->primary ) {
1485 DEBUG(10,("trusted_domains(ads): Searching "
1486 "trusted domain list of %s and storing "
1487 "trust flags for domain %s\n",
1488 domain->name, d.alt_name));
1490 d.domain_flags = trust->trust_flags;
1491 d.domain_type = trust->trust_type;
1492 d.domain_trust_attribs = trust->trust_attributes;
1494 wcache_tdc_add_domain( &d );
1495 ret_count++;
1496 } else if (domain_is_forest_root(domain)) {
1497 /* Check if we already have this record. If
1498 * we are following our forest root that is not
1499 * our primary domain, we want to keep trust
1500 * flags from the perspective of our primary
1501 * domain not our forest root. */
1502 struct winbindd_tdc_domain *exist = NULL;
1504 exist = wcache_tdc_fetch_domain(
1505 talloc_tos(), trust->netbios_name);
1506 if (!exist) {
1507 DEBUG(10,("trusted_domains(ads): Searching "
1508 "trusted domain list of %s and "
1509 "storing trust flags for domain "
1510 "%s\n", domain->name, d.alt_name));
1511 d.domain_flags = trust->trust_flags;
1512 d.domain_type = trust->trust_type;
1513 d.domain_trust_attribs =
1514 trust->trust_attributes;
1516 wcache_tdc_add_domain( &d );
1517 ret_count++;
1519 TALLOC_FREE(exist);
1520 } else {
1521 /* This gets a little tricky. If we are
1522 following a transitive forest trust, then
1523 innerit the flags, type, and attribs from
1524 the domain we queried to make sure we don't
1525 record the view of the trust from the wrong
1526 side. Always view it from the side of our
1527 primary domain. --jerry */
1528 struct winbindd_tdc_domain *parent = NULL;
1530 DEBUG(10,("trusted_domains(ads): Searching "
1531 "trusted domain list of %s and inheriting "
1532 "trust flags for domain %s\n",
1533 domain->name, d.alt_name));
1535 parent = wcache_tdc_fetch_domain(talloc_tos(),
1536 domain->name);
1537 if (parent) {
1538 d.domain_flags = parent->trust_flags;
1539 d.domain_type = parent->trust_type;
1540 d.domain_trust_attribs = parent->trust_attribs;
1541 } else {
1542 d.domain_flags = domain->domain_flags;
1543 d.domain_type = domain->domain_type;
1544 d.domain_trust_attribs =
1545 domain->domain_trust_attribs;
1547 TALLOC_FREE(parent);
1550 * We need to pass the modified properties
1551 * to the caller.
1553 trust->trust_flags = d.domain_flags;
1554 trust->trust_type = d.domain_type;
1555 trust->trust_attributes = d.domain_trust_attribs;
1557 wcache_tdc_add_domain( &d );
1558 ret_count++;
1561 return result;
1564 /* the ADS backend methods are exposed via this structure */
1565 struct winbindd_methods ads_methods = {
1566 True,
1567 query_user_list,
1568 enum_dom_groups,
1569 enum_local_groups,
1570 name_to_sid,
1571 sid_to_name,
1572 rids_to_names,
1573 lookup_usergroups,
1574 lookup_useraliases,
1575 lookup_groupmem,
1576 sequence_number,
1577 lockout_policy,
1578 password_policy,
1579 trusted_domains,
1582 #endif