From 1e28d5b352e3aeb9a4e94720595e5e82bf83503b Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Thu, 2 Feb 2023 21:36:36 +0100 Subject: [PATCH] VPN:OpenVPN: Servers - deferred authentication, work in progress for https://github.com/opnsense/core/issues/6293 This initial commit focusses on structuring the event flow around user and client registration, moving events to our new ovpn_event.py handler. By supporting both deferred and direct authentication in user_pass_verify.php, we should be able to start with a cleanup patch for OpenVPN 2.5.x and work our way up to a smaller fix for 2.6.x. In preperation for 2.6, this commit also moves --cipher to --data-ciphers-fallback as suggested by the warning "DEPRECATED OPTION: --cipher set to '' but missing in --data-ciphers". Rename the option in the gui while there and add a note in the help text. --- plist | 4 - src/etc/inc/plugins.inc.d/openvpn.inc | 35 ++--- .../inc/plugins.inc.d/openvpn/attributes.sh | 8 - .../plugins.inc.d/openvpn/ovpn_auth_verify | 14 -- .../scripts/openvpn/client_connect.php} | 20 ++- .../scripts/openvpn/client_disconnect.sh | 6 + src/opnsense/scripts/openvpn/ovpn_event.py | 99 ++++++++++++ .../scripts/openvpn/tls_verify.php} | 63 +++++--- .../scripts/openvpn/user_pass_verify.php} | 144 ++++++++++-------- src/wizard/openvpn.xml | 4 +- src/www/vpn_openvpn_client.php | 13 +- src/www/vpn_openvpn_server.php | 15 +- 12 files changed, 266 insertions(+), 159 deletions(-) delete mode 100755 src/etc/inc/plugins.inc.d/openvpn/attributes.sh delete mode 100755 src/etc/inc/plugins.inc.d/openvpn/ovpn_auth_verify rename src/{etc/inc/plugins.inc.d/openvpn/ovpn_setup_cso.php => opnsense/scripts/openvpn/client_connect.php} (76%) create mode 100755 src/opnsense/scripts/openvpn/client_disconnect.sh create mode 100755 src/opnsense/scripts/openvpn/ovpn_event.py rename src/{etc/inc/plugins.inc.d/openvpn/tls-verify.php => opnsense/scripts/openvpn/tls_verify.php} (50%) mode change 100644 => 100755 rename src/{etc/inc/plugins.inc.d/openvpn/auth-user.php => opnsense/scripts/openvpn/user_pass_verify.php} (57%) mode change 100644 => 100755 diff --git a/plist b/plist index c3acaa8f4..884dd2dff 100644 --- a/plist +++ b/plist @@ -32,14 +32,10 @@ /usr/local/etc/inc/plugins.inc.d/opendns.inc /usr/local/etc/inc/plugins.inc.d/openssh.inc /usr/local/etc/inc/plugins.inc.d/openvpn.inc -/usr/local/etc/inc/plugins.inc.d/openvpn/attributes.sh -/usr/local/etc/inc/plugins.inc.d/openvpn/auth-user.php /usr/local/etc/inc/plugins.inc.d/openvpn/dh.rfc7919 /usr/local/etc/inc/plugins.inc.d/openvpn/ovpn-linkdown /usr/local/etc/inc/plugins.inc.d/openvpn/ovpn-linkup -/usr/local/etc/inc/plugins.inc.d/openvpn/ovpn_auth_verify /usr/local/etc/inc/plugins.inc.d/openvpn/ovpn_setup_cso.php -/usr/local/etc/inc/plugins.inc.d/openvpn/tls-verify.php /usr/local/etc/inc/plugins.inc.d/openvpn/tunnel_endpoint.php /usr/local/etc/inc/plugins.inc.d/openvpn/wizard.inc /usr/local/etc/inc/plugins.inc.d/pf.inc diff --git a/src/etc/inc/plugins.inc.d/openvpn.inc b/src/etc/inc/plugins.inc.d/openvpn.inc index bbf2ba8a7..3e34906bf 100644 --- a/src/etc/inc/plugins.inc.d/openvpn.inc +++ b/src/etc/inc/plugins.inc.d/openvpn.inc @@ -295,7 +295,7 @@ function openvpn_port_next($prot, $interface = "wan") function openvpn_get_cipherlist() { - $ciphers = array(); + $ciphers = ["" => gettext("None")]; exec('/usr/local/sbin/openvpn --show-ciphers', $lines); foreach ($lines as $line) { if (strstr($line, ' (') !== false) { @@ -304,7 +304,6 @@ function openvpn_get_cipherlist() } } ksort($ciphers, SORT_STRING | SORT_FLAG_CASE); - $ciphers['none'] = gettext('None (No Encryption)'); return $ciphers; } @@ -528,7 +527,9 @@ function openvpn_reconfigure($mode, $settings, $device_only = false) $conf .= "persist-tun\n"; $conf .= "persist-key\n"; $conf .= "proto {$proto}\n"; - $conf .= "cipher {$cipher}\n"; + if (!empty($cipher) && $cipher != 'none') { + $conf .= "data-ciphers-fallback {$cipher}\n"; + } $conf .= "auth {$digest}\n"; $conf .= "up /usr/local/etc/inc/plugins.inc.d/openvpn/ovpn-linkup\n"; $conf .= "down /usr/local/etc/inc/plugins.inc.d/openvpn/ovpn-linkdown\n"; @@ -549,20 +550,20 @@ function openvpn_reconfigure($mode, $settings, $device_only = false) switch ($settings['mode']) { case 'server_user': case 'server_tls_user': - $conf .= "client-disconnect \"/usr/local/etc/inc/plugins.inc.d/openvpn/attributes.sh {$mode_id}\"\n"; + $conf .= "client-disconnect \"/usr/local/opnsense/scripts/openvpn/ovpn_event.py '{$vpnid}'\"\n"; break; case 'server_tls': // For non user auth types setup client specific overrides, // user authenticated ones are commissioned using the auth // script in option auth-user-pass-verify. - $conf .= "client-connect \"/usr/local/etc/inc/plugins.inc.d/openvpn/ovpn_setup_cso.php {$mode_id}\"\n"; + $conf .= "client-connect \"/usr/local/opnsense/scripts/openvpn/ovpn_event.py '{$vpnid}'\"\n"; break; case 'p2p_tls': // same as server_tls, but only valid if cidr < 30, without // server directive client-connect is not valid. // XXX: IPv6 is likely flawed, see "server" directive too. if (!empty($ip) && !empty($mask) && ($cidr < 30)) { - $conf .= "client-connect \"/usr/local/etc/inc/plugins.inc.d/openvpn/ovpn_setup_cso.php {$mode_id}\"\n"; + $conf .= "client-connect \"/usr/local/opnsense/scripts/openvpn/ovpn_event.py '{$vpnid}'\"\n"; } break; default: @@ -664,28 +665,12 @@ function openvpn_reconfigure($mode, $settings, $device_only = false) $conf .= "username-as-common-name\n"; } if (!empty($settings['authmode'])) { - $strictusercn = "false"; - if ($settings['strictusercn']) { - $strictusercn = "true"; - } - $conf .= "auth-user-pass-verify \"/usr/local/etc/inc/plugins.inc.d/openvpn/ovpn_auth_verify " . - "user '{$settings['authmode']}' '{$strictusercn}' '{$mode_id}'\" via-env\n"; + $conf .= "auth-user-pass-verify \"/usr/local/opnsense/scripts/openvpn/ovpn_event.py '{$vpnid}'\" via-env\n"; } break; } - if (!isset($settings['cert_depth']) && (strstr($settings['mode'], 'tls'))) { - $settings['cert_depth'] = 1; - } - if (is_numeric($settings['cert_depth'])) { - if (($mode == 'client') && empty($settings['certref'])) { - $cert = ""; - } else { - $cert = lookup_cert($settings['certref']); - /* XXX: Seems not used at all! */ - $servercn = urlencode(cert_get_cn($cert['crt'])); - $conf .= "tls-verify \"/usr/local/etc/inc/plugins.inc.d/openvpn/ovpn_auth_verify " . - "tls '{$servercn}' {$settings['cert_depth']}\"\n"; - } + if ($mode == 'server' && (strstr($settings['mode'], 'tls'))) { + $conf .= "tls-verify \"/usr/local/opnsense/scripts/openvpn/ovpn_event.py '{$vpnid}'\"\n"; } // The local port to listen on diff --git a/src/etc/inc/plugins.inc.d/openvpn/attributes.sh b/src/etc/inc/plugins.inc.d/openvpn/attributes.sh deleted file mode 100755 index 942cac6b4..000000000 --- a/src/etc/inc/plugins.inc.d/openvpn/attributes.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -if [ "$script_type" = "client-disconnect" ]; then - /sbin/pfctl -k $ifconfig_pool_remote_ip - /sbin/pfctl -K $ifconfig_pool_remote_ip -fi - -exit 0 diff --git a/src/etc/inc/plugins.inc.d/openvpn/ovpn_auth_verify b/src/etc/inc/plugins.inc.d/openvpn/ovpn_auth_verify deleted file mode 100755 index a45cab0ec..000000000 --- a/src/etc/inc/plugins.inc.d/openvpn/ovpn_auth_verify +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -if [ "$1" = "tls" ]; then - /usr/local/bin/php /usr/local/etc/inc/plugins.inc.d/openvpn/tls-verify.php -d "$2" "$3" -else - # Single quoting $password breaks getting the value from the variable. - # XXX I really don't like going through openssl for this... - password=$(echo -n "${password}" | /usr/local/bin/openssl enc -base64 | sed -e 's/=/%3D/g') - username=$(echo -n "${username}" | /usr/local/bin/openssl enc -base64 | sed -e 's/=/%3D/g') - - /usr/local/bin/php /usr/local/etc/inc/plugins.inc.d/openvpn/auth-user.php "$username" "$password" "$common_name" "$3" "$2" "$4" -fi - -exit $? diff --git a/src/etc/inc/plugins.inc.d/openvpn/ovpn_setup_cso.php b/src/opnsense/scripts/openvpn/client_connect.php similarity index 76% rename from src/etc/inc/plugins.inc.d/openvpn/ovpn_setup_cso.php rename to src/opnsense/scripts/openvpn/client_connect.php index 28080b5c9..630d8cf18 100755 --- a/src/etc/inc/plugins.inc.d/openvpn/ovpn_setup_cso.php +++ b/src/opnsense/scripts/openvpn/client_connect.php @@ -2,7 +2,7 @@ $common_name); + $cso = ["common_name" => $common_name]; } - // $argv[2] contains the temporary file used for the profile specified by client-connect - $cso_filename = openvpn_csc_conf_write($cso, $server, $argv[2]); + if (!empty($config_file)) { + $cso_filename = openvpn_csc_conf_write($cso, $server, $config_file); if (!empty($cso_filename)) { syslog(LOG_NOTICE, "client config created @ {$cso_filename}"); } + } else { + syslog(LOG_NOTICE, "unable to write client config for {$common_name}, missing target filename"); + } break; } } } closelog(); -exit(0); +exit(0); \ No newline at end of file diff --git a/src/opnsense/scripts/openvpn/client_disconnect.sh b/src/opnsense/scripts/openvpn/client_disconnect.sh new file mode 100755 index 000000000..56647bcbb --- /dev/null +++ b/src/opnsense/scripts/openvpn/client_disconnect.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +/sbin/pfctl -k $ifconfig_pool_remote_ip +/sbin/pfctl -K $ifconfig_pool_remote_ip + +exit 0 diff --git a/src/opnsense/scripts/openvpn/ovpn_event.py b/src/opnsense/scripts/openvpn/ovpn_event.py new file mode 100755 index 000000000..566aea8af --- /dev/null +++ b/src/opnsense/scripts/openvpn/ovpn_event.py @@ -0,0 +1,99 @@ +#!/usr/local/bin/python3 + +""" + Copyright (c) 2023 Ad Schellevis + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +""" + +import argparse +import sys +import os +import subprocess + + +def main(params): + if params.common_name: + os.environ['common_name'] = params.common_name + if params.auth_control_file: + os.environ['auth_control_file'] = params.auth_control_file + if params.server: + os.environ["auth_server"] = params.server + # script action + cmd_path = "%s/" % os.path.dirname(__file__) + if params.script_type == 'user-pass-verify': + os.environ["auth_method"] = params.auth_method + if params.auth_method == 'via-file' and len(params.args) > 0: + # user/password file to read (via-file), arg1 + os.environ["auth_file"] = params.args[0] + if params.defer: + os.environ["auth_defer"] = 'true' + if os.fork() != 0: + # When deferred, openvpn expects exit code 2 (see help --auth-user-pass-verify) + sys.exit(2) + + # dispatch user_pass_verify + sys.exit(subprocess.run("%s/user_pass_verify.php" % cmd_path).returncode) + elif params.script_type == 'tls-verify': + if len(params.args) > 0: + os.environ["certificate_depth"] = params.args[0] + sys.exit(subprocess.run("%s/tls_verify.php" % cmd_path).returncode) + elif params.script_type == 'client-connect': + # Temporary file used for the profile specified by client-connect + if len(params.args) > 0: + os.environ["config_file"] = params.args[0] + sys.exit(subprocess.run("%s/client_connect.php" % cmd_path).returncode) + elif params.script_type == 'client-disconnect': + sys.exit(subprocess.run("%s/client_disconnect.sh" % cmd_path).returncode) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument( + '--common_name', + help='common name [cn], defaults to "common_name" in environment', + default=os.environ.get('common_name', None) + ) + parser.add_argument( + '--script_type', + help='script_type (event), defaults to "script_type" in environment', + default=os.environ.get('script_type', None), + choices=['user-pass-verify', 'tls-verify', 'client-connect', 'client-disconnect'] + ) + parser.add_argument( + '--auth_control_file', + help='auth control file location, defaults to "auth_control_file" in environment', + default=os.environ.get('auth_control_file', None) + ) + parser.add_argument( + '--auth_method', + help='auth method (via-env or via-file)', + default='via-env', + choices=['via-env', 'via-file'] + ) + parser.add_argument('--defer', help='defer action (when supported)', default=False, action="store_true") + parser.add_argument('server', help='openvpn server id to use, authentication settings are configured per server') + parser.add_argument('args', nargs='*', help='script arguments specified by openvpn') + + main(parser.parse_args()) diff --git a/src/etc/inc/plugins.inc.d/openvpn/tls-verify.php b/src/opnsense/scripts/openvpn/tls_verify.php old mode 100644 new mode 100755 similarity index 50% rename from src/etc/inc/plugins.inc.d/openvpn/tls-verify.php rename to src/opnsense/scripts/openvpn/tls_verify.php index ea4212bc1..d88d63293 --- a/src/etc/inc/plugins.inc.d/openvpn/tls-verify.php +++ b/src/opnsense/scripts/openvpn/tls_verify.php @@ -2,14 +2,13 @@ - * Copyright (C) 2018 Deciso B.V. + * Copyright (C) 2018-2023 Deciso B.V. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, + * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright @@ -28,25 +27,45 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/* - * OpenVPN calls this script to validate a certificate - * This script is called ONCE per DEPTH of the certificate chain - * Normal operation would have two runs - one for the server certificate - * and one for the client certificate. Beyond that, you're dealing with - * intermediates. +require_once("config.inc"); + + +/** + * verify certificate depth + * @param string $serverid server identifier + * @return string|bool an error string or true when properly authenticated */ - -openlog("openvpn", LOG_ODELAY, LOG_AUTH); - -/* read data from command line */ -$cert_depth = intval($argv[1]); -$cert_subject = $argv[2]; - -if (isset($allowed_depth) && ($cert_depth > $allowed_depth)) { - syslog(LOG_WARNING, "Certificate depth {$cert_depth} exceeded max allowed depth of {$allowed_depth}.\n"); - closelog(); - exit(1); +function do_verify($serverid) +{ + global $config; + $a_server = null; + if (isset($config['openvpn']['openvpn-server'])) { + foreach ($config['openvpn']['openvpn-server'] as $server) { + if ($server['vpnid'] == $serverid) { + $a_server = $server; + break; + } + } + } + if ($a_server === null) { + return "OpenVPN '$serverid' was not found. Denying authentication for user {$username}"; + } + $certificate_depth = getenv('certificate_depth') !== false ? getenv('certificate_depth'): 0; + $allowed_depth = !empty($a_server['cert_depth']) ? $a_server['cert_depth'] : 1; + if ($allowed_depth != null && ($certificate_depth > $allowed_depth)) { + return "Certificate depth {$certificate_depth} exceeded max allowed depth of {$allowed_depth}."; + } + return true; +} + +openlog("openvpn", LOG_ODELAY, LOG_AUTH); +$response = do_verify(getenv('auth_server')); +if ($response !== true) { + syslog(LOG_WARNING, $response); + closelog(); + exit(1); +} else { + closelog(); + exit(0); } -closelog(); -exit(0); diff --git a/src/etc/inc/plugins.inc.d/openvpn/auth-user.php b/src/opnsense/scripts/openvpn/user_pass_verify.php old mode 100644 new mode 100755 similarity index 57% rename from src/etc/inc/plugins.inc.d/openvpn/auth-user.php rename to src/opnsense/scripts/openvpn/user_pass_verify.php index 0fc1e09d4..765551e68 --- a/src/etc/inc/plugins.inc.d/openvpn/auth-user.php +++ b/src/opnsense/scripts/openvpn/user_pass_verify.php @@ -2,9 +2,7 @@ - * Copyright (C) 2010 Ermal Luçi - * Copyright (C) 2018 Deciso B.V. + * Copyright (C) 2018-2023 Deciso B.V. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,24 +27,22 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/* - * OpenVPN calls this script to authenticate a user - * based on a username and password. We lookup these - * in our config.xml file and check the credentials. - */ - require_once("config.inc"); require_once("auth.inc"); require_once("util.inc"); require_once("interfaces.inc"); require_once("plugins.inc.d/openvpn.inc"); +/** + * @param string $serverid server identifier + * @return array|null openvpn server properties + */ function get_openvpn_server($serverid) { global $config; if (isset($config['openvpn']['openvpn-server'])) { foreach ($config['openvpn']['openvpn-server'] as $server) { - if ("server{$server['vpnid']}" == $serverid) { + if ($server['vpnid'] == $serverid) { return $server; } } @@ -54,9 +50,14 @@ function get_openvpn_server($serverid) return null; } +/** + * Parse provisioning properties supplied by the authenticator + * @param array $props key value store containing addresses and routes + * @return array formatted like openvpn_csc_conf_write() expects + */ function parse_auth_properties($props) { - $result = array(); + $result = []; if (!empty($props['Framed-IP-Address']) && !empty($props['Framed-IP-Netmask'])) { $cidrmask = 32 - log((ip2long($props['Framed-IP-Netmask']) ^ ip2long('255.255.255.255')) + 1, 2); $result['tunnel_network'] = $props['Framed-IP-Address'] . "/" . $cidrmask; @@ -67,62 +68,58 @@ function parse_auth_properties($props) return $result; } -/* setup syslog logging */ -openlog("openvpn", LOG_ODELAY, LOG_AUTH); - -if (count($argv) > 6) { - $authmodes = explode(',', $argv[5]); - $username = base64_decode(str_replace('%3D', '=', $argv[1])); - $password = base64_decode(str_replace('%3D', '=', $argv[2])); - $common_name = $argv[3]; - $modeid = $argv[6]; - $strictusercn = $argv[4] == 'false' ? false : true; - - $a_server = get_openvpn_server($modeid); - if (strpos($password, 'SCRV1:') === 0) { - // static-challenge https://github.com/OpenVPN/openvpn/blob/v2.4.7/doc/management-notes.txt#L1146 - // validate and concat password into our default pin+password - $tmp = explode(':', $password); - if (count($tmp) == 3) { - $pass = base64_decode($tmp[1]); - $pin = base64_decode($tmp[2]); - if ($pass !== false && $pin !== false) { - $password = $pin . $pass; +/** + * perform authentication + * @param string $common_name certificate common name for this connection + * @param string $serverid server identifier + * @param string $method method to use, supply username+password via-env or via-file + * @param string $auth_file when using a file, defines the name to use + * @return string|bool an error string or true when properly authenticated + */ +function do_auth($common_name, $serverid, $method, $auth_file) +{ + $username = $password = false; + if ($method == 'via-file') { + // via-file + if (!empty($auth_file) && is_file($auth_file)) { + $lines = explode("\n", file_get_contents($auth_file)); + if (count($lines) >= 2) { + $username = $lines[0]; + $password = $lines[1]; } } + } else { + // via-env + $username = getenv('username'); + $password = getenv('password'); } - - // primary input validation - $error_message = null; - if (($strictusercn === true) && ($common_name != $username)) { - $error_message = sprintf( + if (empty($username) || empty($password)) { + return "username or password missing ({$method} - {$auth_file})"; + } + $a_server = $serverid !== null ? get_openvpn_server($serverid) : null; + if ($a_server == null) { + return "OpenVPN '$serverid' was not found. Denying authentication for user {$username}"; + } elseif (!empty($a_server['strictusercn']) && $username != $common_name) { + return sprintf( "Username does not match certificate common name (%s != %s), access denied.", $username, $common_name ); - } elseif (!is_array($authmodes)) { - $error_message = 'No authentication server has been selected to authenticate against. ' . - "Denying authentication for user {$username}"; - } elseif ($a_server == null) { - $error_message = "OpenVPN '$modeid' was not found. Denying authentication for user {$username}"; + } elseif (empty($a_server['authmode'])) { + return 'No authentication server has been selected to authenticate against. ' . + "Denying authentication for user {$username}"; } elseif (!empty($a_server['local_group']) && !in_array($a_server['local_group'], getUserGroups($username))) { - $error_message = "OpenVPN '$modeid' requires the local group {$a_server['local_group']}. " . + return "OpenVPN '$serverid' requires the local group {$a_server['local_group']}. " . "Denying authentication for user {$username}"; } - if ($error_message != null) { - syslog(LOG_WARNING, $error_message); - closelog(); - exit(1); - } - if (file_exists("/var/etc/openvpn/{$modeid}.ca")) { - putenv("LDAPTLS_CACERT=/var/etc/openvpn/{$modeid}.ca"); + if (file_exists("/var/etc/openvpn/server{$serverid}.ca")) { + putenv("LDAPTLS_CACERT=/var/etc/openvpn/server{$serverid}.ca"); putenv("LDAPTLS_REQCERT=never"); } - // perform the actual authentication $authFactory = new OPNsense\Auth\AuthenticationFactory(); - foreach ($authmodes as $authName) { + foreach (explode(',', $a_server['authmode']) as $authName) { $authenticator = $authFactory->get($authName); if ($authenticator) { if ($authenticator->authenticate($username, $password)) { @@ -145,18 +142,41 @@ if (count($argv) > 6) { } else { syslog(LOG_NOTICE, "user '{$username}' authenticated using '{$authName}'"); } - closelog(); - exit(0); + return true; } } } - - // deny access and log - syslog(LOG_WARNING, "user '{$username}' could not authenticate."); - closelog(); - exit(-1); + return "user '{$username}' could not authenticate."; } -syslog(LOG_ERR, "invalid user authentication environment"); -closelog(); -exit(-1); +/* setup syslog logging */ +openlog("openvpn", LOG_ODELAY, LOG_AUTH); + +/* parse environment variables */ +$parms = []; +$parmlist = ['auth_server', 'auth_method', 'common_name', 'auth_file', 'auth_defer', 'auth_control_file']; +foreach ($parmlist as $key) { + $parms[$key] = isset(getenv()[$key]) ? getenv()[$key] : null; +} + +/* perform authentication */ +$response = do_auth($parms['common_name'], $parms['auth_server'], $parms['auth_method'], $parms['auth_file']); + +if (is_string($response)) { + // send failure message to log + syslog(LOG_WARNING, $response); + closelog(); +} + +if (!empty($parms['auth_defer'])) { + if (!empty($parms['auth_control_file'])) { + file_put_contents($parms['auth_control_file'], sprintf("%d", $response === true ? '0' : '1')); + } + exit(0); +} else { + if ($response === true) { + exit(0); + } else { + exit(1); + } +} diff --git a/src/wizard/openvpn.xml b/src/wizard/openvpn.xml index 094544c48..ccdb5a8b3 100644 --- a/src/wizard/openvpn.xml +++ b/src/wizard/openvpn.xml @@ -663,7 +663,7 @@ crypto select - Encryption Algorithm + Encryption algorithm (fallback) wizardtemp->step10->crypto - The method used to encrypt traffic between endpoints. This setting must match on the client and server side, but is otherwise set however you like. Certain algorithms will perform better on different hardware, depending on the availability of supported VPN accelerator chips. + Fallback cipher selection in case none of the default data-ciphers is supported by the client. Only preserved for backwards compatibility reasons digest diff --git a/src/www/vpn_openvpn_client.php b/src/www/vpn_openvpn_client.php index 05a2fd915..6b14cb71f 100644 --- a/src/www/vpn_openvpn_client.php +++ b/src/www/vpn_openvpn_client.php @@ -916,20 +916,19 @@ $( document ).ready(function() { - + + diff --git a/src/www/vpn_openvpn_server.php b/src/www/vpn_openvpn_server.php index 615875ce4..bdd6e278e 100644 --- a/src/www/vpn_openvpn_server.php +++ b/src/www/vpn_openvpn_server.php @@ -50,6 +50,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') { $vpnid = 0; $pconfig['verbosity_level'] = 1; $pconfig['digest'] = "SHA1"; // OpenVPN Defaults to SHA1 if unset + $pconfig['crypto'] = ""; $pconfig['tlsmode'] = "auth"; $pconfig['autokey_enable'] = "yes"; $pconfig['autotls_enable'] = "yes"; @@ -991,23 +992,21 @@ $( document ).ready(function() { - + +