2 Unix SMB/CIFS implementation.
4 Winbind ADS backend functions
6 Copyright (C) Andrew Tridgell 2001
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #define DBGC_CLASS DBGC_WINBIND
30 /* the realm of our primary LDAP server */
31 static char *primary_realm;
35 a wrapper around ldap_search_s that retries depending on the error code
36 this is supposed to catch dropped connections and auto-reconnect
38 ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope,
40 const char **attrs, void **res)
47 time(NULL) - ads->last_attempt < ADS_RECONNECT_TIME) {
48 return ADS_ERROR(LDAP_SERVER_DOWN);
51 bp = strdup(bind_path);
54 status = ads_do_search_all(ads, bp, scope, exp, attrs, res);
55 if (ADS_ERR_OK(status)) {
56 DEBUG(5,("Search for %s gave %d replies\n",
57 exp, ads_count_replies(ads, *res)));
62 if (*res) ads_msgfree(ads, *res);
64 DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n",
65 ads->config.realm, ads_errstr(status)));
70 status = ads_connect(ads);
71 if (!ADS_ERR_OK(status)) {
72 DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n",
81 DEBUG(1,("ads reopen failed after error %s\n", ads_errstr(status)));
86 ADS_STATUS ads_search_retry(ADS_STRUCT *ads, void **res,
90 return ads_do_search_retry(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE,
94 ADS_STATUS ads_search_retry_dn(ADS_STRUCT *ads, void **res,
98 return ads_do_search_retry(ads, dn, LDAP_SCOPE_BASE,
99 "(objectclass=*)", attrs, res);
103 return our ads connections structure for a domain. We keep the connection
104 open to make things faster
106 static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
112 if (domain->private) {
113 return (ADS_STRUCT *)domain->private;
116 /* we don't want this to affect the users ccache */
117 ccache = lock_path("winbindd_ccache");
118 SETENV("KRB5CCNAME", ccache, 1);
121 ads = ads_init(domain->alt_name, domain->name, NULL);
123 DEBUG(1,("ads_init for domain %s failed\n", domain->name));
127 /* the machine acct password might have change - fetch it every time */
128 SAFE_FREE(ads->auth.password);
129 ads->auth.password = secrets_fetch_machine_password();
132 SAFE_FREE(ads->auth.realm);
133 ads->auth.realm = strdup(primary_realm);
136 status = ads_connect(ads);
137 if (!ADS_ERR_OK(status) || !ads->config.realm) {
138 extern struct winbindd_methods msrpc_methods;
139 DEBUG(1,("ads_connect for domain %s failed: %s\n",
140 domain->name, ads_errstr(status)));
143 /* if we get ECONNREFUSED then it might be a NT4
144 server, fall back to MSRPC */
145 if (status.error_type == ADS_ERROR_SYSTEM &&
146 status.rc == ECONNREFUSED) {
147 DEBUG(1,("Trying MSRPC methods\n"));
148 domain->methods = &msrpc_methods;
153 /* remember our primary realm for trusted domain support */
154 if (!primary_realm) {
155 primary_realm = strdup(ads->config.realm);
158 domain->private = (void *)ads;
163 static void sid_from_rid(struct winbindd_domain *domain, uint32 rid, DOM_SID *sid)
165 sid_copy(sid, &domain->sid);
166 sid_append_rid(sid, rid);
169 /* turn a sAMAccountType into a SID_NAME_USE */
170 static enum SID_NAME_USE ads_atype_map(uint32 atype)
172 switch (atype & 0xF0000000) {
174 return SID_NAME_DOM_GRP;
176 return SID_NAME_USER;
178 DEBUG(1,("hmm, need to map account type 0x%x\n", atype));
180 return SID_NAME_UNKNOWN;
184 in order to support usernames longer than 21 characters we need to
185 use both the sAMAccountName and the userPrincipalName attributes
186 It seems that not all users have the userPrincipalName attribute set
188 static char *pull_username(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, void *msg)
192 ret = ads_pull_string(ads, mem_ctx, msg, "userPrincipalName");
193 if (ret && (p = strchr(ret, '@'))) {
197 return ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
201 /* Query display info for a realm. This is the basic user list fn */
202 static NTSTATUS query_user_list(struct winbindd_domain *domain,
205 WINBIND_USERINFO **info)
207 ADS_STRUCT *ads = NULL;
208 const char *attrs[] = {"userPrincipalName",
210 "name", "objectSid", "primaryGroupID",
211 "sAMAccountType", NULL};
216 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
220 DEBUG(3,("ads: query_user_list\n"));
222 ads = ads_cached_connection(domain);
225 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
226 if (!ADS_ERR_OK(rc)) {
227 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
231 count = ads_count_replies(ads, res);
233 DEBUG(1,("query_user_list: No users found\n"));
237 (*info) = talloc_zero(mem_ctx, count * sizeof(**info));
239 status = NT_STATUS_NO_MEMORY;
245 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
251 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
252 ads_atype_map(atype) != SID_NAME_USER) {
253 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
257 name = pull_username(ads, mem_ctx, msg);
258 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
259 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
260 DEBUG(1,("No sid for %s !?\n", name));
263 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
264 DEBUG(1,("No primary group for %s !?\n", name));
268 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
269 DEBUG(1,("No rid for %s !?\n", name));
273 (*info)[i].acct_name = name;
274 (*info)[i].full_name = gecos;
275 (*info)[i].user_rid = rid;
276 (*info)[i].group_rid = group;
281 status = NT_STATUS_OK;
283 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
286 if (res) ads_msgfree(ads, res);
291 /* list all domain groups */
292 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
295 struct acct_info **info)
297 ADS_STRUCT *ads = NULL;
298 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
300 "sAMAccountType", NULL};
305 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
309 DEBUG(3,("ads: enum_dom_groups\n"));
311 ads = ads_cached_connection(domain);
314 rc = ads_search_retry(ads, &res, "(objectCategory=group)", attrs);
315 if (!ADS_ERR_OK(rc)) {
316 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
320 count = ads_count_replies(ads, res);
322 DEBUG(1,("enum_dom_groups: No groups found\n"));
326 (*info) = talloc_zero(mem_ctx, count * sizeof(**info));
328 status = NT_STATUS_NO_MEMORY;
334 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
340 if (!ads_pull_uint32(ads, msg, "sAMAccountType",
342 !(account_type & ATYPE_GROUP)) continue;
344 name = pull_username(ads, mem_ctx, msg);
345 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
346 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
347 DEBUG(1,("No sid for %s !?\n", name));
351 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
352 DEBUG(1,("No rid for %s !?\n", name));
356 fstrcpy((*info)[i].acct_name, name);
357 fstrcpy((*info)[i].acct_desc, gecos);
358 (*info)[i].rid = rid;
364 status = NT_STATUS_OK;
366 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
369 if (res) ads_msgfree(ads, res);
375 /* convert a single name to a sid in a domain */
376 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
379 enum SID_NAME_USE *type)
381 ADS_STRUCT *ads = NULL;
382 const char *attrs[] = {"objectSid", "sAMAccountType", NULL};
388 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
390 DEBUG(3,("ads: name_to_sid\n"));
392 ads = ads_cached_connection(domain);
395 /* accept either the win2000 or the pre-win2000 username */
396 asprintf(&exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))",
397 name, name, ads->config.realm);
398 rc = ads_search_retry(ads, &res, exp, attrs);
400 if (!ADS_ERR_OK(rc)) {
401 DEBUG(1,("name_to_sid ads_search: %s\n", ads_errstr(rc)));
405 count = ads_count_replies(ads, res);
407 DEBUG(1,("name_to_sid: %s not found\n", name));
411 if (!ads_pull_sid(ads, res, "objectSid", sid)) {
412 DEBUG(1,("No sid for %s !?\n", name));
416 if (!ads_pull_uint32(ads, res, "sAMAccountType", &t)) {
417 DEBUG(1,("No sAMAccountType for %s !?\n", name));
421 *type = ads_atype_map(t);
423 status = NT_STATUS_OK;
425 DEBUG(3,("ads name_to_sid mapped %s\n", name));
428 if (res) ads_msgfree(ads, res);
433 /* convert a sid to a user or group name */
434 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
438 enum SID_NAME_USE *type)
440 ADS_STRUCT *ads = NULL;
441 const char *attrs[] = {"userPrincipalName",
443 "sAMAccountType", NULL};
449 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
451 DEBUG(3,("ads: sid_to_name\n"));
453 ads = ads_cached_connection(domain);
456 sidstr = sid_binstring(sid);
457 asprintf(&exp, "(objectSid=%s)", sidstr);
458 rc = ads_search_retry(ads, &msg, exp, attrs);
461 if (!ADS_ERR_OK(rc)) {
462 DEBUG(1,("sid_to_name ads_search: %s\n", ads_errstr(rc)));
466 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) {
470 *name = pull_username(ads, mem_ctx, msg);
471 *type = ads_atype_map(atype);
473 status = NT_STATUS_OK;
475 DEBUG(3,("ads sid_to_name mapped %s\n", *name));
478 if (msg) ads_msgfree(ads, msg);
484 /* convert a DN to a name, rid and name type
485 this might become a major speed bottleneck if groups have
486 lots of users, in which case we could cache the results
488 static BOOL dn_lookup(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
490 char **name, uint32 *name_type, uint32 *rid)
494 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
495 "objectSid", "sAMAccountType", NULL};
500 asprintf(&exp, "(distinguishedName=%s)", dn);
501 rc = ads_search_retry(ads, &res, exp, attrs);
503 if (!ADS_ERR_OK(rc)) {
507 (*name) = pull_username(ads, mem_ctx, res);
509 if (!ads_pull_uint32(ads, res, "sAMAccountType", &atype)) {
512 (*name_type) = ads_atype_map(atype);
514 if (!ads_pull_sid(ads, res, "objectSid", &sid) ||
515 !sid_peek_rid(&sid, rid)) {
519 if (res) ads_msgfree(ads, res);
523 if (res) ads_msgfree(ads, res);
527 /* Lookup user information from a rid */
528 static NTSTATUS query_user(struct winbindd_domain *domain,
531 WINBIND_USERINFO *info)
533 ADS_STRUCT *ads = NULL;
534 const char *attrs[] = {"userPrincipalName",
537 "primaryGroupID", NULL};
544 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
546 DEBUG(3,("ads: query_user\n"));
548 sid_from_rid(domain, user_rid, &sid);
550 ads = ads_cached_connection(domain);
553 sidstr = sid_binstring(&sid);
554 asprintf(&exp, "(objectSid=%s)", sidstr);
555 rc = ads_search_retry(ads, &msg, exp, attrs);
558 if (!ADS_ERR_OK(rc)) {
559 DEBUG(1,("query_user(rid=%d) ads_search: %s\n", user_rid, ads_errstr(rc)));
563 count = ads_count_replies(ads, msg);
565 DEBUG(1,("query_user(rid=%d): Not found\n", user_rid));
569 info->acct_name = pull_username(ads, mem_ctx, msg);
570 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
571 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
572 DEBUG(1,("No sid for %d !?\n", user_rid));
575 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &info->group_rid)) {
576 DEBUG(1,("No primary group for %d !?\n", user_rid));
580 if (!sid_peek_check_rid(&domain->sid,&sid, &info->user_rid)) {
581 DEBUG(1,("No rid for %d !?\n", user_rid));
585 status = NT_STATUS_OK;
587 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
589 if (msg) ads_msgfree(ads, msg);
595 /* Lookup groups a user is a member of. */
596 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
599 uint32 *num_groups, uint32 **user_gids)
601 ADS_STRUCT *ads = NULL;
602 const char *attrs[] = {"distinguishedName", NULL};
603 const char *attrs2[] = {"tokenGroups", "primaryGroupID", NULL};
611 uint32 primary_group;
614 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
618 DEBUG(3,("ads: lookup_usergroups\n"));
622 sid_from_rid(domain, user_rid, &sid);
624 ads = ads_cached_connection(domain);
627 sidstr = sid_binstring(&sid);
628 asprintf(&exp, "(objectSid=%s)", sidstr);
629 rc = ads_search_retry(ads, &msg, exp, attrs);
632 if (!ADS_ERR_OK(rc)) {
633 DEBUG(1,("lookup_usergroups(rid=%d) ads_search: %s\n", user_rid, ads_errstr(rc)));
637 user_dn = ads_pull_string(ads, mem_ctx, msg, "distinguishedName");
639 if (msg) ads_msgfree(ads, msg);
641 rc = ads_search_retry_dn(ads, &msg, user_dn, attrs2);
642 if (!ADS_ERR_OK(rc)) {
643 DEBUG(1,("lookup_usergroups(rid=%d) ads_search tokenGroups: %s\n", user_rid, ads_errstr(rc)));
647 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group)) {
648 DEBUG(1,("%s: No primary group for rid=%d !?\n", domain->name, user_rid));
652 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids) + 1;
653 (*user_gids) = (uint32 *)talloc_zero(mem_ctx, sizeof(uint32) * count);
654 (*user_gids)[(*num_groups)++] = primary_group;
656 for (i=1;i<count;i++) {
658 if (!sid_peek_check_rid(&domain->sid, &sids[i-1], &rid)) continue;
659 (*user_gids)[*num_groups] = rid;
663 status = NT_STATUS_OK;
664 DEBUG(3,("ads lookup_usergroups for rid=%d\n", user_rid));
666 if (msg) ads_msgfree(ads, msg);
672 find the members of a group, given a group rid and domain
674 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
676 uint32 group_rid, uint32 *num_names,
677 uint32 **rid_mem, char ***names,
684 ADS_STRUCT *ads = NULL;
686 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
688 const char *attrs[] = {"member", NULL};
694 ads = ads_cached_connection(domain);
697 sid_from_rid(domain, group_rid, &group_sid);
698 sidstr = sid_binstring(&group_sid);
700 /* search for all members of the group */
701 asprintf(&exp, "(objectSid=%s)",sidstr);
702 rc = ads_search_retry(ads, &res, exp, attrs);
706 if (!ADS_ERR_OK(rc)) {
707 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
711 count = ads_count_replies(ads, res);
713 status = NT_STATUS_OK;
717 members = ads_pull_strings(ads, mem_ctx, res, "member");
719 /* no members? ok ... */
720 status = NT_STATUS_OK;
724 /* now we need to turn a list of members into rids, names and name types
725 the problem is that the members are in the form of distinguised names
727 for (i=0;members[i];i++) /* noop */ ;
730 (*rid_mem) = talloc_zero(mem_ctx, sizeof(uint32) * num_members);
731 (*name_types) = talloc_zero(mem_ctx, sizeof(uint32) * num_members);
732 (*names) = talloc_zero(mem_ctx, sizeof(char *) * num_members);
734 for (i=0;i<num_members;i++) {
735 uint32 name_type, rid;
738 if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &rid)) {
739 (*names)[*num_names] = name;
740 (*name_types)[*num_names] = name_type;
741 (*rid_mem)[*num_names] = rid;
746 status = NT_STATUS_OK;
747 DEBUG(3,("ads lookup_groupmem for rid=%d\n", group_rid));
749 if (res) ads_msgfree(ads, res);
755 /* find the sequence number for a domain */
756 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
758 ADS_STRUCT *ads = NULL;
761 *seq = DOM_SEQUENCE_NONE;
763 ads = ads_cached_connection(domain);
764 if (!ads) return NT_STATUS_UNSUCCESSFUL;
766 rc = ads_USN(ads, seq);
767 if (!ADS_ERR_OK(rc)) {
768 /* its a dead connection */
770 domain->private = NULL;
772 return ads_ntstatus(rc);
775 /* get a list of trusted domains */
776 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
789 ads = ads_cached_connection(domain);
790 if (!ads) return NT_STATUS_UNSUCCESSFUL;
792 rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, alt_names, dom_sids);
794 return ads_ntstatus(rc);
797 /* find the domain sid for a domain */
798 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
803 ads = ads_cached_connection(domain);
804 if (!ads) return NT_STATUS_UNSUCCESSFUL;
806 rc = ads_domain_sid(ads, sid);
808 if (!ADS_ERR_OK(rc)) {
809 /* its a dead connection */
811 domain->private = NULL;
814 return ads_ntstatus(rc);
818 /* find alternate names list for the domain - for ADS this is the
820 static NTSTATUS alternate_name(struct winbindd_domain *domain)
827 ads = ads_cached_connection(domain);
828 if (!ads) return NT_STATUS_UNSUCCESSFUL;
830 if (!(ctx = talloc_init_named("alternate_name"))) {
831 return NT_STATUS_NO_MEMORY;
834 rc = ads_workgroup_name(ads, ctx, &workgroup);
836 if (ADS_ERR_OK(rc)) {
837 fstrcpy(domain->name, workgroup);
838 fstrcpy(domain->alt_name, ads->config.realm);
839 strupper(domain->alt_name);
840 strupper(domain->name);
845 return ads_ntstatus(rc);
848 /* the ADS backend methods are exposed via this structure */
849 struct winbindd_methods ads_methods = {