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.
_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),
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)) {
goto ipc_fallback;
}
- if (domain->primary && lp_security() == SEC_ADS) {
- cli_credentials_set_kerberos_state(creds,
- CRED_AUTO_USE_KERBEROS);
- } else if (domain->active_directory) {
- cli_credentials_set_kerberos_state(creds,
- CRED_MUST_USE_KERBEROS);
- } else {
- cli_credentials_set_kerberos_state(creds,
- CRED_DONT_USE_KERBEROS);
- }
-
if (creds_domain != domain) {
/*
* We can only use schannel against a direct trust
bool *retry)
{
bool try_ipc_auth = false;
- const char *machine_password = NULL;
- const char *machine_krb5_principal = NULL;
+ const char *machine_principal = NULL;
+ const char *machine_realm = NULL;
const char *machine_account = NULL;
const char *machine_domain = NULL;
int flags = 0;
struct cli_credentials *creds = NULL;
- enum credentials_use_kerberos krb5_state;
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_signing();
+ enum smb_signing_setting smb_sign_client_connections = lp_client_ipc_signing();
if (smb_sign_client_connections == SMB_SIGNING_DEFAULT) {
/*
goto done;
}
- flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
-
- *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);
cli_set_timeout(*cli, 10000); /* 10 seconds */
+ set_socket_options(sockfd, lp_socket_options());
+
result = smbXcli_negprot((*cli)->conn, (*cli)->timeout,
lp_client_ipc_min_protocol(),
lp_client_ipc_max_protocol());
}
}
- krb5_state = cli_credentials_get_kerberos_state(creds);
-
- machine_krb5_principal = cli_credentials_get_principal(creds,
+ machine_principal = cli_credentials_get_principal(creds,
talloc_tos());
- if (machine_krb5_principal == NULL) {
- krb5_state = CRED_DONT_USE_KERBEROS;
- }
-
+ machine_realm = cli_credentials_get_realm(creds);
machine_account = cli_credentials_get_username(creds);
- machine_password = cli_credentials_get_password(creds);
machine_domain = cli_credentials_get_domain(creds);
- if (krb5_state != CRED_DONT_USE_KERBEROS) {
+ 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));
- /* Try a krb5 session */
-
- (*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));
-
- 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,
- machine_domain);
-
- if (NT_STATUS_IS_OK(result)) {
- goto session_setup_done;
- }
-
- DEBUG(4,("failed kerberos session setup with %s\n",
- nt_errstr(result)));
+ if (cli_credentials_is_anonymous(creds)) {
+ goto anon_fallback;
}
- if (krb5_state != CRED_MUST_USE_KERBEROS) {
- /* 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 using NTLMSSP with username "
- "[%s]\\[%s]\n", controller, lp_netbios_name(),
- machine_domain, machine_account));
-
- result = cli_session_setup(*cli,
- machine_account,
- machine_password,
- strlen(machine_password)+1,
- machine_password,
- strlen(machine_password)+1,
- machine_domain);
- }
+ winbindd_set_locator_kdc_envs(domain);
+ result = cli_session_setup_creds(*cli, creds);
if (NT_STATUS_IS_OK(result)) {
goto session_setup_done;
}
+ 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
|| NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS)
|| NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE))
{
- if (cli_credentials_is_anonymous(creds)) {
- goto done;
- }
-
if (!cm_is_ipc_credentials(creds)) {
goto ipc_fallback;
}
goto anon_fallback;
}
- DEBUG(4, ("authenticated session setup failed with %s\n",
- nt_errstr(result)));
-
goto done;
ipc_fallback:
- result = cm_get_ipc_credentials(talloc_tos(), &creds);
- if (!NT_STATUS_IS_OK(result)) {
+ TALLOC_FREE(creds);
+ tmp_status = cm_get_ipc_credentials(talloc_tos(), &creds);
+ if (!NT_STATUS_IS_OK(tmp_status)) {
+ result = tmp_status;
goto done;
}
if (cli_credentials_is_anonymous(creds)) {
- TALLOC_FREE(creds);
goto anon_fallback;
}
machine_account = cli_credentials_get_username(creds);
- machine_password = cli_credentials_get_password(creds);
machine_domain = cli_credentials_get_domain(creds);
- /* Fall back to non-kerberos session setup using NTLMSSP SPNEGO with the ipc creds. */
- (*cli)->use_kerberos = False;
-
DEBUG(5, ("connecting to %s from %s using NTLMSSP with username "
"[%s]\\[%s]\n", controller, lp_netbios_name(),
machine_domain, machine_account));
- result = cli_session_setup(*cli,
- machine_account,
- machine_password,
- strlen(machine_password)+1,
- machine_password,
- strlen(machine_password)+1,
- machine_domain);
-
+ result = cli_session_setup_creds(*cli, creds);
if (NT_STATUS_IS_OK(result)) {
goto session_setup_done;
}
+ 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
goto anon_fallback;
}
- DEBUG(4, ("authenticated session setup failed with %s\n",
- nt_errstr(result)));
-
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 ));
- (*cli)->use_kerberos = False;
-
- result = cli_session_setup(*cli, "", "", 0, "", 0, "");
+ result = cli_session_setup_anon(*cli);
if (NT_STATUS_IS_OK(result)) {
DEBUG(5, ("Connected anonymously\n"));
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", "", 0);
-
+ 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);
}
done:
TALLOC_FREE(mutex);
+ 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);
/*******************************************************************
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;
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)) {
*******************************************************************/
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) )
{
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;
*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;
}
table,
session_info,
NULL,
+ NULL,
winbind_messaging_context(),
&cli);
} else {
status = rpc_pipe_open_internal(mem_ctx,
- &table->syntax_id,
+ table,
session_info,
NULL,
+ NULL,
winbind_messaging_context(),
&cli);
}
}
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 = need_rw_dc ? DS_WRITABLE_REQUIRED : 0;
if ((mem_ctx = talloc_init("cm_open_connection")) == NULL) {
set_domain_offline(domain);
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) {
- TALLOC_FREE(mem_ctx);
- 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) {
TALLOC_FREE(mem_ctx);
return NT_STATUS_NO_MEMORY;
}
+
+ domain->dcaddr = ss;
+ } else {
+ winbind_add_failed_connection_entry(domain, saf_servername,
+ NT_STATUS_UNSUCCESSFUL);
}
}
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
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);
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;
}
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 when trying schannel\n", domain->name));
+ DBG_DEBUG("No user available for domain %s when trying "
+ "schannel\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) {
- return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+ 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;
+ }
+
+ DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL for %s, "
+ "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);
+ 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,
}
/****************************************************************************
-Open a LSA connection to a DC, suiteable for LSA lookup calls.
+Open a NETLOGON connection to a DC, suiteable for SamLogon calls.
****************************************************************************/
NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,