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
,
118 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name
));
119 return ADS_ERROR(LDAP_NO_MEMORY
);
122 SAFE_FREE(ads
->auth
.password
);
123 SAFE_FREE(ads
->auth
.realm
);
125 ads
->auth
.renewable
= renewable
;
126 ads
->auth
.password
= password
;
128 ads
->auth
.flags
|= ADS_AUTH_ALLOW_NTLMSSP
;
130 ads
->auth
.realm
= SMB_STRDUP(auth_realm
);
131 if (!strupper_m(ads
->auth
.realm
)) {
133 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
136 /* Setup the server affinity cache. We don't reaally care
137 about the name. Just setup affinity and the KRB5_CONFIG
139 get_dc_name(ads
->server
.workgroup
, ads
->server
.realm
, dc_name
, &dc_ss
);
141 status
= ads_connect(ads
);
142 if (!ADS_ERR_OK(status
)) {
143 DEBUG(1,("ads_connect for domain %s failed: %s\n",
144 target_dom_name
, ads_errstr(status
)));
149 /* set the flag that says we don't own the memory even
150 though we do so that ads_destroy() won't destroy the
151 structure we pass back by reference */
153 ads
->is_mine
= False
;
160 ADS_STATUS
ads_idmap_cached_connection(ADS_STRUCT
**adsp
, const char *dom_name
)
162 char *ldap_server
, *realm
, *password
;
163 struct winbindd_domain
*wb_dom
;
168 * Make sure we never try to use LDAP against
169 * a trusted domain as AD DC.
171 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED
);
174 ads_cached_connection_reuse(adsp
);
180 * At this point we only have the NetBIOS domain name.
181 * Check if we can get server nam and realm from SAF cache
182 * and the domain list.
184 ldap_server
= saf_fetch(talloc_tos(), dom_name
);
185 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
186 ldap_server
? ldap_server
: ""));
188 wb_dom
= find_domain_from_name(dom_name
);
189 if (wb_dom
== NULL
) {
190 DEBUG(10, ("could not find domain '%s'\n", dom_name
));
191 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
194 DEBUG(10, ("find_domain_from_name found realm '%s' for "
195 " domain '%s'\n", wb_dom
->alt_name
, dom_name
));
197 if (!get_trust_pw_clear(dom_name
, &password
, NULL
, NULL
)) {
198 TALLOC_FREE(ldap_server
);
199 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO
);
203 SMB_ASSERT(wb_dom
->alt_name
!= NULL
);
204 realm
= SMB_STRDUP(wb_dom
->alt_name
);
206 struct winbindd_domain
*our_domain
= wb_dom
;
208 /* always give preference to the alt_name in our
209 primary domain if possible */
211 if (!wb_dom
->primary
) {
212 our_domain
= find_our_domain();
215 if (our_domain
->alt_name
!= NULL
) {
216 realm
= SMB_STRDUP(our_domain
->alt_name
);
218 realm
= SMB_STRDUP(lp_realm());
222 status
= ads_cached_connection_connect(
223 adsp
, /* Returns ads struct. */
224 wb_dom
->alt_name
, /* realm to connect to. */
225 dom_name
, /* 'workgroup' name for ads_init */
226 ldap_server
, /* DNS name to connect to. */
227 password
, /* password for auth realm. */
228 realm
, /* realm used for krb5 ticket. */
229 0); /* renewable ticket time. */
232 TALLOC_FREE(ldap_server
);
238 return our ads connections structure for a domain. We keep the connection
239 open to make things faster
241 static ADS_STRUCT
*ads_cached_connection(struct winbindd_domain
*domain
)
244 char *password
, *realm
;
248 * Make sure we never try to use LDAP against
249 * a trusted domain as AD DC.
254 DEBUG(10,("ads_cached_connection\n"));
255 ads_cached_connection_reuse((ADS_STRUCT
**)&domain
->private_data
);
257 if (domain
->private_data
) {
258 return (ADS_STRUCT
*)domain
->private_data
;
261 /* the machine acct password might have change - fetch it every time */
263 if (!get_trust_pw_clear(domain
->name
, &password
, NULL
, NULL
)) {
268 SMB_ASSERT(domain
->alt_name
!= NULL
);
269 realm
= SMB_STRDUP(domain
->alt_name
);
272 struct winbindd_domain
*our_domain
= domain
;
275 /* always give preference to the alt_name in our
276 primary domain if possible */
278 if ( !domain
->primary
)
279 our_domain
= find_our_domain();
281 if (our_domain
->alt_name
!= NULL
) {
282 realm
= SMB_STRDUP( our_domain
->alt_name
);
285 realm
= SMB_STRDUP( lp_realm() );
288 status
= ads_cached_connection_connect(
289 (ADS_STRUCT
**)&domain
->private_data
,
293 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
);
296 if (!ADS_ERR_OK(status
)) {
297 /* if we get ECONNREFUSED then it might be a NT4
298 server, fall back to MSRPC */
299 if (status
.error_type
== ENUM_ADS_ERROR_SYSTEM
&&
300 status
.err
.rc
== ECONNREFUSED
) {
301 /* 'reconnect_methods' is the MS-RPC backend. */
302 DEBUG(1,("Trying MSRPC methods\n"));
303 domain
->backend
= &reconnect_methods
;
308 return (ADS_STRUCT
*)domain
->private_data
;
311 /* Query display info for a realm. This is the basic user list fn */
312 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
316 ADS_STRUCT
*ads
= NULL
;
317 const char *attrs
[] = { "sAMAccountType", "objectSid", NULL
};
319 uint32_t *rids
= NULL
;
321 LDAPMessage
*res
= NULL
;
322 LDAPMessage
*msg
= NULL
;
323 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
325 DEBUG(3,("ads: query_user_list\n"));
327 if ( !winbindd_can_contact_domain( domain
) ) {
328 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
333 ads
= ads_cached_connection(domain
);
336 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
340 rc
= ads_search_retry(ads
, &res
, "(objectCategory=user)", attrs
);
341 if (!ADS_ERR_OK(rc
)) {
342 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc
)));
343 status
= ads_ntstatus(rc
);
346 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
350 count
= ads_count_replies(ads
, res
);
352 DEBUG(1,("query_user_list: No users found\n"));
356 rids
= talloc_zero_array(mem_ctx
, uint32_t, count
);
358 status
= NT_STATUS_NO_MEMORY
;
364 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
365 struct dom_sid user_sid
;
369 ok
= ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
);
371 DBG_INFO("Object lacks sAMAccountType attribute\n");
374 if (ds_atype_map(atype
) != SID_NAME_USER
) {
375 DBG_INFO("Not a user account? atype=0x%x\n", atype
);
379 if (!ads_pull_sid(ads
, msg
, "objectSid", &user_sid
)) {
380 char *dn
= ads_get_dn(ads
, talloc_tos(), msg
);
381 DBG_INFO("No sid for %s !?\n", dn
);
386 if (!dom_sid_in_domain(&domain
->sid
, &user_sid
)) {
387 struct dom_sid_buf sidstr
, domstr
;
388 DBG_WARNING("Got sid %s in domain %s\n",
389 dom_sid_str_buf(&user_sid
, &sidstr
),
390 dom_sid_str_buf(&domain
->sid
, &domstr
));
394 sid_split_rid(&user_sid
, &rids
[count
]);
398 rids
= talloc_realloc(mem_ctx
, rids
, uint32_t, count
);
403 status
= NT_STATUS_OK
;
405 DBG_NOTICE("ads query_user_list gave %d entries\n", count
);
411 /* list all domain groups */
412 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
414 uint32_t *num_entries
,
415 struct wb_acct_info
**info
)
417 ADS_STRUCT
*ads
= NULL
;
418 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
419 "name", "objectSid", NULL
};
422 LDAPMessage
*res
= NULL
;
423 LDAPMessage
*msg
= NULL
;
424 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
426 bool enum_dom_local_groups
= False
;
430 DEBUG(3,("ads: enum_dom_groups\n"));
432 if ( !winbindd_can_contact_domain( domain
) ) {
433 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
438 /* only grab domain local groups for our domain */
439 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
440 enum_dom_local_groups
= True
;
443 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
446 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
447 * default value, it MUST be absent. In case of extensible matching the
448 * "dnattr" boolean defaults to FALSE and so it must be only be present
451 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
452 * filter using bitwise matching rule then the buggy AD fails to decode
453 * the extensible match. As a workaround set it to TRUE and thereby add
454 * the dnAttributes "dn" field to cope with those older AD versions.
455 * It should not harm and won't put any additional load on the AD since
456 * none of the dn components have a bitmask-attribute.
458 * Thanks to Ralf Haferkamp for input and testing - Guenther */
460 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
461 ADS_LDAP_MATCHING_RULE_BIT_AND
, GROUP_TYPE_SECURITY_ENABLED
,
462 ADS_LDAP_MATCHING_RULE_BIT_AND
,
463 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
465 if (filter
== NULL
) {
466 status
= NT_STATUS_NO_MEMORY
;
470 ads
= ads_cached_connection(domain
);
473 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
477 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
478 if (!ADS_ERR_OK(rc
)) {
479 status
= ads_ntstatus(rc
);
480 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
483 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
487 count
= ads_count_replies(ads
, res
);
489 DEBUG(1,("enum_dom_groups: No groups found\n"));
493 (*info
) = talloc_zero_array(mem_ctx
, struct wb_acct_info
, count
);
495 status
= NT_STATUS_NO_MEMORY
;
501 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
506 name
= ads_pull_username(ads
, (*info
), msg
);
507 gecos
= ads_pull_string(ads
, (*info
), msg
, "name");
508 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
509 DEBUG(1,("No sid for %s !?\n", name
));
513 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
514 DEBUG(1,("No rid for %s !?\n", name
));
518 (*info
)[i
].acct_name
= name
;
519 (*info
)[i
].acct_desc
= gecos
;
520 (*info
)[i
].rid
= rid
;
526 status
= NT_STATUS_OK
;
528 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
532 ads_msgfree(ads
, res
);
537 /* list all domain local groups */
538 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
540 uint32_t *num_entries
,
541 struct wb_acct_info
**info
)
544 * This is a stub function only as we returned the domain
545 * local groups in enum_dom_groups() if the domain->native field
546 * was true. This is a simple performance optimization when
549 * if we ever need to enumerate domain local groups separately,
550 * then this optimization in enum_dom_groups() will need
558 /* convert a single name to a sid in a domain - use rpc methods */
559 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
561 const char *domain_name
,
564 const char **pdom_name
,
566 enum lsa_SidType
*type
)
568 return msrpc_methods
.name_to_sid(domain
, mem_ctx
, domain_name
, name
,
569 flags
, pdom_name
, sid
, type
);
572 /* convert a domain SID to a user or group name - use rpc methods */
573 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
575 const struct dom_sid
*sid
,
578 enum lsa_SidType
*type
)
580 return msrpc_methods
.sid_to_name(domain
, mem_ctx
, sid
,
581 domain_name
, name
, type
);
584 /* convert a list of rids to names - use rpc methods */
585 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
587 const struct dom_sid
*sid
,
592 enum lsa_SidType
**types
)
594 return msrpc_methods
.rids_to_names(domain
, mem_ctx
, sid
,
596 domain_name
, names
, types
);
599 /* Lookup groups a user is a member of - alternate method, for when
600 tokenGroups are not available. */
601 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
604 struct dom_sid
*primary_group
,
605 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
608 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
610 LDAPMessage
*res
= NULL
;
611 LDAPMessage
*msg
= NULL
;
614 const char *group_attrs
[] = {"objectSid", NULL
};
616 uint32_t num_groups
= 0;
618 DEBUG(3,("ads: lookup_usergroups_member\n"));
620 if ( !winbindd_can_contact_domain( domain
) ) {
621 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
626 ads
= ads_cached_connection(domain
);
629 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
633 if (!(escaped_dn
= escape_ldap_string(talloc_tos(), user_dn
))) {
634 status
= NT_STATUS_NO_MEMORY
;
638 ldap_exp
= talloc_asprintf(mem_ctx
,
639 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
641 ADS_LDAP_MATCHING_RULE_BIT_AND
,
642 GROUP_TYPE_SECURITY_ENABLED
);
644 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
645 TALLOC_FREE(escaped_dn
);
646 status
= NT_STATUS_NO_MEMORY
;
650 TALLOC_FREE(escaped_dn
);
652 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
654 if (!ADS_ERR_OK(rc
)) {
655 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
656 return ads_ntstatus(rc
);
658 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
659 return NT_STATUS_INTERNAL_ERROR
;
663 count
= ads_count_replies(ads
, res
);
668 /* always add the primary group to the sid array */
669 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
671 if (!NT_STATUS_IS_OK(status
)) {
676 for (msg
= ads_first_entry(ads
, res
); msg
;
677 msg
= ads_next_entry(ads
, msg
)) {
678 struct dom_sid group_sid
;
680 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
681 DEBUG(1,("No sid for this group ?!?\n"));
685 /* ignore Builtin groups from ADS - Guenther */
686 if (sid_check_is_in_builtin(&group_sid
)) {
690 status
= add_sid_to_array(mem_ctx
, &group_sid
,
691 user_sids
, &num_groups
);
692 if (!NT_STATUS_IS_OK(status
)) {
699 *p_num_groups
= num_groups
;
700 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
702 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
705 ads_msgfree(ads
, res
);
710 /* Lookup groups a user is a member of - alternate method, for when
711 tokenGroups are not available. */
712 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
715 struct dom_sid
*primary_group
,
716 uint32_t *p_num_groups
,
717 struct dom_sid
**user_sids
)
720 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
722 const char *attrs
[] = {"memberOf", NULL
};
723 uint32_t num_groups
= 0;
724 struct dom_sid
*group_sids
= NULL
;
726 char **strings
= NULL
;
727 size_t num_strings
= 0, num_sids
= 0;
730 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
732 if ( !winbindd_can_contact_domain( domain
) ) {
733 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
734 "domain %s\n", domain
->name
));
738 ads
= ads_cached_connection(domain
);
741 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
742 return NT_STATUS_UNSUCCESSFUL
;
745 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
746 ADS_EXTENDED_DN_HEX_STRING
,
747 &strings
, &num_strings
);
749 if (!ADS_ERR_OK(rc
)) {
750 DEBUG(1,("lookup_usergroups_memberof ads_search "
751 "member=%s: %s\n", user_dn
, ads_errstr(rc
)));
752 return ads_ntstatus(rc
);
758 /* always add the primary group to the sid array */
759 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
761 if (!NT_STATUS_IS_OK(status
)) {
765 group_sids
= talloc_zero_array(mem_ctx
, struct dom_sid
, num_strings
+ 1);
767 status
= NT_STATUS_NO_MEMORY
;
771 for (i
=0; i
<num_strings
; i
++) {
772 rc
= ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
773 ADS_EXTENDED_DN_HEX_STRING
,
775 if (!ADS_ERR_OK(rc
)) {
776 /* ignore members without SIDs */
777 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
778 NT_STATUS_NOT_FOUND
)) {
782 status
= ads_ntstatus(rc
);
790 DEBUG(1,("No memberOf for this user?!?\n"));
791 status
= NT_STATUS_NO_MEMORY
;
795 for (i
=0; i
<num_sids
; i
++) {
797 /* ignore Builtin groups from ADS - Guenther */
798 if (sid_check_is_in_builtin(&group_sids
[i
])) {
802 status
= add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
804 if (!NT_STATUS_IS_OK(status
)) {
810 *p_num_groups
= num_groups
;
811 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
813 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
817 TALLOC_FREE(strings
);
818 TALLOC_FREE(group_sids
);
824 /* Lookup groups a user is a member of. */
825 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
827 const struct dom_sid
*sid
,
828 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
830 ADS_STRUCT
*ads
= NULL
;
831 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
834 LDAPMessage
*msg
= NULL
;
835 char *user_dn
= NULL
;
836 struct dom_sid
*sids
;
838 struct dom_sid primary_group
;
839 uint32_t primary_group_rid
;
840 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
841 uint32_t num_groups
= 0;
842 struct dom_sid_buf buf
;
844 DEBUG(3,("ads: lookup_usergroups\n"));
847 status
= lookup_usergroups_cached(mem_ctx
, sid
,
848 p_num_groups
, user_sids
);
849 if (NT_STATUS_IS_OK(status
)) {
853 if ( !winbindd_can_contact_domain( domain
) ) {
854 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
857 /* Tell the cache manager not to remember this one */
859 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
862 ads
= ads_cached_connection(domain
);
865 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
866 status
= NT_STATUS_SERVER_DISABLED
;
870 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
872 if (!ADS_ERR_OK(rc
)) {
873 status
= ads_ntstatus(rc
);
874 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
876 dom_sid_str_buf(sid
, &buf
),
881 count
= ads_count_replies(ads
, msg
);
883 status
= NT_STATUS_UNSUCCESSFUL
;
884 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
885 "invalid number of results (count=%d)\n",
886 dom_sid_str_buf(sid
, &buf
),
892 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
893 dom_sid_str_buf(sid
, &buf
)));
894 status
= NT_STATUS_UNSUCCESSFUL
;
898 user_dn
= ads_get_dn(ads
, mem_ctx
, msg
);
899 if (user_dn
== NULL
) {
900 status
= NT_STATUS_NO_MEMORY
;
904 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
905 DEBUG(1,("%s: No primary group for sid=%s !?\n",
907 dom_sid_str_buf(sid
, &buf
)));
911 sid_compose(&primary_group
, &domain
->sid
, primary_group_rid
);
913 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
915 /* there must always be at least one group in the token,
916 unless we are talking to a buggy Win2k server */
918 /* actually this only happens when the machine account has no read
919 * permissions on the tokenGroup attribute - gd */
925 /* lookup what groups this user is a member of by DN search on
928 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
930 &num_groups
, user_sids
);
931 *p_num_groups
= num_groups
;
932 if (NT_STATUS_IS_OK(status
)) {
936 /* lookup what groups this user is a member of by DN search on
939 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
941 &num_groups
, user_sids
);
942 *p_num_groups
= num_groups
;
949 status
= add_sid_to_array(mem_ctx
, &primary_group
, user_sids
,
951 if (!NT_STATUS_IS_OK(status
)) {
955 for (i
=0;i
<count
;i
++) {
957 /* ignore Builtin groups from ADS - Guenther */
958 if (sid_check_is_in_builtin(&sids
[i
])) {
962 status
= add_sid_to_array_unique(mem_ctx
, &sids
[i
],
963 user_sids
, &num_groups
);
964 if (!NT_STATUS_IS_OK(status
)) {
969 *p_num_groups
= (uint32_t)num_groups
;
970 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
972 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
973 dom_sid_str_buf(sid
, &buf
)));
975 TALLOC_FREE(user_dn
);
976 ads_msgfree(ads
, msg
);
980 /* Lookup aliases a user is member of - use rpc methods */
981 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
983 uint32_t num_sids
, const struct dom_sid
*sids
,
984 uint32_t *num_aliases
, uint32_t **alias_rids
)
986 return msrpc_methods
.lookup_useraliases(domain
, mem_ctx
, num_sids
, sids
,
987 num_aliases
, alias_rids
);
990 static NTSTATUS
add_primary_group_members(
991 ADS_STRUCT
*ads
, TALLOC_CTX
*mem_ctx
, uint32_t rid
,
992 char ***all_members
, size_t *num_all_members
)
995 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
997 const char *attrs
[] = { "dn", NULL
};
998 LDAPMessage
*res
= NULL
;
1004 filter
= talloc_asprintf(
1005 mem_ctx
, "(&(objectCategory=user)(primaryGroupID=%u))",
1007 if (filter
== NULL
) {
1011 args
.control
= ADS_EXTENDED_DN_OID
;
1012 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1013 args
.critical
= True
;
1015 rc
= ads_do_search_all_args(ads
, ads
->config
.bind_path
,
1016 LDAP_SCOPE_SUBTREE
, filter
, attrs
, &args
,
1019 if (!ADS_ERR_OK(rc
)) {
1020 status
= ads_ntstatus(rc
);
1021 DEBUG(1,("%s: ads_search: %s\n", __func__
, ads_errstr(rc
)));
1025 DEBUG(1,("%s: ads_search returned NULL res\n", __func__
));
1029 num_members
= ads_count_replies(ads
, res
);
1031 DEBUG(10, ("%s: Got %ju primary group members\n", __func__
,
1032 (uintmax_t)num_members
));
1034 if (num_members
== 0) {
1035 status
= NT_STATUS_OK
;
1039 members
= talloc_realloc(mem_ctx
, *all_members
, char *,
1040 *num_all_members
+ num_members
);
1041 if (members
== NULL
) {
1042 DEBUG(1, ("%s: talloc_realloc failed\n", __func__
));
1045 *all_members
= members
;
1047 for (msg
= ads_first_entry(ads
, res
); msg
!= NULL
;
1048 msg
= ads_next_entry(ads
, msg
)) {
1051 dn
= ads_get_dn(ads
, members
, msg
);
1053 DEBUG(1, ("%s: ads_get_dn failed\n", __func__
));
1057 members
[*num_all_members
] = dn
;
1058 *num_all_members
+= 1;
1061 status
= NT_STATUS_OK
;
1064 ads_msgfree(ads
, res
);
1066 TALLOC_FREE(filter
);
1071 find the members of a group, given a group rid and domain
1073 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1074 TALLOC_CTX
*mem_ctx
,
1075 const struct dom_sid
*group_sid
,
1076 enum lsa_SidType type
,
1077 uint32_t *num_names
,
1078 struct dom_sid
**sid_mem
, char ***names
,
1079 uint32_t **name_types
)
1082 ADS_STRUCT
*ads
= NULL
;
1084 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1086 char **members
= NULL
;
1088 size_t num_members
= 0;
1090 struct dom_sid
*sid_mem_nocache
= NULL
;
1091 char **names_nocache
= NULL
;
1092 enum lsa_SidType
*name_types_nocache
= NULL
;
1093 char **domains_nocache
= NULL
; /* only needed for rpccli_lsa_lookup_sids */
1094 uint32_t num_nocache
= 0;
1095 TALLOC_CTX
*tmp_ctx
= NULL
;
1097 struct dom_sid_buf buf
;
1099 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
1100 dom_sid_str_buf(group_sid
, &buf
)));
1104 tmp_ctx
= talloc_new(mem_ctx
);
1106 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1107 status
= NT_STATUS_NO_MEMORY
;
1111 if (!sid_peek_rid(group_sid
, &rid
)) {
1112 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__
));
1113 status
= NT_STATUS_INVALID_PARAMETER
;
1117 if ( !winbindd_can_contact_domain( domain
) ) {
1118 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1120 return NT_STATUS_OK
;
1123 ads
= ads_cached_connection(domain
);
1126 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1130 if ((sidbinstr
= ldap_encode_ndr_dom_sid(talloc_tos(), group_sid
)) == NULL
) {
1131 status
= NT_STATUS_NO_MEMORY
;
1135 /* search for all members of the group */
1136 ldap_exp
= talloc_asprintf(tmp_ctx
, "(objectSid=%s)", sidbinstr
);
1137 TALLOC_FREE(sidbinstr
);
1138 if (ldap_exp
== NULL
) {
1139 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1140 status
= NT_STATUS_NO_MEMORY
;
1144 args
.control
= ADS_EXTENDED_DN_OID
;
1145 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1146 args
.critical
= True
;
1148 rc
= ads_ranged_search(ads
, tmp_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
1149 ldap_exp
, &args
, "member", &members
, &num_members
);
1151 if (!ADS_ERR_OK(rc
)) {
1152 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
1153 status
= NT_STATUS_UNSUCCESSFUL
;
1157 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members
));
1159 status
= add_primary_group_members(ads
, mem_ctx
, rid
,
1160 &members
, &num_members
);
1161 if (!NT_STATUS_IS_OK(status
)) {
1162 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1163 __func__
, nt_errstr(status
)));
1167 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1168 __func__
, (int)num_members
));
1170 /* Now that we have a list of sids, we need to get the
1171 * lists of names and name_types belonging to these sids.
1172 * even though conceptually not quite clean, we use the
1173 * RPC call lsa_lookup_sids for this since it can handle a
1174 * list of sids. ldap calls can just resolve one sid at a time.
1176 * At this stage, the sids are still hidden in the exetended dn
1177 * member output format. We actually do a little better than
1178 * stated above: In extracting the sids from the member strings,
1179 * we try to resolve as many sids as possible from the
1180 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1183 (*sid_mem
) = talloc_zero_array(mem_ctx
, struct dom_sid
, num_members
);
1184 (*names
) = talloc_zero_array(mem_ctx
, char *, num_members
);
1185 (*name_types
) = talloc_zero_array(mem_ctx
, uint32_t, num_members
);
1186 (sid_mem_nocache
) = talloc_zero_array(tmp_ctx
, struct dom_sid
, num_members
);
1188 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1189 (*names
== NULL
) || (*name_types
== NULL
) ||
1190 (sid_mem_nocache
== NULL
))
1192 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1193 status
= NT_STATUS_NO_MEMORY
;
1200 (*name_types
) = NULL
;
1203 for (i
=0; i
<num_members
; i
++) {
1204 enum lsa_SidType name_type
;
1205 char *name
, *domain_name
;
1208 rc
= ads_get_sid_from_extended_dn(tmp_ctx
, members
[i
], args
.val
,
1210 if (!ADS_ERR_OK(rc
)) {
1211 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
1212 NT_STATUS_NOT_FOUND
)) {
1213 /* Group members can be objects, like Exchange
1214 * Public Folders, that don't have a SID. Skip
1219 status
= ads_ntstatus(rc
);
1223 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
,
1225 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1227 dom_sid_str_buf(&sid
, &buf
)));
1228 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1229 (*names
)[*num_names
] = fill_domain_username_talloc(
1235 (*name_types
)[*num_names
] = name_type
;
1239 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1241 dom_sid_str_buf(&sid
, &buf
)));
1242 sid_copy(&(sid_mem_nocache
)[num_nocache
], &sid
);
1247 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1248 "%d left for lsa_lookupsids\n", *num_names
, num_nocache
));
1250 /* handle sids not resolved from cache by lsa_lookup_sids */
1251 if (num_nocache
> 0) {
1253 status
= winbindd_lookup_sids(tmp_ctx
,
1259 &name_types_nocache
);
1261 if (!(NT_STATUS_IS_OK(status
) ||
1262 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
) ||
1263 NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)))
1265 DEBUG(1, ("lsa_lookupsids call failed with %s "
1266 "- retrying...\n", nt_errstr(status
)));
1268 status
= winbindd_lookup_sids(tmp_ctx
,
1274 &name_types_nocache
);
1277 if (NT_STATUS_IS_OK(status
) ||
1278 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
))
1280 /* Copy the entries over from the "_nocache" arrays
1281 * to the result arrays, skipping the gaps the
1282 * lookup_sids call left. */
1283 for (i
=0; i
< num_nocache
; i
++) {
1284 if (((names_nocache
)[i
] != NULL
) &&
1285 ((name_types_nocache
)[i
] != SID_NAME_UNKNOWN
))
1287 sid_copy(&(*sid_mem
)[*num_names
],
1288 &sid_mem_nocache
[i
]);
1289 (*names
)[*num_names
] =
1290 fill_domain_username_talloc(
1295 (*name_types
)[*num_names
] = name_types_nocache
[i
];
1300 else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1301 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1302 "not map any SIDs at all.\n"));
1303 /* Don't handle this as an error here.
1304 * There is nothing left to do with respect to the
1305 * overall result... */
1307 else if (!NT_STATUS_IS_OK(status
)) {
1308 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1309 "sids via rpc_lsa_lookup_sids: %s\n",
1310 (int)num_members
, nt_errstr(status
)));
1315 status
= NT_STATUS_OK
;
1316 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1317 dom_sid_str_buf(group_sid
, &buf
)));
1321 TALLOC_FREE(tmp_ctx
);
1326 /* find the sequence number for a domain */
1327 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32_t *seq
)
1329 ADS_STRUCT
*ads
= NULL
;
1332 DEBUG(3,("ads: fetch sequence_number for %s\n", domain
->name
));
1334 if ( !winbindd_can_contact_domain( domain
) ) {
1335 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1338 return NT_STATUS_OK
;
1342 DEBUG(10,("sequence: Avoid LDAP connection for domain %s\n",
1345 return NT_STATUS_OK
;
1348 *seq
= DOM_SEQUENCE_NONE
;
1350 ads
= ads_cached_connection(domain
);
1353 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1354 return NT_STATUS_UNSUCCESSFUL
;
1357 rc
= ads_USN(ads
, seq
);
1359 if (!ADS_ERR_OK(rc
)) {
1361 /* its a dead connection, destroy it */
1363 if (domain
->private_data
) {
1364 ads
= (ADS_STRUCT
*)domain
->private_data
;
1365 ads
->is_mine
= True
;
1367 ads_kdestroy(WINBIND_CCACHE_NAME
);
1368 domain
->private_data
= NULL
;
1371 return ads_ntstatus(rc
);
1374 /* find the lockout policy of a domain - use rpc methods */
1375 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1376 TALLOC_CTX
*mem_ctx
,
1377 struct samr_DomInfo12
*policy
)
1379 return msrpc_methods
.lockout_policy(domain
, mem_ctx
, policy
);
1382 /* find the password policy of a domain - use rpc methods */
1383 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1384 TALLOC_CTX
*mem_ctx
,
1385 struct samr_DomInfo1
*policy
)
1387 return msrpc_methods
.password_policy(domain
, mem_ctx
, policy
);
1390 /* get a list of trusted domains */
1391 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1392 TALLOC_CTX
*mem_ctx
,
1393 struct netr_DomainTrustList
*trusts
)
1395 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1399 struct rpc_pipe_client
*cli
;
1401 struct dcerpc_binding_handle
*b
;
1403 DEBUG(3,("ads: trusted_domains\n"));
1405 ZERO_STRUCTP(trusts
);
1407 /* If this is our primary domain or a root in our forest,
1408 query for all trusts. If not, then just look for domain
1409 trusts in the target forest */
1411 if (domain
->primary
|| domain_is_forest_root(domain
)) {
1412 flags
= NETR_TRUST_FLAG_OUTBOUND
|
1413 NETR_TRUST_FLAG_INBOUND
|
1414 NETR_TRUST_FLAG_IN_FOREST
;
1416 flags
= NETR_TRUST_FLAG_IN_FOREST
;
1419 result
= cm_connect_netlogon(domain
, &cli
);
1421 if (!NT_STATUS_IS_OK(result
)) {
1422 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1423 "for PIPE_NETLOGON (%s)\n",
1424 domain
->name
, nt_errstr(result
)));
1425 return NT_STATUS_UNSUCCESSFUL
;
1428 b
= cli
->binding_handle
;
1430 result
= dcerpc_netr_DsrEnumerateDomainTrusts(b
, mem_ctx
,
1435 if (!NT_STATUS_IS_OK(result
)) {
1439 if (!W_ERROR_IS_OK(werr
)) {
1440 return werror_to_ntstatus(werr
);
1442 if (trusts
->count
== 0) {
1443 return NT_STATUS_OK
;
1446 /* Copy across names and sids */
1449 for (i
= 0; i
< trusts
->count
; i
++) {
1450 struct netr_DomainTrust
*trust
= &trusts
->array
[i
];
1451 struct winbindd_domain d
;
1456 * drop external trusts if this is not our primary
1457 * domain. This means that the returned number of
1458 * domains may be less that the ones actually trusted
1462 if ((trust
->trust_attributes
1463 & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) &&
1466 DEBUG(10,("trusted_domains: Skipping external trusted "
1467 "domain %s because it is outside of our "
1469 trust
->netbios_name
));
1473 /* add to the trusted domain cache */
1475 d
.name
= discard_const_p(char, trust
->netbios_name
);
1476 d
.alt_name
= discard_const_p(char, trust
->dns_name
);
1479 sid_copy(&d
.sid
, trust
->sid
);
1481 sid_copy(&d
.sid
, &global_sid_NULL
);
1484 if ( domain
->primary
) {
1485 DEBUG(10,("trusted_domains(ads): Searching "
1486 "trusted domain list of %s and storing "
1487 "trust flags for domain %s\n",
1488 domain
->name
, d
.alt_name
));
1490 d
.domain_flags
= trust
->trust_flags
;
1491 d
.domain_type
= trust
->trust_type
;
1492 d
.domain_trust_attribs
= trust
->trust_attributes
;
1494 wcache_tdc_add_domain( &d
);
1496 } else if (domain_is_forest_root(domain
)) {
1497 /* Check if we already have this record. If
1498 * we are following our forest root that is not
1499 * our primary domain, we want to keep trust
1500 * flags from the perspective of our primary
1501 * domain not our forest root. */
1502 struct winbindd_tdc_domain
*exist
= NULL
;
1504 exist
= wcache_tdc_fetch_domain(
1505 talloc_tos(), trust
->netbios_name
);
1507 DEBUG(10,("trusted_domains(ads): Searching "
1508 "trusted domain list of %s and "
1509 "storing trust flags for domain "
1510 "%s\n", domain
->name
, d
.alt_name
));
1511 d
.domain_flags
= trust
->trust_flags
;
1512 d
.domain_type
= trust
->trust_type
;
1513 d
.domain_trust_attribs
=
1514 trust
->trust_attributes
;
1516 wcache_tdc_add_domain( &d
);
1521 /* This gets a little tricky. If we are
1522 following a transitive forest trust, then
1523 innerit the flags, type, and attribs from
1524 the domain we queried to make sure we don't
1525 record the view of the trust from the wrong
1526 side. Always view it from the side of our
1527 primary domain. --jerry */
1528 struct winbindd_tdc_domain
*parent
= NULL
;
1530 DEBUG(10,("trusted_domains(ads): Searching "
1531 "trusted domain list of %s and inheriting "
1532 "trust flags for domain %s\n",
1533 domain
->name
, d
.alt_name
));
1535 parent
= wcache_tdc_fetch_domain(talloc_tos(),
1538 d
.domain_flags
= parent
->trust_flags
;
1539 d
.domain_type
= parent
->trust_type
;
1540 d
.domain_trust_attribs
= parent
->trust_attribs
;
1542 d
.domain_flags
= domain
->domain_flags
;
1543 d
.domain_type
= domain
->domain_type
;
1544 d
.domain_trust_attribs
=
1545 domain
->domain_trust_attribs
;
1547 TALLOC_FREE(parent
);
1550 * We need to pass the modified properties
1553 trust
->trust_flags
= d
.domain_flags
;
1554 trust
->trust_type
= d
.domain_type
;
1555 trust
->trust_attributes
= d
.domain_trust_attribs
;
1557 wcache_tdc_add_domain( &d
);
1564 /* the ADS backend methods are exposed via this structure */
1565 struct winbindd_methods ads_methods
= {