summaryrefslogtreecommitdiff
path: root/src/conf_mode
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode')
-rwxr-xr-xsrc/conf_mode/container.py31
-rwxr-xr-xsrc/conf_mode/dhcp_server.py2
-rwxr-xr-xsrc/conf_mode/http-api.py7
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py2
-rwxr-xr-xsrc/conf_mode/interfaces-wwan.py2
-rwxr-xr-xsrc/conf_mode/snmp.py5
-rwxr-xr-xsrc/conf_mode/system-login.py40
-rwxr-xr-xsrc/conf_mode/vpn_ipsec.py22
-rwxr-xr-xsrc/conf_mode/vpn_openconnect.py23
9 files changed, 79 insertions, 55 deletions
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index 08861053d..4f93c93a1 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 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
@@ -84,16 +84,16 @@ def get_config(config=None):
# tagNodes in place, it is better to blend in the defaults manually.
if 'port' in container['name'][name]:
for port in container['name'][name]['port']:
- default_values = defaults(base + ['name', 'port'])
+ default_values_port = defaults(base + ['name', 'port'])
container['name'][name]['port'][port] = dict_merge(
- default_values, container['name'][name]['port'][port])
+ default_values_port, container['name'][name]['port'][port])
# XXX: T2665: we can not safely rely on the defaults() when there are
# tagNodes in place, it is better to blend in the defaults manually.
if 'volume' in container['name'][name]:
for volume in container['name'][name]['volume']:
- default_values = defaults(base + ['name', 'volume'])
+ default_values_volume = defaults(base + ['name', 'volume'])
container['name'][name]['volume'][volume] = dict_merge(
- default_values, container['name'][name]['volume'][volume])
+ default_values_volume, container['name'][name]['volume'][volume])
# Delete container network, delete containers
tmp = node_changed(conf, base + ['network'])
@@ -279,8 +279,22 @@ def generate_run_arguments(name, container_config):
f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} ' \
f'--name {name} {device} {port} {volume} {env_opt}'
+ entrypoint = ''
+ if 'entrypoint' in container_config:
+ # it needs to be json-formatted with single quote on the outside
+ entrypoint = json_write(container_config['entrypoint'].split()).replace('"', """)
+ entrypoint = f'--entrypoint '{entrypoint}''
+
+ command = ''
+ if 'command' in container_config:
+ command = container_config['command'].strip()
+
+ command_arguments = ''
+ if 'arguments' in container_config:
+ command_arguments = container_config['arguments'].strip()
+
if 'allow_host_networks' in container_config:
- return f'{container_base_cmd} --net host {image}'
+ return f'{container_base_cmd} --net host {entrypoint} {image} {command} {command_arguments}'.strip()
ip_param = ''
networks = ",".join(container_config['network'])
@@ -289,7 +303,7 @@ def generate_run_arguments(name, container_config):
address = container_config['network'][network]['address']
ip_param = f'--ip {address}'
- return f'{container_base_cmd} --net {networks} {ip_param} {image}'
+ return f'{container_base_cmd} --net {networks} {ip_param} {entrypoint} {image} {command} {command_arguments}'.strip()
def generate(container):
# bail out early - looks like removal from running config
@@ -341,7 +355,8 @@ def generate(container):
file_path = os.path.join(systemd_unit_path, f'vyos-container-{name}.service')
run_args = generate_run_arguments(name, container_config)
- render(file_path, 'container/systemd-unit.j2', {'name': name, 'run_args': run_args})
+ render(file_path, 'container/systemd-unit.j2', {'name': name, 'run_args': run_args,},
+ formater=lambda _: _.replace(""", '"').replace("'", "'"))
return None
diff --git a/src/conf_mode/dhcp_server.py b/src/conf_mode/dhcp_server.py
index 52b682d6d..39c87478f 100755
--- a/src/conf_mode/dhcp_server.py
+++ b/src/conf_mode/dhcp_server.py
@@ -283,7 +283,7 @@ def generate(dhcp):
if not dhcp or 'disable' in dhcp:
return None
- # Please see: https://phabricator.vyos.net/T1129 for quoting of the raw
+ # Please see: https://vyos.dev/T1129 for quoting of the raw
# parameters we can pass to ISC DHCPd
tmp_file = '/tmp/dhcpd.conf'
render(tmp_file, 'dhcp-server/dhcpd.conf.j2', dhcp,
diff --git a/src/conf_mode/http-api.py b/src/conf_mode/http-api.py
index 6328294c1..7e801eb26 100755
--- a/src/conf_mode/http-api.py
+++ b/src/conf_mode/http-api.py
@@ -79,9 +79,10 @@ def get_config(config=None):
# http-api.conf format for api_keys:
if 'keys' in api_dict:
api_dict['api_keys'] = []
- for el in list(api_dict['keys']['id']):
- key = api_dict['keys']['id'][el]['key']
- api_dict['api_keys'].append({'id': el, 'key': key})
+ for el in list(api_dict['keys'].get('id', {})):
+ key = api_dict['keys']['id'][el].get('key', '')
+ if key:
+ api_dict['api_keys'].append({'id': el, 'key': key})
del api_dict['keys']
# Do we run inside a VRF context?
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index 8155f36c2..13d84a6fe 100755
--- a/src/conf_mode/interfaces-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.py
@@ -645,7 +645,7 @@ def generate(openvpn):
user=user, group=group)
# we need to support quoting of raw parameters from OpenVPN CLI
- # see https://phabricator.vyos.net/T1632
+ # see https://vyos.dev/T1632
render(cfg_file.format(**openvpn), 'openvpn/server.conf.j2', openvpn,
formater=lambda _: _.replace(""", '"'), user=user, group=group)
diff --git a/src/conf_mode/interfaces-wwan.py b/src/conf_mode/interfaces-wwan.py
index a14a992ae..9ca495476 100755
--- a/src/conf_mode/interfaces-wwan.py
+++ b/src/conf_mode/interfaces-wwan.py
@@ -171,7 +171,7 @@ def apply(wwan):
options = f'ip-type={ip_type},apn=' + wwan['apn']
if 'authentication' in wwan:
- options += ',user={user},password={password}'.format(**wwan['authentication'])
+ options += ',user={username},password={password}'.format(**wwan['authentication'])
command = f'{base_cmd} --simple-connect="{options}"'
call(command, stdout=DEVNULL)
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index ab2ccf99e..9b7c04eb0 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -92,7 +92,7 @@ def get_config(config=None):
# Always listen on localhost if an explicit address has been configured
# This is a safety measure to not end up with invalid listen addresses
- # that are not configured on this system. See https://phabricator.vyos.net/T850
+ # that are not configured on this system. See https://vyos.dev/T850
if '127.0.0.1' not in snmp['listen_address']:
tmp = {'127.0.0.1': {'port': '161'}}
snmp['listen_address'] = dict_merge(tmp, snmp['listen_address'])
@@ -103,6 +103,9 @@ def get_config(config=None):
if 'community' in snmp:
default_values = defaults(base + ['community'])
+ if 'network' in default_values:
+ # convert multiple default networks to list
+ default_values['network'] = default_values['network'].split()
for community in snmp['community']:
snmp['community'][community] = dict_merge(
default_values, snmp['community'][community])
diff --git a/src/conf_mode/system-login.py b/src/conf_mode/system-login.py
index e26b81e3d..0a4a88bf8 100755
--- a/src/conf_mode/system-login.py
+++ b/src/conf_mode/system-login.py
@@ -16,18 +16,17 @@
import os
-from crypt import crypt
-from crypt import METHOD_SHA512
+from passlib.hosts import linux_context
from psutil import users
from pwd import getpwall
from pwd import getpwnam
-from spwd import getspnam
from sys import exit
from time import sleep
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configverify import verify_vrf
+from vyos.defaults import directories
from vyos.template import render
from vyos.template import is_ipv4
from vyos.util import cmd
@@ -43,6 +42,11 @@ airbag.enable()
autologout_file = "/etc/profile.d/autologout.sh"
radius_config_file = "/etc/pam_radius_auth.conf"
+# LOGIN_TIMEOUT from /etc/loign.defs minus 10 sec
+MAX_RADIUS_TIMEOUT: int = 50
+# MAX_RADIUS_TIMEOUT divided by 2 sec (minimum recomended timeout)
+MAX_RADIUS_COUNT: int = 25
+
def get_local_users():
"""Return list of dynamically allocated users (see Debian Policy Manual)"""
local_users = []
@@ -54,6 +58,13 @@ def get_local_users():
return local_users
+def get_shadow_password(username):
+ with open('/etc/shadow') as f:
+ for user in f.readlines():
+ items = user.split(":")
+ if username == items[0]:
+ return items[1]
+ return None
def get_config(config=None):
if config:
@@ -118,18 +129,27 @@ def verify(login):
if 'radius' in login:
if 'server' not in login['radius']:
raise ConfigError('No RADIUS server defined!')
-
+ sum_timeout: int = 0
+ radius_servers_count: int = 0
fail = True
for server, server_config in dict_search('radius.server', login).items():
if 'key' not in server_config:
raise ConfigError(f'RADIUS server "{server}" requires key!')
-
- if 'disabled' not in server_config:
+ if 'disable' not in server_config:
+ sum_timeout += int(server_config['timeout'])
+ radius_servers_count += 1
fail = False
- continue
+
if fail:
raise ConfigError('All RADIUS servers are disabled')
+ if radius_servers_count > MAX_RADIUS_COUNT:
+ raise ConfigError('Number of RADIUS servers more than 25 ')
+
+ if sum_timeout > MAX_RADIUS_TIMEOUT:
+ raise ConfigError('Sum of RADIUS servers timeouts '
+ 'has to be less or eq 50 sec')
+
verify_vrf(login['radius'])
if 'source_address' in login['radius']:
@@ -153,13 +173,13 @@ def generate(login):
for user, user_config in login['user'].items():
tmp = dict_search('authentication.plaintext_password', user_config)
if tmp:
- encrypted_password = crypt(tmp, METHOD_SHA512)
+ encrypted_password = linux_context.hash(tmp)
login['user'][user]['authentication']['encrypted_password'] = encrypted_password
del login['user'][user]['authentication']['plaintext_password']
# remove old plaintext password and set new encrypted password
env = os.environ.copy()
- env['vyos_libexec_dir'] = '/usr/libexec/vyos'
+ env['vyos_libexec_dir'] = directories['base']
# Set default commands for re-adding user with encrypted password
del_user_plain = f"system login user '{user}' authentication plaintext-password"
@@ -186,7 +206,7 @@ def generate(login):
call(f"/opt/vyatta/sbin/my_set {add_user_encrypt}", env=env)
else:
try:
- if getspnam(user).sp_pwdp == dict_search('authentication.encrypted_password', user_config):
+ if get_shadow_password(user) == dict_search('authentication.encrypted_password', user_config):
# If the current encrypted bassword matches the encrypted password
# from the config - do not update it. This will remove the encrypted
# value from the system logs.
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index ce4f13d27..d207c63df 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -53,8 +53,6 @@ dhcp_wait_attempts = 2
dhcp_wait_sleep = 1
swanctl_dir = '/etc/swanctl'
-ipsec_conf = '/etc/ipsec.conf'
-ipsec_secrets = '/etc/ipsec.secrets'
charon_conf = '/etc/strongswan.d/charon.conf'
charon_dhcp_conf = '/etc/strongswan.d/charon/dhcp.conf'
charon_radius_conf = '/etc/strongswan.d/charon/eap-radius.conf'
@@ -542,8 +540,7 @@ def generate(ipsec):
cleanup_pki_files()
if not ipsec:
- for config_file in [ipsec_conf, ipsec_secrets, charon_dhcp_conf,
- charon_radius_conf, interface_conf, swanctl_conf]:
+ for config_file in [charon_dhcp_conf, charon_radius_conf, interface_conf, swanctl_conf]:
if os.path.isfile(config_file):
os.unlink(config_file)
render(charon_conf, 'ipsec/charon.j2', {'install_routes': default_install_routes})
@@ -618,8 +615,6 @@ def generate(ipsec):
if id:
ipsec['authentication']['psk'][psk]['id'].append(id)
- render(ipsec_conf, 'ipsec/ipsec.conf.j2', ipsec)
- render(ipsec_secrets, 'ipsec/ipsec.secrets.j2', ipsec)
render(charon_conf, 'ipsec/charon.j2', ipsec)
render(charon_dhcp_conf, 'ipsec/charon/dhcp.conf.j2', ipsec)
render(charon_radius_conf, 'ipsec/charon/eap-radius.conf.j2', ipsec)
@@ -634,25 +629,12 @@ def resync_nhrp(ipsec):
if tmp > 0:
print('ERROR: failed to reapply NHRP settings!')
-def wait_for_vici_socket(timeout=5, sleep_interval=0.1):
- start_time = time()
- test_command = f'sudo socat -u OPEN:/dev/null UNIX-CONNECT:{vici_socket}'
- while True:
- if (start_time + timeout) < time():
- return None
- result = run(test_command)
- if result == 0:
- return True
- sleep(sleep_interval)
-
def apply(ipsec):
- systemd_service = 'strongswan-starter.service'
+ systemd_service = 'strongswan.service'
if not ipsec:
call(f'systemctl stop {systemd_service}')
else:
call(f'systemctl reload-or-restart {systemd_service}')
- if wait_for_vici_socket():
- call('sudo swanctl -q')
resync_nhrp(ipsec)
diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py
index 63ffe2a41..68da70d7d 100755
--- a/src/conf_mode/vpn_openconnect.py
+++ b/src/conf_mode/vpn_openconnect.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2022 VyOS maintainers and contributors
+# Copyright (C) 2018-2023 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
@@ -47,9 +47,9 @@ def get_hash(password):
return crypt(password, mksalt(METHOD_SHA512))
-def T2665_default_dict_cleanup(origin: dict, default_values: dict) -> dict:
+def _default_dict_cleanup(origin: dict, default_values: dict) -> dict:
"""
- https://phabricator.vyos.net/T2665
+ https://vyos.dev/T2665
Clear unnecessary key values in merged config by dict_merge function
:param origin: config
:type origin: dict
@@ -63,7 +63,7 @@ def T2665_default_dict_cleanup(origin: dict, default_values: dict) -> dict:
del origin['authentication']['local_users']['username']['otp']
if not origin["authentication"]["local_users"]["username"]:
raise ConfigError(
- 'Openconnect mode local required at least one user')
+ 'Openconnect authentication mode local requires at least one user')
default_ocserv_usr_values = \
default_values['authentication']['local_users']['username']['otp']
for user, params in origin['authentication']['local_users'][
@@ -82,7 +82,7 @@ def T2665_default_dict_cleanup(origin: dict, default_values: dict) -> dict:
del origin['authentication']['radius']['server']['port']
if not origin["authentication"]['radius']['server']:
raise ConfigError(
- 'Openconnect authentication mode radius required at least one radius server')
+ 'Openconnect authentication mode radius requires at least one RADIUS server')
default_values_radius_port = \
default_values['authentication']['radius']['server']['port']
for server, params in origin['authentication']['radius'][
@@ -95,7 +95,7 @@ def T2665_default_dict_cleanup(origin: dict, default_values: dict) -> dict:
del origin['accounting']['radius']['server']['port']
if not origin["accounting"]['radius']['server']:
raise ConfigError(
- 'Openconnect accounting mode radius required at least one radius server')
+ 'Openconnect accounting mode radius requires at least one RADIUS server')
default_values_radius_port = \
default_values['accounting']['radius']['server']['port']
for server, params in origin['accounting']['radius'][
@@ -105,8 +105,11 @@ def T2665_default_dict_cleanup(origin: dict, default_values: dict) -> dict:
return origin
-def get_config():
- conf = Config()
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
base = ['vpn', 'openconnect']
if not conf.exists(base):
return None
@@ -116,8 +119,8 @@ def get_config():
# options which we need to update into the dictionary retrived.
default_values = defaults(base)
ocserv = dict_merge(default_values, ocserv)
- # workaround a "know limitation" - https://phabricator.vyos.net/T2665
- ocserv = T2665_default_dict_cleanup(ocserv, default_values)
+ # workaround a "know limitation" - https://vyos.dev/T2665
+ ocserv = _default_dict_cleanup(ocserv, default_values)
if ocserv:
ocserv['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)