pid_t parent_pid = getpid();
char *lfile = NULL;
NTSTATUS status;
+ bool ok;
if (domain->dc_probe_pid != (pid_t)-1) {
/*
if (domain->dc_probe_pid != (pid_t)0) {
/* Parent */
- messaging_register(winbind_messaging_context(), NULL,
+ messaging_register(server_messaging_context(), NULL,
MSG_WINBIND_TRY_TO_GO_ONLINE,
msg_try_to_go_online);
- messaging_register(winbind_messaging_context(), NULL,
+ messaging_register(server_messaging_context(), NULL,
MSG_WINBIND_FAILED_TO_GO_ONLINE,
msg_failed_to_go_online);
return True;
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("winbindd_reinit_after_fork failed: %s\n",
nt_errstr(status)));
- messaging_send_buf(winbind_messaging_context(),
+ messaging_send_buf(server_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_FAILED_TO_GO_ONLINE,
(const uint8_t *)domain->name,
}
SAFE_FREE(lfile);
+ setproctitle("dc-connect child");
+
mem_ctx = talloc_init("fork_child_dc_connect");
if (!mem_ctx) {
DEBUG(0,("talloc_init failed.\n"));
- messaging_send_buf(winbind_messaging_context(),
+ messaging_send_buf(server_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_FAILED_TO_GO_ONLINE,
(const uint8_t *)domain->name,
_exit(1);
}
- if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs, 0)) || (num_dcs == 0)) {
+ ok = get_dcs(mem_ctx, domain, &dcs, &num_dcs, 0);
+ TALLOC_FREE(mem_ctx);
+ if (!ok || (num_dcs == 0)) {
/* Still offline ? Can't find DC's. */
- messaging_send_buf(winbind_messaging_context(),
+ messaging_send_buf(server_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_FAILED_TO_GO_ONLINE,
(const uint8_t *)domain->name,
/* We got a DC. Send a message to our parent to get it to
try and do the same. */
- messaging_send_buf(winbind_messaging_context(),
+ messaging_send_buf(server_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_TRY_TO_GO_ONLINE,
(const uint8_t *)domain->name,
calc_new_online_timeout_check(domain);
- domain->check_online_event = tevent_add_timer(winbind_event_context(),
+ domain->check_online_event = tevent_add_timer(server_event_context(),
NULL,
timeval_current_ofs(domain->check_online_timeout,0),
check_domain_online_handler,
/* Send a message to the parent that the domain is offline. */
if (parent_pid > 1 && !domain->internal) {
- messaging_send_buf(winbind_messaging_context(),
+ messaging_send_buf(server_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_DOMAIN_OFFLINE,
(uint8_t *)domain->name,
struct winbindd_child *idmap = idmap_child();
if ( idmap->pid != 0 ) {
- messaging_send_buf(winbind_messaging_context(),
+ messaging_send_buf(server_messaging_context(),
pid_to_procid(idmap->pid),
MSG_WINBIND_OFFLINE,
(const uint8_t *)domain->name,
TALLOC_FREE(domain->check_online_event);
/* Ensure we ignore any pending child messages. */
- messaging_deregister(winbind_messaging_context(),
+ messaging_deregister(server_messaging_context(),
MSG_WINBIND_TRY_TO_GO_ONLINE, NULL);
- messaging_deregister(winbind_messaging_context(),
+ messaging_deregister(server_messaging_context(),
MSG_WINBIND_FAILED_TO_GO_ONLINE, NULL);
domain->online = True;
/* Send a message to the parent that the domain is online. */
if (parent_pid > 1 && !domain->internal) {
- messaging_send_buf(winbind_messaging_context(),
+ messaging_send_buf(server_messaging_context(),
pid_to_procid(parent_pid),
MSG_WINBIND_DOMAIN_ONLINE,
(uint8_t *)domain->name,
struct winbindd_child *idmap = idmap_child();
if ( idmap->pid != 0 ) {
- messaging_send_buf(winbind_messaging_context(),
+ messaging_send_buf(server_messaging_context(),
pid_to_procid(idmap->pid),
MSG_WINBIND_ONLINE,
(const uint8_t *)domain->name,
TALLOC_FREE(domain->check_online_event);
- domain->check_online_event = tevent_add_timer(winbind_event_context(),
+ domain->check_online_event = tevent_add_timer(server_event_context(),
NULL,
tev,
check_domain_online_handler,
enum smb_signing_setting smb_sign_client_connections = lp_client_ipc_signing();
+ if (IS_AD_DC) {
+ if (domain->secure_channel_type == SEC_CHAN_NULL) {
+ /*
+ * Make sure we don't even try to
+ * connect to a foreign domain
+ * without a direct outbound trust.
+ */
+ return NT_STATUS_NO_TRUST_LSA_SECRET;
+ }
+
+ /*
+ * As AD DC we only use netlogon and lsa
+ * using schannel over an anonymous transport
+ * (ncacn_ip_tcp or ncacn_np).
+ *
+ * Currently we always establish the SMB connection,
+ * even if we don't use it, because we later use ncacn_ip_tcp.
+ *
+ * As we won't use the SMB connection there's no
+ * need to try kerberos. And NT4 domains expect
+ * an anonymous IPC$ connection anyway.
+ */
+ smb_sign_client_connections = SMB_SIGNING_OFF;
+ }
+
if (smb_sign_client_connections == SMB_SIGNING_DEFAULT) {
/*
* If we are connecting to our own AD domain, require
* AD domain in our forest
* then require smb signing to disrupt MITM attacks
*/
- } else if ((lp_security() == SEC_ADS ||
- lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC)
+ } else if ((lp_security() == SEC_ADS)
&& domain->active_directory
&& (domain->domain_trust_attribs
& LSA_TRUST_ATTRIBUTE_WITHIN_FOREST)) {
goto done;
}
- *cli = cli_state_create(NULL, sockfd,
- controller, domain->alt_name,
+ *cli = cli_state_create(NULL, sockfd, controller,
smb_sign_client_connections, flags);
if (*cli == NULL) {
close(sockfd);
try_ipc_auth = true;
}
+ if (IS_AD_DC) {
+ /*
+ * As AD DC we only use netlogon and lsa
+ * using schannel over an anonymous transport
+ * (ncacn_ip_tcp or ncacn_np).
+ *
+ * Currently we always establish the SMB connection,
+ * even if we don't use it, because we later use ncacn_ip_tcp.
+ *
+ * As we won't use the SMB connection there's no
+ * need to try kerberos. And NT4 domains expect
+ * an anonymous IPC$ connection anyway.
+ */
+ try_ipc_auth = false;
+ }
+
if (try_ipc_auth) {
result = get_trust_credentials(domain, talloc_tos(), false, &creds);
if (!NT_STATUS_IS_OK(result)) {
ads = ads_init(domain->alt_name, domain->name, addr);
ads->auth.flags |= ADS_AUTH_NO_BIND;
ads->config.flags |= request_flags;
+ ads->server.no_fallback = true;
ads_status = ads_connect(ads);
if (ADS_ERR_OK(ads_status)) {
}
#endif
- status = nbt_getdc(winbind_messaging_context(), 10, pss, domain->name,
+ status = nbt_getdc(server_messaging_context(), 10, pss, domain->name,
&domain->sid, nt_version, mem_ctx, &nt_version,
&dc_name, NULL);
if (NT_STATUS_IS_OK(status)) {
session_info,
NULL,
NULL,
- winbind_messaging_context(),
+ server_messaging_context(),
&cli);
} else {
status = rpc_pipe_open_internal(mem_ctx,
session_info,
NULL,
NULL,
- winbind_messaging_context(),
+ server_messaging_context(),
&cli);
}
if (!NT_STATUS_IS_OK(status)) {
}
static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
- struct winbindd_cm_conn *new_conn)
+ struct winbindd_cm_conn *new_conn,
+ bool need_rw_dc)
{
TALLOC_CTX *mem_ctx;
NTSTATUS result;
char *saf_servername;
int retries;
- uint32_t request_flags = 0;
+ uint32_t request_flags = need_rw_dc ? DS_WRITABLE_REQUIRED : 0;
if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
set_domain_offline(domain);
}
conn->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
- conn->netlogon_force_reauth = false;
- conn->netlogon_flags = 0;
- TALLOC_FREE(conn->netlogon_creds);
+ TALLOC_FREE(conn->netlogon_creds_ctx);
if (conn->cli) {
cli_shutdown(conn->cli);
set_dc_type_and_flags_trustinfo(domain);
}
- result = cm_open_connection(domain, &domain->conn);
+ result = cm_open_connection(domain, &domain->conn, need_rw_dc);
if (NT_STATUS_IS_OK(result) && !domain->initialized) {
set_dc_type_and_flags(domain);
TALLOC_CTX *mem_ctx = NULL;
struct dcerpc_binding_handle *b;
+ if (IS_DC) {
+ /*
+ * On a DC we loaded all trusts
+ * from configuration and never learn
+ * new domains.
+ */
+ return true;
+ }
+
DEBUG(5, ("set_dc_type_and_flags_trustinfo: domain %s\n", domain->name ));
/* Our primary domain doesn't need to worry about trust flags.
static void set_dc_type_and_flags( struct winbindd_domain *domain )
{
+ if (IS_DC) {
+ /*
+ * On a DC we loaded all trusts
+ * from configuration and never learn
+ * new domains.
+ */
+ return;
+ }
+
/* we always have to contact our primary domain */
if ( domain->primary || domain->internal) {
return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
}
- if (domain->conn.netlogon_creds != NULL) {
- if (!(domain->conn.netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
- return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
- }
- *ppdc = domain->conn.netlogon_creds;
+ if (domain->conn.netlogon_creds_ctx != NULL) {
+ *ppdc = domain->conn.netlogon_creds_ctx;
return NT_STATUS_OK;
}
- result = cm_connect_netlogon(domain, &netlogon_pipe);
+ result = cm_connect_netlogon_secure(domain, &netlogon_pipe, ppdc);
if (!NT_STATUS_IS_OK(result)) {
return result;
}
- if (domain->conn.netlogon_creds == NULL) {
- return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
- }
-
- if (!(domain->conn.netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
- return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
- }
-
- *ppdc = domain->conn.netlogon_creds;
return NT_STATUS_OK;
}
}
}
+ if (IS_AD_DC) {
+ /*
+ * In theory we should not use SAMR within
+ * winbindd at all, but that's a larger task to
+ * remove this and avoid breaking existing
+ * setups.
+ *
+ * At least as AD DC we have the restriction
+ * to avoid SAMR against trusted domains,
+ * as there're no existing setups.
+ */
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
retry:
status = init_dc_connection_rpc(domain, need_rw_dc);
if (!NT_STATUS_IS_OK(status)) {
goto anonymous;
}
TALLOC_FREE(creds);
- result = get_trust_credentials(domain, talloc_tos(), true, &creds);
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(10, ("cm_connect_sam: No user available for "
- "domain %s (error %s), trying anon\n", domain->name,
- nt_errstr(result)));
- goto anonymous;
- }
- status = cli_rpc_pipe_open_schannel_with_creds
- (conn->cli, &ndr_table_samr, NCACN_NP,
- creds, p_creds, &conn->samr_pipe);
+ status = cli_rpc_pipe_open_schannel_with_creds(
+ conn->cli, &ndr_table_samr, NCACN_NP, p_creds,
+ &conn->samr_pipe);
if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)
&& !retry) {
{
struct winbindd_cm_conn *conn;
struct netlogon_creds_cli_context *p_creds = NULL;
- struct cli_credentials *creds = NULL;
NTSTATUS status;
DEBUG(10,("cm_connect_lsa_tcp\n"));
conn = &domain->conn;
- if (conn->lsa_pipe_tcp &&
+ /*
+ * rpccli_is_connected handles more error cases
+ */
+ if (rpccli_is_connected(conn->lsa_pipe_tcp) &&
conn->lsa_pipe_tcp->transport->transport == NCACN_IP_TCP &&
- conn->lsa_pipe_tcp->auth->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY &&
- rpccli_is_connected(conn->lsa_pipe_tcp)) {
+ conn->lsa_pipe_tcp->auth->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
goto done;
}
goto done;
}
- status = get_trust_credentials(domain, talloc_tos(), true, &creds);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
status = cli_rpc_pipe_open_schannel_with_creds(conn->cli,
&ndr_table_lsarpc,
NCACN_IP_TCP,
- creds,
p_creds,
&conn->lsa_pipe_tcp);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(conn->lsa_pipe);
+ if (IS_AD_DC) {
+ /*
+ * Make sure we only use schannel as AD DC.
+ */
+ goto schannel;
+ }
+
result = get_trust_credentials(domain, talloc_tos(), false, &creds);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(10, ("cm_connect_lsa: No user available for "
}
TALLOC_FREE(creds);
- result = get_trust_credentials(domain, talloc_tos(), true, &creds);
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(10, ("cm_connect_lsa: No user available for "
- "domain %s (error %s), trying anon\n", domain->name,
- nt_errstr(result)));
- goto anonymous;
- }
- result = cli_rpc_pipe_open_schannel_with_creds
- (conn->cli, &ndr_table_lsarpc, NCACN_NP,
- creds, p_creds, &conn->lsa_pipe);
+ result = cli_rpc_pipe_open_schannel_with_creds(
+ conn->cli, &ndr_table_lsarpc, NCACN_NP, p_creds,
+ &conn->lsa_pipe);
if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED)
&& !retry) {
goto done;
}
+ if (IS_AD_DC) {
+ /*
+ * Make sure we only use schannel as AD DC.
+ */
+ goto done;
+ }
+
DEBUG(10,("cm_connect_lsa: rpccli_lsa_open_policy failed, trying "
"anonymous\n"));
anonymous:
+ if (IS_AD_DC) {
+ /*
+ * Make sure we only use schannel as AD DC.
+ */
+ goto done;
+ }
+
if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
result = NT_STATUS_DOWNGRADE_DETECTED;
DEBUG(1, ("Unwilling to make LSA connection to domain %s "
}
/****************************************************************************
- Open the netlogon pipe to this DC. Use schannel if specified in client conf.
- session key stored in conn->netlogon_pipe->dc->sess_key.
+ Open the netlogon pipe to this DC.
****************************************************************************/
static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
enum dcerpc_transport_t transport,
struct rpc_pipe_client **cli)
{
- struct messaging_context *msg_ctx = winbind_messaging_context();
+ struct messaging_context *msg_ctx = server_messaging_context();
struct winbindd_cm_conn *conn;
NTSTATUS result;
enum netr_SchannelType sec_chan_type;
- struct netlogon_creds_CredentialState *netlogon_creds = NULL;
struct cli_credentials *creds = NULL;
*cli = NULL;
+ if (IS_AD_DC) {
+ if (domain->secure_channel_type == SEC_CHAN_NULL) {
+ /*
+ * Make sure we don't even try to
+ * connect to a foreign domain
+ * without a direct outbound trust.
+ */
+ return NT_STATUS_NO_TRUST_LSA_SECRET;
+ }
+ }
+
result = init_dc_connection_rpc(domain, domain->rodc);
if (!NT_STATUS_IS_OK(result)) {
return result;
}
TALLOC_FREE(conn->netlogon_pipe);
- conn->netlogon_flags = 0;
- TALLOC_FREE(conn->netlogon_creds);
+ TALLOC_FREE(conn->netlogon_creds_ctx);
result = get_trust_credentials(domain, talloc_tos(), true, &creds);
if (!NT_STATUS_IS_OK(result)) {
}
if (cli_credentials_is_anonymous(creds)) {
- DEBUG(1, ("get_trust_credential only gave anonymous for %s, unable to make get NETLOGON credentials\n",
- domain->name));
+ DBG_WARNING("get_trust_credential only gave anonymous for %s, "
+ "unable to make get NETLOGON credentials\n",
+ domain->name);
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
sec_chan_type = cli_credentials_get_secure_channel_type(creds);
if (sec_chan_type == SEC_CHAN_NULL) {
if (transport == NCACN_IP_TCP) {
- DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL for %s, "
- " deny NCACN_IP_TCP and let the caller fallback to NCACN_NP.\n",
+ DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL "
+ "for %s, deny NCACN_IP_TCP and let the "
+ "caller fallback to NCACN_NP.\n",
domain->name);
return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
"fallback to noauth on NCACN_NP.\n",
domain->name);
- result = cli_rpc_pipe_open_noauth_transport(conn->cli,
- transport,
- &ndr_table_netlogon,
- &conn->netlogon_pipe);
+ result = cli_rpc_pipe_open_noauth_transport(
+ conn->cli,
+ transport,
+ &ndr_table_netlogon,
+ &conn->netlogon_pipe);
if (!NT_STATUS_IS_OK(result)) {
invalidate_cm_connection(domain);
return result;
return NT_STATUS_OK;
}
- result = rpccli_create_netlogon_creds_with_creds(creds,
- domain->dcname,
- msg_ctx,
- domain,
- &conn->netlogon_creds);
+ result = rpccli_create_netlogon_creds_ctx(creds,
+ domain->dcname,
+ msg_ctx,
+ domain,
+ &conn->netlogon_creds_ctx);
if (!NT_STATUS_IS_OK(result)) {
DEBUG(1, ("rpccli_create_netlogon_creds failed for %s, "
"unable to create NETLOGON credentials: %s\n",
return result;
}
- result = rpccli_setup_netlogon_creds_with_creds(conn->cli, transport,
- conn->netlogon_creds,
- conn->netlogon_force_reauth,
- creds);
- conn->netlogon_force_reauth = false;
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(1, ("rpccli_setup_netlogon_creds failed for %s, "
- "unable to setup NETLOGON credentials: %s\n",
- domain->name, nt_errstr(result)));
- return result;
- }
-
- result = netlogon_creds_cli_get(conn->netlogon_creds,
- talloc_tos(),
- &netlogon_creds);
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(1, ("netlogon_creds_cli_get failed for %s, "
- "unable to get NETLOGON credentials: %s\n",
- domain->name, nt_errstr(result)));
- return result;
- }
- conn->netlogon_flags = netlogon_creds->negotiate_flags;
- TALLOC_FREE(netlogon_creds);
-
- if (!(conn->netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
- if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
- result = NT_STATUS_DOWNGRADE_DETECTED;
- DEBUG(1, ("Unwilling to make connection to domain %s"
- "without connection level security, "
- "must set 'winbind sealed pipes = false' and "
- "'require strong key = false' to proceed: %s\n",
- domain->name, nt_errstr(result)));
- invalidate_cm_connection(domain);
- return result;
- }
- result = cli_rpc_pipe_open_noauth_transport(conn->cli,
- transport,
- &ndr_table_netlogon,
- &conn->netlogon_pipe);
- if (!NT_STATUS_IS_OK(result)) {
- invalidate_cm_connection(domain);
- return result;
- }
-
- *cli = conn->netlogon_pipe;
- return NT_STATUS_OK;
- }
-
- /* Using the credentials from the first pipe, open a signed and sealed
- second netlogon pipe. The session key is stored in the schannel
- part of the new pipe auth struct.
- */
-
- result = cli_rpc_pipe_open_schannel_with_creds(
- conn->cli, &ndr_table_netlogon, transport,
- creds,
- conn->netlogon_creds,
+ result = rpccli_connect_netlogon(
+ conn->cli, transport,
+ conn->netlogon_creds_ctx, conn->netlogon_force_reauth, creds,
&conn->netlogon_pipe);
+ conn->netlogon_force_reauth = false;
if (!NT_STATUS_IS_OK(result)) {
- DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
- "was %s\n", nt_errstr(result)));
-
- invalidate_cm_connection(domain);
+ DBG_DEBUG("rpccli_connect_netlogon failed: %s\n",
+ nt_errstr(result));
return result;
}
return status;
}
+NTSTATUS cm_connect_netlogon_secure(struct winbindd_domain *domain,
+ struct rpc_pipe_client **cli,
+ struct netlogon_creds_cli_context **ppdc)
+{
+ NTSTATUS status;
+
+ if (domain->secure_channel_type == SEC_CHAN_NULL) {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
+
+ status = cm_connect_netlogon(domain, cli);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (domain->conn.netlogon_creds_ctx == NULL) {
+ return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
+ }
+
+ *ppdc = domain->conn.netlogon_creds_ctx;
+ return NT_STATUS_OK;
+}
+
void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
void *private_data,
uint32_t msg_type,
}
TALLOC_FREE(freeit);
}
+
+void winbind_msg_disconnect_dc(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ struct winbindd_domain *domain;
+
+ for (domain = domain_list(); domain; domain = domain->next) {
+ if (domain->internal) {
+ continue;
+ }
+ invalidate_cm_connection(domain);
+ }
+}