Extend "open new tab in current directory" feature to remote shells (SSH)
Submitted by Simon Sapin
Link to original bug (#777960)
Description
Created attachment 344595 git show -U8
I couldn’t find out what the workflow is to contribute code, so a patch file is attached. I don’t expect it to be accepted as-is, this is a proof-of-concept to support discussion. I based it on the 3.22.1 git tag because my distribution doesn’t have a recent enough libvte to build master.
The commit message explains what/why/how, and is reproduced here:
Background
Currently, when everything is configured correctly, opening a new tab in gnome-terminal from an existing tab will start a new shell in the current directory of the shell of the existing tab.
This is great, but doesn’t work when the existing shell is remote, used through SSH. This is an attempt at fixing that.
The way the current feature works is that libvte is distributed with a file that distrubutions and/or users are advised to source in their bash or zsh configuration:
https://git.gnome.org/browse/vte/tree/src/vte.sh
This makes makes the shell, every time there is a prompt, print an escape sequence that includes the current directory path. libvte interprets this sequence and does not show it to the user.
printf "\033]7;file://%s%s\007" "${HOSTNAME:-}" "$(__vte_urlencode "${PWD}")"
The good news is the that the host name is already included in this sequence. The less good news is that $HOSTNAME is apparently not required by POSIX, and vte.sh does nothing if $VTE_VERSION is not set. On my systems, I’ve had to:
- Add
SendEnv VTE_VERSION
to the OpenSSH client configuration - Add
VTE_VERSION
to the existingAcceptEnv
in OpenSSH server config - Add
[ -n "$HOSTNAME" ] && export HOSTNAME="$HOST"
to zsh config
Perhaps vte.sh should be modified to fall back on $HOST or $(hostname).
This change
When the current-directory-uri-changed VTE sequence contains a host name that is different from the local host’s name, use the existing "override command" mechanism to start, instead of the default shell:
ssh -t $HOSTNAME cd $PWD ; exec \$SHELL
(Where $HOSTNAME and $PWD come from the VTE sequence, escaped properly, and $SHELL is sent with no backslash but a literal dollar sign.)
That is: run ssh with a pseudo-terminal allocation, then on the server change to the given directory, then run the server’s default shell.
This is similar to what "Open in a remote terminal" does in GNOME Terminal’s extension for Nautilus. Whoever, while Nautilus (by necessity) knows exactly how to connect to the remote server, this relies on the server’s idea of what its name is (which could be misconfigured) to match the client’s SSH configuration. For example, with OpenSSH:
Host myserver
Hostname myserver.example.net
Caveats
Making this works requires configuration (of local and remote ssh and shell) this is unlikely to happen out of the box.
However, in default configurations ($VTE_VERSION not sent to the remote shell), this falls back gracefully to the previous behavior. (The new tab runs a local shell.)
A possible improvement would be: when ssh exits with an unsuccessful exit code (perhaps because no server is configured or reachable with the given host name), fall back to running a local shell. (This would probably require running "sh -c '...'" with an extra layer of shell escaping.)
From the security viewpoint, when a client A is connected to a malicious SSH server B, this change enables B to make A (when the user opens a new tab) connect to an arbitrary server C. However, this only runs the default $SHELL as configured on C. B has no control over that $SHELL variable. Proper use of shell escaping (which should be double-checked in review) in the ssh command prevents B from gaining arbitrary code execution access on either A or C.
Patch 344595, "git show -U8":
new-tab-in-same-remote-directory.patch
Version: 3.22.x