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 acount 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 nam 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
);
454 status
= NT_STATUS_OK
;
456 DBG_NOTICE("ads query_user_list gave %d entries\n", count
);
459 ads_msgfree(ads
, res
);
463 /* list all domain groups */
464 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
466 uint32_t *num_entries
,
467 struct wb_acct_info
**info
)
469 ADS_STRUCT
*ads
= NULL
;
470 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
471 "name", "objectSid", NULL
};
474 LDAPMessage
*res
= NULL
;
475 LDAPMessage
*msg
= NULL
;
476 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
478 bool enum_dom_local_groups
= False
;
482 DEBUG(3,("ads: enum_dom_groups\n"));
484 if ( !winbindd_can_contact_domain( domain
) ) {
485 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
490 /* only grab domain local groups for our domain */
491 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
492 enum_dom_local_groups
= True
;
495 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
498 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
499 * default value, it MUST be absent. In case of extensible matching the
500 * "dnattr" boolean defaults to FALSE and so it must be only be present
503 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
504 * filter using bitwise matching rule then the buggy AD fails to decode
505 * the extensible match. As a workaround set it to TRUE and thereby add
506 * the dnAttributes "dn" field to cope with those older AD versions.
507 * It should not harm and won't put any additional load on the AD since
508 * none of the dn components have a bitmask-attribute.
510 * Thanks to Ralf Haferkamp for input and testing - Guenther */
512 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
513 ADS_LDAP_MATCHING_RULE_BIT_AND
, GROUP_TYPE_SECURITY_ENABLED
,
514 ADS_LDAP_MATCHING_RULE_BIT_AND
,
515 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
517 if (filter
== NULL
) {
518 status
= NT_STATUS_NO_MEMORY
;
522 rc
= ads_cached_connection(domain
, &ads
);
523 if (!ADS_ERR_OK(rc
)) {
524 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
528 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
529 if (!ADS_ERR_OK(rc
)) {
530 status
= ads_ntstatus(rc
);
531 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
534 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
538 count
= ads_count_replies(ads
, res
);
540 DEBUG(1,("enum_dom_groups: No groups found\n"));
544 (*info
) = talloc_zero_array(mem_ctx
, struct wb_acct_info
, count
);
546 status
= NT_STATUS_NO_MEMORY
;
552 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
557 name
= ads_pull_username(ads
, (*info
), msg
);
558 gecos
= ads_pull_string(ads
, (*info
), msg
, "name");
559 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
560 DEBUG(1,("No sid for %s !?\n", name
));
564 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
565 DEBUG(1,("No rid for %s !?\n", name
));
569 (*info
)[i
].acct_name
= name
;
570 (*info
)[i
].acct_desc
= gecos
;
571 (*info
)[i
].rid
= rid
;
577 status
= NT_STATUS_OK
;
579 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
583 ads_msgfree(ads
, res
);
588 /* list all domain local groups */
589 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
591 uint32_t *num_entries
,
592 struct wb_acct_info
**info
)
595 * This is a stub function only as we returned the domain
596 * local groups in enum_dom_groups() if the domain->native field
597 * was true. This is a simple performance optimization when
600 * if we ever need to enumerate domain local groups separately,
601 * then this optimization in enum_dom_groups() will need
609 /* convert a single name to a sid in a domain - use rpc methods */
610 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
612 const char *domain_name
,
615 const char **pdom_name
,
617 enum lsa_SidType
*type
)
619 return msrpc_methods
.name_to_sid(domain
, mem_ctx
, domain_name
, name
,
620 flags
, pdom_name
, sid
, type
);
623 /* convert a domain SID to a user or group name - use rpc methods */
624 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
626 const struct dom_sid
*sid
,
629 enum lsa_SidType
*type
)
631 return msrpc_methods
.sid_to_name(domain
, mem_ctx
, sid
,
632 domain_name
, name
, type
);
635 /* convert a list of rids to names - use rpc methods */
636 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
638 const struct dom_sid
*sid
,
643 enum lsa_SidType
**types
)
645 return msrpc_methods
.rids_to_names(domain
, mem_ctx
, sid
,
647 domain_name
, names
, types
);
650 /* Lookup groups a user is a member of - alternate method, for when
651 tokenGroups are not available. */
652 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
655 struct dom_sid
*primary_group
,
656 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
659 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
661 LDAPMessage
*res
= NULL
;
662 LDAPMessage
*msg
= NULL
;
664 ADS_STRUCT
*ads
= NULL
;
665 const char *group_attrs
[] = {"objectSid", NULL
};
667 uint32_t num_groups
= 0;
669 DEBUG(3,("ads: lookup_usergroups_member\n"));
671 if ( !winbindd_can_contact_domain( domain
) ) {
672 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
677 rc
= ads_cached_connection(domain
, &ads
);
678 if (!ADS_ERR_OK(rc
)) {
679 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
683 if (!(escaped_dn
= escape_ldap_string(talloc_tos(), user_dn
))) {
684 status
= NT_STATUS_NO_MEMORY
;
688 ldap_exp
= talloc_asprintf(mem_ctx
,
689 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
691 ADS_LDAP_MATCHING_RULE_BIT_AND
,
692 GROUP_TYPE_SECURITY_ENABLED
);
694 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
695 TALLOC_FREE(escaped_dn
);
696 status
= NT_STATUS_NO_MEMORY
;
700 TALLOC_FREE(escaped_dn
);
702 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
704 if (!ADS_ERR_OK(rc
)) {
705 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
706 return ads_ntstatus(rc
);
708 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
709 return NT_STATUS_INTERNAL_ERROR
;
713 count
= ads_count_replies(ads
, res
);
718 /* always add the primary group to the sid array */
719 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
721 if (!NT_STATUS_IS_OK(status
)) {
726 for (msg
= ads_first_entry(ads
, res
); msg
;
727 msg
= ads_next_entry(ads
, msg
)) {
728 struct dom_sid group_sid
;
730 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
731 DEBUG(1,("No sid for this group ?!?\n"));
735 /* ignore Builtin groups from ADS - Guenther */
736 if (sid_check_is_in_builtin(&group_sid
)) {
740 status
= add_sid_to_array(mem_ctx
, &group_sid
,
741 user_sids
, &num_groups
);
742 if (!NT_STATUS_IS_OK(status
)) {
749 *p_num_groups
= num_groups
;
750 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
752 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
755 ads_msgfree(ads
, res
);
760 /* Lookup groups a user is a member of - alternate method, for when
761 tokenGroups are not available. */
762 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
765 struct dom_sid
*primary_group
,
766 uint32_t *p_num_groups
,
767 struct dom_sid
**user_sids
)
770 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
771 ADS_STRUCT
*ads
= NULL
;
772 const char *attrs
[] = {"memberOf", NULL
};
773 uint32_t num_groups
= 0;
774 struct dom_sid
*group_sids
= NULL
;
776 char **strings
= NULL
;
777 size_t num_strings
= 0, num_sids
= 0;
780 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
782 if ( !winbindd_can_contact_domain( domain
) ) {
783 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
784 "domain %s\n", domain
->name
));
788 rc
= ads_cached_connection(domain
, &ads
);
789 if (!ADS_ERR_OK(rc
)) {
790 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
791 return NT_STATUS_UNSUCCESSFUL
;
794 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
795 ADS_EXTENDED_DN_HEX_STRING
,
796 &strings
, &num_strings
);
798 if (!ADS_ERR_OK(rc
)) {
799 DEBUG(1,("lookup_usergroups_memberof ads_search "
800 "member=%s: %s\n", user_dn
, ads_errstr(rc
)));
801 return ads_ntstatus(rc
);
807 /* always add the primary group to the sid array */
808 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
810 if (!NT_STATUS_IS_OK(status
)) {
814 group_sids
= talloc_zero_array(mem_ctx
, struct dom_sid
, num_strings
+ 1);
816 status
= NT_STATUS_NO_MEMORY
;
820 for (i
=0; i
<num_strings
; i
++) {
821 rc
= ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
822 ADS_EXTENDED_DN_HEX_STRING
,
824 if (!ADS_ERR_OK(rc
)) {
825 /* ignore members without SIDs */
826 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
827 NT_STATUS_NOT_FOUND
)) {
831 status
= ads_ntstatus(rc
);
839 DEBUG(1,("No memberOf for this user?!?\n"));
840 status
= NT_STATUS_NO_MEMORY
;
844 for (i
=0; i
<num_sids
; i
++) {
846 /* ignore Builtin groups from ADS - Guenther */
847 if (sid_check_is_in_builtin(&group_sids
[i
])) {
851 status
= add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
853 if (!NT_STATUS_IS_OK(status
)) {
859 *p_num_groups
= num_groups
;
860 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
862 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
866 TALLOC_FREE(strings
);
867 TALLOC_FREE(group_sids
);
873 /* Lookup groups a user is a member of. */
874 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
876 const struct dom_sid
*sid
,
877 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
879 ADS_STRUCT
*ads
= NULL
;
880 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
883 LDAPMessage
*msg
= NULL
;
884 char *user_dn
= NULL
;
885 struct dom_sid
*sids
;
887 struct dom_sid primary_group
;
888 uint32_t primary_group_rid
;
889 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
890 uint32_t num_groups
= 0;
891 struct dom_sid_buf buf
;
893 DEBUG(3,("ads: lookup_usergroups\n"));
896 status
= lookup_usergroups_cached(mem_ctx
, sid
,
897 p_num_groups
, user_sids
);
898 if (NT_STATUS_IS_OK(status
)) {
902 if ( !winbindd_can_contact_domain( domain
) ) {
903 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
906 /* Tell the cache manager not to remember this one */
908 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
911 rc
= ads_cached_connection(domain
, &ads
);
912 if (!ADS_ERR_OK(rc
)) {
913 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
914 status
= NT_STATUS_SERVER_DISABLED
;
918 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
920 if (!ADS_ERR_OK(rc
)) {
921 status
= ads_ntstatus(rc
);
922 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
924 dom_sid_str_buf(sid
, &buf
),
929 count
= ads_count_replies(ads
, msg
);
931 status
= NT_STATUS_UNSUCCESSFUL
;
932 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
933 "invalid number of results (count=%d)\n",
934 dom_sid_str_buf(sid
, &buf
),
940 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
941 dom_sid_str_buf(sid
, &buf
)));
942 status
= NT_STATUS_UNSUCCESSFUL
;
946 user_dn
= ads_get_dn(ads
, mem_ctx
, msg
);
947 if (user_dn
== NULL
) {
948 status
= NT_STATUS_NO_MEMORY
;
952 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
953 DEBUG(1,("%s: No primary group for sid=%s !?\n",
955 dom_sid_str_buf(sid
, &buf
)));
959 sid_compose(&primary_group
, &domain
->sid
, primary_group_rid
);
961 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
963 /* there must always be at least one group in the token,
964 unless we are talking to a buggy Win2k server */
966 /* actually this only happens when the machine account has no read
967 * permissions on the tokenGroup attribute - gd */
973 /* lookup what groups this user is a member of by DN search on
976 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
978 &num_groups
, user_sids
);
979 *p_num_groups
= num_groups
;
980 if (NT_STATUS_IS_OK(status
)) {
984 /* lookup what groups this user is a member of by DN search on
987 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
989 &num_groups
, user_sids
);
990 *p_num_groups
= num_groups
;
997 status
= add_sid_to_array(mem_ctx
, &primary_group
, user_sids
,
999 if (!NT_STATUS_IS_OK(status
)) {
1003 for (i
=0;i
<count
;i
++) {
1005 /* ignore Builtin groups from ADS - Guenther */
1006 if (sid_check_is_in_builtin(&sids
[i
])) {
1010 status
= add_sid_to_array_unique(mem_ctx
, &sids
[i
],
1011 user_sids
, &num_groups
);
1012 if (!NT_STATUS_IS_OK(status
)) {
1017 *p_num_groups
= (uint32_t)num_groups
;
1018 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1020 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1021 dom_sid_str_buf(sid
, &buf
)));
1023 TALLOC_FREE(user_dn
);
1024 ads_msgfree(ads
, msg
);
1028 /* Lookup aliases a user is member of - use rpc methods */
1029 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1030 TALLOC_CTX
*mem_ctx
,
1031 uint32_t num_sids
, const struct dom_sid
*sids
,
1032 uint32_t *num_aliases
, uint32_t **alias_rids
)
1034 return msrpc_methods
.lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
1035 num_aliases
, alias_rids
);
1038 static NTSTATUS
add_primary_group_members(
1039 ADS_STRUCT
*ads
, TALLOC_CTX
*mem_ctx
, uint32_t rid
,
1040 char ***all_members
, size_t *num_all_members
)
1043 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1045 const char *attrs
[] = { "dn", NULL
};
1046 LDAPMessage
*res
= NULL
;
1052 filter
= talloc_asprintf(
1053 mem_ctx
, "(&(objectCategory=user)(primaryGroupID=%u))",
1055 if (filter
== NULL
) {
1059 args
.control
= ADS_EXTENDED_DN_OID
;
1060 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1061 args
.critical
= True
;
1063 rc
= ads_do_search_all_args(ads
, ads
->config
.bind_path
,
1064 LDAP_SCOPE_SUBTREE
, filter
, attrs
, &args
,
1067 if (!ADS_ERR_OK(rc
)) {
1068 status
= ads_ntstatus(rc
);
1069 DEBUG(1,("%s: ads_search: %s\n", __func__
, ads_errstr(rc
)));
1073 DEBUG(1,("%s: ads_search returned NULL res\n", __func__
));
1077 num_members
= ads_count_replies(ads
, res
);
1079 DEBUG(10, ("%s: Got %ju primary group members\n", __func__
,
1080 (uintmax_t)num_members
));
1082 if (num_members
== 0) {
1083 status
= NT_STATUS_OK
;
1087 members
= talloc_realloc(mem_ctx
, *all_members
, char *,
1088 *num_all_members
+ num_members
);
1089 if (members
== NULL
) {
1090 DEBUG(1, ("%s: talloc_realloc failed\n", __func__
));
1093 *all_members
= members
;
1095 for (msg
= ads_first_entry(ads
, res
); msg
!= NULL
;
1096 msg
= ads_next_entry(ads
, msg
)) {
1099 dn
= ads_get_dn(ads
, members
, msg
);
1101 DEBUG(1, ("%s: ads_get_dn failed\n", __func__
));
1105 members
[*num_all_members
] = dn
;
1106 *num_all_members
+= 1;
1109 status
= NT_STATUS_OK
;
1112 ads_msgfree(ads
, res
);
1114 TALLOC_FREE(filter
);
1119 find the members of a group, given a group rid and domain
1121 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1122 TALLOC_CTX
*mem_ctx
,
1123 const struct dom_sid
*group_sid
,
1124 enum lsa_SidType type
,
1125 uint32_t *num_names
,
1126 struct dom_sid
**sid_mem
, char ***names
,
1127 uint32_t **name_types
)
1130 ADS_STRUCT
*ads
= NULL
;
1132 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1134 char **members
= NULL
;
1136 size_t num_members
= 0;
1138 struct dom_sid
*sid_mem_nocache
= NULL
;
1139 char **names_nocache
= NULL
;
1140 enum lsa_SidType
*name_types_nocache
= NULL
;
1141 char **domains_nocache
= NULL
; /* only needed for rpccli_lsa_lookup_sids */
1142 uint32_t num_nocache
= 0;
1143 TALLOC_CTX
*tmp_ctx
= NULL
;
1145 struct dom_sid_buf buf
;
1147 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
1148 dom_sid_str_buf(group_sid
, &buf
)));
1152 tmp_ctx
= talloc_new(mem_ctx
);
1154 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1155 status
= NT_STATUS_NO_MEMORY
;
1159 if (!sid_peek_rid(group_sid
, &rid
)) {
1160 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__
));
1161 status
= NT_STATUS_INVALID_PARAMETER
;
1165 if ( !winbindd_can_contact_domain( domain
) ) {
1166 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1168 return NT_STATUS_OK
;
1171 rc
= ads_cached_connection(domain
, &ads
);
1172 if (!ADS_ERR_OK(rc
)) {
1173 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1177 if ((sidbinstr
= ldap_encode_ndr_dom_sid(talloc_tos(), group_sid
)) == NULL
) {
1178 status
= NT_STATUS_NO_MEMORY
;
1182 /* search for all members of the group */
1183 ldap_exp
= talloc_asprintf(tmp_ctx
, "(objectSid=%s)", sidbinstr
);
1184 TALLOC_FREE(sidbinstr
);
1185 if (ldap_exp
== NULL
) {
1186 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1187 status
= NT_STATUS_NO_MEMORY
;
1191 args
.control
= ADS_EXTENDED_DN_OID
;
1192 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1193 args
.critical
= True
;
1195 rc
= ads_ranged_search(ads
, tmp_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
1196 ldap_exp
, &args
, "member", &members
, &num_members
);
1198 if (!ADS_ERR_OK(rc
)) {
1199 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
1200 status
= NT_STATUS_UNSUCCESSFUL
;
1204 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members
));
1206 status
= add_primary_group_members(ads
, mem_ctx
, rid
,
1207 &members
, &num_members
);
1208 if (!NT_STATUS_IS_OK(status
)) {
1209 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1210 __func__
, nt_errstr(status
)));
1214 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1215 __func__
, (int)num_members
));
1217 /* Now that we have a list of sids, we need to get the
1218 * lists of names and name_types belonging to these sids.
1219 * even though conceptually not quite clean, we use the
1220 * RPC call lsa_lookup_sids for this since it can handle a
1221 * list of sids. ldap calls can just resolve one sid at a time.
1223 * At this stage, the sids are still hidden in the exetended dn
1224 * member output format. We actually do a little better than
1225 * stated above: In extracting the sids from the member strings,
1226 * we try to resolve as many sids as possible from the
1227 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1230 (*sid_mem
) = talloc_zero_array(mem_ctx
, struct dom_sid
, num_members
);
1231 (*names
) = talloc_zero_array(mem_ctx
, char *, num_members
);
1232 (*name_types
) = talloc_zero_array(mem_ctx
, uint32_t, num_members
);
1233 (sid_mem_nocache
) = talloc_zero_array(tmp_ctx
, struct dom_sid
, num_members
);
1235 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1236 (*names
== NULL
) || (*name_types
== NULL
) ||
1237 (sid_mem_nocache
== NULL
))
1239 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1240 status
= NT_STATUS_NO_MEMORY
;
1247 (*name_types
) = NULL
;
1250 for (i
=0; i
<num_members
; i
++) {
1251 enum lsa_SidType name_type
;
1252 char *name
, *domain_name
;
1255 rc
= ads_get_sid_from_extended_dn(tmp_ctx
, members
[i
], args
.val
,
1257 if (!ADS_ERR_OK(rc
)) {
1258 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
1259 NT_STATUS_NOT_FOUND
)) {
1260 /* Group members can be objects, like Exchange
1261 * Public Folders, that don't have a SID. Skip
1266 status
= ads_ntstatus(rc
);
1270 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
,
1272 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1274 dom_sid_str_buf(&sid
, &buf
)));
1275 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1276 (*names
)[*num_names
] = fill_domain_username_talloc(
1282 (*name_types
)[*num_names
] = name_type
;
1286 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1288 dom_sid_str_buf(&sid
, &buf
)));
1289 sid_copy(&(sid_mem_nocache
)[num_nocache
], &sid
);
1294 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1295 "%d left for lsa_lookupsids\n", *num_names
, num_nocache
));
1297 /* handle sids not resolved from cache by lsa_lookup_sids */
1298 if (num_nocache
> 0) {
1300 status
= winbindd_lookup_sids(tmp_ctx
,
1306 &name_types_nocache
);
1308 if (!(NT_STATUS_IS_OK(status
) ||
1309 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
) ||
1310 NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)))
1312 DEBUG(1, ("lsa_lookupsids call failed with %s "
1313 "- retrying...\n", nt_errstr(status
)));
1315 status
= winbindd_lookup_sids(tmp_ctx
,
1321 &name_types_nocache
);
1324 if (NT_STATUS_IS_OK(status
) ||
1325 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
))
1327 /* Copy the entries over from the "_nocache" arrays
1328 * to the result arrays, skipping the gaps the
1329 * lookup_sids call left. */
1330 for (i
=0; i
< num_nocache
; i
++) {
1331 if (((names_nocache
)[i
] != NULL
) &&
1332 ((name_types_nocache
)[i
] != SID_NAME_UNKNOWN
))
1334 sid_copy(&(*sid_mem
)[*num_names
],
1335 &sid_mem_nocache
[i
]);
1336 (*names
)[*num_names
] =
1337 fill_domain_username_talloc(
1342 (*name_types
)[*num_names
] = name_types_nocache
[i
];
1347 else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1348 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1349 "not map any SIDs at all.\n"));
1350 /* Don't handle this as an error here.
1351 * There is nothing left to do with respect to the
1352 * overall result... */
1354 else if (!NT_STATUS_IS_OK(status
)) {
1355 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1356 "sids via rpc_lsa_lookup_sids: %s\n",
1357 (int)num_members
, nt_errstr(status
)));
1362 status
= NT_STATUS_OK
;
1363 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1364 dom_sid_str_buf(group_sid
, &buf
)));
1368 TALLOC_FREE(tmp_ctx
);
1373 /* find the lockout policy of a domain - use rpc methods */
1374 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1375 TALLOC_CTX
*mem_ctx
,
1376 struct samr_DomInfo12
*policy
)
1378 return msrpc_methods
.lockout_policy(domain
, mem_ctx
, policy
);
1381 /* find the password policy of a domain - use rpc methods */
1382 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1383 TALLOC_CTX
*mem_ctx
,
1384 struct samr_DomInfo1
*policy
)
1386 return msrpc_methods
.password_policy(domain
, mem_ctx
, policy
);
1389 /* get a list of trusted domains */
1390 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1391 TALLOC_CTX
*mem_ctx
,
1392 struct netr_DomainTrustList
*trusts
)
1394 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1398 struct rpc_pipe_client
*cli
;
1399 struct dcerpc_binding_handle
*b
;
1401 DEBUG(3,("ads: trusted_domains\n"));
1403 ZERO_STRUCTP(trusts
);
1405 /* If this is our primary domain or a root in our forest,
1406 query for all trusts. If not, then just look for domain
1407 trusts in the target forest */
1409 if (domain
->primary
|| domain_is_forest_root(domain
)) {
1410 flags
= NETR_TRUST_FLAG_OUTBOUND
|
1411 NETR_TRUST_FLAG_INBOUND
|
1412 NETR_TRUST_FLAG_IN_FOREST
;
1414 flags
= NETR_TRUST_FLAG_IN_FOREST
;
1417 result
= cm_connect_netlogon(domain
, &cli
);
1419 if (!NT_STATUS_IS_OK(result
)) {
1420 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1421 "for PIPE_NETLOGON (%s)\n",
1422 domain
->name
, nt_errstr(result
)));
1423 return NT_STATUS_UNSUCCESSFUL
;
1426 b
= cli
->binding_handle
;
1428 result
= dcerpc_netr_DsrEnumerateDomainTrusts(b
, mem_ctx
,
1433 if (!NT_STATUS_IS_OK(result
)) {
1437 if (!W_ERROR_IS_OK(werr
)) {
1438 return werror_to_ntstatus(werr
);
1440 if (trusts
->count
== 0) {
1441 return NT_STATUS_OK
;
1444 /* Copy across names and sids */
1446 for (i
= 0; i
< trusts
->count
; i
++) {
1447 struct netr_DomainTrust
*trust
= &trusts
->array
[i
];
1448 struct winbindd_domain d
;
1453 * drop external trusts if this is not our primary
1454 * domain. This means that the returned number of
1455 * domains may be less that the ones actually trusted
1459 if ((trust
->trust_attributes
1460 & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) &&
1463 DEBUG(10,("trusted_domains: Skipping external trusted "
1464 "domain %s because it is outside of our "
1466 trust
->netbios_name
));
1470 /* add to the trusted domain cache */
1472 d
.name
= discard_const_p(char, trust
->netbios_name
);
1473 d
.alt_name
= discard_const_p(char, trust
->dns_name
);
1476 sid_copy(&d
.sid
, trust
->sid
);
1478 sid_copy(&d
.sid
, &global_sid_NULL
);
1481 if ( domain
->primary
) {
1482 DEBUG(10,("trusted_domains(ads): Searching "
1483 "trusted domain list of %s and storing "
1484 "trust flags for domain %s\n",
1485 domain
->name
, d
.alt_name
));
1487 d
.domain_flags
= trust
->trust_flags
;
1488 d
.domain_type
= trust
->trust_type
;
1489 d
.domain_trust_attribs
= trust
->trust_attributes
;
1491 wcache_tdc_add_domain( &d
);
1492 } else if (domain_is_forest_root(domain
)) {
1493 /* Check if we already have this record. If
1494 * we are following our forest root that is not
1495 * our primary domain, we want to keep trust
1496 * flags from the perspective of our primary
1497 * domain not our forest root. */
1498 struct winbindd_tdc_domain
*exist
= NULL
;
1500 exist
= wcache_tdc_fetch_domain(
1501 talloc_tos(), trust
->netbios_name
);
1503 DEBUG(10,("trusted_domains(ads): Searching "
1504 "trusted domain list of %s and "
1505 "storing trust flags for domain "
1506 "%s\n", domain
->name
, d
.alt_name
));
1507 d
.domain_flags
= trust
->trust_flags
;
1508 d
.domain_type
= trust
->trust_type
;
1509 d
.domain_trust_attribs
=
1510 trust
->trust_attributes
;
1512 wcache_tdc_add_domain( &d
);
1516 /* This gets a little tricky. If we are
1517 following a transitive forest trust, then
1518 innerit the flags, type, and attribs from
1519 the domain we queried to make sure we don't
1520 record the view of the trust from the wrong
1521 side. Always view it from the side of our
1522 primary domain. --jerry */
1523 struct winbindd_tdc_domain
*parent
= NULL
;
1525 DEBUG(10,("trusted_domains(ads): Searching "
1526 "trusted domain list of %s and inheriting "
1527 "trust flags for domain %s\n",
1528 domain
->name
, d
.alt_name
));
1530 parent
= wcache_tdc_fetch_domain(talloc_tos(),
1533 d
.domain_flags
= parent
->trust_flags
;
1534 d
.domain_type
= parent
->trust_type
;
1535 d
.domain_trust_attribs
= parent
->trust_attribs
;
1537 d
.domain_flags
= domain
->domain_flags
;
1538 d
.domain_type
= domain
->domain_type
;
1539 d
.domain_trust_attribs
=
1540 domain
->domain_trust_attribs
;
1542 TALLOC_FREE(parent
);
1545 * We need to pass the modified properties
1548 trust
->trust_flags
= d
.domain_flags
;
1549 trust
->trust_type
= d
.domain_type
;
1550 trust
->trust_attributes
= d
.domain_trust_attribs
;
1552 wcache_tdc_add_domain( &d
);
1558 /* the ADS backend methods are exposed via this structure */
1559 struct winbindd_methods ads_methods
= {