krb5_wrap: Move krb5_princ_component() to the top
[Samba.git] / source3 / winbindd / winbindd_ads.c
blobdc92a4acc4b44890f1213ac7b31c772a6cb3ecea
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;
346 bool ok;
348 ok = ads_pull_uint32(ads, msg, "sAMAccountType", &atype);
349 if (!ok) {
350 DBG_INFO("Object lacks sAMAccountType attribute\n");
351 continue;
353 if (ds_atype_map(atype) != SID_NAME_USER) {
354 DBG_INFO("Not a user account? atype=0x%x\n", atype);
355 continue;
358 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
359 info->full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
360 if (info->full_name == NULL) {
361 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
363 info->homedir = NULL;
364 info->shell = NULL;
365 info->primary_gid = (gid_t)-1;
367 if (!ads_pull_sid(ads, msg, "objectSid",
368 &info->user_sid)) {
369 DEBUG(1, ("No sid for %s !?\n", info->acct_name));
370 continue;
373 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
374 DEBUG(1, ("No primary group for %s !?\n",
375 info->acct_name));
376 continue;
378 sid_compose(&info->group_sid, &domain->sid, group);
380 count += 1;
383 (*num_entries) = count;
384 ads_msgfree(ads, res);
386 for (i=0; i<count; i++) {
387 struct wbint_userinfo *info = &((*pinfo)[i]);
388 const char *gecos = NULL;
389 gid_t primary_gid = (gid_t)-1;
391 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
392 &info->homedir, &info->shell,
393 &gecos, &primary_gid);
394 if (!NT_STATUS_IS_OK(status)) {
396 * Deliberately ignore this error, there might be more
397 * users to fill
399 continue;
402 if (gecos != NULL) {
403 info->full_name = gecos;
405 info->primary_gid = primary_gid;
408 status = NT_STATUS_OK;
410 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
412 done:
413 return status;
416 /* list all domain groups */
417 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
418 TALLOC_CTX *mem_ctx,
419 uint32_t *num_entries,
420 struct wb_acct_info **info)
422 ADS_STRUCT *ads = NULL;
423 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
424 "name", "objectSid", NULL};
425 int i, count;
426 ADS_STATUS rc;
427 LDAPMessage *res = NULL;
428 LDAPMessage *msg = NULL;
429 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
430 const char *filter;
431 bool enum_dom_local_groups = False;
433 *num_entries = 0;
435 DEBUG(3,("ads: enum_dom_groups\n"));
437 if ( !winbindd_can_contact_domain( domain ) ) {
438 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
439 domain->name));
440 return NT_STATUS_OK;
443 /* only grab domain local groups for our domain */
444 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
445 enum_dom_local_groups = True;
448 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
449 * rollup-fixes:
451 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
452 * default value, it MUST be absent. In case of extensible matching the
453 * "dnattr" boolean defaults to FALSE and so it must be only be present
454 * when set to TRUE.
456 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
457 * filter using bitwise matching rule then the buggy AD fails to decode
458 * the extensible match. As a workaround set it to TRUE and thereby add
459 * the dnAttributes "dn" field to cope with those older AD versions.
460 * It should not harm and won't put any additional load on the AD since
461 * none of the dn components have a bitmask-attribute.
463 * Thanks to Ralf Haferkamp for input and testing - Guenther */
465 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
466 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
467 ADS_LDAP_MATCHING_RULE_BIT_AND,
468 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
470 if (filter == NULL) {
471 status = NT_STATUS_NO_MEMORY;
472 goto done;
475 ads = ads_cached_connection(domain);
477 if (!ads) {
478 domain->last_status = NT_STATUS_SERVER_DISABLED;
479 goto done;
482 rc = ads_search_retry(ads, &res, filter, attrs);
483 if (!ADS_ERR_OK(rc)) {
484 status = ads_ntstatus(rc);
485 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
486 goto done;
487 } else if (!res) {
488 DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
489 goto done;
492 count = ads_count_replies(ads, res);
493 if (count == 0) {
494 DEBUG(1,("enum_dom_groups: No groups found\n"));
495 goto done;
498 (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
499 if (!*info) {
500 status = NT_STATUS_NO_MEMORY;
501 goto done;
504 i = 0;
506 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
507 char *name, *gecos;
508 struct dom_sid sid;
509 uint32_t rid;
511 name = ads_pull_username(ads, mem_ctx, msg);
512 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
513 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
514 DEBUG(1,("No sid for %s !?\n", name));
515 continue;
518 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
519 DEBUG(1,("No rid for %s !?\n", name));
520 continue;
523 fstrcpy((*info)[i].acct_name, name);
524 fstrcpy((*info)[i].acct_desc, gecos);
525 (*info)[i].rid = rid;
526 i++;
529 (*num_entries) = i;
531 status = NT_STATUS_OK;
533 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
535 done:
536 if (res)
537 ads_msgfree(ads, res);
539 return status;
542 /* list all domain local groups */
543 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
544 TALLOC_CTX *mem_ctx,
545 uint32_t *num_entries,
546 struct wb_acct_info **info)
549 * This is a stub function only as we returned the domain
550 * local groups in enum_dom_groups() if the domain->native field
551 * was true. This is a simple performance optimization when
552 * using LDAP.
554 * if we ever need to enumerate domain local groups separately,
555 * then this optimization in enum_dom_groups() will need
556 * to be split out
558 *num_entries = 0;
560 return NT_STATUS_OK;
563 /* convert a single name to a sid in a domain - use rpc methods */
564 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
565 TALLOC_CTX *mem_ctx,
566 const char *domain_name,
567 const char *name,
568 uint32_t flags,
569 struct dom_sid *sid,
570 enum lsa_SidType *type)
572 return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
573 flags, sid, type);
576 /* convert a domain SID to a user or group name - use rpc methods */
577 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
578 TALLOC_CTX *mem_ctx,
579 const struct dom_sid *sid,
580 char **domain_name,
581 char **name,
582 enum lsa_SidType *type)
584 return msrpc_methods.sid_to_name(domain, mem_ctx, sid,
585 domain_name, name, type);
588 /* convert a list of rids to names - use rpc methods */
589 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
590 TALLOC_CTX *mem_ctx,
591 const struct dom_sid *sid,
592 uint32_t *rids,
593 size_t num_rids,
594 char **domain_name,
595 char ***names,
596 enum lsa_SidType **types)
598 return msrpc_methods.rids_to_names(domain, mem_ctx, sid,
599 rids, num_rids,
600 domain_name, names, types);
603 /* If you are looking for "dn_lookup": Yes, it used to be here!
604 * It has gone now since it was a major speed bottleneck in
605 * lookup_groupmem (its only use). It has been replaced by
606 * an rpc lookup sids call... R.I.P. */
608 /* Lookup user information from a rid */
609 static NTSTATUS query_user(struct winbindd_domain *domain,
610 TALLOC_CTX *mem_ctx,
611 const struct dom_sid *sid,
612 struct wbint_userinfo *info)
614 ADS_STRUCT *ads = NULL;
615 const char *attrs[] = { "*", NULL };
616 ADS_STATUS rc;
617 int count;
618 LDAPMessage *msg = NULL;
619 char *ldap_exp;
620 char *sidstr;
621 uint32_t group_rid;
622 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
623 struct netr_SamInfo3 *user = NULL;
624 gid_t gid = -1;
625 int ret;
626 char *full_name;
628 DEBUG(3,("ads: query_user\n"));
630 info->homedir = NULL;
631 info->shell = NULL;
633 /* try netsamlogon cache first */
635 if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
637 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
638 sid_string_dbg(sid)));
640 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
641 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
643 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
644 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
646 nss_get_info_cached( domain, sid, mem_ctx,
647 &info->homedir, &info->shell, &info->full_name,
648 &gid );
649 info->primary_gid = gid;
651 TALLOC_FREE(user);
653 if (info->full_name == NULL) {
654 /* this might fail so we don't check the return code */
655 wcache_query_user_fullname(domain,
656 mem_ctx,
657 sid,
658 &info->full_name);
661 return NT_STATUS_OK;
664 if ( !winbindd_can_contact_domain(domain)) {
665 DEBUG(8,("query_user: No incoming trust from domain %s\n",
666 domain->name));
668 /* We still need to generate some basic information
669 about the user even if we cannot contact the
670 domain. Most of this stuff we can deduce. */
672 sid_copy( &info->user_sid, sid );
674 /* Assume "Domain Users" for the primary group */
676 sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
678 /* Try to fill in what the nss_info backend can do */
680 nss_get_info_cached( domain, sid, mem_ctx,
681 &info->homedir, &info->shell, &info->full_name,
682 &gid);
683 info->primary_gid = gid;
685 return NT_STATUS_OK;
688 /* no cache...do the query */
690 if ( (ads = ads_cached_connection(domain)) == NULL ) {
691 domain->last_status = NT_STATUS_SERVER_DISABLED;
692 return NT_STATUS_SERVER_DISABLED;
695 sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
697 ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
698 TALLOC_FREE(sidstr);
699 if (ret == -1) {
700 return NT_STATUS_NO_MEMORY;
702 rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
703 SAFE_FREE(ldap_exp);
704 if (!ADS_ERR_OK(rc)) {
705 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
706 sid_string_dbg(sid), ads_errstr(rc)));
707 return ads_ntstatus(rc);
708 } else if (!msg) {
709 DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
710 sid_string_dbg(sid)));
711 return NT_STATUS_INTERNAL_ERROR;
714 count = ads_count_replies(ads, msg);
715 if (count != 1) {
716 DEBUG(1,("query_user(sid=%s): Not found\n",
717 sid_string_dbg(sid)));
718 ads_msgfree(ads, msg);
719 return NT_STATUS_NO_SUCH_USER;
722 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
724 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
725 DEBUG(1,("No primary group for %s !?\n",
726 sid_string_dbg(sid)));
727 ads_msgfree(ads, msg);
728 return NT_STATUS_NO_SUCH_USER;
730 sid_copy(&info->user_sid, sid);
731 sid_compose(&info->group_sid, &domain->sid, group_rid);
734 * We have to fetch the "name" attribute before doing the
735 * nss_get_info_cached call. nss_get_info_cached might destroy
736 * the ads struct, potentially invalidating the ldap message.
738 full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
739 if (full_name == NULL) {
740 full_name = ads_pull_string(ads, mem_ctx, msg, "name");
743 ads_msgfree(ads, msg);
744 msg = NULL;
746 status = nss_get_info_cached( domain, sid, mem_ctx,
747 &info->homedir, &info->shell, &info->full_name,
748 &gid);
749 info->primary_gid = gid;
750 if (!NT_STATUS_IS_OK(status)) {
751 DEBUG(1, ("nss_get_info_cached failed: %s\n",
752 nt_errstr(status)));
753 return status;
756 if (info->full_name == NULL) {
757 info->full_name = full_name;
758 } else {
759 TALLOC_FREE(full_name);
762 status = NT_STATUS_OK;
764 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
765 return NT_STATUS_OK;
768 /* Lookup groups a user is a member of - alternate method, for when
769 tokenGroups are not available. */
770 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
771 TALLOC_CTX *mem_ctx,
772 const char *user_dn,
773 struct dom_sid *primary_group,
774 uint32_t *p_num_groups, struct dom_sid **user_sids)
776 ADS_STATUS rc;
777 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
778 int count;
779 LDAPMessage *res = NULL;
780 LDAPMessage *msg = NULL;
781 char *ldap_exp;
782 ADS_STRUCT *ads;
783 const char *group_attrs[] = {"objectSid", NULL};
784 char *escaped_dn;
785 uint32_t num_groups = 0;
787 DEBUG(3,("ads: lookup_usergroups_member\n"));
789 if ( !winbindd_can_contact_domain( domain ) ) {
790 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
791 domain->name));
792 return NT_STATUS_OK;
795 ads = ads_cached_connection(domain);
797 if (!ads) {
798 domain->last_status = NT_STATUS_SERVER_DISABLED;
799 goto done;
802 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
803 status = NT_STATUS_NO_MEMORY;
804 goto done;
807 ldap_exp = talloc_asprintf(mem_ctx,
808 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
809 escaped_dn,
810 ADS_LDAP_MATCHING_RULE_BIT_AND,
811 GROUP_TYPE_SECURITY_ENABLED);
812 if (!ldap_exp) {
813 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
814 TALLOC_FREE(escaped_dn);
815 status = NT_STATUS_NO_MEMORY;
816 goto done;
819 TALLOC_FREE(escaped_dn);
821 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
823 if (!ADS_ERR_OK(rc)) {
824 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
825 return ads_ntstatus(rc);
826 } else if (!res) {
827 DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
828 return NT_STATUS_INTERNAL_ERROR;
832 count = ads_count_replies(ads, res);
834 *user_sids = NULL;
835 num_groups = 0;
837 /* always add the primary group to the sid array */
838 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
839 &num_groups);
840 if (!NT_STATUS_IS_OK(status)) {
841 goto done;
844 if (count > 0) {
845 for (msg = ads_first_entry(ads, res); msg;
846 msg = ads_next_entry(ads, msg)) {
847 struct dom_sid group_sid;
849 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
850 DEBUG(1,("No sid for this group ?!?\n"));
851 continue;
854 /* ignore Builtin groups from ADS - Guenther */
855 if (sid_check_is_in_builtin(&group_sid)) {
856 continue;
859 status = add_sid_to_array(mem_ctx, &group_sid,
860 user_sids, &num_groups);
861 if (!NT_STATUS_IS_OK(status)) {
862 goto done;
868 *p_num_groups = num_groups;
869 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
871 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
872 done:
873 if (res)
874 ads_msgfree(ads, res);
876 return status;
879 /* Lookup groups a user is a member of - alternate method, for when
880 tokenGroups are not available. */
881 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
882 TALLOC_CTX *mem_ctx,
883 const char *user_dn,
884 struct dom_sid *primary_group,
885 uint32_t *p_num_groups,
886 struct dom_sid **user_sids)
888 ADS_STATUS rc;
889 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
890 ADS_STRUCT *ads;
891 const char *attrs[] = {"memberOf", NULL};
892 uint32_t num_groups = 0;
893 struct dom_sid *group_sids = NULL;
894 int i;
895 char **strings = NULL;
896 size_t num_strings = 0, num_sids = 0;
899 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
901 if ( !winbindd_can_contact_domain( domain ) ) {
902 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
903 "domain %s\n", domain->name));
904 return NT_STATUS_OK;
907 ads = ads_cached_connection(domain);
909 if (!ads) {
910 domain->last_status = NT_STATUS_SERVER_DISABLED;
911 return NT_STATUS_UNSUCCESSFUL;
914 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
915 ADS_EXTENDED_DN_HEX_STRING,
916 &strings, &num_strings);
918 if (!ADS_ERR_OK(rc)) {
919 DEBUG(1,("lookup_usergroups_memberof ads_search "
920 "member=%s: %s\n", user_dn, ads_errstr(rc)));
921 return ads_ntstatus(rc);
924 *user_sids = NULL;
925 num_groups = 0;
927 /* always add the primary group to the sid array */
928 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
929 &num_groups);
930 if (!NT_STATUS_IS_OK(status)) {
931 goto done;
934 group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
935 if (!group_sids) {
936 status = NT_STATUS_NO_MEMORY;
937 goto done;
940 for (i=0; i<num_strings; i++) {
941 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
942 ADS_EXTENDED_DN_HEX_STRING,
943 &(group_sids)[i]);
944 if (!ADS_ERR_OK(rc)) {
945 /* ignore members without SIDs */
946 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
947 NT_STATUS_NOT_FOUND)) {
948 continue;
950 else {
951 status = ads_ntstatus(rc);
952 goto done;
955 num_sids++;
958 if (i == 0) {
959 DEBUG(1,("No memberOf for this user?!?\n"));
960 status = NT_STATUS_NO_MEMORY;
961 goto done;
964 for (i=0; i<num_sids; i++) {
966 /* ignore Builtin groups from ADS - Guenther */
967 if (sid_check_is_in_builtin(&group_sids[i])) {
968 continue;
971 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
972 &num_groups);
973 if (!NT_STATUS_IS_OK(status)) {
974 goto done;
979 *p_num_groups = num_groups;
980 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
982 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
983 user_dn));
985 done:
986 TALLOC_FREE(strings);
987 TALLOC_FREE(group_sids);
989 return status;
993 /* Lookup groups a user is a member of. */
994 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
995 TALLOC_CTX *mem_ctx,
996 const struct dom_sid *sid,
997 uint32_t *p_num_groups, struct dom_sid **user_sids)
999 ADS_STRUCT *ads = NULL;
1000 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
1001 ADS_STATUS rc;
1002 int count;
1003 LDAPMessage *msg = NULL;
1004 char *user_dn = NULL;
1005 struct dom_sid *sids;
1006 int i;
1007 struct dom_sid primary_group;
1008 uint32_t primary_group_rid;
1009 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1010 uint32_t num_groups = 0;
1012 DEBUG(3,("ads: lookup_usergroups\n"));
1013 *p_num_groups = 0;
1015 status = lookup_usergroups_cached(domain, mem_ctx, sid,
1016 p_num_groups, user_sids);
1017 if (NT_STATUS_IS_OK(status)) {
1018 return NT_STATUS_OK;
1021 if ( !winbindd_can_contact_domain( domain ) ) {
1022 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
1023 domain->name));
1025 /* Tell the cache manager not to remember this one */
1027 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
1030 ads = ads_cached_connection(domain);
1032 if (!ads) {
1033 domain->last_status = NT_STATUS_SERVER_DISABLED;
1034 status = NT_STATUS_SERVER_DISABLED;
1035 goto done;
1038 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
1040 if (!ADS_ERR_OK(rc)) {
1041 status = ads_ntstatus(rc);
1042 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1043 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
1044 goto done;
1047 count = ads_count_replies(ads, msg);
1048 if (count != 1) {
1049 status = NT_STATUS_UNSUCCESSFUL;
1050 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
1051 "invalid number of results (count=%d)\n",
1052 sid_string_dbg(sid), count));
1053 goto done;
1056 if (!msg) {
1057 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
1058 sid_string_dbg(sid)));
1059 status = NT_STATUS_UNSUCCESSFUL;
1060 goto done;
1063 user_dn = ads_get_dn(ads, mem_ctx, msg);
1064 if (user_dn == NULL) {
1065 status = NT_STATUS_NO_MEMORY;
1066 goto done;
1069 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
1070 DEBUG(1,("%s: No primary group for sid=%s !?\n",
1071 domain->name, sid_string_dbg(sid)));
1072 goto done;
1075 sid_compose(&primary_group, &domain->sid, primary_group_rid);
1077 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
1079 /* there must always be at least one group in the token,
1080 unless we are talking to a buggy Win2k server */
1082 /* actually this only happens when the machine account has no read
1083 * permissions on the tokenGroup attribute - gd */
1085 if (count == 0) {
1087 /* no tokenGroups */
1089 /* lookup what groups this user is a member of by DN search on
1090 * "memberOf" */
1092 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
1093 &primary_group,
1094 &num_groups, user_sids);
1095 *p_num_groups = num_groups;
1096 if (NT_STATUS_IS_OK(status)) {
1097 goto done;
1100 /* lookup what groups this user is a member of by DN search on
1101 * "member" */
1103 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
1104 &primary_group,
1105 &num_groups, user_sids);
1106 *p_num_groups = num_groups;
1107 goto done;
1110 *user_sids = NULL;
1111 num_groups = 0;
1113 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
1114 &num_groups);
1115 if (!NT_STATUS_IS_OK(status)) {
1116 goto done;
1119 for (i=0;i<count;i++) {
1121 /* ignore Builtin groups from ADS - Guenther */
1122 if (sid_check_is_in_builtin(&sids[i])) {
1123 continue;
1126 status = add_sid_to_array_unique(mem_ctx, &sids[i],
1127 user_sids, &num_groups);
1128 if (!NT_STATUS_IS_OK(status)) {
1129 goto done;
1133 *p_num_groups = (uint32_t)num_groups;
1134 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1136 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
1137 sid_string_dbg(sid)));
1138 done:
1139 TALLOC_FREE(user_dn);
1140 ads_msgfree(ads, msg);
1141 return status;
1144 /* Lookup aliases a user is member of - use rpc methods */
1145 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
1146 TALLOC_CTX *mem_ctx,
1147 uint32_t num_sids, const struct dom_sid *sids,
1148 uint32_t *num_aliases, uint32_t **alias_rids)
1150 return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids,
1151 num_aliases, alias_rids);
1154 static NTSTATUS add_primary_group_members(
1155 ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
1156 char ***all_members, size_t *num_all_members)
1158 char *filter;
1159 NTSTATUS status = NT_STATUS_NO_MEMORY;
1160 ADS_STATUS rc;
1161 const char *attrs[] = { "dn", NULL };
1162 LDAPMessage *res = NULL;
1163 LDAPMessage *msg;
1164 char **members;
1165 size_t num_members;
1166 ads_control args;
1168 filter = talloc_asprintf(
1169 mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
1170 (unsigned)rid);
1171 if (filter == NULL) {
1172 goto done;
1175 args.control = ADS_EXTENDED_DN_OID;
1176 args.val = ADS_EXTENDED_DN_HEX_STRING;
1177 args.critical = True;
1179 rc = ads_do_search_all_args(ads, ads->config.bind_path,
1180 LDAP_SCOPE_SUBTREE, filter, attrs, &args,
1181 &res);
1183 if (!ADS_ERR_OK(rc)) {
1184 status = ads_ntstatus(rc);
1185 DEBUG(1,("%s: ads_search: %s\n", __func__, ads_errstr(rc)));
1186 goto done;
1188 if (res == NULL) {
1189 DEBUG(1,("%s: ads_search returned NULL res\n", __func__));
1190 goto done;
1193 num_members = ads_count_replies(ads, res);
1195 DEBUG(10, ("%s: Got %ju primary group members\n", __func__,
1196 (uintmax_t)num_members));
1198 if (num_members == 0) {
1199 status = NT_STATUS_OK;
1200 goto done;
1203 members = talloc_realloc(mem_ctx, *all_members, char *,
1204 *num_all_members + num_members);
1205 if (members == NULL) {
1206 DEBUG(1, ("%s: talloc_realloc failed\n", __func__));
1207 goto done;
1209 *all_members = members;
1211 for (msg = ads_first_entry(ads, res); msg != NULL;
1212 msg = ads_next_entry(ads, msg)) {
1213 char *dn;
1215 dn = ads_get_dn(ads, members, msg);
1216 if (dn == NULL) {
1217 DEBUG(1, ("%s: ads_get_dn failed\n", __func__));
1218 continue;
1221 members[*num_all_members] = dn;
1222 *num_all_members += 1;
1225 status = NT_STATUS_OK;
1226 done:
1227 if (res != NULL) {
1228 ads_msgfree(ads, res);
1230 TALLOC_FREE(filter);
1231 return status;
1235 find the members of a group, given a group rid and domain
1237 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
1238 TALLOC_CTX *mem_ctx,
1239 const struct dom_sid *group_sid,
1240 enum lsa_SidType type,
1241 uint32_t *num_names,
1242 struct dom_sid **sid_mem, char ***names,
1243 uint32_t **name_types)
1245 ADS_STATUS rc;
1246 ADS_STRUCT *ads = NULL;
1247 char *ldap_exp;
1248 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1249 char *sidbinstr;
1250 char **members = NULL;
1251 int i;
1252 size_t num_members = 0;
1253 ads_control args;
1254 struct dom_sid *sid_mem_nocache = NULL;
1255 char **names_nocache = NULL;
1256 enum lsa_SidType *name_types_nocache = NULL;
1257 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1258 uint32_t num_nocache = 0;
1259 TALLOC_CTX *tmp_ctx = NULL;
1260 uint32_t rid;
1262 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1263 sid_string_dbg(group_sid)));
1265 *num_names = 0;
1267 tmp_ctx = talloc_new(mem_ctx);
1268 if (!tmp_ctx) {
1269 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1270 status = NT_STATUS_NO_MEMORY;
1271 goto done;
1274 if (!sid_peek_rid(group_sid, &rid)) {
1275 DEBUG(1, ("%s: sid_peek_rid failed\n", __func__));
1276 status = NT_STATUS_INVALID_PARAMETER;
1277 goto done;
1280 if ( !winbindd_can_contact_domain( domain ) ) {
1281 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1282 domain->name));
1283 return NT_STATUS_OK;
1286 ads = ads_cached_connection(domain);
1288 if (!ads) {
1289 domain->last_status = NT_STATUS_SERVER_DISABLED;
1290 goto done;
1293 if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
1294 status = NT_STATUS_NO_MEMORY;
1295 goto done;
1298 /* search for all members of the group */
1299 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1300 TALLOC_FREE(sidbinstr);
1301 if (ldap_exp == NULL) {
1302 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1303 status = NT_STATUS_NO_MEMORY;
1304 goto done;
1307 args.control = ADS_EXTENDED_DN_OID;
1308 args.val = ADS_EXTENDED_DN_HEX_STRING;
1309 args.critical = True;
1311 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1312 ldap_exp, &args, "member", &members, &num_members);
1314 if (!ADS_ERR_OK(rc)) {
1315 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1316 status = NT_STATUS_UNSUCCESSFUL;
1317 goto done;
1320 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1322 status = add_primary_group_members(ads, mem_ctx, rid,
1323 &members, &num_members);
1324 if (!NT_STATUS_IS_OK(status)) {
1325 DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
1326 __func__, nt_errstr(status)));
1327 goto done;
1330 DEBUG(10, ("%s: Got %d sids after adding primary group members\n",
1331 __func__, (int)num_members));
1333 /* Now that we have a list of sids, we need to get the
1334 * lists of names and name_types belonging to these sids.
1335 * even though conceptually not quite clean, we use the
1336 * RPC call lsa_lookup_sids for this since it can handle a
1337 * list of sids. ldap calls can just resolve one sid at a time.
1339 * At this stage, the sids are still hidden in the exetended dn
1340 * member output format. We actually do a little better than
1341 * stated above: In extracting the sids from the member strings,
1342 * we try to resolve as many sids as possible from the
1343 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1345 if (num_members) {
1346 (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
1347 (*names) = talloc_zero_array(mem_ctx, char *, num_members);
1348 (*name_types) = talloc_zero_array(mem_ctx, uint32_t, num_members);
1349 (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
1351 if ((members == NULL) || (*sid_mem == NULL) ||
1352 (*names == NULL) || (*name_types == NULL) ||
1353 (sid_mem_nocache == NULL))
1355 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1356 status = NT_STATUS_NO_MEMORY;
1357 goto done;
1360 else {
1361 (*sid_mem) = NULL;
1362 (*names) = NULL;
1363 (*name_types) = NULL;
1366 for (i=0; i<num_members; i++) {
1367 enum lsa_SidType name_type;
1368 char *name, *domain_name;
1369 struct dom_sid sid;
1371 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1372 &sid);
1373 if (!ADS_ERR_OK(rc)) {
1374 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1375 NT_STATUS_NOT_FOUND)) {
1376 /* Group members can be objects, like Exchange
1377 * Public Folders, that don't have a SID. Skip
1378 * them. */
1379 continue;
1381 else {
1382 status = ads_ntstatus(rc);
1383 goto done;
1386 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1387 &name_type)) {
1388 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1389 "cache\n", sid_string_dbg(&sid)));
1390 sid_copy(&(*sid_mem)[*num_names], &sid);
1391 (*names)[*num_names] = fill_domain_username_talloc(
1392 *names,
1393 domain_name,
1394 name,
1395 true);
1397 (*name_types)[*num_names] = name_type;
1398 (*num_names)++;
1400 else {
1401 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1402 "cache\n", sid_string_dbg(&sid)));
1403 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1404 num_nocache++;
1408 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1409 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1411 /* handle sids not resolved from cache by lsa_lookup_sids */
1412 if (num_nocache > 0) {
1414 status = winbindd_lookup_sids(tmp_ctx,
1415 domain,
1416 num_nocache,
1417 sid_mem_nocache,
1418 &domains_nocache,
1419 &names_nocache,
1420 &name_types_nocache);
1422 if (!(NT_STATUS_IS_OK(status) ||
1423 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1424 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1426 DEBUG(1, ("lsa_lookupsids call failed with %s "
1427 "- retrying...\n", nt_errstr(status)));
1429 status = winbindd_lookup_sids(tmp_ctx,
1430 domain,
1431 num_nocache,
1432 sid_mem_nocache,
1433 &domains_nocache,
1434 &names_nocache,
1435 &name_types_nocache);
1438 if (NT_STATUS_IS_OK(status) ||
1439 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1441 /* Copy the entries over from the "_nocache" arrays
1442 * to the result arrays, skipping the gaps the
1443 * lookup_sids call left. */
1444 for (i=0; i < num_nocache; i++) {
1445 if (((names_nocache)[i] != NULL) &&
1446 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1448 sid_copy(&(*sid_mem)[*num_names],
1449 &sid_mem_nocache[i]);
1450 (*names)[*num_names] =
1451 fill_domain_username_talloc(
1452 *names,
1453 domains_nocache[i],
1454 names_nocache[i],
1455 true);
1456 (*name_types)[*num_names] = name_types_nocache[i];
1457 (*num_names)++;
1461 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1462 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1463 "not map any SIDs at all.\n"));
1464 /* Don't handle this as an error here.
1465 * There is nothing left to do with respect to the
1466 * overall result... */
1468 else if (!NT_STATUS_IS_OK(status)) {
1469 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1470 "sids via rpc_lsa_lookup_sids: %s\n",
1471 (int)num_members, nt_errstr(status)));
1472 goto done;
1476 status = NT_STATUS_OK;
1477 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1478 sid_string_dbg(group_sid)));
1480 done:
1482 TALLOC_FREE(tmp_ctx);
1484 return status;
1487 /* find the sequence number for a domain */
1488 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
1490 ADS_STRUCT *ads = NULL;
1491 ADS_STATUS rc;
1493 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1495 if ( !winbindd_can_contact_domain( domain ) ) {
1496 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1497 domain->name));
1498 *seq = time(NULL);
1499 return NT_STATUS_OK;
1502 *seq = DOM_SEQUENCE_NONE;
1504 ads = ads_cached_connection(domain);
1506 if (!ads) {
1507 domain->last_status = NT_STATUS_SERVER_DISABLED;
1508 return NT_STATUS_UNSUCCESSFUL;
1511 rc = ads_USN(ads, seq);
1513 if (!ADS_ERR_OK(rc)) {
1515 /* its a dead connection, destroy it */
1517 if (domain->private_data) {
1518 ads = (ADS_STRUCT *)domain->private_data;
1519 ads->is_mine = True;
1520 ads_destroy(&ads);
1521 ads_kdestroy(WINBIND_CCACHE_NAME);
1522 domain->private_data = NULL;
1525 return ads_ntstatus(rc);
1528 /* find the lockout policy of a domain - use rpc methods */
1529 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1530 TALLOC_CTX *mem_ctx,
1531 struct samr_DomInfo12 *policy)
1533 return msrpc_methods.lockout_policy(domain, mem_ctx, policy);
1536 /* find the password policy of a domain - use rpc methods */
1537 static NTSTATUS password_policy(struct winbindd_domain *domain,
1538 TALLOC_CTX *mem_ctx,
1539 struct samr_DomInfo1 *policy)
1541 return msrpc_methods.password_policy(domain, mem_ctx, policy);
1544 /* get a list of trusted domains */
1545 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1546 TALLOC_CTX *mem_ctx,
1547 struct netr_DomainTrustList *trusts)
1549 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1550 WERROR werr;
1551 int i;
1552 uint32_t flags;
1553 struct rpc_pipe_client *cli;
1554 int ret_count;
1555 struct dcerpc_binding_handle *b;
1557 DEBUG(3,("ads: trusted_domains\n"));
1559 ZERO_STRUCTP(trusts);
1561 /* If this is our primary domain or a root in our forest,
1562 query for all trusts. If not, then just look for domain
1563 trusts in the target forest */
1565 if (domain->primary || domain_is_forest_root(domain)) {
1566 flags = NETR_TRUST_FLAG_OUTBOUND |
1567 NETR_TRUST_FLAG_INBOUND |
1568 NETR_TRUST_FLAG_IN_FOREST;
1569 } else {
1570 flags = NETR_TRUST_FLAG_IN_FOREST;
1573 result = cm_connect_netlogon(domain, &cli);
1575 if (!NT_STATUS_IS_OK(result)) {
1576 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1577 "for PIPE_NETLOGON (%s)\n",
1578 domain->name, nt_errstr(result)));
1579 return NT_STATUS_UNSUCCESSFUL;
1582 b = cli->binding_handle;
1584 result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
1585 cli->desthost,
1586 flags,
1587 trusts,
1588 &werr);
1589 if (!NT_STATUS_IS_OK(result)) {
1590 return result;
1593 if (!W_ERROR_IS_OK(werr)) {
1594 return werror_to_ntstatus(werr);
1596 if (trusts->count == 0) {
1597 return NT_STATUS_OK;
1600 /* Copy across names and sids */
1602 ret_count = 0;
1603 for (i = 0; i < trusts->count; i++) {
1604 struct netr_DomainTrust *trust = &trusts->array[i];
1605 struct winbindd_domain d;
1607 ZERO_STRUCT(d);
1610 * drop external trusts if this is not our primary
1611 * domain. This means that the returned number of
1612 * domains may be less that the ones actually trusted
1613 * by the DC.
1616 if ((trust->trust_attributes
1617 == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1618 !domain->primary )
1620 DEBUG(10,("trusted_domains: Skipping external trusted "
1621 "domain %s because it is outside of our "
1622 "primary domain\n",
1623 trust->netbios_name));
1624 continue;
1627 /* add to the trusted domain cache */
1629 d.name = discard_const_p(char, trust->netbios_name);
1630 d.alt_name = discard_const_p(char, trust->dns_name);
1632 if (trust->sid) {
1633 sid_copy(&d.sid, trust->sid);
1634 } else {
1635 sid_copy(&d.sid, &global_sid_NULL);
1638 if ( domain->primary ) {
1639 DEBUG(10,("trusted_domains(ads): Searching "
1640 "trusted domain list of %s and storing "
1641 "trust flags for domain %s\n",
1642 domain->name, d.alt_name));
1644 d.domain_flags = trust->trust_flags;
1645 d.domain_type = trust->trust_type;
1646 d.domain_trust_attribs = trust->trust_attributes;
1648 wcache_tdc_add_domain( &d );
1649 ret_count++;
1650 } else if (domain_is_forest_root(domain)) {
1651 /* Check if we already have this record. If
1652 * we are following our forest root that is not
1653 * our primary domain, we want to keep trust
1654 * flags from the perspective of our primary
1655 * domain not our forest root. */
1656 struct winbindd_tdc_domain *exist = NULL;
1658 exist = wcache_tdc_fetch_domain(
1659 talloc_tos(), trust->netbios_name);
1660 if (!exist) {
1661 DEBUG(10,("trusted_domains(ads): Searching "
1662 "trusted domain list of %s and "
1663 "storing trust flags for domain "
1664 "%s\n", domain->name, d.alt_name));
1665 d.domain_flags = trust->trust_flags;
1666 d.domain_type = trust->trust_type;
1667 d.domain_trust_attribs =
1668 trust->trust_attributes;
1670 wcache_tdc_add_domain( &d );
1671 ret_count++;
1673 TALLOC_FREE(exist);
1674 } else {
1675 /* This gets a little tricky. If we are
1676 following a transitive forest trust, then
1677 innerit the flags, type, and attribs from
1678 the domain we queried to make sure we don't
1679 record the view of the trust from the wrong
1680 side. Always view it from the side of our
1681 primary domain. --jerry */
1682 struct winbindd_tdc_domain *parent = NULL;
1684 DEBUG(10,("trusted_domains(ads): Searching "
1685 "trusted domain list of %s and inheriting "
1686 "trust flags for domain %s\n",
1687 domain->name, d.alt_name));
1689 parent = wcache_tdc_fetch_domain(talloc_tos(),
1690 domain->name);
1691 if (parent) {
1692 d.domain_flags = parent->trust_flags;
1693 d.domain_type = parent->trust_type;
1694 d.domain_trust_attribs = parent->trust_attribs;
1695 } else {
1696 d.domain_flags = domain->domain_flags;
1697 d.domain_type = domain->domain_type;
1698 d.domain_trust_attribs =
1699 domain->domain_trust_attribs;
1701 TALLOC_FREE(parent);
1703 wcache_tdc_add_domain( &d );
1704 ret_count++;
1707 return result;
1710 /* the ADS backend methods are exposed via this structure */
1711 struct winbindd_methods ads_methods = {
1712 True,
1713 query_user_list,
1714 enum_dom_groups,
1715 enum_local_groups,
1716 name_to_sid,
1717 sid_to_name,
1718 rids_to_names,
1719 query_user,
1720 lookup_usergroups,
1721 lookup_useraliases,
1722 lookup_groupmem,
1723 sequence_number,
1724 lockout_policy,
1725 password_policy,
1726 trusted_domains,
1729 #endif