From 49bb0e1fabe13d68bea89b29f51f8f316e0b6cdf Mon Sep 17 00:00:00 2001 From: vg Date: Mon, 21 Jan 2019 16:54:00 +0100 Subject: add a script to help me help users by taking control over their computer --- scripts/help-me.bash | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100755 scripts/help-me.bash 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 </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 -- cgit v1.2.3