%PDF- %PDF-
Direktori : /backups/router/usr/local/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ |
Current File : //backups/router/usr/local/opnsense/mvc/app/controllers/OPNsense/OpenVPN/Api/ExportController.php |
<?php /* * 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. */ namespace OPNsense\OpenVPN\Api; use OPNsense\Base\ApiControllerBase; use OPNsense\Base\UserException; use OPNsense\Core\Config; use OPNsense\Core\Backend; use OPNsense\Trust\Store; use OPNsense\OpenVPN\OpenVPN; use OPNsense\OpenVPN\Export; use OPNsense\OpenVPN\ExportFactory; use OPNsense\Trust\Cert; /** * Class ExportController handles client export functions * @package OPNsense\OpenVPN */ class ExportController extends ApiControllerBase { /** * @var null|Export model object to work on */ private $modelHandle = null; /** * @var array list of configured interfaces (addresses) */ private $physicalInterfaces = array(); /** * Get (or create) model object * @return Export * @throws \OPNsense\Base\ModelException when unable to create model */ private function getModel() { if ($this->modelHandle == null) { $this->modelHandle = new Export(); } return $this->modelHandle; } /** * collect (and store) configured interfaces by name [lan, wan, optX] * @return mixed * @throws \Exception when unable to contact configd */ private function getInterfaces() { if (empty($this->physicalInterfaces)) { $ifconfig = json_decode((new Backend())->configdRun('interface list ifconfig'), true); $config = Config::getInstance()->object(); if ($config->interfaces->count() > 0) { foreach ($config->interfaces->children() as $key => $node) { $this->physicalInterfaces[(string)$key] = array(); if (!empty($ifconfig[(string)($node->if)])) { $this->physicalInterfaces[(string)$key] = $ifconfig[(string)($node->if)]; } } } } return $this->physicalInterfaces; } /** * find configured servers * @param bool $active only active servers * @return \Generator */ private function openvpnServers($active = true) { $cfg = Config::getInstance()->object(); if (isset($cfg->openvpn)) { foreach ($cfg->openvpn->children() as $key => $server) { if ($key == 'openvpn-server' && !empty($server)) { if (empty($server->disable) || !$active) { $name = empty($server->description) ? "server" : (string)$server->description; $name .= " " . $server->protocol . ":" . $server->local_port; yield [ 'name' => $name, 'mode' => (string)$server->mode, 'vpnid' => (string)$server->vpnid ]; } } } } foreach ((new OpenVPN())->Instances->Instance->iterateItems() as $node_uuid => $node) { if (!empty((string)$node->enabled) && $node->role == 'server') { $name = empty($node->description) ? "server" : (string)$node->description; $name .= " " . $node->proto . ":" . $node->port; yield [ 'name' => $name, 'mode' => !empty((string)$node->authmode) ? 'server_tls_user' : '', 'vpnid' => $node_uuid ]; } } } /** * Determine configured settings for selected server * @param string $vpnid server handle * @return array * @throws \OPNsense\Base\ModelException when unable to create model */ private function configuredSettings($vpnid) { $result = array(); $serverModel = $this->getModel()->getServer($vpnid); $server = (new OpenVPN())->getInstanceById($vpnid); // hostname if (!empty((string)$serverModel->hostname)) { $result["hostname"] = (string)$serverModel->hostname; } elseif (!empty($server['interface'])) { $allInterfaces = $this->getInterfaces(); if (!empty($allInterfaces[$server['interface']])) { if (strstr($server['protocol'], "6") !== false) { if (!empty($allInterfaces[$server['interface']]['ipv6'])) { $result["hostname"] = $allInterfaces[$server['interface']]['ipv6'][0]['ipaddr']; } } elseif (!empty($allInterfaces[$server['interface']]['ipv4'])) { $result["hostname"] = $allInterfaces[$server['interface']]['ipv4'][0]['ipaddr']; } } } // simple 1-1 field mappings (overwrites) foreach ($serverModel->iterateItems() as $field => $value) { if (!empty((string)$value)) { $result[$field] = (string)$value; } elseif (!empty($server[$field]) || !isset($result[$field])) { $result[$field] = $server[$field] ?? null; } } return $result; } /** * list providers * @return array list of configured openvpn providers (servers) * @throws \Exception when unable to contact configd */ public function providersAction() { $result = array(); foreach ($this->openvpnServers() as $server) { $vpnid = $server['vpnid']; $result[$vpnid] = array_merge($server, $this->configuredSettings($vpnid)); } return $result; } /** * list configured accounts * @param string $vpnid server handle * @return array list of configured accounts */ public function accountsAction($vpnid = null) { $result = [ null => [ "description" => gettext("(none) Exclude certificate from export"), "users" => [] ] ]; $server = (new OpenVPN())->getInstanceById($vpnid); if ($server !== null) { $usernames = []; foreach (Config::getInstance()->object()->system->user as $user) { $usernames[] = (string)$user->name; } foreach ((new Cert())->cert->iterateItems() as $cert) { if ($cert->caref == $server['caref']) { $result[(string)$cert->refid] = [ "description" => (string)$cert->descr, "users" => [] ]; if ( in_array($cert->commonname, $usernames) && in_array($cert->cert_type, ['usr_cert', 'combined_server_client']) ) { $result[(string)$cert->refid]['users'][] = (string)$cert->commonname; } } } } return $result; } /** * list configured export options (client types) * @return array list of templates */ public function templatesAction() { $result = array(); $factory = new ExportFactory(); foreach ($factory->listProviders() as $key => $provider) { $result[$key] = array( "name" => $provider['handle']->getName(), "supportedOptions" => $provider['handle']->supportedOptions() ); } return $result; } /** * validate user/model input for configurable options * @param $vpnid server handle * @return array status and validation output * @throws \OPNsense\Base\ModelException */ public function validatePresetsAction($vpnid) { $result = array("result" => ""); if ($this->request->isPost()) { $result['result'] = 'ok'; $result['changed'] = false; $serverModel = $this->getModel()->getServer($vpnid); foreach ($this->request->getPost('openvpn_export') as $key => $value) { if ($serverModel->$key !== null) { $serverModel->$key = (string)$value; $result['changed'] = $result['changed'] ? $result['changed'] : $serverModel->$key->isFieldChanged(); } } foreach ($this->getModel()->performValidation() as $field => $msg) { if (!array_key_exists("validations", $result)) { $result["validations"] = array(); $result["result"] = "failed"; } $fieldnm = str_replace($serverModel->__reference, 'openvpn_export', $msg->getField()); $result["validations"][$fieldnm] = $msg->getMessage(); } } return $result; } /** * store presets when valid and changed * @param $vpnid server handle * @return array status and validation output * @throws \OPNsense\Base\ModelException */ public function storePresetsAction($vpnid) { $result = array("result" => "failed"); if ($this->request->isPost()) { $result = $this->validatePresetsAction($vpnid); if ($result['result'] == 'ok' && $result['changed']) { $this->getModel()->serializeToConfig(); Config::getInstance()->save(); } } return $result; } /** * download configuration * @param string $vpnid server handle * @param string $certref certificate to export if applicable * @return array * @throws \OPNsense\Base\ModelException * @throws UserException when invalid user input */ public function downloadAction($vpnid, $certref = null) { $response = array("result" => "failed"); if ($this->request->isPost()) { $server = (new OpenVPN())->getInstanceById($vpnid); if ($server !== null) { // fetch server config data $config = $server; // fetch associated certificate data, add to config $config['server_ca_chain'] = ''; $config['server_subject_name'] = null; $config['server_cert_is_srv'] = null; if (!empty($server['certref'])) { $cert = (new Store())->getCertificate($server['certref']); if ($cert) { $config['server_cert_is_srv'] = $cert['is_server']; $config['server_subject_name'] = $cert['name'] ?? ''; $config['server_subject'] = $cert['subject'] ?? ''; if (!empty($cert['ca'])) { $config['server_ca_chain'] = $cert['ca']['crt']; } } } if ($certref !== null) { $cert = (new Store())->getCertificate($certref); if ($cert) { if (!empty($cert['subject']) && !empty($cert['subject']['CN'])) { $config['client_cn'] = $cert['subject']['CN']; $config['client_crt'] = $cert['crt']; $config['client_prv'] = $cert['prv']; } } if (empty($config['client_cn'])) { throw new UserException("Client certificate not found", gettext("OpenVPN export")); } } // overlay (saved) user settings if ($this->request->hasPost('openvpn_export')) { $response = $this->storePresetsAction($vpnid); // p12 password shouldn't be saved to the config, so we need to copy the content here as // not defined in either model or configuration data. if (!empty($this->request->getPost('openvpn_export')['p12_password'])) { $config['p12_password'] = $this->request->getPost('openvpn_export')['p12_password']; } } foreach ($this->getModel()->getServer($vpnid)->iterateItems() as $key => $value) { if ($value !== "") { $config[$key] = (string)$value; } } if ($response['result'] == 'ok') { // request config generation $factory = new ExportFactory(); $provider = $factory->getProvider($config['template']); if ($provider !== null) { $provider->setConfig($config); $response['filename'] = $provider->getFilename(); $response['filetype'] = $provider->getFileType(); $response['content'] = base64_encode($provider->getContent()); } } } } return $response; } }