summaryrefslogtreecommitdiff
path: root/src/openvpn/options.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/options.c')
-rw-r--r--src/openvpn/options.c206
1 files changed, 169 insertions, 37 deletions
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 23af272..7741dbf 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -5,10 +5,8 @@
* packet encryption, packet authentication, and
* packet compression.
*
- * 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
+ * Copyright (C) 2002-2013 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2008-2013 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
@@ -100,9 +98,6 @@ const char title_string[] =
#ifdef ENABLE_PKCS11
" [PKCS11]"
#endif
-#ifdef ENABLE_EUREPHIA
- " [eurephia]"
-#endif
#if ENABLE_IP_PKTINFO
" [MH]"
#endif
@@ -248,6 +243,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"
@@ -572,6 +569,9 @@ static const char usage_message[] =
" by a Certificate Authority in --ca file.\n"
"--extra-certs file : one or more PEM certs that complete the cert chain.\n"
"--key file : Local private key in .pem format.\n"
+ "--tls-version-min <version> ['or-highest'] : sets the minimum TLS version we\n"
+ " will accept from the peer. If version is unrecognized and 'or-highest'\n"
+ " is specified, require max TLS version supported by SSL implementation.\n"
#ifndef ENABLE_CRYPTO_POLARSSL
"--pkcs12 file : PKCS#12 file containing local private key, local certificate\n"
" and optionally the root CA certificate.\n"
@@ -1979,6 +1979,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
#ifdef ENABLE_HTTP_PROXY
if ((ce->http_proxy_options) && ce->proto != PROTO_TCPv4_CLIENT)
msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)");
+ if ((ce->http_proxy_options) && !ce->http_proxy_options->server)
+ msg (M_USAGE, "--http-proxy not specified but other http proxy options present");
#endif
#if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_SOCKS)
@@ -2603,6 +2605,44 @@ check_file_access(const int type, const char *file, const int mode, const char *
return (errcode != 0 ? true : false);
}
+/* A wrapper for check_file_access() which also takes a chroot directory.
+ * If chroot is NULL, behaviour is exactly the same as calling check_file_access() directly,
+ * otherwise it will look for the file inside the given chroot directory instead.
+ */
+static bool
+check_file_access_chroot(const char *chroot, const int type, const char *file, const int mode, const char *opt)
+{
+ bool ret = false;
+
+ /* If no file configured, no errors to look for */
+ if (!file)
+ return false;
+
+ /* If chroot is set, look for the file/directory inside the chroot */
+ if( chroot )
+ {
+ struct gc_arena gc = gc_new();
+ struct buffer chroot_file;
+ int len = 0;
+
+ /* Build up a new full path including chroot directory */
+ len = strlen(chroot) + strlen(PATH_SEPARATOR_STR) + strlen(file) + 1;
+ chroot_file = alloc_buf_gc(len, &gc);
+ buf_printf(&chroot_file, "%s%s%s", chroot, PATH_SEPARATOR_STR, file);
+ ASSERT (chroot_file.len > 0);
+
+ ret = check_file_access(type, BSTR(&chroot_file), mode, opt);
+ gc_free(&gc);
+ }
+ else
+ {
+ /* No chroot in play, just call core file check function */
+ ret = check_file_access(type, file, mode, opt);
+ }
+ return ret;
+}
+
+
/*
* Verifies that the path in the "command" that comes after certain script options (e.g., --up) is a
* valid file with appropriate permissions.
@@ -2620,7 +2660,7 @@ check_file_access(const int type, const char *file, const int mode, const char *
* check_file_access() arguments.
*/
static bool
-check_cmd_access(const char *command, const char *opt)
+check_cmd_access(const char *command, const char *opt, const char *chroot)
{
struct argv argv;
bool return_code;
@@ -2639,7 +2679,7 @@ check_cmd_access(const char *command, const char *opt)
* only requires X_OK to function on Unix - a scenario not unlikely to
* be seen on suid binaries.
*/
- return_code = check_file_access(CHKACC_FILE, argv.argv[0], X_OK, opt);
+ return_code = check_file_access_chroot(chroot, CHKACC_FILE, argv.argv[0], X_OK, opt);
else
{
msg (M_NOPREFIX|M_OPTERR, "%s fails with '%s': No path to executable.",
@@ -2665,7 +2705,7 @@ options_postprocess_filechecks (struct options *options)
#ifdef ENABLE_SSL
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->dh_file, R_OK, "--dh");
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->ca_file, R_OK, "--ca");
- errs |= check_file_access (CHKACC_FILE, options->ca_path, R_OK, "--capath");
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->ca_path, R_OK, "--capath");
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->cert_file, R_OK, "--cert");
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->extra_certs_file, R_OK,
"--extra-certs");
@@ -2678,10 +2718,10 @@ options_postprocess_filechecks (struct options *options)
"--pkcs12");
if (options->ssl_flags & SSLF_CRL_VERIFY_DIR)
- errs |= check_file_access (CHKACC_FILE, options->crl_file, R_OK|X_OK,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK|X_OK,
"--crl-verify directory");
else
- errs |= check_file_access (CHKACC_FILE, options->crl_file, R_OK,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK,
"--crl-verify");
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->tls_auth_file, R_OK,
@@ -2723,13 +2763,13 @@ options_postprocess_filechecks (struct options *options)
/* ** Config related ** */
#ifdef ENABLE_SSL
- errs |= check_file_access (CHKACC_FILE, options->tls_export_cert,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tls_export_cert,
R_OK|W_OK|X_OK, "--tls-export-cert");
#endif /* ENABLE_SSL */
#if P2MP_SERVER
- errs |= check_file_access (CHKACC_FILE, options->client_config_dir,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->client_config_dir,
R_OK|X_OK, "--client-config-dir");
- errs |= check_file_access (CHKACC_FILE, options->tmp_dir,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tmp_dir,
R_OK|W_OK|X_OK, "Temporary directory (--tmp-dir)");
#endif /* P2MP_SERVER */
@@ -2829,6 +2869,7 @@ pre_pull_restore (struct options *o)
}
o->push_continuation = 0;
+ o->push_option_types_found = 0;
}
#endif
@@ -3806,7 +3847,7 @@ read_config_string (const char *prefix,
{
bypass_doubledash (&p[0]);
check_inline_file_via_buf (&multiline, p, &options->gc);
- add_option (options, p, NULL, line_num, 0, msglevel, permission_mask, option_types_found, es);
+ add_option (options, p, prefix, line_num, 0, msglevel, permission_mask, option_types_found, es);
}
CLEAR (p);
}
@@ -3926,27 +3967,43 @@ void options_string_import (struct options *options,
#if P2MP
-#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, (mask), permission_mask, option_types_found, msglevel)) goto err; }
+#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, line, (mask), permission_mask, option_types_found, msglevel, options)) goto err; }
static bool
verify_permission (const char *name,
const char* file,
+ int line,
const unsigned int type,
const unsigned int allowed,
unsigned int *found,
- const int msglevel)
+ const int msglevel,
+ struct options* options)
{
if (!(type & allowed))
{
msg (msglevel, "option '%s' cannot be used in this context (%s)", name, file);
return false;
}
- else
+
+ if (found)
+ *found |= type;
+
+#ifndef ENABLE_SMALL
+ /* Check if this options is allowed in connection block,
+ * but we are currently not in a connection block
+ * Parsing a connection block uses a temporary options struct without
+ * connection_list
+ */
+
+ if ((type & OPT_P_CONNECTION) && options->connection_list)
{
- if (found)
- *found |= type;
- return true;
+ if (file)
+ msg (M_WARN, "Option '%s' in %s:%d is ignored by previous <connection> blocks ", name, file, line);
+ else
+ msg (M_WARN, "Option '%s' is ignored by previous <connection> blocks", name);
}
+#endif
+ return true;
}
#else
@@ -3996,7 +4053,8 @@ static void
set_user_script (struct options *options,
const char **script,
const char *new_script,
- const char *type)
+ const char *type,
+ bool in_chroot)
{
if (*script) {
msg (M_WARN, "Multiple --%s scripts defined. "
@@ -4011,8 +4069,9 @@ set_user_script (struct options *options,
openvpn_snprintf (script_name, sizeof(script_name),
"--%s script", type);
- if (check_cmd_access (*script, script_name))
+ if (check_cmd_access (*script, script_name, (in_chroot ? options->chroot_dir : NULL)))
msg (M_USAGE, "Please correct this error.");
+
}
#endif
}
@@ -4033,7 +4092,18 @@ add_option (struct options *options,
const bool pull_mode = BOOL_CAST (permission_mask & OPT_P_PULL_MODE);
int msglevel_fc = msglevel_forward_compatible (options, msglevel);
- ASSERT (MAX_PARMS >= 5);
+ ASSERT (MAX_PARMS >= 7);
+
+ /*
+ * If directive begins with "setenv opt" prefix, don't raise an error if
+ * directive is unrecognized.
+ */
+ if (streq (p[0], "setenv") && p[1] && streq (p[1], "opt") && !(permission_mask & OPT_P_PULL_MODE))
+ {
+ p += 2;
+ msglevel_fc = M_WARN;
+ }
+
if (!file)
{
file = "[CMD-LINE]";
@@ -4394,6 +4464,43 @@ 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);
@@ -4482,7 +4589,7 @@ add_option (struct options *options,
set_user_script (options,
&options->ipchange,
string_substitute (p[1], ',', ' ', &options->gc),
- "ipchange");
+ "ipchange", true);
}
else if (streq (p[0], "float"))
{
@@ -4528,14 +4635,14 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- set_user_script (options, &options->up_script, p[1], "up");
+ set_user_script (options, &options->up_script, p[1], "up", false);
}
else if (streq (p[0], "down") && p[1])
{
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- set_user_script (options, &options->down_script, p[1], "down");
+ set_user_script (options, &options->down_script, p[1], "down", true);
}
else if (streq (p[0], "down-pre"))
{
@@ -5216,7 +5323,7 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- set_user_script (options, &options->route_script, p[1], "route-up");
+ set_user_script (options, &options->route_script, p[1], "route-up", false);
}
else if (streq (p[0], "route-pre-down") && p[1])
{
@@ -5226,7 +5333,7 @@ add_option (struct options *options,
set_user_script (options,
&options->route_predown_script,
p[1],
- "route-pre-down");
+ "route-pre-down", true);
}
else if (streq (p[0], "route-noexec"))
{
@@ -5595,7 +5702,7 @@ add_option (struct options *options,
}
set_user_script (options,
&options->auth_user_pass_verify_script,
- p[1], "auth-user-pass-verify");
+ p[1], "auth-user-pass-verify", true);
}
else if (streq (p[0], "client-connect") && p[1])
{
@@ -5603,7 +5710,7 @@ add_option (struct options *options,
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
set_user_script (options, &options->client_connect_script,
- p[1], "client-connect");
+ p[1], "client-connect", true);
}
else if (streq (p[0], "client-disconnect") && p[1])
{
@@ -5611,7 +5718,7 @@ add_option (struct options *options,
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
set_user_script (options, &options->client_disconnect_script,
- p[1], "client-disconnect");
+ p[1], "client-disconnect", true);
}
else if (streq (p[0], "learn-address") && p[1])
{
@@ -5619,7 +5726,7 @@ add_option (struct options *options,
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
set_user_script (options, &options->learn_address_script,
- p[1], "learn-address");
+ p[1], "learn-address", true);
}
else if (streq (p[0], "tmp-dir") && p[1])
{
@@ -6438,6 +6545,19 @@ add_option (struct options *options,
options->priv_key_file_inline = p[2];
}
}
+ else if (streq (p[0], "tls-version-min") && p[1])
+ {
+ int ver;
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ ver = tls_version_min_parse(p[1], p[2]);
+ if (ver == TLS_VER_BAD)
+ {
+ msg (msglevel, "unknown tls-version-min parameter: %s", p[1]);
+ goto err;
+ }
+ options->ssl_flags &= ~(SSLF_TLS_VERSION_MASK << SSLF_TLS_VERSION_SHIFT);
+ options->ssl_flags |= (ver << SSLF_TLS_VERSION_SHIFT);
+ }
#ifndef ENABLE_CRYPTO_POLARSSL
else if (streq (p[0], "pkcs12") && p[1])
{
@@ -6509,7 +6629,7 @@ add_option (struct options *options,
goto err;
set_user_script (options, &options->tls_verify,
string_substitute (p[1], ',', ' ', &options->gc),
- "tls-verify");
+ "tls-verify", true);
}
#ifndef ENABLE_CRYPTO_POLARSSL
else if (streq (p[0], "tls-export-cert") && p[1])
@@ -6823,10 +6943,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);