#!/bin/bash

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

## Runs inside a cowbuilder amd64 chroot. Creates the VirtualBox VM
## (convertfromraw, createvm, storageattach, modifyvm, ...) so that
## 'VBoxManage' does not need to be installed on the build host.
## Invoked by 'build-steps.d/*_create-vbox-vm' via 'cowbuilder --execute'.

set -x
set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
shopt -s inherit_errexit
shopt -s shift_verbose
export LC_ALL=C

true "INFO: Currently running chroot script: ${BASH_SOURCE[0]}"

## Variables arrive through the environment: the '4600_create-vbox-vm' host
## wrapper exports the curated allowlist and invokes `sudo ... cowbuilder`
## with '--preserve-env', so they are carried into this chroot. Fail loud if a
## required one did not make it.
for required_var in \
   VMNAME VMRAM VRAM binary_image_raw_file binary_image_vdi_dir HOMEVAR_VBOX_TEMP \
   SUDO_TO_VBOX_TEMP vm_names_to_be_exported LC_ALL LANG LANGUAGE ; do
   if [ ! -v "${required_var}" ]; then
      printf '%s\n' "ERROR: required variable '${required_var}' not present in the chroot environment." >&2
      exit 1
   fi
done

if [ -n "${dist_source_help_steps_folder:-}" ]; then
   vbox_chroot_shared_file="${dist_source_help_steps_folder}/vbox-chroot-shared"
else
   vbox_chroot_shared_file="$(dirname -- "${BASH_SOURCE[0]}")/vbox-chroot-shared"
fi
# shellcheck source=./vbox-chroot-shared
source "${vbox_chroot_shared_file}"

## Absolute path of the VM disk. It lives under '$binary_image_vdi_dir' (on the
## bind-mounted host build folder), NOT the chroot-local 'dm-vbox-temp' home,
## so the multi-gigabyte disk stays off the small pbuilder chroot filesystem
## and out of 'base.cow'. The VirtualBox registry (persisted into 'base.cow'
## via '--save-after-login') records this absolute path; the same bind mount
## is re-established in the export step, so it resolves there too. See
## 'help-steps/variables' ('binary_image_vdi_dir').
vdi_dir="${binary_image_vdi_dir}/${VMNAME}"
vdi_file="${vdi_dir}/${VMNAME}.vdi"

debugging_pre() {
   qemu-img \
      info \
         "${binary_image_raw_file}"
}

delete_vbox_vm() {
   ## Turning off the VM without saving.
   ${SUDO_TO_VBOX_TEMP} VBoxManage controlvm "${VMNAME}" poweroff || true
   sync

   ## Delete old VM.
   ${SUDO_TO_VBOX_TEMP} VBoxManage unregistervm "${VMNAME}" --delete || true
   sync

   ## The "$SUDO_TO_VBOX_TEMP VBoxManage unregistervm --delete" does not do its job,
   ## we have to manually delete the VM folder (the machine registration, which
   ## 'createvm --register' stores in the 'dm-vbox-temp' default machine folder)
   ## and the VM disk work folder (on the bind-mounted host build folder).
   ${SUDO_TO_ROOT} safe-rm -r -f -- "${HOMEVAR_VBOX_TEMP}/VirtualBox VMs/${VMNAME}"
   ${SUDO_TO_ROOT} safe-rm -r -f -- "${vdi_dir}"
   sync

   ## Delete old ova.
   #$SUDO_TO_ROOT safe-rm -f -- "$binary_image_ova_file"
   #sync
}

convert_raw_to_vdi() {
   ${SUDO_TO_ROOT} mkdir --parents "${vdi_dir}"

   ## Must be deleted for this step to be idempotent. Otherwise
   ## "VBoxManage convertfromraw" would fail.
   ${SUDO_TO_ROOT} safe-rm -f -- "${vdi_file}"

   ## Convert directly from the bind-mounted '$binary_image_raw_file'; no
   ## intermediate multi-gigabyte copy is made. 'convertfromraw' only reads its
   ## source, so run it as root (this script already runs as root; '$SUDO_TO_ROOT'
   ## is empty here, and root reads the bind-mounted raw regardless of its mode).
   ## The output '.vdi' lands on the bind-mounted host build folder (/rw), not
   ## the chroot (dmroot).
   ## TODO: Sequential / non-parallel. Not yet parallelizable builds.
   ${SUDO_TO_ROOT} VBoxManage convertfromraw "${binary_image_raw_file}" "${vdi_file}"

   ## Hand ownership of the per-VM disk folder and its '.vdi' to 'dm-vbox-temp'
   ## so the subsequent 'VBoxManage' calls (which drop to that account to
   ## compact and register the disk) can read/write it. Chown the bind-mount
   ## root itself too, but NON-recursively: making 'dm-vbox-temp' its owner
   ## lets it traverse into the per-VM folder regardless of the host umask on
   ## the mount point, while leaving sibling per-flavor VM folders under it
   ## (e.g. a Gateway folder while building the Workstation) untouched.
   ${SUDO_TO_ROOT} chown -- "dm-vbox-temp:dm-vbox-temp" "${binary_image_vdi_dir}"
   ${SUDO_TO_ROOT} chown --recursive -- "dm-vbox-temp:dm-vbox-temp" "${vdi_dir}"

   ## Debugging.
   ${SUDO_TO_VBOX_TEMP} qemu-img info "${vdi_file}"

   if [ "${dist_build_fast1:-}" = "1" ]; then
      printf '%s\n' "INFO: run with '--fast 1' switch, skipping compacting vdi."
   else
      ${SUDO_TO_VBOX_TEMP} VBoxManage modifymedium --compact "${vdi_file}"
   fi

   ## Debugging.
   ${SUDO_TO_VBOX_TEMP} qemu-img info "${vdi_file}"
}

general_setup() {
   ## Create a new VM. Name: $VMNAME
   ##
   ## The platform architecture is fixed at 'createvm' time and the OS type must
   ## match it, so select both from '$dist_build_target_arch' with an exact
   ## 'case' (a substring test for '64' would misfile 'arm64' as x86-64).
   case "${dist_build_target_arch}" in
      amd64)
         ${SUDO_TO_VBOX_TEMP} VBoxManage createvm --name "${VMNAME}" --register
         ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --ostype Debian_64
         ;;
      arm64)
         ${SUDO_TO_VBOX_TEMP} VBoxManage createvm --name "${VMNAME}" --platform-architecture arm --register
         ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --ostype Debian_arm64
         ## ARM has no legacy BIOS; boot via EFI.
         ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --firmware efi
         ;;
      *)
         error "Unsupported dist_build_target_arch '${dist_build_target_arch}' for VirtualBox VM creation."
         ;;
   esac

   ## SATA AHCI is VirtualBox's default for VMs created using the VirtualBox
   ## graphical user interface (GUI) for Debian 64-bit VMs.
   ##
   ## No longer using `--add sas`, because:
   ## https://forums.whonix.org/t/whonix-virtualbox-failed-to-start-ns-error-failure-0x80004005-the-vm-session-was-aborted/11471
   ## Related:
   ## - https://github.com/Whonix/Whonix/issues/274
   ## - https://www.virtualbox.org/ticket/10031
   ## - https://www.whonix.org/wiki/VirtualBox/Troubleshooting#Failed_to_open_a_session_for_the_virtual_machine
   ##
   ## `--name` is mandatory by `$SUDO_TO_VBOX_TEMP VBoxManage`.
   ## `--name "controller"` is arbitrary. VirtualBox default for VMs created
   ## by VirtualBox GUI would be "Controller: SATA". Keeping it generic to
   ## simplify maybe required later manual user changes.
   ${SUDO_TO_VBOX_TEMP} VBoxManage storagectl "${VMNAME}" --add sata --name "controller"

   ## Only 4 sata ports instead of 30. Speeds up booting.
   ${SUDO_TO_VBOX_TEMP} VBoxManage storagectl "${VMNAME}" --name "controller" --portcount 4

   ## HDD gets added in the gateway / workstation specific functions below.

   ## Attach the HDD.
   ${SUDO_TO_VBOX_TEMP} VBoxManage storageattach "${VMNAME}" --storagectl "controller" --nonrotational=on --discard=on --type hdd --port 0 --medium "${vdi_file}"

   ## RAM
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --memory "${VMRAM}"

   ## Settings->Display->Video Memory
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --vram "${VRAM}"

   ## Enable PAE. x86-only feature.
   ##
   ## TODO: Now that we don't support i386, should we stop setting this option
   ## entirely?
   if [ ! "${dist_build_target_arch}" = "arm64" ]; then
      ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --x86-pae on
   fi

   ## 3 virtual CPU cores by default.
   ## No longer 4 virtual CPU cores by default.
   ## https://www.virtualbox.org/ticket/19500
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --cpus 3

   ## Restrict Boot devices
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --boot4 none
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --boot3 none
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --boot2 none
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --boot1 disk

   ## Hide hosts CPU info. This does not have a GUI option.
   ## Was removed from VirtualBox.
   ## https://phabricator.whonix.org/T408
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --synthcpu on

   ## Quote VirtualBox documentation:
   ##
   ## "[...] Advanced Configuration and Power Interface (ACPI) which VirtualBox
   ## presents to the guest operating system by default. ACPI is the current
   ## industry standard to allow operating systems to recognize hardware,
   ## configure motherboards and other devices and manage power. As all modern
   ## PCs contain this feature and Windows and Linux have been supporting it
   ## for years, it is also enabled by default in VirtualBox. [...]"
   ##
   ## Conclusion: The linux kernel is better tested with ACPI enabled
   ## rather than ACPI disabled.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --acpi on

   ## VirtualBox documentation can be found on:
   ## https://www.virtualbox.org/manual/ch03.html
   ##
   ## Quote VirtualBox documentation:
   ## "[...] Enabling the I/O APIC is required for 64-bit guest operating
   ## systems, especially Windows Vista; it is also required if you want to use
   ## more than one virtual CPU in a virtual machine. [...]"
   ##
   ## Conclusion: it is better to leave it enabled to avoid support requests by
   ## users who wish to use more than one virtual CPU, or create their own
   ## Custom-Whonix-Workstation.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --ioapic on

   ## Set system clock of VM to UTC.
   ## When VirtualBox starts it looks up date and time of the host, i.e. "JAN 15 2012 00:00:00"
   ## and sets the VM clock to that date and time. The following option translates the date
   ## and time to UTC, thus hiding the hosts timezone from the guest.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --rtcuseutc on

   ## Deactivate time synchronization between host and VMs.
   ## This is documented in Whonix Design on TimeSync page
   ## Thanks to
   ## http://www.braingia.org/webnotes/2011/06/22/disable-time-sync-with-virtualbox/
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" "VBoxInternal/Devices/VMMDev/0/Config/GetHostTimeDisabled" "1"

   ## Clipboard sharing.
   ## https://www.whonix.org/wiki/VirtualBox_Guest_Additions#Clipboard_Sharing
   ## Disabled due to security concerns.
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --clipboard-mode bidirectional
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --clipboard-mode disabled

   ## Drag 'n Drop
   ## Disabled due to usability issues. Causes "Drag and Drop operation
   ## failed" popups if the user is dragging something within the VM and the
   ## mouse pointer accidentally leaves the VM window.
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --draganddrop hosttoguest
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --draganddrop disabled

   ## Disable microphones.
   ## https://www.whonix.org/wiki/Hardware_Threat_Minimization#Microphones
   ## was: --audioin off
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --audio-in=off

   ## equivalent to:
   ## VirtualBox -> click a VM -> Settings -> Display -> Graphics Controller -> VMSVGA -> OK
   ##
   ## Quote https://www.virtualbox.org/manual/ch03.html
   ## > "VMSVGA: Use this graphics controller to emulate a VMware SVGA graphics device."
   ## > "This is the default graphics controller for Linux guests."
   ##
   ## - Has better desktop resolution in CLI (virtual terminal) mode.
   ## - functional VirtualBox VM Window -> View -> Virtual Screen 1 -> resize to resolution
   ## - functional VirtualBox VM Window -> View -> Adjust Window Size
   ##
   ## Broken for some users?
   ## https://forums.whonix.org/t/black-screen-on-15-0-0-6-6-and-15-0-0-7-1/8554
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --graphicscontroller vmsvga

   ## Debugging.
   ${SUDO_TO_VBOX_TEMP} VBoxManage getextradata "${VMNAME}"

   ## Quote https://www.virtualbox.org/manual/ch09.html#max-resolution-guests
   ##
   ## > "Configuring the Maximum Resolution of Guests When Using the Graphical Frontend"
   ##
   ## > "When guest systems with the Guest Additions installed are started using the graphical frontend, the normal Oracle VM VirtualBox application, they will not be allowed to use screen resolutions greater than the host's screen size unless the user manually resizes them by dragging the window, switching to full screen or seamless mode or sending a video mode hint using $SUDO_TO_VBOX_TEMP VBoxManage. This behavior is what most users will want, but if you have different needs, you can change it by issuing one of the following commands from the command line:"
   ##
   ## In conclusion, by VirtualBox default the VM screen resolution will not be higher than the
   ## host's screen size. Therefore set to "standard screen resolution 1920x1080".
   ## https://forums.whonix.org/t/consider-making-screen-resolution-1920x1080-by-default-for-all-vms/9143
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" GUI/LastGuestSizeHint "1920, 1080"

   ## Debugging.
   ${SUDO_TO_VBOX_TEMP} VBoxManage getextradata "${VMNAME}"
}

spectre_meltdown_defenses() {
   ## This code is currently not in use! Reasons:
   ## https://www.whonix.org/wiki/Spectre_Meltdown#VirtualBox

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--ibpb-on-vm-[enter|exit] on|off: Enables flushing of the indirect branch prediction buffers on every VM enter or exit respectively. This could be enabled by users overly worried about possible spectre attacks by the VM. Please note that these options may have sever impact on performance."
   ##
   ## There is a mistake in VirtualBox manual saying 'enter' which does not work. It's 'entry'.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --ibpb-on-vm-entry on
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --ibpb-on-vm-exit on

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--l1d-flush-on-vm-enter on|off: Enables flushing of the level 1 data cache on VM enter. See Section 13.4.1, "CVE-2018-3646"."
   ##
   ## There is a mistake in VirtualBox manual saying 'enter' which does not work. It's 'entry'.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --l1d-flush-on-vm-entry on

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--l1d-flush-on-sched on|off: Enables flushing of the level 1 data cache on scheduling EMT for guest execution. See Section 13.4.1, "[https://www.virtualbox.org/manual/ch13.html#sec-rec-cve-2018-3646 CVE-2018-3646]"."
   ## https://www.virtualbox.org/manual/ch13.html#sec-rec-cve-2018-3646
   ## > "For users not concerned by this security issue, the default mitigation can be disabled using
   ##    $SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --l1d-flush-on-sched off"
   ## Since we want to enable the security feature we set '--l1d-flush-on-sched on'.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --l1d-flush-on-sched on

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--spec-ctrl on|off: This setting enables/disables exposing speculation control interfaces to the guest, provided they are available on the host. Depending on the host CPU and workload, enabling speculation control may significantly reduce performance."
   ## According to https://www.virtualbox.org/ticket/17987 '--spec-ctrl' should be set to 'on'.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --spec-ctrl on

   ## https://www.virtualbox.org/manual/ch08.html
   ## > "--nestedpaging on|off: If hardware virtualization is enabled, this additional setting enables or disables the use of the nested paging feature in the processor of your host system; see Section 10.7, "Nested paging and VPIDs" and Section 13.4.1, "CVE-2018-3646"."
   ## https://www.virtualbox.org/manual/ch13.html#sec-rec-cve-2018-3646
   ## > "13.4.1. CVE-2018-3646"
   ##
   ## > "This security issue affects a range of Intel CPUs with nested paging. AMD CPUs are expected not to be impacted (pending direct confirmation by AMD). Also the issue does not affect VMs running with hardware virtualization disabled or with nested paging disabled."
   ##
   ## > "For more information about nested paging, see Section 10.7, "Nested paging and VPIDs"."
   ##
   ## > "Mitigation options:"
   ## > "13.4.1.1. Disable nested paging"
   ##
   ## > "By disabling nested paging (EPT), the VMM will construct page tables shadowing the ones in the guest. It is no possible for the guest to insert anything fishy into the page tables, since the VMM carefully validates each entry before shadowing it."
   ##
   ## > "As a side effect of disabling nested paging, several CPU features will not be made available to the guest. Among these features are AVX, AVX2, XSAVE, AESNI, and POPCNT. Not all guests may be able to cope with dropping these features after installation. Also, for some guests, especially in SMP configurations, there could be stability issues arising from disabling nested paging. Finally, some workloads may experience a performance degradation."
   ##
   ## NOTE: This restricts the CPU instructions to x86_64-v1 level. If the
   ## architecture baseline of Debian is raised, this will need to be undone.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --nestedpaging off
}

hardware_obfuscation() {
   # This code is no longer in use!
   # remove attempts to hide CPU information from VM in VirtualBox
   # https://phabricator.whonix.org/T881
   # It could be enabled through an optional build option if there is interest.

   # Thanks to dumbmouse contributing this!
   # https://phabricator.whonix.org/T408#11595

   # Clear existing (not necessary for initial install)
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --cpuidremoveall

   # GenuineIntel
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/00000000/ebx 0x756e6547
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/00000000/ecx 0x6c65746e
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/00000000/edx 0x49656e69
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000000/ebx 0x756e6547
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000000/ecx 0x6c65746e
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000000/edx 0x49656e69

   # Model/Family/Stepping
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/00000001/eax 0x00000f43
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000001/eax 0x00000f43

   # Pentium model name
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000002/eax 0x20202020
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000002/ebx 0x20202020
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000002/ecx 0x20202020
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000002/edx 0x6e492020
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000003/eax 0x286c6574
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000003/ebx 0x50202952
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000003/ecx 0x69746e65
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000003/edx 0x52286d75
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000004/eax 0x20342029
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000004/ebx 0x20555043
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000004/ecx 0x30302e33
   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" VBoxInternal/CPUM/HostCPUID/80000004/edx 0x007a4847
}

whonix-gateway_specific() {
   ## Disable Audio
   ## was: --audio none
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --audio-driver=none
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --audio-enabled=off

   ## Leave Adapter 1 as NAT.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --nic1 nat

   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --cableconnected1 on

   ## Enable Adapter 2, set to "Internal Network".
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --nic2 intnet

   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --cableconnected2 on

   ## Change the internal network to "Whonix", IMPORTANT!
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --intnet2 "Whonix"
}

whonix-workstation_specific() {
   ## Add Adapter 1, an internal network, IMPORTANT!
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --nic1 intnet

   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --cableconnected1 on

   ## Change the internal network to "Whonix", IMPORTANT!
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --intnet1 "Whonix"
}

whonix-custom-workstation_specific() {
   whonix-workstation_specific

   ## Only for Whonix-Custom-Workstation.
   ## https://forums.whonix.org/t/no-longer-add-virtual-dvd-drive-to-vm-by-default/9337

   ## Add DVD.
   ${SUDO_TO_VBOX_TEMP} VBoxManage storageattach "${VMNAME}" --storagectl "controller" --type dvddrive --port 1 --medium emptydrive

   ${SUDO_TO_VBOX_TEMP} VBoxManage setextradata "${VMNAME}" "GUI/FirstRun" "yes"
}

debian_specific() {
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --nic1 nat

   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --cableconnected1 on
}

audio_enable() {
   ## Enable audio controller.
   ## https://www.kicksecure.com/wiki/Dev/audio
   ##
   ## sb16:
   ## Obsolete.
   ##
   ## ac97:
   ## Older. Issues have been reported:
   ## https://forums.whonix.org/t/choppy-sound-on-workstation-change-virtualbox-audio-settings-to-virtualbox-defaults-ac97-versus-intel-hd/17876
   ## But overall was still better than Intel HD in combination with PipeWire.
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audio-controller=ac97
   ##
   ## hda:
   ## Completely broken in combination with PipeWire.
   ## https://forums.whonix.org/t/virtualbox-intel-hd-audio-and-pipewire-incompatibility-audio-broken-after-increasing-ram-to-5-gb-no-sound-after-latest-updates-pipewire-bug/18211
   ## https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4263
   ## Switching back to Intel HDA as per:
   ## https://forums.whonix.org/t/virtualbox-intel-hd-audio-and-pipewire-incompatibility-audio-broken-after-increasing-ram-to-5-gb-no-sound-after-latest-updates-pipewire-bug/18211/31
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --audio-controller=hda

   ## Host audio driver can be oss, alsa or pulse.
   ## Unfortunately, no auto detection available.
   ## Depends on host driver.
   ## Ubuntu host uses pulse audio.
   #$SUDO_TO_VBOX_TEMP VBoxManage modifyvm "$VMNAME" --audio-driver=pulse

   ## Activate audio output.
   ## According to the manual but does not actually do anything.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --audio-enabled=on
   ## Undocumented but functional.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --audioout on
}

dns_specific() {
   ## https://serverfault.com/questions/453185/vagrant-virtualbox-dns-10-0-2-3-not-working

   ## Prevents leaking DNS info from the host into the guest.
   ## Also useful in other cases.
   ## https://www.virtualbox.org/manual/ch09.html#nat-adv-dns
   ##
   ## '--natdnsproxy1 on' might cause issues:
   ## https://forums.virtualbox.org/viewtopic.php?f=6&t=94671&p=457620#p457620
   ##
   ## Probably not both required 'natdnsproxy1 on' and 'natdnshostresolver1 on'.
   ##
   ## Both enabled at the same time causes an error in VirtualBox VM log:
   ## 00:00:00.933430 NAT: Host Resolver conflicts with DNS proxy, the last one was forcely ignored
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --natdnsproxy1 off

   ## Prevents leaking DNS info from the host into the guest.
   ## Also useful in other cases.
   ## https://www.virtualbox.org/manual/ch09.html#nat_host_resolver_proxy
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --natdnshostresolver1 on

   ## Do not pass the domain name for network name resolution to the VM.
   ${SUDO_TO_VBOX_TEMP} VBoxManage modifyvm "${VMNAME}" --natdnspassdomain1 off
}

debugging_post() {
   ${SUDO_TO_VBOX_TEMP} VBoxManage showvminfo "${VMNAME}"
   ${SUDO_TO_VBOX_TEMP} VBoxManage getextradata "${VMNAME}"
}

main() {
   if [ ! "${dist_build_virtualbox:-}" = "true" ]; then
      printf '%s\n' "INFO: Skipping ${BASH_SOURCE[0]}, because dist_build_virtualbox is not set to 'true'."
      return 0
   fi

   diagnostics_dump

   vbox_stale_ipc_cleanup

   setup_vbox_temp_sudo

   debugging_pre

   delete_vbox_vm

   convert_raw_to_vdi

   general_setup

   ## Possibly not worth it due to huge performance penalty and unclear security benefits. Despite:
   ##
   ##     host microcode upgrade
   ##     host kernel upgrade
   ##     VM kernel upgrade
   ##     spectre-meltdown-checker on the host showing "not vulnerable"
   ##     latest VirtualBox version
   ##     all spectre/meltdown related VirtualBox settings tuned for better security as documented below
   ##
   ## VirtualBox is likely still vulnerable to spectre/meltdown. For reference see VirtualBox bug report / forum discussion.
   ## https://www.whonix.org/wiki/Spectre_Meltdown#VirtualBox
   ## https://www.virtualbox.org/ticket/17987
   ## https://forums.virtualbox.org/viewtopic.php?f=7&t=89395
   ## https://forums.whonix.org/t/whonix-vulerable-due-to-missing-processor-microcode-packages/5739/22
   #spectre_meltdown_defenses

   if [ "${dist_build_type_long:-}" = "gateway" ]; then
      whonix-gateway_specific
      dns_specific
      ## For screen reader support.
      audio_enable
   elif [ "${dist_build_type_long:-}" = "workstation" ]; then
      whonix-workstation_specific
      audio_enable
   elif [ "${dist_build_type_long:-}" = "custom-workstation" ]; then
      whonix-custom-workstation_specific
      audio_enable
   elif [ "${dist_build_type_long:-}" = "whonix-host" ]; then
      debian_specific
      dns_specific
      audio_enable
   elif [ "${dist_build_type_short:-}" = "kicksecure" ]; then
      debian_specific
      audio_enable
   else
      error "Invalid dist_build_flavor '${dist_build_flavor:-}'. Please report this bug!"
   fi

   debugging_post

   ## Safe disk space.
   ## Delete temporary VM in temporary VM user build folder to save disk space
   ## during the build process.
   ## Out-commented.
   ## NOTE: Not possible at this time. The VM will be exported in later step
   ##       prepare-release.
   #delete_vbox_vm

   if [ "${dist_build_raw:-}" = "true" ]; then
      printf '%s\n' "INFO: Skip deletion of raw image because using dist_build_raw=true."
   else
      ## Safe disk space.
      ## Delete no longer needed raw image to save disk space during the build process.
      ## The raw image is bind-mounted from the host, so deleting it from
      ## inside the chroot deletes it on the host too (intentional: matches
      ## the previous host-side behavior).
      ${SUDO_TO_ROOT} safe-rm -f -- "${binary_image_raw_file}"
   fi

   vbox_stale_ipc_cleanup

   sync
}

main "$@"
