Atlus runs as root (systemd) but user-facing processes must run under the authenticated user's identity. Added privilege-dropping via preexec_fn (os.setgid + os.initgroups + os.setuid) to both terminal PTY spawning and GUI app launching. System admin operations (services, packages, network, updates) intentionally remain root. Autostart apps now support a configurable default_user; without one set, autostart defers until the first user logs in and runs as that user. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
37 lines
1.3 KiB
Python
37 lines
1.3 KiB
Python
"""Privilege-dropping helpers for spawning processes as non-root users.
|
|
|
|
Atlus runs as root (systemd service) but user-facing processes — terminal
|
|
PTYs and GUI applications — must run as the authenticated user. This
|
|
module provides a ``preexec_fn`` factory that drops privileges after
|
|
``fork()`` but before ``exec()``.
|
|
"""
|
|
|
|
import os
|
|
import pwd
|
|
from typing import Callable
|
|
|
|
|
|
def get_user_info(username: str) -> tuple[int, int, str, str]:
|
|
"""Return (uid, gid, home_dir, shell) for *username*.
|
|
|
|
Raises ``KeyError`` if the user does not exist on the system.
|
|
"""
|
|
pw = pwd.getpwnam(username)
|
|
return pw.pw_uid, pw.pw_gid, pw.pw_dir, pw.pw_shell
|
|
|
|
|
|
def make_preexec_fn(username: str) -> Callable[[], None]:
|
|
"""Return a closure suitable for ``preexec_fn`` that drops to *username*.
|
|
|
|
The user lookup (``pwd.getpwnam``) happens eagerly in the **parent**
|
|
process so that errors surface immediately. The ``os.set*`` calls
|
|
execute in the **child** process after ``fork()``.
|
|
"""
|
|
uid, gid, home, _shell = get_user_info(username)
|
|
|
|
def _drop_privileges() -> None:
|
|
os.setgid(gid)
|
|
os.initgroups(username, gid) # supplementary groups (sudo, video …)
|
|
os.setuid(uid) # must be last — can't setgid after this
|
|
|
|
return _drop_privileges
|