Replace the session-keyring option with a configure option

Join the new session keyring when the server starts rather than once the
configuration file has been loaded, and control it at build time with
--enable-keyring, on by default if linux/keyctl.h is found.

Rename keyring_join and keyring_revoke to new_session_keyring and
revoke_session_keyring.
This commit is contained in:
Ilya Priven
2026-10-12 11:26:28 +00:00
parent 3d0839b7a3
commit 90cc41de32
8 changed files with 34 additions and 60 deletions

4
cfg.c
View File

@@ -62,10 +62,6 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
} }
prompt_load_history(); prompt_load_history();
#ifdef HAVE_KEYCTL
if (options_get_number(global_options, "session-keyring"))
keyring_join();
#endif
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -443,8 +443,8 @@ void *recallocarray(void *, size_t, size_t, size_t);
#ifdef HAVE_KEYCTL #ifdef HAVE_KEYCTL
/* keyring-linux.c */ /* keyring-linux.c */
void keyring_join(void); void new_session_keyring(void);
void keyring_revoke(void); void revoke_session_keyring(void);
#endif #endif
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD

View File

@@ -17,7 +17,7 @@ static long keyring_serial;
* the login session's keyring when it ends). * the login session's keyring when it ends).
*/ */
void void
keyring_join(void) new_session_keyring(void)
{ {
long serial; long serial;
@@ -33,7 +33,7 @@ keyring_join(void)
} }
void void
keyring_revoke(void) revoke_session_keyring(void)
{ {
if (keyring_serial == 0) if (keyring_serial == 0)
return; return;

View File

@@ -795,10 +795,18 @@ else
AC_LIBOBJ(daemon) AC_LIBOBJ(daemon)
fi fi
# Look for linux/keyctl.h, compat/keyring-linux.c used if found. # Look for linux/keyctl.h, compat/keyring-linux.c used if found and enabled.
AC_CHECK_HEADER(linux/keyctl.h, found_keyctl=yes, found_keyctl=no) AC_ARG_ENABLE(
if test "x$found_keyctl" = xyes; then keyring,
AS_HELP_STRING(--disable-keyring, disable giving the server its own Linux session keyring)
)
if test "x$enable_keyring" != xno; then
AC_CHECK_HEADER(linux/keyctl.h, found_keyctl=yes, found_keyctl=no)
if test "x$found_keyctl" = xyes; then
AC_DEFINE(HAVE_KEYCTL) AC_DEFINE(HAVE_KEYCTL)
elif test "x$enable_keyring" = xyes; then
AC_MSG_ERROR("linux/keyctl.h not found")
fi
fi fi
AM_CONDITIONAL(HAVE_KEYCTL, [test "x$found_keyctl" = xyes]) AM_CONDITIONAL(HAVE_KEYCTL, [test "x$found_keyctl" = xyes])

View File

@@ -532,14 +532,6 @@ const struct options_table_entry options_table[] = {
.text = "Maximum number of commands to keep in history." .text = "Maximum number of commands to keep in history."
}, },
{ .name = "session-keyring",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER,
.default_num = 1,
.text = "Whether the server should join a new session keyring "
"(Linux only)."
},
{ .name = "set-clipboard", { .name = "set-clipboard",
.type = OPTIONS_TABLE_CHOICE, .type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,

View File

@@ -1,8 +1,8 @@
#!/bin/sh #!/bin/sh
# On Linux the server should join a session keyring of its own unless the # On Linux the server should join a session keyring of its own, so it keeps
# session-keyring option is off, so it keeps working after the login session's # working after the login session's keyring is revoked, and revoke it when it
# keyring is revoked, and revoke it when it exits. # exits.
PATH=/bin:/usr/bin PATH=/bin:/usr/bin
TERM=screen TERM=screen
@@ -12,10 +12,8 @@ keyctl session - true >/dev/null 2>&1 || exit 0
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) [ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
OUT=$(mktemp -d) OUT=$(mktemp -d)
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null" TMUX="$TEST_TMUX -Ltest$$ -f/dev/null"
TMUX2="$TEST_TMUX -LtestB$$ -f$OUT/conf"
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
$TMUX2 kill-server 2>/dev/null
fail() fail()
{ {
@@ -26,35 +24,11 @@ fail()
cleanup() cleanup()
{ {
$TMUX kill-server 2>/dev/null $TMUX kill-server 2>/dev/null
$TMUX2 kill-server 2>/dev/null
[ -s $OUT/holder ] && kill $(cat $OUT/holder) 2>/dev/null [ -s $OUT/holder ] && kill $(cat $OUT/holder) 2>/dev/null
rm -rf "$OUT" rm -rf "$OUT"
} }
trap cleanup 0 1 15 trap cleanup 0 1 15
# Set KEYRING to the session keyring of a new pane on server $1.
pane_keyring()
{
$1 new-window -d "keyctl id @s >$OUT/pane 2>&1; $1 wait-for -S pane" ||
fail "could not create pane"
$1 wait-for pane
KEYRING=$(cat $OUT/pane)
case "$KEYRING" in
''|*[!0-9]*)
fail "pane keyring not usable: $KEYRING"
;;
esac
}
# With the option off, the server should keep the keyring it was started with.
echo 'set -g session-keyring off' >$OUT/conf
OFF=$(keyctl session - sh -c "
$TMUX2 new -d 'sleep 1000' && keyctl id @s
" 2>/dev/null) || fail "could not start server"
pane_keyring "$TMUX2"
[ "$KEYRING" = "$OFF" ] || fail "pane has a new keyring with option off"
$TMUX2 kill-server
# Start the server from a login session with its own keyring, then revoke that # Start the server from a login session with its own keyring, then revoke that
# keyring as pam_keyinit(8) does when the login session ends. # keyring as pam_keyinit(8) does when the login session ends.
LOGIN=$(keyctl session - sh -c " LOGIN=$(keyctl session - sh -c "
@@ -62,7 +36,15 @@ LOGIN=$(keyctl session - sh -c "
" 2>/dev/null) || fail "could not start server" " 2>/dev/null) || fail "could not start server"
# A new pane should still have a usable keyring, with the user keyring linked. # A new pane should still have a usable keyring, with the user keyring linked.
pane_keyring "$TMUX" $TMUX new-window -d "keyctl id @s >$OUT/pane 2>&1; $TMUX wait-for -S pane" ||
fail "could not create pane"
$TMUX wait-for pane
KEYRING=$(cat $OUT/pane)
case "$KEYRING" in
''|*[!0-9]*)
fail "pane keyring not usable: $KEYRING"
;;
esac
[ "$KEYRING" != "$LOGIN" ] || fail "pane has the login keyring" [ "$KEYRING" != "$LOGIN" ] || fail "pane has the login keyring"
keyctl rlist $KEYRING | grep -qw "$(keyctl id @u)" || keyctl rlist $KEYRING | grep -qw "$(keyctl id @u)" ||
fail "user keyring not linked" fail "user keyring not linked"

View File

@@ -220,6 +220,10 @@ server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base,
TAILQ_INIT(&message_log); TAILQ_INIT(&message_log);
gettimeofday(&start_time, NULL); gettimeofday(&start_time, NULL);
#ifdef HAVE_KEYCTL
new_session_keyring();
#endif
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD
server_fd = systemd_create_socket(flags, &cause); server_fd = systemd_create_socket(flags, &cause);
#else #else
@@ -260,7 +264,7 @@ server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base,
job_kill_all(); job_kill_all();
prompt_save_history(); prompt_save_history();
#ifdef HAVE_KEYCTL #ifdef HAVE_KEYCTL
keyring_revoke(); revoke_session_keyring();
#endif #endif
exit(0); exit(0);

8
tmux.1
View File

@@ -5096,14 +5096,6 @@ each client.
.It Ic prompt\-history\-limit Ar number .It Ic prompt\-history\-limit Ar number
Set the number of history items to save in the history file for each type of Set the number of history items to save in the history file for each type of
command prompt. command prompt.
.It Xo Ic session\-keyring
.Op Cm on | off
.Xc
On Linux, if enabled (the default), the server joins a new session keyring with
the user keyring linked into it, rather than keeping the session keyring of the
login session it was started from, which may be revoked when that session ends.
The new keyring is revoked when the server exits.
This option is checked once the configuration file has been loaded.
.It Xo Ic set\-clipboard .It Xo Ic set\-clipboard
.Op Cm on | external | off .Op Cm on | external | off
.Xc .Xc