summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/vyos/utils/auth.py49
-rw-r--r--python/vyos/utils/file.py44
2 files changed, 92 insertions, 1 deletions
diff --git a/python/vyos/utils/auth.py b/python/vyos/utils/auth.py
index 6e816af71..d64ee1f7e 100644
--- a/python/vyos/utils/auth.py
+++ b/python/vyos/utils/auth.py
@@ -20,9 +20,35 @@ import string
from enum import StrEnum
from decimal import Decimal
+from pwd import getpwall
+from pwd import getpwnam
from vyos.utils.process import cmd
-
+# Minimum UID used when adding system users
+MIN_USER_UID: int = 1000
+# Maximim UID used when adding system users
+MAX_USER_UID: int = 59999
+# List of local user accounts that must be preserved
+SYSTEM_USER_SKIP_LIST: frozenset = {
+ 'radius_user',
+ 'radius_priv_user',
+ 'tacacs0',
+ 'tacacs1',
+ 'tacacs2',
+ 'tacacs3',
+ 'tacacs4',
+ 'tacacs5',
+ 'tacacs6',
+ 'tacacs7',
+ 'tacacs8',
+ 'tacacs9',
+ 'tacacs10',
+ 'tacacs11',
+ 'tacacs12',
+ 'tacacs13',
+ 'tacacs14',
+ 'tacacs15',
+}
DEFAULT_PASSWORD: str = 'vyos'
LOW_ENTROPY_MSG: str = 'should be at least 8 characters long;'
WEAK_PASSWORD_MSG: str = 'The password complexity is too low - @MSG@'
@@ -119,3 +145,24 @@ def get_current_user() -> str:
elif 'USER' in os.environ:
current_user = os.environ['USER']
return current_user
+
+
+def get_local_users(min_uid=MIN_USER_UID, max_uid=MAX_USER_UID) -> list:
+ """Return list of dynamically allocated users (see Debian Policy Manual)"""
+ local_users = []
+
+ for s_user in getpwall():
+ if s_user.pw_uid < min_uid:
+ continue
+ if s_user.pw_uid > max_uid:
+ continue
+ if s_user.pw_name in SYSTEM_USER_SKIP_LIST:
+ continue
+ local_users.append(s_user.pw_name)
+
+ return local_users
+
+
+def get_user_home_dir(user: str) -> str:
+ """Return user's home directory"""
+ return getpwnam(user).pw_dir
diff --git a/python/vyos/utils/file.py b/python/vyos/utils/file.py
index 491cc6547..98d88d9e4 100644
--- a/python/vyos/utils/file.py
+++ b/python/vyos/utils/file.py
@@ -15,6 +15,7 @@
import os
import tempfile
+import shutil
from vyos.utils.permission import chown
@@ -268,3 +269,46 @@ def write_file_atomic(file_path, data: str, mode='w'):
except OSError as e:
cleanup()
raise OSError(f'rename {e}')
+
+def copy_recursive(src: str, dst: str, overwrite: bool = False):
+ """
+ Recursively copy files from `src` to `dst`.
+
+ :param src: Source directory
+ :param dst: Destination directory
+ :param overwrite: If True, overwrite existing files. If False, skip them.
+ """
+
+ if not os.path.exists(src):
+ raise FileNotFoundError(f"Source path does not exist: {src}")
+
+ os.makedirs(dst, exist_ok=True) # Create destination directory if not exists
+
+ for root, _, files in os.walk(src):
+ # Find relative path to maintain directory structure
+ rel_path = os.path.relpath(root, src)
+ target_dir = os.path.join(dst, rel_path) if rel_path != "." else dst
+
+ os.makedirs(target_dir, exist_ok=True)
+
+ for file in files:
+ src_file = os.path.join(root, file)
+ dst_file = os.path.join(target_dir, file)
+
+ if not os.path.exists(dst_file) or overwrite:
+ shutil.copy2(src_file, dst_file)
+
+
+def move_recursive(src: str, dst: str, overwrite=False):
+ """
+ Recursively move files from `src` to `dst` and removing the source.
+
+ :param src: Source directory
+ :param dst: Destination directory
+ :param overwrite: If True, overwrite existing files. If False, skip them.
+ """
+ if not os.path.exists(src):
+ raise FileNotFoundError(f"Source path does not exist: {src}")
+
+ copy_recursive(src, dst, overwrite=overwrite)
+ shutil.rmtree(src)