From 211b762f9bdc5704e07638ac8f948277ef4f4319 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 13:18:18 +0200 Subject: ntp.py: start/stop service via systemctl --- src/conf_mode/ntp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/ntp.py b/src/conf_mode/ntp.py index b618cbd89..8533411cc 100755 --- a/src/conf_mode/ntp.py +++ b/src/conf_mode/ntp.py @@ -154,10 +154,10 @@ def generate(ntp): def apply(ntp): if ntp is not None: - os.system('sudo /usr/sbin/invoke-rc.d ntp force-reload') + os.system('sudo systemctl restart ntp.service') else: # NTP support is removed in the commit - os.system('sudo /usr/sbin/invoke-rc.d ntp stop') + os.system('sudo systemctl stop ntp.service') os.unlink(config_file) return None -- cgit v1.2.3 From bc8b7305111d890e2933f06d72c60c0ab9258f0f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 13:18:31 +0200 Subject: ssh.py: start/stop service via systemctl --- src/conf_mode/ssh.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/ssh.py b/src/conf_mode/ssh.py index f1ac19473..beca7bb9a 100755 --- a/src/conf_mode/ssh.py +++ b/src/conf_mode/ssh.py @@ -236,10 +236,10 @@ def generate(ssh): def apply(ssh): if ssh is not None and 'port' in ssh.keys(): - os.system("sudo systemctl restart ssh") + os.system("sudo systemctl restart ssh.service") else: # SSH access is removed in the commit - os.system("sudo systemctl stop ssh") + os.system("sudo systemctl stop ssh.service") os.unlink(config_file) return None -- cgit v1.2.3 From 4d222bc14c23ba010b6e245ff35ddb766401b20d Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 13:19:14 +0200 Subject: T792: add TFTP server functionality --- debian/control | 1 + interface-definitions/tftp-server.xml | 57 ++++++++++++ src/conf_mode/tftp_server.py | 159 ++++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 interface-definitions/tftp-server.xml create mode 100755 src/conf_mode/tftp_server.py (limited to 'src/conf_mode') diff --git a/debian/control b/debian/control index 70bf7a61c..04b228737 100644 --- a/debian/control +++ b/debian/control @@ -38,6 +38,7 @@ Depends: python3, beep, keepalived (>=2.0.5), wireguard, + tftpd-hpa, ${shlibs:Depends}, ${misc:Depends} Description: VyOS configuration scripts and data diff --git a/interface-definitions/tftp-server.xml b/interface-definitions/tftp-server.xml new file mode 100644 index 000000000..2874b034c --- /dev/null +++ b/interface-definitions/tftp-server.xml @@ -0,0 +1,57 @@ + + + + + + + + Trivial File Transfer Protocol (TFTP) server + 990 + + + + + Folder containing files served by TFTP [REQUIRED] + + + + + Allow TFTP file uploads + + + + + + Port for TFTP service + + 1-65535 + Numeric IP port (default: 69) + + + + + + + + + Addresses for TFTP server to listen [REQUIRED] + + ipv4 + TFTP IPv4 listen address + + + ipv6 + TFTP IPv6 listen address + + + + + + + + + + + + + diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py new file mode 100755 index 000000000..8133ed215 --- /dev/null +++ b/src/conf_mode/tftp_server.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2018 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 . +# +# + +import sys +import os +import stat +import pwd + +import jinja2 +import ipaddress +import netifaces + +from vyos.config import Config +from vyos import ConfigError + +config_file = r'/etc/default/tftpd-hpa' + +# Please be careful if you edit the template. +config_tmpl = """ +### Autogenerated by tftp_server.py ### + +# See manual at https://linux.die.net/man/8/tftpd + +TFTP_USERNAME="tftp" +TFTP_DIRECTORY="{{ directory }}" +{% if listen_ipv4 and listen_ipv6 -%} +TFTP_ADDRESS="{% for a in listen_ipv4 -%}{{ a }}:{{ port }}{{- " --address " if not loop.last -}}{% endfor -%} {% for a in listen_ipv6 %} --address [{{ a }}]:{{ port }}{% endfor -%}" +{% elif listen_ipv4 -%} +TFTP_ADDRESS="{% for a in listen_ipv4 -%}{{ a }}:{{ port }}{{- " --address " if not loop.last -}}{% endfor %} -4" +{% elif listen_ipv6 -%} +TFTP_ADDRESS="{% for a in listen_ipv6 -%}[{{ a }}]:{{ port }}{{- " --address " if not loop.last -}}{% endfor %} -6" +{%- endif %} + +TFTP_OPTIONS="--secure {% if allow_upload %}--create --umask 002{% endif %}" +""" + +default_config_data = { + 'directory': '', + 'allow_upload': False, + 'port': '69', + 'listen_ipv4': [], + 'listen_ipv6': [] +} + +# Verify if an IP address is assigned to any interface, IPv4 and IPv6 +def addrok(ipaddr, ipversion): + for interface in netifaces.interfaces(): + # Retrieve IP address of network interfaces + if ipversion in netifaces.ifaddresses(interface).keys(): + for addr in netifaces.ifaddresses(interface)[ipversion]: + if addr['addr'] == ipaddr: + return True + + return False + +def get_config(): + tftpd = default_config_data + conf = Config() + if not conf.exists('service tftp-server'): + return None + else: + conf.set_level('service tftp-server') + + if conf.exists('directory'): + tftpd['directory'] = conf.return_value('directory') + + if conf.exists('allow-upload'): + tftpd['allow_upload'] = True + + if conf.exists('port'): + tftpd['port'] = conf.return_value('port') + + if conf.exists('listen-address'): + for addr in conf.return_values('listen-address'): + if (ipaddress.ip_address(addr).version == 4): + tftpd['listen_ipv4'].append(addr) + + if (ipaddress.ip_address(addr).version == 6): + tftpd['listen_ipv6'].append(addr) + + return tftpd + +def verify(tftpd): + # bail out early - looks like removal from running config + if tftpd is None: + return None + + # Configuring allowed clients without a server makes no sense + if not tftpd['directory']: + raise ConfigError('TFTP root directory must be configured!') + + if not (tftpd['listen_ipv4'] or tftpd['listen_ipv6']): + raise ConfigError('TFTP server listen address must be configured!') + + for address in tftpd['listen_ipv4']: + if not addrok(address, netifaces.AF_INET): + raise ConfigError('TFTP server listen address "{0}" not configured on this system.'.format(address)) + + for address in tftpd['listen_ipv6']: + if not addrok(address, netifaces.AF_INET6): + raise ConfigError('TFTP server listen address "{0}" not configured on this system.'.format(address)) + + return None + +def generate(tftpd): + # bail out early - looks like removal from running config + if tftpd is None: + return None + + tmpl = jinja2.Template(config_tmpl) + config_text = tmpl.render(tftpd) + with open(config_file, 'w') as f: + f.write(config_text) + + return None + +def apply(tftpd): + if tftpd is not None: + + tftp_root = tftpd['directory'] + if not os.path.exists(tftp_root): + os.makedirs(tftp_root) + os.chmod(tftp_root, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IRGRP|stat.S_IXGRP|stat.S_IROTH|stat.S_IXOTH) + # get uid for user 'snmp' + tftp_uid = pwd.getpwnam('tftp').pw_uid + os.chown(tftp_root, tftp_uid, -1) + + os.system('sudo systemctl restart tftpd-hpa.service') + else: + # TFTP server support is removed in the commit + os.system('sudo systemctl stop tftpd-hpa.service') + 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) + sys.exit(1) -- cgit v1.2.3 From 5150b2890ec6a38dbeae2e105fce6855ce0f589e Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 16:55:49 +0200 Subject: tftp_server.py: fix indention and add more verbose comments --- src/conf_mode/tftp_server.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py index 8133ed215..8665f2964 100755 --- a/src/conf_mode/tftp_server.py +++ b/src/conf_mode/tftp_server.py @@ -59,12 +59,15 @@ default_config_data = { # Verify if an IP address is assigned to any interface, IPv4 and IPv6 def addrok(ipaddr, ipversion): + # For every available interface on this system for interface in netifaces.interfaces(): - # Retrieve IP address of network interfaces - if ipversion in netifaces.ifaddresses(interface).keys(): - for addr in netifaces.ifaddresses(interface)[ipversion]: - if addr['addr'] == ipaddr: - return True + # If it has any IPv4 or IPv6 address (depending on ipversion) configured + if ipversion in netifaces.ifaddresses(interface).keys(): + # For every configured IP address + for addr in netifaces.ifaddresses(interface)[ipversion]: + # Check if it matches to the address requested + if addr['addr'] == ipaddr: + return True return False -- cgit v1.2.3 From 23022977a6bf94e6be7d37de04c97ab0b5d1ea35 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 26 Aug 2018 16:56:37 +0200 Subject: tftp_server.py: fix copy-paste comment --- src/conf_mode/tftp_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py index 8665f2964..9cf4489af 100755 --- a/src/conf_mode/tftp_server.py +++ b/src/conf_mode/tftp_server.py @@ -139,7 +139,7 @@ def apply(tftpd): if not os.path.exists(tftp_root): os.makedirs(tftp_root) os.chmod(tftp_root, stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IRGRP|stat.S_IXGRP|stat.S_IROTH|stat.S_IXOTH) - # get uid for user 'snmp' + # get UNIX uid for user 'tftp' tftp_uid = pwd.getpwnam('tftp').pw_uid os.chown(tftp_root, tftp_uid, -1) -- cgit v1.2.3