#!/bin/bash

# Print a message
echo "* Setup a client to be managed via SSH push"

# Check if we are root
if [ 0$UID -gt 0 ]; then
  echo "ERROR: You need to be root in order to run this!"
  exit 1
fi

# This script's name
ME=`basename $0`

# Print usage instructions
function usage() {
  if [ -n "$1" ] ; then
    echo "$1" >&2
  fi

  echo "USAGE: ${ME} --client <client> [--register <bootstrap_script> [--tunnel]] "
  exit 1
}

# Parse arguments
USE_TUNNEL=""
BOOTSTRAP_ORIG=""
CLIENT=""
VARIABLE=""
while true; do
  case "$1" in
    --client) VARIABLE=CLIENT;;
    --help|-h) usage;;
    --register) VARIABLE=BOOTSTRAP_ORIG;;
    --tunnel) USE_TUNNEL="Y";;
    "") break;;
    *) usage "ERROR: Unknown option $1";;
  esac
  if [ -n "${VARIABLE}" ]; then
    test -z "$2" && usage "ERROR: Option $1 needs an argument"
    eval $VARIABLE=\$2
    shift
    VARIABLE=""
  fi
  shift
done

# A client's hostname or IP address is always required
if [ -z "${CLIENT}" ]; then
  usage "ERROR: A client's hostname or IP is required"
# Tunnel setup requires registration
elif [ "${USE_TUNNEL}" = "Y" ] && [ -z "${BOOTSTRAP_ORIG}" ]; then
  usage "ERROR: Setup with '--tunnel' requires a bootstrap script for registration"
# Check bootstrap script existence
elif [ -n "${BOOTSTRAP_ORIG}" ] && [ ! -f "${BOOTSTRAP_ORIG}" ]; then
  usage "ERROR: Bootstrap script not found: ${BOOTSTRAP_ORIG}"
fi

# Get the server's fully qualified hostname
HOSTNAME=`hostname -f`
if [ ${?} -ne '0' ]; then
  echo "ERROR: SUSE Manager hostname not found (failed to execute 'hostname -f')"
  exit 1
fi

# Read tunnel ports from configuration
PATH_RHN_CONF=/etc/rhn/rhn.conf
PATH_RHN_DEFAULTS=/usr/share/rhn/config-defaults/rhn_web.conf

# Init tunnel setup
if [ "${USE_TUNNEL}" = "Y" ]; then
  # Tunnel port config keys
  PORT_HTTP_KEY=ssh_push_port_http
  PORT_HTTPS_KEY=ssh_push_port_https

  # Check config files existence
  if [ ! -f "${PATH_RHN_CONF}" ]; then
    echo "ERROR: SUSE Manager configuration not found: ${PATH_RHN_CONF}"
    exit 1
  fi
  if [ ! -f "${PATH_RHN_DEFAULTS}" ]; then
    echo "ERROR: SUSE Manager default configuration not found: ${PATH_RHN_DEFAULTS}"
    exit 1
  fi

  # Try /etc/rhn/rhn.conf first, then go to defaults
  PORT_HTTP=$( grep -E -m1 "^${PORT_HTTP_KEY}[[:space:]]*=" ${PATH_RHN_CONF} | sed "s/^${PORT_HTTP_KEY}[[:space:]]*=[[:space:]]*\(.*\)/\1/" || echo "" )
  if [ -z "${PORT_HTTP}" ]; then
    PORT_HTTP=$( grep -E -m1 "^${PORT_HTTP_KEY}[[:space:]]*=" ${PATH_RHN_DEFAULTS} | sed "s/^${PORT_HTTP_KEY}[[:space:]]*=[[:space:]]*\(.*\)/\1/" || echo "" )
  fi

  # Same for HTTPS
  PORT_HTTPS=$( grep -E -m1 "^${PORT_HTTPS_KEY}[[:space:]]*=" ${PATH_RHN_CONF} | sed "s/^${PORT_HTTPS_KEY}[[:space:]]*=[[:space:]]*\(.*\)/\1/" || echo "" )
  if [ -z "${PORT_HTTPS}" ]; then
    PORT_HTTPS=$( grep -E -m1 "^${PORT_HTTPS_KEY}[[:space:]]*=" ${PATH_RHN_DEFAULTS} | sed "s/^${PORT_HTTPS_KEY}[[:space:]]*=[[:space:]]*\(.*\)/\1/" || echo "" )
  fi

  # Exit if we still don't have the ports
  if [ -z "${PORT_HTTP}" -o -z "${PORT_HTTPS}" ]; then
    echo "ERROR: Server push configuration not found, please update."
    exit 1
  fi

  # Generating the enablement script
  ENABLE=`mktemp`
  echo "* Generating tunnel setup script (${ENABLE})"
  echo "if [[ \`grep ^127.0.0.1 /etc/hosts\` != *${HOSTNAME}* ]]; then" >> ${ENABLE}
  echo "sed -i 's/\(127\.0\.0\.1.*\)/& ${HOSTNAME}/' /etc/hosts" >> ${ENABLE}
  echo "fi" >> ${ENABLE}
  # Restart name service caching
  echo "if [ -x '/etc/init.d/nscd' ]; then" >> ${ENABLE}
  echo "/etc/init.d/nscd restart" >> ${ENABLE}
  echo "fi" >> ${ENABLE}
  # Disable osad completely
  echo "if [ -x '/etc/init.d/osad' ]; then" >> ${ENABLE}
  echo "/etc/init.d/osad stop" >> ${ENABLE}
  echo "chkconfig --del osad" >> ${ENABLE}
  echo "fi" >> ${ENABLE}
  # Disable rhnsd completely
  echo "if [ -x '/etc/init.d/rhnsd' ]; then" >> ${ENABLE}
  echo "/etc/init.d/rhnsd stop" >> ${ENABLE}
  echo "chkconfig --del rhnsd" >> ${ENABLE}
  echo "fi" >> ${ENABLE}

  # Create a tunnel version of client-config-overrides.txt
  PATH_OVERRIDES=/srv/www/htdocs/pub/bootstrap/client-config-overrides-tunnel.txt
  echo "* Creating tunnel version of client-config-overrides.txt"
  cp /srv/www/htdocs/pub/bootstrap/client-config-overrides.txt ${PATH_OVERRIDES}
  sed -i "s/\(enableProxy=\).*/\10/" ${PATH_OVERRIDES}
  sed -i "s/\(enableProxyAuth=\).*/\10/" ${PATH_OVERRIDES}
  sed -i "s/\(httpProxy=\).*/\1/" ${PATH_OVERRIDES}
  sed -i "s/\(noSSLServerURL=\).*/\1http:\/\/${HOSTNAME}:${PORT_HTTP}/" ${PATH_OVERRIDES}
  sed -i "s/\(proxyPassword=\).*/\1/" ${PATH_OVERRIDES}
  sed -i "s/\(proxyUser=\).*/\1/" ${PATH_OVERRIDES}
  sed -i "s/\(serverURL=\).*/\1https:\/\/${HOSTNAME}:${PORT_HTTPS}\/XMLRPC/" ${PATH_OVERRIDES}
fi

# ssh-push sudo user
SUDO_USER_KEY=ssh_push_sudo_user

# Same for sudo user
SUDO_USER=$( grep -E -m1 "^${SUDO_USER_KEY}[[:space:]]*=" ${PATH_RHN_CONF} | sed "s/^${SUDO_USER_KEY}[[:space:]]*=[[:space:]]*\(.*\)/\1/" || echo "" )
if [ -z "${SUDO_USER}" ]; then
  SUDO_USER=$( grep -E -m1 "^${SUDO_USER_KEY}[[:space:]]*=" ${PATH_RHN_DEFAULTS} | sed "s/^${SUDO_USER_KEY}[[:space:]]*=[[:space:]]*\(.*\)/\1/" || echo "" )
fi

# Set the sudo command, it'll be blank if no sudo user was set
# Set the user variable, defaults to root if no sudo user is set
if [ -z "${SUDO_USER}" ]; then
  SUDO_CMD=
  USER=root
else
  SUDO_CMD=sudo
  USER=${SUDO_USER}
fi

# Prepare the bootstrap script used for registration
if [ "${USE_TUNNEL}" = "Y" ]; then
  BOOTSTRAP=`mktemp`
  echo "* Preparing bootstrap script (${BOOTSTRAP})"
  cp ${BOOTSTRAP_ORIG} ${BOOTSTRAP}
  sed -i "s/\(CLIENT_OVERRIDES=\).*/\1client-config-overrides-tunnel.txt/" ${BOOTSTRAP}
  sed -i "s/\(HOSTNAME=\).*/\1${HOSTNAME}:${PORT_HTTPS}/" ${BOOTSTRAP}
  sed -i "s/\(HTTP_PUB_DIRECTORY=\).*/\1http:\/\/${HOSTNAME}:${PORT_HTTP}\/pub/" ${BOOTSTRAP}
elif [ -n "${BOOTSTRAP_ORIG}" ]; then
  # Otherwise just use the given file
  BOOTSTRAP=${BOOTSTRAP_ORIG}
fi

# SUSE Manager SSH key comment and identity file
SSH_KEY_COMMENT=susemanager
SSH_IDENTITY=~/.ssh/id_susemanager

# Logfile for this script
LOGFILE=/var/log/rhn/${ME}.log
# set -x
exec > >(tee -a $LOGFILE) 2>&1

# Run key generation if key doesn't exist
if [ ! -f "${SSH_IDENTITY}" ]; then
  echo "* SUSE Manager key not found, generating it (${SSH_IDENTITY})"
  ssh-keygen -q -N '' -C ${SSH_KEY_COMMENT} -f ${SSH_IDENTITY}
else
  echo "* SUSE Manager key found: ${SSH_IDENTITY}"
fi

# Function to cleanup temp files in case a previous command failed
function exit_in_case_of_error() {
  if [ ${?} -ne '0' ]; then
    echo "ERROR: Connection to client (${CLIENT}) failed, exiting..."
    if [ "${USE_TUNNEL}" = "Y" ]; then
      rm -fv ${ENABLE} ${BOOTSTRAP}
    fi
    exit 1
  fi
}

# Remove existing host key entries from known_hosts
echo "* Removing existing host key entries from known_hosts"
if [ -f ~/.ssh/known_hosts ];then
  ssh-keygen -R ${CLIENT}
fi

# Copy public key to the client, require 'ssh-rsa' as host key algorithm
echo "* Pushing SSH key to '${CLIENT}', please login as ${user}:"
ssh-copy-id -o HostKeyAlgorithms=ssh-rsa -i ${SSH_IDENTITY}.pub ${USER}@${CLIENT} 2>&1
exit_in_case_of_error

# Check if sudo exists or if user has sudo access
# Will fail if sudo isn't installed or user doesn't have sudo access
if [ -n "${SUDO_USER}" ]; then
  ssh -i ${SSH_IDENTITY} ${USER}@${CLIENT} 'sudo -v'
  exit_in_case_of_error
fi

# Remove duplicate entries from authorized keys
echo "* Removing duplicate host keys remotely"
AUTH_KEYS=~/.ssh/authorized_keys
AUTH_KEYS2=~/.ssh/authorized_keys2
ssh -i ${SSH_IDENTITY} ${USER}@${CLIENT} "[ -f ${AUTH_KEYS} ] && sed -i \"\\\$!{/${SSH_KEY_COMMENT}/d;}\" ${AUTH_KEYS} && echo 'Cleaned: ${AUTH_KEYS}' || echo 'Skipping: ${AUTH_KEYS} (not found)'"
ssh -i ${SSH_IDENTITY} ${USER}@${CLIENT} "[ -f ${AUTH_KEYS2} ] && sed -i \"\\\$!{/${SSH_KEY_COMMENT}/d;}\" ${AUTH_KEYS2} && echo 'Cleaned: ${AUTH_KEYS2}' || echo 'Skipping: ${AUTH_KEYS2} (not found)'"
exit_in_case_of_error

# Copy scripts to the client
if [ -n "${BOOTSTRAP}" ]; then
  echo "* Pushing scripts to the client"
  if [ "${USE_TUNNEL}" = "Y" ]; then
    scp -i ${SSH_IDENTITY} ${ENABLE} ${USER}@${CLIENT}:enable.sh
    exit_in_case_of_error
  fi
  scp -i ${SSH_IDENTITY} ${BOOTSTRAP} ${USER}@${CLIENT}:bootstrap.sh
  exit_in_case_of_error
fi

# Enablement, registration and cleanup
if [ "${USE_TUNNEL}" = "Y" ]; then
  echo "* Enabling client for SSH Push via tunnel"
  ssh -i ${SSH_IDENTITY} ${USER}@${CLIENT} "${SUDO_CMD} bash enable.sh"
  exit_in_case_of_error

  echo "* Registering client with SUSE Manager: ${CLIENT}"
  ssh -i ${SSH_IDENTITY} -R ${PORT_HTTP}:${HOSTNAME}:80 -R ${PORT_HTTPS}:${HOSTNAME}:443 ${USER}@${CLIENT} "${SUDO_CMD} bash bootstrap.sh"
  exit_in_case_of_error

  echo "* Cleaning up temporary files"
  ssh -i ${SSH_IDENTITY} ${USER}@${CLIENT} "rm -f enable.sh bootstrap.sh client-config-overrides-tunnel.txt client_config_update.py"
  rm -fv ${ENABLE} ${BOOTSTRAP}
elif [ -n "${BOOTSTRAP}" ]; then
  # Simple registration with given bootstrap script
  echo "* Registering client with SUSE Manager: ${CLIENT}"
  ssh -i ${SSH_IDENTITY} ${USER}@${CLIENT} "${SUDO_CMD} bash bootstrap.sh"
  exit_in_case_of_error
fi
