#!/usr/bin/sh

# Helper script which sets the root password from several sources
# - ISO file metadata
# - Kernel boot command line
# - Systemd ask password tool
# - Interactively using a dialog
# - Generates a random password as a fallback

MYDIR=$(realpath "$(dirname "$0")")
export DIALOGRC="$MYDIR/../share/live/misc/dialog.conf"

# dialog titles
BTITLE="Live System Configuration (Press Ctrl+L to refresh the screen)"
TITLE="Set Login Password"

# functions for entering the password in an interactive dialog
confirm_exit() {
  # --keep-tite is not a misspelling of "title"
  dialog --keep-tite --backtitle "$BTITLE" --defaultno --yesno "Are you sure you want to cancel?" 5 40
}

msg_box() {
  dialog --keep-tite --backtitle "$BTITLE" --msgbox "$1" 6 30
}

ask_password() {
  # check if user wants dialog password
  if ! grep -q "\blive.password_dialog=1\b" /run/agama/cmdline.d/agama.conf; then
    return
  fi

  if ! PWD1=$(dialog --keep-tite --title "$TITLE" --backtitle "$BTITLE" --stdout --insecure --passwordbox "Password:" 8 40); then
    if confirm_exit; then
      return
    fi

    ask_password
  fi

  if ! PWD2=$(dialog --keep-tite --title "$TITLE" --backtitle "$BTITLE" --stdout --insecure --passwordbox "Verify Password:" 8 40); then
    if confirm_exit; then
      return
    fi
    ask_password
  fi

  if [ "$PWD1" != "$PWD2" ]; then
    msg_box "Passwords do not match.\nPlease try again."
    ask_password
  elif [ -z "$PWD1" ]; then
    msg_box "Password cannot be empty.\nPlease try again."
    ask_password
  else
    echo "$PWD1" | passwd --stdin
  fi

  # clear the terminal
  clear
  # unfortunately it also changes the cursor position, move it back to the last line
  tput cup $(tput lines) 0
}

# functions for entering the password using the "systemd-ask-password" tool
ask_password_systemd() {
  # check if user wants systemd password
  if ! grep -q "\blive.password_systemd=1\b" /run/agama/cmdline.d/agama.conf; then
    return
  fi
  if ! PWD1=$(systemd-ask-password --timeout=0 "Set login password: "); then
    return
  fi

  if ! PWD2=$(systemd-ask-password --timeout=0 "Verify password: "); then
    return
  fi

  if [ "$PWD1" != "$PWD2" ]; then
    echo "Passwords do not match, please try again."
    ask_password_systemd
  elif [ -z "$PWD1" ]; then
    echo "Password cannot be empty, please try again. To skip the password configuration press Ctrl+C."
    ask_password_systemd
  else
    echo "$PWD1" | passwd --stdin
  fi
}

# check if the root password is present in the ISO file metadata
password_from_iso() {
  # get the partition where the live ISO is mounted, the real name is set by the
  # config.sh script which gets the live partition label name from KIWI
  PARTITION=$(blkid -L "@@LIVE_MEDIUM_LABEL@@")

  if [ -z "$PARTITION" ]; then
    echo "Live ISO partition not found, skipping password configuration"
    return
  fi

  # get the parent device name for the partition (/dev/sda2 -> /dev/sda),
  # for some devices just removing the trailing number does not work
  DEVICE=$(lsblk --noheadings --output PKNAME "$PARTITION")

  # if there is no parent device use the device itself (e.g. /dev/sr0)
  if [ -z "$DEVICE" ]; then
    DEVICE="$PARTITION"
  else
    # add the /dev/ prefix
    DEVICE="/dev/$DEVICE"
  fi

  # run tagmedia and extract the password value
  TAG=$(tagmedia "$DEVICE" | grep "^live_password = " | sed -e "s/^live_password = //")

  if [ -z "$TAG" ]; then
    return
  fi

  if PWD=$(echo "$TAG" | base64 -d); then
    usermod -p "$PWD" root
  else
    echo "Base64 decoding of the password failed!"
  fi
}

# generate a random password unless a password is already set
random_password() {
  if grep -q '^root:!\*:' /etc/shadow; then
    echo "Root password not set, generating a random password..."
    # generate a random password, omit symbols and confusing characters to avoid
    # mistakes, the password will be very likely re-typed in a different device
    # so make the password easy to type (it cannot be copy pasted)
    #
    # TODO: check this with the security team
    PASSWD=$((base64 -w 0 < /dev/random | tr -d "+/0OolI1" | head -c 8) 2>/dev/null)

    if [ -n "$PASSWD" ]; then
      echo "$PASSWD" | passwd --stdin
    else
      # uh, the user cannot login now... =:-o
      echo "Failed to generate a password"
      return
    fi

    # display the generated password in the console
    mkdir -p /run/issue.d
    echo "Password for root user: \e{lightcyan}$PASSWD\e{reset}" > /run/issue.d/99-live-password.issue
    # the /etc/issue or /run/issue file must exist to show the issues in console
    # hint: run "agetty --show-issue" to see what will be displayed
    touch /run/issue
  fi
}

password_from_iso

# get the password from the kernel command line. It can contain newlines
PWD=$(grep 'live.password=' < /run/agama/cmdline.d/agama.conf | awk -F 'live.password=' '{sub(/ .*$/, "", $2); print $2}')
if [ -n "$PWD" ]; then
  echo "$PWD" | passwd --stdin
fi

# get the password hash from the kernel command line. It can contain newlines
PWD=$(grep 'live.password_hash=' < /run/agama/cmdline.d/agama.conf | awk -F 'live.password_hash=' '{sub(/ .*$/, "", $2); print $2}')
if [ -n "$PWD" ]; then
  usermod -p "$PWD" root
fi

# set the password interactively (using dialog)
ask_password

# set the password interactively (using systemd)
ask_password_systemd

# fallback to random password if not set
random_password
