#!/usr/local/bin/php * Copyright (C) 2010 Ermal Luçi * Copyright (C) 2018 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, * 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. */ /* * 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"); 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) { return $server; } } } return null; } function parse_auth_properties($props) { $result = array(); 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; } if (!empty($props['Framed-Route']) && is_array($props['Framed-Route'])) { $result['local_network'] = implode(",", $props['Framed-Route']); } 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); // primary input validation $error_message = null; if (($strictusercn === true) && ($common_name != $username)) { $error_message = 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['local_group']) && !in_array($a_server['local_group'], getUserGroups($username))) { $error_message = "OpenVPN '$modeid' 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"); putenv("LDAPTLS_REQCERT=never"); } // perform the actual authentication $authFactory = new OPNsense\Auth\AuthenticationFactory; foreach ($authmodes as $authName) { $authenticator = $authFactory->get($authName); if ($authenticator) { if ($authenticator->authenticate($username, $password)) { $vpnid = filter_var($a_server['vpnid'], FILTER_SANITIZE_NUMBER_INT); // fetch or create client specif override $all_cso = openvpn_fetch_csc_list(); $common_name = empty($a_server['cso_login_matching']) ? $common_name : $username; $login_type = empty($a_server['cso_login_matching']) ? "CN" : "USER"; if (!empty($all_cso[$vpnid][$common_name])) { $cso = $all_cso[$vpnid][$common_name]; } else { $cso = array("common_name" => $common_name); } $cso = array_merge($cso, parse_auth_properties($authenticator->getLastAuthProperties())); $cso_filename = openvpn_csc_conf_write($cso, $a_server); if (!empty($cso_filename)) { $tmp = empty($a_server['cso_login_matching']) ? "CSO [CN]" : "CSO [USER]"; syslog(LOG_NOTICE, "user '{$username}' authenticated using '{$authName}' {$tmp}:{$cso_filename}"); } else { syslog(LOG_NOTICE, "user '{$username}' authenticated using '{$authName}'"); } closelog(); exit(0); } } } // deny access and log syslog(LOG_WARNING, "user '{$username}' could not authenticate."); closelog(); exit(-1); } syslog(LOG_ERR, "invalid user authentication environment"); closelog(); exit(-1);