REPORT_EXPORT_TO_EXCEL/rport-installer.sh

1349 lines
46 KiB
Bash

#!/bin/sh -e
MY_COMMAND="$0 $*"
exit_trap() {
# shellcheck disable=SC2181
if [ $? -eq 0 ]; then
return 0
fi
echo ""
echo "An error occurred."
echo "Try running in debug mode with 'sh -x ${MY_COMMAND}'"
echo "Ask for help on https://github.com/openrport/openrport-pairing/discussions/categories/help-needed "
echo ""
}
trap exit_trap EXIT
# BEGINNING of templates/header.txt ----------------------------------------------------------------------------------|
##
## This is the RPort client installer script.
## It helps you to quickly install the rport client on a variety of Linux distributions.
## The scripts creates a initial configuration and connects the client to your server.
##
## For any inquiries use our GitHub forum on
## https://github.com/openrport/rport-pairing/discussions/
##
## Copyright cloudradar GmbH, Potsdam Germany, 2022
## Maintainer openrport, Lille, France, 2023
## Released under the MIT open-source license.
## https://github.com/openrport/rport-pairing/blob/main/LICENSE
##
# END of templates/header.txt ----------------------------------------------------------------------------------------|
## BEGINNING of rendered template templates/linux/installer_vars.sh
#
# Dynamically inserted variables
#
FINGERPRINT="05:7f:44:a8:62:02:72:e6:e0:ab:56:f3:42:01:0a:8f"
CONNECT_URL="http://rport.stines.de:8000"
CLIENT_ID="stines"
PASSWORD="WdwCpNJGcnsuriu"
#
# Global static installer vars
#
TMP_FOLDER=/tmp/rport-install
FORCE=1
USE_ALTERNATIVE_MACHINEID=0
LOG_DIR=/var/log/rport
LOG_FILE=${LOG_DIR}/rport.log
## END of rendered template templates/linux/installer_vars.sh
# BEGINNING of templates/linux/vars.sh -------------------------------------------------------------------------------|
#
# Global Variables for installation and update
#
CONF_DIR=/etc/rport
CONFIG_FILE=${CONF_DIR}/rport.conf
USER=rport
ARCH=$(uname -m | sed s/"armv\(6\|7\)l"/'armv\1'/ | sed s/aarch64/arm64/)
# END of templates/linux/vars.sh -------------------------------------------------------------------------------------|
# BEGINNING of templates/linux/functions.sh --------------------------------------------------------------------------|
set -e
if which tput >/dev/null 2>&1; then
true
else
alias tput=true
fi
throw_fatal() {
echo 2>&1 "[!] $1"
echo "[=] Fatal Exit. Don't give up. Good luck with the next try."
false
}
throw_hint() {
echo "[>] $1"
}
throw_info() {
echo "$(tput setab 2 2>/dev/null)$(tput setaf 7 2>/dev/null)[*]$(tput sgr 0 2>/dev/null) $1"
}
throw_warning() {
echo "[:] $1"
}
throw_debug() {
echo "$(tput setab 4 2>/dev/null)$(tput setaf 7 2>/dev/null)[-]$(tput sgr 0 2>/dev/null) $1"
}
wait_for_rport() {
i=0
while [ "$i" -lt 40 ]; do
pidof rport >/dev/null 2>&1 && return 0
echo "$i waiting for rport process to come up ..."
sleep 0.2
i=$((i + 1))
done
return 1
}
is_rport_subprocess() {
if [ -n "$1" ]; then
SEARCH_PID=$1
else
SEARCH_PID=$$
fi
PARENT_PID=$(ps -o ppid= -p "$SEARCH_PID" | tr -d ' ')
PARENT_NAME=$(ps -p "$PARENT_PID" -o comm=)
if [ "$PARENT_NAME" = "rport" ]; then
return 0
elif [ "$PARENT_PID" -eq 1 ]; then
return 1
fi
is_rport_subprocess "$PARENT_PID"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: is_available
# DESCRIPTION: Check if a command is available on the system.
# PARAMETERS: command name
# RETURNS: 0 if available, 1 otherwise
#----------------------------------------------------------------------------------------------------------------------
is_available() {
if command -v "$1" >/dev/null 2>&1; then
return 0
else
return 1
fi
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: uninstall
# DESCRIPTION: Uninstall everything and remove the user
#----------------------------------------------------------------------------------------------------------------------
uninstall() {
if pgrep rportd >/dev/null; then
echo 1>&2 "You are running the rportd server on this machine. Uninstall manually."
exit 0
fi
stop_rport >/dev/null 2>&1 || true
rc-service rport stop >/dev/null 2>&1 || true
pkill -9 rport >/dev/null 2>&1 || true
rport --service uninstall >/dev/null 2>&1 || true
FILES="/usr/local/bin/rport
/usr/local/bin/rport
/etc/systemd/system/rport.service
/etc/sudoers.d/rport-update-status
/etc/sudoers.d/rport-all-cmd
/usr/local/bin/tacoscript
/etc/init.d/rport
/var/run/rport.pid
/etc/runlevels/default/rport
/etc/apt/sources.list.d/rport.list"
for FILE in $FILES; do
if [ -e "$FILE" ]; then
rm -f "$FILE" && echo " [ DELETED ] File $FILE"
fi
done
if id rport >/dev/null 2>&1; then
if is_available deluser; then
deluser --remove-home rport >/dev/null 2>&1 || true
deluser --only-if-empty --group rport >/dev/null 2>&1 || true
elif is_available userdel; then
userdel -r -f rport >/dev/null 2>&1
fi
if is_available groupdel; then
groupdel -f rport >/dev/null 2>&1 || true
fi
echo " [ DELETED ] User rport"
fi
FOLDERS="/etc/rport
/var/log/rport
/var/lib/rport"
for FOLDER in $FOLDERS; do
if [ -e "$FOLDER" ]; then
rm -rf "$FOLDER" && echo " [ DELETED ] Folder $FOLDER"
fi
done
if dpkg -l 2>&1 | grep -q "rport.*Remote access"; then
apt-get -y remove --purge rport
fi
echo "RPort client successfully uninstalled."
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: print_distro
# DESCRIPTION: print name of the distro
#----------------------------------------------------------------------------------------------------------------------
print_distro() {
if [ -e /etc/os-release ]; then
# shellcheck source=/dev/null
. /etc/os-release 2>/dev/null || true
echo "Detected Linux Distribution: ${PRETTY_NAME}"
fi
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: has_sudo
# DESCRIPTION: Check if sudo is installed and sudo rules can be managed as separated files
# RETURNS: 0 (success, sudo os present), 1 (fail, sudo can't be used by rport)
#----------------------------------------------------------------------------------------------------------------------
has_sudo() {
if ! which sudo >/dev/null 2>&1; then
return 1
fi
if [ -e /etc/sudoers.d/ ]; then
return 0
fi
return 1
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: create_sudoers_all
# DESCRIPTION: create a sudoers file to grant full sudo right to the rport user
#----------------------------------------------------------------------------------------------------------------------
create_sudoers_all() {
SUDOERS_FILE=/etc/sudoers.d/rport-all-cmd
if [ -e "$SUDOERS_FILE" ]; then
throw_info "You already have a $SUDOERS_FILE. Not changing."
return 1
fi
if has_sudo; then
echo "#
# This file has been auto-generated during the installation of the rport client.
# Change to your needs or delete.
#
${USER} ALL=(ALL) NOPASSWD:ALL
" >$SUDOERS_FILE
echo "A $SUDOERS_FILE has been created. Please review and change to your needs."
else
echo "You don't have sudo installed. No sudo rules created. RPort will not be able to get elevated right."
fi
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: create_sudoers_updates
# DESCRIPTION: create a sudoers file to allow rport supervise the update status
#----------------------------------------------------------------------------------------------------------------------
create_sudoers_updates() {
SUDOERS_FILE=/etc/sudoers.d/rport-update-status
if [ -e "$SUDOERS_FILE" ]; then
throw_info "You already have a $SUDOERS_FILE. Not changing."
return 0
fi
if has_sudo; then
echo '#
# This file has been auto-generated during the installation of the rport client.
# Change to your needs.
#' >$SUDOERS_FILE
if is_available apt-get; then
echo "${USER} ALL=NOPASSWD: SETENV: /usr/bin/apt-get update -o Debug\:\:NoLocking=true" >>$SUDOERS_FILE
fi
#if is_available yum;then
# echo 'rport ALL=NOPASSWD: SETENV: /usr/bin/yum *'>>$SUDOERS_FILE
#fi
#if is_available dnf;then
# echo 'rport ALL=NOPASSWD: SETENV: /usr/bin/dnf *'>>$SUDOERS_FILE
#fi
if is_available zypper; then
echo "${USER} ALL=NOPASSWD: SETENV: /usr/bin/zypper refresh *" >>$SUDOERS_FILE
fi
#if is_available apk;then
# echo 'rport ALL=NOPASSWD: SETENV: /sbin/apk *'>>$SUDOERS_FILE
#fi
echo "A $SUDOERS_FILE has been created. Please review and change to your needs."
fi
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: abort
# DESCRIPTION: Exit the script with an error message.
#----------------------------------------------------------------------------------------------------------------------
abort() {
echo >&2 "$1 Exit!"
clean_up
exit 1
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: confirm
# DESCRIPTION: Print a success message.
#----------------------------------------------------------------------------------------------------------------------
confirm() {
echo "Success: $1"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: check_prerequisites
# DESCRIPTION: Check if prerequisites are fulfilled.
#----------------------------------------------------------------------------------------------------------------------
check_prerequisites() {
if [ "$(id -u)" -ne 0 ]; then
abort "Execute as root or use sudo."
fi
if command -v sed >/dev/null 2>&1; then
true
else
abort "sed command missing. Make sure sed is in your path."
fi
if command -v tar >/dev/null 2>&1; then
true
else
abort "tar command missing. Make sure tar is in your path."
fi
}
is_terminal() {
if echo "$TERM" | grep -q "^xterm"; then
return 0
else
echo 1>&2 "You are not on a terminal. Please use command line switches to avoid interactive questions."
return 1
fi
}
update_tacoscript() {
TACO_VERSION=$(/usr/local/bin/tacoscript --version | grep -o "Version:.*" | awk '{print $2}')
cd /tmp
test -e tacoscript.tar.gz && rm -f tacoscript.tar.gz
curl -LSso tacoscript.tar.gz "https://download.rport.io/tacoscript/${RELEASE}/?arch=Linux_${ARCH}&gt=$TACO_VERSION"
if tar xzf tacoscript.tar.gz 2>/dev/null; then
echo ""
throw_info "Updating Tacoscript from ${TACO_VERSION} to latest ${RELEASE} $(./tacoscript --version | grep -o "Version:.*")"
mv -f /tmp/tacoscript /usr/local/bin/tacoscript
else
throw_info "Nothing to do. Tacoscript is on the latest version ${TACO_VERSION}."
fi
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: install_tacoscript
# DESCRIPTION: install Tacoscript on Linux
#----------------------------------------------------------------------------------------------------------------------
install_tacoscript() {
if [ -e /usr/local/bin/tacoscript ]; then
throw_info "Tacoscript already installed. Checking for updates ..."
update_tacoscript
return 0
fi
cd /tmp
test -e tacoscript.tar.gz && rm -f tacoscript.tar.gz
curl -Ls "https://download.rport.io/tacoscript/${RELEASE}/?arch=Linux_${ARCH}" -o tacoscript.tar.gz
tar xvzf tacoscript.tar.gz -C /usr/local/bin/ tacoscript
rm -f tacoscript.tar.gz
echo "Tacoscript installed $(/usr/local/bin/tacoscript --version)"
}
version_to_int() {
echo "$1" |
awk -v 'maxsections=3' -F'.' 'NF < maxsections {printf("%s",$0);for(i=NF;i<maxsections;i++)printf("%s",".0");printf("\n")} NF >= maxsections {print}' |
awk -v 'maxdigits=3' -F'.' '{print $1*10^(maxdigits*2)+$2*10^(maxdigits)+$3}'
}
runs_with_selinux() {
if command -v getenforce >/dev/null 2>&1 && getenforce | grep -q Enforcing; then
return 0
else
return 1
fi
}
enable_file_reception() {
if [ "$(version_to_int "$TARGET_VERSION")" -lt 6005 ]; then
# Version does not handle file reception yet.
return 0
fi
if [ "$ENABLE_FILEREC" -eq 0 ]; then
echo "File reception disabled."
FILEREC_CONF="false"
else
echo "File reception enabled."
FILEREC_CONF="true"
fi
if grep -q '\[file-reception\]' "$CONFIG_FILE"; then
echo "File reception already configured"
else
cat <<EOF >>"$CONFIG_FILE"
[file-reception]
## Receive files pushed by the server, enabled by default
# enabled = true
## The rport client will reject writing files to any of the following folders and its subfolders.
## https://oss.rport.io/docs/no18-file-reception.html
## Wildcards (glob) are supported.
## Linux defaults
# protected = ['/bin', '/sbin', '/boot', '/usr/bin', '/usr/sbin', '/dev', '/lib*', '/run']
## Windows defaults
# protected = ['C:\Windows\', 'C:\ProgramData']
EOF
fi
toml_set "$CONFIG_FILE" file-reception enabled $FILEREC_CONF
# Clean up from pre-releases
test -e /etc/sudoers.d/rport-filepush && rm -f /etc/sudoers.d/rport-filepush
if [ "$ENABLE_FILEREC_SUDO" -eq 0 ]; then
# File receptions sudo rules not desired, end this function here
return 0
fi
# Create a sudoers file
FILERCV_SUDO="/etc/sudoers.d/rport-filereception"
if [ -e $FILERCV_SUDO ]; then
echo "Sudo rule $FILERCV_SUDO already exists"
else
cat <<EOF >$FILERCV_SUDO
# The following rule allows the rport client to change the ownership of any file retrieved from the rport server
rport ALL=NOPASSWD: /usr/bin/chown * /var/lib/rport/filepush/*_rport_filepush
# The following rules allows the rport client to move copied files to any folder
rport ALL=NOPASSWD: /usr/bin/mv /var/lib/rport/filepush/*_rport_filepush *
EOF
fi
}
enable_lan_monitoring() {
if [ "$(version_to_int "$TARGET_VERSION")" -lt 5008 ]; then
# Version does not handle network interfaces yet.
return 0
fi
if grep "^\s*net_[wl]" "$CONFIG_FILE"; then
# Network interfaces already configured
return 0
fi
echo "Enabling Network monitoring"
for IFACE in /sys/class/net/*; do
IFACE=$(basename "${IFACE}")
[ "$IFACE" = 'lo' ] && continue
if ip addr show "$IFACE" | grep -E -q "inet (10|192\.168|172\.16)\."; then
# Private IP
NET_LAN="$IFACE"
else
# Public IP
NET_WAN="$IFACE"
fi
done
if [ -n "$NET_LAN" ]; then
sed -i "/^\[monitoring\]/a \ \ net_lan = ['${NET_LAN}' , '1000' ]" "$CONFIG_FILE"
fi
if [ -n "$NET_WAN" ]; then
sed -i "/^\[monitoring\]/a \ \ net_wan = ['${NET_WAN}' , '1000' ]" "$CONFIG_FILE"
fi
}
detect_interpreters() {
if [ "$(version_to_int "$TARGET_VERSION")" -lt 5008 ]; then
# Version does not handle interpreters yet.
return 0
fi
if grep -q "\[interpreter\-aliases\]" "$CONFIG_FILE"; then
# Config already updated
true
else
echo "Updating config with new interpreter-aliases ..."
echo '[interpreter-aliases]' >>"$CONFIG_FILE"
fi
SEARCH="bash zsh ksh csh python3 python2 perl pwsh fish"
for ITEM in $SEARCH; do
FOUND=$(command -v "$ITEM" 2>/dev/null || true)
if [ -z "$FOUND" ]; then
continue
fi
echo "Interpreter '$ITEM' found in '$FOUND'"
if grep -q -E "^\s*$ITEM =" "$CONFIG_FILE"; then
echo "Interpreter '$ITEM' already registered."
continue
fi
# Append the found interpreter to the config
sed -i "/^\[interpreter-aliases\]/a \ \ $ITEM = \"$FOUND\"" "${CONFIG_FILE}"
done
}
toml_set() {
TOML_FILE="$1"
BLOCK="$2"
KEY="$3"
VALUE="$4"
if [ -w "$TOML_FILE" ]; then
true
else
echo 2>&1 "$TOML_FILE does not exist or is not writable."
return 1
fi
if grep -q "\[$BLOCK\]" "$TOML_FILE"; then
true
else
echo 2>&1 "$TOML_FILE has no block [$BLOCK]"
return 1
fi
LINE=$(grep -n -A100 "\[$BLOCK\]" "$TOML_FILE" | grep "${KEY} = ")
if [ -z "$LINE" ]; then
echo 2>&1 "Key $KEY not found in block $BLOCK"
return 1
fi
LINE_NO=$(echo "$LINE" | cut -d'-' -f1)
sed -i "${LINE_NO}s/.*/ ${KEY} = ${VALUE}/" "$TOML_FILE"
}
gen_uuid() {
if [ -e /proc/sys/kernel/random/uuid ]; then
cat /proc/sys/kernel/random/uuid
return 0
fi
if which uuidgen >/dev/null 2>&1; then
uuidgen
return 0
fi
if which dbus-uuidgen >/dev/null 2>&1; then
dbus-uuidgen
return 0
fi
# Use a internet-based fallback
curl -s https://www.uuidtools.com/api/generate/v4 | tr -d '"[]'
}
get_ip_from_fqdn() {
if which getent >/dev/null; then
getent hosts "$1" | awk '{ print $1 }'
return 0
fi
ping "$1" -c 1 -q 2>&1 | grep -Po "(\d{1,3}\.){3}\d{1,3}"
}
start_rport() {
if is_available systemctl; then
systemctl daemon-reload
systemctl start rport
systemctl enable rport
elif [ -e /etc/init/rport.conf ]; then
# We are on an upstart system
start rport
elif is_available service; then
service rport start
fi
if pidof rport >/dev/null 2>&1; then
return 0
else
return 1
fi
}
stop_rport() {
if is_available systemctl; then
systemctl stop rport
elif [ -e /etc/init/rport.conf ]; then
# We are on an upstart system
stop rport
elif is_available service; then
service rport stop
fi
}
backup_config() {
if [ -z "$CONFIG_FILE" ]; then
throw_fatal "backup_config() \$CONFIG_FILE undefined."
fi
CONFIG_BACKUP="/tmp/.rport-conf.$(date +%s)"
cp "$CONFIG_FILE" "$CONFIG_BACKUP"
throw_debug "Configuration file copied to $CONFIG_BACKUP"
}
clean_up_legacy_installation() {
# If this is a migration from the old none deb-based installation, clean up
if [ -e /etc/systemd/system/rport.service ]; then
throw_info "Removing old systemd service /etc/systemd/system/rport.service"
rm -f /etc/systemd/system/rport.service
systemctl daemon-reload
fi
if [ -e /usr/local/bin/rport ]; then
throw_info "Removing old version /usr/local/bin/rport"
rm -f /usr/local/bin/rport
fi
}
install_via_deb_repo() {
if [ -z "$RELEASE" ]; then
throw_fatal "install_via_deb_repo() \$RELEASE undefined"
fi
validate_custom_user
if [ -e /etc/apt/trusted.gpg.d/rport.gpg ] && dpkg -l | grep -q rport; then
throw_info "System is already using the rport deb repo."
else
throw_info "RPort will use Debian package ..."
# shellcheck source=/dev/null
. /etc/os-release
if [ -n "$UBUNTU_CODENAME" ]; then
CODENAME=$UBUNTU_CODENAME
else
CODENAME=$VERSION_CODENAME
fi
curl -sf https://repo.openrport.io/dearmor.gpg >/etc/apt/trusted.gpg.d/openrport.gpg
echo "deb [signed-by=/etc/apt/trusted.gpg.d/openrport.gpg] https://repo.openrport.io/deb ${CODENAME} ${RELEASE}" >/etc/apt/sources.list.d/rport.list
fi
apt-get update
if dpkg -s rport >/dev/null 2>&1 && ! [ -e /etc/rport/rport.conf ]; then
throw_warning "Broken DEB package installation found."
throw_debug "Will remove old package first."
apt-get -y --purge remove rport
fi
DEBIAN_FRONTEND=noninteractive apt-get --yes -o Dpkg::Options::="--force-confold" install rport
TARGET_VERSION=$(rport --version | cut -d" " -f2)
clean_up_legacy_installation
}
install_via_rpm_repo() {
if [ -z "$RELEASE" ]; then
throw_fatal "install_via_rpm_repo() \$RELEASE undefined"
fi
validate_custom_user
if [ -e /etc/yum.repos.d/openrport.repo ] && rpm -qa | grep -q rport; then
throw_info "System is already using the rport yum repo."
else
throw_info "RPort will use RPM package ..."
rpm --import https://repo.openrport.io/key.gpg
cat <<EOF >/etc/yum.repos.d/rport.repo
[rport-stable]
name=RPort $RELEASE
baseurl=https://repo.openrport.io/rpm/$RELEASE/
enabled=1
gpgcheck=1
gpgkey=https://repo.openrport.io/key.gpg
EOF
fi
dnf -y install rport --refresh
TARGET_VERSION=$(rport --version | cut -d" " -f2)
clean_up_legacy_installation
}
validate_custom_user() {
if [ "$USER" != "rport" ]; then
throw_fatal "RPM/DEB packages cannot be used with a custom user. Try '-p'"
fi
}
# Check if it's a supported debian system
is_debian() {
if [ "$NO_REPO" -eq 1 ]; then
return 1
fi
if which apt-get >/dev/null 2>&1 && test -e /etc/apt/sources.list.d/; then
true
else
return 1
fi
DIST_SUPPORTED="jammy focal bionic bullseye buster bookworm"
for DIST in $DIST_SUPPORTED; do
if grep -qi "CODENAME.*$DIST" /etc/os-release; then
return 0
fi
done
return 1
}
is_rhel() {
if [ "$NO_REPO" -eq 1 ]; then
return 1
fi
if grep -q "VERSION=.[6-7]" /etc/os-release; then
throw_info "RHEL/CentOS too old for RPM installation. Switching to tar.gz package."
return 1
fi
if which rpm >/dev/null 2>&1 && test -e /etc/yum.repos.d; then
return 0
fi
return 1
}
validate_pkg_url() {
if echo "${PKG_URL}" | grep -q -E "https*:\/\/.*_linux_$(uname -m)\.(tar\.gz|deb|rpm)$"; then
true
else
throw_fatal "Invalid PKG_URL '$PKG_URL'."
fi
}
download_pkg_url() {
DL_AUTH=""
if [ -n "$RPORT_INSTALLER_DL_USERNAME" ] && [ -n "$RPORT_INSTALLER_DL_PASSWORD" ]; then
DL_AUTH="-u ${RPORT_INSTALLER_DL_USERNAME}:${RPORT_INSTALLER_DL_PASSWORD}"
throw_info "Download will use HTTP basic authentication"
fi
throw_info "Downloading from ${PKG_URL} ..."
PKG_DOWNLOAD=$(mktemp)
# shellcheck disable=SC2086
curl -LSs "${PKG_URL}" ${DL_AUTH} >${PKG_DOWNLOAD}
if [ -n "$(find "${PKG_DOWNLOAD}" -empty)" ]; then
rm -f "${PKG_DOWNLOAD}"
throw_fatal "Download to ${PKG_DOWNLOAD} failed"
fi
throw_info "Download to ${PKG_DOWNLOAD} completed"
}
install_from_deb_download() {
validate_pkg_url
if echo "${PKG_URL}" | grep -q "deb$"; then
true
else
throw_fatal "URL not pointing to a debian package"
fi
download_pkg_url
mv "${PKG_DOWNLOAD}" "${PKG_DOWNLOAD}".deb
PKG_DOWNLOAD=${PKG_DOWNLOAD}.deb
chmod 0644 "${PKG_DOWNLOAD}"
throw_info "Installing debian package ${PKG_DOWNLOAD}"
DEBIAN_FRONTEND=noninteractive apt-get --yes -o Dpkg::Options::="--force-confold" install "${PKG_DOWNLOAD}"
rm -f "${PKG_DOWNLOAD}"
clean_up_legacy_installation
}
install_from_rpm_download() {
validate_pkg_url
if echo "${PKG_URL}" | grep -q "rpm$"; then
true
else
throw_fatal "URL not pointing to an rpm package"
fi
download_pkg_url
throw_info "Installing rpm package"
rpm -U "${PKG_DOWNLOAD}"
rm -f "${PKG_DOWNLOAD}"
clean_up_legacy_installation
}
abort_on_rport_subprocess() {
if is_rport_subprocess; then
throw_hint "Execute the rport update in a process decoupled from its parent, e.g."
throw_hint ' nohup sh -c "curl -s https://pairing.openrport.io/update|sh" >/tmp/rport-update.log 2>&1 &'
throw_fatal "You cannot update rport from an rport subprocess."
fi
}
# END of templates/linux/functions.sh --------------------------------------------------------------------------------|
# BEGINNING of templates/linux/install.sh ----------------------------------------------------------------------------|
set -e
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: prepare
# DESCRIPTION: Create a temporary folder and prepare the system to execute the installation
#----------------------------------------------------------------------------------------------------------------------
prepare() {
test -e "${TMP_FOLDER}" && rm -rf "${TMP_FOLDER}"
mkdir "${TMP_FOLDER}"
cd "${TMP_FOLDER}"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: cleanup
# DESCRIPTION: Remove the temporary folder and cleanup any leftovers after script has ended
#----------------------------------------------------------------------------------------------------------------------
clean_up() {
cd /tmp
rm -rf "${TMP_FOLDER}"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: test_connection
# DESCRIPTION: Check if the RPort server is reachable or abort.
#----------------------------------------------------------------------------------------------------------------------
test_connection() {
CONN_TEST=$(curl -vIs -m5 "${CONNECT_URL}" 2>&1 || true)
if echo "${CONN_TEST}" | grep -q "Connected to"; then
confirm "${CONNECT_URL} is reachable. All good."
else
echo "$CONN_TEST"
echo ""
echo "Testing the connection to the RPort server on ${CONNECT_URL} failed."
echo "* Check your internet connection and firewall rules."
echo "* Check if a transparent HTTP proxy is sniffing and blocking connections."
echo "* Check if a virus scanner is inspecting HTTP connections."
abort "FATAL: No connection to the RPort server."
fi
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: download_and_extract
# DESCRIPTION: Download the package from Github and unpack to the temp folder
# https://downloads.openrport.io/ acts a redirector service
# returning the real download URL of GitHub in a more handy fashion
#----------------------------------------------------------------------------------------------------------------------
download_and_extract() {
cd "${TMP_FOLDER}"
# Download the tar.gz package
if is_available curl; then
curl -LSs "https://downloads.openrport.io/rport/${RELEASE}/latest.php?arch=Linux_${ARCH}" -o rport.tar.gz
elif is_available wget; then
wget -q "https://downloads.openrport.io/rport/${RELEASE}/latest.php?arch=Linux_${ARCH}" -O rport.tar.gz
else
abort "No download tool found. Install curl or wget."
fi
# Unpack
tar xzf rport.tar.gz
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: download_and_extract_from_url
# DESCRIPTION: Download the package from any URL and unpack to the temp folder
#----------------------------------------------------------------------------------------------------------------------
download_and_extract_from_url() {
cd "${TMP_FOLDER}"
ARCH=$(uname -m)
DL_AUTH=""
DL="rport.tar.gz"
# Use a specific version
if echo "$PKG_URL" | grep -q -E "^https?:\/\/.*\_linux_${ARCH}.tar.gz"; then
DOWNLOAD_URL="$PKG_URL"
else
echo "PKG_URL does not match 'http(s)://... _linux_${ARCH}.tar.gz'"
abort "Invalid download URL."
fi
if [ -n "$RPORT_INSTALLER_DL_USERNAME" ] && [ -n "$RPORT_INSTALLER_DL_PASSWORD" ]; then
DL_AUTH="-u ${RPORT_INSTALLER_DL_USERNAME}:${RPORT_INSTALLER_DL_PASSWORD}"
confirm "Download will use HTTP basic authentication"
fi
echo "Downloading from ${DOWNLOAD_URL}"
[ -e "${DL}" ] && rm -f "${DL}"
# shellcheck disable=SC2086
curl -LSs "${DOWNLOAD_URL}" -o "${DL}" ${DL_AUTH}
echo "Verifying download"
FILES_IN_TAR=$(tar tzf "${DL}")
confirm "Package contains $(echo "$FILES_IN_TAR" | wc -w) files"
tar xzf "${DL}" rport
tar xzf "${DL}" rport.example.conf
rm -f "${DL}"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: install_bin
# DESCRIPTION: Install a binary located in the temp folder to /usr/local/bin
# PARAMETERS: binary name relative to the temp folder
#----------------------------------------------------------------------------------------------------------------------
install_bin() {
EXEC_BIN=/usr/local/bin/${1}
if [ -e "$EXEC_BIN" ]; then
if [ "$FORCE" -eq 0 ]; then
abort "${EXEC_BIN} already exists. Use -f to overwrite."
fi
fi
mv "${TMP_FOLDER}/${1}" "${EXEC_BIN}"
confirm "${1} installed to ${EXEC_BIN}"
TARGET_VERSION=$(${EXEC_BIN} --version | awk '{print $2}')
confirm "RPort $TARGET_VERSION installed to $EXEC_BIN"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: install_config
# DESCRIPTION: Install an example config located in the temp folder to /etc/rport
# PARAMETERS: config name relative to the temp folder without suffix .example.conf
#----------------------------------------------------------------------------------------------------------------------
install_config() {
test -e "$CONF_DIR" || mkdir "$CONF_DIR"
CONFIG_FILE=${CONF_DIR}/${1}.conf
if [ -e "${CONFIG_FILE}" ]; then
true
elif [ -e "${TMP_FOLDER}/rport.example.conf" ]; then
mv "${TMP_FOLDER}/rport.example.conf" "${CONFIG_FILE}"
else
throw_hint "If you have used the RPort RPM or DEB package previously, remove it first using the package manager."
throw_fatal "No rport.conf file found."
fi
confirm "${CONFIG_FILE} created."
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: create_user
# DESCRIPTION: Create a system user "rport"
#----------------------------------------------------------------------------------------------------------------------
create_user() {
confirm "RPort will run as user ${USER}"
if id "${USER}" >/dev/null 2>&1; then
confirm "User ${USER} already exist."
else
if is_available useradd; then
useradd -r -d /var/lib/rport -m -s /bin/false -U -c "System user for rport client" $USER
elif is_available adduser; then
addgroup rport
adduser -h /var/lib/rport -s /bin/false -G rport -S -D $USER
else
abort "No command found to add a user"
fi
fi
# test -e "$LOG_DIR" || mkdir -p "$LOG_DIR"
# test -e /var/lib/rport/scripts || mkdir -p /var/lib/rport/scripts
# chown "${USER}":root "$LOG_DIR"
# chown "${USER}":root /var/lib/rport/scripts
# chmod 0700 /var/lib/rport/scripts
# chown "${USER}":root "$CONFIG_FILE"
# chmod 0640 "$CONFIG_FILE"
# chown root:root /usr/local/bin/rport
# chmod 0755 /usr/local/bin/rport
}
set_file_and_dir_owner() {
test -e "$LOG_DIR" || mkdir -p "$LOG_DIR"
test -e /var/lib/rport/scripts || mkdir -p /var/lib/rport/scripts
chown "${USER}":root "$LOG_DIR"
chown "${USER}":root /var/lib/rport/scripts
chmod 0700 /var/lib/rport/scripts
chown "${USER}":root "$CONFIG_FILE"
chmod 0640 "$CONFIG_FILE"
if [ -e /usr/local/bin/rport ]; then
chown root:root /usr/local/bin/rport
chmod 0755 /usr/local/bin/rport
fi
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: create_systemd_service
# DESCRIPTION: Install a systemd service file
#----------------------------------------------------------------------------------------------------------------------
create_systemd_service() {
if [ -e /lib/systemd/system/rport.service ]; then
echo "Systemd service already present."
else
echo "Installing systemd service for rport"
test -e /etc/systemd/system/rport.service && rm -f /etc/systemd/system/rport.service
/usr/local/bin/rport --service install --service-user "${USER}" --config /etc/rport/rport.conf
fi
start_rport
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: create_openrc_service
# DESCRIPTION: Install a oprnrc service file
#----------------------------------------------------------------------------------------------------------------------
create_openrc_service() {
echo "Installing openrc service for rport"
cat <<EOF >/etc/init.d/rport
#!/sbin/openrc-run
command="/usr/local/bin/rport"
command_args="-c /etc/rport/rport.conf"
command_user="${USER}"
command_background=true
pidfile=/var/run/rport.pid
EOF
chmod 0755 /etc/init.d/rport
rc-service rport start
rc-update add rport default
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: prepare_server_cofnig
# DESCRIPTION: Make changes to the example config to give the user a better starting point
#----------------------------------------------------------------------------------------------------------------------
prepare_config() {
echo "Preparing $CONFIG_FILE"
sed -i "s|#*server = .*|server = \"${CONNECT_URL}\"|g" "$CONFIG_FILE"
sed -i "s/#*auth = .*/auth = \"${CLIENT_ID}:${PASSWORD}\"/g" "$CONFIG_FILE"
sed -i "s/#*fingerprint = .*/fingerprint = \"${FINGERPRINT}\"/g" "$CONFIG_FILE"
sed -i "s/#*log_file = .*C.*Program Files.*/""/g" "$CONFIG_FILE"
sed -i "s/#*log_file = /log_file = /g" "$CONFIG_FILE"
sed -i "s|#updates_interval = '4h'|updates_interval = '4h'|g" "$CONFIG_FILE"
if [ "$ENABLE_COMMANDS" -eq 1 ]; then
sed -i "s/#allow = .*/allow = ['.*']/g" "$CONFIG_FILE"
sed -i "s/#deny = .*/deny = []/g" "$CONFIG_FILE"
sed -i '/^\[remote-scripts\]/a \ \ enabled = true' "$CONFIG_FILE"
sed -i "s|# script_dir = '/var/lib/rport/scripts'|script_dir = '/var/lib/rport/scripts'|g" "$CONFIG_FILE"
else
sed -i '/^\[remote-commands\]/a \ \ enabled = false' "$CONFIG_FILE"
fi
# Set the hostname.
if grep -Eq "\s+use_hostname = true" "$CONFIG_FILE"; then
# For versions >= 0.5.9
# Just insert an example.
sed -i "s/#name = .*/#name = \"$(get_hostname)\"/g" "$CONFIG_FILE"
else
# Older versions
# Insert a hardcoded name
sed -i "s/#*name = .*/name = \"$(get_hostname)\"/g" "$CONFIG_FILE"
fi
# Set the machine_id
if [ -n "$MACHINE_ID" ]; then
#User wants a hard-coded client id
sed -i "s/.*use_system_id = .*/ use_system_id = false/g" "$CONFIG_FILE"
sed -i "s/#id = .*/id = \"$MACHINE_ID\"/g" "$CONFIG_FILE"
echo "Using a random hard-coded client id not based on /etc/machine-id"
else
if grep -Eq "\s+use_system_id = true" "$CONFIG_FILE" && [ -e /etc/machine-id ]; then
# Versions >= 0.5.9 read it dynamically, nothing to do here
echo "Using /etc/machine-id as rport client id"
else
# Older versions need a hard-coded id in the rport.conf, preferably based on /etc/machine-id
sed -i "s/#id = .*/id = \"$(machine_id)\"/g" "$CONFIG_FILE"
fi
fi
# Activate client attributes
if get_geodata; then
LABELS="\"city\":\"${CITY}\", \"country\":\"${COUNTRY}\""
fi
if [ -n "$XTAG" ]; then
XTAG="\"$XTAG\""
fi
CLIENT_ATTRIBUTES="/var/lib/rport/client_attributes.json"
if [ -e /var/lib/rport ]; then
true
else
mkdir /var/lib/rport
chown "${USER}":root /var/lib/rport
fi
cat <<EOF >$CLIENT_ATTRIBUTES
{
"tags": [${TAGS}],
"labels": { ${LABELS} }
}
EOF
sed -i "s|#attributes_file_path = \"/var/.*|attributes_file_path = \"${CLIENT_ATTRIBUTES}\"|g" "$CONFIG_FILE"
chown "${USER}" "${CLIENT_ATTRIBUTES}"
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: get_hostname
# DESCRIPTION: Try to get the hostname from various sources
#----------------------------------------------------------------------------------------------------------------------
get_hostname() {
hostname -f 2>/dev/null && return 0
hostname 2>/dev/null && return 0
cat /etc/hostname 2>/dev/null && return 0
LANG=en hostnamectl | grep hostname | grep -v 'n/a' | cut -d':' -f2 | tr -d ' '
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: machine_id
# DESCRIPTION: Try to get a unique machine id form different locations.
# Generate one based on the hostname as a fallback.
#----------------------------------------------------------------------------------------------------------------------
machine_id() {
if [ -e /etc/machine-id ]; then
cat /etc/machine-id
return 0
fi
if [ -e /var/lib/dbus/machine-id ]; then
cat /var/lib/dbus/machine-id
return 0
fi
alt_machine_id
}
alt_machine_id() {
ip a | grep ether | md5sum | awk '{print $1}'
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: install_client
# DESCRIPTION: Execute all needed steps to install the rport client
#----------------------------------------------------------------------------------------------------------------------
install_client() {
echo "Installing rport client"
print_distro
if runs_with_selinux && [ "$SELINUX_FORCE" -ne 1 ]; then
echo ""
echo "Your system has SELinux enabled. This installer will not create the needed policies."
echo "Rport will not connect with out the right policies."
echo "Read more https://kb.openrport.io/digging-deeper/advanced-client-management/run-with-selinux"
echo "Excute '$0 ${RAW_ARGS} -l' to skip this warning and install anyways. You must create the polcies later."
exit 1
fi
test_connection
if [ -n "$PKG_URL" ]; then
if is_debian; then
install_from_deb_download
elif is_rhel; then
install_from_rpm_download
else
download_and_extract_from_url
install_bin rport
fi
elif is_debian; then
install_via_deb_repo
elif is_rhel; then
install_via_rpm_repo
else
download_and_extract
install_bin rport
fi
# install_bin rport
create_user
install_config rport
prepare_config
enable_lan_monitoring
detect_interpreters
set_file_and_dir_owner
if is_available openrc; then
create_openrc_service
else
create_systemd_service
fi
create_sudoers_updates
[ "$ENABLE_SUDO" -eq 1 ] && create_sudoers_all
[ "$INSTALL_TACO" -eq 1 ] && install_tacoscript
verify_and_terminate
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: verify_and_terminate
# DESCRIPTION: Verify the installation has succeeded
#----------------------------------------------------------------------------------------------------------------------
verify_and_terminate() {
sleep 1
if pgrep rport >/dev/null 2>&1; then
if check_log; then
finish
return 0
elif [ $? -eq 1 ] && [ "$USE_ALTERNATIVE_MACHINEID" -ne 1 ]; then
USE_ALTERNATIVE_MACHINEID=1
use_alternative_machineid
verify_and_terminate
return 0
fi
fi
fail
}
use_alternative_machineid() {
# If the /etc/machine-id is already used, use an alternative unique id
stop_rport
rm -f "$LOG_FILE"
echo "Creating a unique id based on the mac addresses of the network cards."
sed -i "s/^id = .*/id = \"$(alt_machine_id)\"/g" "$CONFIG_FILE"
start_rport
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: get_geodata
# DESCRIPTION: Retrieve the Country and the city of the currently used public IP address
#----------------------------------------------------------------------------------------------------------------------
get_geodata() {
GEODATA=""
GEOSERVICE_URL="http://ip-api.com/line/?fields=status,country,city"
if is_available curl; then
GEODATA=$(curl -m2 -Ss "${GEOSERVICE_URL}" 2>/dev/null)
else
GEODATA=$(wget --timeout=2 -O - -q "${GEOSERVICE_URL}" 2>/dev/null)
fi
if echo "$GEODATA" | grep -q "^success"; then
CITY="$(echo "$GEODATA" | head -n3 | tail -n1)"
COUNTRY="$(echo "$GEODATA" | head -n2 | tail -n1)"
GEODATA="1"
return 0
else
return 1
fi
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: check_log
# DESCRIPTION: Check the log file for proper operation or common errors
#----------------------------------------------------------------------------------------------------------------------
check_log() {
if [ -e "$LOG_FILE" ]; then
true
else
echo 2>&1 "[!] Logfile $LOG_FILE does not exist."
echo 2>&1 "[!] RPOrt very likely failed to start."
return 4
fi
if grep -q "client id .* is already in use" "$LOG_FILE"; then
echo ""
echo 2>&1 "[!] Configuration error: client id is already in use."
echo 2>&1 "[!] Likely you have systems with an duplicated machine-id in your network."
echo ""
return 1
elif grep -q "Connection error: websocket: bad handshake" "$LOG_FILE"; then
echo ""
echo 2>&1 "[!] Connection error: websocket: bad handshake"
echo "Check if transparent proxies are interfering outgoing http connections."
return 2
elif tac "$LOG_FILE" | grep error; then
return 3
fi
return 0
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: help
# DESCRIPTION: print a help message and exit
#----------------------------------------------------------------------------------------------------------------------
help() {
cat <<EOF
Usage $0 [OPTION(s)]
Options:
-h Print this help message.
-f Force overwriting existing files and configurations.
-t Use the latest unstable version (DANGEROUS!).
-u Uninstall the rport client and all configurations and logs.
-x Enable unrestricted command execution in rport.conf.
-s Create sudo rules to grant full root access to the rport user.
-r Enable file reception. (sending files from server to client)
-b Create sudo rule for file reception to give full filesystem write access. Requires -r.
-a <USER> Use a different user account than 'rport'. Will be created if not present.
-i Install Tacoscript along with the RPort client.
-l Install with SELinux enabled.
-g <TAG> Add an extra tag to the client.
-d Do not use /etc/machine-id to identify this machine. A random UUID will be used instead.
-p Do not use the RPM/DEB repository. Forces tar.gz installation.
-z Download the rport client tar.gz from the given URL instead of using GitHub releases. See environment variables.
Environment variables:
If RPORT_INSTALLER_DL_USERNAME and RPORT_INSTALLER_DL_PASSWORD are set, downloads of custom packages triggered with
'-z' are initiated with HTTP basic authentication.
Learn more https://kb.openrport.io/connecting-clients#advanced-pairing-options
EOF
exit 0
}
#--- FUNCTION -------------------------------------------------------------------------------------------------------
# NAME: finish
# DESCRIPTION: print some information
#----------------------------------------------------------------------------------------------------------------------
finish() {
echo "
#
# Installation of rport finished.
#
# This client is now connected to $SERVER
#
# Look at $CONFIG_FILE and explore all options.
# Logs are written to /var/log/rport/rport.log.
#
# READ THE DOCS ON https://kb.openrport.io/
#
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Give us a star on https://github.com/openrport/openrport
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#
Thanks for using
____ _____ _____ _
/ __ \ | __ \| __ \ | |
| | | |_ __ ___ _ __ | |__) | |__) |__ _ __| |_
| | | | '_ \ / _ \ '_ \| _ /| ___/ _ \| '__| __|
| |__| | |_) | __/ | | | | \ \| | | (_) | | | |_
\____/| .__/ \___|_| |_|_| \_\_| \___/|_| \__|
| |
|_|
"
}
fail() {
echo "
#
# -------------!! ERROR !!-------------
#
# Installation of openrport finished with errors.
#
Try the following to investigate:
1) systemctl rport status
2) tail /var/log/rport/rport.log
3) Ask for help on https://kb.openrport.io/need-help/request-support
"
if runs_with_selinux; then
echo "
4) Check your SELinux settings and create a policy for rport."
fi
}
#----------------------------------------------------------------------------------------------------------------------
# END OF FUNCTION DECLARATION
#----------------------------------------------------------------------------------------------------------------------
#
# Check for prerequisites
#
check_prerequisites
MANDATORY="SERVER FINGERPRINT CLIENT_ID PASSWORD"
for VAR in $MANDATORY; do
if eval "[ -z $${VAR} ]"; then
abort "Variable \$${VAR} not set."
fi
done
#
# Read the command line options and map to a function call
#
RAW_ARGS=$*
ACTION=install_client
ENABLE_COMMANDS=0
ENABLE_SUDO=0
RELEASE=stable
INSTALL_TACO=0
SELINUX_FORCE=0
ENABLE_FILEREC=0
ENABLE_FILEREC_SUDO=0
XTAG=""
NO_REPO=0
while getopts 'phvfcsuxstildrba:g:z:' opt; do
case "${opt}" in
h)
help
exit 0
;;
f) FORCE=1 ;;
v)
echo "$0 -- Version $VERSION"
exit 0
;;
c) ACTION=install_client ;;
u) ACTION=uninstall ;;
x) ENABLE_COMMANDS=1 ;;
s) ENABLE_SUDO=1 ;;
t) RELEASE=unstable ;;
i) INSTALL_TACO=1 ;;
l) SELINUX_FORCE=1 ;;
r) ENABLE_FILEREC=1 ;;
b) ENABLE_FILEREC_SUDO=1 ;;
a) USER=${OPTARG} ;;
g) XTAG=${OPTARG} ;;
z) export PKG_URL="${OPTARG}" ;;
d) MACHINE_ID=$(gen_uuid) ;;
p) NO_REPO=1 ;;
\?)
echo "Option does not exist."
exit 1
;;
esac # --- end of case ---
done
shift $((OPTIND - 1))
prepare # Prepare the system
$ACTION # Execute the function according to the users decision
clean_up # Clean up the system
# END of templates/linux/install.sh ----------------------------------------------------------------------------------|