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/cli_netlogon.h"
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)
44 struct sockaddr_storage dc_ss;
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);
89 if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, NULL, NULL ) ) {
93 ads->auth.realm = SMB_STRDUP( ads->server.realm );
94 strupper_m( ads->auth.realm );
97 struct winbindd_domain *our_domain = domain;
99 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
101 /* always give preference to the alt_name in our
102 primary domain if possible */
104 if ( !domain->primary )
105 our_domain = find_our_domain();
107 if ( our_domain->alt_name[0] != '\0' ) {
108 ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
109 strupper_m( ads->auth.realm );
112 ads->auth.realm = SMB_STRDUP( lp_realm() );
115 ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
117 /* Setup the server affinity cache. We don't reaally care
118 about the name. Just setup affinity and the KRB5_CONFIG
121 get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ss );
123 status = ads_connect(ads);
124 if (!ADS_ERR_OK(status) || !ads->config.realm) {
125 DEBUG(1,("ads_connect for domain %s failed: %s\n",
126 domain->name, ads_errstr(status)));
129 /* if we get ECONNREFUSED then it might be a NT4
130 server, fall back to MSRPC */
131 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
132 status.err.rc == ECONNREFUSED) {
133 /* 'reconnect_methods' is the MS-RPC backend. */
134 DEBUG(1,("Trying MSRPC methods\n"));
135 domain->backend = &reconnect_methods;
140 /* set the flag that says we don't own the memory even
141 though we do so that ads_destroy() won't destroy the
142 structure we pass back by reference */
144 ads->is_mine = False;
146 domain->private_data = (void *)ads;
151 /* Query display info for a realm. This is the basic user list fn */
152 static NTSTATUS query_user_list(struct winbindd_domain *domain,
155 struct wbint_userinfo **info)
157 ADS_STRUCT *ads = NULL;
158 const char *attrs[] = { "*", NULL };
161 LDAPMessage *res = NULL;
162 LDAPMessage *msg = NULL;
163 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
167 DEBUG(3,("ads: query_user_list\n"));
169 if ( !winbindd_can_contact_domain( domain ) ) {
170 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
175 ads = ads_cached_connection(domain);
178 domain->last_status = NT_STATUS_SERVER_DISABLED;
182 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
183 if (!ADS_ERR_OK(rc)) {
184 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
185 status = ads_ntstatus(rc);
187 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
192 count = ads_count_replies(ads, res);
194 DEBUG(1,("query_user_list: No users found\n"));
198 (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct wbint_userinfo, count);
200 status = NT_STATUS_NO_MEMORY;
206 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
208 const char *gecos = NULL;
209 const char *homedir = NULL;
210 const char *shell = NULL;
214 gid_t primary_gid = (gid_t)-1;
216 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
217 ds_atype_map(atype) != SID_NAME_USER) {
218 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
222 name = ads_pull_username(ads, mem_ctx, msg);
224 if ( ads_pull_sid( ads, msg, "objectSid", &user_sid ) ) {
225 status = nss_get_info_cached( domain, &user_sid, mem_ctx,
226 ads, msg, &homedir, &shell, &gecos,
231 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
234 if (!ads_pull_sid(ads, msg, "objectSid",
235 &(*info)[i].user_sid)) {
236 DEBUG(1,("No sid for %s !?\n", name));
239 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
240 DEBUG(1,("No primary group for %s !?\n", name));
244 (*info)[i].acct_name = name;
245 (*info)[i].full_name = gecos;
246 (*info)[i].homedir = homedir;
247 (*info)[i].shell = shell;
248 (*info)[i].primary_gid = primary_gid;
249 sid_compose(&(*info)[i].group_sid, &domain->sid, group);
254 status = NT_STATUS_OK;
256 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
260 ads_msgfree(ads, res);
265 /* list all domain groups */
266 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
269 struct acct_info **info)
271 ADS_STRUCT *ads = NULL;
272 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
273 "name", "objectSid", NULL};
276 LDAPMessage *res = NULL;
277 LDAPMessage *msg = NULL;
278 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
280 bool enum_dom_local_groups = False;
284 DEBUG(3,("ads: enum_dom_groups\n"));
286 if ( !winbindd_can_contact_domain( domain ) ) {
287 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
292 /* only grab domain local groups for our domain */
293 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
294 enum_dom_local_groups = True;
297 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
300 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
301 * default value, it MUST be absent. In case of extensible matching the
302 * "dnattr" boolean defaults to FALSE and so it must be only be present
305 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
306 * filter using bitwise matching rule then the buggy AD fails to decode
307 * the extensible match. As a workaround set it to TRUE and thereby add
308 * the dnAttributes "dn" field to cope with those older AD versions.
309 * It should not harm and won't put any additional load on the AD since
310 * none of the dn components have a bitmask-attribute.
312 * Thanks to Ralf Haferkamp for input and testing - Guenther */
314 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
315 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
316 ADS_LDAP_MATCHING_RULE_BIT_AND,
317 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
319 if (filter == NULL) {
320 status = NT_STATUS_NO_MEMORY;
324 ads = ads_cached_connection(domain);
327 domain->last_status = NT_STATUS_SERVER_DISABLED;
331 rc = ads_search_retry(ads, &res, filter, attrs);
332 if (!ADS_ERR_OK(rc)) {
333 status = ads_ntstatus(rc);
334 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
337 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
341 count = ads_count_replies(ads, res);
343 DEBUG(1,("enum_dom_groups: No groups found\n"));
347 (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct acct_info, count);
349 status = NT_STATUS_NO_MEMORY;
355 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
360 name = ads_pull_username(ads, mem_ctx, msg);
361 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
362 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
363 DEBUG(1,("No sid for %s !?\n", name));
367 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
368 DEBUG(1,("No rid for %s !?\n", name));
372 fstrcpy((*info)[i].acct_name, name);
373 fstrcpy((*info)[i].acct_desc, gecos);
374 (*info)[i].rid = rid;
380 status = NT_STATUS_OK;
382 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
386 ads_msgfree(ads, res);
391 /* list all domain local groups */
392 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
395 struct acct_info **info)
398 * This is a stub function only as we returned the domain
399 * local groups in enum_dom_groups() if the domain->native field
400 * was true. This is a simple performance optimization when
403 * if we ever need to enumerate domain local groups separately,
404 * then this optimization in enum_dom_groups() will need
412 /* convert a single name to a sid in a domain - use rpc methods */
413 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
415 const char *domain_name,
419 enum lsa_SidType *type)
421 return reconnect_methods.name_to_sid(domain, mem_ctx,
422 domain_name, name, flags,
426 /* convert a domain SID to a user or group name - use rpc methods */
427 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
432 enum lsa_SidType *type)
434 return reconnect_methods.sid_to_name(domain, mem_ctx, sid,
435 domain_name, name, type);
438 /* convert a list of rids to names - use rpc methods */
439 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
446 enum lsa_SidType **types)
448 return reconnect_methods.rids_to_names(domain, mem_ctx, sid,
450 domain_name, names, types);
453 /* If you are looking for "dn_lookup": Yes, it used to be here!
454 * It has gone now since it was a major speed bottleneck in
455 * lookup_groupmem (its only use). It has been replaced by
456 * an rpc lookup sids call... R.I.P. */
458 /* Lookup user information from a rid */
459 static NTSTATUS query_user(struct winbindd_domain *domain,
462 struct wbint_userinfo *info)
464 ADS_STRUCT *ads = NULL;
465 const char *attrs[] = { "*", NULL };
468 LDAPMessage *msg = NULL;
472 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
473 struct netr_SamInfo3 *user = NULL;
476 DEBUG(3,("ads: query_user\n"));
478 info->homedir = NULL;
480 info->primary_gid = (gid_t)-1;
482 /* try netsamlogon cache first */
484 if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
486 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
487 sid_string_dbg(sid)));
489 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
490 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
492 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
493 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
495 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL,
496 &info->homedir, &info->shell, &info->full_name,
498 info->primary_gid = gid;
505 if ( !winbindd_can_contact_domain(domain)) {
506 DEBUG(8,("query_user: No incoming trust from domain %s\n",
509 /* We still need to generate some basic information
510 about the user even if we cannot contact the
511 domain. Most of this stuff we can deduce. */
513 sid_copy( &info->user_sid, sid );
515 /* Assume "Domain Users" for the primary group */
517 sid_compose(&info->group_sid, &domain->sid, DOMAIN_GROUP_RID_USERS );
519 /* Try to fill in what the nss_info backend can do */
521 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL,
522 &info->homedir, &info->shell, &info->full_name,
524 info->primary_gid = gid;
526 status = NT_STATUS_OK;
530 /* no cache...do the query */
532 if ( (ads = ads_cached_connection(domain)) == NULL ) {
533 domain->last_status = NT_STATUS_SERVER_DISABLED;
537 sidstr = sid_binstring(talloc_tos(), sid);
538 if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) {
539 status = NT_STATUS_NO_MEMORY;
542 rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
545 if (!ADS_ERR_OK(rc)) {
546 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
547 sid_string_dbg(sid), ads_errstr(rc)));
548 return ads_ntstatus(rc);
550 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
551 sid_string_dbg(sid)));
552 return NT_STATUS_INTERNAL_ERROR;
555 count = ads_count_replies(ads, msg);
557 DEBUG(1,("query_user(sid=%s): Not found\n",
558 sid_string_dbg(sid)));
562 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
564 nss_get_info_cached( domain, sid, mem_ctx, ads, msg,
565 &info->homedir, &info->shell, &info->full_name,
567 info->primary_gid = gid;
569 if (info->full_name == NULL) {
570 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
573 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
574 DEBUG(1,("No primary group for %s !?\n",
575 sid_string_dbg(sid)));
579 sid_copy(&info->user_sid, sid);
580 sid_compose(&info->group_sid, &domain->sid, group_rid);
582 status = NT_STATUS_OK;
584 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
587 ads_msgfree(ads, msg);
592 /* Lookup groups a user is a member of - alternate method, for when
593 tokenGroups are not available. */
594 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
597 DOM_SID *primary_group,
598 size_t *p_num_groups, DOM_SID **user_sids)
601 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
603 LDAPMessage *res = NULL;
604 LDAPMessage *msg = NULL;
607 const char *group_attrs[] = {"objectSid", NULL};
609 size_t num_groups = 0;
611 DEBUG(3,("ads: lookup_usergroups_member\n"));
613 if ( !winbindd_can_contact_domain( domain ) ) {
614 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
619 ads = ads_cached_connection(domain);
622 domain->last_status = NT_STATUS_SERVER_DISABLED;
626 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
627 status = NT_STATUS_NO_MEMORY;
631 ldap_exp = talloc_asprintf(mem_ctx,
632 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
634 ADS_LDAP_MATCHING_RULE_BIT_AND,
635 GROUP_TYPE_SECURITY_ENABLED);
637 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
638 TALLOC_FREE(escaped_dn);
639 status = NT_STATUS_NO_MEMORY;
643 TALLOC_FREE(escaped_dn);
645 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
647 if (!ADS_ERR_OK(rc)) {
648 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
649 return ads_ntstatus(rc);
651 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
652 return NT_STATUS_INTERNAL_ERROR;
656 count = ads_count_replies(ads, res);
661 /* always add the primary group to the sid array */
662 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
664 if (!NT_STATUS_IS_OK(status)) {
669 for (msg = ads_first_entry(ads, res); msg;
670 msg = ads_next_entry(ads, msg)) {
673 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
674 DEBUG(1,("No sid for this group ?!?\n"));
678 /* ignore Builtin groups from ADS - Guenther */
679 if (sid_check_is_in_builtin(&group_sid)) {
683 status = add_sid_to_array(mem_ctx, &group_sid,
684 user_sids, &num_groups);
685 if (!NT_STATUS_IS_OK(status)) {
692 *p_num_groups = num_groups;
693 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
695 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
698 ads_msgfree(ads, res);
703 /* Lookup groups a user is a member of - alternate method, for when
704 tokenGroups are not available. */
705 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
708 DOM_SID *primary_group,
709 size_t *p_num_groups,
713 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
715 const char *attrs[] = {"memberOf", NULL};
716 size_t num_groups = 0;
717 DOM_SID *group_sids = NULL;
719 char **strings = NULL;
720 size_t num_strings = 0, num_sids = 0;
723 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
725 if ( !winbindd_can_contact_domain( domain ) ) {
726 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
727 "domain %s\n", domain->name));
731 ads = ads_cached_connection(domain);
734 domain->last_status = NT_STATUS_SERVER_DISABLED;
735 return NT_STATUS_UNSUCCESSFUL;
738 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
739 ADS_EXTENDED_DN_HEX_STRING,
740 &strings, &num_strings);
742 if (!ADS_ERR_OK(rc)) {
743 DEBUG(1,("lookup_usergroups_memberof ads_search "
744 "member=%s: %s\n", user_dn, ads_errstr(rc)));
745 return ads_ntstatus(rc);
751 /* always add the primary group to the sid array */
752 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
754 if (!NT_STATUS_IS_OK(status)) {
758 group_sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_strings + 1);
760 status = NT_STATUS_NO_MEMORY;
764 for (i=0; i<num_strings; i++) {
765 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
766 ADS_EXTENDED_DN_HEX_STRING,
768 if (!ADS_ERR_OK(rc)) {
769 /* ignore members without SIDs */
770 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
771 NT_STATUS_NOT_FOUND)) {
775 status = ads_ntstatus(rc);
783 DEBUG(1,("No memberOf for this user?!?\n"));
784 status = NT_STATUS_NO_MEMORY;
788 for (i=0; i<num_sids; i++) {
790 /* ignore Builtin groups from ADS - Guenther */
791 if (sid_check_is_in_builtin(&group_sids[i])) {
795 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
797 if (!NT_STATUS_IS_OK(status)) {
803 *p_num_groups = num_groups;
804 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
806 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
810 TALLOC_FREE(strings);
811 TALLOC_FREE(group_sids);
817 /* Lookup groups a user is a member of. */
818 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
821 uint32 *p_num_groups, DOM_SID **user_sids)
823 ADS_STRUCT *ads = NULL;
824 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
827 LDAPMessage *msg = NULL;
828 char *user_dn = NULL;
831 DOM_SID primary_group;
832 uint32 primary_group_rid;
833 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
834 size_t num_groups = 0;
836 DEBUG(3,("ads: lookup_usergroups\n"));
839 status = lookup_usergroups_cached(domain, mem_ctx, sid,
840 p_num_groups, user_sids);
841 if (NT_STATUS_IS_OK(status)) {
845 if ( !winbindd_can_contact_domain( domain ) ) {
846 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
849 /* Tell the cache manager not to remember this one */
851 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
854 ads = ads_cached_connection(domain);
857 domain->last_status = NT_STATUS_SERVER_DISABLED;
858 status = NT_STATUS_SERVER_DISABLED;
862 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
864 if (!ADS_ERR_OK(rc)) {
865 status = ads_ntstatus(rc);
866 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
867 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
871 count = ads_count_replies(ads, msg);
873 status = NT_STATUS_UNSUCCESSFUL;
874 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
875 "invalid number of results (count=%d)\n",
876 sid_string_dbg(sid), count));
881 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
882 sid_string_dbg(sid)));
883 status = NT_STATUS_UNSUCCESSFUL;
887 user_dn = ads_get_dn(ads, mem_ctx, msg);
888 if (user_dn == NULL) {
889 status = NT_STATUS_NO_MEMORY;
893 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
894 DEBUG(1,("%s: No primary group for sid=%s !?\n",
895 domain->name, sid_string_dbg(sid)));
899 sid_copy(&primary_group, &domain->sid);
900 sid_append_rid(&primary_group, primary_group_rid);
902 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
904 /* there must always be at least one group in the token,
905 unless we are talking to a buggy Win2k server */
907 /* actually this only happens when the machine account has no read
908 * permissions on the tokenGroup attribute - gd */
914 /* lookup what groups this user is a member of by DN search on
917 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
919 &num_groups, user_sids);
920 *p_num_groups = (uint32)num_groups;
921 if (NT_STATUS_IS_OK(status)) {
925 /* lookup what groups this user is a member of by DN search on
928 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
930 &num_groups, user_sids);
931 *p_num_groups = (uint32)num_groups;
938 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
940 if (!NT_STATUS_IS_OK(status)) {
944 for (i=0;i<count;i++) {
946 /* ignore Builtin groups from ADS - Guenther */
947 if (sid_check_is_in_builtin(&sids[i])) {
951 status = add_sid_to_array_unique(mem_ctx, &sids[i],
952 user_sids, &num_groups);
953 if (!NT_STATUS_IS_OK(status)) {
958 *p_num_groups = (uint32)num_groups;
959 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
961 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
962 sid_string_dbg(sid)));
964 TALLOC_FREE(user_dn);
965 ads_msgfree(ads, msg);
969 /* Lookup aliases a user is member of - use rpc methods */
970 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
972 uint32 num_sids, const DOM_SID *sids,
973 uint32 *num_aliases, uint32 **alias_rids)
975 return reconnect_methods.lookup_useraliases(domain, mem_ctx,
982 find the members of a group, given a group rid and domain
984 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
986 const DOM_SID *group_sid,
987 enum lsa_SidType type,
989 DOM_SID **sid_mem, char ***names,
993 ADS_STRUCT *ads = NULL;
995 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
997 char **members = NULL;
999 size_t num_members = 0;
1001 DOM_SID *sid_mem_nocache = NULL;
1002 char **names_nocache = NULL;
1003 enum lsa_SidType *name_types_nocache = NULL;
1004 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1005 uint32 num_nocache = 0;
1006 TALLOC_CTX *tmp_ctx = NULL;
1008 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1009 sid_string_dbg(group_sid)));
1013 tmp_ctx = talloc_new(mem_ctx);
1015 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1016 status = NT_STATUS_NO_MEMORY;
1020 if ( !winbindd_can_contact_domain( domain ) ) {
1021 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1023 return NT_STATUS_OK;
1026 ads = ads_cached_connection(domain);
1029 domain->last_status = NT_STATUS_SERVER_DISABLED;
1033 if ((sidbinstr = sid_binstring(talloc_tos(), group_sid)) == NULL) {
1034 status = NT_STATUS_NO_MEMORY;
1038 /* search for all members of the group */
1039 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1040 TALLOC_FREE(sidbinstr);
1041 if (ldap_exp == NULL) {
1042 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1043 status = NT_STATUS_NO_MEMORY;
1047 args.control = ADS_EXTENDED_DN_OID;
1048 args.val = ADS_EXTENDED_DN_HEX_STRING;
1049 args.critical = True;
1051 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1052 ldap_exp, &args, "member", &members, &num_members);
1054 if (!ADS_ERR_OK(rc)) {
1055 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1056 status = NT_STATUS_UNSUCCESSFUL;
1060 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1062 /* Now that we have a list of sids, we need to get the
1063 * lists of names and name_types belonging to these sids.
1064 * even though conceptually not quite clean, we use the
1065 * RPC call lsa_lookup_sids for this since it can handle a
1066 * list of sids. ldap calls can just resolve one sid at a time.
1068 * At this stage, the sids are still hidden in the exetended dn
1069 * member output format. We actually do a little better than
1070 * stated above: In extracting the sids from the member strings,
1071 * we try to resolve as many sids as possible from the
1072 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1075 (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
1076 (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
1077 (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
1078 (sid_mem_nocache) = TALLOC_ZERO_ARRAY(tmp_ctx, DOM_SID, num_members);
1080 if ((members == NULL) || (*sid_mem == NULL) ||
1081 (*names == NULL) || (*name_types == NULL) ||
1082 (sid_mem_nocache == NULL))
1084 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1085 status = NT_STATUS_NO_MEMORY;
1092 (*name_types) = NULL;
1095 for (i=0; i<num_members; i++) {
1096 enum lsa_SidType name_type;
1097 char *name, *domain_name;
1100 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1102 if (!ADS_ERR_OK(rc)) {
1103 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1104 NT_STATUS_NOT_FOUND)) {
1105 /* Group members can be objects, like Exchange
1106 * Public Folders, that don't have a SID. Skip
1111 status = ads_ntstatus(rc);
1115 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1117 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1118 "cache\n", sid_string_dbg(&sid)));
1119 sid_copy(&(*sid_mem)[*num_names], &sid);
1120 (*names)[*num_names] = fill_domain_username_talloc(
1126 (*name_types)[*num_names] = name_type;
1130 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1131 "cache\n", sid_string_dbg(&sid)));
1132 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1137 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1138 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1140 /* handle sids not resolved from cache by lsa_lookup_sids */
1141 if (num_nocache > 0) {
1143 status = winbindd_lookup_sids(tmp_ctx,
1149 &name_types_nocache);
1151 if (!(NT_STATUS_IS_OK(status) ||
1152 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1153 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1155 DEBUG(1, ("lsa_lookupsids call failed with %s "
1156 "- retrying...\n", nt_errstr(status)));
1158 status = winbindd_lookup_sids(tmp_ctx,
1164 &name_types_nocache);
1167 if (NT_STATUS_IS_OK(status) ||
1168 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1170 /* Copy the entries over from the "_nocache" arrays
1171 * to the result arrays, skipping the gaps the
1172 * lookup_sids call left. */
1173 for (i=0; i < num_nocache; i++) {
1174 if (((names_nocache)[i] != NULL) &&
1175 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1177 sid_copy(&(*sid_mem)[*num_names],
1178 &sid_mem_nocache[i]);
1179 (*names)[*num_names] =
1180 fill_domain_username_talloc(
1185 (*name_types)[*num_names] = name_types_nocache[i];
1190 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1191 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1192 "not map any SIDs at all.\n"));
1193 /* Don't handle this as an error here.
1194 * There is nothing left to do with respect to the
1195 * overall result... */
1197 else if (!NT_STATUS_IS_OK(status)) {
1198 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1199 "sids via rpc_lsa_lookup_sids: %s\n",
1200 (int)num_members, nt_errstr(status)));
1205 status = NT_STATUS_OK;
1206 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1207 sid_string_dbg(group_sid)));
1211 TALLOC_FREE(tmp_ctx);
1216 /* find the sequence number for a domain */
1217 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1219 ADS_STRUCT *ads = NULL;
1222 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1224 if ( !winbindd_can_contact_domain( domain ) ) {
1225 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1228 return NT_STATUS_OK;
1231 *seq = DOM_SEQUENCE_NONE;
1233 ads = ads_cached_connection(domain);
1236 domain->last_status = NT_STATUS_SERVER_DISABLED;
1237 return NT_STATUS_UNSUCCESSFUL;
1240 rc = ads_USN(ads, seq);
1242 if (!ADS_ERR_OK(rc)) {
1244 /* its a dead connection, destroy it */
1246 if (domain->private_data) {
1247 ads = (ADS_STRUCT *)domain->private_data;
1248 ads->is_mine = True;
1250 ads_kdestroy("MEMORY:winbind_ccache");
1251 domain->private_data = NULL;
1254 return ads_ntstatus(rc);
1257 /* find the lockout policy of a domain - use rpc methods */
1258 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1259 TALLOC_CTX *mem_ctx,
1260 struct samr_DomInfo12 *policy)
1262 return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
1265 /* find the password policy of a domain - use rpc methods */
1266 static NTSTATUS password_policy(struct winbindd_domain *domain,
1267 TALLOC_CTX *mem_ctx,
1268 struct samr_DomInfo1 *policy)
1270 return reconnect_methods.password_policy(domain, mem_ctx, policy);
1273 /* get a list of trusted domains */
1274 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1275 TALLOC_CTX *mem_ctx,
1276 struct netr_DomainTrustList *trusts)
1278 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1281 struct rpc_pipe_client *cli;
1282 uint32 fr_flags = (NETR_TRUST_FLAG_IN_FOREST | NETR_TRUST_FLAG_TREEROOT);
1285 DEBUG(3,("ads: trusted_domains\n"));
1287 ZERO_STRUCTP(trusts);
1289 /* If this is our primary domain or a root in our forest,
1290 query for all trusts. If not, then just look for domain
1291 trusts in the target forest */
1293 if ( domain->primary ||
1294 ((domain->domain_flags&fr_flags) == fr_flags) )
1296 flags = NETR_TRUST_FLAG_OUTBOUND |
1297 NETR_TRUST_FLAG_INBOUND |
1298 NETR_TRUST_FLAG_IN_FOREST;
1300 flags = NETR_TRUST_FLAG_IN_FOREST;
1303 result = cm_connect_netlogon(domain, &cli);
1305 if (!NT_STATUS_IS_OK(result)) {
1306 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1307 "for PIPE_NETLOGON (%s)\n",
1308 domain->name, nt_errstr(result)));
1309 return NT_STATUS_UNSUCCESSFUL;
1312 result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
1317 if (!NT_STATUS_IS_OK(result)) {
1320 if (trusts->count == 0) {
1321 return NT_STATUS_OK;
1324 /* Copy across names and sids */
1327 for (i = 0; i < trusts->count; i++) {
1328 struct netr_DomainTrust *trust = &trusts->array[i];
1329 struct winbindd_domain d;
1334 * drop external trusts if this is not our primary
1335 * domain. This means that the returned number of
1336 * domains may be less that the ones actually trusted
1340 if ((trust->trust_attributes
1341 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1344 DEBUG(10,("trusted_domains: Skipping external trusted "
1345 "domain %s because it is outside of our "
1347 trust->netbios_name));
1351 /* add to the trusted domain cache */
1353 fstrcpy(d.name, trust->netbios_name);
1354 fstrcpy(d.alt_name, trust->dns_name);
1356 sid_copy(&d.sid, trust->sid);
1358 sid_copy(&d.sid, &global_sid_NULL);
1361 if ( domain->primary ) {
1362 DEBUG(10,("trusted_domains(ads): Searching "
1363 "trusted domain list of %s and storing "
1364 "trust flags for domain %s\n",
1365 domain->name, d.alt_name));
1367 d.domain_flags = trust->trust_flags;
1368 d.domain_type = trust->trust_type;
1369 d.domain_trust_attribs = trust->trust_attributes;
1371 wcache_tdc_add_domain( &d );
1373 } else if ( (domain->domain_flags&fr_flags) == fr_flags ) {
1374 /* Check if we already have this record. If
1375 * we are following our forest root that is not
1376 * our primary domain, we want to keep trust
1377 * flags from the perspective of our primary
1378 * domain not our forest root. */
1379 struct winbindd_tdc_domain *exist = NULL;
1381 exist = wcache_tdc_fetch_domain(
1382 talloc_tos(), trust->netbios_name);
1384 DEBUG(10,("trusted_domains(ads): Searching "
1385 "trusted domain list of %s and "
1386 "storing trust flags for domain "
1387 "%s\n", domain->name, d.alt_name));
1388 d.domain_flags = trust->trust_flags;
1389 d.domain_type = trust->trust_type;
1390 d.domain_trust_attribs =
1391 trust->trust_attributes;
1393 wcache_tdc_add_domain( &d );
1398 /* This gets a little tricky. If we are
1399 following a transitive forest trust, then
1400 innerit the flags, type, and attribs from
1401 the domain we queried to make sure we don't
1402 record the view of the trust from the wrong
1403 side. Always view it from the side of our
1404 primary domain. --jerry */
1405 struct winbindd_tdc_domain *parent = NULL;
1407 DEBUG(10,("trusted_domains(ads): Searching "
1408 "trusted domain list of %s and inheriting "
1409 "trust flags for domain %s\n",
1410 domain->name, d.alt_name));
1412 parent = wcache_tdc_fetch_domain(talloc_tos(),
1415 d.domain_flags = parent->trust_flags;
1416 d.domain_type = parent->trust_type;
1417 d.domain_trust_attribs = parent->trust_attribs;
1419 d.domain_flags = domain->domain_flags;
1420 d.domain_type = domain->domain_type;
1421 d.domain_trust_attribs =
1422 domain->domain_trust_attribs;
1424 TALLOC_FREE(parent);
1426 wcache_tdc_add_domain( &d );
1433 /* the ADS backend methods are exposed via this structure */
1434 struct winbindd_methods ads_methods = {