2 Unix SMB/CIFS implementation.
4 Winbind ADS backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
8 Copyright (C) Gerald (Jerry) Carter 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "rpc_client/rpc_client.h"
27 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
28 #include "../libds/common/flags.h"
30 #include "../libcli/ldap/ldap_ndr.h"
31 #include "../libcli/security/security.h"
32 #include "../libds/common/flag_mapping.h"
38 #define DBGC_CLASS DBGC_WINBIND
40 extern struct winbindd_methods reconnect_methods;
42 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
45 * Check if cached connection can be reused. If the connection cannot
46 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
48 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
51 ADS_STRUCT *ads = *adsp;
55 time_t now = time(NULL);
57 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
59 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
60 "is now %d)\n", (uint32)expire - (uint32)now,
61 (uint32) expire, (uint32) now));
63 if ( ads->config.realm && (expire > now)) {
66 /* we own this ADS_STRUCT so make sure it goes away */
67 DEBUG(7,("Deleting expired krb5 credential cache\n"));
70 ads_kdestroy(WINBIND_CCACHE_NAME);
77 * @brief Establish a connection to a DC
79 * @param[out] adsp ADS_STRUCT that will be created
80 * @param[in] target_realm Realm of domain to connect to
81 * @param[in] target_dom_name 'workgroup' name of domain to connect to
82 * @param[in] ldap_server DNS name of server to connect to
83 * @param[in] password Our machine acount secret
84 * @param[in] auth_realm Realm of local domain for creating krb token
85 * @param[in] renewable Renewable ticket time
89 static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
90 const char *target_realm,
91 const char *target_dom_name,
92 const char *ldap_server,
99 struct sockaddr_storage dc_ss;
102 if (auth_realm == NULL) {
103 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
106 /* we don't want this to affect the users ccache */
107 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
109 ads = ads_init(target_realm, target_dom_name, ldap_server);
111 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
112 return ADS_ERROR(LDAP_NO_MEMORY);
115 SAFE_FREE(ads->auth.password);
116 SAFE_FREE(ads->auth.realm);
118 ads->auth.renewable = renewable;
119 ads->auth.password = password;
121 ads->auth.realm = SMB_STRDUP(auth_realm);
122 if (!strupper_m(ads->auth.realm)) {
124 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
127 /* Setup the server affinity cache. We don't reaally care
128 about the name. Just setup affinity and the KRB5_CONFIG
130 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
132 status = ads_connect(ads);
133 if (!ADS_ERR_OK(status)) {
134 DEBUG(1,("ads_connect for domain %s failed: %s\n",
135 target_dom_name, ads_errstr(status)));
140 /* set the flag that says we don't own the memory even
141 though we do so that ads_destroy() won't destroy the
142 structure we pass back by reference */
144 ads->is_mine = False;
151 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
153 char *ldap_server, *realm, *password;
154 struct winbindd_domain *wb_dom;
157 ads_cached_connection_reuse(adsp);
163 * At this point we only have the NetBIOS domain name.
164 * Check if we can get server nam and realm from SAF cache
165 * and the domain list.
167 ldap_server = saf_fetch(talloc_tos(), dom_name);
168 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
169 ldap_server ? ldap_server : ""));
171 wb_dom = find_domain_from_name(dom_name);
172 if (wb_dom == NULL) {
173 DEBUG(10, ("could not find domain '%s'\n", dom_name));
174 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
177 DEBUG(10, ("find_domain_from_name found realm '%s' for "
178 " domain '%s'\n", wb_dom->alt_name, dom_name));
180 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
181 TALLOC_FREE(ldap_server);
182 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
186 realm = SMB_STRDUP(wb_dom->alt_name);
188 struct winbindd_domain *our_domain = wb_dom;
190 /* always give preference to the alt_name in our
191 primary domain if possible */
193 if (!wb_dom->primary) {
194 our_domain = find_our_domain();
197 if (our_domain->alt_name != NULL) {
198 realm = SMB_STRDUP(our_domain->alt_name);
200 realm = SMB_STRDUP(lp_realm());
204 status = ads_cached_connection_connect(
205 adsp, /* Returns ads struct. */
206 wb_dom->alt_name, /* realm to connect to. */
207 dom_name, /* 'workgroup' name for ads_init */
208 ldap_server, /* DNS name to connect to. */
209 password, /* password for auth realm. */
210 realm, /* realm used for krb5 ticket. */
211 0); /* renewable ticket time. */
214 TALLOC_FREE(ldap_server);
220 return our ads connections structure for a domain. We keep the connection
221 open to make things faster
223 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
226 char *password, *realm;
228 DEBUG(10,("ads_cached_connection\n"));
229 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
231 if (domain->private_data) {
232 return (ADS_STRUCT *)domain->private_data;
235 /* the machine acct password might have change - fetch it every time */
237 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
243 realm = SMB_STRDUP(domain->alt_name);
246 struct winbindd_domain *our_domain = domain;
249 /* always give preference to the alt_name in our
250 primary domain if possible */
252 if ( !domain->primary )
253 our_domain = find_our_domain();
255 if (our_domain->alt_name != NULL) {
256 realm = SMB_STRDUP( our_domain->alt_name );
259 realm = SMB_STRDUP( lp_realm() );
262 status = ads_cached_connection_connect(
263 (ADS_STRUCT **)&domain->private_data,
267 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
270 if (!ADS_ERR_OK(status)) {
271 /* if we get ECONNREFUSED then it might be a NT4
272 server, fall back to MSRPC */
273 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
274 status.err.rc == ECONNREFUSED) {
275 /* 'reconnect_methods' is the MS-RPC backend. */
276 DEBUG(1,("Trying MSRPC methods\n"));
277 domain->backend = &reconnect_methods;
282 return (ADS_STRUCT *)domain->private_data;
285 /* Query display info for a realm. This is the basic user list fn */
286 static NTSTATUS query_user_list(struct winbindd_domain *domain,
289 struct wbint_userinfo **pinfo)
291 ADS_STRUCT *ads = NULL;
292 const char *attrs[] = { "*", NULL };
295 LDAPMessage *res = NULL;
296 LDAPMessage *msg = NULL;
297 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
301 DEBUG(3,("ads: query_user_list\n"));
303 if ( !winbindd_can_contact_domain( domain ) ) {
304 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
309 ads = ads_cached_connection(domain);
312 domain->last_status = NT_STATUS_SERVER_DISABLED;
316 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
317 if (!ADS_ERR_OK(rc)) {
318 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
319 status = ads_ntstatus(rc);
322 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
326 count = ads_count_replies(ads, res);
328 DEBUG(1,("query_user_list: No users found\n"));
332 (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
334 status = NT_STATUS_NO_MEMORY;
340 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
341 struct wbint_userinfo *info = &((*pinfo)[count]);
345 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
346 ds_atype_map(atype) != SID_NAME_USER) {
347 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
351 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
352 info->full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
353 if (info->full_name == NULL) {
354 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
356 info->homedir = NULL;
358 info->primary_gid = (gid_t)-1;
360 if (!ads_pull_sid(ads, msg, "objectSid",
362 DEBUG(1, ("No sid for %s !?\n", info->acct_name));
366 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
367 DEBUG(1, ("No primary group for %s !?\n",
371 sid_compose(&info->group_sid, &domain->sid, group);
376 (*num_entries) = count;
377 ads_msgfree(ads, res);
379 for (i=0; i<count; i++) {
380 struct wbint_userinfo *info = &((*pinfo)[i]);
381 const char *gecos = NULL;
382 gid_t primary_gid = (gid_t)-1;
384 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
385 &info->homedir, &info->shell,
386 &gecos, &primary_gid);
387 if (!NT_STATUS_IS_OK(status)) {
389 * Deliberately ignore this error, there might be more
396 info->full_name = gecos;
398 info->primary_gid = primary_gid;
401 status = NT_STATUS_OK;
403 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
409 /* list all domain groups */
410 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
413 struct wb_acct_info **info)
415 ADS_STRUCT *ads = NULL;
416 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
417 "name", "objectSid", NULL};
420 LDAPMessage *res = NULL;
421 LDAPMessage *msg = NULL;
422 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
424 bool enum_dom_local_groups = False;
428 DEBUG(3,("ads: enum_dom_groups\n"));
430 if ( !winbindd_can_contact_domain( domain ) ) {
431 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
436 /* only grab domain local groups for our domain */
437 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
438 enum_dom_local_groups = True;
441 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
444 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
445 * default value, it MUST be absent. In case of extensible matching the
446 * "dnattr" boolean defaults to FALSE and so it must be only be present
449 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
450 * filter using bitwise matching rule then the buggy AD fails to decode
451 * the extensible match. As a workaround set it to TRUE and thereby add
452 * the dnAttributes "dn" field to cope with those older AD versions.
453 * It should not harm and won't put any additional load on the AD since
454 * none of the dn components have a bitmask-attribute.
456 * Thanks to Ralf Haferkamp for input and testing - Guenther */
458 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
459 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
460 ADS_LDAP_MATCHING_RULE_BIT_AND,
461 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
463 if (filter == NULL) {
464 status = NT_STATUS_NO_MEMORY;
468 ads = ads_cached_connection(domain);
471 domain->last_status = NT_STATUS_SERVER_DISABLED;
475 rc = ads_search_retry(ads, &res, filter, attrs);
476 if (!ADS_ERR_OK(rc)) {
477 status = ads_ntstatus(rc);
478 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
481 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
485 count = ads_count_replies(ads, res);
487 DEBUG(1,("enum_dom_groups: No groups found\n"));
491 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
493 status = NT_STATUS_NO_MEMORY;
499 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
504 name = ads_pull_username(ads, mem_ctx, msg);
505 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
506 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
507 DEBUG(1,("No sid for %s !?\n", name));
511 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
512 DEBUG(1,("No rid for %s !?\n", name));
516 fstrcpy((*info)[i].acct_name, name);
517 fstrcpy((*info)[i].acct_desc, gecos);
518 (*info)[i].rid = rid;
524 status = NT_STATUS_OK;
526 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
530 ads_msgfree(ads, res);
535 /* list all domain local groups */
536 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
539 struct wb_acct_info **info)
542 * This is a stub function only as we returned the domain
543 * local groups in enum_dom_groups() if the domain->native field
544 * was true. This is a simple performance optimization when
547 * if we ever need to enumerate domain local groups separately,
548 * then this optimization in enum_dom_groups() will need
556 /* convert a single name to a sid in a domain - use rpc methods */
557 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
559 const char *domain_name,
563 enum lsa_SidType *type)
565 return reconnect_methods.name_to_sid(domain, mem_ctx,
566 domain_name, name, flags,
570 /* convert a domain SID to a user or group name - use rpc methods */
571 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
573 const struct dom_sid *sid,
576 enum lsa_SidType *type)
578 return reconnect_methods.sid_to_name(domain, mem_ctx, sid,
579 domain_name, name, type);
582 /* convert a list of rids to names - use rpc methods */
583 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
585 const struct dom_sid *sid,
590 enum lsa_SidType **types)
592 return reconnect_methods.rids_to_names(domain, mem_ctx, sid,
594 domain_name, names, types);
597 /* If you are looking for "dn_lookup": Yes, it used to be here!
598 * It has gone now since it was a major speed bottleneck in
599 * lookup_groupmem (its only use). It has been replaced by
600 * an rpc lookup sids call... R.I.P. */
602 /* Lookup user information from a rid */
603 static NTSTATUS query_user(struct winbindd_domain *domain,
605 const struct dom_sid *sid,
606 struct wbint_userinfo *info)
608 ADS_STRUCT *ads = NULL;
609 const char *attrs[] = { "*", NULL };
612 LDAPMessage *msg = NULL;
616 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
617 struct netr_SamInfo3 *user = NULL;
622 DEBUG(3,("ads: query_user\n"));
624 info->homedir = NULL;
627 /* try netsamlogon cache first */
629 if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
631 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
632 sid_string_dbg(sid)));
634 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
635 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
637 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
638 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
640 nss_get_info_cached( domain, sid, mem_ctx,
641 &info->homedir, &info->shell, &info->full_name,
643 info->primary_gid = gid;
647 if (info->full_name == NULL) {
648 /* this might fail so we dont check the return code */
649 wcache_query_user_fullname(domain,
658 if ( !winbindd_can_contact_domain(domain)) {
659 DEBUG(8,("query_user: No incoming trust from domain %s\n",
662 /* We still need to generate some basic information
663 about the user even if we cannot contact the
664 domain. Most of this stuff we can deduce. */
666 sid_copy( &info->user_sid, sid );
668 /* Assume "Domain Users" for the primary group */
670 sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
672 /* Try to fill in what the nss_info backend can do */
674 nss_get_info_cached( domain, sid, mem_ctx,
675 &info->homedir, &info->shell, &info->full_name,
677 info->primary_gid = gid;
682 /* no cache...do the query */
684 if ( (ads = ads_cached_connection(domain)) == NULL ) {
685 domain->last_status = NT_STATUS_SERVER_DISABLED;
686 return NT_STATUS_SERVER_DISABLED;
689 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
691 ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
694 return NT_STATUS_NO_MEMORY;
696 rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
698 if (!ADS_ERR_OK(rc)) {
699 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
700 sid_string_dbg(sid), ads_errstr(rc)));
701 return ads_ntstatus(rc);
703 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
704 sid_string_dbg(sid)));
705 return NT_STATUS_INTERNAL_ERROR;
708 count = ads_count_replies(ads, msg);
710 DEBUG(1,("query_user(sid=%s): Not found\n",
711 sid_string_dbg(sid)));
712 ads_msgfree(ads, msg);
713 return NT_STATUS_NO_SUCH_USER;
716 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
718 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
719 DEBUG(1,("No primary group for %s !?\n",
720 sid_string_dbg(sid)));
721 ads_msgfree(ads, msg);
722 return NT_STATUS_NO_SUCH_USER;
724 sid_copy(&info->user_sid, sid);
725 sid_compose(&info->group_sid, &domain->sid, group_rid);
728 * We have to fetch the "name" attribute before doing the
729 * nss_get_info_cached call. nss_get_info_cached might destroy
730 * the ads struct, potentially invalidating the ldap message.
732 full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
733 if (full_name == NULL) {
734 full_name = ads_pull_string(ads, mem_ctx, msg, "name");
737 ads_msgfree(ads, msg);
740 status = nss_get_info_cached( domain, sid, mem_ctx,
741 &info->homedir, &info->shell, &info->full_name,
743 info->primary_gid = gid;
744 if (!NT_STATUS_IS_OK(status)) {
745 DEBUG(1, ("nss_get_info_cached failed: %s\n",
750 if (info->full_name == NULL) {
751 info->full_name = full_name;
753 TALLOC_FREE(full_name);
756 status = NT_STATUS_OK;
758 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
762 /* Lookup groups a user is a member of - alternate method, for when
763 tokenGroups are not available. */
764 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
767 struct dom_sid *primary_group,
768 uint32_t *p_num_groups, struct dom_sid **user_sids)
771 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
773 LDAPMessage *res = NULL;
774 LDAPMessage *msg = NULL;
777 const char *group_attrs[] = {"objectSid", NULL};
779 uint32_t num_groups = 0;
781 DEBUG(3,("ads: lookup_usergroups_member\n"));
783 if ( !winbindd_can_contact_domain( domain ) ) {
784 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
789 ads = ads_cached_connection(domain);
792 domain->last_status = NT_STATUS_SERVER_DISABLED;
796 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
797 status = NT_STATUS_NO_MEMORY;
801 ldap_exp = talloc_asprintf(mem_ctx,
802 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
804 ADS_LDAP_MATCHING_RULE_BIT_AND,
805 GROUP_TYPE_SECURITY_ENABLED);
807 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
808 TALLOC_FREE(escaped_dn);
809 status = NT_STATUS_NO_MEMORY;
813 TALLOC_FREE(escaped_dn);
815 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
817 if (!ADS_ERR_OK(rc)) {
818 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
819 return ads_ntstatus(rc);
821 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
822 return NT_STATUS_INTERNAL_ERROR;
826 count = ads_count_replies(ads, res);
831 /* always add the primary group to the sid array */
832 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
834 if (!NT_STATUS_IS_OK(status)) {
839 for (msg = ads_first_entry(ads, res); msg;
840 msg = ads_next_entry(ads, msg)) {
841 struct dom_sid group_sid;
843 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
844 DEBUG(1,("No sid for this group ?!?\n"));
848 /* ignore Builtin groups from ADS - Guenther */
849 if (sid_check_is_in_builtin(&group_sid)) {
853 status = add_sid_to_array(mem_ctx, &group_sid,
854 user_sids, &num_groups);
855 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 (member) succeeded for dn=%s\n", user_dn));
868 ads_msgfree(ads, res);
873 /* Lookup groups a user is a member of - alternate method, for when
874 tokenGroups are not available. */
875 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
878 struct dom_sid *primary_group,
879 uint32_t *p_num_groups,
880 struct dom_sid **user_sids)
883 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
885 const char *attrs[] = {"memberOf", NULL};
886 uint32_t num_groups = 0;
887 struct dom_sid *group_sids = NULL;
889 char **strings = NULL;
890 size_t num_strings = 0, num_sids = 0;
893 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
895 if ( !winbindd_can_contact_domain( domain ) ) {
896 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
897 "domain %s\n", domain->name));
901 ads = ads_cached_connection(domain);
904 domain->last_status = NT_STATUS_SERVER_DISABLED;
905 return NT_STATUS_UNSUCCESSFUL;
908 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
909 ADS_EXTENDED_DN_HEX_STRING,
910 &strings, &num_strings);
912 if (!ADS_ERR_OK(rc)) {
913 DEBUG(1,("lookup_usergroups_memberof ads_search "
914 "member=%s: %s\n", user_dn, ads_errstr(rc)));
915 return ads_ntstatus(rc);
921 /* always add the primary group to the sid array */
922 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
924 if (!NT_STATUS_IS_OK(status)) {
928 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
930 status = NT_STATUS_NO_MEMORY;
934 for (i=0; i<num_strings; i++) {
935 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
936 ADS_EXTENDED_DN_HEX_STRING,
938 if (!ADS_ERR_OK(rc)) {
939 /* ignore members without SIDs */
940 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
941 NT_STATUS_NOT_FOUND)) {
945 status = ads_ntstatus(rc);
953 DEBUG(1,("No memberOf for this user?!?\n"));
954 status = NT_STATUS_NO_MEMORY;
958 for (i=0; i<num_sids; i++) {
960 /* ignore Builtin groups from ADS - Guenther */
961 if (sid_check_is_in_builtin(&group_sids[i])) {
965 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
967 if (!NT_STATUS_IS_OK(status)) {
973 *p_num_groups = num_groups;
974 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
976 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
980 TALLOC_FREE(strings);
981 TALLOC_FREE(group_sids);
987 /* Lookup groups a user is a member of. */
988 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
990 const struct dom_sid *sid,
991 uint32 *p_num_groups, struct dom_sid **user_sids)
993 ADS_STRUCT *ads = NULL;
994 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
997 LDAPMessage *msg = NULL;
998 char *user_dn = NULL;
999 struct dom_sid *sids;
1001 struct dom_sid primary_group;
1002 uint32 primary_group_rid;
1003 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1004 uint32_t num_groups = 0;
1006 DEBUG(3,("ads: lookup_usergroups\n"));
1009 status = lookup_usergroups_cached(domain, mem_ctx, sid,
1010 p_num_groups, user_sids);
1011 if (NT_STATUS_IS_OK(status)) {
1012 return NT_STATUS_OK;
1015 if ( !winbindd_can_contact_domain( domain ) ) {
1016 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
1019 /* Tell the cache manager not to remember this one */
1021 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
1024 ads = ads_cached_connection(domain);
1027 domain->last_status = NT_STATUS_SERVER_DISABLED;
1028 status = NT_STATUS_SERVER_DISABLED;
1032 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
1034 if (!ADS_ERR_OK(rc)) {
1035 status = ads_ntstatus(rc);
1036 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1037 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
1041 count = ads_count_replies(ads, msg);
1043 status = NT_STATUS_UNSUCCESSFUL;
1044 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1045 "invalid number of results (count=%d)\n",
1046 sid_string_dbg(sid), count));
1051 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
1052 sid_string_dbg(sid)));
1053 status = NT_STATUS_UNSUCCESSFUL;
1057 user_dn = ads_get_dn(ads, mem_ctx, msg);
1058 if (user_dn == NULL) {
1059 status = NT_STATUS_NO_MEMORY;
1063 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
1064 DEBUG(1,("%s: No primary group for sid=%s !?\n",
1065 domain->name, sid_string_dbg(sid)));
1069 sid_compose(&primary_group, &domain->sid, primary_group_rid);
1071 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
1073 /* there must always be at least one group in the token,
1074 unless we are talking to a buggy Win2k server */
1076 /* actually this only happens when the machine account has no read
1077 * permissions on the tokenGroup attribute - gd */
1081 /* no tokenGroups */
1083 /* lookup what groups this user is a member of by DN search on
1086 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
1088 &num_groups, user_sids);
1089 *p_num_groups = num_groups;
1090 if (NT_STATUS_IS_OK(status)) {
1094 /* lookup what groups this user is a member of by DN search on
1097 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
1099 &num_groups, user_sids);
1100 *p_num_groups = num_groups;
1107 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
1109 if (!NT_STATUS_IS_OK(status)) {
1113 for (i=0;i<count;i++) {
1115 /* ignore Builtin groups from ADS - Guenther */
1116 if (sid_check_is_in_builtin(&sids[i])) {
1120 status = add_sid_to_array_unique(mem_ctx, &sids[i],
1121 user_sids, &num_groups);
1122 if (!NT_STATUS_IS_OK(status)) {
1127 *p_num_groups = (uint32)num_groups;
1128 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1130 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1131 sid_string_dbg(sid)));
1133 TALLOC_FREE(user_dn);
1134 ads_msgfree(ads, msg);
1138 /* Lookup aliases a user is member of - use rpc methods */
1139 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1140 TALLOC_CTX *mem_ctx,
1141 uint32 num_sids, const struct dom_sid *sids,
1142 uint32 *num_aliases, uint32 **alias_rids)
1144 return reconnect_methods.lookup_useraliases(domain, mem_ctx,
1151 find the members of a group, given a group rid and domain
1153 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1154 TALLOC_CTX *mem_ctx,
1155 const struct dom_sid *group_sid,
1156 enum lsa_SidType type,
1158 struct dom_sid **sid_mem, char ***names,
1159 uint32 **name_types)
1162 ADS_STRUCT *ads = NULL;
1164 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1166 char **members = NULL;
1168 size_t num_members = 0;
1170 struct dom_sid *sid_mem_nocache = NULL;
1171 char **names_nocache = NULL;
1172 enum lsa_SidType *name_types_nocache = NULL;
1173 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1174 uint32 num_nocache = 0;
1175 TALLOC_CTX *tmp_ctx = NULL;
1177 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1178 sid_string_dbg(group_sid)));
1182 tmp_ctx = talloc_new(mem_ctx);
1184 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1185 status = NT_STATUS_NO_MEMORY;
1189 if ( !winbindd_can_contact_domain( domain ) ) {
1190 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1192 return NT_STATUS_OK;
1195 ads = ads_cached_connection(domain);
1198 domain->last_status = NT_STATUS_SERVER_DISABLED;
1202 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1203 status = NT_STATUS_NO_MEMORY;
1207 /* search for all members of the group */
1208 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1209 TALLOC_FREE(sidbinstr);
1210 if (ldap_exp == NULL) {
1211 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1212 status = NT_STATUS_NO_MEMORY;
1216 args.control = ADS_EXTENDED_DN_OID;
1217 args.val = ADS_EXTENDED_DN_HEX_STRING;
1218 args.critical = True;
1220 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1221 ldap_exp, &args, "member", &members, &num_members);
1223 if (!ADS_ERR_OK(rc)) {
1224 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1225 status = NT_STATUS_UNSUCCESSFUL;
1229 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1231 /* Now that we have a list of sids, we need to get the
1232 * lists of names and name_types belonging to these sids.
1233 * even though conceptually not quite clean, we use the
1234 * RPC call lsa_lookup_sids for this since it can handle a
1235 * list of sids. ldap calls can just resolve one sid at a time.
1237 * At this stage, the sids are still hidden in the exetended dn
1238 * member output format. We actually do a little better than
1239 * stated above: In extracting the sids from the member strings,
1240 * we try to resolve as many sids as possible from the
1241 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1244 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1245 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1246 (*name_types) = talloc_zero_array(mem_ctx, uint32, num_members);
1247 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1249 if ((members == NULL) || (*sid_mem == NULL) ||
1250 (*names == NULL) || (*name_types == NULL) ||
1251 (sid_mem_nocache == NULL))
1253 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1254 status = NT_STATUS_NO_MEMORY;
1261 (*name_types) = NULL;
1264 for (i=0; i<num_members; i++) {
1265 enum lsa_SidType name_type;
1266 char *name, *domain_name;
1269 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1271 if (!ADS_ERR_OK(rc)) {
1272 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1273 NT_STATUS_NOT_FOUND)) {
1274 /* Group members can be objects, like Exchange
1275 * Public Folders, that don't have a SID. Skip
1280 status = ads_ntstatus(rc);
1284 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1286 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1287 "cache\n", sid_string_dbg(&sid)));
1288 sid_copy(&(*sid_mem)[*num_names], &sid);
1289 (*names)[*num_names] = fill_domain_username_talloc(
1295 (*name_types)[*num_names] = name_type;
1299 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1300 "cache\n", sid_string_dbg(&sid)));
1301 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1306 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1307 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1309 /* handle sids not resolved from cache by lsa_lookup_sids */
1310 if (num_nocache > 0) {
1312 status = winbindd_lookup_sids(tmp_ctx,
1318 &name_types_nocache);
1320 if (!(NT_STATUS_IS_OK(status) ||
1321 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1322 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1324 DEBUG(1, ("lsa_lookupsids call failed with %s "
1325 "- retrying...\n", nt_errstr(status)));
1327 status = winbindd_lookup_sids(tmp_ctx,
1333 &name_types_nocache);
1336 if (NT_STATUS_IS_OK(status) ||
1337 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1339 /* Copy the entries over from the "_nocache" arrays
1340 * to the result arrays, skipping the gaps the
1341 * lookup_sids call left. */
1342 for (i=0; i < num_nocache; i++) {
1343 if (((names_nocache)[i] != NULL) &&
1344 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1346 sid_copy(&(*sid_mem)[*num_names],
1347 &sid_mem_nocache[i]);
1348 (*names)[*num_names] =
1349 fill_domain_username_talloc(
1354 (*name_types)[*num_names] = name_types_nocache[i];
1359 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1360 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1361 "not map any SIDs at all.\n"));
1362 /* Don't handle this as an error here.
1363 * There is nothing left to do with respect to the
1364 * overall result... */
1366 else if (!NT_STATUS_IS_OK(status)) {
1367 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1368 "sids via rpc_lsa_lookup_sids: %s\n",
1369 (int)num_members, nt_errstr(status)));
1374 status = NT_STATUS_OK;
1375 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1376 sid_string_dbg(group_sid)));
1380 TALLOC_FREE(tmp_ctx);
1385 /* find the sequence number for a domain */
1386 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1388 ADS_STRUCT *ads = NULL;
1391 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1393 if ( !winbindd_can_contact_domain( domain ) ) {
1394 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1397 return NT_STATUS_OK;
1400 *seq = DOM_SEQUENCE_NONE;
1402 ads = ads_cached_connection(domain);
1405 domain->last_status = NT_STATUS_SERVER_DISABLED;
1406 return NT_STATUS_UNSUCCESSFUL;
1409 rc = ads_USN(ads, seq);
1411 if (!ADS_ERR_OK(rc)) {
1413 /* its a dead connection, destroy it */
1415 if (domain->private_data) {
1416 ads = (ADS_STRUCT *)domain->private_data;
1417 ads->is_mine = True;
1419 ads_kdestroy(WINBIND_CCACHE_NAME);
1420 domain->private_data = NULL;
1423 return ads_ntstatus(rc);
1426 /* find the lockout policy of a domain - use rpc methods */
1427 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1428 TALLOC_CTX *mem_ctx,
1429 struct samr_DomInfo12 *policy)
1431 return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
1434 /* find the password policy of a domain - use rpc methods */
1435 static NTSTATUS password_policy(struct winbindd_domain *domain,
1436 TALLOC_CTX *mem_ctx,
1437 struct samr_DomInfo1 *policy)
1439 return reconnect_methods.password_policy(domain, mem_ctx, policy);
1442 /* get a list of trusted domains */
1443 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1444 TALLOC_CTX *mem_ctx,
1445 struct netr_DomainTrustList *trusts)
1447 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1451 struct rpc_pipe_client *cli;
1453 struct dcerpc_binding_handle *b;
1455 DEBUG(3,("ads: trusted_domains\n"));
1457 ZERO_STRUCTP(trusts);
1459 /* If this is our primary domain or a root in our forest,
1460 query for all trusts. If not, then just look for domain
1461 trusts in the target forest */
1463 if (domain->primary || domain_is_forest_root(domain)) {
1464 flags = NETR_TRUST_FLAG_OUTBOUND |
1465 NETR_TRUST_FLAG_INBOUND |
1466 NETR_TRUST_FLAG_IN_FOREST;
1468 flags = NETR_TRUST_FLAG_IN_FOREST;
1471 result = cm_connect_netlogon(domain, &cli);
1473 if (!NT_STATUS_IS_OK(result)) {
1474 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1475 "for PIPE_NETLOGON (%s)\n",
1476 domain->name, nt_errstr(result)));
1477 return NT_STATUS_UNSUCCESSFUL;
1480 b = cli->binding_handle;
1482 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1487 if (!NT_STATUS_IS_OK(result)) {
1491 if (!W_ERROR_IS_OK(werr)) {
1492 return werror_to_ntstatus(werr);
1494 if (trusts->count == 0) {
1495 return NT_STATUS_OK;
1498 /* Copy across names and sids */
1501 for (i = 0; i < trusts->count; i++) {
1502 struct netr_DomainTrust *trust = &trusts->array[i];
1503 struct winbindd_domain d;
1508 * drop external trusts if this is not our primary
1509 * domain. This means that the returned number of
1510 * domains may be less that the ones actually trusted
1514 if ((trust->trust_attributes
1515 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1518 DEBUG(10,("trusted_domains: Skipping external trusted "
1519 "domain %s because it is outside of our "
1521 trust->netbios_name));
1525 /* add to the trusted domain cache */
1527 d.name = discard_const_p(char, trust->netbios_name);
1528 d.alt_name = discard_const_p(char, trust->dns_name);
1531 sid_copy(&d.sid, trust->sid);
1533 sid_copy(&d.sid, &global_sid_NULL);
1536 if ( domain->primary ) {
1537 DEBUG(10,("trusted_domains(ads): Searching "
1538 "trusted domain list of %s and storing "
1539 "trust flags for domain %s\n",
1540 domain->name, d.alt_name));
1542 d.domain_flags = trust->trust_flags;
1543 d.domain_type = trust->trust_type;
1544 d.domain_trust_attribs = trust->trust_attributes;
1546 wcache_tdc_add_domain( &d );
1548 } else if (domain_is_forest_root(domain)) {
1549 /* Check if we already have this record. If
1550 * we are following our forest root that is not
1551 * our primary domain, we want to keep trust
1552 * flags from the perspective of our primary
1553 * domain not our forest root. */
1554 struct winbindd_tdc_domain *exist = NULL;
1556 exist = wcache_tdc_fetch_domain(
1557 talloc_tos(), trust->netbios_name);
1559 DEBUG(10,("trusted_domains(ads): Searching "
1560 "trusted domain list of %s and "
1561 "storing trust flags for domain "
1562 "%s\n", domain->name, d.alt_name));
1563 d.domain_flags = trust->trust_flags;
1564 d.domain_type = trust->trust_type;
1565 d.domain_trust_attribs =
1566 trust->trust_attributes;
1568 wcache_tdc_add_domain( &d );
1573 /* This gets a little tricky. If we are
1574 following a transitive forest trust, then
1575 innerit the flags, type, and attribs from
1576 the domain we queried to make sure we don't
1577 record the view of the trust from the wrong
1578 side. Always view it from the side of our
1579 primary domain. --jerry */
1580 struct winbindd_tdc_domain *parent = NULL;
1582 DEBUG(10,("trusted_domains(ads): Searching "
1583 "trusted domain list of %s and inheriting "
1584 "trust flags for domain %s\n",
1585 domain->name, d.alt_name));
1587 parent = wcache_tdc_fetch_domain(talloc_tos(),
1590 d.domain_flags = parent->trust_flags;
1591 d.domain_type = parent->trust_type;
1592 d.domain_trust_attribs = parent->trust_attribs;
1594 d.domain_flags = domain->domain_flags;
1595 d.domain_type = domain->domain_type;
1596 d.domain_trust_attribs =
1597 domain->domain_trust_attribs;
1599 TALLOC_FREE(parent);
1601 wcache_tdc_add_domain( &d );
1608 /* the ADS backend methods are exposed via this structure */
1609 struct winbindd_methods ads_methods = {