#include "includes.h"
#include "winbindd.h"
+#include "winbindd_ads.h"
+#include "libsmb/namequery.h"
#include "rpc_client/rpc_client.h"
#include "../librpc/gen_ndr/ndr_netlogon_c.h"
#include "../libds/common/flags.h"
#include "../libds/common/flag_mapping.h"
#include "libsmb/samlogon_cache.h"
#include "passdb.h"
+#include "auth/credentials/credentials.h"
#ifdef HAVE_ADS
extern struct winbindd_methods reconnect_methods;
extern struct winbindd_methods msrpc_methods;
-#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
-
/**
* Check if cached connection can be reused. If the connection cannot
* be reused the ADS_STRUCT is freed and the pointer is set to NULL.
time_t expire;
time_t now = time(NULL);
- expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
+ expire = nt_time_to_unix(ads->auth.expire_time);
DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
"is now %d)\n", (uint32_t)expire - (uint32_t)now,
return;
} else {
/* we own this ADS_STRUCT so make sure it goes away */
- DEBUG(7,("Deleting expired krb5 credential cache\n"));
- ads->is_mine = True;
- ads_destroy( &ads );
- ads_kdestroy(WINBIND_CCACHE_NAME);
+ DEBUG(7,("Deleting expired ads struct\n"));
+ TALLOC_FREE(ads);
*adsp = NULL;
}
}
}
+
+static NTSTATUS ads_cached_connection_reconnect_creds(struct ads_struct *ads,
+ void *private_data,
+ TALLOC_CTX *mem_ctx,
+ struct cli_credentials **creds)
+{
+ struct winbindd_domain *target_domain = NULL;
+
+ if (ads->server.realm != NULL) {
+ target_domain = find_domain_from_name_noinit(ads->server.realm);
+ }
+ if (target_domain == NULL && ads->server.workgroup != NULL) {
+ target_domain = find_domain_from_name_noinit(ads->server.workgroup);
+ }
+
+ if (target_domain == NULL) {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ return winbindd_get_trust_credentials(target_domain,
+ mem_ctx,
+ false, /* netlogon */
+ false, /* ipc_fallback */
+ creds);
+}
+
/**
* @brief Establish a connection to a DC
*
* @param[out] adsp ADS_STRUCT that will be created
- * @param[in] target_realm Realm of domain to connect to
- * @param[in] target_dom_name 'workgroup' name of domain to connect to
+ * @param[in] target_domain target domain
* @param[in] ldap_server DNS name of server to connect to
- * @param[in] password Our machine acount secret
+ * @param[in] creds credentials to use
* @param[in] auth_realm Realm of local domain for creating krb token
- * @param[in] renewable Renewable ticket time
*
* @return ADS_STATUS
*/
-static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
- const char *target_realm,
- const char *target_dom_name,
+static ADS_STATUS ads_cached_connection_connect(struct winbindd_domain *target_domain,
const char *ldap_server,
- char *password,
- char *auth_realm,
- time_t renewable)
+ TALLOC_CTX *mem_ctx,
+ ADS_STRUCT **adsp)
{
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ const char *target_realm = target_domain->alt_name;
+ const char *target_dom_name = target_domain->name;
+ struct cli_credentials *creds = NULL;
ADS_STRUCT *ads;
ADS_STATUS status;
+ NTSTATUS ntstatus;
struct sockaddr_storage dc_ss;
fstring dc_name;
- if (auth_realm == NULL) {
- return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
- }
-
- /* we don't want this to affect the users ccache */
- setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
+ /* the machine acct password might have change - fetch it every time */
- ads = ads_init(target_realm, target_dom_name, ldap_server);
+ ntstatus = winbindd_get_trust_credentials(target_domain,
+ tmp_ctx,
+ false, /* netlogon */
+ false, /* ipc_fallback */
+ &creds);
+ if (!NT_STATUS_IS_OK(ntstatus)) {
+ status = ADS_ERROR_NT(ntstatus);
+ goto out;
+ }
+
+ ads = ads_init(tmp_ctx,
+ target_realm,
+ target_dom_name,
+ ldap_server,
+ ADS_SASL_SEAL);
if (!ads) {
DEBUG(1,("ads_init for domain %s failed\n", target_dom_name));
- return ADS_ERROR(LDAP_NO_MEMORY);
+ status = ADS_ERROR(LDAP_NO_MEMORY);
+ goto out;
}
- SAFE_FREE(ads->auth.password);
- SAFE_FREE(ads->auth.realm);
-
- ads->auth.renewable = renewable;
- ads->auth.password = password;
-
- ads->auth.realm = SMB_STRDUP(auth_realm);
- if (!strupper_m(ads->auth.realm)) {
- ads_destroy(&ads);
- return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
- }
+ ads_set_reconnect_fn(ads, ads_cached_connection_reconnect_creds, NULL);
/* Setup the server affinity cache. We don't reaally care
about the name. Just setup affinity and the KRB5_CONFIG
file. */
get_dc_name(ads->server.workgroup, ads->server.realm, dc_name, &dc_ss);
- status = ads_connect(ads);
+ status = ads_connect_creds(ads, creds);
if (!ADS_ERR_OK(status)) {
DEBUG(1,("ads_connect for domain %s failed: %s\n",
target_dom_name, ads_errstr(status)));
- ads_destroy(&ads);
- return status;
+ goto out;
}
- /* set the flag that says we don't own the memory even
- though we do so that ads_destroy() won't destroy the
- structure we pass back by reference */
-
- ads->is_mine = False;
-
- *adsp = ads;
-
+ *adsp = talloc_move(mem_ctx, &ads);
+out:
+ TALLOC_FREE(tmp_ctx);
return status;
}
-ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name)
+ADS_STATUS ads_idmap_cached_connection(const char *dom_name,
+ TALLOC_CTX *mem_ctx,
+ ADS_STRUCT **adsp)
{
- char *ldap_server, *realm, *password;
- struct winbindd_domain *wb_dom;
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
+ char *ldap_server = NULL;
+ struct winbindd_domain *wb_dom = NULL;
ADS_STATUS status;
+ if (IS_AD_DC) {
+ /*
+ * Make sure we never try to use LDAP against
+ * a trusted domain as AD DC.
+ */
+ TALLOC_FREE(tmp_ctx);
+ return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
+ }
+
ads_cached_connection_reuse(adsp);
if (*adsp != NULL) {
+ TALLOC_FREE(tmp_ctx);
return ADS_SUCCESS;
}
/*
* At this point we only have the NetBIOS domain name.
- * Check if we can get server nam and realm from SAF cache
+ * Check if we can get server name and realm from SAF cache
* and the domain list.
*/
- ldap_server = saf_fetch(talloc_tos(), dom_name);
- DEBUG(10, ("ldap_server from saf cache: '%s'\n",
- ldap_server ? ldap_server : ""));
+ ldap_server = saf_fetch(tmp_ctx, dom_name);
+
+ DBG_DEBUG("ldap_server from saf cache: '%s'\n",
+ ldap_server ? ldap_server : "");
wb_dom = find_domain_from_name(dom_name);
if (wb_dom == NULL) {
- DEBUG(10, ("could not find domain '%s'\n", dom_name));
+ DBG_DEBUG("could not find domain '%s'\n", dom_name);
+ TALLOC_FREE(tmp_ctx);
return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
}
- DEBUG(10, ("find_domain_from_name found realm '%s' for "
- " domain '%s'\n", wb_dom->alt_name, dom_name));
-
- if (!get_trust_pw_clear(dom_name, &password, NULL, NULL)) {
- TALLOC_FREE(ldap_server);
- return ADS_ERROR_NT(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
- }
-
- if (IS_DC) {
- SMB_ASSERT(wb_dom->alt_name != NULL);
- realm = SMB_STRDUP(wb_dom->alt_name);
- } else {
- struct winbindd_domain *our_domain = wb_dom;
-
- /* always give preference to the alt_name in our
- primary domain if possible */
-
- if (!wb_dom->primary) {
- our_domain = find_our_domain();
- }
-
- if (our_domain->alt_name != NULL) {
- realm = SMB_STRDUP(our_domain->alt_name);
- } else {
- realm = SMB_STRDUP(lp_realm());
- }
- }
+ DBG_DEBUG("find_domain_from_name found realm '%s' for "
+ " domain '%s'\n", wb_dom->alt_name, dom_name);
status = ads_cached_connection_connect(
- adsp, /* Returns ads struct. */
- wb_dom->alt_name, /* realm to connect to. */
- dom_name, /* 'workgroup' name for ads_init */
+ wb_dom,
ldap_server, /* DNS name to connect to. */
- password, /* password for auth realm. */
- realm, /* realm used for krb5 ticket. */
- 0); /* renewable ticket time. */
+ mem_ctx, /* memory context for ads struct */
+ adsp); /* Returns ads struct. */
- SAFE_FREE(realm);
- TALLOC_FREE(ldap_server);
+ TALLOC_FREE(tmp_ctx);
return status;
}
return our ads connections structure for a domain. We keep the connection
open to make things faster
*/
-static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
+static ADS_STATUS ads_cached_connection(struct winbindd_domain *domain,
+ ADS_STRUCT **adsp)
{
+ TALLOC_CTX *tmp_ctx = talloc_stackframe();
ADS_STATUS status;
- char *password, *realm;
-
- DEBUG(10,("ads_cached_connection\n"));
- ads_cached_connection_reuse((ADS_STRUCT **)&domain->private_data);
-
- if (domain->private_data) {
- return (ADS_STRUCT *)domain->private_data;
- }
-
- /* the machine acct password might have change - fetch it every time */
-
- if (!get_trust_pw_clear(domain->name, &password, NULL, NULL)) {
- return NULL;
- }
- if ( IS_DC ) {
- SMB_ASSERT(domain->alt_name != NULL);
- realm = SMB_STRDUP(domain->alt_name);
+ if (IS_AD_DC) {
+ /*
+ * Make sure we never try to use LDAP against
+ * a trusted domain as AD DC.
+ */
+ TALLOC_FREE(tmp_ctx);
+ return ADS_ERROR_NT(NT_STATUS_REQUEST_NOT_ACCEPTED);
}
- else {
- struct winbindd_domain *our_domain = domain;
+ DBG_DEBUG("ads_cached_connection\n");
- /* always give preference to the alt_name in our
- primary domain if possible */
-
- if ( !domain->primary )
- our_domain = find_our_domain();
-
- if (our_domain->alt_name != NULL) {
- realm = SMB_STRDUP( our_domain->alt_name );
- }
- else
- realm = SMB_STRDUP( lp_realm() );
+ ads_cached_connection_reuse(&domain->backend_data.ads_conn);
+ if (domain->backend_data.ads_conn != NULL) {
+ *adsp = domain->backend_data.ads_conn;
+ TALLOC_FREE(tmp_ctx);
+ return ADS_SUCCESS;
}
status = ads_cached_connection_connect(
- (ADS_STRUCT **)&domain->private_data,
- domain->alt_name,
- domain->name, NULL,
- password, realm,
- WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
- SAFE_FREE(realm);
-
+ domain,
+ NULL,
+ domain,
+ &domain->backend_data.ads_conn);
if (!ADS_ERR_OK(status)) {
/* if we get ECONNREFUSED then it might be a NT4
server, fall back to MSRPC */
if (status.error_type == ENUM_ADS_ERROR_SYSTEM &&
status.err.rc == ECONNREFUSED) {
/* 'reconnect_methods' is the MS-RPC backend. */
- DEBUG(1,("Trying MSRPC methods\n"));
+ DBG_NOTICE("Trying MSRPC methods for domain '%s'\n",
+ domain->name);
domain->backend = &reconnect_methods;
}
- return NULL;
+ TALLOC_FREE(tmp_ctx);
+ return status;
}
- return (ADS_STRUCT *)domain->private_data;
+ *adsp = domain->backend_data.ads_conn;
+ TALLOC_FREE(tmp_ctx);
+ return ADS_SUCCESS;
}
/* Query display info for a realm. This is the basic user list fn */
static NTSTATUS query_user_list(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- uint32_t *num_entries,
- struct wbint_userinfo **pinfo)
+ uint32_t **prids)
{
ADS_STRUCT *ads = NULL;
- const char *attrs[] = { "*", NULL };
- int i, count;
+ const char *attrs[] = { "sAMAccountType", "objectSid", NULL };
+ int count;
+ uint32_t *rids = NULL;
ADS_STATUS rc;
LDAPMessage *res = NULL;
LDAPMessage *msg = NULL;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- *num_entries = 0;
-
DEBUG(3,("ads: query_user_list\n"));
if ( !winbindd_can_contact_domain( domain ) ) {
DEBUG(10,("query_user_list: No incoming trust for domain %s\n",
- domain->name));
+ domain->name));
return NT_STATUS_OK;
}
- ads = ads_cached_connection(domain);
-
- if (!ads) {
+ rc = ads_cached_connection(domain, &ads);
+ if (!ADS_ERR_OK(rc)) {
domain->last_status = NT_STATUS_SERVER_DISABLED;
goto done;
}
goto done;
}
- (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
- if (!*pinfo) {
+ rids = talloc_zero_array(mem_ctx, uint32_t, count);
+ if (rids == NULL) {
status = NT_STATUS_NO_MEMORY;
goto done;
}
count = 0;
for (msg = ads_first_entry(ads, res); msg; msg = ads_next_entry(ads, msg)) {
- struct wbint_userinfo *info = &((*pinfo)[count]);
- uint32_t group;
+ struct dom_sid user_sid;
uint32_t atype;
bool ok;
continue;
}
- info->acct_name = ads_pull_username(ads, mem_ctx, msg);
- info->full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
- if (info->full_name == NULL) {
- info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");
- }
- info->homedir = NULL;
- info->shell = NULL;
- info->primary_gid = (gid_t)-1;
-
- if (!ads_pull_sid(ads, msg, "objectSid",
- &info->user_sid)) {
- DEBUG(1, ("No sid for %s !?\n", info->acct_name));
+ if (!ads_pull_sid(ads, msg, "objectSid", &user_sid)) {
+ char *dn = ads_get_dn(ads, talloc_tos(), msg);
+ DBG_INFO("No sid for %s !?\n", dn);
+ TALLOC_FREE(dn);
continue;
}
- if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group)) {
- DEBUG(1, ("No primary group for %s !?\n",
- info->acct_name));
+ if (!dom_sid_in_domain(&domain->sid, &user_sid)) {
+ struct dom_sid_buf sidstr, domstr;
+ DBG_WARNING("Got sid %s in domain %s\n",
+ dom_sid_str_buf(&user_sid, &sidstr),
+ dom_sid_str_buf(&domain->sid, &domstr));
continue;
}
- sid_compose(&info->group_sid, &domain->sid, group);
+ sid_split_rid(&user_sid, &rids[count]);
count += 1;
}
- (*num_entries) = count;
- ads_msgfree(ads, res);
-
- for (i=0; i<count; i++) {
- struct wbint_userinfo *info = &((*pinfo)[i]);
- const char *gecos = NULL;
- gid_t primary_gid = (gid_t)-1;
-
- status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
- &info->homedir, &info->shell,
- &gecos, &primary_gid);
- if (!NT_STATUS_IS_OK(status)) {
- /*
- * Deliberately ignore this error, there might be more
- * users to fill
- */
- continue;
- }
-
- if (gecos != NULL) {
- info->full_name = gecos;
- }
- info->primary_gid = primary_gid;
+ rids = talloc_realloc(mem_ctx, rids, uint32_t, count);
+ if (prids != NULL) {
+ *prids = rids;
+ } else {
+ TALLOC_FREE(rids);
}
status = NT_STATUS_OK;
- DEBUG(3,("ads query_user_list gave %d entries\n", (*num_entries)));
+ DBG_NOTICE("ads query_user_list gave %d entries\n", count);
done:
+ ads_msgfree(ads, res);
return status;
}
if ( !winbindd_can_contact_domain( domain ) ) {
DEBUG(10,("enum_dom_groups: No incoming trust for domain %s\n",
- domain->name));
+ domain->name));
return NT_STATUS_OK;
}
* According to Section 5.1(4) of RFC 2251 if a value of a type is it's
* default value, it MUST be absent. In case of extensible matching the
* "dnattr" boolean defaults to FALSE and so it must be only be present
- * when set to TRUE.
+ * when set to TRUE.
*
* When it is set to FALSE and the OpenLDAP lib (correctly) encodes a
* filter using bitwise matching rule then the buggy AD fails to decode
*
* Thanks to Ralf Haferkamp for input and testing - Guenther */
- filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)(&(groupType:dn:%s:=%d)(!(groupType:dn:%s:=%d))))",
- ADS_LDAP_MATCHING_RULE_BIT_AND, GROUP_TYPE_SECURITY_ENABLED,
- ADS_LDAP_MATCHING_RULE_BIT_AND,
+ filter = talloc_asprintf(mem_ctx, "(&(objectCategory=group)"
+ "(&(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d)"
+ "(!(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))))",
+ GROUP_TYPE_SECURITY_ENABLED,
enum_dom_local_groups ? GROUP_TYPE_BUILTIN_LOCAL_GROUP : GROUP_TYPE_RESOURCE_GROUP);
if (filter == NULL) {
goto done;
}
- ads = ads_cached_connection(domain);
-
- if (!ads) {
+ rc = ads_cached_connection(domain, &ads);
+ if (!ADS_ERR_OK(rc)) {
domain->last_status = NT_STATUS_SERVER_DISABLED;
goto done;
}
struct dom_sid sid;
uint32_t rid;
- name = ads_pull_username(ads, mem_ctx, msg);
- gecos = ads_pull_string(ads, mem_ctx, msg, "name");
+ name = ads_pull_username(ads, (*info), msg);
+ gecos = ads_pull_string(ads, (*info), msg, "name");
if (!ads_pull_sid(ads, msg, "objectSid", &sid)) {
DEBUG(1,("No sid for %s !?\n", name));
continue;
continue;
}
- fstrcpy((*info)[i].acct_name, name);
- fstrcpy((*info)[i].acct_desc, gecos);
+ (*info)[i].acct_name = name;
+ (*info)[i].acct_desc = gecos;
(*info)[i].rid = rid;
i++;
}
DEBUG(3,("ads enum_dom_groups gave %d entries\n", (*num_entries)));
done:
- if (res)
+ if (res)
ads_msgfree(ads, res);
return status;
struct wb_acct_info **info)
{
/*
- * This is a stub function only as we returned the domain
+ * This is a stub function only as we returned the domain
* local groups in enum_dom_groups() if the domain->native field
* was true. This is a simple performance optimization when
* using LDAP.
*
- * if we ever need to enumerate domain local groups separately,
+ * if we ever need to enumerate domain local groups separately,
* then this optimization in enum_dom_groups() will need
* to be split out
*/
const char *domain_name,
const char *name,
uint32_t flags,
+ const char **pdom_name,
struct dom_sid *sid,
enum lsa_SidType *type)
{
return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name,
- flags, sid, type);
+ flags, pdom_name, sid, type);
}
/* convert a domain SID to a user or group name - use rpc methods */
domain_name, names, types);
}
-/* If you are looking for "dn_lookup": Yes, it used to be here!
- * It has gone now since it was a major speed bottleneck in
- * lookup_groupmem (its only use). It has been replaced by
- * an rpc lookup sids call... R.I.P. */
-
-/* Lookup user information from a rid */
-static NTSTATUS query_user(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
- const struct dom_sid *sid,
- struct wbint_userinfo *info)
-{
- ADS_STRUCT *ads = NULL;
- const char *attrs[] = { "*", NULL };
- ADS_STATUS rc;
- int count;
- LDAPMessage *msg = NULL;
- char *ldap_exp;
- char *sidstr;
- uint32_t group_rid;
- NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- struct netr_SamInfo3 *user = NULL;
- gid_t gid = -1;
- int ret;
- char *full_name;
-
- DEBUG(3,("ads: query_user\n"));
-
- info->homedir = NULL;
- info->shell = NULL;
-
- /* try netsamlogon cache first */
-
- if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
- {
- DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
- sid_string_dbg(sid)));
-
- sid_compose(&info->user_sid, &domain->sid, user->base.rid);
- sid_compose(&info->group_sid, &domain->sid, user->base.primary_gid);
-
- info->acct_name = talloc_strdup(mem_ctx, user->base.account_name.string);
- info->full_name = talloc_strdup(mem_ctx, user->base.full_name.string);
-
- nss_get_info_cached( domain, sid, mem_ctx,
- &info->homedir, &info->shell, &info->full_name,
- &gid );
- info->primary_gid = gid;
-
- TALLOC_FREE(user);
-
- if (info->full_name == NULL) {
- /* this might fail so we don't check the return code */
- wcache_query_user_fullname(domain,
- mem_ctx,
- sid,
- &info->full_name);
- }
-
- return NT_STATUS_OK;
- }
-
- if ( !winbindd_can_contact_domain(domain)) {
- DEBUG(8,("query_user: No incoming trust from domain %s\n",
- domain->name));
-
- /* We still need to generate some basic information
- about the user even if we cannot contact the
- domain. Most of this stuff we can deduce. */
-
- sid_copy( &info->user_sid, sid );
-
- /* Assume "Domain Users" for the primary group */
-
- sid_compose(&info->group_sid, &domain->sid, DOMAIN_RID_USERS );
-
- /* Try to fill in what the nss_info backend can do */
-
- nss_get_info_cached( domain, sid, mem_ctx,
- &info->homedir, &info->shell, &info->full_name,
- &gid);
- info->primary_gid = gid;
-
- return NT_STATUS_OK;
- }
-
- /* no cache...do the query */
-
- if ( (ads = ads_cached_connection(domain)) == NULL ) {
- domain->last_status = NT_STATUS_SERVER_DISABLED;
- return NT_STATUS_SERVER_DISABLED;
- }
-
- sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
-
- ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
- TALLOC_FREE(sidstr);
- if (ret == -1) {
- return NT_STATUS_NO_MEMORY;
- }
- rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
- SAFE_FREE(ldap_exp);
- if (!ADS_ERR_OK(rc)) {
- DEBUG(1,("query_user(sid=%s) ads_search: %s\n",
- sid_string_dbg(sid), ads_errstr(rc)));
- return ads_ntstatus(rc);
- } else if (!msg) {
- DEBUG(1,("query_user(sid=%s) ads_search returned NULL res\n",
- sid_string_dbg(sid)));
- return NT_STATUS_INTERNAL_ERROR;
- }
-
- count = ads_count_replies(ads, msg);
- if (count != 1) {
- DEBUG(1,("query_user(sid=%s): Not found\n",
- sid_string_dbg(sid)));
- ads_msgfree(ads, msg);
- return NT_STATUS_NO_SUCH_USER;
- }
-
- info->acct_name = ads_pull_username(ads, mem_ctx, msg);
-
- if (!ads_pull_uint32(ads, msg, "primaryGroupID", &group_rid)) {
- DEBUG(1,("No primary group for %s !?\n",
- sid_string_dbg(sid)));
- ads_msgfree(ads, msg);
- return NT_STATUS_NO_SUCH_USER;
- }
- sid_copy(&info->user_sid, sid);
- sid_compose(&info->group_sid, &domain->sid, group_rid);
-
- /*
- * We have to fetch the "name" attribute before doing the
- * nss_get_info_cached call. nss_get_info_cached might destroy
- * the ads struct, potentially invalidating the ldap message.
- */
- full_name = ads_pull_string(ads, mem_ctx, msg, "displayName");
- if (full_name == NULL) {
- full_name = ads_pull_string(ads, mem_ctx, msg, "name");
- }
-
- ads_msgfree(ads, msg);
- msg = NULL;
-
- status = nss_get_info_cached( domain, sid, mem_ctx,
- &info->homedir, &info->shell, &info->full_name,
- &gid);
- info->primary_gid = gid;
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("nss_get_info_cached failed: %s\n",
- nt_errstr(status)));
- return status;
- }
-
- if (info->full_name == NULL) {
- info->full_name = full_name;
- } else {
- TALLOC_FREE(full_name);
- }
-
- status = NT_STATUS_OK;
-
- DEBUG(3,("ads query_user gave %s\n", info->acct_name));
- return NT_STATUS_OK;
-}
-
/* Lookup groups a user is a member of - alternate method, for when
tokenGroups are not available. */
static NTSTATUS lookup_usergroups_member(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
- const char *user_dn,
+ const char *user_dn,
struct dom_sid *primary_group,
uint32_t *p_num_groups, struct dom_sid **user_sids)
{
LDAPMessage *res = NULL;
LDAPMessage *msg = NULL;
char *ldap_exp;
- ADS_STRUCT *ads;
+ ADS_STRUCT *ads = NULL;
const char *group_attrs[] = {"objectSid", NULL};
char *escaped_dn;
uint32_t num_groups = 0;
if ( !winbindd_can_contact_domain( domain ) ) {
DEBUG(10,("lookup_usergroups_members: No incoming trust for domain %s\n",
- domain->name));
+ domain->name));
return NT_STATUS_OK;
}
- ads = ads_cached_connection(domain);
-
- if (!ads) {
+ rc = ads_cached_connection(domain, &ads);
+ if (!ADS_ERR_OK(rc)) {
domain->last_status = NT_STATUS_SERVER_DISABLED;
goto done;
}
}
ldap_exp = talloc_asprintf(mem_ctx,
- "(&(member=%s)(objectCategory=group)(groupType:dn:%s:=%d))",
+ "(&(member=%s)(objectCategory=group)"
+ "(groupType:dn:"ADS_LDAP_MATCHING_RULE_BIT_AND":=%d))",
escaped_dn,
- ADS_LDAP_MATCHING_RULE_BIT_AND,
GROUP_TYPE_SECURITY_ENABLED);
if (!ldap_exp) {
DEBUG(1,("lookup_usergroups(dn=%s) asprintf failed!\n", user_dn));
DEBUG(3,("ads lookup_usergroups (member) succeeded for dn=%s\n", user_dn));
done:
- if (res)
+ if (res)
ads_msgfree(ads, res);
return status;
{
ADS_STATUS rc;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- ADS_STRUCT *ads;
+ ADS_STRUCT *ads = NULL;
const char *attrs[] = {"memberOf", NULL};
uint32_t num_groups = 0;
struct dom_sid *group_sids = NULL;
- int i;
+ size_t i;
char **strings = NULL;
size_t num_strings = 0, num_sids = 0;
return NT_STATUS_OK;
}
- ads = ads_cached_connection(domain);
-
- if (!ads) {
+ rc = ads_cached_connection(domain, &ads);
+ if (!ADS_ERR_OK(rc)) {
domain->last_status = NT_STATUS_SERVER_DISABLED;
return NT_STATUS_UNSUCCESSFUL;
}
uint32_t primary_group_rid;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
uint32_t num_groups = 0;
+ struct dom_sid_buf buf;
DEBUG(3,("ads: lookup_usergroups\n"));
*p_num_groups = 0;
- status = lookup_usergroups_cached(domain, mem_ctx, sid,
+ status = lookup_usergroups_cached(mem_ctx, sid,
p_num_groups, user_sids);
if (NT_STATUS_IS_OK(status)) {
return NT_STATUS_OK;
return NT_STATUS_SYNCHRONIZATION_REQUIRED;
}
- ads = ads_cached_connection(domain);
-
- if (!ads) {
+ rc = ads_cached_connection(domain, &ads);
+ if (!ADS_ERR_OK(rc)) {
domain->last_status = NT_STATUS_SERVER_DISABLED;
status = NT_STATUS_SERVER_DISABLED;
goto done;
if (!ADS_ERR_OK(rc)) {
status = ads_ntstatus(rc);
DEBUG(1, ("lookup_usergroups(sid=%s) ads_search tokenGroups: "
- "%s\n", sid_string_dbg(sid), ads_errstr(rc)));
+ "%s\n",
+ dom_sid_str_buf(sid, &buf),
+ ads_errstr(rc)));
goto done;
}
if (count != 1) {
status = NT_STATUS_UNSUCCESSFUL;
DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: "
- "invalid number of results (count=%d)\n",
- sid_string_dbg(sid), count));
+ "invalid number of results (count=%d)\n",
+ dom_sid_str_buf(sid, &buf),
+ count));
goto done;
}
if (!msg) {
- DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
- sid_string_dbg(sid)));
+ DEBUG(1,("lookup_usergroups(sid=%s) ads_search tokenGroups: NULL msg\n",
+ dom_sid_str_buf(sid, &buf)));
status = NT_STATUS_UNSUCCESSFUL;
goto done;
}
}
if (!ads_pull_uint32(ads, msg, "primaryGroupID", &primary_group_rid)) {
- DEBUG(1,("%s: No primary group for sid=%s !?\n",
- domain->name, sid_string_dbg(sid)));
+ DEBUG(1,("%s: No primary group for sid=%s !?\n",
+ domain->name,
+ dom_sid_str_buf(sid, &buf)));
goto done;
}
count = ads_pull_sids(ads, mem_ctx, msg, "tokenGroups", &sids);
- /* there must always be at least one group in the token,
+ /* there must always be at least one group in the token,
unless we are talking to a buggy Win2k server */
/* actually this only happens when the machine account has no read
/* lookup what groups this user is a member of by DN search on
* "member" */
- status = lookup_usergroups_member(domain, mem_ctx, user_dn,
+ status = lookup_usergroups_member(domain, mem_ctx, user_dn,
&primary_group,
&num_groups, user_sids);
*p_num_groups = num_groups;
status = (*user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n",
- sid_string_dbg(sid)));
+ dom_sid_str_buf(sid, &buf)));
done:
TALLOC_FREE(user_dn);
ads_msgfree(ads, msg);
}
static NTSTATUS add_primary_group_members(
- ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid,
+ ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, uint32_t rid, const char *domname,
char ***all_members, size_t *num_all_members)
{
char *filter;
char **members;
size_t num_members;
ads_control args;
+ bool all_groupmem = idmap_config_bool(domname, "all_groupmem", false);
filter = talloc_asprintf(
- mem_ctx, "(&(objectCategory=user)(primaryGroupID=%u))",
- (unsigned)rid);
+ mem_ctx,
+ "(&(objectCategory=user)(primaryGroupID=%u)%s)",
+ (unsigned)rid,
+ all_groupmem ? "" : "(uidNumber=*)(!(uidNumber=0))");
if (filter == NULL) {
goto done;
}
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
char *sidbinstr;
char **members = NULL;
- int i;
+ size_t i;
size_t num_members = 0;
ads_control args;
struct dom_sid *sid_mem_nocache = NULL;
uint32_t num_nocache = 0;
TALLOC_CTX *tmp_ctx = NULL;
uint32_t rid;
+ struct dom_sid_buf buf;
DEBUG(10,("ads: lookup_groupmem %s sid=%s\n", domain->name,
- sid_string_dbg(group_sid)));
+ dom_sid_str_buf(group_sid, &buf)));
*num_names = 0;
return NT_STATUS_OK;
}
- ads = ads_cached_connection(domain);
-
- if (!ads) {
+ rc = ads_cached_connection(domain, &ads);
+ if (!ADS_ERR_OK(rc)) {
domain->last_status = NT_STATUS_SERVER_DISABLED;
goto done;
}
DEBUG(10, ("ads lookup_groupmem: got %d sids via extended dn call\n", (int)num_members));
- status = add_primary_group_members(ads, mem_ctx, rid,
+ status = add_primary_group_members(ads, mem_ctx, rid, domain->name,
&members, &num_members);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("%s: add_primary_group_members failed: %s\n",
if (lookup_cached_sid(mem_ctx, &sid, &domain_name, &name,
&name_type)) {
DEBUG(10,("ads: lookup_groupmem: got sid %s from "
- "cache\n", sid_string_dbg(&sid)));
+ "cache\n",
+ dom_sid_str_buf(&sid, &buf)));
sid_copy(&(*sid_mem)[*num_names], &sid);
(*names)[*num_names] = fill_domain_username_talloc(
*names,
}
else {
DEBUG(10, ("ads: lookup_groupmem: sid %s not found in "
- "cache\n", sid_string_dbg(&sid)));
+ "cache\n",
+ dom_sid_str_buf(&sid, &buf)));
sid_copy(&(sid_mem_nocache)[num_nocache], &sid);
num_nocache++;
}
DEBUG(10, ("lookup_groupmem: lsa_lookup_sids could "
"not map any SIDs at all.\n"));
/* Don't handle this as an error here.
- * There is nothing left to do with respect to the
+ * There is nothing left to do with respect to the
* overall result... */
}
else if (!NT_STATUS_IS_OK(status)) {
status = NT_STATUS_OK;
DEBUG(3,("ads lookup_groupmem for sid=%s succeeded\n",
- sid_string_dbg(group_sid)));
+ dom_sid_str_buf(group_sid, &buf)));
done:
return status;
}
-/* find the sequence number for a domain */
-static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
+static NTSTATUS lookup_aliasmem(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ const struct dom_sid *sid,
+ enum lsa_SidType type,
+ uint32_t *num_sids,
+ struct dom_sid **sids)
{
- ADS_STRUCT *ads = NULL;
- ADS_STATUS rc;
-
- DEBUG(3,("ads: fetch sequence_number for %s\n", domain->name));
-
- if ( !winbindd_can_contact_domain( domain ) ) {
- DEBUG(10,("sequence: No incoming trust for domain %s\n",
- domain->name));
- *seq = time(NULL);
- return NT_STATUS_OK;
- }
-
- *seq = DOM_SEQUENCE_NONE;
-
- ads = ads_cached_connection(domain);
-
- if (!ads) {
- domain->last_status = NT_STATUS_SERVER_DISABLED;
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- rc = ads_USN(ads, seq);
-
- if (!ADS_ERR_OK(rc)) {
-
- /* its a dead connection, destroy it */
-
- if (domain->private_data) {
- ads = (ADS_STRUCT *)domain->private_data;
- ads->is_mine = True;
- ads_destroy(&ads);
- ads_kdestroy(WINBIND_CCACHE_NAME);
- domain->private_data = NULL;
- }
- }
- return ads_ntstatus(rc);
+ char **names = NULL;
+ uint32_t *name_types = NULL;
+ struct dom_sid_buf buf;
+
+ DBG_DEBUG("ads: lookup_aliasmem %s sid=%s\n",
+ domain->name,
+ dom_sid_str_buf(sid, &buf));
+ /* Search for alias and group membership uses the same LDAP command. */
+ return lookup_groupmem(domain,
+ mem_ctx,
+ sid,
+ type,
+ num_sids,
+ sids,
+ &names,
+ &name_types);
}
/* find the lockout policy of a domain - use rpc methods */
{
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
WERROR werr;
- int i;
+ uint32_t i;
uint32_t flags;
struct rpc_pipe_client *cli;
- int ret_count;
struct dcerpc_binding_handle *b;
DEBUG(3,("ads: trusted_domains\n"));
NETR_TRUST_FLAG_IN_FOREST;
} else {
flags = NETR_TRUST_FLAG_IN_FOREST;
- }
+ }
result = cm_connect_netlogon(domain, &cli);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(5, ("trusted_domains: Could not open a connection to %s "
- "for PIPE_NETLOGON (%s)\n",
+ "for PIPE_NETLOGON (%s)\n",
domain->name, nt_errstr(result)));
return NT_STATUS_UNSUCCESSFUL;
}
/* Copy across names and sids */
- ret_count = 0;
for (i = 0; i < trusts->count; i++) {
struct netr_DomainTrust *trust = &trusts->array[i];
struct winbindd_domain d;
*/
if ((trust->trust_attributes
- == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
+ & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) &&
!domain->primary )
{
DEBUG(10,("trusted_domains: Skipping external trusted "
d.domain_trust_attribs = trust->trust_attributes;
wcache_tdc_add_domain( &d );
- ret_count++;
} else if (domain_is_forest_root(domain)) {
/* Check if we already have this record. If
* we are following our forest root that is not
trust->trust_attributes;
wcache_tdc_add_domain( &d );
- ret_count++;
}
TALLOC_FREE(exist);
} else {
}
TALLOC_FREE(parent);
+ /*
+ * We need to pass the modified properties
+ * to the caller.
+ */
+ trust->trust_flags = d.domain_flags;
+ trust->trust_type = d.domain_type;
+ trust->trust_attributes = d.domain_trust_attribs;
+
wcache_tdc_add_domain( &d );
- ret_count++;
}
}
return result;
name_to_sid,
sid_to_name,
rids_to_names,
- query_user,
lookup_usergroups,
lookup_useraliases,
lookup_groupmem,
- sequence_number,
+ lookup_aliasmem,
lockout_policy,
password_policy,
trusted_domains,