#!/bin/bash # SPDX-License-Identifier: MIT # Copyright vg 2019 vg+dev@devys.org # This script has been created to help users by taking control of their # computer with their consent. # This script is intended to be used by doing this: # sudo apt-get install -yq curl && curl https://devys.org/help | bash set -eu ################################################################################ # parameters ################################################################################ # by: ssh-keygen -t rsa -b 4096 -C 'vg help key 2019' -f ~/.ssh/id_help2019 ssh_key="ssh-xxx help key here" remote='remote help host here' remote_port='remote port to use on remote host' ################################################################################ # normal functions ################################################################################ ### # using only bash builtins ### echo_notice() { echo $'\e[32m'"$*"$'\e[m'; } echo_warning() { echo $'\e[33m'"$*"$'\e[m' >&2; } echo_error() { echo $'\e[31m'"$*"$'\e[m' >&2; } die() { echo_error "$*"; exit 1; } join() { local IFS="$1"; shift; echo "$*"; } ### # using commands ### get_ssh_port() { local conf="$1" grep -i ^port -- "$conf" | head -1 | cut -d' ' -f2 || echo 22 } get_ssh_conf_from_running_process() { # in case of sshd is not running, xargs will failed to load from # /proc//cmdline, but it is ok as the return value will be non zero which # is wanted. But in order to detect potential dev problem, avoid using # 2>/dev/null and first check if file exists: local cmdline_file="/proc/$(pgrep -xo sshd)/cmdline" if [ ! -f "$cmdline_file" ]; then return 1 fi xargs -0 -a "$cmdline_file" bash -c ' while [ "$#" -gt 0 -a "$1" != "-f" ]; do shift done shift if [ "$#" -eq 0 ]; then exit 1; fi echo "$1" ' } get_ssh_conf_from_etc_default() { # Warning, we source /etc/default/ssh meaning any command will be # executed, but that's the system is already doing anyway so I consider it # to be low risk here given the context. if [ ! -f /etc/default/ssh ]; then return 1 fi source /etc/default/ssh if [ -z "${SSHD_OPTS:-}" ]; then return 1 fi local - set -- $SSHD_OPTS while [ "$#" -gt 0 -a "$1" != "-f" ]; do shift done shift if [ "$#" -eq 0 ]; then return 1 fi echo "$1" } get_ssh_conf() { # try to get it from running program command line invocation # if failing, get it from /etc/default/ssh # if still failing, assume the config file is the default location get_ssh_conf_from_running_process \ || get_ssh_conf_from_etc_default \ || echo /etc/ssh/sshd_config } generate_tmux_conf() { local user_version="$1" cat </dev/null if [ -z "$tmpdir" ]; then return; fi tmux -S "$tmpdir/help-root" kill-server 2>/dev/null rm -rf -- "$tmpdir" } run_tmux() { ( # subshell for chdir, easier when openning new tmux panes cd ~ || true # not mandatory, just easier within tmux if ! tmux -L help has-session -t help 2>/dev/null; then local tmpfile="$tmpdir/help-root.tmux.conf" sudo -v generate_tmux_conf 0 | sudo tee "$tmpfile" >/dev/null sudo -i tmux -S "$tmpdir/help-root" -f "$tmpfile" start sudo rm -f -- "$tmpfile" sudo chown $USER "$tmpdir/help-root" # tmpfile is not necessary when not using sudo tmux -L help -f <(generate_tmux_conf 1) start fi ) } ################################################################################ # steps and display functions (functions being called by main): in order ################################################################################ ensure_script_requirement() { # this function assumes coreutils and procps are installed echo_notice 'Check whether required tools are installed' local tool for tool in apt-get dpkg grep sed sudo; do if [ ! -x $(which $tool 2>/dev/null) ]; then die " $tool is required and is not installed, aborting" fi done echo_notice '=> ok' } get_user_consent() { echo_notice 'Check for user consent' local prompt=' Do you want me to take control over your computer [Y/n] ? ' while true; do read -p "$prompt" -N 1 -r case "$REPLY" in $'\n'|Y|y) break;; N|n) echo_notice '=> ok, bye'; exit 0;; *) echo_warning $'\n'' bad answer, try again';; esac done echo_notice '=> ok' } ensure_required_packages_are_installed() { echo_notice 'Ensure required packages are installed' local packages=( openssh-server socat tmux ) if [ "$(dpkg --get-selections \ | grep -P "^($(join '|' "${packages[@]}"))\\s+install$" \ | wc -l )" -ne "${#packages[@]}" ]; then echo_notice ' Some required packages are missing, installing them' echo_notice ' You might be asked for your password, it is normal' sudo apt-get install -yq "${packages[@]}" fi echo_notice '=> ok' } ensure_key_is_in_authorized_keys() { echo_notice 'Ensure access key is in ~/.ssh/authorized_keys' if [ ! -d ~/.ssh ]; then echo_notice ' ~/.ssh did not exist, creating it' mkdir -m 0700 -p ~/.ssh elif [ "$(stat -c %a ~/.ssh)" -ne 700 ]; then echo_notice ' ~/.ssh do not have correct permission, fixing it' chmod 0700 ~/.ssh fi if [ ! -f ~/.ssh/authorized_keys ]; then echo_notice ' ~/.ssh/authorized_keys do not exist, creating it' touch ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys elif [ "$(stat -c %a ~/.ssh/authorized_keys)" -ne 600 ]; then echo_notice ' ~/.ssh/authorized_keys bad permission, fixing it' chmod 0600 ~/.ssh/authorized_keys fi if ! grep -qxF "$ssh_key" ~/.ssh/authorized_keys; then echo_notice ' adding my key to ~/.ssh/authorized_keys' echo "$ssh_key" >> ~/.ssh/authorized_keys fi echo_notice '=> ok' } display_warning_for_bad_ssh_configuration() { echo_notice 'Sanity check sshd configuration' # do this to help users signal me if I should adjust their ssh config local conf="$(get_ssh_conf)" if [ ! -f "$conf" ]; then die ' sshd configuration file not found' fi local port="$(get_ssh_port "$conf")" if [ "$port" == "22" ]; then echo_warning ' sshd use default port 22, **please fix it**' fi if grep -P '^\s*PasswordAuthentication\s+yes' "$conf"; then echo_warning ' sshd allows access by password, **please fix it**' fi echo_notice '=> done' } ensure_ssh_is_running() { echo_notice 'Ensure sshd is running' if [ "$(pgrep -xc sshd)" -gt 0 ]; then echo_notice ' sshd is correctly running' else echo_warning ' sshd is not running, trying to start it' sudo systemctl start ssh sleep 3 if [ "$(pgrep -xc sshd)" -gt 0 ]; then echo_notice ' sshd correctly started' else die ' failed to start sshd, abort' fi fi echo_notice '=> ok' } ensure_tmux_is_running() { echo_notice 'Ensure tmux is running for you to see what I do' run_tmux echo_notice '=> ok' } open_xterm_with_tmux_inside() { echo_notice 'Running a terminal with tmux inside' if [ -z "${DISPLAY:-}" ]; then echo_warning ' not inside X server ? unable to run a term' return fi if [ -x "$(which gnome-terminal 2>/dev/null)" ]; then gnome-terminal -x tmux -L help attach & elif [ -x "$(which xfce4-terminal 2>/dev/null)" ]; then xfce4-terminal -x tmux -L help attach & elif [ -x "$(which lxterminal 2>/dev/null)" ]; then xfce4-terminal -e 'tmux -L help attach' & elif [ -x "$(which xterm 2>/dev/null)" ]; then xterm -e tmux -L help attach & fi echo_notice '=> ok' } make_connection_to_local_ssh_server() { echo_notice 'Making connection to help server through the internet' echo_notice ' Please ensure internet is available' echo_notice ' Please give me the following informations:' echo_notice " - username: $USER" echo_notice " - hostname: $HOSTNAME" local conf="$(get_ssh_conf)" local port="$(get_ssh_port "$conf")" while true; do echo_notice " connecting to $remote:$remote_port, CTRL-C to stop" socat \ tcp-connect:localhost:$port \ tcp-connect:$remote:$remote_port,forever,interval=3 echo_notice " socat ended, waiting 5 seconds before trying again" sleep 5 done echo_notice '=> end' } ################################################################################ # main ################################################################################ main() { # log local logfile="$(mktemp --tmpdir --suffix=.log help.XXXXXXXXXX)" exec > >(tee "$logfile") 2>&1