summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2024-06-24 19:05:54 +0200
committerGitHub <noreply@github.com>2024-06-24 19:05:54 +0200
commit340e44c59663d2b94e7b1fddb05c49a3ad737938 (patch)
treec9049d3911b4bfbeec7c938122213dd47cad0a62
parentae8390a110ec4c507aad8eca252b3153ae1f3316 (diff)
parent8603967cbd7eb1ecdbad2e0960d1a18c667d38a3 (diff)
downloadvyos-1x-340e44c59663d2b94e7b1fddb05c49a3ad737938.tar.gz
vyos-1x-340e44c59663d2b94e7b1fddb05c49a3ad737938.zip
Merge pull request #3717 from vyos/mergify/bp/circinus/pr-3652
T6489: Add support for CLI config scripts that change the underlaying working configuration (backport #3652)
-rw-r--r--data/configd-include.json1
-rw-r--r--python/vyos/configsession.py10
-rw-r--r--python/vyos/defaults.py5
-rw-r--r--python/vyos/utils/__init__.py1
-rw-r--r--python/vyos/utils/auth.py12
-rw-r--r--python/vyos/utils/configfs.py37
-rwxr-xr-xsrc/conf_mode/system_login.py50
7 files changed, 70 insertions, 46 deletions
diff --git a/data/configd-include.json b/data/configd-include.json
index dcee50306..ac1c18ad1 100644
--- a/data/configd-include.json
+++ b/data/configd-include.json
@@ -92,6 +92,7 @@
"system_ip.py",
"system_ipv6.py",
"system_lcd.py",
+"system_login.py",
"system_login_banner.py",
"system_logs.py",
"system_option.py",
diff --git a/python/vyos/configsession.py b/python/vyos/configsession.py
index beec6010b..ccf2ce8f2 100644
--- a/python/vyos/configsession.py
+++ b/python/vyos/configsession.py
@@ -1,5 +1,4 @@
-# configsession -- the write API for the VyOS running config
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 VyOS maintainers and contributors
#
# This library is free software; you can redistribute it and/or modify it under the terms of
# the GNU Lesser General Public License as published by the Free Software Foundation;
@@ -12,11 +11,14 @@
# You should have received a copy of the GNU Lesser General Public License along with this library;
# if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# configsession -- the write API for the VyOS running config
+
import os
import re
import sys
import subprocess
+from vyos.defaults import directories
from vyos.utils.process import is_systemd_service_running
from vyos.utils.dict import dict_to_paths
@@ -58,7 +60,7 @@ def inject_vyos_env(env):
env['VYOS_HEADLESS_CLIENT'] = 'vyos_http_api'
env['vyatta_bindir']= '/opt/vyatta/bin'
env['vyatta_cfg_templates'] = '/opt/vyatta/share/vyatta-cfg/templates'
- env['vyatta_configdir'] = '/opt/vyatta/config'
+ env['vyatta_configdir'] = directories['vyos_configdir']
env['vyatta_datadir'] = '/opt/vyatta/share'
env['vyatta_datarootdir'] = '/opt/vyatta/share'
env['vyatta_libdir'] = '/opt/vyatta/lib'
@@ -70,7 +72,7 @@ def inject_vyos_env(env):
env['vyos_bin_dir'] = '/usr/bin'
env['vyos_cfg_templates'] = '/opt/vyatta/share/vyatta-cfg/templates'
env['vyos_completion_dir'] = '/usr/libexec/vyos/completion'
- env['vyos_configdir'] = '/opt/vyatta/config'
+ env['vyos_configdir'] = directories['vyos_configdir']
env['vyos_conf_scripts_dir'] = '/usr/libexec/vyos/conf_mode'
env['vyos_datadir'] = '/opt/vyatta/share'
env['vyos_datarootdir']= '/opt/vyatta/share'
diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py
index e7cd69a8b..9ccd925ce 100644
--- a/python/vyos/defaults.py
+++ b/python/vyos/defaults.py
@@ -1,4 +1,4 @@
-# Copyright 2018-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2018-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -35,6 +35,7 @@ directories = {
'vyos_udev_dir' : '/run/udev/vyos',
'isc_dhclient_dir' : '/run/dhclient',
'dhcp6_client_dir' : '/run/dhcp6c',
+ 'vyos_configdir' : '/opt/vyatta/config'
}
config_status = '/tmp/vyos-config-status'
@@ -44,7 +45,7 @@ cfg_group = 'vyattacfg'
cfg_vintage = 'vyos'
-commit_lock = '/opt/vyatta/config/.lock'
+commit_lock = os.path.join(directories['vyos_configdir'], '.lock')
component_version_json = os.path.join(directories['data'], 'component-versions.json')
diff --git a/python/vyos/utils/__init__.py b/python/vyos/utils/__init__.py
index 1cd062a11..90620071b 100644
--- a/python/vyos/utils/__init__.py
+++ b/python/vyos/utils/__init__.py
@@ -17,6 +17,7 @@ from vyos.utils import assertion
from vyos.utils import auth
from vyos.utils import boot
from vyos.utils import commit
+from vyos.utils import configfs
from vyos.utils import convert
from vyos.utils import cpu
from vyos.utils import dict
diff --git a/python/vyos/utils/auth.py b/python/vyos/utils/auth.py
index a59858d72..d014f756f 100644
--- a/python/vyos/utils/auth.py
+++ b/python/vyos/utils/auth.py
@@ -1,6 +1,6 @@
# authutils -- miscelanneous functions for handling passwords and publis keys
#
-# Copyright (C) 2018 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 VyOS maintainers and contributors
#
# This library is free software; you can redistribute it and/or modify it under the terms of
# the GNU Lesser General Public License as published by the Free Software Foundation;
@@ -11,13 +11,12 @@
# See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along with this library;
-# if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import re
from vyos.utils.process import cmd
-
def make_password_hash(password):
""" Makes a password hash for /etc/shadow using mkpasswd """
@@ -39,3 +38,10 @@ def split_ssh_public_key(key_string, defaultname=""):
raise ValueError("Bad key type \'{0}\', must be one of must be one of ssh-rsa, ssh-dss, ecdsa-sha2-nistp<256|384|521> or ssh-ed25519".format(key_type))
return({"type": key_type, "data": key_data, "name": key_name})
+
+def get_current_user() -> str:
+ import os
+ current_user = 'nobody'
+ if 'SUDO_USER' in os.environ:
+ current_user = os.environ['SUDO_USER']
+ return current_user
diff --git a/python/vyos/utils/configfs.py b/python/vyos/utils/configfs.py
new file mode 100644
index 000000000..8617f0129
--- /dev/null
+++ b/python/vyos/utils/configfs.py
@@ -0,0 +1,37 @@
+# Copyright 2024 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+
+def delete_cli_node(cli_path: list):
+ from shutil import rmtree
+ for config_dir in ['VYATTA_TEMP_CONFIG_DIR', 'VYATTA_CHANGES_ONLY_DIR']:
+ tmp = os.path.join(os.environ[config_dir], '/'.join(cli_path))
+ # delete CLI node
+ if os.path.exists(tmp):
+ rmtree(tmp)
+
+def add_cli_node(cli_path: list, value: str=None):
+ from vyos.utils.auth import get_current_user
+ from vyos.utils.file import write_file
+
+ current_user = get_current_user()
+ for config_dir in ['VYATTA_TEMP_CONFIG_DIR', 'VYATTA_CHANGES_ONLY_DIR']:
+ # store new value
+ tmp = os.path.join(os.environ[config_dir], '/'.join(cli_path))
+ write_file(f'{tmp}/node.val', value, user=current_user, group='vyattacfg', mode=0o664)
+ # mark CLI node as modified
+ if config_dir == 'VYATTA_CHANGES_ONLY_DIR':
+ write_file(f'{tmp}/.modified', '', user=current_user, group='vyattacfg', mode=0o664)
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')