#!/bin/bash

### Include ymclibnettools
. /usr/lib/lib-fliwi/ymc-networktools.bash

minPasswordLength=8
maxPasswordLength=16

if [ $(ymc_is_chroot) -ne 0 ]; then
  echo "WARNING: $0 can not be run inside a chroot..." 1>&2
  exit 0
fi

if [ $(id -u) -ne 0 ]; then
  echo "ERROR: only root can execute $0 ..." 1>&2
  exit 1
fi

### display usage
usage() {
  echo "" 1>&2
  echo "Usage: $0 [--non-interactive] [--force] [-h|--help]" 1>&2
  echo "======" 1>&2
  echo "  Sets a root password. Option --non-interactive is required." 1>&2
  echo "  Properties of the new password are:" 1>&2
  echo "  - password length in the range from $minPasswordLength to $maxPasswordLength characters" 1>&2
  echo "  - at least one capital letter, one number and one special character" 1>&2
  echo "" 1>&2
  echo "  --non-interactive : Set a new password without user interaction." 1>&2
  echo "                      Without option --force no new password will be set," 1>&2
  echo "                      if there already is a password present." 1>&2
  echo "  --force           : Force creation of a new password even if there is" 1>&2
  echo "                      already one." 1>&2
  echo "  -h|--help         : display this help and exit" 1>&2
  echo "" 1>&2
  exit 1
}

### send the pgp encrypted password by mail
send_pgp_encrypted_pw() {
  gpgBin=/usr/bin/gpg
  if [ ! -x $gpgBin ]; then
    echo "PGP binary not found: $gpgBin" 1>&2
    exit 1
  fi

  local ringDir=/etc/fliwi/global/access/gpg
  local gpgRecipientList=""
  local mailRecipientList=""
  local subject="$1"
  local password=$2
  if [ -z "$subject" ] || [ -z "$password" ]; then
    echo "subject and password must not be empty" 1>&2
    exit 1
  fi

  local message="Password: $password"

  temporary_trustdb=/tmp/trustdb.gpg
  temporary_keyring=/tmp/pubring.gpg
  if [ -e "$temporary_trustdb" ]; then
    rm -f $temporary_trustdb
  fi
  if [ -e "$temporary_keyring" ]; then
    rm -f $temporary_keyring
  fi

  # fetch admin addresses and import keyring, if applicable
  for contact in $(fliwi-get-my-human-admins); do
    adminDefaultMail=$(fliwi-get-contact --show-default-email $contact)
    if [ -f $ringDir/$contact.pubring.gpg ]; then
      $gpgBin --homedir /tmp --import $ringDir/$contact.pubring.gpg 2>/dev/null
      gpgRecipientList="${gpgRecipientList} -r $adminDefaultMail"
      mailRecipientList="${mailRecipientList} $adminDefaultMail"
    fi
  done

  # send encrypted mail, if there are valid recipients
  if [ -n "$mailRecipientList" ] && [ -n "$gpgRecipientList" ]; then
    PGPMSG=$(echo "$message" | $gpgBin -n --ignore-time-conflict \
      --no-options --no-default-keyring --secret-keyring /dev/null \
      --trustdb-name $temporary_trustdb --no-auto-check-trustdb \
      --keyring $temporary_keyring --no-random-seed-file --armor \
      --trust-model always -e $gpgRecipientList 2>/dev/null) \
      && echo -e "Subject: $subject\n\n$PGPMSG" | sendmail -t $mailRecipientList
  fi

  # cleanup the temp.files
  rm -f $temporary_keyring $temporary_trustdb 2>/dev/null
}

### generate a new password
generatePassword() {
  local pwLength=10
  local optionString="-c -n -y"
  local calculatedRange=$(($maxPasswordLength-$minPasswordLength))
  ### gather the length of the password being created
  if [ $calculatedRange -ge 0 ]; then
    moduloValue=$(($calculatedRange+1))
    pwLength=$(($RANDOM%$moduloValue+$minPasswordLength))
  fi

  echo $(pwgen $optionString $pwLength 1)
}

###
### "main"
###

### parse command line parameters
TEMP=$(getopt -o h --long force,non-interactive,help -- "$@")
if [ $? != 0 ]; then
  usage
  exit 1
fi
eval set -- "$TEMP"
paramForce=false
paramNonInteractive=false
while true; do
  case "$1" in
    --force ) paramForce=true; shift ;;
    --non-interactive ) paramNonInteractive=true; shift ;;
    -h | --help ) usage;;
    -- ) shift; break ;;
    * ) usage ;;
  esac
done

### check for required parameter '--non-interactive'
if [ "$paramNonInteractive" = "false" ]; then
  echo -e "\nMissing parameter '--non-interactive'. Exiting\n"
  exit 1
fi

### check if a password is already set
hasEmptyPassword=$(passwd -S | awk '{print $2}' | grep -c -e 'NP' -e 'L')
if [ $hasEmptyPassword -eq 0 ]; then
  ### check if the existing password shall be overwritten
  if [ "$paramForce" = "false" ]; then
    echo -e "\nPassword for user root was set already, leaving untouched.\n" 1>&2
    exit 0
  fi
fi

### generate and send new password
NEW_PW=$(generatePassword)
if [ $? -eq 0 ]; then
  echo "root:$NEW_PW" | chpasswd
  if [ $? -eq 0 ]; then
    ### send the new password by mail
    send_pgp_encrypted_pw "new pw on $(hostname)" $NEW_PW
    if [ $? -eq 0 ]; then
      echo "Mail containing the new password has been sent to configured admins." 1>&2
    else
      echo "ERROR: sending mail failed, but password has been changed..." 1>&2
      exit 1
    fi
  else
    echo "ERROR: setting password '$NEW_PW' failed." 1>&2
    exit 1
  fi
else
  echo "ERROR: generating new password failed." 1>&2
  exit 1
fi

exit 0
