New package: turnstile-0.1.8
This commit is contained in:
parent
2c125b9383
commit
1c48af667e
50
srcpkgs/turnstile/files/README.voidlinux
Normal file
50
srcpkgs/turnstile/files/README.voidlinux
Normal file
@ -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
|
11
srcpkgs/turnstile/files/dbus.run
Executable file
11
srcpkgs/turnstile/files/dbus.run
Executable file
@ -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
|
4
srcpkgs/turnstile/files/turnstiled/run
Normal file
4
srcpkgs/turnstile/files/turnstiled/run
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exec 2>&1
|
||||||
|
exec turnstiled
|
121
srcpkgs/turnstile/patches/defer-rundir.patch
Normal file
121
srcpkgs/turnstile/patches/defer-rundir.patch
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
From cae619b4f23c7b1bc44ba8cef59d004a1911a01d Mon Sep 17 00:00:00 2001
|
||||||
|
From: q66 <q66@chimera-linux.org>
|
||||||
|
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 {
|
300
srcpkgs/turnstile/patches/dummy.patch
Normal file
300
srcpkgs/turnstile/patches/dummy.patch
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
From b7f8fd1c1d6493a83d52347be65a6c6535d5c18f Mon Sep 17 00:00:00 2001
|
||||||
|
From: q66 <q66@chimera-linux.org>
|
||||||
|
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 <q66@chimera-linux.org>
|
||||||
|
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,
|
25
srcpkgs/turnstile/patches/fix-chdir.patch
Normal file
25
srcpkgs/turnstile/patches/fix-chdir.patch
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
From 00fd0b1ad7b5fd262bb83c75cb463ad32b1940c9 Mon Sep 17 00:00:00 2001
|
||||||
|
From: q66 <q66@chimera-linux.org>
|
||||||
|
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;
|
||||||
|
}
|
256
srcpkgs/turnstile/patches/runit.patch
Normal file
256
srcpkgs/turnstile/patches/runit.patch
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
From 3974343c76392aad6f6998805fc0d2a6fa1eab8d Mon Sep 17 00:00:00 2001
|
||||||
|
From: classabbyamp <dev@placeviolette.net>
|
||||||
|
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 <dev@placeviolette.net>
|
||||||
|
+# 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 <dev@placeviolette.net>
|
||||||
|
+# 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'
|
24
srcpkgs/turnstile/template
Normal file
24
srcpkgs/turnstile/template
Normal file
@ -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 <void@placeviolette.net>"
|
||||||
|
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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user