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"
37 #include "auth/credentials/credentials.h"
42 #define DBGC_CLASS DBGC_WINBIND
44 extern struct winbindd_methods reconnect_methods;
45 extern struct winbindd_methods msrpc_methods;
47 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
50 * Check if cached connection can be reused. If the connection cannot
51 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
53 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
56 ADS_STRUCT *ads = *adsp;
60 time_t now = time(NULL);
62 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
64 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
65 "is now %d)\n", (uint32_t)expire - (uint32_t)now,
66 (uint32_t) expire, (uint32_t) now));
68 if ( ads->config.realm && (expire > now)) {
71 /* we own this ADS_STRUCT so make sure it goes away */
72 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 account 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(const char *target_realm,
94 const char *target_dom_name,
95 const char *ldap_server,
102 TALLOC_CTX *tmp_ctx = talloc_stackframe();
105 struct sockaddr_storage dc_ss;
107 enum credentials_use_kerberos krb5_state;
109 if (auth_realm == NULL) {
110 TALLOC_FREE(tmp_ctx);
111 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
114 /* we don't want this to affect the users ccache */
115 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
117 ads = ads_init(tmp_ctx,
123 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
124 status = ADS_ERROR(LDAP_NO_MEMORY);
128 ADS_TALLOC_CONST_FREE(ads->auth.password);
129 ADS_TALLOC_CONST_FREE(ads->auth.realm);
131 ads->auth.renewable = renewable;
132 ads->auth.password = talloc_strdup(ads, password);
133 if (ads->auth.password == NULL) {
134 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
138 /* In FIPS mode, client use kerberos is forced to required. */
139 krb5_state = lp_client_use_kerberos();
140 switch (krb5_state) {
141 case CRED_USE_KERBEROS_REQUIRED:
142 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
143 ads->auth.flags &= ~ADS_AUTH_ALLOW_NTLMSSP;
145 case CRED_USE_KERBEROS_DESIRED:
146 ads->auth.flags &= ~ADS_AUTH_DISABLE_KERBEROS;
147 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
149 case CRED_USE_KERBEROS_DISABLED:
150 ads->auth.flags |= ADS_AUTH_DISABLE_KERBEROS;
151 ads->auth.flags |= ADS_AUTH_ALLOW_NTLMSSP;
155 ads->auth.realm = talloc_asprintf_strupper_m(ads, "%s", auth_realm);
156 if (ads->auth.realm == NULL) {
157 status = ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
161 /* Setup the server affinity cache. We don't reaally care
162 about the name. Just setup affinity and the KRB5_CONFIG
164 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
166 status = ads_connect(ads);
167 if (!ADS_ERR_OK(status)) {
168 DEBUG(1,("ads_connect for domain %s failed: %s\n",
169 target_dom_name, ads_errstr(status)));
173 *adsp = talloc_move(mem_ctx, &ads);
175 TALLOC_FREE(tmp_ctx);
179 ADS_STATUS ads_idmap_cached_connection(const char *dom_name,
183 TALLOC_CTX *tmp_ctx = talloc_stackframe();
184 char *ldap_server = NULL;
186 char *password = NULL;
187 struct winbindd_domain *wb_dom = NULL;
192 * Make sure we never try to use LDAP against
193 * a trusted domain as AD DC.
195 TALLOC_FREE(tmp_ctx);
196 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
199 ads_cached_connection_reuse(adsp);
201 TALLOC_FREE(tmp_ctx);
206 * At this point we only have the NetBIOS domain name.
207 * Check if we can get server name and realm from SAF cache
208 * and the domain list.
210 ldap_server = saf_fetch(tmp_ctx, dom_name);
212 DBG_DEBUG("ldap_server from saf cache: '%s'\n",
213 ldap_server ? ldap_server : "");
215 wb_dom = find_domain_from_name(dom_name);
216 if (wb_dom == NULL) {
217 DBG_DEBUG("could not find domain '%s'\n", dom_name);
218 status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
222 DBG_DEBUG("find_domain_from_name found realm '%s' for "
223 " domain '%s'\n", wb_dom->alt_name, dom_name);
225 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
226 status = ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
231 SMB_ASSERT(wb_dom->alt_name != NULL);
232 realm = talloc_strdup(tmp_ctx, wb_dom->alt_name);
234 struct winbindd_domain *our_domain = wb_dom;
236 /* always give preference to the alt_name in our
237 primary domain if possible */
239 if (!wb_dom->primary) {
240 our_domain = find_our_domain();
243 if (our_domain->alt_name != NULL) {
244 realm = talloc_strdup(tmp_ctx, our_domain->alt_name);
246 realm = talloc_strdup(tmp_ctx, lp_realm());
251 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
255 status = ads_cached_connection_connect(
256 wb_dom->alt_name, /* realm to connect to. */
257 dom_name, /* 'workgroup' name for ads_init */
258 ldap_server, /* DNS name to connect to. */
259 password, /* password for auth realm. */
260 realm, /* realm used for krb5 ticket. */
261 0, /* renewable ticket time. */
262 mem_ctx, /* memory context for ads struct */
263 adsp); /* Returns ads struct. */
266 TALLOC_FREE(tmp_ctx);
273 return our ads connections structure for a domain. We keep the connection
274 open to make things faster
276 static ADS_STATUS ads_cached_connection(struct winbindd_domain *domain,
279 TALLOC_CTX *tmp_ctx = talloc_stackframe();
281 char *password = NULL;
286 * Make sure we never try to use LDAP against
287 * a trusted domain as AD DC.
289 TALLOC_FREE(tmp_ctx);
290 return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
293 DBG_DEBUG("ads_cached_connection\n");
295 ads_cached_connection_reuse(&domain->backend_data.ads_conn);
296 if (domain->backend_data.ads_conn != NULL) {
297 *adsp = domain->backend_data.ads_conn;
298 TALLOC_FREE(tmp_ctx);
302 /* the machine acct password might have change - fetch it every time */
304 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
305 status = ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
310 SMB_ASSERT(domain->alt_name != NULL);
311 realm = talloc_strdup(tmp_ctx, domain->alt_name);
313 struct winbindd_domain *our_domain = domain;
316 /* always give preference to the alt_name in our
317 primary domain if possible */
319 if ( !domain->primary )
320 our_domain = find_our_domain();
322 if (our_domain->alt_name != NULL) {
323 realm = talloc_strdup(tmp_ctx, our_domain->alt_name );
325 realm = talloc_strdup(tmp_ctx, lp_realm() );
330 status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
334 status = ads_cached_connection_connect(
339 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
341 &domain->backend_data.ads_conn);
342 if (!ADS_ERR_OK(status)) {
343 /* if we get ECONNREFUSED then it might be a NT4
344 server, fall back to MSRPC */
345 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
346 status.err.rc == ECONNREFUSED) {
347 /* 'reconnect_methods' is the MS-RPC backend. */
348 DBG_NOTICE("Trying MSRPC methods for domain '%s'\n",
350 domain->backend = &reconnect_methods;
355 *adsp = domain->backend_data.ads_conn;
357 TALLOC_FREE(tmp_ctx);
363 /* Query display info for a realm. This is the basic user list fn */
364 static NTSTATUS query_user_list(struct winbindd_domain *domain,
368 ADS_STRUCT *ads = NULL;
369 const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
371 uint32_t *rids = NULL;
373 LDAPMessage *res = NULL;
374 LDAPMessage *msg = NULL;
375 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
377 DEBUG(3,("ads: query_user_list\n"));
379 if ( !winbindd_can_contact_domain( domain ) ) {
380 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
385 rc = ads_cached_connection(domain, &ads);
386 if (!ADS_ERR_OK(rc)) {
387 domain->last_status = NT_STATUS_SERVER_DISABLED;
391 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
392 if (!ADS_ERR_OK(rc)) {
393 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
394 status = ads_ntstatus(rc);
397 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
401 count = ads_count_replies(ads, res);
403 DEBUG(1,("query_user_list: No users found\n"));
407 rids = talloc_zero_array(mem_ctx, uint32_t, count);
409 status = NT_STATUS_NO_MEMORY;
415 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
416 struct dom_sid user_sid;
420 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
422 DBG_INFO("Object lacks sAMAccountType attribute\n");
425 if (ds_atype_map(atype) != SID_NAME_USER) {
426 DBG_INFO("Not a user account? atype=0x%x\n", atype);
430 if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
431 char *dn = ads_get_dn(ads, talloc_tos(), msg);
432 DBG_INFO("No sid for %s !?\n", dn);
437 if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
438 struct dom_sid_buf sidstr, domstr;
439 DBG_WARNING("Got sid %s in domain %s\n",
440 dom_sid_str_buf(&user_sid, &sidstr),
441 dom_sid_str_buf(&domain->sid, &domstr));
445 sid_split_rid(&user_sid, &rids[count]);
449 rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
456 status = NT_STATUS_OK;
458 DBG_NOTICE("ads query_user_list gave %d entries\n", count);
461 ads_msgfree(ads, res);
465 /* list all domain groups */
466 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
468 uint32_t *num_entries,
469 struct wb_acct_info **info)
471 ADS_STRUCT *ads = NULL;
472 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
473 "name", "objectSid", NULL};
476 LDAPMessage *res = NULL;
477 LDAPMessage *msg = NULL;
478 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
480 bool enum_dom_local_groups = False;
484 DEBUG(3,("ads: enum_dom_groups\n"));
486 if ( !winbindd_can_contact_domain( domain ) ) {
487 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
492 /* only grab domain local groups for our domain */
493 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
494 enum_dom_local_groups = True;
497 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
500 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
501 * default value, it MUST be absent. In case of extensible matching the
502 * "dnattr" boolean defaults to FALSE and so it must be only be present
505 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
506 * filter using bitwise matching rule then the buggy AD fails to decode
507 * the extensible match. As a workaround set it to TRUE and thereby add
508 * the dnAttributes "dn" field to cope with those older AD versions.
509 * It should not harm and won't put any additional load on the AD since
510 * none of the dn components have a bitmask-attribute.
512 * Thanks to Ralf Haferkamp for input and testing - Guenther */
514 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)"
515 "(&(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d)"
516 "(!(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))))",
517 GROUP_TYPE_SECURITY_ENABLED,
518 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
520 if (filter == NULL) {
521 status = NT_STATUS_NO_MEMORY;
525 rc = ads_cached_connection(domain, &ads);
526 if (!ADS_ERR_OK(rc)) {
527 domain->last_status = NT_STATUS_SERVER_DISABLED;
531 rc = ads_search_retry(ads, &res, filter, attrs);
532 if (!ADS_ERR_OK(rc)) {
533 status = ads_ntstatus(rc);
534 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
537 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
541 count = ads_count_replies(ads, res);
543 DEBUG(1,("enum_dom_groups: No groups found\n"));
547 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
549 status = NT_STATUS_NO_MEMORY;
555 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
560 name = ads_pull_username(ads, (*info), msg);
561 gecos = ads_pull_string(ads, (*info), msg, "name");
562 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
563 DEBUG(1,("No sid for %s !?\n", name));
567 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
568 DEBUG(1,("No rid for %s !?\n", name));
572 (*info)[i].acct_name = name;
573 (*info)[i].acct_desc = gecos;
574 (*info)[i].rid = rid;
580 status = NT_STATUS_OK;
582 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
586 ads_msgfree(ads, res);
591 /* list all domain local groups */
592 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
594 uint32_t *num_entries,
595 struct wb_acct_info **info)
598 * This is a stub function only as we returned the domain
599 * local groups in enum_dom_groups() if the domain->native field
600 * was true. This is a simple performance optimization when
603 * if we ever need to enumerate domain local groups separately,
604 * then this optimization in enum_dom_groups() will need
612 /* convert a single name to a sid in a domain - use rpc methods */
613 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
615 const char *domain_name,
618 const char **pdom_name,
620 enum lsa_SidType *type)
622 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
623 flags, pdom_name, sid, type);
626 /* convert a domain SID to a user or group name - use rpc methods */
627 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
629 const struct dom_sid *sid,
632 enum lsa_SidType *type)
634 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
635 domain_name, name, type);
638 /* convert a list of rids to names - use rpc methods */
639 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
641 const struct dom_sid *sid,
646 enum lsa_SidType **types)
648 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
650 domain_name, names, types);
653 /* Lookup groups a user is a member of - alternate method, for when
654 tokenGroups are not available. */
655 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
658 struct dom_sid *primary_group,
659 uint32_t *p_num_groups, struct dom_sid **user_sids)
662 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
664 LDAPMessage *res = NULL;
665 LDAPMessage *msg = NULL;
667 ADS_STRUCT *ads = NULL;
668 const char *group_attrs[] = {"objectSid", NULL};
670 uint32_t num_groups = 0;
672 DEBUG(3,("ads: lookup_usergroups_member\n"));
674 if ( !winbindd_can_contact_domain( domain ) ) {
675 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
680 rc = ads_cached_connection(domain, &ads);
681 if (!ADS_ERR_OK(rc)) {
682 domain->last_status = NT_STATUS_SERVER_DISABLED;
686 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
687 status = NT_STATUS_NO_MEMORY;
691 ldap_exp = talloc_asprintf(mem_ctx,
692 "(&(member=%s)(objectCategory=group)"
693 "(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))",
695 GROUP_TYPE_SECURITY_ENABLED);
697 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
698 TALLOC_FREE(escaped_dn);
699 status = NT_STATUS_NO_MEMORY;
703 TALLOC_FREE(escaped_dn);
705 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
707 if (!ADS_ERR_OK(rc)) {
708 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
709 return ads_ntstatus(rc);
711 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
712 return NT_STATUS_INTERNAL_ERROR;
716 count = ads_count_replies(ads, res);
721 /* always add the primary group to the sid array */
722 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
724 if (!NT_STATUS_IS_OK(status)) {
729 for (msg = ads_first_entry(ads, res); msg;
730 msg = ads_next_entry(ads, msg)) {
731 struct dom_sid group_sid;
733 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
734 DEBUG(1,("No sid for this group ?!?\n"));
738 /* ignore Builtin groups from ADS - Guenther */
739 if (sid_check_is_in_builtin(&group_sid)) {
743 status = add_sid_to_array(mem_ctx, &group_sid,
744 user_sids, &num_groups);
745 if (!NT_STATUS_IS_OK(status)) {
752 *p_num_groups = num_groups;
753 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
755 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
758 ads_msgfree(ads, res);
763 /* Lookup groups a user is a member of - alternate method, for when
764 tokenGroups are not available. */
765 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
768 struct dom_sid *primary_group,
769 uint32_t *p_num_groups,
770 struct dom_sid **user_sids)
773 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
774 ADS_STRUCT *ads = NULL;
775 const char *attrs[] = {"memberOf", NULL};
776 uint32_t num_groups = 0;
777 struct dom_sid *group_sids = NULL;
779 char **strings = NULL;
780 size_t num_strings = 0, num_sids = 0;
783 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
785 if ( !winbindd_can_contact_domain( domain ) ) {
786 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
787 "domain %s\n", domain->name));
791 rc = ads_cached_connection(domain, &ads);
792 if (!ADS_ERR_OK(rc)) {
793 domain->last_status = NT_STATUS_SERVER_DISABLED;
794 return NT_STATUS_UNSUCCESSFUL;
797 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
798 ADS_EXTENDED_DN_HEX_STRING,
799 &strings, &num_strings);
801 if (!ADS_ERR_OK(rc)) {
802 DEBUG(1,("lookup_usergroups_memberof ads_search "
803 "member=%s: %s\n", user_dn, ads_errstr(rc)));
804 return ads_ntstatus(rc);
810 /* always add the primary group to the sid array */
811 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
813 if (!NT_STATUS_IS_OK(status)) {
817 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
819 status = NT_STATUS_NO_MEMORY;
823 for (i=0; i<num_strings; i++) {
824 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
825 ADS_EXTENDED_DN_HEX_STRING,
827 if (!ADS_ERR_OK(rc)) {
828 /* ignore members without SIDs */
829 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
830 NT_STATUS_NOT_FOUND)) {
834 status = ads_ntstatus(rc);
842 DEBUG(1,("No memberOf for this user?!?\n"));
843 status = NT_STATUS_NO_MEMORY;
847 for (i=0; i<num_sids; i++) {
849 /* ignore Builtin groups from ADS - Guenther */
850 if (sid_check_is_in_builtin(&group_sids[i])) {
854 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
856 if (!NT_STATUS_IS_OK(status)) {
862 *p_num_groups = num_groups;
863 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
865 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
869 TALLOC_FREE(strings);
870 TALLOC_FREE(group_sids);
876 /* Lookup groups a user is a member of. */
877 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
879 const struct dom_sid *sid,
880 uint32_t *p_num_groups, struct dom_sid **user_sids)
882 ADS_STRUCT *ads = NULL;
883 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
886 LDAPMessage *msg = NULL;
887 char *user_dn = NULL;
888 struct dom_sid *sids;
890 struct dom_sid primary_group;
891 uint32_t primary_group_rid;
892 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
893 uint32_t num_groups = 0;
894 struct dom_sid_buf buf;
896 DEBUG(3,("ads: lookup_usergroups\n"));
899 status = lookup_usergroups_cached(mem_ctx, sid,
900 p_num_groups, user_sids);
901 if (NT_STATUS_IS_OK(status)) {
905 if ( !winbindd_can_contact_domain( domain ) ) {
906 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
909 /* Tell the cache manager not to remember this one */
911 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
914 rc = ads_cached_connection(domain, &ads);
915 if (!ADS_ERR_OK(rc)) {
916 domain->last_status = NT_STATUS_SERVER_DISABLED;
917 status = NT_STATUS_SERVER_DISABLED;
921 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
923 if (!ADS_ERR_OK(rc)) {
924 status = ads_ntstatus(rc);
925 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
927 dom_sid_str_buf(sid, &buf),
932 count = ads_count_replies(ads, msg);
934 status = NT_STATUS_UNSUCCESSFUL;
935 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
936 "invalid number of results (count=%d)\n",
937 dom_sid_str_buf(sid, &buf),
943 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
944 dom_sid_str_buf(sid, &buf)));
945 status = NT_STATUS_UNSUCCESSFUL;
949 user_dn = ads_get_dn(ads, mem_ctx, msg);
950 if (user_dn == NULL) {
951 status = NT_STATUS_NO_MEMORY;
955 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
956 DEBUG(1,("%s: No primary group for sid=%s !?\n",
958 dom_sid_str_buf(sid, &buf)));
962 sid_compose(&primary_group, &domain->sid, primary_group_rid);
964 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
966 /* there must always be at least one group in the token,
967 unless we are talking to a buggy Win2k server */
969 /* actually this only happens when the machine account has no read
970 * permissions on the tokenGroup attribute - gd */
976 /* lookup what groups this user is a member of by DN search on
979 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
981 &num_groups, user_sids);
982 *p_num_groups = num_groups;
983 if (NT_STATUS_IS_OK(status)) {
987 /* lookup what groups this user is a member of by DN search on
990 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
992 &num_groups, user_sids);
993 *p_num_groups = num_groups;
1000 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
1002 if (!NT_STATUS_IS_OK(status)) {
1006 for (i=0;i<count;i++) {
1008 /* ignore Builtin groups from ADS - Guenther */
1009 if (sid_check_is_in_builtin(&sids[i])) {
1013 status = add_sid_to_array_unique(mem_ctx, &sids[i],
1014 user_sids, &num_groups);
1015 if (!NT_STATUS_IS_OK(status)) {
1020 *p_num_groups = (uint32_t)num_groups;
1021 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1023 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1024 dom_sid_str_buf(sid, &buf)));
1026 TALLOC_FREE(user_dn);
1027 ads_msgfree(ads, msg);
1031 /* Lookup aliases a user is member of - use rpc methods */
1032 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1033 TALLOC_CTX *mem_ctx,
1034 uint32_t num_sids, const struct dom_sid *sids,
1035 uint32_t *num_aliases, uint32_t **alias_rids)
1037 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
1038 num_aliases, alias_rids);
1041 static NTSTATUS add_primary_group_members(
1042 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
1043 char ***all_members, size_t *num_all_members)
1046 NTSTATUS status = NT_STATUS_NO_MEMORY;
1048 const char *attrs[] = { "dn", NULL };
1049 LDAPMessage *res = NULL;
1055 filter = talloc_asprintf(
1056 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1058 if (filter == NULL) {
1062 args.control = ADS_EXTENDED_DN_OID;
1063 args.val = ADS_EXTENDED_DN_HEX_STRING;
1064 args.critical = True;
1066 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1067 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1070 if (!ADS_ERR_OK(rc)) {
1071 status = ads_ntstatus(rc);
1072 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1076 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1080 num_members = ads_count_replies(ads, res);
1082 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1083 (uintmax_t)num_members));
1085 if (num_members == 0) {
1086 status = NT_STATUS_OK;
1090 members = talloc_realloc(mem_ctx, *all_members, char *,
1091 *num_all_members + num_members);
1092 if (members == NULL) {
1093 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1096 *all_members = members;
1098 for (msg = ads_first_entry(ads, res); msg != NULL;
1099 msg = ads_next_entry(ads, msg)) {
1102 dn = ads_get_dn(ads, members, msg);
1104 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1108 members[*num_all_members] = dn;
1109 *num_all_members += 1;
1112 status = NT_STATUS_OK;
1115 ads_msgfree(ads, res);
1117 TALLOC_FREE(filter);
1122 find the members of a group, given a group rid and domain
1124 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1125 TALLOC_CTX *mem_ctx,
1126 const struct dom_sid *group_sid,
1127 enum lsa_SidType type,
1128 uint32_t *num_names,
1129 struct dom_sid **sid_mem, char ***names,
1130 uint32_t **name_types)
1133 ADS_STRUCT *ads = NULL;
1135 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1137 char **members = NULL;
1139 size_t num_members = 0;
1141 struct dom_sid *sid_mem_nocache = NULL;
1142 char **names_nocache = NULL;
1143 enum lsa_SidType *name_types_nocache = NULL;
1144 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1145 uint32_t num_nocache = 0;
1146 TALLOC_CTX *tmp_ctx = NULL;
1148 struct dom_sid_buf buf;
1150 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1151 dom_sid_str_buf(group_sid, &buf)));
1155 tmp_ctx = talloc_new(mem_ctx);
1157 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1158 status = NT_STATUS_NO_MEMORY;
1162 if (!sid_peek_rid(group_sid, &rid)) {
1163 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1164 status = NT_STATUS_INVALID_PARAMETER;
1168 if ( !winbindd_can_contact_domain( domain ) ) {
1169 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1171 return NT_STATUS_OK;
1174 rc = ads_cached_connection(domain, &ads);
1175 if (!ADS_ERR_OK(rc)) {
1176 domain->last_status = NT_STATUS_SERVER_DISABLED;
1180 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1181 status = NT_STATUS_NO_MEMORY;
1185 /* search for all members of the group */
1186 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1187 TALLOC_FREE(sidbinstr);
1188 if (ldap_exp == NULL) {
1189 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1190 status = NT_STATUS_NO_MEMORY;
1194 args.control = ADS_EXTENDED_DN_OID;
1195 args.val = ADS_EXTENDED_DN_HEX_STRING;
1196 args.critical = True;
1198 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1199 ldap_exp, &args, "member", &members, &num_members);
1201 if (!ADS_ERR_OK(rc)) {
1202 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1203 status = NT_STATUS_UNSUCCESSFUL;
1207 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1209 status = add_primary_group_members(ads, mem_ctx, rid,
1210 &members, &num_members);
1211 if (!NT_STATUS_IS_OK(status)) {
1212 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1213 __func__, nt_errstr(status)));
1217 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1218 __func__, (int)num_members));
1220 /* Now that we have a list of sids, we need to get the
1221 * lists of names and name_types belonging to these sids.
1222 * even though conceptually not quite clean, we use the
1223 * RPC call lsa_lookup_sids for this since it can handle a
1224 * list of sids. ldap calls can just resolve one sid at a time.
1226 * At this stage, the sids are still hidden in the exetended dn
1227 * member output format. We actually do a little better than
1228 * stated above: In extracting the sids from the member strings,
1229 * we try to resolve as many sids as possible from the
1230 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1233 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1234 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1235 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1236 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1238 if ((members == NULL) || (*sid_mem == NULL) ||
1239 (*names == NULL) || (*name_types == NULL) ||
1240 (sid_mem_nocache == NULL))
1242 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1243 status = NT_STATUS_NO_MEMORY;
1250 (*name_types) = NULL;
1253 for (i=0; i<num_members; i++) {
1254 enum lsa_SidType name_type;
1255 char *name, *domain_name;
1258 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1260 if (!ADS_ERR_OK(rc)) {
1261 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1262 NT_STATUS_NOT_FOUND)) {
1263 /* Group members can be objects, like Exchange
1264 * Public Folders, that don't have a SID. Skip
1269 status = ads_ntstatus(rc);
1273 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1275 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1277 dom_sid_str_buf(&sid, &buf)));
1278 sid_copy(&(*sid_mem)[*num_names], &sid);
1279 (*names)[*num_names] = fill_domain_username_talloc(
1285 (*name_types)[*num_names] = name_type;
1289 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1291 dom_sid_str_buf(&sid, &buf)));
1292 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1297 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1298 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1300 /* handle sids not resolved from cache by lsa_lookup_sids */
1301 if (num_nocache > 0) {
1303 status = winbindd_lookup_sids(tmp_ctx,
1309 &name_types_nocache);
1311 if (!(NT_STATUS_IS_OK(status) ||
1312 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1313 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1315 DEBUG(1, ("lsa_lookupsids call failed with %s "
1316 "- retrying...\n", nt_errstr(status)));
1318 status = winbindd_lookup_sids(tmp_ctx,
1324 &name_types_nocache);
1327 if (NT_STATUS_IS_OK(status) ||
1328 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1330 /* Copy the entries over from the "_nocache" arrays
1331 * to the result arrays, skipping the gaps the
1332 * lookup_sids call left. */
1333 for (i=0; i < num_nocache; i++) {
1334 if (((names_nocache)[i] != NULL) &&
1335 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1337 sid_copy(&(*sid_mem)[*num_names],
1338 &sid_mem_nocache[i]);
1339 (*names)[*num_names] =
1340 fill_domain_username_talloc(
1345 (*name_types)[*num_names] = name_types_nocache[i];
1350 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1351 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1352 "not map any SIDs at all.\n"));
1353 /* Don't handle this as an error here.
1354 * There is nothing left to do with respect to the
1355 * overall result... */
1357 else if (!NT_STATUS_IS_OK(status)) {
1358 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1359 "sids via rpc_lsa_lookup_sids: %s\n",
1360 (int)num_members, nt_errstr(status)));
1365 status = NT_STATUS_OK;
1366 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1367 dom_sid_str_buf(group_sid, &buf)));
1371 TALLOC_FREE(tmp_ctx);
1376 static NTSTATUS lookup_aliasmem(struct winbindd_domain *domain,
1377 TALLOC_CTX *mem_ctx,
1378 const struct dom_sid *sid,
1379 enum lsa_SidType type,
1381 struct dom_sid **sids)
1383 char **names = NULL;
1384 uint32_t *name_types = NULL;
1385 struct dom_sid_buf buf;
1387 DBG_DEBUG("ads: lookup_aliasmem %s sid=%s\n",
1389 dom_sid_str_buf(sid, &buf));
1390 /* Search for alias and group membership uses the same LDAP command. */
1391 return lookup_groupmem(domain,
1401 /* find the lockout policy of a domain - use rpc methods */
1402 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1403 TALLOC_CTX *mem_ctx,
1404 struct samr_DomInfo12 *policy)
1406 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1409 /* find the password policy of a domain - use rpc methods */
1410 static NTSTATUS password_policy(struct winbindd_domain *domain,
1411 TALLOC_CTX *mem_ctx,
1412 struct samr_DomInfo1 *policy)
1414 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1417 /* get a list of trusted domains */
1418 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1419 TALLOC_CTX *mem_ctx,
1420 struct netr_DomainTrustList *trusts)
1422 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1426 struct rpc_pipe_client *cli;
1427 struct dcerpc_binding_handle *b;
1429 DEBUG(3,("ads: trusted_domains\n"));
1431 ZERO_STRUCTP(trusts);
1433 /* If this is our primary domain or a root in our forest,
1434 query for all trusts. If not, then just look for domain
1435 trusts in the target forest */
1437 if (domain->primary || domain_is_forest_root(domain)) {
1438 flags = NETR_TRUST_FLAG_OUTBOUND |
1439 NETR_TRUST_FLAG_INBOUND |
1440 NETR_TRUST_FLAG_IN_FOREST;
1442 flags = NETR_TRUST_FLAG_IN_FOREST;
1445 result = cm_connect_netlogon(domain, &cli);
1447 if (!NT_STATUS_IS_OK(result)) {
1448 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1449 "for PIPE_NETLOGON (%s)\n",
1450 domain->name, nt_errstr(result)));
1451 return NT_STATUS_UNSUCCESSFUL;
1454 b = cli->binding_handle;
1456 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1461 if (!NT_STATUS_IS_OK(result)) {
1465 if (!W_ERROR_IS_OK(werr)) {
1466 return werror_to_ntstatus(werr);
1468 if (trusts->count == 0) {
1469 return NT_STATUS_OK;
1472 /* Copy across names and sids */
1474 for (i = 0; i < trusts->count; i++) {
1475 struct netr_DomainTrust *trust = &trusts->array[i];
1476 struct winbindd_domain d;
1481 * drop external trusts if this is not our primary
1482 * domain. This means that the returned number of
1483 * domains may be less that the ones actually trusted
1487 if ((trust->trust_attributes
1488 & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1491 DEBUG(10,("trusted_domains: Skipping external trusted "
1492 "domain %s because it is outside of our "
1494 trust->netbios_name));
1498 /* add to the trusted domain cache */
1500 d.name = discard_const_p(char, trust->netbios_name);
1501 d.alt_name = discard_const_p(char, trust->dns_name);
1504 sid_copy(&d.sid, trust->sid);
1506 sid_copy(&d.sid, &global_sid_NULL);
1509 if ( domain->primary ) {
1510 DEBUG(10,("trusted_domains(ads): Searching "
1511 "trusted domain list of %s and storing "
1512 "trust flags for domain %s\n",
1513 domain->name, d.alt_name));
1515 d.domain_flags = trust->trust_flags;
1516 d.domain_type = trust->trust_type;
1517 d.domain_trust_attribs = trust->trust_attributes;
1519 wcache_tdc_add_domain( &d );
1520 } else if (domain_is_forest_root(domain)) {
1521 /* Check if we already have this record. If
1522 * we are following our forest root that is not
1523 * our primary domain, we want to keep trust
1524 * flags from the perspective of our primary
1525 * domain not our forest root. */
1526 struct winbindd_tdc_domain *exist = NULL;
1528 exist = wcache_tdc_fetch_domain(
1529 talloc_tos(), trust->netbios_name);
1531 DEBUG(10,("trusted_domains(ads): Searching "
1532 "trusted domain list of %s and "
1533 "storing trust flags for domain "
1534 "%s\n", domain->name, d.alt_name));
1535 d.domain_flags = trust->trust_flags;
1536 d.domain_type = trust->trust_type;
1537 d.domain_trust_attribs =
1538 trust->trust_attributes;
1540 wcache_tdc_add_domain( &d );
1544 /* This gets a little tricky. If we are
1545 following a transitive forest trust, then
1546 innerit the flags, type, and attribs from
1547 the domain we queried to make sure we don't
1548 record the view of the trust from the wrong
1549 side. Always view it from the side of our
1550 primary domain. --jerry */
1551 struct winbindd_tdc_domain *parent = NULL;
1553 DEBUG(10,("trusted_domains(ads): Searching "
1554 "trusted domain list of %s and inheriting "
1555 "trust flags for domain %s\n",
1556 domain->name, d.alt_name));
1558 parent = wcache_tdc_fetch_domain(talloc_tos(),
1561 d.domain_flags = parent->trust_flags;
1562 d.domain_type = parent->trust_type;
1563 d.domain_trust_attribs = parent->trust_attribs;
1565 d.domain_flags = domain->domain_flags;
1566 d.domain_type = domain->domain_type;
1567 d.domain_trust_attribs =
1568 domain->domain_trust_attribs;
1570 TALLOC_FREE(parent);
1573 * We need to pass the modified properties
1576 trust->trust_flags = d.domain_flags;
1577 trust->trust_type = d.domain_type;
1578 trust->trust_attributes = d.domain_trust_attribs;
1580 wcache_tdc_add_domain( &d );
1586 /* the ADS backend methods are exposed via this structure */
1587 struct winbindd_methods ads_methods = {