aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvg <vg@devys.org>2019-01-21 16:54:00 +0100
committervg <vg@devys.org>2019-01-21 16:54:00 +0100
commit49bb0e1fabe13d68bea89b29f51f8f316e0b6cdf (patch)
tree5eff4a1abe647d09079ed84fbfd5b88694d0a28e
parent165f06e419fe6987f9ae8b01ab6ec99098560600 (diff)
downloadscripts-49bb0e1fabe13d68bea89b29f51f8f316e0b6cdf.tar.gz
scripts-49bb0e1fabe13d68bea89b29f51f8f316e0b6cdf.tar.bz2
scripts-49bb0e1fabe13d68bea89b29f51f8f316e0b6cdf.zip
add a script to help me help users by taking control over their computer
-rwxr-xr-xscripts/help-me.bash344
1 files changed, 344 insertions, 0 deletions
diff --git a/scripts/help-me.bash b/scripts/help-me.bash
new file mode 100755
index 0000000..0d8a84b
--- /dev/null
+++ b/scripts/help-me.bash
@@ -0,0 +1,344 @@
+#!/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 <<EOF
+setw -g aggressive-resize on
+set -s escape-time 0
+set -g mode-keys vi
+set -g status-keys vi
+unbind C-b
+set -g prefix C-a
+bind a send-prefix
+bind C-a send-prefix
+unbind Up
+unbind Down
+unbind Left
+unbind Right
+bind -n C-PgUp previous-window
+bind -n C-PgDn next-window
+bind Up select-pane -U
+bind Down select-pane -D
+bind Left select-pane -L
+bind Right select-pane -R
+bind - split-window
+bind | split-window -h
+bind v choose-window "join-pane -h -s "%%""
+bind b break-pane
+bind Tab next-window
+EOF
+ if [ "$user_version" -ne 0 ]; then
+ cat <<EOF
+new-session -s help
+rename-window user
+new-window -dn root tmux -S /run/help-root attach
+EOF
+ else
+ cat <<EOF
+new-session -s help
+rename-window root
+EOF
+ fi
+}
+
+exit_cleanup()
+{
+ set +e # avoid getting error stopping the script to do all cleanup
+ tmux -L help kill-server 2>/dev/null
+ tmux -S /run/help-root kill-server 2>/dev/null
+ rm -f /run/help-root
+}
+
+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="$(sudo mktemp)"
+ generate_tmux_conf 0 | sudo tee "$tmpfile" >/dev/null
+ sudo -i tmux -S /run/help-root -f "$tmpfile" start
+ sudo rm -f -- "$tmpfile"
+ sudo chown $USER /run/help-root
+ # mktemp 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()
+{
+ exec > >(tee /tmp/help.log) 2>&1
+ trap exit_cleanup EXIT INT
+ ensure_script_requirement
+ get_user_consent
+ ensure_required_packages_are_installed
+ ensure_key_is_in_authorized_keys
+ display_warning_for_bad_ssh_configuration
+ ensure_ssh_is_running
+ ensure_tmux_is_running
+ open_xterm_with_tmux_inside
+ make_connection_to_local_ssh_server
+}
+
+# run all the stuff
+main