Docu review done: Mon 03 Jul 2023 17:13:12 CEST

Table of content

General

This small snippet should help you in your (work) live. Often admins have to ssh with a different user and gather then higher permissions, e.g. by using sudo or thinks like that. sshc want to make that a bit easier for you, buy performing the connection and becoming any other user (e.g. root) for you. And it is the older brother of sshc

Requirements

To make use of ssht, you some applications or functions are needed in your system

  • tmux
  • Password store with CLI access e.g. pass
  • Being able to generate a list of hosts you want to ssh and fetch passwords e.g. your ~/.ssh/config

Installation

The installation is as simple as it can be (expected that you have tmux, pwd store and your host list already in place.

Go to a place on your system where you store your .rc files which get sourced by your shell and either add there a new file or copy/past the below functions into an existing one.

The function below expects that your ssh host list comes from ~/.ssh/config, if you dont have it like that, just search for it and replace it with the commands you need.

############################################
#
# TMUX ssh root login
#

function _tmux_login_usage() {
    echo "-l <local tmux socket name>   # as it says"
    echo "-t <tmux connection string>   # <session>:<window>(.<pane>)"
    echo "-s <ssh remote server>        # as it says"
    echo "-p <match string>             # string that is shown when requesting pwd (default: 'Password:')"
    echo "-P <absolut path to pwd bin>  # defines the absolutpath to the binary for fetching the pwd"
    echo "-h                            # hows this help"
    return 64
}

function tmux_login() {
    local optstring="l:t:s:p:P:h"
    tmux_socket_name=""
    tmux_connect=""
    ssh_server_name=""
    pwd_question_matcher="Password:"
    password_bin=""

    while getopts ${optstring} c; do
        case ${c} in
            l)  tmux_socket_name="${OPTARG}" ;;
            t)  tmux_connect="${OPTARG}" ;;
            s)  ssh_server_name="${OPTARG}" ;;
            p)  pwd_question_matcher="${OPTARG}" ;;
            P)  password_bin="${OPTARG}" ;;
            h)  _tmux_login_usage ; return 64 ;;
            *)  _tmux_login_usage ; return 64 ;;
        esac
    done

    local pw
    if pw=$("${password_bin}" "${ssh_server_name}") ; then
        while_counter=20
        while [[ $(tmux -L "${tmux_socket_name}" capture-pane -p -t "${tmux_connect}" | grep -v "^$" | tail -n 1) != "${pwd_question_matcher}" ]]; do
            if (( while_counter > 0 )); then
                sleep 0.3
                let while_counter-=1
            else
                return 1
            fi
        done
        &>/dev/null tmux -L "${tmux_socket_name}" send-keys -t "${tmux_connect}" "$pw" C-m
        &>/dev/null tmux -L "${tmux_socket_name}" send-keys -t "${tmux_connect}" "printf '\033]2;${ssh_server_name}\033\\'" C-m
        &>/dev/null tmux -L "${tmux_socket_name}" send-keys -t "${tmux_connect}" "printf '\033]2;${ssh_server_name}\033\\' ; clear" C-m
    else
        echo "failed to get pwd for ${ssh_server_name}"
    fi
}

function _ssht_compl_zsh() {
    compadd ${=${${${${${(f)"$(cat ~/.ssh/config(n) /dev/null)"}##[A-Z][a-z]* }##  *[A-Z][a-z]* *}%%[# ]*}%%--*}//,/ }
}

function _ssht_compl_bash() {
    if [ "${#COMP_WORDS[@]}" != "2" ]; then
        return
    fi

    local IFS=$'\n'
    local suggestions=($(compgen -W "$(sed -E '/^Host +[a-zA-Z0-9]/!d;s/Host //g' ~/.ssh/config | sort -u)" -- "${COMP_WORDS[1]}"))

    if [ "${#suggestions[@]}" == "1" ]; then
        local onlyonesuggestion="${suggestions[0]/%\ */}"
        COMPREPLY=("${onlyonesuggestion}")
    else
        for i in "${!suggestions[@]}"; do
            suggestions[$i]="$(printf '%*s' "-$COLUMNS"  "${suggestions[$i]}")"
        done

        COMPREPLY=("${suggestions[@]}")
    fi
}

function _ssht() {
    server="${1}"
    pane_nr="$(( ( RANDOM % 9999 )  + 1 ))"
    sub_nr="$(( ( RANDOM % 9999 )  + 1 ))"
    password_bin="<DEFAULT PWD FETCH COMMAND>"

    if ! [ -x "${password_bin}" ]; then
        echo "${password_bin} has no execution permission or does not exist on FS"
        return 1
    fi

    ( &>/dev/null tmux_login -s "${server}" -t "${pane_nr}:${sub_nr}" -l "ssh_root_sessions" -P "${password_bin}" & )
    &>/dev/null tmux -L ssh_root_sessions -f ~/.tmux_ssh.conf new -s "${pane_nr}" -n ${sub_nr} "ssh -q -t ${server} \"su -\""
}

current_shell="$(ps -o comm -p $$ | tail -1)"
alias ssht="_ssht"

if [[ "${current_shell}" == "zsh" ]]; then
    compdef _ssht_compl_zsh _ssht
elif [[ "${current_shell}" == "bash" ]]; then
    complete -F _ssht_compl_bash ssht
fi

As an well trained engineer, you saw ofcourse that a different tmux config was used, ~/.tmux_ssh.conf

Why do we load an additional tmux config? Easy to say, this ensures that mod+b gets unset, so if you run tmux on the destination server you will controle the remote one and not yours. It will also sets alertings to inform the shell/terminal about alerts, the status bar will be removed to have the full view of your terminal and the scallback buffer got increased. Also the title is getting enabled, as the above function will replace it so that your terminal title gets the hostname from the server. This can help you for faster switching to the open connection for example.

This is what it contains:

#tmux source-file .tmux_ssh.conf
unbind C-b

#Set alert if something happens
setw -g monitor-activity on
set -g visual-activity on

# scrollback buffer n lines
set -g history-limit 99999

# enable wm window titles
set -g set-titles on

# center align the window list
set -g status off

# Enable mouse mode to avoide scroll back issues
set -g mouse off

Now the time has tome to source it to your .rc file.

Usage

To use it, you just have to run ssht followed either by <tab><tab> or type the full or beginning of the hostname + tab till you have the full name displayed in your shell. Guess what, now just hit the enter key ;)

You will see that it cleans the output of your terminal (because it starts tmux). After that you will find on the to something like “Password:” which will disapear and you will get a shell on the remote host as root user. When you close now the connection, it will look like before you perfmored the ssht command. And we are done.

If you want to know how the tab completion works, have a look at