From f03d3a8561ff9a744c522963895a32bd170dcc74 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Fri, 19 Apr 2024 11:03:02 -0500 Subject: [PATCH] Handle non-GUI sessions (SSH, tmux) When there is a "global" SSH agent running in a GUI session, attempting to use it from a remote SSH session may not work well. For keys that need a passphrase or confirmation, the prompt will appear on the graphical display, rather than the remote client's terminal, essentially preventing the remote client from using those keys. To resolve this, we need to use a separate SSH agent for remote clients. At login, the remote client should spawn its own agent, e.g. with `eval $(ssh-agent)`. Then, the ssh-askpass script will be able to spawn `pinentry` attached to theh remote client's terminal. In the specific case of running `tmux` in a remote SSH session, things get a bit more complicated. Since `tmux` has control of the SSH client's terminal, attaching `pinentry` to it wreaks havoc and makes both programs unusable. Thus, we need to spawn `pinentry` _inside_ `tmux`. Since we do not know which TTY the invoker is using, we need to spawn a new window for the `pinentry` prompt. This of course detaches the `pinentry` process from our stdin/stdout, so we have to used named pipes to communicate with it. --- ssh-askpass | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/ssh-askpass b/ssh-askpass index 4da060d..57e65a4 100755 --- a/ssh-askpass +++ b/ssh-askpass @@ -1,8 +1,34 @@ #!/bin/sh # vim: set sw=4 ts=4 sts=4 et : +pinentry() { + if [ -n "${TMUX}" ] && [ -z "${DISPLAY}" ]; then + # We're running in a TMUX pane, launch a new window to handle + # passphrase/confirmation prompt + unset t1 t2 + mkfifo "${t1:=$(mktemp -u)}" + mkfifo "${t2:=$(mktemp -u)}" + tmux new-window sh -c "exec pinentry -T \$(tty) < '$t1' > '$t2'" + cat > "$t1" + cat "$t2" + rm -f "$t1" "$t2" + return + elif [ -n "${SSH_TTY}" ]; then + # We're in an SSH session, so prompt for the passphrase on the + # SSH client terminal + set -- -T "${SSH_TTY}" "$@" + elif [ -t 0 ]; then + set -- -T $(tty) "$@" + elif [ -t 1 ]; then + set -- -T $(tty <&1) "$@" + elif [ -t 2 ]; then + set -- -T $(tty <&2) "$@" + fi + command pinentry "$@" +} + prompt_confirm() { - result=$(pinentry -T $(tty) -g <