s3-winbindd: Fix #10264, cache_traverse_validate_fn failure for NDR cache entries.
[Samba.git] / source3 / winbindd / winbindd_ads.c
bloba33aac2008196eb8d58f8017d71d586b38ef0a7a
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 "rpc_client/rpc_client.h"
27 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
28 #include "../libds/common/flags.h"
29 #include "ads.h"
30 #include "secrets.h"
31 #include "../libcli/ldap/ldap_ndr.h"
32 #include "../libcli/security/security.h"
33 #include "../libds/common/flag_mapping.h"
34 #include "passdb.h"
36 #ifdef HAVE_ADS
38 #undef DBGC_CLASS
39 #define DBGC_CLASS DBGC_WINBIND
41 extern struct winbindd_methods reconnect_methods;
44 return our ads connections structure for a domain. We keep the connection
45 open to make things faster
47 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
49 ADS_STRUCT *ads;
50 ADS_STATUS status;
51 fstring dc_name;
52 struct sockaddr_storage dc_ss;
54 DEBUG(10,("ads_cached_connection\n"));
56 if (domain->private_data) {
58 time_t expire;
59 time_t now = time(NULL);
61 /* check for a valid structure */
62 ads = (ADS_STRUCT *)domain->private_data;
64 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
66 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
67 (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
69 if ( ads->config.realm && (expire > now)) {
70 return ads;
71 } else {
72 /* we own this ADS_STRUCT so make sure it goes away */
73 DEBUG(7,("Deleting expired krb5 credential cache\n"));
74 ads->is_mine = True;
75 ads_destroy( &ads );
76 ads_kdestroy("MEMORY:winbind_ccache");
77 domain->private_data = NULL;
81 ads = ads_init(domain->alt_name, domain->name, NULL);
82 if (!ads) {
83 DEBUG(1,("ads_init for domain %s failed\n", domain->name));
84 return NULL;
87 /* we don't want ads operations to affect the default ccache */
88 ads->auth.ccache_name = SMB_STRDUP("MEMORY:winbind_ccache");
90 /* the machine acct password might have change - fetch it every time */
92 SAFE_FREE(ads->auth.password);
93 SAFE_FREE(ads->auth.realm);
95 if ( IS_DC ) {
97 if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, NULL, NULL ) ) {
98 ads_destroy( &ads );
99 return NULL;
101 ads->auth.realm = SMB_STRDUP( ads->server.realm );
102 if (!strupper_m( ads->auth.realm )) {
103 ads_destroy( &ads );
104 return NULL;
107 else {
108 struct winbindd_domain *our_domain = domain;
110 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
112 /* always give preference to the alt_name in our
113 primary domain if possible */
115 if ( !domain->primary )
116 our_domain = find_our_domain();
118 if ( our_domain->alt_name[0] != '\0' ) {
119 ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
120 if (!strupper_m( ads->auth.realm )) {
121 ads_destroy( &ads );
122 return NULL;
125 else
126 ads->auth.realm = SMB_STRDUP( lp_realm() );
129 ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
131 /* Setup the server affinity cache. We don't reaally care
132 about the name. Just setup affinity and the KRB5_CONFIG
133 file. */
135 get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ss );
137 status = ads_connect(ads);
138 if (!ADS_ERR_OK(status) || !ads->config.realm) {
139 DEBUG(1,("ads_connect for domain %s failed: %s\n",
140 domain->name, ads_errstr(status)));
141 ads_destroy(&ads);
143 /* if we get ECONNREFUSED then it might be a NT4
144 server, fall back to MSRPC */
145 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
146 status.err.rc == ECONNREFUSED) {
147 /* 'reconnect_methods' is the MS-RPC backend. */
148 DEBUG(1,("Trying MSRPC methods\n"));
149 domain->backend = &reconnect_methods;
151 return NULL;
154 /* set the flag that says we don't own the memory even
155 though we do so that ads_destroy() won't destroy the
156 structure we pass back by reference */
158 ads->is_mine = False;
160 domain->private_data = (void *)ads;
161 return ads;
165 /* Query display info for a realm. This is the basic user list fn */
166 static NTSTATUS query_user_list(struct winbindd_domain *domain,
167 TALLOC_CTX *mem_ctx,
168 uint32 *num_entries,
169 struct wbint_userinfo **pinfo)
171 ADS_STRUCT *ads = NULL;
172 const char *attrs[] = { "*", NULL };
173 int i, count;
174 ADS_STATUS rc;
175 LDAPMessage *res = NULL;
176 LDAPMessage *msg = NULL;
177 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
179 *num_entries = 0;
181 DEBUG(3,("ads: query_user_list\n"));
183 if ( !winbindd_can_contact_domain( domain ) ) {
184 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
185 domain->name));
186 return NT_STATUS_OK;
189 ads = ads_cached_connection(domain);
191 if (!ads) {
192 domain->last_status = NT_STATUS_SERVER_DISABLED;
193 goto done;
196 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
197 if (!ADS_ERR_OK(rc)) {
198 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
199 status = ads_ntstatus(rc);
200 } else if (!res) {
201 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
203 goto done;
206 count = ads_count_replies(ads, res);
207 if (count == 0) {
208 DEBUG(1,("query_user_list: No users found\n"));
209 goto done;
212 (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
213 if (!*pinfo) {
214 status = NT_STATUS_NO_MEMORY;
215 goto done;
218 count = 0;
220 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
221 struct wbint_userinfo *info = &((*pinfo)[count]);
222 uint32 group;
223 uint32 atype;
225 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
226 ds_atype_map(atype) != SID_NAME_USER) {
227 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
228 continue;
231 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
232 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
233 info->homedir = NULL;
234 info->shell = NULL;
235 info->primary_gid = (gid_t)-1;
237 if (!ads_pull_sid(ads, msg, "objectSid",
238 &info->user_sid)) {
239 DEBUG(1, ("No sid for %s !?\n", info->acct_name));
240 continue;
243 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
244 DEBUG(1, ("No primary group for %s !?\n",
245 info->acct_name));
246 continue;
248 sid_compose(&info->group_sid, &domain->sid, group);
250 count += 1;
253 (*num_entries) = count;
254 ads_msgfree(ads, res);
256 for (i=0; i<count; i++) {
257 struct wbint_userinfo *info = &((*pinfo)[i]);
258 const char *gecos = NULL;
259 gid_t primary_gid = (gid_t)-1;
261 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
262 &info->homedir, &info->shell,
263 &gecos, &primary_gid);
264 if (!NT_STATUS_IS_OK(status)) {
266 * Deliberately ignore this error, there might be more
267 * users to fill
269 continue;
272 if (gecos != NULL) {
273 info->full_name = gecos;
275 info->primary_gid = primary_gid;
278 status = NT_STATUS_OK;
280 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
282 done:
283 return status;
286 /* list all domain groups */
287 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
288 TALLOC_CTX *mem_ctx,
289 uint32 *num_entries,
290 struct wb_acct_info **info)
292 ADS_STRUCT *ads = NULL;
293 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
294 "name", "objectSid", NULL};
295 int i, count;
296 ADS_STATUS rc;
297 LDAPMessage *res = NULL;
298 LDAPMessage *msg = NULL;
299 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
300 const char *filter;
301 bool enum_dom_local_groups = False;
303 *num_entries = 0;
305 DEBUG(3,("ads: enum_dom_groups\n"));
307 if ( !winbindd_can_contact_domain( domain ) ) {
308 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
309 domain->name));
310 return NT_STATUS_OK;
313 /* only grab domain local groups for our domain */
314 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
315 enum_dom_local_groups = True;
318 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
319 * rollup-fixes:
321 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
322 * default value, it MUST be absent. In case of extensible matching the
323 * "dnattr" boolean defaults to FALSE and so it must be only be present
324 * when set to TRUE.
326 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
327 * filter using bitwise matching rule then the buggy AD fails to decode
328 * the extensible match. As a workaround set it to TRUE and thereby add
329 * the dnAttributes "dn" field to cope with those older AD versions.
330 * It should not harm and won't put any additional load on the AD since
331 * none of the dn components have a bitmask-attribute.
333 * Thanks to Ralf Haferkamp for input and testing - Guenther */
335 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
336 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
337 ADS_LDAP_MATCHING_RULE_BIT_AND,
338 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
340 if (filter == NULL) {
341 status = NT_STATUS_NO_MEMORY;
342 goto done;
345 ads = ads_cached_connection(domain);
347 if (!ads) {
348 domain->last_status = NT_STATUS_SERVER_DISABLED;
349 goto done;
352 rc = ads_search_retry(ads, &res, filter, attrs);
353 if (!ADS_ERR_OK(rc)) {
354 status = ads_ntstatus(rc);
355 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
356 goto done;
357 } else if (!res) {
358 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
359 goto done;
362 count = ads_count_replies(ads, res);
363 if (count == 0) {
364 DEBUG(1,("enum_dom_groups: No groups found\n"));
365 goto done;
368 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
369 if (!*info) {
370 status = NT_STATUS_NO_MEMORY;
371 goto done;
374 i = 0;
376 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
377 char *name, *gecos;
378 struct dom_sid sid;
379 uint32 rid;
381 name = ads_pull_username(ads, mem_ctx, msg);
382 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
383 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
384 DEBUG(1,("No sid for %s !?\n", name));
385 continue;
388 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
389 DEBUG(1,("No rid for %s !?\n", name));
390 continue;
393 fstrcpy((*info)[i].acct_name, name);
394 fstrcpy((*info)[i].acct_desc, gecos);
395 (*info)[i].rid = rid;
396 i++;
399 (*num_entries) = i;
401 status = NT_STATUS_OK;
403 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
405 done:
406 if (res)
407 ads_msgfree(ads, res);
409 return status;
412 /* list all domain local groups */
413 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
414 TALLOC_CTX *mem_ctx,
415 uint32 *num_entries,
416 struct wb_acct_info **info)
419 * This is a stub function only as we returned the domain
420 * local groups in enum_dom_groups() if the domain->native field
421 * was true. This is a simple performance optimization when
422 * using LDAP.
424 * if we ever need to enumerate domain local groups separately,
425 * then this optimization in enum_dom_groups() will need
426 * to be split out
428 *num_entries = 0;
430 return NT_STATUS_OK;
433 /* convert a single name to a sid in a domain - use rpc methods */
434 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
435 TALLOC_CTX *mem_ctx,
436 const char *domain_name,
437 const char *name,
438 uint32_t flags,
439 struct dom_sid *sid,
440 enum lsa_SidType *type)
442 return reconnect_methods.name_to_sid(domain, mem_ctx,
443 domain_name, name, flags,
444 sid, type);
447 /* convert a domain SID to a user or group name - use rpc methods */
448 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
449 TALLOC_CTX *mem_ctx,
450 const struct dom_sid *sid,
451 char **domain_name,
452 char **name,
453 enum lsa_SidType *type)
455 return reconnect_methods.sid_to_name(domain, mem_ctx, sid,
456 domain_name, name, type);
459 /* convert a list of rids to names - use rpc methods */
460 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
461 TALLOC_CTX *mem_ctx,
462 const struct dom_sid *sid,
463 uint32 *rids,
464 size_t num_rids,
465 char **domain_name,
466 char ***names,
467 enum lsa_SidType **types)
469 return reconnect_methods.rids_to_names(domain, mem_ctx, sid,
470 rids, num_rids,
471 domain_name, names, types);
474 /* If you are looking for "dn_lookup": Yes, it used to be here!
475 * It has gone now since it was a major speed bottleneck in
476 * lookup_groupmem (its only use). It has been replaced by
477 * an rpc lookup sids call... R.I.P. */
479 /* Lookup user information from a rid */
480 static NTSTATUS query_user(struct winbindd_domain *domain,
481 TALLOC_CTX *mem_ctx,
482 const struct dom_sid *sid,
483 struct wbint_userinfo *info)
485 ADS_STRUCT *ads = NULL;
486 const char *attrs[] = { "*", NULL };
487 ADS_STATUS rc;
488 int count;
489 LDAPMessage *msg = NULL;
490 char *ldap_exp;
491 char *sidstr;
492 uint32 group_rid;
493 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
494 struct netr_SamInfo3 *user = NULL;
495 gid_t gid = -1;
496 int ret;
497 char *ads_name;
499 DEBUG(3,("ads: query_user\n"));
501 info->homedir = NULL;
502 info->shell = NULL;
504 /* try netsamlogon cache first */
506 if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
508 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
509 sid_string_dbg(sid)));
511 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
512 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
514 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
515 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
517 nss_get_info_cached( domain, sid, mem_ctx,
518 &info->homedir, &info->shell, &info->full_name,
519 &gid );
520 info->primary_gid = gid;
522 TALLOC_FREE(user);
524 return NT_STATUS_OK;
527 if ( !winbindd_can_contact_domain(domain)) {
528 DEBUG(8,("query_user: No incoming trust from domain %s\n",
529 domain->name));
531 /* We still need to generate some basic information
532 about the user even if we cannot contact the
533 domain. Most of this stuff we can deduce. */
535 sid_copy( &info->user_sid, sid );
537 /* Assume "Domain Users" for the primary group */
539 sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
541 /* Try to fill in what the nss_info backend can do */
543 nss_get_info_cached( domain, sid, mem_ctx,
544 &info->homedir, &info->shell, &info->full_name,
545 &gid);
546 info->primary_gid = gid;
548 return NT_STATUS_OK;
551 /* no cache...do the query */
553 if ( (ads = ads_cached_connection(domain)) == NULL ) {
554 domain->last_status = NT_STATUS_SERVER_DISABLED;
555 return NT_STATUS_SERVER_DISABLED;
558 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
560 ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
561 TALLOC_FREE(sidstr);
562 if (ret == -1) {
563 return NT_STATUS_NO_MEMORY;
565 rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
566 SAFE_FREE(ldap_exp);
567 if (!ADS_ERR_OK(rc)) {
568 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
569 sid_string_dbg(sid), ads_errstr(rc)));
570 return ads_ntstatus(rc);
571 } else if (!msg) {
572 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
573 sid_string_dbg(sid)));
574 return NT_STATUS_INTERNAL_ERROR;
577 count = ads_count_replies(ads, msg);
578 if (count != 1) {
579 DEBUG(1,("query_user(sid=%s): Not found\n",
580 sid_string_dbg(sid)));
581 ads_msgfree(ads, msg);
582 return NT_STATUS_NO_SUCH_USER;
585 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
587 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
588 DEBUG(1,("No primary group for %s !?\n",
589 sid_string_dbg(sid)));
590 ads_msgfree(ads, msg);
591 return NT_STATUS_NO_SUCH_USER;
593 sid_copy(&info->user_sid, sid);
594 sid_compose(&info->group_sid, &domain->sid, group_rid);
597 * We have to fetch the "name" attribute before doing the
598 * nss_get_info_cached call. nss_get_info_cached might destroy
599 * the ads struct, potentially invalidating the ldap message.
601 ads_name = ads_pull_string(ads, mem_ctx, msg, "name");
603 ads_msgfree(ads, msg);
604 msg = NULL;
606 status = nss_get_info_cached( domain, sid, mem_ctx,
607 &info->homedir, &info->shell, &info->full_name,
608 &gid);
609 info->primary_gid = gid;
610 if (!NT_STATUS_IS_OK(status)) {
611 DEBUG(1, ("nss_get_info_cached failed: %s\n",
612 nt_errstr(status)));
613 return status;
616 if (info->full_name == NULL) {
617 info->full_name = ads_name;
618 } else {
619 TALLOC_FREE(ads_name);
622 status = NT_STATUS_OK;
624 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
625 return NT_STATUS_OK;
628 /* Lookup groups a user is a member of - alternate method, for when
629 tokenGroups are not available. */
630 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
631 TALLOC_CTX *mem_ctx,
632 const char *user_dn,
633 struct dom_sid *primary_group,
634 uint32_t *p_num_groups, struct dom_sid **user_sids)
636 ADS_STATUS rc;
637 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
638 int count;
639 LDAPMessage *res = NULL;
640 LDAPMessage *msg = NULL;
641 char *ldap_exp;
642 ADS_STRUCT *ads;
643 const char *group_attrs[] = {"objectSid", NULL};
644 char *escaped_dn;
645 uint32_t num_groups = 0;
647 DEBUG(3,("ads: lookup_usergroups_member\n"));
649 if ( !winbindd_can_contact_domain( domain ) ) {
650 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
651 domain->name));
652 return NT_STATUS_OK;
655 ads = ads_cached_connection(domain);
657 if (!ads) {
658 domain->last_status = NT_STATUS_SERVER_DISABLED;
659 goto done;
662 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
663 status = NT_STATUS_NO_MEMORY;
664 goto done;
667 ldap_exp = talloc_asprintf(mem_ctx,
668 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
669 escaped_dn,
670 ADS_LDAP_MATCHING_RULE_BIT_AND,
671 GROUP_TYPE_SECURITY_ENABLED);
672 if (!ldap_exp) {
673 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
674 TALLOC_FREE(escaped_dn);
675 status = NT_STATUS_NO_MEMORY;
676 goto done;
679 TALLOC_FREE(escaped_dn);
681 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
683 if (!ADS_ERR_OK(rc)) {
684 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
685 return ads_ntstatus(rc);
686 } else if (!res) {
687 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
688 return NT_STATUS_INTERNAL_ERROR;
692 count = ads_count_replies(ads, res);
694 *user_sids = NULL;
695 num_groups = 0;
697 /* always add the primary group to the sid array */
698 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
699 &num_groups);
700 if (!NT_STATUS_IS_OK(status)) {
701 goto done;
704 if (count > 0) {
705 for (msg = ads_first_entry(ads, res); msg;
706 msg = ads_next_entry(ads, msg)) {
707 struct dom_sid group_sid;
709 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
710 DEBUG(1,("No sid for this group ?!?\n"));
711 continue;
714 /* ignore Builtin groups from ADS - Guenther */
715 if (sid_check_is_in_builtin(&group_sid)) {
716 continue;
719 status = add_sid_to_array(mem_ctx, &group_sid,
720 user_sids, &num_groups);
721 if (!NT_STATUS_IS_OK(status)) {
722 goto done;
728 *p_num_groups = num_groups;
729 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
731 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
732 done:
733 if (res)
734 ads_msgfree(ads, res);
736 return status;
739 /* Lookup groups a user is a member of - alternate method, for when
740 tokenGroups are not available. */
741 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
742 TALLOC_CTX *mem_ctx,
743 const char *user_dn,
744 struct dom_sid *primary_group,
745 uint32_t *p_num_groups,
746 struct dom_sid **user_sids)
748 ADS_STATUS rc;
749 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
750 ADS_STRUCT *ads;
751 const char *attrs[] = {"memberOf", NULL};
752 uint32_t num_groups = 0;
753 struct dom_sid *group_sids = NULL;
754 int i;
755 char **strings = NULL;
756 size_t num_strings = 0, num_sids = 0;
759 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
761 if ( !winbindd_can_contact_domain( domain ) ) {
762 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
763 "domain %s\n", domain->name));
764 return NT_STATUS_OK;
767 ads = ads_cached_connection(domain);
769 if (!ads) {
770 domain->last_status = NT_STATUS_SERVER_DISABLED;
771 return NT_STATUS_UNSUCCESSFUL;
774 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
775 ADS_EXTENDED_DN_HEX_STRING,
776 &strings, &num_strings);
778 if (!ADS_ERR_OK(rc)) {
779 DEBUG(1,("lookup_usergroups_memberof ads_search "
780 "member=%s: %s\n", user_dn, ads_errstr(rc)));
781 return ads_ntstatus(rc);
784 *user_sids = NULL;
785 num_groups = 0;
787 /* always add the primary group to the sid array */
788 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
789 &num_groups);
790 if (!NT_STATUS_IS_OK(status)) {
791 goto done;
794 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
795 if (!group_sids) {
796 status = NT_STATUS_NO_MEMORY;
797 goto done;
800 for (i=0; i<num_strings; i++) {
801 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
802 ADS_EXTENDED_DN_HEX_STRING,
803 &(group_sids)[i]);
804 if (!ADS_ERR_OK(rc)) {
805 /* ignore members without SIDs */
806 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
807 NT_STATUS_NOT_FOUND)) {
808 continue;
810 else {
811 status = ads_ntstatus(rc);
812 goto done;
815 num_sids++;
818 if (i == 0) {
819 DEBUG(1,("No memberOf for this user?!?\n"));
820 status = NT_STATUS_NO_MEMORY;
821 goto done;
824 for (i=0; i<num_sids; i++) {
826 /* ignore Builtin groups from ADS - Guenther */
827 if (sid_check_is_in_builtin(&group_sids[i])) {
828 continue;
831 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
832 &num_groups);
833 if (!NT_STATUS_IS_OK(status)) {
834 goto done;
839 *p_num_groups = num_groups;
840 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
842 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
843 user_dn));
845 done:
846 TALLOC_FREE(strings);
847 TALLOC_FREE(group_sids);
849 return status;
853 /* Lookup groups a user is a member of. */
854 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
855 TALLOC_CTX *mem_ctx,
856 const struct dom_sid *sid,
857 uint32 *p_num_groups, struct dom_sid **user_sids)
859 ADS_STRUCT *ads = NULL;
860 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
861 ADS_STATUS rc;
862 int count;
863 LDAPMessage *msg = NULL;
864 char *user_dn = NULL;
865 struct dom_sid *sids;
866 int i;
867 struct dom_sid primary_group;
868 uint32 primary_group_rid;
869 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
870 uint32_t num_groups = 0;
872 DEBUG(3,("ads: lookup_usergroups\n"));
873 *p_num_groups = 0;
875 status = lookup_usergroups_cached(domain, mem_ctx, sid,
876 p_num_groups, user_sids);
877 if (NT_STATUS_IS_OK(status)) {
878 return NT_STATUS_OK;
881 if ( !winbindd_can_contact_domain( domain ) ) {
882 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
883 domain->name));
885 /* Tell the cache manager not to remember this one */
887 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
890 ads = ads_cached_connection(domain);
892 if (!ads) {
893 domain->last_status = NT_STATUS_SERVER_DISABLED;
894 status = NT_STATUS_SERVER_DISABLED;
895 goto done;
898 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
900 if (!ADS_ERR_OK(rc)) {
901 status = ads_ntstatus(rc);
902 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
903 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
904 goto done;
907 count = ads_count_replies(ads, msg);
908 if (count != 1) {
909 status = NT_STATUS_UNSUCCESSFUL;
910 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
911 "invalid number of results (count=%d)\n",
912 sid_string_dbg(sid), count));
913 goto done;
916 if (!msg) {
917 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
918 sid_string_dbg(sid)));
919 status = NT_STATUS_UNSUCCESSFUL;
920 goto done;
923 user_dn = ads_get_dn(ads, mem_ctx, msg);
924 if (user_dn == NULL) {
925 status = NT_STATUS_NO_MEMORY;
926 goto done;
929 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
930 DEBUG(1,("%s: No primary group for sid=%s !?\n",
931 domain->name, sid_string_dbg(sid)));
932 goto done;
935 sid_compose(&primary_group, &domain->sid, primary_group_rid);
937 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
939 /* there must always be at least one group in the token,
940 unless we are talking to a buggy Win2k server */
942 /* actually this only happens when the machine account has no read
943 * permissions on the tokenGroup attribute - gd */
945 if (count == 0) {
947 /* no tokenGroups */
949 /* lookup what groups this user is a member of by DN search on
950 * "memberOf" */
952 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
953 &primary_group,
954 &num_groups, user_sids);
955 *p_num_groups = num_groups;
956 if (NT_STATUS_IS_OK(status)) {
957 goto done;
960 /* lookup what groups this user is a member of by DN search on
961 * "member" */
963 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
964 &primary_group,
965 &num_groups, user_sids);
966 *p_num_groups = num_groups;
967 goto done;
970 *user_sids = NULL;
971 num_groups = 0;
973 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
974 &num_groups);
975 if (!NT_STATUS_IS_OK(status)) {
976 goto done;
979 for (i=0;i<count;i++) {
981 /* ignore Builtin groups from ADS - Guenther */
982 if (sid_check_is_in_builtin(&sids[i])) {
983 continue;
986 status = add_sid_to_array_unique(mem_ctx, &sids[i],
987 user_sids, &num_groups);
988 if (!NT_STATUS_IS_OK(status)) {
989 goto done;
993 *p_num_groups = (uint32)num_groups;
994 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
996 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
997 sid_string_dbg(sid)));
998 done:
999 TALLOC_FREE(user_dn);
1000 ads_msgfree(ads, msg);
1001 return status;
1004 /* Lookup aliases a user is member of - use rpc methods */
1005 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1006 TALLOC_CTX *mem_ctx,
1007 uint32 num_sids, const struct dom_sid *sids,
1008 uint32 *num_aliases, uint32 **alias_rids)
1010 return reconnect_methods.lookup_useraliases(domain, mem_ctx,
1011 num_sids, sids,
1012 num_aliases,
1013 alias_rids);
1017 find the members of a group, given a group rid and domain
1019 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1020 TALLOC_CTX *mem_ctx,
1021 const struct dom_sid *group_sid,
1022 enum lsa_SidType type,
1023 uint32 *num_names,
1024 struct dom_sid **sid_mem, char ***names,
1025 uint32 **name_types)
1027 ADS_STATUS rc;
1028 ADS_STRUCT *ads = NULL;
1029 char *ldap_exp;
1030 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1031 char *sidbinstr;
1032 char **members = NULL;
1033 int i;
1034 size_t num_members = 0;
1035 ads_control args;
1036 struct dom_sid *sid_mem_nocache = NULL;
1037 char **names_nocache = NULL;
1038 enum lsa_SidType *name_types_nocache = NULL;
1039 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1040 uint32 num_nocache = 0;
1041 TALLOC_CTX *tmp_ctx = NULL;
1043 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1044 sid_string_dbg(group_sid)));
1046 *num_names = 0;
1048 tmp_ctx = talloc_new(mem_ctx);
1049 if (!tmp_ctx) {
1050 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1051 status = NT_STATUS_NO_MEMORY;
1052 goto done;
1055 if ( !winbindd_can_contact_domain( domain ) ) {
1056 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1057 domain->name));
1058 return NT_STATUS_OK;
1061 ads = ads_cached_connection(domain);
1063 if (!ads) {
1064 domain->last_status = NT_STATUS_SERVER_DISABLED;
1065 goto done;
1068 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1069 status = NT_STATUS_NO_MEMORY;
1070 goto done;
1073 /* search for all members of the group */
1074 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1075 TALLOC_FREE(sidbinstr);
1076 if (ldap_exp == NULL) {
1077 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1078 status = NT_STATUS_NO_MEMORY;
1079 goto done;
1082 args.control = ADS_EXTENDED_DN_OID;
1083 args.val = ADS_EXTENDED_DN_HEX_STRING;
1084 args.critical = True;
1086 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1087 ldap_exp, &args, "member", &members, &num_members);
1089 if (!ADS_ERR_OK(rc)) {
1090 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1091 status = NT_STATUS_UNSUCCESSFUL;
1092 goto done;
1095 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1097 /* Now that we have a list of sids, we need to get the
1098 * lists of names and name_types belonging to these sids.
1099 * even though conceptually not quite clean, we use the
1100 * RPC call lsa_lookup_sids for this since it can handle a
1101 * list of sids. ldap calls can just resolve one sid at a time.
1103 * At this stage, the sids are still hidden in the exetended dn
1104 * member output format. We actually do a little better than
1105 * stated above: In extracting the sids from the member strings,
1106 * we try to resolve as many sids as possible from the
1107 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1109 if (num_members) {
1110 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1111 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1112 (*name_types) = talloc_zero_array(mem_ctx, uint32, num_members);
1113 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1115 if ((members == NULL) || (*sid_mem == NULL) ||
1116 (*names == NULL) || (*name_types == NULL) ||
1117 (sid_mem_nocache == NULL))
1119 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1120 status = NT_STATUS_NO_MEMORY;
1121 goto done;
1124 else {
1125 (*sid_mem) = NULL;
1126 (*names) = NULL;
1127 (*name_types) = NULL;
1130 for (i=0; i<num_members; i++) {
1131 enum lsa_SidType name_type;
1132 char *name, *domain_name;
1133 struct dom_sid sid;
1135 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1136 &sid);
1137 if (!ADS_ERR_OK(rc)) {
1138 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1139 NT_STATUS_NOT_FOUND)) {
1140 /* Group members can be objects, like Exchange
1141 * Public Folders, that don't have a SID. Skip
1142 * them. */
1143 continue;
1145 else {
1146 status = ads_ntstatus(rc);
1147 goto done;
1150 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1151 &name_type)) {
1152 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1153 "cache\n", sid_string_dbg(&sid)));
1154 sid_copy(&(*sid_mem)[*num_names], &sid);
1155 (*names)[*num_names] = fill_domain_username_talloc(
1156 *names,
1157 domain_name,
1158 name,
1159 true);
1161 (*name_types)[*num_names] = name_type;
1162 (*num_names)++;
1164 else {
1165 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1166 "cache\n", sid_string_dbg(&sid)));
1167 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1168 num_nocache++;
1172 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1173 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1175 /* handle sids not resolved from cache by lsa_lookup_sids */
1176 if (num_nocache > 0) {
1178 status = winbindd_lookup_sids(tmp_ctx,
1179 domain,
1180 num_nocache,
1181 sid_mem_nocache,
1182 &domains_nocache,
1183 &names_nocache,
1184 &name_types_nocache);
1186 if (!(NT_STATUS_IS_OK(status) ||
1187 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1188 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1190 DEBUG(1, ("lsa_lookupsids call failed with %s "
1191 "- retrying...\n", nt_errstr(status)));
1193 status = winbindd_lookup_sids(tmp_ctx,
1194 domain,
1195 num_nocache,
1196 sid_mem_nocache,
1197 &domains_nocache,
1198 &names_nocache,
1199 &name_types_nocache);
1202 if (NT_STATUS_IS_OK(status) ||
1203 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1205 /* Copy the entries over from the "_nocache" arrays
1206 * to the result arrays, skipping the gaps the
1207 * lookup_sids call left. */
1208 for (i=0; i < num_nocache; i++) {
1209 if (((names_nocache)[i] != NULL) &&
1210 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1212 sid_copy(&(*sid_mem)[*num_names],
1213 &sid_mem_nocache[i]);
1214 (*names)[*num_names] =
1215 fill_domain_username_talloc(
1216 *names,
1217 domains_nocache[i],
1218 names_nocache[i],
1219 true);
1220 (*name_types)[*num_names] = name_types_nocache[i];
1221 (*num_names)++;
1225 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1226 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1227 "not map any SIDs at all.\n"));
1228 /* Don't handle this as an error here.
1229 * There is nothing left to do with respect to the
1230 * overall result... */
1232 else if (!NT_STATUS_IS_OK(status)) {
1233 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1234 "sids via rpc_lsa_lookup_sids: %s\n",
1235 (int)num_members, nt_errstr(status)));
1236 goto done;
1240 status = NT_STATUS_OK;
1241 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1242 sid_string_dbg(group_sid)));
1244 done:
1246 TALLOC_FREE(tmp_ctx);
1248 return status;
1251 /* find the sequence number for a domain */
1252 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1254 ADS_STRUCT *ads = NULL;
1255 ADS_STATUS rc;
1257 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1259 if ( !winbindd_can_contact_domain( domain ) ) {
1260 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1261 domain->name));
1262 *seq = time(NULL);
1263 return NT_STATUS_OK;
1266 *seq = DOM_SEQUENCE_NONE;
1268 ads = ads_cached_connection(domain);
1270 if (!ads) {
1271 domain->last_status = NT_STATUS_SERVER_DISABLED;
1272 return NT_STATUS_UNSUCCESSFUL;
1275 rc = ads_USN(ads, seq);
1277 if (!ADS_ERR_OK(rc)) {
1279 /* its a dead connection, destroy it */
1281 if (domain->private_data) {
1282 ads = (ADS_STRUCT *)domain->private_data;
1283 ads->is_mine = True;
1284 ads_destroy(&ads);
1285 ads_kdestroy("MEMORY:winbind_ccache");
1286 domain->private_data = NULL;
1289 return ads_ntstatus(rc);
1292 /* find the lockout policy of a domain - use rpc methods */
1293 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1294 TALLOC_CTX *mem_ctx,
1295 struct samr_DomInfo12 *policy)
1297 return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
1300 /* find the password policy of a domain - use rpc methods */
1301 static NTSTATUS password_policy(struct winbindd_domain *domain,
1302 TALLOC_CTX *mem_ctx,
1303 struct samr_DomInfo1 *policy)
1305 return reconnect_methods.password_policy(domain, mem_ctx, policy);
1308 /* get a list of trusted domains */
1309 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1310 TALLOC_CTX *mem_ctx,
1311 struct netr_DomainTrustList *trusts)
1313 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1314 WERROR werr;
1315 int i;
1316 uint32 flags;
1317 struct rpc_pipe_client *cli;
1318 int ret_count;
1319 struct dcerpc_binding_handle *b;
1321 DEBUG(3,("ads: trusted_domains\n"));
1323 ZERO_STRUCTP(trusts);
1325 /* If this is our primary domain or a root in our forest,
1326 query for all trusts. If not, then just look for domain
1327 trusts in the target forest */
1329 if (domain->primary || domain_is_forest_root(domain)) {
1330 flags = NETR_TRUST_FLAG_OUTBOUND |
1331 NETR_TRUST_FLAG_INBOUND |
1332 NETR_TRUST_FLAG_IN_FOREST;
1333 } else {
1334 flags = NETR_TRUST_FLAG_IN_FOREST;
1337 result = cm_connect_netlogon(domain, &cli);
1339 if (!NT_STATUS_IS_OK(result)) {
1340 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1341 "for PIPE_NETLOGON (%s)\n",
1342 domain->name, nt_errstr(result)));
1343 return NT_STATUS_UNSUCCESSFUL;
1346 b = cli->binding_handle;
1348 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1349 cli->desthost,
1350 flags,
1351 trusts,
1352 &werr);
1353 if (!NT_STATUS_IS_OK(result)) {
1354 return result;
1357 if (!W_ERROR_IS_OK(werr)) {
1358 return werror_to_ntstatus(werr);
1360 if (trusts->count == 0) {
1361 return NT_STATUS_OK;
1364 /* Copy across names and sids */
1366 ret_count = 0;
1367 for (i = 0; i < trusts->count; i++) {
1368 struct netr_DomainTrust *trust = &trusts->array[i];
1369 struct winbindd_domain d;
1371 ZERO_STRUCT(d);
1374 * drop external trusts if this is not our primary
1375 * domain. This means that the returned number of
1376 * domains may be less that the ones actually trusted
1377 * by the DC.
1380 if ((trust->trust_attributes
1381 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1382 !domain->primary )
1384 DEBUG(10,("trusted_domains: Skipping external trusted "
1385 "domain %s because it is outside of our "
1386 "primary domain\n",
1387 trust->netbios_name));
1388 continue;
1391 /* add to the trusted domain cache */
1393 fstrcpy(d.name, trust->netbios_name);
1394 fstrcpy(d.alt_name, trust->dns_name);
1395 if (trust->sid) {
1396 sid_copy(&d.sid, trust->sid);
1397 } else {
1398 sid_copy(&d.sid, &global_sid_NULL);
1401 if ( domain->primary ) {
1402 DEBUG(10,("trusted_domains(ads): Searching "
1403 "trusted domain list of %s and storing "
1404 "trust flags for domain %s\n",
1405 domain->name, d.alt_name));
1407 d.domain_flags = trust->trust_flags;
1408 d.domain_type = trust->trust_type;
1409 d.domain_trust_attribs = trust->trust_attributes;
1411 wcache_tdc_add_domain( &d );
1412 ret_count++;
1413 } else if (domain_is_forest_root(domain)) {
1414 /* Check if we already have this record. If
1415 * we are following our forest root that is not
1416 * our primary domain, we want to keep trust
1417 * flags from the perspective of our primary
1418 * domain not our forest root. */
1419 struct winbindd_tdc_domain *exist = NULL;
1421 exist = wcache_tdc_fetch_domain(
1422 talloc_tos(), trust->netbios_name);
1423 if (!exist) {
1424 DEBUG(10,("trusted_domains(ads): Searching "
1425 "trusted domain list of %s and "
1426 "storing trust flags for domain "
1427 "%s\n", domain->name, d.alt_name));
1428 d.domain_flags = trust->trust_flags;
1429 d.domain_type = trust->trust_type;
1430 d.domain_trust_attribs =
1431 trust->trust_attributes;
1433 wcache_tdc_add_domain( &d );
1434 ret_count++;
1436 TALLOC_FREE(exist);
1437 } else {
1438 /* This gets a little tricky. If we are
1439 following a transitive forest trust, then
1440 innerit the flags, type, and attribs from
1441 the domain we queried to make sure we don't
1442 record the view of the trust from the wrong
1443 side. Always view it from the side of our
1444 primary domain. --jerry */
1445 struct winbindd_tdc_domain *parent = NULL;
1447 DEBUG(10,("trusted_domains(ads): Searching "
1448 "trusted domain list of %s and inheriting "
1449 "trust flags for domain %s\n",
1450 domain->name, d.alt_name));
1452 parent = wcache_tdc_fetch_domain(talloc_tos(),
1453 domain->name);
1454 if (parent) {
1455 d.domain_flags = parent->trust_flags;
1456 d.domain_type = parent->trust_type;
1457 d.domain_trust_attribs = parent->trust_attribs;
1458 } else {
1459 d.domain_flags = domain->domain_flags;
1460 d.domain_type = domain->domain_type;
1461 d.domain_trust_attribs =
1462 domain->domain_trust_attribs;
1464 TALLOC_FREE(parent);
1466 wcache_tdc_add_domain( &d );
1467 ret_count++;
1470 return result;
1473 /* the ADS backend methods are exposed via this structure */
1474 struct winbindd_methods ads_methods = {
1475 True,
1476 query_user_list,
1477 enum_dom_groups,
1478 enum_local_groups,
1479 name_to_sid,
1480 sid_to_name,
1481 rids_to_names,
1482 query_user,
1483 lookup_usergroups,
1484 lookup_useraliases,
1485 lookup_groupmem,
1486 sequence_number,
1487 lockout_policy,
1488 password_policy,
1489 trusted_domains,
1492 #endif