bool active_directory; /* is this a win2k active directory ? */
bool primary; /* is this our primary domain ? */
bool internal; /* BUILTIN and member SAM */
+ bool rodc; /* Are we an RODC for this AD domain? (do some operations locally) */
bool online; /* is this domain available ? */
time_t startup_time; /* When we set "startup" true. monotonic clock */
bool startup; /* are we in the first 30 seconds after startup_time ? */
}
if ( !domain->initialized ) {
- init_dc_connection( domain );
+ /* We do not need a connection to an RW DC for cache operation */
+ init_dc_connection(domain, false);
}
/*
extern struct winbindd_methods reconnect_methods;
extern bool override_logfile;
-static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain);
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool need_rw_dc);
static void set_dc_type_and_flags( struct winbindd_domain *domain );
static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
struct dc_name_ip **dcs, int *num_dcs);
the offline handler if false. Bypasses online
check so always does network calls. */
- init_dc_connection_network(domain);
+ init_dc_connection_network(domain, true);
break;
}
}
/* Initialize a new connection up to the RPC BIND.
Bypass online status check so always does network calls. */
-static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain)
+static NTSTATUS init_dc_connection_network(struct winbindd_domain *domain, bool need_rw_dc)
{
NTSTATUS result;
+ bool skip_connection = domain->internal;
+ if (need_rw_dc && domain->rodc) {
+ skip_connection = false;
+ }
/* Internal connections never use the network. */
if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
}
/* Still ask the internal LSA and SAMR server about the local domain */
- if (domain->internal || connection_ok(domain)) {
+ if (skip_connection || connection_ok(domain)) {
if (!domain->initialized) {
set_dc_type_and_flags(domain);
}
return result;
}
-NTSTATUS init_dc_connection(struct winbindd_domain *domain)
+NTSTATUS init_dc_connection(struct winbindd_domain *domain, bool need_rw_dc)
{
if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
}
- return init_dc_connection_network(domain);
+ return init_dc_connection_network(domain, need_rw_dc);
}
-static NTSTATUS init_dc_connection_rpc(struct winbindd_domain *domain)
+static NTSTATUS init_dc_connection_rpc(struct winbindd_domain *domain, bool need_rw_dc)
{
NTSTATUS status;
- status = init_dc_connection(domain);
+ status = init_dc_connection(domain, need_rw_dc);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
}
NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+ bool need_rw_dc,
struct rpc_pipe_client **cli, struct policy_handle *sam_handle)
{
struct winbindd_cm_conn *conn;
const char *domain_name = NULL;
if (sid_check_is_our_sam(&domain->sid)) {
- return open_internal_samr_conn(mem_ctx, domain, cli, sam_handle);
+ if (domain->rodc == false || need_rw_dc == false) {
+ return open_internal_samr_conn(mem_ctx, domain, cli, sam_handle);
+ }
}
- status = init_dc_connection_rpc(domain);
+ status = init_dc_connection_rpc(domain, need_rw_dc);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
DEBUG(10,("cm_connect_lsa_tcp\n"));
- status = init_dc_connection_rpc(domain);
+ status = init_dc_connection_rpc(domain, false);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
struct netlogon_creds_cli_context *p_creds;
- result = init_dc_connection_rpc(domain);
+ result = init_dc_connection_rpc(domain, false);
if (!NT_STATUS_IS_OK(result))
return result;
*cli = NULL;
- result = init_dc_connection_rpc(domain);
+ result = init_dc_connection_rpc(domain, true);
if (!NT_STATUS_IS_OK(result)) {
return result;
}
goto done;
}
- status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+ status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
goto done;
}
- status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+ status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
goto done;
}
- status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+ status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
}
/* no cache; hit the wire */
- status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+ status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
}
/* no cache; hit the wire */
- status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+ status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
goto done;
}
- status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+ status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
*num_names = 0;
- result = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ result = cm_connect_sam(domain, mem_ctx, false, &cli, &dom_pol);
if (!NT_STATUS_IS_OK(result))
return result;
}
#endif /* HAVE_LDAP */
- status = cm_connect_sam(domain, tmp_ctx, &samr_pipe, &dom_pol);
+ status = cm_connect_sam(domain, tmp_ctx, false, &samr_pipe, &dom_pol);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
return NT_STATUS_NOT_SUPPORTED;
}
- status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ status = cm_connect_sam(domain, mem_ctx, false, &cli, &dom_pol);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
return NT_STATUS_NOT_SUPPORTED;
}
- status = cm_connect_sam(domain, mem_ctx, &cli, &dom_pol);
+ status = cm_connect_sam(domain, mem_ctx, false, &cli, &dom_pol);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
}
if (!contact_domain->initialized) {
- init_dc_connection(contact_domain);
+ init_dc_connection(contact_domain, false);
}
if (!contact_domain->active_directory) {
uint32 acct_flags;
struct dcerpc_binding_handle *b;
- status_tmp = cm_connect_sam(domain, mem_ctx,
+ status_tmp = cm_connect_sam(domain, mem_ctx, false,
&samr_pipe, &samr_domain_handle);
if (!NT_STATUS_IS_OK(status_tmp)) {
"request in startup mode.\n", domain->name ));
winbindd_flush_negative_conn_cache(domain);
- result = init_dc_connection(domain);
+ result = init_dc_connection(domain, false);
}
}
/* Get sam handle */
- result = cm_connect_sam(contact_domain, state->mem_ctx, &cli,
+ result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli,
&dom_pol);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
/* Get sam handle */
- result = cm_connect_sam(contact_domain, state->mem_ctx, &cli, &dom_pol);
+ result = cm_connect_sam(contact_domain, state->mem_ctx, true, &cli, &dom_pol);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
goto done;
struct rpc_pipe_client **ret_pipe);
void invalidate_cm_connection(struct winbindd_cm_conn *conn);
void close_conns_after_fork(void);
-NTSTATUS init_dc_connection(struct winbindd_domain *domain);
+NTSTATUS init_dc_connection(struct winbindd_domain *domain, bool need_rw_dc);
NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
+ bool need_rw_dc,
struct rpc_pipe_client **cli, struct policy_handle *sam_handle);
NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
struct rpc_pipe_client **cli, struct policy_handle *lsa_policy);
#include "../libcli/security/security.h"
#include "../libcli/auth/pam_errors.h"
#include "passdb/machine_sid.h"
+#include "passdb.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
}
- init_dc_connection(domain);
+ init_dc_connection(domain, false);
if (!domain->initialized) {
/* If we return error here we can't do any cached authentication,
/* Local SAM */
if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
- (void)add_trusted_domain(get_global_sam_name(), lp_dnsdomain(),
- &cache_methods, get_global_sam_sid());
+ struct winbindd_domain *domain;
+ enum netr_SchannelType sec_chan_type;
+ const char *account_name;
+ struct samr_Password current_nt_hash;
+ bool ok;
+
+ domain = add_trusted_domain(get_global_sam_name(), lp_dnsdomain(),
+ &cache_methods, get_global_sam_sid());
+ if (domain == NULL) {
+ DEBUG(0, ("Failed to add our own, local AD domain to winbindd's internal list\n"));
+ return false;
+ }
+
+ /*
+ * We need to call this to find out if we are an RODC
+ */
+ ok = get_trust_pw_hash(domain->name,
+ current_nt_hash.hash,
+ &account_name,
+ &sec_chan_type);
+ if (!ok) {
+ DEBUG(0, ("Failed to fetch our own, local AD domain join password for winbindd's internal use\n"));
+ return false;
+ }
+ if (sec_chan_type == SEC_CHAN_RODC) {
+ domain->rodc = true;
+ }
+
} else {
(void)add_trusted_domain(get_global_sam_name(), NULL,
&cache_methods, get_global_sam_sid());
return NULL;
if (!domain->initialized)
- init_dc_connection(domain);
+ init_dc_connection(domain, false);
return domain;
}
return NULL;
if (!domain->initialized)
- init_dc_connection(domain);
+ init_dc_connection(domain, false);
return domain;
}