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/>.
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"
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"
37 #include "auth/credentials/credentials.h"
42 #define DBGC_CLASS DBGC_WINBIND
44 extern struct winbindd_methods reconnect_methods
;
45 extern struct winbindd_methods msrpc_methods
;
47 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
50 * Check if cached connection can be reused. If the connection cannot
51 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
53 static void ads_cached_connection_reuse(ADS_STRUCT
**adsp
)
56 ADS_STRUCT
*ads
= *adsp
;
60 time_t now
= time(NULL
);
62 expire
= MIN(ads
->auth
.tgt_expire
, ads
->auth
.tgs_expire
);
64 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
65 "is now %d)\n", (uint32_t)expire
- (uint32_t)now
,
66 (uint32_t) expire
, (uint32_t) now
));
68 if ( ads
->config
.realm
&& (expire
> now
)) {
71 /* we own this ADS_STRUCT so make sure it goes away */
72 DEBUG(7,("Deleting expired krb5 credential cache\n"));
74 ads_kdestroy(WINBIND_CCACHE_NAME
);
81 * @brief Establish a connection to a DC
83 * @param[out] adsp ADS_STRUCT that will be created
84 * @param[in] target_realm Realm of domain to connect to
85 * @param[in] target_dom_name 'workgroup' name of domain to connect to
86 * @param[in] ldap_server DNS name of server to connect to
87 * @param[in] password Our machine account secret
88 * @param[in] auth_realm Realm of local domain for creating krb token
89 * @param[in] renewable Renewable ticket time
93 static ADS_STATUS
ads_cached_connection_connect(const char *target_realm
,
94 const char *target_dom_name
,
95 const char *ldap_server
,
102 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
105 struct sockaddr_storage dc_ss
;
107 enum credentials_use_kerberos krb5_state
;
109 if (auth_realm
== NULL
) {
110 TALLOC_FREE(tmp_ctx
);
111 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
114 /* we don't want this to affect the users ccache */
115 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME
, 1);
117 ads
= ads_init(tmp_ctx
,
123 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name
));
124 status
= ADS_ERROR(LDAP_NO_MEMORY
);
128 ADS_TALLOC_CONST_FREE(ads
->auth
.password
);
129 ADS_TALLOC_CONST_FREE(ads
->auth
.realm
);
131 ads
->auth
.renewable
= renewable
;
132 ads
->auth
.password
= talloc_strdup(ads
, password
);
133 if (ads
->auth
.password
== NULL
) {
134 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
138 /* In FIPS mode, client use kerberos is forced to required. */
139 krb5_state
= lp_client_use_kerberos();
140 switch (krb5_state
) {
141 case CRED_USE_KERBEROS_REQUIRED
:
142 ads
->auth
.flags
&= ~ADS_AUTH_DISABLE_KERBEROS
;
143 ads
->auth
.flags
&= ~ADS_AUTH_ALLOW_NTLMSSP
;
145 case CRED_USE_KERBEROS_DESIRED
:
146 ads
->auth
.flags
&= ~ADS_AUTH_DISABLE_KERBEROS
;
147 ads
->auth
.flags
|= ADS_AUTH_ALLOW_NTLMSSP
;
149 case CRED_USE_KERBEROS_DISABLED
:
150 ads
->auth
.flags
|= ADS_AUTH_DISABLE_KERBEROS
;
151 ads
->auth
.flags
|= ADS_AUTH_ALLOW_NTLMSSP
;
155 ads
->auth
.realm
= talloc_asprintf_strupper_m(ads
, "%s", auth_realm
);
156 if (ads
->auth
.realm
== NULL
) {
157 status
= ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
161 /* Setup the server affinity cache. We don't reaally care
162 about the name. Just setup affinity and the KRB5_CONFIG
164 get_dc_name(ads
->server
.workgroup
, ads
->server
.realm
, dc_name
, &dc_ss
);
166 status
= ads_connect(ads
);
167 if (!ADS_ERR_OK(status
)) {
168 DEBUG(1,("ads_connect for domain %s failed: %s\n",
169 target_dom_name
, ads_errstr(status
)));
173 *adsp
= talloc_move(mem_ctx
, &ads
);
175 TALLOC_FREE(tmp_ctx
);
179 ADS_STATUS
ads_idmap_cached_connection(const char *dom_name
,
183 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
184 char *ldap_server
= NULL
;
186 char *password
= NULL
;
187 struct winbindd_domain
*wb_dom
= NULL
;
192 * Make sure we never try to use LDAP against
193 * a trusted domain as AD DC.
195 TALLOC_FREE(tmp_ctx
);
196 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED
);
199 ads_cached_connection_reuse(adsp
);
201 TALLOC_FREE(tmp_ctx
);
206 * At this point we only have the NetBIOS domain name.
207 * Check if we can get server name and realm from SAF cache
208 * and the domain list.
210 ldap_server
= saf_fetch(tmp_ctx
, dom_name
);
212 DBG_DEBUG("ldap_server from saf cache: '%s'\n",
213 ldap_server
? ldap_server
: "");
215 wb_dom
= find_domain_from_name(dom_name
);
216 if (wb_dom
== NULL
) {
217 DBG_DEBUG("could not find domain '%s'\n", dom_name
);
218 status
= ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
222 DBG_DEBUG("find_domain_from_name found realm '%s' for "
223 " domain '%s'\n", wb_dom
->alt_name
, dom_name
);
225 if (!get_trust_pw_clear(dom_name
, &password
, NULL
, NULL
)) {
226 status
= ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO
);
231 SMB_ASSERT(wb_dom
->alt_name
!= NULL
);
232 realm
= talloc_strdup(tmp_ctx
, wb_dom
->alt_name
);
234 struct winbindd_domain
*our_domain
= wb_dom
;
236 /* always give preference to the alt_name in our
237 primary domain if possible */
239 if (!wb_dom
->primary
) {
240 our_domain
= find_our_domain();
243 if (our_domain
->alt_name
!= NULL
) {
244 realm
= talloc_strdup(tmp_ctx
, our_domain
->alt_name
);
246 realm
= talloc_strdup(tmp_ctx
, lp_realm());
251 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
255 status
= ads_cached_connection_connect(
256 wb_dom
->alt_name
, /* realm to connect to. */
257 dom_name
, /* 'workgroup' name for ads_init */
258 ldap_server
, /* DNS name to connect to. */
259 password
, /* password for auth realm. */
260 realm
, /* realm used for krb5 ticket. */
261 0, /* renewable ticket time. */
262 mem_ctx
, /* memory context for ads struct */
263 adsp
); /* Returns ads struct. */
266 TALLOC_FREE(tmp_ctx
);
273 return our ads connections structure for a domain. We keep the connection
274 open to make things faster
276 static ADS_STATUS
ads_cached_connection(struct winbindd_domain
*domain
,
279 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
281 char *password
= NULL
;
286 * Make sure we never try to use LDAP against
287 * a trusted domain as AD DC.
289 TALLOC_FREE(tmp_ctx
);
290 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED
);
293 DBG_DEBUG("ads_cached_connection\n");
295 ads_cached_connection_reuse(&domain
->backend_data
.ads_conn
);
296 if (domain
->backend_data
.ads_conn
!= NULL
) {
297 *adsp
= domain
->backend_data
.ads_conn
;
298 TALLOC_FREE(tmp_ctx
);
302 /* the machine acct password might have change - fetch it every time */
304 if (!get_trust_pw_clear(domain
->name
, &password
, NULL
, NULL
)) {
305 status
= ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO
);
310 SMB_ASSERT(domain
->alt_name
!= NULL
);
311 realm
= talloc_strdup(tmp_ctx
, domain
->alt_name
);
313 struct winbindd_domain
*our_domain
= domain
;
316 /* always give preference to the alt_name in our
317 primary domain if possible */
319 if ( !domain
->primary
)
320 our_domain
= find_our_domain();
322 if (our_domain
->alt_name
!= NULL
) {
323 realm
= talloc_strdup(tmp_ctx
, our_domain
->alt_name
);
325 realm
= talloc_strdup(tmp_ctx
, lp_realm() );
330 status
= ADS_ERROR_NT(NT_STATUS_NO_MEMORY
);
334 status
= ads_cached_connection_connect(
339 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
,
341 &domain
->backend_data
.ads_conn
);
342 if (!ADS_ERR_OK(status
)) {
343 /* if we get ECONNREFUSED then it might be a NT4
344 server, fall back to MSRPC */
345 if (status
.error_type
== ENUM_ADS_ERROR_SYSTEM
&&
346 status
.err
.rc
== ECONNREFUSED
) {
347 /* 'reconnect_methods' is the MS-RPC backend. */
348 DBG_NOTICE("Trying MSRPC methods for domain '%s'\n",
350 domain
->backend
= &reconnect_methods
;
355 *adsp
= domain
->backend_data
.ads_conn
;
357 TALLOC_FREE(tmp_ctx
);
363 /* Query display info for a realm. This is the basic user list fn */
364 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
368 ADS_STRUCT
*ads
= NULL
;
369 const char *attrs
[] = { "sAMAccountType", "objectSid", NULL
};
371 uint32_t *rids
= NULL
;
373 LDAPMessage
*res
= NULL
;
374 LDAPMessage
*msg
= NULL
;
375 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
377 DEBUG(3,("ads: query_user_list\n"));
379 if ( !winbindd_can_contact_domain( domain
) ) {
380 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
385 rc
= ads_cached_connection(domain
, &ads
);
386 if (!ADS_ERR_OK(rc
)) {
387 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
391 rc
= ads_search_retry(ads
, &res
, "(objectCategory=user)", attrs
);
392 if (!ADS_ERR_OK(rc
)) {
393 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc
)));
394 status
= ads_ntstatus(rc
);
397 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
401 count
= ads_count_replies(ads
, res
);
403 DEBUG(1,("query_user_list: No users found\n"));
407 rids
= talloc_zero_array(mem_ctx
, uint32_t, count
);
409 status
= NT_STATUS_NO_MEMORY
;
415 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
416 struct dom_sid user_sid
;
420 ok
= ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
);
422 DBG_INFO("Object lacks sAMAccountType attribute\n");
425 if (ds_atype_map(atype
) != SID_NAME_USER
) {
426 DBG_INFO("Not a user account? atype=0x%x\n", atype
);
430 if (!ads_pull_sid(ads
, msg
, "objectSid", &user_sid
)) {
431 char *dn
= ads_get_dn(ads
, talloc_tos(), msg
);
432 DBG_INFO("No sid for %s !?\n", dn
);
437 if (!dom_sid_in_domain(&domain
->sid
, &user_sid
)) {
438 struct dom_sid_buf sidstr
, domstr
;
439 DBG_WARNING("Got sid %s in domain %s\n",
440 dom_sid_str_buf(&user_sid
, &sidstr
),
441 dom_sid_str_buf(&domain
->sid
, &domstr
));
445 sid_split_rid(&user_sid
, &rids
[count
]);
449 rids
= talloc_realloc(mem_ctx
, rids
, uint32_t, count
);
456 status
= NT_STATUS_OK
;
458 DBG_NOTICE("ads query_user_list gave %d entries\n", count
);
461 ads_msgfree(ads
, res
);
465 /* list all domain groups */
466 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
468 uint32_t *num_entries
,
469 struct wb_acct_info
**info
)
471 ADS_STRUCT
*ads
= NULL
;
472 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
473 "name", "objectSid", NULL
};
476 LDAPMessage
*res
= NULL
;
477 LDAPMessage
*msg
= NULL
;
478 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
480 bool enum_dom_local_groups
= False
;
484 DEBUG(3,("ads: enum_dom_groups\n"));
486 if ( !winbindd_can_contact_domain( domain
) ) {
487 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
492 /* only grab domain local groups for our domain */
493 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
494 enum_dom_local_groups
= True
;
497 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
500 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
501 * default value, it MUST be absent. In case of extensible matching the
502 * "dnattr" boolean defaults to FALSE and so it must be only be present
505 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
506 * filter using bitwise matching rule then the buggy AD fails to decode
507 * the extensible match. As a workaround set it to TRUE and thereby add
508 * the dnAttributes "dn" field to cope with those older AD versions.
509 * It should not harm and won't put any additional load on the AD since
510 * none of the dn components have a bitmask-attribute.
512 * Thanks to Ralf Haferkamp for input and testing - Guenther */
514 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)"
515 "(&(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND
":=%d)"
516 "(!(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND
":=%d))))",
517 GROUP_TYPE_SECURITY_ENABLED
,
518 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
520 if (filter
== NULL
) {
521 status
= NT_STATUS_NO_MEMORY
;
525 rc
= ads_cached_connection(domain
, &ads
);
526 if (!ADS_ERR_OK(rc
)) {
527 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
531 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
532 if (!ADS_ERR_OK(rc
)) {
533 status
= ads_ntstatus(rc
);
534 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
537 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
541 count
= ads_count_replies(ads
, res
);
543 DEBUG(1,("enum_dom_groups: No groups found\n"));
547 (*info
) = talloc_zero_array(mem_ctx
, struct wb_acct_info
, count
);
549 status
= NT_STATUS_NO_MEMORY
;
555 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
560 name
= ads_pull_username(ads
, (*info
), msg
);
561 gecos
= ads_pull_string(ads
, (*info
), msg
, "name");
562 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
563 DEBUG(1,("No sid for %s !?\n", name
));
567 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
568 DEBUG(1,("No rid for %s !?\n", name
));
572 (*info
)[i
].acct_name
= name
;
573 (*info
)[i
].acct_desc
= gecos
;
574 (*info
)[i
].rid
= rid
;
580 status
= NT_STATUS_OK
;
582 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
586 ads_msgfree(ads
, res
);
591 /* list all domain local groups */
592 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
594 uint32_t *num_entries
,
595 struct wb_acct_info
**info
)
598 * This is a stub function only as we returned the domain
599 * local groups in enum_dom_groups() if the domain->native field
600 * was true. This is a simple performance optimization when
603 * if we ever need to enumerate domain local groups separately,
604 * then this optimization in enum_dom_groups() will need
612 /* convert a single name to a sid in a domain - use rpc methods */
613 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
615 const char *domain_name
,
618 const char **pdom_name
,
620 enum lsa_SidType
*type
)
622 return msrpc_methods
.name_to_sid(domain
, mem_ctx
, domain_name
, name
,
623 flags
, pdom_name
, sid
, type
);
626 /* convert a domain SID to a user or group name - use rpc methods */
627 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
629 const struct dom_sid
*sid
,
632 enum lsa_SidType
*type
)
634 return msrpc_methods
.sid_to_name(domain
, mem_ctx
, sid
,
635 domain_name
, name
, type
);
638 /* convert a list of rids to names - use rpc methods */
639 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
641 const struct dom_sid
*sid
,
646 enum lsa_SidType
**types
)
648 return msrpc_methods
.rids_to_names(domain
, mem_ctx
, sid
,
650 domain_name
, names
, types
);
653 /* Lookup groups a user is a member of - alternate method, for when
654 tokenGroups are not available. */
655 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
658 struct dom_sid
*primary_group
,
659 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
662 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
664 LDAPMessage
*res
= NULL
;
665 LDAPMessage
*msg
= NULL
;
667 ADS_STRUCT
*ads
= NULL
;
668 const char *group_attrs
[] = {"objectSid", NULL
};
670 uint32_t num_groups
= 0;
672 DEBUG(3,("ads: lookup_usergroups_member\n"));
674 if ( !winbindd_can_contact_domain( domain
) ) {
675 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
680 rc
= ads_cached_connection(domain
, &ads
);
681 if (!ADS_ERR_OK(rc
)) {
682 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
686 if (!(escaped_dn
= escape_ldap_string(talloc_tos(), user_dn
))) {
687 status
= NT_STATUS_NO_MEMORY
;
691 ldap_exp
= talloc_asprintf(mem_ctx
,
692 "(&(member=%s)(objectCategory=group)"
693 "(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND
":=%d))",
695 GROUP_TYPE_SECURITY_ENABLED
);
697 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
698 TALLOC_FREE(escaped_dn
);
699 status
= NT_STATUS_NO_MEMORY
;
703 TALLOC_FREE(escaped_dn
);
705 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
707 if (!ADS_ERR_OK(rc
)) {
708 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
709 return ads_ntstatus(rc
);
711 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
712 return NT_STATUS_INTERNAL_ERROR
;
716 count
= ads_count_replies(ads
, res
);
721 /* always add the primary group to the sid array */
722 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
724 if (!NT_STATUS_IS_OK(status
)) {
729 for (msg
= ads_first_entry(ads
, res
); msg
;
730 msg
= ads_next_entry(ads
, msg
)) {
731 struct dom_sid group_sid
;
733 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
734 DEBUG(1,("No sid for this group ?!?\n"));
738 /* ignore Builtin groups from ADS - Guenther */
739 if (sid_check_is_in_builtin(&group_sid
)) {
743 status
= add_sid_to_array(mem_ctx
, &group_sid
,
744 user_sids
, &num_groups
);
745 if (!NT_STATUS_IS_OK(status
)) {
752 *p_num_groups
= num_groups
;
753 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
755 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
758 ads_msgfree(ads
, res
);
763 /* Lookup groups a user is a member of - alternate method, for when
764 tokenGroups are not available. */
765 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
768 struct dom_sid
*primary_group
,
769 uint32_t *p_num_groups
,
770 struct dom_sid
**user_sids
)
773 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
774 ADS_STRUCT
*ads
= NULL
;
775 const char *attrs
[] = {"memberOf", NULL
};
776 uint32_t num_groups
= 0;
777 struct dom_sid
*group_sids
= NULL
;
779 char **strings
= NULL
;
780 size_t num_strings
= 0, num_sids
= 0;
783 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
785 if ( !winbindd_can_contact_domain( domain
) ) {
786 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
787 "domain %s\n", domain
->name
));
791 rc
= ads_cached_connection(domain
, &ads
);
792 if (!ADS_ERR_OK(rc
)) {
793 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
794 return NT_STATUS_UNSUCCESSFUL
;
797 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
798 ADS_EXTENDED_DN_HEX_STRING
,
799 &strings
, &num_strings
);
801 if (!ADS_ERR_OK(rc
)) {
802 DEBUG(1,("lookup_usergroups_memberof ads_search "
803 "member=%s: %s\n", user_dn
, ads_errstr(rc
)));
804 return ads_ntstatus(rc
);
810 /* always add the primary group to the sid array */
811 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
813 if (!NT_STATUS_IS_OK(status
)) {
817 group_sids
= talloc_zero_array(mem_ctx
, struct dom_sid
, num_strings
+ 1);
819 status
= NT_STATUS_NO_MEMORY
;
823 for (i
=0; i
<num_strings
; i
++) {
824 rc
= ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
825 ADS_EXTENDED_DN_HEX_STRING
,
827 if (!ADS_ERR_OK(rc
)) {
828 /* ignore members without SIDs */
829 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
830 NT_STATUS_NOT_FOUND
)) {
834 status
= ads_ntstatus(rc
);
842 DEBUG(1,("No memberOf for this user?!?\n"));
843 status
= NT_STATUS_NO_MEMORY
;
847 for (i
=0; i
<num_sids
; i
++) {
849 /* ignore Builtin groups from ADS - Guenther */
850 if (sid_check_is_in_builtin(&group_sids
[i
])) {
854 status
= add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
856 if (!NT_STATUS_IS_OK(status
)) {
862 *p_num_groups
= num_groups
;
863 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
865 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
869 TALLOC_FREE(strings
);
870 TALLOC_FREE(group_sids
);
876 /* Lookup groups a user is a member of. */
877 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
879 const struct dom_sid
*sid
,
880 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
882 ADS_STRUCT
*ads
= NULL
;
883 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
886 LDAPMessage
*msg
= NULL
;
887 char *user_dn
= NULL
;
888 struct dom_sid
*sids
;
890 struct dom_sid primary_group
;
891 uint32_t primary_group_rid
;
892 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
893 uint32_t num_groups
= 0;
894 struct dom_sid_buf buf
;
896 DEBUG(3,("ads: lookup_usergroups\n"));
899 status
= lookup_usergroups_cached(mem_ctx
, sid
,
900 p_num_groups
, user_sids
);
901 if (NT_STATUS_IS_OK(status
)) {
905 if ( !winbindd_can_contact_domain( domain
) ) {
906 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
909 /* Tell the cache manager not to remember this one */
911 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
914 rc
= ads_cached_connection(domain
, &ads
);
915 if (!ADS_ERR_OK(rc
)) {
916 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
917 status
= NT_STATUS_SERVER_DISABLED
;
921 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
923 if (!ADS_ERR_OK(rc
)) {
924 status
= ads_ntstatus(rc
);
925 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
927 dom_sid_str_buf(sid
, &buf
),
932 count
= ads_count_replies(ads
, msg
);
934 status
= NT_STATUS_UNSUCCESSFUL
;
935 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
936 "invalid number of results (count=%d)\n",
937 dom_sid_str_buf(sid
, &buf
),
943 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
944 dom_sid_str_buf(sid
, &buf
)));
945 status
= NT_STATUS_UNSUCCESSFUL
;
949 user_dn
= ads_get_dn(ads
, mem_ctx
, msg
);
950 if (user_dn
== NULL
) {
951 status
= NT_STATUS_NO_MEMORY
;
955 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
956 DEBUG(1,("%s: No primary group for sid=%s !?\n",
958 dom_sid_str_buf(sid
, &buf
)));
962 sid_compose(&primary_group
, &domain
->sid
, primary_group_rid
);
964 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
966 /* there must always be at least one group in the token,
967 unless we are talking to a buggy Win2k server */
969 /* actually this only happens when the machine account has no read
970 * permissions on the tokenGroup attribute - gd */
976 /* lookup what groups this user is a member of by DN search on
979 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
981 &num_groups
, user_sids
);
982 *p_num_groups
= num_groups
;
983 if (NT_STATUS_IS_OK(status
)) {
987 /* lookup what groups this user is a member of by DN search on
990 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
992 &num_groups
, user_sids
);
993 *p_num_groups
= num_groups
;
1000 status
= add_sid_to_array(mem_ctx
, &primary_group
, user_sids
,
1002 if (!NT_STATUS_IS_OK(status
)) {
1006 for (i
=0;i
<count
;i
++) {
1008 /* ignore Builtin groups from ADS - Guenther */
1009 if (sid_check_is_in_builtin(&sids
[i
])) {
1013 status
= add_sid_to_array_unique(mem_ctx
, &sids
[i
],
1014 user_sids
, &num_groups
);
1015 if (!NT_STATUS_IS_OK(status
)) {
1020 *p_num_groups
= (uint32_t)num_groups
;
1021 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1023 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1024 dom_sid_str_buf(sid
, &buf
)));
1026 TALLOC_FREE(user_dn
);
1027 ads_msgfree(ads
, msg
);
1031 /* Lookup aliases a user is member of - use rpc methods */
1032 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1033 TALLOC_CTX
*mem_ctx
,
1034 uint32_t num_sids
, const struct dom_sid
*sids
,
1035 uint32_t *num_aliases
, uint32_t **alias_rids
)
1037 return msrpc_methods
.lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
1038 num_aliases
, alias_rids
);
1041 static NTSTATUS
add_primary_group_members(
1042 ADS_STRUCT
*ads
, TALLOC_CTX
*mem_ctx
, uint32_t rid
, const char *domname
,
1043 char ***all_members
, size_t *num_all_members
)
1046 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1048 const char *attrs
[] = { "dn", NULL
};
1049 LDAPMessage
*res
= NULL
;
1054 bool all_groupmem
= idmap_config_bool(domname
, "all_groupmem", false);
1056 filter
= talloc_asprintf(
1058 "(&(objectCategory=user)(primaryGroupID=%u)%s)",
1060 all_groupmem
? "" : "(uidNumber=*)(!(uidNumber=0))");
1061 if (filter
== NULL
) {
1065 args
.control
= ADS_EXTENDED_DN_OID
;
1066 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1067 args
.critical
= True
;
1069 rc
= ads_do_search_all_args(ads
, ads
->config
.bind_path
,
1070 LDAP_SCOPE_SUBTREE
, filter
, attrs
, &args
,
1073 if (!ADS_ERR_OK(rc
)) {
1074 status
= ads_ntstatus(rc
);
1075 DEBUG(1,("%s: ads_search: %s\n", __func__
, ads_errstr(rc
)));
1079 DEBUG(1,("%s: ads_search returned NULL res\n", __func__
));
1083 num_members
= ads_count_replies(ads
, res
);
1085 DEBUG(10, ("%s: Got %ju primary group members\n", __func__
,
1086 (uintmax_t)num_members
));
1088 if (num_members
== 0) {
1089 status
= NT_STATUS_OK
;
1093 members
= talloc_realloc(mem_ctx
, *all_members
, char *,
1094 *num_all_members
+ num_members
);
1095 if (members
== NULL
) {
1096 DEBUG(1, ("%s: talloc_realloc failed\n", __func__
));
1099 *all_members
= members
;
1101 for (msg
= ads_first_entry(ads
, res
); msg
!= NULL
;
1102 msg
= ads_next_entry(ads
, msg
)) {
1105 dn
= ads_get_dn(ads
, members
, msg
);
1107 DEBUG(1, ("%s: ads_get_dn failed\n", __func__
));
1111 members
[*num_all_members
] = dn
;
1112 *num_all_members
+= 1;
1115 status
= NT_STATUS_OK
;
1118 ads_msgfree(ads
, res
);
1120 TALLOC_FREE(filter
);
1125 find the members of a group, given a group rid and domain
1127 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1128 TALLOC_CTX
*mem_ctx
,
1129 const struct dom_sid
*group_sid
,
1130 enum lsa_SidType type
,
1131 uint32_t *num_names
,
1132 struct dom_sid
**sid_mem
, char ***names
,
1133 uint32_t **name_types
)
1136 ADS_STRUCT
*ads
= NULL
;
1138 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1140 char **members
= NULL
;
1142 size_t num_members
= 0;
1144 struct dom_sid
*sid_mem_nocache
= NULL
;
1145 char **names_nocache
= NULL
;
1146 enum lsa_SidType
*name_types_nocache
= NULL
;
1147 char **domains_nocache
= NULL
; /* only needed for rpccli_lsa_lookup_sids */
1148 uint32_t num_nocache
= 0;
1149 TALLOC_CTX
*tmp_ctx
= NULL
;
1151 struct dom_sid_buf buf
;
1153 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
1154 dom_sid_str_buf(group_sid
, &buf
)));
1158 tmp_ctx
= talloc_new(mem_ctx
);
1160 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1161 status
= NT_STATUS_NO_MEMORY
;
1165 if (!sid_peek_rid(group_sid
, &rid
)) {
1166 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__
));
1167 status
= NT_STATUS_INVALID_PARAMETER
;
1171 if ( !winbindd_can_contact_domain( domain
) ) {
1172 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1174 return NT_STATUS_OK
;
1177 rc
= ads_cached_connection(domain
, &ads
);
1178 if (!ADS_ERR_OK(rc
)) {
1179 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1183 if ((sidbinstr
= ldap_encode_ndr_dom_sid(talloc_tos(), group_sid
)) == NULL
) {
1184 status
= NT_STATUS_NO_MEMORY
;
1188 /* search for all members of the group */
1189 ldap_exp
= talloc_asprintf(tmp_ctx
, "(objectSid=%s)", sidbinstr
);
1190 TALLOC_FREE(sidbinstr
);
1191 if (ldap_exp
== NULL
) {
1192 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1193 status
= NT_STATUS_NO_MEMORY
;
1197 args
.control
= ADS_EXTENDED_DN_OID
;
1198 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1199 args
.critical
= True
;
1201 rc
= ads_ranged_search(ads
, tmp_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
1202 ldap_exp
, &args
, "member", &members
, &num_members
);
1204 if (!ADS_ERR_OK(rc
)) {
1205 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
1206 status
= NT_STATUS_UNSUCCESSFUL
;
1210 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members
));
1212 status
= add_primary_group_members(ads
, mem_ctx
, rid
, domain
->name
,
1213 &members
, &num_members
);
1214 if (!NT_STATUS_IS_OK(status
)) {
1215 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1216 __func__
, nt_errstr(status
)));
1220 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1221 __func__
, (int)num_members
));
1223 /* Now that we have a list of sids, we need to get the
1224 * lists of names and name_types belonging to these sids.
1225 * even though conceptually not quite clean, we use the
1226 * RPC call lsa_lookup_sids for this since it can handle a
1227 * list of sids. ldap calls can just resolve one sid at a time.
1229 * At this stage, the sids are still hidden in the exetended dn
1230 * member output format. We actually do a little better than
1231 * stated above: In extracting the sids from the member strings,
1232 * we try to resolve as many sids as possible from the
1233 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1236 (*sid_mem
) = talloc_zero_array(mem_ctx
, struct dom_sid
, num_members
);
1237 (*names
) = talloc_zero_array(mem_ctx
, char *, num_members
);
1238 (*name_types
) = talloc_zero_array(mem_ctx
, uint32_t, num_members
);
1239 (sid_mem_nocache
) = talloc_zero_array(tmp_ctx
, struct dom_sid
, num_members
);
1241 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1242 (*names
== NULL
) || (*name_types
== NULL
) ||
1243 (sid_mem_nocache
== NULL
))
1245 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1246 status
= NT_STATUS_NO_MEMORY
;
1253 (*name_types
) = NULL
;
1256 for (i
=0; i
<num_members
; i
++) {
1257 enum lsa_SidType name_type
;
1258 char *name
, *domain_name
;
1261 rc
= ads_get_sid_from_extended_dn(tmp_ctx
, members
[i
], args
.val
,
1263 if (!ADS_ERR_OK(rc
)) {
1264 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
1265 NT_STATUS_NOT_FOUND
)) {
1266 /* Group members can be objects, like Exchange
1267 * Public Folders, that don't have a SID. Skip
1272 status
= ads_ntstatus(rc
);
1276 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
,
1278 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1280 dom_sid_str_buf(&sid
, &buf
)));
1281 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1282 (*names
)[*num_names
] = fill_domain_username_talloc(
1288 (*name_types
)[*num_names
] = name_type
;
1292 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1294 dom_sid_str_buf(&sid
, &buf
)));
1295 sid_copy(&(sid_mem_nocache
)[num_nocache
], &sid
);
1300 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1301 "%d left for lsa_lookupsids\n", *num_names
, num_nocache
));
1303 /* handle sids not resolved from cache by lsa_lookup_sids */
1304 if (num_nocache
> 0) {
1306 status
= winbindd_lookup_sids(tmp_ctx
,
1312 &name_types_nocache
);
1314 if (!(NT_STATUS_IS_OK(status
) ||
1315 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
) ||
1316 NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)))
1318 DEBUG(1, ("lsa_lookupsids call failed with %s "
1319 "- retrying...\n", nt_errstr(status
)));
1321 status
= winbindd_lookup_sids(tmp_ctx
,
1327 &name_types_nocache
);
1330 if (NT_STATUS_IS_OK(status
) ||
1331 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
))
1333 /* Copy the entries over from the "_nocache" arrays
1334 * to the result arrays, skipping the gaps the
1335 * lookup_sids call left. */
1336 for (i
=0; i
< num_nocache
; i
++) {
1337 if (((names_nocache
)[i
] != NULL
) &&
1338 ((name_types_nocache
)[i
] != SID_NAME_UNKNOWN
))
1340 sid_copy(&(*sid_mem
)[*num_names
],
1341 &sid_mem_nocache
[i
]);
1342 (*names
)[*num_names
] =
1343 fill_domain_username_talloc(
1348 (*name_types
)[*num_names
] = name_types_nocache
[i
];
1353 else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1354 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1355 "not map any SIDs at all.\n"));
1356 /* Don't handle this as an error here.
1357 * There is nothing left to do with respect to the
1358 * overall result... */
1360 else if (!NT_STATUS_IS_OK(status
)) {
1361 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1362 "sids via rpc_lsa_lookup_sids: %s\n",
1363 (int)num_members
, nt_errstr(status
)));
1368 status
= NT_STATUS_OK
;
1369 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1370 dom_sid_str_buf(group_sid
, &buf
)));
1374 TALLOC_FREE(tmp_ctx
);
1379 static NTSTATUS
lookup_aliasmem(struct winbindd_domain
*domain
,
1380 TALLOC_CTX
*mem_ctx
,
1381 const struct dom_sid
*sid
,
1382 enum lsa_SidType type
,
1384 struct dom_sid
**sids
)
1386 char **names
= NULL
;
1387 uint32_t *name_types
= NULL
;
1388 struct dom_sid_buf buf
;
1390 DBG_DEBUG("ads: lookup_aliasmem %s sid=%s\n",
1392 dom_sid_str_buf(sid
, &buf
));
1393 /* Search for alias and group membership uses the same LDAP command. */
1394 return lookup_groupmem(domain
,
1404 /* find the lockout policy of a domain - use rpc methods */
1405 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1406 TALLOC_CTX
*mem_ctx
,
1407 struct samr_DomInfo12
*policy
)
1409 return msrpc_methods
.lockout_policy(domain
, mem_ctx
, policy
);
1412 /* find the password policy of a domain - use rpc methods */
1413 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1414 TALLOC_CTX
*mem_ctx
,
1415 struct samr_DomInfo1
*policy
)
1417 return msrpc_methods
.password_policy(domain
, mem_ctx
, policy
);
1420 /* get a list of trusted domains */
1421 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1422 TALLOC_CTX
*mem_ctx
,
1423 struct netr_DomainTrustList
*trusts
)
1425 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1429 struct rpc_pipe_client
*cli
;
1430 struct dcerpc_binding_handle
*b
;
1432 DEBUG(3,("ads: trusted_domains\n"));
1434 ZERO_STRUCTP(trusts
);
1436 /* If this is our primary domain or a root in our forest,
1437 query for all trusts. If not, then just look for domain
1438 trusts in the target forest */
1440 if (domain
->primary
|| domain_is_forest_root(domain
)) {
1441 flags
= NETR_TRUST_FLAG_OUTBOUND
|
1442 NETR_TRUST_FLAG_INBOUND
|
1443 NETR_TRUST_FLAG_IN_FOREST
;
1445 flags
= NETR_TRUST_FLAG_IN_FOREST
;
1448 result
= cm_connect_netlogon(domain
, &cli
);
1450 if (!NT_STATUS_IS_OK(result
)) {
1451 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1452 "for PIPE_NETLOGON (%s)\n",
1453 domain
->name
, nt_errstr(result
)));
1454 return NT_STATUS_UNSUCCESSFUL
;
1457 b
= cli
->binding_handle
;
1459 result
= dcerpc_netr_DsrEnumerateDomainTrusts(b
, mem_ctx
,
1464 if (!NT_STATUS_IS_OK(result
)) {
1468 if (!W_ERROR_IS_OK(werr
)) {
1469 return werror_to_ntstatus(werr
);
1471 if (trusts
->count
== 0) {
1472 return NT_STATUS_OK
;
1475 /* Copy across names and sids */
1477 for (i
= 0; i
< trusts
->count
; i
++) {
1478 struct netr_DomainTrust
*trust
= &trusts
->array
[i
];
1479 struct winbindd_domain d
;
1484 * drop external trusts if this is not our primary
1485 * domain. This means that the returned number of
1486 * domains may be less that the ones actually trusted
1490 if ((trust
->trust_attributes
1491 & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) &&
1494 DEBUG(10,("trusted_domains: Skipping external trusted "
1495 "domain %s because it is outside of our "
1497 trust
->netbios_name
));
1501 /* add to the trusted domain cache */
1503 d
.name
= discard_const_p(char, trust
->netbios_name
);
1504 d
.alt_name
= discard_const_p(char, trust
->dns_name
);
1507 sid_copy(&d
.sid
, trust
->sid
);
1509 sid_copy(&d
.sid
, &global_sid_NULL
);
1512 if ( domain
->primary
) {
1513 DEBUG(10,("trusted_domains(ads): Searching "
1514 "trusted domain list of %s and storing "
1515 "trust flags for domain %s\n",
1516 domain
->name
, d
.alt_name
));
1518 d
.domain_flags
= trust
->trust_flags
;
1519 d
.domain_type
= trust
->trust_type
;
1520 d
.domain_trust_attribs
= trust
->trust_attributes
;
1522 wcache_tdc_add_domain( &d
);
1523 } else if (domain_is_forest_root(domain
)) {
1524 /* Check if we already have this record. If
1525 * we are following our forest root that is not
1526 * our primary domain, we want to keep trust
1527 * flags from the perspective of our primary
1528 * domain not our forest root. */
1529 struct winbindd_tdc_domain
*exist
= NULL
;
1531 exist
= wcache_tdc_fetch_domain(
1532 talloc_tos(), trust
->netbios_name
);
1534 DEBUG(10,("trusted_domains(ads): Searching "
1535 "trusted domain list of %s and "
1536 "storing trust flags for domain "
1537 "%s\n", domain
->name
, d
.alt_name
));
1538 d
.domain_flags
= trust
->trust_flags
;
1539 d
.domain_type
= trust
->trust_type
;
1540 d
.domain_trust_attribs
=
1541 trust
->trust_attributes
;
1543 wcache_tdc_add_domain( &d
);
1547 /* This gets a little tricky. If we are
1548 following a transitive forest trust, then
1549 innerit the flags, type, and attribs from
1550 the domain we queried to make sure we don't
1551 record the view of the trust from the wrong
1552 side. Always view it from the side of our
1553 primary domain. --jerry */
1554 struct winbindd_tdc_domain
*parent
= NULL
;
1556 DEBUG(10,("trusted_domains(ads): Searching "
1557 "trusted domain list of %s and inheriting "
1558 "trust flags for domain %s\n",
1559 domain
->name
, d
.alt_name
));
1561 parent
= wcache_tdc_fetch_domain(talloc_tos(),
1564 d
.domain_flags
= parent
->trust_flags
;
1565 d
.domain_type
= parent
->trust_type
;
1566 d
.domain_trust_attribs
= parent
->trust_attribs
;
1568 d
.domain_flags
= domain
->domain_flags
;
1569 d
.domain_type
= domain
->domain_type
;
1570 d
.domain_trust_attribs
=
1571 domain
->domain_trust_attribs
;
1573 TALLOC_FREE(parent
);
1576 * We need to pass the modified properties
1579 trust
->trust_flags
= d
.domain_flags
;
1580 trust
->trust_type
= d
.domain_type
;
1581 trust
->trust_attributes
= d
.domain_trust_attribs
;
1583 wcache_tdc_add_domain( &d
);
1589 /* the ADS backend methods are exposed via this structure */
1590 struct winbindd_methods ads_methods
= {