Page Menu
Home
VyOS Platform
Search
Configure Global Search
Log In
Files
F119064437
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/data/templates/ssh/sshd_config.tmpl b/data/templates/ssh/sshd_config.tmpl
index 1dc700d38..7d7257cae 100644
--- a/data/templates/ssh/sshd_config.tmpl
+++ b/data/templates/ssh/sshd_config.tmpl
@@ -1,107 +1,107 @@
### Autogenerated by ssh.py ###
# https://linux.die.net/man/5/sshd_config
#
# Non-configurable defaults
#
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
SyslogFacility AUTH
LoginGraceTime 120
StrictModes yes
PubkeyAuthentication yes
IgnoreRhosts yes
HostbasedAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
X11Forwarding yes
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
Banner /etc/issue.net
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes
PermitRootLogin no
PidFile /run/sshd/sshd.pid
#
# User configurable section
#
# Look up remote host name and check that the resolved host name for the remote IP
# address maps back to the very same IP address.
UseDNS {{ "no" if disable_host_validation is defined else "yes" }}
# Specifies the port number that sshd(8) listens on
{% for value in port %}
Port {{ value }}
{% endfor %}
# Gives the verbosity level that is used when logging messages from sshd
LogLevel {{ loglevel | upper }}
# Specifies whether password authentication is allowed
PasswordAuthentication {{ "no" if disable_password_authentication is defined else "yes" }}
-{% if listen_address %}
+{% if listen_address is defined and listen_address is not none %}
# Specifies the local addresses sshd should listen on
{% for address in listen_address %}
ListenAddress {{ address }}
{% endfor %}
{% endif %}
-{% if ciphers %}
+{% if ciphers is defined and ciphers is not none %}
# Specifies the ciphers allowed for protocol version 2
-{% set value = ciphers if ciphers is string else ciphers | join(',') %}
+{% set value = ciphers if ciphers is string else ciphers | join(',') %}
Ciphers {{ value }}
{% endif %}
-{% if mac %}
+{% if mac is defined and mac is not none %}
# Specifies the available MAC (message authentication code) algorithms
-{% set value = mac if mac is string else mac | join(',') %}
+{% set value = mac if mac is string else mac | join(',') %}
MACs {{ value }}
{% endif %}
-{% if key_exchange %}
+{% if key_exchange is defined and key_exchange is not none %}
# Specifies the available Key Exchange algorithms
-{% set value = key_exchange if key_exchange is string else key_exchange | join(',') %}
+{% set value = key_exchange if key_exchange is string else key_exchange | join(',') %}
KexAlgorithms {{ value }}
{% endif %}
-{% if access_control is defined %}
-{% if access_control.allow is defined %}
+{% if access_control is defined and access_control is not none %}
+{% if access_control.allow is defined and access_control.allow is not none %}
{% if access_control.allow.user is defined %}
# If specified, login is allowed only for user names that match
-{% set value = access_control.allow.user if access_control.allow.user is string else access_control.allow.user | join(' ') %}
+{% set value = access_control.allow.user if access_control.allow.user is string else access_control.allow.user | join(' ') %}
AllowUsers {{ value }}
{% endif %}
{% if access_control.allow.group is defined %}
# If specified, login is allowed only for users whose primary group or supplementary group list matches
-{% set value = access_control.allow.group if access_control.allow.group is string else access_control.allow.group | join(' ') %}
+{% set value = access_control.allow.group if access_control.allow.group is string else access_control.allow.group | join(' ') %}
AllowGroups {{ value }}
{% endif %}
{% endif %}
-{% if access_control.deny is defined %}
+{% if access_control.deny is defined and access_control.deny is not none %}
{% if access_control.deny.user is defined %}
# Login is disallowed for user names that match
-{% set value = access_control.deny.user if access_control.deny.user is string else access_control.deny.user | join(' ') %}
+{% set value = access_control.deny.user if access_control.deny.user is string else access_control.deny.user | join(' ') %}
DenyUsers {{ value }}
{% endif %}
{% if access_control.deny.group is defined %}
# Login is disallowed for users whose primary group or supplementary group list matches
-{% set value = access_control.deny.group if access_control.deny.group is string else access_control.deny.group | join(' ') %}
+{% set value = access_control.deny.group if access_control.deny.group is string else access_control.deny.group | join(' ') %}
DenyGroups {{ value }}
{% endif %}
{% endif %}
{% endif %}
-{% if client_keepalive_interval %}
+{% if client_keepalive_interval is defined and client_keepalive_interval is not none %}
# Sets a timeout interval in seconds after which if no data has been received from the client,
# sshd(8) will send a message through the encrypted channel to request a response from the client
ClientAliveInterval {{ client_keepalive_interval }}
{% endif %}
diff --git a/smoketest/scripts/cli/test_service_ssh.py b/smoketest/scripts/cli/test_service_ssh.py
index e9e4639fc..eede042de 100755
--- a/smoketest/scripts/cli/test_service_ssh.py
+++ b/smoketest/scripts/cli/test_service_ssh.py
@@ -1,163 +1,161 @@
#!/usr/bin/env python3
#
# Copyright (C) 2019-2020 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
import os
import unittest
from vyos.configsession import ConfigSession
from vyos.configsession import ConfigSessionError
from vyos.util import cmd
from vyos.util import process_named_running
from vyos.util import read_file
PROCESS_NAME = 'sshd'
SSHD_CONF = '/run/sshd/sshd_config'
base_path = ['service', 'ssh']
vrf = 'ssh-test'
def get_config_value(key):
tmp = read_file(SSHD_CONF)
tmp = re.findall(f'\n?{key}\s+(.*)', tmp)
return tmp
class TestServiceSSH(unittest.TestCase):
def setUp(self):
self.session = ConfigSession(os.getpid())
# ensure we can also run this test on a live system - so lets clean
# out the current configuration :)
self.session.delete(base_path)
def tearDown(self):
# delete testing SSH config
self.session.delete(base_path)
- # restore "plain" SSH access
- self.session.set(base_path)
- # delete VRF
- self.session.delete(['vrf', 'name', vrf])
-
self.session.commit()
del self.session
def test_ssh_default(self):
# Check if SSH service runs with default settings - used for checking
# behavior of <defaultValue> in XML definition
self.session.set(base_path)
# commit changes
self.session.commit()
# Check configured port
port = get_config_value('Port')[0]
self.assertEqual('22', port)
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
def test_ssh_single_listen_address(self):
# Check if SSH service can be configured and runs
self.session.set(base_path + ['port', '1234'])
self.session.set(base_path + ['disable-host-validation'])
self.session.set(base_path + ['disable-password-authentication'])
self.session.set(base_path + ['loglevel', 'verbose'])
self.session.set(base_path + ['client-keepalive-interval', '100'])
self.session.set(base_path + ['listen-address', '127.0.0.1'])
# commit changes
self.session.commit()
# Check configured port
port = get_config_value('Port')[0]
self.assertTrue("1234" in port)
# Check DNS usage
dns = get_config_value('UseDNS')[0]
self.assertTrue("no" in dns)
# Check PasswordAuthentication
pwd = get_config_value('PasswordAuthentication')[0]
self.assertTrue("no" in pwd)
# Check loglevel
loglevel = get_config_value('LogLevel')[0]
self.assertTrue("VERBOSE" in loglevel)
# Check listen address
address = get_config_value('ListenAddress')[0]
self.assertTrue("127.0.0.1" in address)
# Check keepalive
keepalive = get_config_value('ClientAliveInterval')[0]
self.assertTrue("100" in keepalive)
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
def test_ssh_multiple_listen_addresses(self):
# Check if SSH service can be configured and runs with multiple
# listen ports and listen-addresses
- ports = ['22', '2222']
+ ports = ['22', '2222', '2223', '2224']
for port in ports:
self.session.set(base_path + ['port', port])
addresses = ['127.0.0.1', '::1']
for address in addresses:
self.session.set(base_path + ['listen-address', address])
# commit changes
self.session.commit()
# Check configured port
tmp = get_config_value('Port')
for port in ports:
self.assertIn(port, tmp)
# Check listen address
tmp = get_config_value('ListenAddress')
for address in addresses:
self.assertIn(address, tmp)
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
def test_ssh_vrf(self):
# Check if SSH service can be bound to given VRF
port = '22'
self.session.set(base_path + ['port', port])
self.session.set(base_path + ['vrf', vrf])
# VRF does yet not exist - an error must be thrown
with self.assertRaises(ConfigSessionError):
self.session.commit()
- self.session.set(['vrf', 'name', vrf, 'table', '1001'])
+ self.session.set(['vrf', 'name', vrf, 'table', '1338'])
# commit changes
self.session.commit()
# Check configured port
tmp = get_config_value('Port')
self.assertIn(port, tmp)
# Check for running process
self.assertTrue(process_named_running(PROCESS_NAME))
# Check for process in VRF
tmp = cmd(f'ip vrf pids {vrf}')
self.assertIn(PROCESS_NAME, tmp)
+ # delete VRF
+ self.session.delete(['vrf', 'name', vrf])
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/src/conf_mode/ssh.py b/src/conf_mode/ssh.py
index 07c057fd7..28e606663 100755
--- a/src/conf_mode/ssh.py
+++ b/src/conf_mode/ssh.py
@@ -1,95 +1,94 @@
#!/usr/bin/env python3
#
# Copyright (C) 2018-2020 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from sys import exit
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configverify import verify_vrf
from vyos.util import call
from vyos.template import render
from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
config_file = r'/run/sshd/sshd_config'
systemd_override = r'/etc/systemd/system/ssh.service.d/override.conf'
def get_config(config=None):
if config:
conf = config
else:
conf = Config()
base = ['service', 'ssh']
if not conf.exists(base):
return None
ssh = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
default_values = defaults(base)
ssh = dict_merge(default_values, ssh)
# pass config file path - used in override template
ssh['config_file'] = config_file
return ssh
def verify(ssh):
if not ssh:
return None
verify_vrf(ssh)
return None
def generate(ssh):
if not ssh:
if os.path.isfile(config_file):
os.unlink(config_file)
if os.path.isfile(systemd_override):
os.unlink(systemd_override)
return None
render(config_file, 'ssh/sshd_config.tmpl', ssh)
render(systemd_override, 'ssh/override.conf.tmpl', ssh)
+ # Reload systemd manager configuration
+ call('systemctl daemon-reload')
return None
def apply(ssh):
if not ssh:
# SSH access is removed in the commit
call('systemctl stop ssh.service')
- # Reload systemd manager configuration
- call('systemctl daemon-reload')
-
if ssh:
call('systemctl restart ssh.service')
return None
if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
exit(1)
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Nov 6, 10:05 AM (41 m, 27 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4654137
Default Alt Text
(13 KB)
Attached To
Mode
rVYOSONEX vyos-1x
Attached
Detach File
Event Timeline
Log In to Comment