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(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 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO
);
172 SMB_ASSERT(wb_dom
->alt_name
!= NULL
);
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. */
206 return our ads connections structure for a domain. We keep the connection
207 open to make things faster
209 static ADS_STRUCT
*ads_cached_connection(struct winbindd_domain
*domain
)
212 char *password
, *realm
;
214 DEBUG(10,("ads_cached_connection\n"));
215 ads_cached_connection_reuse((ADS_STRUCT
**)&domain
->private_data
);
217 if (domain
->private_data
) {
218 return (ADS_STRUCT
*)domain
->private_data
;
221 /* the machine acct password might have change - fetch it every time */
223 if (!get_trust_pw_clear(domain
->name
, &password
, NULL
, NULL
)) {
228 SMB_ASSERT(domain
->alt_name
!= NULL
);
229 realm
= SMB_STRDUP(domain
->alt_name
);
232 struct winbindd_domain
*our_domain
= domain
;
235 /* always give preference to the alt_name in our
236 primary domain if possible */
238 if ( !domain
->primary
)
239 our_domain
= find_our_domain();
241 if (our_domain
->alt_name
!= NULL
) {
242 realm
= SMB_STRDUP( our_domain
->alt_name
);
245 realm
= SMB_STRDUP( lp_realm() );
248 status
= ads_cached_connection_connect(
249 (ADS_STRUCT
**)&domain
->private_data
,
253 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
);
256 if (!ADS_ERR_OK(status
)) {
257 /* if we get ECONNREFUSED then it might be a NT4
258 server, fall back to MSRPC */
259 if (status
.error_type
== ENUM_ADS_ERROR_SYSTEM
&&
260 status
.err
.rc
== ECONNREFUSED
) {
261 /* 'reconnect_methods' is the MS-RPC backend. */
262 DEBUG(1,("Trying MSRPC methods\n"));
263 domain
->backend
= &reconnect_methods
;
268 return (ADS_STRUCT
*)domain
->private_data
;
271 /* Query display info for a realm. This is the basic user list fn */
272 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
275 struct wbint_userinfo
**pinfo
)
277 ADS_STRUCT
*ads
= NULL
;
278 const char *attrs
[] = { "*", NULL
};
281 LDAPMessage
*res
= NULL
;
282 LDAPMessage
*msg
= NULL
;
283 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
287 DEBUG(3,("ads: query_user_list\n"));
289 if ( !winbindd_can_contact_domain( domain
) ) {
290 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
295 ads
= ads_cached_connection(domain
);
298 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
302 rc
= ads_search_retry(ads
, &res
, "(objectCategory=user)", attrs
);
303 if (!ADS_ERR_OK(rc
)) {
304 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc
)));
305 status
= ads_ntstatus(rc
);
307 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
312 count
= ads_count_replies(ads
, res
);
314 DEBUG(1,("query_user_list: No users found\n"));
318 (*pinfo
) = talloc_zero_array(mem_ctx
, struct wbint_userinfo
, count
);
320 status
= NT_STATUS_NO_MEMORY
;
326 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
327 struct wbint_userinfo
*info
= &((*pinfo
)[count
]);
331 if (!ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
) ||
332 ds_atype_map(atype
) != SID_NAME_USER
) {
333 DEBUG(1,("Not a user account? atype=0x%x\n", atype
));
337 info
->acct_name
= ads_pull_username(ads
, mem_ctx
, msg
);
338 info
->full_name
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
339 info
->homedir
= NULL
;
341 info
->primary_gid
= (gid_t
)-1;
343 if (!ads_pull_sid(ads
, msg
, "objectSid",
345 DEBUG(1, ("No sid for %s !?\n", info
->acct_name
));
349 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group
)) {
350 DEBUG(1, ("No primary group for %s !?\n",
354 sid_compose(&info
->group_sid
, &domain
->sid
, group
);
359 (*num_entries
) = count
;
360 ads_msgfree(ads
, res
);
362 for (i
=0; i
<count
; i
++) {
363 struct wbint_userinfo
*info
= &((*pinfo
)[i
]);
364 const char *gecos
= NULL
;
365 gid_t primary_gid
= (gid_t
)-1;
367 status
= nss_get_info_cached(domain
, &info
->user_sid
, mem_ctx
,
368 &info
->homedir
, &info
->shell
,
369 &gecos
, &primary_gid
);
370 if (!NT_STATUS_IS_OK(status
)) {
372 * Deliberately ignore this error, there might be more
379 info
->full_name
= gecos
;
381 info
->primary_gid
= primary_gid
;
384 status
= NT_STATUS_OK
;
386 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries
)));
392 /* list all domain groups */
393 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
396 struct wb_acct_info
**info
)
398 ADS_STRUCT
*ads
= NULL
;
399 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
400 "name", "objectSid", NULL
};
403 LDAPMessage
*res
= NULL
;
404 LDAPMessage
*msg
= NULL
;
405 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
407 bool enum_dom_local_groups
= False
;
411 DEBUG(3,("ads: enum_dom_groups\n"));
413 if ( !winbindd_can_contact_domain( domain
) ) {
414 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
419 /* only grab domain local groups for our domain */
420 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
421 enum_dom_local_groups
= True
;
424 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
427 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
428 * default value, it MUST be absent. In case of extensible matching the
429 * "dnattr" boolean defaults to FALSE and so it must be only be present
432 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
433 * filter using bitwise matching rule then the buggy AD fails to decode
434 * the extensible match. As a workaround set it to TRUE and thereby add
435 * the dnAttributes "dn" field to cope with those older AD versions.
436 * It should not harm and won't put any additional load on the AD since
437 * none of the dn components have a bitmask-attribute.
439 * Thanks to Ralf Haferkamp for input and testing - Guenther */
441 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
442 ADS_LDAP_MATCHING_RULE_BIT_AND
, GROUP_TYPE_SECURITY_ENABLED
,
443 ADS_LDAP_MATCHING_RULE_BIT_AND
,
444 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
446 if (filter
== NULL
) {
447 status
= NT_STATUS_NO_MEMORY
;
451 ads
= ads_cached_connection(domain
);
454 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
458 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
459 if (!ADS_ERR_OK(rc
)) {
460 status
= ads_ntstatus(rc
);
461 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
464 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
468 count
= ads_count_replies(ads
, res
);
470 DEBUG(1,("enum_dom_groups: No groups found\n"));
474 (*info
) = talloc_zero_array(mem_ctx
, struct wb_acct_info
, count
);
476 status
= NT_STATUS_NO_MEMORY
;
482 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
487 name
= ads_pull_username(ads
, mem_ctx
, msg
);
488 gecos
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
489 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
490 DEBUG(1,("No sid for %s !?\n", name
));
494 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
495 DEBUG(1,("No rid for %s !?\n", name
));
499 fstrcpy((*info
)[i
].acct_name
, name
);
500 fstrcpy((*info
)[i
].acct_desc
, gecos
);
501 (*info
)[i
].rid
= rid
;
507 status
= NT_STATUS_OK
;
509 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
513 ads_msgfree(ads
, res
);
518 /* list all domain local groups */
519 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
522 struct wb_acct_info
**info
)
525 * This is a stub function only as we returned the domain
526 * local groups in enum_dom_groups() if the domain->native field
527 * was true. This is a simple performance optimization when
530 * if we ever need to enumerate domain local groups separately,
531 * then this optimization in enum_dom_groups() will need
539 /* convert a single name to a sid in a domain - use rpc methods */
540 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
542 const char *domain_name
,
546 enum lsa_SidType
*type
)
548 return reconnect_methods
.name_to_sid(domain
, mem_ctx
,
549 domain_name
, name
, flags
,
553 /* convert a domain SID to a user or group name - use rpc methods */
554 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
556 const struct dom_sid
*sid
,
559 enum lsa_SidType
*type
)
561 return reconnect_methods
.sid_to_name(domain
, mem_ctx
, sid
,
562 domain_name
, name
, type
);
565 /* convert a list of rids to names - use rpc methods */
566 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
568 const struct dom_sid
*sid
,
573 enum lsa_SidType
**types
)
575 return reconnect_methods
.rids_to_names(domain
, mem_ctx
, sid
,
577 domain_name
, names
, types
);
580 /* If you are looking for "dn_lookup": Yes, it used to be here!
581 * It has gone now since it was a major speed bottleneck in
582 * lookup_groupmem (its only use). It has been replaced by
583 * an rpc lookup sids call... R.I.P. */
585 /* Lookup user information from a rid */
586 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
588 const struct dom_sid
*sid
,
589 struct wbint_userinfo
*info
)
591 ADS_STRUCT
*ads
= NULL
;
592 const char *attrs
[] = { "*", NULL
};
595 LDAPMessage
*msg
= NULL
;
599 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
600 struct netr_SamInfo3
*user
= NULL
;
605 DEBUG(3,("ads: query_user\n"));
607 info
->homedir
= NULL
;
610 /* try netsamlogon cache first */
612 if ( (user
= netsamlogon_cache_get( mem_ctx
, sid
)) != NULL
)
614 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
615 sid_string_dbg(sid
)));
617 sid_compose(&info
->user_sid
, &domain
->sid
, user
->base
.rid
);
618 sid_compose(&info
->group_sid
, &domain
->sid
, user
->base
.primary_gid
);
620 info
->acct_name
= talloc_strdup(mem_ctx
, user
->base
.account_name
.string
);
621 info
->full_name
= talloc_strdup(mem_ctx
, user
->base
.full_name
.string
);
623 nss_get_info_cached( domain
, sid
, mem_ctx
,
624 &info
->homedir
, &info
->shell
, &info
->full_name
,
626 info
->primary_gid
= gid
;
633 if ( !winbindd_can_contact_domain(domain
)) {
634 DEBUG(8,("query_user: No incoming trust from domain %s\n",
637 /* We still need to generate some basic information
638 about the user even if we cannot contact the
639 domain. Most of this stuff we can deduce. */
641 sid_copy( &info
->user_sid
, sid
);
643 /* Assume "Domain Users" for the primary group */
645 sid_compose(&info
->group_sid
, &domain
->sid
, DOMAIN_RID_USERS
);
647 /* Try to fill in what the nss_info backend can do */
649 nss_get_info_cached( domain
, sid
, mem_ctx
,
650 &info
->homedir
, &info
->shell
, &info
->full_name
,
652 info
->primary_gid
= gid
;
657 /* no cache...do the query */
659 if ( (ads
= ads_cached_connection(domain
)) == NULL
) {
660 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
661 return NT_STATUS_SERVER_DISABLED
;
664 sidstr
= ldap_encode_ndr_dom_sid(talloc_tos(), sid
);
666 ret
= asprintf(&ldap_exp
, "(objectSid=%s)", sidstr
);
669 return NT_STATUS_NO_MEMORY
;
671 rc
= ads_search_retry(ads
, &msg
, ldap_exp
, attrs
);
673 if (!ADS_ERR_OK(rc
)) {
674 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
675 sid_string_dbg(sid
), ads_errstr(rc
)));
676 return ads_ntstatus(rc
);
678 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
679 sid_string_dbg(sid
)));
680 return NT_STATUS_INTERNAL_ERROR
;
683 count
= ads_count_replies(ads
, msg
);
685 DEBUG(1,("query_user(sid=%s): Not found\n",
686 sid_string_dbg(sid
)));
687 ads_msgfree(ads
, msg
);
688 return NT_STATUS_NO_SUCH_USER
;
691 info
->acct_name
= ads_pull_username(ads
, mem_ctx
, msg
);
693 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group_rid
)) {
694 DEBUG(1,("No primary group for %s !?\n",
695 sid_string_dbg(sid
)));
696 ads_msgfree(ads
, msg
);
697 return NT_STATUS_NO_SUCH_USER
;
699 sid_copy(&info
->user_sid
, sid
);
700 sid_compose(&info
->group_sid
, &domain
->sid
, group_rid
);
703 * We have to fetch the "name" attribute before doing the
704 * nss_get_info_cached call. nss_get_info_cached might destroy
705 * the ads struct, potentially invalidating the ldap message.
707 ads_name
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
709 ads_msgfree(ads
, msg
);
712 status
= nss_get_info_cached( domain
, sid
, mem_ctx
,
713 &info
->homedir
, &info
->shell
, &info
->full_name
,
715 info
->primary_gid
= gid
;
716 if (!NT_STATUS_IS_OK(status
)) {
717 DEBUG(1, ("nss_get_info_cached failed: %s\n",
722 if (info
->full_name
== NULL
) {
723 info
->full_name
= ads_name
;
725 TALLOC_FREE(ads_name
);
728 status
= NT_STATUS_OK
;
730 DEBUG(3,("ads query_user gave %s\n", info
->acct_name
));
734 /* Lookup groups a user is a member of - alternate method, for when
735 tokenGroups are not available. */
736 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
739 struct dom_sid
*primary_group
,
740 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
743 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
745 LDAPMessage
*res
= NULL
;
746 LDAPMessage
*msg
= NULL
;
749 const char *group_attrs
[] = {"objectSid", NULL
};
751 uint32_t num_groups
= 0;
753 DEBUG(3,("ads: lookup_usergroups_member\n"));
755 if ( !winbindd_can_contact_domain( domain
) ) {
756 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
761 ads
= ads_cached_connection(domain
);
764 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
768 if (!(escaped_dn
= escape_ldap_string(talloc_tos(), user_dn
))) {
769 status
= NT_STATUS_NO_MEMORY
;
773 ldap_exp
= talloc_asprintf(mem_ctx
,
774 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
776 ADS_LDAP_MATCHING_RULE_BIT_AND
,
777 GROUP_TYPE_SECURITY_ENABLED
);
779 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
780 TALLOC_FREE(escaped_dn
);
781 status
= NT_STATUS_NO_MEMORY
;
785 TALLOC_FREE(escaped_dn
);
787 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
789 if (!ADS_ERR_OK(rc
)) {
790 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
791 return ads_ntstatus(rc
);
793 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
794 return NT_STATUS_INTERNAL_ERROR
;
798 count
= ads_count_replies(ads
, res
);
803 /* always add the primary group to the sid array */
804 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
806 if (!NT_STATUS_IS_OK(status
)) {
811 for (msg
= ads_first_entry(ads
, res
); msg
;
812 msg
= ads_next_entry(ads
, msg
)) {
813 struct dom_sid group_sid
;
815 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
816 DEBUG(1,("No sid for this group ?!?\n"));
820 /* ignore Builtin groups from ADS - Guenther */
821 if (sid_check_is_in_builtin(&group_sid
)) {
825 status
= add_sid_to_array(mem_ctx
, &group_sid
,
826 user_sids
, &num_groups
);
827 if (!NT_STATUS_IS_OK(status
)) {
834 *p_num_groups
= num_groups
;
835 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
837 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
840 ads_msgfree(ads
, res
);
845 /* Lookup groups a user is a member of - alternate method, for when
846 tokenGroups are not available. */
847 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
850 struct dom_sid
*primary_group
,
851 uint32_t *p_num_groups
,
852 struct dom_sid
**user_sids
)
855 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
857 const char *attrs
[] = {"memberOf", NULL
};
858 uint32_t num_groups
= 0;
859 struct dom_sid
*group_sids
= NULL
;
861 char **strings
= NULL
;
862 size_t num_strings
= 0, num_sids
= 0;
865 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
867 if ( !winbindd_can_contact_domain( domain
) ) {
868 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
869 "domain %s\n", domain
->name
));
873 ads
= ads_cached_connection(domain
);
876 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
877 return NT_STATUS_UNSUCCESSFUL
;
880 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
881 ADS_EXTENDED_DN_HEX_STRING
,
882 &strings
, &num_strings
);
884 if (!ADS_ERR_OK(rc
)) {
885 DEBUG(1,("lookup_usergroups_memberof ads_search "
886 "member=%s: %s\n", user_dn
, ads_errstr(rc
)));
887 return ads_ntstatus(rc
);
893 /* always add the primary group to the sid array */
894 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
896 if (!NT_STATUS_IS_OK(status
)) {
900 group_sids
= talloc_zero_array(mem_ctx
, struct dom_sid
, num_strings
+ 1);
902 status
= NT_STATUS_NO_MEMORY
;
906 for (i
=0; i
<num_strings
; i
++) {
907 rc
= ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
908 ADS_EXTENDED_DN_HEX_STRING
,
910 if (!ADS_ERR_OK(rc
)) {
911 /* ignore members without SIDs */
912 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
913 NT_STATUS_NOT_FOUND
)) {
917 status
= ads_ntstatus(rc
);
925 DEBUG(1,("No memberOf for this user?!?\n"));
926 status
= NT_STATUS_NO_MEMORY
;
930 for (i
=0; i
<num_sids
; i
++) {
932 /* ignore Builtin groups from ADS - Guenther */
933 if (sid_check_is_in_builtin(&group_sids
[i
])) {
937 status
= add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
939 if (!NT_STATUS_IS_OK(status
)) {
945 *p_num_groups
= num_groups
;
946 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
948 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
952 TALLOC_FREE(strings
);
953 TALLOC_FREE(group_sids
);
959 /* Lookup groups a user is a member of. */
960 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
962 const struct dom_sid
*sid
,
963 uint32
*p_num_groups
, struct dom_sid
**user_sids
)
965 ADS_STRUCT
*ads
= NULL
;
966 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
969 LDAPMessage
*msg
= NULL
;
970 char *user_dn
= NULL
;
971 struct dom_sid
*sids
;
973 struct dom_sid primary_group
;
974 uint32 primary_group_rid
;
975 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
976 uint32_t num_groups
= 0;
978 DEBUG(3,("ads: lookup_usergroups\n"));
981 status
= lookup_usergroups_cached(domain
, mem_ctx
, sid
,
982 p_num_groups
, user_sids
);
983 if (NT_STATUS_IS_OK(status
)) {
987 if ( !winbindd_can_contact_domain( domain
) ) {
988 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
991 /* Tell the cache manager not to remember this one */
993 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
996 ads
= ads_cached_connection(domain
);
999 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1000 status
= NT_STATUS_SERVER_DISABLED
;
1004 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
1006 if (!ADS_ERR_OK(rc
)) {
1007 status
= ads_ntstatus(rc
);
1008 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1009 "%s\n", sid_string_dbg(sid
), ads_errstr(rc
)));
1013 count
= ads_count_replies(ads
, msg
);
1015 status
= NT_STATUS_UNSUCCESSFUL
;
1016 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1017 "invalid number of results (count=%d)\n",
1018 sid_string_dbg(sid
), count
));
1023 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
1024 sid_string_dbg(sid
)));
1025 status
= NT_STATUS_UNSUCCESSFUL
;
1029 user_dn
= ads_get_dn(ads
, mem_ctx
, msg
);
1030 if (user_dn
== NULL
) {
1031 status
= NT_STATUS_NO_MEMORY
;
1035 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
1036 DEBUG(1,("%s: No primary group for sid=%s !?\n",
1037 domain
->name
, sid_string_dbg(sid
)));
1041 sid_compose(&primary_group
, &domain
->sid
, primary_group_rid
);
1043 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
1045 /* there must always be at least one group in the token,
1046 unless we are talking to a buggy Win2k server */
1048 /* actually this only happens when the machine account has no read
1049 * permissions on the tokenGroup attribute - gd */
1053 /* no tokenGroups */
1055 /* lookup what groups this user is a member of by DN search on
1058 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
1060 &num_groups
, user_sids
);
1061 *p_num_groups
= num_groups
;
1062 if (NT_STATUS_IS_OK(status
)) {
1066 /* lookup what groups this user is a member of by DN search on
1069 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
1071 &num_groups
, user_sids
);
1072 *p_num_groups
= num_groups
;
1079 status
= add_sid_to_array(mem_ctx
, &primary_group
, user_sids
,
1081 if (!NT_STATUS_IS_OK(status
)) {
1085 for (i
=0;i
<count
;i
++) {
1087 /* ignore Builtin groups from ADS - Guenther */
1088 if (sid_check_is_in_builtin(&sids
[i
])) {
1092 status
= add_sid_to_array_unique(mem_ctx
, &sids
[i
],
1093 user_sids
, &num_groups
);
1094 if (!NT_STATUS_IS_OK(status
)) {
1099 *p_num_groups
= (uint32
)num_groups
;
1100 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
1102 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1103 sid_string_dbg(sid
)));
1105 TALLOC_FREE(user_dn
);
1106 ads_msgfree(ads
, msg
);
1110 /* Lookup aliases a user is member of - use rpc methods */
1111 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1112 TALLOC_CTX
*mem_ctx
,
1113 uint32 num_sids
, const struct dom_sid
*sids
,
1114 uint32
*num_aliases
, uint32
**alias_rids
)
1116 return reconnect_methods
.lookup_useraliases(domain
, mem_ctx
,
1123 find the members of a group, given a group rid and domain
1125 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1126 TALLOC_CTX
*mem_ctx
,
1127 const struct dom_sid
*group_sid
,
1128 enum lsa_SidType type
,
1130 struct dom_sid
**sid_mem
, char ***names
,
1131 uint32
**name_types
)
1134 ADS_STRUCT
*ads
= NULL
;
1136 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1138 char **members
= NULL
;
1140 size_t num_members
= 0;
1142 struct dom_sid
*sid_mem_nocache
= NULL
;
1143 char **names_nocache
= NULL
;
1144 enum lsa_SidType
*name_types_nocache
= NULL
;
1145 char **domains_nocache
= NULL
; /* only needed for rpccli_lsa_lookup_sids */
1146 uint32 num_nocache
= 0;
1147 TALLOC_CTX
*tmp_ctx
= NULL
;
1149 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
1150 sid_string_dbg(group_sid
)));
1154 tmp_ctx
= talloc_new(mem_ctx
);
1156 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1157 status
= NT_STATUS_NO_MEMORY
;
1161 if ( !winbindd_can_contact_domain( domain
) ) {
1162 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1164 return NT_STATUS_OK
;
1167 ads
= ads_cached_connection(domain
);
1170 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1174 if ((sidbinstr
= ldap_encode_ndr_dom_sid(talloc_tos(), group_sid
)) == NULL
) {
1175 status
= NT_STATUS_NO_MEMORY
;
1179 /* search for all members of the group */
1180 ldap_exp
= talloc_asprintf(tmp_ctx
, "(objectSid=%s)", sidbinstr
);
1181 TALLOC_FREE(sidbinstr
);
1182 if (ldap_exp
== NULL
) {
1183 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1184 status
= NT_STATUS_NO_MEMORY
;
1188 args
.control
= ADS_EXTENDED_DN_OID
;
1189 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1190 args
.critical
= True
;
1192 rc
= ads_ranged_search(ads
, tmp_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
1193 ldap_exp
, &args
, "member", &members
, &num_members
);
1195 if (!ADS_ERR_OK(rc
)) {
1196 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
1197 status
= NT_STATUS_UNSUCCESSFUL
;
1201 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members
));
1203 /* Now that we have a list of sids, we need to get the
1204 * lists of names and name_types belonging to these sids.
1205 * even though conceptually not quite clean, we use the
1206 * RPC call lsa_lookup_sids for this since it can handle a
1207 * list of sids. ldap calls can just resolve one sid at a time.
1209 * At this stage, the sids are still hidden in the exetended dn
1210 * member output format. We actually do a little better than
1211 * stated above: In extracting the sids from the member strings,
1212 * we try to resolve as many sids as possible from the
1213 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1216 (*sid_mem
) = talloc_zero_array(mem_ctx
, struct dom_sid
, num_members
);
1217 (*names
) = talloc_zero_array(mem_ctx
, char *, num_members
);
1218 (*name_types
) = talloc_zero_array(mem_ctx
, uint32
, num_members
);
1219 (sid_mem_nocache
) = talloc_zero_array(tmp_ctx
, struct dom_sid
, num_members
);
1221 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1222 (*names
== NULL
) || (*name_types
== NULL
) ||
1223 (sid_mem_nocache
== NULL
))
1225 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1226 status
= NT_STATUS_NO_MEMORY
;
1233 (*name_types
) = NULL
;
1236 for (i
=0; i
<num_members
; i
++) {
1237 enum lsa_SidType name_type
;
1238 char *name
, *domain_name
;
1241 rc
= ads_get_sid_from_extended_dn(tmp_ctx
, members
[i
], args
.val
,
1243 if (!ADS_ERR_OK(rc
)) {
1244 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
1245 NT_STATUS_NOT_FOUND
)) {
1246 /* Group members can be objects, like Exchange
1247 * Public Folders, that don't have a SID. Skip
1252 status
= ads_ntstatus(rc
);
1256 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
,
1258 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1259 "cache\n", sid_string_dbg(&sid
)));
1260 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1261 (*names
)[*num_names
] = fill_domain_username_talloc(
1267 (*name_types
)[*num_names
] = name_type
;
1271 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1272 "cache\n", sid_string_dbg(&sid
)));
1273 sid_copy(&(sid_mem_nocache
)[num_nocache
], &sid
);
1278 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1279 "%d left for lsa_lookupsids\n", *num_names
, num_nocache
));
1281 /* handle sids not resolved from cache by lsa_lookup_sids */
1282 if (num_nocache
> 0) {
1284 status
= winbindd_lookup_sids(tmp_ctx
,
1290 &name_types_nocache
);
1292 if (!(NT_STATUS_IS_OK(status
) ||
1293 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
) ||
1294 NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)))
1296 DEBUG(1, ("lsa_lookupsids call failed with %s "
1297 "- retrying...\n", nt_errstr(status
)));
1299 status
= winbindd_lookup_sids(tmp_ctx
,
1305 &name_types_nocache
);
1308 if (NT_STATUS_IS_OK(status
) ||
1309 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
))
1311 /* Copy the entries over from the "_nocache" arrays
1312 * to the result arrays, skipping the gaps the
1313 * lookup_sids call left. */
1314 for (i
=0; i
< num_nocache
; i
++) {
1315 if (((names_nocache
)[i
] != NULL
) &&
1316 ((name_types_nocache
)[i
] != SID_NAME_UNKNOWN
))
1318 sid_copy(&(*sid_mem
)[*num_names
],
1319 &sid_mem_nocache
[i
]);
1320 (*names
)[*num_names
] =
1321 fill_domain_username_talloc(
1326 (*name_types
)[*num_names
] = name_types_nocache
[i
];
1331 else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1332 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1333 "not map any SIDs at all.\n"));
1334 /* Don't handle this as an error here.
1335 * There is nothing left to do with respect to the
1336 * overall result... */
1338 else if (!NT_STATUS_IS_OK(status
)) {
1339 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1340 "sids via rpc_lsa_lookup_sids: %s\n",
1341 (int)num_members
, nt_errstr(status
)));
1346 status
= NT_STATUS_OK
;
1347 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1348 sid_string_dbg(group_sid
)));
1352 TALLOC_FREE(tmp_ctx
);
1357 /* find the sequence number for a domain */
1358 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1360 ADS_STRUCT
*ads
= NULL
;
1363 DEBUG(3,("ads: fetch sequence_number for %s\n", domain
->name
));
1365 if ( !winbindd_can_contact_domain( domain
) ) {
1366 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1369 return NT_STATUS_OK
;
1372 *seq
= DOM_SEQUENCE_NONE
;
1374 ads
= ads_cached_connection(domain
);
1377 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1378 return NT_STATUS_UNSUCCESSFUL
;
1381 rc
= ads_USN(ads
, seq
);
1383 if (!ADS_ERR_OK(rc
)) {
1385 /* its a dead connection, destroy it */
1387 if (domain
->private_data
) {
1388 ads
= (ADS_STRUCT
*)domain
->private_data
;
1389 ads
->is_mine
= True
;
1391 ads_kdestroy(WINBIND_CCACHE_NAME
);
1392 domain
->private_data
= NULL
;
1395 return ads_ntstatus(rc
);
1398 /* find the lockout policy of a domain - use rpc methods */
1399 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1400 TALLOC_CTX
*mem_ctx
,
1401 struct samr_DomInfo12
*policy
)
1403 return reconnect_methods
.lockout_policy(domain
, mem_ctx
, policy
);
1406 /* find the password policy of a domain - use rpc methods */
1407 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1408 TALLOC_CTX
*mem_ctx
,
1409 struct samr_DomInfo1
*policy
)
1411 return reconnect_methods
.password_policy(domain
, mem_ctx
, policy
);
1414 /* get a list of trusted domains */
1415 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1416 TALLOC_CTX
*mem_ctx
,
1417 struct netr_DomainTrustList
*trusts
)
1419 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1423 struct rpc_pipe_client
*cli
;
1425 struct dcerpc_binding_handle
*b
;
1427 DEBUG(3,("ads: trusted_domains\n"));
1429 ZERO_STRUCTP(trusts
);
1431 /* If this is our primary domain or a root in our forest,
1432 query for all trusts. If not, then just look for domain
1433 trusts in the target forest */
1435 if (domain
->primary
|| domain_is_forest_root(domain
)) {
1436 flags
= NETR_TRUST_FLAG_OUTBOUND
|
1437 NETR_TRUST_FLAG_INBOUND
|
1438 NETR_TRUST_FLAG_IN_FOREST
;
1440 flags
= NETR_TRUST_FLAG_IN_FOREST
;
1443 result
= cm_connect_netlogon(domain
, &cli
);
1445 if (!NT_STATUS_IS_OK(result
)) {
1446 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1447 "for PIPE_NETLOGON (%s)\n",
1448 domain
->name
, nt_errstr(result
)));
1449 return NT_STATUS_UNSUCCESSFUL
;
1452 b
= cli
->binding_handle
;
1454 result
= dcerpc_netr_DsrEnumerateDomainTrusts(b
, mem_ctx
,
1459 if (!NT_STATUS_IS_OK(result
)) {
1463 if (!W_ERROR_IS_OK(werr
)) {
1464 return werror_to_ntstatus(werr
);
1466 if (trusts
->count
== 0) {
1467 return NT_STATUS_OK
;
1470 /* Copy across names and sids */
1473 for (i
= 0; i
< trusts
->count
; i
++) {
1474 struct netr_DomainTrust
*trust
= &trusts
->array
[i
];
1475 struct winbindd_domain d
;
1480 * drop external trusts if this is not our primary
1481 * domain. This means that the returned number of
1482 * domains may be less that the ones actually trusted
1486 if ((trust
->trust_attributes
1487 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) &&
1490 DEBUG(10,("trusted_domains: Skipping external trusted "
1491 "domain %s because it is outside of our "
1493 trust
->netbios_name
));
1497 /* add to the trusted domain cache */
1499 d
.name
= discard_const_p(char, trust
->netbios_name
);
1500 d
.alt_name
= discard_const_p(char, trust
->dns_name
);
1503 sid_copy(&d
.sid
, trust
->sid
);
1505 sid_copy(&d
.sid
, &global_sid_NULL
);
1508 if ( domain
->primary
) {
1509 DEBUG(10,("trusted_domains(ads): Searching "
1510 "trusted domain list of %s and storing "
1511 "trust flags for domain %s\n",
1512 domain
->name
, d
.alt_name
));
1514 d
.domain_flags
= trust
->trust_flags
;
1515 d
.domain_type
= trust
->trust_type
;
1516 d
.domain_trust_attribs
= trust
->trust_attributes
;
1518 wcache_tdc_add_domain( &d
);
1520 } else if (domain_is_forest_root(domain
)) {
1521 /* Check if we already have this record. If
1522 * we are following our forest root that is not
1523 * our primary domain, we want to keep trust
1524 * flags from the perspective of our primary
1525 * domain not our forest root. */
1526 struct winbindd_tdc_domain
*exist
= NULL
;
1528 exist
= wcache_tdc_fetch_domain(
1529 talloc_tos(), trust
->netbios_name
);
1531 DEBUG(10,("trusted_domains(ads): Searching "
1532 "trusted domain list of %s and "
1533 "storing trust flags for domain "
1534 "%s\n", domain
->name
, d
.alt_name
));
1535 d
.domain_flags
= trust
->trust_flags
;
1536 d
.domain_type
= trust
->trust_type
;
1537 d
.domain_trust_attribs
=
1538 trust
->trust_attributes
;
1540 wcache_tdc_add_domain( &d
);
1545 /* This gets a little tricky. If we are
1546 following a transitive forest trust, then
1547 innerit the flags, type, and attribs from
1548 the domain we queried to make sure we don't
1549 record the view of the trust from the wrong
1550 side. Always view it from the side of our
1551 primary domain. --jerry */
1552 struct winbindd_tdc_domain
*parent
= NULL
;
1554 DEBUG(10,("trusted_domains(ads): Searching "
1555 "trusted domain list of %s and inheriting "
1556 "trust flags for domain %s\n",
1557 domain
->name
, d
.alt_name
));
1559 parent
= wcache_tdc_fetch_domain(talloc_tos(),
1562 d
.domain_flags
= parent
->trust_flags
;
1563 d
.domain_type
= parent
->trust_type
;
1564 d
.domain_trust_attribs
= parent
->trust_attribs
;
1566 d
.domain_flags
= domain
->domain_flags
;
1567 d
.domain_type
= domain
->domain_type
;
1568 d
.domain_trust_attribs
=
1569 domain
->domain_trust_attribs
;
1571 TALLOC_FREE(parent
);
1573 wcache_tdc_add_domain( &d
);
1580 /* the ADS backend methods are exposed via this structure */
1581 struct winbindd_methods ads_methods
= {