Commit 72888a44 authored by Paul Gofman's avatar Paul Gofman Committed by Alexandre Julliard

secur32: Implement ApplyControlToken for SCHANNEL_SHUTDOWN.

parent e55bb2bc
...@@ -65,6 +65,7 @@ struct schan_context ...@@ -65,6 +65,7 @@ struct schan_context
ULONG req_ctx_attr; ULONG req_ctx_attr;
const CERT_CONTEXT *cert; const CERT_CONTEXT *cert;
SIZE_T header_size; SIZE_T header_size;
BOOL shutdown_requested;
}; };
static struct schan_handle *schan_handle_table; static struct schan_handle *schan_handle_table;
...@@ -901,9 +902,9 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( ...@@ -901,9 +902,9 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
unsigned char *ptr; unsigned char *ptr;
if (!(ctx = schan_get_object(phContext->dwLower, SCHAN_HANDLE_CTX))) return SEC_E_INVALID_HANDLE; if (!(ctx = schan_get_object(phContext->dwLower, SCHAN_HANDLE_CTX))) return SEC_E_INVALID_HANDLE;
if (!pInput && !is_dtls_context(ctx)) return SEC_E_INCOMPLETE_MESSAGE; if (!pInput && !ctx->shutdown_requested && !is_dtls_context(ctx)) return SEC_E_INCOMPLETE_MESSAGE;
if (pInput) if (!ctx->shutdown_requested && pInput)
{ {
if (!validate_input_buffers(pInput)) return SEC_E_INVALID_TOKEN; if (!validate_input_buffers(pInput)) return SEC_E_INVALID_TOKEN;
if ((idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_TOKEN)) == -1) return SEC_E_INCOMPLETE_MESSAGE; if ((idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_TOKEN)) == -1) return SEC_E_INCOMPLETE_MESSAGE;
...@@ -976,6 +977,8 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW( ...@@ -976,6 +977,8 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
params.input_offset = &input_offset; params.input_offset = &input_offset;
params.output_buffer_idx = &output_buffer_idx; params.output_buffer_idx = &output_buffer_idx;
params.output_offset = &output_offset; params.output_offset = &output_offset;
params.control_token = ctx->shutdown_requested ? control_token_shutdown : control_token_none;
ctx->shutdown_requested = FALSE;
ret = GNUTLS_CALL( handshake, &params ); ret = GNUTLS_CALL( handshake, &params );
if (output_buffer_idx != -1) if (output_buffer_idx != -1)
...@@ -1575,6 +1578,8 @@ static SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context ...@@ -1575,6 +1578,8 @@ static SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context
static SECURITY_STATUS SEC_ENTRY schan_ApplyControlToken(PCtxtHandle context_handle, PSecBufferDesc input) static SECURITY_STATUS SEC_ENTRY schan_ApplyControlToken(PCtxtHandle context_handle, PSecBufferDesc input)
{ {
struct schan_context *ctx;
TRACE("%p %p\n", context_handle, input); TRACE("%p %p\n", context_handle, input);
dump_buffer_desc(input); dump_buffer_desc(input);
...@@ -1587,7 +1592,8 @@ static SECURITY_STATUS SEC_ENTRY schan_ApplyControlToken(PCtxtHandle context_han ...@@ -1587,7 +1592,8 @@ static SECURITY_STATUS SEC_ENTRY schan_ApplyControlToken(PCtxtHandle context_han
if (input->pBuffers[0].cbBuffer < sizeof(DWORD)) return SEC_E_UNSUPPORTED_FUNCTION; if (input->pBuffers[0].cbBuffer < sizeof(DWORD)) return SEC_E_UNSUPPORTED_FUNCTION;
if (*(DWORD *)input->pBuffers[0].pvBuffer != SCHANNEL_SHUTDOWN) return SEC_E_UNSUPPORTED_FUNCTION; if (*(DWORD *)input->pBuffers[0].pvBuffer != SCHANNEL_SHUTDOWN) return SEC_E_UNSUPPORTED_FUNCTION;
FIXME("stub.\n"); ctx = schan_get_object(context_handle->dwLower, SCHAN_HANDLE_CTX);
ctx->shutdown_requested = TRUE;
return SEC_E_OK; return SEC_E_OK;
} }
......
...@@ -121,6 +121,7 @@ MAKE_FUNCPTR(gnutls_x509_crt_deinit); ...@@ -121,6 +121,7 @@ MAKE_FUNCPTR(gnutls_x509_crt_deinit);
MAKE_FUNCPTR(gnutls_x509_crt_import); MAKE_FUNCPTR(gnutls_x509_crt_import);
MAKE_FUNCPTR(gnutls_x509_crt_init); MAKE_FUNCPTR(gnutls_x509_crt_init);
MAKE_FUNCPTR(gnutls_x509_privkey_deinit); MAKE_FUNCPTR(gnutls_x509_privkey_deinit);
MAKE_FUNCPTR(gnutls_alert_send);
#undef MAKE_FUNCPTR #undef MAKE_FUNCPTR
#if GNUTLS_VERSION_MAJOR < 3 #if GNUTLS_VERSION_MAJOR < 3
...@@ -557,6 +558,25 @@ static NTSTATUS schan_handshake( void *args ) ...@@ -557,6 +558,25 @@ static NTSTATUS schan_handshake( void *args )
t->in.limit = params->input_size; t->in.limit = params->input_size;
init_schan_buffers(&t->out, params->output); init_schan_buffers(&t->out, params->output);
if (params->control_token == control_token_shutdown)
{
err = pgnutls_alert_send(s, GNUTLS_AL_WARNING, GNUTLS_A_CLOSE_NOTIFY);
if (err == GNUTLS_E_SUCCESS)
{
status = SEC_E_OK;
}
else if (err == GNUTLS_E_AGAIN)
{
status = SEC_E_INVALID_TOKEN;
}
else
{
pgnutls_perror(err);
status = SEC_E_INTERNAL_ERROR;
}
goto done;
}
while (1) while (1)
{ {
err = pgnutls_handshake(s); err = pgnutls_handshake(s);
...@@ -598,6 +618,7 @@ static NTSTATUS schan_handshake( void *args ) ...@@ -598,6 +618,7 @@ static NTSTATUS schan_handshake( void *args )
break; break;
} }
done:
*params->input_offset = t->in.offset; *params->input_offset = t->in.offset;
*params->output_buffer_idx = t->out.current_buffer_idx; *params->output_buffer_idx = t->out.current_buffer_idx;
*params->output_offset = t->out.offset; *params->output_offset = t->out.offset;
...@@ -1427,6 +1448,7 @@ static NTSTATUS process_attach( void *args ) ...@@ -1427,6 +1448,7 @@ static NTSTATUS process_attach( void *args )
LOAD_FUNCPTR(gnutls_x509_crt_import) LOAD_FUNCPTR(gnutls_x509_crt_import)
LOAD_FUNCPTR(gnutls_x509_crt_init) LOAD_FUNCPTR(gnutls_x509_crt_init)
LOAD_FUNCPTR(gnutls_x509_privkey_deinit) LOAD_FUNCPTR(gnutls_x509_privkey_deinit)
LOAD_FUNCPTR(gnutls_alert_send)
#undef LOAD_FUNCPTR #undef LOAD_FUNCPTR
if (!(pgnutls_cipher_get_block_size = dlsym(libgnutls_handle, "gnutls_cipher_get_block_size"))) if (!(pgnutls_cipher_get_block_size = dlsym(libgnutls_handle, "gnutls_cipher_get_block_size")))
...@@ -1707,6 +1729,7 @@ static NTSTATUS wow64_schan_handshake( void *args ) ...@@ -1707,6 +1729,7 @@ static NTSTATUS wow64_schan_handshake( void *args )
PTR32 input_offset; PTR32 input_offset;
PTR32 output_buffer_idx; PTR32 output_buffer_idx;
PTR32 output_offset; PTR32 output_offset;
enum control_token control_token;
} const *params32 = args; } const *params32 = args;
struct handshake_params params = struct handshake_params params =
{ {
...@@ -1717,6 +1740,7 @@ static NTSTATUS wow64_schan_handshake( void *args ) ...@@ -1717,6 +1740,7 @@ static NTSTATUS wow64_schan_handshake( void *args )
ULongToPtr(params32->input_offset), ULongToPtr(params32->input_offset),
ULongToPtr(params32->output_buffer_idx), ULongToPtr(params32->output_buffer_idx),
ULongToPtr(params32->output_offset), ULongToPtr(params32->output_offset),
params32->control_token,
}; };
if (params32->input) if (params32->input)
{ {
......
...@@ -147,6 +147,12 @@ struct get_unique_channel_binding_params ...@@ -147,6 +147,12 @@ struct get_unique_channel_binding_params
ULONG *bufsize; ULONG *bufsize;
}; };
enum control_token
{
control_token_none,
control_token_shutdown,
};
struct handshake_params struct handshake_params
{ {
schan_session session; schan_session session;
...@@ -156,6 +162,7 @@ struct handshake_params ...@@ -156,6 +162,7 @@ struct handshake_params
ULONG *input_offset; ULONG *input_offset;
int *output_buffer_idx; int *output_buffer_idx;
ULONG *output_offset; ULONG *output_offset;
enum control_token control_token;
}; };
struct recv_params struct recv_params
......
...@@ -1869,13 +1869,13 @@ static void test_connection_shutdown(void) ...@@ -1869,13 +1869,13 @@ static void test_connection_shutdown(void)
context2.dwLower = context2.dwUpper = 0xdeadbeef; context2.dwLower = context2.dwUpper = 0xdeadbeef;
status = InitializeSecurityContextA( &cred_handle, &context, NULL, 0, 0, 0, &buffers[1], 0, status = InitializeSecurityContextA( &cred_handle, &context, NULL, 0, 0, 0, &buffers[1], 0,
&context2, &buffers[0], &attrs, NULL ); &context2, &buffers[0], &attrs, NULL );
todo_wine ok( status == SEC_E_OK, "got %08lx.\n", status ); ok( status == SEC_E_OK, "got %08lx.\n", status );
ok( context.dwLower == context2.dwLower, "dwLower mismatch, expected %#Ix, got %#Ix\n", ok( context.dwLower == context2.dwLower, "dwLower mismatch, expected %#Ix, got %#Ix\n",
context.dwLower, context2.dwLower ); context.dwLower, context2.dwLower );
ok( context.dwUpper == context2.dwUpper, "dwUpper mismatch, expected %#Ix, got %#Ix\n", ok( context.dwUpper == context2.dwUpper, "dwUpper mismatch, expected %#Ix, got %#Ix\n",
context.dwUpper, context2.dwUpper ); context.dwUpper, context2.dwUpper );
todo_wine ok( buf->cbBuffer == sizeof(message), "got cbBuffer %#lx.\n", buf->cbBuffer ); ok( buf->cbBuffer == sizeof(message), "got cbBuffer %#lx.\n", buf->cbBuffer );
todo_wine ok( !memcmp( buf->pvBuffer, message, sizeof(message) ), "message data mismatch.\n" ); ok( !memcmp( buf->pvBuffer, message, sizeof(message) ), "message data mismatch.\n" );
buf->BufferType = SECBUFFER_TOKEN; buf->BufferType = SECBUFFER_TOKEN;
buf->cbBuffer = 1000; buf->cbBuffer = 1000;
...@@ -1896,9 +1896,9 @@ static void test_connection_shutdown(void) ...@@ -1896,9 +1896,9 @@ static void test_connection_shutdown(void)
buf->cbBuffer = 1000; buf->cbBuffer = 1000;
status = InitializeSecurityContextA( &cred_handle, &context, NULL, 0, 0, 0, status = InitializeSecurityContextA( &cred_handle, &context, NULL, 0, 0, 0,
NULL, 0, NULL, &buffers[0], &attrs, NULL ); NULL, 0, NULL, &buffers[0], &attrs, NULL );
todo_wine ok( status == SEC_E_OK, "got %08lx.\n", status ); ok( status == SEC_E_OK, "got %08lx.\n", status );
todo_wine ok( buf->cbBuffer == sizeof(message), "got cbBuffer %#lx.\n", buf->cbBuffer ); ok( buf->cbBuffer == sizeof(message), "got cbBuffer %#lx.\n", buf->cbBuffer );
todo_wine ok( !memcmp( buf->pvBuffer, message, sizeof(message) ), "message data mismatch.\n" ); ok( !memcmp( buf->pvBuffer, message, sizeof(message) ), "message data mismatch.\n" );
free_buffers( &buffers[0] ); free_buffers( &buffers[0] );
free_buffers( &buffers[1] ); free_buffers( &buffers[1] );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment