Commit 1cf48b46 authored by Alexandre Julliard's avatar Alexandre Julliard

secur32: Pre-allocate the token buffer for handshake() on the PE side.

parent abdae539
......@@ -689,12 +689,14 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
{
const ULONG extra_size = 0x10000;
struct schan_context *ctx;
struct schan_buffers *out_buffers;
struct schan_credentials *cred;
SIZE_T expected_size = ~0UL;
SECURITY_STATUS ret;
SecBuffer *buffer;
SecBuffer alloc_buffer = { 0 };
int idx;
TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext,
......@@ -814,19 +816,32 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
ctx->req_ctx_attr = fContextReq;
/* Perform the TLS handshake */
ret = schan_funcs->handshake(ctx->transport.session, pInput, expected_size, pOutput, fContextReq);
if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
{
alloc_buffer.cbBuffer = extra_size;
alloc_buffer.BufferType = SECBUFFER_TOKEN;
alloc_buffer.pvBuffer = RtlAllocateHeap( GetProcessHeap(), 0, extra_size );
}
ret = schan_funcs->handshake(ctx->transport.session, pInput, expected_size, pOutput, &alloc_buffer);
out_buffers = &ctx->transport.out;
if (out_buffers->current_buffer_idx != -1)
{
SecBuffer *buffer = &out_buffers->desc->pBuffers[out_buffers->current_buffer_idx];
buffer->cbBuffer = out_buffers->offset;
if (buffer->pvBuffer == alloc_buffer.pvBuffer)
{
RtlReAllocateHeap( GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY,
buffer->pvBuffer, buffer->cbBuffer );
alloc_buffer.pvBuffer = NULL;
}
}
else if (out_buffers->desc && out_buffers->desc->cBuffers > 0)
{
SecBuffer *buffer = &out_buffers->desc->pBuffers[0];
buffer->cbBuffer = 0;
}
RtlFreeHeap( GetProcessHeap(), 0, alloc_buffer.pvBuffer );
if(ctx->transport.in.offset && ctx->transport.in.offset != pInput->pBuffers[0].cbBuffer) {
if(pInput->cBuffers<2 || pInput->pBuffers[1].BufferType!=SECBUFFER_EMPTY)
......
......@@ -204,7 +204,7 @@ static void init_schan_buffers(struct schan_buffers *s, const PSecBufferDesc des
s->limit = ~0UL;
s->desc = desc;
s->current_buffer_idx = -1;
s->allow_buffer_resize = FALSE;
s->alloc_buffer = NULL;
s->get_next_buffer = get_next_buffer;
}
......@@ -240,10 +240,9 @@ static int handshake_get_next_buffer_alloc(const struct schan_transport *t, stru
idx = schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_EMPTY);
if (idx != -1) s->desc->pBuffers[idx].BufferType = SECBUFFER_TOKEN;
}
if (idx != -1 && !s->desc->pBuffers[idx].pvBuffer)
if (idx != -1 && !s->desc->pBuffers[idx].pvBuffer && s->alloc_buffer)
{
s->desc->pBuffers[idx].cbBuffer = 0;
s->allow_buffer_resize = TRUE;
s->desc->pBuffers[idx] = *s->alloc_buffer;
}
return idx;
}
......@@ -302,31 +301,6 @@ static int recv_message_get_next_buffer(const struct schan_transport *t, struct
return schan_find_sec_buffer_idx(s->desc, 0, SECBUFFER_DATA);
}
static void resize_current_buffer(const struct schan_buffers *s, SIZE_T min_size)
{
SecBuffer *b = &s->desc->pBuffers[s->current_buffer_idx];
SIZE_T new_size = b->cbBuffer ? b->cbBuffer * 2 : 128;
void *new_data;
if (b->cbBuffer >= min_size || !s->allow_buffer_resize || min_size > UINT_MAX / 2) return;
while (new_size < min_size) new_size *= 2;
if (b->pvBuffer) /* freed with FreeContextBuffer */
new_data = RtlReAllocateHeap(GetProcessHeap(), 0, b->pvBuffer, new_size);
else
new_data = RtlAllocateHeap(GetProcessHeap(), 0, new_size);
if (!new_data)
{
TRACE("Failed to resize %p from %d to %ld\n", b->pvBuffer, b->cbBuffer, new_size);
return;
}
b->cbBuffer = new_size;
b->pvBuffer = new_data;
}
static char *get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count)
{
SIZE_T max_count;
......@@ -353,7 +327,6 @@ static char *get_buffer(const struct schan_transport *t, struct schan_buffers *s
buffer = &s->desc->pBuffers[s->current_buffer_idx];
TRACE("Using buffer %d: cbBuffer %d, BufferType %#x, pvBuffer %p\n", s->current_buffer_idx, buffer->cbBuffer, buffer->BufferType, buffer->pvBuffer);
resize_current_buffer(s, s->offset + *count);
max_count = buffer->cbBuffer - s->offset;
if (s->limit != ~0UL && s->limit < max_count)
max_count = s->limit;
......@@ -362,7 +335,6 @@ static char *get_buffer(const struct schan_transport *t, struct schan_buffers *s
{
int buffer_idx;
s->allow_buffer_resize = FALSE;
buffer_idx = s->get_next_buffer(t, s);
if (buffer_idx == -1)
{
......@@ -580,7 +552,8 @@ static void CDECL schan_set_session_target(schan_session session, const char *ta
}
static SECURITY_STATUS CDECL schan_handshake(schan_session session, SecBufferDesc *input,
SIZE_T input_size, SecBufferDesc *output, ULONG flags )
SIZE_T input_size, SecBufferDesc *output,
SecBuffer *alloc_buffer )
{
gnutls_session_t s = (gnutls_session_t)session;
struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
......@@ -588,8 +561,8 @@ static SECURITY_STATUS CDECL schan_handshake(schan_session session, SecBufferDes
init_schan_buffers(&t->in, input, handshake_get_next_buffer);
t->in.limit = input_size;
init_schan_buffers(&t->out, output, (flags & ISC_REQ_ALLOCATE_MEMORY) ?
handshake_get_next_buffer_alloc : handshake_get_next_buffer );
init_schan_buffers(&t->out, output, handshake_get_next_buffer_alloc );
t->out.alloc_buffer = alloc_buffer;
while(1) {
err = pgnutls_handshake(s);
......
......@@ -95,8 +95,8 @@ struct schan_buffers
SIZE_T offset;
SIZE_T limit;
const SecBufferDesc *desc;
SecBuffer *alloc_buffer;
int current_buffer_idx;
BOOL allow_buffer_resize;
int (*get_next_buffer)(const struct schan_transport *, struct schan_buffers *);
};
......@@ -122,7 +122,7 @@ struct schan_funcs
unsigned int (CDECL *get_session_cipher_block_size)(schan_session);
SECURITY_STATUS (CDECL *get_session_peer_certificate)(schan_session, CERT_BLOB *, ULONG *, ULONG *);
SECURITY_STATUS (CDECL *get_unique_channel_binding)(schan_session, void *, ULONG *);
SECURITY_STATUS (CDECL *handshake)(schan_session, SecBufferDesc *, SIZE_T, SecBufferDesc *, ULONG );
SECURITY_STATUS (CDECL *handshake)(schan_session, SecBufferDesc *, SIZE_T, SecBufferDesc *, SecBuffer * );
SECURITY_STATUS (CDECL *recv)(schan_session, SecBufferDesc *, SIZE_T, void *, SIZE_T *);
SECURITY_STATUS (CDECL *send)(schan_session, SecBufferDesc *, const void *, SIZE_T *);
void (CDECL *set_application_protocols)(schan_session, unsigned char *, unsigned int);
......
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