util:datablob: data_blob_pad checks its alignment assumption
[samba.git] / source3 / winbindd / winbindd_ads.c
blob90f1fbf15ff8f22c2e6a94e16d08fa883e2f0cbe
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 /**
48 * Check if cached connection can be reused. If the connection cannot
49 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
51 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
54 ADS_STRUCT *ads = *adsp;
56 if (ads != NULL) {
57 time_t expire;
58 time_t now = time(NULL);
60 expire = nt_time_to_unix(ads->auth.expire_time);
62 DBG_INFO("Current tickets expire in %" PRIu64 " seconds "
63 "(at %" PRIu64 ", time is now %" PRIu64 ")\n",
64 (uint64_t)expire - (uint64_t)now,
65 (uint64_t)expire,
66 (uint64_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 ads struct\n"));
73 TALLOC_FREE(ads);
74 *adsp = NULL;
80 static NTSTATUS ads_cached_connection_reconnect_creds(struct ads_struct *ads,
81 void *private_data,
82 TALLOC_CTX *mem_ctx,
83 struct cli_credentials **creds)
85 struct winbindd_domain *target_domain = NULL;
87 if (ads->server.realm != NULL) {
88 target_domain = find_domain_from_name_noinit(ads->server.realm);
90 if (target_domain == NULL && ads->server.workgroup != NULL) {
91 target_domain = find_domain_from_name_noinit(ads->server.workgroup);
94 if (target_domain == NULL) {
95 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
98 return winbindd_get_trust_credentials(target_domain,
99 mem_ctx,
100 false, /* netlogon */
101 false, /* ipc_fallback */
102 creds);
106 * @brief Establish a connection to a DC
108 * @param[out] adsp ADS_STRUCT that will be created
109 * @param[in] target_domain target domain
110 * @param[in] ldap_server DNS name of server to connect to
111 * @param[in] creds credentials to use
112 * @param[in] auth_realm Realm of local domain for creating krb token
114 * @return ADS_STATUS
116 static ADS_STATUS ads_cached_connection_connect(struct winbindd_domain *target_domain,
117 const char *ldap_server,
118 TALLOC_CTX *mem_ctx,
119 ADS_STRUCT **adsp)
121 TALLOC_CTX *tmp_ctx = talloc_stackframe();
122 const char *target_realm = target_domain->alt_name;
123 const char *target_dom_name = target_domain->name;
124 struct cli_credentials *creds = NULL;
125 ADS_STRUCT *ads;
126 ADS_STATUS status;
127 NTSTATUS ntstatus;
128 struct sockaddr_storage dc_ss;
129 fstring dc_name;
131 /* the machine acct password might have change - fetch it every time */
133 ntstatus = winbindd_get_trust_credentials(target_domain,
134 tmp_ctx,
135 false, /* netlogon */
136 false, /* ipc_fallback */
137 &creds);
138 if (!NT_STATUS_IS_OK(ntstatus)) {
139 status = ADS_ERROR_NT(ntstatus);
140 goto out;
143 ads = ads_init(tmp_ctx,
144 target_realm,
145 target_dom_name,
146 ldap_server,
147 ADS_SASL_SEAL);
148 if (!ads) {
149 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
150 status = ADS_ERROR(LDAP_NO_MEMORY);
151 goto out;
154 ads_set_reconnect_fn(ads, ads_cached_connection_reconnect_creds, NULL);
156 /* Setup the server affinity cache. We don't reaally care
157 about the name. Just setup affinity and the KRB5_CONFIG
158 file. */
159 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
161 status = ads_connect_creds(ads, creds);
162 if (!ADS_ERR_OK(status)) {
163 DEBUG(1,("ads_connect for domain %s failed: %s\n",
164 target_dom_name, ads_errstr(status)));
165 goto out;
168 *adsp = talloc_move(mem_ctx, &ads);
169 out:
170 TALLOC_FREE(tmp_ctx);
171 return status;
174 ADS_STATUS ads_idmap_cached_connection(const char *dom_name,
175 TALLOC_CTX *mem_ctx,
176 ADS_STRUCT **adsp)
178 TALLOC_CTX *tmp_ctx = talloc_stackframe();
179 char *ldap_server = NULL;
180 struct winbindd_domain *wb_dom = NULL;
181 ADS_STATUS status;
183 if (IS_AD_DC) {
185 * Make sure we never try to use LDAP against
186 * a trusted domain as AD DC.
188 TALLOC_FREE(tmp_ctx);
189 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
192 ads_cached_connection_reuse(adsp);
193 if (*adsp != NULL) {
194 TALLOC_FREE(tmp_ctx);
195 return ADS_SUCCESS;
199 * At this point we only have the NetBIOS domain name.
200 * Check if we can get server name and realm from SAF cache
201 * and the domain list.
203 ldap_server = saf_fetch(tmp_ctx, dom_name);
205 DBG_DEBUG("ldap_server from saf cache: '%s'\n",
206 ldap_server ? ldap_server : "");
208 wb_dom = find_domain_from_name(dom_name);
209 if (wb_dom == NULL) {
210 DBG_DEBUG("could not find domain '%s'\n", dom_name);
211 TALLOC_FREE(tmp_ctx);
212 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
215 DBG_DEBUG("find_domain_from_name found realm '%s' for "
216 " domain '%s'\n", wb_dom->alt_name, dom_name);
218 status = ads_cached_connection_connect(
219 wb_dom,
220 ldap_server, /* DNS name to connect to. */
221 mem_ctx, /* memory context for ads struct */
222 adsp); /* Returns ads struct. */
224 TALLOC_FREE(tmp_ctx);
226 return status;
230 return our ads connections structure for a domain. We keep the connection
231 open to make things faster
233 static ADS_STATUS ads_cached_connection(struct winbindd_domain *domain,
234 ADS_STRUCT **adsp)
236 TALLOC_CTX *tmp_ctx = talloc_stackframe();
237 ADS_STATUS status;
239 if (IS_AD_DC) {
241 * Make sure we never try to use LDAP against
242 * a trusted domain as AD DC.
244 TALLOC_FREE(tmp_ctx);
245 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
248 DBG_DEBUG("ads_cached_connection\n");
250 ads_cached_connection_reuse(&domain->backend_data.ads_conn);
251 if (domain->backend_data.ads_conn != NULL) {
252 *adsp = domain->backend_data.ads_conn;
253 TALLOC_FREE(tmp_ctx);
254 return ADS_SUCCESS;
257 status = ads_cached_connection_connect(
258 domain,
259 NULL,
260 domain,
261 &domain->backend_data.ads_conn);
262 if (!ADS_ERR_OK(status)) {
263 /* if we get ECONNREFUSED then it might be a NT4
264 server, fall back to MSRPC */
265 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
266 status.err.rc == ECONNREFUSED) {
267 /* 'reconnect_methods' is the MS-RPC backend. */
268 DBG_NOTICE("Trying MSRPC methods for domain '%s'\n",
269 domain->name);
270 domain->backend = &reconnect_methods;
272 TALLOC_FREE(tmp_ctx);
273 return status;
276 *adsp = domain->backend_data.ads_conn;
277 TALLOC_FREE(tmp_ctx);
278 return ADS_SUCCESS;
281 /* Query display info for a realm. This is the basic user list fn */
282 static NTSTATUS query_user_list(struct winbindd_domain *domain,
283 TALLOC_CTX *mem_ctx,
284 uint32_t **prids)
286 ADS_STRUCT *ads = NULL;
287 const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
288 int count;
289 uint32_t *rids = NULL;
290 ADS_STATUS rc;
291 LDAPMessage *res = NULL;
292 LDAPMessage *msg = NULL;
293 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
295 DEBUG(3,("ads: query_user_list\n"));
297 if ( !winbindd_can_contact_domain( domain ) ) {
298 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
299 domain->name));
300 return NT_STATUS_OK;
303 rc = ads_cached_connection(domain, &ads);
304 if (!ADS_ERR_OK(rc)) {
305 domain->last_status = NT_STATUS_SERVER_DISABLED;
306 goto done;
309 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
310 if (!ADS_ERR_OK(rc)) {
311 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
312 status = ads_ntstatus(rc);
313 goto done;
314 } else if (!res) {
315 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
316 goto done;
319 count = ads_count_replies(ads, res);
320 if (count == 0) {
321 DEBUG(1,("query_user_list: No users found\n"));
322 goto done;
325 rids = talloc_zero_array(mem_ctx, uint32_t, count);
326 if (rids == NULL) {
327 status = NT_STATUS_NO_MEMORY;
328 goto done;
331 count = 0;
333 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
334 struct dom_sid user_sid;
335 uint32_t atype;
336 bool ok;
338 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
339 if (!ok) {
340 DBG_INFO("Object lacks sAMAccountType attribute\n");
341 continue;
343 if (ds_atype_map(atype) != SID_NAME_USER) {
344 DBG_INFO("Not a user account? atype=0x%x\n", atype);
345 continue;
348 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
349 char *dn = ads_get_dn(ads, talloc_tos(), msg);
350 DBG_INFO("No sid for %s !?\n", dn);
351 TALLOC_FREE(dn);
352 continue;
355 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
356 struct dom_sid_buf sidstr, domstr;
357 DBG_WARNING("Got sid %s in domain %s\n",
358 dom_sid_str_buf(&user_sid, &sidstr),
359 dom_sid_str_buf(&domain->sid, &domstr));
360 continue;
363 sid_split_rid(&user_sid, &rids[count]);
364 count += 1;
367 rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
368 if (prids != NULL) {
369 *prids = rids;
370 } else {
371 TALLOC_FREE(rids);
374 status = NT_STATUS_OK;
376 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
378 done:
379 ads_msgfree(ads, res);
380 return status;
383 /* list all domain groups */
384 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
385 TALLOC_CTX *mem_ctx,
386 uint32_t *num_entries,
387 struct wb_acct_info **info)
389 ADS_STRUCT *ads = NULL;
390 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
391 "name", "objectSid", NULL};
392 int i, count;
393 ADS_STATUS rc;
394 LDAPMessage *res = NULL;
395 LDAPMessage *msg = NULL;
396 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
397 const char *filter;
398 bool enum_dom_local_groups = False;
400 *num_entries = 0;
402 DEBUG(3,("ads: enum_dom_groups\n"));
404 if ( !winbindd_can_contact_domain( domain ) ) {
405 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
406 domain->name));
407 return NT_STATUS_OK;
410 /* only grab domain local groups for our domain */
411 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
412 enum_dom_local_groups = True;
415 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
416 * rollup-fixes:
418 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
419 * default value, it MUST be absent. In case of extensible matching the
420 * "dnattr" boolean defaults to FALSE and so it must be only be present
421 * when set to TRUE.
423 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
424 * filter using bitwise matching rule then the buggy AD fails to decode
425 * the extensible match. As a workaround set it to TRUE and thereby add
426 * the dnAttributes "dn" field to cope with those older AD versions.
427 * It should not harm and won't put any additional load on the AD since
428 * none of the dn components have a bitmask-attribute.
430 * Thanks to Ralf Haferkamp for input and testing - Guenther */
432 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)"
433 "(&(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d)"
434 "(!(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))))",
435 GROUP_TYPE_SECURITY_ENABLED,
436 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
438 if (filter == NULL) {
439 status = NT_STATUS_NO_MEMORY;
440 goto done;
443 rc = ads_cached_connection(domain, &ads);
444 if (!ADS_ERR_OK(rc)) {
445 domain->last_status = NT_STATUS_SERVER_DISABLED;
446 goto done;
449 rc = ads_search_retry(ads, &res, filter, attrs);
450 if (!ADS_ERR_OK(rc)) {
451 status = ads_ntstatus(rc);
452 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
453 goto done;
454 } else if (!res) {
455 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
456 goto done;
459 count = ads_count_replies(ads, res);
460 if (count == 0) {
461 DEBUG(1,("enum_dom_groups: No groups found\n"));
462 goto done;
465 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
466 if (!*info) {
467 status = NT_STATUS_NO_MEMORY;
468 goto done;
471 i = 0;
473 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
474 char *name, *gecos;
475 struct dom_sid sid;
476 uint32_t rid;
478 name = ads_pull_username(ads, (*info), msg);
479 gecos = ads_pull_string(ads, (*info), msg, "name");
480 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
481 DEBUG(1,("No sid for %s !?\n", name));
482 continue;
485 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
486 DEBUG(1,("No rid for %s !?\n", name));
487 continue;
490 (*info)[i].acct_name = name;
491 (*info)[i].acct_desc = gecos;
492 (*info)[i].rid = rid;
493 i++;
496 (*num_entries) = i;
498 status = NT_STATUS_OK;
500 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
502 done:
503 if (res)
504 ads_msgfree(ads, res);
506 return status;
509 /* list all domain local groups */
510 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
511 TALLOC_CTX *mem_ctx,
512 uint32_t *num_entries,
513 struct wb_acct_info **info)
516 * This is a stub function only as we returned the domain
517 * local groups in enum_dom_groups() if the domain->native field
518 * was true. This is a simple performance optimization when
519 * using LDAP.
521 * if we ever need to enumerate domain local groups separately,
522 * then this optimization in enum_dom_groups() will need
523 * to be split out
525 *num_entries = 0;
527 return NT_STATUS_OK;
530 /* convert a single name to a sid in a domain - use rpc methods */
531 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
532 TALLOC_CTX *mem_ctx,
533 const char *domain_name,
534 const char *name,
535 uint32_t flags,
536 const char **pdom_name,
537 struct dom_sid *sid,
538 enum lsa_SidType *type)
540 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
541 flags, pdom_name, sid, type);
544 /* convert a domain SID to a user or group name - use rpc methods */
545 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
546 TALLOC_CTX *mem_ctx,
547 const struct dom_sid *sid,
548 char **domain_name,
549 char **name,
550 enum lsa_SidType *type)
552 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
553 domain_name, name, type);
556 /* convert a list of rids to names - use rpc methods */
557 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
558 TALLOC_CTX *mem_ctx,
559 const struct dom_sid *sid,
560 uint32_t *rids,
561 size_t num_rids,
562 char **domain_name,
563 char ***names,
564 enum lsa_SidType **types)
566 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
567 rids, num_rids,
568 domain_name, names, types);
571 /* Lookup groups a user is a member of - alternate method, for when
572 tokenGroups are not available. */
573 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
574 TALLOC_CTX *mem_ctx,
575 const char *user_dn,
576 struct dom_sid *primary_group,
577 uint32_t *p_num_groups, struct dom_sid **user_sids)
579 ADS_STATUS rc;
580 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
581 int count;
582 LDAPMessage *res = NULL;
583 LDAPMessage *msg = NULL;
584 char *ldap_exp;
585 ADS_STRUCT *ads = NULL;
586 const char *group_attrs[] = {"objectSid", NULL};
587 char *escaped_dn;
588 uint32_t num_groups = 0;
590 DEBUG(3,("ads: lookup_usergroups_member\n"));
592 if ( !winbindd_can_contact_domain( domain ) ) {
593 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
594 domain->name));
595 return NT_STATUS_OK;
598 rc = ads_cached_connection(domain, &ads);
599 if (!ADS_ERR_OK(rc)) {
600 domain->last_status = NT_STATUS_SERVER_DISABLED;
601 goto done;
604 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
605 status = NT_STATUS_NO_MEMORY;
606 goto done;
609 ldap_exp = talloc_asprintf(mem_ctx,
610 "(&(member=%s)(objectCategory=group)"
611 "(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))",
612 escaped_dn,
613 GROUP_TYPE_SECURITY_ENABLED);
614 if (!ldap_exp) {
615 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
616 TALLOC_FREE(escaped_dn);
617 status = NT_STATUS_NO_MEMORY;
618 goto done;
621 TALLOC_FREE(escaped_dn);
623 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
625 if (!ADS_ERR_OK(rc)) {
626 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
627 return ads_ntstatus(rc);
628 } else if (!res) {
629 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
630 return NT_STATUS_INTERNAL_ERROR;
634 count = ads_count_replies(ads, res);
636 *user_sids = NULL;
637 num_groups = 0;
639 /* always add the primary group to the sid array */
640 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
641 &num_groups);
642 if (!NT_STATUS_IS_OK(status)) {
643 goto done;
646 if (count > 0) {
647 for (msg = ads_first_entry(ads, res); msg;
648 msg = ads_next_entry(ads, msg)) {
649 struct dom_sid group_sid;
651 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
652 DEBUG(1,("No sid for this group ?!?\n"));
653 continue;
656 /* ignore Builtin groups from ADS - Guenther */
657 if (sid_check_is_in_builtin(&group_sid)) {
658 continue;
661 status = add_sid_to_array(mem_ctx, &group_sid,
662 user_sids, &num_groups);
663 if (!NT_STATUS_IS_OK(status)) {
664 goto done;
670 *p_num_groups = num_groups;
671 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
673 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
674 done:
675 if (res)
676 ads_msgfree(ads, res);
678 return status;
681 /* Lookup groups a user is a member of - alternate method, for when
682 tokenGroups are not available. */
683 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
684 TALLOC_CTX *mem_ctx,
685 const char *user_dn,
686 struct dom_sid *primary_group,
687 uint32_t *p_num_groups,
688 struct dom_sid **user_sids)
690 ADS_STATUS rc;
691 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
692 ADS_STRUCT *ads = NULL;
693 const char *attrs[] = {"memberOf", NULL};
694 uint32_t num_groups = 0;
695 struct dom_sid *group_sids = NULL;
696 size_t i;
697 char **strings = NULL;
698 size_t num_strings = 0, num_sids = 0;
701 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
703 if ( !winbindd_can_contact_domain( domain ) ) {
704 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
705 "domain %s\n", domain->name));
706 return NT_STATUS_OK;
709 rc = ads_cached_connection(domain, &ads);
710 if (!ADS_ERR_OK(rc)) {
711 domain->last_status = NT_STATUS_SERVER_DISABLED;
712 return NT_STATUS_UNSUCCESSFUL;
715 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
716 ADS_EXTENDED_DN_HEX_STRING,
717 &strings, &num_strings);
719 if (!ADS_ERR_OK(rc)) {
720 DEBUG(1,("lookup_usergroups_memberof ads_search "
721 "member=%s: %s\n", user_dn, ads_errstr(rc)));
722 return ads_ntstatus(rc);
725 *user_sids = NULL;
726 num_groups = 0;
728 /* always add the primary group to the sid array */
729 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
730 &num_groups);
731 if (!NT_STATUS_IS_OK(status)) {
732 goto done;
735 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
736 if (!group_sids) {
737 status = NT_STATUS_NO_MEMORY;
738 goto done;
741 for (i=0; i<num_strings; i++) {
742 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
743 ADS_EXTENDED_DN_HEX_STRING,
744 &(group_sids)[i]);
745 if (!ADS_ERR_OK(rc)) {
746 /* ignore members without SIDs */
747 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
748 NT_STATUS_NOT_FOUND)) {
749 continue;
751 else {
752 status = ads_ntstatus(rc);
753 goto done;
756 num_sids++;
759 if (i == 0) {
760 DEBUG(1,("No memberOf for this user?!?\n"));
761 status = NT_STATUS_NO_MEMORY;
762 goto done;
765 for (i=0; i<num_sids; i++) {
767 /* ignore Builtin groups from ADS - Guenther */
768 if (sid_check_is_in_builtin(&group_sids[i])) {
769 continue;
772 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
773 &num_groups);
774 if (!NT_STATUS_IS_OK(status)) {
775 goto done;
780 *p_num_groups = num_groups;
781 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
783 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
784 user_dn));
786 done:
787 TALLOC_FREE(strings);
788 TALLOC_FREE(group_sids);
790 return status;
794 /* Lookup groups a user is a member of. */
795 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
796 TALLOC_CTX *mem_ctx,
797 const struct dom_sid *sid,
798 uint32_t *p_num_groups, struct dom_sid **user_sids)
800 ADS_STRUCT *ads = NULL;
801 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
802 ADS_STATUS rc;
803 int count;
804 LDAPMessage *msg = NULL;
805 char *user_dn = NULL;
806 struct dom_sid *sids;
807 int i;
808 struct dom_sid primary_group;
809 uint32_t primary_group_rid;
810 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
811 uint32_t num_groups = 0;
812 struct dom_sid_buf buf;
814 DEBUG(3,("ads: lookup_usergroups\n"));
815 *p_num_groups = 0;
817 status = lookup_usergroups_cached(mem_ctx, sid,
818 p_num_groups, user_sids);
819 if (NT_STATUS_IS_OK(status)) {
820 return NT_STATUS_OK;
823 if ( !winbindd_can_contact_domain( domain ) ) {
824 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
825 domain->name));
827 /* Tell the cache manager not to remember this one */
829 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
832 rc = ads_cached_connection(domain, &ads);
833 if (!ADS_ERR_OK(rc)) {
834 domain->last_status = NT_STATUS_SERVER_DISABLED;
835 status = NT_STATUS_SERVER_DISABLED;
836 goto done;
839 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
841 if (!ADS_ERR_OK(rc)) {
842 status = ads_ntstatus(rc);
843 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
844 "%s\n",
845 dom_sid_str_buf(sid, &buf),
846 ads_errstr(rc)));
847 goto done;
850 count = ads_count_replies(ads, msg);
851 if (count != 1) {
852 status = NT_STATUS_UNSUCCESSFUL;
853 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
854 "invalid number of results (count=%d)\n",
855 dom_sid_str_buf(sid, &buf),
856 count));
857 goto done;
860 if (!msg) {
861 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
862 dom_sid_str_buf(sid, &buf)));
863 status = NT_STATUS_UNSUCCESSFUL;
864 goto done;
867 user_dn = ads_get_dn(ads, mem_ctx, msg);
868 if (user_dn == NULL) {
869 status = NT_STATUS_NO_MEMORY;
870 goto done;
873 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
874 DEBUG(1,("%s: No primary group for sid=%s !?\n",
875 domain->name,
876 dom_sid_str_buf(sid, &buf)));
877 goto done;
880 sid_compose(&primary_group, &domain->sid, primary_group_rid);
882 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
884 /* there must always be at least one group in the token,
885 unless we are talking to a buggy Win2k server */
887 /* actually this only happens when the machine account has no read
888 * permissions on the tokenGroup attribute - gd */
890 if (count == 0) {
892 /* no tokenGroups */
894 /* lookup what groups this user is a member of by DN search on
895 * "memberOf" */
897 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
898 &primary_group,
899 &num_groups, user_sids);
900 *p_num_groups = num_groups;
901 if (NT_STATUS_IS_OK(status)) {
902 goto done;
905 /* lookup what groups this user is a member of by DN search on
906 * "member" */
908 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
909 &primary_group,
910 &num_groups, user_sids);
911 *p_num_groups = num_groups;
912 goto done;
915 *user_sids = NULL;
916 num_groups = 0;
918 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
919 &num_groups);
920 if (!NT_STATUS_IS_OK(status)) {
921 goto done;
924 for (i=0;i<count;i++) {
926 /* ignore Builtin groups from ADS - Guenther */
927 if (sid_check_is_in_builtin(&sids[i])) {
928 continue;
931 status = add_sid_to_array_unique(mem_ctx, &sids[i],
932 user_sids, &num_groups);
933 if (!NT_STATUS_IS_OK(status)) {
934 goto done;
938 *p_num_groups = (uint32_t)num_groups;
939 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
941 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
942 dom_sid_str_buf(sid, &buf)));
943 done:
944 TALLOC_FREE(user_dn);
945 ads_msgfree(ads, msg);
946 return status;
949 /* Lookup aliases a user is member of - use rpc methods */
950 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
951 TALLOC_CTX *mem_ctx,
952 uint32_t num_sids, const struct dom_sid *sids,
953 uint32_t *num_aliases, uint32_t **alias_rids)
955 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
956 num_aliases, alias_rids);
959 static NTSTATUS add_primary_group_members(
960 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid, const char *domname,
961 char ***all_members, size_t *num_all_members)
963 char *filter;
964 NTSTATUS status = NT_STATUS_NO_MEMORY;
965 ADS_STATUS rc;
966 const char *attrs[] = { "dn", NULL };
967 LDAPMessage *res = NULL;
968 LDAPMessage *msg;
969 char **members;
970 size_t num_members;
971 ads_control args;
972 bool all_groupmem = idmap_config_bool(domname, "all_groupmem", false);
974 filter = talloc_asprintf(
975 mem_ctx,
976 "(&(objectCategory=user)(primaryGroupID=%u)%s)",
977 (unsigned)rid,
978 all_groupmem ? "" : "(uidNumber=*)(!(uidNumber=0))");
979 if (filter == NULL) {
980 goto done;
983 args.control = ADS_EXTENDED_DN_OID;
984 args.val = ADS_EXTENDED_DN_HEX_STRING;
985 args.critical = True;
987 rc = ads_do_search_all_args(ads, ads->config.bind_path,
988 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
989 &res);
991 if (!ADS_ERR_OK(rc)) {
992 status = ads_ntstatus(rc);
993 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
994 goto done;
996 if (res == NULL) {
997 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
998 goto done;
1001 num_members = ads_count_replies(ads, res);
1003 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1004 (uintmax_t)num_members));
1006 if (num_members == 0) {
1007 status = NT_STATUS_OK;
1008 goto done;
1011 members = talloc_realloc(mem_ctx, *all_members, char *,
1012 *num_all_members + num_members);
1013 if (members == NULL) {
1014 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1015 goto done;
1017 *all_members = members;
1019 for (msg = ads_first_entry(ads, res); msg != NULL;
1020 msg = ads_next_entry(ads, msg)) {
1021 char *dn;
1023 dn = ads_get_dn(ads, members, msg);
1024 if (dn == NULL) {
1025 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1026 continue;
1029 members[*num_all_members] = dn;
1030 *num_all_members += 1;
1033 status = NT_STATUS_OK;
1034 done:
1035 if (res != NULL) {
1036 ads_msgfree(ads, res);
1038 TALLOC_FREE(filter);
1039 return status;
1043 find the members of a group, given a group rid and domain
1045 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1046 TALLOC_CTX *mem_ctx,
1047 const struct dom_sid *group_sid,
1048 enum lsa_SidType type,
1049 uint32_t *num_names,
1050 struct dom_sid **sid_mem, char ***names,
1051 uint32_t **name_types)
1053 ADS_STATUS rc;
1054 ADS_STRUCT *ads = NULL;
1055 char *ldap_exp;
1056 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1057 char *sidbinstr;
1058 char **members = NULL;
1059 size_t i;
1060 size_t num_members = 0;
1061 ads_control args;
1062 struct dom_sid *sid_mem_nocache = NULL;
1063 char **names_nocache = NULL;
1064 enum lsa_SidType *name_types_nocache = NULL;
1065 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1066 uint32_t num_nocache = 0;
1067 TALLOC_CTX *tmp_ctx = NULL;
1068 uint32_t rid;
1069 struct dom_sid_buf buf;
1071 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1072 dom_sid_str_buf(group_sid, &buf)));
1074 *num_names = 0;
1076 tmp_ctx = talloc_new(mem_ctx);
1077 if (!tmp_ctx) {
1078 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1079 status = NT_STATUS_NO_MEMORY;
1080 goto done;
1083 if (!sid_peek_rid(group_sid, &rid)) {
1084 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1085 status = NT_STATUS_INVALID_PARAMETER;
1086 goto done;
1089 if ( !winbindd_can_contact_domain( domain ) ) {
1090 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1091 domain->name));
1092 return NT_STATUS_OK;
1095 rc = ads_cached_connection(domain, &ads);
1096 if (!ADS_ERR_OK(rc)) {
1097 domain->last_status = NT_STATUS_SERVER_DISABLED;
1098 goto done;
1101 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1102 status = NT_STATUS_NO_MEMORY;
1103 goto done;
1106 /* search for all members of the group */
1107 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1108 TALLOC_FREE(sidbinstr);
1109 if (ldap_exp == NULL) {
1110 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1111 status = NT_STATUS_NO_MEMORY;
1112 goto done;
1115 args.control = ADS_EXTENDED_DN_OID;
1116 args.val = ADS_EXTENDED_DN_HEX_STRING;
1117 args.critical = True;
1119 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1120 ldap_exp, &args, "member", &members, &num_members);
1122 if (!ADS_ERR_OK(rc)) {
1123 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1124 status = NT_STATUS_UNSUCCESSFUL;
1125 goto done;
1128 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1130 status = add_primary_group_members(ads, mem_ctx, rid, domain->name,
1131 &members, &num_members);
1132 if (!NT_STATUS_IS_OK(status)) {
1133 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1134 __func__, nt_errstr(status)));
1135 goto done;
1138 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1139 __func__, (int)num_members));
1141 /* Now that we have a list of sids, we need to get the
1142 * lists of names and name_types belonging to these sids.
1143 * even though conceptually not quite clean, we use the
1144 * RPC call lsa_lookup_sids for this since it can handle a
1145 * list of sids. ldap calls can just resolve one sid at a time.
1147 * At this stage, the sids are still hidden in the exetended dn
1148 * member output format. We actually do a little better than
1149 * stated above: In extracting the sids from the member strings,
1150 * we try to resolve as many sids as possible from the
1151 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1153 if (num_members) {
1154 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1155 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1156 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1157 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1159 if ((members == NULL) || (*sid_mem == NULL) ||
1160 (*names == NULL) || (*name_types == NULL) ||
1161 (sid_mem_nocache == NULL))
1163 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1164 status = NT_STATUS_NO_MEMORY;
1165 goto done;
1168 else {
1169 (*sid_mem) = NULL;
1170 (*names) = NULL;
1171 (*name_types) = NULL;
1174 for (i=0; i<num_members; i++) {
1175 enum lsa_SidType name_type;
1176 char *name, *domain_name;
1177 struct dom_sid sid;
1179 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1180 &sid);
1181 if (!ADS_ERR_OK(rc)) {
1182 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1183 NT_STATUS_NOT_FOUND)) {
1184 /* Group members can be objects, like Exchange
1185 * Public Folders, that don't have a SID. Skip
1186 * them. */
1187 continue;
1189 else {
1190 status = ads_ntstatus(rc);
1191 goto done;
1194 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1195 &name_type)) {
1196 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1197 "cache\n",
1198 dom_sid_str_buf(&sid, &buf)));
1199 sid_copy(&(*sid_mem)[*num_names], &sid);
1200 (*names)[*num_names] = fill_domain_username_talloc(
1201 *names,
1202 domain_name,
1203 name,
1204 true);
1206 (*name_types)[*num_names] = name_type;
1207 (*num_names)++;
1209 else {
1210 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1211 "cache\n",
1212 dom_sid_str_buf(&sid, &buf)));
1213 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1214 num_nocache++;
1218 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1219 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1221 /* handle sids not resolved from cache by lsa_lookup_sids */
1222 if (num_nocache > 0) {
1224 status = winbindd_lookup_sids(tmp_ctx,
1225 domain,
1226 num_nocache,
1227 sid_mem_nocache,
1228 &domains_nocache,
1229 &names_nocache,
1230 &name_types_nocache);
1232 if (!(NT_STATUS_IS_OK(status) ||
1233 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1234 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1236 DEBUG(1, ("lsa_lookupsids call failed with %s "
1237 "- retrying...\n", nt_errstr(status)));
1239 status = winbindd_lookup_sids(tmp_ctx,
1240 domain,
1241 num_nocache,
1242 sid_mem_nocache,
1243 &domains_nocache,
1244 &names_nocache,
1245 &name_types_nocache);
1248 if (NT_STATUS_IS_OK(status) ||
1249 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1251 /* Copy the entries over from the "_nocache" arrays
1252 * to the result arrays, skipping the gaps the
1253 * lookup_sids call left. */
1254 for (i=0; i < num_nocache; i++) {
1255 if (((names_nocache)[i] != NULL) &&
1256 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1258 sid_copy(&(*sid_mem)[*num_names],
1259 &sid_mem_nocache[i]);
1260 (*names)[*num_names] =
1261 fill_domain_username_talloc(
1262 *names,
1263 domains_nocache[i],
1264 names_nocache[i],
1265 true);
1266 (*name_types)[*num_names] = name_types_nocache[i];
1267 (*num_names)++;
1271 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1272 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1273 "not map any SIDs at all.\n"));
1274 /* Don't handle this as an error here.
1275 * There is nothing left to do with respect to the
1276 * overall result... */
1278 else if (!NT_STATUS_IS_OK(status)) {
1279 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1280 "sids via rpc_lsa_lookup_sids: %s\n",
1281 (int)num_members, nt_errstr(status)));
1282 goto done;
1286 status = NT_STATUS_OK;
1287 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1288 dom_sid_str_buf(group_sid, &buf)));
1290 done:
1292 TALLOC_FREE(tmp_ctx);
1294 return status;
1297 static NTSTATUS lookup_aliasmem(struct winbindd_domain *domain,
1298 TALLOC_CTX *mem_ctx,
1299 const struct dom_sid *sid,
1300 enum lsa_SidType type,
1301 uint32_t *num_sids,
1302 struct dom_sid **sids)
1304 char **names = NULL;
1305 uint32_t *name_types = NULL;
1306 struct dom_sid_buf buf;
1308 DBG_DEBUG("ads: lookup_aliasmem %s sid=%s\n",
1309 domain->name,
1310 dom_sid_str_buf(sid, &buf));
1311 /* Search for alias and group membership uses the same LDAP command. */
1312 return lookup_groupmem(domain,
1313 mem_ctx,
1314 sid,
1315 type,
1316 num_sids,
1317 sids,
1318 &names,
1319 &name_types);
1322 /* find the lockout policy of a domain - use rpc methods */
1323 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1324 TALLOC_CTX *mem_ctx,
1325 struct samr_DomInfo12 *policy)
1327 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1330 /* find the password policy of a domain - use rpc methods */
1331 static NTSTATUS password_policy(struct winbindd_domain *domain,
1332 TALLOC_CTX *mem_ctx,
1333 struct samr_DomInfo1 *policy)
1335 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1338 /* get a list of trusted domains */
1339 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1340 TALLOC_CTX *mem_ctx,
1341 struct netr_DomainTrustList *trusts)
1343 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1344 WERROR werr;
1345 uint32_t i;
1346 uint32_t flags;
1347 struct rpc_pipe_client *cli;
1348 struct dcerpc_binding_handle *b;
1350 DEBUG(3,("ads: trusted_domains\n"));
1352 ZERO_STRUCTP(trusts);
1354 /* If this is our primary domain or a root in our forest,
1355 query for all trusts. If not, then just look for domain
1356 trusts in the target forest */
1358 if (domain->primary || domain_is_forest_root(domain)) {
1359 flags = NETR_TRUST_FLAG_OUTBOUND |
1360 NETR_TRUST_FLAG_INBOUND |
1361 NETR_TRUST_FLAG_IN_FOREST;
1362 } else {
1363 flags = NETR_TRUST_FLAG_IN_FOREST;
1366 result = cm_connect_netlogon(domain, &cli);
1368 if (!NT_STATUS_IS_OK(result)) {
1369 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1370 "for PIPE_NETLOGON (%s)\n",
1371 domain->name, nt_errstr(result)));
1372 return NT_STATUS_UNSUCCESSFUL;
1375 b = cli->binding_handle;
1377 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1378 cli->desthost,
1379 flags,
1380 trusts,
1381 &werr);
1382 if (!NT_STATUS_IS_OK(result)) {
1383 return result;
1386 if (!W_ERROR_IS_OK(werr)) {
1387 return werror_to_ntstatus(werr);
1389 if (trusts->count == 0) {
1390 return NT_STATUS_OK;
1393 /* Copy across names and sids */
1395 for (i = 0; i < trusts->count; i++) {
1396 struct netr_DomainTrust *trust = &trusts->array[i];
1397 struct winbindd_domain d;
1399 ZERO_STRUCT(d);
1402 * drop external trusts if this is not our primary
1403 * domain. This means that the returned number of
1404 * domains may be less that the ones actually trusted
1405 * by the DC.
1408 if ((trust->trust_attributes
1409 & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1410 !domain->primary )
1412 DEBUG(10,("trusted_domains: Skipping external trusted "
1413 "domain %s because it is outside of our "
1414 "primary domain\n",
1415 trust->netbios_name));
1416 continue;
1419 /* add to the trusted domain cache */
1421 d.name = discard_const_p(char, trust->netbios_name);
1422 d.alt_name = discard_const_p(char, trust->dns_name);
1424 if (trust->sid) {
1425 sid_copy(&d.sid, trust->sid);
1426 } else {
1427 sid_copy(&d.sid, &global_sid_NULL);
1430 if ( domain->primary ) {
1431 DEBUG(10,("trusted_domains(ads): Searching "
1432 "trusted domain list of %s and storing "
1433 "trust flags for domain %s\n",
1434 domain->name, d.alt_name));
1436 d.domain_flags = trust->trust_flags;
1437 d.domain_type = trust->trust_type;
1438 d.domain_trust_attribs = trust->trust_attributes;
1440 wcache_tdc_add_domain( &d );
1441 } else if (domain_is_forest_root(domain)) {
1442 /* Check if we already have this record. If
1443 * we are following our forest root that is not
1444 * our primary domain, we want to keep trust
1445 * flags from the perspective of our primary
1446 * domain not our forest root. */
1447 struct winbindd_tdc_domain *exist = NULL;
1449 exist = wcache_tdc_fetch_domain(
1450 talloc_tos(), trust->netbios_name);
1451 if (!exist) {
1452 DEBUG(10,("trusted_domains(ads): Searching "
1453 "trusted domain list of %s and "
1454 "storing trust flags for domain "
1455 "%s\n", domain->name, d.alt_name));
1456 d.domain_flags = trust->trust_flags;
1457 d.domain_type = trust->trust_type;
1458 d.domain_trust_attribs =
1459 trust->trust_attributes;
1461 wcache_tdc_add_domain( &d );
1463 TALLOC_FREE(exist);
1464 } else {
1465 /* This gets a little tricky. If we are
1466 following a transitive forest trust, then
1467 innerit the flags, type, and attribs from
1468 the domain we queried to make sure we don't
1469 record the view of the trust from the wrong
1470 side. Always view it from the side of our
1471 primary domain. --jerry */
1472 struct winbindd_tdc_domain *parent = NULL;
1474 DEBUG(10,("trusted_domains(ads): Searching "
1475 "trusted domain list of %s and inheriting "
1476 "trust flags for domain %s\n",
1477 domain->name, d.alt_name));
1479 parent = wcache_tdc_fetch_domain(talloc_tos(),
1480 domain->name);
1481 if (parent) {
1482 d.domain_flags = parent->trust_flags;
1483 d.domain_type = parent->trust_type;
1484 d.domain_trust_attribs = parent->trust_attribs;
1485 } else {
1486 d.domain_flags = domain->domain_flags;
1487 d.domain_type = domain->domain_type;
1488 d.domain_trust_attribs =
1489 domain->domain_trust_attribs;
1491 TALLOC_FREE(parent);
1494 * We need to pass the modified properties
1495 * to the caller.
1497 trust->trust_flags = d.domain_flags;
1498 trust->trust_type = d.domain_type;
1499 trust->trust_attributes = d.domain_trust_attribs;
1501 wcache_tdc_add_domain( &d );
1504 return result;
1507 /* the ADS backend methods are exposed via this structure */
1508 struct winbindd_methods ads_methods = {
1509 True,
1510 query_user_list,
1511 enum_dom_groups,
1512 enum_local_groups,
1513 name_to_sid,
1514 sid_to_name,
1515 rids_to_names,
1516 lookup_usergroups,
1517 lookup_useraliases,
1518 lookup_groupmem,
1519 lookup_aliasmem,
1520 lockout_policy,
1521 password_policy,
1522 trusted_domains,
1525 #endif