secur32: Convert the Unix library to the __wine_unix_call interface.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-12-04 13:18:34 +01:00
parent 1cf48b4684
commit 392bdb85e7
4 changed files with 328 additions and 178 deletions

View file

@ -1,5 +1,6 @@
MODULE = secur32.dll
IMPORTLIB = secur32
UNIXLIB = secur32.so
IMPORTS = advapi32
DELAYIMPORTS = crypt32
EXTRAINCL = $(GNUTLS_CFLAGS)

View file

@ -33,12 +33,15 @@
#include "sspi.h"
#include "schannel.h"
#include "wine/unixlib.h"
#include "wine/debug.h"
#include "secur32_priv.h"
WINE_DEFAULT_DEBUG_CHANNEL(secur32);
const struct schan_funcs *schan_funcs = NULL;
static unixlib_handle_t gnutls_handle;
#define GNUTLS_CALL( func, params ) __wine_unix_call( gnutls_handle, unix_ ## func, params )
#define SCHAN_INVALID_HANDLE ~0UL
@ -231,7 +234,7 @@ static void read_config(void)
RegCloseKey(protocols_key);
config_enabled_protocols = enabled & schan_funcs->get_enabled_protocols();
config_enabled_protocols = enabled & GNUTLS_CALL( get_enabled_protocols, NULL );
config_default_disabled_protocols = default_disabled;
config_read = TRUE;
@ -492,6 +495,7 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
SECURITY_STATUS status = SEC_E_OK;
const CERT_CONTEXT *cert = NULL;
DATA_BLOB key_blob = {0};
struct allocate_certificate_credentials_params params;
TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
@ -526,7 +530,10 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
creds->enabled_protocols = enabled_protocols;
if (cert && !(key_blob.pbData = get_key_blob(cert, &key_blob.cbData))) goto fail;
if (!schan_funcs->allocate_certificate_credentials(creds, cert, &key_blob)) goto fail;
params.c = creds;
params.ctx = cert;
params.key_blob = &key_blob;
if (GNUTLS_CALL( allocate_certificate_credentials, &params )) goto fail;
RtlFreeHeap(GetProcessHeap(), 0, key_blob.pbData);
handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED);
@ -634,7 +641,11 @@ static SECURITY_STATUS SEC_ENTRY schan_FreeCredentialsHandle(
creds = schan_free_handle(phCredential->dwLower, SCHAN_HANDLE_CRED);
if (!creds) return SEC_E_INVALID_HANDLE;
if (creds->credential_use == SECPKG_CRED_OUTBOUND) schan_funcs->free_certificate_credentials(creds);
if (creds->credential_use == SECPKG_CRED_OUTBOUND)
{
struct free_certificate_credentials_params params = { creds };
GNUTLS_CALL( free_certificate_credentials, &params );
}
free(creds);
return SEC_E_OK;
}
@ -697,6 +708,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
SECURITY_STATUS ret;
SecBuffer *buffer;
SecBuffer alloc_buffer = { 0 };
struct handshake_params params;
int idx;
TRACE("%p %p %s 0x%08x %d %d %p %d %p %p %p %p\n", phCredential, phContext,
@ -715,6 +727,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
if (!phContext)
{
ULONG_PTR handle;
struct create_session_params create_params;
if (!phCredential) return SEC_E_INVALID_HANDLE;
@ -737,7 +750,9 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
return SEC_E_INTERNAL_ERROR;
}
if (!schan_funcs->create_session(&ctx->transport.session, cred))
create_params.transport = &ctx->transport;
create_params.cred = cred;
if (GNUTLS_CALL( create_session, &create_params ))
{
schan_free_handle(handle, SCHAN_HANDLE_CTX);
free(ctx);
@ -750,7 +765,6 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
ctx->header_size = HEADER_SIZE_TLS;
ctx->transport.ctx = ctx;
schan_funcs->set_session_transport(ctx->transport.session, &ctx->transport);
if (pszTargetName && *pszTargetName)
{
@ -759,22 +773,28 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
if (target)
{
struct set_session_target_params params = { ctx->transport.session, target };
WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, target, len, NULL, NULL );
schan_funcs->set_session_target( ctx->transport.session, target );
GNUTLS_CALL( set_session_target, &params );
free( target );
}
}
if (pInput && (idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_APPLICATION_PROTOCOLS)) != -1)
{
buffer = &pInput->pBuffers[idx];
schan_funcs->set_application_protocols(ctx->transport.session, buffer->pvBuffer, buffer->cbBuffer);
struct set_application_protocols_params params = { ctx->transport.session,
pInput->pBuffers[idx].pvBuffer, pInput->pBuffers[idx].cbBuffer };
GNUTLS_CALL( set_application_protocols, &params );
}
if (pInput && (idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_DTLS_MTU)) != -1)
{
buffer = &pInput->pBuffers[idx];
if (buffer->cbBuffer >= sizeof(WORD)) schan_funcs->set_dtls_mtu(ctx->transport.session, *(WORD *)buffer->pvBuffer);
if (buffer->cbBuffer >= sizeof(WORD))
{
struct set_dtls_mtu_params params = { ctx->transport.session, *(WORD *)buffer->pvBuffer };
GNUTLS_CALL( set_dtls_mtu, &params );
}
else WARN("invalid buffer size %u\n", buffer->cbBuffer);
}
@ -822,7 +842,12 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
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);
params.session = ctx->transport.session;
params.input = pInput;
params.input_size = expected_size;
params.output = pOutput;
params.alloc_buffer = &alloc_buffer;
ret = GNUTLS_CALL( handshake, &params );
out_buffers = &ctx->transport.out;
if (out_buffers->current_buffer_idx != -1)
@ -926,19 +951,21 @@ static SECURITY_STATUS ensure_remote_cert(struct schan_context *ctx)
SECURITY_STATUS status;
CERT_BLOB *certs;
ULONG count, size = 0;
struct get_session_peer_certificate_params params = { ctx->transport.session, NULL, &size, &count };
if (ctx->cert) return SEC_E_OK;
if (!(store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL)))
return GetLastError();
status = schan_funcs->get_session_peer_certificate(ctx->transport.session, NULL, &size, &count);
status = GNUTLS_CALL( get_session_peer_certificate, &params );
if (status != SEC_E_BUFFER_TOO_SMALL) goto done;
if (!(certs = malloc( size )))
{
status = SEC_E_INSUFFICIENT_MEMORY;
goto done;
}
status = schan_funcs->get_session_peer_certificate(ctx->transport.session, certs, &size, &count);
params.certs = certs;
status = GNUTLS_CALL( get_session_peer_certificate, &params );
if (status == SEC_E_OK)
{
unsigned int i;
@ -977,13 +1004,15 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
case SECPKG_ATTR_STREAM_SIZES:
{
SecPkgContext_ConnectionInfo info;
status = schan_funcs->get_connection_info(ctx->transport.session, &info);
struct get_connection_info_params params = { ctx->transport.session, &info };
status = GNUTLS_CALL( get_connection_info, &params );
if (status == SEC_E_OK)
{
struct session_params params = { ctx->transport.session };
SecPkgContext_StreamSizes *stream_sizes = buffer;
SIZE_T mac_size = info.dwHashStrength;
unsigned int block_size = schan_funcs->get_session_cipher_block_size(ctx->transport.session);
unsigned int message_size = schan_funcs->get_max_message_size(ctx->transport.session);
unsigned int block_size = GNUTLS_CALL( get_session_cipher_block_size, &params );
unsigned int message_size = GNUTLS_CALL( get_max_message_size, &params );
TRACE("Using header size %lu mac bytes %lu, message size %u, block size %u\n",
ctx->header_size, mac_size, message_size, block_size);
@ -1001,12 +1030,14 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
case SECPKG_ATTR_KEY_INFO:
{
SecPkgContext_ConnectionInfo conn_info;
status = schan_funcs->get_connection_info(ctx->transport.session, &conn_info);
struct get_connection_info_params params = { ctx->transport.session, &conn_info };
status = GNUTLS_CALL( get_connection_info, &params );
if (status == SEC_E_OK)
{
struct session_params params = { ctx->transport.session };
SecPkgContext_KeyInfoW *info = buffer;
info->KeySize = conn_info.dwCipherStrength;
info->SignatureAlgorithm = schan_funcs->get_key_signature_algorithm(ctx->transport.session);
info->SignatureAlgorithm = GNUTLS_CALL( get_key_signature_algorithm, &params );
info->EncryptAlgorithm = conn_info.aiCipher;
info->sSignatureAlgorithmName = get_alg_name(info->SignatureAlgorithm, TRUE);
info->sEncryptAlgorithmName = get_alg_name(info->EncryptAlgorithm, TRUE);
@ -1027,7 +1058,8 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
case SECPKG_ATTR_CONNECTION_INFO:
{
SecPkgContext_ConnectionInfo *info = buffer;
return schan_funcs->get_connection_info(ctx->transport.session, info);
struct get_connection_info_params params = { ctx->transport.session, info };
return GNUTLS_CALL( get_connection_info, &params );
}
case SECPKG_ATTR_ENDPOINT_BINDINGS:
{
@ -1076,8 +1108,9 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
SecPkgContext_Bindings *bindings = buffer;
ULONG size;
char *p;
struct get_unique_channel_binding_params params = { ctx->transport.session, NULL, &size };
if (schan_funcs->get_unique_channel_binding(ctx->transport.session, NULL, &size) != SEC_E_BUFFER_TOO_SMALL)
if (GNUTLS_CALL( get_unique_channel_binding, &params ) != SEC_E_BUFFER_TOO_SMALL)
return SEC_E_INTERNAL_ERROR;
bindings->BindingsLength = sizeof(*bindings->Bindings) + sizeof(prefix)-1 + size;
@ -1092,12 +1125,14 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
p = (char*)(bindings->Bindings+1);
memcpy(p, prefix, sizeof(prefix)-1);
p += sizeof(prefix)-1;
return schan_funcs->get_unique_channel_binding(ctx->transport.session, p, &size);
params.buffer = p;
return GNUTLS_CALL( get_unique_channel_binding, &params );
}
case SECPKG_ATTR_APPLICATION_PROTOCOL:
{
SecPkgContext_ApplicationProtocol *protocol = buffer;
return schan_funcs->get_application_protocol(ctx->transport.session, protocol);
struct get_application_protocol_params params = { ctx->transport.session, protocol };
return GNUTLS_CALL( get_application_protocol, &params );
}
default:
@ -1148,6 +1183,7 @@ static SECURITY_STATUS SEC_ENTRY schan_EncryptMessage(PCtxtHandle context_handle
ULONG quality, PSecBufferDesc message, ULONG message_seq_no)
{
struct schan_context *ctx;
struct send_params params;
SECURITY_STATUS status;
SecBuffer *buffer;
SIZE_T data_size;
@ -1176,7 +1212,11 @@ static SECURITY_STATUS SEC_ENTRY schan_EncryptMessage(PCtxtHandle context_handle
memcpy(data, buffer->pvBuffer, data_size);
length = data_size;
status = schan_funcs->send(ctx->transport.session, message, data, &length);
params.session = ctx->transport.session;
params.output = message;
params.buffer = data;
params.length = &length;
status = GNUTLS_CALL( send, &params );
TRACE("Sent %ld bytes.\n", length);
@ -1251,6 +1291,7 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle
{
SECURITY_STATUS status = SEC_E_OK;
struct schan_context *ctx;
struct recv_params params;
SecBuffer *buffer;
SIZE_T data_size;
char *data;
@ -1294,7 +1335,13 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle
data = malloc(data_size);
received = data_size;
status = schan_funcs->recv(ctx->transport.session, message, expected_size, data, &received);
params.session = ctx->transport.session;
params.input = message;
params.input_size = expected_size;
params.buffer = data;
params.length = &received;
status = GNUTLS_CALL( recv, &params );
if (status != SEC_E_OK && status != SEC_I_RENEGOTIATE)
{
@ -1327,6 +1374,7 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle
static SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context_handle)
{
struct schan_context *ctx;
struct session_params params;
TRACE("context_handle %p\n", context_handle);
@ -1336,7 +1384,8 @@ static SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context
if (!ctx) return SEC_E_INVALID_HANDLE;
if (ctx->cert) CertFreeCertificateContext(ctx->cert);
schan_funcs->dispose_session(ctx->transport.session);
params.session = ctx->transport.session;
GNUTLS_CALL( dispose_session, &params );
free(ctx);
return SEC_E_OK;
}
@ -1428,10 +1477,15 @@ void SECUR32_initSchannelSP(void)
};
SecureProvider *provider;
if (!schan_funcs && __wine_init_unix_lib(hsecur32, DLL_PROCESS_ATTACH, NULL, &schan_funcs))
if (!gnutls_handle)
{
ERR( "no schannel support, expect problems\n" );
return;
if (NtQueryVirtualMemory( GetCurrentProcess(), hsecur32, MemoryWineUnixFuncs,
&gnutls_handle, sizeof(gnutls_handle), NULL ) ||
GNUTLS_CALL( process_attach, NULL ))
{
ERR( "no schannel support, expect problems\n" );
return;
}
}
schan_handle_table = malloc(64 * sizeof(*schan_handle_table));
@ -1471,7 +1525,8 @@ void SECUR32_deinitSchannelSP(void)
if (schan_handle_table[i].type == SCHAN_HANDLE_CTX)
{
struct schan_context *ctx = schan_free_handle(i, SCHAN_HANDLE_CTX);
schan_funcs->dispose_session(ctx->transport.session);
struct session_params params = { ctx->transport.session };
GNUTLS_CALL( dispose_session, &params );
free(ctx);
}
}
@ -1480,14 +1535,13 @@ void SECUR32_deinitSchannelSP(void)
{
if (schan_handle_table[i].type != SCHAN_HANDLE_FREE)
{
struct schan_credentials *cred;
cred = schan_free_handle(i, SCHAN_HANDLE_CRED);
schan_funcs->free_certificate_credentials(cred);
struct schan_credentials *cred = schan_free_handle(i, SCHAN_HANDLE_CRED);
struct free_certificate_credentials_params params = { cred };
GNUTLS_CALL( free_certificate_credentials, &params );
free(cred);
}
}
free(schan_handle_table);
__wine_init_unix_lib(hsecur32, DLL_PROCESS_DETACH, NULL, NULL);
schan_funcs = NULL;
GNUTLS_CALL( process_detach, NULL );
gnutls_handle = 0;
}

View file

@ -45,6 +45,7 @@
#include "sspi.h"
#include "secur32_priv.h"
#include "wine/unixlib.h"
#include "wine/debug.h"
#if defined(SONAME_LIBGNUTLS)
@ -445,7 +446,7 @@ static void check_supported_protocols(void)
pgnutls_deinit(session);
}
static DWORD CDECL schan_get_enabled_protocols(void)
static NTSTATUS schan_get_enabled_protocols( void *args )
{
return supported_protocols;
}
@ -463,9 +464,11 @@ static int pull_timeout(gnutls_transport_ptr_t transport, unsigned int timeout)
return -1;
}
static BOOL CDECL schan_create_session(schan_session *session, schan_credentials *cred)
static NTSTATUS schan_create_session( void *args )
{
gnutls_session_t *s = (gnutls_session_t*)session;
const struct create_session_params *params = args;
schan_credentials *cred = params->cred;
gnutls_session_t *s = (gnutls_session_t*)&params->transport->session;
char priority[128] = "NORMAL:%LATEST_RECORD_VERSION", *p;
BOOL using_vers_all = FALSE, disabled;
unsigned int i, flags = (cred->credential_use == SECPKG_CRED_INBOUND) ? GNUTLS_SERVER : GNUTLS_CLIENT;
@ -480,7 +483,7 @@ static BOOL CDECL schan_create_session(schan_session *session, schan_credentials
if (err != GNUTLS_E_SUCCESS)
{
pgnutls_perror(err);
return FALSE;
return STATUS_INTERNAL_ERROR;
}
p = priority + strlen(priority);
@ -514,7 +517,7 @@ static BOOL CDECL schan_create_session(schan_session *session, schan_credentials
{
pgnutls_perror(err);
pgnutls_deinit(*s);
return FALSE;
return STATUS_INTERNAL_ERROR;
}
err = pgnutls_credentials_set(*s, GNUTLS_CRD_CERTIFICATE,
@ -523,46 +526,44 @@ static BOOL CDECL schan_create_session(schan_session *session, schan_credentials
{
pgnutls_perror(err);
pgnutls_deinit(*s);
return FALSE;
return STATUS_INTERNAL_ERROR;
}
pgnutls_transport_set_pull_function(*s, pull_adapter);
if (flags & GNUTLS_DATAGRAM) pgnutls_transport_set_pull_timeout_function(*s, pull_timeout);
pgnutls_transport_set_push_function(*s, push_adapter);
pgnutls_transport_set_ptr(*s, (gnutls_transport_ptr_t)params->transport);
return TRUE;
return STATUS_SUCCESS;
}
static void CDECL schan_dispose_session(schan_session session)
static NTSTATUS schan_dispose_session( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct session_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
pgnutls_deinit(s);
return STATUS_SUCCESS;
}
static void CDECL schan_set_session_transport(schan_session session, struct schan_transport *t)
static NTSTATUS schan_set_session_target( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
pgnutls_transport_set_ptr(s, (gnutls_transport_ptr_t)t);
const struct set_session_target_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
pgnutls_server_name_set( s, GNUTLS_NAME_DNS, params->target, strlen(params->target) );
return STATUS_SUCCESS;
}
static void CDECL schan_set_session_target(schan_session session, const char *target)
static NTSTATUS schan_handshake( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
pgnutls_server_name_set( s, GNUTLS_NAME_DNS, target, strlen(target) );
}
static SECURITY_STATUS CDECL schan_handshake(schan_session session, SecBufferDesc *input,
SIZE_T input_size, SecBufferDesc *output,
SecBuffer *alloc_buffer )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct handshake_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
int err;
init_schan_buffers(&t->in, input, handshake_get_next_buffer);
t->in.limit = input_size;
init_schan_buffers(&t->out, output, handshake_get_next_buffer_alloc );
t->out.alloc_buffer = alloc_buffer;
init_schan_buffers(&t->in, params->input, handshake_get_next_buffer);
t->in.limit = params->input_size;
init_schan_buffers(&t->out, params->output, handshake_get_next_buffer_alloc );
t->out.alloc_buffer = params->alloc_buffer;
while(1) {
err = pgnutls_handshake(s);
@ -698,20 +699,24 @@ static ALG_ID get_kx_algid(int kx)
}
}
static unsigned int CDECL schan_get_session_cipher_block_size(schan_session session)
static NTSTATUS schan_get_session_cipher_block_size( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct session_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
return pgnutls_cipher_get_block_size(pgnutls_cipher_get(s));
}
static unsigned int CDECL schan_get_max_message_size(schan_session session)
static NTSTATUS schan_get_max_message_size( void *args )
{
return pgnutls_record_get_max_size((gnutls_session_t)session);
const struct session_params *params = args;
return pgnutls_record_get_max_size((gnutls_session_t)params->session);
}
static SECURITY_STATUS CDECL schan_get_connection_info(schan_session session, SecPkgContext_ConnectionInfo *info)
static NTSTATUS schan_get_connection_info( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct get_connection_info_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
SecPkgContext_ConnectionInfo *info = params->info;
gnutls_protocol_t proto = pgnutls_protocol_get_version(s);
gnutls_cipher_algorithm_t alg = pgnutls_cipher_get(s);
gnutls_mac_algorithm_t mac = pgnutls_mac_get(s);
@ -728,12 +733,13 @@ static SECURITY_STATUS CDECL schan_get_connection_info(schan_session session, Se
return SEC_E_OK;
}
static SECURITY_STATUS CDECL schan_get_unique_channel_binding(schan_session session, void *buffer, ULONG *bufsize)
static NTSTATUS schan_get_unique_channel_binding( void *args )
{
const struct get_unique_channel_binding_params *params = args;
gnutls_datum_t datum;
int rc;
SECURITY_STATUS ret;
gnutls_session_t s = (gnutls_session_t)session;
gnutls_session_t s = (gnutls_session_t)params->session;
rc = pgnutls_session_channel_binding(s, GNUTLS_CB_TLS_UNIQUE, &datum);
if (rc)
@ -741,24 +747,25 @@ static SECURITY_STATUS CDECL schan_get_unique_channel_binding(schan_session sess
pgnutls_perror(rc);
return SEC_E_INTERNAL_ERROR;
}
if (buffer && *bufsize >= datum.size)
if (params->buffer && *params->bufsize >= datum.size)
{
memcpy( buffer, datum.data, datum.size );
memcpy( params->buffer, datum.data, datum.size );
ret = SEC_E_OK;
}
else ret = SEC_E_BUFFER_TOO_SMALL;
*bufsize = datum.size;
*params->bufsize = datum.size;
free(datum.data);
return ret;
}
static ALG_ID CDECL schan_get_key_signature_algorithm(schan_session session)
static NTSTATUS schan_get_key_signature_algorithm( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct session_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
gnutls_kx_algorithm_t kx = pgnutls_kx_get(s);
TRACE("(%p)\n", session);
TRACE("(%p)\n", params->session);
switch (kx)
{
@ -774,10 +781,11 @@ static ALG_ID CDECL schan_get_key_signature_algorithm(schan_session session)
}
}
static SECURITY_STATUS CDECL schan_get_session_peer_certificate(schan_session session, CERT_BLOB *certs,
ULONG *bufsize, ULONG *retcount)
static NTSTATUS schan_get_session_peer_certificate( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct get_session_peer_certificate_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
CERT_BLOB *certs = params->certs;
const gnutls_datum_t *datum;
unsigned int i, size;
BYTE *ptr;
@ -788,9 +796,9 @@ static SECURITY_STATUS CDECL schan_get_session_peer_certificate(schan_session se
size = count * sizeof(certs[0]);
for (i = 0; i < count; i++) size += datum[i].size;
if (!certs || *bufsize < size)
if (!certs || *params->bufsize < size)
{
*bufsize = size;
*params->bufsize = size;
return SEC_E_BUFFER_TOO_SMALL;
}
ptr = (BYTE *)&certs[count];
@ -802,31 +810,31 @@ static SECURITY_STATUS CDECL schan_get_session_peer_certificate(schan_session se
ptr += datum[i].size;
}
*bufsize = size;
*retcount = count;
*params->bufsize = size;
*params->retcount = count;
return SEC_E_OK;
}
static SECURITY_STATUS CDECL schan_send(schan_session session, SecBufferDesc *output,
const void *buffer, SIZE_T *length)
static NTSTATUS schan_send( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct send_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
SSIZE_T ret, total = 0;
if (schan_find_sec_buffer_idx(output, 0, SECBUFFER_STREAM_HEADER) != -1)
init_schan_buffers(&t->out, output, send_message_get_next_buffer);
if (schan_find_sec_buffer_idx(params->output, 0, SECBUFFER_STREAM_HEADER) != -1)
init_schan_buffers(&t->out, params->output, send_message_get_next_buffer);
else
init_schan_buffers(&t->out, output, send_message_get_next_buffer_token);
init_schan_buffers(&t->out, params->output, send_message_get_next_buffer_token);
for (;;)
{
ret = pgnutls_record_send(s, (const char *)buffer + total, *length - total);
ret = pgnutls_record_send(s, (const char *)params->buffer + total, *params->length - total);
if (ret >= 0)
{
total += ret;
TRACE( "sent %ld now %ld/%ld\n", ret, total, *length );
if (total == *length) break;
TRACE( "sent %ld now %ld/%ld\n", ret, total, *params->length );
if (total == *params->length) break;
}
else if (ret == GNUTLS_E_AGAIN)
{
@ -846,22 +854,22 @@ static SECURITY_STATUS CDECL schan_send(schan_session session, SecBufferDesc *ou
return SEC_E_OK;
}
static SECURITY_STATUS CDECL schan_recv(schan_session session, SecBufferDesc *input,
SIZE_T input_size, void *buffer, SIZE_T *length)
static NTSTATUS schan_recv( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct recv_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
size_t data_size = *length;
size_t data_size = *params->length;
size_t received = 0;
ssize_t ret;
SECURITY_STATUS status = SEC_E_OK;
init_schan_buffers(&t->in, input, recv_message_get_next_buffer);
t->in.limit = input_size;
init_schan_buffers(&t->in, params->input, recv_message_get_next_buffer);
t->in.limit = params->input_size;
while (received < data_size)
{
ret = pgnutls_record_recv(s, (char *)buffer + received, data_size - received);
ret = pgnutls_record_recv(s, (char *)params->buffer + received, data_size - received);
if (ret > 0) received += ret;
else if (!ret) break;
@ -884,7 +892,7 @@ static SECURITY_STATUS CDECL schan_recv(schan_session session, SecBufferDesc *in
}
}
*length = received;
*params->length = received;
return status;
}
@ -910,48 +918,51 @@ static unsigned int parse_alpn_protocol_list(unsigned char *buffer, unsigned int
return count;
}
static void CDECL schan_set_application_protocols(schan_session session, unsigned char *buffer, unsigned int buflen)
static NTSTATUS schan_set_application_protocols( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct set_application_protocols_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
unsigned int extension_len, extension, count = 0, offset = 0;
unsigned short list_len;
gnutls_datum_t *protocols;
int ret;
if (sizeof(extension_len) > buflen) return;
extension_len = *(unsigned int *)&buffer[offset];
if (sizeof(extension_len) > params->buflen) return STATUS_INVALID_PARAMETER;
extension_len = *(unsigned int *)&params->buffer[offset];
offset += sizeof(extension_len);
if (offset + sizeof(extension) > buflen) return;
extension = *(unsigned int *)&buffer[offset];
if (offset + sizeof(extension) > params->buflen) return STATUS_INVALID_PARAMETER;
extension = *(unsigned int *)&params->buffer[offset];
if (extension != SecApplicationProtocolNegotiationExt_ALPN)
{
FIXME("extension %u not supported\n", extension);
return;
return STATUS_NOT_SUPPORTED;
}
offset += sizeof(extension);
if (offset + sizeof(list_len) > buflen) return;
list_len = *(unsigned short *)&buffer[offset];
if (offset + sizeof(list_len) > params->buflen) return STATUS_INVALID_PARAMETER;
list_len = *(unsigned short *)&params->buffer[offset];
offset += sizeof(list_len);
if (offset + list_len > buflen) return;
count = parse_alpn_protocol_list(&buffer[offset], list_len, NULL);
if (!count || !(protocols = RtlAllocateHeap(GetProcessHeap(), 0, count * sizeof(*protocols)))) return;
if (offset + list_len > params->buflen) return STATUS_INVALID_PARAMETER;
count = parse_alpn_protocol_list(&params->buffer[offset], list_len, NULL);
if (!count || !(protocols = malloc(count * sizeof(*protocols)))) return STATUS_NO_MEMORY;
parse_alpn_protocol_list(&buffer[offset], list_len, protocols);
parse_alpn_protocol_list(&params->buffer[offset], list_len, protocols);
if ((ret = pgnutls_alpn_set_protocols(s, protocols, count, GNUTLS_ALPN_SERVER_PRECEDENCE) < 0))
{
pgnutls_perror(ret);
}
RtlFreeHeap(GetProcessHeap(), 0, protocols);
free(protocols);
return STATUS_SUCCESS;
}
static SECURITY_STATUS CDECL schan_get_application_protocol(schan_session session,
SecPkgContext_ApplicationProtocol *protocol)
static NTSTATUS schan_get_application_protocol( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct get_application_protocol_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
SecPkgContext_ApplicationProtocol *protocol = params->protocol;
gnutls_datum_t selected;
memset(protocol, 0, sizeof(*protocol));
@ -968,12 +979,13 @@ static SECURITY_STATUS CDECL schan_get_application_protocol(schan_session sessio
return SEC_E_OK;
}
static SECURITY_STATUS CDECL schan_set_dtls_mtu(schan_session session, unsigned int mtu)
static NTSTATUS schan_set_dtls_mtu( void *args )
{
gnutls_session_t s = (gnutls_session_t)session;
const struct set_dtls_mtu_params *params = args;
gnutls_session_t s = (gnutls_session_t)params->session;
pgnutls_dtls_set_mtu(s, mtu);
TRACE("MTU set to %u\n", mtu);
pgnutls_dtls_set_mtu(s, params->mtu);
TRACE("MTU set to %u\n", params->mtu);
return SEC_E_OK;
}
@ -1079,9 +1091,9 @@ static gnutls_x509_crt_t get_x509_crt(const CERT_CONTEXT *ctx)
return crt;
}
static BOOL CDECL schan_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *ctx,
const DATA_BLOB *key_blob )
static NTSTATUS schan_allocate_certificate_credentials( void *args )
{
const struct allocate_certificate_credentials_params *params = args;
gnutls_certificate_credentials_t creds;
gnutls_x509_crt_t crt;
gnutls_x509_privkey_t key;
@ -1091,26 +1103,26 @@ static BOOL CDECL schan_allocate_certificate_credentials(schan_credentials *c, c
if (ret != GNUTLS_E_SUCCESS)
{
pgnutls_perror(ret);
return FALSE;
return STATUS_INTERNAL_ERROR;
}
if (!ctx)
if (!params->ctx)
{
c->credentials = creds;
return TRUE;
params->c->credentials = creds;
return STATUS_SUCCESS;
}
if (!(crt = get_x509_crt(ctx)))
if (!(crt = get_x509_crt(params->ctx)))
{
pgnutls_certificate_free_credentials(creds);
return FALSE;
return STATUS_INTERNAL_ERROR;
}
if (!(key = get_x509_key(key_blob)))
if (!(key = get_x509_key(params->key_blob)))
{
pgnutls_x509_crt_deinit(crt);
pgnutls_certificate_free_credentials(creds);
return FALSE;
return STATUS_INTERNAL_ERROR;
}
ret = pgnutls_certificate_set_x509_key(creds, &crt, 1, key);
@ -1120,16 +1132,18 @@ static BOOL CDECL schan_allocate_certificate_credentials(schan_credentials *c, c
{
pgnutls_perror(ret);
pgnutls_certificate_free_credentials(creds);
return FALSE;
return STATUS_INTERNAL_ERROR;
}
c->credentials = creds;
return TRUE;
params->c->credentials = creds;
return STATUS_SUCCESS;
}
static void CDECL schan_free_certificate_credentials(schan_credentials *c)
static NTSTATUS schan_free_certificate_credentials( void *args )
{
pgnutls_certificate_free_credentials(c->credentials);
const struct free_certificate_credentials_params *params = args;
pgnutls_certificate_free_credentials(params->c->credentials);
return STATUS_SUCCESS;
}
static void gnutls_log(int level, const char *msg)
@ -1137,7 +1151,7 @@ static void gnutls_log(int level, const char *msg)
TRACE("<%d> %s", level, msg);
}
static BOOL gnutls_initialize(void)
static NTSTATUS process_attach( void *args )
{
const char *env_str;
int ret;
@ -1156,7 +1170,7 @@ static BOOL gnutls_initialize(void)
if (!libgnutls_handle)
{
ERR_(winediag)("Failed to load libgnutls, secure connections will not be available.\n");
return FALSE;
return STATUS_DLL_NOT_FOUND;
}
#define LOAD_FUNCPTR(f) \
@ -1256,23 +1270,26 @@ static BOOL gnutls_initialize(void)
}
check_supported_protocols();
return TRUE;
return STATUS_SUCCESS;
fail:
dlclose(libgnutls_handle);
libgnutls_handle = NULL;
return FALSE;
return STATUS_DLL_NOT_FOUND;
}
static void gnutls_uninitialize(void)
static NTSTATUS process_detach( void *args )
{
pgnutls_global_deinit();
dlclose(libgnutls_handle);
libgnutls_handle = NULL;
return STATUS_SUCCESS;
}
static const struct schan_funcs funcs =
const unixlib_entry_t __wine_unix_call_funcs[] =
{
process_attach,
process_detach,
schan_allocate_certificate_credentials,
schan_create_session,
schan_dispose_session,
@ -1291,22 +1308,6 @@ static const struct schan_funcs funcs =
schan_set_application_protocols,
schan_set_dtls_mtu,
schan_set_session_target,
schan_set_session_transport,
};
NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out )
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
if (!gnutls_initialize()) return STATUS_DLL_NOT_FOUND;
*(const struct schan_funcs **)ptr_out = &funcs;
break;
case DLL_PROCESS_DETACH:
if (libgnutls_handle) gnutls_uninitialize();
break;
}
return STATUS_SUCCESS;
}
#endif /* SONAME_LIBGNUTLS */

View file

@ -108,29 +108,123 @@ struct schan_transport
struct schan_buffers out;
};
struct schan_funcs
struct session_params
{
BOOL (CDECL *allocate_certificate_credentials)(schan_credentials *, const CERT_CONTEXT *, const DATA_BLOB *);
BOOL (CDECL *create_session)(schan_session *, schan_credentials *);
void (CDECL *dispose_session)(schan_session);
void (CDECL *free_certificate_credentials)(schan_credentials *);
SECURITY_STATUS (CDECL *get_application_protocol)(schan_session, SecPkgContext_ApplicationProtocol *);
SECURITY_STATUS (CDECL *get_connection_info)(schan_session, SecPkgContext_ConnectionInfo *);
DWORD (CDECL *get_enabled_protocols)(void);
ALG_ID (CDECL *get_key_signature_algorithm)(schan_session);
unsigned int (CDECL *get_max_message_size)(schan_session);
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 *, 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);
SECURITY_STATUS (CDECL *set_dtls_mtu)(schan_session, unsigned int);
void (CDECL *set_session_target)(schan_session, const char *);
void (CDECL *set_session_transport)(schan_session, struct schan_transport *);
schan_session session;
};
extern const struct schan_funcs *schan_funcs;
struct allocate_certificate_credentials_params
{
schan_credentials *c;
const CERT_CONTEXT *ctx;
const DATA_BLOB *key_blob;
};
struct create_session_params
{
struct schan_transport *transport;
schan_credentials *cred;
};
struct free_certificate_credentials_params
{
schan_credentials *c;
};
struct get_application_protocol_params
{
schan_session session;
SecPkgContext_ApplicationProtocol *protocol;
};
struct get_connection_info_params
{
schan_session session;
SecPkgContext_ConnectionInfo *info;
};
struct get_session_peer_certificate_params
{
schan_session session;
CERT_BLOB *certs;
ULONG *bufsize;
ULONG *retcount;
};
struct get_unique_channel_binding_params
{
schan_session session;
void *buffer;
ULONG *bufsize;
};
struct handshake_params
{
schan_session session;
SecBufferDesc *input;
SIZE_T input_size;
SecBufferDesc *output;
SecBuffer *alloc_buffer;
};
struct recv_params
{
schan_session session;
SecBufferDesc *input;
SIZE_T input_size;
void *buffer;
SIZE_T *length;
};
struct send_params
{
schan_session session;
SecBufferDesc *output;
const void *buffer;
SIZE_T *length;
};
struct set_application_protocols_params
{
schan_session session;
unsigned char *buffer;
unsigned int buflen;
};
struct set_dtls_mtu_params
{
schan_session session;
unsigned int mtu;
};
struct set_session_target_params
{
schan_session session;
const char *target;
};
enum schan_funcs
{
unix_process_attach,
unix_process_detach,
unix_allocate_certificate_credentials,
unix_create_session,
unix_dispose_session,
unix_free_certificate_credentials,
unix_get_application_protocol,
unix_get_connection_info,
unix_get_enabled_protocols,
unix_get_key_signature_algorithm,
unix_get_max_message_size,
unix_get_session_cipher_block_size,
unix_get_session_peer_certificate,
unix_get_unique_channel_binding,
unix_handshake,
unix_recv,
unix_send,
unix_set_application_protocols,
unix_set_dtls_mtu,
unix_set_session_target,
};
#endif /* __SECUR32_PRIV_H__ */