summaryrefslogtreecommitdiff
path: root/src/openvpn
diff options
context:
space:
mode:
authorAlberto Gonzalez Iniesta <agi@inittab.org>2016-01-20 12:01:07 +0100
committerAlberto Gonzalez Iniesta <agi@inittab.org>2016-01-20 12:01:07 +0100
commit9653b1bffea4e96c1eb7c1814e8bed21fea62321 (patch)
tree485f02f91b424955a45c1cc12876c31d3d957f9b /src/openvpn
parent41ffafc126abd9af67061f4931b7614f3cb898b0 (diff)
Imported Upstream version 2.3.10upstream/2.3.10
Diffstat (limited to 'src/openvpn')
-rw-r--r--src/openvpn/Makefile.am4
-rw-r--r--src/openvpn/Makefile.in10
-rw-r--r--src/openvpn/buffer.h2
-rw-r--r--src/openvpn/console.c13
-rw-r--r--src/openvpn/crypto.c2
-rw-r--r--src/openvpn/crypto_openssl.c7
-rw-r--r--src/openvpn/crypto_polarssl.c13
-rw-r--r--src/openvpn/cryptoapi.c5
-rw-r--r--src/openvpn/error.c8
-rw-r--r--src/openvpn/error.h20
-rw-r--r--src/openvpn/forward.c5
-rw-r--r--src/openvpn/helper.c2
-rw-r--r--src/openvpn/httpdigest.c44
-rw-r--r--src/openvpn/init.c68
-rw-r--r--src/openvpn/misc.c121
-rw-r--r--src/openvpn/misc.h5
-rw-r--r--src/openvpn/mss.c17
-rw-r--r--src/openvpn/multi.c23
-rw-r--r--src/openvpn/openvpn.c3
-rw-r--r--src/openvpn/openvpn.h6
-rw-r--r--[-rwxr-xr-x]src/openvpn/openvpn.vcxproj8
-rw-r--r--src/openvpn/openvpn.vcxproj.filters5
-rw-r--r--src/openvpn/options.c118
-rw-r--r--src/openvpn/options.h8
-rw-r--r--src/openvpn/pkcs11_polarssl.c26
-rw-r--r--src/openvpn/plugin.c2
-rw-r--r--src/openvpn/push.c7
-rw-r--r--src/openvpn/route.c24
-rw-r--r--src/openvpn/socket.c52
-rw-r--r--src/openvpn/socket.h10
-rw-r--r--src/openvpn/ssl.c20
-rw-r--r--src/openvpn/ssl_backend.h9
-rw-r--r--src/openvpn/ssl_openssl.c49
-rw-r--r--src/openvpn/ssl_polarssl.c323
-rw-r--r--src/openvpn/ssl_polarssl.h7
-rw-r--r--src/openvpn/ssl_verify.c2
-rw-r--r--src/openvpn/ssl_verify_backend.h2
-rw-r--r--src/openvpn/ssl_verify_openssl.c8
-rw-r--r--src/openvpn/ssl_verify_polarssl.c124
-rw-r--r--src/openvpn/ssl_verify_polarssl.h6
-rw-r--r--src/openvpn/syshead.h1
-rw-r--r--src/openvpn/tun.c23
-rw-r--r--src/openvpn/win32.c335
-rw-r--r--src/openvpn/win32.h17
-rw-r--r--src/openvpn/win32_wfp.h359
45 files changed, 1454 insertions, 469 deletions
diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index 2e602f1..6d02fea 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -110,7 +110,7 @@ openvpn_SOURCES = \
status.c status.h \
syshead.h \
tun.c tun.h \
- win32.h win32.c \
+ win32.h win32_wfp.h win32.c \
cryptoapi.h cryptoapi.c
openvpn_LDADD = \
$(top_builddir)/src/compat/libcompat.la \
@@ -123,5 +123,5 @@ openvpn_LDADD = \
$(OPTIONAL_DL_LIBS)
if WIN32
openvpn_SOURCES += openvpn_win32_resources.rc
-openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm
+openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lrpcrt4 -lwinmm
endif
diff --git a/src/openvpn/Makefile.in b/src/openvpn/Makefile.in
index ea9547c..8519969 100644
--- a/src/openvpn/Makefile.in
+++ b/src/openvpn/Makefile.in
@@ -106,7 +106,7 @@ DIST_COMMON = $(top_srcdir)/build/ltrc.inc $(srcdir)/Makefile.in \
@WIN32_TRUE@am__append_1 = -municode -UUNICODE
sbin_PROGRAMS = openvpn$(EXEEXT)
@WIN32_TRUE@am__append_2 = openvpn_win32_resources.rc
-@WIN32_TRUE@am__append_3 = -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm
+@WIN32_TRUE@am__append_3 = -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lrpcrt4 -lwinmm
subdir = src/openvpn
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_emptyarray.m4 \
@@ -149,8 +149,8 @@ am__openvpn_SOURCES_DIST = base64.c base64.h basic.h buffer.c buffer.h \
ssl_verify.c ssl_verify.h ssl_verify_backend.h \
ssl_verify_openssl.c ssl_verify_openssl.h \
ssl_verify_polarssl.c ssl_verify_polarssl.h status.c status.h \
- syshead.h tun.c tun.h win32.h win32.c cryptoapi.h cryptoapi.c \
- openvpn_win32_resources.rc
+ syshead.h tun.c tun.h win32.h win32_wfp.h win32.c cryptoapi.h \
+ cryptoapi.c openvpn_win32_resources.rc
@WIN32_TRUE@am__objects_1 = openvpn_win32_resources.$(OBJEXT)
am_openvpn_OBJECTS = base64.$(OBJEXT) buffer.$(OBJEXT) \
clinat.$(OBJEXT) crypto.$(OBJEXT) crypto_openssl.$(OBJEXT) \
@@ -452,8 +452,8 @@ openvpn_SOURCES = base64.c base64.h basic.h buffer.c buffer.h \
ssl_verify.c ssl_verify.h ssl_verify_backend.h \
ssl_verify_openssl.c ssl_verify_openssl.h \
ssl_verify_polarssl.c ssl_verify_polarssl.h status.c status.h \
- syshead.h tun.c tun.h win32.h win32.c cryptoapi.h cryptoapi.c \
- $(am__append_2)
+ syshead.h tun.c tun.h win32.h win32_wfp.h win32.c cryptoapi.h \
+ cryptoapi.c $(am__append_2)
openvpn_LDADD = $(top_builddir)/src/compat/libcompat.la \
$(SOCKETS_LIBS) $(OPTIONAL_LZO_LIBS) \
$(OPTIONAL_PKCS11_HELPER_LIBS) $(OPTIONAL_CRYPTO_LIBS) \
diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h
index d306a04..58f0601 100644
--- a/src/openvpn/buffer.h
+++ b/src/openvpn/buffer.h
@@ -873,7 +873,7 @@ gc_reset (struct gc_arena *a)
}
static inline void
-check_malloc_return (void *p)
+check_malloc_return (const void *p)
{
if (!p)
out_of_memory ();
diff --git a/src/openvpn/console.c b/src/openvpn/console.c
index d66d408..e1d46c4 100644
--- a/src/openvpn/console.c
+++ b/src/openvpn/console.c
@@ -208,6 +208,19 @@ get_console_input (const char *prompt, const bool echo, char *input, const int c
#if defined(WIN32)
return get_console_input_win32 (prompt, echo, input, capacity);
#elif defined(HAVE_GETPASS)
+
+ /* did we --daemon'ize before asking for passwords?
+ * (in which case neither stdin or stderr are connected to a tty and
+ * /dev/tty can not be open()ed anymore)
+ */
+ if ( !isatty(0) && !isatty(2) )
+ {
+ int fd = open( "/dev/tty", O_RDWR );
+ if ( fd < 0 )
+ { msg(M_FATAL, "neither stdin nor stderr are a tty device and you have neither a controlling tty nor systemd - can't ask for '%s'. If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prompt ); }
+ close(fd);
+ }
+
if (echo)
{
FILE *fp;
diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c
index c2d5c27..400bf11 100644
--- a/src/openvpn/crypto.c
+++ b/src/openvpn/crypto.c
@@ -1383,7 +1383,7 @@ prng_bytes (uint8_t *output, int len)
}
}
else
- rand_bytes (output, len);
+ ASSERT (rand_bytes (output, len));
}
/* an analogue to the random() function, but use prng_bytes */
diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c
index 348bdee..4e195ce 100644
--- a/src/openvpn/crypto_openssl.c
+++ b/src/openvpn/crypto_openssl.c
@@ -378,7 +378,12 @@ show_available_engines ()
int rand_bytes(uint8_t *output, int len)
{
- return RAND_bytes (output, len);
+ if (unlikely(1 != RAND_bytes (output, len)))
+ {
+ msg(D_CRYPT_ERRORS, "RAND_bytes() failed");
+ return 0;
+ }
+ return 1;
}
/*
diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c
index af79029..24712ed 100644
--- a/src/openvpn/crypto_polarssl.c
+++ b/src/openvpn/crypto_polarssl.c
@@ -457,7 +457,7 @@ cipher_ctx_init (cipher_context_t *ctx, uint8_t *key, int key_len,
void cipher_ctx_cleanup (cipher_context_t *ctx)
{
- cipher_free_ctx(ctx);
+ cipher_free(ctx);
}
int cipher_ctx_iv_length (const cipher_context_t *ctx)
@@ -487,7 +487,12 @@ cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf)
{
- return 0 == cipher_reset(ctx, iv_buf);
+ int retval = cipher_reset(ctx);
+
+ if (0 == retval)
+ retval = cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size);
+
+ return 0 == retval;
}
int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len,
@@ -614,7 +619,7 @@ void
md_ctx_final (md_context_t *ctx, uint8_t *dst)
{
ASSERT(0 == md_finish(ctx, dst));
- ASSERT(0 == md_free_ctx(ctx));
+ md_free(ctx);
}
@@ -645,7 +650,7 @@ hmac_ctx_init (md_context_t *ctx, const uint8_t *key, int key_len, const md_info
void
hmac_ctx_cleanup(md_context_t *ctx)
{
- ASSERT(0 == md_free_ctx(ctx));
+ md_free(ctx);
}
int
diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c
index b7fc11e..853c07b 100644
--- a/src/openvpn/cryptoapi.c
+++ b/src/openvpn/cryptoapi.c
@@ -46,6 +46,8 @@
#include <ctype.h>
#include <assert.h>
+#include "buffer.h"
+
/* MinGW w32api 3.17 is still incomplete when it comes to CryptoAPI while
* MinGW32-w64 defines all macros used. This is a hack around that problem.
*/
@@ -116,7 +118,7 @@ static char *ms_error_text(DWORD ms_err)
(LPTSTR) &lpMsgBuf, 0, NULL);
if (lpMsgBuf) {
char *p;
- rv = strdup(lpMsgBuf);
+ rv = string_alloc(lpMsgBuf, NULL);
LocalFree(lpMsgBuf);
/* trim to the left */
if (rv)
@@ -162,6 +164,7 @@ static void err_put_ms_error(DWORD ms_err, int func, const char *file, int line)
err_map[i].ms_err = ms_err;
err_map[i].err = esd->error = i + 100;
esd->string = ms_error_text(ms_err);
+ check_malloc_return(esd->string);
ERR_load_strings(ERR_LIB_CRYPTOAPI, esd);
ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line);
break;
diff --git a/src/openvpn/error.c b/src/openvpn/error.c
index 6848425..f503cf4 100644
--- a/src/openvpn/error.c
+++ b/src/openvpn/error.c
@@ -397,9 +397,13 @@ dont_mute (unsigned int flags)
}
void
-assert_failed (const char *filename, int line)
+assert_failed (const char *filename, int line, const char *condition)
{
- msg (M_FATAL, "Assertion failed at %s:%d", filename, line);
+ if (condition)
+ msg (M_FATAL, "Assertion failed at %s:%d (%s)", filename, line, condition);
+ else
+ msg (M_FATAL, "Assertion failed at %s:%d", filename, line);
+ _exit(1);
}
/*
diff --git a/src/openvpn/error.h b/src/openvpn/error.h
index 27c48b6..42308e8 100644
--- a/src/openvpn/error.h
+++ b/src/openvpn/error.h
@@ -144,19 +144,22 @@ bool dont_mute (unsigned int flags); /* check muting filter */
#define MSG_TEST(flags) (unlikely((((unsigned int)flags) & M_DEBUG_LEVEL) <= x_debug_level) && dont_mute (flags))
+/* Macro to ensure (and teach static analysis tools) we exit on fatal errors */
+#define EXIT_FATAL(flags) do { if ((flags) & M_FATAL) _exit(1); } while (false)
+
#if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__)
# define HAVE_VARARG_MACROS
-# define msg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); } while (false)
+# define msg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false)
# ifdef ENABLE_DEBUG
-# define dmsg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); } while (false)
+# define dmsg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false)
# else
# define dmsg(flags, ...)
# endif
#elif defined(HAVE_CPP_VARARG_MACRO_GCC) && !defined(__LCLINT__)
# define HAVE_VARARG_MACROS
-# define msg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); } while (false)
+# define msg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false)
# ifdef ENABLE_DEBUG
-# define dmsg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); } while (false)
+# define dmsg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false)
# else
# define dmsg(flags, args...)
# endif
@@ -211,9 +214,14 @@ const char *msg_flags_string (const unsigned int flags, struct gc_arena *gc);
FILE *msg_fp(const unsigned int flags);
/* Fatal logic errors */
-#define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__); } while (false)
+#ifndef ENABLE_SMALL
+#define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__, #x); } while (false)
+#else
+#define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__, NULL); } while (false)
+#endif
-void assert_failed (const char *filename, int line);
+void assert_failed (const char *filename, int line, const char *condition)
+ __attribute__((__noreturn__));
#ifdef ENABLE_DEBUG
void crash (void); /* force a segfault (debugging only) */
diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index 217fbb3..d55fa3b 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -956,8 +956,9 @@ read_incoming_tun (struct context *c)
/* Was TUN/TAP I/O operation aborted? */
if (tuntap_abort(c->c2.buf.len))
{
- register_signal(c, SIGTERM, "tun-abort");
- msg(M_FATAL, "TUN/TAP I/O operation aborted, exiting");
+ register_signal(c, SIGHUP, "tun-abort");
+ c->persist.restart_sleep_seconds = 10;
+ msg(M_INFO, "TUN/TAP I/O operation aborted, restarting");
perf_pop();
return;
}
diff --git a/src/openvpn/helper.c b/src/openvpn/helper.c
index 339e2ae..62f88ec 100644
--- a/src/openvpn/helper.c
+++ b/src/openvpn/helper.c
@@ -167,7 +167,7 @@ helper_client_server (struct options *o)
* push "tun-ipv6"
* ifconfig-ipv6 2001:db8::1 2001:db8::2
* if !nopool:
- * ifconfig-ipv6-pool 2001:db8::1:0/64
+ * ifconfig-ipv6-pool 2001:db8::1000/64
*
*/
if ( o->server_ipv6_defined )
diff --git a/src/openvpn/httpdigest.c b/src/openvpn/httpdigest.c
index 78b8344..99bbda4 100644
--- a/src/openvpn/httpdigest.c
+++ b/src/openvpn/httpdigest.c
@@ -76,20 +76,20 @@ DigestCalcHA1(
const md_kt_t *md5_kt = md_kt_get("MD5");
md_ctx_init(&md5_ctx, md5_kt);
- md_ctx_update(&md5_ctx, pszUserName, strlen(pszUserName));
- md_ctx_update(&md5_ctx, ":", 1);
- md_ctx_update(&md5_ctx, pszRealm, strlen(pszRealm));
- md_ctx_update(&md5_ctx, ":", 1);
- md_ctx_update(&md5_ctx, pszPassword, strlen(pszPassword));
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName));
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm));
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword));
md_ctx_final(&md5_ctx, HA1);
if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)
{
md_ctx_init(&md5_ctx, md5_kt);
md_ctx_update(&md5_ctx, HA1, HASHLEN);
- md_ctx_update(&md5_ctx, ":", 1);
- md_ctx_update(&md5_ctx, pszNonce, strlen(pszNonce));
- md_ctx_update(&md5_ctx, ":", 1);
- md_ctx_update(&md5_ctx, pszCNonce, strlen(pszCNonce));
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
md_ctx_final(&md5_ctx, HA1);
};
md_ctx_cleanup(&md5_ctx);
@@ -119,12 +119,12 @@ DigestCalcResponse(
/* calculate H(A2) */
md_ctx_init(&md5_ctx, md5_kt);
- md_ctx_update(&md5_ctx, pszMethod, strlen(pszMethod));
- md_ctx_update(&md5_ctx, ":", 1);
- md_ctx_update(&md5_ctx, pszDigestUri, strlen(pszDigestUri));
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod));
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri));
if (strcasecmp(pszQop, "auth-int") == 0)
{
- md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
md_ctx_update(&md5_ctx, HEntity, HASHHEXLEN);
};
md_ctx_final(&md5_ctx, HA2);
@@ -133,17 +133,17 @@ DigestCalcResponse(
/* calculate response */
md_ctx_init(&md5_ctx, md5_kt);
md_ctx_update(&md5_ctx, HA1, HASHHEXLEN);
- md_ctx_update(&md5_ctx, ":", 1);
- md_ctx_update(&md5_ctx, pszNonce, strlen(pszNonce));
- md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce));
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
if (*pszQop)
{
- md_ctx_update(&md5_ctx, pszNonceCount, strlen(pszNonceCount));
- md_ctx_update(&md5_ctx, ":", 1);
- md_ctx_update(&md5_ctx, pszCNonce, strlen(pszCNonce));
- md_ctx_update(&md5_ctx, ":", 1);
- md_ctx_update(&md5_ctx, pszQop, strlen(pszQop));
- md_ctx_update(&md5_ctx, ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount));
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce));
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
+ md_ctx_update(&md5_ctx, (const uint8_t *) pszQop, strlen(pszQop));
+ md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1);
};
md_ctx_update(&md5_ctx, HA2Hex, HASHHEXLEN);
md_ctx_final(&md5_ctx, RespHash);
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 71c91a2..2148777 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -840,7 +840,7 @@ void
init_options_dev (struct options *options)
{
if (!options->dev && options->dev_node) {
- char *dev_node = strdup(options->dev_node); /* POSIX basename() implementaions may modify its arguments */
+ char *dev_node = string_alloc(options->dev_node, NULL); /* POSIX basename() implementaions may modify its arguments */
options->dev = basename (dev_node);
}
}
@@ -973,31 +973,30 @@ do_uid_gid_chroot (struct context *c, bool no_delay)
static const char why_not[] = "will be delayed because of --client, --pull, or --up-delay";
struct context_0 *c0 = c->c0;
- if (c->first_time && c0 && !c0->uid_gid_set)
+ if (c0 && !c0->uid_gid_chroot_set)
{
/* chroot if requested */
if (c->options.chroot_dir)
{
if (no_delay)
platform_chroot (c->options.chroot_dir);
- else
+ else if (c->first_time)
msg (M_INFO, "NOTE: chroot %s", why_not);
}
- /* set user and/or group that we want to setuid/setgid to */
- if (no_delay)
- {
- platform_group_set (&c0->platform_state_group);
- platform_user_set (&c0->platform_state_user);
- c0->uid_gid_set = true;
- }
- else if (c0->uid_gid_specified)
+ /* set user and/or group if we want to setuid/setgid */
+ if (c0->uid_gid_specified)
{
- msg (M_INFO, "NOTE: UID/GID downgrade %s", why_not);
+ if (no_delay) {
+ platform_group_set (&c0->platform_state_group);
+ platform_user_set (&c0->platform_state_user);
+ }
+ else if (c->first_time)
+ msg (M_INFO, "NOTE: UID/GID downgrade %s", why_not);
}
#ifdef ENABLE_MEMSTATS
- if (c->options.memstats_fn)
+ if (c->first_time && c->options.memstats_fn)
mstats_open(c->options.memstats_fn);
#endif
@@ -1016,10 +1015,16 @@ do_uid_gid_chroot (struct context *c, bool no_delay)
else
msg (M_INFO, "setcon to '%s' succeeded", c->options.selinux_context);
}
- else
+ else if (c->first_time)
msg (M_INFO, "NOTE: setcon %s", why_not);
}
#endif
+
+ /* Privileges are going to be dropped by now (if requested), be sure
+ * to prevent any future privilege dropping attempts from now on.
+ */
+ if (no_delay)
+ c0->uid_gid_chroot_set = true;
}
}
@@ -1453,6 +1458,9 @@ do_open_tun (struct context *c)
c->plugins,
OPENVPN_PLUGIN_UP,
c->c1.tuntap->actual_name,
+#ifdef WIN32
+ c->c1.tuntap->adapter_index,
+#endif
dev_type_string (c->options.dev, c->options.dev_type),
TUN_MTU_SIZE (&c->c2.frame),
EXPANDED_SIZE (&c->c2.frame),
@@ -1463,6 +1471,15 @@ do_open_tun (struct context *c)
"up",
c->c2.es);
+#ifdef WIN32
+ if (c->options.block_outside_dns)
+ {
+ dmsg (D_LOW, "Blocking outside DNS");
+ if (!win_wfp_block_dns(c->c1.tuntap->adapter_index))
+ msg (M_FATAL, "Blocking DNS failed!");
+ }
+#endif
+
/* possibly add routes */
if (!c->options.route_delay_defined)
do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
@@ -1493,6 +1510,9 @@ do_open_tun (struct context *c)
c->plugins,
OPENVPN_PLUGIN_UP,
c->c1.tuntap->actual_name,
+#ifdef WIN32
+ c->c1.tuntap->adapter_index,
+#endif
dev_type_string (c->options.dev, c->options.dev_type),
TUN_MTU_SIZE (&c->c2.frame),
EXPANDED_SIZE (&c->c2.frame),
@@ -1530,6 +1550,9 @@ do_close_tun (struct context *c, bool force)
if (c->c1.tuntap && c->c1.tuntap_owned)
{
const char *tuntap_actual = string_alloc (c->c1.tuntap->actual_name, &gc);
+#ifdef WIN32
+ DWORD adapter_index = c->c1.tuntap->adapter_index;
+#endif
const in_addr_t local = c->c1.tuntap->local;
const in_addr_t remote_netmask = c->c1.tuntap->remote_netmask;
@@ -1553,6 +1576,9 @@ do_close_tun (struct context *c, bool force)
c->plugins,
OPENVPN_PLUGIN_ROUTE_PREDOWN,
tuntap_actual,
+#ifdef WIN32
+ adapter_index,
+#endif
NULL,
TUN_MTU_SIZE (&c->c2.frame),
EXPANDED_SIZE (&c->c2.frame),
@@ -1578,6 +1604,9 @@ do_close_tun (struct context *c, bool force)
c->plugins,
OPENVPN_PLUGIN_DOWN,
tuntap_actual,
+#ifdef WIN32
+ adapter_index,
+#endif
NULL,
TUN_MTU_SIZE (&c->c2.frame),
EXPANDED_SIZE (&c->c2.frame),
@@ -1589,6 +1618,14 @@ do_close_tun (struct context *c, bool force)
"down",
c->c2.es);
+#ifdef WIN32
+ if (c->options.block_outside_dns)
+ {
+ if (!win_wfp_uninit())
+ msg (M_FATAL, "Uninitialising WFP failed!");
+ }
+#endif
+
/* actually close tun/tap device based on --down-pre flag */
if (c->options.down_pre)
do_close_tun_simple (c);
@@ -1601,6 +1638,9 @@ do_close_tun (struct context *c, bool force)
c->plugins,
OPENVPN_PLUGIN_DOWN,
tuntap_actual,
+#ifdef WIN32
+ adapter_index,
+#endif
NULL,
TUN_MTU_SIZE (&c->c2.frame),
EXPANDED_SIZE (&c->c2.frame),
diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c
index f20d059..04a5b5f 100644
--- a/src/openvpn/misc.c
+++ b/src/openvpn/misc.c
@@ -62,6 +62,9 @@ run_up_down (const char *command,
const struct plugin_list *plugins,
int plugin_type,
const char *arg,
+#ifdef WIN32
+ DWORD adapter_index,
+#endif
const char *dev_type,
int tun_mtu,
int link_mtu,
@@ -82,6 +85,9 @@ run_up_down (const char *command,
setenv_str (es, "dev", arg);
if (dev_type)
setenv_str (es, "dev_type", dev_type);
+#ifdef WIN32
+ setenv_int (es, "dev_idx", adapter_index);
+#endif
if (!ifconfig_local)
ifconfig_local = "";
@@ -1035,7 +1041,9 @@ get_user_pass_cr (struct user_pass *up,
if (!up->defined)
{
- const bool from_stdin = (!auth_file || !strcmp (auth_file, "stdin"));
+ bool from_authfile = (auth_file && !streq (auth_file, "stdin"));
+ bool username_from_stdin = false;
+ bool password_from_stdin = false;
if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED)
msg (M_WARN, "Note: previous '%s' credentials failed", prefix);
@@ -1045,7 +1053,7 @@ get_user_pass_cr (struct user_pass *up,
* Get username/password from management interface?
*/
if (management
- && ((auth_file && streq (auth_file, "management")) || (from_stdin && (flags & GET_USER_PASS_MANAGEMENT)))
+ && ((auth_file && streq (auth_file, "management")) || (!from_authfile && (flags & GET_USER_PASS_MANAGEMENT)))
&& management_query_user_pass_enabled (management))
{
const char *sc = NULL;
@@ -1082,18 +1090,59 @@ get_user_pass_cr (struct user_pass *up,
if (!strlen (up->password))
strcpy (up->password, "ok");
}
-
+ else if (from_authfile)
+ {
+ /*
+ * Try to get username/password from a file.
+ */
+ FILE *fp;
+ char password_buf[USER_PASS_LEN] = { '\0' };
+
+ warn_if_group_others_accessible (auth_file);
+
+ fp = platform_fopen (auth_file, "r");
+ if (!fp)
+ msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file);
+
+ if ((flags & GET_USER_PASS_PASSWORD_ONLY) == 0)
+ {
+ /* Read username first */
+ if (fgets (up->username, USER_PASS_LEN, fp) == NULL)
+ msg (M_FATAL, "Error reading username from %s authfile: %s",
+ prefix,
+ auth_file);
+ }
+ chomp (up->username);
+
+ if (fgets (password_buf, USER_PASS_LEN, fp) != NULL)
+ {
+ chomp (password_buf);
+ }
+
+ if (flags & GET_USER_PASS_PASSWORD_ONLY && !password_buf[0])
+ msg (M_FATAL, "Error reading password from %s authfile: %s", prefix, auth_file);
+
+ if (password_buf[0])
+ strncpy(up->password, password_buf, USER_PASS_LEN);
+ else
+ password_from_stdin = 1;
+
+ fclose (fp);
+
+ if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen (up->username) == 0)
+ msg (M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file);
+ }
+ else
+ {
+ username_from_stdin = true;
+ password_from_stdin = true;
+ }
+
/*
* Get username/password from standard input?
*/
- else if (from_stdin)
+ if (username_from_stdin || password_from_stdin)
{
-#ifndef WIN32
- /* did we --daemon'ize before asking for passwords? */
- if ( !isatty(0) && !isatty(2) )
- { msg(M_FATAL, "neither stdin nor stderr are a tty device, can't ask for %s password. If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prefix ); }
-#endif
-
#ifdef ENABLE_CLIENT_CR
if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE))
{
@@ -1124,7 +1173,7 @@ get_user_pass_cr (struct user_pass *up,
buf_printf (&user_prompt, "Enter %s Username:", prefix);
buf_printf (&pass_prompt, "Enter %s Password:", prefix);
- if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
+ if (username_from_stdin && !(flags & GET_USER_PASS_PASSWORD_ONLY))
{
if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
@@ -1132,7 +1181,7 @@ get_user_pass_cr (struct user_pass *up,
msg (M_FATAL, "ERROR: %s username is empty", prefix);
}
- if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
+ if (password_from_stdin && !get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix);
#ifdef ENABLE_CLIENT_CR
@@ -1158,52 +1207,6 @@ get_user_pass_cr (struct user_pass *up,
#endif
}
}
- else
- {
- /*
- * Get username/password from a file.
- */
- FILE *fp;
-
-#ifndef ENABLE_PASSWORD_SAVE
- /*
- * Unless ENABLE_PASSWORD_SAVE is defined, don't allow sensitive passwords
- * to be read from a file.
- */
- if (flags & GET_USER_PASS_SENSITIVE)
- msg (M_FATAL, "Sorry, '%s' password cannot be read from a file", prefix);
-#endif
-
- warn_if_group_others_accessible (auth_file);
-
- fp = platform_fopen (auth_file, "r");
- if (!fp)
- msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file);
-
- if (flags & GET_USER_PASS_PASSWORD_ONLY)
- {
- if (fgets (up->password, USER_PASS_LEN, fp) == NULL)
- msg (M_FATAL, "Error reading password from %s authfile: %s",
- prefix,
- auth_file);
- }
- else
- {
- if (fgets (up->username, USER_PASS_LEN, fp) == NULL
- || fgets (up->password, USER_PASS_LEN, fp) == NULL)
- msg (M_FATAL, "Error reading username and password (must be on two consecutive lines) from %s authfile: %s",
- prefix,
- auth_file);
- }
-
- fclose (fp);
-
- chomp (up->username);
- chomp (up->password);
-
- if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen (up->username) == 0)
- msg (M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file);
- }
string_mod (up->username, CC_PRINT, CC_CRLF, 0);
string_mod (up->password, CC_PRINT, CC_CRLF, 0);
@@ -1647,7 +1650,7 @@ argv_extract_cmd_name (const char *path)
{
if (path)
{
- char *path_cp = strdup(path); /* POSIX basename() implementaions may modify its arguments */
+ char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */
const char *bn = basename (path_cp);
if (bn)
{
diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h
index e67b5e4..c1942b6 100644
--- a/src/openvpn/misc.h
+++ b/src/openvpn/misc.h
@@ -63,6 +63,9 @@ void run_up_down (const char *command,
const struct plugin_list *plugins,
int plugin_type,
const char *arg,
+#ifdef WIN32
+ DWORD adapter_index,
+#endif
const char *dev_type,
int tun_mtu,
int link_mtu,
@@ -239,7 +242,7 @@ struct static_challenge_info {};
* Flags for get_user_pass and management_query_user_pass
*/
#define GET_USER_PASS_MANAGEMENT (1<<0)
-#define GET_USER_PASS_SENSITIVE (1<<1)
+/* GET_USER_PASS_SENSITIVE (1<<1) not used anymore */
#define GET_USER_PASS_PASSWORD_ONLY (1<<2)
#define GET_USER_PASS_NEED_OK (1<<3)
#define GET_USER_PASS_NOFATAL (1<<4)
diff --git a/src/openvpn/mss.c b/src/openvpn/mss.c
index 64fd722..7298c7b 100644
--- a/src/openvpn/mss.c
+++ b/src/openvpn/mss.c
@@ -129,7 +129,7 @@ mss_fixup_dowork (struct buffer *buf, uint16_t maxmss)
{
int hlen, olen, optlen;
uint8_t *opt;
- uint16_t *mss;
+ uint16_t mssval;
int accumulate;
struct openvpn_tcphdr *tc;
@@ -159,14 +159,13 @@ mss_fixup_dowork (struct buffer *buf, uint16_t maxmss)
if (*opt == OPENVPN_TCPOPT_MAXSEG) {
if (optlen != OPENVPN_TCPOLEN_MAXSEG)
continue;
- mss = (uint16_t *)(opt + 2);
- if (ntohs (*mss) > maxmss) {
- dmsg (D_MSS, "MSS: %d -> %d",
- (int) ntohs (*mss),
- (int) maxmss);
- accumulate = *mss;
- *mss = htons (maxmss);
- accumulate -= *mss;
+ mssval = (opt[2]<<8)+opt[3];
+ if (mssval > maxmss) {
+ dmsg (D_MSS, "MSS: %d -> %d", (int) mssval, (int) maxmss);
+ accumulate = htons(mssval);
+ opt[2] = (maxmss>>8)&0xff;
+ opt[3] = maxmss&0xff;
+ accumulate -= htons(maxmss);
ADJUST_CHECKSUM (accumulate, tc->check);
}
}
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 374950e..577c5d3 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -1426,10 +1426,24 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi)
}
}
- /* TODO: I'm not exactly sure what these environment variables are
- * used for, but if we have them for IPv4, we should also have
- * them for IPv6, no?
- */
+ setenv_del (mi->context.c2.es, "ifconfig_pool_local_ip6");
+ setenv_del (mi->context.c2.es, "ifconfig_pool_remote_ip6");
+ setenv_del (mi->context.c2.es, "ifconfig_pool_ip6_netbits");
+
+ if (mi->context.c1.tuntap->ipv6 && mi->context.c2.push_ifconfig_ipv6_defined)
+ {
+ setenv_in6_addr (mi->context.c2.es,
+ "ifconfig_pool_remote",
+ &mi->context.c2.push_ifconfig_ipv6_local,
+ SA_SET_IF_NONZERO);
+ setenv_in6_addr (mi->context.c2.es,
+ "ifconfig_pool_local",
+ &mi->context.c2.push_ifconfig_ipv6_remote,
+ SA_SET_IF_NONZERO);
+ setenv_int (mi->context.c2.es,
+ "ifconfig_pool_ip6_netbits",
+ mi->context.c2.push_ifconfig_ipv6_netbits);
+ }
}
/*
@@ -1780,6 +1794,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
{
msg (D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive");
cc_succeeded = false;
+ cc_succeeded_count = 0;
}
if (cc_succeeded)
diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c
index 32e326e..823c3dd 100644
--- a/src/openvpn/openvpn.c
+++ b/src/openvpn/openvpn.c
@@ -220,6 +220,9 @@ openvpn_main (int argc, char *argv[])
/* print version number */
msg (M_INFO, "%s", title_string);
+#ifdef WIN32
+ show_windows_version(M_INFO);
+#endif
show_library_versions(M_INFO);
/* misc stuff */
diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h
index 10ec859..36c3100 100644
--- a/src/openvpn/openvpn.h
+++ b/src/openvpn/openvpn.h
@@ -133,13 +133,15 @@ struct context_persist
*
* Level 0 state is initialized once at program startup, and then remains
* throughout the lifetime of the OpenVPN process. This structure
- * contains information related to the process's PID, user, and group.
+ * contains information related to the process's PID, user, group, and
+ * privileges.
*/
struct context_0
{
/* workspace for --user/--group */
bool uid_gid_specified;
- bool uid_gid_set;
+ /* helper which tells us whether we should keep trying to drop privileges */
+ bool uid_gid_chroot_set;
struct platform_state_user platform_state_user;
struct platform_state_group platform_state_group;
};
diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj
index 3b2340e..d691500 100755..100644
--- a/src/openvpn/openvpn.vcxproj
+++ b/src/openvpn/openvpn.vcxproj
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -20,10 +20,12 @@
<ConfigurationType>Application</ConfigurationType>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@@ -62,7 +64,7 @@
<AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Link>
- <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
@@ -87,7 +89,7 @@
<AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Link>
- <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters
index 40336ba..dbed3cd 100644
--- a/src/openvpn/openvpn.vcxproj.filters
+++ b/src/openvpn/openvpn.vcxproj.filters
@@ -449,10 +449,13 @@
<ClInclude Include="win32.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="win32_wfp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="openvpn_win32_resources.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 007bd8c..a49a4fb 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -486,8 +486,10 @@ static const char usage_message[] =
"Client options (when connecting to a multi-client server):\n"
"--client : Helper option to easily configure client mode.\n"
"--auth-user-pass [up] : Authenticate with server using username/password.\n"
- " up is a file containing username/password on 2 lines,\n"
- " or omit to prompt from console.\n"
+ " up is a file containing the username on the first line,\n"
+ " and a password on the second. If either the password or both\n"
+ " the username and the password are omitted OpenVPN will prompt\n"
+ " for them from console.\n"
"--pull : Accept certain config file options from the peer as if they\n"
" were part of the local config file. Must be specified\n"
" when connecting to a '--mode server' remote host.\n"
@@ -713,6 +715,7 @@ static const char usage_message[] =
" optional parameter controls the initial state of ex.\n"
"--show-net-up : Show " PACKAGE_NAME "'s view of routing table and net adapter list\n"
" after TAP adapter is up and routes have been added.\n"
+ "--block-outside-dns : Block DNS on other network adapters to prevent DNS leaks\n"
"Windows Standalone Options:\n"
"\n"
"--show-adapters : Show all TAP-Windows adapters.\n"
@@ -800,10 +803,6 @@ init_options (struct options *o, const bool init_gc)
#ifdef ENABLE_FEATURE_TUN_PERSIST
o->persist_mode = 1;
#endif
-#ifndef WIN32
- o->rcvbuf = 65536;
- o->sndbuf = 65536;
-#endif
#ifdef TARGET_LINUX
o->tuntap_options.txqueuelen = 100;
#endif
@@ -816,6 +815,7 @@ init_options (struct options *o, const bool init_gc)
o->tuntap_options.dhcp_lease_time = 31536000; /* one year */
o->tuntap_options.dhcp_masq_offset = 0; /* use network address as internal DHCP server address */
o->route_method = ROUTE_METHOD_ADAPTIVE;
+ o->block_outside_dns = false;
#endif
#if P2MP_SERVER
o->real_hash_size = 256;
@@ -965,13 +965,11 @@ get_ip_addr (const char *ip_string, int msglevel, bool *error)
* "/nn" is optional, default to /64 if missing
*
* return true if parsing succeeded, modify *network and *netbits
- * return address part without "/nn" in *printable_ipv6 (if != NULL)
*/
bool
get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
- unsigned int * netbits, char ** printable_ipv6, int msglevel )
+ unsigned int * netbits, int msglevel)
{
- int rc;
char * sep, * endp;
int bits;
struct in6_addr t_network;
@@ -998,21 +996,14 @@ get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
if ( sep != NULL ) *sep = '\0';
- rc = inet_pton( AF_INET6, prefix_str, &t_network );
-
- if ( rc == 1 && printable_ipv6 != NULL )
- {
- *printable_ipv6 = string_alloc( prefix_str, NULL );
- }
-
- if ( sep != NULL ) *sep = '/';
-
- if ( rc != 1 )
+ if ( inet_pton( AF_INET6, prefix_str, &t_network ) != 1 )
{
msg (msglevel, "IPv6 prefix '%s': invalid IPv6 address", prefix_str);
return false;
}
+ if ( sep != NULL ) *sep = '/';
+
if ( netbits != NULL )
{
*netbits = bits;
@@ -1024,12 +1015,35 @@ get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
return true; /* parsing OK, values set */
}
+/**
+ * Returns newly allocated string containing address part without "/nn".
+ *
+ * If gc != NULL, the allocated memory is registered in the supplied gc.
+ */
+static char *
+get_ipv6_addr_no_netbits (const char *addr, struct gc_arena *gc)
+{
+ const char *end = strchr (addr, '/');
+ char *ret = NULL;
+ if (NULL == end)
+ {
+ ret = string_alloc (addr, gc);
+ }
+ else
+ {
+ size_t len = end - addr;
+ ret = gc_malloc (len + 1, true, gc);
+ memcpy (ret, addr, len);
+ }
+ return ret;
+}
+
static bool ipv6_addr_safe_hexplusbits( const char * ipv6_prefix_spec )
{
struct in6_addr t_addr;
unsigned int t_bits;
- return get_ipv6_addr( ipv6_prefix_spec, &t_addr, &t_bits, NULL, M_WARN );
+ return get_ipv6_addr( ipv6_prefix_spec, &t_addr, &t_bits, M_WARN );
}
static char *
@@ -1271,7 +1285,7 @@ option_iroute_ipv6 (struct options *o,
ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc);
- if ( !get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, NULL, msglevel ))
+ if ( !get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, msglevel ))
{
msg (msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification",
prefix_str);
@@ -1585,6 +1599,7 @@ show_settings (const struct options *o)
SHOW_STR (ca_path);
SHOW_STR (dh_file);
SHOW_STR (cert_file);
+ SHOW_STR (extra_certs_file);
#ifdef MANAGMENT_EXTERNAL_KEY
if((o->management_flags & MF_EXTERNAL_KEY))
@@ -1665,6 +1680,7 @@ show_settings (const struct options *o)
#ifdef WIN32
SHOW_BOOL (show_net_up);
SHOW_INT (route_method);
+ SHOW_BOOL (block_outside_dns);
show_tuntap_options (&o->tuntap_options);
#endif
#endif
@@ -2616,7 +2632,7 @@ check_file_access(const int type, const char *file, const int mode, const char *
/* Is the directory path leading to the given file accessible? */
if (type & CHKACC_DIRPATH)
{
- char *fullpath = strdup(file); /* POSIX dirname() implementaion may modify its arguments */
+ char *fullpath = string_alloc (file, NULL); /* POSIX dirname() implementaion may modify its arguments */
char *dirpath = dirname(fullpath);
if (platform_access (dirpath, mode|X_OK) != 0)
@@ -3473,6 +3489,15 @@ usage_small (void)
openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
}
+#ifdef WIN32
+void show_windows_version(const unsigned int flags)
+{
+ struct gc_arena gc = gc_new ();
+ msg (flags, "Windows version %s", win32_version_string (&gc, true));
+ gc_free (&gc);
+}
+#endif
+
void
show_library_versions(const unsigned int flags)
{
@@ -3498,6 +3523,9 @@ usage_version (void)
{
msg (M_INFO|M_NOPREFIX, "%s", title_string);
show_library_versions( M_INFO|M_NOPREFIX );
+#ifdef WIN32
+ show_windows_version( M_INFO|M_NOPREFIX );
+#endif
msg (M_INFO|M_NOPREFIX, "Originally developed by James Yonan");
msg (M_INFO|M_NOPREFIX, "Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>");
#ifndef ENABLE_SMALL
@@ -3761,7 +3789,10 @@ read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc)
while (in_src_get (is, line, sizeof (line)))
{
- if (!strncmp (line, close_tag, strlen (close_tag)))
+ char *line_ptr = line;
+ /* Remove leading spaces */
+ while (isspace(*line_ptr)) line_ptr++;
+ if (!strncmp (line_ptr, close_tag, strlen (close_tag)))
{
endtagfound = true;
break;
@@ -3853,7 +3884,7 @@ read_config_file (struct options *options,
const int max_recursive_levels = 10;
FILE *fp;
int line_num;
- char line[OPTION_LINE_SIZE];
+ char line[OPTION_LINE_SIZE+1];
char *p[MAX_PARMS];
++level;
@@ -3871,6 +3902,10 @@ read_config_file (struct options *options,
int offset = 0;
CLEAR (p);
++line_num;
+ if (strlen(line) == OPTION_LINE_SIZE)
+ msg (msglevel, "In %s:%d: Maximum optione line length (%d) exceeded, line starts with %s",
+ file, line_num, OPTION_LINE_SIZE, line);
+
/* Ignore UTF-8 BOM at start of stream */
if (line_num == 1 && strncmp (line, "\xEF\xBB\xBF", 3) == 0)
offset = 3;
@@ -4467,10 +4502,9 @@ add_option (struct options *options,
else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] )
{
unsigned int netbits;
- char * ipv6_local;
VERIFY_PERMISSION (OPT_P_UP);
- if ( get_ipv6_addr( p[1], NULL, &netbits, &ipv6_local, msglevel ) &&
+ if ( get_ipv6_addr( p[1], NULL, &netbits, msglevel ) &&
ipv6_addr_safe( p[2] ) )
{
if ( netbits < 64 || netbits > 124 )
@@ -4479,11 +4513,7 @@ add_option (struct options *options,
goto err;
}
- if (options->ifconfig_ipv6_local)
- /* explicitly ignoring this is a const char */
- free ((char *) options->ifconfig_ipv6_local);
-
- options->ifconfig_ipv6_local = ipv6_local;
+ options->ifconfig_ipv6_local = get_ipv6_addr_no_netbits (p[1], &options->gc);
options->ifconfig_ipv6_netbits = netbits;
options->ifconfig_ipv6_remote = p[2];
}
@@ -5558,7 +5588,7 @@ add_option (struct options *options,
unsigned int netbits = 0;
VERIFY_PERMISSION (OPT_P_GENERAL);
- if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev) )
+ if ( ! get_ipv6_addr (p[1], &network, &netbits, lev) )
{
msg (msglevel, "error parsing --server-ipv6 parameter");
goto err;
@@ -5669,7 +5699,7 @@ add_option (struct options *options,
unsigned int netbits = 0;
VERIFY_PERMISSION (OPT_P_GENERAL);
- if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev ) )
+ if ( ! get_ipv6_addr (p[1], &network, &netbits, lev ) )
{
msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters");
goto err;
@@ -5930,7 +5960,7 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_INSTANCE);
- if ( ! get_ipv6_addr( p[1], &local, &netbits, NULL, msglevel ) )
+ if ( ! get_ipv6_addr( p[1], &local, &netbits, msglevel ) )
{
msg (msglevel, "cannot parse --ifconfig-ipv6-push addresses");
goto err;
@@ -5938,7 +5968,7 @@ add_option (struct options *options,
if ( p[2] )
{
- if ( !get_ipv6_addr( p[2], &remote, NULL, NULL, msglevel ) )
+ if ( !get_ipv6_addr( p[2], &remote, NULL, msglevel ) )
{
msg( msglevel, "cannot parse --ifconfig-ipv6-push addresses");
goto err;
@@ -5948,7 +5978,7 @@ add_option (struct options *options,
{
if ( ! options->ifconfig_ipv6_local ||
! get_ipv6_addr( options->ifconfig_ipv6_local, &remote,
- NULL, NULL, msglevel ) )
+ NULL, msglevel ) )
{
msg( msglevel, "second argument to --ifconfig-ipv6-push missing and no global --ifconfig-ipv6 address set");
goto err;
@@ -6230,6 +6260,22 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_IPWIN32);
options->tuntap_options.register_dns = true;
}
+#ifdef WIN32
+ else if (streq (p[0], "block-outside-dns") && !p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_IPWIN32);
+ if (win_wfp_init_funcs())
+ {
+ options->block_outside_dns = true;
+ }
+ else
+ {
+ msg (msglevel_fc, "Failed to enable --block-outside-dns. "
+ "Maybe WFP is not supported on your system?");
+ goto err;
+ }
+ }
+#endif
else if (streq (p[0], "rdns-internal"))
/* standalone method for internal use
*
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index af9a47f..26b09ea 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -593,6 +593,7 @@ struct options
bool exit_event_initial_state;
bool show_net_up;
int route_method;
+ bool block_outside_dns;
#endif
bool use_peer_id;
@@ -689,6 +690,10 @@ void usage_small (void);
void show_library_versions(const unsigned int flags);
+#ifdef WIN32
+void show_windows_version(const unsigned int flags);
+#endif
+
void init_options (struct options *o, const bool init_gc);
void uninit_options (struct options *o);
@@ -777,8 +782,7 @@ void options_string_import (struct options *options,
struct env_set *es);
bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network,
- unsigned int * netbits, char ** printable_ipv6,
- int msglevel );
+ unsigned int * netbits, int msglevel );
/*
* inline functions
diff --git a/src/openvpn/pkcs11_polarssl.c b/src/openvpn/pkcs11_polarssl.c
index 03b2bab..a58beef 100644
--- a/src/openvpn/pkcs11_polarssl.c
+++ b/src/openvpn/pkcs11_polarssl.c
@@ -40,6 +40,7 @@
#include "errlevel.h"
#include "pkcs11_backend.h"
#include <polarssl/pkcs11.h>
+#include <polarssl/x509.h>
int
pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
@@ -49,20 +50,21 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
ASSERT (NULL != ssl_ctx);
+ ALLOC_OBJ_CLEAR (ssl_ctx->crt_chain, x509_crt);
if (pkcs11_x509_cert_init(ssl_ctx->crt_chain, certificate)) {
msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
goto cleanup;
}
- ssl_ctx->priv_key_pkcs11 = malloc(sizeof(pkcs11_context));
-
- if (ssl_ctx->priv_key_pkcs11 == NULL) {
- msg (M_FATAL, "PKCS#11: Cannot allocate PolarSSL private key object");
+ ALLOC_OBJ_CLEAR (ssl_ctx->priv_key_pkcs11, pkcs11_context);
+ if (pkcs11_priv_key_init(ssl_ctx->priv_key_pkcs11, certificate)) {
+ msg (M_FATAL, "PKCS#11: Cannot initialize PolarSSL private key object");
goto cleanup;
}
- if (pkcs11_priv_key_init(ssl_ctx->priv_key_pkcs11, certificate)) {
- msg (M_FATAL, "PKCS#11: Cannot initialize PolarSSL private key object");
+ ALLOC_OBJ_CLEAR (ssl_ctx->priv_key, pk_context);
+ if (0 != pk_init_ctx_rsa_alt(ssl_ctx->priv_key, ssl_ctx->priv_key_pkcs11,
+ ssl_pkcs11_decrypt, ssl_pkcs11_sign, ssl_pkcs11_key_len)) {
goto cleanup;
}
@@ -78,14 +80,14 @@ pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc)
char *ret = NULL;
char dn[1024] = {0};
- x509_cert polar_cert = {0};
+ x509_crt polar_cert = {0};
if (pkcs11_x509_cert_init(&polar_cert, cert)) {
msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
goto cleanup;
}
- if (-1 == x509parse_dn_gets (dn, sizeof(dn), &polar_cert.subject)) {
+ if (-1 == x509_dn_gets (dn, sizeof(dn), &polar_cert.subject)) {
msg (M_FATAL, "PKCS#11: PolarSSL cannot parse subject");
goto cleanup;
}
@@ -93,7 +95,7 @@ pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc)
ret = string_alloc(dn, gc);
cleanup:
- x509_free(&polar_cert);
+ x509_crt_free(&polar_cert);
return ret;
}
@@ -104,14 +106,14 @@ pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial,
{
int ret = 1;
- x509_cert polar_cert = {0};
+ x509_crt polar_cert = {0};
if (pkcs11_x509_cert_init(&polar_cert, cert)) {
msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
goto cleanup;
}
- if (-1 == x509parse_serial_gets (serial, serial_len, &polar_cert.serial)) {
+ if (-1 == x509_serial_gets (serial, serial_len, &polar_cert.serial)) {
msg (M_FATAL, "PKCS#11: PolarSSL cannot parse serial");
goto cleanup;
}
@@ -119,7 +121,7 @@ pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial,
ret = 0;
cleanup:
- x509_free(&polar_cert);
+ x509_crt_free(&polar_cert);
return ret;
}
diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c
index 0948f23..54c5b52 100644
--- a/src/openvpn/plugin.c
+++ b/src/openvpn/plugin.c
@@ -291,7 +291,7 @@ plugin_init_item (struct plugin *p, const struct plugin_option *o)
static void
plugin_vlog (openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist)
{
- unsigned int msg_flags;
+ unsigned int msg_flags = 0;
if (!format)
return;
diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index 11505cb..e4f3984 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -103,6 +103,7 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool
m = BSTR (&buf);
/* preserve cached passwords? */
+ /* advance to next server? */
{
bool purge = true;
@@ -113,6 +114,12 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool
{
if (m[i] == 'P')
purge = false;
+ else if (m[i] == 'N')
+ {
+ /* next server? */
+ if (c->options.connection_list)
+ c->options.connection_list->no_advance = false;
+ }
}
}
if (purge)
diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index 2acfbe8..f35bc85 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -42,6 +42,7 @@
#include "manage.h"
#include "win32.h"
#include "options.h"
+#include "win32.h"
#include "memdbg.h"
@@ -390,7 +391,7 @@ init_route_ipv6 (struct route_ipv6 *r6,
{
r6->defined = false;
- if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, NULL, M_WARN ))
+ if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, M_WARN ))
goto fail;
/* gateway */
@@ -648,7 +649,7 @@ init_route_list (struct route_list *rl,
bool warned = false;
for (i = 0; i < opt->n; ++i)
{
- struct addrinfo* netlist;
+ struct addrinfo* netlist = NULL;
struct route_ipv4 r;
if (!init_route (&r,
@@ -675,8 +676,9 @@ init_route_list (struct route_list *rl,
}
}
}
- freeaddrinfo(netlist);
}
+ if (netlist)
+ freeaddrinfo(netlist);
}
rl->n = j;
}
@@ -1622,6 +1624,13 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
#elif defined (WIN32)
+ if (win32_version_info() != WIN_XP)
+ {
+ struct buffer out = alloc_buf_gc (64, &gc);
+ buf_printf (&out, "interface=%d", tt->adapter_index );
+ device = buf_bptr(&out);
+ }
+
/* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */
argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s",
get_win_sys_path(),
@@ -1953,6 +1962,13 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
#elif defined (WIN32)
+ if (win32_version_info() != WIN_XP)
+ {
+ struct buffer out = alloc_buf_gc (64, &gc);
+ buf_printf (&out, "interface=%d", tt->adapter_index );
+ device = buf_bptr(&out);
+ }
+
/* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */
argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s",
get_win_sys_path(),
@@ -3195,7 +3211,7 @@ test_local_addr (const in_addr_t addr, const struct route_gateway_info *rgi)
{
struct gc_arena gc = gc_new ();
const in_addr_t nonlocal_netmask = 0x80000000L; /* routes with netmask <= to this are considered non-local */
- bool ret = TLA_NONLOCAL;
+ int ret = TLA_NONLOCAL;
/* get full routing table */
const MIB_IPFORWARDTABLE *rt = get_windows_routing_table (&gc);
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
index 0424c0b..3e30c75 100644
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -494,12 +494,9 @@ static void
socket_set_sndbuf (int sd, int size)
{
#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)
- if (size > 0 && size < SOCKET_SND_RCV_BUF_MAX)
+ if (setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof (size)) != 0)
{
- if (setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof (size)) != 0)
- {
- msg (M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size);
- }
+ msg (M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size);
}
#endif
}
@@ -523,13 +520,10 @@ static bool
socket_set_rcvbuf (int sd, int size)
{
#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)
- if (size > 0 && size < SOCKET_SND_RCV_BUF_MAX)
+ if (setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof (size)) != 0)
{
- if (setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof (size)) != 0)
- {
- msg (M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size);
- return false;
- }
+ msg (M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size);
+ return false;
}
return true;
#endif
@@ -1265,20 +1259,24 @@ resolve_remote (struct link_socket *sock,
ASSERT (0);
}
- /* Temporary fix, this need to be changed for dual stack */
- status = openvpn_getaddrinfo(flags, sock->remote_host, retry,
- signal_received, af, &ai);
- if(status == 0) {
- sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr));
- freeaddrinfo(ai);
+ /* Temporary fix, this need to be changed for dual stack */
+ status = openvpn_getaddrinfo(flags, sock->remote_host, retry,
+ signal_received, af, &ai);
+ if(status == 0)
+ {
+ if ( ai->ai_family == AF_INET6 )
+ sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr));
+ else
+ sock->info.lsa->remote.addr.in4 = *((struct sockaddr_in*)(ai->ai_addr));
+ freeaddrinfo(ai);
- dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
+ dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
flags,
phase,
retry,
signal_received ? *signal_received : -1,
status);
- }
+ }
if (signal_received)
{
if (*signal_received)
@@ -2412,6 +2410,22 @@ setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, c
}
void
+setenv_in6_addr (struct env_set *es,
+ const char *name_prefix,
+ const struct in6_addr *addr,
+ const unsigned int flags)
+{
+ if (!IN6_IS_ADDR_UNSPECIFIED (addr) || !(flags & SA_SET_IF_NONZERO))
+ {
+ struct openvpn_sockaddr si;
+ CLEAR (si);
+ si.addr.in6.sin6_family = AF_INET6;
+ si.addr.in6.sin6_addr = *addr;
+ setenv_sockaddr (es, name_prefix, &si, flags);
+ }
+}
+
+void
setenv_link_socket_actual (struct env_set *es,
const char *name_prefix,
const struct link_socket_actual *act,
diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h
index 793cd9f..b7a4e01 100644
--- a/src/openvpn/socket.h
+++ b/src/openvpn/socket.h
@@ -42,11 +42,6 @@
#define OPENVPN_PORT 1194
/*
- * Maximum size passed passed to setsockopt SNDBUF/RCVBUF
- */
-#define SOCKET_SND_RCV_BUF_MAX 1000000
-
-/*
* Number of seconds that "resolv-retry infinite"
* represents.
*/
@@ -383,6 +378,11 @@ void setenv_in_addr_t (struct env_set *es,
in_addr_t addr,
const unsigned int flags);
+void setenv_in6_addr (struct env_set *es,
+ const char *name_prefix,
+ const struct in6_addr *addr,
+ const unsigned int flags);
+
void setenv_link_socket_actual (struct env_set *es,
const char *name_prefix,
const struct link_socket_actual *act,
diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c
index a17c738..0679890 100644
--- a/src/openvpn/ssl.c
+++ b/src/openvpn/ssl.c
@@ -43,6 +43,7 @@
#endif
#include "syshead.h"
+#include "win32.h"
#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
@@ -301,8 +302,9 @@ tls_init_control_channel_frame_parameters(const struct frame *data_channel_frame
reliable_ack_adjust_frame_parameters (frame, CONTROL_SEND_ACK_MAX);
frame_add_to_extra_frame (frame, SID_SIZE + sizeof (packet_id_type));
- /* set dynamic link MTU to minimum value */
- frame_set_mtu_dynamic (frame, 0, SET_MTU_TUN);
+ /* set dynamic link MTU to cap control channel packets at 1250 bytes */
+ ASSERT (TUN_LINK_DELTA (frame) < min_int (frame->link_mtu, 1250));
+ frame->link_mtu_dynamic = min_int (frame->link_mtu, 1250) - TUN_LINK_DELTA (frame);
}
void
@@ -333,7 +335,7 @@ void
pem_password_setup (const char *auth_file)
{
if (!strlen (passbuf.password))
- get_user_pass (&passbuf, auth_file, UP_TYPE_PRIVATE_KEY, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_PASSWORD_ONLY);
+ get_user_pass (&passbuf, auth_file, UP_TYPE_PRIVATE_KEY, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY);
}
int
@@ -376,11 +378,11 @@ auth_user_pass_setup (const char *auth_file, const struct static_challenge_info
get_user_pass_cr (&auth_user_pass,
auth_file,
UP_TYPE_AUTH,
- GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_DYNAMIC_CHALLENGE,
+ GET_USER_PASS_MANAGEMENT|GET_USER_PASS_DYNAMIC_CHALLENGE,
auth_challenge);
else if (sci) /* static challenge response */
{
- int flags = GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_STATIC_CHALLENGE;
+ int flags = GET_USER_PASS_MANAGEMENT|GET_USER_PASS_STATIC_CHALLENGE;
if (sci->flags & SC_ECHO)
flags |= GET_USER_PASS_STATIC_CHALLENGE_ECHO;
get_user_pass_cr (&auth_user_pass,
@@ -391,7 +393,7 @@ auth_user_pass_setup (const char *auth_file, const struct static_challenge_info
}
else
# endif
- get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE);
+ get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT);
#endif
}
}
@@ -555,6 +557,9 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_file_inline);
}
+ /* Check certificate notBefore and notAfter */
+ tls_ctx_check_cert_time(new_ctx);
+
/* Allowable ciphers */
if (options->cipher_list)
{
@@ -1844,6 +1849,9 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
if (rgi.flags & RGI_HWADDR_DEFINED)
buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc));
buf_printf (&out, "IV_SSL=%s\n", get_ssl_library_version() );
+#if defined(WIN32)
+ buf_printf (&out, "IV_PLAT_VER=%s\n", win32_version_string (&gc, false));
+#endif
}
/* push env vars that begin with UV_ and IV_GUI_VER */
diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h
index 6d47bd0..4b35e51 100644
--- a/src/openvpn/ssl_backend.h
+++ b/src/openvpn/ssl_backend.h
@@ -176,6 +176,15 @@ void tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags);
void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers);
/**
+ * Check our certificate notBefore and notAfter fields, and warn if the cert is
+ * either not yet valid or has expired. Note that this is a non-fatal error,
+ * since we compare against the system time, which might be incorrect.
+ *
+ * @param ctx TLS context to get our certificate from.
+ */
+void tls_ctx_check_cert_time (const struct tls_root_ctx *ctx);
+
+/**
* Load Diffie Hellman Parameters, and load them into the library-specific
* TLS context.
*
diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c
index be33caa..e595e1b 100644
--- a/src/openvpn/ssl_openssl.c
+++ b/src/openvpn/ssl_openssl.c
@@ -335,6 +335,55 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
}
void
+tls_ctx_check_cert_time (const struct tls_root_ctx *ctx)
+{
+ int ret;
+ const X509 *cert;
+
+ ASSERT (ctx);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ /* OpenSSL 1.0.2 and up */
+ cert = SSL_CTX_get0_certificate (ctx->ctx);
+#else
+ /* OpenSSL 1.0.1 and earlier need an SSL object to get at the certificate */
+ SSL *ssl = SSL_new (ctx->ctx);
+ cert = SSL_get_certificate (ssl);
+#endif
+
+ if (cert == NULL)
+ {
+ goto cleanup; /* Nothing to check if there is no certificate */
+ }
+
+ ret = X509_cmp_time (X509_get_notBefore (cert), NULL);
+ if (ret == 0)
+ {
+ msg (D_TLS_DEBUG_MED, "Failed to read certificate notBefore field.");
+ }
+ if (ret > 0)
+ {
+ msg (M_WARN, "WARNING: Your certificate is not yet valid!");
+ }
+
+ ret = X509_cmp_time (X509_get_notAfter (cert), NULL);
+ if (ret == 0)
+ {
+ msg (D_TLS_DEBUG_MED, "Failed to read certificate notAfter field.");
+ }
+ if (ret < 0)
+ {
+ msg (M_WARN, "WARNING: Your certificate has expired!");
+ }
+
+cleanup:
+#if OPENSSL_VERSION_NUMBER < 0x10002000L
+ SSL_free (ssl);
+#endif
+ return;
+}
+
+void
tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
const char *dh_file_inline
)
diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c
index 30c7395..cd8ee1a 100644
--- a/src/openvpn/ssl_polarssl.c
+++ b/src/openvpn/ssl_polarssl.c
@@ -46,12 +46,13 @@
#include "manage.h"
#include "ssl_common.h"
-#include <polarssl/sha2.h>
#include <polarssl/havege.h>
#include "ssl_verify_polarssl.h"
#include <polarssl/error.h>
+#include <polarssl/oid.h>
#include <polarssl/pem.h>
+#include <polarssl/sha256.h>
#include <polarssl/version.h>
void
@@ -76,11 +77,8 @@ tls_ctx_server_new(struct tls_root_ctx *ctx, unsigned int ssl_flags)
CLEAR(*ctx);
ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
- ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);
-
- ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert);
- ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert);
+ ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt);
ctx->endpoint = SSL_IS_SERVER;
ctx->initialised = true;
@@ -93,10 +91,7 @@ tls_ctx_client_new(struct tls_root_ctx *ctx, unsigned int ssl_flags)
CLEAR(*ctx);
ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
- ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);
-
- ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert);
- ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert);
+ ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt);
ctx->endpoint = SSL_IS_CLIENT;
ctx->initialised = true;
@@ -107,17 +102,21 @@ tls_ctx_free(struct tls_root_ctx *ctx)
{
if (ctx)
{
- rsa_free(ctx->priv_key);
- free(ctx->priv_key);
+ pk_free(ctx->priv_key);
+ if (ctx->priv_key)
+ free(ctx->priv_key);
- x509_free(ctx->ca_chain);
- free(ctx->ca_chain);
+ x509_crt_free(ctx->ca_chain);
+ if (ctx->ca_chain)
+ free(ctx->ca_chain);
- x509_free(ctx->crt_chain);
- free(ctx->crt_chain);
+ x509_crt_free(ctx->crt_chain);
+ if (ctx->crt_chain)
+ free(ctx->crt_chain);
dhm_free(ctx->dhm_ctx);
- free(ctx->dhm_ctx);
+ if (ctx->dhm_ctx)
+ free(ctx->dhm_ctx);
#if defined(ENABLE_PKCS11)
if (ctx->priv_key_pkcs11 != NULL) {
@@ -191,7 +190,7 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
/* Parse allowed ciphers, getting IDs */
i = 0;
- tmp_ciphers_orig = tmp_ciphers = strdup(ciphers);
+ tmp_ciphers_orig = tmp_ciphers = string_alloc (ciphers, NULL);
token = strtok (tmp_ciphers, ":");
while(token)
@@ -206,19 +205,39 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
}
void
+tls_ctx_check_cert_time (const struct tls_root_ctx *ctx)
+{
+ ASSERT (ctx);
+ if (ctx->crt_chain == NULL)
+ {
+ return; /* Nothing to check if there is no certificate */
+ }
+
+ if (x509_time_future (&ctx->crt_chain->valid_from))
+ {
+ msg (M_WARN, "WARNING: Your certificate is not yet valid!");
+ }
+
+ if (x509_time_expired (&ctx->crt_chain->valid_to))
+ {
+ msg (M_WARN, "WARNING: Your certificate has expired!");
+ }
+}
+
+void
tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
const char *dh_inline
)
{
if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_inline)
{
- if (0 != x509parse_dhm(ctx->dhm_ctx, (const unsigned char *) dh_inline,
+ if (0 != dhm_parse_dhm(ctx->dhm_ctx, (const unsigned char *) dh_inline,
strlen(dh_inline)))
msg (M_FATAL, "Cannot read inline DH parameters");
}
else
{
- if (0 != x509parse_dhmfile(ctx->dhm_ctx, dh_file))
+ if (0 != dhm_parse_dhmfile(ctx->dhm_ctx, dh_file))
msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file);
}
@@ -251,15 +270,20 @@ tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
{
ASSERT(NULL != ctx);
+ if (!ctx->crt_chain)
+ {
+ ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt);
+ }
+
if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_inline)
{
- if (0 != x509parse_crt(ctx->crt_chain,
+ if (0 != x509_crt_parse(ctx->crt_chain,
(const unsigned char *) cert_inline, strlen(cert_inline)))
msg (M_FATAL, "Cannot load inline certificate file");
}
else
{
- if (0 != x509parse_crtfile(ctx->crt_chain, cert_file))
+ if (0 != x509_crt_parse_file(ctx->crt_chain, cert_file))
msg (M_FATAL, "Cannot load certificate file %s", cert_file);
}
}
@@ -272,34 +296,40 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
int status;
ASSERT(NULL != ctx);
+ if (!ctx->priv_key)
+ {
+ ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context);
+ }
+
if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_inline)
{
- status = x509parse_key(ctx->priv_key,
+ status = pk_parse_key(ctx->priv_key,
(const unsigned char *) priv_key_inline, strlen(priv_key_inline),
NULL, 0);
- if (POLARSSL_ERR_X509_PASSWORD_REQUIRED == status)
+
+ if (POLARSSL_ERR_PK_PASSWORD_REQUIRED == status)
{
char passbuf[512] = {0};
pem_password_callback(passbuf, 512, 0, NULL);
- status = x509parse_key(ctx->priv_key,
+ status = pk_parse_key(ctx->priv_key,
(const unsigned char *) priv_key_inline, strlen(priv_key_inline),
- (const unsigned char *) passbuf, strlen(passbuf));
+ (unsigned char *) passbuf, strlen(passbuf));
}
}
else
{
- status = x509parse_keyfile(ctx->priv_key, priv_key_file, NULL);
- if (POLARSSL_ERR_X509_PASSWORD_REQUIRED == status)
+ status = pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL);
+ if (POLARSSL_ERR_PK_PASSWORD_REQUIRED == status)
{
char passbuf[512] = {0};
pem_password_callback(passbuf, 512, 0, NULL);
- status = x509parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
+ status = pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
}
}
if (0 != status)
{
#ifdef ENABLE_MANAGEMENT
- if (management && (POLARSSL_ERR_X509_PASSWORD_MISMATCH == status))
+ if (management && (POLARSSL_ERR_PK_PASSWORD_MISMATCH == status))
management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
#endif
msg (M_WARN, "Cannot load private key file %s", priv_key_file);
@@ -323,43 +353,43 @@ struct external_context {
size_t signature_length;
};
-int
-tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
- const char *cert_file, const char *cert_file_inline)
-{
- ASSERT(NULL != ctx);
-
- tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline);
-
- if (ctx->crt_chain == NULL)
- return 0;
-
- /* Most of the initialization happens in key_state_ssl_init() */
- ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context);
- ctx->external_key->signature_length = ctx->crt_chain->rsa.len;
-
- return 1;
-}
-
+/**
+ * external_pkcs1_sign implements a PolarSSL rsa_sign_func callback, that uses
+ * the management interface to request an RSA signature for the supplied hash.
+ *
+ * @param ctx_voidptr Management external key context.
+ * @param f_rng (Unused)
+ * @param p_rng (Unused)
+ * @param mode RSA mode (should be RSA_PRIVATE).
+ * @param md_alg Message digest ('hash') algorithm type.
+ * @param hashlen Length of hash (overridden by length specified by md_alg
+ * if md_alg != POLARSSL_MD_NONE).
+ * @param hash The digest ('hash') to sign. Should have a size
+ * matching the length of md_alg (if != POLARSSL_MD_NONE),
+ * or hashlen otherwise.
+ * @param sig Buffer that returns the signature. Should be at least of
+ * size ctx->signature_length.
+ *
+ * @return 0 on success, non-zero polarssl error code on failure.
+ */
static inline int external_pkcs1_sign( void *ctx_voidptr,
int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode,
- int hash_id, unsigned int hashlen, const unsigned char *hash,
+ md_type_t md_alg, unsigned int hashlen, const unsigned char *hash,
unsigned char *sig )
{
struct external_context * const ctx = ctx_voidptr;
char *in_b64 = NULL;
char *out_b64 = NULL;
int rv;
- unsigned char * const p = sig;
- size_t asn_len;
+ unsigned char *p = sig;
+ size_t asn_len = 0, oid_size = 0, sig_len = 0;
+ const char *oid = NULL;
- ASSERT(NULL != ctx);
+ if( NULL == ctx )
+ return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
- if (RSA_PRIVATE != mode)
- {
- rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA;
- goto done;
- }
+ if( RSA_PRIVATE != mode )
+ return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
/*
* Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW,
@@ -367,67 +397,54 @@ static inline int external_pkcs1_sign( void *ctx_voidptr,
*
* This code has been taken from PolarSSL pkcs11_sign(), under the GPLv2.0+.
*/
- switch( hash_id )
- {
- case SIG_RSA_RAW:
- asn_len = 0;
- memcpy( p, hash, hashlen );
- break;
-
- case SIG_RSA_MD2:
- asn_len = OID_SIZE(ASN1_HASH_MDX);
- memcpy( p, ASN1_HASH_MDX, asn_len );
- memcpy( p + asn_len, hash, hashlen );
- p[13] = 2; break;
-
- case SIG_RSA_MD4:
- asn_len = OID_SIZE(ASN1_HASH_MDX);
- memcpy( p, ASN1_HASH_MDX, asn_len );
- memcpy( p + asn_len, hash, hashlen );
- p[13] = 4; break;
-
- case SIG_RSA_MD5:
- asn_len = OID_SIZE(ASN1_HASH_MDX);
- memcpy( p, ASN1_HASH_MDX, asn_len );
- memcpy( p + asn_len, hash, hashlen );
- p[13] = 5; break;
-
- case SIG_RSA_SHA1:
- asn_len = OID_SIZE(ASN1_HASH_SHA1);
- memcpy( p, ASN1_HASH_SHA1, asn_len );
- memcpy( p + 15, hash, hashlen );
- break;
-
- case SIG_RSA_SHA224:
- asn_len = OID_SIZE(ASN1_HASH_SHA2X);
- memcpy( p, ASN1_HASH_SHA2X, asn_len );
- memcpy( p + asn_len, hash, hashlen );
- p[1] += hashlen; p[14] = 4; p[18] += hashlen; break;
-
- case SIG_RSA_SHA256:
- asn_len = OID_SIZE(ASN1_HASH_SHA2X);
- memcpy( p, ASN1_HASH_SHA2X, asn_len );
- memcpy( p + asn_len, hash, hashlen );
- p[1] += hashlen; p[14] = 1; p[18] += hashlen; break;
-
- case SIG_RSA_SHA384:
- asn_len = OID_SIZE(ASN1_HASH_SHA2X);
- memcpy( p, ASN1_HASH_SHA2X, asn_len );
- memcpy( p + asn_len, hash, hashlen );
- p[1] += hashlen; p[14] = 2; p[18] += hashlen; break;
-
- case SIG_RSA_SHA512:
- asn_len = OID_SIZE(ASN1_HASH_SHA2X);
- memcpy( p, ASN1_HASH_SHA2X, asn_len );
- memcpy( p + asn_len, hash, hashlen );
- p[1] += hashlen; p[14] = 3; p[18] += hashlen; break;
-
- /* End of copy */
- default:
- rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA;
- goto done;
+ if( md_alg != POLARSSL_MD_NONE )
+ {
+ const md_info_t *md_info = md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+ if( oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
+ return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+ hashlen = md_get_size( md_info );
+ asn_len = 10 + oid_size;
+ }
+
+ sig_len = ctx->signature_length;
+ if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len )
+ return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+
+ if( md_alg != POLARSSL_MD_NONE )
+ {
+ /*
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * digest Digest }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ */
+ *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
+ *p++ = (unsigned char) ( 0x08 + oid_size + hashlen );
+ *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
+ *p++ = (unsigned char) ( 0x04 + oid_size );
+ *p++ = ASN1_OID;
+ *p++ = oid_size & 0xFF;
+ memcpy( p, oid, oid_size );
+ p += oid_size;
+ *p++ = ASN1_NULL;
+ *p++ = 0x00;
+ *p++ = ASN1_OCTET_STRING;
+ *p++ = hashlen;
+
+ /* Determine added ASN length */
+ asn_len = p - sig;
}
+ /* Copy the hash to be signed */
+ memcpy( p, hash, hashlen );
+
/* convert 'from' to base64 */
if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0)
{
@@ -454,7 +471,7 @@ static inline int external_pkcs1_sign( void *ctx_voidptr,
rv = 0;
- done:
+done:
if (in_b64)
free (in_b64);
if (out_b64)
@@ -468,6 +485,28 @@ static inline size_t external_key_len(void *vctx)
return ctx->signature_length;
}
+
+int
+tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
+ const char *cert_file, const char *cert_file_inline)
+{
+ ASSERT(NULL != ctx);
+
+ tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline);
+
+ if (ctx->crt_chain == NULL)
+ return 0;
+
+ ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context);
+ ctx->external_key->signature_length = pk_get_len(&ctx->crt_chain->pk);
+
+ ALLOC_OBJ_CLEAR (ctx->priv_key, pk_context);
+ if (0 != pk_init_ctx_rsa_alt(ctx->priv_key, ctx->external_key,
+ NULL, external_pkcs1_sign, external_key_len))
+ return 0;
+
+ return 1;
+}
#endif
void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
@@ -480,14 +519,14 @@ void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_inline)
{
- if (0 != x509parse_crt(ctx->ca_chain, (const unsigned char *) ca_inline,
+ if (0 != x509_crt_parse(ctx->ca_chain, (unsigned char *) ca_inline,
strlen(ca_inline)))
msg (M_FATAL, "Cannot load inline CA certificates");
}
else
{
/* Load CA file for verifying peer supplied certificate */
- if (0 != x509parse_crtfile(ctx->ca_chain, ca_file))
+ if (0 != x509_crt_parse_file(ctx->ca_chain, ca_file))
msg (M_FATAL, "Cannot load CA certificate file %s", ca_file);
}
}
@@ -499,16 +538,21 @@ tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file
{
ASSERT(NULL != ctx);
+ if (!ctx->crt_chain)
+ {
+ ALLOC_OBJ_CLEAR (ctx->crt_chain, x509_crt);
+ }
+
if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline)
{
- if (0 != x509parse_crt(ctx->crt_chain,
- (const unsigned char *) extra_certs_inline,
+ if (0 != x509_crt_parse(ctx->crt_chain,
+ (const unsigned char *) extra_certs_inline,
strlen(extra_certs_inline)))
msg (M_FATAL, "Cannot load inline extra-certs file");
}
else
{
- if (0 != x509parse_crtfile(ctx->crt_chain, extra_certs_file))
+ if (0 != x509_crt_parse_file(ctx->crt_chain, extra_certs_file))
msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file);
}
}
@@ -631,9 +675,9 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
if (NULL != ctx->crt_chain)
{
- x509_cert *cert = ctx->crt_chain;
+ x509_crt *cert = ctx->crt_chain;
- sha2(cert->tbs.p, cert->tbs.len, sha256_hash, false);
+ sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false);
if ( 0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash)))
{
ctr_drbg_update(cd_ctx, sha256_hash, 32);
@@ -707,24 +751,19 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
if (ssl_ctx->allowed_ciphers)
ssl_set_ciphersuites (ks_ssl->ctx, ssl_ctx->allowed_ciphers);
+ /* Disable record splitting (for now). OpenVPN assumes records are sent
+ * unfragmented, and changing that will require thorough review and
+ * testing. Since OpenVPN is not susceptible to BEAST, we can just
+ * disable record splitting as a quick fix. */
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+ ssl_set_cbc_record_splitting (ks_ssl->ctx, SSL_CBC_RECORD_SPLITTING_DISABLED);
+#endif /* POLARSSL_SSL_CBC_RECORD_SPLITTING */
+
/* Initialise authentication information */
if (is_server)
- ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx );
-#if defined(ENABLE_PKCS11)
- if (ssl_ctx->priv_key_pkcs11 != NULL)
- ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain,
- ssl_ctx->priv_key_pkcs11, ssl_pkcs11_decrypt, ssl_pkcs11_sign,
- ssl_pkcs11_key_len );
- else
-#endif
-#if defined(MANAGMENT_EXTERNAL_KEY)
- if (ssl_ctx->external_key != NULL)
- ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain,
- ssl_ctx->external_key, NULL, external_pkcs1_sign,
- external_key_len );
- else
-#endif
- ssl_set_own_cert( ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key );
+ ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx);
+
+ ssl_set_own_cert (ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key);
/* Initialise SSL verification */
#if P2MP_SERVER
@@ -815,8 +854,8 @@ key_state_write_plaintext (struct key_state_ssl *ks, struct buffer *buf)
if (0 == buf->len)
{
- return 0;
perf_pop ();
+ return 0;
}
retval = ssl_write(ks->ctx, BPTR(buf), buf->len);
@@ -1055,7 +1094,7 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
void
print_details (struct key_state_ssl * ks_ssl, const char *prefix)
{
- const x509_cert *cert;
+ const x509_crt *cert;
char s1[256];
char s2[256];
@@ -1068,7 +1107,7 @@ print_details (struct key_state_ssl * ks_ssl, const char *prefix)
cert = ssl_get_peer_cert(ks_ssl->ctx);
if (cert != NULL)
{
- openvpn_snprintf (s2, sizeof (s2), ", " counter_format " bit RSA", (counter_type) cert->rsa.len * 8);
+ openvpn_snprintf (s2, sizeof (s2), ", %zu bit key", pk_get_size(&cert->pk));
}
msg (D_HANDSHAKE, "%s%s", s1, s2);
diff --git a/src/openvpn/ssl_polarssl.h b/src/openvpn/ssl_polarssl.h
index fc9aa78..b80a509 100644
--- a/src/openvpn/ssl_polarssl.h
+++ b/src/openvpn/ssl_polarssl.h
@@ -33,6 +33,7 @@
#include "syshead.h"
#include <polarssl/ssl.h>
+#include <polarssl/x509_crt.h>
#if defined(ENABLE_PKCS11)
#include <polarssl/pkcs11.h>
@@ -64,9 +65,9 @@ struct tls_root_ctx {
int endpoint; /**< Whether or not this is a server or a client */
dhm_context *dhm_ctx; /**< Diffie-Helmann-Merkle context */
- x509_cert *crt_chain; /**< Local Certificate chain */
- x509_cert *ca_chain; /**< CA chain for remote verification */
- rsa_context *priv_key; /**< Local private key */
+ x509_crt *crt_chain; /**< Local Certificate chain */
+ x509_crt *ca_chain; /**< CA chain for remote verification */
+ pk_context *priv_key; /**< Local private key */
#if defined(ENABLE_PKCS11)
pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */
#endif
diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c
index 9693b81..ca69b41 100644
--- a/src/openvpn/ssl_verify.c
+++ b/src/openvpn/ssl_verify.c
@@ -619,7 +619,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep
string_replace_leading (subject, '-', '_');
/* extract the username (default is CN) */
- if (SUCCESS != x509_get_username (common_name, sizeof(common_name),
+ if (SUCCESS != backend_x509_get_username (common_name, sizeof(common_name),
opt->x509_username_field, cert))
{
if (!cert_depth)
diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h
index 6f118c9..01e453e 100644
--- a/src/openvpn/ssl_verify_backend.h
+++ b/src/openvpn/ssl_verify_backend.h
@@ -109,7 +109,7 @@ unsigned char *x509_get_sha1_hash (openvpn_x509_cert_t *cert, struct gc_arena *g
*
* @return \c FAILURE, \c or SUCCESS
*/
-result_t x509_get_username (char *common_name, int cn_len,
+result_t backend_x509_get_username (char *common_name, int cn_len,
char * x509_username_field, openvpn_x509_cert_t *peer_cert);
/*
diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c
index e1118d6..4750f02 100644
--- a/src/openvpn/ssl_verify_openssl.c
+++ b/src/openvpn/ssl_verify_openssl.c
@@ -200,7 +200,7 @@ extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out,
}
result_t
-x509_get_username (char *common_name, int cn_len,
+backend_x509_get_username (char *common_name, int cn_len,
char * x509_username_field, X509 *peer_cert)
{
#ifdef ENABLE_X509ALTUSERNAME
@@ -585,6 +585,8 @@ x509_verify_crl(const char *crl_file, X509 *peer_cert, const char *subject)
BIO *in=NULL;
int n,i;
result_t retval = FAILURE;
+ struct gc_arena gc = gc_new();
+ char *serial;
in = BIO_new_file (crl_file, "r");
@@ -609,7 +611,8 @@ x509_verify_crl(const char *crl_file, X509 *peer_cert, const char *subject)
for (i = 0; i < n; i++) {
revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(peer_cert)) == 0) {
- msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject);
+ serial = backend_x509_get_serial_hex(peer_cert, &gc);
+ msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE"));
goto end;
}
}
@@ -618,6 +621,7 @@ x509_verify_crl(const char *crl_file, X509 *peer_cert, const char *subject)
msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
end:
+ gc_free(&gc);
BIO_free(in);
if (crl)
X509_CRL_free (crl);
diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c
index f8f9ab5..ac252a3 100644
--- a/src/openvpn/ssl_verify_polarssl.c
+++ b/src/openvpn/ssl_verify_polarssl.c
@@ -38,14 +38,15 @@
#if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL)
#include "ssl_verify.h"
-#include <polarssl/error.h>
#include <polarssl/bignum.h>
+#include <polarssl/error.h>
+#include <polarssl/oid.h>
#include <polarssl/sha1.h>
#define MAX_SUBJECT_LENGTH 256
int
-verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
+verify_callback (void *session_obj, x509_crt *cert, int cert_depth,
int *flags)
{
struct tls_session *session = (struct tls_session *) session_obj;
@@ -90,8 +91,8 @@ verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
#endif
result_t
-x509_get_username (char *cn, int cn_len,
- char *x509_username_field, x509_cert *cert)
+backend_x509_get_username (char *cn, int cn_len,
+ char *x509_username_field, x509_crt *cert)
{
x509_name *name;
@@ -102,7 +103,7 @@ x509_get_username (char *cn, int cn_len,
/* Find common name */
while( name != NULL )
{
- if( memcmp( name->oid.p, OID_CN, OID_SIZE(OID_CN) ) == 0)
+ if( memcmp( name->oid.p, OID_AT_CN, OID_SIZE(OID_AT_CN) ) == 0)
break;
name = name->next;
@@ -127,8 +128,6 @@ x509_get_username (char *cn, int cn_len,
char *
backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc)
{
- int ret = 0;
- int i = 0;
char *buf = NULL;
size_t buflen = 0;
mpi serial_mpi = { 0 };
@@ -172,14 +171,14 @@ backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc)
buf = gc_malloc(len, true, gc);
- if(x509parse_serial_gets(buf, len-1, &cert->serial) < 0)
+ if(x509_serial_gets(buf, len-1, &cert->serial) < 0)
buf = NULL;
return buf;
}
unsigned char *
-x509_get_sha1_hash (x509_cert *cert, struct gc_arena *gc)
+x509_get_sha1_hash (x509_crt *cert, struct gc_arena *gc)
{
unsigned char *sha1_hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
sha1(cert->tbs.p, cert->tbs.len, sha1_hash);
@@ -187,14 +186,14 @@ x509_get_sha1_hash (x509_cert *cert, struct gc_arena *gc)
}
char *
-x509_get_subject(x509_cert *cert, struct gc_arena *gc)
+x509_get_subject(x509_crt *cert, struct gc_arena *gc)
{
char tmp_subject[MAX_SUBJECT_LENGTH] = {0};
char *subject = NULL;
int ret = 0;
- ret = x509parse_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject );
+ ret = x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject );
if (ret > 0)
{
/* Allocate the required space for the subject */
@@ -224,70 +223,28 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert)
while( name != NULL )
{
char name_expand[64+8];
+ const char *shortname;
- if( name->oid.len == 2 && memcmp( name->oid.p, OID_X520, 2 ) == 0 )
+ if( 0 == oid_get_attr_short_name(&name->oid, &shortname) )
{
- switch( name->oid.p[2] )
- {
- case X520_COMMON_NAME:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_CN",
- cert_depth); break;
-
- case X520_COUNTRY:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_C",
- cert_depth); break;
-
- case X520_LOCALITY:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_L",
- cert_depth); break;
-
- case X520_STATE:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_ST",
- cert_depth); break;
-
- case X520_ORGANIZATION:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_O",
- cert_depth); break;
-
- case X520_ORG_UNIT:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_OU",
- cert_depth); break;
-
- default:
- openvpn_snprintf (name_expand, sizeof(name_expand),
- "X509_%d_0x%02X", cert_depth, name->oid.p[2]);
- break;
- }
+ openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s",
+ cert_depth, shortname);
}
- else if( name->oid.len == 8 && memcmp( name->oid.p, OID_PKCS9, 8 ) == 0 )
- {
- switch( name->oid.p[8] )
- {
- case PKCS9_EMAIL:
- openvpn_snprintf (name_expand, sizeof(name_expand),
- "X509_%d_emailAddress", cert_depth); break;
-
- default:
- openvpn_snprintf (name_expand, sizeof(name_expand),
- "X509_%d_0x%02X", cert_depth, name->oid.p[8]);
- break;
- }
- }
- else
- {
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?",
- cert_depth);
- }
-
- for( i = 0; i < name->val.len; i++ )
+ else
+ {
+ openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?",
+ cert_depth);
+ }
+
+ for( i = 0; i < name->val.len; i++ )
{
- if( i >= (int) sizeof( s ) - 1 )
- break;
+ if( i >= (int) sizeof( s ) - 1 )
+ break;
- c = name->val.p[i];
- if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
- s[i] = '?';
- else s[i] = c;
+ c = name->val.p[i];
+ if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
+ s[i] = '?';
+ else s[i] = c;
}
s[i] = '\0';
@@ -301,7 +258,7 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert)
}
result_t
-x509_verify_ns_cert_type(const x509_cert *cert, const int usage)
+x509_verify_ns_cert_type(const x509_crt *cert, const int usage)
{
if (usage == NS_CERT_CHECK_NONE)
return SUCCESS;
@@ -316,7 +273,7 @@ x509_verify_ns_cert_type(const x509_cert *cert, const int usage)
}
result_t
-x509_verify_cert_ku (x509_cert *cert, const unsigned * const expected_ku,
+x509_verify_cert_ku (x509_crt *cert, const unsigned * const expected_ku,
int expected_len)
{
result_t fFound = FAILURE;
@@ -349,7 +306,7 @@ x509_verify_cert_ku (x509_cert *cert, const unsigned * const expected_ku,
}
result_t
-x509_verify_cert_eku (x509_cert *cert, const char * const expected_oid)
+x509_verify_cert_eku (x509_crt *cert, const char * const expected_oid)
{
result_t fFound = FAILURE;
@@ -368,8 +325,7 @@ x509_verify_cert_eku (x509_cert *cert, const char * const expected_oid)
char oid_num_str[1024];
const char *oid_str;
- oid_str = x509_oid_get_description(oid);
- if (oid_str != NULL)
+ if (0 == oid_get_extended_key_usage( oid, &oid_str ))
{
msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s",
oid_str, expected_oid);
@@ -380,7 +336,7 @@ x509_verify_cert_eku (x509_cert *cert, const char * const expected_oid)
}
}
- if (0 < x509_oid_get_numeric_string( oid_num_str,
+ if (0 < oid_get_numeric_string( oid_num_str,
sizeof (oid_num_str), oid))
{
msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s",
@@ -399,7 +355,7 @@ x509_verify_cert_eku (x509_cert *cert, const char * const expected_oid)
}
result_t
-x509_write_pem(FILE *peercert_file, x509_cert *peercert)
+x509_write_pem(FILE *peercert_file, x509_crt *peercert)
{
msg (M_WARN, "PolarSSL does not support writing peer certificate in PEM format");
return FAILURE;
@@ -409,16 +365,18 @@ x509_write_pem(FILE *peercert_file, x509_cert *peercert)
* check peer cert against CRL
*/
result_t
-x509_verify_crl(const char *crl_file, x509_cert *cert, const char *subject)
+x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject)
{
result_t retval = FAILURE;
x509_crl crl = {0};
+ struct gc_arena gc = gc_new();
+ char *serial;
- int polar_retval = x509parse_crlfile(&crl, crl_file);
+ int polar_retval = x509_crl_parse_file(&crl, crl_file);
if (polar_retval != 0)
{
char errstr[128];
- error_strerror(polar_retval, errstr, sizeof(errstr));
+ polarssl_strerror(polar_retval, errstr, sizeof(errstr));
msg (M_WARN, "CRL: cannot read CRL from file %s (%s)", crl_file, errstr);
goto end;
}
@@ -432,9 +390,10 @@ x509_verify_crl(const char *crl_file, x509_cert *cert, const char *subject)
goto end;
}
- if (0 != x509parse_revoked(cert, &crl))
+ if (0 != x509_crt_revoked(cert, &crl))
{
- msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED", subject);
+ serial = backend_x509_get_serial_hex(cert, &gc);
+ msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE"));
goto end;
}
@@ -442,6 +401,7 @@ x509_verify_crl(const char *crl_file, x509_cert *cert, const char *subject)
msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
end:
+ gc_free(&gc);
x509_crl_free(&crl);
return retval;
}
diff --git a/src/openvpn/ssl_verify_polarssl.h b/src/openvpn/ssl_verify_polarssl.h
index b259081..b5157ed 100644
--- a/src/openvpn/ssl_verify_polarssl.h
+++ b/src/openvpn/ssl_verify_polarssl.h
@@ -33,11 +33,11 @@
#include "syshead.h"
#include "misc.h"
#include "manage.h"
-#include <polarssl/x509.h>
+#include <polarssl/x509_crt.h>
#ifndef __OPENVPN_X509_CERT_T_DECLARED
#define __OPENVPN_X509_CERT_T_DECLARED
-typedef x509_cert openvpn_x509_cert_t;
+typedef x509_crt openvpn_x509_cert_t;
#endif
/** @name Function for authenticating a new connection from a remote OpenVPN peer
@@ -72,7 +72,7 @@ typedef x509_cert openvpn_x509_cert_t;
*
* @return The return value is 0 unless a fatal error occurred.
*/
-int verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
+int verify_callback (void *session_obj, x509_crt *cert, int cert_depth,
int *flags);
/** @} name Function for authenticating a new connection from a remote OpenVPN peer */
diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h
index ffba4e8..24926ae 100644
--- a/src/openvpn/syshead.h
+++ b/src/openvpn/syshead.h
@@ -47,6 +47,7 @@
#ifdef _MSC_VER // Visual Studio
#define __func__ __FUNCTION__
+#define __attribute__(x)
#endif
#if defined(__APPLE__)
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 3e20215..bb019c0 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -66,6 +66,8 @@ static void netsh_command (const struct argv *a, int n);
static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc);
+static DWORD get_adapter_index_flexible (const char *name);
+
#endif
#ifdef TARGET_SOLARIS
@@ -633,7 +635,7 @@ void delete_route_connected_v6_net(struct tuntap * tt,
* is still point to point and no layer 2 resolution is done...
*/
-char *
+const char *
create_arbitrary_remote( struct tuntap *tt, struct gc_arena * gc )
{
in_addr_t remote;
@@ -642,7 +644,7 @@ create_arbitrary_remote( struct tuntap *tt, struct gc_arena * gc )
if ( remote == tt->local ) remote ++;
- return print_in_addr_t (remote, 0, &gc);
+ return print_in_addr_t (remote, 0, gc);
}
#endif
@@ -1228,18 +1230,22 @@ do_ifconfig (struct tuntap *tt,
if ( do_ipv6 )
{
char * saved_actual;
+ char iface[64];
+ DWORD idx;
if (!strcmp (actual, "NULL"))
msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than one TAP-Windows adapter, you must also specify --dev-node");
- /* example: netsh interface ipv6 set address MyTap 2001:608:8003::d store=active */
+ idx = get_adapter_index_flexible(actual);
+ openvpn_snprintf(iface, sizeof(iface), "interface=%lu", idx);
+
+ /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */
argv_printf (&argv,
- "%s%sc interface ipv6 set address %s %s store=active",
+ "%s%sc interface ipv6 set address %s %s store=active",
get_win_sys_path(),
NETSH_PATH_SUFFIX,
- actual,
- ifconfig_ipv6_local );
-
+ win32_version_info() == WIN_XP ? actual : iface,
+ ifconfig_ipv6_local);
netsh_command (&argv, 4);
/* explicit route needed */
@@ -1249,6 +1255,8 @@ do_ifconfig (struct tuntap *tt,
*/
saved_actual = tt->actual_name;
tt->actual_name = (char*) actual;
+ /* we use adapter_index in add_route_ipv6 */
+ tt->adapter_index = idx;
add_route_connected_v6_net(tt, es);
tt->actual_name = saved_actual;
}
@@ -2389,7 +2397,6 @@ close_tun (struct tuntap *tt)
}
else if (tt) /* close and destroy */
{
- struct gc_arena gc = gc_new ();
struct argv argv;
/* setup command, close tun dev (clears tt->actual_name!), run command
diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c
index f35c96b..6c6ac4c 100644
--- a/src/openvpn/win32.c
+++ b/src/openvpn/win32.c
@@ -46,6 +46,34 @@
#include "memdbg.h"
+#include "win32_wfp.h"
+
+#ifdef HAVE_VERSIONHELPERS_H
+#include <versionhelpers.h>
+#else
+#include "compat-versionhelpers.h"
+#endif
+
+/* WFP function pointers. Initialized in win_wfp_init_funcs() */
+func_ConvertInterfaceIndexToLuid ConvertInterfaceIndexToLuid = NULL;
+func_FwpmEngineOpen0 FwpmEngineOpen0 = NULL;
+func_FwpmEngineClose0 FwpmEngineClose0 = NULL;
+func_FwpmFilterAdd0 FwpmFilterAdd0 = NULL;
+func_FwpmSubLayerAdd0 FwpmSubLayerAdd0 = NULL;
+func_FwpmSubLayerDeleteByKey0 FwpmSubLayerDeleteByKey0 = NULL;
+func_FwpmFreeMemory0 FwpmFreeMemory0 = NULL;
+func_FwpmGetAppIdFromFileName0 FwpmGetAppIdFromFileName0 = NULL;
+
+/*
+ * WFP firewall name.
+ */
+WCHAR * FIREWALL_NAME = L"OpenVPN"; /* GLOBAL */
+
+/*
+ * WFP handle and GUID.
+ */
+static HANDLE m_hEngineHandle = NULL; /* GLOBAL */
+
/*
* Windows internal socket API state (opaque).
*/
@@ -324,6 +352,53 @@ net_event_win32_close (struct net_event_win32 *ne)
* (2) Service mode -- map Windows event object to SIGTERM
*/
+static void
+win_trigger_event(struct win32_signal *ws)
+{
+ if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED(ws->in.read))
+ SetEvent (ws->in.read);
+ else /* generate a key-press event */
+ {
+ DWORD tmp;
+ INPUT_RECORD ir;
+ HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
+
+ CLEAR(ir);
+ ir.EventType = KEY_EVENT;
+ ir.Event.KeyEvent.bKeyDown = true;
+ if (!stdin_handle || !WriteConsoleInput(stdin_handle, &ir, 1, &tmp))
+ msg(M_WARN|M_ERRNO, "WARN: win_trigger_event: WriteConsoleInput");
+ }
+}
+
+/*
+ * Callback to handle console ctrl events
+ */
+static bool WINAPI
+win_ctrl_handler (DWORD signum)
+{
+ msg(D_LOW, "win_ctrl_handler: signal received (code=%lu)", (unsigned long) signum);
+
+ if (siginfo_static.signal_received == SIGTERM)
+ return true;
+
+ switch (signum)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ throw_signal(SIGTERM);
+ /* trigget the win32_signal to interrupt the event loop */
+ win_trigger_event(&win32_signal);
+ return true;
+ break;
+ default:
+ msg(D_LOW, "win_ctrl_handler: signal (code=%lu) not handled", (unsigned long) signum);
+ break;
+ }
+ /* pass all other signals to the next handler */
+ return false;
+}
+
void
win32_signal_clear (struct win32_signal *ws)
{
@@ -403,6 +478,9 @@ win32_signal_open (struct win32_signal *ws,
ws->mode = WSO_MODE_SERVICE;
}
}
+ /* set the ctrl handler in both console and service modes */
+ if (!SetConsoleCtrlHandler ((PHANDLER_ROUTINE) win_ctrl_handler, true))
+ msg (M_WARN|M_ERRNO, "WARN: SetConsoleCtrlHandler failed");
}
static bool
@@ -512,6 +590,9 @@ win32_signal_get (struct win32_signal *ws)
case 0x3E: /* F4 -> TERM */
ret = SIGTERM;
break;
+ case 0x03: /* CTRL-C -> TERM */
+ ret = SIGTERM;
+ break;
}
}
if (ret)
@@ -763,7 +844,12 @@ win_safe_filename (const char *fn)
static char *
env_block (const struct env_set *es)
{
- char * force_path = "PATH=C:\\Windows\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem";
+ char force_path[256];
+ char *sysroot = get_win_sys_path();
+
+ if (!openvpn_snprintf(force_path, sizeof(force_path), "PATH=%s\\System32;%s;%s\\System32\\Wbem",
+ sysroot, sysroot, sysroot))
+ msg(M_WARN, "env_block: default path truncated to %s", force_path);
if (es)
{
@@ -1019,4 +1105,251 @@ win_get_tempdir()
WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), NULL, NULL);
return tmpdir;
}
+
+bool
+win_wfp_init_funcs ()
+{
+ /* Initialize all WFP-related function pointers */
+ HMODULE iphlpapiHandle;
+ HMODULE fwpuclntHandle;
+
+ iphlpapiHandle = LoadLibrary("iphlpapi.dll");
+ if (iphlpapiHandle == NULL)
+ {
+ msg (M_NONFATAL, "Can't load iphlpapi.dll");
+ return false;
+ }
+
+ fwpuclntHandle = LoadLibrary("fwpuclnt.dll");
+ if (fwpuclntHandle == NULL)
+ {
+ msg (M_NONFATAL, "Can't load fwpuclnt.dll");
+ return false;
+ }
+
+ ConvertInterfaceIndexToLuid = (func_ConvertInterfaceIndexToLuid)GetProcAddress(iphlpapiHandle, "ConvertInterfaceIndexToLuid");
+ FwpmFilterAdd0 = (func_FwpmFilterAdd0)GetProcAddress(fwpuclntHandle, "FwpmFilterAdd0");
+ FwpmEngineOpen0 = (func_FwpmEngineOpen0)GetProcAddress(fwpuclntHandle, "FwpmEngineOpen0");
+ FwpmEngineClose0 = (func_FwpmEngineClose0)GetProcAddress(fwpuclntHandle, "FwpmEngineClose0");
+ FwpmSubLayerAdd0 = (func_FwpmSubLayerAdd0)GetProcAddress(fwpuclntHandle, "FwpmSubLayerAdd0");
+ FwpmSubLayerDeleteByKey0 = (func_FwpmSubLayerDeleteByKey0)GetProcAddress(fwpuclntHandle, "FwpmSubLayerDeleteByKey0");
+ FwpmFreeMemory0 = (func_FwpmFreeMemory0)GetProcAddress(fwpuclntHandle, "FwpmFreeMemory0");
+ FwpmGetAppIdFromFileName0 = (func_FwpmGetAppIdFromFileName0)GetProcAddress(fwpuclntHandle, "FwpmGetAppIdFromFileName0");
+
+ if (!ConvertInterfaceIndexToLuid ||
+ !FwpmFilterAdd0 ||
+ !FwpmEngineOpen0 ||
+ !FwpmEngineClose0 ||
+ !FwpmSubLayerAdd0 ||
+ !FwpmSubLayerDeleteByKey0 ||
+ !FwpmFreeMemory0 ||
+ !FwpmGetAppIdFromFileName0)
+ {
+ msg (M_NONFATAL, "Can't get address for all WFP-related procedures.");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+win_wfp_add_filter (HANDLE engineHandle,
+ const FWPM_FILTER0 *filter,
+ PSECURITY_DESCRIPTOR sd,
+ UINT64 *id)
+{
+ if (FwpmFilterAdd0(engineHandle, filter, sd, id) != ERROR_SUCCESS)
+ {
+ msg (M_NONFATAL, "Can't add WFP filter");
+ return false;
+ }
+ return true;
+}
+
+bool
+win_wfp_block_dns (const NET_IFINDEX index)
+{
+ FWPM_SESSION0 session = {0};
+ FWPM_SUBLAYER0 SubLayer = {0};
+ NET_LUID tapluid;
+ UINT64 filterid;
+ WCHAR openvpnpath[MAX_PATH];
+ FWP_BYTE_BLOB *openvpnblob = NULL;
+ FWPM_FILTER0 Filter = {0};
+ FWPM_FILTER_CONDITION0 Condition[2] = {0};
+
+ /* Add temporary filters which don't survive reboots or crashes. */
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ dmsg (D_LOW, "Opening WFP engine");
+
+ if (FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &m_hEngineHandle) != ERROR_SUCCESS)
+ {
+ msg (M_NONFATAL, "Can't open WFP engine");
+ return false;
+ }
+
+ if (UuidCreate(&SubLayer.subLayerKey) != NO_ERROR)
+ return false;
+
+ /* Populate packet filter layer information. */
+ SubLayer.displayData.name = FIREWALL_NAME;
+ SubLayer.displayData.description = FIREWALL_NAME;
+ SubLayer.flags = 0;
+ SubLayer.weight = 0x100;
+
+ /* Add packet filter to our interface. */
+ dmsg (D_LOW, "Adding WFP sublayer");
+ if (FwpmSubLayerAdd0(m_hEngineHandle, &SubLayer, NULL) != ERROR_SUCCESS)
+ {
+ msg (M_NONFATAL, "Can't add WFP sublayer");
+ return false;
+ }
+
+ dmsg (D_LOW, "Blocking DNS using WFP");
+ if (ConvertInterfaceIndexToLuid(index, &tapluid) != NO_ERROR)
+ {
+ msg (M_NONFATAL, "Can't convert interface index to LUID");
+ return false;
+ }
+ dmsg (D_LOW, "Tap Luid: %I64d", tapluid.Value);
+
+ /* Get OpenVPN path. */
+ GetModuleFileNameW(NULL, openvpnpath, MAX_PATH);
+
+ if (FwpmGetAppIdFromFileName0(openvpnpath, &openvpnblob) != ERROR_SUCCESS)
+ return false;
+
+ /* Prepare filter. */
+ Filter.subLayerKey = SubLayer.subLayerKey;
+ Filter.displayData.name = FIREWALL_NAME;
+ Filter.weight.type = FWP_EMPTY;
+ Filter.filterCondition = Condition;
+ Filter.numFilterConditions = 2;
+
+ /* First filter. Block IPv4 DNS queries except from OpenVPN itself. */
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
+ Filter.action.type = FWP_ACTION_BLOCK;
+
+ Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
+ Condition[0].matchType = FWP_MATCH_EQUAL;
+ Condition[0].conditionValue.type = FWP_UINT16;
+ Condition[0].conditionValue.uint16 = 53;
+
+ Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID;
+ Condition[1].matchType = FWP_MATCH_NOT_EQUAL;
+ Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE;
+ Condition[1].conditionValue.byteBlob = openvpnblob;
+
+ /* Add filter condition to our interface. */
+ if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
+ goto err;
+ dmsg (D_LOW, "Filter (Block IPv4 DNS) added with ID=%I64d", filterid);
+
+ /* Second filter. Block IPv6 DNS queries except from OpenVPN itself. */
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
+
+ /* Add filter condition to our interface. */
+ if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
+ goto err;
+ dmsg (D_LOW, "Filter (Block IPv6 DNS) added with ID=%I64d", filterid);
+
+ /* Third filter. Permit IPv4 DNS queries from TAP. */
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
+ Filter.action.type = FWP_ACTION_PERMIT;
+
+ Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE;
+ Condition[1].matchType = FWP_MATCH_EQUAL;
+ Condition[1].conditionValue.type = FWP_UINT64;
+ Condition[1].conditionValue.uint64 = &tapluid.Value;
+
+ /* Add filter condition to our interface. */
+ if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
+ goto err;
+ dmsg (D_LOW, "Filter (Permit IPv4 DNS queries from TAP) added with ID=%I64d", filterid);
+
+ /* Forth filter. Permit IPv6 DNS queries from TAP. */
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
+
+ /* Add filter condition to our interface. */
+ if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
+ goto err;
+ dmsg (D_LOW, "Filter (Permit IPv6 DNS queries from TAP) added with ID=%I64d", filterid);
+
+ FwpmFreeMemory0((void **)&openvpnblob);
+ return true;
+
+ err:
+ FwpmFreeMemory0((void **)&openvpnblob);
+ return false;
+}
+
+bool
+win_wfp_uninit()
+{
+ dmsg (D_LOW, "Uninitializing WFP");
+ if (m_hEngineHandle) {
+ FwpmEngineClose0(m_hEngineHandle);
+ m_hEngineHandle = NULL;
+ }
+ return true;
+}
+
+int
+win32_version_info()
+{
+ if (!IsWindowsXPOrGreater())
+ {
+ msg (M_FATAL, "Error: Windows version must be XP or greater.");
+ }
+
+ if (!IsWindowsVistaOrGreater())
+ {
+ return WIN_XP;
+ }
+
+ if (!IsWindows7OrGreater())
+ {
+ return WIN_VISTA;
+ }
+
+ if (!IsWindows8OrGreater())
+ {
+ return WIN_7;
+ }
+ else
+ {
+ return WIN_8;
+ }
+}
+
+const char *
+win32_version_string(struct gc_arena *gc, bool add_name)
+{
+ int version = win32_version_info();
+ struct buffer out = alloc_buf_gc (256, gc);
+
+ switch (version)
+ {
+ case WIN_XP:
+ buf_printf (&out, "5.1%s", add_name ? " (Windows XP)" : "");
+ break;
+ case WIN_VISTA:
+ buf_printf (&out, "6.0%s", add_name ? " (Windows Vista)" : "");
+ break;
+ case WIN_7:
+ buf_printf (&out, "6.1%s", add_name ? " (Windows 7)" : "");
+ break;
+ case WIN_8:
+ buf_printf (&out, "6.2%s", add_name ? " (Windows 8 or greater)" : "");
+ break;
+ default:
+ msg (M_NONFATAL, "Unknown Windows version: %d", version);
+ buf_printf (&out, "0.0%s", add_name ? " (unknown)" : "");
+ break;
+ }
+
+ return (const char *)out.data;
+}
+
#endif
diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h
index cc18f02..0990182 100644
--- a/src/openvpn/win32.h
+++ b/src/openvpn/win32.h
@@ -271,5 +271,22 @@ const char *win_get_tempdir();
/* Convert a string from UTF-8 to UCS-2 */
WCHAR *wide_string (const char* utf8, struct gc_arena *gc);
+bool win_wfp_init_funcs();
+bool win_wfp_block_dns(const NET_IFINDEX index);
+bool win_wfp_uninit();
+
+#define WIN_XP 0
+#define WIN_VISTA 1
+#define WIN_7 2
+#define WIN_8 3
+
+int win32_version_info();
+
+/*
+String representation of Windows version number and name, see
+https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx
+*/
+const char * win32_version_string(struct gc_arena *gc, bool add_name);
+
#endif
#endif
diff --git a/src/openvpn/win32_wfp.h b/src/openvpn/win32_wfp.h
new file mode 100644
index 0000000..7559e5b
--- /dev/null
+++ b/src/openvpn/win32_wfp.h
@@ -0,0 +1,359 @@
+/*
+ This Software is provided under the Zope Public License (ZPL) Version 2.1.
+
+ Copyright (c) 2009, 2010 by the mingw-w64 project
+
+ See the AUTHORS file for the list of contributors to the mingw-w64 project.
+
+ This license has been certified as open source. It has also been designated
+ as GPL compatible by the Free Software Foundation (FSF).
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions in source code must retain the accompanying copyright
+ notice, this list of conditions, and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the accompanying
+ copyright notice, this list of conditions, and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+ 3. Names of the copyright holders must not be used to endorse or promote
+ products derived from this software without prior written permission
+ from the copyright holders.
+ 4. The right to distribute this software or to use it for any purpose does
+ not give you the right to use Servicemarks (sm) or Trademarks (tm) of
+ the copyright holders. Use of them is covered by separate agreement
+ with the copyright holders.
+ 5. If any files are modified, you must cause the modified files to carry
+ prominent notices stating that you changed the files and the date of
+ any change.
+
+ Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Windows Filtering Platform (WFP) related prototypes, mostly stripped out of
+ * mingw-w64.
+ */
+
+/*
+ * WFP-related defines and GUIDs.
+ */
+
+#ifndef WIN32_WFP_H
+#define WIN32_WFP_H
+
+#include <initguid.h>
+#include <iphlpapi.h>
+#include <rpc.h>
+#include <rpcdce.h>
+
+#ifndef FWPM_SESSION_FLAG_DYNAMIC
+#define FWPM_SESSION_FLAG_DYNAMIC 0x00000001
+#endif
+
+// c38d57d1-05a7-4c33-904f-7fbceee60e82
+DEFINE_GUID(
+ FWPM_LAYER_ALE_AUTH_CONNECT_V4,
+ 0xc38d57d1,
+ 0x05a7,
+ 0x4c33,
+ 0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82
+);
+
+// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4
+DEFINE_GUID(
+ FWPM_LAYER_ALE_AUTH_CONNECT_V6,
+ 0x4a72393b,
+ 0x319f,
+ 0x44bc,
+ 0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4
+);
+
+// d78e1e87-8644-4ea5-9437-d809ecefc971
+DEFINE_GUID(
+ FWPM_CONDITION_ALE_APP_ID,
+ 0xd78e1e87,
+ 0x8644,
+ 0x4ea5,
+ 0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71
+);
+
+// c35a604d-d22b-4e1a-91b4-68f674ee674b
+DEFINE_GUID(
+ FWPM_CONDITION_IP_REMOTE_PORT,
+ 0xc35a604d,
+ 0xd22b,
+ 0x4e1a,
+ 0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b
+);
+
+// 4cd62a49-59c3-4969-b7f3-bda5d32890a4
+DEFINE_GUID(
+ FWPM_CONDITION_IP_LOCAL_INTERFACE,
+ 0x4cd62a49,
+ 0x59c3,
+ 0x4969,
+ 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4
+);
+
+/* From fwptypes.h */
+
+#define FWP_ACTION_FLAG_TERMINATING (0x00001000)
+#define FWP_ACTION_FLAG_NON_TERMINATING (0x00002000)
+
+#define FWP_ACTION_BLOCK (0x1 | FWP_ACTION_FLAG_TERMINATING)
+#define FWP_ACTION_PERMIT (0x2 | FWP_ACTION_FLAG_TERMINATING)
+
+typedef UINT32 FWP_ACTION_TYPE;
+
+typedef enum FWP_DATA_TYPE_ {
+ FWP_EMPTY = 0,
+ FWP_UINT8 = 1,
+ FWP_UINT16 = 2,
+ FWP_UINT32 = 3,
+ FWP_UINT64 = 4,
+ FWP_INT8 = 5,
+ FWP_INT16 = 6,
+ FWP_INT32 = 7,
+ FWP_INT64 = 8,
+ FWP_FLOAT = 9,
+ FWP_DOUBLE = 10,
+ FWP_BYTE_ARRAY16_TYPE = 11,
+ FWP_BYTE_BLOB_TYPE = 12,
+ FWP_SID = 13,
+ FWP_SECURITY_DESCRIPTOR_TYPE = 14,
+ FWP_TOKEN_INFORMATION_TYPE = 15,
+ FWP_TOKEN_ACCESS_INFORMATION_TYPE = 16,
+ FWP_UNICODE_STRING_TYPE = 17,
+ FWP_BYTE_ARRAY6_TYPE = 18,
+ FWP_SINGLE_DATA_TYPE_MAX = 0xff,
+ FWP_V4_ADDR_MASK = 0x100,
+ FWP_V6_ADDR_MASK = 0x101,
+ FWP_RANGE_TYPE = 0x102,
+ FWP_DATA_TYPE_MAX = 0x103
+} FWP_DATA_TYPE;
+
+typedef enum FWP_MATCH_TYPE_ {
+ FWP_MATCH_EQUAL = 0,
+ FWP_MATCH_GREATER = 1,
+ FWP_MATCH_LESS = 2,
+ FWP_MATCH_GREATER_OR_EQUAL = 3,
+ FWP_MATCH_LESS_OR_EQUAL = 4,
+ FWP_MATCH_RANGE = 5,
+ FWP_MATCH_FLAGS_ALL_SET = 6,
+ FWP_MATCH_FLAGS_ANY_SET = 7,
+ FWP_MATCH_FLAGS_NONE_SET = 8,
+ FWP_MATCH_EQUAL_CASE_INSENSITIVE = 9,
+ FWP_MATCH_NOT_EQUAL = 10,
+ FWP_MATCH_TYPE_MAX = 11
+} FWP_MATCH_TYPE;
+
+typedef struct FWP_BYTE_ARRAY6_ {
+ UINT8 byteArray6[6];
+} FWP_BYTE_ARRAY6;
+
+typedef struct FWP_BYTE_ARRAY16_ {
+ UINT8 byteArray16[16];
+} FWP_BYTE_ARRAY16;
+
+typedef struct FWP_BYTE_BLOB_ {
+ UINT32 size;
+ UINT8 *data;
+} FWP_BYTE_BLOB;
+
+typedef struct FWP_TOKEN_INFORMATION_ {
+ ULONG sidCount;
+ PSID_AND_ATTRIBUTES sids;
+ ULONG restrictedSidCount;
+ PSID_AND_ATTRIBUTES restrictedSids;
+} FWP_TOKEN_INFORMATION;
+
+typedef struct FWP_VALUE0_ {
+ FWP_DATA_TYPE type;
+ union {
+ UINT8 uint8;
+ UINT16 uint16;
+ UINT32 uint32;
+ UINT64 *uint64;
+ INT8 int8;
+ INT16 int16;
+ INT32 int32;
+ INT64 *int64;
+ float float32;
+ double *double64;
+ FWP_BYTE_ARRAY16 *byteArray16;
+ FWP_BYTE_BLOB *byteBlob;
+ SID *sid;
+ FWP_BYTE_BLOB *sd;
+ FWP_TOKEN_INFORMATION *tokenInformation;
+ FWP_BYTE_BLOB *tokenAccessInformation;
+ LPWSTR unicodeString;
+ FWP_BYTE_ARRAY6 *byteArray6;
+ };
+} FWP_VALUE0;
+
+typedef struct FWP_V4_ADDR_AND_MASK_ {
+ UINT32 addr;
+ UINT32 mask;
+} FWP_V4_ADDR_AND_MASK;
+
+typedef struct FWP_V6_ADDR_AND_MASK_ {
+ UINT8 addr[16];
+ UINT8 prefixLength;
+} FWP_V6_ADDR_AND_MASK;
+
+typedef struct FWP_RANGE0_ {
+ FWP_VALUE0 valueLow;
+ FWP_VALUE0 valueHigh;
+} FWP_RANGE0;
+
+typedef struct FWP_CONDITION_VALUE0_ {
+ FWP_DATA_TYPE type;
+ union {
+ UINT8 uint8;
+ UINT16 uint16;
+ UINT32 uint32;
+ UINT64 *uint64;
+ INT8 int8;
+ INT16 int16;
+ INT32 int32;
+ INT64 *int64;
+ float float32;
+ double *double64;
+ FWP_BYTE_ARRAY16 *byteArray16;
+ FWP_BYTE_BLOB *byteBlob;
+ SID *sid;
+ FWP_BYTE_BLOB *sd;
+ FWP_TOKEN_INFORMATION *tokenInformation;
+ FWP_BYTE_BLOB *tokenAccessInformation;
+ LPWSTR unicodeString;
+ FWP_BYTE_ARRAY6 *byteArray6;
+ FWP_V4_ADDR_AND_MASK *v4AddrMask;
+ FWP_V6_ADDR_AND_MASK *v6AddrMask;
+ FWP_RANGE0 *rangeValue;
+ };
+} FWP_CONDITION_VALUE0;
+
+typedef struct FWPM_DISPLAY_DATA0_ {
+ wchar_t *name;
+ wchar_t *description;
+} FWPM_DISPLAY_DATA0;
+
+/* From fwpmtypes.h */
+
+typedef struct FWPM_ACTION0_ {
+ FWP_ACTION_TYPE type;
+ union {
+ GUID filterType;
+ GUID calloutKey;
+ };
+} FWPM_ACTION0;
+
+typedef struct FWPM_SESSION0_ {
+ GUID sessionKey;
+ FWPM_DISPLAY_DATA0 displayData;
+ UINT32 flags;
+ UINT32 txnWaitTimeoutInMSec;
+ DWORD processId;
+ SID *sid;
+ wchar_t *username;
+ BOOL kernelMode;
+} FWPM_SESSION0;
+
+typedef struct FWPM_SUBLAYER0_ {
+ GUID subLayerKey;
+ FWPM_DISPLAY_DATA0 displayData;
+ UINT16 flags;
+ GUID *providerKey;
+ FWP_BYTE_BLOB providerData;
+ UINT16 weight;
+} FWPM_SUBLAYER0;
+
+typedef struct FWPM_FILTER_CONDITION0_ {
+ GUID fieldKey;
+ FWP_MATCH_TYPE matchType;
+ FWP_CONDITION_VALUE0 conditionValue;
+} FWPM_FILTER_CONDITION0;
+
+typedef struct FWPM_FILTER0_ {
+ GUID filterKey;
+ FWPM_DISPLAY_DATA0 displayData;
+ UINT32 flags;
+ GUID *providerKey;
+ FWP_BYTE_BLOB providerData;
+ GUID layerKey;
+ GUID subLayerKey;
+ FWP_VALUE0 weight;
+ UINT32 numFilterConditions;
+ FWPM_FILTER_CONDITION0 *filterCondition;
+ FWPM_ACTION0 action;
+ union {
+ UINT64 rawContext;
+ GUID providerContextKey;
+ };
+ GUID *reserved;
+ UINT64 filterId;
+ FWP_VALUE0 effectiveWeight;
+} FWPM_FILTER0;
+
+/* Typedefs of WFP functions */
+
+#define NETIO_STATUS DWORD
+
+typedef NETIO_STATUS *(WINAPI *func_ConvertInterfaceIndexToLuid)(
+ NET_IFINDEX InterfaceIndex,
+ PNET_LUID InterfaceLuid
+);
+
+typedef DWORD *(WINAPI *func_FwpmEngineOpen0)(
+ const wchar_t *serverName,
+ UINT32 authnService,
+ SEC_WINNT_AUTH_IDENTITY_W *authIdentity,
+ const FWPM_SESSION0 *session,
+ HANDLE *engineHandle
+);
+
+typedef DWORD *(WINAPI *func_FwpmEngineClose0)(
+ HANDLE engineHandle
+);
+
+typedef DWORD *(WINAPI *func_FwpmFilterAdd0)(
+ HANDLE engineHandle,
+ const FWPM_FILTER0 *filter,
+ PSECURITY_DESCRIPTOR sd,
+ UINT64 *id
+);
+
+typedef DWORD *(WINAPI *func_FwpmSubLayerAdd0)(
+ HANDLE engineHandle,
+ const FWPM_SUBLAYER0 *subLayer,
+ PSECURITY_DESCRIPTOR sd
+);
+
+typedef DWORD *(WINAPI *func_FwpmSubLayerDeleteByKey0)(
+ HANDLE engineHandle,
+ const GUID *key
+);
+
+typedef void *(WINAPI *func_FwpmFreeMemory0)(
+ void **p
+);
+
+typedef DWORD *(WINAPI *func_FwpmGetAppIdFromFileName0)(
+ const wchar_t *fileName,
+ FWP_BYTE_BLOB **appId
+);
+
+#endif