%PDF- %PDF-
Direktori : /backups/router/usr/local/etc/inc/plugins.inc.d/ |
Current File : //backups/router/usr/local/etc/inc/plugins.inc.d/openssh.inc |
<?php /* * Copyright (C) 2004 Scott Ullrich <sullrich@gmail.com> * Copyright (C) 2004 Fred Mol <fredmol@xs4all.nl> * Copyright (C) 2015-2024 Franco Fichtner <franco@opnsense.org> * 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. */ function openssh_enabled() { global $config; return isset($config['system']['ssh']['enabled']) || (!isset($config['system']['ssh']['noauto']) && is_install_media()); } function openssh_configure() { return [ 'early' => ['openssh_configure_do'], 'local' => ['openssh_configure_do'], 'newwanip' => ['openssh_configure_do:2'], ]; } function openssh_services() { $services = []; if (openssh_enabled()) { $pconfig = []; $pconfig['description'] = gettext('Secure Shell Daemon'); $pconfig['configd']['restart'] = ['openssh restart']; $pconfig['configd']['start'] = ['openssh start']; $pconfig['configd']['stop'] = ['openssh stop']; $pconfig['pidfile'] = '/var/run/sshd.pid'; $pconfig['name'] = 'openssh'; $services[] = $pconfig; } return $services; } /** * sync configuration via xmlrpc * @return array */ function openssh_xmlrpc_sync() { return [[ 'description' => gettext('OpenSSH'), 'section' => 'system.ssh', 'services' => ['openssh'], 'id' => 'ssh', ]]; } function openssh_stop() { /* if run from a shell session, `-af' and the full path is needed */ mwexecf('/bin/pkill -af %s', '/usr/local/sbin/sshd', true); } function openssh_configure_do($verbose = false, $interface_map = null) { global $config; if (!plugins_argument_map($interface_map)) { return; } $sshcfg = null; if (isset($config['system']['ssh']['enabled'])) { $sshcfg = $config['system']['ssh']; } elseif (!isset($config['system']['ssh']['noauto']) && is_install_media()) { /* only revert to installer config when ssh is not set at all */ $sshcfg = ['permitrootlogin' => 1, 'passwordauth' => 1]; } if ($sshcfg === null) { openssh_stop(); return; } $interfaces = []; if (!empty($sshcfg['interfaces'])) { $interfaces = explode(',', $sshcfg['interfaces']); array_unshift($interfaces, 'lo0'); } /* return if interfaces specified do not match or interfaces are not bound at all */ if (!empty($interface_map) && !count(array_intersect($interface_map, $interfaces))) { return; } /* lock the config generation and service start/stop, also secures key generation */ $fobj = new \OPNsense\Core\FileObject('/usr/local/etc/ssh/sshd_config', 'a+', null, LOCK_EX); openssh_stop(); /* make sshd key store */ @mkdir('/conf/sshd', 0777, true); /* make ssh home directory */ @mkdir('/var/empty', 0555, true); $keys = [ /* .pub files are implied */ 'rsa' => 'ssh_host_rsa_key', 'ecdsa' => 'ssh_host_ecdsa_key', 'ed25519' => 'ssh_host_ed25519_key', ]; /* Check for all needed key files. If any are missing, the keys need to be regenerated. */ $generate_keys = false; foreach ($keys as $name) { $file = "/conf/sshd/{$name}"; if (!file_exists($file) || !file_exists("{$file}.pub")) { $generate_keys = true; break; } } if ($generate_keys) { foreach ($keys as $type => $name) { $file = "/conf/sshd/{$name}"; @unlink("{$file}.pub"); @unlink($file); mwexecf('/usr/local/bin/ssh-keygen -t %s -N "" -f %s', [$type, $file]); } } $sshport = isset($sshcfg['port']) ? $sshcfg['port'] : 22; $sshconf = "# This file was automatically generated by /usr/local/etc/inc/plugins.inc.d/openssh.inc\n"; $sshconf .= 'Include /usr/local/etc/ssh/sshd_config.d/*.conf' . PHP_EOL; $sshconf .= "Port {$sshport}\n"; $sshconf .= "Protocol 2\n"; $sshconf .= "Compression yes\n"; $sshconf .= "ClientAliveInterval 30\n"; $sshconf .= "UseDNS no\n"; $sshconf .= "X11Forwarding no\n"; $sshconf .= "PubkeyAuthentication yes\n"; $sshconf .= "Subsystem sftp internal-sftp\n"; $sshconf .= "AllowGroups wheel"; if (!empty($sshcfg['group'][0])) { $sshconf .= " {$sshcfg['group'][0]}"; } $sshconf .= "\n"; if (isset($sshcfg['permitrootlogin'])) { $sshconf .= "PermitRootLogin yes\n"; } else { $sshconf .= "PermitRootLogin no\n"; } if (isset($sshcfg['passwordauth'])) { $sshconf .= "ChallengeResponseAuthentication yes\n"; $sshconf .= "PasswordAuthentication yes\n"; } else { $sshconf .= "ChallengeResponseAuthentication no\n"; $sshconf .= "PasswordAuthentication no\n"; } if (!empty($sshcfg['rekeylimit'])) { $sshconf .= sprintf("RekeyLimit %s\n", $sshcfg['rekeylimit']); } foreach ($keys as $name) { $file = "/conf/sshd/{$name}"; if (!file_exists($file)) { continue; } $sshconf .= "HostKey {$file}\n"; } $listeners = []; foreach (interfaces_addresses($interfaces) as $tmpaddr => $info) { if (!$info['bind']) { continue; } if (count($listeners) >= 16) { log_msg("The SSH listening address $tmpaddr cannot be added due to MAX_LISTEN_SOCKS limit reached.", LOG_WARNING); continue; } $listeners[] = $tmpaddr; } foreach ($listeners as $listener) { $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 { log_msg("OpenSSH: Configured {$adv['node']} value '{$elem}' is not supported.", LOG_WARNING); } } if (count($selected) == 0) { log_msg("OpenSSH: No configured {$adv['node']} value is supported - using defaults.", LOG_WARNING); } else { $sshconf .= $adv['config'] . ' ' . implode(',', $selected) . PHP_EOL; } } $fobj->truncate(0)->write($sshconf); service_log('Configuring OpenSSH...', $verbose); if ((count($interfaces) && !count($listeners)) || mwexecf('/usr/bin/protect -i /usr/local/sbin/sshd')) { service_log("failed.\n", $verbose); } else { service_log("done.\n", $verbose); } unset($fobj); }