Description: tests: refactor the handling of the unprivileged account
Origin: upstream, https://gitlab.com/ppentchev/remrun/-/commit/81da8f81c1622f466ec9740361cf56c76586e6dd
Author: Peter Pentchev <roam@ringlet.net>
Last-Update: 2025-05-03

--- a/tests/python/run_sshd_test/__main__.py
+++ b/tests/python/run_sshd_test/__main__.py
@@ -35,13 +35,21 @@
 
 
 @dataclasses.dataclass(frozen=True)
+class Account:
+    """The (possibly unprivileged) account to run the tests as."""
+
+    pw_ent: pwd.struct_passwd
+    need_setuid: bool
+
+
+@dataclasses.dataclass(frozen=True)
 class Config:
     """Runtime configuration for the remrun test tool."""
 
     log: logging.Logger
     prog: pathlib.Path
     test_prog: pathlib.Path | None
-    unpriv_account: str | None
+    test_account: Account
     utf8_env: dict[str, str]
 
 
@@ -57,6 +65,30 @@
     server_config: pathlib.Path
 
 
+def get_test_account(log: logging.Logger, unprivileged: str | None) -> Account:
+    """Get the data about the account we are running as or the other one."""
+    if unprivileged is None:
+        our_uid: Final = os.geteuid()
+        log.debug("Getting information about our own account, uid %(uid)d", {"uid": our_uid})
+        our_pw_ent: Final = pwd.getpwuid(our_uid)
+        log.debug(
+            "Got username %(name)s, uid %(uid)d, home %(home)s",
+            {"name": our_pw_ent.pw_name, "uid": our_pw_ent.pw_uid, "home": our_pw_ent.pw_dir},
+        )
+        return Account(pw_ent=our_pw_ent, need_setuid=False)
+
+    log.debug(
+        "Getting information about another account, username %(name)s",
+        {"name": unprivileged},
+    )
+    unpriv_pw_ent: Final = pwd.getpwnam(unprivileged)
+    log.debug(
+        "Got username %(name)s, uid %(uid)d, home %(home)s",
+        {"name": unpriv_pw_ent.pw_name, "uid": unpriv_pw_ent.pw_uid, "home": unpriv_pw_ent.pw_dir},
+    )
+    return Account(pw_ent=unpriv_pw_ent, need_setuid=True)
+
+
 def parse_args() -> Config:
     """Parse the command-line arguments."""
     parser: Final = argparse.ArgumentParser(prog="run_sshd_test")
@@ -86,11 +118,14 @@
     if not prog.is_file() or not os.access(prog, os.R_OK | os.X_OK):
         sys.exit(f"Not an executable regular file: {prog}")
 
+    log: Final = util.build_logger(verbose=args.verbose, quiet=False)
+    test_account: Final = get_test_account(log, args.unprivileged)
+
     return Config(
-        log=util.build_logger(verbose=args.verbose, quiet=False),
+        log=log,
         prog=prog,
         test_prog=args.test_prog.absolute() if args.test_prog is not None else None,
-        unpriv_account=args.unprivileged if args.unprivileged is not None else None,
+        test_account=test_account,
         utf8_env=util.get_utf8_env(),
     )
 
@@ -413,26 +448,21 @@
         cfg.log.debug("Creating the %(path)s directory", {"path": PATH_PRIVSEP})
         PATH_PRIVSEP.mkdir(mode=0o744, parents=True)
 
-    if cfg.unpriv_account is not None:
-        cfg.log.debug(
-            "Getting information about the %(unpriv)r account",
-            {"unpriv": cfg.unpriv_account},
+    if cfg.test_account.need_setuid:
+        name, uid, gid = (
+            cfg.test_account.pw_ent.pw_name,
+            cfg.test_account.pw_ent.pw_uid,
+            cfg.test_account.pw_ent.pw_gid,
         )
-        try:
-            acc_ent: Final = pwd.getpwnam(cfg.unpriv_account)
-        except KeyError:
-            sys.exit(f"Unknown user account {cfg.unpriv_account!r}")
-
         cfg.log.debug(
-            "Changing the ownership of %(tempd)s to %(unpriv)r",
-            {"tempd": tempd, "unpriv": cfg.unpriv_account},
+            "Changing the ownership of %(tempd)s to %(uid)d:%(gid)d for %(unpriv)r",
+            {"tempd": tempd, "uid": uid, "gid": gid, "unpriv": cfg.test_account.pw_ent.pw_name},
         )
         try:
-            os.chown(tempd, acc_ent.pw_uid, acc_ent.pw_gid)
+            os.chown(tempd, uid, gid)
         except OSError as err:
             sys.exit(
-                f"Could not chown() {tempd} to {acc_ent.pw_uid}:{acc_ent.pw_gid} for "
-                f"{cfg.unpriv_account!r}: {err}",
+                f"Could not chown() {tempd} to {uid}:{gid} for {name!r}: {err}",
             )
 
         child_pid: Final = os.fork()
@@ -448,14 +478,13 @@
             )
             return False
 
-        cfg.log.debug("Trying to setuid() to %(unpriv)r", {"unpriv": cfg.unpriv_account})
+        cfg.log.debug("Trying to setuid() to %(unpriv)r", {"unpriv": name})
         try:
-            os.setgid(acc_ent.pw_gid)
-            os.setuid(acc_ent.pw_uid)
+            os.setgid(gid)
+            os.setuid(uid)
         except OSError as err:
             sys.exit(
-                f"Could not setuid()/setgid() to {acc_ent.pw_uid}:{acc_ent.pw_gid} for "
-                f"{cfg.unpriv_account!r}: {err}",
+                f"Could not setuid()/setgid() to {uid}:{gid} for {name!r}: {err}",
             )
 
     return True
