#!/bin/bash

## Copyright (C) 2019 - 2023 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## noexec in /tmp and/or /home can break some malware but also legitimate
## applications.

## https://forums.whonix.org/t/re-mount-home-and-other-with-noexec-and-nosuid-among-other-useful-mount-options-for-better-security/7707

#set -x
set -e
set -o pipefail
set -o nounset

## Not simple with dracut.
# if [ -f /usr/libexec/helper-scripts/pre.bsh ]; then
#    ## pre.bsh would `source` the following folders:
#    ## /etc/remount-secure_pre.d/*.conf
#    ## /usr/local/etc/remount-secure_pre.d/*.conf
#    # shellcheck disable=SC1091
#    source /usr/libexec/helper-scripts/pre.bsh
# fi

if test -o xtrace ; then
   output_command=true
else
   output_command=echo
fi

if [ -e /etc/remount-disable ] || [ -e /usr/local/etc/remount-disable ]; then
   $output_command "INFO: file /etc/remount-disable exists. Doing nothing."
   exit 0
fi

if [ -e /etc/exec ] || [ -e /usr/local/etc/exec ]; then
   noexec=false
   $output_command "INFO: Will remount with exec because file /etc/exec or /usr/local/etc/exec exists."
else
   if [ -e /etc/noexec ] || [ -e /usr/local/etc/noexec ]; then
      noexec=true
      $output_command "INFO: Will remount with noexec because file /etc/noexec or /usr/local/etc/noexec exists."
   else
      $output_command "INFO: Will not remount with noexec because file /etc/noexec or /usr/local/etc/noexec does not exist."
   fi
fi

mkdir --parents "/var/run/remount-secure"

[[ -v noexec ]] || noexec=""
[[ -v noexec_maybe ]] || noexec_maybe=""

if [ "$noexec" = "true" ]; then
   noexec_maybe=",noexec"
fi

exit_code=0

mount_output="$(mount)"

remount_secure() {
   ## ${FUNCNAME[1]} is the name of the calling function. I.e. the function
   ## which called this function.
   status_file_name="${FUNCNAME[1]}"
   ## example status_file_name:
   ## _home
   status_file_full_path="/var/run/remount-secure/${status_file_name}"
   ## example status_file_full_path:
   ## /var/run/remount-secure/_home

   mount_line_of_mount_folder="$(echo "$mount_output" | grep "$mount_folder ")" || true

   if echo "$mount_line_of_mount_folder" | grep --quiet "$new_mount_options" ; then
      $output_command "INFO: $mount_folder has already intended mount options. ($new_mount_options)"
      return 0
   fi

   ## When this package is upgraded, the systemd unit will run again.
   ## If the user meanwhile manually relaxed mount options, this should not be undone.

   if [ "${1:-}" == "--force" ]; then
      if [ -e "$status_file_full_path" ]; then
         $output_command "INFO: $mount_folder already remounted earlier. Not remounting again. Use --force if this is what you want."
         return 0
      fi
   fi

   ## BUG: echo: write error: Broken pipe
   if echo "$mount_output" | grep --quiet "$mount_folder " ; then
      ## Already mounted. Using remount.
      $output_command INFO: Executing: mount -o "remount,${new_mount_options}" "$mount_folder"
      mount -o "remount,${new_mount_options}" "$mount_folder" || exit_code=100
   else
      ## Not yet mounted. Using mount bind.
      $output_command INFO: Executing: mount -o "$new_mount_options" --bind "$mount_folder" "$mount_folder"
      mount -o "$new_mount_options" --bind "$mount_folder" "$mount_folder" || exit_code=101
   fi

   touch "$status_file_full_path"
}

_home() {
   mount_folder="/home"
   new_mount_options="nosuid,nodev${noexec_maybe}"
   remount_secure "$@"
}

_run() {
   mount_folder="/run"
   ## https://lists.freedesktop.org/archives/systemd-devel/2015-February/028456.html
   new_mount_options="nosuid,nodev${noexec_maybe}"
   remount_secure "$@"
}

_dev_shm() {
   mount_folder="/dev/shm"
   new_mount_options="nosuid,nodev${noexec_maybe}"
   remount_secure "$@"
}

_tmp() {
   mount_folder="/tmp"
   new_mount_options="nosuid,nodev${noexec_maybe}"
   remount_secure "$@"
}

## https://forums.whonix.org/t/re-mount-home-and-other-with-noexec-and-nosuid-among-other-useful-mount-options-for-better-security/7707/25
# _lib() {
#    mount_folder="/lib"
#    ## Not using noexec on /lib.
#    new_mount_options="nosuid,nodev"
#    remount_secure "$@"
# }

end() {
   exit $exit_code
}

main() {
   _home "$@"
   _run "$@"
   _dev_shm "$@"
   _tmp "$@"
   #_lib "$@"
   end "$@"
}

main "$@"