2 Unix SMB/CIFS implementation.
4 Winbind ADS backend functions
6 Copyright (C) Andrew Tridgell 2001
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
8 Copyright (C) Gerald (Jerry) Carter 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 #include "../librpc/gen_ndr/cli_netlogon.h"
27 #include "../libds/common/flags.h"
32 #define DBGC_CLASS DBGC_WINBIND
34 extern struct winbindd_methods reconnect_methods;
37 return our ads connections structure for a domain. We keep the connection
38 open to make things faster
40 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
45 struct sockaddr_storage dc_ss;
47 DEBUG(10,("ads_cached_connection\n"));
49 if (domain->private_data) {
52 time_t now = time(NULL);
54 /* check for a valid structure */
55 ads = (ADS_STRUCT *)domain->private_data;
57 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
59 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
60 (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
62 if ( ads->config.realm && (expire > now)) {
65 /* we own this ADS_STRUCT so make sure it goes away */
66 DEBUG(7,("Deleting expired krb5 credential cache\n"));
69 ads_kdestroy("MEMORY:winbind_ccache");
70 domain->private_data = NULL;
74 /* we don't want this to affect the users ccache */
75 setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1);
77 ads = ads_init(domain->alt_name, domain->name, NULL);
79 DEBUG(1,("ads_init for domain %s failed\n", domain->name));
83 /* the machine acct password might have change - fetch it every time */
85 SAFE_FREE(ads->auth.password);
86 SAFE_FREE(ads->auth.realm);
90 if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, NULL, NULL ) ) {
94 ads->auth.realm = SMB_STRDUP( ads->server.realm );
95 strupper_m( ads->auth.realm );
98 struct winbindd_domain *our_domain = domain;
100 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
102 /* always give preference to the alt_name in our
103 primary domain if possible */
105 if ( !domain->primary )
106 our_domain = find_our_domain();
108 if ( our_domain->alt_name[0] != '\0' ) {
109 ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
110 strupper_m( ads->auth.realm );
113 ads->auth.realm = SMB_STRDUP( lp_realm() );
116 ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
118 /* Setup the server affinity cache. We don't reaally care
119 about the name. Just setup affinity and the KRB5_CONFIG
122 get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ss );
124 status = ads_connect(ads);
125 if (!ADS_ERR_OK(status) || !ads->config.realm) {
126 DEBUG(1,("ads_connect for domain %s failed: %s\n",
127 domain->name, ads_errstr(status)));
130 /* if we get ECONNREFUSED then it might be a NT4
131 server, fall back to MSRPC */
132 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
133 status.err.rc == ECONNREFUSED) {
134 /* 'reconnect_methods' is the MS-RPC backend. */
135 DEBUG(1,("Trying MSRPC methods\n"));
136 domain->backend = &reconnect_methods;
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 domain->private_data = (void *)ads;
152 /* Query display info for a realm. This is the basic user list fn */
153 static NTSTATUS query_user_list(struct winbindd_domain *domain,
156 struct wbint_userinfo **pinfo)
158 ADS_STRUCT *ads = NULL;
159 const char *attrs[] = { "*", NULL };
162 LDAPMessage *res = NULL;
163 LDAPMessage *msg = NULL;
164 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
168 DEBUG(3,("ads: query_user_list\n"));
170 if ( !winbindd_can_contact_domain( domain ) ) {
171 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
176 ads = ads_cached_connection(domain);
179 domain->last_status = NT_STATUS_SERVER_DISABLED;
183 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
184 if (!ADS_ERR_OK(rc) || !res) {
185 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
189 count = ads_count_replies(ads, res);
191 DEBUG(1,("query_user_list: No users found\n"));
195 (*pinfo) = TALLOC_ZERO_ARRAY(mem_ctx, struct wbint_userinfo, count);
197 status = NT_STATUS_NO_MEMORY;
203 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
204 struct wbint_userinfo *info = &((*pinfo)[count]);
208 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
209 ds_atype_map(atype) != SID_NAME_USER) {
210 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
214 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
215 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
216 info->homedir = NULL;
218 info->primary_gid = (gid_t)-1;
220 if (!ads_pull_sid(ads, msg, "objectSid",
222 DEBUG(1, ("No sid for %s !?\n", info->acct_name));
226 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
227 DEBUG(1, ("No primary group for %s !?\n",
231 sid_compose(&info->group_sid, &domain->sid, group);
236 (*num_entries) = count;
237 ads_msgfree(ads, res);
239 for (i=0; i<count; i++) {
240 struct wbint_userinfo *info = &((*pinfo)[i]);
241 const char *gecos = NULL;
242 gid_t primary_gid = (gid_t)-1;
245 * Don't use our variable "ads" in this call here, every call
246 * to nss_get_info_cached can destroy the connection inside
249 status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
250 ads_cached_connection(domain),
251 msg, &info->homedir, &info->shell,
252 &gecos, &primary_gid);
253 if (!NT_STATUS_IS_OK(status)) {
255 * Deliberately ignore this error, there might be more
262 info->full_name = gecos;
264 info->primary_gid = primary_gid;
267 status = NT_STATUS_OK;
269 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
275 /* list all domain groups */
276 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
279 struct acct_info **info)
281 ADS_STRUCT *ads = NULL;
282 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
283 "name", "objectSid", NULL};
286 LDAPMessage *res = NULL;
287 LDAPMessage *msg = NULL;
288 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
290 bool enum_dom_local_groups = False;
294 DEBUG(3,("ads: enum_dom_groups\n"));
296 if ( !winbindd_can_contact_domain( domain ) ) {
297 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
302 /* only grab domain local groups for our domain */
303 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
304 enum_dom_local_groups = True;
307 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
310 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
311 * default value, it MUST be absent. In case of extensible matching the
312 * "dnattr" boolean defaults to FALSE and so it must be only be present
315 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
316 * filter using bitwise matching rule then the buggy AD fails to decode
317 * the extensible match. As a workaround set it to TRUE and thereby add
318 * the dnAttributes "dn" field to cope with those older AD versions.
319 * It should not harm and won't put any additional load on the AD since
320 * none of the dn components have a bitmask-attribute.
322 * Thanks to Ralf Haferkamp for input and testing - Guenther */
324 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
325 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
326 ADS_LDAP_MATCHING_RULE_BIT_AND,
327 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
329 if (filter == NULL) {
330 status = NT_STATUS_NO_MEMORY;
334 ads = ads_cached_connection(domain);
337 domain->last_status = NT_STATUS_SERVER_DISABLED;
341 rc = ads_search_retry(ads, &res, filter, attrs);
342 if (!ADS_ERR_OK(rc) || !res) {
343 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
347 count = ads_count_replies(ads, res);
349 DEBUG(1,("enum_dom_groups: No groups found\n"));
353 (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct acct_info, count);
355 status = NT_STATUS_NO_MEMORY;
361 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
366 name = ads_pull_username(ads, mem_ctx, msg);
367 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
368 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
369 DEBUG(1,("No sid for %s !?\n", name));
373 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
374 DEBUG(1,("No rid for %s !?\n", name));
378 fstrcpy((*info)[i].acct_name, name);
379 fstrcpy((*info)[i].acct_desc, gecos);
380 (*info)[i].rid = rid;
386 status = NT_STATUS_OK;
388 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
392 ads_msgfree(ads, res);
397 /* list all domain local groups */
398 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
401 struct acct_info **info)
404 * This is a stub function only as we returned the domain
405 * local groups in enum_dom_groups() if the domain->native field
406 * was true. This is a simple performance optimization when
409 * if we ever need to enumerate domain local groups separately,
410 * then this optimization in enum_dom_groups() will need
418 /* convert a single name to a sid in a domain - use rpc methods */
419 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
421 const char *domain_name,
425 enum lsa_SidType *type)
427 return reconnect_methods.name_to_sid(domain, mem_ctx,
428 domain_name, name, flags,
432 /* convert a domain SID to a user or group name - use rpc methods */
433 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
435 const struct dom_sid *sid,
438 enum lsa_SidType *type)
440 return reconnect_methods.sid_to_name(domain, mem_ctx, sid,
441 domain_name, name, type);
444 /* convert a list of rids to names - use rpc methods */
445 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
447 const struct dom_sid *sid,
452 enum lsa_SidType **types)
454 return reconnect_methods.rids_to_names(domain, mem_ctx, sid,
456 domain_name, names, types);
459 /* If you are looking for "dn_lookup": Yes, it used to be here!
460 * It has gone now since it was a major speed bottleneck in
461 * lookup_groupmem (its only use). It has been replaced by
462 * an rpc lookup sids call... R.I.P. */
464 /* Lookup user information from a rid */
465 static NTSTATUS query_user(struct winbindd_domain *domain,
467 const struct dom_sid *sid,
468 struct wbint_userinfo *info)
470 ADS_STRUCT *ads = NULL;
471 const char *attrs[] = { "*", NULL };
474 LDAPMessage *msg = NULL;
478 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
479 struct netr_SamInfo3 *user = NULL;
484 DEBUG(3,("ads: query_user\n"));
486 info->homedir = NULL;
489 /* try netsamlogon cache first */
491 if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
493 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
494 sid_string_dbg(sid)));
496 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
497 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
499 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
500 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
502 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL,
503 &info->homedir, &info->shell, &info->full_name,
505 info->primary_gid = gid;
512 if ( !winbindd_can_contact_domain(domain)) {
513 DEBUG(8,("query_user: No incoming trust from domain %s\n",
516 /* We still need to generate some basic information
517 about the user even if we cannot contact the
518 domain. Most of this stuff we can deduce. */
520 sid_copy( &info->user_sid, sid );
522 /* Assume "Domain Users" for the primary group */
524 sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
526 /* Try to fill in what the nss_info backend can do */
528 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL,
529 &info->homedir, &info->shell, &info->full_name,
531 info->primary_gid = gid;
536 /* no cache...do the query */
538 if ( (ads = ads_cached_connection(domain)) == NULL ) {
539 domain->last_status = NT_STATUS_SERVER_DISABLED;
540 return NT_STATUS_SERVER_DISABLED;
543 sidstr = sid_binstring(talloc_tos(), sid);
545 ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
548 return NT_STATUS_NO_MEMORY;
550 rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
552 if (!ADS_ERR_OK(rc) || !msg) {
553 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
554 sid_string_dbg(sid), ads_errstr(rc)));
555 return ads_ntstatus(rc);
558 count = ads_count_replies(ads, msg);
560 DEBUG(1,("query_user(sid=%s): Not found\n",
561 sid_string_dbg(sid)));
562 ads_msgfree(ads, msg);
563 return NT_STATUS_NO_SUCH_USER;
566 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
568 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
569 DEBUG(1,("No primary group for %s !?\n",
570 sid_string_dbg(sid)));
571 ads_msgfree(ads, msg);
572 return NT_STATUS_NO_SUCH_USER;
574 sid_copy(&info->user_sid, sid);
575 sid_compose(&info->group_sid, &domain->sid, group_rid);
578 * We have to fetch the "name" attribute before doing the
579 * nss_get_info_cached call. nss_get_info_cached might destroy
580 * the ads struct, potentially invalidating the ldap message.
582 ads_name = ads_pull_string(ads, mem_ctx, msg, "name");
584 ads_msgfree(ads, msg);
587 status = nss_get_info_cached( domain, sid, mem_ctx, ads, msg,
588 &info->homedir, &info->shell, &info->full_name,
590 info->primary_gid = gid;
591 if (!NT_STATUS_IS_OK(status)) {
592 DEBUG(1, ("nss_get_info_cached failed: %s\n",
597 if (info->full_name == NULL) {
598 info->full_name = ads_name;
600 TALLOC_FREE(ads_name);
603 status = NT_STATUS_OK;
605 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
609 /* Lookup groups a user is a member of - alternate method, for when
610 tokenGroups are not available. */
611 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
614 struct dom_sid *primary_group,
615 size_t *p_num_groups, struct dom_sid **user_sids)
618 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
620 LDAPMessage *res = NULL;
621 LDAPMessage *msg = NULL;
624 const char *group_attrs[] = {"objectSid", NULL};
626 size_t num_groups = 0;
628 DEBUG(3,("ads: lookup_usergroups_member\n"));
630 if ( !winbindd_can_contact_domain( domain ) ) {
631 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
636 ads = ads_cached_connection(domain);
639 domain->last_status = NT_STATUS_SERVER_DISABLED;
643 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
644 status = NT_STATUS_NO_MEMORY;
648 ldap_exp = talloc_asprintf(mem_ctx,
649 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
651 ADS_LDAP_MATCHING_RULE_BIT_AND,
652 GROUP_TYPE_SECURITY_ENABLED);
654 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
655 TALLOC_FREE(escaped_dn);
656 status = NT_STATUS_NO_MEMORY;
660 TALLOC_FREE(escaped_dn);
662 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
664 if (!ADS_ERR_OK(rc) || !res) {
665 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
666 return ads_ntstatus(rc);
669 count = ads_count_replies(ads, res);
674 /* always add the primary group to the sid array */
675 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
677 if (!NT_STATUS_IS_OK(status)) {
682 for (msg = ads_first_entry(ads, res); msg;
683 msg = ads_next_entry(ads, msg)) {
684 struct dom_sid group_sid;
686 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
687 DEBUG(1,("No sid for this group ?!?\n"));
691 /* ignore Builtin groups from ADS - Guenther */
692 if (sid_check_is_in_builtin(&group_sid)) {
696 status = add_sid_to_array(mem_ctx, &group_sid,
697 user_sids, &num_groups);
698 if (!NT_STATUS_IS_OK(status)) {
705 *p_num_groups = num_groups;
706 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
708 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
711 ads_msgfree(ads, res);
716 /* Lookup groups a user is a member of - alternate method, for when
717 tokenGroups are not available. */
718 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
721 struct dom_sid *primary_group,
722 size_t *p_num_groups,
723 struct dom_sid **user_sids)
726 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
728 const char *attrs[] = {"memberOf", NULL};
729 size_t num_groups = 0;
730 struct dom_sid *group_sids = NULL;
732 char **strings = NULL;
733 size_t num_strings = 0, num_sids = 0;
736 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
738 if ( !winbindd_can_contact_domain( domain ) ) {
739 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
740 "domain %s\n", domain->name));
744 ads = ads_cached_connection(domain);
747 domain->last_status = NT_STATUS_SERVER_DISABLED;
748 return NT_STATUS_UNSUCCESSFUL;
751 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
752 ADS_EXTENDED_DN_HEX_STRING,
753 &strings, &num_strings);
755 if (!ADS_ERR_OK(rc)) {
756 DEBUG(1,("lookup_usergroups_memberof ads_search "
757 "member=%s: %s\n", user_dn, ads_errstr(rc)));
758 return ads_ntstatus(rc);
764 /* always add the primary group to the sid array */
765 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
767 if (!NT_STATUS_IS_OK(status)) {
771 group_sids = TALLOC_ZERO_ARRAY(mem_ctx, struct dom_sid, num_strings + 1);
773 status = NT_STATUS_NO_MEMORY;
777 for (i=0; i<num_strings; i++) {
778 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
779 ADS_EXTENDED_DN_HEX_STRING,
781 if (!ADS_ERR_OK(rc)) {
782 /* ignore members without SIDs */
783 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
784 NT_STATUS_NOT_FOUND)) {
788 status = ads_ntstatus(rc);
796 DEBUG(1,("No memberOf for this user?!?\n"));
797 status = NT_STATUS_NO_MEMORY;
801 for (i=0; i<num_sids; i++) {
803 /* ignore Builtin groups from ADS - Guenther */
804 if (sid_check_is_in_builtin(&group_sids[i])) {
808 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
810 if (!NT_STATUS_IS_OK(status)) {
816 *p_num_groups = num_groups;
817 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
819 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
823 TALLOC_FREE(strings);
824 TALLOC_FREE(group_sids);
830 /* Lookup groups a user is a member of. */
831 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
833 const struct dom_sid *sid,
834 uint32 *p_num_groups, struct dom_sid **user_sids)
836 ADS_STRUCT *ads = NULL;
837 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
840 LDAPMessage *msg = NULL;
841 char *user_dn = NULL;
842 struct dom_sid *sids;
844 struct dom_sid primary_group;
845 uint32 primary_group_rid;
846 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
847 size_t num_groups = 0;
849 DEBUG(3,("ads: lookup_usergroups\n"));
852 status = lookup_usergroups_cached(domain, mem_ctx, sid,
853 p_num_groups, user_sids);
854 if (NT_STATUS_IS_OK(status)) {
858 if ( !winbindd_can_contact_domain( domain ) ) {
859 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
862 /* Tell the cache manager not to remember this one */
864 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
867 ads = ads_cached_connection(domain);
870 domain->last_status = NT_STATUS_SERVER_DISABLED;
871 status = NT_STATUS_SERVER_DISABLED;
875 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
877 if (!ADS_ERR_OK(rc)) {
878 status = ads_ntstatus(rc);
879 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
880 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
884 count = ads_count_replies(ads, msg);
886 status = NT_STATUS_UNSUCCESSFUL;
887 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
888 "invalid number of results (count=%d)\n",
889 sid_string_dbg(sid), count));
894 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
895 sid_string_dbg(sid)));
896 status = NT_STATUS_UNSUCCESSFUL;
900 user_dn = ads_get_dn(ads, mem_ctx, msg);
901 if (user_dn == NULL) {
902 status = NT_STATUS_NO_MEMORY;
906 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
907 DEBUG(1,("%s: No primary group for sid=%s !?\n",
908 domain->name, sid_string_dbg(sid)));
912 sid_compose(&primary_group, &domain->sid, primary_group_rid);
914 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
916 /* there must always be at least one group in the token,
917 unless we are talking to a buggy Win2k server */
919 /* actually this only happens when the machine account has no read
920 * permissions on the tokenGroup attribute - gd */
926 /* lookup what groups this user is a member of by DN search on
929 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
931 &num_groups, user_sids);
932 *p_num_groups = (uint32)num_groups;
933 if (NT_STATUS_IS_OK(status)) {
937 /* lookup what groups this user is a member of by DN search on
940 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
942 &num_groups, user_sids);
943 *p_num_groups = (uint32)num_groups;
950 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
952 if (!NT_STATUS_IS_OK(status)) {
956 for (i=0;i<count;i++) {
958 /* ignore Builtin groups from ADS - Guenther */
959 if (sid_check_is_in_builtin(&sids[i])) {
963 status = add_sid_to_array_unique(mem_ctx, &sids[i],
964 user_sids, &num_groups);
965 if (!NT_STATUS_IS_OK(status)) {
970 *p_num_groups = (uint32)num_groups;
971 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
973 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
974 sid_string_dbg(sid)));
976 TALLOC_FREE(user_dn);
977 ads_msgfree(ads, msg);
981 /* Lookup aliases a user is member of - use rpc methods */
982 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
984 uint32 num_sids, const struct dom_sid *sids,
985 uint32 *num_aliases, uint32 **alias_rids)
987 return reconnect_methods.lookup_useraliases(domain, mem_ctx,
994 find the members of a group, given a group rid and domain
996 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
998 const struct dom_sid *group_sid,
999 enum lsa_SidType type,
1001 struct dom_sid **sid_mem, char ***names,
1002 uint32 **name_types)
1005 ADS_STRUCT *ads = NULL;
1007 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
1009 char **members = NULL;
1011 size_t num_members = 0;
1013 struct dom_sid *sid_mem_nocache = NULL;
1014 char **names_nocache = NULL;
1015 enum lsa_SidType *name_types_nocache = NULL;
1016 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1017 uint32 num_nocache = 0;
1018 TALLOC_CTX *tmp_ctx = NULL;
1020 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1021 sid_string_dbg(group_sid)));
1025 tmp_ctx = talloc_new(mem_ctx);
1027 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1028 status = NT_STATUS_NO_MEMORY;
1032 if ( !winbindd_can_contact_domain( domain ) ) {
1033 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1035 return NT_STATUS_OK;
1038 ads = ads_cached_connection(domain);
1041 domain->last_status = NT_STATUS_SERVER_DISABLED;
1045 if ((sidbinstr = sid_binstring(talloc_tos(), group_sid)) == NULL) {
1046 status = NT_STATUS_NO_MEMORY;
1050 /* search for all members of the group */
1051 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1052 TALLOC_FREE(sidbinstr);
1053 if (ldap_exp == NULL) {
1054 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1055 status = NT_STATUS_NO_MEMORY;
1059 args.control = ADS_EXTENDED_DN_OID;
1060 args.val = ADS_EXTENDED_DN_HEX_STRING;
1061 args.critical = True;
1063 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1064 ldap_exp, &args, "member", &members, &num_members);
1066 if (!ADS_ERR_OK(rc)) {
1067 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1068 status = NT_STATUS_UNSUCCESSFUL;
1072 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1074 /* Now that we have a list of sids, we need to get the
1075 * lists of names and name_types belonging to these sids.
1076 * even though conceptually not quite clean, we use the
1077 * RPC call lsa_lookup_sids for this since it can handle a
1078 * list of sids. ldap calls can just resolve one sid at a time.
1080 * At this stage, the sids are still hidden in the exetended dn
1081 * member output format. We actually do a little better than
1082 * stated above: In extracting the sids from the member strings,
1083 * we try to resolve as many sids as possible from the
1084 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1087 (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, struct dom_sid, num_members);
1088 (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
1089 (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
1090 (sid_mem_nocache) = TALLOC_ZERO_ARRAY(tmp_ctx, struct dom_sid, num_members);
1092 if ((members == NULL) || (*sid_mem == NULL) ||
1093 (*names == NULL) || (*name_types == NULL) ||
1094 (sid_mem_nocache == NULL))
1096 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1097 status = NT_STATUS_NO_MEMORY;
1104 (*name_types) = NULL;
1107 for (i=0; i<num_members; i++) {
1108 enum lsa_SidType name_type;
1109 char *name, *domain_name;
1112 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1114 if (!ADS_ERR_OK(rc)) {
1115 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1116 NT_STATUS_NOT_FOUND)) {
1117 /* Group members can be objects, like Exchange
1118 * Public Folders, that don't have a SID. Skip
1123 status = ads_ntstatus(rc);
1127 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1129 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1130 "cache\n", sid_string_dbg(&sid)));
1131 sid_copy(&(*sid_mem)[*num_names], &sid);
1132 (*names)[*num_names] = fill_domain_username_talloc(
1138 (*name_types)[*num_names] = name_type;
1142 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1143 "cache\n", sid_string_dbg(&sid)));
1144 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1149 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1150 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1152 /* handle sids not resolved from cache by lsa_lookup_sids */
1153 if (num_nocache > 0) {
1155 status = winbindd_lookup_sids(tmp_ctx,
1161 &name_types_nocache);
1163 if (!(NT_STATUS_IS_OK(status) ||
1164 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1165 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1167 DEBUG(1, ("lsa_lookupsids call failed with %s "
1168 "- retrying...\n", nt_errstr(status)));
1170 status = winbindd_lookup_sids(tmp_ctx,
1176 &name_types_nocache);
1179 if (NT_STATUS_IS_OK(status) ||
1180 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1182 /* Copy the entries over from the "_nocache" arrays
1183 * to the result arrays, skipping the gaps the
1184 * lookup_sids call left. */
1185 for (i=0; i < num_nocache; i++) {
1186 if (((names_nocache)[i] != NULL) &&
1187 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1189 sid_copy(&(*sid_mem)[*num_names],
1190 &sid_mem_nocache[i]);
1191 (*names)[*num_names] =
1192 fill_domain_username_talloc(
1197 (*name_types)[*num_names] = name_types_nocache[i];
1202 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1203 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1204 "not map any SIDs at all.\n"));
1205 /* Don't handle this as an error here.
1206 * There is nothing left to do with respect to the
1207 * overall result... */
1209 else if (!NT_STATUS_IS_OK(status)) {
1210 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1211 "sids via rpc_lsa_lookup_sids: %s\n",
1212 (int)num_members, nt_errstr(status)));
1217 status = NT_STATUS_OK;
1218 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1219 sid_string_dbg(group_sid)));
1223 TALLOC_FREE(tmp_ctx);
1228 /* find the sequence number for a domain */
1229 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1231 ADS_STRUCT *ads = NULL;
1234 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1236 if ( !winbindd_can_contact_domain( domain ) ) {
1237 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1240 return NT_STATUS_OK;
1243 *seq = DOM_SEQUENCE_NONE;
1245 ads = ads_cached_connection(domain);
1248 domain->last_status = NT_STATUS_SERVER_DISABLED;
1249 return NT_STATUS_UNSUCCESSFUL;
1252 rc = ads_USN(ads, seq);
1254 if (!ADS_ERR_OK(rc)) {
1256 /* its a dead connection, destroy it */
1258 if (domain->private_data) {
1259 ads = (ADS_STRUCT *)domain->private_data;
1260 ads->is_mine = True;
1262 ads_kdestroy("MEMORY:winbind_ccache");
1263 domain->private_data = NULL;
1266 return ads_ntstatus(rc);
1269 /* find the lockout policy of a domain - use rpc methods */
1270 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1271 TALLOC_CTX *mem_ctx,
1272 struct samr_DomInfo12 *policy)
1274 return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
1277 /* find the password policy of a domain - use rpc methods */
1278 static NTSTATUS password_policy(struct winbindd_domain *domain,
1279 TALLOC_CTX *mem_ctx,
1280 struct samr_DomInfo1 *policy)
1282 return reconnect_methods.password_policy(domain, mem_ctx, policy);
1285 /* get a list of trusted domains */
1286 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1287 TALLOC_CTX *mem_ctx,
1288 struct netr_DomainTrustList *trusts)
1290 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1293 struct rpc_pipe_client *cli;
1296 DEBUG(3,("ads: trusted_domains\n"));
1298 ZERO_STRUCTP(trusts);
1300 /* If this is our primary domain or a root in our forest,
1301 query for all trusts. If not, then just look for domain
1302 trusts in the target forest */
1304 if (domain->primary || domain_is_forest_root(domain)) {
1305 flags = NETR_TRUST_FLAG_OUTBOUND |
1306 NETR_TRUST_FLAG_INBOUND |
1307 NETR_TRUST_FLAG_IN_FOREST;
1309 flags = NETR_TRUST_FLAG_IN_FOREST;
1312 result = cm_connect_netlogon(domain, &cli);
1314 if (!NT_STATUS_IS_OK(result)) {
1315 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1316 "for PIPE_NETLOGON (%s)\n",
1317 domain->name, nt_errstr(result)));
1318 return NT_STATUS_UNSUCCESSFUL;
1321 result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
1326 if (!NT_STATUS_IS_OK(result)) {
1329 if (trusts->count == 0) {
1330 return NT_STATUS_OK;
1333 /* Copy across names and sids */
1336 for (i = 0; i < trusts->count; i++) {
1337 struct netr_DomainTrust *trust = &trusts->array[i];
1338 struct winbindd_domain d;
1343 * drop external trusts if this is not our primary
1344 * domain. This means that the returned number of
1345 * domains may be less that the ones actually trusted
1349 if ((trust->trust_attributes
1350 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1353 DEBUG(10,("trusted_domains: Skipping external trusted "
1354 "domain %s because it is outside of our "
1356 trust->netbios_name));
1360 /* add to the trusted domain cache */
1362 fstrcpy(d.name, trust->netbios_name);
1363 fstrcpy(d.alt_name, trust->dns_name);
1365 sid_copy(&d.sid, trust->sid);
1367 sid_copy(&d.sid, &global_sid_NULL);
1370 if ( domain->primary ) {
1371 DEBUG(10,("trusted_domains(ads): Searching "
1372 "trusted domain list of %s and storing "
1373 "trust flags for domain %s\n",
1374 domain->name, d.alt_name));
1376 d.domain_flags = trust->trust_flags;
1377 d.domain_type = trust->trust_type;
1378 d.domain_trust_attribs = trust->trust_attributes;
1380 wcache_tdc_add_domain( &d );
1382 } else if (domain_is_forest_root(domain)) {
1383 /* Check if we already have this record. If
1384 * we are following our forest root that is not
1385 * our primary domain, we want to keep trust
1386 * flags from the perspective of our primary
1387 * domain not our forest root. */
1388 struct winbindd_tdc_domain *exist = NULL;
1390 exist = wcache_tdc_fetch_domain(
1391 talloc_tos(), trust->netbios_name);
1393 DEBUG(10,("trusted_domains(ads): Searching "
1394 "trusted domain list of %s and "
1395 "storing trust flags for domain "
1396 "%s\n", domain->name, d.alt_name));
1397 d.domain_flags = trust->trust_flags;
1398 d.domain_type = trust->trust_type;
1399 d.domain_trust_attribs =
1400 trust->trust_attributes;
1402 wcache_tdc_add_domain( &d );
1407 /* This gets a little tricky. If we are
1408 following a transitive forest trust, then
1409 innerit the flags, type, and attribs from
1410 the domain we queried to make sure we don't
1411 record the view of the trust from the wrong
1412 side. Always view it from the side of our
1413 primary domain. --jerry */
1414 struct winbindd_tdc_domain *parent = NULL;
1416 DEBUG(10,("trusted_domains(ads): Searching "
1417 "trusted domain list of %s and inheriting "
1418 "trust flags for domain %s\n",
1419 domain->name, d.alt_name));
1421 parent = wcache_tdc_fetch_domain(talloc_tos(),
1424 d.domain_flags = parent->trust_flags;
1425 d.domain_type = parent->trust_type;
1426 d.domain_trust_attribs = parent->trust_attribs;
1428 d.domain_flags = domain->domain_flags;
1429 d.domain_type = domain->domain_type;
1430 d.domain_trust_attribs =
1431 domain->domain_trust_attribs;
1433 TALLOC_FREE(parent);
1435 wcache_tdc_add_domain( &d );
1442 /* the ADS backend methods are exposed via this structure */
1443 struct winbindd_methods ads_methods = {