wbinfo: Add --unix-ids-to-sids
[Samba.git] / source3 / winbindd / winbindd_ads.c
bloba9a23db423ba6dc906d769b26cea25d5d9d9675c
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;
41 extern struct winbindd_methods msrpc_methods;
43 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
45 /**
46 * Check if cached connection can be reused. If the connection cannot
47 * be reused the ADS_STRUCT is freed and the pointer is set to NULL.
49 static void ads_cached_connection_reuse(ADS_STRUCT **adsp)
52 ADS_STRUCT *ads = *adsp;
54 if (ads != NULL) {
55 time_t expire;
56 time_t now = time(NULL);
58 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
60 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
61 "is now %d)\n", (uint32_t)expire - (uint32_t)now,
62 (uint32_t) expire, (uint32_t) now));
64 if ( ads->config.realm && (expire > now)) {
65 return;
66 } else {
67 /* we own this ADS_STRUCT so make sure it goes away */
68 DEBUG(7,("Deleting expired krb5 credential cache\n"));
69 ads->is_mine = True;
70 ads_destroy( &ads );
71 ads_kdestroy(WINBIND_CCACHE_NAME);
72 *adsp = NULL;
77 /**
78 * @brief Establish a connection to a DC
80 * @param[out] adsp ADS_STRUCT that will be created
81 * @param[in] target_realm Realm of domain to connect to
82 * @param[in] target_dom_name 'workgroup' name of domain to connect to
83 * @param[in] ldap_server DNS name of server to connect to
84 * @param[in] password Our machine acount secret
85 * @param[in] auth_realm Realm of local domain for creating krb token
86 * @param[in] renewable Renewable ticket time
88 * @return ADS_STATUS
90 static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
91 const char *target_realm,
92 const char *target_dom_name,
93 const char *ldap_server,
94 char *password,
95 char *auth_realm,
96 time_t renewable)
98 ADS_STRUCT *ads;
99 ADS_STATUS status;
100 struct sockaddr_storage dc_ss;
101 fstring dc_name;
103 if (auth_realm == NULL) {
104 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
107 /* we don't want this to affect the users ccache */
108 setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
110 ads = ads_init(target_realm, target_dom_name, ldap_server);
111 if (!ads) {
112 DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
113 return ADS_ERROR(LDAP_NO_MEMORY);
116 SAFE_FREE(ads->auth.password);
117 SAFE_FREE(ads->auth.realm);
119 ads->auth.renewable = renewable;
120 ads->auth.password = password;
122 ads->auth.realm = SMB_STRDUP(auth_realm);
123 if (!strupper_m(ads->auth.realm)) {
124 ads_destroy(&ads);
125 return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
128 /* Setup the server affinity cache. We don't reaally care
129 about the name. Just setup affinity and the KRB5_CONFIG
130 file. */
131 get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
133 status = ads_connect(ads);
134 if (!ADS_ERR_OK(status)) {
135 DEBUG(1,("ads_connect for domain %s failed: %s\n",
136 target_dom_name, ads_errstr(status)));
137 ads_destroy(&ads);
138 return status;
141 /* set the flag that says we don't own the memory even
142 though we do so that ads_destroy() won't destroy the
143 structure we pass back by reference */
145 ads->is_mine = False;
147 *adsp = ads;
149 return status;
152 ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
154 char *ldap_server, *realm, *password;
155 struct winbindd_domain *wb_dom;
156 ADS_STATUS status;
158 ads_cached_connection_reuse(adsp);
159 if (*adsp != NULL) {
160 return ADS_SUCCESS;
164 * At this point we only have the NetBIOS domain name.
165 * Check if we can get server nam and realm from SAF cache
166 * and the domain list.
168 ldap_server = saf_fetch(talloc_tos(), dom_name);
169 DEBUG(10, ("ldap_server from saf cache: '%s'\n",
170 ldap_server ? ldap_server : ""));
172 wb_dom = find_domain_from_name(dom_name);
173 if (wb_dom == NULL) {
174 DEBUG(10, ("could not find domain '%s'\n", dom_name));
175 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
178 DEBUG(10, ("find_domain_from_name found realm '%s' for "
179 " domain '%s'\n", wb_dom->alt_name, dom_name));
181 if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
182 TALLOC_FREE(ldap_server);
183 return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
186 if (IS_DC) {
187 SMB_ASSERT(wb_dom->alt_name != NULL);
188 realm = SMB_STRDUP(wb_dom->alt_name);
189 } else {
190 struct winbindd_domain *our_domain = wb_dom;
192 /* always give preference to the alt_name in our
193 primary domain if possible */
195 if (!wb_dom->primary) {
196 our_domain = find_our_domain();
199 if (our_domain->alt_name != NULL) {
200 realm = SMB_STRDUP(our_domain->alt_name);
201 } else {
202 realm = SMB_STRDUP(lp_realm());
206 status = ads_cached_connection_connect(
207 adsp, /* Returns ads struct. */
208 wb_dom->alt_name, /* realm to connect to. */
209 dom_name, /* 'workgroup' name for ads_init */
210 ldap_server, /* DNS name to connect to. */
211 password, /* password for auth realm. */
212 realm, /* realm used for krb5 ticket. */
213 0); /* renewable ticket time. */
215 SAFE_FREE(realm);
216 TALLOC_FREE(ldap_server);
218 return status;
222 return our ads connections structure for a domain. We keep the connection
223 open to make things faster
225 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
227 ADS_STATUS status;
228 char *password, *realm;
230 DEBUG(10,("ads_cached_connection\n"));
231 ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
233 if (domain->private_data) {
234 return (ADS_STRUCT *)domain->private_data;
237 /* the machine acct password might have change - fetch it every time */
239 if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
240 return NULL;
243 if ( IS_DC ) {
244 SMB_ASSERT(domain->alt_name != NULL);
245 realm = SMB_STRDUP(domain->alt_name);
247 else {
248 struct winbindd_domain *our_domain = domain;
251 /* always give preference to the alt_name in our
252 primary domain if possible */
254 if ( !domain->primary )
255 our_domain = find_our_domain();
257 if (our_domain->alt_name != NULL) {
258 realm = SMB_STRDUP( our_domain->alt_name );
260 else
261 realm = SMB_STRDUP( lp_realm() );
264 status = ads_cached_connection_connect(
265 (ADS_STRUCT **)&domain->private_data,
266 domain->alt_name,
267 domain->name, NULL,
268 password, realm,
269 WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
270 SAFE_FREE(realm);
272 if (!ADS_ERR_OK(status)) {
273 /* if we get ECONNREFUSED then it might be a NT4
274 server, fall back to MSRPC */
275 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
276 status.err.rc == ECONNREFUSED) {
277 /* 'reconnect_methods' is the MS-RPC backend. */
278 DEBUG(1,("Trying MSRPC methods\n"));
279 domain->backend = &reconnect_methods;
281 return NULL;
284 return (ADS_STRUCT *)domain->private_data;
287 /* Query display info for a realm. This is the basic user list fn */
288 static NTSTATUS query_user_list(struct winbindd_domain *domain,
289 TALLOC_CTX *mem_ctx,
290 uint32_t *num_entries,
291 struct wbint_userinfo **pinfo)
293 ADS_STRUCT *ads = NULL;
294 const char *attrs[] = { "*", NULL };
295 int i, count;
296 ADS_STATUS rc;
297 LDAPMessage *res = NULL;
298 LDAPMessage *msg = NULL;
299 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
301 *num_entries = 0;
303 DEBUG(3,("ads: query_user_list\n"));
305 if ( !winbindd_can_contact_domain( domain ) ) {
306 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
307 domain->name));
308 return NT_STATUS_OK;
311 ads = ads_cached_connection(domain);
313 if (!ads) {
314 domain->last_status = NT_STATUS_SERVER_DISABLED;
315 goto done;
318 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
319 if (!ADS_ERR_OK(rc)) {
320 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
321 status = ads_ntstatus(rc);
322 goto done;
323 } else if (!res) {
324 DEBUG(1,("query_user_list ads_search returned NULL res\n"));
325 goto done;
328 count = ads_count_replies(ads, res);
329 if (count == 0) {
330 DEBUG(1,("query_user_list: No users found\n"));
331 goto done;
334 (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
335 if (!*pinfo) {
336 status = NT_STATUS_NO_MEMORY;
337 goto done;
340 count = 0;
342 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
343 struct wbint_userinfo *info = &((*pinfo)[count]);
344 uint32_t group;
345 uint32_t atype;
347 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
348 ds_atype_map(atype) != SID_NAME_USER) {
349 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
350 continue;
353 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
354 info->full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
355 if (info->full_name == NULL) {
356 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
358 info->homedir = NULL;
359 info->shell = NULL;
360 info->primary_gid = (gid_t)-1;
362 if (!ads_pull_sid(ads, msg, "objectSid",
363 &info->user_sid)) {
364 DEBUG(1, ("No sid for %s !?\n", info->acct_name));
365 continue;
368 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
369 DEBUG(1, ("No primary group for %s !?\n",
370 info->acct_name));
371 continue;
373 sid_compose(&info->group_sid, &domain->sid, group);
375 count += 1;
378 (*num_entries) = count;
379 ads_msgfree(ads, res);
381 for (i=0; i<count; i++) {
382 struct wbint_userinfo *info = &((*pinfo)[i]);
383 const char *gecos = NULL;
384 gid_t primary_gid = (gid_t)-1;
386 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
387 &info->homedir, &info->shell,
388 &gecos, &primary_gid);
389 if (!NT_STATUS_IS_OK(status)) {
391 * Deliberately ignore this error, there might be more
392 * users to fill
394 continue;
397 if (gecos != NULL) {
398 info->full_name = gecos;
400 info->primary_gid = primary_gid;
403 status = NT_STATUS_OK;
405 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
407 done:
408 return status;
411 /* list all domain groups */
412 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
413 TALLOC_CTX *mem_ctx,
414 uint32_t *num_entries,
415 struct wb_acct_info **info)
417 ADS_STRUCT *ads = NULL;
418 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
419 "name", "objectSid", NULL};
420 int i, count;
421 ADS_STATUS rc;
422 LDAPMessage *res = NULL;
423 LDAPMessage *msg = NULL;
424 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
425 const char *filter;
426 bool enum_dom_local_groups = False;
428 *num_entries = 0;
430 DEBUG(3,("ads: enum_dom_groups\n"));
432 if ( !winbindd_can_contact_domain( domain ) ) {
433 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
434 domain->name));
435 return NT_STATUS_OK;
438 /* only grab domain local groups for our domain */
439 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
440 enum_dom_local_groups = True;
443 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
444 * rollup-fixes:
446 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
447 * default value, it MUST be absent. In case of extensible matching the
448 * "dnattr" boolean defaults to FALSE and so it must be only be present
449 * when set to TRUE.
451 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
452 * filter using bitwise matching rule then the buggy AD fails to decode
453 * the extensible match. As a workaround set it to TRUE and thereby add
454 * the dnAttributes "dn" field to cope with those older AD versions.
455 * It should not harm and won't put any additional load on the AD since
456 * none of the dn components have a bitmask-attribute.
458 * Thanks to Ralf Haferkamp for input and testing - Guenther */
460 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
461 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
462 ADS_LDAP_MATCHING_RULE_BIT_AND,
463 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
465 if (filter == NULL) {
466 status = NT_STATUS_NO_MEMORY;
467 goto done;
470 ads = ads_cached_connection(domain);
472 if (!ads) {
473 domain->last_status = NT_STATUS_SERVER_DISABLED;
474 goto done;
477 rc = ads_search_retry(ads, &res, filter, attrs);
478 if (!ADS_ERR_OK(rc)) {
479 status = ads_ntstatus(rc);
480 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
481 goto done;
482 } else if (!res) {
483 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
484 goto done;
487 count = ads_count_replies(ads, res);
488 if (count == 0) {
489 DEBUG(1,("enum_dom_groups: No groups found\n"));
490 goto done;
493 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
494 if (!*info) {
495 status = NT_STATUS_NO_MEMORY;
496 goto done;
499 i = 0;
501 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
502 char *name, *gecos;
503 struct dom_sid sid;
504 uint32_t rid;
506 name = ads_pull_username(ads, mem_ctx, msg);
507 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
508 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
509 DEBUG(1,("No sid for %s !?\n", name));
510 continue;
513 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
514 DEBUG(1,("No rid for %s !?\n", name));
515 continue;
518 fstrcpy((*info)[i].acct_name, name);
519 fstrcpy((*info)[i].acct_desc, gecos);
520 (*info)[i].rid = rid;
521 i++;
524 (*num_entries) = i;
526 status = NT_STATUS_OK;
528 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
530 done:
531 if (res)
532 ads_msgfree(ads, res);
534 return status;
537 /* list all domain local groups */
538 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
539 TALLOC_CTX *mem_ctx,
540 uint32_t *num_entries,
541 struct wb_acct_info **info)
544 * This is a stub function only as we returned the domain
545 * local groups in enum_dom_groups() if the domain->native field
546 * was true. This is a simple performance optimization when
547 * using LDAP.
549 * if we ever need to enumerate domain local groups separately,
550 * then this optimization in enum_dom_groups() will need
551 * to be split out
553 *num_entries = 0;
555 return NT_STATUS_OK;
558 /* convert a single name to a sid in a domain - use rpc methods */
559 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
560 TALLOC_CTX *mem_ctx,
561 const char *domain_name,
562 const char *name,
563 uint32_t flags,
564 struct dom_sid *sid,
565 enum lsa_SidType *type)
567 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
568 flags, 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 msrpc_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 msrpc_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 don't 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 msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
1146 num_aliases, alias_rids);
1149 static NTSTATUS add_primary_group_members(
1150 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
1151 char ***all_members, size_t *num_all_members)
1153 char *filter;
1154 NTSTATUS status = NT_STATUS_NO_MEMORY;
1155 ADS_STATUS rc;
1156 const char *attrs[] = { "dn", NULL };
1157 LDAPMessage *res = NULL;
1158 LDAPMessage *msg;
1159 char **members;
1160 size_t num_members;
1161 ads_control args;
1163 filter = talloc_asprintf(
1164 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1165 (unsigned)rid);
1166 if (filter == NULL) {
1167 goto done;
1170 args.control = ADS_EXTENDED_DN_OID;
1171 args.val = ADS_EXTENDED_DN_HEX_STRING;
1172 args.critical = True;
1174 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1175 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1176 &res);
1178 if (!ADS_ERR_OK(rc)) {
1179 status = ads_ntstatus(rc);
1180 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1181 goto done;
1183 if (res == NULL) {
1184 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1185 goto done;
1188 num_members = ads_count_replies(ads, res);
1190 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1191 (uintmax_t)num_members));
1193 if (num_members == 0) {
1194 status = NT_STATUS_OK;
1195 goto done;
1198 members = talloc_realloc(mem_ctx, *all_members, char *,
1199 *num_all_members + num_members);
1200 if (members == NULL) {
1201 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1202 goto done;
1204 *all_members = members;
1206 for (msg = ads_first_entry(ads, res); msg != NULL;
1207 msg = ads_next_entry(ads, msg)) {
1208 char *dn;
1210 dn = ads_get_dn(ads, members, msg);
1211 if (dn == NULL) {
1212 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1213 continue;
1216 members[*num_all_members] = dn;
1217 *num_all_members += 1;
1220 status = NT_STATUS_OK;
1221 done:
1222 if (res != NULL) {
1223 ads_msgfree(ads, res);
1225 TALLOC_FREE(filter);
1226 return status;
1230 find the members of a group, given a group rid and domain
1232 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1233 TALLOC_CTX *mem_ctx,
1234 const struct dom_sid *group_sid,
1235 enum lsa_SidType type,
1236 uint32_t *num_names,
1237 struct dom_sid **sid_mem, char ***names,
1238 uint32_t **name_types)
1240 ADS_STATUS rc;
1241 ADS_STRUCT *ads = NULL;
1242 char *ldap_exp;
1243 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1244 char *sidbinstr;
1245 char **members = NULL;
1246 int i;
1247 size_t num_members = 0;
1248 ads_control args;
1249 struct dom_sid *sid_mem_nocache = NULL;
1250 char **names_nocache = NULL;
1251 enum lsa_SidType *name_types_nocache = NULL;
1252 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1253 uint32_t num_nocache = 0;
1254 TALLOC_CTX *tmp_ctx = NULL;
1255 uint32_t rid;
1257 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1258 sid_string_dbg(group_sid)));
1260 *num_names = 0;
1262 tmp_ctx = talloc_new(mem_ctx);
1263 if (!tmp_ctx) {
1264 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1265 status = NT_STATUS_NO_MEMORY;
1266 goto done;
1269 if (!sid_peek_rid(group_sid, &rid)) {
1270 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1271 status = NT_STATUS_INVALID_PARAMETER;
1272 goto done;
1275 if ( !winbindd_can_contact_domain( domain ) ) {
1276 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1277 domain->name));
1278 return NT_STATUS_OK;
1281 ads = ads_cached_connection(domain);
1283 if (!ads) {
1284 domain->last_status = NT_STATUS_SERVER_DISABLED;
1285 goto done;
1288 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1289 status = NT_STATUS_NO_MEMORY;
1290 goto done;
1293 /* search for all members of the group */
1294 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1295 TALLOC_FREE(sidbinstr);
1296 if (ldap_exp == NULL) {
1297 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1298 status = NT_STATUS_NO_MEMORY;
1299 goto done;
1302 args.control = ADS_EXTENDED_DN_OID;
1303 args.val = ADS_EXTENDED_DN_HEX_STRING;
1304 args.critical = True;
1306 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1307 ldap_exp, &args, "member", &members, &num_members);
1309 if (!ADS_ERR_OK(rc)) {
1310 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1311 status = NT_STATUS_UNSUCCESSFUL;
1312 goto done;
1315 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1317 status = add_primary_group_members(ads, mem_ctx, rid,
1318 &members, &num_members);
1319 if (!NT_STATUS_IS_OK(status)) {
1320 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1321 __func__, nt_errstr(status)));
1322 goto done;
1325 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1326 __func__, (int)num_members));
1328 /* Now that we have a list of sids, we need to get the
1329 * lists of names and name_types belonging to these sids.
1330 * even though conceptually not quite clean, we use the
1331 * RPC call lsa_lookup_sids for this since it can handle a
1332 * list of sids. ldap calls can just resolve one sid at a time.
1334 * At this stage, the sids are still hidden in the exetended dn
1335 * member output format. We actually do a little better than
1336 * stated above: In extracting the sids from the member strings,
1337 * we try to resolve as many sids as possible from the
1338 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1340 if (num_members) {
1341 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1342 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1343 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1344 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1346 if ((members == NULL) || (*sid_mem == NULL) ||
1347 (*names == NULL) || (*name_types == NULL) ||
1348 (sid_mem_nocache == NULL))
1350 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1351 status = NT_STATUS_NO_MEMORY;
1352 goto done;
1355 else {
1356 (*sid_mem) = NULL;
1357 (*names) = NULL;
1358 (*name_types) = NULL;
1361 for (i=0; i<num_members; i++) {
1362 enum lsa_SidType name_type;
1363 char *name, *domain_name;
1364 struct dom_sid sid;
1366 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1367 &sid);
1368 if (!ADS_ERR_OK(rc)) {
1369 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1370 NT_STATUS_NOT_FOUND)) {
1371 /* Group members can be objects, like Exchange
1372 * Public Folders, that don't have a SID. Skip
1373 * them. */
1374 continue;
1376 else {
1377 status = ads_ntstatus(rc);
1378 goto done;
1381 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1382 &name_type)) {
1383 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1384 "cache\n", sid_string_dbg(&sid)));
1385 sid_copy(&(*sid_mem)[*num_names], &sid);
1386 (*names)[*num_names] = fill_domain_username_talloc(
1387 *names,
1388 domain_name,
1389 name,
1390 true);
1392 (*name_types)[*num_names] = name_type;
1393 (*num_names)++;
1395 else {
1396 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1397 "cache\n", sid_string_dbg(&sid)));
1398 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1399 num_nocache++;
1403 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1404 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1406 /* handle sids not resolved from cache by lsa_lookup_sids */
1407 if (num_nocache > 0) {
1409 status = winbindd_lookup_sids(tmp_ctx,
1410 domain,
1411 num_nocache,
1412 sid_mem_nocache,
1413 &domains_nocache,
1414 &names_nocache,
1415 &name_types_nocache);
1417 if (!(NT_STATUS_IS_OK(status) ||
1418 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1419 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1421 DEBUG(1, ("lsa_lookupsids call failed with %s "
1422 "- retrying...\n", nt_errstr(status)));
1424 status = winbindd_lookup_sids(tmp_ctx,
1425 domain,
1426 num_nocache,
1427 sid_mem_nocache,
1428 &domains_nocache,
1429 &names_nocache,
1430 &name_types_nocache);
1433 if (NT_STATUS_IS_OK(status) ||
1434 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1436 /* Copy the entries over from the "_nocache" arrays
1437 * to the result arrays, skipping the gaps the
1438 * lookup_sids call left. */
1439 for (i=0; i < num_nocache; i++) {
1440 if (((names_nocache)[i] != NULL) &&
1441 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1443 sid_copy(&(*sid_mem)[*num_names],
1444 &sid_mem_nocache[i]);
1445 (*names)[*num_names] =
1446 fill_domain_username_talloc(
1447 *names,
1448 domains_nocache[i],
1449 names_nocache[i],
1450 true);
1451 (*name_types)[*num_names] = name_types_nocache[i];
1452 (*num_names)++;
1456 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1457 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1458 "not map any SIDs at all.\n"));
1459 /* Don't handle this as an error here.
1460 * There is nothing left to do with respect to the
1461 * overall result... */
1463 else if (!NT_STATUS_IS_OK(status)) {
1464 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1465 "sids via rpc_lsa_lookup_sids: %s\n",
1466 (int)num_members, nt_errstr(status)));
1467 goto done;
1471 status = NT_STATUS_OK;
1472 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1473 sid_string_dbg(group_sid)));
1475 done:
1477 TALLOC_FREE(tmp_ctx);
1479 return status;
1482 /* find the sequence number for a domain */
1483 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1485 ADS_STRUCT *ads = NULL;
1486 ADS_STATUS rc;
1488 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1490 if ( !winbindd_can_contact_domain( domain ) ) {
1491 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1492 domain->name));
1493 *seq = time(NULL);
1494 return NT_STATUS_OK;
1497 *seq = DOM_SEQUENCE_NONE;
1499 ads = ads_cached_connection(domain);
1501 if (!ads) {
1502 domain->last_status = NT_STATUS_SERVER_DISABLED;
1503 return NT_STATUS_UNSUCCESSFUL;
1506 rc = ads_USN(ads, seq);
1508 if (!ADS_ERR_OK(rc)) {
1510 /* its a dead connection, destroy it */
1512 if (domain->private_data) {
1513 ads = (ADS_STRUCT *)domain->private_data;
1514 ads->is_mine = True;
1515 ads_destroy(&ads);
1516 ads_kdestroy(WINBIND_CCACHE_NAME);
1517 domain->private_data = NULL;
1520 return ads_ntstatus(rc);
1523 /* find the lockout policy of a domain - use rpc methods */
1524 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1525 TALLOC_CTX *mem_ctx,
1526 struct samr_DomInfo12 *policy)
1528 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1531 /* find the password policy of a domain - use rpc methods */
1532 static NTSTATUS password_policy(struct winbindd_domain *domain,
1533 TALLOC_CTX *mem_ctx,
1534 struct samr_DomInfo1 *policy)
1536 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1539 /* get a list of trusted domains */
1540 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1541 TALLOC_CTX *mem_ctx,
1542 struct netr_DomainTrustList *trusts)
1544 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1545 WERROR werr;
1546 int i;
1547 uint32_t flags;
1548 struct rpc_pipe_client *cli;
1549 int ret_count;
1550 struct dcerpc_binding_handle *b;
1552 DEBUG(3,("ads: trusted_domains\n"));
1554 ZERO_STRUCTP(trusts);
1556 /* If this is our primary domain or a root in our forest,
1557 query for all trusts. If not, then just look for domain
1558 trusts in the target forest */
1560 if (domain->primary || domain_is_forest_root(domain)) {
1561 flags = NETR_TRUST_FLAG_OUTBOUND |
1562 NETR_TRUST_FLAG_INBOUND |
1563 NETR_TRUST_FLAG_IN_FOREST;
1564 } else {
1565 flags = NETR_TRUST_FLAG_IN_FOREST;
1568 result = cm_connect_netlogon(domain, &cli);
1570 if (!NT_STATUS_IS_OK(result)) {
1571 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1572 "for PIPE_NETLOGON (%s)\n",
1573 domain->name, nt_errstr(result)));
1574 return NT_STATUS_UNSUCCESSFUL;
1577 b = cli->binding_handle;
1579 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1580 cli->desthost,
1581 flags,
1582 trusts,
1583 &werr);
1584 if (!NT_STATUS_IS_OK(result)) {
1585 return result;
1588 if (!W_ERROR_IS_OK(werr)) {
1589 return werror_to_ntstatus(werr);
1591 if (trusts->count == 0) {
1592 return NT_STATUS_OK;
1595 /* Copy across names and sids */
1597 ret_count = 0;
1598 for (i = 0; i < trusts->count; i++) {
1599 struct netr_DomainTrust *trust = &trusts->array[i];
1600 struct winbindd_domain d;
1602 ZERO_STRUCT(d);
1605 * drop external trusts if this is not our primary
1606 * domain. This means that the returned number of
1607 * domains may be less that the ones actually trusted
1608 * by the DC.
1611 if ((trust->trust_attributes
1612 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1613 !domain->primary )
1615 DEBUG(10,("trusted_domains: Skipping external trusted "
1616 "domain %s because it is outside of our "
1617 "primary domain\n",
1618 trust->netbios_name));
1619 continue;
1622 /* add to the trusted domain cache */
1624 d.name = discard_const_p(char, trust->netbios_name);
1625 d.alt_name = discard_const_p(char, trust->dns_name);
1627 if (trust->sid) {
1628 sid_copy(&d.sid, trust->sid);
1629 } else {
1630 sid_copy(&d.sid, &global_sid_NULL);
1633 if ( domain->primary ) {
1634 DEBUG(10,("trusted_domains(ads): Searching "
1635 "trusted domain list of %s and storing "
1636 "trust flags for domain %s\n",
1637 domain->name, d.alt_name));
1639 d.domain_flags = trust->trust_flags;
1640 d.domain_type = trust->trust_type;
1641 d.domain_trust_attribs = trust->trust_attributes;
1643 wcache_tdc_add_domain( &d );
1644 ret_count++;
1645 } else if (domain_is_forest_root(domain)) {
1646 /* Check if we already have this record. If
1647 * we are following our forest root that is not
1648 * our primary domain, we want to keep trust
1649 * flags from the perspective of our primary
1650 * domain not our forest root. */
1651 struct winbindd_tdc_domain *exist = NULL;
1653 exist = wcache_tdc_fetch_domain(
1654 talloc_tos(), trust->netbios_name);
1655 if (!exist) {
1656 DEBUG(10,("trusted_domains(ads): Searching "
1657 "trusted domain list of %s and "
1658 "storing trust flags for domain "
1659 "%s\n", domain->name, d.alt_name));
1660 d.domain_flags = trust->trust_flags;
1661 d.domain_type = trust->trust_type;
1662 d.domain_trust_attribs =
1663 trust->trust_attributes;
1665 wcache_tdc_add_domain( &d );
1666 ret_count++;
1668 TALLOC_FREE(exist);
1669 } else {
1670 /* This gets a little tricky. If we are
1671 following a transitive forest trust, then
1672 innerit the flags, type, and attribs from
1673 the domain we queried to make sure we don't
1674 record the view of the trust from the wrong
1675 side. Always view it from the side of our
1676 primary domain. --jerry */
1677 struct winbindd_tdc_domain *parent = NULL;
1679 DEBUG(10,("trusted_domains(ads): Searching "
1680 "trusted domain list of %s and inheriting "
1681 "trust flags for domain %s\n",
1682 domain->name, d.alt_name));
1684 parent = wcache_tdc_fetch_domain(talloc_tos(),
1685 domain->name);
1686 if (parent) {
1687 d.domain_flags = parent->trust_flags;
1688 d.domain_type = parent->trust_type;
1689 d.domain_trust_attribs = parent->trust_attribs;
1690 } else {
1691 d.domain_flags = domain->domain_flags;
1692 d.domain_type = domain->domain_type;
1693 d.domain_trust_attribs =
1694 domain->domain_trust_attribs;
1696 TALLOC_FREE(parent);
1698 wcache_tdc_add_domain( &d );
1699 ret_count++;
1702 return result;
1705 /* the ADS backend methods are exposed via this structure */
1706 struct winbindd_methods ads_methods = {
1707 True,
1708 query_user_list,
1709 enum_dom_groups,
1710 enum_local_groups,
1711 name_to_sid,
1712 sid_to_name,
1713 rids_to_names,
1714 query_user,
1715 lookup_usergroups,
1716 lookup_useraliases,
1717 lookup_groupmem,
1718 sequence_number,
1719 lockout_policy,
1720 password_policy,
1721 trusted_domains,
1724 #endif