From 17b294b38ee4e8fb7e684e8ec538e12fdcf3a22d Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Tue, 18 Jan 2022 16:39:18 +0100 Subject: [PATCH] system: generic rewrite of ssh advanced opts o Batch the backend call calling from GUI once and only if needed from configuration. o Turn the configuration into a generic loop. o Move advanced options to the back of the configuration. o Warning level for both log messages. --- src/etc/inc/plugins.inc.d/openssh.inc | 86 ++++++++----------- src/opnsense/scripts/openssh/ssh_query.py | 20 +++-- .../conf/actions.d/actions_openssh.conf | 10 +-- src/www/system_advanced_admin.php | 36 +++----- 4 files changed, 66 insertions(+), 86 deletions(-) diff --git a/src/etc/inc/plugins.inc.d/openssh.inc b/src/etc/inc/plugins.inc.d/openssh.inc index 1d4b8997f..a401cb6b1 100644 --- a/src/etc/inc/plugins.inc.d/openssh.inc +++ b/src/etc/inc/plugins.inc.d/openssh.inc @@ -3,7 +3,7 @@ /* * Copyright (C) 2004 Scott Ullrich * Copyright (C) 2004 Fred Mol - * Copyright (C) 2015-2021 Franco Fichtner + * Copyright (C) 2015-2022 Franco Fichtner * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -87,24 +87,6 @@ function openssh_stop() mwexecf('/bin/pkill -af %s', '/usr/local/sbin/sshd', true); } -function openssh_check_querylist($list, $config) -{ - $supported = json_decode(configd_run("openssh query {$list}")); - $selected = []; - foreach (explode(',', $config) as $elem) { - if (in_array($elem, $supported)) { - $selected[] = $elem; - } else { - syslog(LOG_NOTICE, "OpenSSH: Configured value '{$elem}' of {$list} setting not suppored."); - } - } - - if (count($selected) == 0) { - syslog(LOG_WARNING, "OpenSSH: No configured {$list} ({$config}) supported - using defaults."); - } - return implode(',', $selected); -} - function openssh_configure_do($verbose = false, $interface = '') { global $config; @@ -209,36 +191,6 @@ function openssh_configure_do($verbose = false, $interface = '') $sshconf .= "ChallengeResponseAuthentication no\n"; $sshconf .= "PasswordAuthentication no\n"; } - if (!empty($sshcfg['kex'])) { - $kexs = openssh_check_querylist('kex', $sshcfg['kex']); - if (strlen($kexs) > 0) { - $sshconf .= "KexAlgorithms {$kexs}\n"; - } - } - if (!empty($sshcfg['ciphers'])) { - $ciphers = openssh_check_querylist('cipher', $sshcfg['ciphers']); - if (strlen($ciphers) > 0) { - $sshconf .= "Ciphers {$ciphers}\n"; - } - } - if (!empty($sshcfg['macs'])) { - $macs = openssh_check_querylist('mac', $sshcfg['macs']); - if (strlen($macs) > 0) { - $sshconf .= "MACs {$macs}\n"; - } - } - if (!empty($sshcfg['keys'])) { - $keys = openssh_check_querylist('key', $sshcfg['keys']); - if (strlen($keys) > 0) { - $sshconf .= "HostKeyAlgorithms {$keys}\n"; - } - } - if (!empty($sshcfg['keysig'])) { - $keysigs = openssh_check_querylist('key-sig', $sshcfg['keysig']); - if (strlen($keysigs) > 0) { - $sshconf .= "PubkeyAcceptedAlgorithms {$keysigs}\n"; - } - } foreach ($keys_all as $name) { $file = "/conf/sshd/{$name}"; @@ -272,6 +224,42 @@ function openssh_configure_do($verbose = false, $interface = '') $sshconf .= "ListenAddress {$listener}\n"; } + $supported = null; + $advanced = [ + [ 'config' => 'Ciphers', 'node' => 'ciphers', 'key' => 'cipher'], + [ 'config' => 'HostKeyAlgorithms', 'node' => 'keys', 'key' => 'key'], + [ 'config' => 'KexAlgorithms', 'node' => 'kex', 'key' => 'kex'], + [ 'config' => 'MACs', 'node' => 'macs', 'key' => 'mac'], + [ 'config' => 'PubkeyAcceptedAlgorithms', 'node' => 'keysig', 'key' => 'key-sig'], + ]; + + foreach ($advanced as $adv) { + if (empty($sshcfg[$adv['node']])) { + continue; + } + + if ($supported === null) { + /* cache return as it includes all probable values */ + $supported = json_decode(configd_run('openssh query'), true); + } + + $selected = []; + + foreach (explode(',', $sshcfg[$adv['node']]) as $elem) { + if (in_array($elem, $supported[$adv['key']])) { + $selected[] = $elem; + } else { + syslog(LOG_WARNING, "OpenSSH: Configured {$adv['node']} value '{$elem}' is not supported."); + } + } + + if (count($selected) == 0) { + syslog(LOG_WARNING, "OpenSSH: No configured {$adv['node']} value is supported - using defaults."); + } else { + $sshconf .= $adv['config'] . ' ' . implode(',', $selected) . PHP_EOL; + } + } + file_put_contents("/usr/local/etc/ssh/sshd_config", $sshconf); if ($verbose) { diff --git a/src/opnsense/scripts/openssh/ssh_query.py b/src/opnsense/scripts/openssh/ssh_query.py index 10d7628af..f789b3660 100755 --- a/src/opnsense/scripts/openssh/ssh_query.py +++ b/src/opnsense/scripts/openssh/ssh_query.py @@ -30,14 +30,18 @@ import subprocess import ujson import argparse -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('option', help='query option', choices=['kex', 'mac', 'cipher' ,'key', 'key-sig']) - args = parser.parse_args() +opts = ['kex', 'mac', 'cipher' ,'key', 'key-sig'] + +if __name__ == '__main__': + result = dict() + + for opt in opts: + partial = list() + for l in subprocess.run(['/usr/local/bin/ssh', '-Q', opt], capture_output=True).stdout.decode().split('\n'): + if len(l.strip()) > 1: + partial.append(l.strip()) + sorted(partial) + result[opt] = partial - result = list() - for l in subprocess.run(['/usr/local/bin/ssh', '-Q', args.option], capture_output=True).stdout.decode().split('\n'): - if len(l.strip()) > 1: - result.append(l.strip()) sorted(result) print(ujson.dumps(result)) diff --git a/src/opnsense/service/conf/actions.d/actions_openssh.conf b/src/opnsense/service/conf/actions.d/actions_openssh.conf index d845e5933..c6c6eabd9 100644 --- a/src/opnsense/service/conf/actions.d/actions_openssh.conf +++ b/src/opnsense/service/conf/actions.d/actions_openssh.conf @@ -2,23 +2,23 @@ command:/usr/local/etc/rc.sshd parameters: type:script -message:starting openssh +message:Starting OpenSSH [restart] command:/usr/local/etc/rc.sshd parameters: type:script -message:restarting openssh +message:Restarting OpenSSH description:Restart OpenSSH service [stop] command:/bin/pkill -TERM sshd parameters: type:script -message:stopping openssh +message:Stopping OpenSSH [query] command:/usr/local/opnsense/scripts/openssh/ssh_query.py -parameters: %s +parameters: type:script_output -message: query options %s +message:Query OpenSSH options diff --git a/src/www/system_advanced_admin.php b/src/www/system_advanced_admin.php index 13db17a77..e446c9e15 100644 --- a/src/www/system_advanced_admin.php +++ b/src/www/system_advanced_admin.php @@ -366,6 +366,8 @@ if (empty($pconfig['webguiproto']) || !$certs_available) { $pconfig['webguiproto'] = "http"; } +$sshoptions = json_decode(configd_run('openssh query'), true); + legacy_html_escape_form_data($pconfig); legacy_html_escape_form_data($a_group); @@ -770,21 +772,18 @@ $(document).ready(function() { - +