diff options
-rw-r--r-- | source4/librpc/rpc/dcerpc_schannel.c | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c index f3e52585ae..be1ab240bd 100644 --- a/source4/librpc/rpc/dcerpc_schannel.c +++ b/source4/librpc/rpc/dcerpc_schannel.c @@ -54,6 +54,7 @@ static void continue_secondary_connection(struct composite_context *ctx); static void continue_bind_auth_none(struct composite_context *ctx); static void continue_srv_challenge(struct tevent_req *subreq); static void continue_srv_auth2(struct tevent_req *subreq); +static void continue_get_capabilities(struct tevent_req *subreq); /* @@ -300,7 +301,6 @@ static void continue_srv_auth2(struct tevent_req *subreq) composite_done(c); } - /* Initiate establishing a schannel key using netlogon challenge on a secondary pipe @@ -383,6 +383,11 @@ struct auth_schannel_state { const struct ndr_interface_table *table; struct loadparm_context *lp_ctx; uint8_t auth_level; + struct netlogon_creds_CredentialState *creds_state; + struct netr_Authenticator auth; + struct netr_Authenticator return_auth; + union netr_Capabilities capabilities; + struct netr_LogonGetCapabilities c; }; @@ -428,10 +433,114 @@ static void continue_bind_auth(struct composite_context *ctx) { struct composite_context *c = talloc_get_type(ctx->async.private_data, struct composite_context); + struct auth_schannel_state *s = talloc_get_type(c->private_data, + struct auth_schannel_state); + struct tevent_req *subreq; c->status = dcerpc_bind_auth_recv(ctx); if (!composite_is_ok(c)) return; + /* if we have a AES encrypted connection, verify the capabilities */ + if (ndr_syntax_id_equal(&s->table->syntax_id, + &ndr_table_netlogon.syntax_id)) { + ZERO_STRUCT(s->return_auth); + + s->creds_state = cli_credentials_get_netlogon_creds(s->credentials); + if (composite_nomem(s->creds_state, c)) return; + + netlogon_creds_client_authenticator(s->creds_state, &s->auth); + + s->c.in.server_name = talloc_asprintf(c, + "\\\\%s", + dcerpc_server_name(s->pipe)); + if (composite_nomem(s->c.in.server_name, c)) return; + s->c.in.computer_name = cli_credentials_get_workstation(s->credentials); + s->c.in.credential = &s->auth; + s->c.in.return_authenticator = &s->return_auth; + s->c.in.query_level = 1; + + s->c.out.capabilities = &s->capabilities; + s->c.out.return_authenticator = &s->return_auth; + + DEBUG(5, ("We established a AES connection, verifying logon " + "capabilities\n")); + + subreq = dcerpc_netr_LogonGetCapabilities_r_send(s, + c->event_ctx, + s->pipe->binding_handle, + &s->c); + if (composite_nomem(subreq, c)) return; + + tevent_req_set_callback(subreq, continue_get_capabilities, c); + return; + } + + composite_done(c); +} + +/* + Stage 4 of auth_schannel: Get the Logon Capablities and verify them. +*/ +static void continue_get_capabilities(struct tevent_req *subreq) +{ + struct composite_context *c; + struct auth_schannel_state *s; + + c = tevent_req_callback_data(subreq, struct composite_context); + s = talloc_get_type(c->private_data, struct auth_schannel_state); + + /* receive rpc request result */ + c->status = dcerpc_netr_LogonGetCapabilities_r_recv(subreq, s); + TALLOC_FREE(subreq); + if (NT_STATUS_EQUAL(c->status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) { + if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } else { + /* This is probably NT */ + composite_done(c); + return; + } + } else if (!composite_is_ok(c)) { + return; + } + + if (NT_STATUS_EQUAL(s->c.out.result, NT_STATUS_NOT_IMPLEMENTED)) { + if (s->creds_state->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) { + /* This means AES isn't supported. */ + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + /* This is probably an old Samba version */ + composite_done(c); + return; + } + + /* verify credentials */ + if (!netlogon_creds_client_check(s->creds_state, + &s->c.out.return_authenticator->cred)) { + composite_error(c, NT_STATUS_UNSUCCESSFUL); + return; + } + + if (!NT_STATUS_IS_OK(s->c.out.result)) { + composite_error(c, s->c.out.result); + return; + } + + /* compare capabilities */ + if (s->creds_state->negotiate_flags != s->capabilities.server_capabilities) { + DEBUG(2, ("The client capabilities don't match the server " + "capabilities: local[0x%08X] remote[0x%08X]\n", + s->creds_state->negotiate_flags, + s->capabilities.server_capabilities)); + composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + /* TODO: Add downgrade dectection. */ + composite_done(c); } |