From 54987a9ce57f4186940c2e00422cf10b3b0ff8c7 Mon Sep 17 00:00:00 2001 From: Michael Seevogel <git@michaelseevogel.de> Date: Wed, 7 Oct 2020 15:35:05 +0200 Subject: [PATCH] try to detect the correct OpenSSL version and activate TLS 1.3 if available for Nginx systems --- server/conf/nginx_vhost.conf.master | 7 +- .../100-monitor_needs_restarting.inc.php | 243 ++++++++++++++++++ server/lib/classes/system.inc.php | 21 ++ server/plugins-available/nginx_plugin.inc.php | 4 + 4 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 server/lib/classes/cron.d/100-monitor_needs_restarting.inc.php diff --git a/server/conf/nginx_vhost.conf.master b/server/conf/nginx_vhost.conf.master index bfa94f8fb3..f6addcc44d 100644 --- a/server/conf/nginx_vhost.conf.master +++ b/server/conf/nginx_vhost.conf.master @@ -18,7 +18,12 @@ server { listen <tmpl_var name='ip_address'>:<tmpl_var name='proxy_protocol_https'> ssl proxy_protocol; </tmpl_if> </tmpl_if> - ssl_protocols TLSv1.2; + +<tmpl_if name='openssl_version' op='>=' value='1.1.1' format='version'> +<tmpl_var name="ssl_comment">ssl_protocols TLSv1.3 TLSv1.2; +<tmpl_else> +<tmpl_var name="ssl_comment">ssl_protocols TLSv1.2; +</tmpl_if> # ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; # ssl_prefer_server_ciphers on; <tmpl_if name='ipv6_enabled'> diff --git a/server/lib/classes/cron.d/100-monitor_needs_restarting.inc.php b/server/lib/classes/cron.d/100-monitor_needs_restarting.inc.php new file mode 100644 index 0000000000..cab5f68edb --- /dev/null +++ b/server/lib/classes/cron.d/100-monitor_needs_restarting.inc.php @@ -0,0 +1,243 @@ +<?php + +/* +Copyright (c) 2013, Marius Cramer, pixcept KG +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + * Neither the name of ISPConfig nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. +*/ + +class cronjob_monitor_system_update extends cronjob { + + // job schedule + protected $_schedule = '0 * * * *'; + protected $_run_at_new = true; + + private $_tools = null; + + /* this function is optional if it contains no custom code */ + public function onPrepare() { + global $app; + + parent::onPrepare(); + } + + /* this function is optional if it contains no custom code */ + public function onBeforeRun() { + global $app; + + return parent::onBeforeRun(); + } + + public function onRunJob() { + global $app, $conf; + + $app->uses('getconf'); + $server_config = $app->getconf->get_server_config($conf['server_id'], 'server'); + if($server_config['monitor_system_updates'] == 'n') return; + + /* used for all monitor cronjobs */ + $app->load('monitor_tools'); + $this->_tools = new monitor_tools(); + /* end global section for monitor cronjobs */ + + /* the id of the server as int */ + $server_id = intval($conf['server_id']); + + /** The type of the data */ + + + $type = 'system_update'; + + /* This monitoring is only available on Debian or Ubuntu */ + if (file_exists('/etc/debian_version')) { + + /* + * first update the "apt database" + */ + shell_exec('while fuser /var/lib/apt/lists/lock >/dev/null 2>&1 ; do sleep 2; done; apt-get update'); + + /* + * Then test the upgrade. + * if there is any output, then there is a needed update + */ + $aptData = shell_exec('while fuser /var/lib/dpkg/lock >/dev/null 2>&1 || fuser /var/lib/apt/lists/lock >/dev/null 2>&1 ; do sleep 2; done; apt-get -s -qq dist-upgrade'); + if ($aptData == '') { + /* There is nothing to update! */ + $state = 'ok'; + } else { + /* + * There is something to update! this is in most cases not critical, so we can + * do a system-update once a month or so... + */ + $state = 'info'; + } + + /* + * Fetch the output + */ + $data['output'] = $aptData; + } elseif (file_exists('/etc/gentoo-release')) { + + /* + * first update the portage tree + */ + + // In keeping with gentoo's rsync policy, don't update to frequently (every four hours - taken from http://www.gentoo.org/doc/en/source_mirrors.xml) + $do_update = true; + if (file_exists('/usr/portage/metadata/timestamp.chk')) { + $datetime = file_get_contents('/usr/portage/metadata/timestamp.chk'); + $datetime = trim($datetime); + + $dstamp = strtotime($datetime); + if ($dstamp) { + $checkat = $dstamp + 14400; // + 4hours + if (mktime() < $checkat) { + $do_update = false; + } + } + } + + if ($do_update) { + shell_exec('emerge --sync --quiet'); + } + + /* + * Then test the upgrade. + * if there is any output, then there is a needed update + */ + $emergeData = shell_exec('glsa-check -t affected'); + if ($emergeData == '') { + /* There is nothing to update! */ + $state = 'ok'; + $data['output'] = 'No unapplied GLSA\'s found on the system.'; + } else { + /* There is something to update! */ + $state = 'info'; + $data['output'] = shell_exec('glsa-check -pv --nocolor affected 2>/dev/null'); + } + } elseif (file_exists('/etc/SuSE-release')) { + + /* + * update and find the upgrade. + * if there is any output, then there is a needed update + */ + $aptData = shell_exec('zypper -q lu'); + if ($aptData == '') { + /* There is nothing to update! */ + $state = 'ok'; + } else { + /* + * There is something to update! this is in most cases not critical, so we can + * do a system-update once a month or so... + */ + $state = 'info'; + } + + /* + * Fetch the output + */ + $data['output'] = shell_exec('zypper lu'); + + } elseif(file_exists('/etc/redhat-release')) { + /* + * update and find the upgrade. + * if there is any output, then there is a needed update + */ + + /* try to figure out the default package manager first */ + if(file_exists('/usr/bin/dnf') && (is_link('/usr/bin/yum'))) { + $rhPkgMgr = 'dnf'; + } elseif(file_exists('/usr/bin/dnf') && (!file_exists('/usr/bin/yum'))) { + $rhPkgMgr = 'dnf'; + } else { + $rhPkgMgr = 'yum'; + } + + $aptData = shell_exec($rhPkgMgr. ' -q list updates'); + + if ($aptData == '') { + /* There is nothing to update! */ + $state = 'ok'; + } else { + /* + * There is something to update! this is in most cases not critical, so we can + * do a system-update once a month or so... + */ + $state = 'info'; + } + + /* + * Fetch the output + */ + + $data['output'] = shell_exec($rhPkgMgr. ' -q list updates'); + + } else { + /* + * It is not Debian/Ubuntu, so there is no data and no state + * + * no_state, NOT unknown, because "unknown" is shown as state + * inside the GUI. no_state is hidden. + * + * We have to write NO DATA inside the DB, because the GUI + * could not know, if there is any dat, or not... + */ + $state = 'no_state'; + $data['output'] = ''; + } + + $res = array(); + $res['server_id'] = $server_id; + $res['type'] = $type; + $res['data'] = $data; + $res['state'] = $state; + + //* Ensure that output is encoded so that it does not break the serialize + //$res['data']['output'] = htmlentities($res['data']['output']); + $res['data']['output'] = htmlentities($res['data']['output'], ENT_QUOTES, 'UTF-8'); + + /* + * Insert the data into the database + */ + $sql = 'REPLACE INTO monitor_data (server_id, type, created, data, state) ' . + 'VALUES (?, ?, UNIX_TIMESTAMP(), ?, ?)'; + $app->dbmaster->query($sql, $res['server_id'], $res['type'], serialize($res['data']), $res['state']); + + /* The new data is written, now we can delete the old one */ + $this->_tools->delOldRecords($res['type'], $res['server_id']); + + parent::onRunJob(); + } + + /* this function is optional if it contains no custom code */ + public function onAfterRun() { + global $app; + + parent::onAfterRun(); + } + +} + +?> diff --git a/server/lib/classes/system.inc.php b/server/lib/classes/system.inc.php index 32afb9943c..bcaef1f2c4 100644 --- a/server/lib/classes/system.inc.php +++ b/server/lib/classes/system.inc.php @@ -2087,6 +2087,27 @@ class system{ } } + function getopensslversion($get_minor = false) { + global $app; + if($this->is_installed('openssl')) $cmd = 'openssl version'; + else { + $app->log("Could not check OpenSSL version, openssl not found.", LOGLEVEL_DEBUG); + return '1.0.1'; + } + exec($cmd, $output, $return_var); + if($return_var != 0 || !$output[0]) { + $app->log("Could not check OpenSSL version, openssl did not return any data.", LOGLEVEL_WARN); + return '1.0.1'; + } + if(preg_match('/OpenSSL\s*(\d+)(\.(\d+)(\.(\d+))*)?(\D|$)/i', $output[0], $matches)) { + return $matches[1] . (isset($matches[3]) ? '.' . $matches[3] : '') . (isset($matches[5]) && $get_minor == true ? '.' . $matches[5] : ''); + } else { + $app->log("Could not check OpenSSL version, did not find version string in openssl output.", LOGLEVEL_WARN); + return '1.0.1'; + } + + } + function getapacheversion($get_minor = false) { global $app; diff --git a/server/plugins-available/nginx_plugin.inc.php b/server/plugins-available/nginx_plugin.inc.php index c361d3f62f..bdc2c0e276 100644 --- a/server/plugins-available/nginx_plugin.inc.php +++ b/server/plugins-available/nginx_plugin.inc.php @@ -1621,6 +1621,10 @@ class nginx_plugin { // set logging variable $vhost_data['logging'] = $web_config['logging']; + $app->log("Found OpenSSL version: " . $app->system->getopensslversion($get_minor = true), LOGLEVEL_DEBUG); + + $vhost_data['openssl_version'] = $app->system->getopensslversion($get_minor = true); + $tpl->setVar($vhost_data); $server_alias = array(); -- GitLab