[SCHANNEL]

- Import TLS/SSL support on top of GNUTLS from wine
Won't work until we ship the gnutls DLLs

svn path=/trunk/; revision=63996
This commit is contained in:
Jérôme Gardou 2014-08-30 21:33:21 +00:00
parent cccf98d172
commit 57108b7872
9 changed files with 2675 additions and 20 deletions

View file

@ -1,12 +1,20 @@
include_directories(${REACTOS_SOURCE_DIR}/include/reactos/wine)
add_definitions(-D__WINESRC__)
include_directories(
${REACTOS_SOURCE_DIR}/include/reactos/wine
${REACTOS_SOURCE_DIR}/include/reactos/libs/gnutls)
add_definitions(-D__WINESRC__ -D_WINE)
spec2def(schannel.dll schannel.spec)
list(APPEND SOURCE
lsamode.c
schannel_gnutls.c
schannel_main.c
schannel_wine.c
secur32_wine.c
usermode.c
stubs.c
precomp.h
${CMAKE_CURRENT_BINARY_DIR}/schannel_stubs.c)
@ -17,6 +25,6 @@ add_library(schannel SHARED
set_module_type(schannel win32dll)
target_link_libraries(schannel wine)
add_importlibs(schannel secur32 msvcrt kernel32 ntdll)
add_importlibs(schannel crypt32 advapi32 msvcrt kernel32 ntdll)
add_pch(schannel precomp.h SOURCE)
add_cd_file(TARGET schannel DESTINATION reactos/system32 FOR all)

View file

@ -10,11 +10,20 @@
#define WIN32_NO_STATUS
#include <windef.h>
#include <winbase.h>
#include <winnls.h>
#include <winreg.h>
#include <sspi.h>
#include <ntsecapi.h>
#include <ntsecpkg.h>
#include <schannel.h>
#include <wine/list.h>
#include "schannel_priv.h"
#include <wine/debug.h>
#include <wine/unicode.h>
WINE_DEFAULT_DEBUG_CHANNEL(schannel);
#endif /* _SCHANNEL_PCH_ */

View file

@ -1,24 +1,24 @@
@ stdcall AcceptSecurityContext(ptr ptr ptr long long ptr ptr ptr ptr) secur32.AcceptSecurityContext
@ stdcall AcquireCredentialsHandleA(str str long ptr ptr ptr ptr ptr ptr) secur32.AcquireCredentialsHandleA
@ stdcall AcquireCredentialsHandleW(wstr wstr long ptr ptr ptr ptr ptr ptr) secur32.AcquireCredentialsHandleW
@ stdcall ApplyControlToken(ptr ptr) secur32.ApplyControlToken
@ stdcall AcceptSecurityContext(ptr ptr ptr long long ptr ptr ptr ptr) schan_AcceptSecurityContext
@ stdcall AcquireCredentialsHandleA(str str long ptr ptr ptr ptr ptr ptr) schan_AcquireCredentialsHandleA
@ stdcall AcquireCredentialsHandleW(wstr wstr long ptr ptr ptr ptr ptr ptr) schan_AcquireCredentialsHandleW
@ stdcall ApplyControlToken(ptr ptr) schan_ApplyControlToken
@ stub CloseSslPerformanceData
@ stub CollectSslPerformanceData
@ stdcall CompleteAuthToken(ptr ptr) secur32.CompleteAuthToken
@ stdcall DeleteSecurityContext(ptr) secur32.DeleteSecurityContext
@ stdcall EnumerateSecurityPackagesA(ptr ptr) secur32.EnumerateSecurityPackagesA
@ stdcall EnumerateSecurityPackagesW(ptr ptr) secur32.EnumerateSecurityPackagesW
@ stdcall FreeContextBuffer(ptr) secur32.FreeContextBuffer
@ stdcall FreeCredentialsHandle(ptr) secur32.FreeCredentialsHandle
@ stdcall ImpersonateSecurityContext(ptr) secur32.ImpersonateSecurityContext
@ stdcall InitSecurityInterfaceA() secur32.InitSecurityInterfaceA
@ stdcall InitSecurityInterfaceW() secur32.InitSecurityInterfaceW
@ stdcall InitializeSecurityContextA(ptr ptr str long long long ptr long ptr ptr ptr ptr) secur32.InitializeSecurityContextA
@ stdcall InitializeSecurityContextW(ptr ptr wstr long long long ptr long ptr ptr ptr ptr) secur32.InitializeSecurityContextW
@ stdcall CompleteAuthToken(ptr ptr) schan_CompleteAuthToken
@ stdcall DeleteSecurityContext(ptr) schan_DeleteSecurityContext
@ stdcall EnumerateSecurityPackagesA(ptr ptr) schan_EnumerateSecurityPackagesA
@ stdcall EnumerateSecurityPackagesW(ptr ptr) schan_EnumerateSecurityPackagesW
@ stdcall FreeContextBuffer(ptr) schan_FreeContextBuffer
@ stdcall FreeCredentialsHandle(ptr) schan_FreeCredentialsHandle
@ stdcall ImpersonateSecurityContext(ptr) schan_ImpersonateSecurityContext
@ stdcall InitSecurityInterfaceA() schan_InitSecurityInterfaceA
@ stdcall InitSecurityInterfaceW() schan_InitSecurityInterfaceW
@ stdcall InitializeSecurityContextA(ptr ptr str long long long ptr long ptr ptr ptr ptr) schan_InitializeSecurityContextA
@ stdcall InitializeSecurityContextW(ptr ptr wstr long long long ptr long ptr ptr ptr ptr) schan_InitializeSecurityContextW
@ stdcall MakeSignature(ptr long ptr long) secur32.MakeSignature
@ stub OpenSslPerformanceData
@ stdcall QueryContextAttributesA(ptr long ptr) secur32.QueryContextAttributesA
@ stdcall QueryContextAttributesW(ptr long ptr) secur32.QueryContextAttributesW
@ stdcall QueryContextAttributesA(ptr long ptr) schan_QueryContextAttributesA
@ stdcall QueryContextAttributesW(ptr long ptr) schan_QueryContextAttributesW
@ stdcall QuerySecurityPackageInfoA(str ptr) secur32.QuerySecurityPackageInfoA
@ stdcall QuerySecurityPackageInfoW(wstr ptr) secur32.QuerySecurityPackageInfoW
@ stdcall RevertSecurityContext(ptr) secur32.RevertSecurityContext

View file

@ -0,0 +1,593 @@
/*
* GnuTLS-based implementation of the schannel (SSL/TLS) provider.
*
* Copyright 2005 Juan Lang
* Copyright 2008 Henri Verbeet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "precomp.h"
#include <wine/config.h>
#include <wine/port.h>
#include <strsafe.h>
#ifdef SONAME_LIBGNUTLS
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#endif
#define __wine_dbch_secur32 __wine_dbch_schannel
#if defined(SONAME_LIBGNUTLS) && !defined(HAVE_SECURITY_SECURITY_H)
static void *libgnutls_handle;
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
MAKE_FUNCPTR(gnutls_alert_get);
MAKE_FUNCPTR(gnutls_alert_get_name);
MAKE_FUNCPTR(gnutls_certificate_allocate_credentials);
MAKE_FUNCPTR(gnutls_certificate_free_credentials);
MAKE_FUNCPTR(gnutls_certificate_get_peers);
MAKE_FUNCPTR(gnutls_cipher_get);
MAKE_FUNCPTR(gnutls_cipher_get_key_size);
MAKE_FUNCPTR(gnutls_credentials_set);
MAKE_FUNCPTR(gnutls_deinit);
MAKE_FUNCPTR(gnutls_global_deinit);
MAKE_FUNCPTR(gnutls_global_init);
MAKE_FUNCPTR(gnutls_global_set_log_function);
MAKE_FUNCPTR(gnutls_global_set_log_level);
MAKE_FUNCPTR(gnutls_handshake);
MAKE_FUNCPTR(gnutls_init);
MAKE_FUNCPTR(gnutls_kx_get);
MAKE_FUNCPTR(gnutls_mac_get);
MAKE_FUNCPTR(gnutls_mac_get_key_size);
MAKE_FUNCPTR(gnutls_perror);
MAKE_FUNCPTR(gnutls_protocol_get_version);
MAKE_FUNCPTR(gnutls_priority_set_direct);
MAKE_FUNCPTR(gnutls_record_get_max_size);
MAKE_FUNCPTR(gnutls_record_recv);
MAKE_FUNCPTR(gnutls_record_send);
MAKE_FUNCPTR(gnutls_server_name_set);
MAKE_FUNCPTR(gnutls_transport_get_ptr);
MAKE_FUNCPTR(gnutls_transport_set_errno);
MAKE_FUNCPTR(gnutls_transport_set_ptr);
MAKE_FUNCPTR(gnutls_transport_set_pull_function);
MAKE_FUNCPTR(gnutls_transport_set_push_function);
#undef MAKE_FUNCPTR
static ssize_t schan_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);
int ret = schan_pull(transport, buff, &buff_len);
if (ret)
{
pgnutls_transport_set_errno(s, ret);
return -1;
}
return buff_len;
}
static ssize_t schan_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);
int ret = schan_push(transport, buff, &buff_len);
if (ret)
{
pgnutls_transport_set_errno(s, ret);
return -1;
}
return buff_len;
}
static const struct {
DWORD enable_flag;
const char *gnutls_flag;
} protocol_priority_flags[] = {
{SP_PROT_TLS1_2_CLIENT, "VERS-TLS1.2"},
{SP_PROT_TLS1_1_CLIENT, "VERS-TLS1.1"},
{SP_PROT_TLS1_0_CLIENT, "VERS-TLS1.0"},
{SP_PROT_SSL3_CLIENT, "VERS-SSL3.0"}
/* {SP_PROT_SSL2_CLIENT} is not supported by GnuTLS */
};
DWORD schan_imp_enabled_protocols(void)
{
/* NOTE: No support for SSL 2.0 */
return SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT;
}
BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred)
{
gnutls_session_t *s = (gnutls_session_t*)session;
char priority[64] = "NORMAL", *p;
unsigned i;
int err = pgnutls_init(s, cred->credential_use == SECPKG_CRED_INBOUND ? GNUTLS_SERVER : GNUTLS_CLIENT);
if (err != GNUTLS_E_SUCCESS)
{
pgnutls_perror(err);
return FALSE;
}
p = priority + strlen(priority);
for(i=0; i < sizeof(protocol_priority_flags)/sizeof(*protocol_priority_flags); i++) {
*p++ = ':';
*p++ = (cred->enabled_protocols & protocol_priority_flags[i].enable_flag) ? '+' : '-';
strcpy(p, protocol_priority_flags[i].gnutls_flag);
p += strlen(p);
}
TRACE("Using %s priority\n", debugstr_a(priority));
err = pgnutls_priority_set_direct(*s, priority, NULL);
if (err != GNUTLS_E_SUCCESS)
{
pgnutls_perror(err);
pgnutls_deinit(*s);
return FALSE;
}
err = pgnutls_credentials_set(*s, GNUTLS_CRD_CERTIFICATE,
(gnutls_certificate_credentials_t)cred->credentials);
if (err != GNUTLS_E_SUCCESS)
{
pgnutls_perror(err);
pgnutls_deinit(*s);
return FALSE;
}
pgnutls_transport_set_pull_function(*s, schan_pull_adapter);
pgnutls_transport_set_push_function(*s, schan_push_adapter);
return TRUE;
}
void schan_imp_dispose_session(schan_imp_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)
{
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)
{
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)
{
gnutls_session_t s = (gnutls_session_t)session;
int err;
while(1) {
err = pgnutls_handshake(s);
switch(err) {
case GNUTLS_E_SUCCESS:
TRACE("Handshake completed\n");
return SEC_E_OK;
case GNUTLS_E_AGAIN:
TRACE("Continue...\n");
return SEC_I_CONTINUE_NEEDED;
case GNUTLS_E_WARNING_ALERT_RECEIVED:
{
gnutls_alert_description_t alert = pgnutls_alert_get(s);
WARN("WARNING ALERT: %d %s\n", alert, pgnutls_alert_get_name(alert));
switch(alert) {
case GNUTLS_A_UNRECOGNIZED_NAME:
TRACE("Ignoring\n");
continue;
default:
return SEC_E_INTERNAL_ERROR;
}
}
case GNUTLS_E_FATAL_ALERT_RECEIVED:
{
gnutls_alert_description_t alert = pgnutls_alert_get(s);
WARN("FATAL ALERT: %d %s\n", alert, pgnutls_alert_get_name(alert));
return SEC_E_INTERNAL_ERROR;
}
default:
pgnutls_perror(err);
return SEC_E_INTERNAL_ERROR;
}
}
/* Never reached */
return SEC_E_OK;
}
static unsigned int schannel_get_cipher_block_size(gnutls_cipher_algorithm_t cipher)
{
const struct
{
gnutls_cipher_algorithm_t cipher;
unsigned int block_size;
}
algorithms[] =
{
{GNUTLS_CIPHER_3DES_CBC, 8},
{GNUTLS_CIPHER_AES_128_CBC, 16},
{GNUTLS_CIPHER_AES_256_CBC, 16},
{GNUTLS_CIPHER_ARCFOUR_128, 1},
{GNUTLS_CIPHER_ARCFOUR_40, 1},
{GNUTLS_CIPHER_DES_CBC, 8},
{GNUTLS_CIPHER_NULL, 1},
{GNUTLS_CIPHER_RC2_40_CBC, 8},
};
unsigned int i;
for (i = 0; i < sizeof(algorithms) / sizeof(*algorithms); ++i)
{
if (algorithms[i].cipher == cipher)
return algorithms[i].block_size;
}
FIXME("Unknown cipher %#x, returning 1\n", cipher);
return 1;
}
static DWORD schannel_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
* context doesn't tell us which it is, so assume client for now.
*/
switch (proto)
{
case GNUTLS_SSL3: return SP_PROT_SSL3_CLIENT;
case GNUTLS_TLS1_0: return SP_PROT_TLS1_0_CLIENT;
case GNUTLS_TLS1_1: return SP_PROT_TLS1_1_CLIENT;
case GNUTLS_TLS1_2: return SP_PROT_TLS1_2_CLIENT;
default:
FIXME("unknown protocol %d\n", proto);
return 0;
}
}
static ALG_ID schannel_get_cipher_algid(gnutls_cipher_algorithm_t cipher)
{
switch (cipher)
{
case GNUTLS_CIPHER_UNKNOWN:
case GNUTLS_CIPHER_NULL: return 0;
case GNUTLS_CIPHER_ARCFOUR_40:
case GNUTLS_CIPHER_ARCFOUR_128: return CALG_RC4;
case GNUTLS_CIPHER_DES_CBC:
case GNUTLS_CIPHER_3DES_CBC: return CALG_DES;
case GNUTLS_CIPHER_AES_128_CBC:
case GNUTLS_CIPHER_AES_256_CBC: return CALG_AES;
case GNUTLS_CIPHER_RC2_40_CBC: return CALG_RC2;
default:
FIXME("unknown algorithm %d\n", cipher);
return 0;
}
}
static ALG_ID schannel_get_mac_algid(gnutls_mac_algorithm_t mac)
{
switch (mac)
{
case GNUTLS_MAC_UNKNOWN:
case GNUTLS_MAC_NULL: return 0;
case GNUTLS_MAC_MD5: return CALG_MD5;
case GNUTLS_MAC_SHA1:
case GNUTLS_MAC_SHA256:
case GNUTLS_MAC_SHA384:
case GNUTLS_MAC_SHA512: return CALG_SHA;
default:
FIXME("unknown algorithm %d\n", mac);
return 0;
}
}
static ALG_ID schannel_get_kx_algid(gnutls_kx_algorithm_t kx)
{
switch (kx)
{
case GNUTLS_KX_RSA: return CALG_RSA_KEYX;
case GNUTLS_KX_DHE_DSS:
case GNUTLS_KX_DHE_RSA: return CALG_DH_EPHEM;
default:
FIXME("unknown algorithm %d\n", kx);
return 0;
}
}
unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session)
{
gnutls_session_t s = (gnutls_session_t)session;
gnutls_cipher_algorithm_t cipher = pgnutls_cipher_get(s);
return schannel_get_cipher_block_size(cipher);
}
unsigned int schan_imp_get_max_message_size(schan_imp_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)
{
gnutls_session_t s = (gnutls_session_t)session;
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);
gnutls_kx_algorithm_t kx = pgnutls_kx_get(s);
info->dwProtocol = schannel_get_protocol(proto);
info->aiCipher = schannel_get_cipher_algid(alg);
info->dwCipherStrength = pgnutls_cipher_get_key_size(alg) * 8;
info->aiHash = schannel_get_mac_algid(mac);
info->dwHashStrength = pgnutls_mac_get_key_size(mac) * 8;
info->aiExch = schannel_get_kx_algid(kx);
/* FIXME: info->dwExchStrength? */
info->dwExchStrength = 0;
return SEC_E_OK;
}
SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store,
PCCERT_CONTEXT *ret)
{
gnutls_session_t s = (gnutls_session_t)session;
PCCERT_CONTEXT cert = NULL;
const gnutls_datum_t *datum;
unsigned list_size, i;
BOOL res;
datum = pgnutls_certificate_get_peers(s, &list_size);
if(!datum)
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();
}
}
*ret = cert;
return SEC_E_OK;
}
SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
SIZE_T *length)
{
gnutls_session_t s = (gnutls_session_t)session;
ssize_t ret;
again:
ret = pgnutls_record_send(s, buffer, *length);
if (ret >= 0)
*length = ret;
else if (ret == GNUTLS_E_AGAIN)
{
struct schan_transport *t = (struct schan_transport *)pgnutls_transport_get_ptr(s);
SIZE_T count = 0;
if (schan_get_buffer(t, &t->out, &count))
goto again;
return SEC_I_CONTINUE_NEEDED;
}
else
{
pgnutls_perror(ret);
return SEC_E_INTERNAL_ERROR;
}
return SEC_E_OK;
}
SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
SIZE_T *length)
{
gnutls_session_t s = (gnutls_session_t)session;
ssize_t ret;
again:
ret = pgnutls_record_recv(s, buffer, *length);
if (ret >= 0)
*length = ret;
else if (ret == GNUTLS_E_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))
goto again;
return SEC_I_CONTINUE_NEEDED;
}
else
{
pgnutls_perror(ret);
return SEC_E_INTERNAL_ERROR;
}
return SEC_E_OK;
}
BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c)
{
int ret = pgnutls_certificate_allocate_credentials((gnutls_certificate_credentials_t*)&c->credentials);
if (ret != GNUTLS_E_SUCCESS)
pgnutls_perror(ret);
return (ret == GNUTLS_E_SUCCESS);
}
void schan_imp_free_certificate_credentials(schan_credentials *c)
{
pgnutls_certificate_free_credentials(c->credentials);
}
static void schan_gnutls_log(int level, const char *msg)
{
TRACE("<%d> %s", level, msg);
}
BOOL schan_imp_init(void)
{
int ret;
#ifndef __REACTOS__
libgnutls_handle = wine_dlopen(SONAME_LIBGNUTLS, RTLD_NOW, NULL, 0);
if (!libgnutls_handle)
{
WARN("Failed to load libgnutls.\n");
return FALSE;
}
#define LOAD_FUNCPTR(f) \
if (!(p##f = wine_dlsym(libgnutls_handle, #f, NULL, 0))) \
{ \
ERR("Failed to load %s\n", #f); \
goto fail; \
}
#else
/*
static const WCHAR RosSchannelKey[] = L"Software\\ReactOS\\Schannel";
static const WCHAR PathValue[] = L"GnuTLSPath";
WCHAR Path[MAX_PATH];
DWORD PathSize = sizeof(Path), ValueType;
HKEY Key;
DWORD Error;
Error = RegOpenKeyW(HKEY_LOCAL_MACHINE, RosSchannelKey, &Key);
if(Error != ERROR_SUCCESS)
return FALSE;
Error = RegQueryValueExW(Key, PathValue, NULL, &ValueType, (LPBYTE)Path, &PathSize);
RegCloseKey(Key);
if ((Error != ERROR_SUCCESS) || (ValueType != REG_SZ))
return FALSE;
wcscat(Path, L"\\");
wcscat(Path, SONAME_LIBGNUTLS);
*/
static const WCHAR Path[] = L"C:\\Reactos\\system32\\gnutls\\libgnutls-28.dll";
libgnutls_handle = LoadLibraryExW(Path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (!libgnutls_handle)
{
ERR("Could not load %S.\n", Path);
return FALSE;
}
#define LOAD_FUNCPTR(f) \
if (!(p##f = (void*)GetProcAddress(libgnutls_handle, #f))) \
{ \
ERR("Failed to load %s\n", #f); \
goto fail; \
}
#endif // __REACTOS__
LOAD_FUNCPTR(gnutls_alert_get)
LOAD_FUNCPTR(gnutls_alert_get_name)
LOAD_FUNCPTR(gnutls_certificate_allocate_credentials)
LOAD_FUNCPTR(gnutls_certificate_free_credentials)
LOAD_FUNCPTR(gnutls_certificate_get_peers)
LOAD_FUNCPTR(gnutls_cipher_get)
LOAD_FUNCPTR(gnutls_cipher_get_key_size)
LOAD_FUNCPTR(gnutls_credentials_set)
LOAD_FUNCPTR(gnutls_deinit)
LOAD_FUNCPTR(gnutls_global_deinit)
LOAD_FUNCPTR(gnutls_global_init)
LOAD_FUNCPTR(gnutls_global_set_log_function)
LOAD_FUNCPTR(gnutls_global_set_log_level)
LOAD_FUNCPTR(gnutls_handshake)
LOAD_FUNCPTR(gnutls_init)
LOAD_FUNCPTR(gnutls_kx_get)
LOAD_FUNCPTR(gnutls_mac_get)
LOAD_FUNCPTR(gnutls_mac_get_key_size)
LOAD_FUNCPTR(gnutls_perror)
LOAD_FUNCPTR(gnutls_protocol_get_version)
LOAD_FUNCPTR(gnutls_priority_set_direct)
LOAD_FUNCPTR(gnutls_record_get_max_size);
LOAD_FUNCPTR(gnutls_record_recv);
LOAD_FUNCPTR(gnutls_record_send);
LOAD_FUNCPTR(gnutls_server_name_set)
LOAD_FUNCPTR(gnutls_transport_get_ptr)
LOAD_FUNCPTR(gnutls_transport_set_errno)
LOAD_FUNCPTR(gnutls_transport_set_ptr)
LOAD_FUNCPTR(gnutls_transport_set_pull_function)
LOAD_FUNCPTR(gnutls_transport_set_push_function)
#undef LOAD_FUNCPTR
ret = pgnutls_global_init();
if (ret != GNUTLS_E_SUCCESS)
{
pgnutls_perror(ret);
goto fail;
}
if (TRACE_ON(secur32))
{
pgnutls_global_set_log_level(4);
pgnutls_global_set_log_function(schan_gnutls_log);
}
return TRUE;
fail:
#ifndef __REACTOS__
wine_dlclose(libgnutls_handle, NULL, 0);
#else
FreeLibrary(libgnutls_handle);
#endif
libgnutls_handle = NULL;
return FALSE;
}
void schan_imp_deinit(void)
{
pgnutls_global_deinit();
#ifndef __REACTOS__
wine_dlclose(libgnutls_handle, NULL, 0);
#else
FreeLibrary(libgnutls_handle);
#endif
libgnutls_handle = NULL;
}
#endif /* SONAME_LIBGNUTLS && !HAVE_SECURITY_SECURITY_H */

View file

@ -27,7 +27,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
if (fdwReason == DLL_WINE_PREATTACH) return FALSE; /* prefer native version */
if (fdwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hinstDLL);
SECUR32_initSchannelSP();
}
return TRUE;
}
@ -43,3 +46,19 @@ BOOL WINAPI SslEmptyCacheW(LPWSTR target, DWORD flags)
FIXME("%s %x\n", debugstr_w(target), flags);
return TRUE;
}
PSecurityFunctionTableW
WINAPI
schan_InitSecurityInterfaceW(VOID)
{
TRACE("InitSecurityInterfaceW() called\n");
return &schanTableW;
}
PSecurityFunctionTableA
WINAPI
schan_InitSecurityInterfaceA(VOID)
{
TRACE("InitSecurityInterfaceA() called\n");
return &schanTableA;
}

View file

@ -0,0 +1,130 @@
/*
* secur32 private definitions.
*
* Copyright (C) 2004 Juan Lang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __SCHANNEL_PRIV_H__
#define __SCHANNEL_PRIV_H__
typedef struct _SecureProvider
{
struct list entry;
BOOL loaded;
PWSTR moduleName;
HMODULE lib;
} SecureProvider;
typedef struct _SecurePackage
{
struct list entry;
SecPkgInfoW infoW;
SecureProvider *provider;
} SecurePackage;
/* Allocates space for and initializes a new provider. If fnTableA or fnTableW
* is non-NULL, assumes the provider is built-in, and if moduleName is non-NULL,
* means must load the LSA/user mode functions tables from external SSP/AP module.
* Otherwise moduleName must not be NULL.
* Returns a pointer to the stored provider entry, for use adding packages.
*/
SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
const SecurityFunctionTableW *fnTableW, PCWSTR moduleName) DECLSPEC_HIDDEN;
/* Allocates space for and adds toAdd packages with the given provider.
* provider must not be NULL, and either infoA or infoW may be NULL, but not
* both.
*/
void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
const SecPkgInfoA *infoA, const SecPkgInfoW *infoW) DECLSPEC_HIDDEN;
/* Initialization functions for built-in providers */
void SECUR32_initSchannelSP(void) DECLSPEC_HIDDEN;
/* schannel internal interface */
typedef struct schan_imp_session_opaque *schan_imp_session;
typedef struct schan_credentials
{
ULONG credential_use;
void *credentials;
DWORD enabled_protocols;
} schan_credentials;
struct schan_transport;
struct schan_buffers
{
SIZE_T offset;
SIZE_T limit;
const SecBufferDesc *desc;
int current_buffer_idx;
BOOL allow_buffer_resize;
int (*get_next_buffer)(const struct schan_transport *, struct schan_buffers *);
};
struct schan_transport
{
struct schan_context *ctx;
struct schan_buffers in;
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 SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
SecPkgContext_ConnectionInfo *info) 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*) 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;
SECURITY_STATUS
WINAPI
schan_FreeContextBuffer (
PVOID pvoid
);
SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesA(PULONG pcPackages,
PSecPkgInfoA *ppPackageInfo);
SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesW(PULONG pcPackages,
PSecPkgInfoW *ppPackageInfo);
extern SecurityFunctionTableA schanTableA;
extern SecurityFunctionTableW schanTableW;
#endif /* ndef __SCHANNEL_PRIV_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,399 @@
/* Copyright (C) 2004 Juan Lang
*
* This file implements loading of SSP DLLs.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "precomp.h"
#include <assert.h>
typedef struct _SecurePackageTable
{
DWORD numPackages;
DWORD numAllocated;
struct list table;
} SecurePackageTable;
typedef struct _SecureProviderTable
{
DWORD numProviders;
DWORD numAllocated;
struct list table;
} SecureProviderTable;
/**
* Globals
*/
static CRITICAL_SECTION cs;
static CRITICAL_SECTION_DEBUG cs_debug =
{
0, 0, &cs,
{ &cs_debug.ProcessLocksList, &cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": cs") }
};
static CRITICAL_SECTION cs = { &cs_debug, -1, 0, 0, 0, 0 };
static SecurePackageTable *packageTable = NULL;
static SecureProviderTable *providerTable = NULL;
/***********************************************************************
* EnumerateSecurityPackagesW (SECUR32.@)
*/
SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesW(PULONG pcPackages,
PSecPkgInfoW *ppPackageInfo)
{
SECURITY_STATUS ret = SEC_E_OK;
TRACE("(%p, %p)\n", pcPackages, ppPackageInfo);
/* windows just crashes if pcPackages or ppPackageInfo is NULL, so will I */
*pcPackages = 0;
EnterCriticalSection(&cs);
if (packageTable)
{
SecurePackage *package;
size_t bytesNeeded;
bytesNeeded = packageTable->numPackages * sizeof(SecPkgInfoW);
LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
{
if (package->infoW.Name)
bytesNeeded += (lstrlenW(package->infoW.Name) + 1) * sizeof(WCHAR);
if (package->infoW.Comment)
bytesNeeded += (lstrlenW(package->infoW.Comment) + 1) * sizeof(WCHAR);
}
if (bytesNeeded)
{
*ppPackageInfo = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
if (*ppPackageInfo)
{
ULONG i = 0;
PWSTR nextString;
*pcPackages = packageTable->numPackages;
nextString = (PWSTR)((PBYTE)*ppPackageInfo +
packageTable->numPackages * sizeof(SecPkgInfoW));
LIST_FOR_EACH_ENTRY(package, &packageTable->table, SecurePackage, entry)
{
PSecPkgInfoW pkgInfo = *ppPackageInfo + i++;
*pkgInfo = package->infoW;
if (package->infoW.Name)
{
TRACE("Name[%d] = %S\n", i - 1, package->infoW.Name);
pkgInfo->Name = nextString;
lstrcpyW(nextString, package->infoW.Name);
nextString += lstrlenW(nextString) + 1;
}
else
pkgInfo->Name = NULL;
if (package->infoW.Comment)
{
TRACE("Comment[%d] = %S\n", i - 1, package->infoW.Comment);
pkgInfo->Comment = nextString;
lstrcpyW(nextString, package->infoW.Comment);
nextString += lstrlenW(nextString) + 1;
}
else
pkgInfo->Comment = NULL;
}
}
else
ret = SEC_E_INSUFFICIENT_MEMORY;
}
}
LeaveCriticalSection(&cs);
TRACE("<-- 0x%08x\n", ret);
return ret;
}
/* Converts info (which is assumed to be an array of cPackages SecPkgInfoW
* structures) into an array of SecPkgInfoA structures, which it returns.
*/
static PSecPkgInfoA thunk_PSecPkgInfoWToA(ULONG cPackages,
const SecPkgInfoW *info)
{
PSecPkgInfoA ret;
if (info)
{
size_t bytesNeeded = cPackages * sizeof(SecPkgInfoA);
ULONG i;
for (i = 0; i < cPackages; i++)
{
if (info[i].Name)
bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Name,
-1, NULL, 0, NULL, NULL);
if (info[i].Comment)
bytesNeeded += WideCharToMultiByte(CP_ACP, 0, info[i].Comment,
-1, NULL, 0, NULL, NULL);
}
ret = HeapAlloc(GetProcessHeap(), 0, bytesNeeded);
if (ret)
{
PSTR nextString;
nextString = (PSTR)((PBYTE)ret + cPackages * sizeof(SecPkgInfoA));
for (i = 0; i < cPackages; i++)
{
PSecPkgInfoA pkgInfo = ret + i;
int bytes;
memcpy(pkgInfo, &info[i], sizeof(SecPkgInfoA));
if (info[i].Name)
{
pkgInfo->Name = nextString;
/* just repeat back to WideCharToMultiByte how many bytes
* it requires, since we asked it earlier
*/
bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, info[i].Name, -1,
pkgInfo->Name, bytes, NULL, NULL);
nextString += lstrlenA(nextString) + 1;
}
else
pkgInfo->Name = NULL;
if (info[i].Comment)
{
pkgInfo->Comment = nextString;
/* just repeat back to WideCharToMultiByte how many bytes
* it requires, since we asked it earlier
*/
bytes = WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, info[i].Comment, -1,
pkgInfo->Comment, bytes, NULL, NULL);
nextString += lstrlenA(nextString) + 1;
}
else
pkgInfo->Comment = NULL;
}
}
}
else
ret = NULL;
return ret;
}
/***********************************************************************
* EnumerateSecurityPackagesA (SECUR32.@)
*/
SECURITY_STATUS WINAPI schan_EnumerateSecurityPackagesA(PULONG pcPackages,
PSecPkgInfoA *ppPackageInfo)
{
SECURITY_STATUS ret;
PSecPkgInfoW info;
ret = schan_EnumerateSecurityPackagesW(pcPackages, &info);
if (ret == SEC_E_OK && *pcPackages && info)
{
*ppPackageInfo = thunk_PSecPkgInfoWToA(*pcPackages, info);
if (*pcPackages && !*ppPackageInfo)
{
*pcPackages = 0;
ret = SEC_E_INSUFFICIENT_MEMORY;
}
schan_FreeContextBuffer(info);
}
return ret;
}
SECURITY_STATUS
WINAPI
schan_FreeContextBuffer (
PVOID pvoid
)
{
HeapFree(GetProcessHeap(), 0, pvoid);
return SEC_E_OK;
}
static PWSTR SECUR32_strdupW(PCWSTR str)
{
PWSTR ret;
if (str)
{
ret = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR));
if (ret)
lstrcpyW(ret, str);
}
else
ret = NULL;
return ret;
}
PWSTR SECUR32_AllocWideFromMultiByte(PCSTR str)
{
PWSTR ret;
if (str)
{
int charsNeeded = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
if (charsNeeded)
{
ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded * sizeof(WCHAR));
if (ret)
MultiByteToWideChar(CP_ACP, 0, str, -1, ret, charsNeeded);
}
else
ret = NULL;
}
else
ret = NULL;
return ret;
}
PSTR SECUR32_AllocMultiByteFromWide(PCWSTR str)
{
PSTR ret;
if (str)
{
int charsNeeded = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0,
NULL, NULL);
if (charsNeeded)
{
ret = HeapAlloc(GetProcessHeap(), 0, charsNeeded);
if (ret)
WideCharToMultiByte(CP_ACP, 0, str, -1, ret, charsNeeded,
NULL, NULL);
}
else
ret = NULL;
}
else
ret = NULL;
return ret;
}
static void _copyPackageInfo(PSecPkgInfoW info, const SecPkgInfoA *inInfoA,
const SecPkgInfoW *inInfoW)
{
if (info && (inInfoA || inInfoW))
{
/* odd, I know, but up until Name and Comment the structures are
* identical
*/
memcpy(info, inInfoW ? inInfoW : (const SecPkgInfoW *)inInfoA, sizeof(*info));
if (inInfoW)
{
info->Name = SECUR32_strdupW(inInfoW->Name);
info->Comment = SECUR32_strdupW(inInfoW->Comment);
}
else
{
info->Name = SECUR32_AllocWideFromMultiByte(inInfoA->Name);
info->Comment = SECUR32_AllocWideFromMultiByte(inInfoA->Comment);
}
}
}
SecureProvider *SECUR32_addProvider(const SecurityFunctionTableA *fnTableA,
const SecurityFunctionTableW *fnTableW, PCWSTR moduleName)
{
SecureProvider *ret;
EnterCriticalSection(&cs);
if (!providerTable)
{
providerTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProviderTable));
if (!providerTable)
{
LeaveCriticalSection(&cs);
return NULL;
}
list_init(&providerTable->table);
}
ret = HeapAlloc(GetProcessHeap(), 0, sizeof(SecureProvider));
if (!ret)
{
LeaveCriticalSection(&cs);
return NULL;
}
list_add_tail(&providerTable->table, &ret->entry);
ret->lib = NULL;
#ifndef __REACTOS__
if (fnTableA || fnTableW)
{
ret->moduleName = moduleName ? SECUR32_strdupW(moduleName) : NULL;
_makeFnTableA(&ret->fnTableA, fnTableA, fnTableW);
_makeFnTableW(&ret->fnTableW, fnTableA, fnTableW);
ret->loaded = !moduleName;
}
else
#endif
{
ret->moduleName = SECUR32_strdupW(moduleName);
ret->loaded = FALSE;
}
LeaveCriticalSection(&cs);
return ret;
}
void SECUR32_addPackages(SecureProvider *provider, ULONG toAdd,
const SecPkgInfoA *infoA, const SecPkgInfoW *infoW)
{
ULONG i;
assert(provider);
assert(infoA || infoW);
EnterCriticalSection(&cs);
if (!packageTable)
{
packageTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackageTable));
if (!packageTable)
{
LeaveCriticalSection(&cs);
return;
}
packageTable->numPackages = 0;
list_init(&packageTable->table);
}
for (i = 0; i < toAdd; i++)
{
SecurePackage *package = HeapAlloc(GetProcessHeap(), 0, sizeof(SecurePackage));
if (!package)
continue;
list_add_tail(&packageTable->table, &package->entry);
package->provider = provider;
_copyPackageInfo(&package->infoW,
infoA ? &infoA[i] : NULL,
infoW ? &infoW[i] : NULL);
}
packageTable->numPackages += toAdd;
LeaveCriticalSection(&cs);
}

View file

@ -0,0 +1,28 @@
#include "precomp.h"
SECURITY_STATUS WINAPI schan_AcceptSecurityContext(
PCredHandle phCredential, PCtxtHandle phContext, PSecBufferDesc pInput,
ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
PSecBufferDesc pOutput, ULONG *pfContextAttr, PTimeStamp ptsExpiry)
{
return SEC_E_UNSUPPORTED_FUNCTION;
}
SECURITY_STATUS WINAPI schan_ApplyControlToken(PCtxtHandle phContext,
PSecBufferDesc pInput)
{
return SEC_E_UNSUPPORTED_FUNCTION;
}
SECURITY_STATUS WINAPI schan_CompleteAuthToken(PCtxtHandle phContext,
PSecBufferDesc pToken)
{
return SEC_E_UNSUPPORTED_FUNCTION;
}
SECURITY_STATUS WINAPI schan_ImpersonateSecurityContext(PCtxtHandle phContext)
{
return SEC_E_UNSUPPORTED_FUNCTION;
}