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,
562 enum lsa_SidType *type)
564 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
568 /* convert a domain SID to a user or group name - use rpc methods */
569 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
571 const struct dom_sid *sid,
574 enum lsa_SidType *type)
576 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
577 domain_name, name, type);
580 /* convert a list of rids to names - use rpc methods */
581 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
583 const struct dom_sid *sid,
588 enum lsa_SidType **types)
590 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
592 domain_name, names, types);
595 /* Lookup groups a user is a member of - alternate method, for when
596 tokenGroups are not available. */
597 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
600 struct dom_sid *primary_group,
601 uint32_t *p_num_groups, struct dom_sid **user_sids)
604 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
606 LDAPMessage *res = NULL;
607 LDAPMessage *msg = NULL;
610 const char *group_attrs[] = {"objectSid", NULL};
612 uint32_t num_groups = 0;
614 DEBUG(3,("ads: lookup_usergroups_member\n"));
616 if ( !winbindd_can_contact_domain( domain ) ) {
617 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
622 ads = ads_cached_connection(domain);
625 domain->last_status = NT_STATUS_SERVER_DISABLED;
629 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
630 status = NT_STATUS_NO_MEMORY;
634 ldap_exp = talloc_asprintf(mem_ctx,
635 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
637 ADS_LDAP_MATCHING_RULE_BIT_AND,
638 GROUP_TYPE_SECURITY_ENABLED);
640 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
641 TALLOC_FREE(escaped_dn);
642 status = NT_STATUS_NO_MEMORY;
646 TALLOC_FREE(escaped_dn);
648 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
650 if (!ADS_ERR_OK(rc)) {
651 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
652 return ads_ntstatus(rc);
654 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
655 return NT_STATUS_INTERNAL_ERROR;
659 count = ads_count_replies(ads, res);
664 /* always add the primary group to the sid array */
665 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
667 if (!NT_STATUS_IS_OK(status)) {
672 for (msg = ads_first_entry(ads, res); msg;
673 msg = ads_next_entry(ads, msg)) {
674 struct dom_sid group_sid;
676 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
677 DEBUG(1,("No sid for this group ?!?\n"));
681 /* ignore Builtin groups from ADS - Guenther */
682 if (sid_check_is_in_builtin(&group_sid)) {
686 status = add_sid_to_array(mem_ctx, &group_sid,
687 user_sids, &num_groups);
688 if (!NT_STATUS_IS_OK(status)) {
695 *p_num_groups = num_groups;
696 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
698 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
701 ads_msgfree(ads, res);
706 /* Lookup groups a user is a member of - alternate method, for when
707 tokenGroups are not available. */
708 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
711 struct dom_sid *primary_group,
712 uint32_t *p_num_groups,
713 struct dom_sid **user_sids)
716 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
718 const char *attrs[] = {"memberOf", NULL};
719 uint32_t num_groups = 0;
720 struct dom_sid *group_sids = NULL;
722 char **strings = NULL;
723 size_t num_strings = 0, num_sids = 0;
726 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
728 if ( !winbindd_can_contact_domain( domain ) ) {
729 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
730 "domain %s\n", domain->name));
734 ads = ads_cached_connection(domain);
737 domain->last_status = NT_STATUS_SERVER_DISABLED;
738 return NT_STATUS_UNSUCCESSFUL;
741 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
742 ADS_EXTENDED_DN_HEX_STRING,
743 &strings, &num_strings);
745 if (!ADS_ERR_OK(rc)) {
746 DEBUG(1,("lookup_usergroups_memberof ads_search "
747 "member=%s: %s\n", user_dn, ads_errstr(rc)));
748 return ads_ntstatus(rc);
754 /* always add the primary group to the sid array */
755 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
757 if (!NT_STATUS_IS_OK(status)) {
761 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
763 status = NT_STATUS_NO_MEMORY;
767 for (i=0; i<num_strings; i++) {
768 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
769 ADS_EXTENDED_DN_HEX_STRING,
771 if (!ADS_ERR_OK(rc)) {
772 /* ignore members without SIDs */
773 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
774 NT_STATUS_NOT_FOUND)) {
778 status = ads_ntstatus(rc);
786 DEBUG(1,("No memberOf for this user?!?\n"));
787 status = NT_STATUS_NO_MEMORY;
791 for (i=0; i<num_sids; i++) {
793 /* ignore Builtin groups from ADS - Guenther */
794 if (sid_check_is_in_builtin(&group_sids[i])) {
798 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
800 if (!NT_STATUS_IS_OK(status)) {
806 *p_num_groups = num_groups;
807 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
809 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
813 TALLOC_FREE(strings);
814 TALLOC_FREE(group_sids);
820 /* Lookup groups a user is a member of. */
821 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
823 const struct dom_sid *sid,
824 uint32_t *p_num_groups, struct dom_sid **user_sids)
826 ADS_STRUCT *ads = NULL;
827 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
830 LDAPMessage *msg = NULL;
831 char *user_dn = NULL;
832 struct dom_sid *sids;
834 struct dom_sid primary_group;
835 uint32_t primary_group_rid;
836 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
837 uint32_t num_groups = 0;
838 struct dom_sid_buf buf;
840 DEBUG(3,("ads: lookup_usergroups\n"));
843 status = lookup_usergroups_cached(mem_ctx, sid,
844 p_num_groups, user_sids);
845 if (NT_STATUS_IS_OK(status)) {
849 if ( !winbindd_can_contact_domain( domain ) ) {
850 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
853 /* Tell the cache manager not to remember this one */
855 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
858 ads = ads_cached_connection(domain);
861 domain->last_status = NT_STATUS_SERVER_DISABLED;
862 status = NT_STATUS_SERVER_DISABLED;
866 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
868 if (!ADS_ERR_OK(rc)) {
869 status = ads_ntstatus(rc);
870 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
872 dom_sid_str_buf(sid, &buf),
877 count = ads_count_replies(ads, msg);
879 status = NT_STATUS_UNSUCCESSFUL;
880 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
881 "invalid number of results (count=%d)\n",
882 dom_sid_str_buf(sid, &buf),
888 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
889 dom_sid_str_buf(sid, &buf)));
890 status = NT_STATUS_UNSUCCESSFUL;
894 user_dn = ads_get_dn(ads, mem_ctx, msg);
895 if (user_dn == NULL) {
896 status = NT_STATUS_NO_MEMORY;
900 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
901 DEBUG(1,("%s: No primary group for sid=%s !?\n",
903 dom_sid_str_buf(sid, &buf)));
907 sid_compose(&primary_group, &domain->sid, primary_group_rid);
909 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
911 /* there must always be at least one group in the token,
912 unless we are talking to a buggy Win2k server */
914 /* actually this only happens when the machine account has no read
915 * permissions on the tokenGroup attribute - gd */
921 /* lookup what groups this user is a member of by DN search on
924 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
926 &num_groups, user_sids);
927 *p_num_groups = num_groups;
928 if (NT_STATUS_IS_OK(status)) {
932 /* lookup what groups this user is a member of by DN search on
935 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
937 &num_groups, user_sids);
938 *p_num_groups = num_groups;
945 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
947 if (!NT_STATUS_IS_OK(status)) {
951 for (i=0;i<count;i++) {
953 /* ignore Builtin groups from ADS - Guenther */
954 if (sid_check_is_in_builtin(&sids[i])) {
958 status = add_sid_to_array_unique(mem_ctx, &sids[i],
959 user_sids, &num_groups);
960 if (!NT_STATUS_IS_OK(status)) {
965 *p_num_groups = (uint32_t)num_groups;
966 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
968 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
969 dom_sid_str_buf(sid, &buf)));
971 TALLOC_FREE(user_dn);
972 ads_msgfree(ads, msg);
976 /* Lookup aliases a user is member of - use rpc methods */
977 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
979 uint32_t num_sids, const struct dom_sid *sids,
980 uint32_t *num_aliases, uint32_t **alias_rids)
982 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
983 num_aliases, alias_rids);
986 static NTSTATUS add_primary_group_members(
987 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
988 char ***all_members, size_t *num_all_members)
991 NTSTATUS status = NT_STATUS_NO_MEMORY;
993 const char *attrs[] = { "dn", NULL };
994 LDAPMessage *res = NULL;
1000 filter = talloc_asprintf(
1001 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1003 if (filter == NULL) {
1007 args.control = ADS_EXTENDED_DN_OID;
1008 args.val = ADS_EXTENDED_DN_HEX_STRING;
1009 args.critical = True;
1011 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1012 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1015 if (!ADS_ERR_OK(rc)) {
1016 status = ads_ntstatus(rc);
1017 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1021 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1025 num_members = ads_count_replies(ads, res);
1027 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1028 (uintmax_t)num_members));
1030 if (num_members == 0) {
1031 status = NT_STATUS_OK;
1035 members = talloc_realloc(mem_ctx, *all_members, char *,
1036 *num_all_members + num_members);
1037 if (members == NULL) {
1038 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1041 *all_members = members;
1043 for (msg = ads_first_entry(ads, res); msg != NULL;
1044 msg = ads_next_entry(ads, msg)) {
1047 dn = ads_get_dn(ads, members, msg);
1049 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1053 members[*num_all_members] = dn;
1054 *num_all_members += 1;
1057 status = NT_STATUS_OK;
1060 ads_msgfree(ads, res);
1062 TALLOC_FREE(filter);
1067 find the members of a group, given a group rid and domain
1069 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1070 TALLOC_CTX *mem_ctx,
1071 const struct dom_sid *group_sid,
1072 enum lsa_SidType type,
1073 uint32_t *num_names,
1074 struct dom_sid **sid_mem, char ***names,
1075 uint32_t **name_types)
1078 ADS_STRUCT *ads = NULL;
1080 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1082 char **members = NULL;
1084 size_t num_members = 0;
1086 struct dom_sid *sid_mem_nocache = NULL;
1087 char **names_nocache = NULL;
1088 enum lsa_SidType *name_types_nocache = NULL;
1089 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1090 uint32_t num_nocache = 0;
1091 TALLOC_CTX *tmp_ctx = NULL;
1093 struct dom_sid_buf buf;
1095 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1096 dom_sid_str_buf(group_sid, &buf)));
1100 tmp_ctx = talloc_new(mem_ctx);
1102 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1103 status = NT_STATUS_NO_MEMORY;
1107 if (!sid_peek_rid(group_sid, &rid)) {
1108 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1109 status = NT_STATUS_INVALID_PARAMETER;
1113 if ( !winbindd_can_contact_domain( domain ) ) {
1114 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1116 return NT_STATUS_OK;
1119 ads = ads_cached_connection(domain);
1122 domain->last_status = NT_STATUS_SERVER_DISABLED;
1126 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1127 status = NT_STATUS_NO_MEMORY;
1131 /* search for all members of the group */
1132 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1133 TALLOC_FREE(sidbinstr);
1134 if (ldap_exp == NULL) {
1135 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1136 status = NT_STATUS_NO_MEMORY;
1140 args.control = ADS_EXTENDED_DN_OID;
1141 args.val = ADS_EXTENDED_DN_HEX_STRING;
1142 args.critical = True;
1144 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1145 ldap_exp, &args, "member", &members, &num_members);
1147 if (!ADS_ERR_OK(rc)) {
1148 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1149 status = NT_STATUS_UNSUCCESSFUL;
1153 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1155 status = add_primary_group_members(ads, mem_ctx, rid,
1156 &members, &num_members);
1157 if (!NT_STATUS_IS_OK(status)) {
1158 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1159 __func__, nt_errstr(status)));
1163 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1164 __func__, (int)num_members));
1166 /* Now that we have a list of sids, we need to get the
1167 * lists of names and name_types belonging to these sids.
1168 * even though conceptually not quite clean, we use the
1169 * RPC call lsa_lookup_sids for this since it can handle a
1170 * list of sids. ldap calls can just resolve one sid at a time.
1172 * At this stage, the sids are still hidden in the exetended dn
1173 * member output format. We actually do a little better than
1174 * stated above: In extracting the sids from the member strings,
1175 * we try to resolve as many sids as possible from the
1176 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1179 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1180 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1181 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1182 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1184 if ((members == NULL) || (*sid_mem == NULL) ||
1185 (*names == NULL) || (*name_types == NULL) ||
1186 (sid_mem_nocache == NULL))
1188 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1189 status = NT_STATUS_NO_MEMORY;
1196 (*name_types) = NULL;
1199 for (i=0; i<num_members; i++) {
1200 enum lsa_SidType name_type;
1201 char *name, *domain_name;
1204 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1206 if (!ADS_ERR_OK(rc)) {
1207 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1208 NT_STATUS_NOT_FOUND)) {
1209 /* Group members can be objects, like Exchange
1210 * Public Folders, that don't have a SID. Skip
1215 status = ads_ntstatus(rc);
1219 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1221 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1223 dom_sid_str_buf(&sid, &buf)));
1224 sid_copy(&(*sid_mem)[*num_names], &sid);
1225 (*names)[*num_names] = fill_domain_username_talloc(
1231 (*name_types)[*num_names] = name_type;
1235 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1237 dom_sid_str_buf(&sid, &buf)));
1238 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1243 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1244 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1246 /* handle sids not resolved from cache by lsa_lookup_sids */
1247 if (num_nocache > 0) {
1249 status = winbindd_lookup_sids(tmp_ctx,
1255 &name_types_nocache);
1257 if (!(NT_STATUS_IS_OK(status) ||
1258 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1259 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1261 DEBUG(1, ("lsa_lookupsids call failed with %s "
1262 "- retrying...\n", nt_errstr(status)));
1264 status = winbindd_lookup_sids(tmp_ctx,
1270 &name_types_nocache);
1273 if (NT_STATUS_IS_OK(status) ||
1274 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1276 /* Copy the entries over from the "_nocache" arrays
1277 * to the result arrays, skipping the gaps the
1278 * lookup_sids call left. */
1279 for (i=0; i < num_nocache; i++) {
1280 if (((names_nocache)[i] != NULL) &&
1281 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1283 sid_copy(&(*sid_mem)[*num_names],
1284 &sid_mem_nocache[i]);
1285 (*names)[*num_names] =
1286 fill_domain_username_talloc(
1291 (*name_types)[*num_names] = name_types_nocache[i];
1296 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1297 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1298 "not map any SIDs at all.\n"));
1299 /* Don't handle this as an error here.
1300 * There is nothing left to do with respect to the
1301 * overall result... */
1303 else if (!NT_STATUS_IS_OK(status)) {
1304 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1305 "sids via rpc_lsa_lookup_sids: %s\n",
1306 (int)num_members, nt_errstr(status)));
1311 status = NT_STATUS_OK;
1312 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1313 dom_sid_str_buf(group_sid, &buf)));
1317 TALLOC_FREE(tmp_ctx);
1322 /* find the sequence number for a domain */
1323 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1325 ADS_STRUCT *ads = NULL;
1328 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1330 if ( !winbindd_can_contact_domain( domain ) ) {
1331 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1334 return NT_STATUS_OK;
1338 DEBUG(10,("sequence: Avoid LDAP connection for domain %s\n",
1341 return NT_STATUS_OK;
1344 *seq = DOM_SEQUENCE_NONE;
1346 ads = ads_cached_connection(domain);
1349 domain->last_status = NT_STATUS_SERVER_DISABLED;
1350 return NT_STATUS_UNSUCCESSFUL;
1353 rc = ads_USN(ads, seq);
1355 if (!ADS_ERR_OK(rc)) {
1357 /* its a dead connection, destroy it */
1359 if (domain->private_data) {
1360 ads = (ADS_STRUCT *)domain->private_data;
1361 ads->is_mine = True;
1363 ads_kdestroy(WINBIND_CCACHE_NAME);
1364 domain->private_data = NULL;
1367 return ads_ntstatus(rc);
1370 /* find the lockout policy of a domain - use rpc methods */
1371 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1372 TALLOC_CTX *mem_ctx,
1373 struct samr_DomInfo12 *policy)
1375 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1378 /* find the password policy of a domain - use rpc methods */
1379 static NTSTATUS password_policy(struct winbindd_domain *domain,
1380 TALLOC_CTX *mem_ctx,
1381 struct samr_DomInfo1 *policy)
1383 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1386 /* get a list of trusted domains */
1387 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1388 TALLOC_CTX *mem_ctx,
1389 struct netr_DomainTrustList *trusts)
1391 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1395 struct rpc_pipe_client *cli;
1397 struct dcerpc_binding_handle *b;
1399 DEBUG(3,("ads: trusted_domains\n"));
1401 ZERO_STRUCTP(trusts);
1403 /* If this is our primary domain or a root in our forest,
1404 query for all trusts. If not, then just look for domain
1405 trusts in the target forest */
1407 if (domain->primary || domain_is_forest_root(domain)) {
1408 flags = NETR_TRUST_FLAG_OUTBOUND |
1409 NETR_TRUST_FLAG_INBOUND |
1410 NETR_TRUST_FLAG_IN_FOREST;
1412 flags = NETR_TRUST_FLAG_IN_FOREST;
1415 result = cm_connect_netlogon(domain, &cli);
1417 if (!NT_STATUS_IS_OK(result)) {
1418 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1419 "for PIPE_NETLOGON (%s)\n",
1420 domain->name, nt_errstr(result)));
1421 return NT_STATUS_UNSUCCESSFUL;
1424 b = cli->binding_handle;
1426 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1431 if (!NT_STATUS_IS_OK(result)) {
1435 if (!W_ERROR_IS_OK(werr)) {
1436 return werror_to_ntstatus(werr);
1438 if (trusts->count == 0) {
1439 return NT_STATUS_OK;
1442 /* Copy across names and sids */
1445 for (i = 0; i < trusts->count; i++) {
1446 struct netr_DomainTrust *trust = &trusts->array[i];
1447 struct winbindd_domain d;
1452 * drop external trusts if this is not our primary
1453 * domain. This means that the returned number of
1454 * domains may be less that the ones actually trusted
1458 if ((trust->trust_attributes
1459 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1462 DEBUG(10,("trusted_domains: Skipping external trusted "
1463 "domain %s because it is outside of our "
1465 trust->netbios_name));
1469 /* add to the trusted domain cache */
1471 d.name = discard_const_p(char, trust->netbios_name);
1472 d.alt_name = discard_const_p(char, trust->dns_name);
1475 sid_copy(&d.sid, trust->sid);
1477 sid_copy(&d.sid, &global_sid_NULL);
1480 if ( domain->primary ) {
1481 DEBUG(10,("trusted_domains(ads): Searching "
1482 "trusted domain list of %s and storing "
1483 "trust flags for domain %s\n",
1484 domain->name, d.alt_name));
1486 d.domain_flags = trust->trust_flags;
1487 d.domain_type = trust->trust_type;
1488 d.domain_trust_attribs = trust->trust_attributes;
1490 wcache_tdc_add_domain( &d );
1492 } else if (domain_is_forest_root(domain)) {
1493 /* Check if we already have this record. If
1494 * we are following our forest root that is not
1495 * our primary domain, we want to keep trust
1496 * flags from the perspective of our primary
1497 * domain not our forest root. */
1498 struct winbindd_tdc_domain *exist = NULL;
1500 exist = wcache_tdc_fetch_domain(
1501 talloc_tos(), trust->netbios_name);
1503 DEBUG(10,("trusted_domains(ads): Searching "
1504 "trusted domain list of %s and "
1505 "storing trust flags for domain "
1506 "%s\n", domain->name, d.alt_name));
1507 d.domain_flags = trust->trust_flags;
1508 d.domain_type = trust->trust_type;
1509 d.domain_trust_attribs =
1510 trust->trust_attributes;
1512 wcache_tdc_add_domain( &d );
1517 /* This gets a little tricky. If we are
1518 following a transitive forest trust, then
1519 innerit the flags, type, and attribs from
1520 the domain we queried to make sure we don't
1521 record the view of the trust from the wrong
1522 side. Always view it from the side of our
1523 primary domain. --jerry */
1524 struct winbindd_tdc_domain *parent = NULL;
1526 DEBUG(10,("trusted_domains(ads): Searching "
1527 "trusted domain list of %s and inheriting "
1528 "trust flags for domain %s\n",
1529 domain->name, d.alt_name));
1531 parent = wcache_tdc_fetch_domain(talloc_tos(),
1534 d.domain_flags = parent->trust_flags;
1535 d.domain_type = parent->trust_type;
1536 d.domain_trust_attribs = parent->trust_attribs;
1538 d.domain_flags = domain->domain_flags;
1539 d.domain_type = domain->domain_type;
1540 d.domain_trust_attribs =
1541 domain->domain_trust_attribs;
1543 TALLOC_FREE(parent);
1546 * We need to pass the modified properties
1549 trust->trust_flags = d.domain_flags;
1550 trust->trust_type = d.domain_type;
1551 trust->trust_attributes = d.domain_trust_attribs;
1553 wcache_tdc_add_domain( &d );
1560 /* the ADS backend methods are exposed via this structure */
1561 struct winbindd_methods ads_methods = {