From 17d124490b79cf14e53263eaef333756e18f7ff2 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 12 Dec 2011 19:28:49 +0100 Subject: [PATCH] s4-librpc: Fix NETLOGON credential chain with Windows 2008. Windows Server 2008 returns NT_STATUS_DOWNGRADE_DETECTED if you call netrServerAuthenticate2 during a domain join without setting the strong keys flag (128bit crypto). Only for NT4 we need to do a downgrade to the returned negotiate flags. See also 0970369ca0cb9ae465cff40e5c75739824daf1d0. --- librpc/rpc/rpc_common.h | 3 ++ source4/librpc/rpc/dcerpc_schannel.c | 49 +++++++++++++++++++++++----- source4/winbind/wb_init_domain.c | 4 +-- 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/librpc/rpc/rpc_common.h b/librpc/rpc/rpc_common.h index 44c3cfd39b5..a28835fa634 100644 --- a/librpc/rpc/rpc_common.h +++ b/librpc/rpc/rpc_common.h @@ -107,6 +107,9 @@ struct dcerpc_binding { /* specify binding interface */ #define DCERPC_LOCALADDRESS (1<<22) +/* handle upgrades or downgrades automatically */ +#define DCERPC_SCHANNEL_AUTO (1<<23) + /* The following definitions come from ../librpc/rpc/dcerpc_error.c */ const char *dcerpc_errstr(TALLOC_CTX *mem_ctx, uint32_t fault_code); diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index fc56eccf7c5..9501e3e047e 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -36,9 +36,11 @@ struct schannel_key_state { struct dcerpc_pipe *pipe; struct dcerpc_pipe *pipe2; struct dcerpc_binding *binding; + bool dcerpc_schannel_auto; struct cli_credentials *credentials; struct netlogon_creds_CredentialState *creds; - uint32_t negotiate_flags; + uint32_t local_negotiate_flags; + uint32_t remote_negotiate_flags; struct netr_Credential credentials1; struct netr_Credential credentials2; struct netr_Credential credentials3; @@ -176,16 +178,17 @@ static void continue_srv_challenge(struct tevent_req *subreq) s->a.in.secure_channel_type = cli_credentials_get_secure_channel_type(s->credentials); s->a.in.computer_name = cli_credentials_get_workstation(s->credentials); - s->a.in.negotiate_flags = &s->negotiate_flags; + s->a.in.negotiate_flags = &s->local_negotiate_flags; s->a.in.credentials = &s->credentials3; - s->a.out.negotiate_flags = &s->negotiate_flags; + s->a.out.negotiate_flags = &s->remote_negotiate_flags; s->a.out.return_credentials = &s->credentials3; s->creds = netlogon_creds_client_init(s, s->a.in.account_name, s->a.in.computer_name, &s->credentials1, &s->credentials2, - s->mach_pwd, &s->credentials3, s->negotiate_flags); + s->mach_pwd, &s->credentials3, + s->local_negotiate_flags); if (composite_nomem(s->creds, c)) { return; } @@ -218,6 +221,30 @@ static void continue_srv_auth2(struct tevent_req *subreq) TALLOC_FREE(subreq); if (!composite_is_ok(c)) return; + /* + * Strong keys could be unsupported (NT4) or disables. So retry with the + * flags returned by the server. - asn + */ + if (NT_STATUS_EQUAL(s->a.out.result, NT_STATUS_ACCESS_DENIED) && + s->dcerpc_schannel_auto && + (s->local_negotiate_flags & NETLOGON_NEG_STRONG_KEYS)) { + DEBUG(3, ("Server doesn't support strong keys, " + "downgrade and retry!\n")); + s->local_negotiate_flags = s->remote_negotiate_flags; + + generate_random_buffer(s->credentials1.data, + sizeof(s->credentials1.data)); + + subreq = dcerpc_netr_ServerReqChallenge_r_send(s, + c->event_ctx, + s->pipe2->binding_handle, + &s->r); + if (composite_nomem(subreq, c)) return; + + tevent_req_set_callback(subreq, continue_srv_challenge, c); + return; + } + /* verify credentials */ if (!netlogon_creds_client_check(s->creds, s->a.out.return_credentials)) { composite_error(c, NT_STATUS_UNSUCCESSFUL); @@ -256,15 +283,19 @@ struct composite_context *dcerpc_schannel_key_send(TALLOC_CTX *mem_ctx, /* store parameters in the state structure */ s->pipe = p; s->credentials = credentials; + s->local_negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS; /* allocate credentials */ /* type of authentication depends on schannel type */ if (schannel_type == SEC_CHAN_RODC) { - s->negotiate_flags = NETLOGON_NEG_AUTH2_RODC_FLAGS; - } else if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) { - s->negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; - } else { - s->negotiate_flags = NETLOGON_NEG_AUTH2_FLAGS; + s->local_negotiate_flags = NETLOGON_NEG_AUTH2_RODC_FLAGS; + } + if (s->pipe->conn->flags & DCERPC_SCHANNEL_128) { + s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + } + if (s->pipe->conn->flags & DCERPC_SCHANNEL_AUTO) { + s->local_negotiate_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; + s->dcerpc_schannel_auto = true; } /* allocate binding structure */ diff --git a/source4/winbind/wb_init_domain.c b/source4/winbind/wb_init_domain.c index 9847afbba05..9d807d87764 100644 --- a/source4/winbind/wb_init_domain.c +++ b/source4/winbind/wb_init_domain.c @@ -154,7 +154,7 @@ struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx, (lpcfg_server_role(service->task->lp_ctx) == ROLE_DOMAIN_CONTROLLER)) && (dom_sid_equal(state->domain->info->sid, state->service->primary_sid))) { - state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL | DCERPC_SCHANNEL_128; + state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO; /* For debugging, it can be a real pain if all the traffic is encrypted */ if (lpcfg_winbind_sealed_pipes(service->task->lp_ctx)) { @@ -236,7 +236,7 @@ static bool retry_with_schannel(struct init_domain_state *state, * NTLMSSP binds */ /* Try again with schannel */ - binding->flags |= DCERPC_SCHANNEL; + binding->flags |= DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO; /* Try again, likewise on the same IPC$ share, secured with SCHANNEL */ -- 2.34.1