s3:winbind: Remove unused variable
[Samba.git] / source3 / winbindd / winbindd_ads.c
blob942159f5df8f40bd506bbe12fe7f6f0a537faa22
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"
37 #include "auth/credentials/credentials.h"
39 #ifdef HAVE_ADS
41 #undef DBGC_CLASS
42 #define DBGC_CLASS DBGC_WINBIND
44 extern struct winbindd_methods reconnect_methods;
45 extern struct winbindd_methods msrpc_methods;
47 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
49 /**
50 * Check if cached connection can be reused. If the connection cannot
51 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
53 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
56 ADS_STRUCT *ads = *adsp;
58 if (ads != NULL) {
59 time_t expire;
60 time_t now = time(NULL);
62 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
64 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
65 "is now %d)\n", (uint32_t)expire - (uint32_t)now,
66 (uint32_t) expire, (uint32_t) now));
68 if ( ads->config.realm && (expire > now)) {
69 return;
70 } else {
71 /* we own this ADS_STRUCT so make sure it goes away */
72 DEBUG(7,("Deleting expired krb5 credential cache\n"));
73 TALLOC_FREE(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(const char *target_realm,
94 const char *target_dom_name,
95 const char *ldap_server,
96 char *password,
97 char *auth_realm,
98 time_t renewable,
99 TALLOC_CTX *mem_ctx,
100 ADS_STRUCT **adsp)
102 TALLOC_CTX *tmp_ctx = talloc_stackframe();
103 ADS_STRUCT *ads;
104 ADS_STATUS status;
105 struct sockaddr_storage dc_ss;
106 fstring dc_name;
107 enum credentials_use_kerberos krb5_state;
109 if (auth_realm == NULL) {
110 TALLOC_FREE(tmp_ctx);
111 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
114 /* we don't want this to affect the users ccache */
115 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
117 ads = ads_init(tmp_ctx,
118 target_realm,
119 target_dom_name,
120 ldap_server,
121 ADS_SASL_SEAL);
122 if (!ads) {
123 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
124 status = ADS_ERROR(LDAP_NO_MEMORY);
125 goto out;
128 ADS_TALLOC_CONST_FREE(ads->auth.password);
129 ADS_TALLOC_CONST_FREE(ads->auth.realm);
131 ads->auth.renewable = renewable;
132 ads->auth.password = talloc_strdup(ads, password);
133 if (ads->auth.password == NULL) {
134 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
135 goto out;
138 /* In FIPS mode, client use kerberos is forced to required. */
139 krb5_state = lp_client_use_kerberos();
140 switch (krb5_state) {
141 case CRED_USE_KERBEROS_REQUIRED:
142 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
143 ads->auth.flags &= ~ADS_AUTH_ALLOW_NTLMSSP;
144 break;
145 case CRED_USE_KERBEROS_DESIRED:
146 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
147 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
148 break;
149 case CRED_USE_KERBEROS_DISABLED:
150 ads->auth.flags |= ADS_AUTH_DISABLE_KERBEROS;
151 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
152 break;
155 ads->auth.realm = talloc_asprintf_strupper_m(ads, "%s", auth_realm);
156 if (ads->auth.realm == NULL) {
157 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
158 goto out;
161 /* Setup the server affinity cache. We don't reaally care
162 about the name. Just setup affinity and the KRB5_CONFIG
163 file. */
164 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
166 status = ads_connect(ads);
167 if (!ADS_ERR_OK(status)) {
168 DEBUG(1,("ads_connect for domain %s failed: %s\n",
169 target_dom_name, ads_errstr(status)));
170 goto out;
173 *adsp = talloc_move(mem_ctx, &ads);
174 out:
175 TALLOC_FREE(tmp_ctx);
176 return status;
179 ADS_STATUS ads_idmap_cached_connection(const char *dom_name,
180 TALLOC_CTX *mem_ctx,
181 ADS_STRUCT **adsp)
183 TALLOC_CTX *tmp_ctx = talloc_stackframe();
184 char *ldap_server = NULL;
185 char *realm = NULL;
186 char *password = NULL;
187 struct winbindd_domain *wb_dom = NULL;
188 ADS_STATUS status;
190 if (IS_AD_DC) {
192 * Make sure we never try to use LDAP against
193 * a trusted domain as AD DC.
195 TALLOC_FREE(tmp_ctx);
196 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
199 ads_cached_connection_reuse(adsp);
200 if (*adsp != NULL) {
201 TALLOC_FREE(tmp_ctx);
202 return ADS_SUCCESS;
206 * At this point we only have the NetBIOS domain name.
207 * Check if we can get server nam and realm from SAF cache
208 * and the domain list.
210 ldap_server = saf_fetch(tmp_ctx, dom_name);
212 DBG_DEBUG("ldap_server from saf cache: '%s'\n",
213 ldap_server ? ldap_server : "");
215 wb_dom = find_domain_from_name(dom_name);
216 if (wb_dom == NULL) {
217 DBG_DEBUG("could not find domain '%s'\n", dom_name);
218 status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
219 goto out;
222 DBG_DEBUG("find_domain_from_name found realm '%s' for "
223 " domain '%s'\n", wb_dom->alt_name, dom_name);
225 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
226 status = ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
227 goto out;
230 if (IS_DC) {
231 SMB_ASSERT(wb_dom->alt_name != NULL);
232 realm = talloc_strdup(tmp_ctx, wb_dom->alt_name);
233 } else {
234 struct winbindd_domain *our_domain = wb_dom;
236 /* always give preference to the alt_name in our
237 primary domain if possible */
239 if (!wb_dom->primary) {
240 our_domain = find_our_domain();
243 if (our_domain->alt_name != NULL) {
244 realm = talloc_strdup(tmp_ctx, our_domain->alt_name);
245 } else {
246 realm = talloc_strdup(tmp_ctx, lp_realm());
250 if (realm == NULL) {
251 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
252 goto out;
255 status = ads_cached_connection_connect(
256 wb_dom->alt_name, /* realm to connect to. */
257 dom_name, /* 'workgroup' name for ads_init */
258 ldap_server, /* DNS name to connect to. */
259 password, /* password for auth realm. */
260 realm, /* realm used for krb5 ticket. */
261 0, /* renewable ticket time. */
262 mem_ctx, /* memory context for ads struct */
263 adsp); /* Returns ads struct. */
265 out:
266 TALLOC_FREE(tmp_ctx);
267 SAFE_FREE(password);
269 return status;
273 return our ads connections structure for a domain. We keep the connection
274 open to make things faster
276 static ADS_STATUS ads_cached_connection(struct winbindd_domain *domain,
277 ADS_STRUCT **adsp)
279 TALLOC_CTX *tmp_ctx = talloc_stackframe();
280 ADS_STATUS status;
281 char *password = NULL;
282 char *realm = NULL;
284 if (IS_AD_DC) {
286 * Make sure we never try to use LDAP against
287 * a trusted domain as AD DC.
289 TALLOC_FREE(tmp_ctx);
290 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
293 DBG_DEBUG("ads_cached_connection\n");
295 ads_cached_connection_reuse(&domain->backend_data.ads_conn);
296 if (domain->backend_data.ads_conn != NULL) {
297 *adsp = domain->backend_data.ads_conn;
298 TALLOC_FREE(tmp_ctx);
299 return ADS_SUCCESS;
302 /* the machine acct password might have change - fetch it every time */
304 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
305 status = ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
306 goto out;
309 if ( IS_DC ) {
310 SMB_ASSERT(domain->alt_name != NULL);
311 realm = talloc_strdup(tmp_ctx, domain->alt_name);
312 } else {
313 struct winbindd_domain *our_domain = domain;
316 /* always give preference to the alt_name in our
317 primary domain if possible */
319 if ( !domain->primary )
320 our_domain = find_our_domain();
322 if (our_domain->alt_name != NULL) {
323 realm = talloc_strdup(tmp_ctx, our_domain->alt_name );
324 } else {
325 realm = talloc_strdup(tmp_ctx, lp_realm() );
329 if (realm == NULL) {
330 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
331 goto out;
334 status = ads_cached_connection_connect(
335 domain->alt_name,
336 domain->name, NULL,
337 password,
338 realm,
339 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
340 domain,
341 &domain->backend_data.ads_conn);
342 if (!ADS_ERR_OK(status)) {
343 /* if we get ECONNREFUSED then it might be a NT4
344 server, fall back to MSRPC */
345 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
346 status.err.rc == ECONNREFUSED) {
347 /* 'reconnect_methods' is the MS-RPC backend. */
348 DBG_NOTICE("Trying MSRPC methods for domain '%s'\n",
349 domain->name);
350 domain->backend = &reconnect_methods;
352 goto out;
355 *adsp = domain->backend_data.ads_conn;
356 out:
357 TALLOC_FREE(tmp_ctx);
358 SAFE_FREE(password);
360 return status;
363 /* Query display info for a realm. This is the basic user list fn */
364 static NTSTATUS query_user_list(struct winbindd_domain *domain,
365 TALLOC_CTX *mem_ctx,
366 uint32_t **prids)
368 ADS_STRUCT *ads = NULL;
369 const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
370 int count;
371 uint32_t *rids = NULL;
372 ADS_STATUS rc;
373 LDAPMessage *res = NULL;
374 LDAPMessage *msg = NULL;
375 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
377 DEBUG(3,("ads: query_user_list\n"));
379 if ( !winbindd_can_contact_domain( domain ) ) {
380 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
381 domain->name));
382 return NT_STATUS_OK;
385 rc = ads_cached_connection(domain, &ads);
386 if (!ADS_ERR_OK(rc)) {
387 domain->last_status = NT_STATUS_SERVER_DISABLED;
388 goto done;
391 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
392 if (!ADS_ERR_OK(rc)) {
393 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
394 status = ads_ntstatus(rc);
395 goto done;
396 } else if (!res) {
397 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
398 goto done;
401 count = ads_count_replies(ads, res);
402 if (count == 0) {
403 DEBUG(1,("query_user_list: No users found\n"));
404 goto done;
407 rids = talloc_zero_array(mem_ctx, uint32_t, count);
408 if (rids == NULL) {
409 status = NT_STATUS_NO_MEMORY;
410 goto done;
413 count = 0;
415 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
416 struct dom_sid user_sid;
417 uint32_t atype;
418 bool ok;
420 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
421 if (!ok) {
422 DBG_INFO("Object lacks sAMAccountType attribute\n");
423 continue;
425 if (ds_atype_map(atype) != SID_NAME_USER) {
426 DBG_INFO("Not a user account? atype=0x%x\n", atype);
427 continue;
430 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
431 char *dn = ads_get_dn(ads, talloc_tos(), msg);
432 DBG_INFO("No sid for %s !?\n", dn);
433 TALLOC_FREE(dn);
434 continue;
437 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
438 struct dom_sid_buf sidstr, domstr;
439 DBG_WARNING("Got sid %s in domain %s\n",
440 dom_sid_str_buf(&user_sid, &sidstr),
441 dom_sid_str_buf(&domain->sid, &domstr));
442 continue;
445 sid_split_rid(&user_sid, &rids[count]);
446 count += 1;
449 rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
450 if (prids != NULL) {
451 *prids = rids;
454 status = NT_STATUS_OK;
456 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
458 done:
459 ads_msgfree(ads, res);
460 return status;
463 /* list all domain groups */
464 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
465 TALLOC_CTX *mem_ctx,
466 uint32_t *num_entries,
467 struct wb_acct_info **info)
469 ADS_STRUCT *ads = NULL;
470 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
471 "name", "objectSid", NULL};
472 int i, count;
473 ADS_STATUS rc;
474 LDAPMessage *res = NULL;
475 LDAPMessage *msg = NULL;
476 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
477 const char *filter;
478 bool enum_dom_local_groups = False;
480 *num_entries = 0;
482 DEBUG(3,("ads: enum_dom_groups\n"));
484 if ( !winbindd_can_contact_domain( domain ) ) {
485 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
486 domain->name));
487 return NT_STATUS_OK;
490 /* only grab domain local groups for our domain */
491 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
492 enum_dom_local_groups = True;
495 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
496 * rollup-fixes:
498 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
499 * default value, it MUST be absent. In case of extensible matching the
500 * "dnattr" boolean defaults to FALSE and so it must be only be present
501 * when set to TRUE.
503 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
504 * filter using bitwise matching rule then the buggy AD fails to decode
505 * the extensible match. As a workaround set it to TRUE and thereby add
506 * the dnAttributes "dn" field to cope with those older AD versions.
507 * It should not harm and won't put any additional load on the AD since
508 * none of the dn components have a bitmask-attribute.
510 * Thanks to Ralf Haferkamp for input and testing - Guenther */
512 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
513 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
514 ADS_LDAP_MATCHING_RULE_BIT_AND,
515 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
517 if (filter == NULL) {
518 status = NT_STATUS_NO_MEMORY;
519 goto done;
522 rc = ads_cached_connection(domain, &ads);
523 if (!ADS_ERR_OK(rc)) {
524 domain->last_status = NT_STATUS_SERVER_DISABLED;
525 goto done;
528 rc = ads_search_retry(ads, &res, filter, attrs);
529 if (!ADS_ERR_OK(rc)) {
530 status = ads_ntstatus(rc);
531 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
532 goto done;
533 } else if (!res) {
534 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
535 goto done;
538 count = ads_count_replies(ads, res);
539 if (count == 0) {
540 DEBUG(1,("enum_dom_groups: No groups found\n"));
541 goto done;
544 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
545 if (!*info) {
546 status = NT_STATUS_NO_MEMORY;
547 goto done;
550 i = 0;
552 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
553 char *name, *gecos;
554 struct dom_sid sid;
555 uint32_t rid;
557 name = ads_pull_username(ads, (*info), msg);
558 gecos = ads_pull_string(ads, (*info), msg, "name");
559 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
560 DEBUG(1,("No sid for %s !?\n", name));
561 continue;
564 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
565 DEBUG(1,("No rid for %s !?\n", name));
566 continue;
569 (*info)[i].acct_name = name;
570 (*info)[i].acct_desc = gecos;
571 (*info)[i].rid = rid;
572 i++;
575 (*num_entries) = i;
577 status = NT_STATUS_OK;
579 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
581 done:
582 if (res)
583 ads_msgfree(ads, res);
585 return status;
588 /* list all domain local groups */
589 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
590 TALLOC_CTX *mem_ctx,
591 uint32_t *num_entries,
592 struct wb_acct_info **info)
595 * This is a stub function only as we returned the domain
596 * local groups in enum_dom_groups() if the domain->native field
597 * was true. This is a simple performance optimization when
598 * using LDAP.
600 * if we ever need to enumerate domain local groups separately,
601 * then this optimization in enum_dom_groups() will need
602 * to be split out
604 *num_entries = 0;
606 return NT_STATUS_OK;
609 /* convert a single name to a sid in a domain - use rpc methods */
610 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
611 TALLOC_CTX *mem_ctx,
612 const char *domain_name,
613 const char *name,
614 uint32_t flags,
615 const char **pdom_name,
616 struct dom_sid *sid,
617 enum lsa_SidType *type)
619 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
620 flags, pdom_name, sid, type);
623 /* convert a domain SID to a user or group name - use rpc methods */
624 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
625 TALLOC_CTX *mem_ctx,
626 const struct dom_sid *sid,
627 char **domain_name,
628 char **name,
629 enum lsa_SidType *type)
631 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
632 domain_name, name, type);
635 /* convert a list of rids to names - use rpc methods */
636 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
637 TALLOC_CTX *mem_ctx,
638 const struct dom_sid *sid,
639 uint32_t *rids,
640 size_t num_rids,
641 char **domain_name,
642 char ***names,
643 enum lsa_SidType **types)
645 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
646 rids, num_rids,
647 domain_name, names, types);
650 /* Lookup groups a user is a member of - alternate method, for when
651 tokenGroups are not available. */
652 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
653 TALLOC_CTX *mem_ctx,
654 const char *user_dn,
655 struct dom_sid *primary_group,
656 uint32_t *p_num_groups, struct dom_sid **user_sids)
658 ADS_STATUS rc;
659 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
660 int count;
661 LDAPMessage *res = NULL;
662 LDAPMessage *msg = NULL;
663 char *ldap_exp;
664 ADS_STRUCT *ads = NULL;
665 const char *group_attrs[] = {"objectSid", NULL};
666 char *escaped_dn;
667 uint32_t num_groups = 0;
669 DEBUG(3,("ads: lookup_usergroups_member\n"));
671 if ( !winbindd_can_contact_domain( domain ) ) {
672 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
673 domain->name));
674 return NT_STATUS_OK;
677 rc = ads_cached_connection(domain, &ads);
678 if (!ADS_ERR_OK(rc)) {
679 domain->last_status = NT_STATUS_SERVER_DISABLED;
680 goto done;
683 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
684 status = NT_STATUS_NO_MEMORY;
685 goto done;
688 ldap_exp = talloc_asprintf(mem_ctx,
689 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
690 escaped_dn,
691 ADS_LDAP_MATCHING_RULE_BIT_AND,
692 GROUP_TYPE_SECURITY_ENABLED);
693 if (!ldap_exp) {
694 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
695 TALLOC_FREE(escaped_dn);
696 status = NT_STATUS_NO_MEMORY;
697 goto done;
700 TALLOC_FREE(escaped_dn);
702 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
704 if (!ADS_ERR_OK(rc)) {
705 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
706 return ads_ntstatus(rc);
707 } else if (!res) {
708 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
709 return NT_STATUS_INTERNAL_ERROR;
713 count = ads_count_replies(ads, res);
715 *user_sids = NULL;
716 num_groups = 0;
718 /* always add the primary group to the sid array */
719 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
720 &num_groups);
721 if (!NT_STATUS_IS_OK(status)) {
722 goto done;
725 if (count > 0) {
726 for (msg = ads_first_entry(ads, res); msg;
727 msg = ads_next_entry(ads, msg)) {
728 struct dom_sid group_sid;
730 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
731 DEBUG(1,("No sid for this group ?!?\n"));
732 continue;
735 /* ignore Builtin groups from ADS - Guenther */
736 if (sid_check_is_in_builtin(&group_sid)) {
737 continue;
740 status = add_sid_to_array(mem_ctx, &group_sid,
741 user_sids, &num_groups);
742 if (!NT_STATUS_IS_OK(status)) {
743 goto done;
749 *p_num_groups = num_groups;
750 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
752 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
753 done:
754 if (res)
755 ads_msgfree(ads, res);
757 return status;
760 /* Lookup groups a user is a member of - alternate method, for when
761 tokenGroups are not available. */
762 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
763 TALLOC_CTX *mem_ctx,
764 const char *user_dn,
765 struct dom_sid *primary_group,
766 uint32_t *p_num_groups,
767 struct dom_sid **user_sids)
769 ADS_STATUS rc;
770 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
771 ADS_STRUCT *ads = NULL;
772 const char *attrs[] = {"memberOf", NULL};
773 uint32_t num_groups = 0;
774 struct dom_sid *group_sids = NULL;
775 size_t i;
776 char **strings = NULL;
777 size_t num_strings = 0, num_sids = 0;
780 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
782 if ( !winbindd_can_contact_domain( domain ) ) {
783 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
784 "domain %s\n", domain->name));
785 return NT_STATUS_OK;
788 rc = ads_cached_connection(domain, &ads);
789 if (!ADS_ERR_OK(rc)) {
790 domain->last_status = NT_STATUS_SERVER_DISABLED;
791 return NT_STATUS_UNSUCCESSFUL;
794 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
795 ADS_EXTENDED_DN_HEX_STRING,
796 &strings, &num_strings);
798 if (!ADS_ERR_OK(rc)) {
799 DEBUG(1,("lookup_usergroups_memberof ads_search "
800 "member=%s: %s\n", user_dn, ads_errstr(rc)));
801 return ads_ntstatus(rc);
804 *user_sids = NULL;
805 num_groups = 0;
807 /* always add the primary group to the sid array */
808 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
809 &num_groups);
810 if (!NT_STATUS_IS_OK(status)) {
811 goto done;
814 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
815 if (!group_sids) {
816 status = NT_STATUS_NO_MEMORY;
817 goto done;
820 for (i=0; i<num_strings; i++) {
821 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
822 ADS_EXTENDED_DN_HEX_STRING,
823 &(group_sids)[i]);
824 if (!ADS_ERR_OK(rc)) {
825 /* ignore members without SIDs */
826 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
827 NT_STATUS_NOT_FOUND)) {
828 continue;
830 else {
831 status = ads_ntstatus(rc);
832 goto done;
835 num_sids++;
838 if (i == 0) {
839 DEBUG(1,("No memberOf for this user?!?\n"));
840 status = NT_STATUS_NO_MEMORY;
841 goto done;
844 for (i=0; i<num_sids; i++) {
846 /* ignore Builtin groups from ADS - Guenther */
847 if (sid_check_is_in_builtin(&group_sids[i])) {
848 continue;
851 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
852 &num_groups);
853 if (!NT_STATUS_IS_OK(status)) {
854 goto done;
859 *p_num_groups = num_groups;
860 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
862 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
863 user_dn));
865 done:
866 TALLOC_FREE(strings);
867 TALLOC_FREE(group_sids);
869 return status;
873 /* Lookup groups a user is a member of. */
874 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
875 TALLOC_CTX *mem_ctx,
876 const struct dom_sid *sid,
877 uint32_t *p_num_groups, struct dom_sid **user_sids)
879 ADS_STRUCT *ads = NULL;
880 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
881 ADS_STATUS rc;
882 int count;
883 LDAPMessage *msg = NULL;
884 char *user_dn = NULL;
885 struct dom_sid *sids;
886 int i;
887 struct dom_sid primary_group;
888 uint32_t primary_group_rid;
889 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
890 uint32_t num_groups = 0;
891 struct dom_sid_buf buf;
893 DEBUG(3,("ads: lookup_usergroups\n"));
894 *p_num_groups = 0;
896 status = lookup_usergroups_cached(mem_ctx, sid,
897 p_num_groups, user_sids);
898 if (NT_STATUS_IS_OK(status)) {
899 return NT_STATUS_OK;
902 if ( !winbindd_can_contact_domain( domain ) ) {
903 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
904 domain->name));
906 /* Tell the cache manager not to remember this one */
908 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
911 rc = ads_cached_connection(domain, &ads);
912 if (!ADS_ERR_OK(rc)) {
913 domain->last_status = NT_STATUS_SERVER_DISABLED;
914 status = NT_STATUS_SERVER_DISABLED;
915 goto done;
918 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
920 if (!ADS_ERR_OK(rc)) {
921 status = ads_ntstatus(rc);
922 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
923 "%s\n",
924 dom_sid_str_buf(sid, &buf),
925 ads_errstr(rc)));
926 goto done;
929 count = ads_count_replies(ads, msg);
930 if (count != 1) {
931 status = NT_STATUS_UNSUCCESSFUL;
932 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
933 "invalid number of results (count=%d)\n",
934 dom_sid_str_buf(sid, &buf),
935 count));
936 goto done;
939 if (!msg) {
940 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
941 dom_sid_str_buf(sid, &buf)));
942 status = NT_STATUS_UNSUCCESSFUL;
943 goto done;
946 user_dn = ads_get_dn(ads, mem_ctx, msg);
947 if (user_dn == NULL) {
948 status = NT_STATUS_NO_MEMORY;
949 goto done;
952 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
953 DEBUG(1,("%s: No primary group for sid=%s !?\n",
954 domain->name,
955 dom_sid_str_buf(sid, &buf)));
956 goto done;
959 sid_compose(&primary_group, &domain->sid, primary_group_rid);
961 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
963 /* there must always be at least one group in the token,
964 unless we are talking to a buggy Win2k server */
966 /* actually this only happens when the machine account has no read
967 * permissions on the tokenGroup attribute - gd */
969 if (count == 0) {
971 /* no tokenGroups */
973 /* lookup what groups this user is a member of by DN search on
974 * "memberOf" */
976 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
977 &primary_group,
978 &num_groups, user_sids);
979 *p_num_groups = num_groups;
980 if (NT_STATUS_IS_OK(status)) {
981 goto done;
984 /* lookup what groups this user is a member of by DN search on
985 * "member" */
987 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
988 &primary_group,
989 &num_groups, user_sids);
990 *p_num_groups = num_groups;
991 goto done;
994 *user_sids = NULL;
995 num_groups = 0;
997 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
998 &num_groups);
999 if (!NT_STATUS_IS_OK(status)) {
1000 goto done;
1003 for (i=0;i<count;i++) {
1005 /* ignore Builtin groups from ADS - Guenther */
1006 if (sid_check_is_in_builtin(&sids[i])) {
1007 continue;
1010 status = add_sid_to_array_unique(mem_ctx, &sids[i],
1011 user_sids, &num_groups);
1012 if (!NT_STATUS_IS_OK(status)) {
1013 goto done;
1017 *p_num_groups = (uint32_t)num_groups;
1018 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1020 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1021 dom_sid_str_buf(sid, &buf)));
1022 done:
1023 TALLOC_FREE(user_dn);
1024 ads_msgfree(ads, msg);
1025 return status;
1028 /* Lookup aliases a user is member of - use rpc methods */
1029 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1030 TALLOC_CTX *mem_ctx,
1031 uint32_t num_sids, const struct dom_sid *sids,
1032 uint32_t *num_aliases, uint32_t **alias_rids)
1034 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
1035 num_aliases, alias_rids);
1038 static NTSTATUS add_primary_group_members(
1039 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
1040 char ***all_members, size_t *num_all_members)
1042 char *filter;
1043 NTSTATUS status = NT_STATUS_NO_MEMORY;
1044 ADS_STATUS rc;
1045 const char *attrs[] = { "dn", NULL };
1046 LDAPMessage *res = NULL;
1047 LDAPMessage *msg;
1048 char **members;
1049 size_t num_members;
1050 ads_control args;
1052 filter = talloc_asprintf(
1053 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1054 (unsigned)rid);
1055 if (filter == NULL) {
1056 goto done;
1059 args.control = ADS_EXTENDED_DN_OID;
1060 args.val = ADS_EXTENDED_DN_HEX_STRING;
1061 args.critical = True;
1063 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1064 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1065 &res);
1067 if (!ADS_ERR_OK(rc)) {
1068 status = ads_ntstatus(rc);
1069 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1070 goto done;
1072 if (res == NULL) {
1073 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1074 goto done;
1077 num_members = ads_count_replies(ads, res);
1079 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1080 (uintmax_t)num_members));
1082 if (num_members == 0) {
1083 status = NT_STATUS_OK;
1084 goto done;
1087 members = talloc_realloc(mem_ctx, *all_members, char *,
1088 *num_all_members + num_members);
1089 if (members == NULL) {
1090 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1091 goto done;
1093 *all_members = members;
1095 for (msg = ads_first_entry(ads, res); msg != NULL;
1096 msg = ads_next_entry(ads, msg)) {
1097 char *dn;
1099 dn = ads_get_dn(ads, members, msg);
1100 if (dn == NULL) {
1101 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1102 continue;
1105 members[*num_all_members] = dn;
1106 *num_all_members += 1;
1109 status = NT_STATUS_OK;
1110 done:
1111 if (res != NULL) {
1112 ads_msgfree(ads, res);
1114 TALLOC_FREE(filter);
1115 return status;
1119 find the members of a group, given a group rid and domain
1121 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1122 TALLOC_CTX *mem_ctx,
1123 const struct dom_sid *group_sid,
1124 enum lsa_SidType type,
1125 uint32_t *num_names,
1126 struct dom_sid **sid_mem, char ***names,
1127 uint32_t **name_types)
1129 ADS_STATUS rc;
1130 ADS_STRUCT *ads = NULL;
1131 char *ldap_exp;
1132 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1133 char *sidbinstr;
1134 char **members = NULL;
1135 size_t i;
1136 size_t num_members = 0;
1137 ads_control args;
1138 struct dom_sid *sid_mem_nocache = NULL;
1139 char **names_nocache = NULL;
1140 enum lsa_SidType *name_types_nocache = NULL;
1141 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1142 uint32_t num_nocache = 0;
1143 TALLOC_CTX *tmp_ctx = NULL;
1144 uint32_t rid;
1145 struct dom_sid_buf buf;
1147 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1148 dom_sid_str_buf(group_sid, &buf)));
1150 *num_names = 0;
1152 tmp_ctx = talloc_new(mem_ctx);
1153 if (!tmp_ctx) {
1154 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1155 status = NT_STATUS_NO_MEMORY;
1156 goto done;
1159 if (!sid_peek_rid(group_sid, &rid)) {
1160 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1161 status = NT_STATUS_INVALID_PARAMETER;
1162 goto done;
1165 if ( !winbindd_can_contact_domain( domain ) ) {
1166 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1167 domain->name));
1168 return NT_STATUS_OK;
1171 rc = ads_cached_connection(domain, &ads);
1172 if (!ADS_ERR_OK(rc)) {
1173 domain->last_status = NT_STATUS_SERVER_DISABLED;
1174 goto done;
1177 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1178 status = NT_STATUS_NO_MEMORY;
1179 goto done;
1182 /* search for all members of the group */
1183 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1184 TALLOC_FREE(sidbinstr);
1185 if (ldap_exp == NULL) {
1186 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1187 status = NT_STATUS_NO_MEMORY;
1188 goto done;
1191 args.control = ADS_EXTENDED_DN_OID;
1192 args.val = ADS_EXTENDED_DN_HEX_STRING;
1193 args.critical = True;
1195 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1196 ldap_exp, &args, "member", &members, &num_members);
1198 if (!ADS_ERR_OK(rc)) {
1199 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1200 status = NT_STATUS_UNSUCCESSFUL;
1201 goto done;
1204 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1206 status = add_primary_group_members(ads, mem_ctx, rid,
1207 &members, &num_members);
1208 if (!NT_STATUS_IS_OK(status)) {
1209 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1210 __func__, nt_errstr(status)));
1211 goto done;
1214 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1215 __func__, (int)num_members));
1217 /* Now that we have a list of sids, we need to get the
1218 * lists of names and name_types belonging to these sids.
1219 * even though conceptually not quite clean, we use the
1220 * RPC call lsa_lookup_sids for this since it can handle a
1221 * list of sids. ldap calls can just resolve one sid at a time.
1223 * At this stage, the sids are still hidden in the exetended dn
1224 * member output format. We actually do a little better than
1225 * stated above: In extracting the sids from the member strings,
1226 * we try to resolve as many sids as possible from the
1227 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1229 if (num_members) {
1230 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1231 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1232 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1233 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1235 if ((members == NULL) || (*sid_mem == NULL) ||
1236 (*names == NULL) || (*name_types == NULL) ||
1237 (sid_mem_nocache == NULL))
1239 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1240 status = NT_STATUS_NO_MEMORY;
1241 goto done;
1244 else {
1245 (*sid_mem) = NULL;
1246 (*names) = NULL;
1247 (*name_types) = NULL;
1250 for (i=0; i<num_members; i++) {
1251 enum lsa_SidType name_type;
1252 char *name, *domain_name;
1253 struct dom_sid sid;
1255 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1256 &sid);
1257 if (!ADS_ERR_OK(rc)) {
1258 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1259 NT_STATUS_NOT_FOUND)) {
1260 /* Group members can be objects, like Exchange
1261 * Public Folders, that don't have a SID. Skip
1262 * them. */
1263 continue;
1265 else {
1266 status = ads_ntstatus(rc);
1267 goto done;
1270 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1271 &name_type)) {
1272 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1273 "cache\n",
1274 dom_sid_str_buf(&sid, &buf)));
1275 sid_copy(&(*sid_mem)[*num_names], &sid);
1276 (*names)[*num_names] = fill_domain_username_talloc(
1277 *names,
1278 domain_name,
1279 name,
1280 true);
1282 (*name_types)[*num_names] = name_type;
1283 (*num_names)++;
1285 else {
1286 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1287 "cache\n",
1288 dom_sid_str_buf(&sid, &buf)));
1289 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1290 num_nocache++;
1294 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1295 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1297 /* handle sids not resolved from cache by lsa_lookup_sids */
1298 if (num_nocache > 0) {
1300 status = winbindd_lookup_sids(tmp_ctx,
1301 domain,
1302 num_nocache,
1303 sid_mem_nocache,
1304 &domains_nocache,
1305 &names_nocache,
1306 &name_types_nocache);
1308 if (!(NT_STATUS_IS_OK(status) ||
1309 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1310 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1312 DEBUG(1, ("lsa_lookupsids call failed with %s "
1313 "- retrying...\n", nt_errstr(status)));
1315 status = winbindd_lookup_sids(tmp_ctx,
1316 domain,
1317 num_nocache,
1318 sid_mem_nocache,
1319 &domains_nocache,
1320 &names_nocache,
1321 &name_types_nocache);
1324 if (NT_STATUS_IS_OK(status) ||
1325 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1327 /* Copy the entries over from the "_nocache" arrays
1328 * to the result arrays, skipping the gaps the
1329 * lookup_sids call left. */
1330 for (i=0; i < num_nocache; i++) {
1331 if (((names_nocache)[i] != NULL) &&
1332 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1334 sid_copy(&(*sid_mem)[*num_names],
1335 &sid_mem_nocache[i]);
1336 (*names)[*num_names] =
1337 fill_domain_username_talloc(
1338 *names,
1339 domains_nocache[i],
1340 names_nocache[i],
1341 true);
1342 (*name_types)[*num_names] = name_types_nocache[i];
1343 (*num_names)++;
1347 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1348 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1349 "not map any SIDs at all.\n"));
1350 /* Don't handle this as an error here.
1351 * There is nothing left to do with respect to the
1352 * overall result... */
1354 else if (!NT_STATUS_IS_OK(status)) {
1355 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1356 "sids via rpc_lsa_lookup_sids: %s\n",
1357 (int)num_members, nt_errstr(status)));
1358 goto done;
1362 status = NT_STATUS_OK;
1363 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1364 dom_sid_str_buf(group_sid, &buf)));
1366 done:
1368 TALLOC_FREE(tmp_ctx);
1370 return status;
1373 /* find the lockout policy of a domain - use rpc methods */
1374 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1375 TALLOC_CTX *mem_ctx,
1376 struct samr_DomInfo12 *policy)
1378 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1381 /* find the password policy of a domain - use rpc methods */
1382 static NTSTATUS password_policy(struct winbindd_domain *domain,
1383 TALLOC_CTX *mem_ctx,
1384 struct samr_DomInfo1 *policy)
1386 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1389 /* get a list of trusted domains */
1390 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1391 TALLOC_CTX *mem_ctx,
1392 struct netr_DomainTrustList *trusts)
1394 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1395 WERROR werr;
1396 uint32_t i;
1397 uint32_t flags;
1398 struct rpc_pipe_client *cli;
1399 struct dcerpc_binding_handle *b;
1401 DEBUG(3,("ads: trusted_domains\n"));
1403 ZERO_STRUCTP(trusts);
1405 /* If this is our primary domain or a root in our forest,
1406 query for all trusts. If not, then just look for domain
1407 trusts in the target forest */
1409 if (domain->primary || domain_is_forest_root(domain)) {
1410 flags = NETR_TRUST_FLAG_OUTBOUND |
1411 NETR_TRUST_FLAG_INBOUND |
1412 NETR_TRUST_FLAG_IN_FOREST;
1413 } else {
1414 flags = NETR_TRUST_FLAG_IN_FOREST;
1417 result = cm_connect_netlogon(domain, &cli);
1419 if (!NT_STATUS_IS_OK(result)) {
1420 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1421 "for PIPE_NETLOGON (%s)\n",
1422 domain->name, nt_errstr(result)));
1423 return NT_STATUS_UNSUCCESSFUL;
1426 b = cli->binding_handle;
1428 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1429 cli->desthost,
1430 flags,
1431 trusts,
1432 &werr);
1433 if (!NT_STATUS_IS_OK(result)) {
1434 return result;
1437 if (!W_ERROR_IS_OK(werr)) {
1438 return werror_to_ntstatus(werr);
1440 if (trusts->count == 0) {
1441 return NT_STATUS_OK;
1444 /* Copy across names and sids */
1446 for (i = 0; i < trusts->count; i++) {
1447 struct netr_DomainTrust *trust = &trusts->array[i];
1448 struct winbindd_domain d;
1450 ZERO_STRUCT(d);
1453 * drop external trusts if this is not our primary
1454 * domain. This means that the returned number of
1455 * domains may be less that the ones actually trusted
1456 * by the DC.
1459 if ((trust->trust_attributes
1460 & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1461 !domain->primary )
1463 DEBUG(10,("trusted_domains: Skipping external trusted "
1464 "domain %s because it is outside of our "
1465 "primary domain\n",
1466 trust->netbios_name));
1467 continue;
1470 /* add to the trusted domain cache */
1472 d.name = discard_const_p(char, trust->netbios_name);
1473 d.alt_name = discard_const_p(char, trust->dns_name);
1475 if (trust->sid) {
1476 sid_copy(&d.sid, trust->sid);
1477 } else {
1478 sid_copy(&d.sid, &global_sid_NULL);
1481 if ( domain->primary ) {
1482 DEBUG(10,("trusted_domains(ads): Searching "
1483 "trusted domain list of %s and storing "
1484 "trust flags for domain %s\n",
1485 domain->name, d.alt_name));
1487 d.domain_flags = trust->trust_flags;
1488 d.domain_type = trust->trust_type;
1489 d.domain_trust_attribs = trust->trust_attributes;
1491 wcache_tdc_add_domain( &d );
1492 } else if (domain_is_forest_root(domain)) {
1493 /* Check if we already have this record. If
1494 * we are following our forest root that is not
1495 * our primary domain, we want to keep trust
1496 * flags from the perspective of our primary
1497 * domain not our forest root. */
1498 struct winbindd_tdc_domain *exist = NULL;
1500 exist = wcache_tdc_fetch_domain(
1501 talloc_tos(), trust->netbios_name);
1502 if (!exist) {
1503 DEBUG(10,("trusted_domains(ads): Searching "
1504 "trusted domain list of %s and "
1505 "storing trust flags for domain "
1506 "%s\n", domain->name, d.alt_name));
1507 d.domain_flags = trust->trust_flags;
1508 d.domain_type = trust->trust_type;
1509 d.domain_trust_attribs =
1510 trust->trust_attributes;
1512 wcache_tdc_add_domain( &d );
1514 TALLOC_FREE(exist);
1515 } else {
1516 /* This gets a little tricky. If we are
1517 following a transitive forest trust, then
1518 innerit the flags, type, and attribs from
1519 the domain we queried to make sure we don't
1520 record the view of the trust from the wrong
1521 side. Always view it from the side of our
1522 primary domain. --jerry */
1523 struct winbindd_tdc_domain *parent = NULL;
1525 DEBUG(10,("trusted_domains(ads): Searching "
1526 "trusted domain list of %s and inheriting "
1527 "trust flags for domain %s\n",
1528 domain->name, d.alt_name));
1530 parent = wcache_tdc_fetch_domain(talloc_tos(),
1531 domain->name);
1532 if (parent) {
1533 d.domain_flags = parent->trust_flags;
1534 d.domain_type = parent->trust_type;
1535 d.domain_trust_attribs = parent->trust_attribs;
1536 } else {
1537 d.domain_flags = domain->domain_flags;
1538 d.domain_type = domain->domain_type;
1539 d.domain_trust_attribs =
1540 domain->domain_trust_attribs;
1542 TALLOC_FREE(parent);
1545 * We need to pass the modified properties
1546 * to the caller.
1548 trust->trust_flags = d.domain_flags;
1549 trust->trust_type = d.domain_type;
1550 trust->trust_attributes = d.domain_trust_attribs;
1552 wcache_tdc_add_domain( &d );
1555 return result;
1558 /* the ADS backend methods are exposed via this structure */
1559 struct winbindd_methods ads_methods = {
1560 True,
1561 query_user_list,
1562 enum_dom_groups,
1563 enum_local_groups,
1564 name_to_sid,
1565 sid_to_name,
1566 rids_to_names,
1567 lookup_usergroups,
1568 lookup_useraliases,
1569 lookup_groupmem,
1570 lockout_policy,
1571 password_policy,
1572 trusted_domains,
1575 #endif