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 2 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, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #define DBGC_CLASS DBGC_WINBIND
33 extern struct winbindd_methods reconnect_methods
;
36 return our ads connections structure for a domain. We keep the connection
37 open to make things faster
39 static ADS_STRUCT
*ads_cached_connection(struct winbindd_domain
*domain
)
46 DEBUG(10,("ads_cached_connection\n"));
48 if (domain
->private_data
) {
51 time_t now
= time(NULL
);
53 /* check for a valid structure */
54 ads
= (ADS_STRUCT
*)domain
->private_data
;
56 expire
= MIN(ads
->auth
.tgt_expire
, ads
->auth
.tgs_expire
);
58 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
59 (uint32
)expire
-(uint32
)now
, (uint32
) expire
, (uint32
) now
));
61 if ( ads
->config
.realm
&& (expire
> now
)) {
64 /* we own this ADS_STRUCT so make sure it goes away */
65 DEBUG(7,("Deleting expired krb5 credential cache\n"));
68 ads_kdestroy("MEMORY:winbind_ccache");
69 domain
->private_data
= NULL
;
73 /* we don't want this to affect the users ccache */
74 setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1);
76 ads
= ads_init(domain
->alt_name
, domain
->name
, NULL
);
78 DEBUG(1,("ads_init for domain %s failed\n", domain
->name
));
82 /* the machine acct password might have change - fetch it every time */
84 SAFE_FREE(ads
->auth
.password
);
85 SAFE_FREE(ads
->auth
.realm
);
91 if ( !pdb_get_trusteddom_pw( domain
->name
, &ads
->auth
.password
, &sid
, &last_set_time
) ) {
95 ads
->auth
.realm
= SMB_STRDUP( ads
->server
.realm
);
96 strupper_m( ads
->auth
.realm
);
99 struct winbindd_domain
*our_domain
= domain
;
101 ads
->auth
.password
= secrets_fetch_machine_password(lp_workgroup(), NULL
, NULL
);
103 /* always give preference to the alt_name in our
104 primary domain if possible */
106 if ( !domain
->primary
)
107 our_domain
= find_our_domain();
109 if ( our_domain
->alt_name
[0] != '\0' ) {
110 ads
->auth
.realm
= SMB_STRDUP( our_domain
->alt_name
);
111 strupper_m( ads
->auth
.realm
);
114 ads
->auth
.realm
= SMB_STRDUP( lp_realm() );
117 ads
->auth
.renewable
= WINBINDD_PAM_AUTH_KRB5_RENEW_TIME
;
119 /* Setup the server affinity cache. We don't reaally care
120 about the name. Just setup affinity and the KRB5_CONFIG
123 get_dc_name( ads
->server
.workgroup
, ads
->server
.realm
, dc_name
, &dc_ip
);
125 status
= ads_connect(ads
);
126 if (!ADS_ERR_OK(status
) || !ads
->config
.realm
) {
127 DEBUG(1,("ads_connect for domain %s failed: %s\n",
128 domain
->name
, ads_errstr(status
)));
131 /* if we get ECONNREFUSED then it might be a NT4
132 server, fall back to MSRPC */
133 if (status
.error_type
== ENUM_ADS_ERROR_SYSTEM
&&
134 status
.err
.rc
== ECONNREFUSED
) {
135 /* 'reconnect_methods' is the MS-RPC backend. */
136 DEBUG(1,("Trying MSRPC methods\n"));
137 domain
->backend
= &reconnect_methods
;
142 /* set the flag that says we don't own the memory even
143 though we do so that ads_destroy() won't destroy the
144 structure we pass back by reference */
146 ads
->is_mine
= False
;
148 domain
->private_data
= (void *)ads
;
153 /* Query display info for a realm. This is the basic user list fn */
154 static NTSTATUS
query_user_list(struct winbindd_domain
*domain
,
157 WINBIND_USERINFO
**info
)
159 ADS_STRUCT
*ads
= NULL
;
160 const char *attrs
[] = { "*", NULL
};
163 LDAPMessage
*res
= NULL
;
164 LDAPMessage
*msg
= NULL
;
165 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
169 DEBUG(3,("ads: query_user_list\n"));
171 if ( !winbindd_can_contact_domain( domain
) ) {
172 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
177 ads
= ads_cached_connection(domain
);
180 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
184 rc
= ads_search_retry(ads
, &res
, "(objectCategory=user)", attrs
);
185 if (!ADS_ERR_OK(rc
) || !res
) {
186 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc
)));
190 count
= ads_count_replies(ads
, res
);
192 DEBUG(1,("query_user_list: No users found\n"));
196 (*info
) = TALLOC_ZERO_ARRAY(mem_ctx
, WINBIND_USERINFO
, count
);
198 status
= NT_STATUS_NO_MEMORY
;
204 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
205 char *name
, *gecos
= NULL
;
206 char *homedir
= NULL
;
211 gid_t primary_gid
= (gid_t
)-1;
213 if (!ads_pull_uint32(ads
, msg
, "sAMAccountType", &atype
) ||
214 ads_atype_map(atype
) != SID_NAME_USER
) {
215 DEBUG(1,("Not a user account? atype=0x%x\n", atype
));
219 name
= ads_pull_username(ads
, mem_ctx
, msg
);
221 if ( ads_pull_sid( ads
, msg
, "objectSid", &user_sid
) ) {
222 status
= nss_get_info_cached( domain
, &user_sid
, mem_ctx
,
223 ads
, msg
, &homedir
, &shell
, &gecos
,
228 gecos
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
231 if (!ads_pull_sid(ads
, msg
, "objectSid",
232 &(*info
)[i
].user_sid
)) {
233 DEBUG(1,("No sid for %s !?\n", name
));
236 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group
)) {
237 DEBUG(1,("No primary group for %s !?\n", name
));
241 (*info
)[i
].acct_name
= name
;
242 (*info
)[i
].full_name
= gecos
;
243 (*info
)[i
].homedir
= homedir
;
244 (*info
)[i
].shell
= shell
;
245 (*info
)[i
].primary_gid
= primary_gid
;
246 sid_compose(&(*info
)[i
].group_sid
, &domain
->sid
, group
);
251 status
= NT_STATUS_OK
;
253 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries
)));
257 ads_msgfree(ads
, res
);
262 /* list all domain groups */
263 static NTSTATUS
enum_dom_groups(struct winbindd_domain
*domain
,
266 struct acct_info
**info
)
268 ADS_STRUCT
*ads
= NULL
;
269 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
270 "name", "objectSid", NULL
};
273 LDAPMessage
*res
= NULL
;
274 LDAPMessage
*msg
= NULL
;
275 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
277 BOOL enum_dom_local_groups
= False
;
281 DEBUG(3,("ads: enum_dom_groups\n"));
283 if ( !winbindd_can_contact_domain( domain
) ) {
284 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
289 /* only grab domain local groups for our domain */
290 if ( domain
->active_directory
&& strequal(lp_realm(), domain
->alt_name
) ) {
291 enum_dom_local_groups
= True
;
294 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
297 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
298 * default value, it MUST be absent. In case of extensible matching the
299 * "dnattr" boolean defaults to FALSE and so it must be only be present
302 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
303 * filter using bitwise matching rule then the buggy AD fails to decode
304 * the extensible match. As a workaround set it to TRUE and thereby add
305 * the dnAttributes "dn" field to cope with those older AD versions.
306 * It should not harm and won't put any additional load on the AD since
307 * none of the dn components have a bitmask-attribute.
309 * Thanks to Ralf Haferkamp for input and testing - Guenther */
311 filter
= talloc_asprintf(mem_ctx
, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
312 ADS_LDAP_MATCHING_RULE_BIT_AND
, GROUP_TYPE_SECURITY_ENABLED
,
313 ADS_LDAP_MATCHING_RULE_BIT_AND
,
314 enum_dom_local_groups
? GROUP_TYPE_BUILTIN_LOCAL_GROUP
: GROUP_TYPE_RESOURCE_GROUP
);
316 if (filter
== NULL
) {
317 status
= NT_STATUS_NO_MEMORY
;
321 ads
= ads_cached_connection(domain
);
324 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
328 rc
= ads_search_retry(ads
, &res
, filter
, attrs
);
329 if (!ADS_ERR_OK(rc
) || !res
) {
330 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc
)));
334 count
= ads_count_replies(ads
, res
);
336 DEBUG(1,("enum_dom_groups: No groups found\n"));
340 (*info
) = TALLOC_ZERO_ARRAY(mem_ctx
, struct acct_info
, count
);
342 status
= NT_STATUS_NO_MEMORY
;
348 for (msg
= ads_first_entry(ads
, res
); msg
; msg
= ads_next_entry(ads
, msg
)) {
353 name
= ads_pull_username(ads
, mem_ctx
, msg
);
354 gecos
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
355 if (!ads_pull_sid(ads
, msg
, "objectSid", &sid
)) {
356 DEBUG(1,("No sid for %s !?\n", name
));
360 if (!sid_peek_check_rid(&domain
->sid
, &sid
, &rid
)) {
361 DEBUG(1,("No rid for %s !?\n", name
));
365 fstrcpy((*info
)[i
].acct_name
, name
);
366 fstrcpy((*info
)[i
].acct_desc
, gecos
);
367 (*info
)[i
].rid
= rid
;
373 status
= NT_STATUS_OK
;
375 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries
)));
379 ads_msgfree(ads
, res
);
384 /* list all domain local groups */
385 static NTSTATUS
enum_local_groups(struct winbindd_domain
*domain
,
388 struct acct_info
**info
)
391 * This is a stub function only as we returned the domain
392 * local groups in enum_dom_groups() if the domain->native field
393 * was true. This is a simple performance optimization when
396 * if we ever need to enumerate domain local groups separately,
397 * then this the optimization in enum_dom_groups() will need
405 /* convert a DN to a name, SID and name type
406 this might become a major speed bottleneck if groups have
407 lots of users, in which case we could cache the results
409 static BOOL
dn_lookup(ADS_STRUCT
*ads
, TALLOC_CTX
*mem_ctx
,
411 char **name
, uint32
*name_type
, DOM_SID
*sid
)
413 LDAPMessage
*res
= NULL
;
414 const char *attrs
[] = {"userPrincipalName", "sAMAccountName",
415 "objectSid", "sAMAccountType", NULL
};
418 DEBUG(3,("ads: dn_lookup\n"));
420 rc
= ads_search_retry_dn(ads
, &res
, dn
, attrs
);
422 if (!ADS_ERR_OK(rc
) || !res
) {
426 (*name
) = ads_pull_username(ads
, mem_ctx
, res
);
428 if (!ads_pull_uint32(ads
, res
, "sAMAccountType", &atype
)) {
431 (*name_type
) = ads_atype_map(atype
);
433 if (!ads_pull_sid(ads
, res
, "objectSid", sid
)) {
438 ads_msgfree(ads
, res
);
444 ads_msgfree(ads
, res
);
449 /* Lookup user information from a rid */
450 static NTSTATUS
query_user(struct winbindd_domain
*domain
,
453 WINBIND_USERINFO
*info
)
455 ADS_STRUCT
*ads
= NULL
;
456 const char *attrs
[] = { "*", NULL
};
459 LDAPMessage
*msg
= NULL
;
463 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
464 NET_USER_INFO_3
*user
;
466 DEBUG(3,("ads: query_user\n"));
468 info
->homedir
= NULL
;
470 info
->primary_gid
= (gid_t
)-1;
472 /* try netsamlogon cache first */
474 if ( (user
= netsamlogon_cache_get( mem_ctx
, sid
)) != NULL
)
477 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
478 sid_string_static(sid
)));
480 sid_compose(&info
->user_sid
, &domain
->sid
, user
->user_rid
);
481 sid_compose(&info
->group_sid
, &domain
->sid
, user
->group_rid
);
483 info
->acct_name
= unistr2_tdup(mem_ctx
, &user
->uni_user_name
);
484 info
->full_name
= unistr2_tdup(mem_ctx
, &user
->uni_full_name
);
486 nss_get_info_cached( domain
, sid
, mem_ctx
, NULL
, NULL
,
487 &info
->homedir
, &info
->shell
, &info
->full_name
,
488 &info
->primary_gid
);
495 if ( !winbindd_can_contact_domain(domain
)) {
496 DEBUG(8,("query_user: No incoming trust from domain %s\n",
499 /* We still need to generate some basic information
500 about the user even if we cannot contact the
501 domain. Most of this stuff we can deduce. */
503 sid_copy( &info
->user_sid
, sid
);
505 /* Assume "Domain Users" for the primary group */
507 sid_compose(&info
->group_sid
, &domain
->sid
, DOMAIN_GROUP_RID_USERS
);
509 /* Try to fill in what the nss_info backend can do */
511 nss_get_info_cached( domain
, sid
, mem_ctx
, NULL
, NULL
,
512 &info
->homedir
, &info
->shell
, &info
->full_name
,
513 &info
->primary_gid
);
515 status
= NT_STATUS_OK
;
519 /* no cache...do the query */
521 if ( (ads
= ads_cached_connection(domain
)) == NULL
) {
522 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
526 sidstr
= sid_binstring(sid
);
527 asprintf(&ldap_exp
, "(objectSid=%s)", sidstr
);
528 rc
= ads_search_retry(ads
, &msg
, ldap_exp
, attrs
);
531 if (!ADS_ERR_OK(rc
) || !msg
) {
532 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
533 sid_string_static(sid
), ads_errstr(rc
)));
537 count
= ads_count_replies(ads
, msg
);
539 DEBUG(1,("query_user(sid=%s): Not found\n",
540 sid_string_static(sid
)));
544 info
->acct_name
= ads_pull_username(ads
, mem_ctx
, msg
);
546 nss_get_info_cached( domain
, sid
, mem_ctx
, ads
, msg
,
547 &info
->homedir
, &info
->shell
, &info
->full_name
,
548 &info
->primary_gid
);
550 if (info
->full_name
== NULL
) {
551 info
->full_name
= ads_pull_string(ads
, mem_ctx
, msg
, "name");
554 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &group_rid
)) {
555 DEBUG(1,("No primary group for %s !?\n",
556 sid_string_static(sid
)));
560 sid_copy(&info
->user_sid
, sid
);
561 sid_compose(&info
->group_sid
, &domain
->sid
, group_rid
);
563 status
= NT_STATUS_OK
;
565 DEBUG(3,("ads query_user gave %s\n", info
->acct_name
));
568 ads_msgfree(ads
, msg
);
573 /* Lookup groups a user is a member of - alternate method, for when
574 tokenGroups are not available. */
575 static NTSTATUS
lookup_usergroups_member(struct winbindd_domain
*domain
,
578 DOM_SID
*primary_group
,
579 size_t *p_num_groups
, DOM_SID
**user_sids
)
582 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
584 LDAPMessage
*res
= NULL
;
585 LDAPMessage
*msg
= NULL
;
588 const char *group_attrs
[] = {"objectSid", NULL
};
590 size_t num_groups
= 0;
592 DEBUG(3,("ads: lookup_usergroups_member\n"));
594 if ( !winbindd_can_contact_domain( domain
) ) {
595 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
600 ads
= ads_cached_connection(domain
);
603 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
607 if (!(escaped_dn
= escape_ldap_string_alloc(user_dn
))) {
608 status
= NT_STATUS_NO_MEMORY
;
612 if (!(ldap_exp
= talloc_asprintf(mem_ctx
, "(&(member=%s)(objectCategory=group))", escaped_dn
))) {
613 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn
));
614 SAFE_FREE(escaped_dn
);
615 status
= NT_STATUS_NO_MEMORY
;
619 SAFE_FREE(escaped_dn
);
621 rc
= ads_search_retry(ads
, &res
, ldap_exp
, group_attrs
);
623 if (!ADS_ERR_OK(rc
) || !res
) {
624 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn
, ads_errstr(rc
)));
625 return ads_ntstatus(rc
);
628 count
= ads_count_replies(ads
, res
);
633 /* always add the primary group to the sid array */
634 if (!add_sid_to_array(mem_ctx
, primary_group
, user_sids
, &num_groups
)) {
635 status
= NT_STATUS_NO_MEMORY
;
640 for (msg
= ads_first_entry(ads
, res
); msg
;
641 msg
= ads_next_entry(ads
, msg
)) {
644 if (!ads_pull_sid(ads
, msg
, "objectSid", &group_sid
)) {
645 DEBUG(1,("No sid for this group ?!?\n"));
649 /* ignore Builtin groups from ADS - Guenther */
650 if (sid_check_is_in_builtin(&group_sid
)) {
654 if (!add_sid_to_array(mem_ctx
, &group_sid
, user_sids
,
656 status
= NT_STATUS_NO_MEMORY
;
663 *p_num_groups
= num_groups
;
664 status
= (user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
666 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn
));
669 ads_msgfree(ads
, res
);
674 /* Lookup groups a user is a member of - alternate method, for when
675 tokenGroups are not available. */
676 static NTSTATUS
lookup_usergroups_memberof(struct winbindd_domain
*domain
,
679 DOM_SID
*primary_group
,
680 size_t *p_num_groups
, DOM_SID
**user_sids
)
683 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
685 const char *attrs
[] = {"memberOf", NULL
};
686 size_t num_groups
= 0;
687 DOM_SID
*group_sids
= NULL
;
690 size_t num_strings
= 0;
693 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
695 if ( !winbindd_can_contact_domain( domain
) ) {
696 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for domain %s\n",
701 ads
= ads_cached_connection(domain
);
704 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
708 rc
= ads_search_retry_extended_dn_ranged(ads
, mem_ctx
, user_dn
, attrs
,
709 ADS_EXTENDED_DN_HEX_STRING
,
710 &strings
, &num_strings
);
712 if (!ADS_ERR_OK(rc
)) {
713 DEBUG(1,("lookup_usergroups_memberof ads_search member=%s: %s\n",
714 user_dn
, ads_errstr(rc
)));
715 return ads_ntstatus(rc
);
721 /* always add the primary group to the sid array */
722 if (!add_sid_to_array(mem_ctx
, primary_group
, user_sids
, &num_groups
)) {
723 status
= NT_STATUS_NO_MEMORY
;
727 group_sids
= TALLOC_ZERO_ARRAY(mem_ctx
, DOM_SID
, num_strings
+ 1);
729 TALLOC_FREE(strings
);
730 status
= NT_STATUS_NO_MEMORY
;
734 for (i
=0; i
<num_strings
; i
++) {
736 if (!ads_get_sid_from_extended_dn(mem_ctx
, strings
[i
],
737 ADS_EXTENDED_DN_HEX_STRING
,
739 TALLOC_FREE(group_sids
);
740 TALLOC_FREE(strings
);
741 status
= NT_STATUS_NO_MEMORY
;
747 DEBUG(1,("No memberOf for this user?!?\n"));
748 status
= NT_STATUS_NO_MEMORY
;
752 for (i
=0; i
<num_strings
; i
++) {
754 /* ignore Builtin groups from ADS - Guenther */
755 if (sid_check_is_in_builtin(&group_sids
[i
])) {
759 if (!add_sid_to_array(mem_ctx
, &group_sids
[i
], user_sids
,
761 status
= NT_STATUS_NO_MEMORY
;
767 *p_num_groups
= num_groups
;
768 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
770 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n", user_dn
));
772 TALLOC_FREE(group_sids
);
778 /* Lookup groups a user is a member of. */
779 static NTSTATUS
lookup_usergroups(struct winbindd_domain
*domain
,
782 uint32
*p_num_groups
, DOM_SID
**user_sids
)
784 ADS_STRUCT
*ads
= NULL
;
785 const char *attrs
[] = {"tokenGroups", "primaryGroupID", NULL
};
788 LDAPMessage
*msg
= NULL
;
789 char *user_dn
= NULL
;
792 DOM_SID primary_group
;
793 uint32 primary_group_rid
;
795 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
796 size_t num_groups
= 0;
798 DEBUG(3,("ads: lookup_usergroups\n"));
801 status
= lookup_usergroups_cached(domain
, mem_ctx
, sid
,
802 p_num_groups
, user_sids
);
803 if (NT_STATUS_IS_OK(status
)) {
807 if ( !winbindd_can_contact_domain( domain
) ) {
808 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
811 /* Tell the cache manager not to remember this one */
813 return NT_STATUS_SYNCHRONIZATION_REQUIRED
;
816 ads
= ads_cached_connection(domain
);
819 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
820 status
= NT_STATUS_SERVER_DISABLED
;
824 rc
= ads_search_retry_sid(ads
, &msg
, sid
, attrs
);
826 if (!ADS_ERR_OK(rc
)) {
827 status
= ads_ntstatus(rc
);
828 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: %s\n",
829 sid_to_string(sid_string
, sid
), ads_errstr(rc
)));
833 count
= ads_count_replies(ads
, msg
);
835 status
= NT_STATUS_UNSUCCESSFUL
;
836 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
837 "invalid number of results (count=%d)\n",
838 sid_to_string(sid_string
, sid
), count
));
843 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
844 sid_to_string(sid_string
, sid
)));
845 status
= NT_STATUS_UNSUCCESSFUL
;
849 user_dn
= ads_get_dn(ads
, msg
);
850 if (user_dn
== NULL
) {
851 status
= NT_STATUS_NO_MEMORY
;
855 if (!ads_pull_uint32(ads
, msg
, "primaryGroupID", &primary_group_rid
)) {
856 DEBUG(1,("%s: No primary group for sid=%s !?\n",
857 domain
->name
, sid_to_string(sid_string
, sid
)));
861 sid_copy(&primary_group
, &domain
->sid
);
862 sid_append_rid(&primary_group
, primary_group_rid
);
864 count
= ads_pull_sids(ads
, mem_ctx
, msg
, "tokenGroups", &sids
);
866 /* there must always be at least one group in the token,
867 unless we are talking to a buggy Win2k server */
869 /* actually this only happens when the machine account has no read
870 * permissions on the tokenGroup attribute - gd */
876 /* lookup what groups this user is a member of by DN search on
879 status
= lookup_usergroups_memberof(domain
, mem_ctx
, user_dn
,
881 &num_groups
, user_sids
);
882 *p_num_groups
= (uint32
)num_groups
;
883 if (NT_STATUS_IS_OK(status
)) {
887 /* lookup what groups this user is a member of by DN search on
890 status
= lookup_usergroups_member(domain
, mem_ctx
, user_dn
,
892 &num_groups
, user_sids
);
893 *p_num_groups
= (uint32
)num_groups
;
900 if (!add_sid_to_array(mem_ctx
, &primary_group
, user_sids
, &num_groups
)) {
901 status
= NT_STATUS_NO_MEMORY
;
905 for (i
=0;i
<count
;i
++) {
907 /* ignore Builtin groups from ADS - Guenther */
908 if (sid_check_is_in_builtin(&sids
[i
])) {
912 if (!add_sid_to_array_unique(mem_ctx
, &sids
[i
],
913 user_sids
, &num_groups
)) {
914 status
= NT_STATUS_NO_MEMORY
;
919 *p_num_groups
= (uint32
)num_groups
;
920 status
= (*user_sids
!= NULL
) ? NT_STATUS_OK
: NT_STATUS_NO_MEMORY
;
922 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
923 sid_to_string(sid_string
, sid
)));
925 ads_memfree(ads
, user_dn
);
926 ads_msgfree(ads
, msg
);
931 find the members of a group, given a group rid and domain
933 static NTSTATUS
lookup_groupmem(struct winbindd_domain
*domain
,
935 const DOM_SID
*group_sid
, uint32
*num_names
,
936 DOM_SID
**sid_mem
, char ***names
,
940 LDAPMessage
*res
=NULL
;
941 ADS_STRUCT
*ads
= NULL
;
943 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
951 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain
->name
,
952 sid_string_static(group_sid
)));
956 if ( !winbindd_can_contact_domain( domain
) ) {
957 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
962 ads
= ads_cached_connection(domain
);
965 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
969 if ((sidstr
= sid_binstring(group_sid
)) == NULL
) {
970 status
= NT_STATUS_NO_MEMORY
;
974 /* search for all members of the group */
975 if (!(ldap_exp
= talloc_asprintf(mem_ctx
, "(objectSid=%s)",sidstr
))) {
977 DEBUG(1, ("ads: lookup_groupmem: tallloc_asprintf for ldap_exp failed!\n"));
978 status
= NT_STATUS_NO_MEMORY
;
986 args
.control
= ADS_EXTENDED_DN_OID
;
987 args
.val
= ADS_EXTENDED_DN_HEX_STRING
;
988 args
.critical
= True
;
990 rc
= ads_ranged_search(ads
, mem_ctx
, LDAP_SCOPE_SUBTREE
, ads
->config
.bind_path
,
991 ldap_exp
, &args
, "member", &members
, &num_members
);
993 if (!ADS_ERR_OK(rc
)) {
994 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc
)));
995 status
= NT_STATUS_UNSUCCESSFUL
;
999 /* now we need to turn a list of members into rids, names and name types
1000 the problem is that the members are in the form of distinguised names
1004 (*sid_mem
) = TALLOC_ZERO_ARRAY(mem_ctx
, DOM_SID
, num_members
);
1005 (*name_types
) = TALLOC_ZERO_ARRAY(mem_ctx
, uint32
, num_members
);
1006 (*names
) = TALLOC_ZERO_ARRAY(mem_ctx
, char *, num_members
);
1008 if ((members
== NULL
) || (*sid_mem
== NULL
) ||
1009 (*name_types
== NULL
) || (*names
== NULL
)) {
1010 DEBUG(1, ("talloc failed\n"));
1011 status
= NT_STATUS_NO_MEMORY
;
1016 (*name_types
) = NULL
;
1020 for (i
=0;i
<num_members
;i
++) {
1022 char *name
, *domain_name
, *dn
;
1025 if ((!ads_get_sid_from_extended_dn(mem_ctx
, members
[i
], ADS_EXTENDED_DN_HEX_STRING
, &sid
)) ||
1026 (!ads_get_dn_from_extended_dn(mem_ctx
, members
[i
], &dn
)))
1028 status
= NT_STATUS_INVALID_PARAMETER
;
1032 if (lookup_cached_sid(mem_ctx
, &sid
, &domain_name
, &name
, &name_type
)) {
1034 DEBUG(10,("ads: lookup_groupmem: got sid %s from cache\n",
1035 sid_string_static(&sid
)));
1037 (*names
)[*num_names
] = CONST_DISCARD(char *,name
);
1038 (*name_types
)[*num_names
] = name_type
;
1039 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1046 if (dn_lookup(ads
, mem_ctx
, dn
, &name
, &name_type
, &sid
)) {
1048 DEBUG(10,("ads: lookup_groupmem: got sid %s from dn_lookup\n",
1049 sid_string_static(&sid
)));
1051 (*names
)[*num_names
] = name
;
1052 (*name_types
)[*num_names
] = name_type
;
1053 sid_copy(&(*sid_mem
)[*num_names
], &sid
);
1060 status
= NT_STATUS_OK
;
1061 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n", sid_to_string(sid_string
, group_sid
)));
1065 ads_msgfree(ads
, res
);
1070 /* find the sequence number for a domain */
1071 static NTSTATUS
sequence_number(struct winbindd_domain
*domain
, uint32
*seq
)
1073 ADS_STRUCT
*ads
= NULL
;
1076 DEBUG(3,("ads: fetch sequence_number for %s\n", domain
->name
));
1078 if ( !winbindd_can_contact_domain( domain
) ) {
1079 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1082 return NT_STATUS_OK
;
1085 *seq
= DOM_SEQUENCE_NONE
;
1087 ads
= ads_cached_connection(domain
);
1090 domain
->last_status
= NT_STATUS_SERVER_DISABLED
;
1091 return NT_STATUS_UNSUCCESSFUL
;
1094 rc
= ads_USN(ads
, seq
);
1096 if (!ADS_ERR_OK(rc
)) {
1098 /* its a dead connection, destroy it */
1100 if (domain
->private_data
) {
1101 ads
= (ADS_STRUCT
*)domain
->private_data
;
1102 ads
->is_mine
= True
;
1104 ads_kdestroy("MEMORY:winbind_ccache");
1105 domain
->private_data
= NULL
;
1108 return ads_ntstatus(rc
);
1111 /* get a list of trusted domains */
1112 static NTSTATUS
trusted_domains(struct winbindd_domain
*domain
,
1113 TALLOC_CTX
*mem_ctx
,
1114 uint32
*num_domains
,
1119 NTSTATUS result
= NT_STATUS_UNSUCCESSFUL
;
1120 struct ds_domain_trust
*domains
= NULL
;
1124 struct rpc_pipe_client
*cli
;
1125 uint32 fr_flags
= (DS_DOMAIN_IN_FOREST
| DS_DOMAIN_TREE_ROOT
);
1128 DEBUG(3,("ads: trusted_domains\n"));
1135 /* If this is our primary domain or a root in our forest,
1136 query for all trusts. If not, then just look for domain
1137 trusts in the target forest */
1139 if ( domain
->primary
||
1140 ((domain
->domain_flags
&fr_flags
) == fr_flags
) )
1142 flags
= DS_DOMAIN_DIRECT_OUTBOUND
|
1143 DS_DOMAIN_DIRECT_INBOUND
|
1144 DS_DOMAIN_IN_FOREST
;
1146 flags
= DS_DOMAIN_IN_FOREST
;
1149 result
= cm_connect_netlogon(domain
, &cli
);
1151 if (!NT_STATUS_IS_OK(result
)) {
1152 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1153 "for PIPE_NETLOGON (%s)\n",
1154 domain
->name
, nt_errstr(result
)));
1155 return NT_STATUS_UNSUCCESSFUL
;
1158 if ( NT_STATUS_IS_OK(result
) ) {
1159 result
= rpccli_ds_enum_domain_trusts(cli
, mem_ctx
,
1162 (unsigned int *)&count
);
1165 if ( NT_STATUS_IS_OK(result
) && count
) {
1167 /* Allocate memory for trusted domain names and sids */
1169 if ( !(*names
= TALLOC_ARRAY(mem_ctx
, char *, count
)) ) {
1170 DEBUG(0, ("trusted_domains: out of memory\n"));
1171 return NT_STATUS_NO_MEMORY
;
1174 if ( !(*alt_names
= TALLOC_ARRAY(mem_ctx
, char *, count
)) ) {
1175 DEBUG(0, ("trusted_domains: out of memory\n"));
1176 return NT_STATUS_NO_MEMORY
;
1179 if ( !(*dom_sids
= TALLOC_ARRAY(mem_ctx
, DOM_SID
, count
)) ) {
1180 DEBUG(0, ("trusted_domains: out of memory\n"));
1181 return NT_STATUS_NO_MEMORY
;
1184 /* Copy across names and sids */
1188 for (i
= 0; i
< count
; i
++) {
1189 struct winbindd_domain d
;
1191 /* drop external trusts if this is not our primary
1192 domain. This means that the returned number of
1193 domains may be less that the ones actually trusted
1196 if ( (domains
[i
].trust_attributes
== DS_DOMAIN_TRUST_ATTRIB_QUARANTINED_DOMAIN
) &&
1199 DEBUG(10,("trusted_domains: Skipping external trusted domain "
1200 "%s because it is outside of our primary domain\n",
1201 domains
[i
].netbios_domain
));
1205 (*names
)[ret_count
] = domains
[i
].netbios_domain
;
1206 (*alt_names
)[ret_count
] = domains
[i
].dns_domain
;
1207 sid_copy(&(*dom_sids
)[ret_count
], &domains
[i
].sid
);
1209 /* add to the trusted domain cache */
1211 fstrcpy( d
.name
, domains
[i
].netbios_domain
);
1212 fstrcpy( d
.alt_name
, domains
[i
].dns_domain
);
1213 sid_copy( &d
.sid
, &domains
[i
].sid
);
1215 /* This gets a little tricky. If we are
1216 following a transitive forest trust, then
1217 innerit the flags, type, and attrins from
1218 the domain we queried to make sure we don't
1219 record the view of the trust from the wrong
1220 side. Always view it from the side of our
1221 primary domain. --jerry */
1222 if ( domain
->primary
||
1223 ((domain
->domain_flags
&fr_flags
) == fr_flags
) )
1225 DEBUG(10,("trusted_domains(ads): Storing trust "
1226 "flags for domain %s\n", d
.alt_name
));
1228 /* Look this up in cache to make sure
1229 we have the current trust flags and
1232 d
.domain_flags
= domains
[i
].flags
;
1233 d
.domain_type
= domains
[i
].trust_type
;
1234 d
.domain_trust_attribs
= domains
[i
].trust_attributes
;
1236 DEBUG(10,("trusted_domains(ads): Inheriting trust "
1237 "flags for domain %s\n", d
.alt_name
));
1238 d
.domain_flags
= domain
->domain_flags
;
1239 d
.domain_type
= domain
->domain_type
;
1240 d
.domain_trust_attribs
= domain
->domain_trust_attribs
;
1243 wcache_tdc_add_domain( &d
);
1249 *num_domains
= ret_count
;
1255 /* the ADS backend methods are exposed via this structure */
1256 struct winbindd_methods ads_methods
= {
1263 msrpc_rids_to_names
,
1266 msrpc_lookup_useraliases
,
1269 msrpc_lockout_policy
,
1270 msrpc_password_policy
,