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
;
48 * Check if cached connection can be reused. If the connection cannot
49 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
51 static void ads_cached_connection_reuse(ADS_STRUCT
**adsp
)
54 ADS_STRUCT
*ads
= *adsp
;
58 time_t now
= time(NULL
);
60 expire
= nt_time_to_unix(ads
->auth
.expire_time
);
62 DBG_INFO("Current tickets expire in %" PRIu64
" seconds "
63 "(at %" PRIu64
", time is now %" PRIu64
")\n",
64 (uint64_t)expire
- (uint64_t)now
,
68 if ( ads
->config
.realm
&& (expire
> now
)) {
71 /* we own this ADS_STRUCT so make sure it goes away */
72 DEBUG(7,("Deleting expired ads struct\n"));
80 static NTSTATUS
ads_cached_connection_reconnect_creds(struct ads_struct
*ads
,
83 struct cli_credentials
**creds
)
85 struct winbindd_domain
*target_domain
= NULL
;
87 if (ads
->server
.realm
!= NULL
) {
88 target_domain
= find_domain_from_name_noinit(ads
->server
.realm
);
90 if (target_domain
== NULL
&& ads
->server
.workgroup
!= NULL
) {
91 target_domain
= find_domain_from_name_noinit(ads
->server
.workgroup
);
94 if (target_domain
== NULL
) {
95 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
98 return winbindd_get_trust_credentials(target_domain
,
100 false, /* netlogon */
101 false, /* ipc_fallback */
106 * @brief Establish a connection to a DC
108 * @param[out] adsp ADS_STRUCT that will be created
109 * @param[in] target_domain target domain
110 * @param[in] ldap_server DNS name of server to connect to
111 * @param[in] creds credentials to use
112 * @param[in] auth_realm Realm of local domain for creating krb token
116 static ADS_STATUS
ads_cached_connection_connect(struct winbindd_domain
*target_domain
,
117 const char *ldap_server
,
121 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
122 const char *target_realm
= target_domain
->alt_name
;
123 const char *target_dom_name
= target_domain
->name
;
124 struct cli_credentials
*creds
= NULL
;
128 struct sockaddr_storage dc_ss
;
131 /* the machine acct password might have change - fetch it every time */
133 ntstatus
= winbindd_get_trust_credentials(target_domain
,
135 false, /* netlogon */
136 false, /* ipc_fallback */
138 if (!NT_STATUS_IS_OK(ntstatus
)) {
139 status
= ADS_ERROR_NT(ntstatus
);
143 ads
= ads_init(tmp_ctx
,
149 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name
));
150 status
= ADS_ERROR(LDAP_NO_MEMORY
);
154 ads_set_reconnect_fn(ads
, ads_cached_connection_reconnect_creds
, NULL
);
156 /* Setup the server affinity cache. We don't reaally care
157 about the name. Just setup affinity and the KRB5_CONFIG
159 get_dc_name(ads
->server
.workgroup
, ads
->server
.realm
, dc_name
, &dc_ss
);
161 status
= ads_connect_creds(ads
, creds
);
162 if (!ADS_ERR_OK(status
)) {
163 DEBUG(1,("ads_connect for domain %s failed: %s\n",
164 target_dom_name
, ads_errstr(status
)));
168 *adsp
= talloc_move(mem_ctx
, &ads
);
170 TALLOC_FREE(tmp_ctx
);
174 ADS_STATUS
ads_idmap_cached_connection(const char *dom_name
,
178 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
179 char *ldap_server
= NULL
;
180 struct winbindd_domain
*wb_dom
= NULL
;
185 * Make sure we never try to use LDAP against
186 * a trusted domain as AD DC.
188 TALLOC_FREE(tmp_ctx
);
189 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED
);
192 ads_cached_connection_reuse(adsp
);
194 TALLOC_FREE(tmp_ctx
);
199 * At this point we only have the NetBIOS domain name.
200 * Check if we can get server name and realm from SAF cache
201 * and the domain list.
203 ldap_server
= saf_fetch(tmp_ctx
, dom_name
);
205 DBG_DEBUG("ldap_server from saf cache: '%s'\n",
206 ldap_server
? ldap_server
: "");
208 wb_dom
= find_domain_from_name(dom_name
);
209 if (wb_dom
== NULL
) {
210 DBG_DEBUG("could not find domain '%s'\n", dom_name
);
211 TALLOC_FREE(tmp_ctx
);
212 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
215 DBG_DEBUG("find_domain_from_name found realm '%s' for "
216 " domain '%s'\n", wb_dom
->alt_name
, dom_name
);
218 status
= ads_cached_connection_connect(
220 ldap_server
, /* DNS name to connect to. */
221 mem_ctx
, /* memory context for ads struct */
222 adsp
); /* Returns ads struct. */
224 TALLOC_FREE(tmp_ctx
);
230 return our ads connections structure for a domain. We keep the connection
231 open to make things faster
233 static ADS_STATUS
ads_cached_connection(struct winbindd_domain
*domain
,
236 TALLOC_CTX
*tmp_ctx
= talloc_stackframe();
241 * Make sure we never try to use LDAP against
242 * a trusted domain as AD DC.
244 TALLOC_FREE(tmp_ctx
);
245 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED
);
248 DBG_DEBUG("ads_cached_connection\n");
250 ads_cached_connection_reuse(&domain
->backend_data
.ads_conn
);
251 if (domain
->backend_data
.ads_conn
!= NULL
) {
252 *adsp
= domain
->backend_data
.ads_conn
;
253 TALLOC_FREE(tmp_ctx
);
257 status
= ads_cached_connection_connect(
261 &domain
->backend_data
.ads_conn
);
262 if (!ADS_ERR_OK(status
)) {
263 /* if we get ECONNREFUSED then it might be a NT4
264 server, fall back to MSRPC */
265 if (status
.error_type
== ENUM_ADS_ERROR_SYSTEM
&&
266 status
.err
.rc
== ECONNREFUSED
) {
267 /* 'reconnect_methods' is the MS-RPC backend. */
268 DBG_NOTICE("Trying MSRPC methods for domain '%s'\n",
270 domain
->backend
= &reconnect_methods
;
272 TALLOC_FREE(tmp_ctx
);
276 *adsp
= domain
->backend_data
.ads_conn
;
277 TALLOC_FREE(tmp_ctx
);
281 /* Query display info for a realm. This is the basic user list fn */
282 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
286 ADS_STRUCT
*ads
= NULL
;
287 const char *attrs
[] = { "sAMAccountType", "objectSid", NULL
};
289 uint32_t *rids
= NULL
;
291 LDAPMessage
*res
= NULL
;
292 LDAPMessage
*msg
= NULL
;
293 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
295 DEBUG(3,("ads: query_user_list\n"));
297 if ( !winbindd_can_contact_domain( domain
) ) {
298 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
303 rc
= ads_cached_connection(domain
, &ads
);
304 if (!ADS_ERR_OK(rc
)) {
305 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
309 rc
= ads_search_retry(ads
, &res
, "(objectCategory=user)", attrs
);
310 if (!ADS_ERR_OK(rc
)) {
311 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc
)));
312 status
= ads_ntstatus(rc
);
315 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
319 count
= ads_count_replies(ads
, res
);
321 DEBUG(1,("query_user_list: No users found\n"));
325 rids
= talloc_zero_array(mem_ctx
, uint32_t, count
);
327 status
= NT_STATUS_NO_MEMORY
;
333 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
334 struct dom_sid user_sid
;
338 ok
= ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
);
340 DBG_INFO("Object lacks sAMAccountType attribute\n");
343 if (ds_atype_map(atype
) != SID_NAME_USER
) {
344 DBG_INFO("Not a user account? atype=0x%x\n", atype
);
348 if (!ads_pull_sid(ads
, msg
, "objectSid", &user_sid
)) {
349 char *dn
= ads_get_dn(ads
, talloc_tos(), msg
);
350 DBG_INFO("No sid for %s !?\n", dn
);
355 if (!dom_sid_in_domain(&domain
->sid
, &user_sid
)) {
356 struct dom_sid_buf sidstr
, domstr
;
357 DBG_WARNING("Got sid %s in domain %s\n",
358 dom_sid_str_buf(&user_sid
, &sidstr
),
359 dom_sid_str_buf(&domain
->sid
, &domstr
));
363 sid_split_rid(&user_sid
, &rids
[count
]);
367 rids
= talloc_realloc(mem_ctx
, rids
, uint32_t, count
);
374 status
= NT_STATUS_OK
;
376 DBG_NOTICE("ads query_user_list gave %d entries\n", count
);
379 ads_msgfree(ads
, res
);
383 /* list all domain groups */
384 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
386 uint32_t *num_entries
,
387 struct wb_acct_info
**info
)
389 ADS_STRUCT
*ads
= NULL
;
390 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
391 "name", "objectSid", NULL
};
394 LDAPMessage
*res
= NULL
;
395 LDAPMessage
*msg
= NULL
;
396 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
398 bool enum_dom_local_groups
= False
;
402 DEBUG(3,("ads: enum_dom_groups\n"));
404 if ( !winbindd_can_contact_domain( domain
) ) {
405 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
410 /* only grab domain local groups for our domain */
411 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
412 enum_dom_local_groups
= True
;
415 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
418 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
419 * default value, it MUST be absent. In case of extensible matching the
420 * "dnattr" boolean defaults to FALSE and so it must be only be present
423 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
424 * filter using bitwise matching rule then the buggy AD fails to decode
425 * the extensible match. As a workaround set it to TRUE and thereby add
426 * the dnAttributes "dn" field to cope with those older AD versions.
427 * It should not harm and won't put any additional load on the AD since
428 * none of the dn components have a bitmask-attribute.
430 * Thanks to Ralf Haferkamp for input and testing - Guenther */
432 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)"
433 "(&(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND
":=%d)"
434 "(!(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND
":=%d))))",
435 GROUP_TYPE_SECURITY_ENABLED
,
436 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
438 if (filter
== NULL
) {
439 status
= NT_STATUS_NO_MEMORY
;
443 rc
= ads_cached_connection(domain
, &ads
);
444 if (!ADS_ERR_OK(rc
)) {
445 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
449 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
450 if (!ADS_ERR_OK(rc
)) {
451 status
= ads_ntstatus(rc
);
452 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
455 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
459 count
= ads_count_replies(ads
, res
);
461 DEBUG(1,("enum_dom_groups: No groups found\n"));
465 (*info
) = talloc_zero_array(mem_ctx
, struct wb_acct_info
, count
);
467 status
= NT_STATUS_NO_MEMORY
;
473 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
478 name
= ads_pull_username(ads
, (*info
), msg
);
479 gecos
= ads_pull_string(ads
, (*info
), msg
, "name");
480 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
481 DEBUG(1,("No sid for %s !?\n", name
));
485 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
486 DEBUG(1,("No rid for %s !?\n", name
));
490 (*info
)[i
].acct_name
= name
;
491 (*info
)[i
].acct_desc
= gecos
;
492 (*info
)[i
].rid
= rid
;
498 status
= NT_STATUS_OK
;
500 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
504 ads_msgfree(ads
, res
);
509 /* list all domain local groups */
510 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
512 uint32_t *num_entries
,
513 struct wb_acct_info
**info
)
516 * This is a stub function only as we returned the domain
517 * local groups in enum_dom_groups() if the domain->native field
518 * was true. This is a simple performance optimization when
521 * if we ever need to enumerate domain local groups separately,
522 * then this optimization in enum_dom_groups() will need
530 /* convert a single name to a sid in a domain - use rpc methods */
531 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
533 const char *domain_name
,
536 const char **pdom_name
,
538 enum lsa_SidType
*type
)
540 return msrpc_methods
.name_to_sid(domain
, mem_ctx
, domain_name
, name
,
541 flags
, pdom_name
, sid
, type
);
544 /* convert a domain SID to a user or group name - use rpc methods */
545 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
547 const struct dom_sid
*sid
,
550 enum lsa_SidType
*type
)
552 return msrpc_methods
.sid_to_name(domain
, mem_ctx
, sid
,
553 domain_name
, name
, type
);
556 /* convert a list of rids to names - use rpc methods */
557 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
559 const struct dom_sid
*sid
,
564 enum lsa_SidType
**types
)
566 return msrpc_methods
.rids_to_names(domain
, mem_ctx
, sid
,
568 domain_name
, names
, types
);
571 /* Lookup groups a user is a member of - alternate method, for when
572 tokenGroups are not available. */
573 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
576 struct dom_sid
*primary_group
,
577 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
580 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
582 LDAPMessage
*res
= NULL
;
583 LDAPMessage
*msg
= NULL
;
585 ADS_STRUCT
*ads
= NULL
;
586 const char *group_attrs
[] = {"objectSid", NULL
};
588 uint32_t num_groups
= 0;
590 DEBUG(3,("ads: lookup_usergroups_member\n"));
592 if ( !winbindd_can_contact_domain( domain
) ) {
593 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
598 rc
= ads_cached_connection(domain
, &ads
);
599 if (!ADS_ERR_OK(rc
)) {
600 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
604 if (!(escaped_dn
= escape_ldap_string(talloc_tos(), user_dn
))) {
605 status
= NT_STATUS_NO_MEMORY
;
609 ldap_exp
= talloc_asprintf(mem_ctx
,
610 "(&(member=%s)(objectCategory=group)"
611 "(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND
":=%d))",
613 GROUP_TYPE_SECURITY_ENABLED
);
615 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
616 TALLOC_FREE(escaped_dn
);
617 status
= NT_STATUS_NO_MEMORY
;
621 TALLOC_FREE(escaped_dn
);
623 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
625 if (!ADS_ERR_OK(rc
)) {
626 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
627 return ads_ntstatus(rc
);
629 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
630 return NT_STATUS_INTERNAL_ERROR
;
634 count
= ads_count_replies(ads
, res
);
639 /* always add the primary group to the sid array */
640 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
642 if (!NT_STATUS_IS_OK(status
)) {
647 for (msg
= ads_first_entry(ads
, res
); msg
;
648 msg
= ads_next_entry(ads
, msg
)) {
649 struct dom_sid group_sid
;
651 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
652 DEBUG(1,("No sid for this group ?!?\n"));
656 /* ignore Builtin groups from ADS - Guenther */
657 if (sid_check_is_in_builtin(&group_sid
)) {
661 status
= add_sid_to_array(mem_ctx
, &group_sid
,
662 user_sids
, &num_groups
);
663 if (!NT_STATUS_IS_OK(status
)) {
670 *p_num_groups
= num_groups
;
671 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
673 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
676 ads_msgfree(ads
, res
);
681 /* Lookup groups a user is a member of - alternate method, for when
682 tokenGroups are not available. */
683 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
686 struct dom_sid
*primary_group
,
687 uint32_t *p_num_groups
,
688 struct dom_sid
**user_sids
)
691 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
692 ADS_STRUCT
*ads
= NULL
;
693 const char *attrs
[] = {"memberOf", NULL
};
694 uint32_t num_groups
= 0;
695 struct dom_sid
*group_sids
= NULL
;
697 char **strings
= NULL
;
698 size_t num_strings
= 0, num_sids
= 0;
701 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
703 if ( !winbindd_can_contact_domain( domain
) ) {
704 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
705 "domain %s\n", domain
->name
));
709 rc
= ads_cached_connection(domain
, &ads
);
710 if (!ADS_ERR_OK(rc
)) {
711 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
712 return NT_STATUS_UNSUCCESSFUL
;
715 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
716 ADS_EXTENDED_DN_HEX_STRING
,
717 &strings
, &num_strings
);
719 if (!ADS_ERR_OK(rc
)) {
720 DEBUG(1,("lookup_usergroups_memberof ads_search "
721 "member=%s: %s\n", user_dn
, ads_errstr(rc
)));
722 return ads_ntstatus(rc
);
728 /* always add the primary group to the sid array */
729 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
731 if (!NT_STATUS_IS_OK(status
)) {
735 group_sids
= talloc_zero_array(mem_ctx
, struct dom_sid
, num_strings
+ 1);
737 status
= NT_STATUS_NO_MEMORY
;
741 for (i
=0; i
<num_strings
; i
++) {
742 rc
= ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
743 ADS_EXTENDED_DN_HEX_STRING
,
745 if (!ADS_ERR_OK(rc
)) {
746 /* ignore members without SIDs */
747 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
748 NT_STATUS_NOT_FOUND
)) {
752 status
= ads_ntstatus(rc
);
760 DEBUG(1,("No memberOf for this user?!?\n"));
761 status
= NT_STATUS_NO_MEMORY
;
765 for (i
=0; i
<num_sids
; i
++) {
767 /* ignore Builtin groups from ADS - Guenther */
768 if (sid_check_is_in_builtin(&group_sids
[i
])) {
772 status
= add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
774 if (!NT_STATUS_IS_OK(status
)) {
780 *p_num_groups
= num_groups
;
781 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
783 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
787 TALLOC_FREE(strings
);
788 TALLOC_FREE(group_sids
);
794 /* Lookup groups a user is a member of. */
795 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
797 const struct dom_sid
*sid
,
798 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
800 ADS_STRUCT
*ads
= NULL
;
801 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
804 LDAPMessage
*msg
= NULL
;
805 char *user_dn
= NULL
;
806 struct dom_sid
*sids
;
808 struct dom_sid primary_group
;
809 uint32_t primary_group_rid
;
810 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
811 uint32_t num_groups
= 0;
812 struct dom_sid_buf buf
;
814 DEBUG(3,("ads: lookup_usergroups\n"));
817 status
= lookup_usergroups_cached(mem_ctx
, sid
,
818 p_num_groups
, user_sids
);
819 if (NT_STATUS_IS_OK(status
)) {
823 if ( !winbindd_can_contact_domain( domain
) ) {
824 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
827 /* Tell the cache manager not to remember this one */
829 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
832 rc
= ads_cached_connection(domain
, &ads
);
833 if (!ADS_ERR_OK(rc
)) {
834 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
835 status
= NT_STATUS_SERVER_DISABLED
;
839 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
841 if (!ADS_ERR_OK(rc
)) {
842 status
= ads_ntstatus(rc
);
843 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
845 dom_sid_str_buf(sid
, &buf
),
850 count
= ads_count_replies(ads
, msg
);
852 status
= NT_STATUS_UNSUCCESSFUL
;
853 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
854 "invalid number of results (count=%d)\n",
855 dom_sid_str_buf(sid
, &buf
),
861 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
862 dom_sid_str_buf(sid
, &buf
)));
863 status
= NT_STATUS_UNSUCCESSFUL
;
867 user_dn
= ads_get_dn(ads
, mem_ctx
, msg
);
868 if (user_dn
== NULL
) {
869 status
= NT_STATUS_NO_MEMORY
;
873 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
874 DEBUG(1,("%s: No primary group for sid=%s !?\n",
876 dom_sid_str_buf(sid
, &buf
)));
880 sid_compose(&primary_group
, &domain
->sid
, primary_group_rid
);
882 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
884 /* there must always be at least one group in the token,
885 unless we are talking to a buggy Win2k server */
887 /* actually this only happens when the machine account has no read
888 * permissions on the tokenGroup attribute - gd */
894 /* lookup what groups this user is a member of by DN search on
897 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
899 &num_groups
, user_sids
);
900 *p_num_groups
= num_groups
;
901 if (NT_STATUS_IS_OK(status
)) {
905 /* lookup what groups this user is a member of by DN search on
908 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
910 &num_groups
, user_sids
);
911 *p_num_groups
= num_groups
;
918 status
= add_sid_to_array(mem_ctx
, &primary_group
, user_sids
,
920 if (!NT_STATUS_IS_OK(status
)) {
924 for (i
=0;i
<count
;i
++) {
926 /* ignore Builtin groups from ADS - Guenther */
927 if (sid_check_is_in_builtin(&sids
[i
])) {
931 status
= add_sid_to_array_unique(mem_ctx
, &sids
[i
],
932 user_sids
, &num_groups
);
933 if (!NT_STATUS_IS_OK(status
)) {
938 *p_num_groups
= (uint32_t)num_groups
;
939 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
941 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
942 dom_sid_str_buf(sid
, &buf
)));
944 TALLOC_FREE(user_dn
);
945 ads_msgfree(ads
, msg
);
949 /* Lookup aliases a user is member of - use rpc methods */
950 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
952 uint32_t num_sids
, const struct dom_sid
*sids
,
953 uint32_t *num_aliases
, uint32_t **alias_rids
)
955 return msrpc_methods
.lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
956 num_aliases
, alias_rids
);
959 static NTSTATUS
add_primary_group_members(
960 ADS_STRUCT
*ads
, TALLOC_CTX
*mem_ctx
, uint32_t rid
, const char *domname
,
961 char ***all_members
, size_t *num_all_members
)
964 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
966 const char *attrs
[] = { "dn", NULL
};
967 LDAPMessage
*res
= NULL
;
972 bool all_groupmem
= idmap_config_bool(domname
, "all_groupmem", false);
974 filter
= talloc_asprintf(
976 "(&(objectCategory=user)(primaryGroupID=%u)%s)",
978 all_groupmem
? "" : "(uidNumber=*)(!(uidNumber=0))");
979 if (filter
== NULL
) {
983 args
.control
= ADS_EXTENDED_DN_OID
;
984 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
985 args
.critical
= True
;
987 rc
= ads_do_search_all_args(ads
, ads
->config
.bind_path
,
988 LDAP_SCOPE_SUBTREE
, filter
, attrs
, &args
,
991 if (!ADS_ERR_OK(rc
)) {
992 status
= ads_ntstatus(rc
);
993 DEBUG(1,("%s: ads_search: %s\n", __func__
, ads_errstr(rc
)));
997 DEBUG(1,("%s: ads_search returned NULL res\n", __func__
));
1001 num_members
= ads_count_replies(ads
, res
);
1003 DEBUG(10, ("%s: Got %ju primary group members\n", __func__
,
1004 (uintmax_t)num_members
));
1006 if (num_members
== 0) {
1007 status
= NT_STATUS_OK
;
1011 members
= talloc_realloc(mem_ctx
, *all_members
, char *,
1012 *num_all_members
+ num_members
);
1013 if (members
== NULL
) {
1014 DEBUG(1, ("%s: talloc_realloc failed\n", __func__
));
1017 *all_members
= members
;
1019 for (msg
= ads_first_entry(ads
, res
); msg
!= NULL
;
1020 msg
= ads_next_entry(ads
, msg
)) {
1023 dn
= ads_get_dn(ads
, members
, msg
);
1025 DEBUG(1, ("%s: ads_get_dn failed\n", __func__
));
1029 members
[*num_all_members
] = dn
;
1030 *num_all_members
+= 1;
1033 status
= NT_STATUS_OK
;
1036 ads_msgfree(ads
, res
);
1038 TALLOC_FREE(filter
);
1043 find the members of a group, given a group rid and domain
1045 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1046 TALLOC_CTX
*mem_ctx
,
1047 const struct dom_sid
*group_sid
,
1048 enum lsa_SidType type
,
1049 uint32_t *num_names
,
1050 struct dom_sid
**sid_mem
, char ***names
,
1051 uint32_t **name_types
)
1054 ADS_STRUCT
*ads
= NULL
;
1056 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1058 char **members
= NULL
;
1060 size_t num_members
= 0;
1062 struct dom_sid
*sid_mem_nocache
= NULL
;
1063 char **names_nocache
= NULL
;
1064 enum lsa_SidType
*name_types_nocache
= NULL
;
1065 char **domains_nocache
= NULL
; /* only needed for rpccli_lsa_lookup_sids */
1066 uint32_t num_nocache
= 0;
1067 TALLOC_CTX
*tmp_ctx
= NULL
;
1069 struct dom_sid_buf buf
;
1071 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
1072 dom_sid_str_buf(group_sid
, &buf
)));
1076 tmp_ctx
= talloc_new(mem_ctx
);
1078 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1079 status
= NT_STATUS_NO_MEMORY
;
1083 if (!sid_peek_rid(group_sid
, &rid
)) {
1084 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__
));
1085 status
= NT_STATUS_INVALID_PARAMETER
;
1089 if ( !winbindd_can_contact_domain( domain
) ) {
1090 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1092 return NT_STATUS_OK
;
1095 rc
= ads_cached_connection(domain
, &ads
);
1096 if (!ADS_ERR_OK(rc
)) {
1097 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1101 if ((sidbinstr
= ldap_encode_ndr_dom_sid(talloc_tos(), group_sid
)) == NULL
) {
1102 status
= NT_STATUS_NO_MEMORY
;
1106 /* search for all members of the group */
1107 ldap_exp
= talloc_asprintf(tmp_ctx
, "(objectSid=%s)", sidbinstr
);
1108 TALLOC_FREE(sidbinstr
);
1109 if (ldap_exp
== NULL
) {
1110 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1111 status
= NT_STATUS_NO_MEMORY
;
1115 args
.control
= ADS_EXTENDED_DN_OID
;
1116 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1117 args
.critical
= True
;
1119 rc
= ads_ranged_search(ads
, tmp_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
1120 ldap_exp
, &args
, "member", &members
, &num_members
);
1122 if (!ADS_ERR_OK(rc
)) {
1123 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
1124 status
= NT_STATUS_UNSUCCESSFUL
;
1128 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members
));
1130 status
= add_primary_group_members(ads
, mem_ctx
, rid
, domain
->name
,
1131 &members
, &num_members
);
1132 if (!NT_STATUS_IS_OK(status
)) {
1133 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1134 __func__
, nt_errstr(status
)));
1138 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1139 __func__
, (int)num_members
));
1141 /* Now that we have a list of sids, we need to get the
1142 * lists of names and name_types belonging to these sids.
1143 * even though conceptually not quite clean, we use the
1144 * RPC call lsa_lookup_sids for this since it can handle a
1145 * list of sids. ldap calls can just resolve one sid at a time.
1147 * At this stage, the sids are still hidden in the exetended dn
1148 * member output format. We actually do a little better than
1149 * stated above: In extracting the sids from the member strings,
1150 * we try to resolve as many sids as possible from the
1151 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1154 (*sid_mem
) = talloc_zero_array(mem_ctx
, struct dom_sid
, num_members
);
1155 (*names
) = talloc_zero_array(mem_ctx
, char *, num_members
);
1156 (*name_types
) = talloc_zero_array(mem_ctx
, uint32_t, num_members
);
1157 (sid_mem_nocache
) = talloc_zero_array(tmp_ctx
, struct dom_sid
, num_members
);
1159 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1160 (*names
== NULL
) || (*name_types
== NULL
) ||
1161 (sid_mem_nocache
== NULL
))
1163 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1164 status
= NT_STATUS_NO_MEMORY
;
1171 (*name_types
) = NULL
;
1174 for (i
=0; i
<num_members
; i
++) {
1175 enum lsa_SidType name_type
;
1176 char *name
, *domain_name
;
1179 rc
= ads_get_sid_from_extended_dn(tmp_ctx
, members
[i
], args
.val
,
1181 if (!ADS_ERR_OK(rc
)) {
1182 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
1183 NT_STATUS_NOT_FOUND
)) {
1184 /* Group members can be objects, like Exchange
1185 * Public Folders, that don't have a SID. Skip
1190 status
= ads_ntstatus(rc
);
1194 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
,
1196 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1198 dom_sid_str_buf(&sid
, &buf
)));
1199 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1200 (*names
)[*num_names
] = fill_domain_username_talloc(
1206 (*name_types
)[*num_names
] = name_type
;
1210 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1212 dom_sid_str_buf(&sid
, &buf
)));
1213 sid_copy(&(sid_mem_nocache
)[num_nocache
], &sid
);
1218 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1219 "%d left for lsa_lookupsids\n", *num_names
, num_nocache
));
1221 /* handle sids not resolved from cache by lsa_lookup_sids */
1222 if (num_nocache
> 0) {
1224 status
= winbindd_lookup_sids(tmp_ctx
,
1230 &name_types_nocache
);
1232 if (!(NT_STATUS_IS_OK(status
) ||
1233 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
) ||
1234 NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)))
1236 DEBUG(1, ("lsa_lookupsids call failed with %s "
1237 "- retrying...\n", nt_errstr(status
)));
1239 status
= winbindd_lookup_sids(tmp_ctx
,
1245 &name_types_nocache
);
1248 if (NT_STATUS_IS_OK(status
) ||
1249 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
))
1251 /* Copy the entries over from the "_nocache" arrays
1252 * to the result arrays, skipping the gaps the
1253 * lookup_sids call left. */
1254 for (i
=0; i
< num_nocache
; i
++) {
1255 if (((names_nocache
)[i
] != NULL
) &&
1256 ((name_types_nocache
)[i
] != SID_NAME_UNKNOWN
))
1258 sid_copy(&(*sid_mem
)[*num_names
],
1259 &sid_mem_nocache
[i
]);
1260 (*names
)[*num_names
] =
1261 fill_domain_username_talloc(
1266 (*name_types
)[*num_names
] = name_types_nocache
[i
];
1271 else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1272 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1273 "not map any SIDs at all.\n"));
1274 /* Don't handle this as an error here.
1275 * There is nothing left to do with respect to the
1276 * overall result... */
1278 else if (!NT_STATUS_IS_OK(status
)) {
1279 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1280 "sids via rpc_lsa_lookup_sids: %s\n",
1281 (int)num_members
, nt_errstr(status
)));
1286 status
= NT_STATUS_OK
;
1287 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1288 dom_sid_str_buf(group_sid
, &buf
)));
1292 TALLOC_FREE(tmp_ctx
);
1297 static NTSTATUS
lookup_aliasmem(struct winbindd_domain
*domain
,
1298 TALLOC_CTX
*mem_ctx
,
1299 const struct dom_sid
*sid
,
1300 enum lsa_SidType type
,
1302 struct dom_sid
**sids
)
1304 char **names
= NULL
;
1305 uint32_t *name_types
= NULL
;
1306 struct dom_sid_buf buf
;
1308 DBG_DEBUG("ads: lookup_aliasmem %s sid=%s\n",
1310 dom_sid_str_buf(sid
, &buf
));
1311 /* Search for alias and group membership uses the same LDAP command. */
1312 return lookup_groupmem(domain
,
1322 /* find the lockout policy of a domain - use rpc methods */
1323 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1324 TALLOC_CTX
*mem_ctx
,
1325 struct samr_DomInfo12
*policy
)
1327 return msrpc_methods
.lockout_policy(domain
, mem_ctx
, policy
);
1330 /* find the password policy of a domain - use rpc methods */
1331 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1332 TALLOC_CTX
*mem_ctx
,
1333 struct samr_DomInfo1
*policy
)
1335 return msrpc_methods
.password_policy(domain
, mem_ctx
, policy
);
1338 /* get a list of trusted domains */
1339 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1340 TALLOC_CTX
*mem_ctx
,
1341 struct netr_DomainTrustList
*trusts
)
1343 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1347 struct rpc_pipe_client
*cli
;
1348 struct dcerpc_binding_handle
*b
;
1350 DEBUG(3,("ads: trusted_domains\n"));
1352 ZERO_STRUCTP(trusts
);
1354 /* If this is our primary domain or a root in our forest,
1355 query for all trusts. If not, then just look for domain
1356 trusts in the target forest */
1358 if (domain
->primary
|| domain_is_forest_root(domain
)) {
1359 flags
= NETR_TRUST_FLAG_OUTBOUND
|
1360 NETR_TRUST_FLAG_INBOUND
|
1361 NETR_TRUST_FLAG_IN_FOREST
;
1363 flags
= NETR_TRUST_FLAG_IN_FOREST
;
1366 result
= cm_connect_netlogon(domain
, &cli
);
1368 if (!NT_STATUS_IS_OK(result
)) {
1369 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1370 "for PIPE_NETLOGON (%s)\n",
1371 domain
->name
, nt_errstr(result
)));
1372 return NT_STATUS_UNSUCCESSFUL
;
1375 b
= cli
->binding_handle
;
1377 result
= dcerpc_netr_DsrEnumerateDomainTrusts(b
, mem_ctx
,
1382 if (!NT_STATUS_IS_OK(result
)) {
1386 if (!W_ERROR_IS_OK(werr
)) {
1387 return werror_to_ntstatus(werr
);
1389 if (trusts
->count
== 0) {
1390 return NT_STATUS_OK
;
1393 /* Copy across names and sids */
1395 for (i
= 0; i
< trusts
->count
; i
++) {
1396 struct netr_DomainTrust
*trust
= &trusts
->array
[i
];
1397 struct winbindd_domain d
;
1402 * drop external trusts if this is not our primary
1403 * domain. This means that the returned number of
1404 * domains may be less that the ones actually trusted
1408 if ((trust
->trust_attributes
1409 & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) &&
1412 DEBUG(10,("trusted_domains: Skipping external trusted "
1413 "domain %s because it is outside of our "
1415 trust
->netbios_name
));
1419 /* add to the trusted domain cache */
1421 d
.name
= discard_const_p(char, trust
->netbios_name
);
1422 d
.alt_name
= discard_const_p(char, trust
->dns_name
);
1425 sid_copy(&d
.sid
, trust
->sid
);
1427 sid_copy(&d
.sid
, &global_sid_NULL
);
1430 if ( domain
->primary
) {
1431 DEBUG(10,("trusted_domains(ads): Searching "
1432 "trusted domain list of %s and storing "
1433 "trust flags for domain %s\n",
1434 domain
->name
, d
.alt_name
));
1436 d
.domain_flags
= trust
->trust_flags
;
1437 d
.domain_type
= trust
->trust_type
;
1438 d
.domain_trust_attribs
= trust
->trust_attributes
;
1440 wcache_tdc_add_domain( &d
);
1441 } else if (domain_is_forest_root(domain
)) {
1442 /* Check if we already have this record. If
1443 * we are following our forest root that is not
1444 * our primary domain, we want to keep trust
1445 * flags from the perspective of our primary
1446 * domain not our forest root. */
1447 struct winbindd_tdc_domain
*exist
= NULL
;
1449 exist
= wcache_tdc_fetch_domain(
1450 talloc_tos(), trust
->netbios_name
);
1452 DEBUG(10,("trusted_domains(ads): Searching "
1453 "trusted domain list of %s and "
1454 "storing trust flags for domain "
1455 "%s\n", domain
->name
, d
.alt_name
));
1456 d
.domain_flags
= trust
->trust_flags
;
1457 d
.domain_type
= trust
->trust_type
;
1458 d
.domain_trust_attribs
=
1459 trust
->trust_attributes
;
1461 wcache_tdc_add_domain( &d
);
1465 /* This gets a little tricky. If we are
1466 following a transitive forest trust, then
1467 innerit the flags, type, and attribs from
1468 the domain we queried to make sure we don't
1469 record the view of the trust from the wrong
1470 side. Always view it from the side of our
1471 primary domain. --jerry */
1472 struct winbindd_tdc_domain
*parent
= NULL
;
1474 DEBUG(10,("trusted_domains(ads): Searching "
1475 "trusted domain list of %s and inheriting "
1476 "trust flags for domain %s\n",
1477 domain
->name
, d
.alt_name
));
1479 parent
= wcache_tdc_fetch_domain(talloc_tos(),
1482 d
.domain_flags
= parent
->trust_flags
;
1483 d
.domain_type
= parent
->trust_type
;
1484 d
.domain_trust_attribs
= parent
->trust_attribs
;
1486 d
.domain_flags
= domain
->domain_flags
;
1487 d
.domain_type
= domain
->domain_type
;
1488 d
.domain_trust_attribs
=
1489 domain
->domain_trust_attribs
;
1491 TALLOC_FREE(parent
);
1494 * We need to pass the modified properties
1497 trust
->trust_flags
= d
.domain_flags
;
1498 trust
->trust_type
= d
.domain_type
;
1499 trust
->trust_attributes
= d
.domain_trust_attribs
;
1501 wcache_tdc_add_domain( &d
);
1507 /* the ADS backend methods are exposed via this structure */
1508 struct winbindd_methods ads_methods
= {