jovian-greeter: just bring our own setuid wrapper

No need for pkexec, also remove fallback path that basically never works
This commit is contained in:
K900
2025-01-12 12:15:36 +03:00
parent 6ad0f1cd97
commit f2da0647de
7 changed files with 113 additions and 84 deletions

View File

@@ -134,21 +134,12 @@ in
'';
};
environment = {
systemPackages = [ pkgs.jovian-greeter.helper ];
pathsToLink = [ "lib/jovian-greeter" ];
security.wrappers.jovian-consume-session = {
source = "${pkgs.jovian-greeter.helper}/bin/consume-session";
owner = cfg.user;
group = "users";
setuid = true;
};
security.polkit.extraConfig = ''
polkit.addRule(function(action, subject) {
if (
action.id == "org.freedesktop.policykit.exec" &&
action.lookup("program") == "/run/current-system/sw/lib/jovian-greeter/consume-session" &&
subject.user == "jovian-greeter"
) {
return polkit.Result.YES;
}
});
'';
xdg.portal.configPackages = mkDefault [ pkgs.gamescope-session ];
})

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
if [[ "$#" != "1" ]]; then
>&2 echo "Usage: $0 <user>"
exit 1
fi
user="$1"
uid=$(id -u "$user")
if [[ "$uid" -lt "1000" ]]; then
>&2 echo "UID $uid is too low"
exit 1
fi
home=$(eval echo ~"$user")
if ! [[ "$home" == /* ]]; then
>&2 echo "Invalid home directory"
exit 1
fi
session_file="$home/.local/state/steamos-session-select"
if [[ -e "$session_file" ]]; then
cat "$session_file"
rm "$session_file"
fi

View File

@@ -0,0 +1,46 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bitflags"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "consume-session"
version = "0.1.0"
dependencies = [
"nix",
]
[[package]]
name = "libc"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "nix"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags",
"cfg-if",
"cfg_aliases",
"libc",
]

View File

@@ -0,0 +1,7 @@
[package]
name = "consume-session"
version = "0.1.0"
edition = "2021"
[dependencies]
nix = { version = "*", features = ["user"] }

View File

@@ -0,0 +1,23 @@
use nix::unistd::{Uid, User};
use std::{fs, io};
fn main() {
let uid = Uid::effective();
let user = User::from_uid(uid)
.expect("Unable to get current user info")
.expect("Current user does not exist");
let mut path = user.dir;
path.push(".local/state/steamos-session-select");
let session = fs::read_to_string(&path);
match session {
Ok(s) => {
print!("{}", s);
fs::remove_file(&path).expect("Failed to remove session file");
},
Err(e) => match e.kind() {
io::ErrorKind::NotFound => {}
_ => eprintln!("Error when reading session file: {:?}", e),
},
}
}

View File

@@ -1,10 +1,8 @@
{ lib, stdenv, python3, plymouth, shellcheck, nodePackages }:
{ lib, stdenv, python3, plymouth, shellcheck, nodePackages, rustPlatform }:
stdenv.mkDerivation {
name = "jovian-greeter";
outputs = [ "out" "helper" ];
src = ./.;
nativeBuildInputs = [ python3.pkgs.wrapPython ];
@@ -19,7 +17,6 @@ stdenv.mkDerivation {
checkPhase = ''
runHook preCheck
shellcheck ./consume-session
pyright *.py
runHook postCheck
@@ -31,8 +28,18 @@ stdenv.mkDerivation {
install -Dm555 greeter.py $out/bin/jovian-greeter
wrapPythonPrograms --prefix PATH : ${lib.makeBinPath [ plymouth ]}
install -Dm555 ./consume-session $helper/lib/jovian-greeter/consume-session
runHook postInstall
'';
passthru.helper = rustPlatform.buildRustPackage {
pname = "jovian-consume-session";
version = "0.0.1";
src = ./consume-session;
cargoLock.lockFile = ./consume-session/Cargo.lock;
# avoid a second rebuild
doCheck = false;
};
}

View File

@@ -17,7 +17,6 @@ from typing import cast, override
from systemd.journal import JournalHandler
DEFAULT_SESSION = 'gamescope-wayland'
HELPER_PREFIX = Path('/run/current-system/sw/lib/jovian-greeter')
class Session:
TYPE: str = 'tty'
@@ -86,15 +85,20 @@ class GreetdClient:
raise RuntimeError('Bad response', response)
def start_session(self, command: list[str], environment: list[str]):
def start_session(self, session: Session):
try:
_ = subprocess.check_call(["plymouth", "quit", "--retain-splash", "--wait"])
except Exception as ex:
logging.debug("Failed to stop Plymouth", exc_info=ex)
command = [ 'systemd-cat', '--identifier=jovian-session', '--' ] + command
session_command = session.get_command()
if not session_command:
raise RuntimeError('Session does not have a command')
logging.info("Starting session '%s'", DEFAULT_SESSION)
command = [ 'systemd-cat', '--identifier=jovian-session', '--' ] + session_command
environment = session.get_environment()
logging.info("Starting session '%s'", session.name)
logging.info("Command: %s", command)
logging.info("Environment: %s", environment)
self._send({
@@ -124,9 +128,8 @@ class GreetdClient:
return cast(dict[str, str], json.loads(payload))
class Context:
def __init__(self, user: str, home: Path):
def __init__(self, user: str):
self.user: str = user
self.home: Path = home
self.xdg_data_dirs: list[str] = os.environ.get('XDG_DATA_DIRS', '').split(':')
def next_session(self) -> Session | None:
@@ -138,31 +141,14 @@ class Context:
return self._find_sessions(sessions)
def _consume_session(self) -> str | None:
helper = HELPER_PREFIX.joinpath('consume-session')
if helper.exists():
logging.debug('Using pkexec helper')
res = subprocess.run(
['/run/wrappers/bin/pkexec', helper, self.user],
stdin=subprocess.DEVNULL,
capture_output=True,
check=True,
env={'SHELL': '/bin/sh'}
)
next_session = res.stdout.decode('utf-8').strip()
if not next_session:
return None
return next_session
next_session_file = self.home.joinpath(".local/state/steamos-session-select")
if not next_session_file.exists():
return None
with open(next_session_file, 'r') as f:
next_session = f.read().strip()
next_session_file.unlink()
res = subprocess.run(
['/run/wrappers/bin/jovian-consume-session'],
stdin=subprocess.DEVNULL,
capture_output=True,
check=True,
env={},
)
next_session = res.stdout.decode('utf-8').strip()
if not next_session:
return None
@@ -206,18 +192,13 @@ if __name__ == '__main__':
sys.exit(1)
user = sys.argv[1]
home = os.path.expanduser(f'~{user}/')
socket_path = os.environ.get('GREETD_SOCK')
if not home:
logging.error(f'Home directory for {user} not found')
sys.exit(1)
if not socket_path:
logging.error("GREETD_SOCK must be set")
sys.exit(1)
ctx = Context(user, Path(home))
ctx = Context(user)
client = GreetdClient(Path(socket_path))
client.create_session(user)
@@ -235,4 +216,4 @@ if __name__ == '__main__':
logging.error(".desktop file doesn't contain Exec=")
sys.exit(1)
client.start_session(command, environment)
client.start_session(session)