smbXsrv_session: Remove a "can't happen" NULL check
[Samba.git] / source3 / winbindd / winbindd_ads.c
blob7d6324033ea2f0b8980cea7cb8fd58206dbce952
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 account 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 name 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;
452 } else {
453 TALLOC_FREE(rids);
456 status = NT_STATUS_OK;
458 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
460 done:
461 ads_msgfree(ads, res);
462 return status;
465 /* list all domain groups */
466 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
467 TALLOC_CTX *mem_ctx,
468 uint32_t *num_entries,
469 struct wb_acct_info **info)
471 ADS_STRUCT *ads = NULL;
472 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
473 "name", "objectSid", NULL};
474 int i, count;
475 ADS_STATUS rc;
476 LDAPMessage *res = NULL;
477 LDAPMessage *msg = NULL;
478 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
479 const char *filter;
480 bool enum_dom_local_groups = False;
482 *num_entries = 0;
484 DEBUG(3,("ads: enum_dom_groups\n"));
486 if ( !winbindd_can_contact_domain( domain ) ) {
487 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
488 domain->name));
489 return NT_STATUS_OK;
492 /* only grab domain local groups for our domain */
493 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
494 enum_dom_local_groups = True;
497 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
498 * rollup-fixes:
500 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
501 * default value, it MUST be absent. In case of extensible matching the
502 * "dnattr" boolean defaults to FALSE and so it must be only be present
503 * when set to TRUE.
505 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
506 * filter using bitwise matching rule then the buggy AD fails to decode
507 * the extensible match. As a workaround set it to TRUE and thereby add
508 * the dnAttributes "dn" field to cope with those older AD versions.
509 * It should not harm and won't put any additional load on the AD since
510 * none of the dn components have a bitmask-attribute.
512 * Thanks to Ralf Haferkamp for input and testing - Guenther */
514 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)"
515 "(&(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d)"
516 "(!(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))))",
517 GROUP_TYPE_SECURITY_ENABLED,
518 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
520 if (filter == NULL) {
521 status = NT_STATUS_NO_MEMORY;
522 goto done;
525 rc = ads_cached_connection(domain, &ads);
526 if (!ADS_ERR_OK(rc)) {
527 domain->last_status = NT_STATUS_SERVER_DISABLED;
528 goto done;
531 rc = ads_search_retry(ads, &res, filter, attrs);
532 if (!ADS_ERR_OK(rc)) {
533 status = ads_ntstatus(rc);
534 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
535 goto done;
536 } else if (!res) {
537 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
538 goto done;
541 count = ads_count_replies(ads, res);
542 if (count == 0) {
543 DEBUG(1,("enum_dom_groups: No groups found\n"));
544 goto done;
547 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
548 if (!*info) {
549 status = NT_STATUS_NO_MEMORY;
550 goto done;
553 i = 0;
555 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
556 char *name, *gecos;
557 struct dom_sid sid;
558 uint32_t rid;
560 name = ads_pull_username(ads, (*info), msg);
561 gecos = ads_pull_string(ads, (*info), msg, "name");
562 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
563 DEBUG(1,("No sid for %s !?\n", name));
564 continue;
567 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
568 DEBUG(1,("No rid for %s !?\n", name));
569 continue;
572 (*info)[i].acct_name = name;
573 (*info)[i].acct_desc = gecos;
574 (*info)[i].rid = rid;
575 i++;
578 (*num_entries) = i;
580 status = NT_STATUS_OK;
582 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
584 done:
585 if (res)
586 ads_msgfree(ads, res);
588 return status;
591 /* list all domain local groups */
592 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
593 TALLOC_CTX *mem_ctx,
594 uint32_t *num_entries,
595 struct wb_acct_info **info)
598 * This is a stub function only as we returned the domain
599 * local groups in enum_dom_groups() if the domain->native field
600 * was true. This is a simple performance optimization when
601 * using LDAP.
603 * if we ever need to enumerate domain local groups separately,
604 * then this optimization in enum_dom_groups() will need
605 * to be split out
607 *num_entries = 0;
609 return NT_STATUS_OK;
612 /* convert a single name to a sid in a domain - use rpc methods */
613 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
614 TALLOC_CTX *mem_ctx,
615 const char *domain_name,
616 const char *name,
617 uint32_t flags,
618 const char **pdom_name,
619 struct dom_sid *sid,
620 enum lsa_SidType *type)
622 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
623 flags, pdom_name, sid, type);
626 /* convert a domain SID to a user or group name - use rpc methods */
627 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
628 TALLOC_CTX *mem_ctx,
629 const struct dom_sid *sid,
630 char **domain_name,
631 char **name,
632 enum lsa_SidType *type)
634 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
635 domain_name, name, type);
638 /* convert a list of rids to names - use rpc methods */
639 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
640 TALLOC_CTX *mem_ctx,
641 const struct dom_sid *sid,
642 uint32_t *rids,
643 size_t num_rids,
644 char **domain_name,
645 char ***names,
646 enum lsa_SidType **types)
648 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
649 rids, num_rids,
650 domain_name, names, types);
653 /* Lookup groups a user is a member of - alternate method, for when
654 tokenGroups are not available. */
655 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
656 TALLOC_CTX *mem_ctx,
657 const char *user_dn,
658 struct dom_sid *primary_group,
659 uint32_t *p_num_groups, struct dom_sid **user_sids)
661 ADS_STATUS rc;
662 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
663 int count;
664 LDAPMessage *res = NULL;
665 LDAPMessage *msg = NULL;
666 char *ldap_exp;
667 ADS_STRUCT *ads = NULL;
668 const char *group_attrs[] = {"objectSid", NULL};
669 char *escaped_dn;
670 uint32_t num_groups = 0;
672 DEBUG(3,("ads: lookup_usergroups_member\n"));
674 if ( !winbindd_can_contact_domain( domain ) ) {
675 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
676 domain->name));
677 return NT_STATUS_OK;
680 rc = ads_cached_connection(domain, &ads);
681 if (!ADS_ERR_OK(rc)) {
682 domain->last_status = NT_STATUS_SERVER_DISABLED;
683 goto done;
686 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
687 status = NT_STATUS_NO_MEMORY;
688 goto done;
691 ldap_exp = talloc_asprintf(mem_ctx,
692 "(&(member=%s)(objectCategory=group)"
693 "(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))",
694 escaped_dn,
695 GROUP_TYPE_SECURITY_ENABLED);
696 if (!ldap_exp) {
697 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
698 TALLOC_FREE(escaped_dn);
699 status = NT_STATUS_NO_MEMORY;
700 goto done;
703 TALLOC_FREE(escaped_dn);
705 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
707 if (!ADS_ERR_OK(rc)) {
708 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
709 return ads_ntstatus(rc);
710 } else if (!res) {
711 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
712 return NT_STATUS_INTERNAL_ERROR;
716 count = ads_count_replies(ads, res);
718 *user_sids = NULL;
719 num_groups = 0;
721 /* always add the primary group to the sid array */
722 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
723 &num_groups);
724 if (!NT_STATUS_IS_OK(status)) {
725 goto done;
728 if (count > 0) {
729 for (msg = ads_first_entry(ads, res); msg;
730 msg = ads_next_entry(ads, msg)) {
731 struct dom_sid group_sid;
733 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
734 DEBUG(1,("No sid for this group ?!?\n"));
735 continue;
738 /* ignore Builtin groups from ADS - Guenther */
739 if (sid_check_is_in_builtin(&group_sid)) {
740 continue;
743 status = add_sid_to_array(mem_ctx, &group_sid,
744 user_sids, &num_groups);
745 if (!NT_STATUS_IS_OK(status)) {
746 goto done;
752 *p_num_groups = num_groups;
753 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
755 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
756 done:
757 if (res)
758 ads_msgfree(ads, res);
760 return status;
763 /* Lookup groups a user is a member of - alternate method, for when
764 tokenGroups are not available. */
765 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
766 TALLOC_CTX *mem_ctx,
767 const char *user_dn,
768 struct dom_sid *primary_group,
769 uint32_t *p_num_groups,
770 struct dom_sid **user_sids)
772 ADS_STATUS rc;
773 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
774 ADS_STRUCT *ads = NULL;
775 const char *attrs[] = {"memberOf", NULL};
776 uint32_t num_groups = 0;
777 struct dom_sid *group_sids = NULL;
778 size_t i;
779 char **strings = NULL;
780 size_t num_strings = 0, num_sids = 0;
783 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
785 if ( !winbindd_can_contact_domain( domain ) ) {
786 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
787 "domain %s\n", domain->name));
788 return NT_STATUS_OK;
791 rc = ads_cached_connection(domain, &ads);
792 if (!ADS_ERR_OK(rc)) {
793 domain->last_status = NT_STATUS_SERVER_DISABLED;
794 return NT_STATUS_UNSUCCESSFUL;
797 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
798 ADS_EXTENDED_DN_HEX_STRING,
799 &strings, &num_strings);
801 if (!ADS_ERR_OK(rc)) {
802 DEBUG(1,("lookup_usergroups_memberof ads_search "
803 "member=%s: %s\n", user_dn, ads_errstr(rc)));
804 return ads_ntstatus(rc);
807 *user_sids = NULL;
808 num_groups = 0;
810 /* always add the primary group to the sid array */
811 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
812 &num_groups);
813 if (!NT_STATUS_IS_OK(status)) {
814 goto done;
817 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
818 if (!group_sids) {
819 status = NT_STATUS_NO_MEMORY;
820 goto done;
823 for (i=0; i<num_strings; i++) {
824 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
825 ADS_EXTENDED_DN_HEX_STRING,
826 &(group_sids)[i]);
827 if (!ADS_ERR_OK(rc)) {
828 /* ignore members without SIDs */
829 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
830 NT_STATUS_NOT_FOUND)) {
831 continue;
833 else {
834 status = ads_ntstatus(rc);
835 goto done;
838 num_sids++;
841 if (i == 0) {
842 DEBUG(1,("No memberOf for this user?!?\n"));
843 status = NT_STATUS_NO_MEMORY;
844 goto done;
847 for (i=0; i<num_sids; i++) {
849 /* ignore Builtin groups from ADS - Guenther */
850 if (sid_check_is_in_builtin(&group_sids[i])) {
851 continue;
854 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
855 &num_groups);
856 if (!NT_STATUS_IS_OK(status)) {
857 goto done;
862 *p_num_groups = num_groups;
863 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
865 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
866 user_dn));
868 done:
869 TALLOC_FREE(strings);
870 TALLOC_FREE(group_sids);
872 return status;
876 /* Lookup groups a user is a member of. */
877 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
878 TALLOC_CTX *mem_ctx,
879 const struct dom_sid *sid,
880 uint32_t *p_num_groups, struct dom_sid **user_sids)
882 ADS_STRUCT *ads = NULL;
883 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
884 ADS_STATUS rc;
885 int count;
886 LDAPMessage *msg = NULL;
887 char *user_dn = NULL;
888 struct dom_sid *sids;
889 int i;
890 struct dom_sid primary_group;
891 uint32_t primary_group_rid;
892 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
893 uint32_t num_groups = 0;
894 struct dom_sid_buf buf;
896 DEBUG(3,("ads: lookup_usergroups\n"));
897 *p_num_groups = 0;
899 status = lookup_usergroups_cached(mem_ctx, sid,
900 p_num_groups, user_sids);
901 if (NT_STATUS_IS_OK(status)) {
902 return NT_STATUS_OK;
905 if ( !winbindd_can_contact_domain( domain ) ) {
906 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
907 domain->name));
909 /* Tell the cache manager not to remember this one */
911 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
914 rc = ads_cached_connection(domain, &ads);
915 if (!ADS_ERR_OK(rc)) {
916 domain->last_status = NT_STATUS_SERVER_DISABLED;
917 status = NT_STATUS_SERVER_DISABLED;
918 goto done;
921 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
923 if (!ADS_ERR_OK(rc)) {
924 status = ads_ntstatus(rc);
925 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
926 "%s\n",
927 dom_sid_str_buf(sid, &buf),
928 ads_errstr(rc)));
929 goto done;
932 count = ads_count_replies(ads, msg);
933 if (count != 1) {
934 status = NT_STATUS_UNSUCCESSFUL;
935 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
936 "invalid number of results (count=%d)\n",
937 dom_sid_str_buf(sid, &buf),
938 count));
939 goto done;
942 if (!msg) {
943 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
944 dom_sid_str_buf(sid, &buf)));
945 status = NT_STATUS_UNSUCCESSFUL;
946 goto done;
949 user_dn = ads_get_dn(ads, mem_ctx, msg);
950 if (user_dn == NULL) {
951 status = NT_STATUS_NO_MEMORY;
952 goto done;
955 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
956 DEBUG(1,("%s: No primary group for sid=%s !?\n",
957 domain->name,
958 dom_sid_str_buf(sid, &buf)));
959 goto done;
962 sid_compose(&primary_group, &domain->sid, primary_group_rid);
964 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
966 /* there must always be at least one group in the token,
967 unless we are talking to a buggy Win2k server */
969 /* actually this only happens when the machine account has no read
970 * permissions on the tokenGroup attribute - gd */
972 if (count == 0) {
974 /* no tokenGroups */
976 /* lookup what groups this user is a member of by DN search on
977 * "memberOf" */
979 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
980 &primary_group,
981 &num_groups, user_sids);
982 *p_num_groups = num_groups;
983 if (NT_STATUS_IS_OK(status)) {
984 goto done;
987 /* lookup what groups this user is a member of by DN search on
988 * "member" */
990 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
991 &primary_group,
992 &num_groups, user_sids);
993 *p_num_groups = num_groups;
994 goto done;
997 *user_sids = NULL;
998 num_groups = 0;
1000 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
1001 &num_groups);
1002 if (!NT_STATUS_IS_OK(status)) {
1003 goto done;
1006 for (i=0;i<count;i++) {
1008 /* ignore Builtin groups from ADS - Guenther */
1009 if (sid_check_is_in_builtin(&sids[i])) {
1010 continue;
1013 status = add_sid_to_array_unique(mem_ctx, &sids[i],
1014 user_sids, &num_groups);
1015 if (!NT_STATUS_IS_OK(status)) {
1016 goto done;
1020 *p_num_groups = (uint32_t)num_groups;
1021 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1023 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1024 dom_sid_str_buf(sid, &buf)));
1025 done:
1026 TALLOC_FREE(user_dn);
1027 ads_msgfree(ads, msg);
1028 return status;
1031 /* Lookup aliases a user is member of - use rpc methods */
1032 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1033 TALLOC_CTX *mem_ctx,
1034 uint32_t num_sids, const struct dom_sid *sids,
1035 uint32_t *num_aliases, uint32_t **alias_rids)
1037 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
1038 num_aliases, alias_rids);
1041 static NTSTATUS add_primary_group_members(
1042 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid, const char *domname,
1043 char ***all_members, size_t *num_all_members)
1045 char *filter;
1046 NTSTATUS status = NT_STATUS_NO_MEMORY;
1047 ADS_STATUS rc;
1048 const char *attrs[] = { "dn", NULL };
1049 LDAPMessage *res = NULL;
1050 LDAPMessage *msg;
1051 char **members;
1052 size_t num_members;
1053 ads_control args;
1054 bool all_groupmem = idmap_config_bool(domname, "all_groupmem", false);
1056 filter = talloc_asprintf(
1057 mem_ctx,
1058 "(&(objectCategory=user)(primaryGroupID=%u)%s)",
1059 (unsigned)rid,
1060 all_groupmem ? "" : "(uidNumber=*)(!(uidNumber=0))");
1061 if (filter == NULL) {
1062 goto done;
1065 args.control = ADS_EXTENDED_DN_OID;
1066 args.val = ADS_EXTENDED_DN_HEX_STRING;
1067 args.critical = True;
1069 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1070 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1071 &res);
1073 if (!ADS_ERR_OK(rc)) {
1074 status = ads_ntstatus(rc);
1075 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1076 goto done;
1078 if (res == NULL) {
1079 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1080 goto done;
1083 num_members = ads_count_replies(ads, res);
1085 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1086 (uintmax_t)num_members));
1088 if (num_members == 0) {
1089 status = NT_STATUS_OK;
1090 goto done;
1093 members = talloc_realloc(mem_ctx, *all_members, char *,
1094 *num_all_members + num_members);
1095 if (members == NULL) {
1096 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1097 goto done;
1099 *all_members = members;
1101 for (msg = ads_first_entry(ads, res); msg != NULL;
1102 msg = ads_next_entry(ads, msg)) {
1103 char *dn;
1105 dn = ads_get_dn(ads, members, msg);
1106 if (dn == NULL) {
1107 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1108 continue;
1111 members[*num_all_members] = dn;
1112 *num_all_members += 1;
1115 status = NT_STATUS_OK;
1116 done:
1117 if (res != NULL) {
1118 ads_msgfree(ads, res);
1120 TALLOC_FREE(filter);
1121 return status;
1125 find the members of a group, given a group rid and domain
1127 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1128 TALLOC_CTX *mem_ctx,
1129 const struct dom_sid *group_sid,
1130 enum lsa_SidType type,
1131 uint32_t *num_names,
1132 struct dom_sid **sid_mem, char ***names,
1133 uint32_t **name_types)
1135 ADS_STATUS rc;
1136 ADS_STRUCT *ads = NULL;
1137 char *ldap_exp;
1138 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1139 char *sidbinstr;
1140 char **members = NULL;
1141 size_t i;
1142 size_t num_members = 0;
1143 ads_control args;
1144 struct dom_sid *sid_mem_nocache = NULL;
1145 char **names_nocache = NULL;
1146 enum lsa_SidType *name_types_nocache = NULL;
1147 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1148 uint32_t num_nocache = 0;
1149 TALLOC_CTX *tmp_ctx = NULL;
1150 uint32_t rid;
1151 struct dom_sid_buf buf;
1153 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1154 dom_sid_str_buf(group_sid, &buf)));
1156 *num_names = 0;
1158 tmp_ctx = talloc_new(mem_ctx);
1159 if (!tmp_ctx) {
1160 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1161 status = NT_STATUS_NO_MEMORY;
1162 goto done;
1165 if (!sid_peek_rid(group_sid, &rid)) {
1166 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1167 status = NT_STATUS_INVALID_PARAMETER;
1168 goto done;
1171 if ( !winbindd_can_contact_domain( domain ) ) {
1172 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1173 domain->name));
1174 return NT_STATUS_OK;
1177 rc = ads_cached_connection(domain, &ads);
1178 if (!ADS_ERR_OK(rc)) {
1179 domain->last_status = NT_STATUS_SERVER_DISABLED;
1180 goto done;
1183 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1184 status = NT_STATUS_NO_MEMORY;
1185 goto done;
1188 /* search for all members of the group */
1189 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1190 TALLOC_FREE(sidbinstr);
1191 if (ldap_exp == NULL) {
1192 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1193 status = NT_STATUS_NO_MEMORY;
1194 goto done;
1197 args.control = ADS_EXTENDED_DN_OID;
1198 args.val = ADS_EXTENDED_DN_HEX_STRING;
1199 args.critical = True;
1201 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1202 ldap_exp, &args, "member", &members, &num_members);
1204 if (!ADS_ERR_OK(rc)) {
1205 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1206 status = NT_STATUS_UNSUCCESSFUL;
1207 goto done;
1210 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1212 status = add_primary_group_members(ads, mem_ctx, rid, domain->name,
1213 &members, &num_members);
1214 if (!NT_STATUS_IS_OK(status)) {
1215 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1216 __func__, nt_errstr(status)));
1217 goto done;
1220 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1221 __func__, (int)num_members));
1223 /* Now that we have a list of sids, we need to get the
1224 * lists of names and name_types belonging to these sids.
1225 * even though conceptually not quite clean, we use the
1226 * RPC call lsa_lookup_sids for this since it can handle a
1227 * list of sids. ldap calls can just resolve one sid at a time.
1229 * At this stage, the sids are still hidden in the exetended dn
1230 * member output format. We actually do a little better than
1231 * stated above: In extracting the sids from the member strings,
1232 * we try to resolve as many sids as possible from the
1233 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1235 if (num_members) {
1236 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1237 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1238 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1239 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1241 if ((members == NULL) || (*sid_mem == NULL) ||
1242 (*names == NULL) || (*name_types == NULL) ||
1243 (sid_mem_nocache == NULL))
1245 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1246 status = NT_STATUS_NO_MEMORY;
1247 goto done;
1250 else {
1251 (*sid_mem) = NULL;
1252 (*names) = NULL;
1253 (*name_types) = NULL;
1256 for (i=0; i<num_members; i++) {
1257 enum lsa_SidType name_type;
1258 char *name, *domain_name;
1259 struct dom_sid sid;
1261 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1262 &sid);
1263 if (!ADS_ERR_OK(rc)) {
1264 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1265 NT_STATUS_NOT_FOUND)) {
1266 /* Group members can be objects, like Exchange
1267 * Public Folders, that don't have a SID. Skip
1268 * them. */
1269 continue;
1271 else {
1272 status = ads_ntstatus(rc);
1273 goto done;
1276 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1277 &name_type)) {
1278 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1279 "cache\n",
1280 dom_sid_str_buf(&sid, &buf)));
1281 sid_copy(&(*sid_mem)[*num_names], &sid);
1282 (*names)[*num_names] = fill_domain_username_talloc(
1283 *names,
1284 domain_name,
1285 name,
1286 true);
1288 (*name_types)[*num_names] = name_type;
1289 (*num_names)++;
1291 else {
1292 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1293 "cache\n",
1294 dom_sid_str_buf(&sid, &buf)));
1295 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1296 num_nocache++;
1300 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1301 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1303 /* handle sids not resolved from cache by lsa_lookup_sids */
1304 if (num_nocache > 0) {
1306 status = winbindd_lookup_sids(tmp_ctx,
1307 domain,
1308 num_nocache,
1309 sid_mem_nocache,
1310 &domains_nocache,
1311 &names_nocache,
1312 &name_types_nocache);
1314 if (!(NT_STATUS_IS_OK(status) ||
1315 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1316 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1318 DEBUG(1, ("lsa_lookupsids call failed with %s "
1319 "- retrying...\n", nt_errstr(status)));
1321 status = winbindd_lookup_sids(tmp_ctx,
1322 domain,
1323 num_nocache,
1324 sid_mem_nocache,
1325 &domains_nocache,
1326 &names_nocache,
1327 &name_types_nocache);
1330 if (NT_STATUS_IS_OK(status) ||
1331 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1333 /* Copy the entries over from the "_nocache" arrays
1334 * to the result arrays, skipping the gaps the
1335 * lookup_sids call left. */
1336 for (i=0; i < num_nocache; i++) {
1337 if (((names_nocache)[i] != NULL) &&
1338 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1340 sid_copy(&(*sid_mem)[*num_names],
1341 &sid_mem_nocache[i]);
1342 (*names)[*num_names] =
1343 fill_domain_username_talloc(
1344 *names,
1345 domains_nocache[i],
1346 names_nocache[i],
1347 true);
1348 (*name_types)[*num_names] = name_types_nocache[i];
1349 (*num_names)++;
1353 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1354 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1355 "not map any SIDs at all.\n"));
1356 /* Don't handle this as an error here.
1357 * There is nothing left to do with respect to the
1358 * overall result... */
1360 else if (!NT_STATUS_IS_OK(status)) {
1361 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1362 "sids via rpc_lsa_lookup_sids: %s\n",
1363 (int)num_members, nt_errstr(status)));
1364 goto done;
1368 status = NT_STATUS_OK;
1369 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1370 dom_sid_str_buf(group_sid, &buf)));
1372 done:
1374 TALLOC_FREE(tmp_ctx);
1376 return status;
1379 static NTSTATUS lookup_aliasmem(struct winbindd_domain *domain,
1380 TALLOC_CTX *mem_ctx,
1381 const struct dom_sid *sid,
1382 enum lsa_SidType type,
1383 uint32_t *num_sids,
1384 struct dom_sid **sids)
1386 char **names = NULL;
1387 uint32_t *name_types = NULL;
1388 struct dom_sid_buf buf;
1390 DBG_DEBUG("ads: lookup_aliasmem %s sid=%s\n",
1391 domain->name,
1392 dom_sid_str_buf(sid, &buf));
1393 /* Search for alias and group membership uses the same LDAP command. */
1394 return lookup_groupmem(domain,
1395 mem_ctx,
1396 sid,
1397 type,
1398 num_sids,
1399 sids,
1400 &names,
1401 &name_types);
1404 /* find the lockout policy of a domain - use rpc methods */
1405 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1406 TALLOC_CTX *mem_ctx,
1407 struct samr_DomInfo12 *policy)
1409 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1412 /* find the password policy of a domain - use rpc methods */
1413 static NTSTATUS password_policy(struct winbindd_domain *domain,
1414 TALLOC_CTX *mem_ctx,
1415 struct samr_DomInfo1 *policy)
1417 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1420 /* get a list of trusted domains */
1421 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1422 TALLOC_CTX *mem_ctx,
1423 struct netr_DomainTrustList *trusts)
1425 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1426 WERROR werr;
1427 uint32_t i;
1428 uint32_t flags;
1429 struct rpc_pipe_client *cli;
1430 struct dcerpc_binding_handle *b;
1432 DEBUG(3,("ads: trusted_domains\n"));
1434 ZERO_STRUCTP(trusts);
1436 /* If this is our primary domain or a root in our forest,
1437 query for all trusts. If not, then just look for domain
1438 trusts in the target forest */
1440 if (domain->primary || domain_is_forest_root(domain)) {
1441 flags = NETR_TRUST_FLAG_OUTBOUND |
1442 NETR_TRUST_FLAG_INBOUND |
1443 NETR_TRUST_FLAG_IN_FOREST;
1444 } else {
1445 flags = NETR_TRUST_FLAG_IN_FOREST;
1448 result = cm_connect_netlogon(domain, &cli);
1450 if (!NT_STATUS_IS_OK(result)) {
1451 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1452 "for PIPE_NETLOGON (%s)\n",
1453 domain->name, nt_errstr(result)));
1454 return NT_STATUS_UNSUCCESSFUL;
1457 b = cli->binding_handle;
1459 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1460 cli->desthost,
1461 flags,
1462 trusts,
1463 &werr);
1464 if (!NT_STATUS_IS_OK(result)) {
1465 return result;
1468 if (!W_ERROR_IS_OK(werr)) {
1469 return werror_to_ntstatus(werr);
1471 if (trusts->count == 0) {
1472 return NT_STATUS_OK;
1475 /* Copy across names and sids */
1477 for (i = 0; i < trusts->count; i++) {
1478 struct netr_DomainTrust *trust = &trusts->array[i];
1479 struct winbindd_domain d;
1481 ZERO_STRUCT(d);
1484 * drop external trusts if this is not our primary
1485 * domain. This means that the returned number of
1486 * domains may be less that the ones actually trusted
1487 * by the DC.
1490 if ((trust->trust_attributes
1491 & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1492 !domain->primary )
1494 DEBUG(10,("trusted_domains: Skipping external trusted "
1495 "domain %s because it is outside of our "
1496 "primary domain\n",
1497 trust->netbios_name));
1498 continue;
1501 /* add to the trusted domain cache */
1503 d.name = discard_const_p(char, trust->netbios_name);
1504 d.alt_name = discard_const_p(char, trust->dns_name);
1506 if (trust->sid) {
1507 sid_copy(&d.sid, trust->sid);
1508 } else {
1509 sid_copy(&d.sid, &global_sid_NULL);
1512 if ( domain->primary ) {
1513 DEBUG(10,("trusted_domains(ads): Searching "
1514 "trusted domain list of %s and storing "
1515 "trust flags for domain %s\n",
1516 domain->name, d.alt_name));
1518 d.domain_flags = trust->trust_flags;
1519 d.domain_type = trust->trust_type;
1520 d.domain_trust_attribs = trust->trust_attributes;
1522 wcache_tdc_add_domain( &d );
1523 } else if (domain_is_forest_root(domain)) {
1524 /* Check if we already have this record. If
1525 * we are following our forest root that is not
1526 * our primary domain, we want to keep trust
1527 * flags from the perspective of our primary
1528 * domain not our forest root. */
1529 struct winbindd_tdc_domain *exist = NULL;
1531 exist = wcache_tdc_fetch_domain(
1532 talloc_tos(), trust->netbios_name);
1533 if (!exist) {
1534 DEBUG(10,("trusted_domains(ads): Searching "
1535 "trusted domain list of %s and "
1536 "storing trust flags for domain "
1537 "%s\n", domain->name, d.alt_name));
1538 d.domain_flags = trust->trust_flags;
1539 d.domain_type = trust->trust_type;
1540 d.domain_trust_attribs =
1541 trust->trust_attributes;
1543 wcache_tdc_add_domain( &d );
1545 TALLOC_FREE(exist);
1546 } else {
1547 /* This gets a little tricky. If we are
1548 following a transitive forest trust, then
1549 innerit the flags, type, and attribs from
1550 the domain we queried to make sure we don't
1551 record the view of the trust from the wrong
1552 side. Always view it from the side of our
1553 primary domain. --jerry */
1554 struct winbindd_tdc_domain *parent = NULL;
1556 DEBUG(10,("trusted_domains(ads): Searching "
1557 "trusted domain list of %s and inheriting "
1558 "trust flags for domain %s\n",
1559 domain->name, d.alt_name));
1561 parent = wcache_tdc_fetch_domain(talloc_tos(),
1562 domain->name);
1563 if (parent) {
1564 d.domain_flags = parent->trust_flags;
1565 d.domain_type = parent->trust_type;
1566 d.domain_trust_attribs = parent->trust_attribs;
1567 } else {
1568 d.domain_flags = domain->domain_flags;
1569 d.domain_type = domain->domain_type;
1570 d.domain_trust_attribs =
1571 domain->domain_trust_attribs;
1573 TALLOC_FREE(parent);
1576 * We need to pass the modified properties
1577 * to the caller.
1579 trust->trust_flags = d.domain_flags;
1580 trust->trust_type = d.domain_type;
1581 trust->trust_attributes = d.domain_trust_attribs;
1583 wcache_tdc_add_domain( &d );
1586 return result;
1589 /* the ADS backend methods are exposed via this structure */
1590 struct winbindd_methods ads_methods = {
1591 True,
1592 query_user_list,
1593 enum_dom_groups,
1594 enum_local_groups,
1595 name_to_sid,
1596 sid_to_name,
1597 rids_to_names,
1598 lookup_usergroups,
1599 lookup_useraliases,
1600 lookup_groupmem,
1601 lookup_aliasmem,
1602 lockout_policy,
1603 password_policy,
1604 trusted_domains,
1607 #endif