You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-08 14:02:17 +03:00
CONC-386:
Added support for pem files which contain certificate and private key. In case the file will contain more than one certificate or key, the first certificate or key found will be used.
This commit is contained in:
@@ -133,11 +133,11 @@ void ma_schannel_set_win_error(MARIADB_PVIO *pvio)
|
||||
*/
|
||||
static LPBYTE ma_schannel_load_pem(MARIADB_PVIO *pvio, const char *PemFileName, DWORD *buffer_len)
|
||||
{
|
||||
HANDLE hfile;
|
||||
HANDLE hfile= 0;
|
||||
char *buffer= NULL;
|
||||
DWORD dwBytesRead= 0;
|
||||
LPBYTE der_buffer= NULL;
|
||||
DWORD der_buffer_length;
|
||||
DWORD der_buffer_length= 0;
|
||||
|
||||
if (buffer_len == NULL)
|
||||
return NULL;
|
||||
@@ -156,7 +156,7 @@ static LPBYTE ma_schannel_load_pem(MARIADB_PVIO *pvio, const char *PemFileName,
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(buffer= LocalAlloc(0, *buffer_len + 1)))
|
||||
if (!(buffer= malloc((size_t)(*buffer_len + 1))))
|
||||
{
|
||||
pvio->set_error(pvio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||
goto end;
|
||||
@@ -192,7 +192,7 @@ static LPBYTE ma_schannel_load_pem(MARIADB_PVIO *pvio, const char *PemFileName,
|
||||
}
|
||||
|
||||
*buffer_len= der_buffer_length;
|
||||
LocalFree(buffer);
|
||||
free(buffer);
|
||||
|
||||
return der_buffer;
|
||||
|
||||
@@ -208,6 +208,196 @@ end:
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static LPBYTE ma_schannel_read(MARIADB_PVIO* pvio, const char* PemFile, DWORD* buffer_len)
|
||||
{
|
||||
HANDLE hfile = NULL;
|
||||
char* buffer = NULL;
|
||||
DWORD dwBytesRead = 0;
|
||||
|
||||
if ((hfile = CreateFile(PemFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ma_schannel_set_win_error(pvio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(*buffer_len = GetFileSize(hfile, NULL)))
|
||||
{
|
||||
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Invalid pem format");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(buffer = malloc((size_t)* buffer_len + 1)))
|
||||
{
|
||||
pvio->set_error(pvio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!ReadFile(hfile, buffer, *buffer_len, &dwBytesRead, NULL))
|
||||
{
|
||||
ma_schannel_set_win_error(pvio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
buffer[*buffer_len] = 0;
|
||||
|
||||
CloseHandle(hfile);
|
||||
return buffer;
|
||||
end:
|
||||
if (hfile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(hfile);
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
*buffer_len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LPBYTE ma_schannel_convert_base64(MARIADB_PVIO* pvio, char* buffer, DWORD buffer_len, DWORD* der_len)
|
||||
{
|
||||
LPBYTE der_buffer = NULL;
|
||||
|
||||
*der_len = 0;
|
||||
|
||||
/* calculate the length of DER binary */
|
||||
if (!CryptStringToBinaryA(buffer, buffer_len, CRYPT_STRING_BASE64HEADER,
|
||||
NULL, der_len, NULL, NULL))
|
||||
{
|
||||
ma_schannel_set_win_error(pvio);
|
||||
goto end;
|
||||
}
|
||||
/* allocate DER binary buffer */
|
||||
if (!(der_buffer = (LPBYTE)malloc(*der_len)))
|
||||
{
|
||||
pvio->set_error(pvio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||
goto end;
|
||||
}
|
||||
/* convert to DER binary */
|
||||
if (!CryptStringToBinaryA(buffer, buffer_len, CRYPT_STRING_BASE64HEADER,
|
||||
der_buffer, der_len, NULL, NULL))
|
||||
{
|
||||
ma_schannel_set_win_error(pvio);
|
||||
goto end;
|
||||
}
|
||||
return der_buffer;
|
||||
end:
|
||||
if (der_buffer)
|
||||
free(der_buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
DWORD ma_schannel_load_certs_and_keys(MARIADB_PVIO* pvio, const char* PemFileName, SC_CTX* ctx)
|
||||
{
|
||||
char* buffer = NULL;
|
||||
char* p, * type;
|
||||
DWORD buffer_len = 0;
|
||||
LPBYTE der_buffer = NULL;
|
||||
DWORD der_buffer_length = 0;
|
||||
|
||||
/* check if cert and key was already loaded */
|
||||
if (ctx->client_cert_ctx && ctx->der_key)
|
||||
return 0;
|
||||
|
||||
if (!(buffer = ma_schannel_read(pvio, PemFileName, &buffer_len)))
|
||||
return 0;
|
||||
|
||||
p = buffer;
|
||||
|
||||
while ((p = strstr(p, "-----BEGIN")))
|
||||
{
|
||||
my_bool is_cert = 0;
|
||||
char* cert_end = strstr(p, "-----END");
|
||||
|
||||
if (!cert_end)
|
||||
{
|
||||
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Unknown or unsupported X509 PEM type"); goto error;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(cert_end = strchr(cert_end, '\n')))
|
||||
goto error;
|
||||
|
||||
if ((type = strstr(p, "CERTIFICATE")) && type < cert_end)
|
||||
{
|
||||
is_cert = 1;
|
||||
/* We only read first certificate, further certificates will be ignored */
|
||||
if (ctx->client_cert_ctx)
|
||||
{
|
||||
p = cert_end;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if ((type = strstr(p, "PRIVATE KEY")) && type < cert_end)
|
||||
{
|
||||
/* We only read the first key, further keys will be ignored */
|
||||
if (ctx->der_key)
|
||||
{
|
||||
p = cert_end;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Unknown or unsupported X509 PEM type");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(der_buffer = ma_schannel_convert_base64(pvio, p, (DWORD)(cert_end - p), &der_buffer_length)))
|
||||
goto error;
|
||||
|
||||
if (is_cert)
|
||||
{
|
||||
if (!(ctx->client_cert_ctx = (CERT_CONTEXT*)CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
der_buffer, der_buffer_length)))
|
||||
{
|
||||
ma_schannel_set_win_error(pvio);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(ctx->der_key= (struct st_DER *)malloc(sizeof(struct st_DER))))
|
||||
{
|
||||
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Not enough memory");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ctx->der_key->der_buffer = der_buffer;
|
||||
ctx->der_key->der_length = der_buffer_length;
|
||||
|
||||
der_buffer = 0;
|
||||
der_buffer_length = 0;
|
||||
p = cert_end;
|
||||
}
|
||||
|
||||
free(der_buffer);
|
||||
der_buffer = 0;
|
||||
der_buffer_length = 0;
|
||||
p = cert_end;
|
||||
|
||||
if (ctx->client_cert_ctx && ctx->der_key)
|
||||
break;
|
||||
}
|
||||
free(buffer);
|
||||
return 0;
|
||||
error:
|
||||
if (buffer)
|
||||
free(buffer);
|
||||
if (der_buffer)
|
||||
free(der_buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ma_delete_key_buffer(SC_CTX* ctx)
|
||||
{
|
||||
if (!ctx->der_key)
|
||||
return;
|
||||
free(ctx->der_key->der_buffer);
|
||||
free(ctx->der_key);
|
||||
ctx->der_key = 0;
|
||||
}
|
||||
|
||||
|
||||
/* {{{ CERT_CONTEXT *ma_schannel_create_cert_context(MARIADB_PVIO *pvio, const char *pem_file) */
|
||||
/*
|
||||
Create a certification context from ca or cert file
|
||||
@@ -281,7 +471,7 @@ PCCRL_CONTEXT ma_schannel_create_crl_context(MARIADB_PVIO *pvio, const char *pem
|
||||
ma_schannel_set_win_error(pvio);
|
||||
end:
|
||||
if (der_buffer)
|
||||
LocalFree(der_buffer);
|
||||
free(der_buffer);
|
||||
return ctx;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -306,10 +496,8 @@ end:
|
||||
PCCRL_CONTEXT A pointer to a certification context structure
|
||||
*/
|
||||
|
||||
my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, const CERT_CONTEXT *ctx, char *key_file)
|
||||
my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, SC_CTX *ctx)
|
||||
{
|
||||
DWORD der_buffer_len= 0;
|
||||
LPBYTE der_buffer= NULL;
|
||||
DWORD priv_key_len= 0;
|
||||
LPBYTE priv_key= NULL;
|
||||
HCRYPTPROV crypt_prov= 0;
|
||||
@@ -317,14 +505,16 @@ my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, const CERT_CONTEXT *ctx
|
||||
CERT_KEY_CONTEXT kpi={ 0 };
|
||||
my_bool rc= 0;
|
||||
|
||||
/* load private key into der binary object */
|
||||
if (!(der_buffer= ma_schannel_load_pem(pvio, key_file, &der_buffer_len)))
|
||||
return 0;
|
||||
if (!ctx->der_key || !ctx->client_cert_ctx)
|
||||
{
|
||||
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Invalid certificate or key");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* determine required buffer size for decoded private key */
|
||||
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
PKCS_RSA_PRIVATE_KEY,
|
||||
der_buffer, der_buffer_len,
|
||||
ctx->der_key->der_buffer, ctx->der_key->der_length,
|
||||
0, NULL,
|
||||
NULL, &priv_key_len))
|
||||
{
|
||||
@@ -333,16 +523,15 @@ my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, const CERT_CONTEXT *ctx
|
||||
}
|
||||
|
||||
/* allocate buffer for decoded private key */
|
||||
if (!(priv_key= LocalAlloc(0, priv_key_len)))
|
||||
if (!(priv_key= malloc(priv_key_len)))
|
||||
{
|
||||
pvio->set_error(pvio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* decode */
|
||||
if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
||||
PKCS_RSA_PRIVATE_KEY,
|
||||
der_buffer, der_buffer_len,
|
||||
ctx->der_key->der_buffer, ctx->der_key->der_length,
|
||||
0, NULL,
|
||||
priv_key, &priv_key_len))
|
||||
{
|
||||
@@ -368,19 +557,23 @@ my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, const CERT_CONTEXT *ctx
|
||||
kpi.cbSize= sizeof(kpi);
|
||||
|
||||
/* assign private key to certificate context */
|
||||
if (CertSetCertificateContextProperty(ctx, CERT_KEY_CONTEXT_PROP_ID, 0, &kpi))
|
||||
if (CertSetCertificateContextProperty(ctx->client_cert_ctx, CERT_KEY_CONTEXT_PROP_ID, 0, &kpi))
|
||||
rc= 1;
|
||||
else
|
||||
ma_schannel_set_win_error(pvio);
|
||||
|
||||
end:
|
||||
if (der_buffer)
|
||||
LocalFree(der_buffer);
|
||||
if (ctx->der_key)
|
||||
{
|
||||
free(ctx->der_key->der_buffer);
|
||||
free(ctx->der_key);
|
||||
ctx->der_key = 0;
|
||||
}
|
||||
if (priv_key)
|
||||
{
|
||||
if (crypt_key)
|
||||
CryptDestroyKey(crypt_key);
|
||||
LocalFree(priv_key);
|
||||
free(priv_key);
|
||||
if (!rc)
|
||||
if (crypt_prov)
|
||||
CryptReleaseContext(crypt_prov, 0);
|
||||
|
@@ -46,9 +46,15 @@
|
||||
|
||||
#include <ma_pthread.h>
|
||||
|
||||
struct st_DER {
|
||||
char* der_buffer;
|
||||
DWORD der_length;
|
||||
};
|
||||
|
||||
struct st_schannel {
|
||||
HCERTSTORE cert_store;
|
||||
const CERT_CONTEXT *client_cert_ctx;
|
||||
struct st_DER *der_key;
|
||||
CredHandle CredHdl;
|
||||
my_bool FreeCredHdl;
|
||||
PUCHAR IoBuffer;
|
||||
@@ -70,8 +76,9 @@ extern my_bool ca_Check, crl_Check;
|
||||
CERT_CONTEXT *ma_schannel_create_cert_context(MARIADB_PVIO *pvio, const char *pem_file);
|
||||
SECURITY_STATUS ma_schannel_client_handshake(MARIADB_TLS *ctls);
|
||||
SECURITY_STATUS ma_schannel_handshake_loop(MARIADB_PVIO *pvio, my_bool InitialRead, SecBuffer *pExtraData);
|
||||
my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, const CERT_CONTEXT *ctx, char *key_file);
|
||||
my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, SC_CTX *ctx);
|
||||
PCCRL_CONTEXT ma_schannel_create_crl_context(MARIADB_PVIO *pvio, const char *pem_file);
|
||||
void ma_delete_key_buffer(SC_CTX* ctx);
|
||||
my_bool ma_schannel_verify_certs(MARIADB_TLS *ctls);
|
||||
ssize_t ma_schannel_write_encrypt(MARIADB_PVIO *pvio,
|
||||
uchar *WriteBuffer,
|
||||
|
@@ -154,7 +154,6 @@ cipher_map[] =
|
||||
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "DHE-RSA-AES256-GCM-SHA384",
|
||||
{ CALG_DH_EPHEM, CALG_AES_256, CALG_SHA_384, CALG_RSA_SIGN }
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#define MAX_ALG_ID 50
|
||||
@@ -206,6 +205,7 @@ static int ma_tls_set_client_certs(MARIADB_TLS *ctls)
|
||||
MARIADB_PVIO *pvio= ctls->pvio;
|
||||
|
||||
sctx->client_cert_ctx= NULL;
|
||||
sctx->der_key = NULL;
|
||||
|
||||
if (!certfile && keyfile)
|
||||
certfile= keyfile;
|
||||
@@ -215,15 +215,26 @@ static int ma_tls_set_client_certs(MARIADB_TLS *ctls)
|
||||
if (!certfile)
|
||||
return 0;
|
||||
|
||||
if (!(sctx->client_cert_ctx = ma_schannel_create_cert_context(ctls->pvio, certfile)))
|
||||
if (certfile && ma_schannel_load_certs_and_keys(pvio, certfile, sctx))
|
||||
return 1;
|
||||
|
||||
if (!ma_schannel_load_private_key(pvio, sctx->client_cert_ctx, keyfile))
|
||||
if (keyfile && ma_schannel_load_certs_and_keys(pvio, keyfile, sctx))
|
||||
return 1;
|
||||
|
||||
if (sctx->client_cert_ctx)
|
||||
{
|
||||
CertFreeCertificateContext(sctx->client_cert_ctx);
|
||||
sctx->client_cert_ctx= NULL;
|
||||
if (!ma_schannel_load_private_key(pvio, sctx))
|
||||
return 1;
|
||||
}
|
||||
else if (sctx->der_key)
|
||||
{
|
||||
free(sctx->der_key->der_buffer);
|
||||
free(sctx->der_key);
|
||||
sctx->der_key = 0;
|
||||
pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "SSL connection error: Cert not found");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -293,6 +304,9 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
|
||||
SC_CTX *sctx;
|
||||
SECURITY_STATUS sRet;
|
||||
ALG_ID AlgId[MAX_ALG_ID];
|
||||
size_t i;
|
||||
DWORD protocol = 0;
|
||||
|
||||
|
||||
if (!ctls || !ctls->pvio)
|
||||
return 1;;
|
||||
@@ -310,8 +324,6 @@ my_bool ma_tls_connect(MARIADB_TLS *ctls)
|
||||
/* Set cipher */
|
||||
if (mysql->options.ssl_cipher)
|
||||
{
|
||||
size_t i;
|
||||
DWORD protocol = 0;
|
||||
|
||||
/* check if a protocol was specified as a cipher:
|
||||
* In this case don't allow cipher suites which belong to newer protocols
|
||||
@@ -533,13 +545,15 @@ const char *ma_tls_get_cipher(MARIADB_TLS *ctls)
|
||||
SecPkgContext_CipherInfo CipherInfo = { SECPKGCONTEXT_CIPHERINFO_V1 };
|
||||
SECURITY_STATUS sRet;
|
||||
SC_CTX *sctx;
|
||||
SecPkgContext_ConnectionInfo ci;
|
||||
|
||||
if (!ctls || !ctls->ssl)
|
||||
return NULL;
|
||||
|
||||
sctx= (SC_CTX *)ctls->ssl;
|
||||
sRet = QueryContextAttributesA(&sctx->ctxt, SECPKG_ATTR_CONNECTION_INFO, (PVOID)&ci);
|
||||
sRet= QueryContextAttributesA(&sctx->ctxt, SECPKG_ATTR_CIPHER_INFO, (PVOID)&CipherInfo);
|
||||
|
||||
sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_CIPHER_INFO, (PVOID)&CipherInfo);
|
||||
if (sRet != SEC_E_OK)
|
||||
return NULL;
|
||||
|
||||
|
@@ -16,6 +16,11 @@
|
||||
or write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
||||
*************************************************************************************/
|
||||
#if defined(WIN32) && defined(HEAP_CHECK)
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#include "my_test.h"
|
||||
#include <ma_pthread.h>
|
||||
@@ -34,6 +39,7 @@ const char *ssluser= "ssluser";
|
||||
const char *sslpw= "sslpw";
|
||||
char sslhost[128];
|
||||
char sslcert[FNLEN];
|
||||
char sslcombined[FNLEN];
|
||||
char sslkey[FNLEN];
|
||||
char sslkey_enc[FNLEN];
|
||||
char sslca[FNLEN];
|
||||
@@ -63,6 +69,7 @@ int check_skip_ssl()
|
||||
}
|
||||
}
|
||||
snprintf(sslcert, FNLEN - 1, "%s/%s", ssldir, "client-cert.pem");
|
||||
snprintf(sslcombined, FNLEN - 1, "%s/%s", ssldir, "client-certkey.pem");
|
||||
snprintf(sslkey, FNLEN - 1, "%s/%s", ssldir, "client-key.pem");
|
||||
snprintf(sslkey_enc, FNLEN - 1, "%s/%s", ssldir, "client-key-enc.pem");
|
||||
snprintf(sslca, FNLEN - 1, "%s/%s", ssldir, "cacert.pem");
|
||||
@@ -1287,6 +1294,33 @@ static int test_mdev14101(MYSQL *my __attribute__((unused)))
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int test_conc386(MYSQL *mysql)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (_access(sslcombined, 0) == -1)
|
||||
#else
|
||||
if (access(sslcombined, R_OK) != 0)
|
||||
#endif
|
||||
{
|
||||
diag("combined cert/key file not found");
|
||||
return SKIP;
|
||||
}
|
||||
|
||||
mysql= mysql_init(NULL);
|
||||
mysql_ssl_set(mysql,
|
||||
sslcombined,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
|
||||
port, socketname, 0), mysql_error(mysql));
|
||||
FAIL_IF(check_cipher(mysql) != 0, "Invalid cipher");
|
||||
mysql_close(mysql);
|
||||
unlink(sslcombined);
|
||||
return OK;
|
||||
}
|
||||
|
||||
struct my_tests_st my_tests[] = {
|
||||
{"test_ssl", test_ssl, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||
{"test_mdev14101", test_mdev14101, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||
@@ -1323,6 +1357,8 @@ struct my_tests_st my_tests[] = {
|
||||
#else
|
||||
{"test_schannel_cipher", test_schannel_cipher, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||
#endif
|
||||
|
||||
{"test_conc386", test_conc386, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||
{"drop_ssl_user", drop_ssl_user, TEST_CONNECTION_NEW, 0, NULL, NULL},
|
||||
{NULL, NULL, 0, 0, NULL, NULL}
|
||||
};
|
||||
@@ -1330,6 +1366,15 @@ struct my_tests_st my_tests[] = {
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if defined(WIN32) && defined(HEAP_CHECK)
|
||||
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
|
||||
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
|
||||
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
|
||||
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
|
||||
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
|
||||
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
|
||||
#endif
|
||||
|
||||
get_envvars();
|
||||
|
||||
if (argc > 1)
|
||||
@@ -1337,6 +1382,9 @@ int main(int argc, char **argv)
|
||||
run_tests(my_tests);
|
||||
|
||||
mysql_server_end();
|
||||
#if defined(WIN32) && defined(HEAP_CHECK)
|
||||
_CrtDumpMemoryLeaks();
|
||||
#endif
|
||||
return(exit_status());
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user