WHATSNEW: Add release notes for Samba 4.9.17.
[Samba.git] / source3 / winbindd / winbindd_ads.c
blobeafb19eee3929ea77ff52e9d548525b55eb9c268
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, target_dom_name, ldap_server);
114 if (!ads) {
115 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
116 return ADS_ERROR(LDAP_NO_MEMORY);
119 SAFE_FREE(ads->auth.password);
120 SAFE_FREE(ads->auth.realm);
122 ads->auth.renewable = renewable;
123 ads->auth.password = password;
125 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
127 ads->auth.realm = SMB_STRDUP(auth_realm);
128 if (!strupper_m(ads->auth.realm)) {
129 ads_destroy(&ads);
130 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
133 /* Setup the server affinity cache. We don't reaally care
134 about the name. Just setup affinity and the KRB5_CONFIG
135 file. */
136 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
138 status = ads_connect(ads);
139 if (!ADS_ERR_OK(status)) {
140 DEBUG(1,("ads_connect for domain %s failed: %s\n",
141 target_dom_name, ads_errstr(status)));
142 ads_destroy(&ads);
143 return status;
146 /* set the flag that says we don't own the memory even
147 though we do so that ads_destroy() won't destroy the
148 structure we pass back by reference */
150 ads->is_mine = False;
152 *adsp = ads;
154 return status;
157 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
159 char *ldap_server, *realm, *password;
160 struct winbindd_domain *wb_dom;
161 ADS_STATUS status;
163 if (IS_AD_DC) {
165 * Make sure we never try to use LDAP against
166 * a trusted domain as AD DC.
168 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
171 ads_cached_connection_reuse(adsp);
172 if (*adsp != NULL) {
173 return ADS_SUCCESS;
177 * At this point we only have the NetBIOS domain name.
178 * Check if we can get server nam and realm from SAF cache
179 * and the domain list.
181 ldap_server = saf_fetch(talloc_tos(), dom_name);
182 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
183 ldap_server ? ldap_server : ""));
185 wb_dom = find_domain_from_name(dom_name);
186 if (wb_dom == NULL) {
187 DEBUG(10, ("could not find domain '%s'\n", dom_name));
188 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
191 DEBUG(10, ("find_domain_from_name found realm '%s' for "
192 " domain '%s'\n", wb_dom->alt_name, dom_name));
194 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
195 TALLOC_FREE(ldap_server);
196 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
199 if (IS_DC) {
200 SMB_ASSERT(wb_dom->alt_name != NULL);
201 realm = SMB_STRDUP(wb_dom->alt_name);
202 } else {
203 struct winbindd_domain *our_domain = wb_dom;
205 /* always give preference to the alt_name in our
206 primary domain if possible */
208 if (!wb_dom->primary) {
209 our_domain = find_our_domain();
212 if (our_domain->alt_name != NULL) {
213 realm = SMB_STRDUP(our_domain->alt_name);
214 } else {
215 realm = SMB_STRDUP(lp_realm());
219 status = ads_cached_connection_connect(
220 adsp, /* Returns ads struct. */
221 wb_dom->alt_name, /* realm to connect to. */
222 dom_name, /* 'workgroup' name for ads_init */
223 ldap_server, /* DNS name to connect to. */
224 password, /* password for auth realm. */
225 realm, /* realm used for krb5 ticket. */
226 0); /* renewable ticket time. */
228 SAFE_FREE(realm);
229 TALLOC_FREE(ldap_server);
231 return status;
235 return our ads connections structure for a domain. We keep the connection
236 open to make things faster
238 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
240 ADS_STATUS status;
241 char *password, *realm;
243 if (IS_AD_DC) {
245 * Make sure we never try to use LDAP against
246 * a trusted domain as AD DC.
248 return NULL;
251 DEBUG(10,("ads_cached_connection\n"));
252 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
254 if (domain->private_data) {
255 return (ADS_STRUCT *)domain->private_data;
258 /* the machine acct password might have change - fetch it every time */
260 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
261 return NULL;
264 if ( IS_DC ) {
265 SMB_ASSERT(domain->alt_name != NULL);
266 realm = SMB_STRDUP(domain->alt_name);
268 else {
269 struct winbindd_domain *our_domain = domain;
272 /* always give preference to the alt_name in our
273 primary domain if possible */
275 if ( !domain->primary )
276 our_domain = find_our_domain();
278 if (our_domain->alt_name != NULL) {
279 realm = SMB_STRDUP( our_domain->alt_name );
281 else
282 realm = SMB_STRDUP( lp_realm() );
285 status = ads_cached_connection_connect(
286 (ADS_STRUCT **)&domain->private_data,
287 domain->alt_name,
288 domain->name, NULL,
289 password, realm,
290 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
291 SAFE_FREE(realm);
293 if (!ADS_ERR_OK(status)) {
294 /* if we get ECONNREFUSED then it might be a NT4
295 server, fall back to MSRPC */
296 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
297 status.err.rc == ECONNREFUSED) {
298 /* 'reconnect_methods' is the MS-RPC backend. */
299 DEBUG(1,("Trying MSRPC methods\n"));
300 domain->backend = &reconnect_methods;
302 return NULL;
305 return (ADS_STRUCT *)domain->private_data;
308 /* Query display info for a realm. This is the basic user list fn */
309 static NTSTATUS query_user_list(struct winbindd_domain *domain,
310 TALLOC_CTX *mem_ctx,
311 uint32_t **prids)
313 ADS_STRUCT *ads = NULL;
314 const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
315 int count;
316 uint32_t *rids = NULL;
317 ADS_STATUS rc;
318 LDAPMessage *res = NULL;
319 LDAPMessage *msg = NULL;
320 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
322 DEBUG(3,("ads: query_user_list\n"));
324 if ( !winbindd_can_contact_domain( domain ) ) {
325 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
326 domain->name));
327 return NT_STATUS_OK;
330 ads = ads_cached_connection(domain);
332 if (!ads) {
333 domain->last_status = NT_STATUS_SERVER_DISABLED;
334 goto done;
337 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
338 if (!ADS_ERR_OK(rc)) {
339 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
340 status = ads_ntstatus(rc);
341 goto done;
342 } else if (!res) {
343 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
344 goto done;
347 count = ads_count_replies(ads, res);
348 if (count == 0) {
349 DEBUG(1,("query_user_list: No users found\n"));
350 goto done;
353 rids = talloc_zero_array(mem_ctx, uint32_t, count);
354 if (rids == NULL) {
355 status = NT_STATUS_NO_MEMORY;
356 goto done;
359 count = 0;
361 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
362 struct dom_sid user_sid;
363 uint32_t atype;
364 bool ok;
366 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
367 if (!ok) {
368 DBG_INFO("Object lacks sAMAccountType attribute\n");
369 continue;
371 if (ds_atype_map(atype) != SID_NAME_USER) {
372 DBG_INFO("Not a user account? atype=0x%x\n", atype);
373 continue;
376 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
377 char *dn = ads_get_dn(ads, talloc_tos(), msg);
378 DBG_INFO("No sid for %s !?\n", dn);
379 TALLOC_FREE(dn);
380 continue;
383 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
384 fstring sidstr, domstr;
385 DBG_WARNING("Got sid %s in domain %s\n",
386 sid_to_fstring(sidstr, &user_sid),
387 sid_to_fstring(domstr, &domain->sid));
388 continue;
391 sid_split_rid(&user_sid, &rids[count]);
392 count += 1;
395 rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
396 if (prids != NULL) {
397 *prids = rids;
400 status = NT_STATUS_OK;
402 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
404 done:
405 return status;
408 /* list all domain groups */
409 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
410 TALLOC_CTX *mem_ctx,
411 uint32_t *num_entries,
412 struct wb_acct_info **info)
414 ADS_STRUCT *ads = NULL;
415 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
416 "name", "objectSid", NULL};
417 int i, count;
418 ADS_STATUS rc;
419 LDAPMessage *res = NULL;
420 LDAPMessage *msg = NULL;
421 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
422 const char *filter;
423 bool enum_dom_local_groups = False;
425 *num_entries = 0;
427 DEBUG(3,("ads: enum_dom_groups\n"));
429 if ( !winbindd_can_contact_domain( domain ) ) {
430 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
431 domain->name));
432 return NT_STATUS_OK;
435 /* only grab domain local groups for our domain */
436 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
437 enum_dom_local_groups = True;
440 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
441 * rollup-fixes:
443 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
444 * default value, it MUST be absent. In case of extensible matching the
445 * "dnattr" boolean defaults to FALSE and so it must be only be present
446 * when set to TRUE.
448 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
449 * filter using bitwise matching rule then the buggy AD fails to decode
450 * the extensible match. As a workaround set it to TRUE and thereby add
451 * the dnAttributes "dn" field to cope with those older AD versions.
452 * It should not harm and won't put any additional load on the AD since
453 * none of the dn components have a bitmask-attribute.
455 * Thanks to Ralf Haferkamp for input and testing - Guenther */
457 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
458 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
459 ADS_LDAP_MATCHING_RULE_BIT_AND,
460 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
462 if (filter == NULL) {
463 status = NT_STATUS_NO_MEMORY;
464 goto done;
467 ads = ads_cached_connection(domain);
469 if (!ads) {
470 domain->last_status = NT_STATUS_SERVER_DISABLED;
471 goto done;
474 rc = ads_search_retry(ads, &res, filter, attrs);
475 if (!ADS_ERR_OK(rc)) {
476 status = ads_ntstatus(rc);
477 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
478 goto done;
479 } else if (!res) {
480 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
481 goto done;
484 count = ads_count_replies(ads, res);
485 if (count == 0) {
486 DEBUG(1,("enum_dom_groups: No groups found\n"));
487 goto done;
490 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
491 if (!*info) {
492 status = NT_STATUS_NO_MEMORY;
493 goto done;
496 i = 0;
498 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
499 char *name, *gecos;
500 struct dom_sid sid;
501 uint32_t rid;
503 name = ads_pull_username(ads, mem_ctx, msg);
504 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
505 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
506 DEBUG(1,("No sid for %s !?\n", name));
507 continue;
510 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
511 DEBUG(1,("No rid for %s !?\n", name));
512 continue;
515 fstrcpy((*info)[i].acct_name, name);
516 fstrcpy((*info)[i].acct_desc, gecos);
517 (*info)[i].rid = rid;
518 i++;
521 (*num_entries) = i;
523 status = NT_STATUS_OK;
525 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
527 done:
528 if (res)
529 ads_msgfree(ads, res);
531 return status;
534 /* list all domain local groups */
535 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
536 TALLOC_CTX *mem_ctx,
537 uint32_t *num_entries,
538 struct wb_acct_info **info)
541 * This is a stub function only as we returned the domain
542 * local groups in enum_dom_groups() if the domain->native field
543 * was true. This is a simple performance optimization when
544 * using LDAP.
546 * if we ever need to enumerate domain local groups separately,
547 * then this optimization in enum_dom_groups() will need
548 * to be split out
550 *num_entries = 0;
552 return NT_STATUS_OK;
555 /* convert a single name to a sid in a domain - use rpc methods */
556 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
557 TALLOC_CTX *mem_ctx,
558 const char *domain_name,
559 const char *name,
560 uint32_t flags,
561 const char **pdom_name,
562 struct dom_sid *sid,
563 enum lsa_SidType *type)
565 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
566 flags, pdom_name, sid, type);
569 /* convert a domain SID to a user or group name - use rpc methods */
570 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
571 TALLOC_CTX *mem_ctx,
572 const struct dom_sid *sid,
573 char **domain_name,
574 char **name,
575 enum lsa_SidType *type)
577 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
578 domain_name, name, type);
581 /* convert a list of rids to names - use rpc methods */
582 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
583 TALLOC_CTX *mem_ctx,
584 const struct dom_sid *sid,
585 uint32_t *rids,
586 size_t num_rids,
587 char **domain_name,
588 char ***names,
589 enum lsa_SidType **types)
591 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
592 rids, num_rids,
593 domain_name, names, types);
596 /* Lookup groups a user is a member of - alternate method, for when
597 tokenGroups are not available. */
598 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
599 TALLOC_CTX *mem_ctx,
600 const char *user_dn,
601 struct dom_sid *primary_group,
602 uint32_t *p_num_groups, struct dom_sid **user_sids)
604 ADS_STATUS rc;
605 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
606 int count;
607 LDAPMessage *res = NULL;
608 LDAPMessage *msg = NULL;
609 char *ldap_exp;
610 ADS_STRUCT *ads;
611 const char *group_attrs[] = {"objectSid", NULL};
612 char *escaped_dn;
613 uint32_t num_groups = 0;
615 DEBUG(3,("ads: lookup_usergroups_member\n"));
617 if ( !winbindd_can_contact_domain( domain ) ) {
618 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
619 domain->name));
620 return NT_STATUS_OK;
623 ads = ads_cached_connection(domain);
625 if (!ads) {
626 domain->last_status = NT_STATUS_SERVER_DISABLED;
627 goto done;
630 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
631 status = NT_STATUS_NO_MEMORY;
632 goto done;
635 ldap_exp = talloc_asprintf(mem_ctx,
636 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
637 escaped_dn,
638 ADS_LDAP_MATCHING_RULE_BIT_AND,
639 GROUP_TYPE_SECURITY_ENABLED);
640 if (!ldap_exp) {
641 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
642 TALLOC_FREE(escaped_dn);
643 status = NT_STATUS_NO_MEMORY;
644 goto done;
647 TALLOC_FREE(escaped_dn);
649 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
651 if (!ADS_ERR_OK(rc)) {
652 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
653 return ads_ntstatus(rc);
654 } else if (!res) {
655 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
656 return NT_STATUS_INTERNAL_ERROR;
660 count = ads_count_replies(ads, res);
662 *user_sids = NULL;
663 num_groups = 0;
665 /* always add the primary group to the sid array */
666 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
667 &num_groups);
668 if (!NT_STATUS_IS_OK(status)) {
669 goto done;
672 if (count > 0) {
673 for (msg = ads_first_entry(ads, res); msg;
674 msg = ads_next_entry(ads, msg)) {
675 struct dom_sid group_sid;
677 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
678 DEBUG(1,("No sid for this group ?!?\n"));
679 continue;
682 /* ignore Builtin groups from ADS - Guenther */
683 if (sid_check_is_in_builtin(&group_sid)) {
684 continue;
687 status = add_sid_to_array(mem_ctx, &group_sid,
688 user_sids, &num_groups);
689 if (!NT_STATUS_IS_OK(status)) {
690 goto done;
696 *p_num_groups = num_groups;
697 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
699 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
700 done:
701 if (res)
702 ads_msgfree(ads, res);
704 return status;
707 /* Lookup groups a user is a member of - alternate method, for when
708 tokenGroups are not available. */
709 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
710 TALLOC_CTX *mem_ctx,
711 const char *user_dn,
712 struct dom_sid *primary_group,
713 uint32_t *p_num_groups,
714 struct dom_sid **user_sids)
716 ADS_STATUS rc;
717 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
718 ADS_STRUCT *ads;
719 const char *attrs[] = {"memberOf", NULL};
720 uint32_t num_groups = 0;
721 struct dom_sid *group_sids = NULL;
722 int i;
723 char **strings = NULL;
724 size_t num_strings = 0, num_sids = 0;
727 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
729 if ( !winbindd_can_contact_domain( domain ) ) {
730 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
731 "domain %s\n", domain->name));
732 return NT_STATUS_OK;
735 ads = ads_cached_connection(domain);
737 if (!ads) {
738 domain->last_status = NT_STATUS_SERVER_DISABLED;
739 return NT_STATUS_UNSUCCESSFUL;
742 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
743 ADS_EXTENDED_DN_HEX_STRING,
744 &strings, &num_strings);
746 if (!ADS_ERR_OK(rc)) {
747 DEBUG(1,("lookup_usergroups_memberof ads_search "
748 "member=%s: %s\n", user_dn, ads_errstr(rc)));
749 return ads_ntstatus(rc);
752 *user_sids = NULL;
753 num_groups = 0;
755 /* always add the primary group to the sid array */
756 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
757 &num_groups);
758 if (!NT_STATUS_IS_OK(status)) {
759 goto done;
762 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
763 if (!group_sids) {
764 status = NT_STATUS_NO_MEMORY;
765 goto done;
768 for (i=0; i<num_strings; i++) {
769 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
770 ADS_EXTENDED_DN_HEX_STRING,
771 &(group_sids)[i]);
772 if (!ADS_ERR_OK(rc)) {
773 /* ignore members without SIDs */
774 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
775 NT_STATUS_NOT_FOUND)) {
776 continue;
778 else {
779 status = ads_ntstatus(rc);
780 goto done;
783 num_sids++;
786 if (i == 0) {
787 DEBUG(1,("No memberOf for this user?!?\n"));
788 status = NT_STATUS_NO_MEMORY;
789 goto done;
792 for (i=0; i<num_sids; i++) {
794 /* ignore Builtin groups from ADS - Guenther */
795 if (sid_check_is_in_builtin(&group_sids[i])) {
796 continue;
799 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
800 &num_groups);
801 if (!NT_STATUS_IS_OK(status)) {
802 goto done;
807 *p_num_groups = num_groups;
808 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
810 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
811 user_dn));
813 done:
814 TALLOC_FREE(strings);
815 TALLOC_FREE(group_sids);
817 return status;
821 /* Lookup groups a user is a member of. */
822 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
823 TALLOC_CTX *mem_ctx,
824 const struct dom_sid *sid,
825 uint32_t *p_num_groups, struct dom_sid **user_sids)
827 ADS_STRUCT *ads = NULL;
828 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
829 ADS_STATUS rc;
830 int count;
831 LDAPMessage *msg = NULL;
832 char *user_dn = NULL;
833 struct dom_sid *sids;
834 int i;
835 struct dom_sid primary_group;
836 uint32_t primary_group_rid;
837 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
838 uint32_t num_groups = 0;
840 DEBUG(3,("ads: lookup_usergroups\n"));
841 *p_num_groups = 0;
843 status = lookup_usergroups_cached(mem_ctx, sid,
844 p_num_groups, user_sids);
845 if (NT_STATUS_IS_OK(status)) {
846 return NT_STATUS_OK;
849 if ( !winbindd_can_contact_domain( domain ) ) {
850 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
851 domain->name));
853 /* Tell the cache manager not to remember this one */
855 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
858 ads = ads_cached_connection(domain);
860 if (!ads) {
861 domain->last_status = NT_STATUS_SERVER_DISABLED;
862 status = NT_STATUS_SERVER_DISABLED;
863 goto done;
866 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
868 if (!ADS_ERR_OK(rc)) {
869 status = ads_ntstatus(rc);
870 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
871 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
872 goto done;
875 count = ads_count_replies(ads, msg);
876 if (count != 1) {
877 status = NT_STATUS_UNSUCCESSFUL;
878 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
879 "invalid number of results (count=%d)\n",
880 sid_string_dbg(sid), count));
881 goto done;
884 if (!msg) {
885 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
886 sid_string_dbg(sid)));
887 status = NT_STATUS_UNSUCCESSFUL;
888 goto done;
891 user_dn = ads_get_dn(ads, mem_ctx, msg);
892 if (user_dn == NULL) {
893 status = NT_STATUS_NO_MEMORY;
894 goto done;
897 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
898 DEBUG(1,("%s: No primary group for sid=%s !?\n",
899 domain->name, sid_string_dbg(sid)));
900 goto done;
903 sid_compose(&primary_group, &domain->sid, primary_group_rid);
905 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
907 /* there must always be at least one group in the token,
908 unless we are talking to a buggy Win2k server */
910 /* actually this only happens when the machine account has no read
911 * permissions on the tokenGroup attribute - gd */
913 if (count == 0) {
915 /* no tokenGroups */
917 /* lookup what groups this user is a member of by DN search on
918 * "memberOf" */
920 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
921 &primary_group,
922 &num_groups, user_sids);
923 *p_num_groups = num_groups;
924 if (NT_STATUS_IS_OK(status)) {
925 goto done;
928 /* lookup what groups this user is a member of by DN search on
929 * "member" */
931 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
932 &primary_group,
933 &num_groups, user_sids);
934 *p_num_groups = num_groups;
935 goto done;
938 *user_sids = NULL;
939 num_groups = 0;
941 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
942 &num_groups);
943 if (!NT_STATUS_IS_OK(status)) {
944 goto done;
947 for (i=0;i<count;i++) {
949 /* ignore Builtin groups from ADS - Guenther */
950 if (sid_check_is_in_builtin(&sids[i])) {
951 continue;
954 status = add_sid_to_array_unique(mem_ctx, &sids[i],
955 user_sids, &num_groups);
956 if (!NT_STATUS_IS_OK(status)) {
957 goto done;
961 *p_num_groups = (uint32_t)num_groups;
962 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
964 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
965 sid_string_dbg(sid)));
966 done:
967 TALLOC_FREE(user_dn);
968 ads_msgfree(ads, msg);
969 return status;
972 /* Lookup aliases a user is member of - use rpc methods */
973 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
974 TALLOC_CTX *mem_ctx,
975 uint32_t num_sids, const struct dom_sid *sids,
976 uint32_t *num_aliases, uint32_t **alias_rids)
978 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
979 num_aliases, alias_rids);
982 static NTSTATUS add_primary_group_members(
983 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
984 char ***all_members, size_t *num_all_members)
986 char *filter;
987 NTSTATUS status = NT_STATUS_NO_MEMORY;
988 ADS_STATUS rc;
989 const char *attrs[] = { "dn", NULL };
990 LDAPMessage *res = NULL;
991 LDAPMessage *msg;
992 char **members;
993 size_t num_members;
994 ads_control args;
996 filter = talloc_asprintf(
997 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
998 (unsigned)rid);
999 if (filter == NULL) {
1000 goto done;
1003 args.control = ADS_EXTENDED_DN_OID;
1004 args.val = ADS_EXTENDED_DN_HEX_STRING;
1005 args.critical = True;
1007 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1008 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1009 &res);
1011 if (!ADS_ERR_OK(rc)) {
1012 status = ads_ntstatus(rc);
1013 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1014 goto done;
1016 if (res == NULL) {
1017 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1018 goto done;
1021 num_members = ads_count_replies(ads, res);
1023 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1024 (uintmax_t)num_members));
1026 if (num_members == 0) {
1027 status = NT_STATUS_OK;
1028 goto done;
1031 members = talloc_realloc(mem_ctx, *all_members, char *,
1032 *num_all_members + num_members);
1033 if (members == NULL) {
1034 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1035 goto done;
1037 *all_members = members;
1039 for (msg = ads_first_entry(ads, res); msg != NULL;
1040 msg = ads_next_entry(ads, msg)) {
1041 char *dn;
1043 dn = ads_get_dn(ads, members, msg);
1044 if (dn == NULL) {
1045 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1046 continue;
1049 members[*num_all_members] = dn;
1050 *num_all_members += 1;
1053 status = NT_STATUS_OK;
1054 done:
1055 if (res != NULL) {
1056 ads_msgfree(ads, res);
1058 TALLOC_FREE(filter);
1059 return status;
1063 find the members of a group, given a group rid and domain
1065 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1066 TALLOC_CTX *mem_ctx,
1067 const struct dom_sid *group_sid,
1068 enum lsa_SidType type,
1069 uint32_t *num_names,
1070 struct dom_sid **sid_mem, char ***names,
1071 uint32_t **name_types)
1073 ADS_STATUS rc;
1074 ADS_STRUCT *ads = NULL;
1075 char *ldap_exp;
1076 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1077 char *sidbinstr;
1078 char **members = NULL;
1079 int i;
1080 size_t num_members = 0;
1081 ads_control args;
1082 struct dom_sid *sid_mem_nocache = NULL;
1083 char **names_nocache = NULL;
1084 enum lsa_SidType *name_types_nocache = NULL;
1085 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1086 uint32_t num_nocache = 0;
1087 TALLOC_CTX *tmp_ctx = NULL;
1088 uint32_t rid;
1090 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1091 sid_string_dbg(group_sid)));
1093 *num_names = 0;
1095 tmp_ctx = talloc_new(mem_ctx);
1096 if (!tmp_ctx) {
1097 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1098 status = NT_STATUS_NO_MEMORY;
1099 goto done;
1102 if (!sid_peek_rid(group_sid, &rid)) {
1103 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1104 status = NT_STATUS_INVALID_PARAMETER;
1105 goto done;
1108 if ( !winbindd_can_contact_domain( domain ) ) {
1109 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1110 domain->name));
1111 return NT_STATUS_OK;
1114 ads = ads_cached_connection(domain);
1116 if (!ads) {
1117 domain->last_status = NT_STATUS_SERVER_DISABLED;
1118 goto done;
1121 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1122 status = NT_STATUS_NO_MEMORY;
1123 goto done;
1126 /* search for all members of the group */
1127 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1128 TALLOC_FREE(sidbinstr);
1129 if (ldap_exp == NULL) {
1130 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1131 status = NT_STATUS_NO_MEMORY;
1132 goto done;
1135 args.control = ADS_EXTENDED_DN_OID;
1136 args.val = ADS_EXTENDED_DN_HEX_STRING;
1137 args.critical = True;
1139 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1140 ldap_exp, &args, "member", &members, &num_members);
1142 if (!ADS_ERR_OK(rc)) {
1143 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1144 status = NT_STATUS_UNSUCCESSFUL;
1145 goto done;
1148 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1150 status = add_primary_group_members(ads, mem_ctx, rid,
1151 &members, &num_members);
1152 if (!NT_STATUS_IS_OK(status)) {
1153 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1154 __func__, nt_errstr(status)));
1155 goto done;
1158 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1159 __func__, (int)num_members));
1161 /* Now that we have a list of sids, we need to get the
1162 * lists of names and name_types belonging to these sids.
1163 * even though conceptually not quite clean, we use the
1164 * RPC call lsa_lookup_sids for this since it can handle a
1165 * list of sids. ldap calls can just resolve one sid at a time.
1167 * At this stage, the sids are still hidden in the exetended dn
1168 * member output format. We actually do a little better than
1169 * stated above: In extracting the sids from the member strings,
1170 * we try to resolve as many sids as possible from the
1171 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1173 if (num_members) {
1174 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1175 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1176 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1177 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1179 if ((members == NULL) || (*sid_mem == NULL) ||
1180 (*names == NULL) || (*name_types == NULL) ||
1181 (sid_mem_nocache == NULL))
1183 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1184 status = NT_STATUS_NO_MEMORY;
1185 goto done;
1188 else {
1189 (*sid_mem) = NULL;
1190 (*names) = NULL;
1191 (*name_types) = NULL;
1194 for (i=0; i<num_members; i++) {
1195 enum lsa_SidType name_type;
1196 char *name, *domain_name;
1197 struct dom_sid sid;
1199 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1200 &sid);
1201 if (!ADS_ERR_OK(rc)) {
1202 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1203 NT_STATUS_NOT_FOUND)) {
1204 /* Group members can be objects, like Exchange
1205 * Public Folders, that don't have a SID. Skip
1206 * them. */
1207 continue;
1209 else {
1210 status = ads_ntstatus(rc);
1211 goto done;
1214 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1215 &name_type)) {
1216 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1217 "cache\n", sid_string_dbg(&sid)));
1218 sid_copy(&(*sid_mem)[*num_names], &sid);
1219 (*names)[*num_names] = fill_domain_username_talloc(
1220 *names,
1221 domain_name,
1222 name,
1223 true);
1225 (*name_types)[*num_names] = name_type;
1226 (*num_names)++;
1228 else {
1229 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1230 "cache\n", sid_string_dbg(&sid)));
1231 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1232 num_nocache++;
1236 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1237 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1239 /* handle sids not resolved from cache by lsa_lookup_sids */
1240 if (num_nocache > 0) {
1242 status = winbindd_lookup_sids(tmp_ctx,
1243 domain,
1244 num_nocache,
1245 sid_mem_nocache,
1246 &domains_nocache,
1247 &names_nocache,
1248 &name_types_nocache);
1250 if (!(NT_STATUS_IS_OK(status) ||
1251 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1252 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1254 DEBUG(1, ("lsa_lookupsids call failed with %s "
1255 "- retrying...\n", nt_errstr(status)));
1257 status = winbindd_lookup_sids(tmp_ctx,
1258 domain,
1259 num_nocache,
1260 sid_mem_nocache,
1261 &domains_nocache,
1262 &names_nocache,
1263 &name_types_nocache);
1266 if (NT_STATUS_IS_OK(status) ||
1267 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1269 /* Copy the entries over from the "_nocache" arrays
1270 * to the result arrays, skipping the gaps the
1271 * lookup_sids call left. */
1272 for (i=0; i < num_nocache; i++) {
1273 if (((names_nocache)[i] != NULL) &&
1274 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1276 sid_copy(&(*sid_mem)[*num_names],
1277 &sid_mem_nocache[i]);
1278 (*names)[*num_names] =
1279 fill_domain_username_talloc(
1280 *names,
1281 domains_nocache[i],
1282 names_nocache[i],
1283 true);
1284 (*name_types)[*num_names] = name_types_nocache[i];
1285 (*num_names)++;
1289 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1290 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1291 "not map any SIDs at all.\n"));
1292 /* Don't handle this as an error here.
1293 * There is nothing left to do with respect to the
1294 * overall result... */
1296 else if (!NT_STATUS_IS_OK(status)) {
1297 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1298 "sids via rpc_lsa_lookup_sids: %s\n",
1299 (int)num_members, nt_errstr(status)));
1300 goto done;
1304 status = NT_STATUS_OK;
1305 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1306 sid_string_dbg(group_sid)));
1308 done:
1310 TALLOC_FREE(tmp_ctx);
1312 return status;
1315 /* find the sequence number for a domain */
1316 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1318 ADS_STRUCT *ads = NULL;
1319 ADS_STATUS rc;
1321 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1323 if ( !winbindd_can_contact_domain( domain ) ) {
1324 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1325 domain->name));
1326 *seq = time(NULL);
1327 return NT_STATUS_OK;
1330 if (IS_AD_DC) {
1331 DEBUG(10,("sequence: Avoid LDAP connection for domain %s\n",
1332 domain->name));
1333 *seq = time(NULL);
1334 return NT_STATUS_OK;
1337 *seq = DOM_SEQUENCE_NONE;
1339 ads = ads_cached_connection(domain);
1341 if (!ads) {
1342 domain->last_status = NT_STATUS_SERVER_DISABLED;
1343 return NT_STATUS_UNSUCCESSFUL;
1346 rc = ads_USN(ads, seq);
1348 if (!ADS_ERR_OK(rc)) {
1350 /* its a dead connection, destroy it */
1352 if (domain->private_data) {
1353 ads = (ADS_STRUCT *)domain->private_data;
1354 ads->is_mine = True;
1355 ads_destroy(&ads);
1356 ads_kdestroy(WINBIND_CCACHE_NAME);
1357 domain->private_data = NULL;
1360 return ads_ntstatus(rc);
1363 /* find the lockout policy of a domain - use rpc methods */
1364 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1365 TALLOC_CTX *mem_ctx,
1366 struct samr_DomInfo12 *policy)
1368 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1371 /* find the password policy of a domain - use rpc methods */
1372 static NTSTATUS password_policy(struct winbindd_domain *domain,
1373 TALLOC_CTX *mem_ctx,
1374 struct samr_DomInfo1 *policy)
1376 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1379 /* get a list of trusted domains */
1380 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1381 TALLOC_CTX *mem_ctx,
1382 struct netr_DomainTrustList *trusts)
1384 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1385 WERROR werr;
1386 int i;
1387 uint32_t flags;
1388 struct rpc_pipe_client *cli;
1389 int ret_count;
1390 struct dcerpc_binding_handle *b;
1392 DEBUG(3,("ads: trusted_domains\n"));
1394 ZERO_STRUCTP(trusts);
1396 /* If this is our primary domain or a root in our forest,
1397 query for all trusts. If not, then just look for domain
1398 trusts in the target forest */
1400 if (domain->primary || domain_is_forest_root(domain)) {
1401 flags = NETR_TRUST_FLAG_OUTBOUND |
1402 NETR_TRUST_FLAG_INBOUND |
1403 NETR_TRUST_FLAG_IN_FOREST;
1404 } else {
1405 flags = NETR_TRUST_FLAG_IN_FOREST;
1408 result = cm_connect_netlogon(domain, &cli);
1410 if (!NT_STATUS_IS_OK(result)) {
1411 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1412 "for PIPE_NETLOGON (%s)\n",
1413 domain->name, nt_errstr(result)));
1414 return NT_STATUS_UNSUCCESSFUL;
1417 b = cli->binding_handle;
1419 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1420 cli->desthost,
1421 flags,
1422 trusts,
1423 &werr);
1424 if (!NT_STATUS_IS_OK(result)) {
1425 return result;
1428 if (!W_ERROR_IS_OK(werr)) {
1429 return werror_to_ntstatus(werr);
1431 if (trusts->count == 0) {
1432 return NT_STATUS_OK;
1435 /* Copy across names and sids */
1437 ret_count = 0;
1438 for (i = 0; i < trusts->count; i++) {
1439 struct netr_DomainTrust *trust = &trusts->array[i];
1440 struct winbindd_domain d;
1442 ZERO_STRUCT(d);
1445 * drop external trusts if this is not our primary
1446 * domain. This means that the returned number of
1447 * domains may be less that the ones actually trusted
1448 * by the DC.
1451 if ((trust->trust_attributes
1452 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1453 !domain->primary )
1455 DEBUG(10,("trusted_domains: Skipping external trusted "
1456 "domain %s because it is outside of our "
1457 "primary domain\n",
1458 trust->netbios_name));
1459 continue;
1462 /* add to the trusted domain cache */
1464 d.name = discard_const_p(char, trust->netbios_name);
1465 d.alt_name = discard_const_p(char, trust->dns_name);
1467 if (trust->sid) {
1468 sid_copy(&d.sid, trust->sid);
1469 } else {
1470 sid_copy(&d.sid, &global_sid_NULL);
1473 if ( domain->primary ) {
1474 DEBUG(10,("trusted_domains(ads): Searching "
1475 "trusted domain list of %s and storing "
1476 "trust flags for domain %s\n",
1477 domain->name, d.alt_name));
1479 d.domain_flags = trust->trust_flags;
1480 d.domain_type = trust->trust_type;
1481 d.domain_trust_attribs = trust->trust_attributes;
1483 wcache_tdc_add_domain( &d );
1484 ret_count++;
1485 } else if (domain_is_forest_root(domain)) {
1486 /* Check if we already have this record. If
1487 * we are following our forest root that is not
1488 * our primary domain, we want to keep trust
1489 * flags from the perspective of our primary
1490 * domain not our forest root. */
1491 struct winbindd_tdc_domain *exist = NULL;
1493 exist = wcache_tdc_fetch_domain(
1494 talloc_tos(), trust->netbios_name);
1495 if (!exist) {
1496 DEBUG(10,("trusted_domains(ads): Searching "
1497 "trusted domain list of %s and "
1498 "storing trust flags for domain "
1499 "%s\n", domain->name, d.alt_name));
1500 d.domain_flags = trust->trust_flags;
1501 d.domain_type = trust->trust_type;
1502 d.domain_trust_attribs =
1503 trust->trust_attributes;
1505 wcache_tdc_add_domain( &d );
1506 ret_count++;
1508 TALLOC_FREE(exist);
1509 } else {
1510 /* This gets a little tricky. If we are
1511 following a transitive forest trust, then
1512 innerit the flags, type, and attribs from
1513 the domain we queried to make sure we don't
1514 record the view of the trust from the wrong
1515 side. Always view it from the side of our
1516 primary domain. --jerry */
1517 struct winbindd_tdc_domain *parent = NULL;
1519 DEBUG(10,("trusted_domains(ads): Searching "
1520 "trusted domain list of %s and inheriting "
1521 "trust flags for domain %s\n",
1522 domain->name, d.alt_name));
1524 parent = wcache_tdc_fetch_domain(talloc_tos(),
1525 domain->name);
1526 if (parent) {
1527 d.domain_flags = parent->trust_flags;
1528 d.domain_type = parent->trust_type;
1529 d.domain_trust_attribs = parent->trust_attribs;
1530 } else {
1531 d.domain_flags = domain->domain_flags;
1532 d.domain_type = domain->domain_type;
1533 d.domain_trust_attribs =
1534 domain->domain_trust_attribs;
1536 TALLOC_FREE(parent);
1539 * We need to pass the modified properties
1540 * to the caller.
1542 trust->trust_flags = d.domain_flags;
1543 trust->trust_type = d.domain_type;
1544 trust->trust_attributes = d.domain_trust_attribs;
1546 wcache_tdc_add_domain( &d );
1547 ret_count++;
1550 return result;
1553 /* the ADS backend methods are exposed via this structure */
1554 struct winbindd_methods ads_methods = {
1555 True,
1556 query_user_list,
1557 enum_dom_groups,
1558 enum_local_groups,
1559 name_to_sid,
1560 sid_to_name,
1561 rids_to_names,
1562 lookup_usergroups,
1563 lookup_useraliases,
1564 lookup_groupmem,
1565 sequence_number,
1566 lockout_policy,
1567 password_policy,
1568 trusted_domains,
1571 #endif