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 %s after error %s\n",
65 ads->ldap_server, 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->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)
111 struct in_addr server_ip;
114 if (domain->private) {
115 return (ADS_STRUCT *)domain->private;
118 /* we don't want this to affect the users ccache */
119 ccache = lock_path("winbindd_ccache");
120 SETENV("KRB5CCNAME", ccache, 1);
123 if (resolve_name(domain->name, &server_ip, 0x1b)) {
124 sname = inet_ntoa(server_ip);
125 } else if (resolve_name(domain->name, &server_ip, 0x1c)) {
126 sname = inet_ntoa(server_ip);
128 if (strcasecmp(domain->name, lp_workgroup()) != 0) {
129 DEBUG(1,("can't find domain controller for %s\n", domain->name));
135 ads = ads_init(primary_realm, domain->name, NULL, NULL, NULL);
137 DEBUG(1,("ads_init for domain %s failed\n", domain->name));
141 /* the machine acct password might have change - fetch it every time */
142 SAFE_FREE(ads->password);
143 ads->password = secrets_fetch_machine_password();
145 status = ads_connect(ads);
146 if (!ADS_ERR_OK(status) || !ads->realm) {
147 extern struct winbindd_methods msrpc_methods;
148 DEBUG(1,("ads_connect for domain %s failed: %s\n",
149 domain->name, ads_errstr(status)));
152 /* if we get ECONNREFUSED then it might be a NT4
153 server, fall back to MSRPC */
154 if (status.error_type == ADS_ERROR_SYSTEM &&
155 status.rc == ECONNREFUSED) {
156 DEBUG(1,("Trying MSRPC methods\n"));
157 domain->methods = &msrpc_methods;
162 /* remember our primary realm for trusted domain support */
163 if (!primary_realm) {
164 primary_realm = strdup(ads->realm);
167 fstrcpy(domain->full_name, ads->server_realm);
169 domain->private = (void *)ads;
174 static void sid_from_rid(struct winbindd_domain *domain, uint32 rid, DOM_SID *sid)
176 sid_copy(sid, &domain->sid);
177 sid_append_rid(sid, rid);
180 /* turn a sAMAccountType into a SID_NAME_USE */
181 static enum SID_NAME_USE ads_atype_map(uint32 atype)
183 switch (atype & 0xF0000000) {
185 return SID_NAME_DOM_GRP;
187 return SID_NAME_USER;
189 DEBUG(1,("hmm, need to map account type 0x%x\n", atype));
191 return SID_NAME_UNKNOWN;
195 in order to support usernames longer than 21 characters we need to
196 use both the sAMAccountName and the userPrincipalName attributes
197 It seems that not all users have the userPrincipalName attribute set
199 static char *pull_username(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, void *msg)
203 ret = ads_pull_string(ads, mem_ctx, msg, "userPrincipalName");
204 if (ret && (p = strchr(ret, '@'))) {
208 return ads_pull_string(ads, mem_ctx, msg, "sAMAccountName");
212 /* Query display info for a realm. This is the basic user list fn */
213 static NTSTATUS query_user_list(struct winbindd_domain *domain,
216 WINBIND_USERINFO **info)
218 ADS_STRUCT *ads = NULL;
219 const char *attrs[] = {"userPrincipalName",
221 "name", "objectSid", "primaryGroupID",
222 "sAMAccountType", NULL};
227 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
231 DEBUG(3,("ads: query_user_list\n"));
233 ads = ads_cached_connection(domain);
236 rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
237 if (!ADS_ERR_OK(rc)) {
238 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
242 count = ads_count_replies(ads, res);
244 DEBUG(1,("query_user_list: No users found\n"));
248 (*info) = talloc_zero(mem_ctx, count * sizeof(**info));
250 status = NT_STATUS_NO_MEMORY;
256 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
262 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
263 ads_atype_map(atype) != SID_NAME_USER) {
264 DEBUG(1,("Not a user account? atype=0x%x\n", atype));
268 name = pull_username(ads, mem_ctx, msg);
269 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
270 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
271 DEBUG(1,("No sid for %s !?\n", name));
274 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
275 DEBUG(1,("No primary group for %s !?\n", name));
279 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
280 DEBUG(1,("No rid for %s !?\n", name));
284 (*info)[i].acct_name = name;
285 (*info)[i].full_name = gecos;
286 (*info)[i].user_rid = rid;
287 (*info)[i].group_rid = group;
292 status = NT_STATUS_OK;
294 DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
297 if (res) ads_msgfree(ads, res);
302 /* list all domain groups */
303 static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
306 struct acct_info **info)
308 ADS_STRUCT *ads = NULL;
309 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
311 "sAMAccountType", NULL};
316 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
320 DEBUG(3,("ads: enum_dom_groups\n"));
322 ads = ads_cached_connection(domain);
325 rc = ads_search_retry(ads, &res, "(objectCategory=group)", attrs);
326 if (!ADS_ERR_OK(rc)) {
327 DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
331 count = ads_count_replies(ads, res);
333 DEBUG(1,("enum_dom_groups: No groups found\n"));
337 (*info) = talloc_zero(mem_ctx, count * sizeof(**info));
339 status = NT_STATUS_NO_MEMORY;
345 for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
351 if (!ads_pull_uint32(ads, msg, "sAMAccountType",
353 !(account_type & ATYPE_GROUP)) continue;
355 name = pull_username(ads, mem_ctx, msg);
356 gecos = ads_pull_string(ads, mem_ctx, msg, "name");
357 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
358 DEBUG(1,("No sid for %s !?\n", name));
362 if (!sid_peek_check_rid(&domain->sid, &sid, &rid)) {
363 DEBUG(1,("No rid for %s !?\n", name));
367 fstrcpy((*info)[i].acct_name, name);
368 fstrcpy((*info)[i].acct_desc, gecos);
369 (*info)[i].rid = rid;
375 status = NT_STATUS_OK;
377 DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
380 if (res) ads_msgfree(ads, res);
386 /* convert a single name to a sid in a domain */
387 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
390 enum SID_NAME_USE *type)
392 ADS_STRUCT *ads = NULL;
393 const char *attrs[] = {"objectSid", "sAMAccountType", NULL};
399 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
401 DEBUG(3,("ads: name_to_sid\n"));
403 ads = ads_cached_connection(domain);
406 /* accept either the win2000 or the pre-win2000 username */
407 asprintf(&exp, "(|(sAMAccountName=%s)(userPrincipalName=%s@%s))",
408 name, name, ads->realm);
409 rc = ads_search_retry(ads, &res, exp, attrs);
411 if (!ADS_ERR_OK(rc)) {
412 DEBUG(1,("name_to_sid ads_search: %s\n", ads_errstr(rc)));
416 count = ads_count_replies(ads, res);
418 DEBUG(1,("name_to_sid: %s not found\n", name));
422 if (!ads_pull_sid(ads, res, "objectSid", sid)) {
423 DEBUG(1,("No sid for %s !?\n", name));
427 if (!ads_pull_uint32(ads, res, "sAMAccountType", &t)) {
428 DEBUG(1,("No sAMAccountType for %s !?\n", name));
432 *type = ads_atype_map(t);
434 status = NT_STATUS_OK;
436 DEBUG(3,("ads name_to_sid mapped %s\n", name));
439 if (res) ads_msgfree(ads, res);
444 /* convert a sid to a user or group name */
445 static NTSTATUS sid_to_name(struct winbindd_domain *domain,
449 enum SID_NAME_USE *type)
451 ADS_STRUCT *ads = NULL;
452 const char *attrs[] = {"userPrincipalName",
454 "sAMAccountType", NULL};
460 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
462 DEBUG(3,("ads: sid_to_name\n"));
464 ads = ads_cached_connection(domain);
467 sidstr = sid_binstring(sid);
468 asprintf(&exp, "(objectSid=%s)", sidstr);
469 rc = ads_search_retry(ads, &msg, exp, attrs);
472 if (!ADS_ERR_OK(rc)) {
473 DEBUG(1,("sid_to_name ads_search: %s\n", ads_errstr(rc)));
477 if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) {
481 *name = pull_username(ads, mem_ctx, msg);
482 *type = ads_atype_map(atype);
484 status = NT_STATUS_OK;
486 DEBUG(3,("ads sid_to_name mapped %s\n", *name));
489 if (msg) ads_msgfree(ads, msg);
495 /* convert a DN to a name, rid and name type
496 this might become a major speed bottleneck if groups have
497 lots of users, in which case we could cache the results
499 static BOOL dn_lookup(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx,
501 char **name, uint32 *name_type, uint32 *rid)
505 const char *attrs[] = {"userPrincipalName", "sAMAccountName",
506 "objectSid", "sAMAccountType", NULL};
511 asprintf(&exp, "(distinguishedName=%s)", dn);
512 rc = ads_search_retry(ads, &res, exp, attrs);
514 if (!ADS_ERR_OK(rc)) {
518 (*name) = pull_username(ads, mem_ctx, res);
520 if (!ads_pull_uint32(ads, res, "sAMAccountType", &atype)) {
523 (*name_type) = ads_atype_map(atype);
525 if (!ads_pull_sid(ads, res, "objectSid", &sid) ||
526 !sid_peek_rid(&sid, rid)) {
530 if (res) ads_msgfree(ads, res);
534 if (res) ads_msgfree(ads, res);
539 /* convert a sid to a distnguished name */
540 static NTSTATUS sid_to_distinguished_name(struct winbindd_domain *domain,
545 ADS_STRUCT *ads = NULL;
546 const char *attrs[] = {"distinguishedName", NULL};
551 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
553 DEBUG(3,("ads: sid_to_distinguished_name\n"));
555 ads = ads_cached_connection(domain);
558 sidstr = sid_binstring(sid);
559 asprintf(&exp, "(objectSid=%s)", sidstr);
560 rc = ads_search_retry(ads, &msg, exp, attrs);
563 if (!ADS_ERR_OK(rc)) {
564 DEBUG(1,("sid_to_distinguished_name ads_search: %s\n", ads_errstr(rc)));
568 *dn = ads_pull_string(ads, mem_ctx, msg, "distinguishedName");
570 status = NT_STATUS_OK;
572 DEBUG(3,("ads sid_to_distinguished_name mapped %s\n", *dn));
575 if (msg) ads_msgfree(ads, msg);
581 /* Lookup user information from a rid */
582 static NTSTATUS query_user(struct winbindd_domain *domain,
585 WINBIND_USERINFO *info)
587 ADS_STRUCT *ads = NULL;
588 const char *attrs[] = {"userPrincipalName",
591 "primaryGroupID", NULL};
598 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
600 DEBUG(3,("ads: query_user\n"));
602 sid_from_rid(domain, user_rid, &sid);
604 ads = ads_cached_connection(domain);
607 sidstr = sid_binstring(&sid);
608 asprintf(&exp, "(objectSid=%s)", sidstr);
609 rc = ads_search_retry(ads, &msg, exp, attrs);
612 if (!ADS_ERR_OK(rc)) {
613 DEBUG(1,("query_user(rid=%d) ads_search: %s\n", user_rid, ads_errstr(rc)));
617 count = ads_count_replies(ads, msg);
619 DEBUG(1,("query_user(rid=%d): Not found\n", user_rid));
623 info->acct_name = pull_username(ads, mem_ctx, msg);
624 info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
625 if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
626 DEBUG(1,("No sid for %d !?\n", user_rid));
629 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &info->group_rid)) {
630 DEBUG(1,("No primary group for %d !?\n", user_rid));
634 if (!sid_peek_check_rid(&domain->sid,&sid, &info->user_rid)) {
635 DEBUG(1,("No rid for %d !?\n", user_rid));
639 status = NT_STATUS_OK;
641 DEBUG(3,("ads query_user gave %s\n", info->acct_name));
643 if (msg) ads_msgfree(ads, msg);
649 /* Lookup groups a user is a member of. */
650 static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
653 uint32 *num_groups, uint32 **user_gids)
655 ADS_STRUCT *ads = NULL;
656 const char *attrs[] = {"distinguishedName", NULL};
657 const char *attrs2[] = {"tokenGroups", "primaryGroupID", NULL};
665 uint32 primary_group;
668 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
672 DEBUG(3,("ads: lookup_usergroups\n"));
676 sid_from_rid(domain, user_rid, &sid);
678 ads = ads_cached_connection(domain);
681 sidstr = sid_binstring(&sid);
682 asprintf(&exp, "(objectSid=%s)", sidstr);
683 rc = ads_search_retry(ads, &msg, exp, attrs);
686 if (!ADS_ERR_OK(rc)) {
687 DEBUG(1,("lookup_usergroups(rid=%d) ads_search: %s\n", user_rid, ads_errstr(rc)));
691 user_dn = ads_pull_string(ads, mem_ctx, msg, "distinguishedName");
693 if (msg) ads_msgfree(ads, msg);
695 rc = ads_search_retry_dn(ads, &msg, user_dn, attrs2);
696 if (!ADS_ERR_OK(rc)) {
697 DEBUG(1,("lookup_usergroups(rid=%d) ads_search tokenGroups: %s\n", user_rid, ads_errstr(rc)));
701 if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group)) {
702 DEBUG(1,("%s: No primary group for rid=%d !?\n", domain->name, user_rid));
706 count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids) + 1;
707 (*user_gids) = (uint32 *)talloc_zero(mem_ctx, sizeof(uint32) * count);
708 (*user_gids)[(*num_groups)++] = primary_group;
710 for (i=1;i<count;i++) {
712 if (!sid_peek_check_rid(&domain->sid, &sids[i-1], &rid)) continue;
713 (*user_gids)[*num_groups] = rid;
717 status = NT_STATUS_OK;
718 DEBUG(3,("ads lookup_usergroups for rid=%d\n", user_rid));
720 if (msg) ads_msgfree(ads, msg);
726 find the members of a group, given a group rid and domain
728 static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
730 uint32 group_rid, uint32 *num_names,
731 uint32 **rid_mem, char ***names,
738 ADS_STRUCT *ads = NULL;
740 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
742 const char *attrs[] = {"member", NULL};
748 ads = ads_cached_connection(domain);
751 sid_from_rid(domain, group_rid, &group_sid);
752 sidstr = sid_binstring(&group_sid);
754 /* search for all members of the group */
755 asprintf(&exp, "(objectSid=%s)",sidstr);
756 rc = ads_search_retry(ads, &res, exp, attrs);
760 if (!ADS_ERR_OK(rc)) {
761 DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
765 count = ads_count_replies(ads, res);
767 status = NT_STATUS_OK;
771 members = ads_pull_strings(ads, mem_ctx, res, "member");
773 /* no members? ok ... */
774 status = NT_STATUS_OK;
778 /* now we need to turn a list of members into rids, names and name types
779 the problem is that the members are in the form of distinguised names
781 for (i=0;members[i];i++) /* noop */ ;
784 (*rid_mem) = talloc_zero(mem_ctx, sizeof(uint32) * num_members);
785 (*name_types) = talloc_zero(mem_ctx, sizeof(uint32) * num_members);
786 (*names) = talloc_zero(mem_ctx, sizeof(char *) * num_members);
788 for (i=0;i<num_members;i++) {
789 uint32 name_type, rid;
792 if (dn_lookup(ads, mem_ctx, members[i], &name, &name_type, &rid)) {
793 (*names)[*num_names] = name;
794 (*name_types)[*num_names] = name_type;
795 (*rid_mem)[*num_names] = rid;
800 status = NT_STATUS_OK;
801 DEBUG(3,("ads lookup_groupmem for rid=%d\n", group_rid));
803 if (res) ads_msgfree(ads, res);
809 /* find the sequence number for a domain */
810 static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32 *seq)
812 ADS_STRUCT *ads = NULL;
815 *seq = DOM_SEQUENCE_NONE;
817 ads = ads_cached_connection(domain);
818 if (!ads) return NT_STATUS_UNSUCCESSFUL;
820 rc = ads_USN(ads, seq);
821 if (!ADS_ERR_OK(rc)) {
822 /* its a dead connection */
824 domain->private = NULL;
826 return ads_ntstatus(rc);
829 /* get a list of trusted domains */
830 static NTSTATUS trusted_domains(struct winbindd_domain *domain,
842 ads = ads_cached_connection(domain);
843 if (!ads) return NT_STATUS_UNSUCCESSFUL;
845 rc = ads_trusted_domains(ads, mem_ctx, num_domains, names, dom_sids);
847 return ads_ntstatus(rc);
850 /* find the domain sid for a domain */
851 static NTSTATUS domain_sid(struct winbindd_domain *domain, DOM_SID *sid)
856 ads = ads_cached_connection(domain);
857 if (!ads) return NT_STATUS_UNSUCCESSFUL;
859 rc = ads_domain_sid(ads, sid);
861 if (!ADS_ERR_OK(rc)) {
862 /* its a dead connection */
864 domain->private = NULL;
867 return ads_ntstatus(rc);
870 /* the ADS backend methods are exposed via this structure */
871 struct winbindd_methods ads_methods = {