diff options
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/service_snmp.py | 28 | ||||
| -rwxr-xr-x | src/conf_mode/service_suricata.py | 161 | ||||
| -rwxr-xr-x | src/conf_mode/system_login.py | 50 | ||||
| -rwxr-xr-x | src/conf_mode/system_option.py | 13 | ||||
| -rw-r--r-- | src/etc/systemd/system/suricata.service.d/10-override.conf | 9 | ||||
| -rwxr-xr-x | src/migration-scripts/interfaces/20-to-21 | 7 | ||||
| -rwxr-xr-x | src/services/vyos-configd | 10 | ||||
| -rw-r--r-- | src/shim/vyshim.c | 11 | 
8 files changed, 64 insertions, 225 deletions
| diff --git a/src/conf_mode/service_snmp.py b/src/conf_mode/service_snmp.py index 6565ffd60..6f025cc23 100755 --- a/src/conf_mode/service_snmp.py +++ b/src/conf_mode/service_snmp.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2018-2023 VyOS maintainers and contributors +# Copyright (C) 2018-2024 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 @@ -26,10 +26,12 @@ from vyos.snmpv3_hashgen import plaintext_to_md5  from vyos.snmpv3_hashgen import plaintext_to_sha1  from vyos.snmpv3_hashgen import random  from vyos.template import render -from vyos.utils.process import call -from vyos.utils.permission import chmod_755 +from vyos.utils.configfs import delete_cli_node +from vyos.utils.configfs import add_cli_node  from vyos.utils.dict import dict_search  from vyos.utils.network import is_addr_assigned +from vyos.utils.process import call +from vyos.utils.permission import chmod_755  from vyos.version import get_version_data  from vyos import ConfigError  from vyos import airbag @@ -192,12 +194,8 @@ def generate(snmp):          return None      if 'v3' in snmp: -        # net-snmp is now regenerating the configuration file in the background -        # thus we need to re-open and re-read the file as the content changed. -        # After that we can no read the encrypted password from the config and -        # replace the CLI plaintext password with its encrypted version. -        os.environ['vyos_libexec_dir'] = '/usr/libexec/vyos' - +        # SNMPv3 uses a hashed password. If CLI defines a plaintext password, +        # we will hash it in the background and replace the CLI node!          if 'user' in snmp['v3']:              for user, user_config in snmp['v3']['user'].items():                  if dict_search('auth.type', user_config)  == 'sha': @@ -212,8 +210,9 @@ def generate(snmp):                      snmp['v3']['user'][user]['auth']['encrypted_password'] = tmp                      del snmp['v3']['user'][user]['auth']['plaintext_password'] -                    call(f'/opt/vyatta/sbin/my_set service snmp v3 user "{user}" auth encrypted-password "{tmp}" > /dev/null') -                    call(f'/opt/vyatta/sbin/my_delete service snmp v3 user "{user}" auth plaintext-password > /dev/null') +                    cli_base = ['service', 'snmp', 'v3', 'user', user, 'auth'] +                    delete_cli_node(cli_base + ['plaintext-password']) +                    add_cli_node(cli_base + ['encrypted-password'], value=tmp)                  if dict_search('privacy.plaintext_password', user_config) is not None:                      tmp = hash(dict_search('privacy.plaintext_password', user_config), @@ -222,8 +221,9 @@ def generate(snmp):                      snmp['v3']['user'][user]['privacy']['encrypted_password'] = tmp                      del snmp['v3']['user'][user]['privacy']['plaintext_password'] -                    call(f'/opt/vyatta/sbin/my_set service snmp v3 user "{user}" privacy encrypted-password "{tmp}" > /dev/null') -                    call(f'/opt/vyatta/sbin/my_delete service snmp v3 user "{user}" privacy plaintext-password > /dev/null') +                    cli_base = ['service', 'snmp', 'v3', 'user', user, 'privacy'] +                    delete_cli_node(cli_base + ['plaintext-password']) +                    add_cli_node(cli_base + ['encrypted-password'], value=tmp)      # Write client config file      render(config_file_client, 'snmp/etc.snmp.conf.j2', snmp) @@ -246,7 +246,7 @@ def apply(snmp):          return None      # start SNMP daemon -    call(f'systemctl restart {systemd_service}') +    call(f'systemctl reload-or-restart {systemd_service}')      # Enable AgentX in FRR      # This should be done for each daemon individually because common command diff --git a/src/conf_mode/service_suricata.py b/src/conf_mode/service_suricata.py deleted file mode 100755 index 69b369e0b..000000000 --- a/src/conf_mode/service_suricata.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2024 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.base import Warning -from vyos.config import Config -from vyos.template import render -from vyos.utils.process import call -from vyos import ConfigError -from vyos import airbag -airbag.enable() - -config_file = '/run/suricata/suricata.yaml' -rotate_file = '/etc/logrotate.d/suricata' - -def get_config(config=None): -    if config: -        conf = config -    else: -        conf = Config() -    base = ['service', 'suricata'] - -    if not conf.exists(base): -        return None - -    suricata = conf.get_config_dict(base, key_mangling=('-', '_'), -                                    get_first_key=True, with_recursive_defaults=True) - -    return suricata - -# https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search -def topological_sort(source): -    sorted_nodes = [] -    permanent_marks = set() -    temporary_marks = set() - -    def visit(n, v): -        if n in permanent_marks: -            return -        if n in temporary_marks: -            raise ConfigError('At least one cycle exists in the referenced groups') - -        temporary_marks.add(n) - -        for m in v.get('group', []): -            m = m.lstrip('!') -            if m not in source: -                raise ConfigError(f'Undefined referenced group "{m}"') -            visit(m, source[m]) - -        temporary_marks.remove(n) -        permanent_marks.add(n) -        sorted_nodes.append((n, v)) - -    while len(permanent_marks) < len(source): -        n = next(n for n in source.keys() if n not in permanent_marks) -        visit(n, source[n]) - -    return sorted_nodes - -def verify(suricata): -    if not suricata: -        return None - -    if 'interface' not in suricata: -        raise ConfigError('No interfaces configured!') - -    if 'address_group' not in suricata: -        raise ConfigError('No address-group configured!') - -    if 'port_group' not in suricata: -        raise ConfigError('No port-group configured!') - -    try: -        topological_sort(suricata['address_group']) -    except (ConfigError,StopIteration) as e: -        raise ConfigError(f'Invalid address-group: {e}') - -    try: -        topological_sort(suricata['port_group']) -    except (ConfigError,StopIteration) as e: -        raise ConfigError(f'Invalid port-group: {e}') - -def generate(suricata): -    if not suricata: -        for file in [config_file, rotate_file]: -            if os.path.isfile(file): -                os.unlink(file) - -        return None - -    # Config-related formatters -    def to_var(s:str): -        return s.replace('-','_').upper() - -    def to_val(s:str): -        return s.replace('-',':') - -    def to_ref(s:str): -        if s[0] == '!': -            return '!$' + to_var(s[1:]) -        return '$' + to_var(s) - -    def to_config(kind:str): -        def format_group(group): -            (name, value) = group -            property = [to_val(property) for property in value.get(kind,[])] -            group = [to_ref(group) for group in value.get('group',[])] -            return (to_var(name), property + group) -        return format_group - -    # Format the address group -    suricata['address_group'] = map(to_config('address'), -                                    topological_sort(suricata['address_group'])) - -    # Format the port group -    suricata['port_group'] = map(to_config('port'), -                                    topological_sort(suricata['port_group'])) - -    render(config_file, 'ids/suricata.j2', {'suricata': suricata}) -    render(rotate_file, 'ids/suricata_logrotate.j2', suricata) -    return None - -def apply(suricata): -    systemd_service = 'suricata.service' -    if not suricata or 'interface' not in suricata: -        # Stop suricata service if removed -        call(f'systemctl stop {systemd_service}') -    else: -        Warning('To fetch the latest rules, use "update suricata"; ' -                'To periodically fetch the latest rules, ' -                'use the task scheduler!') -        call(f'systemctl restart {systemd_service}') - -    return None - -if __name__ == '__main__': -    try: -        c = get_config() -        verify(c) -        generate(c) -        apply(c) -    except ConfigError as e: -        print(e) -        exit(1) diff --git a/src/conf_mode/system_login.py b/src/conf_mode/system_login.py index 20121f170..439fa645b 100755 --- a/src/conf_mode/system_login.py +++ b/src/conf_mode/system_login.py @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2020-2023 VyOS maintainers and contributors +# Copyright (C) 2020-2024 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 @@ -26,14 +26,15 @@ from time import sleep  from vyos.config import Config  from vyos.configverify import verify_vrf -from vyos.defaults import directories  from vyos.template import render  from vyos.template import is_ipv4 +from vyos.utils.auth import get_current_user +from vyos.utils.configfs import delete_cli_node +from vyos.utils.configfs import add_cli_node  from vyos.utils.dict import dict_search  from vyos.utils.file import chown  from vyos.utils.process import cmd  from vyos.utils.process import call -from vyos.utils.process import rc_cmd  from vyos.utils.process import run  from vyos.utils.process import DEVNULL  from vyos import ConfigError @@ -125,10 +126,9 @@ def verify(login):          # This check is required as the script is also executed from vyos-router          # init script and there is no SUDO_USER environment variable available          # during system boot. -        if 'SUDO_USER' in os.environ: -            cur_user = os.environ['SUDO_USER'] -            if cur_user in login['rm_users']: -                raise ConfigError(f'Attempting to delete current user: {cur_user}') +        tmp = get_current_user() +        if tmp in login['rm_users']: +            raise ConfigError(f'Attempting to delete current user: {tmp}')      if 'user' in login:          system_users = getpwall() @@ -221,35 +221,13 @@ def generate(login):                  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'] = directories['base'] -                  # Set default commands for re-adding user with encrypted password -                del_user_plain = f"system login user {user} authentication plaintext-password" -                add_user_encrypt = f"system login user {user} authentication encrypted-password '{encrypted_password}'" - -                lvl = env['VYATTA_EDIT_LEVEL'] -                # We're in config edit level, for example "edit system login" -                # Change default commands for re-adding user with encrypted password -                if lvl != '/': -                    # Replace '/system/login' to 'system login' -                    lvl = lvl.strip('/').split('/') -                    # Convert command str to list -                    del_user_plain = del_user_plain.split() -                    # New command exclude level, for example "edit system login" -                    del_user_plain = del_user_plain[len(lvl):] -                    # Convert string to list -                    del_user_plain = " ".join(del_user_plain) - -                    add_user_encrypt = add_user_encrypt.split() -                    add_user_encrypt = add_user_encrypt[len(lvl):] -                    add_user_encrypt = " ".join(add_user_encrypt) - -                ret, out = rc_cmd(f"/opt/vyatta/sbin/my_delete {del_user_plain}", env=env) -                if ret: raise ConfigError(out) -                ret, out = rc_cmd(f"/opt/vyatta/sbin/my_set {add_user_encrypt}", env=env) -                if ret: raise ConfigError(out) +                del_user_plain = ['system', 'login', 'user', user, 'authentication', 'plaintext-password'] +                add_user_encrypt = ['system', 'login', 'user', user, 'authentication', 'encrypted-password'] + +                delete_cli_node(del_user_plain) +                add_cli_node(add_user_encrypt, value=encrypted_password) +              else:                  try:                      if get_shadow_password(user) == dict_search('authentication.encrypted_password', user_config): @@ -283,8 +261,6 @@ def generate(login):          if os.path.isfile(tacacs_nss_config_file):              os.unlink(tacacs_nss_config_file) - -      # NSS must always be present on the system      render(nss_config_file, 'login/nsswitch.conf.j2', login,                 permission=0o644, user='root', group='root') diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py index 2c31703e9..ad4c0deae 100755 --- a/src/conf_mode/system_option.py +++ b/src/conf_mode/system_option.py @@ -24,6 +24,9 @@ from vyos.configverify import verify_source_interface  from vyos.configverify import verify_interface_exists  from vyos.system import grub_util  from vyos.template import render +from vyos.utils.dict import dict_search +from vyos.utils.file import write_file +from vyos.utils.kernel import check_kmod  from vyos.utils.process import cmd  from vyos.utils.process import is_systemd_service_running  from vyos.utils.network import is_addr_assigned @@ -36,6 +39,7 @@ curlrc_config = r'/etc/curlrc'  ssh_config = r'/etc/ssh/ssh_config.d/91-vyos-ssh-client-options.conf'  systemd_action_file = '/lib/systemd/system/ctrl-alt-del.target'  usb_autosuspend = r'/etc/udev/rules.d/40-usb-autosuspend.rules' +kernel_dynamic_debug = r'/sys/kernel/debug/dynamic_debug/control'  time_format_to_locale = {      '12-hour': 'en_US.UTF-8',      '24-hour': 'en_GB.UTF-8' @@ -159,6 +163,15 @@ def apply(options):      cmd('udevadm control --reload-rules') +    # Enable/disable dynamic debugging for kernel modules +    modules = ['wireguard'] +    modules_enabled = dict_search('kernel.debug', options) or [] +    for module in modules: +        if module in modules_enabled: +            check_kmod(module) +            write_file(kernel_dynamic_debug, f'module {module} +p') +        else: +            write_file(kernel_dynamic_debug, f'module {module} -p')  if __name__ == '__main__':      try: diff --git a/src/etc/systemd/system/suricata.service.d/10-override.conf b/src/etc/systemd/system/suricata.service.d/10-override.conf deleted file mode 100644 index 781256cf5..000000000 --- a/src/etc/systemd/system/suricata.service.d/10-override.conf +++ /dev/null @@ -1,9 +0,0 @@ -[Service] -ExecStart= -ExecStart=/usr/bin/suricata -D --af-packet -c /run/suricata/suricata.yaml --pidfile /run/suricata/suricata.pid -PIDFile= -PIDFile=/run/suricata/suricata.pid -ExecReload= -ExecReload=/usr/bin/suricatasc -c reload-rules /run/suricata/suricata.socket ; /bin/kill -HUP $MAINPID -ExecStop= -ExecStop=/usr/bin/suricatasc -c shutdown /run/suricata/suricata.socket diff --git a/src/migration-scripts/interfaces/20-to-21 b/src/migration-scripts/interfaces/20-to-21 index 14ad0fe4d..05a0c7237 100755 --- a/src/migration-scripts/interfaces/20-to-21 +++ b/src/migration-scripts/interfaces/20-to-21 @@ -1,6 +1,6 @@  #!/usr/bin/env python3  # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-2024 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 @@ -22,6 +22,7 @@ from sys import argv  from vyos.ethtool import Ethtool  from vyos.configtree import ConfigTree +from vyos.utils.network import interface_exists  if len(argv) < 2:      print("Must specify file name!") @@ -38,6 +39,10 @@ if not config.exists(base):      exit(0)  for ifname in config.list_nodes(base): +    # Bail out early if interface vanished from system +    if not interface_exists(ifname): +        continue +      eth = Ethtool(ifname)      # If GRO is enabled by the Kernel - we reflect this on the CLI. If GRO is diff --git a/src/services/vyos-configd b/src/services/vyos-configd index c89c486e5..d92b539c8 100755 --- a/src/services/vyos-configd +++ b/src/services/vyos-configd @@ -179,8 +179,13 @@ def initialization(socket):      pid_string = socket.recv().decode("utf-8", "ignore")      resp = "pid"      socket.send(resp.encode()) +    sudo_user_string = socket.recv().decode("utf-8", "ignore") +    resp = "sudo_user" +    socket.send(resp.encode())      logger.debug(f"config session pid is {pid_string}") +    logger.debug(f"config session sudo_user is {sudo_user_string}") +      try:          session_out = os.readlink(f"/proc/{pid_string}/fd/1")          session_mode = 'w' @@ -192,6 +197,8 @@ def initialization(socket):          session_out = script_stdout_log          session_mode = 'a' +    os.environ['SUDO_USER'] = sudo_user_string +      try:          configsource = ConfigSourceString(running_config_text=active_string,                                            session_config_text=session_string) @@ -266,9 +273,6 @@ if __name__ == '__main__':      cfg_group = grp.getgrnam(CFG_GROUP)      os.setgid(cfg_group.gr_gid) -    os.environ['SUDO_USER'] = 'vyos' -    os.environ['SUDO_GID'] = str(cfg_group.gr_gid) -      def sig_handler(signum, frame):          shutdown() diff --git a/src/shim/vyshim.c b/src/shim/vyshim.c index 41723e7a4..4d836127d 100644 --- a/src/shim/vyshim.c +++ b/src/shim/vyshim.c @@ -178,6 +178,13 @@ int initialization(void* Requester)      strsep(&pid_val, "_");      debug_print("config session pid: %s\n", pid_val); +    char *sudo_user = getenv("SUDO_USER"); +    if (!sudo_user) { +        char nobody[] = "nobody"; +        sudo_user = nobody; +    } +    debug_print("sudo_user is %s\n", sudo_user); +      debug_print("Sending init announcement\n");      char *init_announce = mkjson(MKJSON_OBJ, 1,                                   MKJSON_STRING, "type", "init"); @@ -240,6 +247,10 @@ int initialization(void* Requester)      zmq_recv(Requester, buffer, 16, 0);      debug_print("Received pid receipt\n"); +    debug_print("Sending config session sudo_user\n"); +    zmq_send(Requester, sudo_user, strlen(sudo_user), 0); +    zmq_recv(Requester, buffer, 16, 0); +    debug_print("Received sudo_user receipt\n");      return 0;  } | 
