s4:librpc/rpc: let dcerpc_ship_next_request() use DCERPC_AUTH_PAD_ALIGNMENT define
[Samba.git] / source3 / winbindd / winbindd_ads.c
blobfb0bc2698c721e8c296ffe3e4ed64a89a1654c5c
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 "../libcli/ldap/ldap_ndr.h"
31 #include "../libcli/security/security.h"
32 #include "../libds/common/flag_mapping.h"
33 #include "passdb.h"
35 #ifdef HAVE_ADS
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_WINBIND
40 extern struct winbindd_methods reconnect_methods;
42 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
44 /**
45 * Check if cached connection can be reused. If the connection cannot
46 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
48 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
51 ADS_STRUCT *ads = *adsp;
53 if (ads != NULL) {
54 time_t expire;
55 time_t now = time(NULL);
57 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
59 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
60 "is now %d)\n", (uint32)expire - (uint32)now,
61 (uint32) expire, (uint32) now));
63 if ( ads->config.realm && (expire > now)) {
64 return;
65 } else {
66 /* we own this ADS_STRUCT so make sure it goes away */
67 DEBUG(7,("Deleting expired krb5 credential cache\n"));
68 ads->is_mine = True;
69 ads_destroy( &ads );
70 ads_kdestroy(WINBIND_CCACHE_NAME);
71 *adsp = NULL;
76 static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
77 const char *dom_name_alt,
78 const char *dom_name,
79 const char *ldap_server,
80 char *password,
81 char *realm,
82 time_t renewable)
84 ADS_STRUCT *ads;
85 ADS_STATUS status;
86 struct sockaddr_storage dc_ss;
87 fstring dc_name;
89 if (realm == NULL) {
90 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
93 /* we don't want this to affect the users ccache */
94 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
96 ads = ads_init(dom_name_alt, dom_name, ldap_server);
97 if (!ads) {
98 DEBUG(1,("ads_init for domain %s failed\n", dom_name));
99 return ADS_ERROR(LDAP_NO_MEMORY);
102 SAFE_FREE(ads->auth.password);
103 SAFE_FREE(ads->auth.realm);
105 ads->auth.renewable = renewable;
106 ads->auth.password = password;
108 ads->auth.realm = SMB_STRDUP(realm);
109 if (!strupper_m(ads->auth.realm)) {
110 ads_destroy(&ads);
111 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
114 /* Setup the server affinity cache. We don't reaally care
115 about the name. Just setup affinity and the KRB5_CONFIG
116 file. */
117 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
119 status = ads_connect(ads);
120 if (!ADS_ERR_OK(status)) {
121 DEBUG(1,("ads_connect for domain %s failed: %s\n",
122 dom_name, ads_errstr(status)));
123 ads_destroy(&ads);
124 return status;
127 /* set the flag that says we don't own the memory even
128 though we do so that ads_destroy() won't destroy the
129 structure we pass back by reference */
131 ads->is_mine = False;
133 *adsp = ads;
135 return status;
138 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
140 char *ldap_server, *realm, *password;
141 struct winbindd_domain *wb_dom;
142 ADS_STATUS status;
144 ads_cached_connection_reuse(adsp);
145 if (*adsp != NULL) {
146 return ADS_SUCCESS;
150 * At this point we only have the NetBIOS domain name.
151 * Check if we can get server nam and realm from SAF cache
152 * and the domain list.
154 ldap_server = saf_fetch(dom_name);
155 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
156 ldap_server ? ldap_server : ""));
158 wb_dom = find_domain_from_name(dom_name);
159 if (wb_dom == NULL) {
160 DEBUG(10, ("could not find domain '%s'\n", dom_name));
161 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
164 DEBUG(10, ("find_domain_from_name found realm '%s' for "
165 " domain '%s'\n", wb_dom->alt_name, dom_name));
167 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
168 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
171 if (IS_DC) {
172 SMB_ASSERT(wb_dom->alt_name != NULL);
173 realm = SMB_STRDUP(wb_dom->alt_name);
174 } else {
175 struct winbindd_domain *our_domain = wb_dom;
177 /* always give preference to the alt_name in our
178 primary domain if possible */
180 if (!wb_dom->primary) {
181 our_domain = find_our_domain();
184 if (our_domain->alt_name != NULL) {
185 realm = SMB_STRDUP(our_domain->alt_name);
186 } else {
187 realm = SMB_STRDUP(lp_realm());
191 status = ads_cached_connection_connect(
192 adsp, /* Returns ads struct. */
193 wb_dom->alt_name, /* realm to connect to. */
194 dom_name, /* 'workgroup' name for ads_init */
195 ldap_server, /* DNS name to connect to. */
196 password, /* password for auth realm. */
197 realm, /* realm used for krb5 ticket. */
198 0); /* renewable ticket time. */
200 SAFE_FREE(realm);
202 return status;
206 return our ads connections structure for a domain. We keep the connection
207 open to make things faster
209 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
211 ADS_STATUS status;
212 char *password, *realm;
214 DEBUG(10,("ads_cached_connection\n"));
215 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
217 if (domain->private_data) {
218 return (ADS_STRUCT *)domain->private_data;
221 /* the machine acct password might have change - fetch it every time */
223 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
224 return NULL;
227 if ( IS_DC ) {
228 SMB_ASSERT(domain->alt_name != NULL);
229 realm = SMB_STRDUP(domain->alt_name);
231 else {
232 struct winbindd_domain *our_domain = domain;
235 /* always give preference to the alt_name in our
236 primary domain if possible */
238 if ( !domain->primary )
239 our_domain = find_our_domain();
241 if (our_domain->alt_name != NULL) {
242 realm = SMB_STRDUP( our_domain->alt_name );
244 else
245 realm = SMB_STRDUP( lp_realm() );
248 status = ads_cached_connection_connect(
249 (ADS_STRUCT **)&domain->private_data,
250 domain->alt_name,
251 domain->name, NULL,
252 password, realm,
253 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
254 SAFE_FREE(realm);
256 if (!ADS_ERR_OK(status)) {
257 /* if we get ECONNREFUSED then it might be a NT4
258 server, fall back to MSRPC */
259 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
260 status.err.rc == ECONNREFUSED) {
261 /* 'reconnect_methods' is the MS-RPC backend. */
262 DEBUG(1,("Trying MSRPC methods\n"));
263 domain->backend = &reconnect_methods;
265 return NULL;
268 return (ADS_STRUCT *)domain->private_data;
271 /* Query display info for a realm. This is the basic user list fn */
272 static NTSTATUS query_user_list(struct winbindd_domain *domain,
273 TALLOC_CTX *mem_ctx,
274 uint32 *num_entries,
275 struct wbint_userinfo **pinfo)
277 ADS_STRUCT *ads = NULL;
278 const char *attrs[] = { "*", NULL };
279 int i, count;
280 ADS_STATUS rc;
281 LDAPMessage *res = NULL;
282 LDAPMessage *msg = NULL;
283 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
285 *num_entries = 0;
287 DEBUG(3,("ads: query_user_list\n"));
289 if ( !winbindd_can_contact_domain( domain ) ) {
290 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
291 domain->name));
292 return NT_STATUS_OK;
295 ads = ads_cached_connection(domain);
297 if (!ads) {
298 domain->last_status = NT_STATUS_SERVER_DISABLED;
299 goto done;
302 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
303 if (!ADS_ERR_OK(rc)) {
304 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
305 status = ads_ntstatus(rc);
306 } else if (!res) {
307 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
309 goto done;
312 count = ads_count_replies(ads, res);
313 if (count == 0) {
314 DEBUG(1,("query_user_list: No users found\n"));
315 goto done;
318 (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
319 if (!*pinfo) {
320 status = NT_STATUS_NO_MEMORY;
321 goto done;
324 count = 0;
326 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
327 struct wbint_userinfo *info = &((*pinfo)[count]);
328 uint32 group;
329 uint32 atype;
331 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
332 ds_atype_map(atype) != SID_NAME_USER) {
333 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
334 continue;
337 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
338 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
339 info->homedir = NULL;
340 info->shell = NULL;
341 info->primary_gid = (gid_t)-1;
343 if (!ads_pull_sid(ads, msg, "objectSid",
344 &info->user_sid)) {
345 DEBUG(1, ("No sid for %s !?\n", info->acct_name));
346 continue;
349 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
350 DEBUG(1, ("No primary group for %s !?\n",
351 info->acct_name));
352 continue;
354 sid_compose(&info->group_sid, &domain->sid, group);
356 count += 1;
359 (*num_entries) = count;
360 ads_msgfree(ads, res);
362 for (i=0; i<count; i++) {
363 struct wbint_userinfo *info = &((*pinfo)[i]);
364 const char *gecos = NULL;
365 gid_t primary_gid = (gid_t)-1;
367 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
368 &info->homedir, &info->shell,
369 &gecos, &primary_gid);
370 if (!NT_STATUS_IS_OK(status)) {
372 * Deliberately ignore this error, there might be more
373 * users to fill
375 continue;
378 if (gecos != NULL) {
379 info->full_name = gecos;
381 info->primary_gid = primary_gid;
384 status = NT_STATUS_OK;
386 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
388 done:
389 return status;
392 /* list all domain groups */
393 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
394 TALLOC_CTX *mem_ctx,
395 uint32 *num_entries,
396 struct wb_acct_info **info)
398 ADS_STRUCT *ads = NULL;
399 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
400 "name", "objectSid", NULL};
401 int i, count;
402 ADS_STATUS rc;
403 LDAPMessage *res = NULL;
404 LDAPMessage *msg = NULL;
405 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
406 const char *filter;
407 bool enum_dom_local_groups = False;
409 *num_entries = 0;
411 DEBUG(3,("ads: enum_dom_groups\n"));
413 if ( !winbindd_can_contact_domain( domain ) ) {
414 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
415 domain->name));
416 return NT_STATUS_OK;
419 /* only grab domain local groups for our domain */
420 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
421 enum_dom_local_groups = True;
424 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
425 * rollup-fixes:
427 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
428 * default value, it MUST be absent. In case of extensible matching the
429 * "dnattr" boolean defaults to FALSE and so it must be only be present
430 * when set to TRUE.
432 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
433 * filter using bitwise matching rule then the buggy AD fails to decode
434 * the extensible match. As a workaround set it to TRUE and thereby add
435 * the dnAttributes "dn" field to cope with those older AD versions.
436 * It should not harm and won't put any additional load on the AD since
437 * none of the dn components have a bitmask-attribute.
439 * Thanks to Ralf Haferkamp for input and testing - Guenther */
441 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
442 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
443 ADS_LDAP_MATCHING_RULE_BIT_AND,
444 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
446 if (filter == NULL) {
447 status = NT_STATUS_NO_MEMORY;
448 goto done;
451 ads = ads_cached_connection(domain);
453 if (!ads) {
454 domain->last_status = NT_STATUS_SERVER_DISABLED;
455 goto done;
458 rc = ads_search_retry(ads, &res, filter, attrs);
459 if (!ADS_ERR_OK(rc)) {
460 status = ads_ntstatus(rc);
461 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
462 goto done;
463 } else if (!res) {
464 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
465 goto done;
468 count = ads_count_replies(ads, res);
469 if (count == 0) {
470 DEBUG(1,("enum_dom_groups: No groups found\n"));
471 goto done;
474 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
475 if (!*info) {
476 status = NT_STATUS_NO_MEMORY;
477 goto done;
480 i = 0;
482 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
483 char *name, *gecos;
484 struct dom_sid sid;
485 uint32 rid;
487 name = ads_pull_username(ads, mem_ctx, msg);
488 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
489 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
490 DEBUG(1,("No sid for %s !?\n", name));
491 continue;
494 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
495 DEBUG(1,("No rid for %s !?\n", name));
496 continue;
499 fstrcpy((*info)[i].acct_name, name);
500 fstrcpy((*info)[i].acct_desc, gecos);
501 (*info)[i].rid = rid;
502 i++;
505 (*num_entries) = i;
507 status = NT_STATUS_OK;
509 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
511 done:
512 if (res)
513 ads_msgfree(ads, res);
515 return status;
518 /* list all domain local groups */
519 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
520 TALLOC_CTX *mem_ctx,
521 uint32 *num_entries,
522 struct wb_acct_info **info)
525 * This is a stub function only as we returned the domain
526 * local groups in enum_dom_groups() if the domain->native field
527 * was true. This is a simple performance optimization when
528 * using LDAP.
530 * if we ever need to enumerate domain local groups separately,
531 * then this optimization in enum_dom_groups() will need
532 * to be split out
534 *num_entries = 0;
536 return NT_STATUS_OK;
539 /* convert a single name to a sid in a domain - use rpc methods */
540 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
541 TALLOC_CTX *mem_ctx,
542 const char *domain_name,
543 const char *name,
544 uint32_t flags,
545 struct dom_sid *sid,
546 enum lsa_SidType *type)
548 return reconnect_methods.name_to_sid(domain, mem_ctx,
549 domain_name, name, flags,
550 sid, type);
553 /* convert a domain SID to a user or group name - use rpc methods */
554 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
555 TALLOC_CTX *mem_ctx,
556 const struct dom_sid *sid,
557 char **domain_name,
558 char **name,
559 enum lsa_SidType *type)
561 return reconnect_methods.sid_to_name(domain, mem_ctx, sid,
562 domain_name, name, type);
565 /* convert a list of rids to names - use rpc methods */
566 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
567 TALLOC_CTX *mem_ctx,
568 const struct dom_sid *sid,
569 uint32 *rids,
570 size_t num_rids,
571 char **domain_name,
572 char ***names,
573 enum lsa_SidType **types)
575 return reconnect_methods.rids_to_names(domain, mem_ctx, sid,
576 rids, num_rids,
577 domain_name, names, types);
580 /* If you are looking for "dn_lookup": Yes, it used to be here!
581 * It has gone now since it was a major speed bottleneck in
582 * lookup_groupmem (its only use). It has been replaced by
583 * an rpc lookup sids call... R.I.P. */
585 /* Lookup user information from a rid */
586 static NTSTATUS query_user(struct winbindd_domain *domain,
587 TALLOC_CTX *mem_ctx,
588 const struct dom_sid *sid,
589 struct wbint_userinfo *info)
591 ADS_STRUCT *ads = NULL;
592 const char *attrs[] = { "*", NULL };
593 ADS_STATUS rc;
594 int count;
595 LDAPMessage *msg = NULL;
596 char *ldap_exp;
597 char *sidstr;
598 uint32 group_rid;
599 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
600 struct netr_SamInfo3 *user = NULL;
601 gid_t gid = -1;
602 int ret;
603 char *ads_name;
605 DEBUG(3,("ads: query_user\n"));
607 info->homedir = NULL;
608 info->shell = NULL;
610 /* try netsamlogon cache first */
612 if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
614 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
615 sid_string_dbg(sid)));
617 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
618 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
620 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
621 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
623 nss_get_info_cached( domain, sid, mem_ctx,
624 &info->homedir, &info->shell, &info->full_name,
625 &gid );
626 info->primary_gid = gid;
628 TALLOC_FREE(user);
630 return NT_STATUS_OK;
633 if ( !winbindd_can_contact_domain(domain)) {
634 DEBUG(8,("query_user: No incoming trust from domain %s\n",
635 domain->name));
637 /* We still need to generate some basic information
638 about the user even if we cannot contact the
639 domain. Most of this stuff we can deduce. */
641 sid_copy( &info->user_sid, sid );
643 /* Assume "Domain Users" for the primary group */
645 sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
647 /* Try to fill in what the nss_info backend can do */
649 nss_get_info_cached( domain, sid, mem_ctx,
650 &info->homedir, &info->shell, &info->full_name,
651 &gid);
652 info->primary_gid = gid;
654 return NT_STATUS_OK;
657 /* no cache...do the query */
659 if ( (ads = ads_cached_connection(domain)) == NULL ) {
660 domain->last_status = NT_STATUS_SERVER_DISABLED;
661 return NT_STATUS_SERVER_DISABLED;
664 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
666 ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
667 TALLOC_FREE(sidstr);
668 if (ret == -1) {
669 return NT_STATUS_NO_MEMORY;
671 rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
672 SAFE_FREE(ldap_exp);
673 if (!ADS_ERR_OK(rc)) {
674 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
675 sid_string_dbg(sid), ads_errstr(rc)));
676 return ads_ntstatus(rc);
677 } else if (!msg) {
678 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
679 sid_string_dbg(sid)));
680 return NT_STATUS_INTERNAL_ERROR;
683 count = ads_count_replies(ads, msg);
684 if (count != 1) {
685 DEBUG(1,("query_user(sid=%s): Not found\n",
686 sid_string_dbg(sid)));
687 ads_msgfree(ads, msg);
688 return NT_STATUS_NO_SUCH_USER;
691 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
693 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
694 DEBUG(1,("No primary group for %s !?\n",
695 sid_string_dbg(sid)));
696 ads_msgfree(ads, msg);
697 return NT_STATUS_NO_SUCH_USER;
699 sid_copy(&info->user_sid, sid);
700 sid_compose(&info->group_sid, &domain->sid, group_rid);
703 * We have to fetch the "name" attribute before doing the
704 * nss_get_info_cached call. nss_get_info_cached might destroy
705 * the ads struct, potentially invalidating the ldap message.
707 ads_name = ads_pull_string(ads, mem_ctx, msg, "name");
709 ads_msgfree(ads, msg);
710 msg = NULL;
712 status = nss_get_info_cached( domain, sid, mem_ctx,
713 &info->homedir, &info->shell, &info->full_name,
714 &gid);
715 info->primary_gid = gid;
716 if (!NT_STATUS_IS_OK(status)) {
717 DEBUG(1, ("nss_get_info_cached failed: %s\n",
718 nt_errstr(status)));
719 return status;
722 if (info->full_name == NULL) {
723 info->full_name = ads_name;
724 } else {
725 TALLOC_FREE(ads_name);
728 status = NT_STATUS_OK;
730 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
731 return NT_STATUS_OK;
734 /* Lookup groups a user is a member of - alternate method, for when
735 tokenGroups are not available. */
736 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
737 TALLOC_CTX *mem_ctx,
738 const char *user_dn,
739 struct dom_sid *primary_group,
740 uint32_t *p_num_groups, struct dom_sid **user_sids)
742 ADS_STATUS rc;
743 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
744 int count;
745 LDAPMessage *res = NULL;
746 LDAPMessage *msg = NULL;
747 char *ldap_exp;
748 ADS_STRUCT *ads;
749 const char *group_attrs[] = {"objectSid", NULL};
750 char *escaped_dn;
751 uint32_t num_groups = 0;
753 DEBUG(3,("ads: lookup_usergroups_member\n"));
755 if ( !winbindd_can_contact_domain( domain ) ) {
756 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
757 domain->name));
758 return NT_STATUS_OK;
761 ads = ads_cached_connection(domain);
763 if (!ads) {
764 domain->last_status = NT_STATUS_SERVER_DISABLED;
765 goto done;
768 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
769 status = NT_STATUS_NO_MEMORY;
770 goto done;
773 ldap_exp = talloc_asprintf(mem_ctx,
774 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
775 escaped_dn,
776 ADS_LDAP_MATCHING_RULE_BIT_AND,
777 GROUP_TYPE_SECURITY_ENABLED);
778 if (!ldap_exp) {
779 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
780 TALLOC_FREE(escaped_dn);
781 status = NT_STATUS_NO_MEMORY;
782 goto done;
785 TALLOC_FREE(escaped_dn);
787 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
789 if (!ADS_ERR_OK(rc)) {
790 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
791 return ads_ntstatus(rc);
792 } else if (!res) {
793 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
794 return NT_STATUS_INTERNAL_ERROR;
798 count = ads_count_replies(ads, res);
800 *user_sids = NULL;
801 num_groups = 0;
803 /* always add the primary group to the sid array */
804 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
805 &num_groups);
806 if (!NT_STATUS_IS_OK(status)) {
807 goto done;
810 if (count > 0) {
811 for (msg = ads_first_entry(ads, res); msg;
812 msg = ads_next_entry(ads, msg)) {
813 struct dom_sid group_sid;
815 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
816 DEBUG(1,("No sid for this group ?!?\n"));
817 continue;
820 /* ignore Builtin groups from ADS - Guenther */
821 if (sid_check_is_in_builtin(&group_sid)) {
822 continue;
825 status = add_sid_to_array(mem_ctx, &group_sid,
826 user_sids, &num_groups);
827 if (!NT_STATUS_IS_OK(status)) {
828 goto done;
834 *p_num_groups = num_groups;
835 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
837 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
838 done:
839 if (res)
840 ads_msgfree(ads, res);
842 return status;
845 /* Lookup groups a user is a member of - alternate method, for when
846 tokenGroups are not available. */
847 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
848 TALLOC_CTX *mem_ctx,
849 const char *user_dn,
850 struct dom_sid *primary_group,
851 uint32_t *p_num_groups,
852 struct dom_sid **user_sids)
854 ADS_STATUS rc;
855 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
856 ADS_STRUCT *ads;
857 const char *attrs[] = {"memberOf", NULL};
858 uint32_t num_groups = 0;
859 struct dom_sid *group_sids = NULL;
860 int i;
861 char **strings = NULL;
862 size_t num_strings = 0, num_sids = 0;
865 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
867 if ( !winbindd_can_contact_domain( domain ) ) {
868 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
869 "domain %s\n", domain->name));
870 return NT_STATUS_OK;
873 ads = ads_cached_connection(domain);
875 if (!ads) {
876 domain->last_status = NT_STATUS_SERVER_DISABLED;
877 return NT_STATUS_UNSUCCESSFUL;
880 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
881 ADS_EXTENDED_DN_HEX_STRING,
882 &strings, &num_strings);
884 if (!ADS_ERR_OK(rc)) {
885 DEBUG(1,("lookup_usergroups_memberof ads_search "
886 "member=%s: %s\n", user_dn, ads_errstr(rc)));
887 return ads_ntstatus(rc);
890 *user_sids = NULL;
891 num_groups = 0;
893 /* always add the primary group to the sid array */
894 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
895 &num_groups);
896 if (!NT_STATUS_IS_OK(status)) {
897 goto done;
900 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
901 if (!group_sids) {
902 status = NT_STATUS_NO_MEMORY;
903 goto done;
906 for (i=0; i<num_strings; i++) {
907 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
908 ADS_EXTENDED_DN_HEX_STRING,
909 &(group_sids)[i]);
910 if (!ADS_ERR_OK(rc)) {
911 /* ignore members without SIDs */
912 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
913 NT_STATUS_NOT_FOUND)) {
914 continue;
916 else {
917 status = ads_ntstatus(rc);
918 goto done;
921 num_sids++;
924 if (i == 0) {
925 DEBUG(1,("No memberOf for this user?!?\n"));
926 status = NT_STATUS_NO_MEMORY;
927 goto done;
930 for (i=0; i<num_sids; i++) {
932 /* ignore Builtin groups from ADS - Guenther */
933 if (sid_check_is_in_builtin(&group_sids[i])) {
934 continue;
937 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
938 &num_groups);
939 if (!NT_STATUS_IS_OK(status)) {
940 goto done;
945 *p_num_groups = num_groups;
946 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
948 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
949 user_dn));
951 done:
952 TALLOC_FREE(strings);
953 TALLOC_FREE(group_sids);
955 return status;
959 /* Lookup groups a user is a member of. */
960 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
961 TALLOC_CTX *mem_ctx,
962 const struct dom_sid *sid,
963 uint32 *p_num_groups, struct dom_sid **user_sids)
965 ADS_STRUCT *ads = NULL;
966 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
967 ADS_STATUS rc;
968 int count;
969 LDAPMessage *msg = NULL;
970 char *user_dn = NULL;
971 struct dom_sid *sids;
972 int i;
973 struct dom_sid primary_group;
974 uint32 primary_group_rid;
975 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
976 uint32_t num_groups = 0;
978 DEBUG(3,("ads: lookup_usergroups\n"));
979 *p_num_groups = 0;
981 status = lookup_usergroups_cached(domain, mem_ctx, sid,
982 p_num_groups, user_sids);
983 if (NT_STATUS_IS_OK(status)) {
984 return NT_STATUS_OK;
987 if ( !winbindd_can_contact_domain( domain ) ) {
988 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
989 domain->name));
991 /* Tell the cache manager not to remember this one */
993 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
996 ads = ads_cached_connection(domain);
998 if (!ads) {
999 domain->last_status = NT_STATUS_SERVER_DISABLED;
1000 status = NT_STATUS_SERVER_DISABLED;
1001 goto done;
1004 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
1006 if (!ADS_ERR_OK(rc)) {
1007 status = ads_ntstatus(rc);
1008 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1009 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
1010 goto done;
1013 count = ads_count_replies(ads, msg);
1014 if (count != 1) {
1015 status = NT_STATUS_UNSUCCESSFUL;
1016 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1017 "invalid number of results (count=%d)\n",
1018 sid_string_dbg(sid), count));
1019 goto done;
1022 if (!msg) {
1023 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
1024 sid_string_dbg(sid)));
1025 status = NT_STATUS_UNSUCCESSFUL;
1026 goto done;
1029 user_dn = ads_get_dn(ads, mem_ctx, msg);
1030 if (user_dn == NULL) {
1031 status = NT_STATUS_NO_MEMORY;
1032 goto done;
1035 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
1036 DEBUG(1,("%s: No primary group for sid=%s !?\n",
1037 domain->name, sid_string_dbg(sid)));
1038 goto done;
1041 sid_compose(&primary_group, &domain->sid, primary_group_rid);
1043 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
1045 /* there must always be at least one group in the token,
1046 unless we are talking to a buggy Win2k server */
1048 /* actually this only happens when the machine account has no read
1049 * permissions on the tokenGroup attribute - gd */
1051 if (count == 0) {
1053 /* no tokenGroups */
1055 /* lookup what groups this user is a member of by DN search on
1056 * "memberOf" */
1058 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
1059 &primary_group,
1060 &num_groups, user_sids);
1061 *p_num_groups = num_groups;
1062 if (NT_STATUS_IS_OK(status)) {
1063 goto done;
1066 /* lookup what groups this user is a member of by DN search on
1067 * "member" */
1069 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
1070 &primary_group,
1071 &num_groups, user_sids);
1072 *p_num_groups = num_groups;
1073 goto done;
1076 *user_sids = NULL;
1077 num_groups = 0;
1079 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
1080 &num_groups);
1081 if (!NT_STATUS_IS_OK(status)) {
1082 goto done;
1085 for (i=0;i<count;i++) {
1087 /* ignore Builtin groups from ADS - Guenther */
1088 if (sid_check_is_in_builtin(&sids[i])) {
1089 continue;
1092 status = add_sid_to_array_unique(mem_ctx, &sids[i],
1093 user_sids, &num_groups);
1094 if (!NT_STATUS_IS_OK(status)) {
1095 goto done;
1099 *p_num_groups = (uint32)num_groups;
1100 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1102 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1103 sid_string_dbg(sid)));
1104 done:
1105 TALLOC_FREE(user_dn);
1106 ads_msgfree(ads, msg);
1107 return status;
1110 /* Lookup aliases a user is member of - use rpc methods */
1111 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1112 TALLOC_CTX *mem_ctx,
1113 uint32 num_sids, const struct dom_sid *sids,
1114 uint32 *num_aliases, uint32 **alias_rids)
1116 return reconnect_methods.lookup_useraliases(domain, mem_ctx,
1117 num_sids, sids,
1118 num_aliases,
1119 alias_rids);
1123 find the members of a group, given a group rid and domain
1125 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1126 TALLOC_CTX *mem_ctx,
1127 const struct dom_sid *group_sid,
1128 enum lsa_SidType type,
1129 uint32 *num_names,
1130 struct dom_sid **sid_mem, char ***names,
1131 uint32 **name_types)
1133 ADS_STATUS rc;
1134 ADS_STRUCT *ads = NULL;
1135 char *ldap_exp;
1136 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1137 char *sidbinstr;
1138 char **members = NULL;
1139 int i;
1140 size_t num_members = 0;
1141 ads_control args;
1142 struct dom_sid *sid_mem_nocache = NULL;
1143 char **names_nocache = NULL;
1144 enum lsa_SidType *name_types_nocache = NULL;
1145 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1146 uint32 num_nocache = 0;
1147 TALLOC_CTX *tmp_ctx = NULL;
1149 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1150 sid_string_dbg(group_sid)));
1152 *num_names = 0;
1154 tmp_ctx = talloc_new(mem_ctx);
1155 if (!tmp_ctx) {
1156 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1157 status = NT_STATUS_NO_MEMORY;
1158 goto done;
1161 if ( !winbindd_can_contact_domain( domain ) ) {
1162 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1163 domain->name));
1164 return NT_STATUS_OK;
1167 ads = ads_cached_connection(domain);
1169 if (!ads) {
1170 domain->last_status = NT_STATUS_SERVER_DISABLED;
1171 goto done;
1174 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1175 status = NT_STATUS_NO_MEMORY;
1176 goto done;
1179 /* search for all members of the group */
1180 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1181 TALLOC_FREE(sidbinstr);
1182 if (ldap_exp == NULL) {
1183 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1184 status = NT_STATUS_NO_MEMORY;
1185 goto done;
1188 args.control = ADS_EXTENDED_DN_OID;
1189 args.val = ADS_EXTENDED_DN_HEX_STRING;
1190 args.critical = True;
1192 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1193 ldap_exp, &args, "member", &members, &num_members);
1195 if (!ADS_ERR_OK(rc)) {
1196 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1197 status = NT_STATUS_UNSUCCESSFUL;
1198 goto done;
1201 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1203 /* Now that we have a list of sids, we need to get the
1204 * lists of names and name_types belonging to these sids.
1205 * even though conceptually not quite clean, we use the
1206 * RPC call lsa_lookup_sids for this since it can handle a
1207 * list of sids. ldap calls can just resolve one sid at a time.
1209 * At this stage, the sids are still hidden in the exetended dn
1210 * member output format. We actually do a little better than
1211 * stated above: In extracting the sids from the member strings,
1212 * we try to resolve as many sids as possible from the
1213 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1215 if (num_members) {
1216 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1217 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1218 (*name_types) = talloc_zero_array(mem_ctx, uint32, num_members);
1219 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1221 if ((members == NULL) || (*sid_mem == NULL) ||
1222 (*names == NULL) || (*name_types == NULL) ||
1223 (sid_mem_nocache == NULL))
1225 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1226 status = NT_STATUS_NO_MEMORY;
1227 goto done;
1230 else {
1231 (*sid_mem) = NULL;
1232 (*names) = NULL;
1233 (*name_types) = NULL;
1236 for (i=0; i<num_members; i++) {
1237 enum lsa_SidType name_type;
1238 char *name, *domain_name;
1239 struct dom_sid sid;
1241 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1242 &sid);
1243 if (!ADS_ERR_OK(rc)) {
1244 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1245 NT_STATUS_NOT_FOUND)) {
1246 /* Group members can be objects, like Exchange
1247 * Public Folders, that don't have a SID. Skip
1248 * them. */
1249 continue;
1251 else {
1252 status = ads_ntstatus(rc);
1253 goto done;
1256 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1257 &name_type)) {
1258 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1259 "cache\n", sid_string_dbg(&sid)));
1260 sid_copy(&(*sid_mem)[*num_names], &sid);
1261 (*names)[*num_names] = fill_domain_username_talloc(
1262 *names,
1263 domain_name,
1264 name,
1265 true);
1267 (*name_types)[*num_names] = name_type;
1268 (*num_names)++;
1270 else {
1271 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1272 "cache\n", sid_string_dbg(&sid)));
1273 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1274 num_nocache++;
1278 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1279 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1281 /* handle sids not resolved from cache by lsa_lookup_sids */
1282 if (num_nocache > 0) {
1284 status = winbindd_lookup_sids(tmp_ctx,
1285 domain,
1286 num_nocache,
1287 sid_mem_nocache,
1288 &domains_nocache,
1289 &names_nocache,
1290 &name_types_nocache);
1292 if (!(NT_STATUS_IS_OK(status) ||
1293 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1294 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1296 DEBUG(1, ("lsa_lookupsids call failed with %s "
1297 "- retrying...\n", nt_errstr(status)));
1299 status = winbindd_lookup_sids(tmp_ctx,
1300 domain,
1301 num_nocache,
1302 sid_mem_nocache,
1303 &domains_nocache,
1304 &names_nocache,
1305 &name_types_nocache);
1308 if (NT_STATUS_IS_OK(status) ||
1309 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1311 /* Copy the entries over from the "_nocache" arrays
1312 * to the result arrays, skipping the gaps the
1313 * lookup_sids call left. */
1314 for (i=0; i < num_nocache; i++) {
1315 if (((names_nocache)[i] != NULL) &&
1316 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1318 sid_copy(&(*sid_mem)[*num_names],
1319 &sid_mem_nocache[i]);
1320 (*names)[*num_names] =
1321 fill_domain_username_talloc(
1322 *names,
1323 domains_nocache[i],
1324 names_nocache[i],
1325 true);
1326 (*name_types)[*num_names] = name_types_nocache[i];
1327 (*num_names)++;
1331 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1332 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1333 "not map any SIDs at all.\n"));
1334 /* Don't handle this as an error here.
1335 * There is nothing left to do with respect to the
1336 * overall result... */
1338 else if (!NT_STATUS_IS_OK(status)) {
1339 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1340 "sids via rpc_lsa_lookup_sids: %s\n",
1341 (int)num_members, nt_errstr(status)));
1342 goto done;
1346 status = NT_STATUS_OK;
1347 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1348 sid_string_dbg(group_sid)));
1350 done:
1352 TALLOC_FREE(tmp_ctx);
1354 return status;
1357 /* find the sequence number for a domain */
1358 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1360 ADS_STRUCT *ads = NULL;
1361 ADS_STATUS rc;
1363 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1365 if ( !winbindd_can_contact_domain( domain ) ) {
1366 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1367 domain->name));
1368 *seq = time(NULL);
1369 return NT_STATUS_OK;
1372 *seq = DOM_SEQUENCE_NONE;
1374 ads = ads_cached_connection(domain);
1376 if (!ads) {
1377 domain->last_status = NT_STATUS_SERVER_DISABLED;
1378 return NT_STATUS_UNSUCCESSFUL;
1381 rc = ads_USN(ads, seq);
1383 if (!ADS_ERR_OK(rc)) {
1385 /* its a dead connection, destroy it */
1387 if (domain->private_data) {
1388 ads = (ADS_STRUCT *)domain->private_data;
1389 ads->is_mine = True;
1390 ads_destroy(&ads);
1391 ads_kdestroy(WINBIND_CCACHE_NAME);
1392 domain->private_data = NULL;
1395 return ads_ntstatus(rc);
1398 /* find the lockout policy of a domain - use rpc methods */
1399 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1400 TALLOC_CTX *mem_ctx,
1401 struct samr_DomInfo12 *policy)
1403 return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
1406 /* find the password policy of a domain - use rpc methods */
1407 static NTSTATUS password_policy(struct winbindd_domain *domain,
1408 TALLOC_CTX *mem_ctx,
1409 struct samr_DomInfo1 *policy)
1411 return reconnect_methods.password_policy(domain, mem_ctx, policy);
1414 /* get a list of trusted domains */
1415 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1416 TALLOC_CTX *mem_ctx,
1417 struct netr_DomainTrustList *trusts)
1419 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1420 WERROR werr;
1421 int i;
1422 uint32 flags;
1423 struct rpc_pipe_client *cli;
1424 int ret_count;
1425 struct dcerpc_binding_handle *b;
1427 DEBUG(3,("ads: trusted_domains\n"));
1429 ZERO_STRUCTP(trusts);
1431 /* If this is our primary domain or a root in our forest,
1432 query for all trusts. If not, then just look for domain
1433 trusts in the target forest */
1435 if (domain->primary || domain_is_forest_root(domain)) {
1436 flags = NETR_TRUST_FLAG_OUTBOUND |
1437 NETR_TRUST_FLAG_INBOUND |
1438 NETR_TRUST_FLAG_IN_FOREST;
1439 } else {
1440 flags = NETR_TRUST_FLAG_IN_FOREST;
1443 result = cm_connect_netlogon(domain, &cli);
1445 if (!NT_STATUS_IS_OK(result)) {
1446 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1447 "for PIPE_NETLOGON (%s)\n",
1448 domain->name, nt_errstr(result)));
1449 return NT_STATUS_UNSUCCESSFUL;
1452 b = cli->binding_handle;
1454 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1455 cli->desthost,
1456 flags,
1457 trusts,
1458 &werr);
1459 if (!NT_STATUS_IS_OK(result)) {
1460 return result;
1463 if (!W_ERROR_IS_OK(werr)) {
1464 return werror_to_ntstatus(werr);
1466 if (trusts->count == 0) {
1467 return NT_STATUS_OK;
1470 /* Copy across names and sids */
1472 ret_count = 0;
1473 for (i = 0; i < trusts->count; i++) {
1474 struct netr_DomainTrust *trust = &trusts->array[i];
1475 struct winbindd_domain d;
1477 ZERO_STRUCT(d);
1480 * drop external trusts if this is not our primary
1481 * domain. This means that the returned number of
1482 * domains may be less that the ones actually trusted
1483 * by the DC.
1486 if ((trust->trust_attributes
1487 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1488 !domain->primary )
1490 DEBUG(10,("trusted_domains: Skipping external trusted "
1491 "domain %s because it is outside of our "
1492 "primary domain\n",
1493 trust->netbios_name));
1494 continue;
1497 /* add to the trusted domain cache */
1499 d.name = discard_const_p(char, trust->netbios_name);
1500 d.alt_name = discard_const_p(char, trust->dns_name);
1502 if (trust->sid) {
1503 sid_copy(&d.sid, trust->sid);
1504 } else {
1505 sid_copy(&d.sid, &global_sid_NULL);
1508 if ( domain->primary ) {
1509 DEBUG(10,("trusted_domains(ads): Searching "
1510 "trusted domain list of %s and storing "
1511 "trust flags for domain %s\n",
1512 domain->name, d.alt_name));
1514 d.domain_flags = trust->trust_flags;
1515 d.domain_type = trust->trust_type;
1516 d.domain_trust_attribs = trust->trust_attributes;
1518 wcache_tdc_add_domain( &d );
1519 ret_count++;
1520 } else if (domain_is_forest_root(domain)) {
1521 /* Check if we already have this record. If
1522 * we are following our forest root that is not
1523 * our primary domain, we want to keep trust
1524 * flags from the perspective of our primary
1525 * domain not our forest root. */
1526 struct winbindd_tdc_domain *exist = NULL;
1528 exist = wcache_tdc_fetch_domain(
1529 talloc_tos(), trust->netbios_name);
1530 if (!exist) {
1531 DEBUG(10,("trusted_domains(ads): Searching "
1532 "trusted domain list of %s and "
1533 "storing trust flags for domain "
1534 "%s\n", domain->name, d.alt_name));
1535 d.domain_flags = trust->trust_flags;
1536 d.domain_type = trust->trust_type;
1537 d.domain_trust_attribs =
1538 trust->trust_attributes;
1540 wcache_tdc_add_domain( &d );
1541 ret_count++;
1543 TALLOC_FREE(exist);
1544 } else {
1545 /* This gets a little tricky. If we are
1546 following a transitive forest trust, then
1547 innerit the flags, type, and attribs from
1548 the domain we queried to make sure we don't
1549 record the view of the trust from the wrong
1550 side. Always view it from the side of our
1551 primary domain. --jerry */
1552 struct winbindd_tdc_domain *parent = NULL;
1554 DEBUG(10,("trusted_domains(ads): Searching "
1555 "trusted domain list of %s and inheriting "
1556 "trust flags for domain %s\n",
1557 domain->name, d.alt_name));
1559 parent = wcache_tdc_fetch_domain(talloc_tos(),
1560 domain->name);
1561 if (parent) {
1562 d.domain_flags = parent->trust_flags;
1563 d.domain_type = parent->trust_type;
1564 d.domain_trust_attribs = parent->trust_attribs;
1565 } else {
1566 d.domain_flags = domain->domain_flags;
1567 d.domain_type = domain->domain_type;
1568 d.domain_trust_attribs =
1569 domain->domain_trust_attribs;
1571 TALLOC_FREE(parent);
1573 wcache_tdc_add_domain( &d );
1574 ret_count++;
1577 return result;
1580 /* the ADS backend methods are exposed via this structure */
1581 struct winbindd_methods ads_methods = {
1582 True,
1583 query_user_list,
1584 enum_dom_groups,
1585 enum_local_groups,
1586 name_to_sid,
1587 sid_to_name,
1588 rids_to_names,
1589 query_user,
1590 lookup_usergroups,
1591 lookup_useraliases,
1592 lookup_groupmem,
1593 sequence_number,
1594 lockout_policy,
1595 password_policy,
1596 trusted_domains,
1599 #endif