aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am12
-rw-r--r--buffer.c34
-rw-r--r--buffer.h2
-rw-r--r--common.h2
-rw-r--r--configure.ac9
-rw-r--r--configure_h.awk39
-rw-r--r--configure_log.awk33
-rwxr-xr-xeasy-rsa/2.0/pkitool6
-rw-r--r--error.c14
-rw-r--r--init.c24
-rw-r--r--misc.c7
-rw-r--r--misc.h10
-rw-r--r--multi.c6
-rw-r--r--openvpn.842
-rw-r--r--options.c78
-rw-r--r--options.h4
-rw-r--r--proxy.c7
-rw-r--r--route.c53
-rw-r--r--socket.c35
-rw-r--r--socket.h12
-rw-r--r--ssl.c146
-rw-r--r--ssl.h10
-rw-r--r--syshead.h4
-rwxr-xr-xtap-win32/proto.h60
-rwxr-xr-xtap-win32/tapdrvr.c197
-rwxr-xr-xtap-win32/types.h1
-rw-r--r--tun.c59
-rw-r--r--tun.h5
-rw-r--r--version.m42
-rw-r--r--win/build_exe.py15
-rw-r--r--win/config.py1
-rw-r--r--win/make_dist.py44
-rw-r--r--win/msvc.mak.in19
-rw-r--r--win/settings.in3
-rw-r--r--win32.c13
-rw-r--r--win32.h2
36 files changed, 871 insertions, 139 deletions
diff --git a/Makefile.am b/Makefile.am
index 2980dac..75f9b1a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,6 +6,7 @@
# packet compression.
#
# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
+# Copyright (C) 2010 David Sommerseth <dazo@users.sourceforge.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
@@ -37,7 +38,7 @@ MAINTAINERCLEANFILES = \
$(srcdir)/depcomp $(srcdir)/aclocal.m4 \
$(srcdir)/config.guess $(srcdir)/config.sub \
$(srcdir)/openvpn.spec
-CLEANFILES = openvpn.8.html
+CLEANFILES = openvpn.8.html configure.h
EXTRA_DIST = \
easy-rsa \
@@ -64,7 +65,8 @@ dist_noinst_SCRIPTS = \
$(TESTS) \
doclean \
domake-win \
- t_cltsrv-down.sh
+ t_cltsrv-down.sh \
+ configure_h.awk configure_log.awk
dist_noinst_DATA = \
openvpn.spec \
@@ -140,6 +142,12 @@ openvpn_SOURCES = \
win32.h win32.c \
cryptoapi.h cryptoapi.c
+nodist_openvpn_SOURCES = configure.h
+options.$(OBJEXT): configure.h
+
+configure.h: Makefile
+ awk -f $(srcdir)/configure_h.awk config.h > $@
+ awk -f $(srcdir)/configure_log.awk config.log >> $@
dist-hook:
cd $(distdir) && for i in $(EXTRA_DIST) $(SUBDIRS) ; do find $$i -name .svn -type d -prune -exec rm -rf '{}' ';' ; rm -f `find $$i -type f | grep -E '(^|\/)\.?\#|\~$$|\.s?o$$'` ; done
diff --git a/buffer.c b/buffer.c
index c7a42fb..5108429 100644
--- a/buffer.c
+++ b/buffer.c
@@ -896,8 +896,11 @@ buffer_list_new (const int max_size)
void
buffer_list_free (struct buffer_list *ol)
{
- buffer_list_reset (ol);
- free (ol);
+ if (ol)
+ {
+ buffer_list_reset (ol);
+ free (ol);
+ }
}
bool
@@ -924,9 +927,21 @@ buffer_list_reset (struct buffer_list *ol)
void
buffer_list_push (struct buffer_list *ol, const unsigned char *str)
{
- if (!ol->max_size || ol->size < ol->max_size)
+ if (str)
+ {
+ const size_t len = strlen ((const char *)str);
+ struct buffer_entry *e = buffer_list_push_data (ol, str, len+1);
+ if (e)
+ e->buf.len = len; /* Don't count trailing '\0' as part of length */
+ }
+}
+
+struct buffer_entry *
+buffer_list_push_data (struct buffer_list *ol, const uint8_t *data, size_t size)
+{
+ struct buffer_entry *e = NULL;
+ if (data && (!ol->max_size || ol->size < ol->max_size))
{
- struct buffer_entry *e;
ALLOC_OBJ_CLEAR (e, struct buffer_entry);
++ol->size;
@@ -940,15 +955,18 @@ buffer_list_push (struct buffer_list *ol, const unsigned char *str)
ASSERT (!ol->head);
ol->head = e;
}
- e->buf = string_alloc_buf ((const char *) str, NULL);
+ e->buf = alloc_buf (size);
+ memcpy (e->buf.data, data, size);
+ e->buf.len = (int)size;
ol->tail = e;
}
+ return e;
}
struct buffer *
buffer_list_peek (struct buffer_list *ol)
{
- if (ol->head)
+ if (ol && ol->head)
return &ol->head->buf;
else
return NULL;
@@ -993,10 +1011,10 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max)
}
}
-static void
+void
buffer_list_pop (struct buffer_list *ol)
{
- if (ol->head)
+ if (ol && ol->head)
{
struct buffer_entry *e = ol->head->next;
free_buf (&ol->head->buf);
diff --git a/buffer.h b/buffer.h
index 9351c4e..0f22cda 100644
--- a/buffer.h
+++ b/buffer.h
@@ -851,8 +851,10 @@ bool buffer_list_defined (const struct buffer_list *ol);
void buffer_list_reset (struct buffer_list *ol);
void buffer_list_push (struct buffer_list *ol, const unsigned char *str);
+struct buffer_entry *buffer_list_push_data (struct buffer_list *ol, const uint8_t *data, size_t size);
struct buffer *buffer_list_peek (struct buffer_list *ol);
void buffer_list_advance (struct buffer_list *ol, int n);
+void buffer_list_pop (struct buffer_list *ol);
void buffer_list_aggregate (struct buffer_list *bl, const size_t max);
diff --git a/common.h b/common.h
index 5548f7c..ff3a0d5 100644
--- a/common.h
+++ b/common.h
@@ -97,6 +97,6 @@ typedef unsigned long ptr_type;
/*
* Script security warning
*/
-#define SCRIPT_SECURITY_WARNING "openvpn_execve: external program may not be called unless '--script-security 2' or higher is enabled. Use '--script-security 3 system' for backward compatibility with 2.1_rc8 and earlier. See --help text or man page for detailed info."
+#define SCRIPT_SECURITY_WARNING "WARNING: External program may not be called unless '--script-security 2' or higher is enabled. Use '--script-security 3 system' for backward compatibility with 2.1_rc8 and earlier. See --help text or man page for detailed info."
#endif
diff --git a/configure.ac b/configure.ac
index 4626e46..5b27b89 100644
--- a/configure.ac
+++ b/configure.ac
@@ -98,6 +98,12 @@ AC_ARG_ENABLE(plugins,
[PLUGINS="yes"]
)
+AC_ARG_ENABLE(eurephia,
+ [ --disable-eurephia Disable support for the eurephia plug-in],
+ [EUREPHIA="$enableval"],
+ [EUREPHIA="yes"]
+)
+
AC_ARG_ENABLE(management,
[ --disable-management Disable management server support],
[MANAGEMENT="$enableval"],
@@ -631,6 +637,9 @@ if test "${WIN32}" != "yes"; then
)],
[AC_MSG_RESULT([libdl headers not found.])]
)
+ if test "$EUREPHIA" = "yes"; then
+ AC_DEFINE(ENABLE_EUREPHIA, 1, [Enable support for the eurephia plug-in])
+ fi
fi
fi
diff --git a/configure_h.awk b/configure_h.awk
new file mode 100644
index 0000000..672e745
--- /dev/null
+++ b/configure_h.awk
@@ -0,0 +1,39 @@
+#
+# OpenVPN -- An application to securely tunnel IP networks
+# over a single UDP port, with support for SSL/TLS-based
+# session authentication and key exchange,
+# packet encryption, packet authentication, and
+# packet compression.
+#
+# Copyright (C) 2010 David Sommerseth <dazo@users.sourceforge.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program (see the file COPYING included with this
+# distribution); if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# This script will build up a line which can be included into a C program.
+# The line will contain all interesting #define statements from f.ex. ./config.h
+#
+
+BEGIN {
+ printf ("#define CONFIGURE_DEFINES \"")
+}
+
+/^#define (ENABLE|DISABLE|DEPRECATED|USE)_/ {
+ printf (" %s", $2)
+}
+
+END {
+ printf ("\"\n")
+}
diff --git a/configure_log.awk b/configure_log.awk
new file mode 100644
index 0000000..099e5c4
--- /dev/null
+++ b/configure_log.awk
@@ -0,0 +1,33 @@
+#
+# OpenVPN -- An application to securely tunnel IP networks
+# over a single UDP port, with support for SSL/TLS-based
+# session authentication and key exchange,
+# packet encryption, packet authentication, and
+# packet compression.
+#
+# Copyright (C) 2010 David Sommerseth <dazo@users.sourceforge.net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program (see the file COPYING included with this
+# distribution); if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+# This script will build up a line which can be included into a C program.
+# The line will only contain the first entry of the ./configure line from
+# ./config.log.
+#
+
+/\$ (.*)\/configure/ {
+ printf ("#define CONFIGURE_CALL \"%s\"\n", $0)
+ exit 0
+}
diff --git a/easy-rsa/2.0/pkitool b/easy-rsa/2.0/pkitool
index 7266988..49588f5 100755
--- a/easy-rsa/2.0/pkitool
+++ b/easy-rsa/2.0/pkitool
@@ -192,6 +192,12 @@ while [ $# -gt 0 ]; do
$PKCS11TOOL --module "$PKCS11_MODULE_PATH" --list-objects --login --slot "$PKCS11_SLOT"
exit 0;;
+ --help|--usage)
+ usage
+ exit ;;
+ --version)
+ echo "$PROGNAME $VERSION"
+ exit ;;
# errors
--* ) die "$PROGNAME: unknown option: $1" ;;
* ) break ;;
diff --git a/error.c b/error.c
index ce61f6c..873718c 100644
--- a/error.c
+++ b/error.c
@@ -477,14 +477,16 @@ redirect_stdout_stderr (const char *file, bool append)
{
HANDLE log_handle;
int log_fd;
- struct security_attributes sa;
- init_security_attributes_allow_all (&sa);
+ SECURITY_ATTRIBUTES saAttr;
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = NULL;
log_handle = CreateFile (file,
GENERIC_WRITE,
FILE_SHARE_READ,
- &sa.sa,
+ &saAttr,
append ? OPEN_ALWAYS : CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
@@ -505,10 +507,12 @@ redirect_stdout_stderr (const char *file, bool append)
/* save original stderr for password prompts */
orig_stderr = GetStdHandle (STD_ERROR_HANDLE);
+#if 0 /* seems not be necessary with stdout/stderr redirection below*/
/* set up for redirection */
if (!SetStdHandle (STD_OUTPUT_HANDLE, log_handle)
|| !SetStdHandle (STD_ERROR_HANDLE, log_handle))
msg (M_ERR, "Error: cannot redirect stdout/stderr to --log file: %s", file);
+#endif
/* direct stdout/stderr to point to log_handle */
log_fd = _open_osfhandle ((intptr_t)log_handle, _O_TEXT);
@@ -521,6 +525,10 @@ redirect_stdout_stderr (const char *file, bool append)
if (msgfp == NULL)
msg (M_ERR, "Error: --log redirect failed due to _fdopen");
+ /* redirect C-library stdout/stderr to log file */
+ if (_dup2 (log_fd, 1) == -1 || _dup2 (log_fd, 2) == -1)
+ msg (M_WARN, "Error: --log redirect of stdout/stderr failed");
+
std_redir = true;
}
#elif defined(HAVE_DUP2)
diff --git a/init.c b/init.c
index 4b2a8d0..5f64c05 100644
--- a/init.c
+++ b/init.c
@@ -122,7 +122,8 @@ ce_http_proxy_fallback_defined(const struct context *c)
int i;
for (i = 0; i < l->len; ++i)
{
- if (l->array[i]->flags & CE_HTTP_PROXY_FALLBACK)
+ const struct connection_entry *ce = l->array[i];
+ if (ce->flags & CE_HTTP_PROXY_FALLBACK)
return true;
}
}
@@ -193,12 +194,9 @@ management_callback_http_proxy_fallback_cmd (void *arg, const char *server, cons
struct connection_entry *ce = l->array[i];
if (ce->flags & CE_HTTP_PROXY_FALLBACK)
{
- if (ho)
- {
- ce->http_proxy_options = ho;
- ret = true;
- }
+ ce->http_proxy_options = ho;
ce->ce_http_proxy_fallback_timestamp = now;
+ ret = true;
}
}
}
@@ -278,7 +276,7 @@ next_connection_entry (struct context *c)
do {
const char *remote_ip_hint = NULL;
- bool advanced = false;
+ bool newcycle = false;
ce_defined = true;
if (l->no_advance && l->current >= 0)
@@ -295,7 +293,8 @@ next_connection_entry (struct context *c)
msg (M_FATAL, "No usable connection profiles are present");
}
- advanced = true;
+ if (l->current == 0)
+ newcycle = true;
show_connection_list(l);
}
@@ -305,7 +304,7 @@ next_connection_entry (struct context *c)
remote_ip_hint = c->options.remote_ip_hint;
#if HTTP_PROXY_FALLBACK
- if (advanced && ce_http_proxy_fallback_defined(c))
+ if (newcycle && ce_http_proxy_fallback_defined(c))
ce_http_proxy_fallback_start(c, remote_ip_hint);
if (ce->flags & CE_HTTP_PROXY_FALLBACK)
@@ -1139,6 +1138,10 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0 && connection_list_defined (&c->options))
connection_list_set_no_advance (&c->options);
+#ifdef WIN32
+ fork_register_dns_action (c->c1.tuntap);
+#endif
+
#ifdef ENABLE_MANAGEMENT
/* Tell management interface that we initialized */
if (management)
@@ -1188,7 +1191,7 @@ do_route (const struct options *options,
struct argv argv = argv_new ();
setenv_str (es, "script_type", "route-up");
argv_printf (&argv, "%sc", options->route_script);
- openvpn_execve_check (&argv, es, S_SCRIPT, "Route script failed");
+ openvpn_run_script (&argv, es, 0, "--route-up");
argv_reset (&argv);
}
@@ -2021,6 +2024,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
#endif
to.verify_command = options->tls_verify;
+ to.verify_export_cert = options->tls_export_cert;
to.verify_x509name = options->tls_remote;
to.crl_file = options->crl_file;
to.ns_cert_type = options->ns_cert_type;
diff --git a/misc.c b/misc.c
index 1f7f616..eafd892 100644
--- a/misc.c
+++ b/misc.c
@@ -230,7 +230,7 @@ run_up_down (const char *command,
ifconfig_local, ifconfig_remote,
context);
argv_msg (M_INFO, &argv);
- openvpn_execve_check (&argv, es, S_SCRIPT|S_FATAL, "script failed");
+ openvpn_run_script (&argv, es, S_FATAL, "--up/--down");
argv_reset (&argv);
}
@@ -493,6 +493,7 @@ openvpn_execve_allowed (const unsigned int flags)
return script_security >= SSEC_BUILT_IN;
}
+
#ifndef WIN32
/*
* Run execve() inside a fork(). Designed to replicate the semantics of system() but
@@ -504,6 +505,7 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
{
struct gc_arena gc = gc_new ();
int ret = -1;
+ static bool warn_shown = false;
if (a && a->argv[0])
{
@@ -540,9 +542,10 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
ASSERT (0);
}
}
- else
+ else if (!warn_shown && (script_security < SSEC_SCRIPTS))
{
msg (M_WARN, SCRIPT_SECURITY_WARNING);
+ warn_shown = true;
}
#else
msg (M_WARN, "openvpn_execve: execve function not available");
diff --git a/misc.h b/misc.h
index d5ad774..7db9332 100644
--- a/misc.h
+++ b/misc.h
@@ -136,6 +136,15 @@ bool openvpn_execve_check (const struct argv *a, const struct env_set *es, const
bool openvpn_execve_allowed (const unsigned int flags);
int openvpn_system (const char *command, const struct env_set *es, unsigned int flags);
+static inline bool
+openvpn_run_script (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *hook)
+{
+ char msg[256];
+
+ openvpn_snprintf(msg, sizeof(msg), "WARNING: Failed running command (%s)", hook);
+ return openvpn_execve_check(a, es, flags | S_SCRIPT, msg);
+};
+
#ifdef HAVE_STRERROR
/* a thread-safe version of strerror */
const char* strerror_ts (int errnum, struct gc_arena *gc);
@@ -308,6 +317,7 @@ void get_user_pass_auto_userid (struct user_pass *up, const char *tag);
extern const char *iproute_path;
#endif
+/* Script security */
#define SSEC_NONE 0 /* strictly no calling of external programs */
#define SSEC_BUILT_IN 1 /* only call built-in programs such as ifconfig, route, netsh, etc.*/
#define SSEC_SCRIPTS 2 /* allow calling of built-in programs and user-defined scripts */
diff --git a/multi.c b/multi.c
index dc26a02..57310f6 100644
--- a/multi.c
+++ b/multi.c
@@ -109,7 +109,7 @@ learn_address_script (const struct multi_context *m,
mroute_addr_print (addr, &gc));
if (mi)
argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false));
- if (!openvpn_execve_check (&argv, es, S_SCRIPT, "WARNING: learn-address command failed"))
+ if (!openvpn_run_script (&argv, es, 0, "--learn-address"))
ret = false;
argv_reset (&argv);
}
@@ -480,7 +480,7 @@ multi_client_disconnect_script (struct multi_context *m,
struct argv argv = argv_new ();
setenv_str (mi->context.c2.es, "script_type", "client-disconnect");
argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script);
- openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-disconnect command failed");
+ openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect");
argv_reset (&argv);
}
#ifdef MANAGEMENT_DEF_AUTH
@@ -1594,7 +1594,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
mi->context.options.client_connect_script,
dc_file);
- if (openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-connect command failed"))
+ if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect"))
{
multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found);
++cc_succeeded_count;
diff --git a/openvpn.8 b/openvpn.8
index f7fe55a..d8b8653 100644
--- a/openvpn.8
+++ b/openvpn.8
@@ -4254,11 +4254,23 @@ test).
.B cmd
should return 0 to allow the TLS handshake to proceed, or 1 to fail.
+
+Note that
+.B cmd
+is a command line and as such may (if enclosed in quotes) contain
+whitespace separated arguments. The first word of
.B cmd
-is executed as
+is the shell command to execute and the remaining words are its
+arguments.
+When
+.B cmd
+is executed two arguments are appended, as follows:
.B cmd certificate_depth X509_NAME_oneline
+These arguments are, respectively, the current certificate depth and
+the X509 common name (cn) of the peer.
+
This feature is useful if the peer you want to trust has a certificate
which was signed by a certificate authority who also signed many
other certificates, where you don't necessarily want to trust all of them,
@@ -4272,14 +4284,14 @@ in the OpenVPN distribution.
See the "Environmental Variables" section below for
additional parameters passed as environmental variables.
-
-Note that
-.B cmd
-can be a shell command with multiple arguments, in which
-case all OpenVPN-generated arguments will be appended
-to
-.B cmd
-to build a command line which will be passed to the script.
+.\"*********************************************************
+.TP
+.B --tls-export-cert directory
+Store the certificates the clients uses upon connection to this
+directory. This will be done before --tls-verify is called. The
+certificates will use a temporary name and will be deleted when
+the tls-verify script returns. The file name used for the certificate
+is available via the peer_cert environment variable.
.\"*********************************************************
.TP
.B \-\-tls-remote name
@@ -4760,6 +4772,13 @@ This option has the same caveats as
above.
.\"*********************************************************
.TP
+.B \-\-register-dns
+Run net stop dnscache, net start dnscache, ipconfig /flushdns
+and ipconfig /registerdns on connection initiation.
+This is known to kick Windows into
+recognizing pushed DNS servers.
+.\"*********************************************************
+.TP
.B \-\-pause-exit
Put up a "press any key to continue" message on the console prior
to OpenVPN program exit. This option is automatically used by the
@@ -5266,6 +5285,11 @@ than their names as denoted on the command line
or configuration file.
.\"*********************************************************
.TP
+.B peer_cert
+Temporary file name containing the client certificate upon
+connection. Useful in conjunction with --tls-verify
+.\"*********************************************************
+.TP
.B script_context
Set to "init" or "restart" prior to up/down script execution.
For more information, see
diff --git a/options.c b/options.c
index e39a8ba..d40c7f0 100644
--- a/options.c
+++ b/options.c
@@ -7,6 +7,9 @@
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
*
+ * Additions for eurephia plugin done by:
+ * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2009
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
@@ -45,6 +48,8 @@
#include "pool.h"
#include "helper.h"
#include "manage.h"
+#include "configure.h"
+#include <ctype.h>
#include "memdbg.h"
@@ -73,6 +78,9 @@ const char title_string[] =
#ifdef ENABLE_PKCS11
" [PKCS11]"
#endif
+#ifdef ENABLE_EUREPHIA
+ " [eurephia]"
+#endif
" built on " __DATE__
;
@@ -503,6 +511,8 @@ static const char usage_message[] =
"--key file : Local private key in .pem format.\n"
"--pkcs12 file : PKCS#12 file containing local private key, local certificate\n"
" and optionally the root CA certificate.\n"
+ "--x509-username-field : Field used in x509 certificat to be username.\n"
+ " Default is CN.\n"
#ifdef WIN32
"--cryptoapicert select-string : Load the certificate and private key from the\n"
" Windows Certificate System Store.\n"
@@ -533,6 +543,9 @@ static const char usage_message[] =
" tests of certification. cmd should return 0 to allow\n"
" TLS handshake to proceed, or 1 to fail. (cmd is\n"
" executed as 'cmd certificate_depth X509_NAME_oneline')\n"
+ "--tls-export-cert [directory] : Get peer cert in PEM format and store it \n"
+ " in an openvpn temporary file in [directory]. Peer cert is \n"
+ " stored before tls-verify script execution and deleted after.\n"
"--tls-remote x509name: Accept connections only from a host with X509 name\n"
" x509name. The remote host must also pass all other tests\n"
" of verification.\n"
@@ -615,6 +628,8 @@ static const char usage_message[] =
"--dhcp-pre-release : Ask Windows to release the previous TAP adapter lease on\n"
" startup.\n"
"--dhcp-release : Ask Windows to release the TAP adapter lease on shutdown.\n"
+ "--register-dns : Run net stop dnscache, net start dnscache, ipconfig /flushdns\n"
+ " and ipconfig /registerdns on connection initiation.\n"
"--tap-sleep n : Sleep for n seconds after TAP adapter open before\n"
" attempting to set adapter properties.\n"
"--pause-exit : When run from a console window, pause before exiting.\n"
@@ -753,6 +768,7 @@ init_options (struct options *o, const bool init_gc)
o->renegotiate_seconds = 3600;
o->handshake_window = 60;
o->transition_window = 3600;
+ o->x509_username_field = X509_USERNAME_FIELD_DEFAULT;
#endif
#endif
#ifdef ENABLE_PKCS11
@@ -1331,6 +1347,7 @@ show_settings (const struct options *o)
#endif
SHOW_STR (cipher_list);
SHOW_STR (tls_verify);
+ SHOW_STR (tls_export_cert);
SHOW_STR (tls_remote);
SHOW_STR (crl_file);
SHOW_INT (ns_cert_type);
@@ -1464,19 +1481,24 @@ parse_http_proxy_fallback (struct context *c,
const char *flags,
const int msglevel)
{
- struct gc_arena gc = gc_new ();
+ struct gc_arena gc = gc_new ();
+ struct http_proxy_options *ret = NULL;
struct http_proxy_options *hp = parse_http_proxy_override(server, port, flags, msglevel, &gc);
- struct hpo_store *hpos = c->options.hpo_store;
- if (!hpos)
+ if (hp)
{
- ALLOC_OBJ_CLEAR_GC (hpos, struct hpo_store, &c->options.gc);
- c->options.hpo_store = hpos;
+ struct hpo_store *hpos = c->options.hpo_store;
+ if (!hpos)
+ {
+ ALLOC_OBJ_CLEAR_GC (hpos, struct hpo_store, &c->options.gc);
+ c->options.hpo_store = hpos;
+ }
+ hpos->hpo = *hp;
+ hpos->hpo.server = hpos->server;
+ strncpynt(hpos->server, hp->server, sizeof(hpos->server));
+ ret = &hpos->hpo;
}
- hpos->hpo = *hp;
- hpos->hpo.server = hpos->server;
- strncpynt(hpos->server, hp->server, sizeof(hpos->server));
gc_free (&gc);
- return &hpos->hpo;
+ return ret;
}
static void
@@ -2054,6 +2076,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
MUST_BE_UNDEF (pkcs12_file);
MUST_BE_UNDEF (cipher_list);
MUST_BE_UNDEF (tls_verify);
+ MUST_BE_UNDEF (tls_export_cert);
MUST_BE_UNDEF (tls_remote);
MUST_BE_UNDEF (tls_timeout);
MUST_BE_UNDEF (renegotiate_bytes);
@@ -2896,6 +2919,12 @@ usage_version (void)
msg (M_INFO|M_NOPREFIX, "%s", title_string);
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
+#ifdef CONFIGURE_CALL
+ msg (M_INFO|M_NOPREFIX, "\n%s\n", CONFIGURE_CALL);
+#endif
+ msg (M_INFO|M_NOPREFIX, "Compile time defines: %s", CONFIGURE_DEFINES);
+#endif
openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
}
@@ -5300,7 +5329,7 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_IPWIN32);
options->tuntap_options.dhcp_release = true;
}
- else if (streq (p[0], "dhcp-rr") && p[1]) /* standalone method for internal use */
+ else if (streq (p[0], "dhcp-internal") && p[1]) /* standalone method for internal use */
{
unsigned int adapter_index;
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -5311,13 +5340,26 @@ add_option (struct options *options,
dhcp_release_by_adapter_index (adapter_index);
if (options->tuntap_options.dhcp_renew)
dhcp_renew_by_adapter_index (adapter_index);
- openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
+ openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
+ }
+ else if (streq (p[0], "register-dns"))
+ {
+ VERIFY_PERMISSION (OPT_P_IPWIN32);
+ options->tuntap_options.register_dns = true;
+ }
+ else if (streq (p[0], "rdns-internal")) /* standalone method for internal use */
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ set_debug_level (options->verbosity, SDL_CONSTRAIN);
+ if (options->tuntap_options.register_dns)
+ ipconfig_register_dns (NULL);
+ openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
}
else if (streq (p[0], "show-valid-subnets"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
show_valid_win32_tun_subnets ();
- openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
+ openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */
}
else if (streq (p[0], "pause-exit"))
{
@@ -5728,6 +5770,11 @@ add_option (struct options *options,
warn_multiple_script (options->tls_verify, "tls-verify");
options->tls_verify = string_substitute (p[1], ',', ' ', &options->gc);
}
+ else if (streq (p[0], "tls-export-cert") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->tls_export_cert = p[1];
+ }
else if (streq (p[0], "tls-remote") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -5853,6 +5900,13 @@ add_option (struct options *options,
}
options->key_method = key_method;
}
+ else if (streq (p[0], "x509-username-field") && p[1])
+ {
+ char *s = p[1];
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ while ((*s = toupper(*s)) != '\0') s++; /* Uppercase if necessary */
+ options->x509_username_field = p[1];
+ }
#endif /* USE_SSL */
#endif /* USE_CRYPTO */
#ifdef ENABLE_PKCS11
diff --git a/options.h b/options.h
index 240f3bb..efab4c2 100644
--- a/options.h
+++ b/options.h
@@ -465,6 +465,7 @@ struct options
const char *pkcs12_file;
const char *cipher_list;
const char *tls_verify;
+ const char *tls_export_cert;
const char *tls_remote;
const char *crl_file;
@@ -508,6 +509,9 @@ struct options
within n seconds of handshake initiation. */
int handshake_window;
+ /* Field used to be the username in X509 cert. */
+ char *x509_username_field;
+
/* Old key allowed to live n seconds after new key goes active */
int transition_window;
diff --git a/proxy.c b/proxy.c
index ac3fc65..3de2ac1 100644
--- a/proxy.c
+++ b/proxy.c
@@ -620,8 +620,11 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
{
msg (D_PROXY, "Proxy requires authentication");
- /* check for NTLM */
- if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed)
+ if (p->auth_method == HTTP_AUTH_BASIC && !processed)
+ {
+ processed = true;
+ }
+ else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */
{
#if NTLM
/* look for the phase 2 response */
diff --git a/route.c b/route.c
index 2635afd..5d8f8d6 100644
--- a/route.c
+++ b/route.c
@@ -219,6 +219,7 @@ is_special_addr (const char *addr_str)
static bool
init_route (struct route *r,
+ struct resolve_list *network_list,
const struct route_option *ro,
const struct route_special_addr *spec)
{
@@ -237,14 +238,15 @@ init_route (struct route *r,
if (!get_special_addr (spec, ro->network, &r->network, &status))
{
- r->network = getaddr (
- GETADDR_RESOLVE
- | GETADDR_HOST_ORDER
- | GETADDR_WARN_ON_SIGNAL,
- ro->network,
- 0,
- &status,
- NULL);
+ r->network = getaddr_multi (
+ GETADDR_RESOLVE
+ | GETADDR_HOST_ORDER
+ | GETADDR_WARN_ON_SIGNAL,
+ ro->network,
+ 0,
+ &status,
+ NULL,
+ network_list);
}
if (!status)
@@ -438,20 +440,45 @@ init_route_list (struct route_list *rl,
else
rl->spec.remote_endpoint_defined = false;
- if (!(opt->n >= 0 && opt->n <= rl->capacity))
- msg (M_FATAL, PACKAGE_NAME " ROUTE: (init) number of route options (%d) is greater than route list capacity (%d)", opt->n, rl->capacity);
-
/* parse the routes from opt to rl */
{
int i, j = 0;
+ bool warned = false;
for (i = 0; i < opt->n; ++i)
{
- if (!init_route (&rl->routes[j],
+ struct resolve_list netlist;
+ struct route r;
+ int k;
+
+ if (!init_route (&r,
+ &netlist,
&opt->routes[i],
&rl->spec))
ret = false;
else
- ++j;
+ {
+ if (!netlist.len)
+ {
+ netlist.data[0] = r.network;
+ netlist.len = 1;
+ }
+ for (k = 0; k < netlist.len; ++k)
+ {
+ if (j < rl->capacity)
+ {
+ r.network = netlist.data[k];
+ rl->routes[j++] = r;
+ }
+ else
+ {
+ if (!warned)
+ {
+ msg (M_WARN, PACKAGE_NAME " ROUTE: routes dropped because number of expanded routes is greater than route list capacity (%d)", rl->capacity);
+ warned = true;
+ }
+ }
+ }
+ }
}
rl->n = j;
}
diff --git a/socket.c b/socket.c
index dbf65a1..b02d3da 100644
--- a/socket.c
+++ b/socket.c
@@ -89,12 +89,26 @@ getaddr (unsigned int flags,
bool *succeeded,
volatile int *signal_received)
{
+ return getaddr_multi (flags, hostname, resolve_retry_seconds, succeeded, signal_received, NULL);
+}
+
+in_addr_t
+getaddr_multi (unsigned int flags,
+ const char *hostname,
+ int resolve_retry_seconds,
+ bool *succeeded,
+ volatile int *signal_received,
+ struct resolve_list *reslist)
+{
struct in_addr ia;
int status;
int sigrec = 0;
int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
struct gc_arena gc = gc_new ();
+ if (reslist)
+ reslist->len = 0;
+
if (flags & GETADDR_RANDOMIZE)
hostname = hostname_randomize(hostname, &gc);
@@ -212,11 +226,28 @@ getaddr (unsigned int flags,
++n;
ASSERT (n >= 2);
- msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d addresses, choosing the first resolved IP address",
+ msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d addresses",
hostname,
n);
+ /* choose address randomly, for basic load-balancing capability */
+ /*ia.s_addr = *(in_addr_t *) (h->h_addr_list[get_random () % n]);*/
+
+ /* choose first address */
ia.s_addr = *(in_addr_t *) (h->h_addr_list[0]);
+
+ if (reslist)
+ {
+ int i;
+ for (i = 0; i < n && i < SIZE(reslist->data); ++i)
+ {
+ in_addr_t a = *(in_addr_t *) (h->h_addr_list[i]);
+ if (flags & GETADDR_HOST_ORDER)
+ a = ntohl(a);
+ reslist->data[i] = a;
+ }
+ reslist->len = i;
+ }
}
}
@@ -1664,7 +1695,7 @@ link_socket_connection_initiated (const struct buffer *buf,
struct argv argv = argv_new ();
setenv_str (es, "script_type", "ipchange");
ipchange_fmt (true, &argv, info, &gc);
- openvpn_execve_check (&argv, es, S_SCRIPT, "ip-change command failed");
+ openvpn_run_script (&argv, es, 0, "--ipchange");
argv_reset (&argv);
}
diff --git a/socket.h b/socket.h
index 5155853..cd24011 100644
--- a/socket.h
+++ b/socket.h
@@ -439,6 +439,11 @@ bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *
* DNS resolution
*/
+struct resolve_list {
+ int len;
+ in_addr_t data[16];
+};
+
#define GETADDR_RESOLVE (1<<0)
#define GETADDR_FATAL (1<<1)
#define GETADDR_HOST_ORDER (1<<2)
@@ -456,6 +461,13 @@ in_addr_t getaddr (unsigned int flags,
bool *succeeded,
volatile int *signal_received);
+in_addr_t getaddr_multi (unsigned int flags,
+ const char *hostname,
+ int resolve_retry_seconds,
+ bool *succeeded,
+ volatile int *signal_received,
+ struct resolve_list *reslist);
+
/*
* Transport protocol naming and other details.
*/
diff --git a/ssl.c b/ssl.c
index c5f2131..0a84b0d 100644
--- a/ssl.c
+++ b/ssl.c
@@ -7,6 +7,10 @@
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
*
+ * Additions for eurephia plugin done by:
+ * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2008-2009
+ *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
@@ -687,6 +691,51 @@ string_mod_sslname (char *str, const unsigned int restrictive_flags, const unsig
string_mod (str, restrictive_flags, 0, '_');
}
+/* Get peer cert and store it in pem format in a temporary file
+ * in tmp_dir
+ */
+
+const char *
+get_peer_cert(X509_STORE_CTX *ctx, const char *tmp_dir, struct gc_arena *gc)
+{
+ X509 *peercert;
+ FILE *peercert_file;
+ const char *peercert_filename="";
+
+ if(!tmp_dir)
+ return NULL;
+
+ /* get peer cert */
+ peercert = X509_STORE_CTX_get_current_cert(ctx);
+ if(!peercert)
+ {
+ msg (M_ERR, "Unable to get peer certificate from current context");
+ return NULL;
+ }
+
+ /* create tmp file to store peer cert */
+ peercert_filename = create_temp_file (tmp_dir, "pcf", gc);
+
+ /* write peer-cert in tmp-file */
+ peercert_file = fopen(peercert_filename, "w+");
+ if(!peercert_file)
+ {
+ msg (M_ERR, "Failed to open temporary file : %s", peercert_filename);
+ return NULL;
+ }
+ if(PEM_write_X509(peercert_file,peercert)<0)
+ {
+ msg (M_ERR, "Failed to write peer certificate in PEM format");
+ fclose(peercert_file);
+ return NULL;
+ }
+
+ fclose(peercert_file);
+ return peercert_filename;
+}
+
+char * x509_username_field; /* GLOBAL */
+
/*
* Our verify callback function -- check
* that an incoming peer certificate is good.
@@ -697,7 +746,7 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
{
char *subject = NULL;
char envname[64];
- char common_name[TLS_CN_LEN];
+ char common_name[TLS_USERNAME_LEN];
SSL *ssl;
struct tls_session *session;
const struct tls_options *opt;
@@ -729,18 +778,20 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
string_mod_sslname (subject, X509_NAME_CHAR_CLASS, opt->ssl_flags);
string_replace_leading (subject, '-', '_');
- /* extract the common name */
- if (!extract_x509_field_ssl (X509_get_subject_name (ctx->current_cert), "CN", common_name, TLS_CN_LEN))
+ /* extract the username (default is CN) */
+ if (!extract_x509_field_ssl (X509_get_subject_name (ctx->current_cert), x509_username_field, common_name, sizeof(common_name)))
{
if (!ctx->error_depth)
- {
- msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract Common Name from X509 subject string ('%s') -- note that the Common Name length is limited to %d characters",
- subject,
- TLS_CN_LEN);
- goto err;
- }
+ {
+ msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract %s from X509 subject string ('%s') -- note that the username length is limited to %d characters",
+ x509_username_field,
+ subject,
+ TLS_USERNAME_LEN);
+ goto err;
+ }
}
+
string_mod_sslname (common_name, COMMON_NAME_CHAR_CLASS, opt->ssl_flags);
cert_hash_remember (session, ctx->error_depth, ctx->current_cert->sha1_hash);
@@ -780,6 +831,16 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
openvpn_snprintf (envname, sizeof(envname), "tls_id_%d", ctx->error_depth);
setenv_str (opt->es, envname, subject);
+#ifdef ENABLE_EUREPHIA
+ /* export X509 cert SHA1 fingerprint */
+ {
+ struct gc_arena gc = gc_new ();
+ openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", ctx->error_depth);
+ setenv_str (opt->es, envname,
+ format_hex_ex(ctx->current_cert->sha1_hash, SHA_DIGEST_LENGTH, 0, 1, ":", &gc));
+ gc_free(&gc);
+ }
+#endif
#if 0
/* export common name string as environmental variable */
openvpn_snprintf (envname, sizeof(envname), "tls_common_name_%d", ctx->error_depth);
@@ -906,32 +967,48 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx)
/* run --tls-verify script */
if (opt->verify_command)
{
+ const char *tmp_file;
+ struct gc_arena gc;
int ret;
setenv_str (opt->es, "script_type", "tls-verify");
+ if (opt->verify_export_cert)
+ {
+ gc = gc_new();
+ if (tmp_file=get_peer_cert(ctx, opt->verify_export_cert,&gc))
+ {
+ setenv_str(opt->es, "peer_cert", tmp_file);
+ }
+ }
+
argv_printf (&argv, "%sc %d %s",
opt->verify_command,
ctx->error_depth,
subject);
argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command");
- ret = openvpn_execve (&argv, opt->es, S_SCRIPT);
+ ret = openvpn_run_script (&argv, opt->es, 0, "--tls-verify script");
+
+ if (opt->verify_export_cert)
+ {
+ if (tmp_file)
+ delete_file(tmp_file);
+ gc_free(&gc);
+ }
- if (system_ok (ret))
+ if (ret)
{
msg (D_HANDSHAKE, "VERIFY SCRIPT OK: depth=%d, %s",
ctx->error_depth, subject);
}
else
{
- if (!system_executed (ret))
- argv_msg_prefix (M_ERR, &argv, "Verify command failed to execute");
msg (D_HANDSHAKE, "VERIFY SCRIPT ERROR: depth=%d, %s",
ctx->error_depth, subject);
goto err; /* Reject connection */
}
}
-
+
/* check peer cert against CRL */
if (opt->crl_file)
{
@@ -1749,7 +1826,8 @@ init_ssl (const struct options *options)
}
else
#endif
- SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ x509_username_field = (char *) options->x509_username_field;
+ SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
verify_callback);
/* Connection information callback */
@@ -2288,6 +2366,7 @@ key_state_free (struct key_state *ks, bool clear)
free_buf (&ks->plaintext_read_buf);
free_buf (&ks->plaintext_write_buf);
free_buf (&ks->ack_write_buf);
+ buffer_list_free(ks->paybuf);
if (ks->send_reliable)
{
@@ -3086,6 +3165,17 @@ key_source2_read (struct key_source2 *k2,
return 1;
}
+static void
+flush_payload_buffer (struct tls_multi *multi, struct key_state *ks)
+{
+ struct buffer *b;
+ while ((b = buffer_list_peek (ks->paybuf)))
+ {
+ key_state_write_plaintext_const (multi, ks, b->data, b->len);
+ buffer_list_pop (ks->paybuf);
+ }
+}
+
/*
* Macros for key_state_soft_reset & tls_process
*/
@@ -3190,7 +3280,6 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
struct gc_arena gc = gc_new ();
struct argv argv = argv_new ();
const char *tmp_file = "";
- int retval;
bool ret = false;
/* Is username defined? */
@@ -3233,16 +3322,11 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up
/* format command line */
argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file);
-
+
/* call command */
- retval = openvpn_execve (&argv, session->opt->es, S_SCRIPT);
+ ret = openvpn_run_script (&argv, session->opt->es, 0,
+ "--auth-user-pass-verify");
- /* test return status of command */
- if (system_ok (retval))
- ret = true;
- else if (!system_executed (retval))
- argv_msg_prefix (D_TLS_ERRORS, &argv, "TLS Auth Error: user-pass-verify script failed to execute");
-
if (!session->opt->auth_user_pass_verify_script_via_file)
setenv_del (session->opt->es, "password");
}
@@ -3688,9 +3772,9 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
s2 = verify_user_pass_script (session, up);
/* check sizing of username if it will become our common name */
- if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_CN_LEN)
+ if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_USERNAME_LEN)
{
- msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_CN_LEN);
+ msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN);
s1 = OPENVPN_PLUGIN_FUNC_ERROR;
}
@@ -4006,6 +4090,9 @@ tls_process (struct tls_multi *multi,
/* Set outgoing address for data channel packets */
link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es);
+ /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */
+ flush_payload_buffer (multi, ks);
+
#ifdef MEASURE_TLS_HANDSHAKE_STATS
show_tls_performance_stats();
#endif
@@ -5105,6 +5192,13 @@ tls_send_payload (struct tls_multi *multi,
if (key_state_write_plaintext_const (multi, ks, data, size) == 1)
ret = true;
}
+ else
+ {
+ if (!ks->paybuf)
+ ks->paybuf = buffer_list_new (0);
+ buffer_list_push_data (ks->paybuf, data, (size_t)size);
+ ret = true;
+ }
ERR_clear_error ();
diff --git a/ssl.h b/ssl.h
index 5eeca21..8415d55 100644
--- a/ssl.h
+++ b/ssl.h
@@ -278,8 +278,8 @@
* Buffer sizes (also see mtu.h).
*/
-/* Maximum length of common name */
-#define TLS_CN_LEN 64
+/* Maximum length of the username in cert */
+#define TLS_USERNAME_LEN 64
/* Legal characters in an X509 or common name */
#define X509_NAME_CHAR_CLASS (CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT|CC_COLON|CC_SLASH|CC_EQUAL)
@@ -288,6 +288,9 @@
/* Maximum length of OCC options string passed as part of auth handshake */
#define TLS_OPTIONS_LEN 512
+/* Default field in X509 to be username */
+#define X509_USERNAME_FIELD_DEFAULT "CN"
+
/*
* Range of key exchange methods
*/
@@ -376,6 +379,8 @@ struct key_state
struct reliable *rec_reliable; /* order incoming ciphertext packets before we pass to TLS */
struct reliable_ack *rec_ack; /* buffers all packet IDs we want to ACK back to sender */
+ struct buffer_list *paybuf;
+
counter_type n_bytes; /* how many bytes sent/recvd since last key exchange */
counter_type n_packets; /* how many packets sent/recvd since last key exchange */
@@ -444,6 +449,7 @@ struct tls_options
/* cert verification parms */
const char *verify_command;
+ const char *verify_export_cert;
const char *verify_x509name;
const char *crl_file;
int ns_cert_type;
diff --git a/syshead.h b/syshead.h
index 7cc4dba..1b8bfad 100644
--- a/syshead.h
+++ b/syshead.h
@@ -535,11 +535,9 @@ socket_defined (const socket_descriptor_t sd)
#endif
/*
- * Don't compile the struct buffer_list code unless something needs it
+ * Compile the struct buffer_list code
*/
-#if defined(ENABLE_MANAGEMENT) || defined(ENABLE_PF)
#define ENABLE_BUFFER_LIST
-#endif
/*
* Do we have pthread capability?
diff --git a/tap-win32/proto.h b/tap-win32/proto.h
index 0390b08..894a37f 100755
--- a/tap-win32/proto.h
+++ b/tap-win32/proto.h
@@ -29,9 +29,11 @@
#pragma pack(1)
#define IP_HEADER_SIZE 20
+#define IPV6_HEADER_SIZE 40
typedef unsigned char MACADDR [6];
typedef unsigned long IPADDR;
+typedef unsigned char IPV6ADDR [16];
//-----------------
// Ethernet address
@@ -55,6 +57,7 @@ typedef struct
MACADDR src; /* source ether addr */
# define ETH_P_IP 0x0800 /* IPv4 protocol */
+# define ETH_P_IPV6 0x86DD /* IPv6 protocol */
# define ETH_P_ARP 0x0806 /* ARP protocol */
USHORT proto; /* packet type ID field */
} ETH_HEADER, *PETH_HEADER;
@@ -161,4 +164,61 @@ typedef struct {
#define TCPOPT_MAXSEG 2
#define TCPOLEN_MAXSEG 4
+//------------
+// IPv6 Header
+//------------
+
+typedef struct {
+ UCHAR version_prio;
+ UCHAR flow_lbl[3];
+ USHORT payload_len;
+# define IPPROTO_ICMPV6 0x3a /* ICMP protocol v6 */
+ UCHAR nexthdr;
+ UCHAR hop_limit;
+ IPV6ADDR saddr;
+ IPV6ADDR daddr;
+} IPV6HDR;
+
+//--------------------------------------------
+// IPCMPv6 NS/NA Packets (RFC4443 and RFC4861)
+//--------------------------------------------
+
+// Neighbor Solictiation - RFC 4861, 4.3
+// (this is just the ICMPv6 part of the packet)
+typedef struct {
+ UCHAR type;
+# define ICMPV6_TYPE_NS 135 // neighbour solicitation
+ UCHAR code;
+# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA
+ USHORT checksum;
+ ULONG reserved;
+ IPV6ADDR target_addr;
+} ICMPV6_NS;
+
+// Neighbor Advertisement - RFC 4861, 4.4 + 4.6/4.6.1
+// (this is just the ICMPv6 payload)
+typedef struct {
+ UCHAR type;
+# define ICMPV6_TYPE_NA 136 // neighbour advertisement
+ UCHAR code;
+# define ICMPV6_CODE_0 0 // no specific sub-code for NS/NA
+ USHORT checksum;
+ UCHAR rso_bits; // Router(0), Solicited(2), Ovrrd(4)
+ UCHAR reserved[3];
+ IPV6ADDR target_addr;
+// always include "Target Link-layer Address" option (RFC 4861 4.6.1)
+ UCHAR opt_type;
+#define ICMPV6_OPTION_TLLA 2
+ UCHAR opt_length;
+#define ICMPV6_LENGTH_TLLA 1 // multiplied by 8 -> 1 = 8 bytes
+ MACADDR target_macaddr;
+} ICMPV6_NA;
+
+// this is the complete packet with Ethernet and IPv6 headers
+typedef struct {
+ ETH_HEADER eth;
+ IPV6HDR ipv6;
+ ICMPV6_NA icmpv6;
+} ICMPV6_NA_PKT;
+
#pragma pack()
diff --git a/tap-win32/tapdrvr.c b/tap-win32/tapdrvr.c
index 506f1f6..7ab3916 100755
--- a/tap-win32/tapdrvr.c
+++ b/tap-win32/tapdrvr.c
@@ -1430,6 +1430,158 @@ NDIS_STATUS AdapterModify
return l_Status;
}
+// checksum code for ICMPv6 packet, taken from dhcp.c / udp_checksum
+// see RFC 4443, 2.3, and RFC 2460, 8.1
+USHORT
+icmpv6_checksum (const UCHAR *buf,
+ const int len_icmpv6,
+ const UCHAR *saddr6,
+ const UCHAR *daddr6)
+{
+ USHORT word16;
+ ULONG sum = 0;
+ int i;
+
+ // make 16 bit words out of every two adjacent 8 bit words and
+ // calculate the sum of all 16 bit words
+ for (i = 0; i < len_icmpv6; i += 2){
+ word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_icmpv6) ? (buf[i+1] & 0xFF) : 0);
+ sum += word16;
+ }
+
+ // add the IPv6 pseudo header which contains the IP source and destination addresses
+ for (i = 0; i < 16; i += 2){
+ word16 =((saddr6[i] << 8) & 0xFF00) + (saddr6[i+1] & 0xFF);
+ sum += word16;
+ }
+ for (i = 0; i < 16; i += 2){
+ word16 =((daddr6[i] << 8) & 0xFF00) + (daddr6[i+1] & 0xFF);
+ sum += word16;
+ }
+
+ // the next-header number and the length of the ICMPv6 packet
+ sum += (USHORT) IPPROTO_ICMPV6 + (USHORT) len_icmpv6;
+
+ // keep only the last 16 bits of the 32 bit calculated sum and add the carries
+ while (sum >> 16)
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ // Take the one's complement of sum
+ return ((USHORT) ~sum);
+}
+
+// check IPv6 packet for "is this an IPv6 Neighbor Solicitation that
+// the tap driver needs to answer?"
+// see RFC 4861 4.3 for the different cases
+static IPV6ADDR IPV6_NS_TARGET_MCAST =
+ { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x08 };
+static IPV6ADDR IPV6_NS_TARGET_UNICAST =
+ { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 };
+
+BOOLEAN
+HandleIPv6NeighborDiscovery( TapAdapterPointer p_Adapter, UCHAR * m_Data )
+{
+ const ETH_HEADER * e = (ETH_HEADER *) m_Data;
+ const IPV6HDR *ipv6 = (IPV6HDR *) (m_Data + sizeof (ETH_HEADER));
+ const ICMPV6_NS * icmpv6_ns = (ICMPV6_NS *) (m_Data + sizeof (ETH_HEADER) + sizeof (IPV6HDR));
+ ICMPV6_NA_PKT *na;
+ USHORT icmpv6_len, icmpv6_csum;
+
+ // we don't really care about the destination MAC address here
+ // - it's either a multicast MAC, or the userland destination MAC
+ // but since the TAP driver is point-to-point, all packets are "for us"
+
+ // IPv6 target address must be ff02::1::ff00:8 (multicast for
+ // initial NS) or fe80::1 (unicast for recurrent NUD)
+ if ( memcmp( ipv6->daddr, IPV6_NS_TARGET_MCAST,
+ sizeof(IPV6ADDR) ) != 0 &&
+ memcmp( ipv6->daddr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) ) != 0 )
+ {
+ return FALSE; // wrong target address
+ }
+
+ // IPv6 Next-Header must be ICMPv6
+ if ( ipv6->nexthdr != IPPROTO_ICMPV6 )
+ {
+ return FALSE; // wrong next-header
+ }
+
+ // ICMPv6 type+code must be 135/0 for NS
+ if ( icmpv6_ns->type != ICMPV6_TYPE_NS ||
+ icmpv6_ns->code != ICMPV6_CODE_0 )
+ {
+ return FALSE; // wrong ICMPv6 type
+ }
+
+ // ICMPv6 target address must be fe80::8 (magic)
+ if ( memcmp( icmpv6_ns->target_addr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) ) != 0 )
+ {
+ return FALSE; // not for us
+ }
+
+ // packet identified, build magic response packet
+
+ na = (ICMPV6_NA_PKT *) MemAlloc (sizeof (ICMPV6_NA_PKT), TRUE);
+ if ( !na ) return FALSE;
+
+ //------------------------------------------------
+ // Initialize Neighbour Advertisement reply packet
+ //------------------------------------------------
+
+ // ethernet header
+ na->eth.proto = htons(ETH_P_IPV6);
+ COPY_MAC(na->eth.dest, p_Adapter->m_MAC);
+ COPY_MAC(na->eth.src, p_Adapter->m_TapToUser.dest);
+
+ // IPv6 header
+ na->ipv6.version_prio = ipv6->version_prio;
+ NdisMoveMemory( na->ipv6.flow_lbl, ipv6->flow_lbl,
+ sizeof(na->ipv6.flow_lbl) );
+ icmpv6_len = sizeof(ICMPV6_NA_PKT) - sizeof(ETH_HEADER) - sizeof(IPV6HDR);
+ na->ipv6.payload_len = htons(icmpv6_len);
+ na->ipv6.nexthdr = IPPROTO_ICMPV6;
+ na->ipv6.hop_limit = 255;
+ NdisMoveMemory( na->ipv6.saddr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) );
+ NdisMoveMemory( na->ipv6.daddr, ipv6->saddr,
+ sizeof(IPV6ADDR) );
+
+ // ICMPv6
+ na->icmpv6.type = ICMPV6_TYPE_NA;
+ na->icmpv6.code = ICMPV6_CODE_0;
+ na->icmpv6.checksum = 0;
+ na->icmpv6.rso_bits = 0x60; // Solicited + Override
+ NdisZeroMemory( na->icmpv6.reserved, sizeof(na->icmpv6.reserved) );
+ NdisMoveMemory( na->icmpv6.target_addr, IPV6_NS_TARGET_UNICAST,
+ sizeof(IPV6ADDR) );
+
+ // ICMPv6 option "Target Link Layer Address"
+ na->icmpv6.opt_type = ICMPV6_OPTION_TLLA;
+ na->icmpv6.opt_length = ICMPV6_LENGTH_TLLA;
+ COPY_MAC( na->icmpv6.target_macaddr, p_Adapter->m_TapToUser.dest );
+
+ // calculate and set checksum
+ icmpv6_csum = icmpv6_checksum ( (UCHAR*) &(na->icmpv6),
+ icmpv6_len,
+ na->ipv6.saddr,
+ na->ipv6.daddr );
+ na->icmpv6.checksum = htons( icmpv6_csum );
+
+ DUMP_PACKET ("HandleIPv6NeighborDiscovery",
+ (unsigned char *) na,
+ sizeof (ICMPV6_NA_PKT));
+
+ InjectPacketDeferred (p_Adapter, (UCHAR *) na, sizeof (ICMPV6_NA_PKT));
+
+ MemFree (na, sizeof (ICMPV6_NA_PKT));
+
+ return TRUE; // all fine
+}
+
//====================================================================
// Adapter Transmission
//====================================================================
@@ -1566,7 +1718,10 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
//===============================================
// In Point-To-Point mode, check to see whether
- // packet is ARP or IPv4 (if neither, then drop).
+ // packet is ARP (handled) or IPv4 (sent to app).
+ // IPv6 packets are inspected for neighbour discovery
+ // (to be handled locally), and the rest is forwarded
+ // all other protocols are dropped
//===============================================
if (l_Adapter->m_tun)
{
@@ -1611,6 +1766,27 @@ AdapterTransmit (IN NDIS_HANDLE p_AdapterContext,
// Packet looks like IPv4, queue it.
l_PacketBuffer->m_SizeFlags |= TP_TUN;
+
+ case ETH_P_IPV6:
+ // make sure that packet is large
+ // enough to be IPv6
+ if (l_PacketLength
+ < ETHERNET_HEADER_SIZE + IPV6_HEADER_SIZE)
+ goto no_queue;
+
+ // broadcasts and multicasts are handled specially
+ // (to be implemented)
+
+ // neighbor discovery packets to fe80::8 are special
+ // OpenVPN sets this next-hop to signal "handled by tapdrv"
+ if ( HandleIPv6NeighborDiscovery( l_Adapter,
+ l_PacketBuffer->m_Data ))
+ {
+ goto no_queue;
+ }
+
+ // Packet looks like IPv6, queue it :-)
+ l_PacketBuffer->m_SizeFlags |= TP_TUN;
}
}
@@ -1902,6 +2078,8 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
+ l_Adapter->m_UserToTap_IPv6 = l_Adapter->m_UserToTap;
+ l_Adapter->m_UserToTap_IPv6.proto = htons(ETH_P_IPV6);
l_Adapter->m_tun = TRUE;
@@ -1939,6 +2117,8 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
COPY_MAC (l_Adapter->m_UserToTap.dest, l_Adapter->m_MAC);
l_Adapter->m_TapToUser.proto = l_Adapter->m_UserToTap.proto = htons (ETH_P_IP);
+ l_Adapter->m_UserToTap_IPv6 = l_Adapter->m_UserToTap;
+ l_Adapter->m_UserToTap_IPv6.proto = htons(ETH_P_IPV6);
l_Adapter->m_tun = TRUE;
@@ -2236,10 +2416,18 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
{
__try
{
+ ETH_HEADER * p_UserToTap = &l_Adapter->m_UserToTap;
+
+ // for IPv6, need to use ethernet header with IPv6 proto
+ if ( IPH_GET_VER( ((IPHDR*) p_IRP->AssociatedIrp.SystemBuffer)->version_len) == 6 )
+ {
+ p_UserToTap = &l_Adapter->m_UserToTap_IPv6;
+ }
+
p_IRP->IoStatus.Information = l_IrpSp->Parameters.Write.Length;
DUMP_PACKET2 ("IRP_MJ_WRITE P2P",
- &l_Adapter->m_UserToTap,
+ p_UserToTap,
(unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
l_IrpSp->Parameters.Write.Length);
@@ -2258,8 +2446,8 @@ TapDeviceHook (IN PDEVICE_OBJECT p_DeviceObject, IN PIRP p_IRP)
NdisMEthIndicateReceive
(l_Adapter->m_MiniportAdapterHandle,
(NDIS_HANDLE) l_Adapter,
- (unsigned char *) &l_Adapter->m_UserToTap,
- sizeof (l_Adapter->m_UserToTap),
+ (unsigned char *) p_UserToTap,
+ sizeof (ETH_HEADER),
(unsigned char *) p_IRP->AssociatedIrp.SystemBuffer,
l_IrpSp->Parameters.Write.Length,
l_IrpSp->Parameters.Write.Length);
@@ -2820,6 +3008,7 @@ VOID ResetTapAdapterState (TapAdapterPointer p_Adapter)
p_Adapter->m_remoteNetmask = 0;
NdisZeroMemory (&p_Adapter->m_TapToUser, sizeof (p_Adapter->m_TapToUser));
NdisZeroMemory (&p_Adapter->m_UserToTap, sizeof (p_Adapter->m_UserToTap));
+ NdisZeroMemory (&p_Adapter->m_UserToTap_IPv6, sizeof (p_Adapter->m_UserToTap_IPv6));
// DHCP Masq
p_Adapter->m_dhcp_enabled = FALSE;
diff --git a/tap-win32/types.h b/tap-win32/types.h
index 9406252..bdc08e7 100755
--- a/tap-win32/types.h
+++ b/tap-win32/types.h
@@ -143,6 +143,7 @@ typedef struct _TapAdapter
IPADDR m_remoteNetmask;
ETH_HEADER m_TapToUser;
ETH_HEADER m_UserToTap;
+ ETH_HEADER m_UserToTap_IPv6; // same as UserToTap but proto=ipv6
MACADDR m_MAC_Broadcast;
// Used for DHCP server masquerade
diff --git a/tun.c b/tun.c
index 2f2173b..91fff0b 100644
--- a/tun.c
+++ b/tun.c
@@ -3372,6 +3372,48 @@ netsh_command (const struct argv *a, int n)
}
void
+ipconfig_register_dns (const struct env_set *es)
+{
+ struct argv argv;
+ bool status;
+ const char err[] = "ERROR: Windows ipconfig command failed";
+
+ netcmd_semaphore_lock ();
+
+ argv_init (&argv);
+
+ argv_printf (&argv, "%s%sc stop dnscache",
+ get_win_sys_path(),
+ WIN_NET_PATH_SUFFIX);
+ argv_msg (D_TUNTAP_INFO, &argv);
+ status = openvpn_execve_check (&argv, es, 0, err);
+ argv_reset(&argv);
+
+ argv_printf (&argv, "%s%sc start dnscache",
+ get_win_sys_path(),
+ WIN_NET_PATH_SUFFIX);
+ argv_msg (D_TUNTAP_INFO, &argv);
+ status = openvpn_execve_check (&argv, es, 0, err);
+ argv_reset(&argv);
+
+ argv_printf (&argv, "%s%sc /flushdns",
+ get_win_sys_path(),
+ WIN_IPCONFIG_PATH_SUFFIX);
+ argv_msg (D_TUNTAP_INFO, &argv);
+ status = openvpn_execve_check (&argv, es, 0, err);
+ argv_reset(&argv);
+
+ argv_printf (&argv, "%s%sc /registerdns",
+ get_win_sys_path(),
+ WIN_IPCONFIG_PATH_SUFFIX);
+ argv_msg (D_TUNTAP_INFO, &argv);
+ status = openvpn_execve_check (&argv, es, 0, err);
+ argv_reset(&argv);
+
+ netcmd_semaphore_release ();
+}
+
+void
ip_addr_string_to_array (in_addr_t *dest, int *dest_len, const IP_ADDR_STRING *src)
{
int i = 0;
@@ -3806,8 +3848,23 @@ fork_dhcp_action (struct tuntap *tt)
buf_printf (&cmd, " --dhcp-pre-release");
if (tt->options.dhcp_renew)
buf_printf (&cmd, " --dhcp-renew");
- buf_printf (&cmd, " --dhcp-rr %u", (unsigned int)tt->adapter_index);
+ buf_printf (&cmd, " --dhcp-internal %u", (unsigned int)tt->adapter_index);
+
+ fork_to_self (BSTR (&cmd));
+ gc_free (&gc);
+ }
+}
+void
+fork_register_dns_action (struct tuntap *tt)
+{
+ if (tt && tt->options.register_dns)
+ {
+ struct gc_arena gc = gc_new ();
+ struct buffer cmd = alloc_buf_gc (256, &gc);
+ const int verb = 3;
+
+ buf_printf (&cmd, "openvpn --verb %d --register-dns --rdns-internal", verb);
fork_to_self (BSTR (&cmd));
gc_free (&gc);
}
diff --git a/tun.h b/tun.h
index 9e33fd2..011ab54 100644
--- a/tun.h
+++ b/tun.h
@@ -99,6 +99,8 @@ struct tuntap_options {
bool dhcp_renew;
bool dhcp_pre_release;
bool dhcp_release;
+
+ bool register_dns;
};
#elif TARGET_LINUX
@@ -335,6 +337,9 @@ void tun_show_debug (struct tuntap *tt);
bool dhcp_release_by_adapter_index(const DWORD adapter_index);
bool dhcp_renew_by_adapter_index (const DWORD adapter_index);
+void fork_register_dns_action (struct tuntap *tt);
+void ipconfig_register_dns (const struct env_set *es);
+
void tun_standby_init (struct tuntap *tt);
bool tun_standby (struct tuntap *tt);
diff --git a/version.m4 b/version.m4
index 8df30d5..4add313 100644
--- a/version.m4
+++ b/version.m4
@@ -1,5 +1,5 @@
dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1.1i])
+define(PRODUCT_VERSION,[2.1.1o])
dnl define the TAP version
define(PRODUCT_TAP_ID,[tap0901])
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])
diff --git a/win/build_exe.py b/win/build_exe.py
new file mode 100644
index 0000000..087f9a3
--- /dev/null
+++ b/win/build_exe.py
@@ -0,0 +1,15 @@
+from config import main as config_main
+from build import main as build_openvpn
+from build_ddk import main as build_ddk
+from sign import main as sign
+from make_dist import main as make_dist
+
+def main(config):
+ config_main(config)
+ build_openvpn()
+ make_dist(config, tap=False)
+
+# if we are run directly, and not loaded as a module
+if __name__ == "__main__":
+ from wb import config
+ main(config)
diff --git a/win/config.py b/win/config.py
index 67c1d82..cf38cac 100644
--- a/win/config.py
+++ b/win/config.py
@@ -9,6 +9,7 @@ def main(config):
out_fn=home_fn('msvc.mak'),
quote_begin='@',
quote_end='@',
+ if_prefix='!',
head_comment='# %s\n\n' % autogen)
# if we are run directly, and not loaded as a module
diff --git a/win/make_dist.py b/win/make_dist.py
index 3011279..a6a0563 100644
--- a/win/make_dist.py
+++ b/win/make_dist.py
@@ -1,7 +1,7 @@
import os
from wb import home_fn, rm_rf, mkdir, cp_a, cp
-def main(config):
+def main(config, tap=True):
dist = config['DIST']
assert dist
dist = home_fn(dist)
@@ -13,8 +13,9 @@ def main(config):
rm_rf(dist)
mkdir(dist)
mkdir(bin)
- mkdir(i386)
- mkdir(amd64)
+ if tap:
+ mkdir(i386)
+ mkdir(amd64)
# copy openvpn.exe and manifest
cp(home_fn('openvpn.exe'), bin)
@@ -28,25 +29,26 @@ def main(config):
# copy MSVC CRT
cp_a(home_fn(config['MSVC_CRT']), bin)
- # copy TAP drivers
- for dir_name, dest in (('amd64', amd64), ('i386', i386)):
- dir = home_fn(os.path.join('tap-win32', dir_name))
- for dirpath, dirnames, filenames in os.walk(dir):
+ if tap:
+ # copy TAP drivers
+ for dir_name, dest in (('amd64', amd64), ('i386', i386)):
+ dir = home_fn(os.path.join('tap-win32', dir_name))
+ for dirpath, dirnames, filenames in os.walk(dir):
+ for f in filenames:
+ root, ext = os.path.splitext(f)
+ if ext in ('.inf', '.cat', '.sys'):
+ cp(os.path.join(dir, f), dest)
+ break
+
+ # copy tapinstall
+ dest = {'amd64' : amd64, 'i386' : i386}
+ for dirpath, dirnames, filenames in os.walk(home_fn('tapinstall')):
for f in filenames:
- root, ext = os.path.splitext(f)
- if ext in ('.inf', '.cat', '.sys'):
- cp(os.path.join(dir, f), dest)
- break
-
- # copy tapinstall
- dest = {'amd64' : amd64, 'i386' : i386}
- for dirpath, dirnames, filenames in os.walk(home_fn('tapinstall')):
- for f in filenames:
- if f == 'tapinstall.exe':
- dir_name = os.path.basename(dirpath)
- src = os.path.join(dirpath, f)
- if dir_name in dest:
- cp(src, dest[dir_name])
+ if f == 'tapinstall.exe':
+ dir_name = os.path.basename(dirpath)
+ src = os.path.join(dirpath, f)
+ if dir_name in dest:
+ cp(src, dest[dir_name])
# if we are run directly, and not loaded as a module
if __name__ == "__main__":
diff --git a/win/msvc.mak.in b/win/msvc.mak.in
index 3f8102a..5d94a6e 100644
--- a/win/msvc.mak.in
+++ b/win/msvc.mak.in
@@ -23,17 +23,22 @@ LIB_DIRS = -LIBPATH:$(OPENSSL)\lib -LIBPATH:$(LZO)\lib
EXE = openvpn.exe
CPP=cl.exe
-CPP_ARG_COMMON=/nologo /W3 /O2 -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS -D_CRT_SECURE_NO_DEPRECATE $(INCLUDE_DIRS) /FD /c
-# release:
-CPP_PROJ=$(CPP_ARG_COMMON) /MD -DNDEBUG
-# debug:
-#CPP_PROJ=$(CPP_ARG_COMMON) /MDd /Zi /Od -D_DEBUG
+CPP_ARG_COMMON=/nologo /W3 -DWIN32 -DWIN32_LEAN_AND_MEAN -D_CONSOLE -D_MBCS -D_CRT_SECURE_NO_DEPRECATE $(INCLUDE_DIRS) /FD /c
LINK32=link.exe
-# release:
-LINK32_FLAGS=/nologo /subsystem:console /incremental:no /out:"$(EXE)"
+
+!ifdef PRODUCT_OPENVPN_DEBUG
# debug:
+CPP_PROJ=$(CPP_ARG_COMMON) /MD /Z7
+LINK32_FLAGS=/nologo /subsystem:console /incremental:no /opt:ref /opt:icf /debug /out:"$(EXE)"
+# old debug:
+#CPP_PROJ=$(CPP_ARG_COMMON) /MDd /Zi /Od -D_DEBUG
#LINK32_FLAGS=/nologo /subsystem:console /incremental:no /debug /out:"$(EXE)"
+!else
+# release:
+CPP_PROJ=$(CPP_ARG_COMMON) /O2 /MD -DNDEBUG
+LINK32_FLAGS=/nologo /subsystem:console /incremental:no /out:"$(EXE)"
+!endif
# HEADERS and OBJS definitions, automatically generated
@HEADERS_OBJS@
diff --git a/win/settings.in b/win/settings.in
index 044834a..0e1bb1c 100644
--- a/win/settings.in
+++ b/win/settings.in
@@ -40,6 +40,9 @@
# Build debugging version of TAP driver
;!define PRODUCT_TAP_DEBUG
+# Build debugging version of openvpn.exe
+;!define PRODUCT_OPENVPN_DEBUG
+
# DDK path -- currently Windows 7 WDK
!define DDK_PATH "c:/winddk/7600.16385.1"
;!define DDK_PATH "c:/winddk/6001.18002"
diff --git a/win32.c b/win32.c
index 8fa898f..7c9901e 100644
--- a/win32.c
+++ b/win32.c
@@ -952,6 +952,8 @@ int
openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags)
{
int ret = -1;
+ static bool exec_warn = false;
+
if (a && a->argv[0])
{
if (openvpn_execve_allowed (flags))
@@ -971,10 +973,8 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
/* fill in STARTUPINFO struct */
GetStartupInfo(&start_info);
start_info.cb = sizeof(start_info);
- start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ start_info.dwFlags = STARTF_USESHOWWINDOW;
start_info.wShowWindow = SW_HIDE;
- start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
- start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
if (CreateProcess (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info))
{
@@ -1004,9 +1004,10 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
ASSERT (0);
}
}
- else
+ else if (!exec_warn && (script_security < SSEC_SCRIPTS))
{
msg (M_WARN, SCRIPT_SECURITY_WARNING);
+ exec_warn = true;
}
}
else
@@ -1042,10 +1043,8 @@ fork_to_self (const char *cmdline)
/* fill in STARTUPINFO struct */
GetStartupInfo(&start_info);
start_info.cb = sizeof(start_info);
- start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
+ start_info.dwFlags = STARTF_USESHOWWINDOW;
start_info.wShowWindow = SW_HIDE;
- start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
- start_info.hStdOutput = start_info.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
if (CreateProcess (self_exe, cl, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info))
{
diff --git a/win32.h b/win32.h
index b661169..fcc3062 100644
--- a/win32.h
+++ b/win32.h
@@ -33,6 +33,8 @@
#define DEFAULT_WIN_SYS_PATH "C:\\WINDOWS" /* --win-sys default value */
#define NETSH_PATH_SUFFIX "\\system32\\netsh.exe"
#define WIN_ROUTE_PATH_SUFFIX "\\system32\\route.exe"
+#define WIN_IPCONFIG_PATH_SUFFIX "\\system32\\ipconfig.exe"
+#define WIN_NET_PATH_SUFFIX "\\system32\\net.exe"
/*
* Win32-specific OpenVPN code, targetted at the mingw