#include "messages.h"
#include "auth/gensec/gensec.h"
#include "../libcli/smb/smbXcli_base.h"
-#include "lib/param/loadparm.h"
+#include "libcli/auth/netlogon_creds_cli.h"
+#include "auth.h"
+#include "rpc_server/rpc_ncacn_np.h"
+#include "auth/credentials/credentials.h"
+#include "lib/param/param.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
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 set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain );
static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
- struct dc_name_ip **dcs, int *num_dcs);
+ struct dc_name_ip **dcs, int *num_dcs,
+ uint32_t request_flags);
/****************************************************************
Child failed to find DC's. Reschedule check.
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;
}
}
_exit(1);
}
- if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs)) || (num_dcs == 0)) {
+ if ((!get_dcs(mem_ctx, domain, &dcs, &num_dcs, 0)) || (num_dcs == 0)) {
/* Still offline ? Can't find DC's. */
messaging_send_buf(winbind_messaging_context(),
pid_to_procid(parent_pid),
}
}
+void winbind_msg_domain_offline(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ const char *domain_name = (const char *)data->data;
+ struct winbindd_domain *domain;
+
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ return;
+ }
+
+ domain->online = false;
+
+ DEBUG(10, ("Domain %s is marked as offline now.\n",
+ domain_name));
+}
+
+void winbind_msg_domain_online(struct messaging_context *msg_ctx,
+ void *private_data,
+ uint32_t msg_type,
+ struct server_id server_id,
+ DATA_BLOB *data)
+{
+ const char *domain_name = (const char *)data->data;
+ struct winbindd_domain *domain;
+
+ domain = find_domain_from_name_noinit(domain_name);
+ if (domain == NULL) {
+ return;
+ }
+
+ domain->online = true;
+
+ DEBUG(10, ("Domain %s is marked as online now.\n",
+ domain_name));
+}
+
/****************************************************************
Set domain offline and also add handler to put us back online
if we detect a DC.
void set_domain_offline(struct winbindd_domain *domain)
{
+ pid_t parent_pid = getppid();
+
DEBUG(10,("set_domain_offline: called for domain %s\n",
domain->name ));
DEBUG(10,("set_domain_offline: added event handler for domain %s\n",
domain->name ));
+ /* Send a message to the parent that the domain is offline. */
+ if (parent_pid > 1 && !domain->internal) {
+ messaging_send_buf(winbind_messaging_context(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_DOMAIN_OFFLINE,
+ (uint8_t *)domain->name,
+ strlen(domain->name) + 1);
+ }
+
/* Send an offline message to the idmap child when our
primary domain goes offline */
static void set_domain_online(struct winbindd_domain *domain)
{
+ pid_t parent_pid = getppid();
+
DEBUG(10,("set_domain_online: called for domain %s\n",
domain->name ));
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(),
+ pid_to_procid(parent_pid),
+ MSG_WINBIND_DOMAIN_ONLINE,
+ (uint8_t *)domain->name,
+ strlen(domain->name) + 1);
+ }
+
/* Send an online message to the idmap child when our
primary domain comes online */
}
}
+static NTSTATUS cm_get_ipc_credentials(TALLOC_CTX *mem_ctx,
+ struct cli_credentials **_creds)
+{
+
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
+ struct loadparm_context *lp_ctx;
+ char *username = NULL;
+ char *netbios_domain = NULL;
+ char *password = NULL;
+ struct cli_credentials *creds = NULL;
+ bool ok;
+
+ cm_get_ipc_userpass(&username, &netbios_domain, &password);
+
+ lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
+ if (lp_ctx == NULL) {
+ DEBUG(1, ("loadparm_init_s3 failed\n"));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+
+ creds = cli_credentials_init(mem_ctx);
+ if (creds == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ cli_credentials_set_conf(creds, lp_ctx);
+ cli_credentials_set_kerberos_state(creds, CRED_DONT_USE_KERBEROS);
+
+ ok = cli_credentials_set_domain(creds, netbios_domain, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ ok = cli_credentials_set_username(creds, username, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ ok = cli_credentials_set_password(creds, password, CRED_SPECIFIED);
+ if (!ok) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ *_creds = creds;
+ creds = NULL;
+ status = NT_STATUS_OK;
+ fail:
+ TALLOC_FREE(creds);
+ SAFE_FREE(username);
+ SAFE_FREE(netbios_domain);
+ SAFE_FREE(password);
+ TALLOC_FREE(frame);
+ return status;
+}
+
+static bool cm_is_ipc_credentials(struct cli_credentials *creds)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ char *ipc_account = NULL;
+ char *ipc_domain = NULL;
+ char *ipc_password = NULL;
+ const char *creds_account = NULL;
+ const char *creds_domain = NULL;
+ const char *creds_password = NULL;
+ bool ret = false;
+
+ cm_get_ipc_userpass(&ipc_account, &ipc_domain, &ipc_password);
+
+ creds_account = cli_credentials_get_username(creds);
+ creds_domain = cli_credentials_get_domain(creds);
+ creds_password = cli_credentials_get_password(creds);
+
+ if (!strequal(ipc_domain, creds_domain)) {
+ goto done;
+ }
+
+ if (!strequal(ipc_account, creds_account)) {
+ goto done;
+ }
+
+ if (!strcsequal(ipc_password, creds_password)) {
+ goto done;
+ }
+
+ ret = true;
+ done:
+ SAFE_FREE(ipc_account);
+ SAFE_FREE(ipc_domain);
+ SAFE_FREE(ipc_password);
+ TALLOC_FREE(frame);
+ return ret;
+}
+
static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
fstring dcname,
- struct sockaddr_storage *dc_ss)
+ struct sockaddr_storage *dc_ss,
+ uint32_t request_flags)
{
struct winbindd_domain *our_domain = NULL;
struct rpc_pipe_client *netlogon_pipe = NULL;
if (our_domain->active_directory) {
struct netr_DsRGetDCNameInfo *domain_info = NULL;
+ /*
+ * TODO request flags are not respected in the server
+ * (and in some cases, like REQUIRE_PDC, causes an error)
+ */
result = dcerpc_netr_DsRGetDCName(b,
mem_ctx,
our_domain->dcname,
domain->name,
NULL,
NULL,
- DS_RETURN_DNS_NAME,
+ request_flags|DS_RETURN_DNS_NAME,
&domain_info,
&werr);
if (NT_STATUS_IS_OK(result) && W_ERROR_IS_OK(werr)) {
/**
* Helper function to assemble trust password and account name
*/
-static NTSTATUS get_trust_creds(const struct winbindd_domain *domain,
- char **machine_password,
- char **machine_account,
- char **machine_krb5_principal)
+static NTSTATUS get_trust_credentials(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ bool netlogon,
+ struct cli_credentials **_creds)
{
- const char *account_name;
- const char *name = NULL;
+ const struct winbindd_domain *creds_domain = NULL;
+ struct cli_credentials *creds;
+ NTSTATUS status;
+ bool force_machine_account = false;
/* If we are a DC and this is not our own domain */
- if (IS_DC) {
- name = domain->name;
- } else {
- struct winbindd_domain *our_domain = find_our_domain();
-
- if (!our_domain)
- return NT_STATUS_INVALID_SERVER_STATE;
-
- name = our_domain->name;
- }
-
- if (!get_trust_pw_clear(name, machine_password,
- &account_name, NULL))
- {
- return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ if (!domain->active_directory) {
+ if (!netlogon) {
+ /*
+ * For non active directory domains
+ * we can only use NTLMSSP for SMB.
+ *
+ * But the trust account is not allowed
+ * to use SMB with NTLMSSP.
+ */
+ force_machine_account = true;
+ }
}
- if ((machine_account != NULL) &&
- (asprintf(machine_account, "%s$", account_name) == -1))
- {
- return NT_STATUS_NO_MEMORY;
+ if (IS_DC && !force_machine_account) {
+ creds_domain = domain;
+ } else {
+ creds_domain = find_our_domain();
+ if (creds_domain == NULL) {
+ return NT_STATUS_INVALID_SERVER_STATE;
+ }
}
- /* For now assume our machine account only exists in our domain */
+ status = pdb_get_trust_credentials(creds_domain->name,
+ creds_domain->alt_name,
+ mem_ctx,
+ &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto ipc_fallback;
+ }
- if (machine_krb5_principal != NULL)
- {
- struct winbindd_domain *our_domain = find_our_domain();
+ if (creds_domain != domain) {
+ /*
+ * We can only use schannel against a direct trust
+ */
+ cli_credentials_set_secure_channel_type(creds,
+ SEC_CHAN_NULL);
+ }
- if (!our_domain) {
- return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
- }
+ *_creds = creds;
+ return NT_STATUS_OK;
- if (asprintf(machine_krb5_principal, "%s$@%s",
- account_name, our_domain->alt_name) == -1)
- {
- return NT_STATUS_NO_MEMORY;
- }
+ ipc_fallback:
+ if (netlogon) {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
- if (!strupper_m(*machine_krb5_principal)) {
- SAFE_FREE(*machine_krb5_principal);
- return NT_STATUS_INVALID_PARAMETER;
- }
+ status = cm_get_ipc_credentials(mem_ctx, &creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
+ *_creds = creds;
return NT_STATUS_OK;
}
to the pipe.
************************************************************************/
-static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
+static NTSTATUS cm_prepare_connection(struct winbindd_domain *domain,
const int sockfd,
const char *controller,
struct cli_state **cli,
bool *retry)
{
- bool try_spnego = false;
bool try_ipc_auth = false;
- char *machine_password = NULL;
- char *machine_krb5_principal = NULL;
- char *machine_account = NULL;
- char *ipc_username = NULL;
- char *ipc_domain = NULL;
- char *ipc_password = NULL;
+ const char *machine_principal = NULL;
+ const char *machine_realm = NULL;
+ const char *machine_account = NULL;
+ const char *machine_domain = NULL;
int flags = 0;
- uint16_t sec_mode = 0;
+ struct cli_credentials *creds = NULL;
struct named_mutex *mutex;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+ NTSTATUS tmp_status;
+ NTSTATUS tcon_status = NT_STATUS_NETWORK_NAME_DELETED;
+
+ enum smb_signing_setting smb_sign_client_connections = lp_client_ipc_signing();
+
+ if (smb_sign_client_connections == SMB_SIGNING_DEFAULT) {
+ /*
+ * If we are connecting to our own AD domain, require
+ * smb signing to disrupt MITM attacks
+ */
+ if (domain->primary && lp_security() == SEC_ADS) {
+ smb_sign_client_connections = SMB_SIGNING_REQUIRED;
+ /*
+ * If we are in or are an AD domain and connecting to another
+ * 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)
+ && domain->active_directory
+ && (domain->domain_trust_attribs
+ & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST)) {
+ smb_sign_client_connections = SMB_SIGNING_REQUIRED;
+ }
+ }
DEBUG(10,("cm_prepare_connection: connecting to DC %s for domain %s\n",
controller, domain->name ));
goto done;
}
- flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
-
- *cli = cli_state_create(NULL, sockfd,
- controller, domain->alt_name,
- SMB_SIGNING_DEFAULT, flags);
+ *cli = cli_state_create(NULL, sockfd, controller,
+ smb_sign_client_connections, flags);
if (*cli == NULL) {
close(sockfd);
DEBUG(1, ("Could not cli_initialize\n"));
cli_set_timeout(*cli, 10000); /* 10 seconds */
+ set_socket_options(sockfd, lp_socket_options());
+
result = smbXcli_negprot((*cli)->conn, (*cli)->timeout,
- lp_cli_minprotocol(),
- lp_cli_maxprotocol());
+ lp_client_ipc_min_protocol(),
+ lp_client_ipc_max_protocol());
if (!NT_STATUS_IS_OK(result)) {
DEBUG(1, ("cli_negprot failed: %s\n", nt_errstr(result)));
if (smbXcli_conn_protocol((*cli)->conn) >= PROTOCOL_NT1 &&
smb1cli_conn_capabilities((*cli)->conn) & CAP_EXTENDED_SECURITY) {
- try_spnego = true;
+ try_ipc_auth = true;
} else if (smbXcli_conn_protocol((*cli)->conn) >= PROTOCOL_SMB2_02) {
- try_spnego = true;
+ try_ipc_auth = true;
+ } else if (smb_sign_client_connections == SMB_SIGNING_REQUIRED) {
+ /*
+ * If we are forcing on SMB signing, then we must
+ * require authentication unless this is a one-way
+ * trust, and we have no stored user/password
+ */
+ try_ipc_auth = true;
}
- if (!is_dc_trusted_domain_situation(domain->name) && try_spnego) {
- result = get_trust_creds(domain, &machine_password,
- &machine_account,
- &machine_krb5_principal);
+ if (try_ipc_auth) {
+ result = get_trust_credentials(domain, talloc_tos(), false, &creds);
if (!NT_STATUS_IS_OK(result)) {
- goto anon_fallback;
+ DEBUG(1, ("get_trust_credentials(%s) failed: %s\n",
+ domain->name, nt_errstr(result)));
+ goto done;
+ }
+ } else {
+ /*
+ * Without SPNEGO or NTLMSSP (perhaps via SMB2) we
+ * would try and authentication with our machine
+ * account password and fail. This is very rare in
+ * the modern world however
+ */
+ creds = cli_credentials_init_anon(talloc_tos());
+ if (creds == NULL) {
+ result = NT_STATUS_NO_MEMORY;
+ DEBUG(1, ("cli_credentials_init_anon(%s) failed: %s\n",
+ domain->name, nt_errstr(result)));
+ goto done;
}
+ }
- if (lp_security() == SEC_ADS) {
+ machine_principal = cli_credentials_get_principal(creds,
+ talloc_tos());
+ machine_realm = cli_credentials_get_realm(creds);
+ machine_account = cli_credentials_get_username(creds);
+ machine_domain = cli_credentials_get_domain(creds);
- /* Try a krb5 session */
+ DEBUG(5, ("connecting to %s (%s, %s) with account [%s\\%s] principal "
+ "[%s] and realm [%s]\n",
+ controller, domain->name, domain->alt_name,
+ machine_domain, machine_account,
+ machine_principal, machine_realm));
- (*cli)->use_kerberos = True;
- DEBUG(5, ("connecting to %s from %s with kerberos principal "
- "[%s] and realm [%s]\n", controller, lp_netbios_name(),
- machine_krb5_principal, domain->alt_name));
+ if (cli_credentials_is_anonymous(creds)) {
+ goto anon_fallback;
+ }
- winbindd_set_locator_kdc_envs(domain);
+ winbindd_set_locator_kdc_envs(domain);
- result = cli_session_setup(*cli,
- machine_krb5_principal,
- machine_password,
- strlen(machine_password)+1,
- machine_password,
- strlen(machine_password)+1,
- lp_workgroup());
+ result = cli_session_setup_creds(*cli, creds);
+ if (NT_STATUS_IS_OK(result)) {
+ goto session_setup_done;
+ }
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(4,("failed kerberos session setup with %s\n",
- nt_errstr(result)));
- }
+ DEBUG(1, ("authenticated session setup to %s using %s failed with %s\n",
+ controller,
+ cli_credentials_get_unparsed_name(creds, talloc_tos()),
+ nt_errstr(result)));
- if (NT_STATUS_IS_OK(result)) {
- /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
- result = cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
- if (!NT_STATUS_IS_OK(result)) {
- goto done;
- }
- goto session_setup_done;
- }
+ /*
+ * If we are not going to validiate the conneciton
+ * with SMB signing, then allow us to fall back to
+ * anonymous
+ */
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT)
+ || NT_STATUS_EQUAL(result, NT_STATUS_TRUSTED_DOMAIN_FAILURE)
+ || NT_STATUS_EQUAL(result, NT_STATUS_INVALID_ACCOUNT_NAME)
+ || NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS)
+ || NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE))
+ {
+ if (!cm_is_ipc_credentials(creds)) {
+ goto ipc_fallback;
}
- /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the machine account. */
- (*cli)->use_kerberos = False;
-
- DEBUG(5, ("connecting to %s from %s with username "
- "[%s]\\[%s]\n", controller, lp_netbios_name(),
- lp_workgroup(), machine_account));
-
- result = cli_session_setup(*cli,
- machine_account,
- machine_password,
- strlen(machine_password)+1,
- machine_password,
- strlen(machine_password)+1,
- lp_workgroup());
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(4, ("authenticated session setup failed with %s\n",
- nt_errstr(result)));
+ if (smb_sign_client_connections == SMB_SIGNING_REQUIRED) {
+ goto done;
}
- if (NT_STATUS_IS_OK(result)) {
- /* Ensure creds are stored for NTLMSSP authenticated pipe access. */
- result = cli_init_creds(*cli, machine_account, lp_workgroup(), machine_password);
- if (!NT_STATUS_IS_OK(result)) {
- goto done;
- }
- goto session_setup_done;
- }
+ goto anon_fallback;
}
- /* Fall back to non-kerberos session setup with auth_user */
-
- (*cli)->use_kerberos = False;
-
- cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);
+ goto done;
- sec_mode = smb1cli_conn_server_security_mode((*cli)->conn);
+ ipc_fallback:
+ TALLOC_FREE(creds);
+ tmp_status = cm_get_ipc_credentials(talloc_tos(), &creds);
+ if (!NT_STATUS_IS_OK(tmp_status)) {
+ result = tmp_status;
+ goto done;
+ }
- try_ipc_auth = false;
- if (try_spnego) {
- try_ipc_auth = true;
- } else if (sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) {
- try_ipc_auth = true;
+ if (cli_credentials_is_anonymous(creds)) {
+ goto anon_fallback;
}
- if (try_ipc_auth && (strlen(ipc_username) > 0)) {
+ machine_account = cli_credentials_get_username(creds);
+ machine_domain = cli_credentials_get_domain(creds);
- /* Only try authenticated if we have a username */
+ DEBUG(5, ("connecting to %s from %s using NTLMSSP with username "
+ "[%s]\\[%s]\n", controller, lp_netbios_name(),
+ machine_domain, machine_account));
- DEBUG(5, ("connecting to %s from %s with username "
- "[%s]\\[%s]\n", controller, lp_netbios_name(),
- ipc_domain, ipc_username));
+ result = cli_session_setup_creds(*cli, creds);
+ if (NT_STATUS_IS_OK(result)) {
+ goto session_setup_done;
+ }
- if (NT_STATUS_IS_OK(cli_session_setup(
- *cli, ipc_username,
- ipc_password, strlen(ipc_password)+1,
- ipc_password, strlen(ipc_password)+1,
- ipc_domain))) {
- /* Successful logon with given username. */
- result = cli_init_creds(*cli, ipc_username, ipc_domain, ipc_password);
- if (!NT_STATUS_IS_OK(result)) {
- goto done;
- }
- goto session_setup_done;
- } else {
- DEBUG(4, ("authenticated session setup with user %s\\%s failed.\n",
- ipc_domain, ipc_username ));
- }
+ DEBUG(1, ("authenticated session setup to %s using %s failed with %s\n",
+ controller,
+ cli_credentials_get_unparsed_name(creds, talloc_tos()),
+ nt_errstr(result)));
+
+ /*
+ * If we are not going to validiate the conneciton
+ * with SMB signing, then allow us to fall back to
+ * anonymous
+ */
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT)
+ || NT_STATUS_EQUAL(result, NT_STATUS_TRUSTED_DOMAIN_FAILURE)
+ || NT_STATUS_EQUAL(result, NT_STATUS_INVALID_ACCOUNT_NAME)
+ || NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS)
+ || NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE))
+ {
+ goto anon_fallback;
}
+ goto done;
+
anon_fallback:
+ TALLOC_FREE(creds);
+
+ if (smb_sign_client_connections == SMB_SIGNING_REQUIRED) {
+ goto done;
+ }
/* Fall back to anonymous connection, this might fail later */
- DEBUG(10,("cm_prepare_connection: falling back to anonymous "
+ DEBUG(5,("cm_prepare_connection: falling back to anonymous "
"connection for DC %s\n",
controller ));
- result = cli_session_setup(*cli, "", NULL, 0, NULL, 0, "");
+ result = cli_session_setup_anon(*cli);
if (NT_STATUS_IS_OK(result)) {
DEBUG(5, ("Connected anonymously\n"));
- result = cli_init_creds(*cli, "", "", "");
- if (!NT_STATUS_IS_OK(result)) {
- goto done;
- }
goto session_setup_done;
}
+ DEBUG(1, ("anonymous session setup to %s failed with %s\n",
+ controller, nt_errstr(result)));
+
/* We can't session setup */
goto done;
session_setup_done:
+ TALLOC_FREE(creds);
/*
* This should be a short term hack until
smbXcli_session_set_disconnect_expired((*cli)->smb2.session);
}
+ result = cli_tree_connect(*cli, "IPC$", "IPC", NULL);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
+ goto done;
+ }
+ tcon_status = result;
+
/* cache the server name for later connections */
saf_store(domain->name, controller);
- if (domain->alt_name && (*cli)->use_kerberos) {
+ if (domain->alt_name) {
saf_store(domain->alt_name, controller);
}
winbindd_set_locator_kdc_envs(domain);
- result = cli_tree_connect(*cli, "IPC$", "IPC", "", 0);
-
- if (!NT_STATUS_IS_OK(result)) {
- DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));
- goto done;
- }
-
TALLOC_FREE(mutex);
*retry = False;
- /* set the domain if empty; needed for schannel connections */
- if ( !(*cli)->domain[0] ) {
- result = cli_set_domain((*cli), domain->name);
- if (!NT_STATUS_IS_OK(result)) {
- SAFE_FREE(ipc_username);
- SAFE_FREE(ipc_domain);
- SAFE_FREE(ipc_password);
- return result;
- }
- }
-
result = NT_STATUS_OK;
done:
TALLOC_FREE(mutex);
- SAFE_FREE(machine_account);
- SAFE_FREE(machine_password);
- SAFE_FREE(machine_krb5_principal);
- SAFE_FREE(ipc_username);
- SAFE_FREE(ipc_domain);
- SAFE_FREE(ipc_password);
+ TALLOC_FREE(creds);
+
+ if (NT_STATUS_IS_OK(result)) {
+ result = tcon_status;
+ }
if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(1, ("Failed to prepare SMB connection to %s: %s\n",
+ controller, nt_errstr(result)));
winbind_add_failed_connection_entry(domain, controller, result);
if ((*cli) != NULL) {
cli_shutdown(*cli);
}
static bool add_sockaddr_to_array(TALLOC_CTX *mem_ctx,
- struct sockaddr_storage *pss, uint16 port,
+ struct sockaddr_storage *pss, uint16_t port,
struct sockaddr_storage **addrs, int *num)
{
*addrs = talloc_realloc(mem_ctx, *addrs, struct sockaddr_storage, (*num)+1);
/*******************************************************************
convert an ip to a name
+ For an AD Domain, it checks the requirements of the request flags.
*******************************************************************/
-static bool dcip_to_name(TALLOC_CTX *mem_ctx,
- const struct winbindd_domain *domain,
- struct sockaddr_storage *pss,
- char **name)
+static bool dcip_check_name(TALLOC_CTX *mem_ctx,
+ const struct winbindd_domain *domain,
+ struct sockaddr_storage *pss,
+ char **name, uint32_t request_flags)
{
struct ip_service ip_list;
uint32_t nt_version = NETLOGON_NT_VERSION_1;
NTSTATUS status;
const char *dc_name;
fstring nbtname;
-
+#ifdef HAVE_ADS
+ bool is_ad_domain = false;
+#endif
ip_list.ss = *pss;
ip_list.port = 0;
/* For active directory servers, try to get the ldap server name.
None of these failures should be considered critical for now */
- if (lp_security() == SEC_ADS) {
+ if ((lp_security() == SEC_ADS) && (domain->alt_name != NULL)) {
+ is_ad_domain = true;
+ } else if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
+ is_ad_domain = domain->active_directory;
+ }
+
+ if (is_ad_domain) {
ADS_STRUCT *ads;
ADS_STATUS ads_status;
char addr[INET6_ADDRSTRLEN];
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)) {
}
namecache_store(*name, 0x20, 1, &ip_list);
- DEBUG(10,("dcip_to_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
+ DEBUG(10,("dcip_check_name: flags = 0x%x\n", (unsigned int)ads->config.flags));
if (domain->primary && (ads->config.flags & NBT_SERVER_KDC)) {
if (ads_closest_dc(ads)) {
- char *sitename = sitename_fetch(ads->config.realm);
+ char *sitename = sitename_fetch(mem_ctx, ads->config.realm);
/* We're going to use this KDC for this realm/domain.
If we are using sites, then force the krb5 libs
create_local_private_krb5_conf_for_domain(domain->alt_name,
domain->name,
sitename,
- pss,
- *name);
+ pss);
- SAFE_FREE(sitename);
+ TALLOC_FREE(sitename);
} else {
/* use an off site KDC */
create_local_private_krb5_conf_for_domain(domain->alt_name,
domain->name,
NULL,
- pss,
- *name);
+ pss);
}
winbindd_set_locator_kdc_envs(domain);
*******************************************************************/
static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
- struct dc_name_ip **dcs, int *num_dcs)
+ struct dc_name_ip **dcs, int *num_dcs,
+ uint32_t request_flags)
{
fstring dcname;
struct sockaddr_storage ss;
/* If not our domain, get the preferred DC, by asking our primary DC */
if ( !is_our_domain
- && get_dc_name_via_netlogon(domain, dcname, &ss)
+ && get_dc_name_via_netlogon(domain, dcname, &ss, request_flags)
&& add_one_dc_unique(mem_ctx, domain->name, dcname, &ss, dcs,
num_dcs) )
{
return True;
}
- if (sec == SEC_ADS) {
+ if ((sec == SEC_ADS) && (domain->alt_name != NULL)) {
char *sitename = NULL;
/* We need to make sure we know the local site before
get_dc_name(domain->name, domain->alt_name, dcname, &ss);
- sitename = sitename_fetch(domain->alt_name);
+ sitename = sitename_fetch(mem_ctx, domain->alt_name);
if (sitename) {
/* Do the site-specific AD dns lookup first. */
}
SAFE_FREE(ip_list);
- SAFE_FREE(sitename);
+ TALLOC_FREE(sitename);
iplist_size = 0;
}
static bool find_new_dc(TALLOC_CTX *mem_ctx,
struct winbindd_domain *domain,
- char **dcname, struct sockaddr_storage *pss, int *fd)
+ char **dcname, struct sockaddr_storage *pss, int *fd,
+ uint32_t request_flags)
{
struct dc_name_ip *dcs = NULL;
int num_dcs = 0;
const char **dcnames = NULL;
- int num_dcnames = 0;
+ size_t num_dcnames = 0;
struct sockaddr_storage *addrs = NULL;
int num_addrs = 0;
*fd = -1;
again:
- if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs) || (num_dcs == 0))
+ if (!get_dcs(mem_ctx, domain, &dcs, &num_dcs, request_flags) || (num_dcs == 0))
return False;
for (i=0; i<num_dcs; i++) {
}
/* Try to figure out the name */
- if (dcip_to_name(mem_ctx, domain, pss, dcname)) {
+ if (dcip_check_name(mem_ctx, domain, pss, dcname, request_flags)) {
return True;
}
const char *domain_name,
char **p_dc_name, char **p_dc_ip)
{
- char *key, *value, *p;
+ char *key, *p;
+ char *value = NULL;
bool ret = false;
char *dc_name = NULL;
char *dc_ip = NULL;
if (key == NULL) {
goto done;
}
- if (!gencache_get(key, NULL, &value, NULL)) {
+ if (!gencache_get(key, mem_ctx, &value, NULL)) {
goto done;
}
p = strchr(value, ' ');
TALLOC_FREE(dc_name);
TALLOC_FREE(dc_ip);
TALLOC_FREE(key);
+ TALLOC_FREE(value);
return ret;
}
+NTSTATUS wb_open_internal_pipe(TALLOC_CTX *mem_ctx,
+ const struct ndr_interface_table *table,
+ struct rpc_pipe_client **ret_pipe)
+{
+ struct rpc_pipe_client *cli = NULL;
+ const struct auth_session_info *session_info;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+
+ session_info = get_session_info_system();
+ SMB_ASSERT(session_info != NULL);
+
+ /* create a connection to the specified pipe */
+ if (lp_parm_bool(-1, "winbindd", "use external pipes", false)) {
+ status = rpc_pipe_open_interface(mem_ctx,
+ table,
+ session_info,
+ NULL,
+ NULL,
+ winbind_messaging_context(),
+ &cli);
+ } else {
+ status = rpc_pipe_open_internal(mem_ctx,
+ table,
+ session_info,
+ NULL,
+ NULL,
+ winbind_messaging_context(),
+ &cli);
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("open_internal_pipe: Could not connect to %s pipe: %s\n",
+ table->name, nt_errstr(status)));
+ return status;
+ }
+
+ if (ret_pipe) {
+ *ret_pipe = cli;
+ }
+
+ return NT_STATUS_OK;
+}
+
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 = saf_fetch( domain->name );
+ char *saf_servername;
int retries;
+ uint32_t request_flags = need_rw_dc ? DS_WRITABLE_REQUIRED : 0;
if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
- SAFE_FREE(saf_servername);
set_domain_offline(domain);
return NT_STATUS_NO_MEMORY;
}
+ saf_servername = saf_fetch(mem_ctx, domain->name );
+
/* we have to check the server affinity cache here since
later we select a DC based on response time and not preference */
before talking to it. It going down may have
triggered the reconnection. */
- if ( saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, saf_servername))) {
+ if (saf_servername && NT_STATUS_IS_OK(check_negative_conn_cache(domain->name, saf_servername))) {
+ struct sockaddr_storage ss;
+ char *dcname = NULL;
+ bool resolved = true;
- DEBUG(10,("cm_open_connection: saf_servername is '%s' for domain %s\n",
- saf_servername, domain->name ));
+ DEBUG(10, ("cm_open_connection: saf_servername is '%s' for domain %s\n",
+ saf_servername, domain->name));
/* convert an ip address to a name */
- if (is_ipaddress( saf_servername ) ) {
- char *dcname = NULL;
- struct sockaddr_storage ss;
-
+ if (is_ipaddress(saf_servername)) {
if (!interpret_string_addr(&ss, saf_servername,
- AI_NUMERICHOST)) {
+ AI_NUMERICHOST)) {
+ TALLOC_FREE(mem_ctx);
return NT_STATUS_UNSUCCESSFUL;
}
- if (dcip_to_name(mem_ctx, domain, &ss, &dcname)) {
- domain->dcname = talloc_strdup(domain,
- dcname);
- if (domain->dcname == NULL) {
- SAFE_FREE(saf_servername);
- return NT_STATUS_NO_MEMORY;
- }
- } else {
- winbind_add_failed_connection_entry(
- domain, saf_servername,
- NT_STATUS_UNSUCCESSFUL);
- }
} else {
- domain->dcname = talloc_strdup(domain, saf_servername);
+ if (!resolve_name(saf_servername, &ss, 0x20, true)) {
+ resolved = false;
+ }
+ }
+
+ if (resolved && dcip_check_name(mem_ctx, domain, &ss, &dcname, request_flags)) {
+ domain->dcname = talloc_strdup(domain,
+ dcname);
if (domain->dcname == NULL) {
- SAFE_FREE(saf_servername);
+ TALLOC_FREE(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
- }
- SAFE_FREE( saf_servername );
+ domain->dcaddr = ss;
+ } else {
+ winbind_add_failed_connection_entry(domain, saf_servername,
+ NT_STATUS_UNSUCCESSFUL);
+ }
}
for (retries = 0; retries < 3; retries++) {
result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
- DEBUG(10,("cm_open_connection: dcname is '%s' for domain %s\n",
- domain->dcname ? domain->dcname : "", domain->name ));
+ DEBUG(10, ("cm_open_connection: dcname is '%s' for domain %s\n",
+ domain->dcname ? domain->dcname : "", domain->name));
- if (domain->dcname != NULL
- && NT_STATUS_IS_OK(check_negative_conn_cache( domain->name, domain->dcname))
- && (resolve_name(domain->dcname, &domain->dcaddr, 0x20, true)))
+ if (domain->dcname != NULL &&
+ NT_STATUS_IS_OK(check_negative_conn_cache(domain->name,
+ domain->dcname)))
{
NTSTATUS status;
}
if ((fd == -1) &&
- !find_new_dc(mem_ctx, domain, &dcname, &domain->dcaddr, &fd))
+ !find_new_dc(mem_ctx, domain, &dcname, &domain->dcaddr, &fd, request_flags))
{
/* This is the one place where we will
set the global winbindd offline state
}
if (NT_STATUS_IS_OK(result)) {
+ bool seal_pipes = true;
winbindd_set_locator_kdc_envs(domain);
*/
store_current_dc_in_gencache(domain->name, domain->dcname,
new_conn->cli);
+
+ seal_pipes = lp_winbind_sealed_pipes();
+ seal_pipes = lp_parm_bool(-1, "winbind sealed pipes",
+ domain->name,
+ seal_pipes);
+
+ if (seal_pipes) {
+ new_conn->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ } else {
+ new_conn->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+ }
} else {
/* Ensure we setup the retry handler. */
set_domain_offline(domain);
/* Close down all open pipes on a connection. */
-void invalidate_cm_connection(struct winbindd_cm_conn *conn)
+void invalidate_cm_connection(struct winbindd_domain *domain)
{
NTSTATUS result;
+ struct winbindd_cm_conn *conn = &domain->conn;
/* We're closing down a possibly dead
connection. Don't have impossibly long (10s) timeouts. */
}
}
+ conn->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
+ conn->netlogon_force_reauth = false;
+ conn->netlogon_flags = 0;
+ TALLOC_FREE(conn->netlogon_creds);
+
if (conn->cli) {
cli_shutdown(conn->cli);
}
smbXcli_conn_disconnect(domain->conn.cli->conn, NT_STATUS_OK);
}
- invalidate_cm_connection(&domain->conn);
+ invalidate_cm_connection(domain);
}
for (cli_state = winbindd_client_list();
/* 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 (domain->internal) {
- domain->initialized = True;
- return NT_STATUS_OK;
+ if (dom_sid_equal(&domain->sid, &global_sid_Builtin)) {
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
- if (connection_ok(domain)) {
+ /* Still ask the internal LSA and SAMR server about the local domain */
+ if (skip_connection || connection_ok(domain)) {
if (!domain->initialized) {
set_dc_type_and_flags(domain);
}
return NT_STATUS_OK;
}
- invalidate_cm_connection(&domain->conn);
+ invalidate_cm_connection(domain);
+
+ if (!domain->primary && !domain->initialized) {
+ /*
+ * Before we connect to a trust, work out if it is an
+ * AD domain by asking our own domain.
+ */
+ 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);
return result;
}
-NTSTATUS init_dc_connection(struct winbindd_domain *domain)
+NTSTATUS init_dc_connection(struct winbindd_domain *domain, bool need_rw_dc)
{
- if (domain->internal) {
+ 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;
}
WERROR werr;
struct netr_DomainTrustList trusts;
int i;
- uint32 flags = (NETR_TRUST_FLAG_IN_FOREST |
+ uint32_t flags = (NETR_TRUST_FLAG_IN_FOREST |
NETR_TRUST_FLAG_OUTBOUND |
NETR_TRUST_FLAG_INBOUND);
struct rpc_pipe_client *cli;
return False;
}
+ mem_ctx = talloc_stackframe();
our_domain = find_our_domain();
-
- if ( !connection_ok(our_domain) ) {
- DEBUG(3,("set_dc_type_and_flags_trustinfo: No connection to our domain!\n"));
- return False;
+ if (our_domain->internal) {
+ result = init_dc_connection(our_domain, false);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(3,("set_dc_type_and_flags_trustinfo: "
+ "Not able to make a connection to our domain: %s\n",
+ nt_errstr(result)));
+ TALLOC_FREE(mem_ctx);
+ return false;
+ }
}
/* This won't work unless our domain is AD */
-
if ( !our_domain->active_directory ) {
+ TALLOC_FREE(mem_ctx);
return False;
}
- /* Use DsEnumerateDomainTrusts to get us the trust direction
- and type */
-
- result = cm_connect_netlogon(our_domain, &cli);
+ if (our_domain->internal) {
+ result = wb_open_internal_pipe(mem_ctx, &ndr_table_netlogon, &cli);
+ } else if (!connection_ok(our_domain)) {
+ DEBUG(3,("set_dc_type_and_flags_trustinfo: "
+ "No connection to our domain!\n"));
+ TALLOC_FREE(mem_ctx);
+ return False;
+ } else {
+ result = cm_connect_netlogon(our_domain, &cli);
+ }
if (!NT_STATUS_IS_OK(result)) {
DEBUG(5, ("set_dc_type_and_flags_trustinfo: Could not open "
"a connection to %s for PIPE_NETLOGON (%s)\n",
domain->name, nt_errstr(result)));
+ TALLOC_FREE(mem_ctx);
return False;
}
-
b = cli->binding_handle;
- if ( (mem_ctx = talloc_init("set_dc_type_and_flags_trustinfo")) == NULL ) {
- DEBUG(0,("set_dc_type_and_flags_trustinfo: talloc_init() failed!\n"));
- return False;
- }
-
+ /* Use DsEnumerateDomainTrusts to get us the trust direction and type. */
result = dcerpc_netr_DsrEnumerateDomainTrusts(b, mem_ctx,
cli->desthost,
flags,
DEBUG(0,("set_dc_type_and_flags_trustinfo: "
"failed to query trusted domain list: %s\n",
nt_errstr(result)));
- talloc_destroy(mem_ctx);
+ TALLOC_FREE(mem_ctx);
return false;
}
if (!W_ERROR_IS_OK(werr)) {
DEBUG(0,("set_dc_type_and_flags_trustinfo: "
"failed to query trusted domain list: %s\n",
win_errstr(werr)));
- talloc_destroy(mem_ctx);
+ TALLOC_FREE(mem_ctx);
return false;
}
domain->domain_type = trusts.array[i].trust_type;
domain->domain_trust_attribs = trusts.array[i].trust_attributes;
- if ( domain->domain_type == NETR_TRUST_TYPE_UPLEVEL )
+ if ( domain->domain_type == LSA_TRUST_TYPE_UPLEVEL )
domain->active_directory = True;
/* This flag is only set if the domain is *our*
domain->active_directory ? "" : "NOT "));
domain->can_do_ncacn_ip_tcp = domain->active_directory;
- domain->can_do_validation6 = domain->active_directory;
domain->initialized = True;
}
}
- talloc_destroy( mem_ctx );
+ TALLOC_FREE(mem_ctx);
return domain->initialized;
}
union dssetup_DsRoleInfo info;
union lsa_PolicyInformation *lsa_info = NULL;
- if (!connection_ok(domain)) {
+ if (!domain->internal && !connection_ok(domain)) {
return;
}
DEBUG(5, ("set_dc_type_and_flags_connect: domain %s\n", domain->name ));
- status = cli_rpc_pipe_open_noauth(domain->conn.cli,
- &ndr_table_dssetup,
- &cli);
+ if (domain->internal) {
+ status = wb_open_internal_pipe(mem_ctx,
+ &ndr_table_dssetup,
+ &cli);
+ } else {
+ status = cli_rpc_pipe_open_noauth(domain->conn.cli,
+ &ndr_table_dssetup,
+ &cli);
+ }
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
}
no_dssetup:
- status = cli_rpc_pipe_open_noauth(domain->conn.cli,
- &ndr_table_lsarpc, &cli);
-
+ if (domain->internal) {
+ status = wb_open_internal_pipe(mem_ctx,
+ &ndr_table_lsarpc,
+ &cli);
+ } else {
+ status = cli_rpc_pipe_open_noauth(domain->conn.cli,
+ &ndr_table_lsarpc, &cli);
+ }
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5, ("set_dc_type_and_flags_connect: Could not bind to "
"PI_LSARPC on domain %s: (%s)\n",
domain->active_directory = True;
if (lsa_info->dns.name.string) {
+ if (!strequal(domain->name, lsa_info->dns.name.string))
+ {
+ DEBUG(1, ("set_dc_type_and_flags_connect: DC "
+ "for domain %s claimed it was a DC "
+ "for domain %s, refusing to "
+ "initialize\n",
+ domain->name,
+ lsa_info->dns.name.string));
+ TALLOC_FREE(cli);
+ TALLOC_FREE(mem_ctx);
+ return;
+ }
talloc_free(domain->name);
domain->name = talloc_strdup(domain,
lsa_info->dns.name.string);
}
if (lsa_info->dns.dns_domain.string) {
+ if (domain->alt_name != NULL &&
+ !strequal(domain->alt_name,
+ lsa_info->dns.dns_domain.string))
+ {
+ DEBUG(1, ("set_dc_type_and_flags_connect: DC "
+ "for domain %s (%s) claimed it was "
+ "a DC for domain %s, refusing to "
+ "initialize\n",
+ domain->alt_name, domain->name,
+ lsa_info->dns.dns_domain.string));
+ TALLOC_FREE(cli);
+ TALLOC_FREE(mem_ctx);
+ return;
+ }
talloc_free(domain->alt_name);
domain->alt_name =
talloc_strdup(domain,
}
if (lsa_info->dns.sid) {
+ if (!is_null_sid(&domain->sid) &&
+ !dom_sid_equal(&domain->sid,
+ lsa_info->dns.sid))
+ {
+ DEBUG(1, ("set_dc_type_and_flags_connect: DC "
+ "for domain %s (%s) claimed it was "
+ "a DC for domain %s, refusing to "
+ "initialize\n",
+ dom_sid_string(talloc_tos(),
+ &domain->sid),
+ domain->name,
+ dom_sid_string(talloc_tos(),
+ lsa_info->dns.sid)));
+ TALLOC_FREE(cli);
+ TALLOC_FREE(mem_ctx);
+ return;
+ }
sid_copy(&domain->sid, lsa_info->dns.sid);
}
} else {
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
if (lsa_info->account_domain.name.string) {
+ if (!strequal(domain->name,
+ lsa_info->account_domain.name.string))
+ {
+ DEBUG(1,
+ ("set_dc_type_and_flags_connect: "
+ "DC for domain %s claimed it was"
+ " a DC for domain %s, refusing "
+ "to initialize\n", domain->name,
+ lsa_info->
+ account_domain.name.string));
+ TALLOC_FREE(cli);
+ TALLOC_FREE(mem_ctx);
+ return;
+ }
talloc_free(domain->name);
domain->name =
talloc_strdup(domain,
}
if (lsa_info->account_domain.sid) {
+ if (!is_null_sid(&domain->sid) &&
+ !dom_sid_equal(&domain->sid,
+ lsa_info->account_domain.sid))
+ {
+ DEBUG(1,
+ ("set_dc_type_and_flags_connect: "
+ "DC for domain %s (%s) claimed "
+ "it was a DC for domain %s, "
+ "refusing to initialize\n",
+ dom_sid_string(talloc_tos(),
+ &domain->sid),
+ domain->name,
+ dom_sid_string(talloc_tos(),
+ lsa_info->account_domain.sid)));
+ TALLOC_FREE(cli);
+ TALLOC_FREE(mem_ctx);
+ return;
+ }
sid_copy(&domain->sid, lsa_info->account_domain.sid);
}
}
domain->name, domain->active_directory ? "" : "NOT "));
domain->can_do_ncacn_ip_tcp = domain->active_directory;
- domain->can_do_validation6 = domain->active_directory;
TALLOC_FREE(cli);
{
/* we always have to contact our primary domain */
- if ( domain->primary ) {
+ if ( domain->primary || domain->internal) {
DEBUG(10,("set_dc_type_and_flags: setting up flags for "
- "primary domain\n"));
+ "primary or internal domain\n"));
set_dc_type_and_flags_connect( domain );
return;
}
***********************************************************************/
static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain,
- struct netlogon_creds_CredentialState **ppdc)
+ struct netlogon_creds_cli_context **ppdc)
{
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
struct rpc_pipe_client *netlogon_pipe;
- if (lp_client_schannel() == False) {
- return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ *ppdc = NULL;
+
+ if ((!IS_DC) && (!domain->primary)) {
+ 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;
+ return NT_STATUS_OK;
}
result = cm_connect_netlogon(domain, &netlogon_pipe);
return result;
}
- /* Return a pointer to the struct netlogon_creds_CredentialState from the
- netlogon pipe. */
+ if (domain->conn.netlogon_creds == NULL) {
+ return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
+ }
- if (!domain->conn.netlogon_pipe->dc) {
- return NT_STATUS_INTERNAL_ERROR; /* This shouldn't happen. */
+ if (!(domain->conn.netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+ return NT_STATUS_TRUSTED_DOMAIN_FAILURE;
}
- *ppdc = domain->conn.netlogon_pipe->dc;
+ *ppdc = domain->conn.netlogon_creds;
return NT_STATUS_OK;
}
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;
NTSTATUS status, result;
- struct netlogon_creds_CredentialState *p_creds;
- char *machine_password = NULL;
- char *machine_account = NULL;
- const char *domain_name = NULL;
+ struct netlogon_creds_cli_context *p_creds;
+ struct cli_credentials *creds = NULL;
+ bool retry = false; /* allow one retry attempt for expired session */
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);
+retry:
+ status = init_dc_connection_rpc(domain, need_rw_dc);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
* anonymous.
*/
- if ((conn->cli->user_name[0] == '\0') ||
- (conn->cli->domain[0] == '\0') ||
- (conn->cli->password == NULL || conn->cli->password[0] == '\0'))
- {
- status = get_trust_creds(domain, &machine_password,
- &machine_account, NULL);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(10, ("cm_connect_sam: No no user available for "
- "domain %s, trying schannel\n", conn->cli->domain));
- goto schannel;
- }
- domain_name = domain->name;
- } else {
- machine_password = SMB_STRDUP(conn->cli->password);
- machine_account = SMB_STRDUP(conn->cli->user_name);
- domain_name = conn->cli->domain;
+ result = get_trust_credentials(domain, talloc_tos(), false, &creds);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("cm_connect_sam: No user available for "
+ "domain %s, trying schannel\n", domain->name));
+ goto schannel;
}
- if (!machine_password || !machine_account) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
+ if (cli_credentials_is_anonymous(creds)) {
+ goto anonymous;
}
- /* We have an authenticated connection. Use a NTLMSSP SPNEGO
- authenticated SAMR pipe with sign & seal. */
- status = cli_rpc_pipe_open_spnego(conn->cli,
- &ndr_table_samr,
- NCACN_NP,
- GENSEC_OID_NTLMSSP,
- DCERPC_AUTH_LEVEL_PRIVACY,
- smbXcli_conn_remote_name(conn->cli->conn),
- domain_name,
- machine_account,
- machine_password,
- &conn->samr_pipe);
+ /*
+ * We have an authenticated connection. Use a SPNEGO
+ * authenticated SAMR pipe with sign & seal.
+ */
+ status = cli_rpc_pipe_open_with_creds(conn->cli,
+ &ndr_table_samr,
+ NCACN_NP,
+ DCERPC_AUTH_TYPE_SPNEGO,
+ conn->auth_level,
+ smbXcli_conn_remote_name(conn->cli->conn),
+ creds,
+ &conn->samr_pipe);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)
+ && !retry) {
+ invalidate_cm_connection(domain);
+ retry = true;
+ goto retry;
+ }
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("cm_connect_sam: failed to connect to SAMR "
"pipe for domain %s using NTLMSSP "
- "authenticated pipe: user %s\\%s. Error was "
- "%s\n", domain->name, domain_name,
- machine_account, nt_errstr(status)));
+ "authenticated pipe: user %s. Error was "
+ "%s\n", domain->name,
+ cli_credentials_get_unparsed_name(creds, talloc_tos()),
+ nt_errstr(status)));
goto schannel;
}
DEBUG(10,("cm_connect_sam: connected to SAMR pipe for "
"domain %s using NTLMSSP authenticated "
- "pipe: user %s\\%s\n", domain->name,
- domain_name, machine_account));
+ "pipe: user %s\n", domain->name,
+ cli_credentials_get_unparsed_name(creds, talloc_tos())));
status = dcerpc_samr_Connect2(conn->samr_pipe->binding_handle, mem_ctx,
conn->samr_pipe->desthost,
SEC_FLAG_MAXIMUM_ALLOWED,
&conn->sam_connect_handle,
&result);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+ invalidate_cm_connection(domain);
+ TALLOC_FREE(conn->samr_pipe);
+ retry = true;
+ goto retry;
+ }
+
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
goto open_domain;
}
nt_errstr(status) ));
goto anonymous;
}
- status = cli_rpc_pipe_open_schannel_with_key
+ 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,
- DCERPC_AUTH_LEVEL_PRIVACY,
- domain->name, &p_creds, &conn->samr_pipe);
+ creds, p_creds, &conn->samr_pipe);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)
+ && !retry) {
+ invalidate_cm_connection(domain);
+ retry = true;
+ goto retry;
+ }
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for "
SEC_FLAG_MAXIMUM_ALLOWED,
&conn->sam_connect_handle,
&result);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+ invalidate_cm_connection(domain);
+ TALLOC_FREE(conn->samr_pipe);
+ retry = true;
+ goto retry;
+ }
+
if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
goto open_domain;
}
anonymous:
/* Finally fall back to anonymous. */
+ if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
+ status = NT_STATUS_DOWNGRADE_DETECTED;
+ DEBUG(1, ("Unwilling to make SAMR 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(status)));
+ goto done;
+ }
status = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr,
&conn->samr_pipe);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)
+ && !retry) {
+ invalidate_cm_connection(domain);
+ retry = true;
+ goto retry;
+ }
+
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
SEC_FLAG_MAXIMUM_ALLOWED,
&conn->sam_connect_handle,
&result);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+ invalidate_cm_connection(domain);
+ TALLOC_FREE(conn->samr_pipe);
+ retry = true;
+ goto retry;
+ }
+
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10,("cm_connect_sam: rpccli_samr_Connect2 failed "
"for domain %s Error was %s\n",
ZERO_STRUCT(conn->sam_domain_handle);
return status;
} else if (!NT_STATUS_IS_OK(status)) {
- invalidate_cm_connection(conn);
+ invalidate_cm_connection(domain);
return status;
}
*cli = conn->samr_pipe;
*sam_handle = conn->sam_domain_handle;
- SAFE_FREE(machine_password);
- SAFE_FREE(machine_account);
return status;
}
open an schanneld ncacn_ip_tcp connection to LSA
***********************************************************************/
-NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
- TALLOC_CTX *mem_ctx,
- struct rpc_pipe_client **cli)
+static NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
+ TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client **cli)
{
struct winbindd_cm_conn *conn;
- struct netlogon_creds_CredentialState *creds;
+ struct netlogon_creds_cli_context *p_creds = NULL;
+ struct cli_credentials *creds = NULL;
NTSTATUS 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;
}
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_PRIVACY &&
- rpccli_is_connected(conn->lsa_pipe_tcp)) {
+ conn->lsa_pipe_tcp->auth->auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
goto done;
}
TALLOC_FREE(conn->lsa_pipe_tcp);
- status = cm_get_schannel_creds(domain, &creds);
+ status = cm_get_schannel_creds(domain, &p_creds);
if (!NT_STATUS_IS_OK(status)) {
goto done;
}
- status = cli_rpc_pipe_open_schannel_with_key(conn->cli,
- &ndr_table_lsarpc,
- NCACN_IP_TCP,
- DCERPC_AUTH_LEVEL_PRIVACY,
- domain->name,
- &creds,
- &conn->lsa_pipe_tcp);
+ 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)) {
DEBUG(10,("cli_rpc_pipe_open_schannel_with_key failed: %s\n",
nt_errstr(status)));
{
struct winbindd_cm_conn *conn;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
- struct netlogon_creds_CredentialState *p_creds;
+ struct netlogon_creds_cli_context *p_creds;
+ struct cli_credentials *creds = NULL;
+ bool retry = false; /* allow one retry attempt for expired session */
- result = init_dc_connection_rpc(domain);
+retry:
+ result = init_dc_connection_rpc(domain, false);
if (!NT_STATUS_IS_OK(result))
return result;
TALLOC_FREE(conn->lsa_pipe);
- if ((conn->cli->user_name[0] == '\0') ||
- (conn->cli->domain[0] == '\0') ||
- (conn->cli->password == NULL || conn->cli->password[0] == '\0')) {
- DEBUG(10, ("cm_connect_lsa: No no user available for "
- "domain %s, trying schannel\n", conn->cli->domain));
+ result = get_trust_credentials(domain, talloc_tos(), false, &creds);
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10, ("cm_connect_lsa: No user available for "
+ "domain %s, trying schannel\n", domain->name));
goto schannel;
}
- /* We have an authenticated connection. Use a NTLMSSP SPNEGO
- * authenticated LSA pipe with sign & seal. */
- result = cli_rpc_pipe_open_spnego
+ if (cli_credentials_is_anonymous(creds)) {
+ goto anonymous;
+ }
+
+ /*
+ * We have an authenticated connection. Use a SPNEGO
+ * authenticated LSA pipe with sign & seal.
+ */
+ result = cli_rpc_pipe_open_with_creds
(conn->cli, &ndr_table_lsarpc, NCACN_NP,
- GENSEC_OID_NTLMSSP,
- DCERPC_AUTH_LEVEL_PRIVACY,
+ DCERPC_AUTH_TYPE_SPNEGO,
+ conn->auth_level,
smbXcli_conn_remote_name(conn->cli->conn),
- conn->cli->domain, conn->cli->user_name, conn->cli->password,
+ creds,
&conn->lsa_pipe);
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED)
+ && !retry) {
+ invalidate_cm_connection(domain);
+ retry = true;
+ goto retry;
+ }
+
if (!NT_STATUS_IS_OK(result)) {
DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
"domain %s using NTLMSSP authenticated pipe: user "
- "%s\\%s. Error was %s. Trying schannel.\n",
- domain->name, conn->cli->domain,
- conn->cli->user_name, nt_errstr(result)));
+ "%s. Error was %s. Trying schannel.\n",
+ domain->name,
+ cli_credentials_get_unparsed_name(creds, talloc_tos()),
+ nt_errstr(result)));
goto schannel;
}
DEBUG(10,("cm_connect_lsa: connected to LSA pipe for domain %s using "
- "NTLMSSP authenticated pipe: user %s\\%s\n",
- domain->name, conn->cli->domain, conn->cli->user_name ));
+ "NTLMSSP authenticated pipe: user %s\n",
+ domain->name, cli_credentials_get_unparsed_name(creds, talloc_tos())));
result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
SEC_FLAG_MAXIMUM_ALLOWED,
&conn->lsa_policy);
+ if (NT_STATUS_EQUAL(result, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+ invalidate_cm_connection(domain);
+ TALLOC_FREE(conn->lsa_pipe);
+ retry = true;
+ goto retry;
+ }
+
if (NT_STATUS_IS_OK(result)) {
goto done;
}
nt_errstr(result) ));
goto anonymous;
}
- result = cli_rpc_pipe_open_schannel_with_key
+
+ 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,
- DCERPC_AUTH_LEVEL_PRIVACY,
- domain->name, &p_creds, &conn->lsa_pipe);
+ creds, p_creds, &conn->lsa_pipe);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED)
+ && !retry) {
+ invalidate_cm_connection(domain);
+ retry = true;
+ goto retry;
+ }
if (!NT_STATUS_IS_OK(result)) {
DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for "
result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
SEC_FLAG_MAXIMUM_ALLOWED,
&conn->lsa_policy);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+ invalidate_cm_connection(domain);
+ TALLOC_FREE(conn->lsa_pipe);
+ retry = true;
+ goto retry;
+ }
+
if (NT_STATUS_IS_OK(result)) {
goto done;
}
anonymous:
+ if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
+ result = NT_STATUS_DOWNGRADE_DETECTED;
+ DEBUG(1, ("Unwilling to make LSA 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)));
+ goto done;
+ }
+
result = cli_rpc_pipe_open_noauth(conn->cli,
&ndr_table_lsarpc,
&conn->lsa_pipe);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED)
+ && !retry) {
+ invalidate_cm_connection(domain);
+ retry = true;
+ goto retry;
+ }
+
if (!NT_STATUS_IS_OK(result)) {
- result = NT_STATUS_PIPE_NOT_AVAILABLE;
goto done;
}
result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True,
SEC_FLAG_MAXIMUM_ALLOWED,
&conn->lsa_policy);
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
+ invalidate_cm_connection(domain);
+ TALLOC_FREE(conn->lsa_pipe);
+ retry = true;
+ goto retry;
+ }
+
done:
if (!NT_STATUS_IS_OK(result)) {
- invalidate_cm_connection(conn);
+ invalidate_cm_connection(domain);
return result;
}
if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
- invalidate_cm_connection(&domain->conn);
+ invalidate_cm_connection(domain);
status = cm_connect_lsa_tcp(domain, mem_ctx, cli);
}
if (NT_STATUS_IS_OK(status)) {
* we tried twice to connect via ncan_ip_tcp and schannel and
* failed - maybe it is a trusted domain we can't connect to ?
* do not try tcp next time - gd
+ *
+ * This also prevents NETLOGON over TCP
*/
domain->can_do_ncacn_ip_tcp = false;
}
session key stored in conn->netlogon_pipe->dc->sess_key.
****************************************************************************/
-NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
- struct rpc_pipe_client **cli)
+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 winbindd_cm_conn *conn;
NTSTATUS result;
-
- uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES;
- uint8_t mach_pwd[16];
enum netr_SchannelType sec_chan_type;
- const char *account_name;
- struct rpc_pipe_client *netlogon_pipe = NULL;
+ struct netlogon_creds_CredentialState *netlogon_creds = NULL;
+ struct cli_credentials *creds = NULL;
*cli = NULL;
- result = init_dc_connection_rpc(domain);
+ 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);
- result = cli_rpc_pipe_open_noauth(conn->cli,
- &ndr_table_netlogon,
- &netlogon_pipe);
+ result = get_trust_credentials(domain, talloc_tos(), true, &creds);
if (!NT_STATUS_IS_OK(result)) {
- return result;
+ DBG_DEBUG("No user available for domain %s when trying "
+ "schannel\n", domain->name);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
- if ((!IS_DC) && (!domain->primary)) {
- /* Clear the schannel request bit and drop down */
- neg_flags &= ~NETLOGON_NEG_SCHANNEL;
- goto no_schannel;
+ 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));
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
}
- if (lp_client_schannel() != False) {
- neg_flags |= NETLOGON_NEG_SCHANNEL;
- }
+ 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",
+ domain->name);
+ return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ }
- if (!get_trust_pw_hash(domain->name, mach_pwd, &account_name,
- &sec_chan_type))
- {
- TALLOC_FREE(netlogon_pipe);
- return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
- }
+ DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL for %s, "
+ "fallback to noauth on NCACN_NP.\n",
+ domain->name);
- result = rpccli_netlogon_setup_creds(
- netlogon_pipe,
- domain->dcname, /* server name. */
- domain->name, /* domain name */
- lp_netbios_name(), /* client name */
- account_name, /* machine account */
- mach_pwd, /* machine password */
- sec_chan_type, /* from get_trust_pw */
- &neg_flags);
+ 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;
+ }
+ result = rpccli_create_netlogon_creds_with_creds(creds,
+ domain->dcname,
+ msg_ctx,
+ domain,
+ &conn->netlogon_creds);
if (!NT_STATUS_IS_OK(result)) {
- TALLOC_FREE(netlogon_pipe);
+ DEBUG(1, ("rpccli_create_netlogon_creds failed for %s, "
+ "unable to create NETLOGON credentials: %s\n",
+ domain->name, nt_errstr(result)));
return result;
}
- if ((lp_client_schannel() == True) &&
- ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
- DEBUG(3, ("Server did not offer schannel\n"));
- TALLOC_FREE(netlogon_pipe);
- return NT_STATUS_ACCESS_DENIED;
+ 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;
}
- no_schannel:
- if ((lp_client_schannel() == False) ||
- ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) {
- /*
- * NetSamLogonEx only works for schannel
- */
- domain->can_do_samlogon_ex = False;
+ 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;
+ }
- /* We're done - just keep the existing connection to NETLOGON
- * open */
- conn->netlogon_pipe = netlogon_pipe;
*cli = conn->netlogon_pipe;
return NT_STATUS_OK;
}
part of the new pipe auth struct.
*/
- result = cli_rpc_pipe_open_schannel_with_key(
- conn->cli, &ndr_table_netlogon, NCACN_NP,
- DCERPC_AUTH_LEVEL_PRIVACY, domain->name, &netlogon_pipe->dc,
+ result = cli_rpc_pipe_open_schannel_with_creds(
+ conn->cli, &ndr_table_netlogon, transport,
+ creds,
+ conn->netlogon_creds,
&conn->netlogon_pipe);
-
- /* We can now close the initial netlogon pipe. */
- TALLOC_FREE(netlogon_pipe);
-
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(conn);
+ invalidate_cm_connection(domain);
return result;
}
- /*
- * Always try netr_LogonSamLogonEx. We will fall back for NT4
- * which gives DCERPC_FAULT_OP_RNG_ERROR (function not
- * supported). We used to only try SamLogonEx for AD, but
- * Samba DCs can also do it. And because we don't distinguish
- * between Samba and NT4, always try it once.
- */
- domain->can_do_samlogon_ex = true;
-
*cli = conn->netlogon_pipe;
return NT_STATUS_OK;
}
+/****************************************************************************
+Open a NETLOGON connection to a DC, suiteable for SamLogon calls.
+****************************************************************************/
+
+NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
+ struct rpc_pipe_client **cli)
+{
+ NTSTATUS status;
+
+ status = init_dc_connection_rpc(domain, domain->rodc);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (domain->active_directory && domain->can_do_ncacn_ip_tcp) {
+ status = cm_connect_netlogon_transport(domain, NCACN_IP_TCP, cli);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
+ invalidate_cm_connection(domain);
+ status = cm_connect_netlogon_transport(domain, NCACN_IP_TCP, cli);
+ }
+ if (NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /*
+ * we tried twice to connect via ncan_ip_tcp and schannel and
+ * failed - maybe it is a trusted domain we can't connect to ?
+ * do not try tcp next time - gd
+ *
+ * This also prevents LSA over TCP
+ */
+ domain->can_do_ncacn_ip_tcp = false;
+ }
+
+ status = cm_connect_netlogon_transport(domain, NCACN_NP, cli);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
+ /*
+ * SMB2 session expired, needs reauthentication. Drop
+ * connection and retry.
+ */
+ invalidate_cm_connection(domain);
+ status = cm_connect_netlogon_transport(domain, NCACN_NP, cli);
+ }
+
+ return status;
+}
+
void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
void *private_data,
uint32_t msg_type,