summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2025-12-17 21:36:47 +0100
committerGitHub <noreply@github.com>2025-12-17 21:36:47 +0100
commit5a22bd6e6ba87c6666b8cacecb1e8c071b81f2cd (patch)
tree6e044b10e3fa1648de2b6e8c6a3838da8e4dfa0d /python
parent3d5ebd5956c4e4333e66097d6d339c2329c21295 (diff)
parent197809bf77d841fe57bdcbaeeb3b078145aab140 (diff)
downloadvyos-1x-5a22bd6e6ba87c6666b8cacecb1e8c071b81f2cd.tar.gz
vyos-1x-5a22bd6e6ba87c6666b8cacecb1e8c071b81f2cd.zip
Merge pull request #4892 from c-po/getpwall
login: T8086: replace getpwall() based user enumeration to avoid NSS/TACACS timeouts
Diffstat (limited to 'python')
-rw-r--r--python/vyos/utils/auth.py66
1 files changed, 60 insertions, 6 deletions
diff --git a/python/vyos/utils/auth.py b/python/vyos/utils/auth.py
index 462332332..f9551419f 100644
--- a/python/vyos/utils/auth.py
+++ b/python/vyos/utils/auth.py
@@ -18,10 +18,12 @@ import math
import re
import string
-from enum import StrEnum
+from dataclasses import dataclass
from decimal import Decimal
-from pwd import getpwall
-from pwd import getpwnam
+from enum import StrEnum
+from typing import List
+from typing import Optional
+
from vyos.utils.process import cmd
# Minimum UID used when adding system users
@@ -146,12 +148,62 @@ def get_current_user() -> str:
current_user = os.environ['USER']
return current_user
+@dataclass
+class PasswdEntry:
+ pw_name: str
+ pw_passwd: str
+ pw_uid: int
+ pw_gid: int
+ pw_gecos: str
+ pw_dir: str
+ pw_shell: str
+
+def get_local_passwd_entries(uid: Optional[int] = None) -> PasswdEntry | List[PasswdEntry] | None:
+ """
+ If uid is None: return a list of all passwd entries.
+ If uid is given: return the matching entry or None.
+ """
+ entries = []
+ with open('/etc/passwd', 'r') as f:
+ for line in f:
+ line = line.strip()
+ if not line or line.startswith("#"):
+ continue
+ parts = line.split(":")
+ if len(parts) != 7:
+ continue
+
+ try:
+ entry = PasswdEntry(
+ pw_name=parts[0],
+ pw_passwd=parts[1],
+ pw_uid=int(parts[2]),
+ pw_gid=int(parts[3]),
+ pw_gecos=parts[4],
+ pw_dir=parts[5],
+ pw_shell=parts[6],
+ )
+ except ValueError:
+ # Skip entries with non-numeric UID or GID
+ continue
+
+ # If searching for a specific UID, return immediately if found
+ if uid is not None and entry.pw_uid == uid:
+ return entry
+
+ entries.append(entry)
+
+ # uid given but not found
+ if uid is not None:
+ return None
+
+ return entries
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():
+ for s_user in get_local_passwd_entries():
if s_user.pw_uid < min_uid:
continue
if s_user.pw_uid > max_uid:
@@ -162,7 +214,9 @@ def get_local_users(min_uid=MIN_USER_UID, max_uid=MAX_USER_UID) -> list:
return local_users
-
def get_user_home_dir(user: str) -> str:
"""Return user's home directory"""
- return getpwnam(user).pw_dir
+ for u in get_local_passwd_entries():
+ if u.pw_name == user:
+ return u.pw_dir
+ raise KeyError(f"User '{user}' not found in /etc/passwd")