0002-Add-crude-version-of-Windows-SChannel-support.patch
text/x-diff
Filename: 0002-Add-crude-version-of-Windows-SChannel-support.patch
Type: text/x-diff
Part: 1
Patch
Format: unified
Series: patch 0002
| File | + | − |
|---|---|---|
| configure | 45 | 2 |
| configure.in | 14 | 0 |
| src/backend/libpq/be-secure-winschannel.c | 64 | 0 |
| src/backend/libpq/Makefile | 4 | 0 |
| src/include/pg_config.h.in | 3 | 0 |
| src/include/pg_config.h.win32 | 3 | 0 |
| src/include/port.h | 3 | 2 |
| src/interfaces/libpq/fe-secure-winschannel.c | 822 | 0 |
| src/interfaces/libpq/libpq-int.h | 12 | 1 |
| src/interfaces/libpq/Makefile | 4 | 0 |
| src/interfaces/libpq/win32.mak | 12 | 0 |
| src/tools/msvc/config_default.pl | 1 | 0 |
| src/tools/msvc/Mkvcbuild.pm | 18 | 0 |
| src/tools/msvc/Solution.pm | 3 | 0 |
>From 7f8258e911779138e7271f42cf75e2dd414e86be Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Wed, 11 Jun 2014 00:39:28 +0300
Subject: [PATCH 2/2] Add crude version of Windows SChannel support.
libpq only ATM, no server-side support
---
configure | 47 +-
configure.in | 14 +
src/backend/libpq/Makefile | 4 +
src/backend/libpq/be-secure-winschannel.c | 64 +++
src/include/pg_config.h.in | 3 +
src/include/pg_config.h.win32 | 3 +
src/include/port.h | 5 +-
src/interfaces/libpq/Makefile | 4 +
src/interfaces/libpq/fe-secure-winschannel.c | 822 +++++++++++++++++++++++++++
src/interfaces/libpq/libpq-int.h | 13 +-
src/interfaces/libpq/win32.mak | 12 +
src/tools/msvc/Mkvcbuild.pm | 18 +
src/tools/msvc/Solution.pm | 3 +
src/tools/msvc/config_default.pl | 1 +
14 files changed, 1008 insertions(+), 5 deletions(-)
create mode 100644 src/backend/libpq/be-secure-winschannel.c
create mode 100644 src/interfaces/libpq/fe-secure-winschannel.c
diff --git a/configure b/configure
index 0e6b109..6244e38 100755
--- a/configure
+++ b/configure
@@ -708,6 +708,7 @@ XML2_CONFIG
UUID_EXTRA_OBJS
with_uuid
with_selinux
+with_winschannel
with_openssl
krb_srvtab
with_python
@@ -824,6 +825,7 @@ with_pam
with_ldap
with_bonjour
with_openssl
+with_winschannel
with_selinux
with_readline
with_libedit_preferred
@@ -1510,6 +1512,7 @@ Optional Packages:
--with-ldap build with LDAP support
--with-bonjour build with Bonjour support
--with-openssl build with OpenSSL support
+ --with-winschannel build with Windows SChannel support
--with-selinux build with SELinux support
--without-readline do not use GNU Readline nor BSD Libedit for editing
--with-libedit-preferred
@@ -5516,6 +5519,46 @@ $as_echo "$with_openssl" >&6; }
#
+# Windows SChannel
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build with native Windows SSL support" >&5
+$as_echo_n "checking whether to build with native Windows SSL support... " >&6; }
+
+
+
+# Check whether --with-winschannel was given.
+if test "${with_winschannel+set}" = set; then :
+ withval=$with_winschannel;
+ case $withval in
+ yes)
+
+$as_echo "#define USE_WINDOWS_SCHANNEL 1" >>confdefs.h
+
+ ;;
+ no)
+ :
+ ;;
+ *)
+ as_fn_error $? "no argument expected for --with-winschannel option" "$LINENO" 5
+ ;;
+ esac
+
+else
+ with_winschannel=no
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_winschannel" >&5
+$as_echo "$with_winschannel" >&6; }
+
+
+if test "$with_openssl" = yes -a "$with_winschannel" = yes ; then
+ as_fn_error $? "
+*** Cannot select both OpenSSL and Windows SChannel." "$LINENO" 5
+fi
+
+#
# SELinux
#
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build with SELinux support" >&5
@@ -10940,7 +10983,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -10964,7 +11007,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
diff --git a/configure.in b/configure.in
index 4bdd0f7..e1452da 100644
--- a/configure.in
+++ b/configure.in
@@ -663,6 +663,20 @@ AC_MSG_RESULT([$with_openssl])
AC_SUBST(with_openssl)
#
+# Windows SChannel
+#
+AC_MSG_CHECKING([whether to build with native Windows SSL support])
+PGAC_ARG_BOOL(with, winschannel, no, [build with Windows SChannel support],
+ [AC_DEFINE([USE_WINDOWS_SCHANNEL], 1, [Define to build with Windows SChannel support. (--with-winschannel)])])
+AC_MSG_RESULT([$with_winschannel])
+AC_SUBST(with_winschannel)
+
+if test "$with_openssl" = yes -a "$with_winschannel" = yes ; then
+ AC_MSG_ERROR([
+*** Cannot select both OpenSSL and Windows SChannel.])
+fi
+
+#
# SELinux
#
AC_MSG_CHECKING([whether to build with SELinux support])
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index 8be0572..88d0b8b 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -21,4 +21,8 @@ ifeq ($(with_openssl),yes)
OBJS += be-secure-openssl.o
endif
+ifeq ($(with_winschannel),yes)
+OBJS += be-secure-winschannel.o
+endif
+
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/libpq/be-secure-winschannel.c b/src/backend/libpq/be-secure-winschannel.c
new file mode 100644
index 0000000..5fee673
--- /dev/null
+++ b/src/backend/libpq/be-secure-winschannel.c
@@ -0,0 +1,64 @@
+/*-------------------------------------------------------------------------
+ *
+ * be-secure-winschannel.c
+ * SSL support using Windows SChannel APIs
+ *
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/libpq/be-secure-winschannel.c
+ *
+ * TODO: this is just a dummy placeholder
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "libpq/libpq-be.h"
+
+/*
+ * Write data to a secure connection.
+ */
+ssize_t
+be_tls_write(Port *port, void *ptr, size_t len)
+{
+ elog(ERROR, "be_tls_write not implemented");
+ return -1;
+}
+
+/*
+ * Initialize global SSL context.
+ */
+void
+be_tls_init(void)
+{
+}
+
+/*
+ * Attempt to negotiate SSL connection.
+ */
+int
+be_tls_open_server(Port *port)
+{
+ return -1;
+}
+
+/*
+ * Close SSL connection.
+ */
+void
+be_tls_close(Port *port)
+{
+}
+
+ssize_t
+be_tls_read(Port *port, void *ptr, size_t len)
+{
+ elog(ERROR, "be_tls_read not implemented");
+ return -1;
+}
+
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 0a0e0d4..a9f7171 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -803,6 +803,9 @@
/* Define to select Win32-style shared memory. */
#undef USE_WIN32_SHARED_MEMORY
+/* Define to build with Windows SChannel support. (--with-winschannel) */
+#undef USE_WINDOWS_SCHANNEL
+
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 6a6d2f3..c4f8ec4 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -650,6 +650,9 @@
/* Define to select Win32-style semaphores. */
#define USE_WIN32_SEMAPHORES 1
+/* Define to build with Windows SChannel support. (--with-winschannel) */
+#undef USE_WINDOWS_SCHANNEL
+
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
diff --git a/src/include/port.h b/src/include/port.h
index 7d2e0c4..c8b19d5 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -472,9 +472,10 @@ extern char *escape_single_quotes_ascii(const char *src);
/* port/wait_error.c */
extern char *wait_result_to_str(int exit_status);
-/* If we're building with OpenSSL, then we have SSL support */
+/* If we're building with OpenSSL or Windows SChannel, then we have SSL
+ * support */
/* XXX: this doesn't belong here.. I couldn't find a precedence to follow */
-#ifdef USE_OPENSSL
+#if defined (USE_OPENSSL) || defined(USE_WINDOWS_SCHANNEL)
#define USE_SSL
#endif
diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index 7827ac0..3b11b5b 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -48,6 +48,10 @@ ifeq ($(with_openssl),yes)
OBJS += fe-secure-openssl.o
endif
+ifeq ($(with_winschannel),yes)
+OBJS += fe-secure-winschannel.o
+endif
+
ifeq ($(PORTNAME), cygwin)
override shlib = cyg$(NAME)$(DLSUFFIX)
endif
diff --git a/src/interfaces/libpq/fe-secure-winschannel.c b/src/interfaces/libpq/fe-secure-winschannel.c
new file mode 100644
index 0000000..efdbd98
--- /dev/null
+++ b/src/interfaces/libpq/fe-secure-winschannel.c
@@ -0,0 +1,822 @@
+/*-------------------------------------------------------------------------
+ *
+ * fe-winschannel.c
+ * functions for Windows Schannel SSL implementation
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/interfaces/libpq/fe-winschannel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "libpq-fe.h"
+#include "libpq-int.h"
+
+#include "win32.h"
+
+#include <sspi.h>
+#include <schnlsp.h>
+
+struct SchannelContext
+{
+ SecPkgContext_StreamSizes sizes;
+ CtxtHandle ctxHandle;
+
+ char *encryptBuffer;
+ int encryptBufferSize;
+ int encryptBufferLen;
+ int encryptBufferPos;
+ int plaintextLen;
+ bool encrypted;
+
+ char *decryptBuffer;
+ int decryptBufferSize;
+ /*
+ * These are the length and position of the ciphertext left in the buffer,
+ * that hasn't been decrypted yet.
+ */
+ int decryptBufferLen;
+
+ /* decrypted data not returned to the caller yet */
+ char *decryptedData;
+ int decryptedLen;
+
+ /*
+ * extra data not decrypted yet (this is normally a pointer somewhere
+ * in decryptBuffer
+ */
+ char *extraData;
+ int extraLen;
+};
+
+typedef struct SchannelContext SchannelContext;
+
+#define BUFSIZE 10000
+
+static CERT_CONTEXT *getClientCert();
+
+void
+pgtls_init_library(bool do_ssl, int do_crypto)
+{
+}
+
+
+/*
+ * Initialize SSL system, in particular creating the SSL_context object
+ * that will be shared by all SSL-using connections in this process.
+ *
+ * The conn parameter is only used to be able to pass back an error
+ * message - no connection-local setup is made here.
+ *
+ * Returns 0 if OK, -1 on failure (with a message in conn->errorMessage).
+ */
+int
+pgtls_init(PGconn *conn)
+{
+ /* nothing to do here ATM */
+ return 0;
+}
+
+
+/*
+ * Begin or continue negotiating a secure session.
+ */
+PostgresPollingStatusType
+pgtls_open_client(PGconn *conn)
+{
+ SchannelContext *ctx = conn->windows_schannel;
+ SecBufferDesc outsbufdesc;
+ SecBuffer outsbufs[1];
+ SecBufferDesc insbufdesc;
+ SecBuffer insbufs[2];
+ CredHandle credHandle;
+ SECURITY_STATUS rc;
+ DWORD flags;
+ DWORD outflags;
+ int n;
+ bool first_call = (ctx == NULL);
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "pgtls_open_client called: %p\n", conn->windows_schannel);
+ fflush(stderr);
+#endif
+
+ if (first_call)
+ {
+ SCHANNEL_CRED credData;
+ CERT_CONTEXT *cert;
+
+ cert = getClientCert();
+
+ memset(&credData, 0, sizeof(credData));
+ credData.dwVersion = SCHANNEL_CRED_VERSION;
+ credData.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK |
+ SCH_CRED_MANUAL_CRED_VALIDATION; /* FIXME */
+ credData.cCreds = 1;
+ credData.paCred = &cert;
+
+ ctx = (SchannelContext *) malloc(sizeof(SchannelContext));
+ if (ctx == NULL)
+ goto fail;
+ memset(ctx, 0, sizeof(SchannelContext));
+
+ /* FIXME: check server cert */
+ rc = AcquireCredentialsHandle(NULL,
+ UNISP_NAME,
+ SECPKG_CRED_OUTBOUND,
+ NULL,
+ &credData,
+ NULL,
+ NULL,
+ &credHandle,
+ NULL);
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "AcquireCredentialsHandle returned %x\n", rc);
+ fflush(stderr);
+#endif
+ if (rc != SEC_E_OK)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ "AcquireCredentialsHandle failed: %d\n", rc);
+ goto fail;
+ }
+
+ ctx->encryptBufferSize = ctx->decryptBufferSize =
+ BUFSIZE;
+ ctx->encryptBuffer = malloc(ctx->encryptBufferSize);
+ if (ctx->encryptBuffer == NULL)
+ goto fail;
+
+ ctx->decryptBuffer = malloc(ctx->encryptBufferSize);
+ if (ctx->decryptBuffer == NULL)
+ goto fail;
+
+ conn->windows_schannel = ctx;
+ conn->ssl_in_use = true;
+ }
+ else
+ {
+ int maxsize;
+ int readlen;
+
+ /* read more data to buffer, and decrypt */
+ maxsize = ctx->decryptBufferSize - ctx->decryptBufferLen;
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "reading maxsize %d buflen %d\n", maxsize, ctx->decryptBufferLen);
+ fflush(stderr);
+#endif
+ readlen = pqsecure_raw_read(conn,
+ &ctx->decryptBuffer[ctx->decryptBufferLen],
+ maxsize);
+ fprintf(stderr, "received %d bytes in handshake\n", readlen);
+ fflush(stderr);
+ if (readlen < 0)
+ return PGRES_POLLING_FAILED; /* FIXME: error msg? */
+
+ ctx->decryptBufferLen += readlen;
+
+ insbufs[0].pvBuffer = ctx->decryptBuffer;
+ insbufs[0].cbBuffer = ctx->decryptBufferLen;
+ insbufs[0].BufferType = SECBUFFER_TOKEN;
+
+ insbufs[1].pvBuffer = NULL;
+ insbufs[1].cbBuffer = 0;
+ insbufs[1].BufferType = SECBUFFER_EMPTY;
+
+ insbufdesc.cBuffers = 2;
+ insbufdesc.pBuffers = insbufs;
+ insbufdesc.ulVersion = SECBUFFER_VERSION;
+
+ /* consume the input */
+ ctx->decryptBufferLen = 0;
+ }
+
+ flags = ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_RET_EXTENDED_ERROR |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_SEQUENCE_DETECT |
+ ISC_REQ_STREAM;
+
+ outsbufs[0].pvBuffer = NULL;
+ outsbufs[0].BufferType = SECBUFFER_TOKEN;
+ outsbufs[0].cbBuffer = 0;
+
+ outsbufdesc.cBuffers = 1;
+ outsbufdesc.pBuffers = outsbufs;
+ outsbufdesc.ulVersion = SECBUFFER_VERSION;
+
+ rc = InitializeSecurityContext(&credHandle,
+ first_call ? NULL : &ctx->ctxHandle,
+ NULL, /* pszTargetName */
+ flags,
+ 0,
+ 0,
+ first_call ? NULL : &insbufdesc,
+ 0,
+ first_call ? &ctx->ctxHandle : NULL,
+ &outsbufdesc,
+ &outflags,
+ NULL);
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "InitializeSecurityContext returned %x\n", (unsigned int) rc);
+ fflush(stderr);
+#endif
+
+ conn->windows_schannel = ctx;
+
+ switch(rc)
+ {
+ case SEC_E_OK:
+ /* SSL handshake is complete */
+ return PGRES_POLLING_OK;
+
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ printfPQExpBuffer(&conn->errorMessage,
+ "SEC_I_COMPLETE_AND_CONTINUE not implemented\n", rc);
+ return PGRES_POLLING_FAILED;
+
+ case SEC_I_COMPLETE_NEEDED:
+ printfPQExpBuffer(&conn->errorMessage,
+ "SEC_I_COMPLETE_NEEDED not implemented\n", rc);
+ return PGRES_POLLING_FAILED;
+
+ case SEC_I_CONTINUE_NEEDED:
+ /*
+ * Must send the token that InitializeSecurityContext put in
+ * the out buffer.
+ */
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "got SEC_I_CONTINUE_NEEDED. Sending %d bytes\n",
+ outsbufs[0].cbBuffer);
+ fflush(stderr);
+#endif
+ n = pqsecure_raw_write(conn,
+ outsbufs[0].pvBuffer,
+ outsbufs[0].cbBuffer);
+ if (n != outsbufs[0].cbBuffer)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ "short write\n", rc);
+ return PGRES_POLLING_FAILED;
+ }
+ FreeContextBuffer(outsbufs[0].pvBuffer);
+ outsbufs[0].pvBuffer = NULL;
+
+ return PGRES_POLLING_READING;
+
+ case SEC_I_INCOMPLETE_CREDENTIALS:
+ printfPQExpBuffer(&conn->errorMessage,
+ "SEC_I_INCOMPLETE_CREDENTIALS not implemented\n", rc);
+ return PGRES_POLLING_FAILED;
+
+ case SEC_E_INCOMPLETE_MESSAGE:
+ printfPQExpBuffer(&conn->errorMessage,
+ "SEC_E_INCOMPLETE_MESSAGE not implemented\n", rc);
+ return PGRES_POLLING_FAILED;
+
+ default:
+ printfPQExpBuffer(&conn->errorMessage,
+ "InitializeSecurityContext failed: %d\n", rc);
+ return PGRES_POLLING_FAILED;
+ }
+
+ rc = QueryContextAttributes(&ctx->ctxHandle,
+ SECPKG_ATTR_STREAM_SIZES, &ctx->sizes);
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "QueryContextAttributes returned %d\n", rc);
+ fflush(stderr);
+#endif
+ if (rc != SEC_E_OK)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ "QueryContextAttributes failed: %d\n", rc);
+ goto fail; /* FIXME: set errno */
+ }
+
+ /* SSL handshake is complete */
+ return PGRES_POLLING_OK;
+
+fail:
+ if (ctx->decryptBuffer)
+ free(ctx->decryptBuffer);
+ if (ctx->encryptBuffer)
+ free(ctx->encryptBuffer);
+ if (ctx)
+ free(ctx);
+
+ return PGRES_POLLING_FAILED;
+}
+
+
+/*
+ * Close SSL connection.
+ */
+void
+pgtls_close(PGconn *conn)
+{
+ /* TODO: Not implemented. We just leak everything */
+
+ if (conn->ssl_in_use)
+ {
+ conn->windows_schannel = NULL;
+ conn->ssl_in_use = false;
+ }
+}
+
+/*
+ * Read data from a secure connection.
+ *
+ * On failure, this function is responsible for putting a suitable message
+ * into conn->errorMessage. The caller must still inspect errno, but only
+ * to determine whether to continue/retry after error.
+ */
+ssize_t
+pgtls_read(PGconn *conn, char *buffer, size_t len)
+{
+ SchannelContext *ctx = conn->windows_schannel;
+ SecBufferDesc sbufdesc;
+ SecBuffer sbufs[4];
+ int readlen;
+ int maxsize;
+ int rc;
+ int i;
+ int totalreadlen = 0;
+ int origlen = len;
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "pgtls_read called\n");
+ fflush(stderr);
+#endif
+
+ if (ctx->decryptedLen == 0)
+ {
+ /* read more data to buffer, and decrypt */
+ maxsize = ctx->decryptBufferSize - ctx->decryptBufferLen;
+ readlen = pqsecure_raw_read(conn,
+ &ctx->decryptBuffer[ctx->decryptBufferLen],
+ maxsize);
+ if (readlen < 0)
+ return readlen;
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "pgtls_read read %d bytes\n", readlen);
+ fflush(stderr);
+#endif
+
+ ctx->decryptBufferLen += readlen;
+ }
+
+retry:
+ if (ctx->decryptedLen == 0)
+ {
+ /* try to decrypt what we got */
+
+ sbufs[0].pvBuffer = ctx->decryptBuffer;
+ sbufs[0].cbBuffer = ctx->decryptBufferLen;
+ sbufs[0].BufferType = SECBUFFER_DATA;
+ sbufs[1].pvBuffer = NULL;
+ sbufs[1].cbBuffer = 0;
+ sbufs[1].BufferType = SECBUFFER_EMPTY;
+ sbufs[2].pvBuffer = NULL;
+ sbufs[2].cbBuffer = 0;
+ sbufs[2].BufferType = SECBUFFER_EMPTY;
+ sbufs[3].pvBuffer = NULL;
+ sbufs[3].cbBuffer = 0;
+ sbufs[3].BufferType = SECBUFFER_EMPTY;
+
+ sbufdesc.ulVersion = SECBUFFER_VERSION;
+ sbufdesc.cBuffers = 4;
+ sbufdesc.pBuffers = sbufs;
+
+ rc = DecryptMessage(&ctx->ctxHandle, &sbufdesc, 0, NULL);
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "DecryptMessage returned %d\n", rc);
+ fflush(stderr);
+#endif
+
+ if (rc == SEC_E_INCOMPLETE_MESSAGE)
+ {
+ /* We don't have the full message yet. Need more data. */
+ return totalreadlen;
+ }
+ if (rc != SEC_E_OK && rc != SEC_I_RENEGOTIATE)
+ {
+ /* FIXME: set errno */
+ printfPQExpBuffer(&conn->errorMessage,
+ "DecryptMessage failed: %d\n", rc);
+ return -1;
+ }
+
+ /* Did we not decrypt everything? */
+ ctx->extraData = NULL;
+ ctx->extraLen = 0;
+ ctx->decryptedData = NULL;
+ ctx->decryptedLen = 0;
+ for (i = 0; i < 4; i++)
+ {
+ if (sbufs[i].BufferType == SECBUFFER_EXTRA)
+ {
+ ctx->extraData = sbufs[i].pvBuffer;
+ ctx->extraLen = sbufs[i].cbBuffer;
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "found %d extra bytes\n", sbufs[i].cbBuffer);
+ fflush(stderr);
+#endif
+ }
+ if (sbufs[i].BufferType == SECBUFFER_DATA)
+ {
+ ctx->decryptedData = sbufs[i].pvBuffer;
+ ctx->decryptedLen = sbufs[i].cbBuffer;
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "found %d data bytes\n", sbufs[i].cbBuffer);
+ fflush(stderr);
+#endif
+ }
+ }
+ }
+
+ /* we should now have some decrypted data in the buffer. Return it */
+ readlen = len;
+ if (readlen > ctx->decryptedLen)
+ readlen = ctx->decryptedLen;
+
+ memcpy(buffer, ctx->decryptedData, readlen);
+ ctx->decryptedData += readlen;
+ ctx->decryptedLen -= readlen;
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "returning %d decrypted bytes (%d in total, %d max)\n", readlen, totalreadlen, origlen);
+ fflush(stderr);
+#endif
+
+ if (ctx->decryptedLen == 0)
+ {
+ /*
+ * Finished returning this message. If there's some extra data in the
+ * buffer, move it to beginning of buffer for next call.
+ */
+ if (ctx->extraData > 0)
+ {
+ memmove(ctx->decryptBuffer,
+ ctx->extraData,
+ ctx->extraLen);
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "shifted %d extra bytes\n", ctx->extraLen);
+ fflush(stderr);
+#endif
+ }
+ ctx->decryptBufferLen = ctx->extraLen;
+ ctx->extraData = NULL;
+ ctx->extraLen = 0;
+ }
+
+ /*
+ * If we decrypted some data, but it yielded 0 plaintext bytes (i.e. it
+ * was all SSL's internal protocol stuff), try again.
+ */
+ if (readlen == 0)
+ {
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "schannel_read got 0 bytes, retrying\n");
+ fflush(stderr);
+#endif
+ goto retry;
+ }
+
+ totalreadlen += readlen;
+
+ /*
+ * If the target buffer has some room left, and we have more data in the
+ * buffer that we could decrypt and yield more output, try that.
+ */
+ if (readlen < len && ctx->decryptBufferLen > 0)
+ {
+ buffer += readlen;
+ len -= readlen;
+ goto retry;
+ }
+
+ return totalreadlen;
+}
+
+/*
+ * Write data to a secure connection.
+ *
+ * On failure, this function is responsible for putting a suitable message
+ * into conn->errorMessage. The caller must still inspect errno, but only
+ * to determine whether to continue/retry after error.
+ */
+ssize_t
+pgtls_write(PGconn *conn, const void *ptr, size_t len)
+{
+ SchannelContext *ctx = conn->windows_schannel;
+ SecBufferDesc sbufdesc;
+ SecBuffer sbufs[4];
+ int sendlen;
+ SECURITY_STATUS rc;
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "pgtls_write called %d\n", len);
+ fflush(stderr);
+#endif
+ if (!ctx->encrypted)
+ {
+ sendlen = len;
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "pgtls_write sizes before %d + %d + %d\n",
+ ctx->sizes.cbHeader + ctx->sizes.cbMaximumMessage + ctx->sizes.cbTrailer);
+ fflush(stderr);
+#endif
+
+ rc = QueryContextAttributes(&ctx->ctxHandle,
+ SECPKG_ATTR_STREAM_SIZES, &ctx->sizes);
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "QueryContextAttributes returned %d\n", rc);
+ fflush(stderr);
+#endif
+ if (rc != SEC_E_OK)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ "QueryContextAttributes failed: %d\n", rc);
+ return -1; /* FIXME: set errno */
+ }
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "pgtls_write sizes after %d + %d + %d\n",
+ ctx->sizes.cbHeader + ctx->sizes.cbMaximumMessage + ctx->sizes.cbTrailer);
+ fflush(stderr);
+#endif
+
+ if (ctx->sizes.cbHeader + ctx->sizes.cbTrailer + sendlen > ctx->encryptBufferSize)
+ sendlen = ctx->encryptBufferSize - (ctx->sizes.cbHeader + ctx->sizes.cbTrailer);
+
+ memcpy(&ctx->encryptBuffer[ctx->sizes.cbHeader], ptr, sendlen);
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "pgtls_write sendlen %d\n", sendlen);
+ fflush(stderr);
+#endif
+
+ sbufs[0].pvBuffer = ctx->encryptBuffer;
+ sbufs[0].cbBuffer = ctx->sizes.cbHeader;
+ sbufs[0].BufferType = SECBUFFER_STREAM_HEADER;
+
+ sbufs[1].pvBuffer = &ctx->encryptBuffer[ctx->sizes.cbHeader];
+ sbufs[1].cbBuffer = sendlen;
+ sbufs[1].BufferType = SECBUFFER_DATA;
+
+ sbufs[2].pvBuffer = &ctx->encryptBuffer[ctx->sizes.cbHeader + sendlen];
+ sbufs[2].cbBuffer = ctx->sizes.cbTrailer;
+ sbufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
+
+ sbufs[3].pvBuffer = NULL;
+ sbufs[3].cbBuffer = 0;
+ sbufs[3].BufferType = SECBUFFER_EMPTY;
+
+ sbufdesc.ulVersion = SECBUFFER_VERSION;
+ sbufdesc.cBuffers = 4;
+ sbufdesc.pBuffers = sbufs;
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "encrypting %d + %d + %d bytes\n",
+ sbufs[0].cbBuffer, sbufs[1].cbBuffer, sbufs[2].cbBuffer);
+ fflush(stderr);
+#endif
+ rc = EncryptMessage(&ctx->ctxHandle, 0, &sbufdesc, 0);
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "returned %d\n", rc),
+ fflush(stderr);
+#endif
+ if (rc != SEC_E_OK)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ "EncryptMessage failed: %d\n", rc);
+ return -1;
+ }
+
+ ctx->encryptBufferLen = sbufs[0].cbBuffer + sbufs[1].cbBuffer + sbufs[2].cbBuffer;
+ ctx->encryptBufferPos = 0;
+ ctx->plaintextLen = sendlen;
+ ctx->encrypted = true;
+ }
+
+ /* we now have some encrypted data in the buffer. Send it. */
+ sendlen = pqsecure_raw_write(conn,
+ &ctx->encryptBuffer[ctx->encryptBufferPos],
+ ctx->encryptBufferLen - ctx->encryptBufferPos);
+ if (sendlen <= 0)
+ return sendlen;
+
+ ctx->encryptBufferPos += sendlen;
+
+ if (ctx->encryptBufferPos == ctx->encryptBufferLen)
+ {
+ /* sent all the data in the buffer. */
+ ctx->encrypted = false;
+ return ctx->plaintextLen;
+ }
+ else
+ return 0;
+}
+
+static const char *keyStr =
+"-----BEGIN RSA PRIVATE KEY-----\n"
+"MIICXQIBAAKBgQC8K4U6m1APskR3VY277O3fp1/aEMC2UbgohFL2y/jo1Ij2tqr6\n"
+"dxIzwOD/KqjQ2/4DSEoGINDx8RObiLF4HWK6JhN135zn4gs++gN4DDYcZbWV107q\n"
+"zcq3G4FgH8obuUUl7BIWT2NuzfPw9nOJjGkE2ySCW27Iv0/yGG3Jv7am1QIDAQAB\n"
+"AoGAeP4S4KhVRoJ9+62LQTcLjS/2NiVnhNPu8j6DiiWFm1Bt8RVrwzkk/xoakng/\n"
+"rGyIXFvzHRWkxK0aynuOgYmDnMoQhil5aMvemnR7ANJP5JXq3J5sl1ghB1HdBtxd\n"
+"UhbpyoE3NMjHDBi6XDPiIut6w4wusc7EQxCa/L0yNZJ4R9ECQQD2b9/VyEaAwvib\n"
+"Y9UhHf8/KoUt4eC5MUDwDYPqmhyZZniq9D5ucgGQNHdPEK+yJQKcq+j/bo1vNzwu\n"
+"P49/cdrPAkEAw3jRGXVDeitLk0wJYhxr8b4nCMWHcIYfR6NvYlXwLbi2LbDF311W\n"
+"Zo6T+zsm8k/4YnhR1fMlrj8ScqfOxKr9GwJBAN/fIeiD2AiBFneTabp8FbS8W+Ai\n"
+"opOaOvPYU058Uh7JCDXFTDHpP6JRB1G8Rt/+3zCUu0XQmIvAEduxwhp0w+ECQQCq\n"
+"WKqY7glM+VgWWIhA2RX1CUqJKWMb27Z8vuA9qTjzD2qsLMZ0HqpCG/S4V1dcifaj\n"
+"Ecn3krr+u/Z+tuDJoV2LAkB9BHZbcdrYAOpWNfKJ3YyIOmb5ZMabDgav3QTGUXWN\n"
+"hLgVhgidvb6xa3zT2Ps2C8PvsIGpD5d3UzdJvUwcCZfP\n"
+ "-----END RSA PRIVATE KEY-----\n";
+
+static const char *crtStr =
+"-----BEGIN CERTIFICATE-----\n"
+"MIICMjCCAZsCCQCyIo/FfT60NzANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJG\n"
+"STETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\n"
+"cyBQdHkgTHRkMQ8wDQYDVQQDDAZIZWlra2kxHjAcBgkqhkiG9w0BCQEWD2hsaW5u\n"
+"YWthQGlraS5maTAeFw0xNDA2MDkxMzM0MzJaFw0xNDA3MDkxMzM0MzJaMEUxCzAJ\n"
+"BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l\n"
+"dCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALwr\n"
+"hTqbUA+yRHdVjbvs7d+nX9oQwLZRuCiEUvbL+OjUiPa2qvp3EjPA4P8qqNDb/gNI\n"
+"SgYg0PHxE5uIsXgdYromE3XfnOfiCz76A3gMNhxltZXXTurNyrcbgWAfyhu5RSXs\n"
+"EhZPY27N8/D2c4mMaQTbJIJbbsi/T/IYbcm/tqbVAgMBAAEwDQYJKoZIhvcNAQEL\n"
+"BQADgYEAjvK0hCMzGrAawUmSlf7SnCGv3fwjCVDka9NusHX16TQaFP4E1pYBQYkY\n"
+"vKwkSj+bZTrw7fWDHKpGXghS1S8JdqSMOG0uLeqTa2dasnj1SnhbTafK6VgUPB3U\n"
+"J/30HV9WioBqX+4tUzUEvLNl3JYbO4Rd4BX5Kzq2QkrtMX+yPaM=\n"
+ "-----END CERTIFICATE-----\n";
+
+/*
+ * Loads the certificate and associated private key into a Certificate
+ * Context.
+ */
+static CERT_CONTEXT *
+getClientCert()
+{
+ CERT_CONTEXT *cert_cxt;
+ char crtBuf[50000]; /* TODO: enlarge as needed */
+ DWORD crtBufLen = 50000;
+ char keyBuf[50000]; /* TODO: enlarge as needed */
+ DWORD keyBufLen = 50000;
+ char privKeyBlob[50000];
+ int privKeyBlobLen = 50000;
+ CERT_KEY_CONTEXT keyCtx;
+ HCRYPTPROV cryptProvHandle;
+ HCRYPTKEY keyHandle;
+ PUBLICKEYSTRUC *blob;
+
+ /* TODO: read cert from file */
+
+
+ /* convert from PEM to DER */
+ if (!CryptStringToBinary(
+ crtStr,
+ strlen(crtStr),
+ CRYPT_STRING_BASE64HEADER,
+ crtBuf,
+ &crtBufLen,
+ NULL,
+ NULL))
+ {
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "CryptStringToBinary failed: %d\n", GetLastError());
+ fflush(stderr);
+#endif
+ return NULL;
+ }
+
+ cert_cxt = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ crtBuf,
+ crtBufLen);
+ if (cert_cxt == NULL)
+ {
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "CertCreateCertificateContext failed: %x\n", GetLastError());
+ fflush(stderr);
+#endif
+ return NULL;
+ }
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "CertCreateCertificateContext succeeded!\n");
+ fflush(stderr);
+#endif
+
+ /*
+ * Cool, got the cert. But we also need to get the private key associated
+ * with it.
+ */
+
+ /* convert from PEM to DER */
+ if (!CryptStringToBinary(
+ keyStr,
+ strlen(keyStr),
+ CRYPT_STRING_BASE64HEADER,
+ keyBuf,
+ &keyBufLen,
+ NULL,
+ NULL))
+ {
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "CryptStringToBinary failed: %d\n", GetLastError());
+ fflush(stderr);
+#endif
+ return NULL;
+ }
+
+ /*
+ * Get private key
+ */
+ if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ PKCS_RSA_PRIVATE_KEY,
+ keyBuf,
+ keyBufLen,
+ 0,
+ NULL,
+ privKeyBlob,
+ &privKeyBlobLen))
+ {
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "CryptDecodeObjectEx failed: %x\n", GetLastError());
+ fflush(stderr);
+#endif
+ return NULL;
+ }
+ blob = (PUBLICKEYSTRUC *) privKeyBlob;
+
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "decoded bType %d bVersion %d, alg %d len %d\n",
+ blob->bType, blob->bVersion, blob->aiKeyAlg, privKeyBlobLen);
+ fflush(stderr);
+#endif
+
+ if (!CryptAcquireContext(&cryptProvHandle, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ {
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "CryptAcquireContext failed: %x\n", GetLastError());
+ fflush(stderr);
+#endif
+ return NULL;
+ }
+
+ if (!CryptImportKey(cryptProvHandle, privKeyBlob, privKeyBlobLen,
+ (HCRYPTKEY) NULL, 0, &keyHandle))
+ {
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "CryptImportKey failed: %x\n", GetLastError());
+ fflush(stderr);
+#endif
+ return NULL;
+ }
+
+ memset(&keyCtx, 0, sizeof(keyCtx));
+ keyCtx.cbSize = sizeof(keyCtx);
+ keyCtx.hCryptProv = cryptProvHandle;
+ keyCtx.dwKeySpec = AT_KEYEXCHANGE;
+
+ if (!CertSetCertificateContextProperty(cert_cxt,
+ CERT_KEY_CONTEXT_PROP_ID,
+ 0,
+ &keyCtx))
+ {
+#ifdef SCHANNEL_DEBUG
+ fprintf(stderr, "CertSetCertificateContextProperty failed: %x\n", GetLastError());
+ fflush(stderr);
+#endif
+ return NULL;
+ }
+
+ return cert_cxt;
+}
+
+
+
+/*
+ * TODO: need a new API for this.
+ */
+void *
+PQgetssl(PGconn *conn)
+{
+ /*
+ * return non-zero, so that psql reports that SSL is used. Of course, it's
+ * totally bogus for anyone who actually tries to get the OpenSSL
+ * SSL struct.
+ */
+ return (void *) 1;
+}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 6032904..4a1b413 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -82,6 +82,10 @@ typedef struct
#endif
#endif /* USE_OPENSSL */
+#ifdef USE_WINDOWS_SCHANNEL
+struct SchannelContext;
+#endif
+
/*
* POSTGRES backend dependent Constants.
*/
@@ -428,6 +432,7 @@ struct pg_conn
bool wait_ssl_try; /* Delay SSL negotiation until after
* attempting normal connection */
bool ssl_in_use;
+
#ifdef USE_OPENSSL
SSL *ssl; /* SSL status, if have SSL connection */
X509 *peer; /* X509 cert of server */
@@ -438,6 +443,11 @@ struct pg_conn
* OpenSSL version changes */
#endif
#endif /* USE_OPENSSL */
+
+#ifdef USE_WINDOWS_SCHANNEL
+
+#endif /* USE_WINDOWS_SCHANNEL */
+ struct SchannelContext *windows_schannel;
#endif /* USE_SSL */
#ifdef ENABLE_GSS
@@ -634,7 +644,8 @@ extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending,
#endif
/*
- * The SSL implementatation provides these functions (fe-secure-openssl.c)
+ * The SSL implementation provides these functions (i.e. fe-secure-openssl.c
+ * or fe-secure-winschannel.c)
*/
extern void pgtls_init_library(bool do_ssl, int do_crypto);
extern int pgtls_init(PGconn *conn);
diff --git a/src/interfaces/libpq/win32.mak b/src/interfaces/libpq/win32.mak
index 79b6d49..6a78917 100644
--- a/src/interfaces/libpq/win32.mak
+++ b/src/interfaces/libpq/win32.mak
@@ -101,6 +101,12 @@ CLEAN :
-@erase "$(INTDIR)\fe-misc.obj"
-@erase "$(INTDIR)\fe-print.obj"
-@erase "$(INTDIR)\fe-secure.obj"
+!IFDEF USE_OPENSSL
+ -@erase "$(INTDIR)\fe-secure-openssl.obj"
+!ENDIF
+!IFDEF USE_WINDOWS_SCHANNEL
+ -@erase "$(INTDIR)\fe-secure-winschannel.obj"
+!ENDIF
-@erase "$(INTDIR)\libpq-events.obj"
-@erase "$(INTDIR)\pqexpbuffer.obj"
-@erase "$(INTDIR)\win32.obj"
@@ -171,6 +177,12 @@ LIB32_OBJS= \
LIB32_OBJS=$(LIB32_OBJS) "$(INTDIR)\fe-secure-openssl.obj"
!ENDIF
+!IFDEF USE_OPENSSL
+ LIB32_OBJS=$(LIB32_OBJS) "$(INTDIR)\fe-secure-openssl.obj"
+!ENDIF
+!IFDEF USE_WINDOWS_SCHANNEL
+ LIB32_OBJS=$(LIB32_OBJS) "$(INTDIR)\fe-secure-winschannel.obj"
+!ENDIF
config: ..\..\include\pg_config.h ..\..\include\pg_config_ext.h pg_config_paths.h ..\..\include\pg_config_os.h
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index af231ba..d29f450 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -116,6 +116,10 @@ sub mkvcbuild
$postgres->AddLibrary('wsock32.lib');
$postgres->AddLibrary('ws2_32.lib');
$postgres->AddLibrary('secur32.lib');
+ if ($solution->{options}->{winschannel})
+ {
+ $postgres->AddLibrary('crypt32.lib');
+ }
$postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
$postgres->FullExportDLL('postgres.lib');
# The OBJS scraper doesn't know about ifdefs, so remove fe-secure-openssl.c
@@ -124,6 +128,11 @@ sub mkvcbuild
{
$postgres->RemoveFile('src\backend\libpq\be-secure-openssl.c');
}
+ # and same for winschannel
+ if (!$solution->{options}->{winschannel})
+ {
+ $postgres->RemoveFile('src\backend\libpq\be-secure-winschannel.c');
+ }
my $snowball = $solution->AddProject('dict_snowball', 'dll', '',
'src\backend\snowball');
@@ -278,6 +287,10 @@ sub mkvcbuild
$libpq->AddIncludeDir('src\port');
$libpq->AddLibrary('wsock32.lib');
$libpq->AddLibrary('secur32.lib');
+ if ($solution->{options}->{winschannel})
+ {
+ $libpq->AddLibrary('crypt32.lib');
+ }
$libpq->AddLibrary('ws2_32.lib');
$libpq->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
$libpq->UseDef('src\interfaces\libpq\libpqdll.def');
@@ -290,6 +303,11 @@ sub mkvcbuild
{
$libpq->RemoveFile('src\interfaces\libpq\fe-secure-openssl.c');
}
+ # and same for winschannel
+ if (!$solution->{options}->{winschannel})
+ {
+ $libpq->RemoveFile('src\interfaces\libpq\fe-secure-winschannel.c');
+ }
my $libpqwalreceiver =
$solution->AddProject('libpqwalreceiver', 'dll', '',
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index f66d1f6..8031acb 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -181,6 +181,8 @@ s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY
print O "#define USE_LDAP 1\n" if ($self->{options}->{ldap});
print O "#define HAVE_LIBZ 1\n" if ($self->{options}->{zlib});
print O "#define USE_OPENSSL 1\n" if ($self->{options}->{openssl});
+ print O "#define USE_WINDOWS_SCHANNEL 1\n"
+ if ($self->{options}->{winschannel});
print O "#define ENABLE_NLS 1\n" if ($self->{options}->{nls});
print O "#define BLCKSZ ", 1024 * $self->{options}->{blocksize}, "\n";
@@ -625,6 +627,7 @@ sub GetFakeConfigure
$cfg .= ' --with-ldap' if ($self->{options}->{ldap});
$cfg .= ' --without-zlib' unless ($self->{options}->{zlib});
$cfg .= ' --with-openssl' if ($self->{options}->{openssl});
+ $cfg .= ' --with-winschannel' if ($self->{options}->{winschannel});
$cfg .= ' --with-ossp-uuid' if ($self->{options}->{uuid});
$cfg .= ' --with-libxml' if ($self->{options}->{xml});
$cfg .= ' --with-libxslt' if ($self->{options}->{xslt});
diff --git a/src/tools/msvc/config_default.pl b/src/tools/msvc/config_default.pl
index 7c04de0..62bc9ab 100644
--- a/src/tools/msvc/config_default.pl
+++ b/src/tools/msvc/config_default.pl
@@ -16,6 +16,7 @@ our $config = {
perl => undef, # --with-perl
python => undef, # --with-python=<path>
openssl => undef, # --with-openssl=<path>
+ winschannel => 1, # --with-winschannel
uuid => undef, # --with-ossp-uuid
xml => undef, # --with-libxml=<path>
xslt => undef, # --with-libxslt=<path>
--
2.0.0