#!/bin/bash

## Copyright (C) 2012 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## style-ok: no-strict
## style-ok: allow-errexit-toggle
## Does not use the full strict-mode block by design: it enables errexit only
## to source the msgcollector error_handler, installs an ERR trap, then runs
## with 'set +e' so a failing check reports via the trap instead of aborting
## the whole run (the deliberate global mode switch R-011's waiver exists for).
## nounset is likewise unsafe here -- many optional flag variables are read
## before being set.

## If anyone adds a VPN or something similar to Whonix-Workstation
## (i.e. connection scheme: Whonix-Workstation -> Tor -> VPN), he would wonder
## why it is not detected.

#set -x
set -o errexit
set -o pipefail
set -o errtrace

#trap 'sleep 1' DEBUG

NOTIFY_MSG="Checking System Status...
This will happen in the background and will take approximately three minutes..."

ICON="/usr/share/icons/gnome/24x24/status/info.png"

SCRIPTNAME="$(basename "${BASH_SOURCE[0]}")"
IDENTIFIER="${SCRIPTNAME}"

## Debugging with bashdb.
#IDENTIFIER="systemcheck"

bash -n "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/wc-test.sh
# shellcheck source=../../../../helper-scripts/usr/libexec/helper-scripts/wc-test.sh
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/wc-test.sh

bash -n /usr/libexec/msgcollector/error_handler
# shellcheck source=../../../../msgcollector/usr/libexec/msgcollector/error_handler
source /usr/libexec/msgcollector/error_handler
trap "error_handler" ERR ## /usr/libexec/msgcollector/error_handler
set +e

bash -n "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/light_sleep.bsh
# shellcheck source=../../../../helper-scripts/usr/libexec/helper-scripts/light_sleep.bsh
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/light_sleep.bsh

bash -n /usr/libexec/msgcollector/msgdispatcher_run_check
# shellcheck source=../../../../msgcollector/usr/libexec/msgcollector/msgdispatcher_run_check
source /usr/libexec/msgcollector/msgdispatcher_run_check

bash -n "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/tor_enabled_check
# shellcheck source=../../../../helper-scripts/usr/libexec/helper-scripts/tor_enabled_check
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/tor_enabled_check
bash -n "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/pkg_manager_running_check
# shellcheck source=../../../../helper-scripts/usr/libexec/helper-scripts/pkg_manager_running_check
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/pkg_manager_running_check

bash -n "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/has.bsh
# shellcheck source=../../../../helper-scripts/usr/libexec/helper-scripts/has.bsh
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/has.bsh

## provides: is_whole_number
## provides: br_add
bash -n "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/strings.bsh
# shellcheck source=../../../../helper-scripts/usr/libexec/helper-scripts/strings.bsh
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/strings.bsh

## systemcheck sourced fragments. These are listed explicitly so they can be
## sourced by shellcheck. To update, open a terminal in
## systemcheck/usr/libexec/systemcheck, and run:
##    for i in *.bsh; do
##       printf '%s\n' \
##          "bash -n /usr/libexec/systemcheck/${i}" \
##          "# shellcheck source=./${i}" \
##          "source /usr/libexec/systemcheck/${i}"
##    done
bash -n /usr/libexec/systemcheck/arg_max.bsh
# shellcheck source=./arg_max.bsh
source /usr/libexec/systemcheck/arg_max.bsh
bash -n /usr/libexec/systemcheck/autostart.bsh
# shellcheck source=./autostart.bsh
source /usr/libexec/systemcheck/autostart.bsh
bash -n /usr/libexec/systemcheck/check_anondate.bsh
# shellcheck source=./check_anondate.bsh
source /usr/libexec/systemcheck/check_anondate.bsh
bash -n /usr/libexec/systemcheck/check_apparmor.bsh
# shellcheck source=./check_apparmor.bsh
source /usr/libexec/systemcheck/check_apparmor.bsh
bash -n /usr/libexec/systemcheck/check_apt_repository.bsh
# shellcheck source=./check_apt_repository.bsh
source /usr/libexec/systemcheck/check_apt_repository.bsh
bash -n /usr/libexec/systemcheck/check_audio.bsh
# shellcheck source=./check_audio.bsh
source /usr/libexec/systemcheck/check_audio.bsh
bash -n /usr/libexec/systemcheck/check_control_port_filter.bsh
# shellcheck source=./check_control_port_filter.bsh
source /usr/libexec/systemcheck/check_control_port_filter.bsh
bash -n /usr/libexec/systemcheck/check_debian_eol.bsh
# shellcheck source=./check_debian_eol.bsh
source /usr/libexec/systemcheck/check_debian_eol.bsh
bash -n /usr/libexec/systemcheck/check_dpkg.bsh
# shellcheck source=./check_dpkg.bsh
source /usr/libexec/systemcheck/check_dpkg.bsh
bash -n /usr/libexec/systemcheck/check_entropy.bsh
# shellcheck source=./check_entropy.bsh
source /usr/libexec/systemcheck/check_entropy.bsh
bash -n /usr/libexec/systemcheck/check_environment_variables.bsh
# shellcheck source=./check_environment_variables.bsh
source /usr/libexec/systemcheck/check_environment_variables.bsh
bash -n /usr/libexec/systemcheck/check_full_disk_encryption.bsh
# shellcheck source=./check_full_disk_encryption.bsh
source /usr/libexec/systemcheck/check_full_disk_encryption.bsh
bash -n /usr/libexec/systemcheck/check_grub_security.bsh
# shellcheck source=./check_grub_security.bsh
source /usr/libexec/systemcheck/check_grub_security.bsh
bash -n /usr/libexec/systemcheck/check_hostname.bsh
# shellcheck source=./check_hostname.bsh
source /usr/libexec/systemcheck/check_hostname.bsh
bash -n /usr/libexec/systemcheck/check_initializer.bsh
# shellcheck source=./check_initializer.bsh
source /usr/libexec/systemcheck/check_initializer.bsh
bash -n /usr/libexec/systemcheck/check_ip_forwarding_disabled.bsh
# shellcheck source=./check_ip_forwarding_disabled.bsh
source /usr/libexec/systemcheck/check_ip_forwarding_disabled.bsh
bash -n /usr/libexec/systemcheck/check_kernel_hardening_cmdline.bsh
# shellcheck source=./check_kernel_hardening_cmdline.bsh
source /usr/libexec/systemcheck/check_kernel_hardening_cmdline.bsh
bash -n /usr/libexec/systemcheck/check_login_security.bsh
# shellcheck source=./check_login_security.bsh
source /usr/libexec/systemcheck/check_login_security.bsh
bash -n /usr/libexec/systemcheck/check_logs.bsh
# shellcheck source=./check_logs.bsh
source /usr/libexec/systemcheck/check_logs.bsh
bash -n /usr/libexec/systemcheck/check_man.bsh
# shellcheck source=./check_man.bsh
source /usr/libexec/systemcheck/check_man.bsh
bash -n /usr/libexec/systemcheck/check_network_interfaces.bsh
# shellcheck source=./check_network_interfaces.bsh
source /usr/libexec/systemcheck/check_network_interfaces.bsh
bash -n /usr/libexec/systemcheck/check_nonfree.bsh
# shellcheck source=./check_nonfree.bsh
source /usr/libexec/systemcheck/check_nonfree.bsh
bash -n /usr/libexec/systemcheck/check_operating_system.bsh
# shellcheck source=./check_operating_system.bsh
source /usr/libexec/systemcheck/check_operating_system.bsh
bash -n /usr/libexec/systemcheck/check_package_manager_running.bsh
# shellcheck source=./check_package_manager_running.bsh
source /usr/libexec/systemcheck/check_package_manager_running.bsh
bash -n /usr/libexec/systemcheck/check_packages.bsh
# shellcheck source=./check_packages.bsh
source /usr/libexec/systemcheck/check_packages.bsh
bash -n /usr/libexec/systemcheck/check_privilege_escalation_tool.bsh
# shellcheck source=./check_privilege_escalation_tool.bsh
source /usr/libexec/systemcheck/check_privilege_escalation_tool.bsh
bash -n /usr/libexec/systemcheck/check_pvclock.bsh
# shellcheck source=./check_pvclock.bsh
source /usr/libexec/systemcheck/check_pvclock.bsh
bash -n /usr/libexec/systemcheck/check_qubes.bsh
# shellcheck source=./check_qubes.bsh
source /usr/libexec/systemcheck/check_qubes.bsh
bash -n /usr/libexec/systemcheck/check_secure_boot.bsh
# shellcheck source=./check_secure_boot.bsh
source /usr/libexec/systemcheck/check_secure_boot.bsh
bash -n /usr/libexec/systemcheck/check_services.bsh
# shellcheck source=./check_services.bsh
source /usr/libexec/systemcheck/check_services.bsh
bash -n /usr/libexec/systemcheck/check_spectre_meltdown.bsh
# shellcheck source=./check_spectre_meltdown.bsh
source /usr/libexec/systemcheck/check_spectre_meltdown.bsh
bash -n /usr/libexec/systemcheck/check_stream_isolation.bsh
# shellcheck source=./check_stream_isolation.bsh
source /usr/libexec/systemcheck/check_stream_isolation.bsh
bash -n /usr/libexec/systemcheck/check_su_access.bsh
# shellcheck source=./check_su_access.bsh
source /usr/libexec/systemcheck/check_su_access.bsh
bash -n /usr/libexec/systemcheck/check_systemd_clock.bsh
# shellcheck source=./check_systemd_clock.bsh
source /usr/libexec/systemcheck/check_systemd_clock.bsh
bash -n /usr/libexec/systemcheck/check_system_ready.bsh
# shellcheck source=./check_system_ready.bsh
source /usr/libexec/systemcheck/check_system_ready.bsh
bash -n /usr/libexec/systemcheck/check_timezone.bsh
# shellcheck source=./check_timezone.bsh
source /usr/libexec/systemcheck/check_timezone.bsh
bash -n /usr/libexec/systemcheck/check_tirdad_module.bsh
# shellcheck source=./check_tirdad_module.bsh
source /usr/libexec/systemcheck/check_tirdad_module.bsh
bash -n /usr/libexec/systemcheck/check_tor_bootstrap.bsh
# shellcheck source=./check_tor_bootstrap.bsh
source /usr/libexec/systemcheck/check_tor_bootstrap.bsh
bash -n /usr/libexec/systemcheck/check_tor_config.bsh
# shellcheck source=./check_tor_config.bsh
source /usr/libexec/systemcheck/check_tor_config.bsh
bash -n /usr/libexec/systemcheck/check_tor_enabled.bsh
# shellcheck source=./check_tor_enabled.bsh
source /usr/libexec/systemcheck/check_tor_enabled.bsh
bash -n /usr/libexec/systemcheck/check_tor_running.bsh
# shellcheck source=./check_tor_running.bsh
source /usr/libexec/systemcheck/check_tor_running.bsh
bash -n /usr/libexec/systemcheck/check_tor_socks_or_trans_port.bsh
# shellcheck source=./check_tor_socks_or_trans_port.bsh
source /usr/libexec/systemcheck/check_tor_socks_or_trans_port.bsh
bash -n /usr/libexec/systemcheck/check_tor_socks_port_reachability.bsh
# shellcheck source=./check_tor_socks_port_reachability.bsh
source /usr/libexec/systemcheck/check_tor_socks_port_reachability.bsh
bash -n /usr/libexec/systemcheck/check_unrestricted_mode_in_template.bsh
# shellcheck source=./check_unrestricted_mode_in_template.bsh
source /usr/libexec/systemcheck/check_unrestricted_mode_in_template.bsh
bash -n /usr/libexec/systemcheck/check_user_sysmaint_split.bsh
# shellcheck source=./check_user_sysmaint_split.bsh
source /usr/libexec/systemcheck/check_user_sysmaint_split.bsh
bash -n /usr/libexec/systemcheck/check_virtualizer.bsh
# shellcheck source=./check_virtualizer.bsh
source /usr/libexec/systemcheck/check_virtualizer.bsh
bash -n /usr/libexec/systemcheck/check_warrant_canary.bsh
# shellcheck source=./check_warrant_canary.bsh
source /usr/libexec/systemcheck/check_warrant_canary.bsh
bash -n /usr/libexec/systemcheck/cleanup.bsh
# shellcheck source=./cleanup.bsh
source /usr/libexec/systemcheck/cleanup.bsh
bash -n /usr/libexec/systemcheck/disclaimer.bsh
# shellcheck source=./disclaimer.bsh
source /usr/libexec/systemcheck/disclaimer.bsh
bash -n /usr/libexec/systemcheck/donate.bsh
# shellcheck source=./donate.bsh
source /usr/libexec/systemcheck/donate.bsh
bash -n /usr/libexec/systemcheck/function_manual_run.bsh
# shellcheck source=./function_manual_run.bsh
source /usr/libexec/systemcheck/function_manual_run.bsh
bash -n /usr/libexec/systemcheck/help_cli.bsh
# shellcheck source=./help_cli.bsh
source /usr/libexec/systemcheck/help_cli.bsh
bash -n /usr/libexec/systemcheck/parse_cmd.bsh
# shellcheck source=./parse_cmd.bsh
source /usr/libexec/systemcheck/parse_cmd.bsh
bash -n /usr/libexec/systemcheck/preparation.bsh
# shellcheck source=./preparation.bsh
source /usr/libexec/systemcheck/preparation.bsh
bash -n /usr/libexec/systemcheck/process_killer_helper.bsh
# shellcheck source=./process_killer_helper.bsh
source /usr/libexec/systemcheck/process_killer_helper.bsh
bash -n /usr/libexec/systemcheck/root_check.bsh
# shellcheck source=./root_check.bsh
source /usr/libexec/systemcheck/root_check.bsh
bash -n /usr/libexec/systemcheck/show_versions.bsh
# shellcheck source=./show_versions.bsh
source /usr/libexec/systemcheck/show_versions.bsh
bash -n /usr/libexec/systemcheck/uwt_tool.bsh
# shellcheck source=./uwt_tool.bsh
source /usr/libexec/systemcheck/uwt_tool.bsh

systemcheck_move_progress_bar_to_percent() {
   if [ "${silent}" -ge "3" ]; then
      true "silent is ${silent}. Skipping ${FUNCNAME[0]} $1."
      return 0
   fi
   ${output_x} "${output_opts[@]}" --progressbaridx "${progressbaridx}" --progressx "$1"
}

systemcheck_progress_main_increment() {
   if ! is_whole_number "${PROGRESS_MAIN}"; then
      PROGRESS_MAIN="0"
   fi
   local increment
   increment="$1"
   if ! is_whole_number "${increment}"; then
     exit 1
   fi
   PROGRESS_MAIN="$(( PROGRESS_MAIN + increment ))"
   systemcheck_run_function systemcheck_move_progress_bar_to_percent "${PROGRESS_MAIN}"
}

systemcheck_progress_main_open() {
   ## global progressbaridx
   progressbaridx="$(cat "/proc/sys/kernel/random/uuid")"

   local MSG="${NOTIFY_MSG}"

   if [ "${silent}" -ge "3" ]; then
      true "silent is ${silent}. Skipping progress bar."
      return 0
   fi

   ${output_x} "${output_opts[@]}" --progressbaridx "${progressbaridx}" --progressbarx --parentpid "$$" --progressbartitlex "${TITLE_X}" --message "${MSG}" --done
}

systemcheck_main() {
   ## Default optional flag vars (set only conditionally elsewhere) so the
   ## normal path never reads them while unset.
   [ -v verbose ] || verbose=""
   [ -v CLI ] || CLI=""
   [ -v GUI ] || GUI=""
   [ -v BUG ] || BUG=""
   [ -v deprecated_derivative ] || deprecated_derivative=""
   [ -v systemcheck_skip_functions_cli ] || systemcheck_skip_functions_cli=""
   [ -v systemcheck_ignore_failed_units_cli ] || systemcheck_ignore_failed_units_cli=""
   [ -v systemcheck_journal_ignore_fixed_cli ] || systemcheck_journal_ignore_fixed_cli=""
   [ -v systemcheck_journal_ignore_match_cli ] || systemcheck_journal_ignore_match_cli=""

   ## This MUST be done before parse_cmd_options is called, or systemcheck
   ## may execute arbitrary Bash commands present in the 'verbose' env var.
   if ! is_whole_number "${verbose}"; then
     verbose="0"
   fi

   parse_cmd_options "$@" ## parse_cmd
   preparation ## preparation

   ## uses network: no
   systemcheck_run_function source_config ## preparation

   ## Conditionally only run the function name that was given by the --function
   ## command line parameter. Then exit.
   systemcheck_run_function function_manual_run ## function_manual_run

   ## uses network: no
   systemcheck_run_function root_check ## root_check
   systemcheck_run_function check_login_environment ## preparation
   systemcheck_run_function show_systemcheck_header ## preparation
   systemcheck_run_function input_notification ## preparation

   ## uses network: no
   systemcheck_run_function check_unrestricted_mode_in_template ## check_unrestricted_mode_in_template

   ## uses network: no
   systemcheck_run_function check_system_ready ## check_system_ready

   ## uses network: no
   systemcheck_run_function check_apparmor ## check_apparmor

   ## uses network: no
   systemcheck_run_function check_environment_variables ## check_environment_variables

   ## uses network: no
   systemcheck_run_function check_privleap_group_membership ## check_privilege_escalation_tool
   systemcheck_run_function check_privilege_escalation_tools ## check_privilege_escalation_tool

   ## uses network: no
   systemcheck_run_function show_versions ## show_versions
   systemcheck_run_function show_deprecation_notice ## show_versions

   ## uses network: no
   systemcheck_run_function check_man ## check_man

   ## uses network: no
   systemcheck_run_function check_spectre_meltdown ## check_spectre_meltdown

   ## uses network: no
   systemcheck_run_function check_dpkg ## check_dpkg

   ## uses network: no
   systemcheck_run_function check_services ## check_services

   ## uses network: no
   systemcheck_run_function check_journal ## check_services

   ## uses network: no
   systemcheck_run_function check_network_interfaces ## check_network_interfaces

   ## uses network: no
   systemcheck_run_function check_qubes_settings ## check_qubes

   ## uses network: no
   systemcheck_run_function check_whonix_firewall_systemd_status ## check_services

   ## uses network: no
   ## Own Progress Bar: Yes
   systemcheck_run_function check_package_manager_running ## check_package_manager_running

   ## uses network: no (Runs only on Whonix-Gateway.)
   systemcheck_run_function check_tor_enabled ## check_tor_enabled

   ## uses network: no (Runs only on Whonix-Gateway.)
   systemcheck_run_function check_tor_config ## check_tor_config

   ## uses network: no (Runs only on Whonix-Gateway.)
   systemcheck_run_function check_tor_running ## check_tor_running

   ## uses network: no (Runs only on Whonix-Gateway.)
   systemcheck_run_function check_control_port_filter_running ## check_control_port_filter

   ## uses network: no (Runs only on Whonix-Gateway.)
   systemcheck_run_function check_anondate_show

   ## Only connects to Whonix-Gateway.
   systemcheck_run_function check_tor_socks_port_reachability ## check_tor_socks_port_reachability
   ## Only connects to Whonix-Gateway.
   ## Own Progress Bar: Yes
   systemcheck_run_function check_tor_bootstrap ## check_tor_bootstrap

   systemcheck_run_function systemcheck_progress_main_open

   ## uses network: no
   systemcheck_run_function check_packages ## check_packages
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_initializer ## check_initializer
   systemcheck_progress_main_increment "1"

   ## uses network: no
   ## sets: systemcheck_virtualizer_detected
   systemcheck_run_function check_virtualizer ## check_virtualizer
   systemcheck_progress_main_increment "1"

   ## uses network: no
   ## requires: systemcheck_virtualizer_detected
   systemcheck_run_function check_pvclock ## check_pvclock
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_timezone ## check_timezone
   systemcheck_progress_main_increment "1"

   ## Disabled because of systemd bug.
   ## timedatectl: caches NTP enablement state, better shouldn't
   ## https://github.com/systemd/systemd/issues/1329
   ## uses network: no
   #systemcheck_run_function check_systemd_clock ## check_systemd_clock
   #systemcheck_progress_main_increment "6"

   ## uses network: no (Runs only on Whonix-Gateway.)
   systemcheck_run_function check_ip_forwarding_disabled ## check_ip_forwarding_disabled
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function disclaimer ## disclaimer
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_logs ## check_logs
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_hostname ## check_hostname
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_entropy ## check_entropy
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_audio ## check_audio
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_non_freedom ## check_non_freedom
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_debian_eol ## check_debian_eol
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_user_sysmaint_split ## check_user_sysmaint_split
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_full_disk_encryption ## check_full_disk_encryption
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_grub_security ## check_grub_security
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_kernel_hardening_cmdline ## check_kernel_hardening_cmdline
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_login_security ## check_login_security
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_su_access ## check_su_access
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_secure_boot ## check_secure_boot
   systemcheck_run_function check_build_mok_keys ## check_secure_boot
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_tirdad_module ## check_tirdad_module
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function check_apt_repository ## check_apt_repository
   systemcheck_progress_main_increment "1"

   ## uses network: yes (local network only)
   systemcheck_run_function check_qubes_update_proxy ## check_qubes
   systemcheck_progress_main_increment "3"

   ## uses network: yes
   systemcheck_run_function check_tor_connectivity ## check_tor_socks_or_trans_port
   systemcheck_progress_main_increment "15"

   ## uses network: no
   systemcheck_run_function check_stream_isolation ## check_stream_isolation
   systemcheck_progress_main_increment "15"

   ## uses network: yes
   systemcheck_run_function check_operating_system ## check_operating_system
   systemcheck_progress_main_increment "15"

   ## uses network: no
   systemcheck_run_function check_warrant_canary ## check_warrant_canary.bsh
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function donate ## donate
   systemcheck_progress_main_increment "1"

   ## uses network: no
   systemcheck_run_function cleanup ## cleanup
}

systemcheck_main "$@"

## End of systemcheck script.
