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 "rpc_client/rpc_client.h"
27 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
28 #include "../libds/common/flags.h"
30 #include "../libcli/ldap/ldap_ndr.h"
31 #include "../libcli/security/security.h"
32 #include "../libds/common/flag_mapping.h"
38 #define DBGC_CLASS DBGC_WINBIND
40 extern struct winbindd_methods reconnect_methods
;
42 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
45 * Check if cached connection can be reused. If the connection cannot
46 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
48 static void ads_cached_connection_reuse(ADS_STRUCT
**adsp
)
51 ADS_STRUCT
*ads
= *adsp
;
55 time_t now
= time(NULL
);
57 expire
= MIN(ads
->auth
.tgt_expire
, ads
->auth
.tgs_expire
);
59 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
60 "is now %d)\n", (uint32
)expire
- (uint32
)now
,
61 (uint32
) expire
, (uint32
) now
));
63 if ( ads
->config
.realm
&& (expire
> now
)) {
66 /* we own this ADS_STRUCT so make sure it goes away */
67 DEBUG(7,("Deleting expired krb5 credential cache\n"));
70 ads_kdestroy(WINBIND_CCACHE_NAME
);
76 static ADS_STATUS
ads_cached_connection_connect(ADS_STRUCT
**adsp
,
77 const char *dom_name_alt
,
79 const char *ldap_server
,
86 struct sockaddr_storage dc_ss
;
90 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
93 /* we don't want this to affect the users ccache */
94 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME
, 1);
96 ads
= ads_init(dom_name_alt
, dom_name
, ldap_server
);
98 DEBUG(1,("ads_init for domain %s failed\n", dom_name
));
99 return ADS_ERROR(LDAP_NO_MEMORY
);
102 SAFE_FREE(ads
->auth
.password
);
103 SAFE_FREE(ads
->auth
.realm
);
105 ads
->auth
.renewable
= renewable
;
106 ads
->auth
.password
= password
;
108 ads
->auth
.realm
= SMB_STRDUP(realm
);
109 if (!strupper_m(ads
->auth
.realm
)) {
111 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR
);
114 /* Setup the server affinity cache. We don't reaally care
115 about the name. Just setup affinity and the KRB5_CONFIG
117 get_dc_name(ads
->server
.workgroup
, ads
->server
.realm
, dc_name
, &dc_ss
);
119 status
= ads_connect(ads
);
120 if (!ADS_ERR_OK(status
)) {
121 DEBUG(1,("ads_connect for domain %s failed: %s\n",
122 dom_name
, ads_errstr(status
)));
127 /* set the flag that says we don't own the memory even
128 though we do so that ads_destroy() won't destroy the
129 structure we pass back by reference */
131 ads
->is_mine
= False
;
138 ADS_STATUS
ads_idmap_cached_connection(ADS_STRUCT
**adsp
, const char *dom_name
)
140 char *ldap_server
, *realm
, *password
;
141 struct winbindd_domain
*wb_dom
;
144 ads_cached_connection_reuse(adsp
);
150 * At this point we only have the NetBIOS domain name.
151 * Check if we can get server nam and realm from SAF cache
152 * and the domain list.
154 ldap_server
= saf_fetch(talloc_tos(), dom_name
);
155 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
156 ldap_server
? ldap_server
: ""));
158 wb_dom
= find_domain_from_name(dom_name
);
159 if (wb_dom
== NULL
) {
160 DEBUG(10, ("could not find domain '%s'\n", dom_name
));
161 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL
);
164 DEBUG(10, ("find_domain_from_name found realm '%s' for "
165 " domain '%s'\n", wb_dom
->alt_name
, dom_name
));
167 if (!get_trust_pw_clear(dom_name
, &password
, NULL
, NULL
)) {
168 TALLOC_FREE(ldap_server
);
169 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO
);
173 realm
= SMB_STRDUP(wb_dom
->alt_name
);
175 struct winbindd_domain
*our_domain
= wb_dom
;
177 /* always give preference to the alt_name in our
178 primary domain if possible */
180 if (!wb_dom
->primary
) {
181 our_domain
= find_our_domain();
184 if (our_domain
->alt_name
!= NULL
) {
185 realm
= SMB_STRDUP(our_domain
->alt_name
);
187 realm
= SMB_STRDUP(lp_realm());
191 status
= ads_cached_connection_connect(
192 adsp
, /* Returns ads struct. */
193 wb_dom
->alt_name
, /* realm to connect to. */
194 dom_name
, /* 'workgroup' name for ads_init */
195 ldap_server
, /* DNS name to connect to. */
196 password
, /* password for auth realm. */
197 realm
, /* realm used for krb5 ticket. */
198 0); /* renewable ticket time. */
201 TALLOC_FREE(ldap_server
);
207 return our ads connections structure for a domain. We keep the connection
208 open to make things faster
210 static ADS_STRUCT
*ads_cached_connection(struct winbindd_domain
*domain
)
213 char *password
, *realm
;
215 DEBUG(10,("ads_cached_connection\n"));
216 ads_cached_connection_reuse((ADS_STRUCT
**)&domain
->private_data
);
218 if (domain
->private_data
) {
219 return (ADS_STRUCT
*)domain
->private_data
;
222 /* the machine acct password might have change - fetch it every time */
224 if (!get_trust_pw_clear(domain
->name
, &password
, NULL
, NULL
)) {
230 realm
= SMB_STRDUP(domain
->alt_name
);
233 struct winbindd_domain
*our_domain
= domain
;
236 /* always give preference to the alt_name in our
237 primary domain if possible */
239 if ( !domain
->primary
)
240 our_domain
= find_our_domain();
242 if (our_domain
->alt_name
!= NULL
) {
243 realm
= SMB_STRDUP( our_domain
->alt_name
);
246 realm
= SMB_STRDUP( lp_realm() );
249 status
= ads_cached_connection_connect(
250 (ADS_STRUCT
**)&domain
->private_data
,
254 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
);
257 if (!ADS_ERR_OK(status
)) {
258 /* if we get ECONNREFUSED then it might be a NT4
259 server, fall back to MSRPC */
260 if (status
.error_type
== ENUM_ADS_ERROR_SYSTEM
&&
261 status
.err
.rc
== ECONNREFUSED
) {
262 /* 'reconnect_methods' is the MS-RPC backend. */
263 DEBUG(1,("Trying MSRPC methods\n"));
264 domain
->backend
= &reconnect_methods
;
269 return (ADS_STRUCT
*)domain
->private_data
;
272 /* Query display info for a realm. This is the basic user list fn */
273 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
276 struct wbint_userinfo
**pinfo
)
278 ADS_STRUCT
*ads
= NULL
;
279 const char *attrs
[] = { "*", NULL
};
282 LDAPMessage
*res
= NULL
;
283 LDAPMessage
*msg
= NULL
;
284 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
288 DEBUG(3,("ads: query_user_list\n"));
290 if ( !winbindd_can_contact_domain( domain
) ) {
291 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
296 ads
= ads_cached_connection(domain
);
299 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
303 rc
= ads_search_retry(ads
, &res
, "(objectCategory=user)", attrs
);
304 if (!ADS_ERR_OK(rc
)) {
305 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc
)));
306 status
= ads_ntstatus(rc
);
309 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
313 count
= ads_count_replies(ads
, res
);
315 DEBUG(1,("query_user_list: No users found\n"));
319 (*pinfo
) = talloc_zero_array(mem_ctx
, struct wbint_userinfo
, count
);
321 status
= NT_STATUS_NO_MEMORY
;
327 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
328 struct wbint_userinfo
*info
= &((*pinfo
)[count
]);
332 if (!ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
) ||
333 ds_atype_map(atype
) != SID_NAME_USER
) {
334 DEBUG(1,("Not a user account? atype=0x%x\n", atype
));
338 info
->acct_name
= ads_pull_username(ads
, mem_ctx
, msg
);
339 info
->full_name
= ads_pull_string(ads
, mem_ctx
, msg
, "displayName");
340 if (info
->full_name
== NULL
) {
341 info
->full_name
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
343 info
->homedir
= NULL
;
345 info
->primary_gid
= (gid_t
)-1;
347 if (!ads_pull_sid(ads
, msg
, "objectSid",
349 DEBUG(1, ("No sid for %s !?\n", info
->acct_name
));
353 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group
)) {
354 DEBUG(1, ("No primary group for %s !?\n",
358 sid_compose(&info
->group_sid
, &domain
->sid
, group
);
363 (*num_entries
) = count
;
364 ads_msgfree(ads
, res
);
366 for (i
=0; i
<count
; i
++) {
367 struct wbint_userinfo
*info
= &((*pinfo
)[i
]);
368 const char *gecos
= NULL
;
369 gid_t primary_gid
= (gid_t
)-1;
371 status
= nss_get_info_cached(domain
, &info
->user_sid
, mem_ctx
,
372 &info
->homedir
, &info
->shell
,
373 &gecos
, &primary_gid
);
374 if (!NT_STATUS_IS_OK(status
)) {
376 * Deliberately ignore this error, there might be more
383 info
->full_name
= gecos
;
385 info
->primary_gid
= primary_gid
;
388 status
= NT_STATUS_OK
;
390 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries
)));
396 /* list all domain groups */
397 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
400 struct wb_acct_info
**info
)
402 ADS_STRUCT
*ads
= NULL
;
403 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
404 "name", "objectSid", NULL
};
407 LDAPMessage
*res
= NULL
;
408 LDAPMessage
*msg
= NULL
;
409 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
411 bool enum_dom_local_groups
= False
;
415 DEBUG(3,("ads: enum_dom_groups\n"));
417 if ( !winbindd_can_contact_domain( domain
) ) {
418 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
423 /* only grab domain local groups for our domain */
424 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
425 enum_dom_local_groups
= True
;
428 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
431 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
432 * default value, it MUST be absent. In case of extensible matching the
433 * "dnattr" boolean defaults to FALSE and so it must be only be present
436 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
437 * filter using bitwise matching rule then the buggy AD fails to decode
438 * the extensible match. As a workaround set it to TRUE and thereby add
439 * the dnAttributes "dn" field to cope with those older AD versions.
440 * It should not harm and won't put any additional load on the AD since
441 * none of the dn components have a bitmask-attribute.
443 * Thanks to Ralf Haferkamp for input and testing - Guenther */
445 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
446 ADS_LDAP_MATCHING_RULE_BIT_AND
, GROUP_TYPE_SECURITY_ENABLED
,
447 ADS_LDAP_MATCHING_RULE_BIT_AND
,
448 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
450 if (filter
== NULL
) {
451 status
= NT_STATUS_NO_MEMORY
;
455 ads
= ads_cached_connection(domain
);
458 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
462 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
463 if (!ADS_ERR_OK(rc
)) {
464 status
= ads_ntstatus(rc
);
465 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
468 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
472 count
= ads_count_replies(ads
, res
);
474 DEBUG(1,("enum_dom_groups: No groups found\n"));
478 (*info
) = talloc_zero_array(mem_ctx
, struct wb_acct_info
, count
);
480 status
= NT_STATUS_NO_MEMORY
;
486 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
491 name
= ads_pull_username(ads
, mem_ctx
, msg
);
492 gecos
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
493 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
494 DEBUG(1,("No sid for %s !?\n", name
));
498 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
499 DEBUG(1,("No rid for %s !?\n", name
));
503 fstrcpy((*info
)[i
].acct_name
, name
);
504 fstrcpy((*info
)[i
].acct_desc
, gecos
);
505 (*info
)[i
].rid
= rid
;
511 status
= NT_STATUS_OK
;
513 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
517 ads_msgfree(ads
, res
);
522 /* list all domain local groups */
523 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
526 struct wb_acct_info
**info
)
529 * This is a stub function only as we returned the domain
530 * local groups in enum_dom_groups() if the domain->native field
531 * was true. This is a simple performance optimization when
534 * if we ever need to enumerate domain local groups separately,
535 * then this optimization in enum_dom_groups() will need
543 /* convert a single name to a sid in a domain - use rpc methods */
544 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
546 const char *domain_name
,
550 enum lsa_SidType
*type
)
552 return reconnect_methods
.name_to_sid(domain
, mem_ctx
,
553 domain_name
, name
, flags
,
557 /* convert a domain SID to a user or group name - use rpc methods */
558 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
560 const struct dom_sid
*sid
,
563 enum lsa_SidType
*type
)
565 return reconnect_methods
.sid_to_name(domain
, mem_ctx
, sid
,
566 domain_name
, name
, type
);
569 /* convert a list of rids to names - use rpc methods */
570 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
572 const struct dom_sid
*sid
,
577 enum lsa_SidType
**types
)
579 return reconnect_methods
.rids_to_names(domain
, mem_ctx
, sid
,
581 domain_name
, names
, types
);
584 /* If you are looking for "dn_lookup": Yes, it used to be here!
585 * It has gone now since it was a major speed bottleneck in
586 * lookup_groupmem (its only use). It has been replaced by
587 * an rpc lookup sids call... R.I.P. */
589 /* Lookup user information from a rid */
590 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
592 const struct dom_sid
*sid
,
593 struct wbint_userinfo
*info
)
595 ADS_STRUCT
*ads
= NULL
;
596 const char *attrs
[] = { "*", NULL
};
599 LDAPMessage
*msg
= NULL
;
603 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
604 struct netr_SamInfo3
*user
= NULL
;
609 DEBUG(3,("ads: query_user\n"));
611 info
->homedir
= NULL
;
614 /* try netsamlogon cache first */
616 if ( (user
= netsamlogon_cache_get( mem_ctx
, sid
)) != NULL
)
618 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
619 sid_string_dbg(sid
)));
621 sid_compose(&info
->user_sid
, &domain
->sid
, user
->base
.rid
);
622 sid_compose(&info
->group_sid
, &domain
->sid
, user
->base
.primary_gid
);
624 info
->acct_name
= talloc_strdup(mem_ctx
, user
->base
.account_name
.string
);
625 info
->full_name
= talloc_strdup(mem_ctx
, user
->base
.full_name
.string
);
627 nss_get_info_cached( domain
, sid
, mem_ctx
,
628 &info
->homedir
, &info
->shell
, &info
->full_name
,
630 info
->primary_gid
= gid
;
634 if (info
->full_name
== NULL
) {
635 /* this might fail so we dont check the return code */
636 wcache_query_user_fullname(domain
,
645 if ( !winbindd_can_contact_domain(domain
)) {
646 DEBUG(8,("query_user: No incoming trust from domain %s\n",
649 /* We still need to generate some basic information
650 about the user even if we cannot contact the
651 domain. Most of this stuff we can deduce. */
653 sid_copy( &info
->user_sid
, sid
);
655 /* Assume "Domain Users" for the primary group */
657 sid_compose(&info
->group_sid
, &domain
->sid
, DOMAIN_RID_USERS
);
659 /* Try to fill in what the nss_info backend can do */
661 nss_get_info_cached( domain
, sid
, mem_ctx
,
662 &info
->homedir
, &info
->shell
, &info
->full_name
,
664 info
->primary_gid
= gid
;
669 /* no cache...do the query */
671 if ( (ads
= ads_cached_connection(domain
)) == NULL
) {
672 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
673 return NT_STATUS_SERVER_DISABLED
;
676 sidstr
= ldap_encode_ndr_dom_sid(talloc_tos(), sid
);
678 ret
= asprintf(&ldap_exp
, "(objectSid=%s)", sidstr
);
681 return NT_STATUS_NO_MEMORY
;
683 rc
= ads_search_retry(ads
, &msg
, ldap_exp
, attrs
);
685 if (!ADS_ERR_OK(rc
)) {
686 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
687 sid_string_dbg(sid
), ads_errstr(rc
)));
688 return ads_ntstatus(rc
);
690 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
691 sid_string_dbg(sid
)));
692 return NT_STATUS_INTERNAL_ERROR
;
695 count
= ads_count_replies(ads
, msg
);
697 DEBUG(1,("query_user(sid=%s): Not found\n",
698 sid_string_dbg(sid
)));
699 ads_msgfree(ads
, msg
);
700 return NT_STATUS_NO_SUCH_USER
;
703 info
->acct_name
= ads_pull_username(ads
, mem_ctx
, msg
);
705 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group_rid
)) {
706 DEBUG(1,("No primary group for %s !?\n",
707 sid_string_dbg(sid
)));
708 ads_msgfree(ads
, msg
);
709 return NT_STATUS_NO_SUCH_USER
;
711 sid_copy(&info
->user_sid
, sid
);
712 sid_compose(&info
->group_sid
, &domain
->sid
, group_rid
);
715 * We have to fetch the "name" attribute before doing the
716 * nss_get_info_cached call. nss_get_info_cached might destroy
717 * the ads struct, potentially invalidating the ldap message.
719 full_name
= ads_pull_string(ads
, mem_ctx
, msg
, "displayName");
720 if (full_name
== NULL
) {
721 full_name
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
724 ads_msgfree(ads
, msg
);
727 status
= nss_get_info_cached( domain
, sid
, mem_ctx
,
728 &info
->homedir
, &info
->shell
, &info
->full_name
,
730 info
->primary_gid
= gid
;
731 if (!NT_STATUS_IS_OK(status
)) {
732 DEBUG(1, ("nss_get_info_cached failed: %s\n",
737 if (info
->full_name
== NULL
) {
738 info
->full_name
= full_name
;
740 TALLOC_FREE(full_name
);
743 status
= NT_STATUS_OK
;
745 DEBUG(3,("ads query_user gave %s\n", info
->acct_name
));
749 /* Lookup groups a user is a member of - alternate method, for when
750 tokenGroups are not available. */
751 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
754 struct dom_sid
*primary_group
,
755 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
758 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
760 LDAPMessage
*res
= NULL
;
761 LDAPMessage
*msg
= NULL
;
764 const char *group_attrs
[] = {"objectSid", NULL
};
766 uint32_t num_groups
= 0;
768 DEBUG(3,("ads: lookup_usergroups_member\n"));
770 if ( !winbindd_can_contact_domain( domain
) ) {
771 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
776 ads
= ads_cached_connection(domain
);
779 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
783 if (!(escaped_dn
= escape_ldap_string(talloc_tos(), user_dn
))) {
784 status
= NT_STATUS_NO_MEMORY
;
788 ldap_exp
= talloc_asprintf(mem_ctx
,
789 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
791 ADS_LDAP_MATCHING_RULE_BIT_AND
,
792 GROUP_TYPE_SECURITY_ENABLED
);
794 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
795 TALLOC_FREE(escaped_dn
);
796 status
= NT_STATUS_NO_MEMORY
;
800 TALLOC_FREE(escaped_dn
);
802 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
804 if (!ADS_ERR_OK(rc
)) {
805 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
806 return ads_ntstatus(rc
);
808 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
809 return NT_STATUS_INTERNAL_ERROR
;
813 count
= ads_count_replies(ads
, res
);
818 /* always add the primary group to the sid array */
819 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
821 if (!NT_STATUS_IS_OK(status
)) {
826 for (msg
= ads_first_entry(ads
, res
); msg
;
827 msg
= ads_next_entry(ads
, msg
)) {
828 struct dom_sid group_sid
;
830 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
831 DEBUG(1,("No sid for this group ?!?\n"));
835 /* ignore Builtin groups from ADS - Guenther */
836 if (sid_check_is_in_builtin(&group_sid
)) {
840 status
= add_sid_to_array(mem_ctx
, &group_sid
,
841 user_sids
, &num_groups
);
842 if (!NT_STATUS_IS_OK(status
)) {
849 *p_num_groups
= num_groups
;
850 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
852 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
855 ads_msgfree(ads
, res
);
860 /* Lookup groups a user is a member of - alternate method, for when
861 tokenGroups are not available. */
862 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
865 struct dom_sid
*primary_group
,
866 uint32_t *p_num_groups
,
867 struct dom_sid
**user_sids
)
870 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
872 const char *attrs
[] = {"memberOf", NULL
};
873 uint32_t num_groups
= 0;
874 struct dom_sid
*group_sids
= NULL
;
876 char **strings
= NULL
;
877 size_t num_strings
= 0, num_sids
= 0;
880 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
882 if ( !winbindd_can_contact_domain( domain
) ) {
883 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
884 "domain %s\n", domain
->name
));
888 ads
= ads_cached_connection(domain
);
891 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
892 return NT_STATUS_UNSUCCESSFUL
;
895 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
896 ADS_EXTENDED_DN_HEX_STRING
,
897 &strings
, &num_strings
);
899 if (!ADS_ERR_OK(rc
)) {
900 DEBUG(1,("lookup_usergroups_memberof ads_search "
901 "member=%s: %s\n", user_dn
, ads_errstr(rc
)));
902 return ads_ntstatus(rc
);
908 /* always add the primary group to the sid array */
909 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
911 if (!NT_STATUS_IS_OK(status
)) {
915 group_sids
= talloc_zero_array(mem_ctx
, struct dom_sid
, num_strings
+ 1);
917 status
= NT_STATUS_NO_MEMORY
;
921 for (i
=0; i
<num_strings
; i
++) {
922 rc
= ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
923 ADS_EXTENDED_DN_HEX_STRING
,
925 if (!ADS_ERR_OK(rc
)) {
926 /* ignore members without SIDs */
927 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
928 NT_STATUS_NOT_FOUND
)) {
932 status
= ads_ntstatus(rc
);
940 DEBUG(1,("No memberOf for this user?!?\n"));
941 status
= NT_STATUS_NO_MEMORY
;
945 for (i
=0; i
<num_sids
; i
++) {
947 /* ignore Builtin groups from ADS - Guenther */
948 if (sid_check_is_in_builtin(&group_sids
[i
])) {
952 status
= add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
954 if (!NT_STATUS_IS_OK(status
)) {
960 *p_num_groups
= num_groups
;
961 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
963 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
967 TALLOC_FREE(strings
);
968 TALLOC_FREE(group_sids
);
974 /* Lookup groups a user is a member of. */
975 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
977 const struct dom_sid
*sid
,
978 uint32
*p_num_groups
, struct dom_sid
**user_sids
)
980 ADS_STRUCT
*ads
= NULL
;
981 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
984 LDAPMessage
*msg
= NULL
;
985 char *user_dn
= NULL
;
986 struct dom_sid
*sids
;
988 struct dom_sid primary_group
;
989 uint32 primary_group_rid
;
990 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
991 uint32_t num_groups
= 0;
993 DEBUG(3,("ads: lookup_usergroups\n"));
996 status
= lookup_usergroups_cached(domain
, mem_ctx
, sid
,
997 p_num_groups
, user_sids
);
998 if (NT_STATUS_IS_OK(status
)) {
1002 if ( !winbindd_can_contact_domain( domain
) ) {
1003 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
1006 /* Tell the cache manager not to remember this one */
1008 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
1011 ads
= ads_cached_connection(domain
);
1014 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1015 status
= NT_STATUS_SERVER_DISABLED
;
1019 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
1021 if (!ADS_ERR_OK(rc
)) {
1022 status
= ads_ntstatus(rc
);
1023 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1024 "%s\n", sid_string_dbg(sid
), ads_errstr(rc
)));
1028 count
= ads_count_replies(ads
, msg
);
1030 status
= NT_STATUS_UNSUCCESSFUL
;
1031 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1032 "invalid number of results (count=%d)\n",
1033 sid_string_dbg(sid
), count
));
1038 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
1039 sid_string_dbg(sid
)));
1040 status
= NT_STATUS_UNSUCCESSFUL
;
1044 user_dn
= ads_get_dn(ads
, mem_ctx
, msg
);
1045 if (user_dn
== NULL
) {
1046 status
= NT_STATUS_NO_MEMORY
;
1050 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
1051 DEBUG(1,("%s: No primary group for sid=%s !?\n",
1052 domain
->name
, sid_string_dbg(sid
)));
1056 sid_compose(&primary_group
, &domain
->sid
, primary_group_rid
);
1058 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
1060 /* there must always be at least one group in the token,
1061 unless we are talking to a buggy Win2k server */
1063 /* actually this only happens when the machine account has no read
1064 * permissions on the tokenGroup attribute - gd */
1068 /* no tokenGroups */
1070 /* lookup what groups this user is a member of by DN search on
1073 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
1075 &num_groups
, user_sids
);
1076 *p_num_groups
= num_groups
;
1077 if (NT_STATUS_IS_OK(status
)) {
1081 /* lookup what groups this user is a member of by DN search on
1084 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
1086 &num_groups
, user_sids
);
1087 *p_num_groups
= num_groups
;
1094 status
= add_sid_to_array(mem_ctx
, &primary_group
, user_sids
,
1096 if (!NT_STATUS_IS_OK(status
)) {
1100 for (i
=0;i
<count
;i
++) {
1102 /* ignore Builtin groups from ADS - Guenther */
1103 if (sid_check_is_in_builtin(&sids
[i
])) {
1107 status
= add_sid_to_array_unique(mem_ctx
, &sids
[i
],
1108 user_sids
, &num_groups
);
1109 if (!NT_STATUS_IS_OK(status
)) {
1114 *p_num_groups
= (uint32
)num_groups
;
1115 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1117 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1118 sid_string_dbg(sid
)));
1120 TALLOC_FREE(user_dn
);
1121 ads_msgfree(ads
, msg
);
1125 /* Lookup aliases a user is member of - use rpc methods */
1126 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1127 TALLOC_CTX
*mem_ctx
,
1128 uint32 num_sids
, const struct dom_sid
*sids
,
1129 uint32
*num_aliases
, uint32
**alias_rids
)
1131 return reconnect_methods
.lookup_useraliases(domain
, mem_ctx
,
1138 find the members of a group, given a group rid and domain
1140 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1141 TALLOC_CTX
*mem_ctx
,
1142 const struct dom_sid
*group_sid
,
1143 enum lsa_SidType type
,
1145 struct dom_sid
**sid_mem
, char ***names
,
1146 uint32
**name_types
)
1149 ADS_STRUCT
*ads
= NULL
;
1151 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1153 char **members
= NULL
;
1155 size_t num_members
= 0;
1157 struct dom_sid
*sid_mem_nocache
= NULL
;
1158 char **names_nocache
= NULL
;
1159 enum lsa_SidType
*name_types_nocache
= NULL
;
1160 char **domains_nocache
= NULL
; /* only needed for rpccli_lsa_lookup_sids */
1161 uint32 num_nocache
= 0;
1162 TALLOC_CTX
*tmp_ctx
= NULL
;
1164 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
1165 sid_string_dbg(group_sid
)));
1169 tmp_ctx
= talloc_new(mem_ctx
);
1171 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1172 status
= NT_STATUS_NO_MEMORY
;
1176 if ( !winbindd_can_contact_domain( domain
) ) {
1177 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1179 return NT_STATUS_OK
;
1182 ads
= ads_cached_connection(domain
);
1185 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1189 if ((sidbinstr
= ldap_encode_ndr_dom_sid(talloc_tos(), group_sid
)) == NULL
) {
1190 status
= NT_STATUS_NO_MEMORY
;
1194 /* search for all members of the group */
1195 ldap_exp
= talloc_asprintf(tmp_ctx
, "(objectSid=%s)", sidbinstr
);
1196 TALLOC_FREE(sidbinstr
);
1197 if (ldap_exp
== NULL
) {
1198 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1199 status
= NT_STATUS_NO_MEMORY
;
1203 args
.control
= ADS_EXTENDED_DN_OID
;
1204 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1205 args
.critical
= True
;
1207 rc
= ads_ranged_search(ads
, tmp_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
1208 ldap_exp
, &args
, "member", &members
, &num_members
);
1210 if (!ADS_ERR_OK(rc
)) {
1211 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
1212 status
= NT_STATUS_UNSUCCESSFUL
;
1216 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members
));
1218 /* Now that we have a list of sids, we need to get the
1219 * lists of names and name_types belonging to these sids.
1220 * even though conceptually not quite clean, we use the
1221 * RPC call lsa_lookup_sids for this since it can handle a
1222 * list of sids. ldap calls can just resolve one sid at a time.
1224 * At this stage, the sids are still hidden in the exetended dn
1225 * member output format. We actually do a little better than
1226 * stated above: In extracting the sids from the member strings,
1227 * we try to resolve as many sids as possible from the
1228 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1231 (*sid_mem
) = talloc_zero_array(mem_ctx
, struct dom_sid
, num_members
);
1232 (*names
) = talloc_zero_array(mem_ctx
, char *, num_members
);
1233 (*name_types
) = talloc_zero_array(mem_ctx
, uint32
, num_members
);
1234 (sid_mem_nocache
) = talloc_zero_array(tmp_ctx
, struct dom_sid
, num_members
);
1236 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1237 (*names
== NULL
) || (*name_types
== NULL
) ||
1238 (sid_mem_nocache
== NULL
))
1240 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1241 status
= NT_STATUS_NO_MEMORY
;
1248 (*name_types
) = NULL
;
1251 for (i
=0; i
<num_members
; i
++) {
1252 enum lsa_SidType name_type
;
1253 char *name
, *domain_name
;
1256 rc
= ads_get_sid_from_extended_dn(tmp_ctx
, members
[i
], args
.val
,
1258 if (!ADS_ERR_OK(rc
)) {
1259 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
1260 NT_STATUS_NOT_FOUND
)) {
1261 /* Group members can be objects, like Exchange
1262 * Public Folders, that don't have a SID. Skip
1267 status
= ads_ntstatus(rc
);
1271 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
,
1273 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1274 "cache\n", sid_string_dbg(&sid
)));
1275 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1276 (*names
)[*num_names
] = fill_domain_username_talloc(
1282 (*name_types
)[*num_names
] = name_type
;
1286 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1287 "cache\n", sid_string_dbg(&sid
)));
1288 sid_copy(&(sid_mem_nocache
)[num_nocache
], &sid
);
1293 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1294 "%d left for lsa_lookupsids\n", *num_names
, num_nocache
));
1296 /* handle sids not resolved from cache by lsa_lookup_sids */
1297 if (num_nocache
> 0) {
1299 status
= winbindd_lookup_sids(tmp_ctx
,
1305 &name_types_nocache
);
1307 if (!(NT_STATUS_IS_OK(status
) ||
1308 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
) ||
1309 NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)))
1311 DEBUG(1, ("lsa_lookupsids call failed with %s "
1312 "- retrying...\n", nt_errstr(status
)));
1314 status
= winbindd_lookup_sids(tmp_ctx
,
1320 &name_types_nocache
);
1323 if (NT_STATUS_IS_OK(status
) ||
1324 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
))
1326 /* Copy the entries over from the "_nocache" arrays
1327 * to the result arrays, skipping the gaps the
1328 * lookup_sids call left. */
1329 for (i
=0; i
< num_nocache
; i
++) {
1330 if (((names_nocache
)[i
] != NULL
) &&
1331 ((name_types_nocache
)[i
] != SID_NAME_UNKNOWN
))
1333 sid_copy(&(*sid_mem
)[*num_names
],
1334 &sid_mem_nocache
[i
]);
1335 (*names
)[*num_names
] =
1336 fill_domain_username_talloc(
1341 (*name_types
)[*num_names
] = name_types_nocache
[i
];
1346 else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1347 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1348 "not map any SIDs at all.\n"));
1349 /* Don't handle this as an error here.
1350 * There is nothing left to do with respect to the
1351 * overall result... */
1353 else if (!NT_STATUS_IS_OK(status
)) {
1354 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1355 "sids via rpc_lsa_lookup_sids: %s\n",
1356 (int)num_members
, nt_errstr(status
)));
1361 status
= NT_STATUS_OK
;
1362 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1363 sid_string_dbg(group_sid
)));
1367 TALLOC_FREE(tmp_ctx
);
1372 /* find the sequence number for a domain */
1373 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1375 ADS_STRUCT
*ads
= NULL
;
1378 DEBUG(3,("ads: fetch sequence_number for %s\n", domain
->name
));
1380 if ( !winbindd_can_contact_domain( domain
) ) {
1381 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1384 return NT_STATUS_OK
;
1387 *seq
= DOM_SEQUENCE_NONE
;
1389 ads
= ads_cached_connection(domain
);
1392 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1393 return NT_STATUS_UNSUCCESSFUL
;
1396 rc
= ads_USN(ads
, seq
);
1398 if (!ADS_ERR_OK(rc
)) {
1400 /* its a dead connection, destroy it */
1402 if (domain
->private_data
) {
1403 ads
= (ADS_STRUCT
*)domain
->private_data
;
1404 ads
->is_mine
= True
;
1406 ads_kdestroy(WINBIND_CCACHE_NAME
);
1407 domain
->private_data
= NULL
;
1410 return ads_ntstatus(rc
);
1413 /* find the lockout policy of a domain - use rpc methods */
1414 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1415 TALLOC_CTX
*mem_ctx
,
1416 struct samr_DomInfo12
*policy
)
1418 return reconnect_methods
.lockout_policy(domain
, mem_ctx
, policy
);
1421 /* find the password policy of a domain - use rpc methods */
1422 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1423 TALLOC_CTX
*mem_ctx
,
1424 struct samr_DomInfo1
*policy
)
1426 return reconnect_methods
.password_policy(domain
, mem_ctx
, policy
);
1429 /* get a list of trusted domains */
1430 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1431 TALLOC_CTX
*mem_ctx
,
1432 struct netr_DomainTrustList
*trusts
)
1434 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1438 struct rpc_pipe_client
*cli
;
1440 struct dcerpc_binding_handle
*b
;
1442 DEBUG(3,("ads: trusted_domains\n"));
1444 ZERO_STRUCTP(trusts
);
1446 /* If this is our primary domain or a root in our forest,
1447 query for all trusts. If not, then just look for domain
1448 trusts in the target forest */
1450 if (domain
->primary
|| domain_is_forest_root(domain
)) {
1451 flags
= NETR_TRUST_FLAG_OUTBOUND
|
1452 NETR_TRUST_FLAG_INBOUND
|
1453 NETR_TRUST_FLAG_IN_FOREST
;
1455 flags
= NETR_TRUST_FLAG_IN_FOREST
;
1458 result
= cm_connect_netlogon(domain
, &cli
);
1460 if (!NT_STATUS_IS_OK(result
)) {
1461 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1462 "for PIPE_NETLOGON (%s)\n",
1463 domain
->name
, nt_errstr(result
)));
1464 return NT_STATUS_UNSUCCESSFUL
;
1467 b
= cli
->binding_handle
;
1469 result
= dcerpc_netr_DsrEnumerateDomainTrusts(b
, mem_ctx
,
1474 if (!NT_STATUS_IS_OK(result
)) {
1478 if (!W_ERROR_IS_OK(werr
)) {
1479 return werror_to_ntstatus(werr
);
1481 if (trusts
->count
== 0) {
1482 return NT_STATUS_OK
;
1485 /* Copy across names and sids */
1488 for (i
= 0; i
< trusts
->count
; i
++) {
1489 struct netr_DomainTrust
*trust
= &trusts
->array
[i
];
1490 struct winbindd_domain d
;
1495 * drop external trusts if this is not our primary
1496 * domain. This means that the returned number of
1497 * domains may be less that the ones actually trusted
1501 if ((trust
->trust_attributes
1502 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) &&
1505 DEBUG(10,("trusted_domains: Skipping external trusted "
1506 "domain %s because it is outside of our "
1508 trust
->netbios_name
));
1512 /* add to the trusted domain cache */
1514 d
.name
= discard_const_p(char, trust
->netbios_name
);
1515 d
.alt_name
= discard_const_p(char, trust
->dns_name
);
1518 sid_copy(&d
.sid
, trust
->sid
);
1520 sid_copy(&d
.sid
, &global_sid_NULL
);
1523 if ( domain
->primary
) {
1524 DEBUG(10,("trusted_domains(ads): Searching "
1525 "trusted domain list of %s and storing "
1526 "trust flags for domain %s\n",
1527 domain
->name
, d
.alt_name
));
1529 d
.domain_flags
= trust
->trust_flags
;
1530 d
.domain_type
= trust
->trust_type
;
1531 d
.domain_trust_attribs
= trust
->trust_attributes
;
1533 wcache_tdc_add_domain( &d
);
1535 } else if (domain_is_forest_root(domain
)) {
1536 /* Check if we already have this record. If
1537 * we are following our forest root that is not
1538 * our primary domain, we want to keep trust
1539 * flags from the perspective of our primary
1540 * domain not our forest root. */
1541 struct winbindd_tdc_domain
*exist
= NULL
;
1543 exist
= wcache_tdc_fetch_domain(
1544 talloc_tos(), trust
->netbios_name
);
1546 DEBUG(10,("trusted_domains(ads): Searching "
1547 "trusted domain list of %s and "
1548 "storing trust flags for domain "
1549 "%s\n", domain
->name
, d
.alt_name
));
1550 d
.domain_flags
= trust
->trust_flags
;
1551 d
.domain_type
= trust
->trust_type
;
1552 d
.domain_trust_attribs
=
1553 trust
->trust_attributes
;
1555 wcache_tdc_add_domain( &d
);
1560 /* This gets a little tricky. If we are
1561 following a transitive forest trust, then
1562 innerit the flags, type, and attribs from
1563 the domain we queried to make sure we don't
1564 record the view of the trust from the wrong
1565 side. Always view it from the side of our
1566 primary domain. --jerry */
1567 struct winbindd_tdc_domain
*parent
= NULL
;
1569 DEBUG(10,("trusted_domains(ads): Searching "
1570 "trusted domain list of %s and inheriting "
1571 "trust flags for domain %s\n",
1572 domain
->name
, d
.alt_name
));
1574 parent
= wcache_tdc_fetch_domain(talloc_tos(),
1577 d
.domain_flags
= parent
->trust_flags
;
1578 d
.domain_type
= parent
->trust_type
;
1579 d
.domain_trust_attribs
= parent
->trust_attribs
;
1581 d
.domain_flags
= domain
->domain_flags
;
1582 d
.domain_type
= domain
->domain_type
;
1583 d
.domain_trust_attribs
=
1584 domain
->domain_trust_attribs
;
1586 TALLOC_FREE(parent
);
1588 wcache_tdc_add_domain( &d
);
1595 /* the ADS backend methods are exposed via this structure */
1596 struct winbindd_methods ads_methods
= {