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 "winbindd_ads.h"
27 #include "libsmb/namequery.h"
28 #include "rpc_client/rpc_client.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../libds/common/flags.h"
32 #include "../libcli/ldap/ldap_ndr.h"
33 #include "../libcli/security/security.h"
34 #include "../libds/common/flag_mapping.h"
35 #include "libsmb/samlogon_cache.h"
41 #define DBGC_CLASS DBGC_WINBIND
43 extern struct winbindd_methods reconnect_methods;
44 extern struct winbindd_methods msrpc_methods;
46 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
49 * Check if cached connection can be reused. If the connection cannot
50 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
52 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
55 ADS_STRUCT *ads = *adsp;
59 time_t now = time(NULL);
61 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
63 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
64 "is now %d)\n", (uint32_t)expire - (uint32_t)now,
65 (uint32_t) expire, (uint32_t) now));
67 if ( ads->config.realm && (expire > now)) {
70 /* we own this ADS_STRUCT so make sure it goes away */
71 DEBUG(7,("Deleting expired krb5 credential cache\n"));
74 ads_kdestroy(WINBIND_CCACHE_NAME);
81 * @brief Establish a connection to a DC
83 * @param[out] adsp ADS_STRUCT that will be created
84 * @param[in] target_realm Realm of domain to connect to
85 * @param[in] target_dom_name 'workgroup' name of domain to connect to
86 * @param[in] ldap_server DNS name of server to connect to
87 * @param[in] password Our machine acount secret
88 * @param[in] auth_realm Realm of local domain for creating krb token
89 * @param[in] renewable Renewable ticket time
93 static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
94 const char *target_realm,
95 const char *target_dom_name,
96 const char *ldap_server,
103 struct sockaddr_storage dc_ss;
106 if (auth_realm == NULL) {
107 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
110 /* we don't want this to affect the users ccache */
111 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
113 ads = ads_init(target_realm, target_dom_name, ldap_server);
115 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
116 return ADS_ERROR(LDAP_NO_MEMORY);
119 SAFE_FREE(ads->auth.password);
120 SAFE_FREE(ads->auth.realm);
122 ads->auth.renewable = renewable;
123 ads->auth.password = password;
125 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
127 ads->auth.realm = SMB_STRDUP(auth_realm);
128 if (!strupper_m(ads->auth.realm)) {
130 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
133 /* Setup the server affinity cache. We don't reaally care
134 about the name. Just setup affinity and the KRB5_CONFIG
136 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
138 status = ads_connect(ads);
139 if (!ADS_ERR_OK(status)) {
140 DEBUG(1,("ads_connect for domain %s failed: %s\n",
141 target_dom_name, ads_errstr(status)));
146 /* set the flag that says we don't own the memory even
147 though we do so that ads_destroy() won't destroy the
148 structure we pass back by reference */
150 ads->is_mine = False;
157 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
159 char *ldap_server, *realm, *password;
160 struct winbindd_domain *wb_dom;
165 * Make sure we never try to use LDAP against
166 * a trusted domain as AD DC.
168 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
171 ads_cached_connection_reuse(adsp);
177 * At this point we only have the NetBIOS domain name.
178 * Check if we can get server nam and realm from SAF cache
179 * and the domain list.
181 ldap_server = saf_fetch(talloc_tos(), dom_name);
182 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
183 ldap_server ? ldap_server : ""));
185 wb_dom = find_domain_from_name(dom_name);
186 if (wb_dom == NULL) {
187 DEBUG(10, ("could not find domain '%s'\n", dom_name));
188 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
191 DEBUG(10, ("find_domain_from_name found realm '%s' for "
192 " domain '%s'\n", wb_dom->alt_name, dom_name));
194 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
195 TALLOC_FREE(ldap_server);
196 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
200 SMB_ASSERT(wb_dom->alt_name != NULL);
201 realm = SMB_STRDUP(wb_dom->alt_name);
203 struct winbindd_domain *our_domain = wb_dom;
205 /* always give preference to the alt_name in our
206 primary domain if possible */
208 if (!wb_dom->primary) {
209 our_domain = find_our_domain();
212 if (our_domain->alt_name != NULL) {
213 realm = SMB_STRDUP(our_domain->alt_name);
215 realm = SMB_STRDUP(lp_realm());
219 status = ads_cached_connection_connect(
220 adsp, /* Returns ads struct. */
221 wb_dom->alt_name, /* realm to connect to. */
222 dom_name, /* 'workgroup' name for ads_init */
223 ldap_server, /* DNS name to connect to. */
224 password, /* password for auth realm. */
225 realm, /* realm used for krb5 ticket. */
226 0); /* renewable ticket time. */
229 TALLOC_FREE(ldap_server);
235 return our ads connections structure for a domain. We keep the connection
236 open to make things faster
238 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
241 char *password, *realm;
245 * Make sure we never try to use LDAP against
246 * a trusted domain as AD DC.
251 DEBUG(10,("ads_cached_connection\n"));
252 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
254 if (domain->private_data) {
255 return (ADS_STRUCT *)domain->private_data;
258 /* the machine acct password might have change - fetch it every time */
260 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
265 SMB_ASSERT(domain->alt_name != NULL);
266 realm = SMB_STRDUP(domain->alt_name);
269 struct winbindd_domain *our_domain = domain;
272 /* always give preference to the alt_name in our
273 primary domain if possible */
275 if ( !domain->primary )
276 our_domain = find_our_domain();
278 if (our_domain->alt_name != NULL) {
279 realm = SMB_STRDUP( our_domain->alt_name );
282 realm = SMB_STRDUP( lp_realm() );
285 status = ads_cached_connection_connect(
286 (ADS_STRUCT **)&domain->private_data,
290 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
293 if (!ADS_ERR_OK(status)) {
294 /* if we get ECONNREFUSED then it might be a NT4
295 server, fall back to MSRPC */
296 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
297 status.err.rc == ECONNREFUSED) {
298 /* 'reconnect_methods' is the MS-RPC backend. */
299 DEBUG(1,("Trying MSRPC methods\n"));
300 domain->backend = &reconnect_methods;
305 return (ADS_STRUCT *)domain->private_data;
308 /* Query display info for a realm. This is the basic user list fn */
309 static NTSTATUS query_user_list(struct winbindd_domain *domain,
313 ADS_STRUCT *ads = NULL;
314 const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
316 uint32_t *rids = NULL;
318 LDAPMessage *res = NULL;
319 LDAPMessage *msg = NULL;
320 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
322 DEBUG(3,("ads: query_user_list\n"));
324 if ( !winbindd_can_contact_domain( domain ) ) {
325 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
330 ads = ads_cached_connection(domain);
333 domain->last_status = NT_STATUS_SERVER_DISABLED;
337 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
338 if (!ADS_ERR_OK(rc)) {
339 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
340 status = ads_ntstatus(rc);
343 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
347 count = ads_count_replies(ads, res);
349 DEBUG(1,("query_user_list: No users found\n"));
353 rids = talloc_zero_array(mem_ctx, uint32_t, count);
355 status = NT_STATUS_NO_MEMORY;
361 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
362 struct dom_sid user_sid;
366 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
368 DBG_INFO("Object lacks sAMAccountType attribute\n");
371 if (ds_atype_map(atype) != SID_NAME_USER) {
372 DBG_INFO("Not a user account? atype=0x%x\n", atype);
376 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
377 char *dn = ads_get_dn(ads, talloc_tos(), msg);
378 DBG_INFO("No sid for %s !?\n", dn);
383 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
384 struct dom_sid_buf sidstr, domstr;
385 DBG_WARNING("Got sid %s in domain %s\n",
386 dom_sid_str_buf(&user_sid, &sidstr),
387 dom_sid_str_buf(&domain->sid, &domstr));
391 sid_split_rid(&user_sid, &rids[count]);
395 rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
400 status = NT_STATUS_OK;
402 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
408 /* list all domain groups */
409 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
411 uint32_t *num_entries,
412 struct wb_acct_info **info)
414 ADS_STRUCT *ads = NULL;
415 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
416 "name", "objectSid", NULL};
419 LDAPMessage *res = NULL;
420 LDAPMessage *msg = NULL;
421 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
423 bool enum_dom_local_groups = False;
427 DEBUG(3,("ads: enum_dom_groups\n"));
429 if ( !winbindd_can_contact_domain( domain ) ) {
430 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
435 /* only grab domain local groups for our domain */
436 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
437 enum_dom_local_groups = True;
440 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
443 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
444 * default value, it MUST be absent. In case of extensible matching the
445 * "dnattr" boolean defaults to FALSE and so it must be only be present
448 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
449 * filter using bitwise matching rule then the buggy AD fails to decode
450 * the extensible match. As a workaround set it to TRUE and thereby add
451 * the dnAttributes "dn" field to cope with those older AD versions.
452 * It should not harm and won't put any additional load on the AD since
453 * none of the dn components have a bitmask-attribute.
455 * Thanks to Ralf Haferkamp for input and testing - Guenther */
457 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
458 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
459 ADS_LDAP_MATCHING_RULE_BIT_AND,
460 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
462 if (filter == NULL) {
463 status = NT_STATUS_NO_MEMORY;
467 ads = ads_cached_connection(domain);
470 domain->last_status = NT_STATUS_SERVER_DISABLED;
474 rc = ads_search_retry(ads, &res, filter, attrs);
475 if (!ADS_ERR_OK(rc)) {
476 status = ads_ntstatus(rc);
477 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
480 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
484 count = ads_count_replies(ads, res);
486 DEBUG(1,("enum_dom_groups: No groups found\n"));
490 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
492 status = NT_STATUS_NO_MEMORY;
498 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
503 name = ads_pull_username(ads, (*info), msg);
504 gecos = ads_pull_string(ads, (*info), msg, "name");
505 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
506 DEBUG(1,("No sid for %s !?\n", name));
510 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
511 DEBUG(1,("No rid for %s !?\n", name));
515 (*info)[i].acct_name = name;
516 (*info)[i].acct_desc = gecos;
517 (*info)[i].rid = rid;
523 status = NT_STATUS_OK;
525 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
529 ads_msgfree(ads, res);
534 /* list all domain local groups */
535 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
537 uint32_t *num_entries,
538 struct wb_acct_info **info)
541 * This is a stub function only as we returned the domain
542 * local groups in enum_dom_groups() if the domain->native field
543 * was true. This is a simple performance optimization when
546 * if we ever need to enumerate domain local groups separately,
547 * then this optimization in enum_dom_groups() will need
555 /* convert a single name to a sid in a domain - use rpc methods */
556 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
558 const char *domain_name,
561 const char **pdom_name,
563 enum lsa_SidType *type)
565 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
566 flags, pdom_name, sid, type);
569 /* convert a domain SID to a user or group name - use rpc methods */
570 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
572 const struct dom_sid *sid,
575 enum lsa_SidType *type)
577 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
578 domain_name, name, type);
581 /* convert a list of rids to names - use rpc methods */
582 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
584 const struct dom_sid *sid,
589 enum lsa_SidType **types)
591 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
593 domain_name, names, types);
596 /* Lookup groups a user is a member of - alternate method, for when
597 tokenGroups are not available. */
598 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
601 struct dom_sid *primary_group,
602 uint32_t *p_num_groups, struct dom_sid **user_sids)
605 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
607 LDAPMessage *res = NULL;
608 LDAPMessage *msg = NULL;
611 const char *group_attrs[] = {"objectSid", NULL};
613 uint32_t num_groups = 0;
615 DEBUG(3,("ads: lookup_usergroups_member\n"));
617 if ( !winbindd_can_contact_domain( domain ) ) {
618 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
623 ads = ads_cached_connection(domain);
626 domain->last_status = NT_STATUS_SERVER_DISABLED;
630 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
631 status = NT_STATUS_NO_MEMORY;
635 ldap_exp = talloc_asprintf(mem_ctx,
636 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
638 ADS_LDAP_MATCHING_RULE_BIT_AND,
639 GROUP_TYPE_SECURITY_ENABLED);
641 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
642 TALLOC_FREE(escaped_dn);
643 status = NT_STATUS_NO_MEMORY;
647 TALLOC_FREE(escaped_dn);
649 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
651 if (!ADS_ERR_OK(rc)) {
652 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
653 return ads_ntstatus(rc);
655 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
656 return NT_STATUS_INTERNAL_ERROR;
660 count = ads_count_replies(ads, res);
665 /* always add the primary group to the sid array */
666 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
668 if (!NT_STATUS_IS_OK(status)) {
673 for (msg = ads_first_entry(ads, res); msg;
674 msg = ads_next_entry(ads, msg)) {
675 struct dom_sid group_sid;
677 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
678 DEBUG(1,("No sid for this group ?!?\n"));
682 /* ignore Builtin groups from ADS - Guenther */
683 if (sid_check_is_in_builtin(&group_sid)) {
687 status = add_sid_to_array(mem_ctx, &group_sid,
688 user_sids, &num_groups);
689 if (!NT_STATUS_IS_OK(status)) {
696 *p_num_groups = num_groups;
697 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
699 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
702 ads_msgfree(ads, res);
707 /* Lookup groups a user is a member of - alternate method, for when
708 tokenGroups are not available. */
709 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
712 struct dom_sid *primary_group,
713 uint32_t *p_num_groups,
714 struct dom_sid **user_sids)
717 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
719 const char *attrs[] = {"memberOf", NULL};
720 uint32_t num_groups = 0;
721 struct dom_sid *group_sids = NULL;
723 char **strings = NULL;
724 size_t num_strings = 0, num_sids = 0;
727 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
729 if ( !winbindd_can_contact_domain( domain ) ) {
730 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
731 "domain %s\n", domain->name));
735 ads = ads_cached_connection(domain);
738 domain->last_status = NT_STATUS_SERVER_DISABLED;
739 return NT_STATUS_UNSUCCESSFUL;
742 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
743 ADS_EXTENDED_DN_HEX_STRING,
744 &strings, &num_strings);
746 if (!ADS_ERR_OK(rc)) {
747 DEBUG(1,("lookup_usergroups_memberof ads_search "
748 "member=%s: %s\n", user_dn, ads_errstr(rc)));
749 return ads_ntstatus(rc);
755 /* always add the primary group to the sid array */
756 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
758 if (!NT_STATUS_IS_OK(status)) {
762 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
764 status = NT_STATUS_NO_MEMORY;
768 for (i=0; i<num_strings; i++) {
769 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
770 ADS_EXTENDED_DN_HEX_STRING,
772 if (!ADS_ERR_OK(rc)) {
773 /* ignore members without SIDs */
774 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
775 NT_STATUS_NOT_FOUND)) {
779 status = ads_ntstatus(rc);
787 DEBUG(1,("No memberOf for this user?!?\n"));
788 status = NT_STATUS_NO_MEMORY;
792 for (i=0; i<num_sids; i++) {
794 /* ignore Builtin groups from ADS - Guenther */
795 if (sid_check_is_in_builtin(&group_sids[i])) {
799 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
801 if (!NT_STATUS_IS_OK(status)) {
807 *p_num_groups = num_groups;
808 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
810 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
814 TALLOC_FREE(strings);
815 TALLOC_FREE(group_sids);
821 /* Lookup groups a user is a member of. */
822 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
824 const struct dom_sid *sid,
825 uint32_t *p_num_groups, struct dom_sid **user_sids)
827 ADS_STRUCT *ads = NULL;
828 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
831 LDAPMessage *msg = NULL;
832 char *user_dn = NULL;
833 struct dom_sid *sids;
835 struct dom_sid primary_group;
836 uint32_t primary_group_rid;
837 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
838 uint32_t num_groups = 0;
839 struct dom_sid_buf buf;
841 DEBUG(3,("ads: lookup_usergroups\n"));
844 status = lookup_usergroups_cached(mem_ctx, sid,
845 p_num_groups, user_sids);
846 if (NT_STATUS_IS_OK(status)) {
850 if ( !winbindd_can_contact_domain( domain ) ) {
851 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
854 /* Tell the cache manager not to remember this one */
856 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
859 ads = ads_cached_connection(domain);
862 domain->last_status = NT_STATUS_SERVER_DISABLED;
863 status = NT_STATUS_SERVER_DISABLED;
867 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
869 if (!ADS_ERR_OK(rc)) {
870 status = ads_ntstatus(rc);
871 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
873 dom_sid_str_buf(sid, &buf),
878 count = ads_count_replies(ads, msg);
880 status = NT_STATUS_UNSUCCESSFUL;
881 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
882 "invalid number of results (count=%d)\n",
883 dom_sid_str_buf(sid, &buf),
889 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
890 dom_sid_str_buf(sid, &buf)));
891 status = NT_STATUS_UNSUCCESSFUL;
895 user_dn = ads_get_dn(ads, mem_ctx, msg);
896 if (user_dn == NULL) {
897 status = NT_STATUS_NO_MEMORY;
901 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
902 DEBUG(1,("%s: No primary group for sid=%s !?\n",
904 dom_sid_str_buf(sid, &buf)));
908 sid_compose(&primary_group, &domain->sid, primary_group_rid);
910 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
912 /* there must always be at least one group in the token,
913 unless we are talking to a buggy Win2k server */
915 /* actually this only happens when the machine account has no read
916 * permissions on the tokenGroup attribute - gd */
922 /* lookup what groups this user is a member of by DN search on
925 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
927 &num_groups, user_sids);
928 *p_num_groups = num_groups;
929 if (NT_STATUS_IS_OK(status)) {
933 /* lookup what groups this user is a member of by DN search on
936 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
938 &num_groups, user_sids);
939 *p_num_groups = num_groups;
946 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
948 if (!NT_STATUS_IS_OK(status)) {
952 for (i=0;i<count;i++) {
954 /* ignore Builtin groups from ADS - Guenther */
955 if (sid_check_is_in_builtin(&sids[i])) {
959 status = add_sid_to_array_unique(mem_ctx, &sids[i],
960 user_sids, &num_groups);
961 if (!NT_STATUS_IS_OK(status)) {
966 *p_num_groups = (uint32_t)num_groups;
967 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
969 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
970 dom_sid_str_buf(sid, &buf)));
972 TALLOC_FREE(user_dn);
973 ads_msgfree(ads, msg);
977 /* Lookup aliases a user is member of - use rpc methods */
978 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
980 uint32_t num_sids, const struct dom_sid *sids,
981 uint32_t *num_aliases, uint32_t **alias_rids)
983 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
984 num_aliases, alias_rids);
987 static NTSTATUS add_primary_group_members(
988 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
989 char ***all_members, size_t *num_all_members)
992 NTSTATUS status = NT_STATUS_NO_MEMORY;
994 const char *attrs[] = { "dn", NULL };
995 LDAPMessage *res = NULL;
1001 filter = talloc_asprintf(
1002 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1004 if (filter == NULL) {
1008 args.control = ADS_EXTENDED_DN_OID;
1009 args.val = ADS_EXTENDED_DN_HEX_STRING;
1010 args.critical = True;
1012 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1013 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1016 if (!ADS_ERR_OK(rc)) {
1017 status = ads_ntstatus(rc);
1018 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1022 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1026 num_members = ads_count_replies(ads, res);
1028 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1029 (uintmax_t)num_members));
1031 if (num_members == 0) {
1032 status = NT_STATUS_OK;
1036 members = talloc_realloc(mem_ctx, *all_members, char *,
1037 *num_all_members + num_members);
1038 if (members == NULL) {
1039 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1042 *all_members = members;
1044 for (msg = ads_first_entry(ads, res); msg != NULL;
1045 msg = ads_next_entry(ads, msg)) {
1048 dn = ads_get_dn(ads, members, msg);
1050 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1054 members[*num_all_members] = dn;
1055 *num_all_members += 1;
1058 status = NT_STATUS_OK;
1061 ads_msgfree(ads, res);
1063 TALLOC_FREE(filter);
1068 find the members of a group, given a group rid and domain
1070 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1071 TALLOC_CTX *mem_ctx,
1072 const struct dom_sid *group_sid,
1073 enum lsa_SidType type,
1074 uint32_t *num_names,
1075 struct dom_sid **sid_mem, char ***names,
1076 uint32_t **name_types)
1079 ADS_STRUCT *ads = NULL;
1081 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1083 char **members = NULL;
1085 size_t num_members = 0;
1087 struct dom_sid *sid_mem_nocache = NULL;
1088 char **names_nocache = NULL;
1089 enum lsa_SidType *name_types_nocache = NULL;
1090 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1091 uint32_t num_nocache = 0;
1092 TALLOC_CTX *tmp_ctx = NULL;
1094 struct dom_sid_buf buf;
1096 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1097 dom_sid_str_buf(group_sid, &buf)));
1101 tmp_ctx = talloc_new(mem_ctx);
1103 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1104 status = NT_STATUS_NO_MEMORY;
1108 if (!sid_peek_rid(group_sid, &rid)) {
1109 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1110 status = NT_STATUS_INVALID_PARAMETER;
1114 if ( !winbindd_can_contact_domain( domain ) ) {
1115 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1117 return NT_STATUS_OK;
1120 ads = ads_cached_connection(domain);
1123 domain->last_status = NT_STATUS_SERVER_DISABLED;
1127 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1128 status = NT_STATUS_NO_MEMORY;
1132 /* search for all members of the group */
1133 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1134 TALLOC_FREE(sidbinstr);
1135 if (ldap_exp == NULL) {
1136 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1137 status = NT_STATUS_NO_MEMORY;
1141 args.control = ADS_EXTENDED_DN_OID;
1142 args.val = ADS_EXTENDED_DN_HEX_STRING;
1143 args.critical = True;
1145 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1146 ldap_exp, &args, "member", &members, &num_members);
1148 if (!ADS_ERR_OK(rc)) {
1149 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1150 status = NT_STATUS_UNSUCCESSFUL;
1154 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1156 status = add_primary_group_members(ads, mem_ctx, rid,
1157 &members, &num_members);
1158 if (!NT_STATUS_IS_OK(status)) {
1159 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1160 __func__, nt_errstr(status)));
1164 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1165 __func__, (int)num_members));
1167 /* Now that we have a list of sids, we need to get the
1168 * lists of names and name_types belonging to these sids.
1169 * even though conceptually not quite clean, we use the
1170 * RPC call lsa_lookup_sids for this since it can handle a
1171 * list of sids. ldap calls can just resolve one sid at a time.
1173 * At this stage, the sids are still hidden in the exetended dn
1174 * member output format. We actually do a little better than
1175 * stated above: In extracting the sids from the member strings,
1176 * we try to resolve as many sids as possible from the
1177 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1180 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1181 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1182 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1183 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1185 if ((members == NULL) || (*sid_mem == NULL) ||
1186 (*names == NULL) || (*name_types == NULL) ||
1187 (sid_mem_nocache == NULL))
1189 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1190 status = NT_STATUS_NO_MEMORY;
1197 (*name_types) = NULL;
1200 for (i=0; i<num_members; i++) {
1201 enum lsa_SidType name_type;
1202 char *name, *domain_name;
1205 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1207 if (!ADS_ERR_OK(rc)) {
1208 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1209 NT_STATUS_NOT_FOUND)) {
1210 /* Group members can be objects, like Exchange
1211 * Public Folders, that don't have a SID. Skip
1216 status = ads_ntstatus(rc);
1220 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1222 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1224 dom_sid_str_buf(&sid, &buf)));
1225 sid_copy(&(*sid_mem)[*num_names], &sid);
1226 (*names)[*num_names] = fill_domain_username_talloc(
1232 (*name_types)[*num_names] = name_type;
1236 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1238 dom_sid_str_buf(&sid, &buf)));
1239 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1244 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1245 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1247 /* handle sids not resolved from cache by lsa_lookup_sids */
1248 if (num_nocache > 0) {
1250 status = winbindd_lookup_sids(tmp_ctx,
1256 &name_types_nocache);
1258 if (!(NT_STATUS_IS_OK(status) ||
1259 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1260 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1262 DEBUG(1, ("lsa_lookupsids call failed with %s "
1263 "- retrying...\n", nt_errstr(status)));
1265 status = winbindd_lookup_sids(tmp_ctx,
1271 &name_types_nocache);
1274 if (NT_STATUS_IS_OK(status) ||
1275 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1277 /* Copy the entries over from the "_nocache" arrays
1278 * to the result arrays, skipping the gaps the
1279 * lookup_sids call left. */
1280 for (i=0; i < num_nocache; i++) {
1281 if (((names_nocache)[i] != NULL) &&
1282 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1284 sid_copy(&(*sid_mem)[*num_names],
1285 &sid_mem_nocache[i]);
1286 (*names)[*num_names] =
1287 fill_domain_username_talloc(
1292 (*name_types)[*num_names] = name_types_nocache[i];
1297 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1298 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1299 "not map any SIDs at all.\n"));
1300 /* Don't handle this as an error here.
1301 * There is nothing left to do with respect to the
1302 * overall result... */
1304 else if (!NT_STATUS_IS_OK(status)) {
1305 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1306 "sids via rpc_lsa_lookup_sids: %s\n",
1307 (int)num_members, nt_errstr(status)));
1312 status = NT_STATUS_OK;
1313 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1314 dom_sid_str_buf(group_sid, &buf)));
1318 TALLOC_FREE(tmp_ctx);
1323 /* find the sequence number for a domain */
1324 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1326 ADS_STRUCT *ads = NULL;
1329 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1331 if ( !winbindd_can_contact_domain( domain ) ) {
1332 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1335 return NT_STATUS_OK;
1339 DEBUG(10,("sequence: Avoid LDAP connection for domain %s\n",
1342 return NT_STATUS_OK;
1345 *seq = DOM_SEQUENCE_NONE;
1347 ads = ads_cached_connection(domain);
1350 domain->last_status = NT_STATUS_SERVER_DISABLED;
1351 return NT_STATUS_UNSUCCESSFUL;
1354 rc = ads_USN(ads, seq);
1356 if (!ADS_ERR_OK(rc)) {
1358 /* its a dead connection, destroy it */
1360 if (domain->private_data) {
1361 ads = (ADS_STRUCT *)domain->private_data;
1362 ads->is_mine = True;
1364 ads_kdestroy(WINBIND_CCACHE_NAME);
1365 domain->private_data = NULL;
1368 return ads_ntstatus(rc);
1371 /* find the lockout policy of a domain - use rpc methods */
1372 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1373 TALLOC_CTX *mem_ctx,
1374 struct samr_DomInfo12 *policy)
1376 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1379 /* find the password policy of a domain - use rpc methods */
1380 static NTSTATUS password_policy(struct winbindd_domain *domain,
1381 TALLOC_CTX *mem_ctx,
1382 struct samr_DomInfo1 *policy)
1384 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1387 /* get a list of trusted domains */
1388 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1389 TALLOC_CTX *mem_ctx,
1390 struct netr_DomainTrustList *trusts)
1392 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1396 struct rpc_pipe_client *cli;
1398 struct dcerpc_binding_handle *b;
1400 DEBUG(3,("ads: trusted_domains\n"));
1402 ZERO_STRUCTP(trusts);
1404 /* If this is our primary domain or a root in our forest,
1405 query for all trusts. If not, then just look for domain
1406 trusts in the target forest */
1408 if (domain->primary || domain_is_forest_root(domain)) {
1409 flags = NETR_TRUST_FLAG_OUTBOUND |
1410 NETR_TRUST_FLAG_INBOUND |
1411 NETR_TRUST_FLAG_IN_FOREST;
1413 flags = NETR_TRUST_FLAG_IN_FOREST;
1416 result = cm_connect_netlogon(domain, &cli);
1418 if (!NT_STATUS_IS_OK(result)) {
1419 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1420 "for PIPE_NETLOGON (%s)\n",
1421 domain->name, nt_errstr(result)));
1422 return NT_STATUS_UNSUCCESSFUL;
1425 b = cli->binding_handle;
1427 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1432 if (!NT_STATUS_IS_OK(result)) {
1436 if (!W_ERROR_IS_OK(werr)) {
1437 return werror_to_ntstatus(werr);
1439 if (trusts->count == 0) {
1440 return NT_STATUS_OK;
1443 /* Copy across names and sids */
1446 for (i = 0; i < trusts->count; i++) {
1447 struct netr_DomainTrust *trust = &trusts->array[i];
1448 struct winbindd_domain d;
1453 * drop external trusts if this is not our primary
1454 * domain. This means that the returned number of
1455 * domains may be less that the ones actually trusted
1459 if ((trust->trust_attributes
1460 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1463 DEBUG(10,("trusted_domains: Skipping external trusted "
1464 "domain %s because it is outside of our "
1466 trust->netbios_name));
1470 /* add to the trusted domain cache */
1472 d.name = discard_const_p(char, trust->netbios_name);
1473 d.alt_name = discard_const_p(char, trust->dns_name);
1476 sid_copy(&d.sid, trust->sid);
1478 sid_copy(&d.sid, &global_sid_NULL);
1481 if ( domain->primary ) {
1482 DEBUG(10,("trusted_domains(ads): Searching "
1483 "trusted domain list of %s and storing "
1484 "trust flags for domain %s\n",
1485 domain->name, d.alt_name));
1487 d.domain_flags = trust->trust_flags;
1488 d.domain_type = trust->trust_type;
1489 d.domain_trust_attribs = trust->trust_attributes;
1491 wcache_tdc_add_domain( &d );
1493 } else if (domain_is_forest_root(domain)) {
1494 /* Check if we already have this record. If
1495 * we are following our forest root that is not
1496 * our primary domain, we want to keep trust
1497 * flags from the perspective of our primary
1498 * domain not our forest root. */
1499 struct winbindd_tdc_domain *exist = NULL;
1501 exist = wcache_tdc_fetch_domain(
1502 talloc_tos(), trust->netbios_name);
1504 DEBUG(10,("trusted_domains(ads): Searching "
1505 "trusted domain list of %s and "
1506 "storing trust flags for domain "
1507 "%s\n", domain->name, d.alt_name));
1508 d.domain_flags = trust->trust_flags;
1509 d.domain_type = trust->trust_type;
1510 d.domain_trust_attribs =
1511 trust->trust_attributes;
1513 wcache_tdc_add_domain( &d );
1518 /* This gets a little tricky. If we are
1519 following a transitive forest trust, then
1520 innerit the flags, type, and attribs from
1521 the domain we queried to make sure we don't
1522 record the view of the trust from the wrong
1523 side. Always view it from the side of our
1524 primary domain. --jerry */
1525 struct winbindd_tdc_domain *parent = NULL;
1527 DEBUG(10,("trusted_domains(ads): Searching "
1528 "trusted domain list of %s and inheriting "
1529 "trust flags for domain %s\n",
1530 domain->name, d.alt_name));
1532 parent = wcache_tdc_fetch_domain(talloc_tos(),
1535 d.domain_flags = parent->trust_flags;
1536 d.domain_type = parent->trust_type;
1537 d.domain_trust_attribs = parent->trust_attribs;
1539 d.domain_flags = domain->domain_flags;
1540 d.domain_type = domain->domain_type;
1541 d.domain_trust_attribs =
1542 domain->domain_trust_attribs;
1544 TALLOC_FREE(parent);
1547 * We need to pass the modified properties
1550 trust->trust_flags = d.domain_flags;
1551 trust->trust_type = d.domain_type;
1552 trust->trust_attributes = d.domain_trust_attribs;
1554 wcache_tdc_add_domain( &d );
1561 /* the ADS backend methods are exposed via this structure */
1562 struct winbindd_methods ads_methods = {