[PATCH 3/6] secur32: Move Schannel support to a Unix library.

Hans Leidekker hans at codeweavers.com
Fri May 7 04:54:41 CDT 2021


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/secur32/schannel.c        | 252 ++++++++++++++++++-------
 dlls/secur32/schannel_gnutls.c | 323 +++++++++++++--------------------
 dlls/secur32/schannel_macosx.c | 210 ++++++++++++---------
 dlls/secur32/secur32.c         |   3 +
 dlls/secur32/secur32_priv.h    |  81 +++++----
 5 files changed, 477 insertions(+), 392 deletions(-)

diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index 1dd3a029401..5f6b96903c4 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -17,9 +17,8 @@
  *
  * This file implements the schannel provider, or, the SSL/TLS implementations.
  */
-#include "config.h"
-#include "wine/port.h"
 
+#include <assert.h>
 #include <stdarg.h>
 #include <errno.h>
 
@@ -28,6 +27,7 @@
 #include "winbase.h"
 #include "winreg.h"
 #include "winnls.h"
+#include "lmcons.h"
 #include "sspi.h"
 #include "schannel.h"
 #include "secur32_priv.h"
@@ -37,7 +37,7 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
 
-#if defined(SONAME_LIBGNUTLS) || defined (HAVE_SECURITY_SECURITY_H)
+const struct schan_funcs *schan_funcs = NULL;
 
 #define SCHAN_INVALID_HANDLE ~0UL
 
@@ -56,7 +56,7 @@ struct schan_handle
 
 struct schan_context
 {
-    schan_imp_session session;
+    schan_session session;
     struct schan_transport transport;
     ULONG req_ctx_attr;
     const CERT_CONTEXT *cert;
@@ -242,7 +242,7 @@ static void read_config(void)
 
     RegCloseKey(protocols_key);
 
-    config_enabled_protocols = enabled & schan_imp_enabled_protocols();
+    config_enabled_protocols = enabled & schan_funcs->get_enabled_protocols();
     config_default_disabled_protocols = default_disabled;
     config_read = TRUE;
 
@@ -389,6 +389,116 @@ static SECURITY_STATUS get_cert(const SCHANNEL_CRED *cred, CERT_CONTEXT const **
     return status;
 }
 
+static WCHAR *get_key_container_path(const CERT_CONTEXT *ctx)
+{
+    static const WCHAR rsabaseW[] =
+        {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','C','r','y','p','t','o','\\','R','S','A','\\',0};
+    CERT_KEY_CONTEXT keyctx;
+    DWORD size = sizeof(keyctx), prov_size = 0;
+    CRYPT_KEY_PROV_INFO *prov;
+    WCHAR username[UNLEN + 1], *ret = NULL;
+    DWORD len = ARRAY_SIZE(username);
+
+    if (CertGetCertificateContextProperty(ctx, CERT_KEY_CONTEXT_PROP_ID, &keyctx, &size))
+    {
+        char *str;
+        if (!CryptGetProvParam(keyctx.hCryptProv, PP_CONTAINER, NULL, &size, 0)) return NULL;
+        if (!(str = RtlAllocateHeap(GetProcessHeap(), 0, size))) return NULL;
+        if (!CryptGetProvParam(keyctx.hCryptProv, PP_CONTAINER, (BYTE *)str, &size, 0)) return NULL;
+
+        len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+        if (!(ret = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(rsabaseW) + len * sizeof(WCHAR))))
+        {
+            RtlFreeHeap(GetProcessHeap(), 0, str);
+            return NULL;
+        }
+        strcpyW(ret, rsabaseW);
+        MultiByteToWideChar(CP_ACP, 0, str, -1, ret + strlenW(ret), len);
+        RtlFreeHeap(GetProcessHeap(), 0, str);
+    }
+    else if (CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, NULL, &prov_size))
+    {
+        if (!(prov = RtlAllocateHeap(GetProcessHeap(), 0, prov_size))) return NULL;
+        if (!CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, prov, &prov_size))
+        {
+            RtlFreeHeap(GetProcessHeap(), 0, prov);
+            return NULL;
+        }
+        if (!(ret = RtlAllocateHeap(GetProcessHeap(), 0,
+                                    sizeof(rsabaseW) + strlenW(prov->pwszContainerName) * sizeof(WCHAR))))
+        {
+            RtlFreeHeap(GetProcessHeap(), 0, prov);
+            return NULL;
+        }
+        strcpyW(ret, rsabaseW);
+        strcatW(ret, prov->pwszContainerName);
+        RtlFreeHeap(GetProcessHeap(), 0, prov);
+    }
+
+    if (!ret && GetUserNameW(username, &len) && (ret = RtlAllocateHeap(GetProcessHeap(), 0,
+                                                                       sizeof(rsabaseW) + len * sizeof(WCHAR))))
+    {
+        strcpyW(ret, rsabaseW);
+        strcatW(ret, username);
+    }
+
+    return ret;
+}
+
+#define MAX_LEAD_BYTES 8
+static BYTE *get_key_blob(const CERT_CONTEXT *ctx, DWORD *size)
+{
+    static const WCHAR keyexchangeW[] =
+        {'K','e','y','E','x','c','h','a','n','g','e','K','e','y','P','a','i','r',0};
+    static const WCHAR signatureW[] =
+        {'S','i','g','n','a','t','u','r','e','K','e','y','P','a','i','r',0};
+    BYTE *buf, *ret = NULL;
+    DATA_BLOB blob_in, blob_out;
+    DWORD spec = 0, type, len;
+    WCHAR *path;
+    HKEY hkey;
+
+    if (!(path = get_key_container_path(ctx))) return NULL;
+    if (RegOpenKeyExW(HKEY_CURRENT_USER, path, 0, KEY_READ, &hkey))
+    {
+        RtlFreeHeap(GetProcessHeap(), 0, path);
+        return NULL;
+    }
+    RtlFreeHeap(GetProcessHeap(), 0, path);
+
+    if (!RegQueryValueExW(hkey, keyexchangeW, 0, &type, NULL, &len)) spec = AT_KEYEXCHANGE;
+    else if (!RegQueryValueExW(hkey, signatureW, 0, &type, NULL, &len)) spec = AT_SIGNATURE;
+    else
+    {
+        RegCloseKey(hkey);
+        return NULL;
+    }
+
+    if (!(buf = RtlAllocateHeap(GetProcessHeap(), 0, len + MAX_LEAD_BYTES)))
+    {
+        RegCloseKey(hkey);
+        return NULL;
+    }
+
+    if (!RegQueryValueExW(hkey, (spec == AT_KEYEXCHANGE) ? keyexchangeW : signatureW, 0, &type, buf, &len))
+    {
+        blob_in.pbData = buf;
+        blob_in.cbData = len;
+        if (CryptUnprotectData(&blob_in, NULL, NULL, NULL, NULL, 0, &blob_out))
+        {
+            assert(blob_in.cbData >= blob_out.cbData);
+            memcpy(buf, blob_out.pbData, blob_out.cbData);
+            LocalFree(blob_out.pbData);
+            *size = blob_out.cbData + MAX_LEAD_BYTES;
+            ret = buf;
+        }
+    }
+    else RtlFreeHeap(GetProcessHeap(), 0, buf);
+
+    RegCloseKey(hkey);
+    return ret;
+}
+
 static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schanCred,
  PCredHandle phCredential, PTimeStamp ptsExpiry)
 {
@@ -397,6 +507,7 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
     ULONG_PTR handle;
     SECURITY_STATUS status = SEC_E_OK;
     const CERT_CONTEXT *cert = NULL;
+    DATA_BLOB key_blob = {0};
 
     TRACE("schanCred %p, phCredential %p, ptsExpiry %p\n", schanCred, phCredential, ptsExpiry);
 
@@ -426,20 +537,17 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
         return SEC_E_NO_AUTHENTICATING_AUTHORITY;
     }
 
-    creds = heap_alloc(sizeof(*creds));
-    if (!creds) return SEC_E_INSUFFICIENT_MEMORY;
+    if (!(creds = heap_alloc(sizeof(*creds)))) return SEC_E_INSUFFICIENT_MEMORY;
+    creds->credential_use = SECPKG_CRED_OUTBOUND;
+    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;
+    RtlFreeHeap(GetProcessHeap(), 0, key_blob.pbData);
 
     handle = schan_alloc_handle(creds, SCHAN_HANDLE_CRED);
     if (handle == SCHAN_INVALID_HANDLE) goto fail;
 
-    creds->credential_use = SECPKG_CRED_OUTBOUND;
-    if (!schan_imp_allocate_certificate_credentials(creds, cert))
-    {
-        schan_free_handle(handle, SCHAN_HANDLE_CRED);
-        goto fail;
-    }
-
-    creds->enabled_protocols = enabled_protocols;
     phCredential->dwLower = handle;
     phCredential->dwUpper = 0;
 
@@ -454,6 +562,7 @@ static SECURITY_STATUS schan_AcquireClientCredentials(const SCHANNEL_CRED *schan
 
 fail:
     heap_free(creds);
+    RtlFreeHeap(GetProcessHeap(), 0, key_blob.pbData);
     return SEC_E_INTERNAL_ERROR;
 }
 
@@ -542,10 +651,8 @@ 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_imp_free_certificate_credentials(creds);
+    if (creds->credential_use == SECPKG_CRED_OUTBOUND) schan_funcs->free_certificate_credentials(creds);
     heap_free(creds);
-
     return SEC_E_OK;
 }
 
@@ -599,7 +706,7 @@ static void schan_resize_current_buffer(const struct schan_buffers *s, SIZE_T mi
     b->pvBuffer = new_data;
 }
 
-char *schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count)
+static char * CDECL schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count)
 {
     SIZE_T max_count;
     PSecBuffer buffer;
@@ -672,7 +779,7 @@ char *schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s,
  *  another errno-style error value on failure
  *
  */
-int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len)
+static int CDECL schan_pull(struct schan_transport *t, void *buff, size_t *buff_len)
 {
     char *b;
     SIZE_T local_len = *buff_len;
@@ -711,7 +818,7 @@ int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len)
  *  another errno-style error value on failure
  *
  */
-int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len)
+static int CDECL schan_push(struct schan_transport *t, const void *buff, size_t *buff_len)
 {
     char *b;
     SIZE_T local_len = *buff_len;
@@ -733,7 +840,7 @@ int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len)
     return 0;
 }
 
-schan_imp_session schan_session_for_transport(struct schan_transport* t)
+static schan_session CDECL schan_get_session_for_transport(struct schan_transport* t)
 {
     return t->ctx->session;
 }
@@ -845,7 +952,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
             return SEC_E_INTERNAL_ERROR;
         }
 
-        if (!schan_imp_create_session(&ctx->session, cred))
+        if (!schan_funcs->create_session(&ctx->session, cred))
         {
             schan_free_handle(handle, SCHAN_HANDLE_CTX);
             heap_free(ctx);
@@ -858,7 +965,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
             ctx->header_size = HEADER_SIZE_TLS;
 
         ctx->transport.ctx = ctx;
-        schan_imp_set_session_transport(ctx->session, &ctx->transport);
+        schan_funcs->set_session_transport(ctx->session, &ctx->transport);
 
         if (pszTargetName && *pszTargetName)
         {
@@ -868,7 +975,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
             if (target)
             {
                 WideCharToMultiByte( CP_UNIXCP, 0, pszTargetName, -1, target, len, NULL, NULL );
-                schan_imp_set_session_target( ctx->session, target );
+                schan_funcs->set_session_target( ctx->session, target );
                 heap_free( target );
             }
         }
@@ -876,13 +983,13 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
         if (pInput && (idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_APPLICATION_PROTOCOLS)) != -1)
         {
             buffer = &pInput->pBuffers[idx];
-            schan_imp_set_application_protocols(ctx->session, buffer->pvBuffer, buffer->cbBuffer);
+            schan_funcs->set_application_protocols(ctx->session, buffer->pvBuffer, buffer->cbBuffer);
         }
 
         if (pInput && (idx = schan_find_sec_buffer_idx(pInput, 0, SECBUFFER_DTLS_MTU)) != -1)
         {
             buffer = &pInput->pBuffers[idx];
-            if (buffer->cbBuffer >= sizeof(WORD)) schan_imp_set_dtls_mtu(ctx->session, *(WORD *)buffer->pvBuffer);
+            if (buffer->cbBuffer >= sizeof(WORD)) schan_funcs->set_dtls_mtu(ctx->session, *(WORD *)buffer->pvBuffer);
             else WARN("invalid buffer size %u\n", buffer->cbBuffer);
         }
 
@@ -935,7 +1042,7 @@ static SECURITY_STATUS SEC_ENTRY schan_InitializeSecurityContextW(
     init_schan_buffers(&ctx->transport.out, pOutput, schan_init_sec_ctx_get_next_output_buffer);
 
     /* Perform the TLS handshake */
-    ret = schan_imp_handshake(ctx->session);
+    ret = schan_funcs->handshake(ctx->session);
 
     out_buffers = &ctx->transport.out;
     if (out_buffers->current_buffer_idx != -1)
@@ -1027,18 +1134,33 @@ static void *get_alg_name(ALG_ID id, BOOL wide)
 
 static SECURITY_STATUS ensure_remote_cert(struct schan_context *ctx)
 {
-    HCERTSTORE cert_store;
+    HCERTSTORE store;
+    PCCERT_CONTEXT cert = NULL;
     SECURITY_STATUS status;
+    struct schan_cert_list list;
 
-    if(ctx->cert)
-        return SEC_E_OK;
-
-    cert_store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);
-    if(!cert_store)
+    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_imp_get_session_peer_certificate(ctx->session, cert_store, &ctx->cert);
-    CertCloseStore(cert_store, 0);
+    if ((status = schan_funcs->get_session_peer_certificate(ctx->session, &list)) == SEC_E_OK)
+    {
+        unsigned int i;
+        for (i = 0; i < list.count; i++)
+        {
+            if (!CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, list.certs[i].pbData,
+                                                  list.certs[i].cbData, CERT_STORE_ADD_REPLACE_EXISTING,
+                                                  i ? NULL : &cert))
+            {
+                if (i) CertFreeCertificateContext(cert);
+                return GetLastError();
+            }
+        }
+        RtlFreeHeap(GetProcessHeap(), 0, list.certs);
+    }
+
+    ctx->cert = cert;
+    CertCloseStore(store, 0);
     return status;
 }
 
@@ -1059,13 +1181,13 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
         case SECPKG_ATTR_STREAM_SIZES:
         {
             SecPkgContext_ConnectionInfo info;
-            status = schan_imp_get_connection_info(ctx->session, &info);
+            status = schan_funcs->get_connection_info(ctx->session, &info);
             if (status == SEC_E_OK)
             {
                 SecPkgContext_StreamSizes *stream_sizes = buffer;
                 SIZE_T mac_size = info.dwHashStrength;
-                unsigned int block_size = schan_imp_get_session_cipher_block_size(ctx->session);
-                unsigned int message_size = schan_imp_get_max_message_size(ctx->session);
+                unsigned int block_size = schan_funcs->get_session_cipher_block_size(ctx->session);
+                unsigned int message_size = schan_funcs->get_max_message_size(ctx->session);
 
                 TRACE("Using header size %lu mac bytes %lu, message size %u, block size %u\n",
                       ctx->header_size, mac_size, message_size, block_size);
@@ -1083,12 +1205,12 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
         case SECPKG_ATTR_KEY_INFO:
         {
             SecPkgContext_ConnectionInfo conn_info;
-            status = schan_imp_get_connection_info(ctx->session, &conn_info);
+            status = schan_funcs->get_connection_info(ctx->session, &conn_info);
             if (status == SEC_E_OK)
             {
                 SecPkgContext_KeyInfoW *info = buffer;
                 info->KeySize = conn_info.dwCipherStrength;
-                info->SignatureAlgorithm = schan_imp_get_key_signature_algorithm(ctx->session);
+                info->SignatureAlgorithm = schan_funcs->get_key_signature_algorithm(ctx->session);
                 info->EncryptAlgorithm = conn_info.aiCipher;
                 info->sSignatureAlgorithmName = get_alg_name(info->SignatureAlgorithm, TRUE);
                 info->sEncryptAlgorithmName = get_alg_name(info->EncryptAlgorithm, TRUE);
@@ -1109,7 +1231,7 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
         case SECPKG_ATTR_CONNECTION_INFO:
         {
             SecPkgContext_ConnectionInfo *info = buffer;
-            return schan_imp_get_connection_info(ctx->session, info);
+            return schan_funcs->get_connection_info(ctx->session, info);
         }
         case SECPKG_ATTR_ENDPOINT_BINDINGS:
         {
@@ -1154,12 +1276,12 @@ static SECURITY_STATUS SEC_ENTRY schan_QueryContextAttributesW(
         case SECPKG_ATTR_UNIQUE_BINDINGS:
         {
             SecPkgContext_Bindings *bindings = buffer;
-            return schan_imp_get_unique_channel_binding(ctx->session, bindings);
+            return schan_funcs->get_unique_channel_binding(ctx->session, bindings);
         }
         case SECPKG_ATTR_APPLICATION_PROTOCOL:
         {
             SecPkgContext_ApplicationProtocol *protocol = buffer;
-            return schan_imp_get_application_protocol(ctx->session, protocol);
+            return schan_funcs->get_application_protocol(ctx->session, protocol);
         }
 
         default:
@@ -1289,7 +1411,7 @@ static SECURITY_STATUS SEC_ENTRY schan_EncryptMessage(PCtxtHandle context_handle
         init_schan_buffers(&ctx->transport.out, message, schan_encrypt_message_get_next_buffer_token);
 
     length = data_size;
-    status = schan_imp_send(ctx->session, data, &length);
+    status = schan_funcs->send(ctx->session, data, &length);
 
     TRACE("Sent %ld bytes.\n", length);
 
@@ -1422,7 +1544,7 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle
     while (received < data_size)
     {
         SIZE_T length = data_size - received;
-        status = schan_imp_recv(ctx->session, data + received, &length);
+        status = schan_funcs->recv(ctx->session, data + received, &length);
 
         if (status == SEC_I_RENEGOTIATE)
             break;
@@ -1478,11 +1600,9 @@ static SECURITY_STATUS SEC_ENTRY schan_DeleteSecurityContext(PCtxtHandle context
     ctx = schan_free_handle(context_handle->dwLower, SCHAN_HANDLE_CTX);
     if (!ctx) return SEC_E_INVALID_HANDLE;
 
-    if (ctx->cert)
-        CertFreeCertificateContext(ctx->cert);
-    schan_imp_dispose_session(ctx->session);
+    if (ctx->cert) CertFreeCertificateContext(ctx->cert);
+    schan_funcs->dispose_session(ctx->session);
     heap_free(ctx);
-
     return SEC_E_OK;
 }
 
@@ -1552,6 +1672,14 @@ static const WCHAR schannelComment[] = { 'S','c','h','a','n','n','e','l',' ',
  'S','e','c','u','r','i','t','y',' ','P','a','c','k','a','g','e',0 };
 static const WCHAR schannelDllName[] = { 's','c','h','a','n','n','e','l','.','d','l','l',0 };
 
+const struct schan_callbacks schan_callbacks =
+{
+    schan_get_buffer,
+    schan_get_session_for_transport,
+    schan_pull,
+    schan_push,
+};
+
 void SECUR32_initSchannelSP(void)
 {
     /* This is what Windows reports.  This shouldn't break any applications
@@ -1578,8 +1706,11 @@ void SECUR32_initSchannelSP(void)
     };
     SecureProvider *provider;
 
-    if (!schan_imp_init())
+    if (!schan_funcs && __wine_init_unix_lib(hsecur32, DLL_PROCESS_ATTACH, &schan_callbacks, &schan_funcs))
+    {
+        ERR( "no schannel support, expect problems\n" );
         return;
+    }
 
     schan_handle_table = heap_alloc(64 * sizeof(*schan_handle_table));
     if (!schan_handle_table)
@@ -1597,13 +1728,11 @@ void SECUR32_initSchannelSP(void)
     }
 
     SECUR32_addPackages(provider, ARRAY_SIZE(info), NULL, info);
-
     return;
 
 fail:
     heap_free(schan_handle_table);
     schan_handle_table = NULL;
-    schan_imp_deinit();
     return;
 }
 
@@ -1620,7 +1749,7 @@ 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_imp_dispose_session(ctx->session);
+            schan_funcs->dispose_session(ctx->session);
             heap_free(ctx);
         }
     }
@@ -1631,21 +1760,12 @@ void SECUR32_deinitSchannelSP(void)
         {
             struct schan_credentials *cred;
             cred = schan_free_handle(i, SCHAN_HANDLE_CRED);
-            schan_imp_free_certificate_credentials(cred);
+            schan_funcs->free_certificate_credentials(cred);
             heap_free(cred);
         }
     }
     heap_free(schan_handle_table);
-    schan_imp_deinit();
-}
-
-#else /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H */
 
-void SECUR32_initSchannelSP(void)
-{
-    ERR("TLS library not found, SSL connections will fail\n");
+    __wine_init_unix_lib(hsecur32, DLL_PROCESS_DETACH, NULL, NULL);
+    schan_funcs = NULL;
 }
-
-void SECUR32_deinitSchannelSP(void) {}
-
-#endif /* SONAME_LIBGNUTLS || HAVE_SECURITY_SECURITY_H */
diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c
index 785430ddf58..76ab230137d 100644
--- a/dlls/secur32/schannel_gnutls.c
+++ b/dlls/secur32/schannel_gnutls.c
@@ -19,23 +19,27 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#if 0
+#pragma makedep unix
+#endif
+
 #include "config.h"
 #include "wine/port.h"
 
 #include <stdarg.h>
 #include <stdio.h>
-#include <assert.h>
 #ifdef SONAME_LIBGNUTLS
 #include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>
 #include <gnutls/abstract.h>
 #endif
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "sspi.h"
 #include "schannel.h"
-#include "lmcons.h"
 #include "winreg.h"
 #include "secur32_priv.h"
 
@@ -47,6 +51,8 @@
 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
 WINE_DECLARE_DEBUG_CHANNEL(winediag);
 
+static const struct schan_callbacks *callbacks;
+
 /* Not present in gnutls version < 2.9.10. */
 static int (*pgnutls_cipher_get_block_size)(gnutls_cipher_algorithm_t);
 
@@ -192,13 +198,12 @@ static void compat_gnutls_dtls_set_mtu(gnutls_session_t session, unsigned int mt
     FIXME("\n");
 }
 
-static ssize_t schan_pull_adapter(gnutls_transport_ptr_t transport,
-                                      void *buff, size_t buff_len)
+static ssize_t pull_adapter(gnutls_transport_ptr_t transport, void *buff, size_t buff_len)
 {
     struct schan_transport *t = (struct schan_transport*)transport;
-    gnutls_session_t s = (gnutls_session_t)schan_session_for_transport(t);
+    gnutls_session_t s = (gnutls_session_t)callbacks->get_session_for_transport(t);
 
-    int ret = schan_pull(transport, buff, &buff_len);
+    int ret = callbacks->pull(transport, buff, &buff_len);
     if (ret)
     {
         pgnutls_transport_set_errno(s, ret);
@@ -208,13 +213,12 @@ static ssize_t schan_pull_adapter(gnutls_transport_ptr_t transport,
     return buff_len;
 }
 
-static ssize_t schan_push_adapter(gnutls_transport_ptr_t transport,
-                                      const void *buff, size_t buff_len)
+static ssize_t push_adapter(gnutls_transport_ptr_t transport, const void *buff, size_t buff_len)
 {
     struct schan_transport *t = (struct schan_transport*)transport;
-    gnutls_session_t s = (gnutls_session_t)schan_session_for_transport(t);
+    gnutls_session_t s = (gnutls_session_t)callbacks->get_session_for_transport(t);
 
-    int ret = schan_push(transport, buff, &buff_len);
+    int ret = callbacks->push(transport, buff, &buff_len);
     if (ret)
     {
         pgnutls_transport_set_errno(s, ret);
@@ -270,21 +274,21 @@ static void check_supported_protocols(void)
     pgnutls_deinit(session);
 }
 
-DWORD schan_imp_enabled_protocols(void)
+static DWORD CDECL schan_get_enabled_protocols(void)
 {
     return supported_protocols;
 }
 
-static int schan_pull_timeout(gnutls_transport_ptr_t transport, unsigned int timeout)
+static int pull_timeout(gnutls_transport_ptr_t transport, unsigned int timeout)
 {
     struct schan_transport *t = (struct schan_transport *)transport;
     SIZE_T count = 0;
 
-    if (schan_get_buffer(t, &t->in, &count)) return 1;
+    if (callbacks->get_buffer(t, &t->in, &count)) return 1;
     return 0;
 }
 
-BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred)
+static BOOL CDECL schan_create_session(schan_session *session, schan_credentials *cred)
 {
     gnutls_session_t *s = (gnutls_session_t*)session;
     char priority[128] = "NORMAL:%LATEST_RECORD_VERSION", *p;
@@ -347,34 +351,32 @@ BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cre
         return FALSE;
     }
 
-    pgnutls_transport_set_pull_function(*s, schan_pull_adapter);
-    if (flags & GNUTLS_DATAGRAM) pgnutls_transport_set_pull_timeout_function(*s, schan_pull_timeout);
-    pgnutls_transport_set_push_function(*s, schan_push_adapter);
+    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);
 
     return TRUE;
 }
 
-void schan_imp_dispose_session(schan_imp_session session)
+static void CDECL schan_dispose_session(schan_session session)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     pgnutls_deinit(s);
 }
 
-void schan_imp_set_session_transport(schan_imp_session session,
-                                     struct schan_transport *t)
+static void CDECL schan_set_session_transport(schan_session session, struct schan_transport *t)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     pgnutls_transport_set_ptr(s, (gnutls_transport_ptr_t)t);
 }
 
-void schan_imp_set_session_target(schan_imp_session session, const char *target)
+static void CDECL schan_set_session_target(schan_session session, const char *target)
 {
     gnutls_session_t s = (gnutls_session_t)session;
-
     pgnutls_server_name_set( s, GNUTLS_NAME_DNS, target, strlen(target) );
 }
 
-SECURITY_STATUS schan_imp_handshake(schan_imp_session session)
+static SECURITY_STATUS CDECL schan_handshake(schan_session session)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     int err;
@@ -422,7 +424,7 @@ SECURITY_STATUS schan_imp_handshake(schan_imp_session session)
     return SEC_E_OK;
 }
 
-static DWORD schannel_get_protocol(gnutls_protocol_t proto)
+static DWORD get_protocol(gnutls_protocol_t proto)
 {
     /* FIXME: currently schannel only implements client connections, but
      * there's no reason it couldn't be used for servers as well.  The
@@ -442,7 +444,7 @@ static DWORD schannel_get_protocol(gnutls_protocol_t proto)
     }
 }
 
-static ALG_ID schannel_get_cipher_algid(gnutls_cipher_algorithm_t cipher)
+static ALG_ID get_cipher_algid(gnutls_cipher_algorithm_t cipher)
 {
     switch (cipher)
     {
@@ -464,7 +466,7 @@ static ALG_ID schannel_get_cipher_algid(gnutls_cipher_algorithm_t cipher)
     }
 }
 
-static ALG_ID schannel_get_mac_algid(gnutls_mac_algorithm_t mac, gnutls_cipher_algorithm_t cipher)
+static ALG_ID get_mac_algid(gnutls_mac_algorithm_t mac, gnutls_cipher_algorithm_t cipher)
 {
     switch (mac)
     {
@@ -493,7 +495,7 @@ static ALG_ID schannel_get_mac_algid(gnutls_mac_algorithm_t mac, gnutls_cipher_a
     }
 }
 
-static ALG_ID schannel_get_kx_algid(int kx)
+static ALG_ID get_kx_algid(int kx)
 {
     switch (kx)
     {
@@ -513,19 +515,18 @@ static ALG_ID schannel_get_kx_algid(int kx)
     }
 }
 
-unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session)
+static unsigned int CDECL schan_get_session_cipher_block_size(schan_session session)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     return pgnutls_cipher_get_block_size(pgnutls_cipher_get(s));
 }
 
-unsigned int schan_imp_get_max_message_size(schan_imp_session session)
+static unsigned int CDECL schan_get_max_message_size(schan_session session)
 {
     return pgnutls_record_get_max_size((gnutls_session_t)session);
 }
 
-SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
-                                              SecPkgContext_ConnectionInfo *info)
+static SECURITY_STATUS CDECL schan_get_connection_info(schan_session session, SecPkgContext_ConnectionInfo *info)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     gnutls_protocol_t proto = pgnutls_protocol_get_version(s);
@@ -533,19 +534,18 @@ SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
     gnutls_mac_algorithm_t mac = pgnutls_mac_get(s);
     gnutls_kx_algorithm_t kx = pgnutls_kx_get(s);
 
-    info->dwProtocol = schannel_get_protocol(proto);
-    info->aiCipher = schannel_get_cipher_algid(alg);
+    info->dwProtocol = get_protocol(proto);
+    info->aiCipher = get_cipher_algid(alg);
     info->dwCipherStrength = pgnutls_cipher_get_key_size(alg) * 8;
-    info->aiHash = schannel_get_mac_algid(mac, alg);
+    info->aiHash = get_mac_algid(mac, alg);
     info->dwHashStrength = pgnutls_mac_get_key_size(mac) * 8;
-    info->aiExch = schannel_get_kx_algid(kx);
+    info->aiExch = get_kx_algid(kx);
     /* FIXME: info->dwExchStrength? */
     info->dwExchStrength = 0;
     return SEC_E_OK;
 }
 
-SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session,
-                                                     SecPkgContext_Bindings *bindings)
+static SECURITY_STATUS CDECL schan_get_unique_channel_binding(schan_session session, SecPkgContext_Bindings *bindings)
 {
     static const char prefix[] = "tls-unique:";
     gnutls_datum_t datum;
@@ -562,7 +562,7 @@ SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session,
     }
 
     bindings->BindingsLength = sizeof(SEC_CHANNEL_BINDINGS) + sizeof(prefix)-1 + datum.size;
-    bindings->Bindings = heap_alloc_zero(bindings->BindingsLength);
+    bindings->Bindings = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, bindings->BindingsLength);
     if (!bindings->Bindings)
         ret = SEC_E_INSUFFICIENT_MEMORY;
     else
@@ -579,7 +579,7 @@ SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session,
     return ret;
 }
 
-ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session)
+static ALG_ID CDECL schan_get_key_signature_algorithm(schan_session session)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     gnutls_kx_algorithm_t kx = pgnutls_kx_get(s);
@@ -600,35 +600,32 @@ ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session)
     }
 }
 
-SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store,
-                                                       PCCERT_CONTEXT *ret)
+static SECURITY_STATUS CDECL schan_get_session_peer_certificate(schan_session session, struct schan_cert_list *list)
 {
     gnutls_session_t s = (gnutls_session_t)session;
-    PCCERT_CONTEXT cert = NULL;
     const gnutls_datum_t *datum;
-    unsigned list_size, i;
-    BOOL res;
+    unsigned int i, size;
+    BYTE *ptr;
 
-    datum = pgnutls_certificate_get_peers(s, &list_size);
-    if(!datum)
-        return SEC_E_INTERNAL_ERROR;
+    if (!(datum = pgnutls_certificate_get_peers(s, &list->count))) return SEC_E_INTERNAL_ERROR;
 
-    for(i = 0; i < list_size; i++) {
-        res = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, datum[i].data, datum[i].size,
-                CERT_STORE_ADD_REPLACE_EXISTING, i ? NULL : &cert);
-        if(!res) {
-            if(i)
-                CertFreeCertificateContext(cert);
-            return GetLastError();
-        }
+    size = list->count * sizeof(list->certs[0]);
+    for (i = 0; i < list->count; i++) size += datum[i].size;
+    if (!(list->certs = RtlAllocateHeap(GetProcessHeap(), 0, size))) return SEC_E_INSUFFICIENT_MEMORY;
+
+    ptr = (BYTE *)&list->certs[list->count];
+    for (i = 0; i < list->count; i++)
+    {
+        list->certs[i].cbData = datum[i].size;
+        list->certs[i].pbData = ptr;
+        memcpy(list->certs[i].pbData, datum[i].data, datum[i].size);
+        ptr += datum[i].size;
     }
 
-    *ret = cert;
     return SEC_E_OK;
 }
 
-SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
-                               SIZE_T *length)
+static SECURITY_STATUS CDECL schan_send(schan_session session, const void *buffer, SIZE_T *length)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     SSIZE_T ret, total = 0;
@@ -647,7 +644,7 @@ SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
             struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
             SIZE_T count = 0;
 
-            if (schan_get_buffer(t, &t->out, &count)) continue;
+            if (callbacks->get_buffer(t, &t->out, &count)) continue;
             return SEC_I_CONTINUE_NEEDED;
         }
         else
@@ -658,8 +655,7 @@ SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
     }
 }
 
-SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
-                               SIZE_T *length)
+static SECURITY_STATUS CDECL schan_recv(schan_session session, void *buffer, SIZE_T *length)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     ssize_t ret;
@@ -674,7 +670,7 @@ again:
         struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
         SIZE_T count = 0;
 
-        if (schan_get_buffer(t, &t->in, &count))
+        if (callbacks->get_buffer(t, &t->in, &count))
             goto again;
 
         return SEC_I_CONTINUE_NEEDED;
@@ -715,7 +711,7 @@ static unsigned int parse_alpn_protocol_list(unsigned char *buffer, unsigned int
     return count;
 }
 
-void schan_imp_set_application_protocols(schan_imp_session session, unsigned char *buffer, unsigned int buflen)
+static void CDECL schan_set_application_protocols(schan_session session, unsigned char *buffer, unsigned int buflen)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     unsigned int extension_len, extension, count = 0, offset = 0;
@@ -742,7 +738,7 @@ void schan_imp_set_application_protocols(schan_imp_session session, unsigned cha
 
     if (offset + list_len > buflen) return;
     count = parse_alpn_protocol_list(&buffer[offset], list_len, NULL);
-    if (!count || !(protocols = heap_alloc(count * sizeof(*protocols)))) return;
+    if (!count || !(protocols = RtlAllocateHeap(GetProcessHeap(), 0, count * sizeof(*protocols)))) return;
 
     parse_alpn_protocol_list(&buffer[offset], list_len, protocols);
     if ((ret = pgnutls_alpn_set_protocols(s, protocols, count, GNUTLS_ALPN_SERVER_PRECEDENCE) < 0))
@@ -750,11 +746,11 @@ void schan_imp_set_application_protocols(schan_imp_session session, unsigned cha
         pgnutls_perror(ret);
     }
 
-    heap_free(protocols);
+    RtlFreeHeap(GetProcessHeap(), 0, protocols);
 }
 
-SECURITY_STATUS schan_imp_get_application_protocol(schan_imp_session session,
-                                                   SecPkgContext_ApplicationProtocol *protocol)
+static SECURITY_STATUS CDECL schan_get_application_protocol(schan_session session,
+                                                            SecPkgContext_ApplicationProtocol *protocol)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     gnutls_datum_t selected;
@@ -768,12 +764,12 @@ SECURITY_STATUS schan_imp_get_application_protocol(schan_imp_session session,
         protocol->ProtoNegoExt    = SecApplicationProtocolNegotiationExt_ALPN;
         protocol->ProtocolIdSize  = selected.size;
         memcpy(protocol->ProtocolId, selected.data, selected.size);
-        TRACE("returning %s\n", debugstr_an((const char *)selected.data, selected.size));
+        TRACE("returning %s\n", wine_dbgstr_an((const char *)selected.data, selected.size));
     }
     return SEC_E_OK;
 }
 
-SECURITY_STATUS schan_imp_set_dtls_mtu(schan_imp_session session, unsigned int mtu)
+static SECURITY_STATUS CDECL schan_set_dtls_mtu(schan_session session, unsigned int mtu)
 {
     gnutls_session_t s = (gnutls_session_t)session;
 
@@ -782,114 +778,6 @@ SECURITY_STATUS schan_imp_set_dtls_mtu(schan_imp_session session, unsigned int m
     return SEC_E_OK;
 }
 
-static WCHAR *get_key_container_path(const CERT_CONTEXT *ctx)
-{
-    static const WCHAR rsabaseW[] =
-        {'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','C','r','y','p','t','o','\\','R','S','A','\\',0};
-    CERT_KEY_CONTEXT keyctx;
-    DWORD size = sizeof(keyctx), prov_size = 0;
-    CRYPT_KEY_PROV_INFO *prov;
-    WCHAR username[UNLEN + 1], *ret = NULL;
-    DWORD len = ARRAY_SIZE(username);
-
-    if (CertGetCertificateContextProperty(ctx, CERT_KEY_CONTEXT_PROP_ID, &keyctx, &size))
-    {
-        char *str;
-        if (!CryptGetProvParam(keyctx.hCryptProv, PP_CONTAINER, NULL, &size, 0)) return NULL;
-        if (!(str = heap_alloc(size))) return NULL;
-        if (!CryptGetProvParam(keyctx.hCryptProv, PP_CONTAINER, (BYTE *)str, &size, 0)) return NULL;
-
-        len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
-        if (!(ret = heap_alloc(sizeof(rsabaseW) + len * sizeof(WCHAR))))
-        {
-            heap_free(str);
-            return NULL;
-        }
-        strcpyW(ret, rsabaseW);
-        MultiByteToWideChar(CP_ACP, 0, str, -1, ret + strlenW(ret), len);
-        heap_free(str);
-    }
-    else if (CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, NULL, &prov_size))
-    {
-        if (!(prov = heap_alloc(prov_size))) return NULL;
-        if (!CertGetCertificateContextProperty(ctx, CERT_KEY_PROV_INFO_PROP_ID, prov, &prov_size))
-        {
-            heap_free(prov);
-            return NULL;
-        }
-        if (!(ret = heap_alloc(sizeof(rsabaseW) + strlenW(prov->pwszContainerName) * sizeof(WCHAR))))
-        {
-            heap_free(prov);
-            return NULL;
-        }
-        strcpyW(ret, rsabaseW);
-        strcatW(ret, prov->pwszContainerName);
-        heap_free(prov);
-    }
-
-    if (!ret && GetUserNameW(username, &len) && (ret = heap_alloc(sizeof(rsabaseW) + len * sizeof(WCHAR))))
-    {
-        strcpyW(ret, rsabaseW);
-        strcatW(ret, username);
-    }
-
-    return ret;
-}
-
-#define MAX_LEAD_BYTES 8
-static BYTE *get_key_blob(const CERT_CONTEXT *ctx, ULONG *size)
-{
-    static const WCHAR keyexchangeW[] =
-        {'K','e','y','E','x','c','h','a','n','g','e','K','e','y','P','a','i','r',0};
-    static const WCHAR signatureW[] =
-        {'S','i','g','n','a','t','u','r','e','K','e','y','P','a','i','r',0};
-    BYTE *buf, *ret = NULL;
-    DATA_BLOB blob_in, blob_out;
-    DWORD spec = 0, type, len;
-    WCHAR *path;
-    HKEY hkey;
-
-    if (!(path = get_key_container_path(ctx))) return NULL;
-    if (RegOpenKeyExW(HKEY_CURRENT_USER, path, 0, KEY_READ, &hkey))
-    {
-        heap_free(path);
-        return NULL;
-    }
-    heap_free(path);
-
-    if (!RegQueryValueExW(hkey, keyexchangeW, 0, &type, NULL, &len)) spec = AT_KEYEXCHANGE;
-    else if (!RegQueryValueExW(hkey, signatureW, 0, &type, NULL, &len)) spec = AT_SIGNATURE;
-    else
-    {
-        RegCloseKey(hkey);
-        return NULL;
-    }
-
-    if (!(buf = heap_alloc(len + MAX_LEAD_BYTES)))
-    {
-        RegCloseKey(hkey);
-        return NULL;
-    }
-
-    if (!RegQueryValueExW(hkey, (spec == AT_KEYEXCHANGE) ? keyexchangeW : signatureW, 0, &type, buf, &len))
-    {
-        blob_in.pbData = buf;
-        blob_in.cbData = len;
-        if (CryptUnprotectData(&blob_in, NULL, NULL, NULL, NULL, 0, &blob_out))
-        {
-            assert(blob_in.cbData >= blob_out.cbData);
-            memcpy(buf, blob_out.pbData, blob_out.cbData);
-            LocalFree(blob_out.pbData);
-            *size = blob_out.cbData + MAX_LEAD_BYTES;
-            ret = buf;
-        }
-    }
-    else heap_free(buf);
-
-    RegCloseKey(hkey);
-    return ret;
-}
-
 static inline void reverse_bytes(BYTE *buf, ULONG len)
 {
     BYTE tmp;
@@ -917,20 +805,19 @@ static ULONG set_component(gnutls_datum_t *comp, BYTE *data, ULONG len, ULONG *b
     return comp->size;
 }
 
-static gnutls_x509_privkey_t get_x509_key(const CERT_CONTEXT *ctx)
+static gnutls_x509_privkey_t get_x509_key(const DATA_BLOB *key_blob)
 {
     gnutls_privkey_t key = NULL;
     gnutls_x509_privkey_t x509key = NULL;
     gnutls_datum_t m, e, d, p, q, u, e1, e2;
-    BYTE *ptr, *buffer;
+    BYTE *ptr;
     RSAPUBKEY *rsakey;
-    DWORD size;
+    DWORD size = key_blob->cbData;
     int ret;
 
-    if (!(buffer = get_key_blob(ctx, &size))) return NULL;
-    if (size < sizeof(BLOBHEADER)) goto done;
+    if (size < sizeof(BLOBHEADER)) return NULL;
 
-    rsakey = (RSAPUBKEY *)(buffer + sizeof(BLOBHEADER));
+    rsakey = (RSAPUBKEY *)(key_blob->pbData + sizeof(BLOBHEADER));
     TRACE("RSA key bitlen %u pubexp %u\n", rsakey->bitlen, rsakey->pubexp);
 
     size -= sizeof(BLOBHEADER) + FIELD_OFFSET(RSAPUBKEY, pubexp);
@@ -948,23 +835,17 @@ static gnutls_x509_privkey_t get_x509_key(const CERT_CONTEXT *ctx)
     if ((ret = pgnutls_privkey_init(&key)) < 0)
     {
         pgnutls_perror(ret);
-        goto done;
-    }
-
-    if ((ret = pgnutls_privkey_import_rsa_raw(key, &m, &e, &d, &p, &q, &u, &e1, &e2)) < 0)
-    {
-        pgnutls_perror(ret);
-        goto done;
+        return NULL;
     }
 
-    if ((ret = pgnutls_privkey_export_x509(key, &x509key)) < 0)
+    if (((ret = pgnutls_privkey_import_rsa_raw(key, &m, &e, &d, &p, &q, &u, &e1, &e2)) < 0) ||
+         (ret = pgnutls_privkey_export_x509(key, &x509key)) < 0)
     {
         pgnutls_perror(ret);
+        pgnutls_privkey_deinit(key);
+        return NULL;
     }
 
-done:
-    heap_free(buffer);
-    pgnutls_privkey_deinit(key);
     return x509key;
 }
 
@@ -999,7 +880,8 @@ static gnutls_x509_crt_t get_x509_crt(const CERT_CONTEXT *ctx)
     return crt;
 }
 
-BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *ctx)
+static BOOL CDECL schan_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *ctx,
+                                                         const DATA_BLOB *key_blob )
 {
     gnutls_certificate_credentials_t creds;
     gnutls_x509_crt_t crt;
@@ -1025,7 +907,7 @@ BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT
         return FALSE;
     }
 
-    if (!(key = get_x509_key(ctx)))
+    if (!(key = get_x509_key(key_blob)))
     {
         pgnutls_x509_crt_deinit(crt);
         pgnutls_certificate_free_credentials(creds);
@@ -1046,17 +928,17 @@ BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT
     return TRUE;
 }
 
-void schan_imp_free_certificate_credentials(schan_credentials *c)
+static void CDECL schan_free_certificate_credentials(schan_credentials *c)
 {
     pgnutls_certificate_free_credentials(c->credentials);
 }
 
-static void schan_gnutls_log(int level, const char *msg)
+static void gnutls_log(int level, const char *msg)
 {
     TRACE("<%d> %s", level, msg);
 }
 
-BOOL schan_imp_init(void)
+static BOOL gnutls_initialize(void)
 {
     const char *env_str;
     int ret;
@@ -1171,7 +1053,7 @@ BOOL schan_imp_init(void)
     if (TRACE_ON(secur32))
     {
         pgnutls_global_set_log_level(4);
-        pgnutls_global_set_log_function(schan_gnutls_log);
+        pgnutls_global_set_log_function(gnutls_log);
     }
 
     check_supported_protocols();
@@ -1183,11 +1065,50 @@ fail:
     return FALSE;
 }
 
-void schan_imp_deinit(void)
+static void gnutls_uninitialize(void)
 {
     pgnutls_global_deinit();
     dlclose(libgnutls_handle);
     libgnutls_handle = NULL;
 }
 
+static const struct schan_funcs funcs =
+{
+    schan_allocate_certificate_credentials,
+    schan_create_session,
+    schan_dispose_session,
+    schan_free_certificate_credentials,
+    schan_get_application_protocol,
+    schan_get_connection_info,
+    schan_get_enabled_protocols,
+    schan_get_key_signature_algorithm,
+    schan_get_max_message_size,
+    schan_get_session_cipher_block_size,
+    schan_get_session_peer_certificate,
+    schan_get_unique_channel_binding,
+    schan_handshake,
+    schan_recv,
+    schan_send,
+    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;
+        callbacks = ptr_in;
+        *(const struct schan_funcs **)ptr_out = &funcs;
+        break;
+    case DLL_PROCESS_DETACH:
+        if (libgnutls_handle) gnutls_uninitialize();
+        break;
+    }
+    return STATUS_SUCCESS;
+}
+
 #endif /* SONAME_LIBGNUTLS && !HAVE_SECURITY_SECURITY_H */
diff --git a/dlls/secur32/schannel_macosx.c b/dlls/secur32/schannel_macosx.c
index 841f928eef3..daf9d835835 100644
--- a/dlls/secur32/schannel_macosx.c
+++ b/dlls/secur32/schannel_macosx.c
@@ -19,6 +19,10 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#if 0
+#pragma makedep unix
+#endif
+
 #include "config.h"
 #include "wine/port.h"
 
@@ -33,10 +37,13 @@
 #undef LoadResource
 #endif
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "sspi.h"
 #include "schannel.h"
+#include "winternl.h"
 #include "secur32_priv.h"
 #include "wine/debug.h"
 
@@ -44,6 +51,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
 
+static const struct schan_callbacks *callbacks;
+
 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
 /* Defined in <Security/CipherSuite.h> in the 10.6 SDK or later. */
 enum {
@@ -444,7 +453,7 @@ static const struct cipher_suite* get_cipher_suite(SSLCipherSuite cipher_suite)
 }
 
 
-static DWORD schan_get_session_protocol(struct mac_session* s)
+static DWORD get_session_protocol(struct mac_session* s)
 {
     SSLProtocol protocol;
     int status;
@@ -473,7 +482,7 @@ static DWORD schan_get_session_protocol(struct mac_session* s)
     }
 }
 
-static ALG_ID schan_get_cipher_algid(const struct cipher_suite* c)
+static ALG_ID get_cipher_algid(const struct cipher_suite* c)
 {
     TRACE("(%#x)\n", (unsigned int)c->suite);
 
@@ -503,7 +512,7 @@ static ALG_ID schan_get_cipher_algid(const struct cipher_suite* c)
     }
 }
 
-static unsigned int schan_get_cipher_key_size(const struct cipher_suite* c)
+static unsigned int get_cipher_key_size(const struct cipher_suite* c)
 {
     TRACE("(%#x)\n", (unsigned int)c->suite);
 
@@ -533,7 +542,7 @@ static unsigned int schan_get_cipher_key_size(const struct cipher_suite* c)
     }
 }
 
-static ALG_ID schan_get_mac_algid(const struct cipher_suite* c)
+static ALG_ID get_mac_algid(const struct cipher_suite* c)
 {
     TRACE("(%#x)\n", (unsigned int)c->suite);
 
@@ -551,7 +560,7 @@ static ALG_ID schan_get_mac_algid(const struct cipher_suite* c)
     }
 }
 
-static unsigned int schan_get_mac_key_size(const struct cipher_suite* c)
+static unsigned int get_mac_key_size(const struct cipher_suite* c)
 {
     TRACE("(%#x)\n", (unsigned int)c->suite);
 
@@ -569,7 +578,7 @@ static unsigned int schan_get_mac_key_size(const struct cipher_suite* c)
     }
 }
 
-static ALG_ID schan_get_kx_algid(const struct cipher_suite* c)
+static ALG_ID get_kx_algid(const struct cipher_suite* c)
 {
     TRACE("(%#x)\n", (unsigned int)c->suite);
 
@@ -608,7 +617,7 @@ static ALG_ID schan_get_kx_algid(const struct cipher_suite* c)
 }
 
 
-/* schan_pull_adapter
+/* pull_adapter
  *      Callback registered with SSLSetIOFuncs as the read function for a
  *      session.  Reads data from the session connection.  Conforms to the
  *      SSLReadFunc type.
@@ -629,8 +638,7 @@ static ALG_ID schan_get_kx_algid(const struct cipher_suite* c)
  *          more data to be read.
  *      other error code for failure.
  */
-static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff,
-                                   SIZE_T *buff_len)
+static OSStatus pull_adapter(SSLConnectionRef transport, void *buff, SIZE_T *buff_len)
 {
     struct mac_session *s = (struct mac_session*)transport;
     size_t requested = *buff_len;
@@ -645,7 +653,7 @@ static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff,
         return noErr;
     }
 
-    status = schan_pull(s->transport, buff, buff_len);
+    status = callbacks->pull(s->transport, buff, buff_len);
     if (status == 0)
     {
         if (*buff_len == 0)
@@ -678,7 +686,7 @@ static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff,
     return ret;
 }
 
-/* schan_push_adapter
+/* push_adapter
  *      Callback registered with SSLSetIOFuncs as the write function for a
  *      session.  Writes data to the session connection.  Conforms to the
  *      SSLWriteFunc type.
@@ -695,8 +703,7 @@ static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff,
  *          caller should try again.
  *      other error code for failure.
  */
-static OSStatus schan_push_adapter(SSLConnectionRef transport, const void *buff,
-                                       SIZE_T *buff_len)
+static OSStatus push_adapter(SSLConnectionRef transport, const void *buff, SIZE_T *buff_len)
 {
     struct mac_session *s = (struct mac_session*)transport;
     int status;
@@ -710,7 +717,7 @@ static OSStatus schan_push_adapter(SSLConnectionRef transport, const void *buff,
         return noErr;
     }
 
-    status = schan_push(s->transport, buff, buff_len);
+    status = callbacks->push(s->transport, buff, buff_len);
     if (status == 0)
     {
         TRACE("Pushed %lu bytes\n", *buff_len);
@@ -743,12 +750,12 @@ static const struct {
 
 static DWORD supported_protocols;
 
-DWORD schan_imp_enabled_protocols(void)
+static DWORD CDECL schan_get_enabled_protocols(void)
 {
     return supported_protocols;
 }
 
-BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred)
+static BOOL CDECL schan_create_session(schan_session *session, schan_credentials *cred)
 {
     struct mac_session *s;
     unsigned i;
@@ -756,9 +763,7 @@ BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cre
 
     TRACE("(%p)\n", session);
 
-    s = heap_alloc(sizeof(*s));
-    if (!s)
-        return FALSE;
+    if (!(s = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*s)))) return FALSE;
 
     pthread_mutex_init(&s->mutex, NULL);
 
@@ -796,7 +801,7 @@ BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cre
         }
     }
 
-    status = SSLSetIOFuncs(s->context, schan_pull_adapter, schan_push_adapter);
+    status = SSLSetIOFuncs(s->context, pull_adapter, push_adapter);
     if (status != noErr)
     {
         ERR("Failed to set session I/O funcs: %d\n", status);
@@ -807,15 +812,15 @@ BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cre
 
     TRACE("    -> %p/%p\n", s, s->context);
 
-    *session = (schan_imp_session)s;
+    *session = (schan_session)s;
     return TRUE;
 
 fail:
-    heap_free(s);
+    RtlFreeHeap(GetProcessHeap(), 0, s);
     return FALSE;
 }
 
-void schan_imp_dispose_session(schan_imp_session session)
+static void CDECL schan_dispose_session(schan_session session)
 {
     struct mac_session *s = (struct mac_session*)session;
     int status;
@@ -826,11 +831,10 @@ void schan_imp_dispose_session(schan_imp_session session)
     if (status != noErr)
         ERR("Failed to dispose of session context: %d\n", status);
     pthread_mutex_destroy(&s->mutex);
-    heap_free(s);
+    RtlFreeHeap(GetProcessHeap(), 0, s);
 }
 
-void schan_imp_set_session_transport(schan_imp_session session,
-                                     struct schan_transport *t)
+static void CDECL schan_set_session_transport(schan_session session, struct schan_transport *t)
 {
     struct mac_session *s = (struct mac_session*)session;
 
@@ -839,7 +843,7 @@ void schan_imp_set_session_transport(schan_imp_session session,
     s->transport = t;
 }
 
-void schan_imp_set_session_target(schan_imp_session session, const char *target)
+static void CDECL schan_set_session_target(schan_session session, const char *target)
 {
     struct mac_session *s = (struct mac_session*)session;
 
@@ -848,7 +852,7 @@ void schan_imp_set_session_target(schan_imp_session session, const char *target)
     SSLSetPeerDomainName( s->context, target, strlen(target) );
 }
 
-SECURITY_STATUS schan_imp_handshake(schan_imp_session session)
+static SECURITY_STATUS CDECL schan_handshake(schan_session session)
 {
     struct mac_session *s = (struct mac_session*)session;
     int status;
@@ -885,7 +889,7 @@ SECURITY_STATUS schan_imp_handshake(schan_imp_session session)
     return SEC_E_OK;
 }
 
-unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session)
+static unsigned int CDECL schan_get_session_cipher_block_size(schan_session session)
 {
     struct mac_session* s = (struct mac_session*)session;
     SSLCipherSuite cipherSuite;
@@ -934,13 +938,13 @@ unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session)
     }
 }
 
-unsigned int schan_imp_get_max_message_size(schan_imp_session session)
+static unsigned int CDECL schan_get_max_message_size(schan_session session)
 {
     FIXME("Returning 1 << 14.\n");
     return 1 << 14;
 }
 
-ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session)
+static ALG_ID CDECL schan_get_key_signature_algorithm(schan_session session)
 {
     struct mac_session* s = (struct mac_session*)session;
     SSLCipherSuite cipherSuite;
@@ -1002,8 +1006,7 @@ ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session)
     }
 }
 
-SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
-                                              SecPkgContext_ConnectionInfo *info)
+static SECURITY_STATUS CDECL schan_get_connection_info(schan_session session, SecPkgContext_ConnectionInfo *info)
 {
     struct mac_session* s = (struct mac_session*)session;
     SSLCipherSuite cipherSuite;
@@ -1026,46 +1029,44 @@ SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
         return SEC_E_INTERNAL_ERROR;
     }
 
-    info->dwProtocol = schan_get_session_protocol(s);
-    info->aiCipher = schan_get_cipher_algid(c);
-    info->dwCipherStrength = schan_get_cipher_key_size(c);
-    info->aiHash = schan_get_mac_algid(c);
-    info->dwHashStrength = schan_get_mac_key_size(c);
-    info->aiExch = schan_get_kx_algid(c);
+    info->dwProtocol = get_session_protocol(s);
+    info->aiCipher = get_cipher_algid(c);
+    info->dwCipherStrength = get_cipher_key_size(c);
+    info->aiHash = get_mac_algid(c);
+    info->dwHashStrength = get_mac_key_size(c);
+    info->aiExch = get_kx_algid(c);
     /* FIXME: info->dwExchStrength? */
     info->dwExchStrength = 0;
 
     return SEC_E_OK;
 }
 
-SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session,
-                                                     SecPkgContext_Bindings *bindings)
+static SECURITY_STATUS CDECL schan_get_unique_channel_binding(schan_session session, SecPkgContext_Bindings *bindings)
 {
     FIXME("SECPKG_ATTR_UNIQUE_BINDINGS is unsupported on MacOS\n");
     return SEC_E_UNSUPPORTED_FUNCTION;
 }
 
 #ifndef HAVE_SSLCOPYPEERCERTIFICATES
-static void schan_imp_cf_release(const void *arg, void *ctx)
+static void cf_release(const void *arg, void *ctx)
 {
     CFRelease(arg);
 }
 #endif
 
-SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store,
-                                                       PCCERT_CONTEXT *ret_cert)
+static SECURITY_STATUS CDECL schan_get_session_peer_certificate(schan_session session, struct schan_cert_list *list)
 {
-    struct mac_session* s = (struct mac_session*)session;
+    struct mac_session *s = (struct mac_session *)session;
     SECURITY_STATUS ret = SEC_E_OK;
-    PCCERT_CONTEXT cert = NULL;
-    SecCertificateRef mac_cert;
+    SecCertificateRef cert;
     CFArrayRef cert_array;
     int status;
-    CFIndex cnt, i;
+    unsigned int size;
+    CFIndex i;
     CFDataRef data;
-    BOOL res;
+    BYTE *ptr;
 
-    TRACE("(%p/%p, %p)\n", s, s->context, cert);
+    TRACE("(%p/%p, %p)\n", s, s->context, list);
 
 #ifdef HAVE_SSLCOPYPEERCERTIFICATES
     status = SSLCopyPeerCertificates(s->context, &cert_array);
@@ -1078,45 +1079,55 @@ SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session
         return SEC_E_INTERNAL_ERROR;
     }
 
-    cnt = CFArrayGetCount(cert_array);
-    for (i=0; i < cnt; i++) {
-        if (!(mac_cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, i)) ||
-            (SecKeychainItemExport(mac_cert, kSecFormatX509Cert, 0, NULL, &data) != noErr))
+    list->count = CFArrayGetCount(cert_array);
+    size = list->count * sizeof(list->certs[0]);
+
+    for (i = 0; i < list->count; i++)
+    {
+        if (!(cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, i)) ||
+            (SecKeychainItemExport(cert, kSecFormatX509Cert, 0, NULL, &data) != noErr))
         {
             WARN("Couldn't extract certificate data\n");
             ret = SEC_E_INTERNAL_ERROR;
-            break;
+            goto done;
         }
-
-        res = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, CFDataGetBytePtr(data), CFDataGetLength(data),
-                                               CERT_STORE_ADD_REPLACE_EXISTING, i ? NULL : &cert);
+        size += CFDataGetLength(data);
         CFRelease(data);
-        if (!res)
+    }
+
+    if (!(list->certs = RtlAllocateHeap(GetProcessHeap(), 0, size)))
+    {
+        ret = SEC_E_INSUFFICIENT_MEMORY;
+        goto done;
+    }
+
+    ptr = (BYTE *)&list->certs[list->count];
+    for (i = 0; i < list->count; i++)
+    {
+        if (!(cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, i)) ||
+            (SecKeychainItemExport(cert, kSecFormatX509Cert, 0, NULL, &data) != noErr))
         {
-            ret = GetLastError();
-            WARN("CertAddEncodedCertificateToStore failed: %x\n", ret);
-            break;
+            WARN("Couldn't extract certificate data\n");
+            ret = SEC_E_INTERNAL_ERROR;
+            goto done;
         }
+        list->certs[i].cbData = CFDataGetLength(data);
+        list->certs[i].pbData = ptr;
+        memcpy(list->certs[i].pbData, CFDataGetBytePtr(data), CFDataGetLength(data));
+        ptr += CFDataGetLength(data);
+        CFRelease(data);
     }
 
+done:
 #ifndef HAVE_SSLCOPYPEERCERTIFICATES
     /* This is why SSLGetPeerCertificates was deprecated */
-    CFArrayApplyFunction(cert_array, CFRangeMake(0, CFArrayGetCount(cert_array)),
-                         schan_imp_cf_release, NULL);
+    CFArrayApplyFunction(cert_array, CFRangeMake(0, CFArrayGetCount(cert_array)), cf_release, NULL);
 #endif
     CFRelease(cert_array);
-    if (ret != SEC_E_OK) {
-        if(cert)
-            CertFreeCertificateContext(cert);
-        return ret;
-    }
-
-    *ret_cert = cert;
-    return SEC_E_OK;
+    return ret;
 }
 
-SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
-                               SIZE_T *length)
+static SECURITY_STATUS CDECL schan_send(schan_session session, const void *buffer, SIZE_T *length)
 {
     struct mac_session* s = (struct mac_session*)session;
     int status;
@@ -1152,8 +1163,7 @@ SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
     return SEC_E_OK;
 }
 
-SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
-                               SIZE_T *length)
+static SECURITY_STATUS CDECL schan_recv(schan_session session, void *buffer, SIZE_T *length)
 {
     struct mac_session* s = (struct mac_session*)session;
     int status;
@@ -1189,36 +1199,37 @@ SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
     return SEC_E_OK;
 }
 
-BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *cert)
+static BOOL CDECL schan_allocate_certificate_credentials(schan_credentials *c, const CERT_CONTEXT *cert,
+                                                         const DATA_BLOB *key_blob)
 {
     if (cert) FIXME("no support for certificate credentials on this platform\n");
     c->credentials = NULL;
     return TRUE;
 }
 
-void schan_imp_free_certificate_credentials(schan_credentials *c)
+static void CDECL schan_free_certificate_credentials(schan_credentials *c)
 {
 }
 
-void schan_imp_set_application_protocols(schan_imp_session session, unsigned char *buffer, unsigned int buflen)
+static void CDECL schan_set_application_protocols(schan_session session, unsigned char *buffer, unsigned int buflen)
 {
     FIXME("no support for application protocols on this platform\n");
 }
 
-SECURITY_STATUS schan_imp_get_application_protocol(schan_imp_session session,
-                                                   SecPkgContext_ApplicationProtocol *protocol)
+static SECURITY_STATUS CDECL schan_get_application_protocol(schan_session session,
+                                                            SecPkgContext_ApplicationProtocol *protocol)
 {
     FIXME("no support for application protocols on this platform\n");
     return SEC_E_UNSUPPORTED_FUNCTION;
 }
 
-SECURITY_STATUS schan_imp_set_dtls_mtu(schan_imp_session session, unsigned int mtu)
+static SECURITY_STATUS CDECL schan_set_dtls_mtu(schan_session session, unsigned int mtu)
 {
     FIXME("no support for setting dtls mtu on this platform\n");
     return SEC_E_UNSUPPORTED_FUNCTION;
 }
 
-BOOL schan_imp_init(void)
+static void ssl_init(void)
 {
     TRACE("()\n");
 
@@ -1245,13 +1256,38 @@ BOOL schan_imp_init(void)
         }
     }
 #endif
-
-    return TRUE;
 }
 
-void schan_imp_deinit(void)
+static const struct schan_funcs funcs =
 {
-    TRACE("()\n");
+    schan_allocate_certificate_credentials,
+    schan_create_session,
+    schan_dispose_session,
+    schan_free_certificate_credentials,
+    schan_get_application_protocol,
+    schan_get_connection_info,
+    schan_get_enabled_protocols,
+    schan_get_key_signature_algorithm,
+    schan_get_max_message_size,
+    schan_get_session_cipher_block_size,
+    schan_get_session_peer_certificate,
+    schan_get_unique_channel_binding,
+    schan_handshake,
+    schan_recv,
+    schan_send,
+    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 )
+{
+    if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
+    ssl_init();
+    callbacks = ptr_in;
+    *(const struct schan_funcs **)ptr_out = &funcs;
+    return STATUS_SUCCESS;
 }
 
 #endif /* HAVE_SECURITY_SECURITY_H */
diff --git a/dlls/secur32/secur32.c b/dlls/secur32/secur32.c
index 4382ec55174..04cb52dbec9 100644
--- a/dlls/secur32/secur32.c
+++ b/dlls/secur32/secur32.c
@@ -40,6 +40,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
 
+HINSTANCE hsecur32;
+
 /**
  *  Type definitions
  */
@@ -1246,6 +1248,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
     switch (reason)
     {
     case DLL_PROCESS_ATTACH:
+        hsecur32 = hinstDLL;
         DisableThreadLibraryCalls(hinstDLL);
         SECUR32_initializeProviders();
         break;
diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h
index 5571ac290e1..9d191fc4872 100644
--- a/dlls/secur32/secur32_priv.h
+++ b/dlls/secur32/secur32_priv.h
@@ -27,6 +27,8 @@
 #include "wine/list.h"
 #include "schannel.h"
 
+extern HINSTANCE hsecur32 DECLSPEC_HIDDEN;
+
 typedef struct _SecureProvider
 {
     struct list             entry;
@@ -83,7 +85,7 @@ void load_auth_packages(void) DECLSPEC_HIDDEN;
 void SECUR32_deinitSchannelSP(void) DECLSPEC_HIDDEN;
 
 /* schannel internal interface */
-typedef struct schan_imp_session_opaque *schan_imp_session;
+typedef struct schan_session_opaque *schan_session;
 
 typedef struct schan_credentials
 {
@@ -111,40 +113,43 @@ struct schan_transport
     struct schan_buffers out;
 };
 
-char *schan_get_buffer(const struct schan_transport *t, struct schan_buffers *s, SIZE_T *count) DECLSPEC_HIDDEN;
-extern int schan_pull(struct schan_transport *t, void *buff, size_t *buff_len) DECLSPEC_HIDDEN;
-extern int schan_push(struct schan_transport *t, const void *buff, size_t *buff_len) DECLSPEC_HIDDEN;
-
-extern schan_imp_session schan_session_for_transport(struct schan_transport* t) DECLSPEC_HIDDEN;
-
-/* schannel implementation interface */
-extern BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred) DECLSPEC_HIDDEN;
-extern void schan_imp_dispose_session(schan_imp_session session) DECLSPEC_HIDDEN;
-extern void schan_imp_set_session_transport(schan_imp_session session,
-                                            struct schan_transport *t) DECLSPEC_HIDDEN;
-extern void schan_imp_set_session_target(schan_imp_session session, const char *target) DECLSPEC_HIDDEN;
-extern SECURITY_STATUS schan_imp_handshake(schan_imp_session session) DECLSPEC_HIDDEN;
-extern unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) DECLSPEC_HIDDEN;
-extern unsigned int schan_imp_get_max_message_size(schan_imp_session session) DECLSPEC_HIDDEN;
-extern ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session) DECLSPEC_HIDDEN;
-extern SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
-                                                     SecPkgContext_ConnectionInfo *info) DECLSPEC_HIDDEN;
-extern SECURITY_STATUS schan_imp_get_unique_channel_binding(schan_imp_session session,
-                                                            SecPkgContext_Bindings *bindings) DECLSPEC_HIDDEN;
-extern SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE,
-                                                              PCCERT_CONTEXT *cert) DECLSPEC_HIDDEN;
-extern SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
-                                      SIZE_T *length) DECLSPEC_HIDDEN;
-extern SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
-                                      SIZE_T *length) DECLSPEC_HIDDEN;
-extern BOOL schan_imp_allocate_certificate_credentials(schan_credentials *, const CERT_CONTEXT *) DECLSPEC_HIDDEN;
-extern void schan_imp_free_certificate_credentials(schan_credentials*) DECLSPEC_HIDDEN;
-extern DWORD schan_imp_enabled_protocols(void) DECLSPEC_HIDDEN;
-extern BOOL schan_imp_init(void) DECLSPEC_HIDDEN;
-extern void schan_imp_deinit(void) DECLSPEC_HIDDEN;
-extern void schan_imp_set_application_protocols(schan_imp_session, unsigned char *, unsigned int) DECLSPEC_HIDDEN;
-extern SECURITY_STATUS schan_imp_get_application_protocol(schan_imp_session,
-                                                          SecPkgContext_ApplicationProtocol *) DECLSPEC_HIDDEN;
-extern SECURITY_STATUS schan_imp_set_dtls_mtu(schan_imp_session, unsigned int) DECLSPEC_HIDDEN;
-
-#endif /* ndef __SECUR32_PRIV_H__ */
+struct schan_cert_list
+{
+    unsigned int count;
+    CERT_BLOB   *certs;
+};
+
+struct schan_funcs
+{
+    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, struct schan_cert_list *);
+    SECURITY_STATUS (CDECL *get_unique_channel_binding)(schan_session, SecPkgContext_Bindings *);
+    SECURITY_STATUS (CDECL *handshake)(schan_session session);
+    SECURITY_STATUS (CDECL *recv)(schan_session, void *, SIZE_T *);
+    SECURITY_STATUS (CDECL *send)(schan_session, 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 *);
+};
+
+struct schan_callbacks
+{
+    char * (CDECL *get_buffer)(const struct schan_transport *, struct schan_buffers *, SIZE_T *);
+    schan_session (CDECL *get_session_for_transport)(struct schan_transport *);
+    int CDECL (CDECL *pull)(struct schan_transport *, void *, size_t *);
+    int CDECL (CDECL *push)(struct schan_transport *, const void *, size_t *);
+};
+
+extern const struct schan_funcs *schan_funcs;
+
+#endif /* __SECUR32_PRIV_H__ */
-- 
2.30.2




More information about the wine-devel mailing list