idmap: Remove "domname" from idmap_backends_unixid_to_sid
[Samba.git] / source3 / winbindd / winbindd_ads.c
blob78350fd8549eace449ed74db8bbfdd99d61c28b7
1 /*
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/>.
24 #include "includes.h"
25 #include "winbindd.h"
26 #include "rpc_client/rpc_client.h"
27 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
28 #include "../libds/common/flags.h"
29 #include "ads.h"
30 #include "../libcli/ldap/ldap_ndr.h"
31 #include "../libcli/security/security.h"
32 #include "../libds/common/flag_mapping.h"
33 #include "passdb.h"
35 #ifdef HAVE_ADS
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_WINBIND
40 extern struct winbindd_methods reconnect_methods;
42 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
44 /**
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;
53 if (ads != NULL) {
54 time_t expire;
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_t)expire - (uint32_t)now,
61 (uint32_t) expire, (uint32_t) now));
63 if ( ads->config.realm && (expire > now)) {
64 return;
65 } else {
66 /* we own this ADS_STRUCT so make sure it goes away */
67 DEBUG(7,("Deleting expired krb5 credential cache\n"));
68 ads->is_mine = True;
69 ads_destroy( &ads );
70 ads_kdestroy(WINBIND_CCACHE_NAME);
71 *adsp = NULL;
76 /**
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
87 * @return ADS_STATUS
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,
93 char *password,
94 char *auth_realm,
95 time_t renewable)
97 ADS_STRUCT *ads;
98 ADS_STATUS status;
99 struct sockaddr_storage dc_ss;
100 fstring dc_name;
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);
110 if (!ads) {
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)) {
123 ads_destroy(&ads);
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
129 file. */
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)));
136 ads_destroy(&ads);
137 return 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;
146 *adsp = ads;
148 return status;
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;
155 ADS_STATUS status;
157 ads_cached_connection_reuse(adsp);
158 if (*adsp != NULL) {
159 return ADS_SUCCESS;
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);
185 if (IS_DC) {
186 SMB_ASSERT(wb_dom->alt_name != NULL);
187 realm = SMB_STRDUP(wb_dom->alt_name);
188 } else {
189 struct winbindd_domain *our_domain = wb_dom;
191 /* always give preference to the alt_name in our
192 primary domain if possible */
194 if (!wb_dom->primary) {
195 our_domain = find_our_domain();
198 if (our_domain->alt_name != NULL) {
199 realm = SMB_STRDUP(our_domain->alt_name);
200 } else {
201 realm = SMB_STRDUP(lp_realm());
205 status = ads_cached_connection_connect(
206 adsp, /* Returns ads struct. */
207 wb_dom->alt_name, /* realm to connect to. */
208 dom_name, /* 'workgroup' name for ads_init */
209 ldap_server, /* DNS name to connect to. */
210 password, /* password for auth realm. */
211 realm, /* realm used for krb5 ticket. */
212 0); /* renewable ticket time. */
214 SAFE_FREE(realm);
215 TALLOC_FREE(ldap_server);
217 return status;
221 return our ads connections structure for a domain. We keep the connection
222 open to make things faster
224 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
226 ADS_STATUS status;
227 char *password, *realm;
229 DEBUG(10,("ads_cached_connection\n"));
230 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
232 if (domain->private_data) {
233 return (ADS_STRUCT *)domain->private_data;
236 /* the machine acct password might have change - fetch it every time */
238 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
239 return NULL;
242 if ( IS_DC ) {
243 SMB_ASSERT(domain->alt_name != NULL);
244 realm = SMB_STRDUP(domain->alt_name);
246 else {
247 struct winbindd_domain *our_domain = domain;
250 /* always give preference to the alt_name in our
251 primary domain if possible */
253 if ( !domain->primary )
254 our_domain = find_our_domain();
256 if (our_domain->alt_name != NULL) {
257 realm = SMB_STRDUP( our_domain->alt_name );
259 else
260 realm = SMB_STRDUP( lp_realm() );
263 status = ads_cached_connection_connect(
264 (ADS_STRUCT **)&domain->private_data,
265 domain->alt_name,
266 domain->name, NULL,
267 password, realm,
268 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
269 SAFE_FREE(realm);
271 if (!ADS_ERR_OK(status)) {
272 /* if we get ECONNREFUSED then it might be a NT4
273 server, fall back to MSRPC */
274 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
275 status.err.rc == ECONNREFUSED) {
276 /* 'reconnect_methods' is the MS-RPC backend. */
277 DEBUG(1,("Trying MSRPC methods\n"));
278 domain->backend = &reconnect_methods;
280 return NULL;
283 return (ADS_STRUCT *)domain->private_data;
286 /* Query display info for a realm. This is the basic user list fn */
287 static NTSTATUS query_user_list(struct winbindd_domain *domain,
288 TALLOC_CTX *mem_ctx,
289 uint32_t *num_entries,
290 struct wbint_userinfo **pinfo)
292 ADS_STRUCT *ads = NULL;
293 const char *attrs[] = { "*", NULL };
294 int i, count;
295 ADS_STATUS rc;
296 LDAPMessage *res = NULL;
297 LDAPMessage *msg = NULL;
298 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
300 *num_entries = 0;
302 DEBUG(3,("ads: query_user_list\n"));
304 if ( !winbindd_can_contact_domain( domain ) ) {
305 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
306 domain->name));
307 return NT_STATUS_OK;
310 ads = ads_cached_connection(domain);
312 if (!ads) {
313 domain->last_status = NT_STATUS_SERVER_DISABLED;
314 goto done;
317 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
318 if (!ADS_ERR_OK(rc)) {
319 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
320 status = ads_ntstatus(rc);
321 goto done;
322 } else if (!res) {
323 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
324 goto done;
327 count = ads_count_replies(ads, res);
328 if (count == 0) {
329 DEBUG(1,("query_user_list: No users found\n"));
330 goto done;
333 (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
334 if (!*pinfo) {
335 status = NT_STATUS_NO_MEMORY;
336 goto done;
339 count = 0;
341 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
342 struct wbint_userinfo *info = &((*pinfo)[count]);
343 uint32_t group;
344 uint32_t atype;
346 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
347 ds_atype_map(atype) != SID_NAME_USER) {
348 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
349 continue;
352 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
353 info->full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
354 if (info->full_name == NULL) {
355 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
357 info->homedir = NULL;
358 info->shell = NULL;
359 info->primary_gid = (gid_t)-1;
361 if (!ads_pull_sid(ads, msg, "objectSid",
362 &info->user_sid)) {
363 DEBUG(1, ("No sid for %s !?\n", info->acct_name));
364 continue;
367 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
368 DEBUG(1, ("No primary group for %s !?\n",
369 info->acct_name));
370 continue;
372 sid_compose(&info->group_sid, &domain->sid, group);
374 count += 1;
377 (*num_entries) = count;
378 ads_msgfree(ads, res);
380 for (i=0; i<count; i++) {
381 struct wbint_userinfo *info = &((*pinfo)[i]);
382 const char *gecos = NULL;
383 gid_t primary_gid = (gid_t)-1;
385 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
386 &info->homedir, &info->shell,
387 &gecos, &primary_gid);
388 if (!NT_STATUS_IS_OK(status)) {
390 * Deliberately ignore this error, there might be more
391 * users to fill
393 continue;
396 if (gecos != NULL) {
397 info->full_name = gecos;
399 info->primary_gid = primary_gid;
402 status = NT_STATUS_OK;
404 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
406 done:
407 return status;
410 /* list all domain groups */
411 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
412 TALLOC_CTX *mem_ctx,
413 uint32_t *num_entries,
414 struct wb_acct_info **info)
416 ADS_STRUCT *ads = NULL;
417 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
418 "name", "objectSid", NULL};
419 int i, count;
420 ADS_STATUS rc;
421 LDAPMessage *res = NULL;
422 LDAPMessage *msg = NULL;
423 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
424 const char *filter;
425 bool enum_dom_local_groups = False;
427 *num_entries = 0;
429 DEBUG(3,("ads: enum_dom_groups\n"));
431 if ( !winbindd_can_contact_domain( domain ) ) {
432 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
433 domain->name));
434 return NT_STATUS_OK;
437 /* only grab domain local groups for our domain */
438 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
439 enum_dom_local_groups = True;
442 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
443 * rollup-fixes:
445 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
446 * default value, it MUST be absent. In case of extensible matching the
447 * "dnattr" boolean defaults to FALSE and so it must be only be present
448 * when set to TRUE.
450 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
451 * filter using bitwise matching rule then the buggy AD fails to decode
452 * the extensible match. As a workaround set it to TRUE and thereby add
453 * the dnAttributes "dn" field to cope with those older AD versions.
454 * It should not harm and won't put any additional load on the AD since
455 * none of the dn components have a bitmask-attribute.
457 * Thanks to Ralf Haferkamp for input and testing - Guenther */
459 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
460 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
461 ADS_LDAP_MATCHING_RULE_BIT_AND,
462 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
464 if (filter == NULL) {
465 status = NT_STATUS_NO_MEMORY;
466 goto done;
469 ads = ads_cached_connection(domain);
471 if (!ads) {
472 domain->last_status = NT_STATUS_SERVER_DISABLED;
473 goto done;
476 rc = ads_search_retry(ads, &res, filter, attrs);
477 if (!ADS_ERR_OK(rc)) {
478 status = ads_ntstatus(rc);
479 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
480 goto done;
481 } else if (!res) {
482 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
483 goto done;
486 count = ads_count_replies(ads, res);
487 if (count == 0) {
488 DEBUG(1,("enum_dom_groups: No groups found\n"));
489 goto done;
492 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
493 if (!*info) {
494 status = NT_STATUS_NO_MEMORY;
495 goto done;
498 i = 0;
500 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
501 char *name, *gecos;
502 struct dom_sid sid;
503 uint32_t rid;
505 name = ads_pull_username(ads, mem_ctx, msg);
506 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
507 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
508 DEBUG(1,("No sid for %s !?\n", name));
509 continue;
512 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
513 DEBUG(1,("No rid for %s !?\n", name));
514 continue;
517 fstrcpy((*info)[i].acct_name, name);
518 fstrcpy((*info)[i].acct_desc, gecos);
519 (*info)[i].rid = rid;
520 i++;
523 (*num_entries) = i;
525 status = NT_STATUS_OK;
527 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
529 done:
530 if (res)
531 ads_msgfree(ads, res);
533 return status;
536 /* list all domain local groups */
537 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
538 TALLOC_CTX *mem_ctx,
539 uint32_t *num_entries,
540 struct wb_acct_info **info)
543 * This is a stub function only as we returned the domain
544 * local groups in enum_dom_groups() if the domain->native field
545 * was true. This is a simple performance optimization when
546 * using LDAP.
548 * if we ever need to enumerate domain local groups separately,
549 * then this optimization in enum_dom_groups() will need
550 * to be split out
552 *num_entries = 0;
554 return NT_STATUS_OK;
557 /* convert a single name to a sid in a domain - use rpc methods */
558 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
559 TALLOC_CTX *mem_ctx,
560 const char *domain_name,
561 const char *name,
562 uint32_t flags,
563 struct dom_sid *sid,
564 enum lsa_SidType *type)
566 return reconnect_methods.name_to_sid(domain, mem_ctx,
567 domain_name, name, flags,
568 sid, type);
571 /* convert a domain SID to a user or group name - use rpc methods */
572 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
573 TALLOC_CTX *mem_ctx,
574 const struct dom_sid *sid,
575 char **domain_name,
576 char **name,
577 enum lsa_SidType *type)
579 return reconnect_methods.sid_to_name(domain, mem_ctx, sid,
580 domain_name, name, type);
583 /* convert a list of rids to names - use rpc methods */
584 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
585 TALLOC_CTX *mem_ctx,
586 const struct dom_sid *sid,
587 uint32_t *rids,
588 size_t num_rids,
589 char **domain_name,
590 char ***names,
591 enum lsa_SidType **types)
593 return reconnect_methods.rids_to_names(domain, mem_ctx, sid,
594 rids, num_rids,
595 domain_name, names, types);
598 /* If you are looking for "dn_lookup": Yes, it used to be here!
599 * It has gone now since it was a major speed bottleneck in
600 * lookup_groupmem (its only use). It has been replaced by
601 * an rpc lookup sids call... R.I.P. */
603 /* Lookup user information from a rid */
604 static NTSTATUS query_user(struct winbindd_domain *domain,
605 TALLOC_CTX *mem_ctx,
606 const struct dom_sid *sid,
607 struct wbint_userinfo *info)
609 ADS_STRUCT *ads = NULL;
610 const char *attrs[] = { "*", NULL };
611 ADS_STATUS rc;
612 int count;
613 LDAPMessage *msg = NULL;
614 char *ldap_exp;
615 char *sidstr;
616 uint32_t group_rid;
617 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
618 struct netr_SamInfo3 *user = NULL;
619 gid_t gid = -1;
620 int ret;
621 char *full_name;
623 DEBUG(3,("ads: query_user\n"));
625 info->homedir = NULL;
626 info->shell = NULL;
628 /* try netsamlogon cache first */
630 if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
632 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
633 sid_string_dbg(sid)));
635 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
636 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
638 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
639 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
641 nss_get_info_cached( domain, sid, mem_ctx,
642 &info->homedir, &info->shell, &info->full_name,
643 &gid );
644 info->primary_gid = gid;
646 TALLOC_FREE(user);
648 if (info->full_name == NULL) {
649 /* this might fail so we dont check the return code */
650 wcache_query_user_fullname(domain,
651 mem_ctx,
652 sid,
653 &info->full_name);
656 return NT_STATUS_OK;
659 if ( !winbindd_can_contact_domain(domain)) {
660 DEBUG(8,("query_user: No incoming trust from domain %s\n",
661 domain->name));
663 /* We still need to generate some basic information
664 about the user even if we cannot contact the
665 domain. Most of this stuff we can deduce. */
667 sid_copy( &info->user_sid, sid );
669 /* Assume "Domain Users" for the primary group */
671 sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
673 /* Try to fill in what the nss_info backend can do */
675 nss_get_info_cached( domain, sid, mem_ctx,
676 &info->homedir, &info->shell, &info->full_name,
677 &gid);
678 info->primary_gid = gid;
680 return NT_STATUS_OK;
683 /* no cache...do the query */
685 if ( (ads = ads_cached_connection(domain)) == NULL ) {
686 domain->last_status = NT_STATUS_SERVER_DISABLED;
687 return NT_STATUS_SERVER_DISABLED;
690 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
692 ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
693 TALLOC_FREE(sidstr);
694 if (ret == -1) {
695 return NT_STATUS_NO_MEMORY;
697 rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
698 SAFE_FREE(ldap_exp);
699 if (!ADS_ERR_OK(rc)) {
700 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
701 sid_string_dbg(sid), ads_errstr(rc)));
702 return ads_ntstatus(rc);
703 } else if (!msg) {
704 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
705 sid_string_dbg(sid)));
706 return NT_STATUS_INTERNAL_ERROR;
709 count = ads_count_replies(ads, msg);
710 if (count != 1) {
711 DEBUG(1,("query_user(sid=%s): Not found\n",
712 sid_string_dbg(sid)));
713 ads_msgfree(ads, msg);
714 return NT_STATUS_NO_SUCH_USER;
717 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
719 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
720 DEBUG(1,("No primary group for %s !?\n",
721 sid_string_dbg(sid)));
722 ads_msgfree(ads, msg);
723 return NT_STATUS_NO_SUCH_USER;
725 sid_copy(&info->user_sid, sid);
726 sid_compose(&info->group_sid, &domain->sid, group_rid);
729 * We have to fetch the "name" attribute before doing the
730 * nss_get_info_cached call. nss_get_info_cached might destroy
731 * the ads struct, potentially invalidating the ldap message.
733 full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
734 if (full_name == NULL) {
735 full_name = ads_pull_string(ads, mem_ctx, msg, "name");
738 ads_msgfree(ads, msg);
739 msg = NULL;
741 status = nss_get_info_cached( domain, sid, mem_ctx,
742 &info->homedir, &info->shell, &info->full_name,
743 &gid);
744 info->primary_gid = gid;
745 if (!NT_STATUS_IS_OK(status)) {
746 DEBUG(1, ("nss_get_info_cached failed: %s\n",
747 nt_errstr(status)));
748 return status;
751 if (info->full_name == NULL) {
752 info->full_name = full_name;
753 } else {
754 TALLOC_FREE(full_name);
757 status = NT_STATUS_OK;
759 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
760 return NT_STATUS_OK;
763 /* Lookup groups a user is a member of - alternate method, for when
764 tokenGroups are not available. */
765 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
766 TALLOC_CTX *mem_ctx,
767 const char *user_dn,
768 struct dom_sid *primary_group,
769 uint32_t *p_num_groups, struct dom_sid **user_sids)
771 ADS_STATUS rc;
772 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
773 int count;
774 LDAPMessage *res = NULL;
775 LDAPMessage *msg = NULL;
776 char *ldap_exp;
777 ADS_STRUCT *ads;
778 const char *group_attrs[] = {"objectSid", NULL};
779 char *escaped_dn;
780 uint32_t num_groups = 0;
782 DEBUG(3,("ads: lookup_usergroups_member\n"));
784 if ( !winbindd_can_contact_domain( domain ) ) {
785 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
786 domain->name));
787 return NT_STATUS_OK;
790 ads = ads_cached_connection(domain);
792 if (!ads) {
793 domain->last_status = NT_STATUS_SERVER_DISABLED;
794 goto done;
797 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
798 status = NT_STATUS_NO_MEMORY;
799 goto done;
802 ldap_exp = talloc_asprintf(mem_ctx,
803 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
804 escaped_dn,
805 ADS_LDAP_MATCHING_RULE_BIT_AND,
806 GROUP_TYPE_SECURITY_ENABLED);
807 if (!ldap_exp) {
808 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
809 TALLOC_FREE(escaped_dn);
810 status = NT_STATUS_NO_MEMORY;
811 goto done;
814 TALLOC_FREE(escaped_dn);
816 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
818 if (!ADS_ERR_OK(rc)) {
819 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
820 return ads_ntstatus(rc);
821 } else if (!res) {
822 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
823 return NT_STATUS_INTERNAL_ERROR;
827 count = ads_count_replies(ads, res);
829 *user_sids = NULL;
830 num_groups = 0;
832 /* always add the primary group to the sid array */
833 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
834 &num_groups);
835 if (!NT_STATUS_IS_OK(status)) {
836 goto done;
839 if (count > 0) {
840 for (msg = ads_first_entry(ads, res); msg;
841 msg = ads_next_entry(ads, msg)) {
842 struct dom_sid group_sid;
844 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
845 DEBUG(1,("No sid for this group ?!?\n"));
846 continue;
849 /* ignore Builtin groups from ADS - Guenther */
850 if (sid_check_is_in_builtin(&group_sid)) {
851 continue;
854 status = add_sid_to_array(mem_ctx, &group_sid,
855 user_sids, &num_groups);
856 if (!NT_STATUS_IS_OK(status)) {
857 goto done;
863 *p_num_groups = num_groups;
864 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
866 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
867 done:
868 if (res)
869 ads_msgfree(ads, res);
871 return status;
874 /* Lookup groups a user is a member of - alternate method, for when
875 tokenGroups are not available. */
876 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
877 TALLOC_CTX *mem_ctx,
878 const char *user_dn,
879 struct dom_sid *primary_group,
880 uint32_t *p_num_groups,
881 struct dom_sid **user_sids)
883 ADS_STATUS rc;
884 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
885 ADS_STRUCT *ads;
886 const char *attrs[] = {"memberOf", NULL};
887 uint32_t num_groups = 0;
888 struct dom_sid *group_sids = NULL;
889 int i;
890 char **strings = NULL;
891 size_t num_strings = 0, num_sids = 0;
894 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
896 if ( !winbindd_can_contact_domain( domain ) ) {
897 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
898 "domain %s\n", domain->name));
899 return NT_STATUS_OK;
902 ads = ads_cached_connection(domain);
904 if (!ads) {
905 domain->last_status = NT_STATUS_SERVER_DISABLED;
906 return NT_STATUS_UNSUCCESSFUL;
909 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
910 ADS_EXTENDED_DN_HEX_STRING,
911 &strings, &num_strings);
913 if (!ADS_ERR_OK(rc)) {
914 DEBUG(1,("lookup_usergroups_memberof ads_search "
915 "member=%s: %s\n", user_dn, ads_errstr(rc)));
916 return ads_ntstatus(rc);
919 *user_sids = NULL;
920 num_groups = 0;
922 /* always add the primary group to the sid array */
923 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
924 &num_groups);
925 if (!NT_STATUS_IS_OK(status)) {
926 goto done;
929 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
930 if (!group_sids) {
931 status = NT_STATUS_NO_MEMORY;
932 goto done;
935 for (i=0; i<num_strings; i++) {
936 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
937 ADS_EXTENDED_DN_HEX_STRING,
938 &(group_sids)[i]);
939 if (!ADS_ERR_OK(rc)) {
940 /* ignore members without SIDs */
941 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
942 NT_STATUS_NOT_FOUND)) {
943 continue;
945 else {
946 status = ads_ntstatus(rc);
947 goto done;
950 num_sids++;
953 if (i == 0) {
954 DEBUG(1,("No memberOf for this user?!?\n"));
955 status = NT_STATUS_NO_MEMORY;
956 goto done;
959 for (i=0; i<num_sids; i++) {
961 /* ignore Builtin groups from ADS - Guenther */
962 if (sid_check_is_in_builtin(&group_sids[i])) {
963 continue;
966 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
967 &num_groups);
968 if (!NT_STATUS_IS_OK(status)) {
969 goto done;
974 *p_num_groups = num_groups;
975 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
977 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
978 user_dn));
980 done:
981 TALLOC_FREE(strings);
982 TALLOC_FREE(group_sids);
984 return status;
988 /* Lookup groups a user is a member of. */
989 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
990 TALLOC_CTX *mem_ctx,
991 const struct dom_sid *sid,
992 uint32_t *p_num_groups, struct dom_sid **user_sids)
994 ADS_STRUCT *ads = NULL;
995 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
996 ADS_STATUS rc;
997 int count;
998 LDAPMessage *msg = NULL;
999 char *user_dn = NULL;
1000 struct dom_sid *sids;
1001 int i;
1002 struct dom_sid primary_group;
1003 uint32_t primary_group_rid;
1004 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1005 uint32_t num_groups = 0;
1007 DEBUG(3,("ads: lookup_usergroups\n"));
1008 *p_num_groups = 0;
1010 status = lookup_usergroups_cached(domain, mem_ctx, sid,
1011 p_num_groups, user_sids);
1012 if (NT_STATUS_IS_OK(status)) {
1013 return NT_STATUS_OK;
1016 if ( !winbindd_can_contact_domain( domain ) ) {
1017 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
1018 domain->name));
1020 /* Tell the cache manager not to remember this one */
1022 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
1025 ads = ads_cached_connection(domain);
1027 if (!ads) {
1028 domain->last_status = NT_STATUS_SERVER_DISABLED;
1029 status = NT_STATUS_SERVER_DISABLED;
1030 goto done;
1033 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
1035 if (!ADS_ERR_OK(rc)) {
1036 status = ads_ntstatus(rc);
1037 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1038 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
1039 goto done;
1042 count = ads_count_replies(ads, msg);
1043 if (count != 1) {
1044 status = NT_STATUS_UNSUCCESSFUL;
1045 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1046 "invalid number of results (count=%d)\n",
1047 sid_string_dbg(sid), count));
1048 goto done;
1051 if (!msg) {
1052 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
1053 sid_string_dbg(sid)));
1054 status = NT_STATUS_UNSUCCESSFUL;
1055 goto done;
1058 user_dn = ads_get_dn(ads, mem_ctx, msg);
1059 if (user_dn == NULL) {
1060 status = NT_STATUS_NO_MEMORY;
1061 goto done;
1064 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
1065 DEBUG(1,("%s: No primary group for sid=%s !?\n",
1066 domain->name, sid_string_dbg(sid)));
1067 goto done;
1070 sid_compose(&primary_group, &domain->sid, primary_group_rid);
1072 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
1074 /* there must always be at least one group in the token,
1075 unless we are talking to a buggy Win2k server */
1077 /* actually this only happens when the machine account has no read
1078 * permissions on the tokenGroup attribute - gd */
1080 if (count == 0) {
1082 /* no tokenGroups */
1084 /* lookup what groups this user is a member of by DN search on
1085 * "memberOf" */
1087 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
1088 &primary_group,
1089 &num_groups, user_sids);
1090 *p_num_groups = num_groups;
1091 if (NT_STATUS_IS_OK(status)) {
1092 goto done;
1095 /* lookup what groups this user is a member of by DN search on
1096 * "member" */
1098 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
1099 &primary_group,
1100 &num_groups, user_sids);
1101 *p_num_groups = num_groups;
1102 goto done;
1105 *user_sids = NULL;
1106 num_groups = 0;
1108 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
1109 &num_groups);
1110 if (!NT_STATUS_IS_OK(status)) {
1111 goto done;
1114 for (i=0;i<count;i++) {
1116 /* ignore Builtin groups from ADS - Guenther */
1117 if (sid_check_is_in_builtin(&sids[i])) {
1118 continue;
1121 status = add_sid_to_array_unique(mem_ctx, &sids[i],
1122 user_sids, &num_groups);
1123 if (!NT_STATUS_IS_OK(status)) {
1124 goto done;
1128 *p_num_groups = (uint32_t)num_groups;
1129 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1131 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1132 sid_string_dbg(sid)));
1133 done:
1134 TALLOC_FREE(user_dn);
1135 ads_msgfree(ads, msg);
1136 return status;
1139 /* Lookup aliases a user is member of - use rpc methods */
1140 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1141 TALLOC_CTX *mem_ctx,
1142 uint32_t num_sids, const struct dom_sid *sids,
1143 uint32_t *num_aliases, uint32_t **alias_rids)
1145 return reconnect_methods.lookup_useraliases(domain, mem_ctx,
1146 num_sids, sids,
1147 num_aliases,
1148 alias_rids);
1151 static NTSTATUS add_primary_group_members(
1152 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
1153 char ***all_members, size_t *num_all_members)
1155 char *filter;
1156 NTSTATUS status = NT_STATUS_NO_MEMORY;
1157 ADS_STATUS rc;
1158 const char *attrs[] = { "dn", NULL };
1159 LDAPMessage *res = NULL;
1160 LDAPMessage *msg;
1161 char **members;
1162 size_t num_members;
1163 ads_control args;
1165 filter = talloc_asprintf(
1166 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1167 (unsigned)rid);
1168 if (filter == NULL) {
1169 goto done;
1172 args.control = ADS_EXTENDED_DN_OID;
1173 args.val = ADS_EXTENDED_DN_HEX_STRING;
1174 args.critical = True;
1176 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1177 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1178 &res);
1180 if (!ADS_ERR_OK(rc)) {
1181 status = ads_ntstatus(rc);
1182 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1183 goto done;
1185 if (res == NULL) {
1186 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1187 goto done;
1190 num_members = ads_count_replies(ads, res);
1192 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1193 (uintmax_t)num_members));
1195 if (num_members == 0) {
1196 status = NT_STATUS_OK;
1197 goto done;
1200 members = talloc_realloc(mem_ctx, *all_members, char *,
1201 *num_all_members + num_members);
1202 if (members == NULL) {
1203 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1204 goto done;
1206 *all_members = members;
1208 for (msg = ads_first_entry(ads, res); msg != NULL;
1209 msg = ads_next_entry(ads, msg)) {
1210 char *dn;
1212 dn = ads_get_dn(ads, members, msg);
1213 if (dn == NULL) {
1214 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1215 continue;
1218 members[*num_all_members] = dn;
1219 *num_all_members += 1;
1222 status = NT_STATUS_OK;
1223 done:
1224 if (res != NULL) {
1225 ads_msgfree(ads, res);
1227 TALLOC_FREE(filter);
1228 return status;
1232 find the members of a group, given a group rid and domain
1234 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1235 TALLOC_CTX *mem_ctx,
1236 const struct dom_sid *group_sid,
1237 enum lsa_SidType type,
1238 uint32_t *num_names,
1239 struct dom_sid **sid_mem, char ***names,
1240 uint32_t **name_types)
1242 ADS_STATUS rc;
1243 ADS_STRUCT *ads = NULL;
1244 char *ldap_exp;
1245 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1246 char *sidbinstr;
1247 char **members = NULL;
1248 int i;
1249 size_t num_members = 0;
1250 ads_control args;
1251 struct dom_sid *sid_mem_nocache = NULL;
1252 char **names_nocache = NULL;
1253 enum lsa_SidType *name_types_nocache = NULL;
1254 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1255 uint32_t num_nocache = 0;
1256 TALLOC_CTX *tmp_ctx = NULL;
1257 uint32_t rid;
1259 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1260 sid_string_dbg(group_sid)));
1262 *num_names = 0;
1264 tmp_ctx = talloc_new(mem_ctx);
1265 if (!tmp_ctx) {
1266 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1267 status = NT_STATUS_NO_MEMORY;
1268 goto done;
1271 if (!sid_peek_rid(group_sid, &rid)) {
1272 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1273 status = NT_STATUS_INVALID_PARAMETER;
1274 goto done;
1277 if ( !winbindd_can_contact_domain( domain ) ) {
1278 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1279 domain->name));
1280 return NT_STATUS_OK;
1283 ads = ads_cached_connection(domain);
1285 if (!ads) {
1286 domain->last_status = NT_STATUS_SERVER_DISABLED;
1287 goto done;
1290 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1291 status = NT_STATUS_NO_MEMORY;
1292 goto done;
1295 /* search for all members of the group */
1296 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1297 TALLOC_FREE(sidbinstr);
1298 if (ldap_exp == NULL) {
1299 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1300 status = NT_STATUS_NO_MEMORY;
1301 goto done;
1304 args.control = ADS_EXTENDED_DN_OID;
1305 args.val = ADS_EXTENDED_DN_HEX_STRING;
1306 args.critical = True;
1308 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1309 ldap_exp, &args, "member", &members, &num_members);
1311 if (!ADS_ERR_OK(rc)) {
1312 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1313 status = NT_STATUS_UNSUCCESSFUL;
1314 goto done;
1317 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1319 status = add_primary_group_members(ads, mem_ctx, rid,
1320 &members, &num_members);
1321 if (!NT_STATUS_IS_OK(status)) {
1322 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1323 __func__, nt_errstr(status)));
1324 goto done;
1327 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1328 __func__, (int)num_members));
1330 /* Now that we have a list of sids, we need to get the
1331 * lists of names and name_types belonging to these sids.
1332 * even though conceptually not quite clean, we use the
1333 * RPC call lsa_lookup_sids for this since it can handle a
1334 * list of sids. ldap calls can just resolve one sid at a time.
1336 * At this stage, the sids are still hidden in the exetended dn
1337 * member output format. We actually do a little better than
1338 * stated above: In extracting the sids from the member strings,
1339 * we try to resolve as many sids as possible from the
1340 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1342 if (num_members) {
1343 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1344 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1345 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1346 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1348 if ((members == NULL) || (*sid_mem == NULL) ||
1349 (*names == NULL) || (*name_types == NULL) ||
1350 (sid_mem_nocache == NULL))
1352 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1353 status = NT_STATUS_NO_MEMORY;
1354 goto done;
1357 else {
1358 (*sid_mem) = NULL;
1359 (*names) = NULL;
1360 (*name_types) = NULL;
1363 for (i=0; i<num_members; i++) {
1364 enum lsa_SidType name_type;
1365 char *name, *domain_name;
1366 struct dom_sid sid;
1368 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1369 &sid);
1370 if (!ADS_ERR_OK(rc)) {
1371 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1372 NT_STATUS_NOT_FOUND)) {
1373 /* Group members can be objects, like Exchange
1374 * Public Folders, that don't have a SID. Skip
1375 * them. */
1376 continue;
1378 else {
1379 status = ads_ntstatus(rc);
1380 goto done;
1383 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1384 &name_type)) {
1385 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1386 "cache\n", sid_string_dbg(&sid)));
1387 sid_copy(&(*sid_mem)[*num_names], &sid);
1388 (*names)[*num_names] = fill_domain_username_talloc(
1389 *names,
1390 domain_name,
1391 name,
1392 true);
1394 (*name_types)[*num_names] = name_type;
1395 (*num_names)++;
1397 else {
1398 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1399 "cache\n", sid_string_dbg(&sid)));
1400 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1401 num_nocache++;
1405 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1406 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1408 /* handle sids not resolved from cache by lsa_lookup_sids */
1409 if (num_nocache > 0) {
1411 status = winbindd_lookup_sids(tmp_ctx,
1412 domain,
1413 num_nocache,
1414 sid_mem_nocache,
1415 &domains_nocache,
1416 &names_nocache,
1417 &name_types_nocache);
1419 if (!(NT_STATUS_IS_OK(status) ||
1420 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1421 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1423 DEBUG(1, ("lsa_lookupsids call failed with %s "
1424 "- retrying...\n", nt_errstr(status)));
1426 status = winbindd_lookup_sids(tmp_ctx,
1427 domain,
1428 num_nocache,
1429 sid_mem_nocache,
1430 &domains_nocache,
1431 &names_nocache,
1432 &name_types_nocache);
1435 if (NT_STATUS_IS_OK(status) ||
1436 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1438 /* Copy the entries over from the "_nocache" arrays
1439 * to the result arrays, skipping the gaps the
1440 * lookup_sids call left. */
1441 for (i=0; i < num_nocache; i++) {
1442 if (((names_nocache)[i] != NULL) &&
1443 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1445 sid_copy(&(*sid_mem)[*num_names],
1446 &sid_mem_nocache[i]);
1447 (*names)[*num_names] =
1448 fill_domain_username_talloc(
1449 *names,
1450 domains_nocache[i],
1451 names_nocache[i],
1452 true);
1453 (*name_types)[*num_names] = name_types_nocache[i];
1454 (*num_names)++;
1458 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1459 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1460 "not map any SIDs at all.\n"));
1461 /* Don't handle this as an error here.
1462 * There is nothing left to do with respect to the
1463 * overall result... */
1465 else if (!NT_STATUS_IS_OK(status)) {
1466 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1467 "sids via rpc_lsa_lookup_sids: %s\n",
1468 (int)num_members, nt_errstr(status)));
1469 goto done;
1473 status = NT_STATUS_OK;
1474 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1475 sid_string_dbg(group_sid)));
1477 done:
1479 TALLOC_FREE(tmp_ctx);
1481 return status;
1484 /* find the sequence number for a domain */
1485 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1487 ADS_STRUCT *ads = NULL;
1488 ADS_STATUS rc;
1490 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1492 if ( !winbindd_can_contact_domain( domain ) ) {
1493 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1494 domain->name));
1495 *seq = time(NULL);
1496 return NT_STATUS_OK;
1499 *seq = DOM_SEQUENCE_NONE;
1501 ads = ads_cached_connection(domain);
1503 if (!ads) {
1504 domain->last_status = NT_STATUS_SERVER_DISABLED;
1505 return NT_STATUS_UNSUCCESSFUL;
1508 rc = ads_USN(ads, seq);
1510 if (!ADS_ERR_OK(rc)) {
1512 /* its a dead connection, destroy it */
1514 if (domain->private_data) {
1515 ads = (ADS_STRUCT *)domain->private_data;
1516 ads->is_mine = True;
1517 ads_destroy(&ads);
1518 ads_kdestroy(WINBIND_CCACHE_NAME);
1519 domain->private_data = NULL;
1522 return ads_ntstatus(rc);
1525 /* find the lockout policy of a domain - use rpc methods */
1526 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1527 TALLOC_CTX *mem_ctx,
1528 struct samr_DomInfo12 *policy)
1530 return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
1533 /* find the password policy of a domain - use rpc methods */
1534 static NTSTATUS password_policy(struct winbindd_domain *domain,
1535 TALLOC_CTX *mem_ctx,
1536 struct samr_DomInfo1 *policy)
1538 return reconnect_methods.password_policy(domain, mem_ctx, policy);
1541 /* get a list of trusted domains */
1542 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1543 TALLOC_CTX *mem_ctx,
1544 struct netr_DomainTrustList *trusts)
1546 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1547 WERROR werr;
1548 int i;
1549 uint32_t flags;
1550 struct rpc_pipe_client *cli;
1551 int ret_count;
1552 struct dcerpc_binding_handle *b;
1554 DEBUG(3,("ads: trusted_domains\n"));
1556 ZERO_STRUCTP(trusts);
1558 /* If this is our primary domain or a root in our forest,
1559 query for all trusts. If not, then just look for domain
1560 trusts in the target forest */
1562 if (domain->primary || domain_is_forest_root(domain)) {
1563 flags = NETR_TRUST_FLAG_OUTBOUND |
1564 NETR_TRUST_FLAG_INBOUND |
1565 NETR_TRUST_FLAG_IN_FOREST;
1566 } else {
1567 flags = NETR_TRUST_FLAG_IN_FOREST;
1570 result = cm_connect_netlogon(domain, &cli);
1572 if (!NT_STATUS_IS_OK(result)) {
1573 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1574 "for PIPE_NETLOGON (%s)\n",
1575 domain->name, nt_errstr(result)));
1576 return NT_STATUS_UNSUCCESSFUL;
1579 b = cli->binding_handle;
1581 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1582 cli->desthost,
1583 flags,
1584 trusts,
1585 &werr);
1586 if (!NT_STATUS_IS_OK(result)) {
1587 return result;
1590 if (!W_ERROR_IS_OK(werr)) {
1591 return werror_to_ntstatus(werr);
1593 if (trusts->count == 0) {
1594 return NT_STATUS_OK;
1597 /* Copy across names and sids */
1599 ret_count = 0;
1600 for (i = 0; i < trusts->count; i++) {
1601 struct netr_DomainTrust *trust = &trusts->array[i];
1602 struct winbindd_domain d;
1604 ZERO_STRUCT(d);
1607 * drop external trusts if this is not our primary
1608 * domain. This means that the returned number of
1609 * domains may be less that the ones actually trusted
1610 * by the DC.
1613 if ((trust->trust_attributes
1614 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1615 !domain->primary )
1617 DEBUG(10,("trusted_domains: Skipping external trusted "
1618 "domain %s because it is outside of our "
1619 "primary domain\n",
1620 trust->netbios_name));
1621 continue;
1624 /* add to the trusted domain cache */
1626 d.name = discard_const_p(char, trust->netbios_name);
1627 d.alt_name = discard_const_p(char, trust->dns_name);
1629 if (trust->sid) {
1630 sid_copy(&d.sid, trust->sid);
1631 } else {
1632 sid_copy(&d.sid, &global_sid_NULL);
1635 if ( domain->primary ) {
1636 DEBUG(10,("trusted_domains(ads): Searching "
1637 "trusted domain list of %s and storing "
1638 "trust flags for domain %s\n",
1639 domain->name, d.alt_name));
1641 d.domain_flags = trust->trust_flags;
1642 d.domain_type = trust->trust_type;
1643 d.domain_trust_attribs = trust->trust_attributes;
1645 wcache_tdc_add_domain( &d );
1646 ret_count++;
1647 } else if (domain_is_forest_root(domain)) {
1648 /* Check if we already have this record. If
1649 * we are following our forest root that is not
1650 * our primary domain, we want to keep trust
1651 * flags from the perspective of our primary
1652 * domain not our forest root. */
1653 struct winbindd_tdc_domain *exist = NULL;
1655 exist = wcache_tdc_fetch_domain(
1656 talloc_tos(), trust->netbios_name);
1657 if (!exist) {
1658 DEBUG(10,("trusted_domains(ads): Searching "
1659 "trusted domain list of %s and "
1660 "storing trust flags for domain "
1661 "%s\n", domain->name, d.alt_name));
1662 d.domain_flags = trust->trust_flags;
1663 d.domain_type = trust->trust_type;
1664 d.domain_trust_attribs =
1665 trust->trust_attributes;
1667 wcache_tdc_add_domain( &d );
1668 ret_count++;
1670 TALLOC_FREE(exist);
1671 } else {
1672 /* This gets a little tricky. If we are
1673 following a transitive forest trust, then
1674 innerit the flags, type, and attribs from
1675 the domain we queried to make sure we don't
1676 record the view of the trust from the wrong
1677 side. Always view it from the side of our
1678 primary domain. --jerry */
1679 struct winbindd_tdc_domain *parent = NULL;
1681 DEBUG(10,("trusted_domains(ads): Searching "
1682 "trusted domain list of %s and inheriting "
1683 "trust flags for domain %s\n",
1684 domain->name, d.alt_name));
1686 parent = wcache_tdc_fetch_domain(talloc_tos(),
1687 domain->name);
1688 if (parent) {
1689 d.domain_flags = parent->trust_flags;
1690 d.domain_type = parent->trust_type;
1691 d.domain_trust_attribs = parent->trust_attribs;
1692 } else {
1693 d.domain_flags = domain->domain_flags;
1694 d.domain_type = domain->domain_type;
1695 d.domain_trust_attribs =
1696 domain->domain_trust_attribs;
1698 TALLOC_FREE(parent);
1700 wcache_tdc_add_domain( &d );
1701 ret_count++;
1704 return result;
1707 /* the ADS backend methods are exposed via this structure */
1708 struct winbindd_methods ads_methods = {
1709 True,
1710 query_user_list,
1711 enum_dom_groups,
1712 enum_local_groups,
1713 name_to_sid,
1714 sid_to_name,
1715 rids_to_names,
1716 query_user,
1717 lookup_usergroups,
1718 lookup_useraliases,
1719 lookup_groupmem,
1720 sequence_number,
1721 lockout_policy,
1722 password_policy,
1723 trusted_domains,
1726 #endif