2 Unix SMB/CIFS implementation.
4 Winbind ADS backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
8 Copyright (C) Gerald (Jerry) Carter 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "rpc_client/rpc_client.h"
27 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
28 #include "../libds/common/flags.h"
30 #include "../libcli/ldap/ldap_ndr.h"
31 #include "../libcli/security/security.h"
32 #include "../libds/common/flag_mapping.h"
33 #include "libsmb/samlogon_cache.h"
39 #define DBGC_CLASS DBGC_WINBIND
41 extern struct winbindd_methods reconnect_methods;
42 extern struct winbindd_methods msrpc_methods;
44 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
47 * Check if cached connection can be reused. If the connection cannot
48 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
50 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
53 ADS_STRUCT *ads = *adsp;
57 time_t now = time(NULL);
59 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
61 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
62 "is now %d)\n", (uint32_t)expire - (uint32_t)now,
63 (uint32_t) expire, (uint32_t) now));
65 if ( ads->config.realm && (expire > now)) {
68 /* we own this ADS_STRUCT so make sure it goes away */
69 DEBUG(7,("Deleting expired krb5 credential cache\n"));
72 ads_kdestroy(WINBIND_CCACHE_NAME);
79 * @brief Establish a connection to a DC
81 * @param[out] adsp ADS_STRUCT that will be created
82 * @param[in] target_realm Realm of domain to connect to
83 * @param[in] target_dom_name 'workgroup' name of domain to connect to
84 * @param[in] ldap_server DNS name of server to connect to
85 * @param[in] password Our machine acount secret
86 * @param[in] auth_realm Realm of local domain for creating krb token
87 * @param[in] renewable Renewable ticket time
91 static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
92 const char *target_realm,
93 const char *target_dom_name,
94 const char *ldap_server,
101 struct sockaddr_storage dc_ss;
104 if (auth_realm == NULL) {
105 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
108 /* we don't want this to affect the users ccache */
109 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
111 ads = ads_init(target_realm, target_dom_name, ldap_server);
113 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
114 return ADS_ERROR(LDAP_NO_MEMORY);
117 SAFE_FREE(ads->auth.password);
118 SAFE_FREE(ads->auth.realm);
120 ads->auth.renewable = renewable;
121 ads->auth.password = password;
123 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
125 ads->auth.realm = SMB_STRDUP(auth_realm);
126 if (!strupper_m(ads->auth.realm)) {
128 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
131 /* Setup the server affinity cache. We don't reaally care
132 about the name. Just setup affinity and the KRB5_CONFIG
134 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
136 status = ads_connect(ads);
137 if (!ADS_ERR_OK(status)) {
138 DEBUG(1,("ads_connect for domain %s failed: %s\n",
139 target_dom_name, ads_errstr(status)));
144 /* set the flag that says we don't own the memory even
145 though we do so that ads_destroy() won't destroy the
146 structure we pass back by reference */
148 ads->is_mine = False;
155 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
157 char *ldap_server, *realm, *password;
158 struct winbindd_domain *wb_dom;
161 ads_cached_connection_reuse(adsp);
167 * At this point we only have the NetBIOS domain name.
168 * Check if we can get server nam and realm from SAF cache
169 * and the domain list.
171 ldap_server = saf_fetch(talloc_tos(), dom_name);
172 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
173 ldap_server ? ldap_server : ""));
175 wb_dom = find_domain_from_name(dom_name);
176 if (wb_dom == NULL) {
177 DEBUG(10, ("could not find domain '%s'\n", dom_name));
178 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
181 DEBUG(10, ("find_domain_from_name found realm '%s' for "
182 " domain '%s'\n", wb_dom->alt_name, dom_name));
184 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
185 TALLOC_FREE(ldap_server);
186 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
190 SMB_ASSERT(wb_dom->alt_name != NULL);
191 realm = SMB_STRDUP(wb_dom->alt_name);
193 struct winbindd_domain *our_domain = wb_dom;
195 /* always give preference to the alt_name in our
196 primary domain if possible */
198 if (!wb_dom->primary) {
199 our_domain = find_our_domain();
202 if (our_domain->alt_name != NULL) {
203 realm = SMB_STRDUP(our_domain->alt_name);
205 realm = SMB_STRDUP(lp_realm());
209 status = ads_cached_connection_connect(
210 adsp, /* Returns ads struct. */
211 wb_dom->alt_name, /* realm to connect to. */
212 dom_name, /* 'workgroup' name for ads_init */
213 ldap_server, /* DNS name to connect to. */
214 password, /* password for auth realm. */
215 realm, /* realm used for krb5 ticket. */
216 0); /* renewable ticket time. */
219 TALLOC_FREE(ldap_server);
225 return our ads connections structure for a domain. We keep the connection
226 open to make things faster
228 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
231 char *password, *realm;
233 DEBUG(10,("ads_cached_connection\n"));
234 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
236 if (domain->private_data) {
237 return (ADS_STRUCT *)domain->private_data;
240 /* the machine acct password might have change - fetch it every time */
242 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
247 SMB_ASSERT(domain->alt_name != NULL);
248 realm = SMB_STRDUP(domain->alt_name);
251 struct winbindd_domain *our_domain = domain;
254 /* always give preference to the alt_name in our
255 primary domain if possible */
257 if ( !domain->primary )
258 our_domain = find_our_domain();
260 if (our_domain->alt_name != NULL) {
261 realm = SMB_STRDUP( our_domain->alt_name );
264 realm = SMB_STRDUP( lp_realm() );
267 status = ads_cached_connection_connect(
268 (ADS_STRUCT **)&domain->private_data,
272 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
275 if (!ADS_ERR_OK(status)) {
276 /* if we get ECONNREFUSED then it might be a NT4
277 server, fall back to MSRPC */
278 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
279 status.err.rc == ECONNREFUSED) {
280 /* 'reconnect_methods' is the MS-RPC backend. */
281 DEBUG(1,("Trying MSRPC methods\n"));
282 domain->backend = &reconnect_methods;
287 return (ADS_STRUCT *)domain->private_data;
290 /* Query display info for a realm. This is the basic user list fn */
291 static NTSTATUS query_user_list(struct winbindd_domain *domain,
295 ADS_STRUCT *ads = NULL;
296 const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
298 uint32_t *rids = NULL;
300 LDAPMessage *res = NULL;
301 LDAPMessage *msg = NULL;
302 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
304 DEBUG(3,("ads: query_user_list\n"));
306 if ( !winbindd_can_contact_domain( domain ) ) {
307 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
312 ads = ads_cached_connection(domain);
315 domain->last_status = NT_STATUS_SERVER_DISABLED;
319 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
320 if (!ADS_ERR_OK(rc)) {
321 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
322 status = ads_ntstatus(rc);
325 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
329 count = ads_count_replies(ads, res);
331 DEBUG(1,("query_user_list: No users found\n"));
335 rids = talloc_zero_array(mem_ctx, uint32_t, count);
337 status = NT_STATUS_NO_MEMORY;
343 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
344 struct dom_sid user_sid;
348 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
350 DBG_INFO("Object lacks sAMAccountType attribute\n");
353 if (ds_atype_map(atype) != SID_NAME_USER) {
354 DBG_INFO("Not a user account? atype=0x%x\n", atype);
358 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
359 char *dn = ads_get_dn(ads, talloc_tos(), msg);
360 DBG_INFO("No sid for %s !?\n", dn);
365 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
366 fstring sidstr, domstr;
367 DBG_WARNING("Got sid %s in domain %s\n",
368 sid_to_fstring(sidstr, &user_sid),
369 sid_to_fstring(domstr, &domain->sid));
373 sid_split_rid(&user_sid, &rids[count]);
377 rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
382 status = NT_STATUS_OK;
384 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
390 /* list all domain groups */
391 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
393 uint32_t *num_entries,
394 struct wb_acct_info **info)
396 ADS_STRUCT *ads = NULL;
397 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
398 "name", "objectSid", NULL};
401 LDAPMessage *res = NULL;
402 LDAPMessage *msg = NULL;
403 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
405 bool enum_dom_local_groups = False;
409 DEBUG(3,("ads: enum_dom_groups\n"));
411 if ( !winbindd_can_contact_domain( domain ) ) {
412 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
417 /* only grab domain local groups for our domain */
418 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
419 enum_dom_local_groups = True;
422 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
425 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
426 * default value, it MUST be absent. In case of extensible matching the
427 * "dnattr" boolean defaults to FALSE and so it must be only be present
430 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
431 * filter using bitwise matching rule then the buggy AD fails to decode
432 * the extensible match. As a workaround set it to TRUE and thereby add
433 * the dnAttributes "dn" field to cope with those older AD versions.
434 * It should not harm and won't put any additional load on the AD since
435 * none of the dn components have a bitmask-attribute.
437 * Thanks to Ralf Haferkamp for input and testing - Guenther */
439 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
440 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
441 ADS_LDAP_MATCHING_RULE_BIT_AND,
442 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
444 if (filter == NULL) {
445 status = NT_STATUS_NO_MEMORY;
449 ads = ads_cached_connection(domain);
452 domain->last_status = NT_STATUS_SERVER_DISABLED;
456 rc = ads_search_retry(ads, &res, filter, attrs);
457 if (!ADS_ERR_OK(rc)) {
458 status = ads_ntstatus(rc);
459 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
462 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
466 count = ads_count_replies(ads, res);
468 DEBUG(1,("enum_dom_groups: No groups found\n"));
472 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
474 status = NT_STATUS_NO_MEMORY;
480 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
485 name = ads_pull_username(ads, mem_ctx, msg);
486 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
487 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
488 DEBUG(1,("No sid for %s !?\n", name));
492 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
493 DEBUG(1,("No rid for %s !?\n", name));
497 fstrcpy((*info)[i].acct_name, name);
498 fstrcpy((*info)[i].acct_desc, gecos);
499 (*info)[i].rid = rid;
505 status = NT_STATUS_OK;
507 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
511 ads_msgfree(ads, res);
516 /* list all domain local groups */
517 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
519 uint32_t *num_entries,
520 struct wb_acct_info **info)
523 * This is a stub function only as we returned the domain
524 * local groups in enum_dom_groups() if the domain->native field
525 * was true. This is a simple performance optimization when
528 * if we ever need to enumerate domain local groups separately,
529 * then this optimization in enum_dom_groups() will need
537 /* convert a single name to a sid in a domain - use rpc methods */
538 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
540 const char *domain_name,
544 enum lsa_SidType *type)
546 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
550 /* convert a domain SID to a user or group name - use rpc methods */
551 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
553 const struct dom_sid *sid,
556 enum lsa_SidType *type)
558 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
559 domain_name, name, type);
562 /* convert a list of rids to names - use rpc methods */
563 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
565 const struct dom_sid *sid,
570 enum lsa_SidType **types)
572 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
574 domain_name, names, types);
577 /* Lookup groups a user is a member of - alternate method, for when
578 tokenGroups are not available. */
579 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
582 struct dom_sid *primary_group,
583 uint32_t *p_num_groups, struct dom_sid **user_sids)
586 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
588 LDAPMessage *res = NULL;
589 LDAPMessage *msg = NULL;
592 const char *group_attrs[] = {"objectSid", NULL};
594 uint32_t num_groups = 0;
596 DEBUG(3,("ads: lookup_usergroups_member\n"));
598 if ( !winbindd_can_contact_domain( domain ) ) {
599 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
604 ads = ads_cached_connection(domain);
607 domain->last_status = NT_STATUS_SERVER_DISABLED;
611 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
612 status = NT_STATUS_NO_MEMORY;
616 ldap_exp = talloc_asprintf(mem_ctx,
617 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
619 ADS_LDAP_MATCHING_RULE_BIT_AND,
620 GROUP_TYPE_SECURITY_ENABLED);
622 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
623 TALLOC_FREE(escaped_dn);
624 status = NT_STATUS_NO_MEMORY;
628 TALLOC_FREE(escaped_dn);
630 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
632 if (!ADS_ERR_OK(rc)) {
633 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
634 return ads_ntstatus(rc);
636 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
637 return NT_STATUS_INTERNAL_ERROR;
641 count = ads_count_replies(ads, res);
646 /* always add the primary group to the sid array */
647 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
649 if (!NT_STATUS_IS_OK(status)) {
654 for (msg = ads_first_entry(ads, res); msg;
655 msg = ads_next_entry(ads, msg)) {
656 struct dom_sid group_sid;
658 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
659 DEBUG(1,("No sid for this group ?!?\n"));
663 /* ignore Builtin groups from ADS - Guenther */
664 if (sid_check_is_in_builtin(&group_sid)) {
668 status = add_sid_to_array(mem_ctx, &group_sid,
669 user_sids, &num_groups);
670 if (!NT_STATUS_IS_OK(status)) {
677 *p_num_groups = num_groups;
678 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
680 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
683 ads_msgfree(ads, res);
688 /* Lookup groups a user is a member of - alternate method, for when
689 tokenGroups are not available. */
690 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
693 struct dom_sid *primary_group,
694 uint32_t *p_num_groups,
695 struct dom_sid **user_sids)
698 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
700 const char *attrs[] = {"memberOf", NULL};
701 uint32_t num_groups = 0;
702 struct dom_sid *group_sids = NULL;
704 char **strings = NULL;
705 size_t num_strings = 0, num_sids = 0;
708 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
710 if ( !winbindd_can_contact_domain( domain ) ) {
711 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
712 "domain %s\n", domain->name));
716 ads = ads_cached_connection(domain);
719 domain->last_status = NT_STATUS_SERVER_DISABLED;
720 return NT_STATUS_UNSUCCESSFUL;
723 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
724 ADS_EXTENDED_DN_HEX_STRING,
725 &strings, &num_strings);
727 if (!ADS_ERR_OK(rc)) {
728 DEBUG(1,("lookup_usergroups_memberof ads_search "
729 "member=%s: %s\n", user_dn, ads_errstr(rc)));
730 return ads_ntstatus(rc);
736 /* always add the primary group to the sid array */
737 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
739 if (!NT_STATUS_IS_OK(status)) {
743 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
745 status = NT_STATUS_NO_MEMORY;
749 for (i=0; i<num_strings; i++) {
750 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
751 ADS_EXTENDED_DN_HEX_STRING,
753 if (!ADS_ERR_OK(rc)) {
754 /* ignore members without SIDs */
755 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
756 NT_STATUS_NOT_FOUND)) {
760 status = ads_ntstatus(rc);
768 DEBUG(1,("No memberOf for this user?!?\n"));
769 status = NT_STATUS_NO_MEMORY;
773 for (i=0; i<num_sids; i++) {
775 /* ignore Builtin groups from ADS - Guenther */
776 if (sid_check_is_in_builtin(&group_sids[i])) {
780 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
782 if (!NT_STATUS_IS_OK(status)) {
788 *p_num_groups = num_groups;
789 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
791 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
795 TALLOC_FREE(strings);
796 TALLOC_FREE(group_sids);
802 /* Lookup groups a user is a member of. */
803 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
805 const struct dom_sid *sid,
806 uint32_t *p_num_groups, struct dom_sid **user_sids)
808 ADS_STRUCT *ads = NULL;
809 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
812 LDAPMessage *msg = NULL;
813 char *user_dn = NULL;
814 struct dom_sid *sids;
816 struct dom_sid primary_group;
817 uint32_t primary_group_rid;
818 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
819 uint32_t num_groups = 0;
821 DEBUG(3,("ads: lookup_usergroups\n"));
824 status = lookup_usergroups_cached(mem_ctx, sid,
825 p_num_groups, user_sids);
826 if (NT_STATUS_IS_OK(status)) {
830 if ( !winbindd_can_contact_domain( domain ) ) {
831 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
834 /* Tell the cache manager not to remember this one */
836 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
839 ads = ads_cached_connection(domain);
842 domain->last_status = NT_STATUS_SERVER_DISABLED;
843 status = NT_STATUS_SERVER_DISABLED;
847 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
849 if (!ADS_ERR_OK(rc)) {
850 status = ads_ntstatus(rc);
851 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
852 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
856 count = ads_count_replies(ads, msg);
858 status = NT_STATUS_UNSUCCESSFUL;
859 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
860 "invalid number of results (count=%d)\n",
861 sid_string_dbg(sid), count));
866 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
867 sid_string_dbg(sid)));
868 status = NT_STATUS_UNSUCCESSFUL;
872 user_dn = ads_get_dn(ads, mem_ctx, msg);
873 if (user_dn == NULL) {
874 status = NT_STATUS_NO_MEMORY;
878 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
879 DEBUG(1,("%s: No primary group for sid=%s !?\n",
880 domain->name, sid_string_dbg(sid)));
884 sid_compose(&primary_group, &domain->sid, primary_group_rid);
886 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
888 /* there must always be at least one group in the token,
889 unless we are talking to a buggy Win2k server */
891 /* actually this only happens when the machine account has no read
892 * permissions on the tokenGroup attribute - gd */
898 /* lookup what groups this user is a member of by DN search on
901 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
903 &num_groups, user_sids);
904 *p_num_groups = num_groups;
905 if (NT_STATUS_IS_OK(status)) {
909 /* lookup what groups this user is a member of by DN search on
912 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
914 &num_groups, user_sids);
915 *p_num_groups = num_groups;
922 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
924 if (!NT_STATUS_IS_OK(status)) {
928 for (i=0;i<count;i++) {
930 /* ignore Builtin groups from ADS - Guenther */
931 if (sid_check_is_in_builtin(&sids[i])) {
935 status = add_sid_to_array_unique(mem_ctx, &sids[i],
936 user_sids, &num_groups);
937 if (!NT_STATUS_IS_OK(status)) {
942 *p_num_groups = (uint32_t)num_groups;
943 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
945 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
946 sid_string_dbg(sid)));
948 TALLOC_FREE(user_dn);
949 ads_msgfree(ads, msg);
953 /* Lookup aliases a user is member of - use rpc methods */
954 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
956 uint32_t num_sids, const struct dom_sid *sids,
957 uint32_t *num_aliases, uint32_t **alias_rids)
959 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
960 num_aliases, alias_rids);
963 static NTSTATUS add_primary_group_members(
964 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
965 char ***all_members, size_t *num_all_members)
968 NTSTATUS status = NT_STATUS_NO_MEMORY;
970 const char *attrs[] = { "dn", NULL };
971 LDAPMessage *res = NULL;
977 filter = talloc_asprintf(
978 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
980 if (filter == NULL) {
984 args.control = ADS_EXTENDED_DN_OID;
985 args.val = ADS_EXTENDED_DN_HEX_STRING;
986 args.critical = True;
988 rc = ads_do_search_all_args(ads, ads->config.bind_path,
989 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
992 if (!ADS_ERR_OK(rc)) {
993 status = ads_ntstatus(rc);
994 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
998 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1002 num_members = ads_count_replies(ads, res);
1004 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1005 (uintmax_t)num_members));
1007 if (num_members == 0) {
1008 status = NT_STATUS_OK;
1012 members = talloc_realloc(mem_ctx, *all_members, char *,
1013 *num_all_members + num_members);
1014 if (members == NULL) {
1015 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1018 *all_members = members;
1020 for (msg = ads_first_entry(ads, res); msg != NULL;
1021 msg = ads_next_entry(ads, msg)) {
1024 dn = ads_get_dn(ads, members, msg);
1026 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1030 members[*num_all_members] = dn;
1031 *num_all_members += 1;
1034 status = NT_STATUS_OK;
1037 ads_msgfree(ads, res);
1039 TALLOC_FREE(filter);
1044 find the members of a group, given a group rid and domain
1046 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1047 TALLOC_CTX *mem_ctx,
1048 const struct dom_sid *group_sid,
1049 enum lsa_SidType type,
1050 uint32_t *num_names,
1051 struct dom_sid **sid_mem, char ***names,
1052 uint32_t **name_types)
1055 ADS_STRUCT *ads = NULL;
1057 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1059 char **members = NULL;
1061 size_t num_members = 0;
1063 struct dom_sid *sid_mem_nocache = NULL;
1064 char **names_nocache = NULL;
1065 enum lsa_SidType *name_types_nocache = NULL;
1066 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1067 uint32_t num_nocache = 0;
1068 TALLOC_CTX *tmp_ctx = NULL;
1071 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1072 sid_string_dbg(group_sid)));
1076 tmp_ctx = talloc_new(mem_ctx);
1078 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1079 status = NT_STATUS_NO_MEMORY;
1083 if (!sid_peek_rid(group_sid, &rid)) {
1084 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1085 status = NT_STATUS_INVALID_PARAMETER;
1089 if ( !winbindd_can_contact_domain( domain ) ) {
1090 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1092 return NT_STATUS_OK;
1095 ads = ads_cached_connection(domain);
1098 domain->last_status = NT_STATUS_SERVER_DISABLED;
1102 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1103 status = NT_STATUS_NO_MEMORY;
1107 /* search for all members of the group */
1108 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1109 TALLOC_FREE(sidbinstr);
1110 if (ldap_exp == NULL) {
1111 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1112 status = NT_STATUS_NO_MEMORY;
1116 args.control = ADS_EXTENDED_DN_OID;
1117 args.val = ADS_EXTENDED_DN_HEX_STRING;
1118 args.critical = True;
1120 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1121 ldap_exp, &args, "member", &members, &num_members);
1123 if (!ADS_ERR_OK(rc)) {
1124 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1125 status = NT_STATUS_UNSUCCESSFUL;
1129 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1131 status = add_primary_group_members(ads, mem_ctx, rid,
1132 &members, &num_members);
1133 if (!NT_STATUS_IS_OK(status)) {
1134 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1135 __func__, nt_errstr(status)));
1139 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1140 __func__, (int)num_members));
1142 /* Now that we have a list of sids, we need to get the
1143 * lists of names and name_types belonging to these sids.
1144 * even though conceptually not quite clean, we use the
1145 * RPC call lsa_lookup_sids for this since it can handle a
1146 * list of sids. ldap calls can just resolve one sid at a time.
1148 * At this stage, the sids are still hidden in the exetended dn
1149 * member output format. We actually do a little better than
1150 * stated above: In extracting the sids from the member strings,
1151 * we try to resolve as many sids as possible from the
1152 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1155 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1156 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1157 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1158 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1160 if ((members == NULL) || (*sid_mem == NULL) ||
1161 (*names == NULL) || (*name_types == NULL) ||
1162 (sid_mem_nocache == NULL))
1164 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1165 status = NT_STATUS_NO_MEMORY;
1172 (*name_types) = NULL;
1175 for (i=0; i<num_members; i++) {
1176 enum lsa_SidType name_type;
1177 char *name, *domain_name;
1180 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1182 if (!ADS_ERR_OK(rc)) {
1183 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1184 NT_STATUS_NOT_FOUND)) {
1185 /* Group members can be objects, like Exchange
1186 * Public Folders, that don't have a SID. Skip
1191 status = ads_ntstatus(rc);
1195 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1197 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1198 "cache\n", sid_string_dbg(&sid)));
1199 sid_copy(&(*sid_mem)[*num_names], &sid);
1200 (*names)[*num_names] = fill_domain_username_talloc(
1206 (*name_types)[*num_names] = name_type;
1210 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1211 "cache\n", sid_string_dbg(&sid)));
1212 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1217 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1218 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1220 /* handle sids not resolved from cache by lsa_lookup_sids */
1221 if (num_nocache > 0) {
1223 status = winbindd_lookup_sids(tmp_ctx,
1229 &name_types_nocache);
1231 if (!(NT_STATUS_IS_OK(status) ||
1232 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1233 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1235 DEBUG(1, ("lsa_lookupsids call failed with %s "
1236 "- retrying...\n", nt_errstr(status)));
1238 status = winbindd_lookup_sids(tmp_ctx,
1244 &name_types_nocache);
1247 if (NT_STATUS_IS_OK(status) ||
1248 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1250 /* Copy the entries over from the "_nocache" arrays
1251 * to the result arrays, skipping the gaps the
1252 * lookup_sids call left. */
1253 for (i=0; i < num_nocache; i++) {
1254 if (((names_nocache)[i] != NULL) &&
1255 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1257 sid_copy(&(*sid_mem)[*num_names],
1258 &sid_mem_nocache[i]);
1259 (*names)[*num_names] =
1260 fill_domain_username_talloc(
1265 (*name_types)[*num_names] = name_types_nocache[i];
1270 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1271 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1272 "not map any SIDs at all.\n"));
1273 /* Don't handle this as an error here.
1274 * There is nothing left to do with respect to the
1275 * overall result... */
1277 else if (!NT_STATUS_IS_OK(status)) {
1278 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1279 "sids via rpc_lsa_lookup_sids: %s\n",
1280 (int)num_members, nt_errstr(status)));
1285 status = NT_STATUS_OK;
1286 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1287 sid_string_dbg(group_sid)));
1291 TALLOC_FREE(tmp_ctx);
1296 /* find the sequence number for a domain */
1297 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1299 ADS_STRUCT *ads = NULL;
1302 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1304 if ( !winbindd_can_contact_domain( domain ) ) {
1305 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1308 return NT_STATUS_OK;
1311 *seq = DOM_SEQUENCE_NONE;
1313 ads = ads_cached_connection(domain);
1316 domain->last_status = NT_STATUS_SERVER_DISABLED;
1317 return NT_STATUS_UNSUCCESSFUL;
1320 rc = ads_USN(ads, seq);
1322 if (!ADS_ERR_OK(rc)) {
1324 /* its a dead connection, destroy it */
1326 if (domain->private_data) {
1327 ads = (ADS_STRUCT *)domain->private_data;
1328 ads->is_mine = True;
1330 ads_kdestroy(WINBIND_CCACHE_NAME);
1331 domain->private_data = NULL;
1334 return ads_ntstatus(rc);
1337 /* find the lockout policy of a domain - use rpc methods */
1338 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1339 TALLOC_CTX *mem_ctx,
1340 struct samr_DomInfo12 *policy)
1342 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1345 /* find the password policy of a domain - use rpc methods */
1346 static NTSTATUS password_policy(struct winbindd_domain *domain,
1347 TALLOC_CTX *mem_ctx,
1348 struct samr_DomInfo1 *policy)
1350 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1353 /* get a list of trusted domains */
1354 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1355 TALLOC_CTX *mem_ctx,
1356 struct netr_DomainTrustList *trusts)
1358 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1362 struct rpc_pipe_client *cli;
1364 struct dcerpc_binding_handle *b;
1366 DEBUG(3,("ads: trusted_domains\n"));
1368 ZERO_STRUCTP(trusts);
1370 /* If this is our primary domain or a root in our forest,
1371 query for all trusts. If not, then just look for domain
1372 trusts in the target forest */
1374 if (domain->primary || domain_is_forest_root(domain)) {
1375 flags = NETR_TRUST_FLAG_OUTBOUND |
1376 NETR_TRUST_FLAG_INBOUND |
1377 NETR_TRUST_FLAG_IN_FOREST;
1379 flags = NETR_TRUST_FLAG_IN_FOREST;
1382 result = cm_connect_netlogon(domain, &cli);
1384 if (!NT_STATUS_IS_OK(result)) {
1385 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1386 "for PIPE_NETLOGON (%s)\n",
1387 domain->name, nt_errstr(result)));
1388 return NT_STATUS_UNSUCCESSFUL;
1391 b = cli->binding_handle;
1393 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1398 if (!NT_STATUS_IS_OK(result)) {
1402 if (!W_ERROR_IS_OK(werr)) {
1403 return werror_to_ntstatus(werr);
1405 if (trusts->count == 0) {
1406 return NT_STATUS_OK;
1409 /* Copy across names and sids */
1412 for (i = 0; i < trusts->count; i++) {
1413 struct netr_DomainTrust *trust = &trusts->array[i];
1414 struct winbindd_domain d;
1419 * drop external trusts if this is not our primary
1420 * domain. This means that the returned number of
1421 * domains may be less that the ones actually trusted
1425 if ((trust->trust_attributes
1426 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1429 DEBUG(10,("trusted_domains: Skipping external trusted "
1430 "domain %s because it is outside of our "
1432 trust->netbios_name));
1436 /* add to the trusted domain cache */
1438 d.name = discard_const_p(char, trust->netbios_name);
1439 d.alt_name = discard_const_p(char, trust->dns_name);
1442 sid_copy(&d.sid, trust->sid);
1444 sid_copy(&d.sid, &global_sid_NULL);
1447 if ( domain->primary ) {
1448 DEBUG(10,("trusted_domains(ads): Searching "
1449 "trusted domain list of %s and storing "
1450 "trust flags for domain %s\n",
1451 domain->name, d.alt_name));
1453 d.domain_flags = trust->trust_flags;
1454 d.domain_type = trust->trust_type;
1455 d.domain_trust_attribs = trust->trust_attributes;
1457 wcache_tdc_add_domain( &d );
1459 } else if (domain_is_forest_root(domain)) {
1460 /* Check if we already have this record. If
1461 * we are following our forest root that is not
1462 * our primary domain, we want to keep trust
1463 * flags from the perspective of our primary
1464 * domain not our forest root. */
1465 struct winbindd_tdc_domain *exist = NULL;
1467 exist = wcache_tdc_fetch_domain(
1468 talloc_tos(), trust->netbios_name);
1470 DEBUG(10,("trusted_domains(ads): Searching "
1471 "trusted domain list of %s and "
1472 "storing trust flags for domain "
1473 "%s\n", domain->name, d.alt_name));
1474 d.domain_flags = trust->trust_flags;
1475 d.domain_type = trust->trust_type;
1476 d.domain_trust_attribs =
1477 trust->trust_attributes;
1479 wcache_tdc_add_domain( &d );
1484 /* This gets a little tricky. If we are
1485 following a transitive forest trust, then
1486 innerit the flags, type, and attribs from
1487 the domain we queried to make sure we don't
1488 record the view of the trust from the wrong
1489 side. Always view it from the side of our
1490 primary domain. --jerry */
1491 struct winbindd_tdc_domain *parent = NULL;
1493 DEBUG(10,("trusted_domains(ads): Searching "
1494 "trusted domain list of %s and inheriting "
1495 "trust flags for domain %s\n",
1496 domain->name, d.alt_name));
1498 parent = wcache_tdc_fetch_domain(talloc_tos(),
1501 d.domain_flags = parent->trust_flags;
1502 d.domain_type = parent->trust_type;
1503 d.domain_trust_attribs = parent->trust_attribs;
1505 d.domain_flags = domain->domain_flags;
1506 d.domain_type = domain->domain_type;
1507 d.domain_trust_attribs =
1508 domain->domain_trust_attribs;
1510 TALLOC_FREE(parent);
1513 * We need to pass the modified properties
1516 trust->trust_flags = d.domain_flags;
1517 trust->trust_type = d.domain_type;
1518 trust->trust_attributes = d.domain_trust_attribs;
1520 wcache_tdc_add_domain( &d );
1527 /* the ADS backend methods are exposed via this structure */
1528 struct winbindd_methods ads_methods = {