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"
41 #define DBGC_CLASS DBGC_WINBIND
43 extern struct winbindd_methods reconnect_methods
;
44 extern struct winbindd_methods msrpc_methods
;
46 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
49 * Check if cached connection can be reused. If the connection cannot
50 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
52 static void ads_cached_connection_reuse(ADS_STRUCT
**adsp
)
55 ADS_STRUCT
*ads
= *adsp
;
59 time_t now
= time(NULL
);
61 expire
= MIN(ads
->auth
.tgt_expire
, ads
->auth
.tgs_expire
);
63 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
64 "is now %d)\n", (uint32_t)expire
- (uint32_t)now
,
65 (uint32_t) expire
, (uint32_t) now
));
67 if ( ads
->config
.realm
&& (expire
> now
)) {
70 /* we own this ADS_STRUCT so make sure it goes away */
71 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(ADS_STRUCT
**adsp
,
94 const char *target_realm
,
95 const char *target_dom_name
,
96 const char *ldap_server
,
103 struct sockaddr_storage dc_ss
;
106 if (auth_realm
== NULL
) {
107 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
110 /* we don't want this to affect the users ccache */
111 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME
, 1);
113 ads
= ads_init(target_realm
, target_dom_name
, ldap_server
);
115 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name
));
116 return ADS_ERROR(LDAP_NO_MEMORY
);
119 SAFE_FREE(ads
->auth
.password
);
120 SAFE_FREE(ads
->auth
.realm
);
122 ads
->auth
.renewable
= renewable
;
123 ads
->auth
.password
= password
;
125 ads
->auth
.flags
|= ADS_AUTH_ALLOW_NTLMSSP
;
127 ads
->auth
.realm
= SMB_STRDUP(auth_realm
);
128 if (!strupper_m(ads
->auth
.realm
)) {
130 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
133 /* Setup the server affinity cache. We don't reaally care
134 about the name. Just setup affinity and the KRB5_CONFIG
136 get_dc_name(ads
->server
.workgroup
, ads
->server
.realm
, dc_name
, &dc_ss
);
138 status
= ads_connect(ads
);
139 if (!ADS_ERR_OK(status
)) {
140 DEBUG(1,("ads_connect for domain %s failed: %s\n",
141 target_dom_name
, ads_errstr(status
)));
146 /* set the flag that says we don't own the memory even
147 though we do so that ads_destroy() won't destroy the
148 structure we pass back by reference */
150 ads
->is_mine
= False
;
157 ADS_STATUS
ads_idmap_cached_connection(ADS_STRUCT
**adsp
, const char *dom_name
)
159 char *ldap_server
, *realm
, *password
;
160 struct winbindd_domain
*wb_dom
;
165 * Make sure we never try to use LDAP against
166 * a trusted domain as AD DC.
168 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED
);
171 ads_cached_connection_reuse(adsp
);
177 * At this point we only have the NetBIOS domain name.
178 * Check if we can get server nam and realm from SAF cache
179 * and the domain list.
181 ldap_server
= saf_fetch(talloc_tos(), dom_name
);
182 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
183 ldap_server
? ldap_server
: ""));
185 wb_dom
= find_domain_from_name(dom_name
);
186 if (wb_dom
== NULL
) {
187 DEBUG(10, ("could not find domain '%s'\n", dom_name
));
188 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
191 DEBUG(10, ("find_domain_from_name found realm '%s' for "
192 " domain '%s'\n", wb_dom
->alt_name
, dom_name
));
194 if (!get_trust_pw_clear(dom_name
, &password
, NULL
, NULL
)) {
195 TALLOC_FREE(ldap_server
);
196 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO
);
200 SMB_ASSERT(wb_dom
->alt_name
!= NULL
);
201 realm
= SMB_STRDUP(wb_dom
->alt_name
);
203 struct winbindd_domain
*our_domain
= wb_dom
;
205 /* always give preference to the alt_name in our
206 primary domain if possible */
208 if (!wb_dom
->primary
) {
209 our_domain
= find_our_domain();
212 if (our_domain
->alt_name
!= NULL
) {
213 realm
= SMB_STRDUP(our_domain
->alt_name
);
215 realm
= SMB_STRDUP(lp_realm());
219 status
= ads_cached_connection_connect(
220 adsp
, /* Returns ads struct. */
221 wb_dom
->alt_name
, /* realm to connect to. */
222 dom_name
, /* 'workgroup' name for ads_init */
223 ldap_server
, /* DNS name to connect to. */
224 password
, /* password for auth realm. */
225 realm
, /* realm used for krb5 ticket. */
226 0); /* renewable ticket time. */
229 TALLOC_FREE(ldap_server
);
235 return our ads connections structure for a domain. We keep the connection
236 open to make things faster
238 static ADS_STRUCT
*ads_cached_connection(struct winbindd_domain
*domain
)
241 char *password
, *realm
;
245 * Make sure we never try to use LDAP against
246 * a trusted domain as AD DC.
251 DEBUG(10,("ads_cached_connection\n"));
252 ads_cached_connection_reuse((ADS_STRUCT
**)&domain
->private_data
);
254 if (domain
->private_data
) {
255 return (ADS_STRUCT
*)domain
->private_data
;
258 /* the machine acct password might have change - fetch it every time */
260 if (!get_trust_pw_clear(domain
->name
, &password
, NULL
, NULL
)) {
265 SMB_ASSERT(domain
->alt_name
!= NULL
);
266 realm
= SMB_STRDUP(domain
->alt_name
);
269 struct winbindd_domain
*our_domain
= domain
;
272 /* always give preference to the alt_name in our
273 primary domain if possible */
275 if ( !domain
->primary
)
276 our_domain
= find_our_domain();
278 if (our_domain
->alt_name
!= NULL
) {
279 realm
= SMB_STRDUP( our_domain
->alt_name
);
282 realm
= SMB_STRDUP( lp_realm() );
285 status
= ads_cached_connection_connect(
286 (ADS_STRUCT
**)&domain
->private_data
,
290 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
);
293 if (!ADS_ERR_OK(status
)) {
294 /* if we get ECONNREFUSED then it might be a NT4
295 server, fall back to MSRPC */
296 if (status
.error_type
== ENUM_ADS_ERROR_SYSTEM
&&
297 status
.err
.rc
== ECONNREFUSED
) {
298 /* 'reconnect_methods' is the MS-RPC backend. */
299 DEBUG(1,("Trying MSRPC methods\n"));
300 domain
->backend
= &reconnect_methods
;
305 return (ADS_STRUCT
*)domain
->private_data
;
308 /* Query display info for a realm. This is the basic user list fn */
309 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
313 ADS_STRUCT
*ads
= NULL
;
314 const char *attrs
[] = { "sAMAccountType", "objectSid", NULL
};
316 uint32_t *rids
= NULL
;
318 LDAPMessage
*res
= NULL
;
319 LDAPMessage
*msg
= NULL
;
320 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
322 DEBUG(3,("ads: query_user_list\n"));
324 if ( !winbindd_can_contact_domain( domain
) ) {
325 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
330 ads
= ads_cached_connection(domain
);
333 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
337 rc
= ads_search_retry(ads
, &res
, "(objectCategory=user)", attrs
);
338 if (!ADS_ERR_OK(rc
)) {
339 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc
)));
340 status
= ads_ntstatus(rc
);
343 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
347 count
= ads_count_replies(ads
, res
);
349 DEBUG(1,("query_user_list: No users found\n"));
353 rids
= talloc_zero_array(mem_ctx
, uint32_t, count
);
355 status
= NT_STATUS_NO_MEMORY
;
361 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
362 struct dom_sid user_sid
;
366 ok
= ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
);
368 DBG_INFO("Object lacks sAMAccountType attribute\n");
371 if (ds_atype_map(atype
) != SID_NAME_USER
) {
372 DBG_INFO("Not a user account? atype=0x%x\n", atype
);
376 if (!ads_pull_sid(ads
, msg
, "objectSid", &user_sid
)) {
377 char *dn
= ads_get_dn(ads
, talloc_tos(), msg
);
378 DBG_INFO("No sid for %s !?\n", dn
);
383 if (!dom_sid_in_domain(&domain
->sid
, &user_sid
)) {
384 fstring sidstr
, domstr
;
385 DBG_WARNING("Got sid %s in domain %s\n",
386 sid_to_fstring(sidstr
, &user_sid
),
387 sid_to_fstring(domstr
, &domain
->sid
));
391 sid_split_rid(&user_sid
, &rids
[count
]);
395 rids
= talloc_realloc(mem_ctx
, rids
, uint32_t, count
);
400 status
= NT_STATUS_OK
;
402 DBG_NOTICE("ads query_user_list gave %d entries\n", count
);
408 /* list all domain groups */
409 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
411 uint32_t *num_entries
,
412 struct wb_acct_info
**info
)
414 ADS_STRUCT
*ads
= NULL
;
415 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
416 "name", "objectSid", NULL
};
419 LDAPMessage
*res
= NULL
;
420 LDAPMessage
*msg
= NULL
;
421 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
423 bool enum_dom_local_groups
= False
;
427 DEBUG(3,("ads: enum_dom_groups\n"));
429 if ( !winbindd_can_contact_domain( domain
) ) {
430 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
435 /* only grab domain local groups for our domain */
436 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
437 enum_dom_local_groups
= True
;
440 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
443 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
444 * default value, it MUST be absent. In case of extensible matching the
445 * "dnattr" boolean defaults to FALSE and so it must be only be present
448 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
449 * filter using bitwise matching rule then the buggy AD fails to decode
450 * the extensible match. As a workaround set it to TRUE and thereby add
451 * the dnAttributes "dn" field to cope with those older AD versions.
452 * It should not harm and won't put any additional load on the AD since
453 * none of the dn components have a bitmask-attribute.
455 * Thanks to Ralf Haferkamp for input and testing - Guenther */
457 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
458 ADS_LDAP_MATCHING_RULE_BIT_AND
, GROUP_TYPE_SECURITY_ENABLED
,
459 ADS_LDAP_MATCHING_RULE_BIT_AND
,
460 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
462 if (filter
== NULL
) {
463 status
= NT_STATUS_NO_MEMORY
;
467 ads
= ads_cached_connection(domain
);
470 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
474 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
475 if (!ADS_ERR_OK(rc
)) {
476 status
= ads_ntstatus(rc
);
477 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
480 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
484 count
= ads_count_replies(ads
, res
);
486 DEBUG(1,("enum_dom_groups: No groups found\n"));
490 (*info
) = talloc_zero_array(mem_ctx
, struct wb_acct_info
, count
);
492 status
= NT_STATUS_NO_MEMORY
;
498 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
503 name
= ads_pull_username(ads
, mem_ctx
, msg
);
504 gecos
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
505 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
506 DEBUG(1,("No sid for %s !?\n", name
));
510 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
511 DEBUG(1,("No rid for %s !?\n", name
));
515 fstrcpy((*info
)[i
].acct_name
, name
);
516 fstrcpy((*info
)[i
].acct_desc
, gecos
);
517 (*info
)[i
].rid
= rid
;
523 status
= NT_STATUS_OK
;
525 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
529 ads_msgfree(ads
, res
);
534 /* list all domain local groups */
535 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
537 uint32_t *num_entries
,
538 struct wb_acct_info
**info
)
541 * This is a stub function only as we returned the domain
542 * local groups in enum_dom_groups() if the domain->native field
543 * was true. This is a simple performance optimization when
546 * if we ever need to enumerate domain local groups separately,
547 * then this optimization in enum_dom_groups() will need
555 /* convert a single name to a sid in a domain - use rpc methods */
556 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
558 const char *domain_name
,
561 const char **pdom_name
,
563 enum lsa_SidType
*type
)
565 return msrpc_methods
.name_to_sid(domain
, mem_ctx
, domain_name
, name
,
566 flags
, pdom_name
, sid
, type
);
569 /* convert a domain SID to a user or group name - use rpc methods */
570 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
572 const struct dom_sid
*sid
,
575 enum lsa_SidType
*type
)
577 return msrpc_methods
.sid_to_name(domain
, mem_ctx
, sid
,
578 domain_name
, name
, type
);
581 /* convert a list of rids to names - use rpc methods */
582 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
584 const struct dom_sid
*sid
,
589 enum lsa_SidType
**types
)
591 return msrpc_methods
.rids_to_names(domain
, mem_ctx
, sid
,
593 domain_name
, names
, types
);
596 /* Lookup groups a user is a member of - alternate method, for when
597 tokenGroups are not available. */
598 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
601 struct dom_sid
*primary_group
,
602 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
605 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
607 LDAPMessage
*res
= NULL
;
608 LDAPMessage
*msg
= NULL
;
611 const char *group_attrs
[] = {"objectSid", NULL
};
613 uint32_t num_groups
= 0;
615 DEBUG(3,("ads: lookup_usergroups_member\n"));
617 if ( !winbindd_can_contact_domain( domain
) ) {
618 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
623 ads
= ads_cached_connection(domain
);
626 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
630 if (!(escaped_dn
= escape_ldap_string(talloc_tos(), user_dn
))) {
631 status
= NT_STATUS_NO_MEMORY
;
635 ldap_exp
= talloc_asprintf(mem_ctx
,
636 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
638 ADS_LDAP_MATCHING_RULE_BIT_AND
,
639 GROUP_TYPE_SECURITY_ENABLED
);
641 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
642 TALLOC_FREE(escaped_dn
);
643 status
= NT_STATUS_NO_MEMORY
;
647 TALLOC_FREE(escaped_dn
);
649 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
651 if (!ADS_ERR_OK(rc
)) {
652 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
653 return ads_ntstatus(rc
);
655 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
656 return NT_STATUS_INTERNAL_ERROR
;
660 count
= ads_count_replies(ads
, res
);
665 /* always add the primary group to the sid array */
666 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
668 if (!NT_STATUS_IS_OK(status
)) {
673 for (msg
= ads_first_entry(ads
, res
); msg
;
674 msg
= ads_next_entry(ads
, msg
)) {
675 struct dom_sid group_sid
;
677 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
678 DEBUG(1,("No sid for this group ?!?\n"));
682 /* ignore Builtin groups from ADS - Guenther */
683 if (sid_check_is_in_builtin(&group_sid
)) {
687 status
= add_sid_to_array(mem_ctx
, &group_sid
,
688 user_sids
, &num_groups
);
689 if (!NT_STATUS_IS_OK(status
)) {
696 *p_num_groups
= num_groups
;
697 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
699 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
702 ads_msgfree(ads
, res
);
707 /* Lookup groups a user is a member of - alternate method, for when
708 tokenGroups are not available. */
709 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
712 struct dom_sid
*primary_group
,
713 uint32_t *p_num_groups
,
714 struct dom_sid
**user_sids
)
717 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
719 const char *attrs
[] = {"memberOf", NULL
};
720 uint32_t num_groups
= 0;
721 struct dom_sid
*group_sids
= NULL
;
723 char **strings
= NULL
;
724 size_t num_strings
= 0, num_sids
= 0;
727 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
729 if ( !winbindd_can_contact_domain( domain
) ) {
730 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
731 "domain %s\n", domain
->name
));
735 ads
= ads_cached_connection(domain
);
738 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
739 return NT_STATUS_UNSUCCESSFUL
;
742 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
743 ADS_EXTENDED_DN_HEX_STRING
,
744 &strings
, &num_strings
);
746 if (!ADS_ERR_OK(rc
)) {
747 DEBUG(1,("lookup_usergroups_memberof ads_search "
748 "member=%s: %s\n", user_dn
, ads_errstr(rc
)));
749 return ads_ntstatus(rc
);
755 /* always add the primary group to the sid array */
756 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
758 if (!NT_STATUS_IS_OK(status
)) {
762 group_sids
= talloc_zero_array(mem_ctx
, struct dom_sid
, num_strings
+ 1);
764 status
= NT_STATUS_NO_MEMORY
;
768 for (i
=0; i
<num_strings
; i
++) {
769 rc
= ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
770 ADS_EXTENDED_DN_HEX_STRING
,
772 if (!ADS_ERR_OK(rc
)) {
773 /* ignore members without SIDs */
774 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
775 NT_STATUS_NOT_FOUND
)) {
779 status
= ads_ntstatus(rc
);
787 DEBUG(1,("No memberOf for this user?!?\n"));
788 status
= NT_STATUS_NO_MEMORY
;
792 for (i
=0; i
<num_sids
; i
++) {
794 /* ignore Builtin groups from ADS - Guenther */
795 if (sid_check_is_in_builtin(&group_sids
[i
])) {
799 status
= add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
801 if (!NT_STATUS_IS_OK(status
)) {
807 *p_num_groups
= num_groups
;
808 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
810 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
814 TALLOC_FREE(strings
);
815 TALLOC_FREE(group_sids
);
821 /* Lookup groups a user is a member of. */
822 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
824 const struct dom_sid
*sid
,
825 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
827 ADS_STRUCT
*ads
= NULL
;
828 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
831 LDAPMessage
*msg
= NULL
;
832 char *user_dn
= NULL
;
833 struct dom_sid
*sids
;
835 struct dom_sid primary_group
;
836 uint32_t primary_group_rid
;
837 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
838 uint32_t num_groups
= 0;
840 DEBUG(3,("ads: lookup_usergroups\n"));
843 status
= lookup_usergroups_cached(mem_ctx
, sid
,
844 p_num_groups
, user_sids
);
845 if (NT_STATUS_IS_OK(status
)) {
849 if ( !winbindd_can_contact_domain( domain
) ) {
850 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
853 /* Tell the cache manager not to remember this one */
855 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
858 ads
= ads_cached_connection(domain
);
861 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
862 status
= NT_STATUS_SERVER_DISABLED
;
866 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
868 if (!ADS_ERR_OK(rc
)) {
869 status
= ads_ntstatus(rc
);
870 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
871 "%s\n", sid_string_dbg(sid
), ads_errstr(rc
)));
875 count
= ads_count_replies(ads
, msg
);
877 status
= NT_STATUS_UNSUCCESSFUL
;
878 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
879 "invalid number of results (count=%d)\n",
880 sid_string_dbg(sid
), count
));
885 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
886 sid_string_dbg(sid
)));
887 status
= NT_STATUS_UNSUCCESSFUL
;
891 user_dn
= ads_get_dn(ads
, mem_ctx
, msg
);
892 if (user_dn
== NULL
) {
893 status
= NT_STATUS_NO_MEMORY
;
897 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
898 DEBUG(1,("%s: No primary group for sid=%s !?\n",
899 domain
->name
, sid_string_dbg(sid
)));
903 sid_compose(&primary_group
, &domain
->sid
, primary_group_rid
);
905 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
907 /* there must always be at least one group in the token,
908 unless we are talking to a buggy Win2k server */
910 /* actually this only happens when the machine account has no read
911 * permissions on the tokenGroup attribute - gd */
917 /* lookup what groups this user is a member of by DN search on
920 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
922 &num_groups
, user_sids
);
923 *p_num_groups
= num_groups
;
924 if (NT_STATUS_IS_OK(status
)) {
928 /* lookup what groups this user is a member of by DN search on
931 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
933 &num_groups
, user_sids
);
934 *p_num_groups
= num_groups
;
941 status
= add_sid_to_array(mem_ctx
, &primary_group
, user_sids
,
943 if (!NT_STATUS_IS_OK(status
)) {
947 for (i
=0;i
<count
;i
++) {
949 /* ignore Builtin groups from ADS - Guenther */
950 if (sid_check_is_in_builtin(&sids
[i
])) {
954 status
= add_sid_to_array_unique(mem_ctx
, &sids
[i
],
955 user_sids
, &num_groups
);
956 if (!NT_STATUS_IS_OK(status
)) {
961 *p_num_groups
= (uint32_t)num_groups
;
962 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
964 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
965 sid_string_dbg(sid
)));
967 TALLOC_FREE(user_dn
);
968 ads_msgfree(ads
, msg
);
972 /* Lookup aliases a user is member of - use rpc methods */
973 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
975 uint32_t num_sids
, const struct dom_sid
*sids
,
976 uint32_t *num_aliases
, uint32_t **alias_rids
)
978 return msrpc_methods
.lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
979 num_aliases
, alias_rids
);
982 static NTSTATUS
add_primary_group_members(
983 ADS_STRUCT
*ads
, TALLOC_CTX
*mem_ctx
, uint32_t rid
,
984 char ***all_members
, size_t *num_all_members
)
987 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
989 const char *attrs
[] = { "dn", NULL
};
990 LDAPMessage
*res
= NULL
;
996 filter
= talloc_asprintf(
997 mem_ctx
, "(&(objectCategory=user)(primaryGroupID=%u))",
999 if (filter
== NULL
) {
1003 args
.control
= ADS_EXTENDED_DN_OID
;
1004 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1005 args
.critical
= True
;
1007 rc
= ads_do_search_all_args(ads
, ads
->config
.bind_path
,
1008 LDAP_SCOPE_SUBTREE
, filter
, attrs
, &args
,
1011 if (!ADS_ERR_OK(rc
)) {
1012 status
= ads_ntstatus(rc
);
1013 DEBUG(1,("%s: ads_search: %s\n", __func__
, ads_errstr(rc
)));
1017 DEBUG(1,("%s: ads_search returned NULL res\n", __func__
));
1021 num_members
= ads_count_replies(ads
, res
);
1023 DEBUG(10, ("%s: Got %ju primary group members\n", __func__
,
1024 (uintmax_t)num_members
));
1026 if (num_members
== 0) {
1027 status
= NT_STATUS_OK
;
1031 members
= talloc_realloc(mem_ctx
, *all_members
, char *,
1032 *num_all_members
+ num_members
);
1033 if (members
== NULL
) {
1034 DEBUG(1, ("%s: talloc_realloc failed\n", __func__
));
1037 *all_members
= members
;
1039 for (msg
= ads_first_entry(ads
, res
); msg
!= NULL
;
1040 msg
= ads_next_entry(ads
, msg
)) {
1043 dn
= ads_get_dn(ads
, members
, msg
);
1045 DEBUG(1, ("%s: ads_get_dn failed\n", __func__
));
1049 members
[*num_all_members
] = dn
;
1050 *num_all_members
+= 1;
1053 status
= NT_STATUS_OK
;
1056 ads_msgfree(ads
, res
);
1058 TALLOC_FREE(filter
);
1063 find the members of a group, given a group rid and domain
1065 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1066 TALLOC_CTX
*mem_ctx
,
1067 const struct dom_sid
*group_sid
,
1068 enum lsa_SidType type
,
1069 uint32_t *num_names
,
1070 struct dom_sid
**sid_mem
, char ***names
,
1071 uint32_t **name_types
)
1074 ADS_STRUCT
*ads
= NULL
;
1076 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1078 char **members
= NULL
;
1080 size_t num_members
= 0;
1082 struct dom_sid
*sid_mem_nocache
= NULL
;
1083 char **names_nocache
= NULL
;
1084 enum lsa_SidType
*name_types_nocache
= NULL
;
1085 char **domains_nocache
= NULL
; /* only needed for rpccli_lsa_lookup_sids */
1086 uint32_t num_nocache
= 0;
1087 TALLOC_CTX
*tmp_ctx
= NULL
;
1090 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
1091 sid_string_dbg(group_sid
)));
1095 tmp_ctx
= talloc_new(mem_ctx
);
1097 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1098 status
= NT_STATUS_NO_MEMORY
;
1102 if (!sid_peek_rid(group_sid
, &rid
)) {
1103 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__
));
1104 status
= NT_STATUS_INVALID_PARAMETER
;
1108 if ( !winbindd_can_contact_domain( domain
) ) {
1109 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1111 return NT_STATUS_OK
;
1114 ads
= ads_cached_connection(domain
);
1117 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1121 if ((sidbinstr
= ldap_encode_ndr_dom_sid(talloc_tos(), group_sid
)) == NULL
) {
1122 status
= NT_STATUS_NO_MEMORY
;
1126 /* search for all members of the group */
1127 ldap_exp
= talloc_asprintf(tmp_ctx
, "(objectSid=%s)", sidbinstr
);
1128 TALLOC_FREE(sidbinstr
);
1129 if (ldap_exp
== NULL
) {
1130 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1131 status
= NT_STATUS_NO_MEMORY
;
1135 args
.control
= ADS_EXTENDED_DN_OID
;
1136 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1137 args
.critical
= True
;
1139 rc
= ads_ranged_search(ads
, tmp_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
1140 ldap_exp
, &args
, "member", &members
, &num_members
);
1142 if (!ADS_ERR_OK(rc
)) {
1143 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
1144 status
= NT_STATUS_UNSUCCESSFUL
;
1148 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members
));
1150 status
= add_primary_group_members(ads
, mem_ctx
, rid
,
1151 &members
, &num_members
);
1152 if (!NT_STATUS_IS_OK(status
)) {
1153 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1154 __func__
, nt_errstr(status
)));
1158 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1159 __func__
, (int)num_members
));
1161 /* Now that we have a list of sids, we need to get the
1162 * lists of names and name_types belonging to these sids.
1163 * even though conceptually not quite clean, we use the
1164 * RPC call lsa_lookup_sids for this since it can handle a
1165 * list of sids. ldap calls can just resolve one sid at a time.
1167 * At this stage, the sids are still hidden in the exetended dn
1168 * member output format. We actually do a little better than
1169 * stated above: In extracting the sids from the member strings,
1170 * we try to resolve as many sids as possible from the
1171 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1174 (*sid_mem
) = talloc_zero_array(mem_ctx
, struct dom_sid
, num_members
);
1175 (*names
) = talloc_zero_array(mem_ctx
, char *, num_members
);
1176 (*name_types
) = talloc_zero_array(mem_ctx
, uint32_t, num_members
);
1177 (sid_mem_nocache
) = talloc_zero_array(tmp_ctx
, struct dom_sid
, num_members
);
1179 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1180 (*names
== NULL
) || (*name_types
== NULL
) ||
1181 (sid_mem_nocache
== NULL
))
1183 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1184 status
= NT_STATUS_NO_MEMORY
;
1191 (*name_types
) = NULL
;
1194 for (i
=0; i
<num_members
; i
++) {
1195 enum lsa_SidType name_type
;
1196 char *name
, *domain_name
;
1199 rc
= ads_get_sid_from_extended_dn(tmp_ctx
, members
[i
], args
.val
,
1201 if (!ADS_ERR_OK(rc
)) {
1202 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
1203 NT_STATUS_NOT_FOUND
)) {
1204 /* Group members can be objects, like Exchange
1205 * Public Folders, that don't have a SID. Skip
1210 status
= ads_ntstatus(rc
);
1214 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
,
1216 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1217 "cache\n", sid_string_dbg(&sid
)));
1218 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1219 (*names
)[*num_names
] = fill_domain_username_talloc(
1225 (*name_types
)[*num_names
] = name_type
;
1229 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1230 "cache\n", sid_string_dbg(&sid
)));
1231 sid_copy(&(sid_mem_nocache
)[num_nocache
], &sid
);
1236 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1237 "%d left for lsa_lookupsids\n", *num_names
, num_nocache
));
1239 /* handle sids not resolved from cache by lsa_lookup_sids */
1240 if (num_nocache
> 0) {
1242 status
= winbindd_lookup_sids(tmp_ctx
,
1248 &name_types_nocache
);
1250 if (!(NT_STATUS_IS_OK(status
) ||
1251 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
) ||
1252 NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)))
1254 DEBUG(1, ("lsa_lookupsids call failed with %s "
1255 "- retrying...\n", nt_errstr(status
)));
1257 status
= winbindd_lookup_sids(tmp_ctx
,
1263 &name_types_nocache
);
1266 if (NT_STATUS_IS_OK(status
) ||
1267 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
))
1269 /* Copy the entries over from the "_nocache" arrays
1270 * to the result arrays, skipping the gaps the
1271 * lookup_sids call left. */
1272 for (i
=0; i
< num_nocache
; i
++) {
1273 if (((names_nocache
)[i
] != NULL
) &&
1274 ((name_types_nocache
)[i
] != SID_NAME_UNKNOWN
))
1276 sid_copy(&(*sid_mem
)[*num_names
],
1277 &sid_mem_nocache
[i
]);
1278 (*names
)[*num_names
] =
1279 fill_domain_username_talloc(
1284 (*name_types
)[*num_names
] = name_types_nocache
[i
];
1289 else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1290 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1291 "not map any SIDs at all.\n"));
1292 /* Don't handle this as an error here.
1293 * There is nothing left to do with respect to the
1294 * overall result... */
1296 else if (!NT_STATUS_IS_OK(status
)) {
1297 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1298 "sids via rpc_lsa_lookup_sids: %s\n",
1299 (int)num_members
, nt_errstr(status
)));
1304 status
= NT_STATUS_OK
;
1305 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1306 sid_string_dbg(group_sid
)));
1310 TALLOC_FREE(tmp_ctx
);
1315 /* find the sequence number for a domain */
1316 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32_t *seq
)
1318 ADS_STRUCT
*ads
= NULL
;
1321 DEBUG(3,("ads: fetch sequence_number for %s\n", domain
->name
));
1323 if ( !winbindd_can_contact_domain( domain
) ) {
1324 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1327 return NT_STATUS_OK
;
1331 DEBUG(10,("sequence: Avoid LDAP connection for domain %s\n",
1334 return NT_STATUS_OK
;
1337 *seq
= DOM_SEQUENCE_NONE
;
1339 ads
= ads_cached_connection(domain
);
1342 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1343 return NT_STATUS_UNSUCCESSFUL
;
1346 rc
= ads_USN(ads
, seq
);
1348 if (!ADS_ERR_OK(rc
)) {
1350 /* its a dead connection, destroy it */
1352 if (domain
->private_data
) {
1353 ads
= (ADS_STRUCT
*)domain
->private_data
;
1354 ads
->is_mine
= True
;
1356 ads_kdestroy(WINBIND_CCACHE_NAME
);
1357 domain
->private_data
= NULL
;
1360 return ads_ntstatus(rc
);
1363 /* find the lockout policy of a domain - use rpc methods */
1364 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1365 TALLOC_CTX
*mem_ctx
,
1366 struct samr_DomInfo12
*policy
)
1368 return msrpc_methods
.lockout_policy(domain
, mem_ctx
, policy
);
1371 /* find the password policy of a domain - use rpc methods */
1372 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1373 TALLOC_CTX
*mem_ctx
,
1374 struct samr_DomInfo1
*policy
)
1376 return msrpc_methods
.password_policy(domain
, mem_ctx
, policy
);
1379 /* get a list of trusted domains */
1380 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1381 TALLOC_CTX
*mem_ctx
,
1382 struct netr_DomainTrustList
*trusts
)
1384 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1388 struct rpc_pipe_client
*cli
;
1390 struct dcerpc_binding_handle
*b
;
1392 DEBUG(3,("ads: trusted_domains\n"));
1394 ZERO_STRUCTP(trusts
);
1396 /* If this is our primary domain or a root in our forest,
1397 query for all trusts. If not, then just look for domain
1398 trusts in the target forest */
1400 if (domain
->primary
|| domain_is_forest_root(domain
)) {
1401 flags
= NETR_TRUST_FLAG_OUTBOUND
|
1402 NETR_TRUST_FLAG_INBOUND
|
1403 NETR_TRUST_FLAG_IN_FOREST
;
1405 flags
= NETR_TRUST_FLAG_IN_FOREST
;
1408 result
= cm_connect_netlogon(domain
, &cli
);
1410 if (!NT_STATUS_IS_OK(result
)) {
1411 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1412 "for PIPE_NETLOGON (%s)\n",
1413 domain
->name
, nt_errstr(result
)));
1414 return NT_STATUS_UNSUCCESSFUL
;
1417 b
= cli
->binding_handle
;
1419 result
= dcerpc_netr_DsrEnumerateDomainTrusts(b
, mem_ctx
,
1424 if (!NT_STATUS_IS_OK(result
)) {
1428 if (!W_ERROR_IS_OK(werr
)) {
1429 return werror_to_ntstatus(werr
);
1431 if (trusts
->count
== 0) {
1432 return NT_STATUS_OK
;
1435 /* Copy across names and sids */
1438 for (i
= 0; i
< trusts
->count
; i
++) {
1439 struct netr_DomainTrust
*trust
= &trusts
->array
[i
];
1440 struct winbindd_domain d
;
1445 * drop external trusts if this is not our primary
1446 * domain. This means that the returned number of
1447 * domains may be less that the ones actually trusted
1451 if ((trust
->trust_attributes
1452 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) &&
1455 DEBUG(10,("trusted_domains: Skipping external trusted "
1456 "domain %s because it is outside of our "
1458 trust
->netbios_name
));
1462 /* add to the trusted domain cache */
1464 d
.name
= discard_const_p(char, trust
->netbios_name
);
1465 d
.alt_name
= discard_const_p(char, trust
->dns_name
);
1468 sid_copy(&d
.sid
, trust
->sid
);
1470 sid_copy(&d
.sid
, &global_sid_NULL
);
1473 if ( domain
->primary
) {
1474 DEBUG(10,("trusted_domains(ads): Searching "
1475 "trusted domain list of %s and storing "
1476 "trust flags for domain %s\n",
1477 domain
->name
, d
.alt_name
));
1479 d
.domain_flags
= trust
->trust_flags
;
1480 d
.domain_type
= trust
->trust_type
;
1481 d
.domain_trust_attribs
= trust
->trust_attributes
;
1483 wcache_tdc_add_domain( &d
);
1485 } else if (domain_is_forest_root(domain
)) {
1486 /* Check if we already have this record. If
1487 * we are following our forest root that is not
1488 * our primary domain, we want to keep trust
1489 * flags from the perspective of our primary
1490 * domain not our forest root. */
1491 struct winbindd_tdc_domain
*exist
= NULL
;
1493 exist
= wcache_tdc_fetch_domain(
1494 talloc_tos(), trust
->netbios_name
);
1496 DEBUG(10,("trusted_domains(ads): Searching "
1497 "trusted domain list of %s and "
1498 "storing trust flags for domain "
1499 "%s\n", domain
->name
, d
.alt_name
));
1500 d
.domain_flags
= trust
->trust_flags
;
1501 d
.domain_type
= trust
->trust_type
;
1502 d
.domain_trust_attribs
=
1503 trust
->trust_attributes
;
1505 wcache_tdc_add_domain( &d
);
1510 /* This gets a little tricky. If we are
1511 following a transitive forest trust, then
1512 innerit the flags, type, and attribs from
1513 the domain we queried to make sure we don't
1514 record the view of the trust from the wrong
1515 side. Always view it from the side of our
1516 primary domain. --jerry */
1517 struct winbindd_tdc_domain
*parent
= NULL
;
1519 DEBUG(10,("trusted_domains(ads): Searching "
1520 "trusted domain list of %s and inheriting "
1521 "trust flags for domain %s\n",
1522 domain
->name
, d
.alt_name
));
1524 parent
= wcache_tdc_fetch_domain(talloc_tos(),
1527 d
.domain_flags
= parent
->trust_flags
;
1528 d
.domain_type
= parent
->trust_type
;
1529 d
.domain_trust_attribs
= parent
->trust_attribs
;
1531 d
.domain_flags
= domain
->domain_flags
;
1532 d
.domain_type
= domain
->domain_type
;
1533 d
.domain_trust_attribs
=
1534 domain
->domain_trust_attribs
;
1536 TALLOC_FREE(parent
);
1539 * We need to pass the modified properties
1542 trust
->trust_flags
= d
.domain_flags
;
1543 trust
->trust_type
= d
.domain_type
;
1544 trust
->trust_attributes
= d
.domain_trust_attribs
;
1546 wcache_tdc_add_domain( &d
);
1553 /* the ADS backend methods are exposed via this structure */
1554 struct winbindd_methods ads_methods
= {