summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2013-08-18 17:53:34 +0200
committerArne Schwabe <arne@rfc2549.org>2013-08-18 17:53:34 +0200
commit3a94f66677fe7b5ae3ecd5743462318d322010e4 (patch)
tree2a0a74d9a5ef3b4b028d9f76574f27ec8325ebfc
parent94c32221defb9ce513505148f5ae3a037f6a1adc (diff)
Rebase OpenVPN to -master
--HG-- extra : rebase_source : 37025b323cf5e6497cbc92744a32b0b69e397af8
-rw-r--r--openvpn/doc/openvpn.826
-rw-r--r--openvpn/src/openvpn/init.c10
-rw-r--r--openvpn/src/openvpn/misc.c56
-rw-r--r--openvpn/src/openvpn/misc.h7
-rw-r--r--openvpn/src/openvpn/multi.c52
-rw-r--r--openvpn/src/openvpn/multi.h3
-rw-r--r--openvpn/src/openvpn/options.c60
-rw-r--r--openvpn/src/openvpn/options.h2
-rw-r--r--openvpn/src/openvpn/socket.c1
-rw-r--r--openvpn/src/openvpn/socket.h2
-rw-r--r--openvpn/src/openvpn/ssl.c2
-rw-r--r--openvpn/src/openvpn/ssl_openssl.c27
-rw-r--r--openvpn/src/openvpn/win32.c6
13 files changed, 182 insertions, 72 deletions
diff --git a/openvpn/doc/openvpn.8 b/openvpn/doc/openvpn.8
index 868fb841..573d6a80 100644
--- a/openvpn/doc/openvpn.8
+++ b/openvpn/doc/openvpn.8
@@ -1895,6 +1895,13 @@ It is also possible to tag a single directive so as not to trigger
a fatal error if the directive isn't recognized. To do this,
prepend the following before the directive:
.B setenv opt
+
+Versions prior to OpenVPN 2.3.3 will always ignore options set with the
+.B setenv opt
+directive.
+
+See also
+.B \-\-ignore-unknown-option
.\"*********************************************************
.TP
.B \-\-setenv-safe name value
@@ -1908,6 +1915,25 @@ is a safety precaution to prevent a LD_PRELOAD style attack
from a malicious or compromised server.
.\"*********************************************************
.TP
+.B \-\-ignore-unknown-option opt1 opt2 opt3 ... optN
+When one of options
+.B opt1 ... optN
+is encountered in the configuration file the configuration
+file parsing does not fail if this OpenVPN version does not
+support the option. Multiple
+.B \-\-ignore-unknown-option
+options can be given to support a larger number of options to ignore.
+
+This option should be used with caution, as there are good security
+reasons for having OpenVPN fail if it detects problems in a
+config file. Having said that, there are valid reasons for wanting
+new software features to gracefully degrade when encountered by
+older software versions.
+
+.B \-\-ignore-unknown-option
+is available since OpenVPN 2.3.3.
+.\"*********************************************************
+.TP
.B \-\-script-security level
This directive offers policy-level control over OpenVPN's usage of external programs
and scripts. Lower
diff --git a/openvpn/src/openvpn/init.c b/openvpn/src/openvpn/init.c
index c288e924..8cd136d5 100644
--- a/openvpn/src/openvpn/init.c
+++ b/openvpn/src/openvpn/init.c
@@ -174,10 +174,12 @@ ce_management_query_proxy (struct context *c)
if (management)
{
gc = gc_new ();
- struct buffer out = alloc_buf_gc (256, &gc);
- buf_printf (&out, ">PROXY:%u,%s,%s", (l ? l->current : 0) + 1,
- (proto_is_udp (ce->proto) ? "UDP" : "TCP"), np (ce->remote));
- management_notify_generic (management, BSTR (&out));
+ {
+ struct buffer out = alloc_buf_gc (256, &gc);
+ buf_printf (&out, ">PROXY:%u,%s,%s", (l ? l->current : 0) + 1,
+ (proto_is_udp (ce->proto) ? "UDP" : "TCP"), np (ce->remote));
+ management_notify_generic (management, BSTR (&out));
+ }
ce->flags |= CE_MAN_QUERY_PROXY;
while (ce->flags & CE_MAN_QUERY_PROXY)
{
diff --git a/openvpn/src/openvpn/misc.c b/openvpn/src/openvpn/misc.c
index 1120adc4..4688444e 100644
--- a/openvpn/src/openvpn/misc.c
+++ b/openvpn/src/openvpn/misc.c
@@ -2063,3 +2063,59 @@ compat_flag (unsigned int flag)
return (compat_flags & (flag >> 1));
}
+
+#if P2MP_SERVER
+
+/* helper to parse peer_info received from multi client, validate
+ * (this is untrusted data) and put into environment
+ */
+bool
+validate_peer_info_line(char *line)
+{
+ uint8_t c;
+ int state = 0;
+ while (*line)
+ {
+ c = *line;
+ switch (state)
+ {
+ case 0:
+ case 1:
+ if (c == '=' && state == 1)
+ state = 2;
+ else if (isalnum(c) || c == '_')
+ state = 1;
+ else
+ return false;
+ case 2:
+ /* after the '=', replace non-printable or shell meta with '_' */
+ if (!isprint(c) || isspace(c) ||
+ c == '$' || c == '(' || c == '`' )
+ *line = '_';
+ }
+ line++;
+ }
+ return (state == 2);
+}
+
+void
+output_peer_info_env (struct env_set *es, const char * peer_info)
+{
+ char line[256];
+ struct buffer buf;
+ buf_set_read (&buf, (const uint8_t *) peer_info, strlen(peer_info));
+ while (buf_parse (&buf, '\n', line, sizeof (line)))
+ {
+ chomp (line);
+ if (validate_peer_info_line(line) &&
+ (strncmp(line, "IV_", 3) == 0 || strncmp(line, "UV_", 3) == 0) )
+ {
+ msg (M_INFO, "peer info: %s", line);
+ env_set_add(es, line);
+ }
+ else
+ msg (M_WARN, "validation failed on peer_info line received from client");
+ }
+}
+
+#endif /* P2MP_SERVER */
diff --git a/openvpn/src/openvpn/misc.h b/openvpn/src/openvpn/misc.h
index 183898e3..41748bd8 100644
--- a/openvpn/src/openvpn/misc.h
+++ b/openvpn/src/openvpn/misc.h
@@ -369,4 +369,11 @@ void argv_printf_cat (struct argv *a, const char *format, ...)
#define COMPAT_NO_NAME_REMAPPING (1<<2) /** compat flag: --compat-names without char remapping */
bool compat_flag (unsigned int flag);
+#if P2MP_SERVER
+/* helper to parse peer_info received from multi client, validate
+ * (this is untrusted data) and put into environment */
+bool validate_peer_info_line(char *line);
+void output_peer_info_env (struct env_set *es, const char * peer_info);
+#endif /* P2MP_SERVER */
+
#endif
diff --git a/openvpn/src/openvpn/multi.c b/openvpn/src/openvpn/multi.c
index 50f398dd..f016b149 100644
--- a/openvpn/src/openvpn/multi.c
+++ b/openvpn/src/openvpn/multi.c
@@ -1562,58 +1562,6 @@ multi_client_connect_mda (struct multi_context *m,
#endif
-/* helper to parse peer_info received from multi client, validate
- * (this is untrusted data) and put into environment
- */
-bool
-validate_peer_info_line(char *line)
-{
- uint8_t c;
- int state = 0;
- while (*line)
- {
- c = *line;
- switch (state)
- {
- case 0:
- case 1:
- if (c == '=' && state == 1)
- state = 2;
- else if (isalnum(c) || c == '_')
- state = 1;
- else
- return false;
- case 2:
- /* after the '=', replace non-printable or shell meta with '_' */
- if (!isprint(c) || isspace(c) ||
- c == '$' || c == '(' || c == '`' )
- *line = '_';
- }
- line++;
- }
- return (state == 2);
-}
-
-void
-multi_output_peer_info_env (struct env_set *es, const char * peer_info)
-{
- char line[256];
- struct buffer buf;
- buf_set_read (&buf, (const uint8_t *) peer_info, strlen(peer_info));
- while (buf_parse (&buf, '\n', line, sizeof (line)))
- {
- chomp (line);
- if (validate_peer_info_line(line) &&
- (strncmp(line, "IV_", 3) == 0 || strncmp(line, "UV_", 3) == 0) )
- {
- msg (M_INFO, "peer info: %s", line);
- env_set_add(es, line);
- }
- else
- msg (M_WARN, "validation failed on peer_info line received from client");
- }
-}
-
static void
multi_client_connect_setenv (struct multi_context *m,
struct multi_instance *mi)
diff --git a/openvpn/src/openvpn/multi.h b/openvpn/src/openvpn/multi.h
index 7b97b0d2..fc2ffb24 100644
--- a/openvpn/src/openvpn/multi.h
+++ b/openvpn/src/openvpn/multi.h
@@ -312,9 +312,6 @@ void multi_close_instance_on_signal (struct multi_context *m, struct multi_insta
void init_management_callback_multi (struct multi_context *m);
void uninit_management_callback_multi (struct multi_context *m);
-bool validate_peer_info_line(char *line);
-void multi_output_peer_info_env (struct env_set *es, const char * peer_info);
-
/*
* Return true if our output queue is not full
*/
diff --git a/openvpn/src/openvpn/options.c b/openvpn/src/openvpn/options.c
index 48065f99..8b98b45f 100644
--- a/openvpn/src/openvpn/options.c
+++ b/openvpn/src/openvpn/options.c
@@ -250,6 +250,8 @@ static const char usage_message[] =
"--setenv name value : Set a custom environmental variable to pass to script.\n"
"--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n"
" directives for future OpenVPN versions to be ignored.\n"
+ "--ignore-unkown-option opt1 opt2 ...: Relax config file syntax. Allow\n"
+ " these options to be ignored when unknown\n"
"--script-security level: Where level can be:\n"
" 0 -- strictly no calling of external programs\n"
" 1 -- (default) only call built-ins such as ifconfig\n"
@@ -4371,6 +4373,48 @@ add_option (struct options *options,
uninit_options (&sub);
}
}
+ else if (streq (p[0], "ignore-unknown-option") && p[1])
+ {
+ int i;
+ int j;
+ int numignored=0;
+ const char **ignore;
+
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ /* Find out how many options to be ignored */
+ for (i=1;p[i];i++)
+ numignored++;
+
+ /* add number of options already ignored */
+ for (i=0;options->ignore_unknown_option &&
+ options->ignore_unknown_option[i]; i++)
+ numignored++;
+
+ /* Allocate array */
+ ALLOC_ARRAY_GC (ignore, const char*, numignored+1, &options->gc);
+ for (i=0;options->ignore_unknown_option &&
+ options->ignore_unknown_option[i]; i++)
+ ignore[i]=options->ignore_unknown_option[i];
+
+ options->ignore_unknown_option=ignore;
+
+ for (j=1;p[j];j++)
+ {
+ /* Allow the user to specify ignore-unknown-option --opt too */
+ if (p[j][0]=='-' && p[j][1]=='-')
+ options->ignore_unknown_option[i] = (p[j]+2);
+ else
+ options->ignore_unknown_option[i] = p[j];
+ i++;
+ }
+
+ options->ignore_unknown_option[i] = NULL;
+ }
+ else if (streq (p[0], "remote-ip-hint") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->remote_ip_hint = p[1];
+ }
#if HTTP_PROXY_OVERRIDE
else if (streq (p[0], "http-proxy-override") && p[1] && p[2])
{
@@ -6815,10 +6859,22 @@ add_option (struct options *options,
#endif
else
{
+ int i;
+ int msglevel= msglevel_fc;
+ /* Check if an option is in --ignore-unknown-option and
+ set warning level to non fatal */
+ for(i=0; options->ignore_unknown_option && options->ignore_unknown_option[i]; i++)
+ {
+ if (streq(p[0], options->ignore_unknown_option[i]))
+ {
+ msglevel = M_WARN;
+ break;
+ }
+ }
if (file)
- msg (msglevel_fc, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION);
+ msg (msglevel, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION);
else
- msg (msglevel_fc, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION);
+ msg (msglevel, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION);
}
err:
gc_free (&gc);
diff --git a/openvpn/src/openvpn/options.h b/openvpn/src/openvpn/options.h
index cc92da32..86760bbf 100644
--- a/openvpn/src/openvpn/options.h
+++ b/openvpn/src/openvpn/options.h
@@ -186,6 +186,8 @@ struct options
/* enable forward compatibility for post-2.1 features */
bool forward_compatible;
+ /* list of options that should be ignored even if unkown */
+ const char ** ignore_unknown_option;
/* persist parms */
bool persist_config;
diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c
index 115caaac..ee44ad3c 100644
--- a/openvpn/src/openvpn/socket.c
+++ b/openvpn/src/openvpn/socket.c
@@ -1191,7 +1191,6 @@ resolve_remote (struct link_socket *sock,
unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
int retry = 0;
int status = -1;
-
if (proto_is_dgram(sock->info.proto))
flags |= GETADDR_DATAGRAM;
diff --git a/openvpn/src/openvpn/socket.h b/openvpn/src/openvpn/socket.h
index 2b134486..d077a153 100644
--- a/openvpn/src/openvpn/socket.h
+++ b/openvpn/src/openvpn/socket.h
@@ -1109,7 +1109,7 @@ static inline void
link_socket_set_tos (struct link_socket *ls)
{
if (ls && ls->ptos_defined)
- setsockopt (ls->sd, IPPROTO_IP, IP_TOS, &ls->ptos, sizeof (ls->ptos));
+ setsockopt (ls->sd, IPPROTO_IP, IP_TOS, (const void *)&ls->ptos, sizeof (ls->ptos));
}
#endif
diff --git a/openvpn/src/openvpn/ssl.c b/openvpn/src/openvpn/ssl.c
index f78cca88..60f5f67f 100644
--- a/openvpn/src/openvpn/ssl.c
+++ b/openvpn/src/openvpn/ssl.c
@@ -2065,7 +2065,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
free (multi->peer_info);
multi->peer_info = read_string_alloc (buf);
if ( multi->peer_info )
- multi_output_peer_info_env (session->opt->es, multi->peer_info);
+ output_peer_info_env (session->opt->es, multi->peer_info);
#endif
if (verify_user_pass_enabled(session))
diff --git a/openvpn/src/openvpn/ssl_openssl.c b/openvpn/src/openvpn/ssl_openssl.c
index 12c725d9..f64177a8 100644
--- a/openvpn/src/openvpn/ssl_openssl.c
+++ b/openvpn/src/openvpn/ssl_openssl.c
@@ -242,8 +242,7 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
const tls_cipher_name_pair *cipher_pair;
- const size_t openssl_ciphers_size = 4096;
- char openssl_ciphers[openssl_ciphers_size];
+ char openssl_ciphers[4096];
size_t openssl_ciphers_len = 0;
openssl_ciphers[0] = '\0';
@@ -282,8 +281,8 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
}
// Make sure new cipher name fits in cipher string
- if (((openssl_ciphers_size-1) - openssl_ciphers_len) < current_cipher_len) {
- msg(M_SSLERR, "Failed to set restricted TLS cipher list, too long (>%zu).", openssl_ciphers_size-1);
+ if (((sizeof(openssl_ciphers)-1) - openssl_ciphers_len) < current_cipher_len) {
+ msg(M_SSLERR, "Failed to set restricted TLS cipher list, too long (>%d).", (int)sizeof(openssl_ciphers)-1);
}
// Concatenate cipher name to OpenSSL cipher string
@@ -413,16 +412,34 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
/* Set Certificate Verification chain */
if (load_ca_file)
{
+ /* Add CAs from PKCS12 to the cert store and mark them as trusted.
+ * They're also used to fill in the chain of intermediate certs as
+ * necessary.
+ */
if (ca && sk_X509_num(ca))
{
for (i = 0; i < sk_X509_num(ca); i++)
{
- if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i)))
+ if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i)))
msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)");
if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i)))
msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)");
}
}
+ } else {
+ /* If trusted CA certs were loaded from a PEM file, and we ignore the
+ * ones in PKCS12, do load PKCS12-provided certs to the client extra
+ * certs chain just in case they include intermediate CAs needed to
+ * prove my identity to the other end. This does not make them trusted.
+ */
+ if (ca && sk_X509_num(ca))
+ {
+ for (i = 0; i < sk_X509_num(ca); i++)
+ {
+ if (!SSL_CTX_add_extra_chain_cert(ctx->ctx,sk_X509_value(ca, i)))
+ msg (M_SSLERR, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)");
+ }
+ }
}
return 0;
}
diff --git a/openvpn/src/openvpn/win32.c b/openvpn/src/openvpn/win32.c
index 178e2c35..022eec5c 100644
--- a/openvpn/src/openvpn/win32.c
+++ b/openvpn/src/openvpn/win32.c
@@ -870,6 +870,9 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
WCHAR *cl = wide_cmd_line (a, &gc);
WCHAR *cmd = wide_string (a->argv[0], &gc);
+ /* this allows console programs to run, and is ignored otherwise */
+ DWORD proc_flags = CREATE_NO_WINDOW;
+
CLEAR (start_info);
CLEAR (proc_info);
@@ -879,9 +882,6 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
start_info.dwFlags = STARTF_USESHOWWINDOW;
start_info.wShowWindow = SW_HIDE;
- /* this allows console programs to run, and is ignored otherwise */
- DWORD proc_flags = CREATE_NO_WINDOW;
-
if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, proc_flags, env, NULL, &start_info, &proc_info))
{
DWORD exit_status = 0;