From 38d4dba37406515181e4d6f1a1faffc18e652e27 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 27 Jul 2013 11:30:13 +0200 Subject: [PATCH] s3:rpc_client: make use of the new netlogon_creds_cli_context This exchanges rpc_pipe_client->dc with rpc_pipe_client->netlogon_creds and lets the secure channel session state be stored in node local database. This is the proper fix for a large number of bugs: https://bugzilla.samba.org/show_bug.cgi?id=6563 https://bugzilla.samba.org/show_bug.cgi?id=7944 https://bugzilla.samba.org/show_bug.cgi?id=7945 https://bugzilla.samba.org/show_bug.cgi?id=7568 https://bugzilla.samba.org/show_bug.cgi?id=8599 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- source3/libnet/libnet_join.c | 3 +- source3/libnet/libnet_samsync.c | 19 +- source3/rpc_client/cli_netlogon.c | 436 ++++++------------------- source3/rpc_client/cli_pipe.c | 139 ++------ source3/rpc_client/cli_pipe.h | 2 +- source3/rpc_client/cli_pipe_schannel.c | 3 +- source3/rpc_client/rpc_client.h | 2 +- source3/rpcclient/cmd_netlogon.c | 57 +++- source3/winbindd/winbindd.h | 9 - source3/winbindd/winbindd_cm.c | 36 +- source3/winbindd/winbindd_pam.c | 136 ++------ source3/wscript_build | 6 +- 12 files changed, 250 insertions(+), 598 deletions(-) diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index c1eccda1af1..5dc620f270e 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -1279,7 +1279,8 @@ NTSTATUS libnet_join_ok(const char *netbios_domain_name, status = cli_rpc_pipe_open_schannel_with_key( cli, &ndr_table_netlogon, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, - netbios_domain_name, &netlogon_pipe->dc, &pipe_hnd); + netbios_domain_name, + netlogon_pipe->netlogon_creds, &pipe_hnd); cli_shutdown(cli); diff --git a/source3/libnet/libnet_samsync.c b/source3/libnet/libnet_samsync.c index a10378558ca..02d3fc6ce7f 100644 --- a/source3/libnet/libnet_samsync.c +++ b/source3/libnet/libnet_samsync.c @@ -30,6 +30,7 @@ #include "../librpc/gen_ndr/ndr_netlogon_c.h" #include "../libcli/security/security.h" #include "messages.h" +#include "../libcli/auth/netlogon_creds_cli.h" /** * Fix up the delta, dealing with encryption issues so that the final @@ -213,8 +214,15 @@ static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx, do { struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL; + struct netlogon_creds_CredentialState *creds = NULL; - netlogon_creds_client_authenticator(ctx->cli->dc, &credential); + status = netlogon_creds_cli_lock(ctx->cli->netlogon_creds, + mem_ctx, &creds); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + netlogon_creds_client_authenticator(creds, &credential); if (ctx->single_object_replication && !ctx->force_full_replication) { @@ -254,28 +262,33 @@ static NTSTATUS libnet_samsync_delta(TALLOC_CTX *mem_ctx, } if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(creds); return status; } /* Check returned credentials. */ - if (!netlogon_creds_client_check(ctx->cli->dc, + if (!netlogon_creds_client_check(creds, &return_authenticator.cred)) { + TALLOC_FREE(creds); DEBUG(0,("credentials chain check failed\n")); return NT_STATUS_ACCESS_DENIED; } if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED)) { + TALLOC_FREE(creds); return result; } if (NT_STATUS_IS_ERR(result)) { + TALLOC_FREE(creds); break; } samsync_fix_delta_array(mem_ctx, - ctx->cli->dc, + creds, database_id, delta_enum_array); + TALLOC_FREE(creds); /* Process results */ callback_status = ctx->ops->process_objects(mem_ctx, database_id, diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c index 5e8a2fca412..fcd24d6f4cc 100644 --- a/source3/rpc_client/cli_netlogon.c +++ b/source3/rpc_client/cli_netlogon.c @@ -23,11 +23,13 @@ #include "includes.h" #include "rpc_client/rpc_client.h" #include "../libcli/auth/libcli_auth.h" +#include "../libcli/auth/netlogon_creds_cli.h" #include "../librpc/gen_ndr/ndr_netlogon_c.h" #include "rpc_client/cli_netlogon.h" #include "rpc_client/init_netlogon.h" #include "rpc_client/util_netlogon.h" #include "../libcli/security/security.h" +#include "lib/param/param.h" /**************************************************************************** Wrapper function that uses the auth and auth2 calls to set up a NETLOGON @@ -44,113 +46,81 @@ NTSTATUS rpccli_netlogon_setup_creds(struct rpc_pipe_client *cli, enum netr_SchannelType sec_chan_type, uint32_t *neg_flags_inout) { + TALLOC_CTX *frame = talloc_stackframe(); + struct loadparm_context *lp_ctx; NTSTATUS status; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - struct netr_Credential clnt_chal_send; - struct netr_Credential srv_chal_recv; struct samr_Password password; - bool retried = false; fstring mach_acct; - uint32_t neg_flags = *neg_flags_inout; struct dcerpc_binding_handle *b = cli->binding_handle; + struct netlogon_creds_CredentialState *creds = NULL; if (!ndr_syntax_id_equal(&cli->abstract_syntax, &ndr_table_netlogon.syntax_id)) { + TALLOC_FREE(frame); return NT_STATUS_INVALID_PARAMETER; } - TALLOC_FREE(cli->dc); - - /* Store the machine account password we're going to use. */ - memcpy(password.hash, machine_pwd, 16); - - fstr_sprintf( mach_acct, "%s$", machine_account); - - again: - /* Create the client challenge. */ - generate_random_buffer(clnt_chal_send.data, 8); - - /* Get the server challenge. */ - status = dcerpc_netr_ServerReqChallenge(b, talloc_tos(), - cli->srv_name_slash, - clnt_name, - &clnt_chal_send, - &srv_chal_recv, - &result); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - if (!NT_STATUS_IS_OK(result)) { - return result; + if (!strequal(lp_netbios_name(), clnt_name)) { + TALLOC_FREE(frame); + return NT_STATUS_INVALID_PARAMETER; } - /* Calculate the session key and client credentials */ + TALLOC_FREE(cli->netlogon_creds); - cli->dc = netlogon_creds_client_init(cli, - mach_acct, - clnt_name, - sec_chan_type, - &clnt_chal_send, - &srv_chal_recv, - &password, - &clnt_chal_send, - neg_flags); + fstr_sprintf( mach_acct, "%s$", machine_account); - if (!cli->dc) { + lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers()); + if (lp_ctx == NULL) { + TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } - - /* - * Send client auth-2 challenge and receive server repy. - */ - - status = dcerpc_netr_ServerAuthenticate2(b, talloc_tos(), - cli->srv_name_slash, - cli->dc->account_name, - sec_chan_type, - cli->dc->computer_name, - &clnt_chal_send, /* input. */ - &srv_chal_recv, /* output. */ - &neg_flags, - &result); + status = netlogon_creds_cli_context_global(lp_ctx, + NULL, /* msg_ctx */ + mach_acct, + sec_chan_type, + server_name, + domain, + cli, &cli->netlogon_creds); + talloc_unlink(frame, lp_ctx); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); return status; } - /* we might be talking to NT4, so let's downgrade in that case and retry - * with the returned neg_flags - gd */ - if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && !retried) { - retried = true; - TALLOC_FREE(cli->dc); - goto again; + status = netlogon_creds_cli_get(cli->netlogon_creds, + frame, &creds); + if (NT_STATUS_IS_OK(status)) { + DEBUG(5,("rpccli_netlogon_setup_creds: server %s using " + "cached credential\n", + cli->desthost)); + *neg_flags_inout = creds->negotiate_flags; + TALLOC_FREE(frame); + return NT_STATUS_OK; } - if (!NT_STATUS_IS_OK(result)) { - return result; - } - - /* - * Check the returned value using the initial - * server received challenge. - */ - - if (!netlogon_creds_client_check(cli->dc, &srv_chal_recv)) { - /* - * Server replied with bad credential. Fail. - */ - DEBUG(0,("rpccli_netlogon_setup_creds: server %s " - "replied with bad credential\n", - cli->desthost )); - return NT_STATUS_ACCESS_DENIED; - } + /* Store the machine account password we're going to use. */ + memcpy(password.hash, machine_pwd, 16); DEBUG(5,("rpccli_netlogon_setup_creds: server %s credential " "chain established.\n", cli->desthost )); - cli->dc->negotiate_flags = neg_flags; - *neg_flags_inout = neg_flags; + status = netlogon_creds_cli_auth(cli->netlogon_creds, b, + password, NULL); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return status; + } + + status = netlogon_creds_cli_get(cli->netlogon_creds, + frame, &creds); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return NT_STATUS_INTERNAL_ERROR; + } + *neg_flags_inout = creds->negotiate_flags; + TALLOC_FREE(frame); return NT_STATUS_OK; } @@ -163,20 +133,16 @@ NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli, const char *username, const char *password, const char *workstation, - uint16_t validation_level, + uint16_t _ignored_validation_level, int logon_type) { - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; NTSTATUS status; - struct netr_Authenticator clnt_creds; - struct netr_Authenticator ret_creds; union netr_LogonLevel *logon; - union netr_Validation validation; - uint8_t authoritative; + uint16_t validation_level = 0; + union netr_Validation *validation = NULL; + uint8_t authoritative = 0; + uint32_t flags = 0; fstring clnt_name_slash; - struct dcerpc_binding_handle *b = cli->binding_handle; - - ZERO_STRUCT(ret_creds); logon = talloc_zero(mem_ctx, union netr_LogonLevel); if (!logon) { @@ -191,8 +157,6 @@ NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli, /* Initialise input parameters */ - netlogon_creds_client_authenticator(cli->dc, &clnt_creds); - switch (logon_type) { case NetlogonInteractiveInformation: { @@ -208,17 +172,6 @@ NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli, nt_lm_owf_gen(password, ntpassword.hash, lmpassword.hash); - if (cli->dc->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { - netlogon_creds_aes_encrypt(cli->dc, lmpassword.hash, 16); - netlogon_creds_aes_encrypt(cli->dc, ntpassword.hash, 16); - } else if (cli->dc->negotiate_flags & NETLOGON_NEG_ARCFOUR) { - netlogon_creds_arcfour_crypt(cli->dc, lmpassword.hash, 16); - netlogon_creds_arcfour_crypt(cli->dc, ntpassword.hash, 16); - } else { - netlogon_creds_des_encrypt(cli->dc, &lmpassword); - netlogon_creds_des_encrypt(cli->dc, &ntpassword); - } - password_info->identity_info.domain_name.string = domain; password_info->identity_info.parameter_control = logon_parameters; password_info->identity_info.logon_id_low = 0xdead; @@ -281,28 +234,20 @@ NTSTATUS rpccli_netlogon_sam_logon(struct rpc_pipe_client *cli, return NT_STATUS_INVALID_INFO_CLASS; } - status = dcerpc_netr_LogonSamLogon(b, mem_ctx, - cli->srv_name_slash, - lp_netbios_name(), - &clnt_creds, - &ret_creds, - logon_type, - logon, - validation_level, - &validation, - &authoritative, - &result); + status = netlogon_creds_cli_LogonSamLogon(cli->netlogon_creds, + cli->binding_handle, + logon_type, + logon, + mem_ctx, + &validation_level, + &validation, + &authoritative, + &flags); if (!NT_STATUS_IS_OK(status)) { return status; } - /* Always check returned credentials */ - if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) { - DEBUG(0,("rpccli_netlogon_sam_logon: credentials chain check failed\n")); - return NT_STATUS_ACCESS_DENIED; - } - - return result; + return NT_STATUS_OK; } static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx, @@ -366,29 +311,24 @@ NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli, const char *domain, const char *workstation, const uint8 chal[8], - uint16_t validation_level, + uint16_t _ignored_validation_level, DATA_BLOB lm_response, DATA_BLOB nt_response, struct netr_SamInfo3 **info3) { - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; NTSTATUS status; const char *workstation_name_slash; - const char *server_name_slash; - struct netr_Authenticator clnt_creds; - struct netr_Authenticator ret_creds; union netr_LogonLevel *logon = NULL; struct netr_NetworkInfo *network_info; - uint8_t authoritative; - union netr_Validation validation; + uint16_t validation_level = 0; + union netr_Validation *validation = NULL; + uint8_t authoritative = 0; + uint32_t flags = 0; struct netr_ChallengeResponse lm; struct netr_ChallengeResponse nt; - struct dcerpc_binding_handle *b = cli->binding_handle; *info3 = NULL; - ZERO_STRUCT(ret_creds); - ZERO_STRUCT(lm); ZERO_STRUCT(nt); @@ -402,21 +342,13 @@ NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli, return NT_STATUS_NO_MEMORY; } - netlogon_creds_client_authenticator(cli->dc, &clnt_creds); - - if (server[0] != '\\' && server[1] != '\\') { - server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server); - } else { - server_name_slash = server; - } - if (workstation[0] != '\\' && workstation[1] != '\\') { workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation); } else { workstation_name_slash = workstation; } - if (!workstation_name_slash || !server_name_slash) { + if (!workstation_name_slash) { DEBUG(0, ("talloc_asprintf failed!\n")); return NT_STATUS_NO_MEMORY; } @@ -443,40 +375,27 @@ NTSTATUS rpccli_netlogon_sam_network_logon(struct rpc_pipe_client *cli, /* Marshall data and send request */ - status = dcerpc_netr_LogonSamLogon(b, mem_ctx, - server_name_slash, - lp_netbios_name(), - &clnt_creds, - &ret_creds, - NetlogonNetworkInformation, - logon, - validation_level, - &validation, - &authoritative, - &result); + status = netlogon_creds_cli_LogonSamLogon(cli->netlogon_creds, + cli->binding_handle, + NetlogonNetworkInformation, + logon, + mem_ctx, + &validation_level, + &validation, + &authoritative, + &flags); if (!NT_STATUS_IS_OK(status)) { return status; } - /* Always check returned credentials. */ - if (!netlogon_creds_client_check(cli->dc, &ret_creds.cred)) { - DEBUG(0,("rpccli_netlogon_sam_network_logon: credentials chain check failed\n")); - return NT_STATUS_ACCESS_DENIED; - } - - if (!NT_STATUS_IS_OK(result)) { - return result; - } - - netlogon_creds_decrypt_samlogon_validation(cli->dc, validation_level, - &validation); - - result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3); - if (!NT_STATUS_IS_OK(result)) { - return result; + status = map_validation_to_info3(mem_ctx, + validation_level, validation, + info3); + if (!NT_STATUS_IS_OK(status)) { + return status; } - return result; + return NT_STATUS_OK; } NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli, @@ -492,100 +411,18 @@ NTSTATUS rpccli_netlogon_sam_network_logon_ex(struct rpc_pipe_client *cli, DATA_BLOB nt_response, struct netr_SamInfo3 **info3) { - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - NTSTATUS status; - const char *workstation_name_slash; - const char *server_name_slash; - union netr_LogonLevel *logon = NULL; - struct netr_NetworkInfo *network_info; - uint8_t authoritative; - union netr_Validation validation; - struct netr_ChallengeResponse lm; - struct netr_ChallengeResponse nt; - uint32_t flags = 0; - struct dcerpc_binding_handle *b = cli->binding_handle; - - *info3 = NULL; - - ZERO_STRUCT(lm); - ZERO_STRUCT(nt); - - logon = talloc_zero(mem_ctx, union netr_LogonLevel); - if (!logon) { - return NT_STATUS_NO_MEMORY; - } - - network_info = talloc_zero(mem_ctx, struct netr_NetworkInfo); - if (!network_info) { - return NT_STATUS_NO_MEMORY; - } - - if (server[0] != '\\' && server[1] != '\\') { - server_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", server); - } else { - server_name_slash = server; - } - - if (workstation[0] != '\\' && workstation[1] != '\\') { - workstation_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", workstation); - } else { - workstation_name_slash = workstation; - } - - if (!workstation_name_slash || !server_name_slash) { - DEBUG(0, ("talloc_asprintf failed!\n")); - return NT_STATUS_NO_MEMORY; - } - - /* Initialise input parameters */ - - lm.data = lm_response.data; - lm.length = lm_response.length; - nt.data = nt_response.data; - nt.length = nt_response.length; - - network_info->identity_info.domain_name.string = domain; - network_info->identity_info.parameter_control = logon_parameters; - network_info->identity_info.logon_id_low = 0xdead; - network_info->identity_info.logon_id_high = 0xbeef; - network_info->identity_info.account_name.string = username; - network_info->identity_info.workstation.string = workstation_name_slash; - - memcpy(network_info->challenge, chal, 8); - network_info->nt = nt; - network_info->lm = lm; - - logon->network = network_info; - - /* Marshall data and send request */ - - status = dcerpc_netr_LogonSamLogonEx(b, mem_ctx, - server_name_slash, - lp_netbios_name(), - NetlogonNetworkInformation, - logon, - validation_level, - &validation, - &authoritative, - &flags, - &result); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!NT_STATUS_IS_OK(result)) { - return result; - } - - netlogon_creds_decrypt_samlogon_validation(cli->dc, validation_level, - &validation); - - result = map_validation_to_info3(mem_ctx, validation_level, &validation, info3); - if (!NT_STATUS_IS_OK(result)) { - return result; - } - - return result; + return rpccli_netlogon_sam_network_logon(cli, + mem_ctx, + logon_parameters, + server, + username, + domain, + workstation, + chal, + validation_level, + lm_response, + nt_response, + info3); } /********************************************************* @@ -605,11 +442,9 @@ NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli, const unsigned char new_trust_passwd_hash[16], enum netr_SchannelType sec_channel_type) { - NTSTATUS result, status; - struct netr_Authenticator clnt_creds, srv_cred; - struct dcerpc_binding_handle *b = cli->binding_handle; + NTSTATUS result; - if (!cli->dc) { + if (cli->netlogon_creds == NULL) { uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS | NETLOGON_NEG_SUPPORTS_AES; result = rpccli_netlogon_setup_creds(cli, @@ -627,77 +462,16 @@ NTSTATUS rpccli_netlogon_set_trust_password(struct rpc_pipe_client *cli, } } - netlogon_creds_client_authenticator(cli->dc, &clnt_creds); - - if (cli->dc->negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) { - - struct netr_CryptPassword new_password; - uint32_t old_timeout; - - init_netr_CryptPassword(new_trust_pwd_cleartext, - cli->dc, - &new_password); - - old_timeout = dcerpc_binding_handle_set_timeout(b, 600000); - - status = dcerpc_netr_ServerPasswordSet2(b, mem_ctx, - cli->srv_name_slash, - cli->dc->account_name, - sec_channel_type, - cli->dc->computer_name, - &clnt_creds, - &srv_cred, - &new_password, - &result); - - dcerpc_binding_handle_set_timeout(b, old_timeout); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("dcerpc_netr_ServerPasswordSet2 failed: %s\n", - nt_errstr(status))); - return status; - } - } else { - - struct samr_Password new_password; - uint32_t old_timeout; - - memcpy(new_password.hash, new_trust_passwd_hash, sizeof(new_password.hash)); - netlogon_creds_des_encrypt(cli->dc, &new_password); - - old_timeout = dcerpc_binding_handle_set_timeout(b, 600000); - - status = dcerpc_netr_ServerPasswordSet(b, mem_ctx, - cli->srv_name_slash, - cli->dc->account_name, - sec_channel_type, - cli->dc->computer_name, - &clnt_creds, - &srv_cred, - &new_password, - &result); - - dcerpc_binding_handle_set_timeout(b, old_timeout); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("dcerpc_netr_ServerPasswordSet failed: %s\n", - nt_errstr(status))); - return status; - } - } - - /* Always check returned credentials. */ - if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) { - DEBUG(0,("credentials chain check failed\n")); - return NT_STATUS_ACCESS_DENIED; - } - + result = netlogon_creds_cli_ServerPasswordSet(cli->netlogon_creds, + cli->binding_handle, + new_trust_pwd_cleartext, + NULL); /* new_version */ if (!NT_STATUS_IS_OK(result)) { - DEBUG(0,("dcerpc_netr_ServerPasswordSet{2} failed: %s\n", + DEBUG(0,("netlogon_creds_cli_ServerPasswordSet failed: %s\n", nt_errstr(result))); return result; } - return result; + return NT_STATUS_OK; } diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index b6908be7e28..7f79046fc7c 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -24,6 +24,7 @@ #include "librpc/gen_ndr/ndr_epmapper_c.h" #include "../librpc/gen_ndr/ndr_dssetup.h" #include "../libcli/auth/schannel.h" +#include "../libcli/auth/netlogon_creds_cli.h" #include "auth_generic.h" #include "librpc/gen_ndr/ndr_dcerpc.h" #include "librpc/gen_ndr/ndr_netlogon_c.h" @@ -3024,34 +3025,39 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli, enum dcerpc_transport_t transport, enum dcerpc_AuthLevel auth_level, const char *domain, - struct netlogon_creds_CredentialState **pdc, + struct netlogon_creds_cli_context *netlogon_creds, struct rpc_pipe_client **_rpccli) { struct rpc_pipe_client *rpccli; struct pipe_auth_data *rpcauth; + struct netlogon_creds_CredentialState *creds = NULL; NTSTATUS status; - NTSTATUS result; - struct netlogon_creds_CredentialState save_creds; - struct netr_Authenticator auth; - struct netr_Authenticator return_auth; - union netr_Capabilities capabilities; const char *target_service = table->authservices->names[0]; + int rpc_pipe_bind_dbglvl = 0; status = cli_rpc_pipe_open(cli, transport, table, &rpccli); if (!NT_STATUS_IS_OK(status)) { return status; } + status = netlogon_creds_cli_lock(netlogon_creds, rpccli, &creds); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("netlogon_creds_cli_get returned %s\n", + nt_errstr(status))); + TALLOC_FREE(rpccli); + return status; + } + status = rpccli_generic_bind_data(rpccli, DCERPC_AUTH_TYPE_SCHANNEL, auth_level, NULL, target_service, domain, - (*pdc)->computer_name, + creds->computer_name, NULL, CRED_AUTO_USE_KERBEROS, - *pdc, + creds, &rpcauth); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("rpccli_generic_bind_data returned %s\n", @@ -3060,120 +3066,43 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli, return status; } - /* - * The credentials on a new netlogon pipe are the ones we are passed - * in - copy them over - * - * This may get overwritten... in rpc_pipe_bind()... - */ - rpccli->dc = netlogon_creds_copy(rpccli, *pdc); - if (rpccli->dc == NULL) { - TALLOC_FREE(rpccli); - return NT_STATUS_NO_MEMORY; - } - status = rpc_pipe_bind(rpccli, rpcauth); + if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) { + rpc_pipe_bind_dbglvl = 1; + netlogon_creds_cli_delete(netlogon_creds, &creds); + } if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("cli_rpc_pipe_open_schannel_with_key: " - "cli_rpc_pipe_bind failed with error %s\n", - nt_errstr(status) )); + DEBUG(rpc_pipe_bind_dbglvl, + ("cli_rpc_pipe_open_schannel_with_key: " + "rpc_pipe_bind failed with error %s\n", + nt_errstr(status))); TALLOC_FREE(rpccli); return status; } - if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) { - goto done; - } - - save_creds = *rpccli->dc; - ZERO_STRUCT(return_auth); - ZERO_STRUCT(capabilities); + TALLOC_FREE(creds); - netlogon_creds_client_authenticator(&save_creds, &auth); - - status = dcerpc_netr_LogonGetCapabilities(rpccli->binding_handle, - talloc_tos(), - rpccli->srv_name_slash, - save_creds.computer_name, - &auth, &return_auth, - 1, &capabilities, - &result); - if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) { - if (save_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { - DEBUG(5, ("AES was negotiated and the error was %s - " - "downgrade detected\n", - nt_errstr(status))); - TALLOC_FREE(rpccli); - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - /* This is probably an old Samba Version */ - DEBUG(5, ("We are checking against an NT or old Samba - %s\n", - nt_errstr(status))); + if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) { goto done; } + status = netlogon_creds_cli_check(netlogon_creds, + rpccli->binding_handle); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("dcerpc_netr_LogonGetCapabilities failed with %s\n", + DEBUG(0, ("netlogon_creds_cli_check failed with %s\n", nt_errstr(status))); TALLOC_FREE(rpccli); return status; } - if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) { - if (save_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { - /* This means AES isn't supported. */ - DEBUG(5, ("AES was negotiated and the result was %s - " - "downgrade detected\n", - nt_errstr(result))); - TALLOC_FREE(rpccli); - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - /* This is probably an old Windows version */ - DEBUG(5, ("We are checking against an win2k3 or Samba - %s\n", - nt_errstr(result))); - goto done; - } - - /* - * We need to check the credential state here, cause win2k3 and earlier - * returns NT_STATUS_NOT_IMPLEMENTED - */ - if (!netlogon_creds_client_check(&save_creds, &return_auth.cred)) { - /* - * Server replied with bad credential. Fail. - */ - DEBUG(0,("cli_rpc_pipe_open_schannel_with_key: server %s " - "replied with bad credential\n", - rpccli->desthost)); - TALLOC_FREE(rpccli); - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - *rpccli->dc = save_creds; - - if (!NT_STATUS_IS_OK(result)) { - DEBUG(0, ("dcerpc_netr_LogonGetCapabilities failed with %s\n", - nt_errstr(result))); - TALLOC_FREE(rpccli); - return result; - } - - if (!(save_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES)) { - /* This means AES isn't supported. */ - DEBUG(5, ("AES is not negotiated, but netr_LogonGetCapabilities " - "was OK - downgrade detected\n")); - TALLOC_FREE(rpccli); - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - if (save_creds.negotiate_flags != capabilities.server_capabilities) { - DEBUG(0, ("The client capabilities don't match the server " - "capabilities: local[0x%08X] remote[0x%08X]\n", - save_creds.negotiate_flags, - capabilities.server_capabilities)); + status = netlogon_creds_cli_context_copy(netlogon_creds, + rpccli, + &rpccli->netlogon_creds); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0, ("netlogon_creds_cli_context_copy failed with %s\n", + nt_errstr(status))); TALLOC_FREE(rpccli); - return NT_STATUS_INVALID_NETWORK_RESPONSE; + return status; } done: diff --git a/source3/rpc_client/cli_pipe.h b/source3/rpc_client/cli_pipe.h index 1bfb551cf39..4e9f84a333b 100644 --- a/source3/rpc_client/cli_pipe.h +++ b/source3/rpc_client/cli_pipe.h @@ -98,7 +98,7 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli, enum dcerpc_transport_t transport, enum dcerpc_AuthLevel auth_level, const char *domain, - struct netlogon_creds_CredentialState **pdc, + struct netlogon_creds_cli_context *netlogon_creds, struct rpc_pipe_client **presult); NTSTATUS cli_rpc_pipe_open_schannel(struct cli_state *cli, diff --git a/source3/rpc_client/cli_pipe_schannel.c b/source3/rpc_client/cli_pipe_schannel.c index aaae44b512e..e3d65c86203 100644 --- a/source3/rpc_client/cli_pipe_schannel.c +++ b/source3/rpc_client/cli_pipe_schannel.c @@ -112,7 +112,8 @@ NTSTATUS cli_rpc_pipe_open_schannel(struct cli_state *cli, } status = cli_rpc_pipe_open_schannel_with_key( - cli, table, transport, auth_level, domain, &netlogon_pipe->dc, + cli, table, transport, auth_level, domain, + netlogon_pipe->netlogon_creds, &result); /* Now we've bound using the session key we can close the netlog pipe. */ diff --git a/source3/rpc_client/rpc_client.h b/source3/rpc_client/rpc_client.h index 8024f018215..7c4cceb863d 100644 --- a/source3/rpc_client/rpc_client.h +++ b/source3/rpc_client/rpc_client.h @@ -50,7 +50,7 @@ struct rpc_pipe_client { struct pipe_auth_data *auth; /* The following is only non-null on a netlogon client pipe. */ - struct netlogon_creds_CredentialState *dc; + struct netlogon_creds_cli_context *netlogon_creds; }; #endif /* _RPC_CLIENT_H */ diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c index d92434b23c7..2e0b5e5a871 100644 --- a/source3/rpcclient/cmd_netlogon.c +++ b/source3/rpcclient/cmd_netlogon.c @@ -26,6 +26,7 @@ #include "../librpc/gen_ndr/ndr_netlogon_c.h" #include "rpc_client/cli_netlogon.h" #include "secrets.h" +#include "../libcli/auth/netlogon_creds_cli.h" static WERROR cmd_netlogon_logon_ctrl2(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, @@ -630,8 +631,15 @@ static NTSTATUS cmd_netlogon_sam_sync(struct rpc_pipe_client *cli, do { struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL; + struct netlogon_creds_CredentialState *creds = NULL; - netlogon_creds_client_authenticator(cli->dc, &credential); + status = netlogon_creds_cli_lock(cli->netlogon_creds, + mem_ctx, &creds); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + netlogon_creds_client_authenticator(creds, &credential); status = dcerpc_netr_DatabaseSync2(b, mem_ctx, logon_server, @@ -645,15 +653,18 @@ static NTSTATUS cmd_netlogon_sam_sync(struct rpc_pipe_client *cli, 0xffff, &result); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(creds); return status; } /* Check returned credentials. */ - if (!netlogon_creds_client_check(cli->dc, + if (!netlogon_creds_client_check(creds, &return_authenticator.cred)) { DEBUG(0,("credentials chain check failed\n")); + TALLOC_FREE(creds); return NT_STATUS_ACCESS_DENIED; } + TALLOC_FREE(creds); if (NT_STATUS_IS_ERR(result)) { break; @@ -699,8 +710,15 @@ static NTSTATUS cmd_netlogon_sam_deltas(struct rpc_pipe_client *cli, do { struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL; + struct netlogon_creds_CredentialState *creds = NULL; + + status = netlogon_creds_cli_lock(cli->netlogon_creds, + mem_ctx, &creds); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - netlogon_creds_client_authenticator(cli->dc, &credential); + netlogon_creds_client_authenticator(creds, &credential); status = dcerpc_netr_DatabaseDeltas(b, mem_ctx, logon_server, @@ -713,15 +731,18 @@ static NTSTATUS cmd_netlogon_sam_deltas(struct rpc_pipe_client *cli, 0xffff, &result); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(creds); return status; } /* Check returned credentials. */ - if (!netlogon_creds_client_check(cli->dc, + if (!netlogon_creds_client_check(creds, &return_authenticator.cred)) { DEBUG(0,("credentials chain check failed\n")); + TALLOC_FREE(creds); return NT_STATUS_ACCESS_DENIED; } + TALLOC_FREE(creds); if (NT_STATUS_IS_ERR(result)) { break; @@ -1129,6 +1150,7 @@ static NTSTATUS cmd_netlogon_database_redo(struct rpc_pipe_client *cli, struct netr_ChangeLogEntry e; uint32_t rid = 500; struct dcerpc_binding_handle *b = cli->binding_handle; + struct netlogon_creds_CredentialState *creds = NULL; if (argc > 2) { fprintf(stderr, "Usage: %s \n", argv[0]); @@ -1158,7 +1180,13 @@ static NTSTATUS cmd_netlogon_database_redo(struct rpc_pipe_client *cli, return status; } - netlogon_creds_client_authenticator(cli->dc, &clnt_creds); + status = netlogon_creds_cli_lock(cli->netlogon_creds, + mem_ctx, &creds); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + netlogon_creds_client_authenticator(creds, &clnt_creds); ZERO_STRUCT(e); @@ -1176,13 +1204,16 @@ static NTSTATUS cmd_netlogon_database_redo(struct rpc_pipe_client *cli, &delta_enum_array, &result); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(creds); return status; } - if (!netlogon_creds_client_check(cli->dc, &srv_cred.cred)) { + if (!netlogon_creds_client_check(creds, &srv_cred.cred)) { DEBUG(0,("credentials chain check failed\n")); + TALLOC_FREE(creds); return NT_STATUS_ACCESS_DENIED; } + TALLOC_FREE(creds); return result; } @@ -1198,6 +1229,7 @@ static NTSTATUS cmd_netlogon_capabilities(struct rpc_pipe_client *cli, union netr_Capabilities capabilities; uint32_t level = 1; struct dcerpc_binding_handle *b = cli->binding_handle; + struct netlogon_creds_CredentialState *creds = NULL; if (argc > 2) { fprintf(stderr, "Usage: %s \n", argv[0]); @@ -1210,7 +1242,13 @@ static NTSTATUS cmd_netlogon_capabilities(struct rpc_pipe_client *cli, ZERO_STRUCT(return_authenticator); - netlogon_creds_client_authenticator(cli->dc, &credential); + status = netlogon_creds_cli_lock(cli->netlogon_creds, + mem_ctx, &creds); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + netlogon_creds_client_authenticator(creds, &credential); status = dcerpc_netr_LogonGetCapabilities(b, mem_ctx, cli->desthost, @@ -1221,14 +1259,17 @@ static NTSTATUS cmd_netlogon_capabilities(struct rpc_pipe_client *cli, &capabilities, &result); if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(creds); return status; } - if (!netlogon_creds_client_check(cli->dc, + if (!netlogon_creds_client_check(creds, &return_authenticator.cred)) { DEBUG(0,("credentials chain check failed\n")); + TALLOC_FREE(creds); return NT_STATUS_ACCESS_DENIED; } + TALLOC_FREE(creds); printf("capabilities: 0x%08x\n", capabilities.server_capabilities); diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index afde6857f0a..b5fc010d07e 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -165,16 +165,7 @@ struct winbindd_domain { time_t startup_time; /* When we set "startup" true. monotonic clock */ bool startup; /* are we in the first 30 seconds after startup_time ? */ - bool can_do_samlogon_ex; /* Due to the lack of finer control what type - * of DC we have, let us try to do a - * credential-chain less samlogon_ex call - * with AD and schannel. If this fails with - * DCERPC_FAULT_OP_RNG_ERROR, then set this - * to False. This variable is around so that - * we don't have to try _ex every time. */ - bool can_do_ncacn_ip_tcp; - bool can_do_validation6; /* Lookup methods for this domain (LDAP or RPC) */ struct winbindd_methods *methods; diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 5d920d0a782..d08d7de13f8 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -2049,7 +2049,6 @@ static bool set_dc_type_and_flags_trustinfo( struct winbindd_domain *domain ) domain->active_directory ? "" : "NOT ")); domain->can_do_ncacn_ip_tcp = domain->active_directory; - domain->can_do_validation6 = domain->active_directory; domain->initialized = True; @@ -2250,7 +2249,6 @@ done: 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); @@ -2291,7 +2289,7 @@ static void set_dc_type_and_flags( struct winbindd_domain *domain ) ***********************************************************************/ 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; @@ -2308,11 +2306,11 @@ static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain, /* Return a pointer to the struct netlogon_creds_CredentialState from the netlogon pipe. */ - if (!domain->conn.netlogon_pipe->dc) { + if (!domain->conn.netlogon_pipe->netlogon_creds) { return NT_STATUS_INTERNAL_ERROR; /* This shouldn't happen. */ } - *ppdc = domain->conn.netlogon_pipe->dc; + *ppdc = domain->conn.netlogon_pipe->netlogon_creds; return NT_STATUS_OK; } @@ -2321,7 +2319,7 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, { struct winbindd_cm_conn *conn; NTSTATUS status, result; - struct netlogon_creds_CredentialState *p_creds; + struct netlogon_creds_cli_context *p_creds; char *machine_password = NULL; char *machine_account = NULL; const char *domain_name = NULL; @@ -2433,7 +2431,7 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, status = cli_rpc_pipe_open_schannel_with_key (conn->cli, &ndr_table_samr, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, - domain->name, &p_creds, &conn->samr_pipe); + domain->name, p_creds, &conn->samr_pipe); if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for " @@ -2536,7 +2534,7 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain, struct rpc_pipe_client **cli) { struct winbindd_cm_conn *conn; - struct netlogon_creds_CredentialState *creds; + struct netlogon_creds_cli_context *creds; NTSTATUS status; DEBUG(10,("cm_connect_lsa_tcp\n")); @@ -2567,7 +2565,7 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain, NCACN_IP_TCP, DCERPC_AUTH_LEVEL_PRIVACY, domain->name, - &creds, + creds, &conn->lsa_pipe_tcp); if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("cli_rpc_pipe_open_schannel_with_key failed: %s\n", @@ -2591,7 +2589,7 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, { struct winbindd_cm_conn *conn; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - struct netlogon_creds_CredentialState *p_creds; + struct netlogon_creds_cli_context *p_creds; result = init_dc_connection_rpc(domain); if (!NT_STATUS_IS_OK(result)) @@ -2664,7 +2662,7 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, result = cli_rpc_pipe_open_schannel_with_key (conn->cli, &ndr_table_lsarpc, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, - domain->name, &p_creds, &conn->lsa_pipe); + domain->name, p_creds, &conn->lsa_pipe); if (!NT_STATUS_IS_OK(result)) { DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for " @@ -2828,10 +2826,6 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, no_schannel: if ((lp_client_schannel() == False) || ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0)) { - /* - * NetSamLogonEx only works for schannel - */ - domain->can_do_samlogon_ex = False; /* We're done - just keep the existing connection to NETLOGON * open */ @@ -2847,7 +2841,8 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, result = cli_rpc_pipe_open_schannel_with_key( conn->cli, &ndr_table_netlogon, NCACN_NP, - DCERPC_AUTH_LEVEL_PRIVACY, domain->name, &netlogon_pipe->dc, + DCERPC_AUTH_LEVEL_PRIVACY, domain->name, + netlogon_pipe->netlogon_creds, &conn->netlogon_pipe); /* We can now close the initial netlogon pipe. */ @@ -2861,15 +2856,6 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *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; } diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index c356686488a..39483a5d5e6 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -1228,8 +1228,6 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, do { struct rpc_pipe_client *netlogon_pipe; - const struct pipe_auth_data *auth; - uint32_t neg_flags = 0; ZERO_STRUCTP(info3); retry = false; @@ -1278,75 +1276,7 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, } netr_attempts = 0; - auth = netlogon_pipe->auth; - if (netlogon_pipe->dc) { - neg_flags = netlogon_pipe->dc->negotiate_flags; - } - - /* It is really important to try SamLogonEx here, - * because in a clustered environment, we want to use - * one machine account from multiple physical - * computers. - * - * With a normal SamLogon call, we must keep the - * credentials chain updated and intact between all - * users of the machine account (which would imply - * cross-node communication for every NTLM logon). - * - * (The credentials chain is not per NETLOGON pipe - * connection, but globally on the server/client pair - * by machine name). - * - * When using SamLogonEx, the credentials are not - * supplied, but the session key is implied by the - * wrapping SamLogon context. - * - * -- abartlet 21 April 2008 - * - * It's also important to use NetlogonValidationSamInfo4 (6), - * because it relies on the rpc transport encryption - * and avoids using the global netlogon schannel - * session key to en/decrypt secret information - * like the user_session_key for network logons. - * - * [MS-APDS] 3.1.5.2 NTLM Network Logon - * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and - * NETLOGON_NEG_AUTHENTICATED_RPC set together - * are the indication that the server supports - * NetlogonValidationSamInfo4 (6). And it must only - * be used if "SealSecureChannel" is used. - * - * -- metze 4 February 2011 - */ - - if (auth == NULL) { - domain->can_do_validation6 = false; - } else if (auth->auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - domain->can_do_validation6 = false; - } else if (auth->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) { - domain->can_do_validation6 = false; - } else if (!(neg_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) { - domain->can_do_validation6 = false; - } else if (!(neg_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) { - domain->can_do_validation6 = false; - } - - if (domain->can_do_samlogon_ex && domain->can_do_validation6) { - result = rpccli_netlogon_sam_network_logon_ex( - netlogon_pipe, - mem_ctx, - logon_parameters, - server, /* server name */ - username, /* user name */ - domainname, /* target domain */ - workstation, /* workstation */ - chal, - 6, - lm_response, - nt_response, - info3); - } else { - result = rpccli_netlogon_sam_network_logon( + result = rpccli_netlogon_sam_network_logon( netlogon_pipe, mem_ctx, logon_parameters, @@ -1355,48 +1285,10 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, domainname, /* target domain */ workstation, /* workstation */ chal, - domain->can_do_validation6 ? 6 : 3, + -1, /* ignored */ lm_response, nt_response, info3); - } - - if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) { - - /* - * It's likely that the server also does not support - * validation level 6 - */ - domain->can_do_validation6 = false; - - if (domain->can_do_samlogon_ex) { - DEBUG(3, ("Got a DC that can not do NetSamLogonEx, " - "retrying with NetSamLogon\n")); - domain->can_do_samlogon_ex = false; - retry = true; - continue; - } - - - /* Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon - * (no Ex). This happens against old Samba - * DCs. Drop the connection. - */ - invalidate_cm_connection(&domain->conn); - result = NT_STATUS_LOGON_FAILURE; - break; - } - - if (domain->can_do_validation6 && - (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) || - NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) || - NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL))) { - DEBUG(3,("Got a DC that can not do validation level 6, " - "retrying with level 3\n")); - domain->can_do_validation6 = false; - retry = true; - continue; - } /* * we increment this after the "feature negotiation" @@ -1428,6 +1320,30 @@ static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain, retry = true; } + if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) { + /* + * Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon + * (no Ex). This happens against old Samba + * DCs, if LogonSamLogonEx() fails with an error + * e.g. NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD. + * + * The server will log something like this: + * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX. + * + * This sets the whole connection into a fault_state mode + * and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE. + * + * This also happens to our retry with LogonSamLogonWithFlags() + * and LogonSamLogon(). + * + * In order to recover from this situation, we need to + * drop the connection. + */ + invalidate_cm_connection(&domain->conn); + result = NT_STATUS_LOGON_FAILURE; + break; + } + } while ( (attempts < 2) && retry ); if (NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT)) { diff --git a/source3/wscript_build b/source3/wscript_build index ecddfd9dca6..c5dc521cf62 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -84,8 +84,8 @@ bld.SAMBA3_LIBRARY('msrpc3', deps='''ndr ndr-standard RPC_NDR_EPMAPPER NTLMSSP_COMMON COMMON_SCHANNEL LIBCLI_AUTH LIBTSOCKET gse dcerpc-binding - libsmb - ndr-table''', + libsmb ndr-table NETLOGON_CREDS_CLI + ''', private_library=True) bld.SAMBA3_LIBRARY('gpo', @@ -763,7 +763,7 @@ bld.SAMBA3_LIBRARY('libcli_lsa3', bld.SAMBA3_LIBRARY('libcli_netlogon3', source='rpc_client/cli_netlogon.c rpc_client/util_netlogon.c', - deps='RPC_NDR_NETLOGON INIT_NETLOGON cliauth param', + deps='msrpc3 RPC_NDR_NETLOGON INIT_NETLOGON cliauth param NETLOGON_CREDS_CLI', private_library=True) bld.SAMBA3_LIBRARY('cli_spoolss', -- 2.34.1