#!/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 jinja2 import FileSystemLoader, Environment from sys import exit from vyos.config import Config from vyos.defaults import directories as vyos_data_dir from vyos import ConfigError from vyos.util import run config_file = r'/etc/ssh/sshd_config' default_config_data = { 'port' : '22', 'log_level': 'INFO', 'password_authentication': 'yes', 'host_validation': 'yes' } def get_config(): ssh = default_config_data conf = Config() if not conf.exists('service ssh'): return None else: conf.set_level('service ssh') if conf.exists('access-control allow user'): allow_users = conf.return_values('access-control allow user') ssh['allow_users'] = allow_users if conf.exists('access-control allow group'): allow_groups = conf.return_values('access-control allow group') ssh['allow_groups'] = allow_groups if conf.exists('access-control deny user'): deny_users = conf.return_values('access-control deny user') ssh['deny_users'] = deny_users if conf.exists('access-control deny group'): deny_groups = conf.return_values('access-control deny group') ssh['deny_groups'] = deny_groups if conf.exists('ciphers'): ciphers = conf.return_values('ciphers') ssh['ciphers'] = ciphers if conf.exists('disable-host-validation'): ssh['host_validation'] = 'no' if conf.exists('disable-password-authentication'): ssh['password_authentication'] = 'no' if conf.exists('key-exchange'): kex = conf.return_values('key-exchange') ssh['key_exchange'] = kex if conf.exists('listen-address'): # We can listen on both IPv4 and IPv6 addresses # Maybe there could be a check in the future if the configured IP address # is configured on this system at all? addresses = conf.return_values('listen-address') listen = [] for addr in addresses: listen.append(addr) ssh['listen_on'] = listen if conf.exists('loglevel'): ssh['log_level'] = conf.return_value('loglevel') if conf.exists('mac'): mac = conf.return_values('mac') ssh['mac'] = mac if conf.exists('port'): ports = conf.return_values('port') mport = [] for prt in ports: mport.append(prt) ssh['mport'] = mport if conf.exists('client-keepalive-interval'): client_keepalive = conf.return_value('client-keepalive-interval') ssh['client_keepalive'] = client_keepalive return ssh def verify(ssh): if ssh is None: return None if 'loglevel' in ssh.keys(): allowed_loglevel = 'QUIET, FATAL, ERROR, INFO, VERBOSE' if not ssh['loglevel'] in allowed_loglevel: raise ConfigError('loglevel must be one of "{0}"\n'.format(allowed_loglevel)) return None def generate(ssh): if ssh is None: return None # Prepare Jinja2 template loader from files tmpl_path = os.path.join(vyos_data_dir['data'], 'templates', 'ssh') fs_loader = FileSystemLoader(tmpl_path) env = Environment(loader=fs_loader, trim_blocks=True) tmpl = env.get_template('sshd_config.tmpl') config_text = tmpl.render(ssh) with open(config_file, 'w') as f: f.write(config_text) return None def apply(ssh): if ssh is not None and 'port' in ssh.keys(): run("sudo systemctl restart ssh.service") else: # SSH access is removed in the commit run("sudo systemctl stop ssh.service") if os.path.isfile(config_file): os.unlink(config_file) return None if __name__ == '__main__': try: c = get_config() verify(c) generate(c) apply(c) except ConfigError as e: print(e) exit(1)