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"
31 #include "../libcli/ldap/ldap_ndr.h"
32 #include "../libcli/security/security.h"
33 #include "../libds/common/flag_mapping.h"
39 #define DBGC_CLASS DBGC_WINBIND
41 extern struct winbindd_methods reconnect_methods
;
44 return our ads connections structure for a domain. We keep the connection
45 open to make things faster
47 static ADS_STRUCT
*ads_cached_connection(struct winbindd_domain
*domain
)
52 struct sockaddr_storage dc_ss
;
54 DEBUG(10,("ads_cached_connection\n"));
56 if (domain
->private_data
) {
59 time_t now
= time(NULL
);
61 /* check for a valid structure */
62 ads
= (ADS_STRUCT
*)domain
->private_data
;
64 expire
= MIN(ads
->auth
.tgt_expire
, ads
->auth
.tgs_expire
);
66 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
67 (uint32
)expire
-(uint32
)now
, (uint32
) expire
, (uint32
) now
));
69 if ( ads
->config
.realm
&& (expire
> now
)) {
72 /* we own this ADS_STRUCT so make sure it goes away */
73 DEBUG(7,("Deleting expired krb5 credential cache\n"));
76 ads_kdestroy("MEMORY:winbind_ccache");
77 domain
->private_data
= NULL
;
81 ads
= ads_init(domain
->alt_name
, domain
->name
, NULL
);
83 DEBUG(1,("ads_init for domain %s failed\n", domain
->name
));
87 /* we don't want ads operations to affect the default ccache */
88 ads
->auth
.ccache_name
= SMB_STRDUP("MEMORY:winbind_ccache");
90 /* the machine acct password might have change - fetch it every time */
92 SAFE_FREE(ads
->auth
.password
);
93 SAFE_FREE(ads
->auth
.realm
);
97 if ( !pdb_get_trusteddom_pw( domain
->name
, &ads
->auth
.password
, NULL
, NULL
) ) {
101 ads
->auth
.realm
= SMB_STRDUP( ads
->server
.realm
);
102 if (!strupper_m( ads
->auth
.realm
)) {
108 struct winbindd_domain
*our_domain
= domain
;
110 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
112 /* always give preference to the alt_name in our
113 primary domain if possible */
115 if ( !domain
->primary
)
116 our_domain
= find_our_domain();
118 if ( our_domain
->alt_name
[0] != '\0' ) {
119 ads
->auth
.realm
= SMB_STRDUP( our_domain
->alt_name
);
120 if (!strupper_m( ads
->auth
.realm
)) {
126 ads
->auth
.realm
= SMB_STRDUP( lp_realm() );
129 ads
->auth
.renewable
= WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
;
131 /* Setup the server affinity cache. We don't reaally care
132 about the name. Just setup affinity and the KRB5_CONFIG
135 get_dc_name( ads
->server
.workgroup
, ads
->server
.realm
, dc_name
, &dc_ss
);
137 status
= ads_connect(ads
);
138 if (!ADS_ERR_OK(status
) || !ads
->config
.realm
) {
139 DEBUG(1,("ads_connect for domain %s failed: %s\n",
140 domain
->name
, ads_errstr(status
)));
143 /* if we get ECONNREFUSED then it might be a NT4
144 server, fall back to MSRPC */
145 if (status
.error_type
== ENUM_ADS_ERROR_SYSTEM
&&
146 status
.err
.rc
== ECONNREFUSED
) {
147 /* 'reconnect_methods' is the MS-RPC backend. */
148 DEBUG(1,("Trying MSRPC methods\n"));
149 domain
->backend
= &reconnect_methods
;
154 /* set the flag that says we don't own the memory even
155 though we do so that ads_destroy() won't destroy the
156 structure we pass back by reference */
158 ads
->is_mine
= False
;
160 domain
->private_data
= (void *)ads
;
165 /* Query display info for a realm. This is the basic user list fn */
166 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
169 struct wbint_userinfo
**pinfo
)
171 ADS_STRUCT
*ads
= NULL
;
172 const char *attrs
[] = { "*", NULL
};
175 LDAPMessage
*res
= NULL
;
176 LDAPMessage
*msg
= NULL
;
177 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
181 DEBUG(3,("ads: query_user_list\n"));
183 if ( !winbindd_can_contact_domain( domain
) ) {
184 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
189 ads
= ads_cached_connection(domain
);
192 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
196 rc
= ads_search_retry(ads
, &res
, "(objectCategory=user)", attrs
);
197 if (!ADS_ERR_OK(rc
)) {
198 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc
)));
199 status
= ads_ntstatus(rc
);
201 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
206 count
= ads_count_replies(ads
, res
);
208 DEBUG(1,("query_user_list: No users found\n"));
212 (*pinfo
) = talloc_zero_array(mem_ctx
, struct wbint_userinfo
, count
);
214 status
= NT_STATUS_NO_MEMORY
;
220 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
221 struct wbint_userinfo
*info
= &((*pinfo
)[count
]);
225 if (!ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
) ||
226 ds_atype_map(atype
) != SID_NAME_USER
) {
227 DEBUG(1,("Not a user account? atype=0x%x\n", atype
));
231 info
->acct_name
= ads_pull_username(ads
, mem_ctx
, msg
);
232 info
->full_name
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
233 info
->homedir
= NULL
;
235 info
->primary_gid
= (gid_t
)-1;
237 if (!ads_pull_sid(ads
, msg
, "objectSid",
239 DEBUG(1, ("No sid for %s !?\n", info
->acct_name
));
243 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group
)) {
244 DEBUG(1, ("No primary group for %s !?\n",
248 sid_compose(&info
->group_sid
, &domain
->sid
, group
);
253 (*num_entries
) = count
;
254 ads_msgfree(ads
, res
);
256 for (i
=0; i
<count
; i
++) {
257 struct wbint_userinfo
*info
= &((*pinfo
)[i
]);
258 const char *gecos
= NULL
;
259 gid_t primary_gid
= (gid_t
)-1;
261 status
= nss_get_info_cached(domain
, &info
->user_sid
, mem_ctx
,
262 &info
->homedir
, &info
->shell
,
263 &gecos
, &primary_gid
);
264 if (!NT_STATUS_IS_OK(status
)) {
266 * Deliberately ignore this error, there might be more
273 info
->full_name
= gecos
;
275 info
->primary_gid
= primary_gid
;
278 status
= NT_STATUS_OK
;
280 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries
)));
286 /* list all domain groups */
287 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
290 struct wb_acct_info
**info
)
292 ADS_STRUCT
*ads
= NULL
;
293 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
294 "name", "objectSid", NULL
};
297 LDAPMessage
*res
= NULL
;
298 LDAPMessage
*msg
= NULL
;
299 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
301 bool enum_dom_local_groups
= False
;
305 DEBUG(3,("ads: enum_dom_groups\n"));
307 if ( !winbindd_can_contact_domain( domain
) ) {
308 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
313 /* only grab domain local groups for our domain */
314 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
315 enum_dom_local_groups
= True
;
318 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
321 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
322 * default value, it MUST be absent. In case of extensible matching the
323 * "dnattr" boolean defaults to FALSE and so it must be only be present
326 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
327 * filter using bitwise matching rule then the buggy AD fails to decode
328 * the extensible match. As a workaround set it to TRUE and thereby add
329 * the dnAttributes "dn" field to cope with those older AD versions.
330 * It should not harm and won't put any additional load on the AD since
331 * none of the dn components have a bitmask-attribute.
333 * Thanks to Ralf Haferkamp for input and testing - Guenther */
335 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
336 ADS_LDAP_MATCHING_RULE_BIT_AND
, GROUP_TYPE_SECURITY_ENABLED
,
337 ADS_LDAP_MATCHING_RULE_BIT_AND
,
338 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
340 if (filter
== NULL
) {
341 status
= NT_STATUS_NO_MEMORY
;
345 ads
= ads_cached_connection(domain
);
348 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
352 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
353 if (!ADS_ERR_OK(rc
)) {
354 status
= ads_ntstatus(rc
);
355 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
358 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
362 count
= ads_count_replies(ads
, res
);
364 DEBUG(1,("enum_dom_groups: No groups found\n"));
368 (*info
) = talloc_zero_array(mem_ctx
, struct wb_acct_info
, count
);
370 status
= NT_STATUS_NO_MEMORY
;
376 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
381 name
= ads_pull_username(ads
, mem_ctx
, msg
);
382 gecos
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
383 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
384 DEBUG(1,("No sid for %s !?\n", name
));
388 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
389 DEBUG(1,("No rid for %s !?\n", name
));
393 fstrcpy((*info
)[i
].acct_name
, name
);
394 fstrcpy((*info
)[i
].acct_desc
, gecos
);
395 (*info
)[i
].rid
= rid
;
401 status
= NT_STATUS_OK
;
403 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
407 ads_msgfree(ads
, res
);
412 /* list all domain local groups */
413 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
416 struct wb_acct_info
**info
)
419 * This is a stub function only as we returned the domain
420 * local groups in enum_dom_groups() if the domain->native field
421 * was true. This is a simple performance optimization when
424 * if we ever need to enumerate domain local groups separately,
425 * then this optimization in enum_dom_groups() will need
433 /* convert a single name to a sid in a domain - use rpc methods */
434 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
436 const char *domain_name
,
440 enum lsa_SidType
*type
)
442 return reconnect_methods
.name_to_sid(domain
, mem_ctx
,
443 domain_name
, name
, flags
,
447 /* convert a domain SID to a user or group name - use rpc methods */
448 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
450 const struct dom_sid
*sid
,
453 enum lsa_SidType
*type
)
455 return reconnect_methods
.sid_to_name(domain
, mem_ctx
, sid
,
456 domain_name
, name
, type
);
459 /* convert a list of rids to names - use rpc methods */
460 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
462 const struct dom_sid
*sid
,
467 enum lsa_SidType
**types
)
469 return reconnect_methods
.rids_to_names(domain
, mem_ctx
, sid
,
471 domain_name
, names
, types
);
474 /* If you are looking for "dn_lookup": Yes, it used to be here!
475 * It has gone now since it was a major speed bottleneck in
476 * lookup_groupmem (its only use). It has been replaced by
477 * an rpc lookup sids call... R.I.P. */
479 /* Lookup user information from a rid */
480 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
482 const struct dom_sid
*sid
,
483 struct wbint_userinfo
*info
)
485 ADS_STRUCT
*ads
= NULL
;
486 const char *attrs
[] = { "*", NULL
};
489 LDAPMessage
*msg
= NULL
;
493 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
494 struct netr_SamInfo3
*user
= NULL
;
499 DEBUG(3,("ads: query_user\n"));
501 info
->homedir
= NULL
;
504 /* try netsamlogon cache first */
506 if (winbindd_use_cache() && (user
= netsamlogon_cache_get( mem_ctx
, sid
)) != NULL
)
508 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
509 sid_string_dbg(sid
)));
511 sid_compose(&info
->user_sid
, &domain
->sid
, user
->base
.rid
);
512 sid_compose(&info
->group_sid
, &domain
->sid
, user
->base
.primary_gid
);
514 info
->acct_name
= talloc_strdup(mem_ctx
, user
->base
.account_name
.string
);
515 info
->full_name
= talloc_strdup(mem_ctx
, user
->base
.full_name
.string
);
517 nss_get_info_cached( domain
, sid
, mem_ctx
,
518 &info
->homedir
, &info
->shell
, &info
->full_name
,
520 info
->primary_gid
= gid
;
527 if ( !winbindd_can_contact_domain(domain
)) {
528 DEBUG(8,("query_user: No incoming trust from domain %s\n",
531 /* We still need to generate some basic information
532 about the user even if we cannot contact the
533 domain. Most of this stuff we can deduce. */
535 sid_copy( &info
->user_sid
, sid
);
537 /* Assume "Domain Users" for the primary group */
539 sid_compose(&info
->group_sid
, &domain
->sid
, DOMAIN_RID_USERS
);
541 /* Try to fill in what the nss_info backend can do */
543 nss_get_info_cached( domain
, sid
, mem_ctx
,
544 &info
->homedir
, &info
->shell
, &info
->full_name
,
546 info
->primary_gid
= gid
;
551 /* no cache...do the query */
553 if ( (ads
= ads_cached_connection(domain
)) == NULL
) {
554 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
555 return NT_STATUS_SERVER_DISABLED
;
558 sidstr
= ldap_encode_ndr_dom_sid(talloc_tos(), sid
);
560 ret
= asprintf(&ldap_exp
, "(objectSid=%s)", sidstr
);
563 return NT_STATUS_NO_MEMORY
;
565 rc
= ads_search_retry(ads
, &msg
, ldap_exp
, attrs
);
567 if (!ADS_ERR_OK(rc
)) {
568 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
569 sid_string_dbg(sid
), ads_errstr(rc
)));
570 return ads_ntstatus(rc
);
572 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
573 sid_string_dbg(sid
)));
574 return NT_STATUS_INTERNAL_ERROR
;
577 count
= ads_count_replies(ads
, msg
);
579 DEBUG(1,("query_user(sid=%s): Not found\n",
580 sid_string_dbg(sid
)));
581 ads_msgfree(ads
, msg
);
582 return NT_STATUS_NO_SUCH_USER
;
585 info
->acct_name
= ads_pull_username(ads
, mem_ctx
, msg
);
587 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group_rid
)) {
588 DEBUG(1,("No primary group for %s !?\n",
589 sid_string_dbg(sid
)));
590 ads_msgfree(ads
, msg
);
591 return NT_STATUS_NO_SUCH_USER
;
593 sid_copy(&info
->user_sid
, sid
);
594 sid_compose(&info
->group_sid
, &domain
->sid
, group_rid
);
597 * We have to fetch the "name" attribute before doing the
598 * nss_get_info_cached call. nss_get_info_cached might destroy
599 * the ads struct, potentially invalidating the ldap message.
601 ads_name
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
603 ads_msgfree(ads
, msg
);
606 status
= nss_get_info_cached( domain
, sid
, mem_ctx
,
607 &info
->homedir
, &info
->shell
, &info
->full_name
,
609 info
->primary_gid
= gid
;
610 if (!NT_STATUS_IS_OK(status
)) {
611 DEBUG(1, ("nss_get_info_cached failed: %s\n",
616 if (info
->full_name
== NULL
) {
617 info
->full_name
= ads_name
;
619 TALLOC_FREE(ads_name
);
622 status
= NT_STATUS_OK
;
624 DEBUG(3,("ads query_user gave %s\n", info
->acct_name
));
628 /* Lookup groups a user is a member of - alternate method, for when
629 tokenGroups are not available. */
630 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
633 struct dom_sid
*primary_group
,
634 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
637 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
639 LDAPMessage
*res
= NULL
;
640 LDAPMessage
*msg
= NULL
;
643 const char *group_attrs
[] = {"objectSid", NULL
};
645 uint32_t num_groups
= 0;
647 DEBUG(3,("ads: lookup_usergroups_member\n"));
649 if ( !winbindd_can_contact_domain( domain
) ) {
650 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
655 ads
= ads_cached_connection(domain
);
658 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
662 if (!(escaped_dn
= escape_ldap_string(talloc_tos(), user_dn
))) {
663 status
= NT_STATUS_NO_MEMORY
;
667 ldap_exp
= talloc_asprintf(mem_ctx
,
668 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
670 ADS_LDAP_MATCHING_RULE_BIT_AND
,
671 GROUP_TYPE_SECURITY_ENABLED
);
673 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
674 TALLOC_FREE(escaped_dn
);
675 status
= NT_STATUS_NO_MEMORY
;
679 TALLOC_FREE(escaped_dn
);
681 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
683 if (!ADS_ERR_OK(rc
)) {
684 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
685 return ads_ntstatus(rc
);
687 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
688 return NT_STATUS_INTERNAL_ERROR
;
692 count
= ads_count_replies(ads
, res
);
697 /* always add the primary group to the sid array */
698 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
700 if (!NT_STATUS_IS_OK(status
)) {
705 for (msg
= ads_first_entry(ads
, res
); msg
;
706 msg
= ads_next_entry(ads
, msg
)) {
707 struct dom_sid group_sid
;
709 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
710 DEBUG(1,("No sid for this group ?!?\n"));
714 /* ignore Builtin groups from ADS - Guenther */
715 if (sid_check_is_in_builtin(&group_sid
)) {
719 status
= add_sid_to_array(mem_ctx
, &group_sid
,
720 user_sids
, &num_groups
);
721 if (!NT_STATUS_IS_OK(status
)) {
728 *p_num_groups
= num_groups
;
729 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
731 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
734 ads_msgfree(ads
, res
);
739 /* Lookup groups a user is a member of - alternate method, for when
740 tokenGroups are not available. */
741 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
744 struct dom_sid
*primary_group
,
745 uint32_t *p_num_groups
,
746 struct dom_sid
**user_sids
)
749 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
751 const char *attrs
[] = {"memberOf", NULL
};
752 uint32_t num_groups
= 0;
753 struct dom_sid
*group_sids
= NULL
;
755 char **strings
= NULL
;
756 size_t num_strings
= 0, num_sids
= 0;
759 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
761 if ( !winbindd_can_contact_domain( domain
) ) {
762 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
763 "domain %s\n", domain
->name
));
767 ads
= ads_cached_connection(domain
);
770 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
771 return NT_STATUS_UNSUCCESSFUL
;
774 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
775 ADS_EXTENDED_DN_HEX_STRING
,
776 &strings
, &num_strings
);
778 if (!ADS_ERR_OK(rc
)) {
779 DEBUG(1,("lookup_usergroups_memberof ads_search "
780 "member=%s: %s\n", user_dn
, ads_errstr(rc
)));
781 return ads_ntstatus(rc
);
787 /* always add the primary group to the sid array */
788 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
790 if (!NT_STATUS_IS_OK(status
)) {
794 group_sids
= talloc_zero_array(mem_ctx
, struct dom_sid
, num_strings
+ 1);
796 status
= NT_STATUS_NO_MEMORY
;
800 for (i
=0; i
<num_strings
; i
++) {
801 rc
= ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
802 ADS_EXTENDED_DN_HEX_STRING
,
804 if (!ADS_ERR_OK(rc
)) {
805 /* ignore members without SIDs */
806 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
807 NT_STATUS_NOT_FOUND
)) {
811 status
= ads_ntstatus(rc
);
819 DEBUG(1,("No memberOf for this user?!?\n"));
820 status
= NT_STATUS_NO_MEMORY
;
824 for (i
=0; i
<num_sids
; i
++) {
826 /* ignore Builtin groups from ADS - Guenther */
827 if (sid_check_is_in_builtin(&group_sids
[i
])) {
831 status
= add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
833 if (!NT_STATUS_IS_OK(status
)) {
839 *p_num_groups
= num_groups
;
840 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
842 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
846 TALLOC_FREE(strings
);
847 TALLOC_FREE(group_sids
);
853 /* Lookup groups a user is a member of. */
854 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
856 const struct dom_sid
*sid
,
857 uint32
*p_num_groups
, struct dom_sid
**user_sids
)
859 ADS_STRUCT
*ads
= NULL
;
860 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
863 LDAPMessage
*msg
= NULL
;
864 char *user_dn
= NULL
;
865 struct dom_sid
*sids
;
867 struct dom_sid primary_group
;
868 uint32 primary_group_rid
;
869 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
870 uint32_t num_groups
= 0;
872 DEBUG(3,("ads: lookup_usergroups\n"));
875 status
= lookup_usergroups_cached(domain
, mem_ctx
, sid
,
876 p_num_groups
, user_sids
);
877 if (NT_STATUS_IS_OK(status
)) {
881 if ( !winbindd_can_contact_domain( domain
) ) {
882 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
885 /* Tell the cache manager not to remember this one */
887 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
890 ads
= ads_cached_connection(domain
);
893 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
894 status
= NT_STATUS_SERVER_DISABLED
;
898 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
900 if (!ADS_ERR_OK(rc
)) {
901 status
= ads_ntstatus(rc
);
902 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
903 "%s\n", sid_string_dbg(sid
), ads_errstr(rc
)));
907 count
= ads_count_replies(ads
, msg
);
909 status
= NT_STATUS_UNSUCCESSFUL
;
910 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
911 "invalid number of results (count=%d)\n",
912 sid_string_dbg(sid
), count
));
917 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
918 sid_string_dbg(sid
)));
919 status
= NT_STATUS_UNSUCCESSFUL
;
923 user_dn
= ads_get_dn(ads
, mem_ctx
, msg
);
924 if (user_dn
== NULL
) {
925 status
= NT_STATUS_NO_MEMORY
;
929 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
930 DEBUG(1,("%s: No primary group for sid=%s !?\n",
931 domain
->name
, sid_string_dbg(sid
)));
935 sid_compose(&primary_group
, &domain
->sid
, primary_group_rid
);
937 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
939 /* there must always be at least one group in the token,
940 unless we are talking to a buggy Win2k server */
942 /* actually this only happens when the machine account has no read
943 * permissions on the tokenGroup attribute - gd */
949 /* lookup what groups this user is a member of by DN search on
952 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
954 &num_groups
, user_sids
);
955 *p_num_groups
= num_groups
;
956 if (NT_STATUS_IS_OK(status
)) {
960 /* lookup what groups this user is a member of by DN search on
963 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
965 &num_groups
, user_sids
);
966 *p_num_groups
= num_groups
;
973 status
= add_sid_to_array(mem_ctx
, &primary_group
, user_sids
,
975 if (!NT_STATUS_IS_OK(status
)) {
979 for (i
=0;i
<count
;i
++) {
981 /* ignore Builtin groups from ADS - Guenther */
982 if (sid_check_is_in_builtin(&sids
[i
])) {
986 status
= add_sid_to_array_unique(mem_ctx
, &sids
[i
],
987 user_sids
, &num_groups
);
988 if (!NT_STATUS_IS_OK(status
)) {
993 *p_num_groups
= (uint32
)num_groups
;
994 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
996 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
997 sid_string_dbg(sid
)));
999 TALLOC_FREE(user_dn
);
1000 ads_msgfree(ads
, msg
);
1004 /* Lookup aliases a user is member of - use rpc methods */
1005 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
1006 TALLOC_CTX
*mem_ctx
,
1007 uint32 num_sids
, const struct dom_sid
*sids
,
1008 uint32
*num_aliases
, uint32
**alias_rids
)
1010 return reconnect_methods
.lookup_useraliases(domain
, mem_ctx
,
1017 find the members of a group, given a group rid and domain
1019 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
1020 TALLOC_CTX
*mem_ctx
,
1021 const struct dom_sid
*group_sid
,
1022 enum lsa_SidType type
,
1024 struct dom_sid
**sid_mem
, char ***names
,
1025 uint32
**name_types
)
1028 ADS_STRUCT
*ads
= NULL
;
1030 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1032 char **members
= NULL
;
1034 size_t num_members
= 0;
1036 struct dom_sid
*sid_mem_nocache
= NULL
;
1037 char **names_nocache
= NULL
;
1038 enum lsa_SidType
*name_types_nocache
= NULL
;
1039 char **domains_nocache
= NULL
; /* only needed for rpccli_lsa_lookup_sids */
1040 uint32 num_nocache
= 0;
1041 TALLOC_CTX
*tmp_ctx
= NULL
;
1043 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
1044 sid_string_dbg(group_sid
)));
1048 tmp_ctx
= talloc_new(mem_ctx
);
1050 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1051 status
= NT_STATUS_NO_MEMORY
;
1055 if ( !winbindd_can_contact_domain( domain
) ) {
1056 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1058 return NT_STATUS_OK
;
1061 ads
= ads_cached_connection(domain
);
1064 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1068 if ((sidbinstr
= ldap_encode_ndr_dom_sid(talloc_tos(), group_sid
)) == NULL
) {
1069 status
= NT_STATUS_NO_MEMORY
;
1073 /* search for all members of the group */
1074 ldap_exp
= talloc_asprintf(tmp_ctx
, "(objectSid=%s)", sidbinstr
);
1075 TALLOC_FREE(sidbinstr
);
1076 if (ldap_exp
== NULL
) {
1077 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1078 status
= NT_STATUS_NO_MEMORY
;
1082 args
.control
= ADS_EXTENDED_DN_OID
;
1083 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1084 args
.critical
= True
;
1086 rc
= ads_ranged_search(ads
, tmp_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
1087 ldap_exp
, &args
, "member", &members
, &num_members
);
1089 if (!ADS_ERR_OK(rc
)) {
1090 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
1091 status
= NT_STATUS_UNSUCCESSFUL
;
1095 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members
));
1097 /* Now that we have a list of sids, we need to get the
1098 * lists of names and name_types belonging to these sids.
1099 * even though conceptually not quite clean, we use the
1100 * RPC call lsa_lookup_sids for this since it can handle a
1101 * list of sids. ldap calls can just resolve one sid at a time.
1103 * At this stage, the sids are still hidden in the exetended dn
1104 * member output format. We actually do a little better than
1105 * stated above: In extracting the sids from the member strings,
1106 * we try to resolve as many sids as possible from the
1107 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1110 (*sid_mem
) = talloc_zero_array(mem_ctx
, struct dom_sid
, num_members
);
1111 (*names
) = talloc_zero_array(mem_ctx
, char *, num_members
);
1112 (*name_types
) = talloc_zero_array(mem_ctx
, uint32
, num_members
);
1113 (sid_mem_nocache
) = talloc_zero_array(tmp_ctx
, struct dom_sid
, num_members
);
1115 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1116 (*names
== NULL
) || (*name_types
== NULL
) ||
1117 (sid_mem_nocache
== NULL
))
1119 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1120 status
= NT_STATUS_NO_MEMORY
;
1127 (*name_types
) = NULL
;
1130 for (i
=0; i
<num_members
; i
++) {
1131 enum lsa_SidType name_type
;
1132 char *name
, *domain_name
;
1135 rc
= ads_get_sid_from_extended_dn(tmp_ctx
, members
[i
], args
.val
,
1137 if (!ADS_ERR_OK(rc
)) {
1138 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
1139 NT_STATUS_NOT_FOUND
)) {
1140 /* Group members can be objects, like Exchange
1141 * Public Folders, that don't have a SID. Skip
1146 status
= ads_ntstatus(rc
);
1150 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
,
1152 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1153 "cache\n", sid_string_dbg(&sid
)));
1154 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1155 (*names
)[*num_names
] = fill_domain_username_talloc(
1161 (*name_types
)[*num_names
] = name_type
;
1165 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1166 "cache\n", sid_string_dbg(&sid
)));
1167 sid_copy(&(sid_mem_nocache
)[num_nocache
], &sid
);
1172 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1173 "%d left for lsa_lookupsids\n", *num_names
, num_nocache
));
1175 /* handle sids not resolved from cache by lsa_lookup_sids */
1176 if (num_nocache
> 0) {
1178 status
= winbindd_lookup_sids(tmp_ctx
,
1184 &name_types_nocache
);
1186 if (!(NT_STATUS_IS_OK(status
) ||
1187 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
) ||
1188 NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)))
1190 DEBUG(1, ("lsa_lookupsids call failed with %s "
1191 "- retrying...\n", nt_errstr(status
)));
1193 status
= winbindd_lookup_sids(tmp_ctx
,
1199 &name_types_nocache
);
1202 if (NT_STATUS_IS_OK(status
) ||
1203 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
))
1205 /* Copy the entries over from the "_nocache" arrays
1206 * to the result arrays, skipping the gaps the
1207 * lookup_sids call left. */
1208 for (i
=0; i
< num_nocache
; i
++) {
1209 if (((names_nocache
)[i
] != NULL
) &&
1210 ((name_types_nocache
)[i
] != SID_NAME_UNKNOWN
))
1212 sid_copy(&(*sid_mem
)[*num_names
],
1213 &sid_mem_nocache
[i
]);
1214 (*names
)[*num_names
] =
1215 fill_domain_username_talloc(
1220 (*name_types
)[*num_names
] = name_types_nocache
[i
];
1225 else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1226 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1227 "not map any SIDs at all.\n"));
1228 /* Don't handle this as an error here.
1229 * There is nothing left to do with respect to the
1230 * overall result... */
1232 else if (!NT_STATUS_IS_OK(status
)) {
1233 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1234 "sids via rpc_lsa_lookup_sids: %s\n",
1235 (int)num_members
, nt_errstr(status
)));
1240 status
= NT_STATUS_OK
;
1241 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1242 sid_string_dbg(group_sid
)));
1246 TALLOC_FREE(tmp_ctx
);
1251 /* find the sequence number for a domain */
1252 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1254 ADS_STRUCT
*ads
= NULL
;
1257 DEBUG(3,("ads: fetch sequence_number for %s\n", domain
->name
));
1259 if ( !winbindd_can_contact_domain( domain
) ) {
1260 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1263 return NT_STATUS_OK
;
1266 *seq
= DOM_SEQUENCE_NONE
;
1268 ads
= ads_cached_connection(domain
);
1271 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1272 return NT_STATUS_UNSUCCESSFUL
;
1275 rc
= ads_USN(ads
, seq
);
1277 if (!ADS_ERR_OK(rc
)) {
1279 /* its a dead connection, destroy it */
1281 if (domain
->private_data
) {
1282 ads
= (ADS_STRUCT
*)domain
->private_data
;
1283 ads
->is_mine
= True
;
1285 ads_kdestroy("MEMORY:winbind_ccache");
1286 domain
->private_data
= NULL
;
1289 return ads_ntstatus(rc
);
1292 /* find the lockout policy of a domain - use rpc methods */
1293 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1294 TALLOC_CTX
*mem_ctx
,
1295 struct samr_DomInfo12
*policy
)
1297 return reconnect_methods
.lockout_policy(domain
, mem_ctx
, policy
);
1300 /* find the password policy of a domain - use rpc methods */
1301 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1302 TALLOC_CTX
*mem_ctx
,
1303 struct samr_DomInfo1
*policy
)
1305 return reconnect_methods
.password_policy(domain
, mem_ctx
, policy
);
1308 /* get a list of trusted domains */
1309 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1310 TALLOC_CTX
*mem_ctx
,
1311 struct netr_DomainTrustList
*trusts
)
1313 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1317 struct rpc_pipe_client
*cli
;
1319 struct dcerpc_binding_handle
*b
;
1321 DEBUG(3,("ads: trusted_domains\n"));
1323 ZERO_STRUCTP(trusts
);
1325 /* If this is our primary domain or a root in our forest,
1326 query for all trusts. If not, then just look for domain
1327 trusts in the target forest */
1329 if (domain
->primary
|| domain_is_forest_root(domain
)) {
1330 flags
= NETR_TRUST_FLAG_OUTBOUND
|
1331 NETR_TRUST_FLAG_INBOUND
|
1332 NETR_TRUST_FLAG_IN_FOREST
;
1334 flags
= NETR_TRUST_FLAG_IN_FOREST
;
1337 result
= cm_connect_netlogon(domain
, &cli
);
1339 if (!NT_STATUS_IS_OK(result
)) {
1340 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1341 "for PIPE_NETLOGON (%s)\n",
1342 domain
->name
, nt_errstr(result
)));
1343 return NT_STATUS_UNSUCCESSFUL
;
1346 b
= cli
->binding_handle
;
1348 result
= dcerpc_netr_DsrEnumerateDomainTrusts(b
, mem_ctx
,
1353 if (!NT_STATUS_IS_OK(result
)) {
1357 if (!W_ERROR_IS_OK(werr
)) {
1358 return werror_to_ntstatus(werr
);
1360 if (trusts
->count
== 0) {
1361 return NT_STATUS_OK
;
1364 /* Copy across names and sids */
1367 for (i
= 0; i
< trusts
->count
; i
++) {
1368 struct netr_DomainTrust
*trust
= &trusts
->array
[i
];
1369 struct winbindd_domain d
;
1374 * drop external trusts if this is not our primary
1375 * domain. This means that the returned number of
1376 * domains may be less that the ones actually trusted
1380 if ((trust
->trust_attributes
1381 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) &&
1384 DEBUG(10,("trusted_domains: Skipping external trusted "
1385 "domain %s because it is outside of our "
1387 trust
->netbios_name
));
1391 /* add to the trusted domain cache */
1393 fstrcpy(d
.name
, trust
->netbios_name
);
1394 fstrcpy(d
.alt_name
, trust
->dns_name
);
1396 sid_copy(&d
.sid
, trust
->sid
);
1398 sid_copy(&d
.sid
, &global_sid_NULL
);
1401 if ( domain
->primary
) {
1402 DEBUG(10,("trusted_domains(ads): Searching "
1403 "trusted domain list of %s and storing "
1404 "trust flags for domain %s\n",
1405 domain
->name
, d
.alt_name
));
1407 d
.domain_flags
= trust
->trust_flags
;
1408 d
.domain_type
= trust
->trust_type
;
1409 d
.domain_trust_attribs
= trust
->trust_attributes
;
1411 wcache_tdc_add_domain( &d
);
1413 } else if (domain_is_forest_root(domain
)) {
1414 /* Check if we already have this record. If
1415 * we are following our forest root that is not
1416 * our primary domain, we want to keep trust
1417 * flags from the perspective of our primary
1418 * domain not our forest root. */
1419 struct winbindd_tdc_domain
*exist
= NULL
;
1421 exist
= wcache_tdc_fetch_domain(
1422 talloc_tos(), trust
->netbios_name
);
1424 DEBUG(10,("trusted_domains(ads): Searching "
1425 "trusted domain list of %s and "
1426 "storing trust flags for domain "
1427 "%s\n", domain
->name
, d
.alt_name
));
1428 d
.domain_flags
= trust
->trust_flags
;
1429 d
.domain_type
= trust
->trust_type
;
1430 d
.domain_trust_attribs
=
1431 trust
->trust_attributes
;
1433 wcache_tdc_add_domain( &d
);
1438 /* This gets a little tricky. If we are
1439 following a transitive forest trust, then
1440 innerit the flags, type, and attribs from
1441 the domain we queried to make sure we don't
1442 record the view of the trust from the wrong
1443 side. Always view it from the side of our
1444 primary domain. --jerry */
1445 struct winbindd_tdc_domain
*parent
= NULL
;
1447 DEBUG(10,("trusted_domains(ads): Searching "
1448 "trusted domain list of %s and inheriting "
1449 "trust flags for domain %s\n",
1450 domain
->name
, d
.alt_name
));
1452 parent
= wcache_tdc_fetch_domain(talloc_tos(),
1455 d
.domain_flags
= parent
->trust_flags
;
1456 d
.domain_type
= parent
->trust_type
;
1457 d
.domain_trust_attribs
= parent
->trust_attribs
;
1459 d
.domain_flags
= domain
->domain_flags
;
1460 d
.domain_type
= domain
->domain_type
;
1461 d
.domain_trust_attribs
=
1462 domain
->domain_trust_attribs
;
1464 TALLOC_FREE(parent
);
1466 wcache_tdc_add_domain( &d
);
1473 /* the ADS backend methods are exposed via this structure */
1474 struct winbindd_methods ads_methods
= {