#include "includes.h"
#include "winbindd.h"
-#include "../librpc/gen_ndr/cli_netlogon.h"
+#include "rpc_client/rpc_client.h"
+#include "../librpc/gen_ndr/ndr_netlogon_c.h"
#include "../libds/common/flags.h"
#include "ads.h"
#include "secrets.h"
+#include "../libcli/ldap/ldap_ndr.h"
+#include "../libcli/security/security.h"
+#include "../libds/common/flag_mapping.h"
+#include "passdb.h"
#ifdef HAVE_ADS
extern struct winbindd_methods reconnect_methods;
-/*
- 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)
+/**
+ * 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.
+ */
+void ads_cached_connection_reuse(ADS_STRUCT **adsp)
{
- ADS_STRUCT *ads;
- ADS_STATUS status;
- fstring dc_name;
- struct sockaddr_storage dc_ss;
-
- DEBUG(10,("ads_cached_connection\n"));
- if (domain->private_data) {
+ ADS_STRUCT *ads = *adsp;
+ if (ads != NULL) {
time_t expire;
time_t now = time(NULL);
- /* check for a valid structure */
- ads = (ADS_STRUCT *)domain->private_data;
-
expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire);
- DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n",
- (uint32)expire-(uint32)now, (uint32) expire, (uint32) now));
+ DEBUG(7, ("Current tickets expire in %d seconds (at %d, time "
+ "is now %d)\n", (uint32)expire - (uint32)now,
+ (uint32) expire, (uint32) now));
if ( ads->config.realm && (expire > now)) {
- return ads;
+ 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("MEMORY:winbind_ccache");
- domain->private_data = NULL;
+ ads_kdestroy(WINBIND_CCACHE_NAME);
+ *adsp = NULL;
}
}
+}
+
+ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp,
+ const char *dom_name_alt,
+ const char *dom_name,
+ const char *ldap_server,
+ char *password,
+ char *realm,
+ time_t renewable)
+{
+ ADS_STRUCT *ads;
+ ADS_STATUS status;
+ struct sockaddr_storage dc_ss;
+ fstring dc_name;
/* we don't want this to affect the users ccache */
- setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1);
+ setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
- ads = ads_init(domain->alt_name, domain->name, NULL);
+ ads = ads_init(dom_name_alt, dom_name, ldap_server);
if (!ads) {
- DEBUG(1,("ads_init for domain %s failed\n", domain->name));
- return NULL;
+ DEBUG(1,("ads_init for domain %s failed\n", dom_name));
+ return ADS_ERROR(LDAP_NO_MEMORY);
}
- /* the machine acct password might have change - fetch it every time */
-
SAFE_FREE(ads->auth.password);
SAFE_FREE(ads->auth.realm);
+ ads->auth.renewable = renewable;
+ ads->auth.password = password;
+ ads->auth.realm = realm;
+
+ ads->auth.realm = SMB_STRDUP(realm);
+ if (!strupper_m(ads->auth.realm)) {
+ ads_destroy(&ads);
+ return ADS_ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+ }
+
+ /* 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);
+ if (!ADS_ERR_OK(status)) {
+ DEBUG(1,("ads_connect for domain %s failed: %s\n",
+ dom_name, ads_errstr(status)));
+ ads_destroy(&ads);
+ return status;
+ }
+
+ /* 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;
+
+ 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)
+{
+ 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 ( IS_DC ) {
- if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, NULL, NULL ) ) {
- ads_destroy( &ads );
+ if ( !pdb_get_trusteddom_pw( domain->name, &password, NULL,
+ NULL ) ) {
return NULL;
}
- ads->auth.realm = SMB_STRDUP( ads->server.realm );
- strupper_m( ads->auth.realm );
+ realm = NULL;
}
else {
struct winbindd_domain *our_domain = domain;
- ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ password = secrets_fetch_machine_password(lp_workgroup(), NULL,
+ NULL);
/* 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[0] != '\0' ) {
- ads->auth.realm = SMB_STRDUP( our_domain->alt_name );
- strupper_m( ads->auth.realm );
+ if (our_domain->alt_name != NULL) {
+ realm = SMB_STRDUP( our_domain->alt_name );
}
else
- ads->auth.realm = SMB_STRDUP( lp_realm() );
+ realm = SMB_STRDUP( lp_realm() );
}
- ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME;
-
- /* Setup the server affinity cache. We don't reaally care
- about the name. Just setup affinity and the KRB5_CONFIG
- file. */
+ status = ads_cached_connection_connect(
+ (ADS_STRUCT **)&domain->private_data,
+ domain->alt_name,
+ domain->name, NULL,
+ password, realm,
+ WINBINDD_PAM_AUTH_KRB5_RENEW_TIME);
- get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ss );
-
- status = ads_connect(ads);
- if (!ADS_ERR_OK(status) || !ads->config.realm) {
- DEBUG(1,("ads_connect for domain %s failed: %s\n",
- domain->name, ads_errstr(status)));
- ads_destroy(&ads);
+ 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 &&
return NULL;
}
- /* 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;
-
- domain->private_data = (void *)ads;
- return ads;
+ return (ADS_STRUCT *)domain->private_data;
}
-
/* 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,
}
rc = ads_search_retry(ads, &res, "(objectCategory=user)", attrs);
- if (!ADS_ERR_OK(rc) || !res) {
+ if (!ADS_ERR_OK(rc)) {
DEBUG(1,("query_user_list ads_search: %s\n", ads_errstr(rc)));
+ status = ads_ntstatus(rc);
+ } else if (!res) {
+ DEBUG(1,("query_user_list ads_search returned NULL res\n"));
+
goto done;
}
goto done;
}
- (*pinfo) = TALLOC_ZERO_ARRAY(mem_ctx, struct wbint_userinfo, count);
+ (*pinfo) = talloc_zero_array(mem_ctx, struct wbint_userinfo, count);
if (!*pinfo) {
status = NT_STATUS_NO_MEMORY;
goto done;
const char *gecos = NULL;
gid_t primary_gid = (gid_t)-1;
- /*
- * Don't use our variable "ads" in this call here, every call
- * to nss_get_info_cached can destroy the connection inside
- * the domain.
- */
status = nss_get_info_cached(domain, &info->user_sid, mem_ctx,
- ads_cached_connection(domain),
- msg, &info->homedir, &info->shell,
+ &info->homedir, &info->shell,
&gecos, &primary_gid);
if (!NT_STATUS_IS_OK(status)) {
/*
static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_entries,
- struct acct_info **info)
+ struct wb_acct_info **info)
{
ADS_STRUCT *ads = NULL;
const char *attrs[] = {"userPrincipalName", "sAMAccountName",
}
rc = ads_search_retry(ads, &res, filter, attrs);
- if (!ADS_ERR_OK(rc) || !res) {
+ if (!ADS_ERR_OK(rc)) {
+ status = ads_ntstatus(rc);
DEBUG(1,("enum_dom_groups ads_search: %s\n", ads_errstr(rc)));
goto done;
+ } else if (!res) {
+ DEBUG(1,("enum_dom_groups ads_search returned NULL res\n"));
+ goto done;
}
count = ads_count_replies(ads, res);
goto done;
}
- (*info) = TALLOC_ZERO_ARRAY(mem_ctx, struct acct_info, count);
+ (*info) = talloc_zero_array(mem_ctx, struct wb_acct_info, count);
if (!*info) {
status = NT_STATUS_NO_MEMORY;
goto done;
static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
TALLOC_CTX *mem_ctx,
uint32 *num_entries,
- struct acct_info **info)
+ struct wb_acct_info **info)
{
/*
* This is a stub function only as we returned the domain
/* try netsamlogon cache first */
- if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
+ if ( (user = netsamlogon_cache_get( mem_ctx, sid )) != NULL )
{
DEBUG(5,("query_user: Cache lookup succeeded for %s\n",
sid_string_dbg(sid)));
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, NULL, NULL,
+ nss_get_info_cached( domain, sid, mem_ctx,
&info->homedir, &info->shell, &info->full_name,
&gid );
info->primary_gid = gid;
/* Try to fill in what the nss_info backend can do */
- nss_get_info_cached( domain, sid, mem_ctx, NULL, NULL,
+ nss_get_info_cached( domain, sid, mem_ctx,
&info->homedir, &info->shell, &info->full_name,
&gid);
info->primary_gid = gid;
return NT_STATUS_SERVER_DISABLED;
}
- sidstr = sid_binstring(talloc_tos(), sid);
+ sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), sid);
ret = asprintf(&ldap_exp, "(objectSid=%s)", sidstr);
TALLOC_FREE(sidstr);
}
rc = ads_search_retry(ads, &msg, ldap_exp, attrs);
SAFE_FREE(ldap_exp);
- if (!ADS_ERR_OK(rc) || !msg) {
+ 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);
ads_msgfree(ads, msg);
msg = NULL;
- status = nss_get_info_cached( domain, sid, mem_ctx, ads, msg,
+ status = nss_get_info_cached( domain, sid, mem_ctx,
&info->homedir, &info->shell, &info->full_name,
&gid);
info->primary_gid = gid;
TALLOC_CTX *mem_ctx,
const char *user_dn,
struct dom_sid *primary_group,
- size_t *p_num_groups, struct dom_sid **user_sids)
+ uint32_t *p_num_groups, struct dom_sid **user_sids)
{
ADS_STATUS rc;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
ADS_STRUCT *ads;
const char *group_attrs[] = {"objectSid", NULL};
char *escaped_dn;
- size_t num_groups = 0;
+ uint32_t num_groups = 0;
DEBUG(3,("ads: lookup_usergroups_member\n"));
rc = ads_search_retry(ads, &res, ldap_exp, group_attrs);
- if (!ADS_ERR_OK(rc) || !res) {
+ if (!ADS_ERR_OK(rc)) {
DEBUG(1,("lookup_usergroups ads_search member=%s: %s\n", user_dn, ads_errstr(rc)));
return ads_ntstatus(rc);
+ } else if (!res) {
+ DEBUG(1,("lookup_usergroups ads_search returned NULL res\n"));
+ return NT_STATUS_INTERNAL_ERROR;
}
+
count = ads_count_replies(ads, res);
*user_sids = NULL;
TALLOC_CTX *mem_ctx,
const char *user_dn,
struct dom_sid *primary_group,
- size_t *p_num_groups,
+ uint32_t *p_num_groups,
struct dom_sid **user_sids)
{
ADS_STATUS rc;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
ADS_STRUCT *ads;
const char *attrs[] = {"memberOf", NULL};
- size_t num_groups = 0;
+ uint32_t num_groups = 0;
struct dom_sid *group_sids = NULL;
int i;
char **strings = NULL;
goto done;
}
- group_sids = TALLOC_ZERO_ARRAY(mem_ctx, struct dom_sid, num_strings + 1);
+ group_sids = talloc_zero_array(mem_ctx, struct dom_sid, num_strings + 1);
if (!group_sids) {
status = NT_STATUS_NO_MEMORY;
goto done;
struct dom_sid primary_group;
uint32 primary_group_rid;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- size_t num_groups = 0;
+ uint32_t num_groups = 0;
DEBUG(3,("ads: lookup_usergroups\n"));
*p_num_groups = 0;
status = lookup_usergroups_memberof(domain, mem_ctx, user_dn,
&primary_group,
&num_groups, user_sids);
- *p_num_groups = (uint32)num_groups;
+ *p_num_groups = num_groups;
if (NT_STATUS_IS_OK(status)) {
goto done;
}
status = lookup_usergroups_member(domain, mem_ctx, user_dn,
&primary_group,
&num_groups, user_sids);
- *p_num_groups = (uint32)num_groups;
+ *p_num_groups = num_groups;
goto done;
}
goto done;
}
- if ((sidbinstr = sid_binstring(talloc_tos(), group_sid)) == NULL) {
+ if ((sidbinstr = ldap_encode_ndr_dom_sid(talloc_tos(), group_sid)) == NULL) {
status = NT_STATUS_NO_MEMORY;
goto done;
}
* cache. Only the rest is passed to the lsa_lookup_sids call. */
if (num_members) {
- (*sid_mem) = TALLOC_ZERO_ARRAY(mem_ctx, struct dom_sid, num_members);
- (*names) = TALLOC_ZERO_ARRAY(mem_ctx, char *, num_members);
- (*name_types) = TALLOC_ZERO_ARRAY(mem_ctx, uint32, num_members);
- (sid_mem_nocache) = TALLOC_ZERO_ARRAY(tmp_ctx, struct dom_sid, num_members);
+ (*sid_mem) = talloc_zero_array(mem_ctx, struct dom_sid, num_members);
+ (*names) = talloc_zero_array(mem_ctx, char *, num_members);
+ (*name_types) = talloc_zero_array(mem_ctx, uint32, num_members);
+ (sid_mem_nocache) = talloc_zero_array(tmp_ctx, struct dom_sid, num_members);
if ((members == NULL) || (*sid_mem == NULL) ||
(*names == NULL) || (*name_types == NULL) ||
ads = (ADS_STRUCT *)domain->private_data;
ads->is_mine = True;
ads_destroy(&ads);
- ads_kdestroy("MEMORY:winbind_ccache");
+ ads_kdestroy(WINBIND_CCACHE_NAME);
domain->private_data = NULL;
}
}
struct netr_DomainTrustList *trusts)
{
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ WERROR werr;
int i;
uint32 flags;
struct rpc_pipe_client *cli;
int ret_count;
+ struct dcerpc_binding_handle *b;
DEBUG(3,("ads: trusted_domains\n"));
return NT_STATUS_UNSUCCESSFUL;
}
- result = rpccli_netr_DsrEnumerateDomainTrusts(cli, mem_ctx,
+ b = cli->binding_handle;
+
+ result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
cli->desthost,
flags,
trusts,
- NULL);
+ &werr);
if (!NT_STATUS_IS_OK(result)) {
return result;
}
+
+ if (!W_ERROR_IS_OK(werr)) {
+ return werror_to_ntstatus(werr);
+ }
if (trusts->count == 0) {
return NT_STATUS_OK;
}
/* add to the trusted domain cache */
- fstrcpy(d.name, trust->netbios_name);
- fstrcpy(d.alt_name, trust->dns_name);
+ d.name = discard_const_p(char, trust->netbios_name);
+ d.alt_name = discard_const_p(char, trust->dns_name);
+
if (trust->sid) {
sid_copy(&d.sid, trust->sid);
} else {