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 "../librpc/gen_ndr/ndr_netlogon_c.h"
27 #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
;
43 return our ads connections structure for a domain. We keep the connection
44 open to make things faster
46 static ADS_STRUCT
*ads_cached_connection(struct winbindd_domain
*domain
)
51 struct sockaddr_storage dc_ss
;
53 DEBUG(10,("ads_cached_connection\n"));
55 if (domain
->private_data
) {
58 time_t now
= time(NULL
);
60 /* check for a valid structure */
61 ads
= (ADS_STRUCT
*)domain
->private_data
;
63 expire
= MIN(ads
->auth
.tgt_expire
, ads
->auth
.tgs_expire
);
65 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
66 (uint32
)expire
-(uint32
)now
, (uint32
) expire
, (uint32
) now
));
68 if ( ads
->config
.realm
&& (expire
> now
)) {
71 /* we own this ADS_STRUCT so make sure it goes away */
72 DEBUG(7,("Deleting expired krb5 credential cache\n"));
75 ads_kdestroy("MEMORY:winbind_ccache");
76 domain
->private_data
= NULL
;
80 /* we don't want this to affect the users ccache */
81 setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1);
83 ads
= ads_init(domain
->alt_name
, domain
->name
, NULL
);
85 DEBUG(1,("ads_init for domain %s failed\n", domain
->name
));
89 /* the machine acct password might have change - fetch it every time */
91 SAFE_FREE(ads
->auth
.password
);
92 SAFE_FREE(ads
->auth
.realm
);
96 if ( !pdb_get_trusteddom_pw( domain
->name
, &ads
->auth
.password
, NULL
, NULL
) ) {
100 ads
->auth
.realm
= SMB_STRDUP( ads
->server
.realm
);
101 strupper_m( ads
->auth
.realm
);
104 struct winbindd_domain
*our_domain
= domain
;
106 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
108 /* always give preference to the alt_name in our
109 primary domain if possible */
111 if ( !domain
->primary
)
112 our_domain
= find_our_domain();
114 if ( our_domain
->alt_name
[0] != '\0' ) {
115 ads
->auth
.realm
= SMB_STRDUP( our_domain
->alt_name
);
116 strupper_m( ads
->auth
.realm
);
119 ads
->auth
.realm
= SMB_STRDUP( lp_realm() );
122 ads
->auth
.renewable
= WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
;
124 /* Setup the server affinity cache. We don't reaally care
125 about the name. Just setup affinity and the KRB5_CONFIG
128 get_dc_name( ads
->server
.workgroup
, ads
->server
.realm
, dc_name
, &dc_ss
);
130 status
= ads_connect(ads
);
131 if (!ADS_ERR_OK(status
) || !ads
->config
.realm
) {
132 DEBUG(1,("ads_connect for domain %s failed: %s\n",
133 domain
->name
, ads_errstr(status
)));
136 /* if we get ECONNREFUSED then it might be a NT4
137 server, fall back to MSRPC */
138 if (status
.error_type
== ENUM_ADS_ERROR_SYSTEM
&&
139 status
.err
.rc
== ECONNREFUSED
) {
140 /* 'reconnect_methods' is the MS-RPC backend. */
141 DEBUG(1,("Trying MSRPC methods\n"));
142 domain
->backend
= &reconnect_methods
;
147 /* set the flag that says we don't own the memory even
148 though we do so that ads_destroy() won't destroy the
149 structure we pass back by reference */
151 ads
->is_mine
= False
;
153 domain
->private_data
= (void *)ads
;
158 /* Query display info for a realm. This is the basic user list fn */
159 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
162 struct wbint_userinfo
**pinfo
)
164 ADS_STRUCT
*ads
= NULL
;
165 const char *attrs
[] = { "*", NULL
};
168 LDAPMessage
*res
= NULL
;
169 LDAPMessage
*msg
= NULL
;
170 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
174 DEBUG(3,("ads: query_user_list\n"));
176 if ( !winbindd_can_contact_domain( domain
) ) {
177 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
182 ads
= ads_cached_connection(domain
);
185 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
189 rc
= ads_search_retry(ads
, &res
, "(objectCategory=user)", attrs
);
190 if (!ADS_ERR_OK(rc
) || !res
) {
191 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc
)));
195 count
= ads_count_replies(ads
, res
);
197 DEBUG(1,("query_user_list: No users found\n"));
201 (*pinfo
) = TALLOC_ZERO_ARRAY(mem_ctx
, struct wbint_userinfo
, count
);
203 status
= NT_STATUS_NO_MEMORY
;
209 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
210 struct wbint_userinfo
*info
= &((*pinfo
)[count
]);
214 if (!ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
) ||
215 ds_atype_map(atype
) != SID_NAME_USER
) {
216 DEBUG(1,("Not a user account? atype=0x%x\n", atype
));
220 info
->acct_name
= ads_pull_username(ads
, mem_ctx
, msg
);
221 info
->full_name
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
222 info
->homedir
= NULL
;
224 info
->primary_gid
= (gid_t
)-1;
226 if (!ads_pull_sid(ads
, msg
, "objectSid",
228 DEBUG(1, ("No sid for %s !?\n", info
->acct_name
));
232 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group
)) {
233 DEBUG(1, ("No primary group for %s !?\n",
237 sid_compose(&info
->group_sid
, &domain
->sid
, group
);
242 (*num_entries
) = count
;
243 ads_msgfree(ads
, res
);
245 for (i
=0; i
<count
; i
++) {
246 struct wbint_userinfo
*info
= &((*pinfo
)[i
]);
247 const char *gecos
= NULL
;
248 gid_t primary_gid
= (gid_t
)-1;
250 status
= nss_get_info_cached(domain
, &info
->user_sid
, mem_ctx
,
251 &info
->homedir
, &info
->shell
,
252 &gecos
, &primary_gid
);
253 if (!NT_STATUS_IS_OK(status
)) {
255 * Deliberately ignore this error, there might be more
262 info
->full_name
= gecos
;
264 info
->primary_gid
= primary_gid
;
267 status
= NT_STATUS_OK
;
269 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries
)));
275 /* list all domain groups */
276 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
279 struct wb_acct_info
**info
)
281 ADS_STRUCT
*ads
= NULL
;
282 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
283 "name", "objectSid", NULL
};
286 LDAPMessage
*res
= NULL
;
287 LDAPMessage
*msg
= NULL
;
288 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
290 bool enum_dom_local_groups
= False
;
294 DEBUG(3,("ads: enum_dom_groups\n"));
296 if ( !winbindd_can_contact_domain( domain
) ) {
297 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
302 /* only grab domain local groups for our domain */
303 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
304 enum_dom_local_groups
= True
;
307 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
310 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
311 * default value, it MUST be absent. In case of extensible matching the
312 * "dnattr" boolean defaults to FALSE and so it must be only be present
315 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
316 * filter using bitwise matching rule then the buggy AD fails to decode
317 * the extensible match. As a workaround set it to TRUE and thereby add
318 * the dnAttributes "dn" field to cope with those older AD versions.
319 * It should not harm and won't put any additional load on the AD since
320 * none of the dn components have a bitmask-attribute.
322 * Thanks to Ralf Haferkamp for input and testing - Guenther */
324 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
325 ADS_LDAP_MATCHING_RULE_BIT_AND
, GROUP_TYPE_SECURITY_ENABLED
,
326 ADS_LDAP_MATCHING_RULE_BIT_AND
,
327 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
329 if (filter
== NULL
) {
330 status
= NT_STATUS_NO_MEMORY
;
334 ads
= ads_cached_connection(domain
);
337 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
341 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
342 if (!ADS_ERR_OK(rc
) || !res
) {
343 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
347 count
= ads_count_replies(ads
, res
);
349 DEBUG(1,("enum_dom_groups: No groups found\n"));
353 (*info
) = TALLOC_ZERO_ARRAY(mem_ctx
, struct wb_acct_info
, count
);
355 status
= NT_STATUS_NO_MEMORY
;
361 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
366 name
= ads_pull_username(ads
, mem_ctx
, msg
);
367 gecos
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
368 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
369 DEBUG(1,("No sid for %s !?\n", name
));
373 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
374 DEBUG(1,("No rid for %s !?\n", name
));
378 fstrcpy((*info
)[i
].acct_name
, name
);
379 fstrcpy((*info
)[i
].acct_desc
, gecos
);
380 (*info
)[i
].rid
= rid
;
386 status
= NT_STATUS_OK
;
388 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
392 ads_msgfree(ads
, res
);
397 /* list all domain local groups */
398 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
401 struct wb_acct_info
**info
)
404 * This is a stub function only as we returned the domain
405 * local groups in enum_dom_groups() if the domain->native field
406 * was true. This is a simple performance optimization when
409 * if we ever need to enumerate domain local groups separately,
410 * then this optimization in enum_dom_groups() will need
418 /* convert a single name to a sid in a domain - use rpc methods */
419 static NTSTATUS
name_to_sid(struct winbindd_domain
*domain
,
421 const char *domain_name
,
425 enum lsa_SidType
*type
)
427 return reconnect_methods
.name_to_sid(domain
, mem_ctx
,
428 domain_name
, name
, flags
,
432 /* convert a domain SID to a user or group name - use rpc methods */
433 static NTSTATUS
sid_to_name(struct winbindd_domain
*domain
,
435 const struct dom_sid
*sid
,
438 enum lsa_SidType
*type
)
440 return reconnect_methods
.sid_to_name(domain
, mem_ctx
, sid
,
441 domain_name
, name
, type
);
444 /* convert a list of rids to names - use rpc methods */
445 static NTSTATUS
rids_to_names(struct winbindd_domain
*domain
,
447 const struct dom_sid
*sid
,
452 enum lsa_SidType
**types
)
454 return reconnect_methods
.rids_to_names(domain
, mem_ctx
, sid
,
456 domain_name
, names
, types
);
459 /* If you are looking for "dn_lookup": Yes, it used to be here!
460 * It has gone now since it was a major speed bottleneck in
461 * lookup_groupmem (its only use). It has been replaced by
462 * an rpc lookup sids call... R.I.P. */
464 /* Lookup user information from a rid */
465 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
467 const struct dom_sid
*sid
,
468 struct wbint_userinfo
*info
)
470 ADS_STRUCT
*ads
= NULL
;
471 const char *attrs
[] = { "*", NULL
};
474 LDAPMessage
*msg
= NULL
;
478 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
479 struct netr_SamInfo3
*user
= NULL
;
484 DEBUG(3,("ads: query_user\n"));
486 info
->homedir
= NULL
;
489 /* try netsamlogon cache first */
491 if ( (user
= netsamlogon_cache_get( mem_ctx
, sid
)) != NULL
)
493 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
494 sid_string_dbg(sid
)));
496 sid_compose(&info
->user_sid
, &domain
->sid
, user
->base
.rid
);
497 sid_compose(&info
->group_sid
, &domain
->sid
, user
->base
.primary_gid
);
499 info
->acct_name
= talloc_strdup(mem_ctx
, user
->base
.account_name
.string
);
500 info
->full_name
= talloc_strdup(mem_ctx
, user
->base
.full_name
.string
);
502 nss_get_info_cached( domain
, sid
, mem_ctx
,
503 &info
->homedir
, &info
->shell
, &info
->full_name
,
505 info
->primary_gid
= gid
;
512 if ( !winbindd_can_contact_domain(domain
)) {
513 DEBUG(8,("query_user: No incoming trust from domain %s\n",
516 /* We still need to generate some basic information
517 about the user even if we cannot contact the
518 domain. Most of this stuff we can deduce. */
520 sid_copy( &info
->user_sid
, sid
);
522 /* Assume "Domain Users" for the primary group */
524 sid_compose(&info
->group_sid
, &domain
->sid
, DOMAIN_RID_USERS
);
526 /* Try to fill in what the nss_info backend can do */
528 nss_get_info_cached( domain
, sid
, mem_ctx
,
529 &info
->homedir
, &info
->shell
, &info
->full_name
,
531 info
->primary_gid
= gid
;
536 /* no cache...do the query */
538 if ( (ads
= ads_cached_connection(domain
)) == NULL
) {
539 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
540 return NT_STATUS_SERVER_DISABLED
;
543 sidstr
= ldap_encode_ndr_dom_sid(talloc_tos(), sid
);
545 ret
= asprintf(&ldap_exp
, "(objectSid=%s)", sidstr
);
548 return NT_STATUS_NO_MEMORY
;
550 rc
= ads_search_retry(ads
, &msg
, ldap_exp
, attrs
);
552 if (!ADS_ERR_OK(rc
) || !msg
) {
553 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
554 sid_string_dbg(sid
), ads_errstr(rc
)));
555 return ads_ntstatus(rc
);
558 count
= ads_count_replies(ads
, msg
);
560 DEBUG(1,("query_user(sid=%s): Not found\n",
561 sid_string_dbg(sid
)));
562 ads_msgfree(ads
, msg
);
563 return NT_STATUS_NO_SUCH_USER
;
566 info
->acct_name
= ads_pull_username(ads
, mem_ctx
, msg
);
568 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group_rid
)) {
569 DEBUG(1,("No primary group for %s !?\n",
570 sid_string_dbg(sid
)));
571 ads_msgfree(ads
, msg
);
572 return NT_STATUS_NO_SUCH_USER
;
574 sid_copy(&info
->user_sid
, sid
);
575 sid_compose(&info
->group_sid
, &domain
->sid
, group_rid
);
578 * We have to fetch the "name" attribute before doing the
579 * nss_get_info_cached call. nss_get_info_cached might destroy
580 * the ads struct, potentially invalidating the ldap message.
582 ads_name
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
584 ads_msgfree(ads
, msg
);
587 status
= nss_get_info_cached( domain
, sid
, mem_ctx
,
588 &info
->homedir
, &info
->shell
, &info
->full_name
,
590 info
->primary_gid
= gid
;
591 if (!NT_STATUS_IS_OK(status
)) {
592 DEBUG(1, ("nss_get_info_cached failed: %s\n",
597 if (info
->full_name
== NULL
) {
598 info
->full_name
= ads_name
;
600 TALLOC_FREE(ads_name
);
603 status
= NT_STATUS_OK
;
605 DEBUG(3,("ads query_user gave %s\n", info
->acct_name
));
609 /* Lookup groups a user is a member of - alternate method, for when
610 tokenGroups are not available. */
611 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
614 struct dom_sid
*primary_group
,
615 uint32_t *p_num_groups
, struct dom_sid
**user_sids
)
618 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
620 LDAPMessage
*res
= NULL
;
621 LDAPMessage
*msg
= NULL
;
624 const char *group_attrs
[] = {"objectSid", NULL
};
626 uint32_t num_groups
= 0;
628 DEBUG(3,("ads: lookup_usergroups_member\n"));
630 if ( !winbindd_can_contact_domain( domain
) ) {
631 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
636 ads
= ads_cached_connection(domain
);
639 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
643 if (!(escaped_dn
= escape_ldap_string(talloc_tos(), user_dn
))) {
644 status
= NT_STATUS_NO_MEMORY
;
648 ldap_exp
= talloc_asprintf(mem_ctx
,
649 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
651 ADS_LDAP_MATCHING_RULE_BIT_AND
,
652 GROUP_TYPE_SECURITY_ENABLED
);
654 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
655 TALLOC_FREE(escaped_dn
);
656 status
= NT_STATUS_NO_MEMORY
;
660 TALLOC_FREE(escaped_dn
);
662 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
664 if (!ADS_ERR_OK(rc
) || !res
) {
665 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
666 return ads_ntstatus(rc
);
669 count
= ads_count_replies(ads
, res
);
674 /* always add the primary group to the sid array */
675 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
677 if (!NT_STATUS_IS_OK(status
)) {
682 for (msg
= ads_first_entry(ads
, res
); msg
;
683 msg
= ads_next_entry(ads
, msg
)) {
684 struct dom_sid group_sid
;
686 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
687 DEBUG(1,("No sid for this group ?!?\n"));
691 /* ignore Builtin groups from ADS - Guenther */
692 if (sid_check_is_in_builtin(&group_sid
)) {
696 status
= add_sid_to_array(mem_ctx
, &group_sid
,
697 user_sids
, &num_groups
);
698 if (!NT_STATUS_IS_OK(status
)) {
705 *p_num_groups
= num_groups
;
706 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
708 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
711 ads_msgfree(ads
, res
);
716 /* Lookup groups a user is a member of - alternate method, for when
717 tokenGroups are not available. */
718 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
721 struct dom_sid
*primary_group
,
722 uint32_t *p_num_groups
,
723 struct dom_sid
**user_sids
)
726 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
728 const char *attrs
[] = {"memberOf", NULL
};
729 uint32_t num_groups
= 0;
730 struct dom_sid
*group_sids
= NULL
;
732 char **strings
= NULL
;
733 size_t num_strings
= 0, num_sids
= 0;
736 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
738 if ( !winbindd_can_contact_domain( domain
) ) {
739 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
740 "domain %s\n", domain
->name
));
744 ads
= ads_cached_connection(domain
);
747 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
748 return NT_STATUS_UNSUCCESSFUL
;
751 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
752 ADS_EXTENDED_DN_HEX_STRING
,
753 &strings
, &num_strings
);
755 if (!ADS_ERR_OK(rc
)) {
756 DEBUG(1,("lookup_usergroups_memberof ads_search "
757 "member=%s: %s\n", user_dn
, ads_errstr(rc
)));
758 return ads_ntstatus(rc
);
764 /* always add the primary group to the sid array */
765 status
= add_sid_to_array(mem_ctx
, primary_group
, user_sids
,
767 if (!NT_STATUS_IS_OK(status
)) {
771 group_sids
= TALLOC_ZERO_ARRAY(mem_ctx
, struct dom_sid
, num_strings
+ 1);
773 status
= NT_STATUS_NO_MEMORY
;
777 for (i
=0; i
<num_strings
; i
++) {
778 rc
= ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
779 ADS_EXTENDED_DN_HEX_STRING
,
781 if (!ADS_ERR_OK(rc
)) {
782 /* ignore members without SIDs */
783 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
784 NT_STATUS_NOT_FOUND
)) {
788 status
= ads_ntstatus(rc
);
796 DEBUG(1,("No memberOf for this user?!?\n"));
797 status
= NT_STATUS_NO_MEMORY
;
801 for (i
=0; i
<num_sids
; i
++) {
803 /* ignore Builtin groups from ADS - Guenther */
804 if (sid_check_is_in_builtin(&group_sids
[i
])) {
808 status
= add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
810 if (!NT_STATUS_IS_OK(status
)) {
816 *p_num_groups
= num_groups
;
817 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
819 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
823 TALLOC_FREE(strings
);
824 TALLOC_FREE(group_sids
);
830 /* Lookup groups a user is a member of. */
831 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
833 const struct dom_sid
*sid
,
834 uint32
*p_num_groups
, struct dom_sid
**user_sids
)
836 ADS_STRUCT
*ads
= NULL
;
837 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
840 LDAPMessage
*msg
= NULL
;
841 char *user_dn
= NULL
;
842 struct dom_sid
*sids
;
844 struct dom_sid primary_group
;
845 uint32 primary_group_rid
;
846 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
847 uint32_t num_groups
= 0;
849 DEBUG(3,("ads: lookup_usergroups\n"));
852 status
= lookup_usergroups_cached(domain
, mem_ctx
, sid
,
853 p_num_groups
, user_sids
);
854 if (NT_STATUS_IS_OK(status
)) {
858 if ( !winbindd_can_contact_domain( domain
) ) {
859 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
862 /* Tell the cache manager not to remember this one */
864 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
867 ads
= ads_cached_connection(domain
);
870 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
871 status
= NT_STATUS_SERVER_DISABLED
;
875 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
877 if (!ADS_ERR_OK(rc
)) {
878 status
= ads_ntstatus(rc
);
879 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
880 "%s\n", sid_string_dbg(sid
), ads_errstr(rc
)));
884 count
= ads_count_replies(ads
, msg
);
886 status
= NT_STATUS_UNSUCCESSFUL
;
887 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
888 "invalid number of results (count=%d)\n",
889 sid_string_dbg(sid
), count
));
894 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
895 sid_string_dbg(sid
)));
896 status
= NT_STATUS_UNSUCCESSFUL
;
900 user_dn
= ads_get_dn(ads
, mem_ctx
, msg
);
901 if (user_dn
== NULL
) {
902 status
= NT_STATUS_NO_MEMORY
;
906 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
907 DEBUG(1,("%s: No primary group for sid=%s !?\n",
908 domain
->name
, sid_string_dbg(sid
)));
912 sid_compose(&primary_group
, &domain
->sid
, primary_group_rid
);
914 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
916 /* there must always be at least one group in the token,
917 unless we are talking to a buggy Win2k server */
919 /* actually this only happens when the machine account has no read
920 * permissions on the tokenGroup attribute - gd */
926 /* lookup what groups this user is a member of by DN search on
929 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
931 &num_groups
, user_sids
);
932 *p_num_groups
= num_groups
;
933 if (NT_STATUS_IS_OK(status
)) {
937 /* lookup what groups this user is a member of by DN search on
940 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
942 &num_groups
, user_sids
);
943 *p_num_groups
= num_groups
;
950 status
= add_sid_to_array(mem_ctx
, &primary_group
, user_sids
,
952 if (!NT_STATUS_IS_OK(status
)) {
956 for (i
=0;i
<count
;i
++) {
958 /* ignore Builtin groups from ADS - Guenther */
959 if (sid_check_is_in_builtin(&sids
[i
])) {
963 status
= add_sid_to_array_unique(mem_ctx
, &sids
[i
],
964 user_sids
, &num_groups
);
965 if (!NT_STATUS_IS_OK(status
)) {
970 *p_num_groups
= (uint32
)num_groups
;
971 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
973 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
974 sid_string_dbg(sid
)));
976 TALLOC_FREE(user_dn
);
977 ads_msgfree(ads
, msg
);
981 /* Lookup aliases a user is member of - use rpc methods */
982 static NTSTATUS
lookup_useraliases(struct winbindd_domain
*domain
,
984 uint32 num_sids
, const struct dom_sid
*sids
,
985 uint32
*num_aliases
, uint32
**alias_rids
)
987 return reconnect_methods
.lookup_useraliases(domain
, mem_ctx
,
994 find the members of a group, given a group rid and domain
996 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
998 const struct dom_sid
*group_sid
,
999 enum lsa_SidType type
,
1001 struct dom_sid
**sid_mem
, char ***names
,
1002 uint32
**name_types
)
1005 ADS_STRUCT
*ads
= NULL
;
1007 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
1009 char **members
= NULL
;
1011 size_t num_members
= 0;
1013 struct dom_sid
*sid_mem_nocache
= NULL
;
1014 char **names_nocache
= NULL
;
1015 enum lsa_SidType
*name_types_nocache
= NULL
;
1016 char **domains_nocache
= NULL
; /* only needed for rpccli_lsa_lookup_sids */
1017 uint32 num_nocache
= 0;
1018 TALLOC_CTX
*tmp_ctx
= NULL
;
1020 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
1021 sid_string_dbg(group_sid
)));
1025 tmp_ctx
= talloc_new(mem_ctx
);
1027 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1028 status
= NT_STATUS_NO_MEMORY
;
1032 if ( !winbindd_can_contact_domain( domain
) ) {
1033 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1035 return NT_STATUS_OK
;
1038 ads
= ads_cached_connection(domain
);
1041 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1045 if ((sidbinstr
= ldap_encode_ndr_dom_sid(talloc_tos(), group_sid
)) == NULL
) {
1046 status
= NT_STATUS_NO_MEMORY
;
1050 /* search for all members of the group */
1051 ldap_exp
= talloc_asprintf(tmp_ctx
, "(objectSid=%s)", sidbinstr
);
1052 TALLOC_FREE(sidbinstr
);
1053 if (ldap_exp
== NULL
) {
1054 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1055 status
= NT_STATUS_NO_MEMORY
;
1059 args
.control
= ADS_EXTENDED_DN_OID
;
1060 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
1061 args
.critical
= True
;
1063 rc
= ads_ranged_search(ads
, tmp_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
1064 ldap_exp
, &args
, "member", &members
, &num_members
);
1066 if (!ADS_ERR_OK(rc
)) {
1067 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
1068 status
= NT_STATUS_UNSUCCESSFUL
;
1072 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members
));
1074 /* Now that we have a list of sids, we need to get the
1075 * lists of names and name_types belonging to these sids.
1076 * even though conceptually not quite clean, we use the
1077 * RPC call lsa_lookup_sids for this since it can handle a
1078 * list of sids. ldap calls can just resolve one sid at a time.
1080 * At this stage, the sids are still hidden in the exetended dn
1081 * member output format. We actually do a little better than
1082 * stated above: In extracting the sids from the member strings,
1083 * we try to resolve as many sids as possible from the
1084 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1087 (*sid_mem
) = TALLOC_ZERO_ARRAY(mem_ctx
, struct dom_sid
, num_members
);
1088 (*names
) = TALLOC_ZERO_ARRAY(mem_ctx
, char *, num_members
);
1089 (*name_types
) = TALLOC_ZERO_ARRAY(mem_ctx
, uint32
, num_members
);
1090 (sid_mem_nocache
) = TALLOC_ZERO_ARRAY(tmp_ctx
, struct dom_sid
, num_members
);
1092 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1093 (*names
== NULL
) || (*name_types
== NULL
) ||
1094 (sid_mem_nocache
== NULL
))
1096 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1097 status
= NT_STATUS_NO_MEMORY
;
1104 (*name_types
) = NULL
;
1107 for (i
=0; i
<num_members
; i
++) {
1108 enum lsa_SidType name_type
;
1109 char *name
, *domain_name
;
1112 rc
= ads_get_sid_from_extended_dn(tmp_ctx
, members
[i
], args
.val
,
1114 if (!ADS_ERR_OK(rc
)) {
1115 if (NT_STATUS_EQUAL(ads_ntstatus(rc
),
1116 NT_STATUS_NOT_FOUND
)) {
1117 /* Group members can be objects, like Exchange
1118 * Public Folders, that don't have a SID. Skip
1123 status
= ads_ntstatus(rc
);
1127 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
,
1129 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1130 "cache\n", sid_string_dbg(&sid
)));
1131 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1132 (*names
)[*num_names
] = fill_domain_username_talloc(
1138 (*name_types
)[*num_names
] = name_type
;
1142 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1143 "cache\n", sid_string_dbg(&sid
)));
1144 sid_copy(&(sid_mem_nocache
)[num_nocache
], &sid
);
1149 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1150 "%d left for lsa_lookupsids\n", *num_names
, num_nocache
));
1152 /* handle sids not resolved from cache by lsa_lookup_sids */
1153 if (num_nocache
> 0) {
1155 status
= winbindd_lookup_sids(tmp_ctx
,
1161 &name_types_nocache
);
1163 if (!(NT_STATUS_IS_OK(status
) ||
1164 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
) ||
1165 NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)))
1167 DEBUG(1, ("lsa_lookupsids call failed with %s "
1168 "- retrying...\n", nt_errstr(status
)));
1170 status
= winbindd_lookup_sids(tmp_ctx
,
1176 &name_types_nocache
);
1179 if (NT_STATUS_IS_OK(status
) ||
1180 NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
))
1182 /* Copy the entries over from the "_nocache" arrays
1183 * to the result arrays, skipping the gaps the
1184 * lookup_sids call left. */
1185 for (i
=0; i
< num_nocache
; i
++) {
1186 if (((names_nocache
)[i
] != NULL
) &&
1187 ((name_types_nocache
)[i
] != SID_NAME_UNKNOWN
))
1189 sid_copy(&(*sid_mem
)[*num_names
],
1190 &sid_mem_nocache
[i
]);
1191 (*names
)[*num_names
] =
1192 fill_domain_username_talloc(
1197 (*name_types
)[*num_names
] = name_types_nocache
[i
];
1202 else if (NT_STATUS_EQUAL(status
, NT_STATUS_NONE_MAPPED
)) {
1203 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1204 "not map any SIDs at all.\n"));
1205 /* Don't handle this as an error here.
1206 * There is nothing left to do with respect to the
1207 * overall result... */
1209 else if (!NT_STATUS_IS_OK(status
)) {
1210 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1211 "sids via rpc_lsa_lookup_sids: %s\n",
1212 (int)num_members
, nt_errstr(status
)));
1217 status
= NT_STATUS_OK
;
1218 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1219 sid_string_dbg(group_sid
)));
1223 TALLOC_FREE(tmp_ctx
);
1228 /* find the sequence number for a domain */
1229 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1231 ADS_STRUCT
*ads
= NULL
;
1234 DEBUG(3,("ads: fetch sequence_number for %s\n", domain
->name
));
1236 if ( !winbindd_can_contact_domain( domain
) ) {
1237 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1240 return NT_STATUS_OK
;
1243 *seq
= DOM_SEQUENCE_NONE
;
1245 ads
= ads_cached_connection(domain
);
1248 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1249 return NT_STATUS_UNSUCCESSFUL
;
1252 rc
= ads_USN(ads
, seq
);
1254 if (!ADS_ERR_OK(rc
)) {
1256 /* its a dead connection, destroy it */
1258 if (domain
->private_data
) {
1259 ads
= (ADS_STRUCT
*)domain
->private_data
;
1260 ads
->is_mine
= True
;
1262 ads_kdestroy("MEMORY:winbind_ccache");
1263 domain
->private_data
= NULL
;
1266 return ads_ntstatus(rc
);
1269 /* find the lockout policy of a domain - use rpc methods */
1270 static NTSTATUS
lockout_policy(struct winbindd_domain
*domain
,
1271 TALLOC_CTX
*mem_ctx
,
1272 struct samr_DomInfo12
*policy
)
1274 return reconnect_methods
.lockout_policy(domain
, mem_ctx
, policy
);
1277 /* find the password policy of a domain - use rpc methods */
1278 static NTSTATUS
password_policy(struct winbindd_domain
*domain
,
1279 TALLOC_CTX
*mem_ctx
,
1280 struct samr_DomInfo1
*policy
)
1282 return reconnect_methods
.password_policy(domain
, mem_ctx
, policy
);
1285 /* get a list of trusted domains */
1286 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1287 TALLOC_CTX
*mem_ctx
,
1288 struct netr_DomainTrustList
*trusts
)
1290 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1294 struct rpc_pipe_client
*cli
;
1296 struct dcerpc_binding_handle
*b
;
1298 DEBUG(3,("ads: trusted_domains\n"));
1300 ZERO_STRUCTP(trusts
);
1302 /* If this is our primary domain or a root in our forest,
1303 query for all trusts. If not, then just look for domain
1304 trusts in the target forest */
1306 if (domain
->primary
|| domain_is_forest_root(domain
)) {
1307 flags
= NETR_TRUST_FLAG_OUTBOUND
|
1308 NETR_TRUST_FLAG_INBOUND
|
1309 NETR_TRUST_FLAG_IN_FOREST
;
1311 flags
= NETR_TRUST_FLAG_IN_FOREST
;
1314 result
= cm_connect_netlogon(domain
, &cli
);
1316 if (!NT_STATUS_IS_OK(result
)) {
1317 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1318 "for PIPE_NETLOGON (%s)\n",
1319 domain
->name
, nt_errstr(result
)));
1320 return NT_STATUS_UNSUCCESSFUL
;
1323 b
= cli
->binding_handle
;
1325 result
= dcerpc_netr_DsrEnumerateDomainTrusts(b
, mem_ctx
,
1330 if (!NT_STATUS_IS_OK(result
)) {
1334 if (!W_ERROR_IS_OK(werr
)) {
1335 return werror_to_ntstatus(werr
);
1337 if (trusts
->count
== 0) {
1338 return NT_STATUS_OK
;
1341 /* Copy across names and sids */
1344 for (i
= 0; i
< trusts
->count
; i
++) {
1345 struct netr_DomainTrust
*trust
= &trusts
->array
[i
];
1346 struct winbindd_domain d
;
1351 * drop external trusts if this is not our primary
1352 * domain. This means that the returned number of
1353 * domains may be less that the ones actually trusted
1357 if ((trust
->trust_attributes
1358 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN
) &&
1361 DEBUG(10,("trusted_domains: Skipping external trusted "
1362 "domain %s because it is outside of our "
1364 trust
->netbios_name
));
1368 /* add to the trusted domain cache */
1370 fstrcpy(d
.name
, trust
->netbios_name
);
1371 fstrcpy(d
.alt_name
, trust
->dns_name
);
1373 sid_copy(&d
.sid
, trust
->sid
);
1375 sid_copy(&d
.sid
, &global_sid_NULL
);
1378 if ( domain
->primary
) {
1379 DEBUG(10,("trusted_domains(ads): Searching "
1380 "trusted domain list of %s and storing "
1381 "trust flags for domain %s\n",
1382 domain
->name
, d
.alt_name
));
1384 d
.domain_flags
= trust
->trust_flags
;
1385 d
.domain_type
= trust
->trust_type
;
1386 d
.domain_trust_attribs
= trust
->trust_attributes
;
1388 wcache_tdc_add_domain( &d
);
1390 } else if (domain_is_forest_root(domain
)) {
1391 /* Check if we already have this record. If
1392 * we are following our forest root that is not
1393 * our primary domain, we want to keep trust
1394 * flags from the perspective of our primary
1395 * domain not our forest root. */
1396 struct winbindd_tdc_domain
*exist
= NULL
;
1398 exist
= wcache_tdc_fetch_domain(
1399 talloc_tos(), trust
->netbios_name
);
1401 DEBUG(10,("trusted_domains(ads): Searching "
1402 "trusted domain list of %s and "
1403 "storing trust flags for domain "
1404 "%s\n", domain
->name
, d
.alt_name
));
1405 d
.domain_flags
= trust
->trust_flags
;
1406 d
.domain_type
= trust
->trust_type
;
1407 d
.domain_trust_attribs
=
1408 trust
->trust_attributes
;
1410 wcache_tdc_add_domain( &d
);
1415 /* This gets a little tricky. If we are
1416 following a transitive forest trust, then
1417 innerit the flags, type, and attribs from
1418 the domain we queried to make sure we don't
1419 record the view of the trust from the wrong
1420 side. Always view it from the side of our
1421 primary domain. --jerry */
1422 struct winbindd_tdc_domain
*parent
= NULL
;
1424 DEBUG(10,("trusted_domains(ads): Searching "
1425 "trusted domain list of %s and inheriting "
1426 "trust flags for domain %s\n",
1427 domain
->name
, d
.alt_name
));
1429 parent
= wcache_tdc_fetch_domain(talloc_tos(),
1432 d
.domain_flags
= parent
->trust_flags
;
1433 d
.domain_type
= parent
->trust_type
;
1434 d
.domain_trust_attribs
= parent
->trust_attribs
;
1436 d
.domain_flags
= domain
->domain_flags
;
1437 d
.domain_type
= domain
->domain_type
;
1438 d
.domain_trust_attribs
=
1439 domain
->domain_trust_attribs
;
1441 TALLOC_FREE(parent
);
1443 wcache_tdc_add_domain( &d
);
1450 /* the ADS backend methods are exposed via this structure */
1451 struct winbindd_methods ads_methods
= {