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"
31 #define DBGC_CLASS DBGC_WINBIND
33 extern struct winbindd_methods reconnect_methods;
36 return our ads connections structure for a domain. We keep the connection
37 open to make things faster
39 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
44 struct sockaddr_storage dc_ss;
46 DEBUG(10,("ads_cached_connection\n"));
48 if (domain->private_data) {
51 time_t now = time(NULL);
53 /* check for a valid structure */
54 ads = (ADS_STRUCT *)domain->private_data;
56 expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
58 DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
59 (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
61 if ( ads->config.realm && (expire > now)) {
64 /* we own this ADS_STRUCT so make sure it goes away */
65 DEBUG(7,("Deleting expired krb5 credential cache\n"));
68 ads_kdestroy("MEMORY:winbind_ccache");
69 domain->private_data = NULL;
73 /* we don't want this to affect the users ccache */
74 setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1);
76 ads = ads_init(domain->alt_name, domain->name, NULL);
78 DEBUG(1,("ads_init for domain %s failed\n", domain->name));
82 /* the machine acct password might have change - fetch it every time */
84 SAFE_FREE(ads->auth.password);
85 SAFE_FREE(ads->auth.realm);
89 if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, NULL, NULL ) ) {
93 ads->auth.realm = SMB_STRDUP( ads->server.realm );
94 strupper_m( ads->auth.realm );
97 struct winbindd_domain *our_domain = domain;
99 ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
101 /* always give preference to the alt_name in our
102 primary domain if possible */
104 if ( !domain->primary )
105 our_domain = find_our_domain();
107 if ( our_domain->alt_name[0] != '\0' ) {
108 ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
109 strupper_m( ads->auth.realm );
112 ads->auth.realm = SMB_STRDUP( lp_realm() );
115 ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
117 /* Setup the server affinity cache. We don't reaally care
118 about the name. Just setup affinity and the KRB5_CONFIG
121 get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ss );
123 status = ads_connect(ads);
124 if (!ADS_ERR_OK(status) || !ads->config.realm) {
125 DEBUG(1,("ads_connect for domain %s failed: %s\n",
126 domain->name, ads_errstr(status)));
129 /* if we get ECONNREFUSED then it might be a NT4
130 server, fall back to MSRPC */
131 if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
132 status.err.rc == ECONNREFUSED) {
133 /* 'reconnect_methods' is the MS-RPC backend. */
134 DEBUG(1,("Trying MSRPC methods\n"));
135 domain->backend = &reconnect_methods;
140 /* set the flag that says we don't own the memory even
141 though we do so that ads_destroy() won't destroy the
142 structure we pass back by reference */
144 ads->is_mine = False;
146 domain->private_data = (void *)ads;
151 /* Query display info for a realm. This is the basic user list fn */
152 static NTSTATUS query_user_list(struct winbindd_domain *domain,
155 struct wbint_userinfo **info)
157 ADS_STRUCT *ads = NULL;
158 const char *attrs[] = { "*", NULL };
161 LDAPMessage *res = NULL;
162 LDAPMessage *msg = NULL;
163 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
167 DEBUG(3,("ads: query_user_list\n"));
169 if ( !winbindd_can_contact_domain( domain ) ) {
170 DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
175 ads = ads_cached_connection(domain);
178 domain->last_status = NT_STATUS_SERVER_DISABLED;
182 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
183 if (!ADS_ERR_OK(rc) || !res) {
184 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
188 count = ads_count_replies(ads, res);
190 DEBUG(1,("query_user_list: No users found\n"));
194 (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct wbint_userinfo, count);
196 status = NT_STATUS_NO_MEMORY;
202 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
204 const char *gecos = NULL;
205 const char *homedir = NULL;
206 const char *shell = NULL;
209 struct dom_sid user_sid;
210 gid_t primary_gid = (gid_t)-1;
212 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
213 ds_atype_map(atype) != SID_NAME_USER) {
214 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
218 name = ads_pull_username(ads, mem_ctx, msg);
220 if ( ads_pull_sid( ads, msg, "objectSid", &user_sid ) ) {
221 status = nss_get_info_cached( domain, &user_sid, mem_ctx,
222 ads, msg, &homedir, &shell, &gecos,
227 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
230 if (!ads_pull_sid(ads, msg, "objectSid",
231 &(*info)[i].user_sid)) {
232 DEBUG(1,("No sid for %s !?\n", name));
235 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
236 DEBUG(1,("No primary group for %s !?\n", name));
240 (*info)[i].acct_name = name;
241 (*info)[i].full_name = gecos;
242 (*info)[i].homedir = homedir;
243 (*info)[i].shell = shell;
244 (*info)[i].primary_gid = primary_gid;
245 sid_compose(&(*info)[i].group_sid, &domain->sid, group);
250 status = NT_STATUS_OK;
252 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
256 ads_msgfree(ads, res);
261 /* list all domain groups */
262 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
265 struct acct_info **info)
267 ADS_STRUCT *ads = NULL;
268 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
269 "name", "objectSid", NULL};
272 LDAPMessage *res = NULL;
273 LDAPMessage *msg = NULL;
274 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
276 bool enum_dom_local_groups = False;
280 DEBUG(3,("ads: enum_dom_groups\n"));
282 if ( !winbindd_can_contact_domain( domain ) ) {
283 DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
288 /* only grab domain local groups for our domain */
289 if ( domain->active_directory && strequal(lp_realm(), domain->alt_name) ) {
290 enum_dom_local_groups = True;
293 /* Workaround ADS LDAP bug present in MS W2K3 SP0 and W2K SP4 w/o
296 * According to Section 5.1(4) of RFC 2251 if a value of a type is it's
297 * default value, it MUST be absent. In case of extensible matching the
298 * "dnattr" boolean defaults to FALSE and so it must be only be present
301 * When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
302 * filter using bitwise matching rule then the buggy AD fails to decode
303 * the extensible match. As a workaround set it to TRUE and thereby add
304 * the dnAttributes "dn" field to cope with those older AD versions.
305 * It should not harm and won't put any additional load on the AD since
306 * none of the dn components have a bitmask-attribute.
308 * Thanks to Ralf Haferkamp for input and testing - Guenther */
310 filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
311 ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
312 ADS_LDAP_MATCHING_RULE_BIT_AND,
313 enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
315 if (filter == NULL) {
316 status = NT_STATUS_NO_MEMORY;
320 ads = ads_cached_connection(domain);
323 domain->last_status = NT_STATUS_SERVER_DISABLED;
327 rc = ads_search_retry(ads, &res, filter, attrs);
328 if (!ADS_ERR_OK(rc) || !res) {
329 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
333 count = ads_count_replies(ads, res);
335 DEBUG(1,("enum_dom_groups: No groups found\n"));
339 (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct acct_info, count);
341 status = NT_STATUS_NO_MEMORY;
347 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
352 name = ads_pull_username(ads, mem_ctx, msg);
353 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
354 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
355 DEBUG(1,("No sid for %s !?\n", name));
359 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
360 DEBUG(1,("No rid for %s !?\n", name));
364 fstrcpy((*info)[i].acct_name, name);
365 fstrcpy((*info)[i].acct_desc, gecos);
366 (*info)[i].rid = rid;
372 status = NT_STATUS_OK;
374 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
378 ads_msgfree(ads, res);
383 /* list all domain local groups */
384 static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
387 struct acct_info **info)
390 * This is a stub function only as we returned the domain
391 * local groups in enum_dom_groups() if the domain->native field
392 * was true. This is a simple performance optimization when
395 * if we ever need to enumerate domain local groups separately,
396 * then this optimization in enum_dom_groups() will need
404 /* convert a single name to a sid in a domain - use rpc methods */
405 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
407 const char *domain_name,
411 enum lsa_SidType *type)
413 return reconnect_methods.name_to_sid(domain, mem_ctx,
414 domain_name, name, flags,
418 /* convert a domain SID to a user or group name - use rpc methods */
419 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
421 const struct dom_sid *sid,
424 enum lsa_SidType *type)
426 return reconnect_methods.sid_to_name(domain, mem_ctx, sid,
427 domain_name, name, type);
430 /* convert a list of rids to names - use rpc methods */
431 static NTSTATUS rids_to_names(struct winbindd_domain *domain,
433 const struct dom_sid *sid,
438 enum lsa_SidType **types)
440 return reconnect_methods.rids_to_names(domain, mem_ctx, sid,
442 domain_name, names, types);
445 /* If you are looking for "dn_lookup": Yes, it used to be here!
446 * It has gone now since it was a major speed bottleneck in
447 * lookup_groupmem (its only use). It has been replaced by
448 * an rpc lookup sids call... R.I.P. */
450 /* Lookup user information from a rid */
451 static NTSTATUS query_user(struct winbindd_domain *domain,
453 const struct dom_sid *sid,
454 struct wbint_userinfo *info)
456 ADS_STRUCT *ads = NULL;
457 const char *attrs[] = { "*", NULL };
460 LDAPMessage *msg = NULL;
464 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
465 struct netr_SamInfo3 *user = NULL;
470 DEBUG(3,("ads: query_user\n"));
472 info->homedir = NULL;
475 /* try netsamlogon cache first */
477 if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
479 DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
480 sid_string_dbg(sid)));
482 sid_compose(&info->user_sid, &domain->sid, user->base.rid);
483 sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
485 info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
486 info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
488 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL,
489 &info->homedir, &info->shell, &info->full_name,
491 info->primary_gid = gid;
498 if ( !winbindd_can_contact_domain(domain)) {
499 DEBUG(8,("query_user: No incoming trust from domain %s\n",
502 /* We still need to generate some basic information
503 about the user even if we cannot contact the
504 domain. Most of this stuff we can deduce. */
506 sid_copy( &info->user_sid, sid );
508 /* Assume "Domain Users" for the primary group */
510 sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
512 /* Try to fill in what the nss_info backend can do */
514 nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL,
515 &info->homedir, &info->shell, &info->full_name,
517 info->primary_gid = gid;
519 status = NT_STATUS_OK;
523 /* no cache...do the query */
525 if ( (ads = ads_cached_connection(domain)) == NULL ) {
526 domain->last_status = NT_STATUS_SERVER_DISABLED;
530 sidstr = sid_binstring(talloc_tos(), sid);
532 ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
535 status = NT_STATUS_NO_MEMORY;
538 rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
540 if (!ADS_ERR_OK(rc) || !msg) {
541 DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
542 sid_string_dbg(sid), ads_errstr(rc)));
546 count = ads_count_replies(ads, msg);
548 DEBUG(1,("query_user(sid=%s): Not found\n",
549 sid_string_dbg(sid)));
553 info->acct_name = ads_pull_username(ads, mem_ctx, msg);
555 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
556 DEBUG(1,("No primary group for %s !?\n",
557 sid_string_dbg(sid)));
561 sid_copy(&info->user_sid, sid);
562 sid_compose(&info->group_sid, &domain->sid, group_rid);
565 * We have to fetch the "name" attribute before doing the
566 * nss_get_info_cached call. nss_get_info_cached might destroy
567 * the ads struct, potentially invalidating the ldap message.
570 ads_name = ads_pull_string(ads, mem_ctx, msg, "name");
572 ads_msgfree(ads, msg);
575 status = nss_get_info_cached( domain, sid, mem_ctx, ads, msg,
576 &info->homedir, &info->shell, &info->full_name,
578 info->primary_gid = gid;
579 if (!NT_STATUS_IS_OK(status)) {
580 DEBUG(1, ("nss_get_info_cached failed: %s\n",
585 if (info->full_name == NULL) {
586 info->full_name = ads_name;
588 TALLOC_FREE(ads_name);
591 status = NT_STATUS_OK;
593 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
598 /* Lookup groups a user is a member of - alternate method, for when
599 tokenGroups are not available. */
600 static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
603 struct dom_sid *primary_group,
604 size_t *p_num_groups, struct dom_sid **user_sids)
607 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
609 LDAPMessage *res = NULL;
610 LDAPMessage *msg = NULL;
613 const char *group_attrs[] = {"objectSid", NULL};
615 size_t num_groups = 0;
617 DEBUG(3,("ads: lookup_usergroups_member\n"));
619 if ( !winbindd_can_contact_domain( domain ) ) {
620 DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
625 ads = ads_cached_connection(domain);
628 domain->last_status = NT_STATUS_SERVER_DISABLED;
632 if (!(escaped_dn = escape_ldap_string(talloc_tos(), user_dn))) {
633 status = NT_STATUS_NO_MEMORY;
637 ldap_exp = talloc_asprintf(mem_ctx,
638 "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
640 ADS_LDAP_MATCHING_RULE_BIT_AND,
641 GROUP_TYPE_SECURITY_ENABLED);
643 DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
644 TALLOC_FREE(escaped_dn);
645 status = NT_STATUS_NO_MEMORY;
649 TALLOC_FREE(escaped_dn);
651 rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
653 if (!ADS_ERR_OK(rc) || !res) {
654 DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
655 return ads_ntstatus(rc);
658 count = ads_count_replies(ads, res);
663 /* always add the primary group to the sid array */
664 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
666 if (!NT_STATUS_IS_OK(status)) {
671 for (msg = ads_first_entry(ads, res); msg;
672 msg = ads_next_entry(ads, msg)) {
673 struct dom_sid group_sid;
675 if (!ads_pull_sid(ads, msg, "objectSid", &group_sid)) {
676 DEBUG(1,("No sid for this group ?!?\n"));
680 /* ignore Builtin groups from ADS - Guenther */
681 if (sid_check_is_in_builtin(&group_sid)) {
685 status = add_sid_to_array(mem_ctx, &group_sid,
686 user_sids, &num_groups);
687 if (!NT_STATUS_IS_OK(status)) {
694 *p_num_groups = num_groups;
695 status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
697 DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
700 ads_msgfree(ads, res);
705 /* Lookup groups a user is a member of - alternate method, for when
706 tokenGroups are not available. */
707 static NTSTATUS lookup_usergroups_memberof(struct winbindd_domain *domain,
710 struct dom_sid *primary_group,
711 size_t *p_num_groups,
712 struct dom_sid **user_sids)
715 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
717 const char *attrs[] = {"memberOf", NULL};
718 size_t num_groups = 0;
719 struct dom_sid *group_sids = NULL;
721 char **strings = NULL;
722 size_t num_strings = 0, num_sids = 0;
725 DEBUG(3,("ads: lookup_usergroups_memberof\n"));
727 if ( !winbindd_can_contact_domain( domain ) ) {
728 DEBUG(10,("lookup_usergroups_memberof: No incoming trust for "
729 "domain %s\n", domain->name));
733 ads = ads_cached_connection(domain);
736 domain->last_status = NT_STATUS_SERVER_DISABLED;
737 return NT_STATUS_UNSUCCESSFUL;
740 rc = ads_search_retry_extended_dn_ranged(ads, mem_ctx, user_dn, attrs,
741 ADS_EXTENDED_DN_HEX_STRING,
742 &strings, &num_strings);
744 if (!ADS_ERR_OK(rc)) {
745 DEBUG(1,("lookup_usergroups_memberof ads_search "
746 "member=%s: %s\n", user_dn, ads_errstr(rc)));
747 return ads_ntstatus(rc);
753 /* always add the primary group to the sid array */
754 status = add_sid_to_array(mem_ctx, primary_group, user_sids,
756 if (!NT_STATUS_IS_OK(status)) {
760 group_sids = TALLOC_ZERO_ARRAY(mem_ctx, struct dom_sid, num_strings + 1);
762 status = NT_STATUS_NO_MEMORY;
766 for (i=0; i<num_strings; i++) {
767 rc = ads_get_sid_from_extended_dn(mem_ctx, strings[i],
768 ADS_EXTENDED_DN_HEX_STRING,
770 if (!ADS_ERR_OK(rc)) {
771 /* ignore members without SIDs */
772 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
773 NT_STATUS_NOT_FOUND)) {
777 status = ads_ntstatus(rc);
785 DEBUG(1,("No memberOf for this user?!?\n"));
786 status = NT_STATUS_NO_MEMORY;
790 for (i=0; i<num_sids; i++) {
792 /* ignore Builtin groups from ADS - Guenther */
793 if (sid_check_is_in_builtin(&group_sids[i])) {
797 status = add_sid_to_array(mem_ctx, &group_sids[i], user_sids,
799 if (!NT_STATUS_IS_OK(status)) {
805 *p_num_groups = num_groups;
806 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
808 DEBUG(3,("ads lookup_usergroups (memberof) succeeded for dn=%s\n",
812 TALLOC_FREE(strings);
813 TALLOC_FREE(group_sids);
819 /* Lookup groups a user is a member of. */
820 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
822 const struct dom_sid *sid,
823 uint32 *p_num_groups, struct dom_sid **user_sids)
825 ADS_STRUCT *ads = NULL;
826 const char *attrs[] = {"tokenGroups", "primaryGroupID", NULL};
829 LDAPMessage *msg = NULL;
830 char *user_dn = NULL;
831 struct dom_sid *sids;
833 struct dom_sid primary_group;
834 uint32 primary_group_rid;
835 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
836 size_t num_groups = 0;
838 DEBUG(3,("ads: lookup_usergroups\n"));
841 status = lookup_usergroups_cached(domain, mem_ctx, sid,
842 p_num_groups, user_sids);
843 if (NT_STATUS_IS_OK(status)) {
847 if ( !winbindd_can_contact_domain( domain ) ) {
848 DEBUG(10,("lookup_usergroups: No incoming trust for domain %s\n",
851 /* Tell the cache manager not to remember this one */
853 return NT_STATUS_SYNCHRONIZATION_REQUIRED;
856 ads = ads_cached_connection(domain);
859 domain->last_status = NT_STATUS_SERVER_DISABLED;
860 status = NT_STATUS_SERVER_DISABLED;
864 rc = ads_search_retry_sid(ads, &msg, sid, attrs);
866 if (!ADS_ERR_OK(rc)) {
867 status = ads_ntstatus(rc);
868 DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
869 "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
873 count = ads_count_replies(ads, msg);
875 status = NT_STATUS_UNSUCCESSFUL;
876 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
877 "invalid number of results (count=%d)\n",
878 sid_string_dbg(sid), count));
883 DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
884 sid_string_dbg(sid)));
885 status = NT_STATUS_UNSUCCESSFUL;
889 user_dn = ads_get_dn(ads, mem_ctx, msg);
890 if (user_dn == NULL) {
891 status = NT_STATUS_NO_MEMORY;
895 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
896 DEBUG(1,("%s: No primary group for sid=%s !?\n",
897 domain->name, sid_string_dbg(sid)));
901 sid_compose(&primary_group, &domain->sid, primary_group_rid);
903 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
905 /* there must always be at least one group in the token,
906 unless we are talking to a buggy Win2k server */
908 /* actually this only happens when the machine account has no read
909 * permissions on the tokenGroup attribute - gd */
915 /* lookup what groups this user is a member of by DN search on
918 status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
920 &num_groups, user_sids);
921 *p_num_groups = (uint32)num_groups;
922 if (NT_STATUS_IS_OK(status)) {
926 /* lookup what groups this user is a member of by DN search on
929 status = lookup_usergroups_member(domain, mem_ctx, user_dn,
931 &num_groups, user_sids);
932 *p_num_groups = (uint32)num_groups;
939 status = add_sid_to_array(mem_ctx, &primary_group, user_sids,
941 if (!NT_STATUS_IS_OK(status)) {
945 for (i=0;i<count;i++) {
947 /* ignore Builtin groups from ADS - Guenther */
948 if (sid_check_is_in_builtin(&sids[i])) {
952 status = add_sid_to_array_unique(mem_ctx, &sids[i],
953 user_sids, &num_groups);
954 if (!NT_STATUS_IS_OK(status)) {
959 *p_num_groups = (uint32)num_groups;
960 status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
962 DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
963 sid_string_dbg(sid)));
965 TALLOC_FREE(user_dn);
966 ads_msgfree(ads, msg);
970 /* Lookup aliases a user is member of - use rpc methods */
971 static NTSTATUS lookup_useraliases(struct winbindd_domain *domain,
973 uint32 num_sids, const struct dom_sid *sids,
974 uint32 *num_aliases, uint32 **alias_rids)
976 return reconnect_methods.lookup_useraliases(domain, mem_ctx,
983 find the members of a group, given a group rid and domain
985 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
987 const struct dom_sid *group_sid,
988 enum lsa_SidType type,
990 struct dom_sid **sid_mem, char ***names,
994 ADS_STRUCT *ads = NULL;
996 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
998 char **members = NULL;
1000 size_t num_members = 0;
1002 struct dom_sid *sid_mem_nocache = NULL;
1003 char **names_nocache = NULL;
1004 enum lsa_SidType *name_types_nocache = NULL;
1005 char **domains_nocache = NULL; /* only needed for rpccli_lsa_lookup_sids */
1006 uint32 num_nocache = 0;
1007 TALLOC_CTX *tmp_ctx = NULL;
1009 DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
1010 sid_string_dbg(group_sid)));
1014 tmp_ctx = talloc_new(mem_ctx);
1016 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1017 status = NT_STATUS_NO_MEMORY;
1021 if ( !winbindd_can_contact_domain( domain ) ) {
1022 DEBUG(10,("lookup_groupmem: No incoming trust for domain %s\n",
1024 return NT_STATUS_OK;
1027 ads = ads_cached_connection(domain);
1030 domain->last_status = NT_STATUS_SERVER_DISABLED;
1034 if ((sidbinstr = sid_binstring(talloc_tos(), group_sid)) == NULL) {
1035 status = NT_STATUS_NO_MEMORY;
1039 /* search for all members of the group */
1040 ldap_exp = talloc_asprintf(tmp_ctx, "(objectSid=%s)", sidbinstr);
1041 TALLOC_FREE(sidbinstr);
1042 if (ldap_exp == NULL) {
1043 DEBUG(1, ("ads: lookup_groupmem: talloc_asprintf for ldap_exp failed!\n"));
1044 status = NT_STATUS_NO_MEMORY;
1048 args.control = ADS_EXTENDED_DN_OID;
1049 args.val = ADS_EXTENDED_DN_HEX_STRING;
1050 args.critical = True;
1052 rc = ads_ranged_search(ads, tmp_ctx, LDAP_SCOPE_SUBTREE, ads->config.bind_path,
1053 ldap_exp, &args, "member", &members, &num_members);
1055 if (!ADS_ERR_OK(rc)) {
1056 DEBUG(0,("ads_ranged_search failed with: %s\n", ads_errstr(rc)));
1057 status = NT_STATUS_UNSUCCESSFUL;
1061 DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
1063 /* Now that we have a list of sids, we need to get the
1064 * lists of names and name_types belonging to these sids.
1065 * even though conceptually not quite clean, we use the
1066 * RPC call lsa_lookup_sids for this since it can handle a
1067 * list of sids. ldap calls can just resolve one sid at a time.
1069 * At this stage, the sids are still hidden in the exetended dn
1070 * member output format. We actually do a little better than
1071 * stated above: In extracting the sids from the member strings,
1072 * we try to resolve as many sids as possible from the
1073 * cache. Only the rest is passed to the lsa_lookup_sids call. */
1076 (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, struct dom_sid, num_members);
1077 (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
1078 (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
1079 (sid_mem_nocache) = TALLOC_ZERO_ARRAY(tmp_ctx, struct dom_sid, num_members);
1081 if ((members == NULL) || (*sid_mem == NULL) ||
1082 (*names == NULL) || (*name_types == NULL) ||
1083 (sid_mem_nocache == NULL))
1085 DEBUG(1, ("ads: lookup_groupmem: talloc failed\n"));
1086 status = NT_STATUS_NO_MEMORY;
1093 (*name_types) = NULL;
1096 for (i=0; i<num_members; i++) {
1097 enum lsa_SidType name_type;
1098 char *name, *domain_name;
1101 rc = ads_get_sid_from_extended_dn(tmp_ctx, members[i], args.val,
1103 if (!ADS_ERR_OK(rc)) {
1104 if (NT_STATUS_EQUAL(ads_ntstatus(rc),
1105 NT_STATUS_NOT_FOUND)) {
1106 /* Group members can be objects, like Exchange
1107 * Public Folders, that don't have a SID. Skip
1112 status = ads_ntstatus(rc);
1116 if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
1118 DEBUG(10,("ads: lookup_groupmem: got sid %s from "
1119 "cache\n", sid_string_dbg(&sid)));
1120 sid_copy(&(*sid_mem)[*num_names], &sid);
1121 (*names)[*num_names] = fill_domain_username_talloc(
1127 (*name_types)[*num_names] = name_type;
1131 DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
1132 "cache\n", sid_string_dbg(&sid)));
1133 sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
1138 DEBUG(10, ("ads: lookup_groupmem: %d sids found in cache, "
1139 "%d left for lsa_lookupsids\n", *num_names, num_nocache));
1141 /* handle sids not resolved from cache by lsa_lookup_sids */
1142 if (num_nocache > 0) {
1144 status = winbindd_lookup_sids(tmp_ctx,
1150 &name_types_nocache);
1152 if (!(NT_STATUS_IS_OK(status) ||
1153 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED) ||
1154 NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)))
1156 DEBUG(1, ("lsa_lookupsids call failed with %s "
1157 "- retrying...\n", nt_errstr(status)));
1159 status = winbindd_lookup_sids(tmp_ctx,
1165 &name_types_nocache);
1168 if (NT_STATUS_IS_OK(status) ||
1169 NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED))
1171 /* Copy the entries over from the "_nocache" arrays
1172 * to the result arrays, skipping the gaps the
1173 * lookup_sids call left. */
1174 for (i=0; i < num_nocache; i++) {
1175 if (((names_nocache)[i] != NULL) &&
1176 ((name_types_nocache)[i] != SID_NAME_UNKNOWN))
1178 sid_copy(&(*sid_mem)[*num_names],
1179 &sid_mem_nocache[i]);
1180 (*names)[*num_names] =
1181 fill_domain_username_talloc(
1186 (*name_types)[*num_names] = name_types_nocache[i];
1191 else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
1192 DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
1193 "not map any SIDs at all.\n"));
1194 /* Don't handle this as an error here.
1195 * There is nothing left to do with respect to the
1196 * overall result... */
1198 else if (!NT_STATUS_IS_OK(status)) {
1199 DEBUG(10, ("lookup_groupmem: Error looking up %d "
1200 "sids via rpc_lsa_lookup_sids: %s\n",
1201 (int)num_members, nt_errstr(status)));
1206 status = NT_STATUS_OK;
1207 DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
1208 sid_string_dbg(group_sid)));
1212 TALLOC_FREE(tmp_ctx);
1217 /* find the sequence number for a domain */
1218 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
1220 ADS_STRUCT *ads = NULL;
1223 DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
1225 if ( !winbindd_can_contact_domain( domain ) ) {
1226 DEBUG(10,("sequence: No incoming trust for domain %s\n",
1229 return NT_STATUS_OK;
1232 *seq = DOM_SEQUENCE_NONE;
1234 ads = ads_cached_connection(domain);
1237 domain->last_status = NT_STATUS_SERVER_DISABLED;
1238 return NT_STATUS_UNSUCCESSFUL;
1241 rc = ads_USN(ads, seq);
1243 if (!ADS_ERR_OK(rc)) {
1245 /* its a dead connection, destroy it */
1247 if (domain->private_data) {
1248 ads = (ADS_STRUCT *)domain->private_data;
1249 ads->is_mine = True;
1251 ads_kdestroy("MEMORY:winbind_ccache");
1252 domain->private_data = NULL;
1255 return ads_ntstatus(rc);
1258 /* find the lockout policy of a domain - use rpc methods */
1259 static NTSTATUS lockout_policy(struct winbindd_domain *domain,
1260 TALLOC_CTX *mem_ctx,
1261 struct samr_DomInfo12 *policy)
1263 return reconnect_methods.lockout_policy(domain, mem_ctx, policy);
1266 /* find the password policy of a domain - use rpc methods */
1267 static NTSTATUS password_policy(struct winbindd_domain *domain,
1268 TALLOC_CTX *mem_ctx,
1269 struct samr_DomInfo1 *policy)
1271 return reconnect_methods.password_policy(domain, mem_ctx, policy);
1274 /* get a list of trusted domains */
1275 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
1276 TALLOC_CTX *mem_ctx,
1277 struct netr_DomainTrustList *trusts)
1279 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1282 struct rpc_pipe_client *cli;
1285 DEBUG(3,("ads: trusted_domains\n"));
1287 ZERO_STRUCTP(trusts);
1289 /* If this is our primary domain or a root in our forest,
1290 query for all trusts. If not, then just look for domain
1291 trusts in the target forest */
1293 if (domain->primary || domain_is_forest_root(domain)) {
1294 flags = NETR_TRUST_FLAG_OUTBOUND |
1295 NETR_TRUST_FLAG_INBOUND |
1296 NETR_TRUST_FLAG_IN_FOREST;
1298 flags = NETR_TRUST_FLAG_IN_FOREST;
1301 result = cm_connect_netlogon(domain, &cli);
1303 if (!NT_STATUS_IS_OK(result)) {
1304 DEBUG(5, ("trusted_domains: Could not open a connection to %s "
1305 "for PIPE_NETLOGON (%s)\n",
1306 domain->name, nt_errstr(result)));
1307 return NT_STATUS_UNSUCCESSFUL;
1310 result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
1315 if (!NT_STATUS_IS_OK(result)) {
1318 if (trusts->count == 0) {
1319 return NT_STATUS_OK;
1322 /* Copy across names and sids */
1325 for (i = 0; i < trusts->count; i++) {
1326 struct netr_DomainTrust *trust = &trusts->array[i];
1327 struct winbindd_domain d;
1332 * drop external trusts if this is not our primary
1333 * domain. This means that the returned number of
1334 * domains may be less that the ones actually trusted
1338 if ((trust->trust_attributes
1339 == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
1342 DEBUG(10,("trusted_domains: Skipping external trusted "
1343 "domain %s because it is outside of our "
1345 trust->netbios_name));
1349 /* add to the trusted domain cache */
1351 fstrcpy(d.name, trust->netbios_name);
1352 fstrcpy(d.alt_name, trust->dns_name);
1354 sid_copy(&d.sid, trust->sid);
1356 sid_copy(&d.sid, &global_sid_NULL);
1359 if ( domain->primary ) {
1360 DEBUG(10,("trusted_domains(ads): Searching "
1361 "trusted domain list of %s and storing "
1362 "trust flags for domain %s\n",
1363 domain->name, d.alt_name));
1365 d.domain_flags = trust->trust_flags;
1366 d.domain_type = trust->trust_type;
1367 d.domain_trust_attribs = trust->trust_attributes;
1369 wcache_tdc_add_domain( &d );
1371 } else if (domain_is_forest_root(domain)) {
1372 /* Check if we already have this record. If
1373 * we are following our forest root that is not
1374 * our primary domain, we want to keep trust
1375 * flags from the perspective of our primary
1376 * domain not our forest root. */
1377 struct winbindd_tdc_domain *exist = NULL;
1379 exist = wcache_tdc_fetch_domain(
1380 talloc_tos(), trust->netbios_name);
1382 DEBUG(10,("trusted_domains(ads): Searching "
1383 "trusted domain list of %s and "
1384 "storing trust flags for domain "
1385 "%s\n", domain->name, d.alt_name));
1386 d.domain_flags = trust->trust_flags;
1387 d.domain_type = trust->trust_type;
1388 d.domain_trust_attribs =
1389 trust->trust_attributes;
1391 wcache_tdc_add_domain( &d );
1396 /* This gets a little tricky. If we are
1397 following a transitive forest trust, then
1398 innerit the flags, type, and attribs from
1399 the domain we queried to make sure we don't
1400 record the view of the trust from the wrong
1401 side. Always view it from the side of our
1402 primary domain. --jerry */
1403 struct winbindd_tdc_domain *parent = NULL;
1405 DEBUG(10,("trusted_domains(ads): Searching "
1406 "trusted domain list of %s and inheriting "
1407 "trust flags for domain %s\n",
1408 domain->name, d.alt_name));
1410 parent = wcache_tdc_fetch_domain(talloc_tos(),
1413 d.domain_flags = parent->trust_flags;
1414 d.domain_type = parent->trust_type;
1415 d.domain_trust_attribs = parent->trust_attribs;
1417 d.domain_flags = domain->domain_flags;
1418 d.domain_type = domain->domain_type;
1419 d.domain_trust_attribs =
1420 domain->domain_trust_attribs;
1422 TALLOC_FREE(parent);
1424 wcache_tdc_add_domain( &d );
1431 /* the ADS backend methods are exposed via this structure */
1432 struct winbindd_methods ads_methods = {