From f221363fbeaa3b8311eb5d59e60e34c95c2f455a Mon Sep 17 00:00:00 2001 From: classabbyamp Date: Tue, 11 Jul 2023 22:02:49 -0400 Subject: [PATCH 1/5] polkit: patch to support turnstile --- srcpkgs/polkit/patches/turnstile.patch | 57 ++++++++++++++++++++++++++ srcpkgs/polkit/template | 2 +- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 srcpkgs/polkit/patches/turnstile.patch diff --git a/srcpkgs/polkit/patches/turnstile.patch b/srcpkgs/polkit/patches/turnstile.patch new file mode 100644 index 00000000000000..4f56ed130eefd4 --- /dev/null +++ b/srcpkgs/polkit/patches/turnstile.patch @@ -0,0 +1,57 @@ +commit 8d98aa421b92765695af13c033cf7e80375c03fe +Author: q66 +Date: Sun Jul 2 15:44:51 2023 +0200 + + ensure turnstile-session processes fall back to display check + + As turnstile session is shared between sessions, let us fall back + to the check for whether a graphical session is in place. We need + this as our dbus session bus is managed through turnstile. In + systemd-using systems there is no problem because user units are + not a part of any explicit session (we don't get this luxury + because using a session is the only way to make sure our pid is + tracked in systemd at all; we need that to be able to resolve + PID to UID). + +diff --git a/src/polkitbackend/polkitbackendsessionmonitor-systemd.c b/src/polkitbackend/polkitbackendsessionmonitor-systemd.c +index b00cdbd..9a3f3c3 100644 +--- a/src/polkitbackend/polkitbackendsessionmonitor-systemd.c ++++ b/src/polkitbackend/polkitbackendsessionmonitor-systemd.c +@@ -346,7 +346,7 @@ polkit_backend_session_monitor_get_session_for_subject (PolkitBackendSessionMoni + PolkitUnixProcess *tmp_process = NULL; + PolkitUnixProcess *process = NULL; + PolkitSubject *session = NULL; +- char *session_id = NULL; ++ char *session_id = NULL, *service_id = NULL; + pid_t pid; + #if HAVE_SD_UID_GET_DISPLAY + uid_t uid; +@@ -377,8 +377,26 @@ polkit_backend_session_monitor_get_session_for_subject (PolkitBackendSessionMoni + + if (sd_pid_get_session (pid, &session_id) >= 0) + { +- session = polkit_unix_session_new (session_id); +- goto out; ++ /* if belonging to turnstile, ignore */ ++ if (sd_session_get_service (session_id, &service_id) >= 0) ++ { ++ if (strcmp (service_id, "turnstiled")) ++ { ++ free (service_id); ++ session = polkit_unix_session_new (session_id); ++ goto out; ++ } ++ else ++ { ++ /* turnstile-managed processes are shared */ ++ free(service_id); ++ } ++ } ++ else ++ { ++ session = polkit_unix_session_new (session_id); ++ goto out; ++ } + } + + #if HAVE_SD_UID_GET_DISPLAY diff --git a/srcpkgs/polkit/template b/srcpkgs/polkit/template index 84ab7453bb9b66..0435e1ce5976b8 100644 --- a/srcpkgs/polkit/template +++ b/srcpkgs/polkit/template @@ -1,7 +1,7 @@ # Template file for 'polkit' pkgname=polkit version=121 -revision=1 +revision=2 build_style=meson build_helper=gir configure_args="$(vopt_bool gir introspection) -Dman=true From ebec18d806f62133a3a8985b36f1cbf6aeb98e0d Mon Sep 17 00:00:00 2001 From: classabbyamp Date: Sun, 2 Jul 2023 22:04:40 -0400 Subject: [PATCH 2/5] pam-base: add turnstile pam --- srcpkgs/pam-base/files/system-login | 1 + srcpkgs/pam-base/template | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/srcpkgs/pam-base/files/system-login b/srcpkgs/pam-base/files/system-login index 2275deba480d3e..72c4638f07d3fe 100644 --- a/srcpkgs/pam-base/files/system-login +++ b/srcpkgs/pam-base/files/system-login @@ -14,6 +14,7 @@ session optional pam_loginuid.so session include system-auth session optional pam_motd.so motd=/etc/motd session optional pam_mail.so dir=/var/mail standard quiet +-session optional pam_turnstile.so -session optional pam_elogind.so -session optional pam_dumb_runtime_dir.so session required pam_env.so diff --git a/srcpkgs/pam-base/template b/srcpkgs/pam-base/template index 70dfab9fa9965a..38bfa74cd88560 100644 --- a/srcpkgs/pam-base/template +++ b/srcpkgs/pam-base/template @@ -1,7 +1,7 @@ # Template file for 'pam-base' pkgname=pam-base version=0.4 -revision=2 +revision=3 short_desc="PAM base configuration files" maintainer="Érico Nogueira " license="Public Domain" From 12610c1511bea0bfa9ecf333bce2281a09bc1eae Mon Sep 17 00:00:00 2001 From: classabbyamp Date: Tue, 12 Sep 2023 18:54:27 -0400 Subject: [PATCH 3/5] gdm: patch pam files for turnstile --- srcpkgs/gdm/patches/pam-turnstile-elogind.patch | 13 +++++++++++++ srcpkgs/gdm/template | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 srcpkgs/gdm/patches/pam-turnstile-elogind.patch diff --git a/srcpkgs/gdm/patches/pam-turnstile-elogind.patch b/srcpkgs/gdm/patches/pam-turnstile-elogind.patch new file mode 100644 index 00000000000000..23f71ffa6633a2 --- /dev/null +++ b/srcpkgs/gdm/patches/pam-turnstile-elogind.patch @@ -0,0 +1,13 @@ +pam_turnstile allows turnstile to integrate with gdm + +See also: https://github.com/chimera-linux/cports/blob/master/main/gdm/patches/pam.patch + +--- a/data/pam-arch/gdm-launch-environment.pam ++++ b/data/pam-arch/gdm-launch-environment.pam +@@ -14,6 +14,7 @@ + session required pam_succeed_if.so audit quiet_success user in gdm:gnome-initial-setup + session optional pam_permit.so + -session optional pam_systemd.so ++-session optional pam_turnstile.so + -session optional pam_elogind.so + session required pam_env.so diff --git a/srcpkgs/gdm/template b/srcpkgs/gdm/template index c171f236442515..128253f83f885c 100644 --- a/srcpkgs/gdm/template +++ b/srcpkgs/gdm/template @@ -1,7 +1,7 @@ # Template file for 'gdm' pkgname=gdm version=45.0.1 -revision=1 +revision=2 build_helper="gir" build_style=meson configure_args=" From 1fe1a233b26fc98e573dfecbe4abee20855a50f1 Mon Sep 17 00:00:00 2001 From: classabbyamp Date: Tue, 12 Sep 2023 18:54:33 -0400 Subject: [PATCH 4/5] lightdm: patch pam files for turnstile --- .../patches/pam-turnstile-elogind.patch | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 srcpkgs/lightdm/patches/pam-turnstile-elogind.patch diff --git a/srcpkgs/lightdm/patches/pam-turnstile-elogind.patch b/srcpkgs/lightdm/patches/pam-turnstile-elogind.patch new file mode 100644 index 00000000000000..3a54cdd326166a --- /dev/null +++ b/srcpkgs/lightdm/patches/pam-turnstile-elogind.patch @@ -0,0 +1,32 @@ +1. pam_systemd doesn't exist on void, use pam_elogind instead +2. pam_turnstile allows turnstile to integrate with lightdm + +See also: https://github.com/chimera-linux/cports/blob/master/main/gdm/patches/pam.patch + +--- a/data/pam/lightdm ++++ b/data/pam/lightdm +@@ -17,4 +17,6 @@ + + # Setup session + session required pam_unix.so ++- session optional pam_turnstile.so ++- session optional pam_elogind.so + session optional pam_systemd.so +--- a/data/pam/lightdm-autologin ++++ b/data/pam/lightdm-autologin +@@ -19,4 +19,6 @@ + + # Setup session + session required pam_unix.so ++- session optional pam_turnstile.so ++- session optional pam_elogind.so + session optional pam_systemd.so +--- a/data/pam/lightdm-greeter ++++ b/data/pam/lightdm-greeter +@@ -14,4 +14,6 @@ + + # Setup session + session required pam_unix.so ++- session optional pam_turnstile.so ++- session optional pam_elogind.so + session optional pam_systemd.so From f62fa6d89c6f54cacab375a2a204b73dbb4b29a4 Mon Sep 17 00:00:00 2001 From: classabbyamp Date: Wed, 28 Jun 2023 05:10:55 -0400 Subject: [PATCH 5/5] New package: turnstile-0.1.8 --- srcpkgs/turnstile/files/README.voidlinux | 50 ++++ srcpkgs/turnstile/files/dbus.run | 11 + srcpkgs/turnstile/files/turnstiled/run | 4 + srcpkgs/turnstile/patches/defer-rundir.patch | 121 ++++++++ srcpkgs/turnstile/patches/dummy.patch | 300 +++++++++++++++++++ srcpkgs/turnstile/patches/fix-chdir.patch | 25 ++ srcpkgs/turnstile/patches/runit.patch | 256 ++++++++++++++++ srcpkgs/turnstile/template | 24 ++ 8 files changed, 791 insertions(+) create mode 100644 srcpkgs/turnstile/files/README.voidlinux create mode 100755 srcpkgs/turnstile/files/dbus.run create mode 100644 srcpkgs/turnstile/files/turnstiled/run create mode 100644 srcpkgs/turnstile/patches/defer-rundir.patch create mode 100644 srcpkgs/turnstile/patches/dummy.patch create mode 100644 srcpkgs/turnstile/patches/fix-chdir.patch create mode 100644 srcpkgs/turnstile/patches/runit.patch create mode 100644 srcpkgs/turnstile/template diff --git a/srcpkgs/turnstile/files/README.voidlinux b/srcpkgs/turnstile/files/README.voidlinux new file mode 100644 index 00000000000000..32025131de7d62 --- /dev/null +++ b/srcpkgs/turnstile/files/README.voidlinux @@ -0,0 +1,50 @@ +# User Services + +User services can be placed in ~/.config/service/. + +To ensure that a subset of services are started before login can proceed, +these services can be listed in ~/.config/service/turnstile-ready/conf, for +example: + + core_services="dbus foo" + +The turnstile-ready service is created by turnstile on first login. + +## Shared Environment for User Services + +To give user services access to important environment variables, chpst's +envdir functionality can be used. See chpst(8) (-e flag) for more info. + +To make a service aware of these variables: + + - exec foo + + exec chpst -e "$TURNSTILE_ENV_DIR" foo + +Inside user services, the convenience variable "$TURNSTILE_ENV_DIR" can be used +to refer to this directory. + +The helper script 'turnstile-update-runit-env' can be used to easily update +variables in this shared envdir: + + turnstile-update-runit-env DISPLAY XAUTHORITY FOO=bar BAZ= + +# D-Bus Session Bus + +If you want to manage dbus using a turnstile-managed runit user service: + + mkdir ~/.config/service/dbus + ln -s /usr/share/examples/turnstile/dbus.run ~/.config/service/dbus/run + +# Elogind Replacement + +Turnstile is not (nor ever will be, according to the developer) a complete +replacement for elogind, but it can replace several parts, including +XDG_RUNTIME_DIR management. + +If using turnstile with elogind: +- disable rundir management in /etc/turnstile/turnstiled.conf + (manage_rundir = no) + +If using turnstile without elogind: +- install and enable seatd for seat management +- install and enable acpid for lid switch/button handling diff --git a/srcpkgs/turnstile/files/dbus.run b/srcpkgs/turnstile/files/dbus.run new file mode 100755 index 00000000000000..dc7473e45fc52f --- /dev/null +++ b/srcpkgs/turnstile/files/dbus.run @@ -0,0 +1,11 @@ +#!/bin/sh + +[ -r ./conf ] && . ./conf + +: "${DBUS_SESSION_BUS_ADDRESS:=unix:path=/run/user/$(id -u)/bus}" + +if [ -d "$TURNSTILE_ENV_DIR" ]; then + echo "$DBUS_SESSION_BUS_ADDRESS" > "$TURNSTILE_ENV_DIR"/DBUS_SESSION_BUS_ADDRESS +fi + +exec chpst -e "$TURNSTILE_ENV_DIR" dbus-daemon --session --nofork --nopidfile --address="$DBUS_SESSION_BUS_ADDRESS" $OPTS diff --git a/srcpkgs/turnstile/files/turnstiled/run b/srcpkgs/turnstile/files/turnstiled/run new file mode 100644 index 00000000000000..aa5d624fda19a1 --- /dev/null +++ b/srcpkgs/turnstile/files/turnstiled/run @@ -0,0 +1,4 @@ +#!/bin/sh + +exec 2>&1 +exec turnstiled diff --git a/srcpkgs/turnstile/patches/defer-rundir.patch b/srcpkgs/turnstile/patches/defer-rundir.patch new file mode 100644 index 00000000000000..33b94a1489b3dc --- /dev/null +++ b/srcpkgs/turnstile/patches/defer-rundir.patch @@ -0,0 +1,121 @@ +From cae619b4f23c7b1bc44ba8cef59d004a1911a01d Mon Sep 17 00:00:00 2001 +From: q66 +Date: Fri, 1 Sep 2023 22:57:46 +0200 +Subject: [PATCH] defer creation of rundir for after pam session is established + +--- + src/exec_utils.cc | 19 ++++++++++++++++++- + src/turnstiled.cc | 16 +++++----------- + src/turnstiled.hh | 2 +- + 3 files changed, 24 insertions(+), 13 deletions(-) + +diff --git a/src/exec_utils.cc b/src/exec_utils.cc +index 49918be..96440ec 100644 +--- a/src/exec_utils.cc ++++ b/src/exec_utils.cc +@@ -106,6 +106,8 @@ static pam_handle_t *dpam_begin(char const *user, unsigned int gid) { + static void sanitize_limits() { + struct rlimit l{0, 0}; + ++ print_dbg("srv: sanitize rlimits"); ++ + setrlimit(RLIMIT_NICE, &l); + setrlimit(RLIMIT_RTPRIO, &l); + +@@ -129,6 +131,8 @@ static bool dpam_open(pam_handle_t *pamh) { + /* before opening session, do not rely on just PAM and sanitize a bit */ + sanitize_limits(); + ++ print_dbg("srv: open pam session"); ++ + auto pst = pam_open_session(pamh, 0); + if (pst != PAM_SUCCESS) { + fprintf(stderr, "srv: pam_open_session: %s", pam_strerror(pamh, pst)); +@@ -136,6 +140,7 @@ static bool dpam_open(pam_handle_t *pamh) { + pam_end(pamh, pst); + return false; + } ++ + return true; + } + +@@ -288,7 +293,7 @@ static void srv_dummy() { + exit(0); + } + +-void srv_child(login &lgn, char const *backend) { ++void srv_child(login &lgn, char const *backend, bool make_rundir) { + pam_handle_t *pamh = nullptr; + bool is_root = (getuid() == 0); + /* create a new session */ +@@ -297,11 +302,23 @@ void srv_child(login &lgn, char const *backend) { + } + /* begin pam session setup */ + if (is_root) { ++ print_dbg("srv: establish pam"); + pamh = dpam_begin(lgn.username.data(), lgn.gid); + if (!dpam_open(pamh)) { + return; + } + } ++ /* make rundir if needed, we want to make it as late as possible, ideally ++ * after the PAM session setup is already finalized (so that nothing gets ++ * the idea to nuke it), but before we fork and drop privileges ++ */ ++ if (make_rundir) { ++ print_dbg("srv: setup rundir for %u", lgn.uid); ++ if (!rundir_make(lgn.rundir.data(), lgn.uid, lgn.gid)) { ++ return; ++ } ++ } ++ print_dbg("srv: forking for service manager exec"); + /* handle the parent/child logic here + * if we're forking, only child makes it past this func + */ +diff --git a/src/turnstiled.cc b/src/turnstiled.cc +index 71f8372..a886739 100644 +--- a/src/turnstiled.cc ++++ b/src/turnstiled.cc +@@ -124,16 +124,6 @@ static bool srv_start(login &lgn) { + std::snprintf(uidbuf, sizeof(uidbuf), "%u", lgn.uid); + /* mark as waiting */ + lgn.srv_wait = true; +- /* make rundir if needed, we don't want to create that and login dir +- * any earlier than here as here we are sure the previous instance has +- * definitely terminated and stuff like login dirfd is actually clear +- */ +- if (cdata->manage_rdir) { +- print_dbg("srv: setup rundir for %u", lgn.uid); +- if (!rundir_make(lgn.rundir.data(), lgn.uid, lgn.gid)) { +- return false; +- } +- } + bool has_backend = !cdata->disable && ( + (lgn.uid != 0) || cdata->root_session + ); +@@ -208,7 +198,11 @@ static bool srv_start(login &lgn) { + close(sigpipe[0]); + close(sigpipe[1]); + /* and run the login */ +- srv_child(lgn, has_backend ? cdata->backend.data() : nullptr); ++ srv_child( ++ lgn, ++ has_backend ? cdata->backend.data() : nullptr, ++ cdata->manage_rdir ++ ); + exit(1); + } else if (pid < 0) { + print_err("srv: fork failed (%s)", strerror(errno)); +diff --git a/src/turnstiled.hh b/src/turnstiled.hh +index d80043c..479ef83 100644 +--- a/src/turnstiled.hh ++++ b/src/turnstiled.hh +@@ -144,7 +144,7 @@ void cfg_expand_rundir( + ); + + /* service manager utilities */ +-void srv_child(login &sess, char const *backend); ++void srv_child(login &sess, char const *backend, bool make_rundir); + bool srv_boot(login &sess, char const *backend); + + struct cfg_data { diff --git a/srcpkgs/turnstile/patches/dummy.patch b/srcpkgs/turnstile/patches/dummy.patch new file mode 100644 index 00000000000000..693cdbe310efd7 --- /dev/null +++ b/srcpkgs/turnstile/patches/dummy.patch @@ -0,0 +1,300 @@ +From b7f8fd1c1d6493a83d52347be65a6c6535d5c18f Mon Sep 17 00:00:00 2001 +From: q66 +Date: Sat, 2 Sep 2023 14:06:34 +0200 +Subject: [PATCH] write session data in a separate sessions directory + +We need this because all of the session data should be publicly +accessible, while the sessions' individual state directories are +not. + +Also prepare a separate directory for user tracking. +--- + src/turnstiled.cc | 52 +++++++++++++++++++++++++++++++++-------------- + 1 file changed, 37 insertions(+), 15 deletions(-) + +diff --git a/src/turnstiled.cc b/src/turnstiled.cc +index a886739..861c1fe 100644 +--- a/src/turnstiled.cc ++++ b/src/turnstiled.cc +@@ -58,7 +58,11 @@ static constexpr std::time_t kill_timeout = 60; + cfg_data *cdata = nullptr; + + /* the file descriptor for the base directory */ +-static int userv_dirfd = -1; ++static int dirfd_base = -1; ++/* the file descriptor for the users directory */ ++static int dirfd_users = -1; ++/* the file descriptor for the sessions directory */ ++static int dirfd_sessions = -1; + + login::login() { + timer_sev.sigev_notify = SIGEV_SIGNAL; +@@ -70,7 +74,7 @@ login::login() { + void login::remove_sdir() { + char buf[32]; + std::snprintf(buf, sizeof(buf), "%u", this->uid); +- unlinkat(userv_dirfd, buf, AT_REMOVEDIR); ++ unlinkat(dirfd_base, buf, AT_REMOVEDIR); + /* just in case, we know this is a named pipe */ + unlinkat(this->dirfd, "ready", 0); + dir_clear_contents(this->dirfd); +@@ -131,7 +135,7 @@ static bool srv_start(login &lgn) { + if (has_backend) { + print_dbg("srv: create login dir for %u", lgn.uid); + /* make the directory itself */ +- lgn.dirfd = dir_make_at(userv_dirfd, uidbuf, 0700); ++ lgn.dirfd = dir_make_at(dirfd_base, uidbuf, 0700); + if (lgn.dirfd < 0) { + print_err( + "srv: failed to make login dir for %u (%s)", +@@ -141,7 +145,7 @@ static bool srv_start(login &lgn) { + } + /* ensure it's owned by the user */ + if (fchownat( +- userv_dirfd, uidbuf, lgn.uid, lgn.gid, AT_SYMLINK_NOFOLLOW ++ dirfd_base, uidbuf, lgn.uid, lgn.gid, AT_SYMLINK_NOFOLLOW + ) || fcntl(lgn.dirfd, F_SETFD, FD_CLOEXEC)) { + print_err( + "srv: login dir setup failed for %u (%s)", +@@ -194,7 +198,7 @@ static bool srv_start(login &lgn) { + sigaction(SIGINT, &sa, nullptr); + /* close some descriptors, these can be reused */ + close(lgn.userpipe); +- close(userv_dirfd); ++ close(dirfd_base); + close(sigpipe[0]); + close(sigpipe[1]); + /* and run the login */ +@@ -317,11 +321,13 @@ static session *handle_session_new(int fd, unsigned int uid) { + + static bool write_sdata(session const &sess) { + char sessname[64], tmpname[64]; +- std::snprintf(tmpname, sizeof(tmpname), "session.%lu.tmp", sess.id); +- std::snprintf(sessname, sizeof(sessname), "session.%lu", sess.id); ++ std::snprintf(tmpname, sizeof(tmpname), "%lu.tmp", sess.id); ++ std::snprintf(sessname, sizeof(sessname), "%lu", sess.id); + auto &lgn = *sess.lgn; + int omask = umask(0); +- int sessfd = openat(lgn.dirfd, tmpname, O_CREAT | O_TRUNC | O_WRONLY, 0644); ++ int sessfd = openat( ++ dirfd_sessions, tmpname, O_CREAT | O_TRUNC | O_WRONLY, 0644 ++ ); + if (sessfd < 0) { + print_err("msg: session tmpfile failed (%s)", strerror(errno)); + umask(omask); +@@ -365,9 +371,9 @@ static bool write_sdata(session const &sess) { + /* done writing */ + std::fclose(sessf); + /* now rename to real file */ +- if (renameat(lgn.dirfd, tmpname, lgn.dirfd, sessname) < 0) { ++ if (renameat(dirfd_sessions, tmpname, dirfd_sessions, sessname) < 0) { + print_err("msg: session renameat failed (%s)", strerror(errno)); +- unlinkat(lgn.dirfd, tmpname, 0); ++ unlinkat(dirfd_sessions, tmpname, 0); + return false; + } + return true; +@@ -375,8 +381,8 @@ static bool write_sdata(session const &sess) { + + static void drop_sdata(session const &sess) { + char sessname[64]; +- std::snprintf(sessname, sizeof(sessname), "session.%lu", sess.id); +- unlinkat(sess.lgn->dirfd, sessname, 0); ++ std::snprintf(sessname, sizeof(sessname), "%lu", sess.id); ++ unlinkat(dirfd_sessions, sessname, 0); + } + + static bool sock_block(int fd, short events) { +@@ -1173,15 +1179,31 @@ int main(int argc, char **argv) { + print_err("turnstiled base path does not exist"); + return 1; + } +- userv_dirfd = dir_make_at(dfd, SOCK_DIR, 0755); +- if (userv_dirfd < 0) { ++ dirfd_base = dir_make_at(dfd, SOCK_DIR, 0755); ++ if (dirfd_base < 0) { + print_err("failed to create base directory (%s)", strerror(errno)); + return 1; + } ++ dirfd_users = dir_make_at(dirfd_base, "users", 0755); ++ if (dirfd_users < 0) { ++ print_err("failed to create users directory (%s)", strerror(errno)); ++ return 1; ++ } ++ dirfd_sessions = dir_make_at(dirfd_base, "sessions", 0755); ++ if (dirfd_sessions < 0) { ++ print_err( ++ "failed to create sessions directory (%s)", strerror(errno) ++ ); ++ return 1; ++ } + close(dfd); + } + /* ensure it is not accessible by service manager child processes */ +- if (fcntl(userv_dirfd, F_SETFD, FD_CLOEXEC)) { ++ if ( ++ fcntl(dirfd_base, F_SETFD, FD_CLOEXEC) || ++ fcntl(dirfd_users, F_SETFD, FD_CLOEXEC) || ++ fcntl(dirfd_sessions, F_SETFD, FD_CLOEXEC) ++ ) { + print_err("fcntl failed (%s)", strerror(errno)); + return 1; + } + +From 27f29a523cb75ba778ca538d319181a60c533eb4 Mon Sep 17 00:00:00 2001 +From: q66 +Date: Sun, 3 Sep 2023 16:32:16 +0200 +Subject: [PATCH] treat dummy service backend the same as a regular one + +This means less code for handling the dummy backend specifically, +plus it fixes some bugs (e.g. not being able to write session +files in a login dir that was not created). +--- + src/exec_utils.cc | 16 +++++++-- + src/turnstiled.cc | 84 +++++++++++++++++++++++------------------------ + 2 files changed, 55 insertions(+), 45 deletions(-) + +diff --git a/src/exec_utils.cc b/src/exec_utils.cc +index 96440ec..aab57ba 100644 +--- a/src/exec_utils.cc ++++ b/src/exec_utils.cc +@@ -280,13 +280,25 @@ static void fork_and_wait( + } + + /* dummy "service manager" child process with none backend */ +-static void srv_dummy() { ++static void srv_dummy(unsigned int uid) { + /* block all signals except the ones we need to terminate */ + sigset_t mask; + sigfillset(&mask); + /* kill/stop are ignored, but term is not */ + sigdelset(&mask, SIGTERM); + sigprocmask(SIG_SETMASK, &mask, nullptr); ++ /* mark as ready */ ++ char path[4096]; ++ std::snprintf( ++ path, sizeof(path), "%s/%s/%u/ready", RUN_PATH, SOCK_DIR, uid ++ ); ++ FILE *ready = std::fopen(path, "w"); ++ if (!ready) { ++ perror("srv: could not open readiness fifo"); ++ exit(1); ++ } ++ std::fprintf(ready, "boop\n"); ++ std::fclose(ready); + /* this will sleep until a termination signal wakes it */ + pause(); + /* in which case just exit */ +@@ -337,7 +349,7 @@ void srv_child(login &lgn, char const *backend, bool make_rundir) { + } + /* dummy service manager if requested */ + if (!backend) { +- srv_dummy(); ++ srv_dummy(lgn.uid); + return; + } + /* change directory to home, fall back to / or error */ +diff --git a/src/turnstiled.cc b/src/turnstiled.cc +index f33705c..f3166e9 100644 +--- a/src/turnstiled.cc ++++ b/src/turnstiled.cc +@@ -135,51 +135,46 @@ static bool srv_start(login &lgn) { + std::snprintf(uidbuf, sizeof(uidbuf), "%u", lgn.uid); + /* mark as waiting */ + lgn.srv_wait = true; +- bool has_backend = !cdata->disable && ( +- (lgn.uid != 0) || cdata->root_session +- ); + /* set up login dir */ +- if (has_backend) { +- print_dbg("srv: create login dir for %u", lgn.uid); +- /* make the directory itself */ +- lgn.dirfd = dir_make_at(dirfd_base, uidbuf, 0700); +- if (lgn.dirfd < 0) { +- print_err( +- "srv: failed to make login dir for %u (%s)", +- lgn.uid, strerror(errno) +- ); +- return false; +- } +- /* ensure it's owned by the user */ +- if (fchownat( +- dirfd_base, uidbuf, lgn.uid, lgn.gid, AT_SYMLINK_NOFOLLOW +- ) || fcntl(lgn.dirfd, F_SETFD, FD_CLOEXEC)) { +- print_err( +- "srv: login dir setup failed for %u (%s)", +- lgn.uid, strerror(errno) +- ); +- lgn.remove_sdir(); +- return false; +- } +- print_dbg("srv: create readiness pipe"); ++ print_dbg("srv: create login dir for %u", lgn.uid); ++ /* make the directory itself */ ++ lgn.dirfd = dir_make_at(dirfd_base, uidbuf, 0700); ++ if (lgn.dirfd < 0) { ++ print_err( ++ "srv: failed to make login dir for %u (%s)", ++ lgn.uid, strerror(errno) ++ ); ++ return false; ++ } ++ /* ensure it's owned by the user */ ++ if (fchownat( ++ dirfd_base, uidbuf, lgn.uid, lgn.gid, AT_SYMLINK_NOFOLLOW ++ ) || fcntl(lgn.dirfd, F_SETFD, FD_CLOEXEC)) { ++ print_err( ++ "srv: login dir setup failed for %u (%s)", ++ lgn.uid, strerror(errno) ++ ); ++ lgn.remove_sdir(); ++ return false; ++ } ++ print_dbg("srv: create readiness pipe"); ++ unlinkat(lgn.dirfd, "ready", 0); ++ if (mkfifoat(lgn.dirfd, "ready", 0700) < 0) { ++ print_err("srv: failed to make ready pipe (%s)", strerror(errno)); ++ return false; ++ } ++ /* ensure it's owned by user too, and open in nonblocking mode */ ++ if (fchownat( ++ lgn.dirfd, "ready", lgn.uid, lgn.gid, AT_SYMLINK_NOFOLLOW ++ ) || ((lgn.userpipe = openat( ++ lgn.dirfd, "ready", O_NONBLOCK | O_RDONLY ++ )) < 0)) { ++ print_err( ++ "srv: failed to set up ready pipe (%s)", strerror(errno) ++ ); + unlinkat(lgn.dirfd, "ready", 0); +- if (mkfifoat(lgn.dirfd, "ready", 0700) < 0) { +- print_err("srv: failed to make ready pipe (%s)", strerror(errno)); +- return false; +- } +- /* ensure it's owned by user too, and open in nonblocking mode */ +- if (fchownat( +- lgn.dirfd, "ready", lgn.uid, lgn.gid, AT_SYMLINK_NOFOLLOW +- ) || ((lgn.userpipe = openat( +- lgn.dirfd, "ready", O_NONBLOCK | O_RDONLY +- )) < 0)) { +- print_err( +- "srv: failed to set up ready pipe (%s)", strerror(errno) +- ); +- unlinkat(lgn.dirfd, "ready", 0); +- lgn.remove_sdir(); +- return false; +- } ++ lgn.remove_sdir(); ++ return false; + } + /* set up the timer, issue SIGLARM when it fires */ + print_dbg("srv: timer set"); +@@ -209,6 +204,9 @@ static bool srv_start(login &lgn) { + close(sigpipe[0]); + close(sigpipe[1]); + /* and run the login */ ++ bool has_backend = !cdata->disable && ( ++ (lgn.uid != 0) || cdata->root_session ++ ); + srv_child( + lgn, + has_backend ? cdata->backend.data() : nullptr, diff --git a/srcpkgs/turnstile/patches/fix-chdir.patch b/srcpkgs/turnstile/patches/fix-chdir.patch new file mode 100644 index 00000000000000..3428fa79f77a1e --- /dev/null +++ b/srcpkgs/turnstile/patches/fix-chdir.patch @@ -0,0 +1,25 @@ +From 00fd0b1ad7b5fd262bb83c75cb463ad32b1940c9 Mon Sep 17 00:00:00 2001 +From: q66 +Date: Wed, 29 Nov 2023 14:39:16 +0100 +Subject: [PATCH] exec_utils: fix operand for homedir chdir + +Using OR would result in the second operand running on success +of the first so typically all the user services ended up starting +in / by default. +--- + src/exec_utils.cc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/exec_utils.cc b/src/exec_utils.cc +index aab57ba..c48f833 100644 +--- a/src/exec_utils.cc ++++ b/src/exec_utils.cc +@@ -353,7 +353,7 @@ void srv_child(login &lgn, char const *backend, bool make_rundir) { + return; + } + /* change directory to home, fall back to / or error */ +- if ((chdir(lgn.homedir.data()) < 0) || (chdir("/") < 0)) { ++ if ((chdir(lgn.homedir.data()) < 0) && (chdir("/") < 0)) { + perror("srv: failed to change directory"); + return; + } diff --git a/srcpkgs/turnstile/patches/runit.patch b/srcpkgs/turnstile/patches/runit.patch new file mode 100644 index 00000000000000..b7a8c44e8c1b6f --- /dev/null +++ b/srcpkgs/turnstile/patches/runit.patch @@ -0,0 +1,256 @@ +From 3974343c76392aad6f6998805fc0d2a6fa1eab8d Mon Sep 17 00:00:00 2001 +From: classabbyamp +Date: Wed, 28 Jun 2023 05:05:25 -0400 +Subject: [PATCH] add runit backend + +--- + backend/meson.build | 25 ++++++++ + backend/runit | 88 +++++++++++++++++++++++++++ + backend/runit.conf | 16 +++++ + backend/turnstile-update-runit-env.in | 31 ++++++++++ + meson.build | 14 +++-- + meson_options.txt | 10 +++ + 6 files changed, 180 insertions(+), 4 deletions(-) + create mode 100644 backend/runit + create mode 100644 backend/runit.conf + create mode 100644 backend/turnstile-update-runit-env.in + +diff --git a/backend/meson.build b/backend/meson.build +index 681e6a0..5a5b200 100644 +--- a/backend/meson.build ++++ b/backend/meson.build +@@ -13,3 +13,28 @@ if have_dinit + install_mode: 'rw-r--r--' + ) + endif ++ ++# runit backend ++ ++if have_runit ++ install_data( ++ 'runit', ++ install_dir: join_paths(get_option('libexecdir'), 'turnstile'), ++ install_mode: 'rwxr-xr-x' ++ ) ++ ++ install_data( ++ 'runit.conf', ++ install_dir: join_paths(get_option('sysconfdir'), 'turnstile/backend'), ++ install_mode: 'rw-r--r--' ++ ) ++ ++ configure_file( ++ input: 'turnstile-update-runit-env.in', ++ output: 'turnstile-update-runit-env', ++ configuration: conf_data, ++ install: true, ++ install_dir: get_option('bindir'), ++ install_mode: 'rwxr-xr-x' ++ ) ++endif +diff --git a/backend/runit b/backend/runit +new file mode 100644 +index 0000000..a9d7454 +--- /dev/null ++++ b/backend/runit +@@ -0,0 +1,88 @@ ++#!/bin/sh ++# ++# This is the turnstile runit backend. It accepts the action as its first ++# argument, which is either "ready", "run", or "stop". In case of "run", it's ++# invoked directly through /bin/sh as if it was a login shell, and therefore ++# it has acccess to shell profile, and the shebang is functionally useless but ++# should be preserved as a convention. For "ready", it's a regular shell. ++# ++# Arguments for "ready": ++# ++# ready_sv: path to the readiness service ++# ++# Arguments for "run": ++# ++# ready_p: readiness pipe (fifo). has the path to the ready service written to it. ++# srvdir: unused ++# confdir: the path where turnstile's configuration data resides, used ++# to source the configuration file ++# ++# Arguments for "stop": ++# ++# pid: the PID of the service manager to stop (gracefully); it should ++# terminate the services it's running and then stop itself ++# ++# Copyright 2023 classabbyamp ++# License: BSD-2-Clause ++ ++case "$1" in ++ run) ;; ++ ready) ++ if [ -z "$2" ] || [ ! -d "$2" ]; then ++ echo "runit: invalid readiness service '$2'" >&2 ++ exit 69 ++ fi ++ exec sv start "$2" >&2 ++ ;; ++ stop) ++ # If runsvdir receives a HUP signal, it sends a TERM signal to each ++ # runsv(8) process it is monitoring and then exits with 111. ++ exec kill -s HUP "$2" ++ ;; ++ *) ++ exit 32 ++ ;; ++esac ++ ++RUNIT_READY_PIPE="$2" ++RUNIT_CONF="$4/runit.conf" ++ ++if [ ! -p "$RUNIT_READY_PIPE" ]; then ++ echo "runit: invalid input argument(s)" >&2 ++ exit 69 ++fi ++ ++if [ -z "$HOME" ] || [ ! -d "$HOME" ]; then ++ echo "runit: invalid home directory" >&2 ++ exit 70 ++fi ++ ++shift $# ++ ++# be strict ++set -e ++ ++# source the conf ++[ -r "$RUNIT_CONF" ] && . "$RUNIT_CONF" ++ ++# set some defaults in case the conf cannot be read or is mangled ++: "${ready_sv:="turnstile-ready"}" ++: "${services_dir:="${HOME}/.config/service"}" ++: "${service_env_dir:="${HOME}/.config/service-env"}" ++ ++mkdir -p "${services_dir}/${ready_sv}" > /dev/null 2>&1 ++mkdir -p "${service_env_dir}" > /dev/null 2>&1 ++ ++# this must succeed ++cat << EOF > "${services_dir}/${ready_sv}/run" ++#!/bin/sh ++[ -r ./conf ] && . ./conf ++[ -n "\$core_services" ] && SVDIR=".." sv start \$core_services ++[ -p "$RUNIT_READY_PIPE" ] && printf "${services_dir}/${ready_sv}" > "$RUNIT_READY_PIPE" ++exec pause ++EOF ++chmod +x "${services_dir}/${ready_sv}/run" ++ ++exec env TURNSTILE_ENV_DIR="$service_env_dir" \ ++ runsvdir -P "$services_dir" \ ++ 'log: ...........................................................................................................................................................................................................................................................................................................................................................................................................' +diff --git a/backend/runit.conf b/backend/runit.conf +new file mode 100644 +index 0000000..88a2d04 +--- /dev/null ++++ b/backend/runit.conf +@@ -0,0 +1,16 @@ ++# This is the configuration file for turnstile's runit backend. ++# ++# It follows the POSIX shell syntax (being sourced into a script). ++# The complete launch environment available to dinit can be used. ++# ++# It is a low-level configuration file. In most cases, it should ++# not be modified by the user. ++ ++# the name of the service that turnstile will check for login readiness ++ready_sv="turnstile-ready" ++ ++# the directory user service files are read from. ++services_dir="${HOME}/.config/service" ++ ++# the environment variable directory user service files can read from. ++service_env_dir="${HOME}/.config/service-env" +diff --git a/backend/turnstile-update-runit-env.in b/backend/turnstile-update-runit-env.in +new file mode 100644 +index 0000000..9999459 +--- /dev/null ++++ b/backend/turnstile-update-runit-env.in +@@ -0,0 +1,31 @@ ++#!/bin/sh ++# Copyright 2023 classabbyamp ++# License: BSD-2-Clause ++ ++usage() { ++ cat <<-EOF ++ turnstile-update-runit-env [VAR] ... ++ Updates values in the shared chpst(8) env dir. ++ ++ If VAR is a variable name, the value is taken from the environment. ++ If VAR is VAR=VAL, sets VAR to VAL. ++ EOF ++} ++ ++. @CONF_PATH@/backend/runit.conf ++ ++if [ $# -eq 0 ] || [ "$1" = "-h" ]; then ++ usage ++ exit 0 ++fi ++ ++for var; do ++ case "$var" in ++ *=*) ++ eval echo "${var#*=}" > "$service_env_dir/${var%%=*}" ++ ;; ++ *) ++ eval echo '$'"$var" > "$service_env_dir/$var" ++ ;; ++ esac ++done +diff --git a/meson.build b/meson.build +index 762aac7..d5467a2 100644 +--- a/meson.build ++++ b/meson.build +@@ -23,6 +23,7 @@ scdoc_dep = dependency( + ) + + have_dinit = get_option('dinit').enabled() ++have_runit = get_option('runit').enabled() + + conf_data = configuration_data() + conf_data.set_quoted('RUN_PATH', get_option('rundir')) +@@ -118,10 +119,15 @@ install_data( + ) + + # decide the default backend +-if have_dinit +- default_backend = 'dinit' +-else +- default_backend = 'none' ++default_backend = get_option('default_backend') ++if default_backend == '' ++ if have_dinit ++ default_backend = 'dinit' ++ elif have_runit ++ default_backend = 'runit' ++ else ++ default_backend = 'none' ++ endif + endif + + uconf_data = configuration_data() +diff --git a/meson_options.txt b/meson_options.txt +index 9b03995..4325042 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -3,6 +3,16 @@ option('dinit', + description: 'Whether to install Dinit-related backend and data' + ) + ++option('runit', ++ type: 'feature', value: 'disabled', ++ description: 'Whether to install runit-related backend and data' ++) ++ ++option('default_backend', ++ type: 'string', value: '', ++ description: 'Override the default backend' ++) ++ + option('rundir', + type: 'string', value: '/run', + description: 'Where the base directory will be located' diff --git a/srcpkgs/turnstile/template b/srcpkgs/turnstile/template new file mode 100644 index 00000000000000..5a435e1ae64a04 --- /dev/null +++ b/srcpkgs/turnstile/template @@ -0,0 +1,24 @@ +# Template file for 'turnstile' +pkgname=turnstile +version=0.1.8 +revision=1 +build_style=meson +configure_args="-Ddinit=enabled -Drunit=enabled -Ddefault_backend=runit + -Dmanage_rundir=true" +hostmakedepends="pkg-config scdoc" +makedepends="pam-devel" +short_desc="Independent session/login tracker and user service manager" +maintainer="classabbyamp " +license="BSD-2-Clause" +homepage="https://github.com/chimera-linux/turnstile" +distfiles="https://github.com/chimera-linux/turnstile/archive/refs/tags/v${version}.tar.gz" +checksum=7eaab8c80c76ae9a9a711d7dc57ec346b9af09be99b526a5a3129a7fc9bd7a76 +conf_files="/etc/turnstile/turnstiled.conf" + +post_install() { + vsv turnstiled + vsconf "${FILESDIR}/dbus.run" + chmod +x "${DESTDIR}/usr/share/examples/turnstile/dbus.run" + vdoc "${FILESDIR}/README.voidlinux" + vlicense COPYING.md +}