V8.00.000.2025.06.17
Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
This commit is contained in:
376
.archive/func/unlock_wrapper.sh
Normal file
376
.archive/func/unlock_wrapper.sh
Normal file
@@ -0,0 +1,376 @@
|
||||
#!/bin/bash
|
||||
# SPDX-Version: 3.0
|
||||
# SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
|
||||
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
|
||||
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
# SPDX-FileType: SOURCE
|
||||
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
|
||||
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
|
||||
# SPDX-PackageName: CISS.debian.installer
|
||||
# SPDX-Security-Contact: security@coresecret.eu
|
||||
# SPDX-Comment: unlock_wrapper.sh to be executed after dropbear SSH login as forced command
|
||||
|
||||
set -Ceuo pipefail
|
||||
IFS=$(printf ' \n\t')
|
||||
|
||||
# shellcheck disable=SC2155
|
||||
declare -gr CURRENTDATE=$(date +"%F %T")
|
||||
declare -gir MAX_RETRIES=2
|
||||
|
||||
#######################################
|
||||
# Generates informative shell prompt.
|
||||
# Globals:
|
||||
# PS1
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
prompt_string() {
|
||||
declare -gx PS1="\
|
||||
\[\033[1;91m\]\d\[\033[0m\]|\[\033[1;91m\]\u\[\033[0m\]@\
|
||||
\[\033[1;95m\]\h\[\033[0m\]:\
|
||||
\[\033[1;96m\]\w\[\033[0m\]/>>\
|
||||
\$(if [[ \$? -eq 0 ]]; then \
|
||||
# Show exit status in green if zero
|
||||
echo -e \"\[\033[1;92m\]\$?\[\033[0m\]\"; \
|
||||
else \
|
||||
# Show exit status in red otherwise
|
||||
echo -e \"\[\033[1;91m\]\$?\[\033[0m\]\"; \
|
||||
fi)\
|
||||
|~\$ "
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Trap function to be called on 'ERR'.
|
||||
# Arguments:
|
||||
# $1: ${?}
|
||||
# $2: ${BASH_SOURCE[0]}
|
||||
# $3: ${LINENO}
|
||||
# $4: ${FUNCNAME[0]:-main}
|
||||
# $5: ${BASH_COMMAND}
|
||||
#######################################
|
||||
trap_on_err() {
|
||||
declare -r errcode="$1"
|
||||
declare -r errscrt="$2"
|
||||
declare -r errline="$3"
|
||||
declare -r errfunc="$4"
|
||||
declare -r errcmmd="$5"
|
||||
trap - ERR
|
||||
stty echo
|
||||
if [[ ${errcode} -eq 0 ]]; then
|
||||
print_scr_scc
|
||||
prompt_string
|
||||
exit 0
|
||||
else
|
||||
print_scr_err "${errcode}" "${errscrt}" "${errline}" "${errfunc}" "${errcmmd}"
|
||||
sleep 15
|
||||
sync
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Security Trap on 'INT' and 'TERM' to provide a deterministic way to not circumvent the Nuke Routine
|
||||
# Globals:
|
||||
# DEVICES_LUKS
|
||||
# DEVICES_NUKE
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
trap_on_term() {
|
||||
trap - INT
|
||||
stty echo
|
||||
printf "\n"
|
||||
printf "\e[0;91m✘ System caught a 'SIGINT'. System Power Off in 3 seconds. \e[0m\n" >&2
|
||||
sync
|
||||
sleep 3
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Print Error Message for 'non-0' Trap on 'EXIT' on Terminal.
|
||||
# Arguments:
|
||||
# $1: ${?}
|
||||
# $2: ${BASH_SOURCE[0]}
|
||||
# $3: ${LINENO}
|
||||
# $4: ${FUNCNAME[0]:-main}
|
||||
# $5: ${BASH_COMMAND}
|
||||
#######################################
|
||||
print_scr_err() {
|
||||
declare -r scr_err_errcode="$1"
|
||||
declare -r scr_err_errscrt="$2"
|
||||
declare -r scr_err_errline="$3"
|
||||
declare -r scr_err_errfunc="$4"
|
||||
declare -r scr_err_errcmmd="$5"
|
||||
printf "\n"
|
||||
printf "\e[0;91m✘ System caught an 'ERROR'. System Power Off in 15 seconds. \e[0m\n" >&2
|
||||
printf "\n"
|
||||
printf "\e[0;91m✘ Error : %s \e[0m\n" "${scr_err_errcode}" >&2
|
||||
printf "\e[0;91m✘ Line : %s \e[0m\n" "${scr_err_errline}" >&2
|
||||
printf "\e[0;91m✘ Script : %s \e[0m\n" "${scr_err_errscrt}" >&2
|
||||
printf "\e[0;91m✘ Function : %s \e[0m\n" "${scr_err_errfunc}" >&2
|
||||
printf "\e[0;91m✘ Command : %s \e[0m\n" "${scr_err_errcmmd}" >&2
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Print Error Message for '0' Trap on 'ERR' on Terminal.
|
||||
# Arguments:
|
||||
# none
|
||||
#######################################
|
||||
print_scr_scc() {
|
||||
printf "\e[0;92m✅ Script exited successfully. Proceeding with booting. \e[0m\n"
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Gather information of all LUKS Devices available on the system
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
gather_luks_devices() {
|
||||
declare prev=() curr=() dev="" tries=0
|
||||
|
||||
while ((tries < 10)); do
|
||||
mapfile -t curr < <(blkid -t TYPE=crypto_LUKS -o device)
|
||||
|
||||
if [[ ${curr[*]} == "${prev[*]}" ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
prev=("${curr[@]}")
|
||||
tries=$((tries + 1))
|
||||
sleep 1
|
||||
done
|
||||
|
||||
### Print one device per line for mapfile compatibility
|
||||
for dev in "${curr[@]}"; do
|
||||
printf '%s\n' "${dev}"
|
||||
done
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Gather information of all NUKE Devices available on the system
|
||||
# Globals:
|
||||
# DEVICES_LUKS
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
gather_nuke_devices() {
|
||||
### 'DEVICES_LUKS' must already be a bash array of device paths
|
||||
declare dev=""
|
||||
declare result=()
|
||||
|
||||
for dev in "${DEVICES_LUKS[@]}"; do
|
||||
### Check slot 31 for 'luks2'
|
||||
if cryptsetup luksDump "${dev}" 2> /dev/null | grep -qE '^[[:space:]]*31: luks2'; then
|
||||
result+=("${dev}")
|
||||
fi
|
||||
done
|
||||
|
||||
### Print one device per line for mapfile compatibility
|
||||
for dev in "${result[@]}"; do
|
||||
printf '%s\n' "${dev}"
|
||||
done
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Read passphrase interactively.
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
passphrase_ask() {
|
||||
declare -g PASSPHRASE=""
|
||||
printf "\n"
|
||||
stty -echo
|
||||
printf "\e[0;95m🔐 Enter passphrase for decryption: \e[0m\n"
|
||||
read -r PASSPHRASE
|
||||
stty echo
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Test the entered passphrase against the dedicated Nuke Keyslot #31.
|
||||
# Arguments:
|
||||
# $1: DEVICE
|
||||
# $2: PASSWD
|
||||
#######################################
|
||||
passphrase_test() {
|
||||
declare -r DEVICE="$1"
|
||||
declare -r PASPHR="$2"
|
||||
printf '%s' "${PASPHR}" | cryptsetup open --batch-mode --test-passphrase --key-slot 31 "${DEVICE}" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Check the integrity and authenticity of this script itself.
|
||||
# Arguments:
|
||||
# $0: Script Name
|
||||
#######################################
|
||||
verify_coresecret() {
|
||||
### Directory of this script
|
||||
# shellcheck disable=SC2155
|
||||
declare dir="$(dirname "$(readlink -f "${0}")")"
|
||||
# shellcheck disable=SC2155
|
||||
declare script="$(basename "${0}")"
|
||||
declare algo
|
||||
|
||||
for algo in sha512 sha384; do
|
||||
# shellcheck disable=SC2155
|
||||
declare hashfile="${dir}/${script}.${algo}"
|
||||
# shellcheck disable=SC2155
|
||||
declare sigfile="${hashfile}.sig"
|
||||
# shellcheck disable=SC2155
|
||||
declare cmd="${algo}sum"
|
||||
|
||||
printf "\e[0;95m🔏 Verifying signature of: [%s] \e[0m\n" "${hashfile}"
|
||||
gpgv --keyring /etc/keys/pubring.gpg "${sigfile}" "${hashfile}" || {
|
||||
printf "\e[0;91m✘ Signature verification failed for: [%s] \e[0m\n" "${hashfile}" >&2
|
||||
printf "\e[0;91m✘ System Power Off in 3 seconds. \e[0m\n" >&2
|
||||
sync
|
||||
sleep 3
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
}
|
||||
printf "\e[0;92m🔏 Verifying signature of: [%s] successful. \e[0m\n" "${hashfile}"
|
||||
|
||||
printf "\e[0;95m🔢 Recomputing Hash: [%s] \e[0m\n" "${algo}"
|
||||
# shellcheck disable=SC2155
|
||||
declare computed=$($cmd "${dir}/${script}" | awk '{print $1}')
|
||||
# shellcheck disable=SC2155
|
||||
declare expected=$(cat "${hashfile}")
|
||||
|
||||
if [[ ${computed} != "${expected}" ]]; then
|
||||
printf "\e[0;91m✘ Hash mismatch for: [%s] \e[0m\n" "${algo}" >&2
|
||||
printf "\e[0;91m✘ System Power Off in 3 seconds. \e[0m\n" >&2
|
||||
sync
|
||||
sleep 3
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
fi
|
||||
printf "\e[0;92m🔢 Recomputing Hash: [%s] successful. \e[0m\n" "${algo}"
|
||||
done
|
||||
|
||||
printf "\e[0;92m🔏 All signatures and hashes verified successfully. Proceeding. \e[0m\n"
|
||||
}
|
||||
|
||||
### Main Programm
|
||||
trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR
|
||||
trap 'trap_on_term' INT TERM
|
||||
|
||||
printf "\e[0;91mCoresecret Connection established.\e[0m\n"
|
||||
printf "\e[0;91mStarting Time: %s\e[0m\n" "${CURRENTDATE}"
|
||||
printf "\n"
|
||||
|
||||
verify_coresecret
|
||||
|
||||
### Read newline-separated output into an array
|
||||
mapfile -t DEVICES_LUKS < <(gather_luks_devices)
|
||||
mapfile -t DEVICES_NUKE < <(gather_nuke_devices)
|
||||
|
||||
### Debug output: list each element with its index
|
||||
#for idx in "${!DEVICES_LUKS[@]}"; do
|
||||
# printf 'Luks[%d]: %s\n' "${idx}" "${DEVICES_LUKS[${idx}]}"
|
||||
#done
|
||||
|
||||
### Debug output: list each element with its index
|
||||
#for idx in "${!DEVICES_NUKE[@]}"; do
|
||||
# printf 'Nuke[%d]: %s\n' "${idx}" "${DEVICES_NUKE[${idx}]}"
|
||||
#done
|
||||
|
||||
### # If there are no LUKS devices at all, drop to bash
|
||||
[[ -n ${DEVICES_LUKS[*]} ]] || {
|
||||
printf "\e[0;92m✘ No LUKS Devices found. Dropping to bash ... \e[0m\n"
|
||||
prompt_string
|
||||
exec /bin/bash -i
|
||||
}
|
||||
|
||||
### If there are LUKS devices but no Nuke devices, try unlocking flow
|
||||
if [[ -n ${DEVICES_LUKS[*]} ]] && [[ -z ${DEVICES_NUKE[*]} ]]; then
|
||||
### Attempt interactive unlock with cryptroot-unlock
|
||||
if cryptroot-unlock; then
|
||||
|
||||
exit 0
|
||||
|
||||
else
|
||||
|
||||
printf "\n"
|
||||
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
|
||||
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
|
||||
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
|
||||
prompt_string
|
||||
exec /bin/bash -i
|
||||
|
||||
fi
|
||||
|
||||
elif [[ -n ${DEVICES_LUKS[*]} ]] && [[ -n ${DEVICES_NUKE[*]} ]]; then
|
||||
|
||||
declare -i attempt=1
|
||||
declare NUKED=false
|
||||
declare TEST_DEV="${DEVICES_NUKE[0]}"
|
||||
|
||||
while ((attempt <= MAX_RETRIES)); do
|
||||
|
||||
printf "\e[0;95m🔐Attempt %s/%s: \e[0m\n" "${attempt}" "${MAX_RETRIES}"
|
||||
|
||||
passphrase_ask
|
||||
declare -g PASSWD="${PASSPHRASE}"
|
||||
|
||||
if passphrase_test "${TEST_DEV}" "${PASSWD}"; then
|
||||
|
||||
for dev in "${DEVICES_NUKE[@]}"; do
|
||||
cryptsetup erase --batch-mode "${dev}" > /dev/null 2>&1
|
||||
printf "%s:\e[0;95m✘ LUKS Device Header malfunction. \e[0m\n" "${dev}"
|
||||
done
|
||||
|
||||
declare -r NUKED=true
|
||||
unset PASSWD
|
||||
break
|
||||
|
||||
else
|
||||
|
||||
declare code="$?"
|
||||
|
||||
case "${code}" in
|
||||
1) printf "\e[0;91m✘ No usable key slot is available. \e[0m\n" ;;
|
||||
2) printf "\e[0;91m✘ No key available with this passphrase. \e[0m\n" ;;
|
||||
3) printf "\e[0;93m✘ Out of memory. \e[0m\n" ;;
|
||||
*) printf "\e[0;91m✘ Unexpected Return Code. \e[0m\n" ;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
attempt=$((attempt + 1))
|
||||
|
||||
done
|
||||
|
||||
if [[ ${NUKED} == true ]]; then
|
||||
stty echo
|
||||
sleep 3
|
||||
sync
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
fi
|
||||
|
||||
if cryptroot-unlock; then
|
||||
|
||||
exit 0
|
||||
|
||||
else
|
||||
|
||||
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
|
||||
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
|
||||
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
|
||||
prompt_string
|
||||
exec /bin/bash -i
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
@@ -24,6 +24,7 @@ recipe:
|
||||
firmware: "UEFI" # MUST be "UEFI" for "gpt" || "BIOS":
|
||||
id: "guben0afx256r" # MUST be equal to the second part of the recipe-variables string.
|
||||
name: "ciss.2025.gpt.btrfs.ephemeral.non-raid.256GiB.rescue"
|
||||
nuke: true # Activates Nuke-Mechanism in '/etc/crypttab' keyscript and via dropbear SSH forced command.
|
||||
raid: # mdadm RAID settings only (not yet supported).
|
||||
enable: false
|
||||
disks:
|
||||
@@ -44,7 +45,6 @@ recipe:
|
||||
enable: false # MUST be "false" for "/boot/efi"
|
||||
ephemeral: false # MUST be "false" for "/boot/efi"
|
||||
integrity: false # MUST be "false" for "/boot/efi"
|
||||
nuke: false # MUST be "false" for "/boot/efi"
|
||||
cipher: ""
|
||||
hash: ""
|
||||
itertime: ""
|
||||
@@ -79,7 +79,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false # MUST be "false" for "/boot"
|
||||
integrity: false # MUST be "false" for "/boot"
|
||||
nuke: true
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -114,7 +113,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false
|
||||
integrity: false
|
||||
nuke: false
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -149,7 +147,6 @@ recipe:
|
||||
enable: true # MUST be "true" for ephemeral "SWAP"
|
||||
ephemeral: true # MUST be "true" for ephemeral "SWAP"
|
||||
integrity: false # MUST be "false" for ephemeral "SWAP"
|
||||
nuke: false # MUST be "false" for ephemeral "SWAP"
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -184,7 +181,6 @@ recipe:
|
||||
enable: true # MUST be "true" for ephemeral "/tmp"
|
||||
ephemeral: true # MUST be "true" for ephemeral "/tmp"
|
||||
integrity: false # MUST be "false" for ephemeral "/tmp"
|
||||
nuke: false # MUST be "false" for ephemeral "/tmp"
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -219,7 +215,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false
|
||||
integrity: false
|
||||
nuke: true
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -254,7 +249,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false
|
||||
integrity: false
|
||||
nuke: true
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -289,7 +283,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false
|
||||
integrity: false
|
||||
nuke: true
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -324,7 +317,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false
|
||||
integrity: false
|
||||
nuke: true
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -359,7 +351,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false
|
||||
integrity: false
|
||||
nuke: true
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -394,7 +385,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false
|
||||
integrity: false
|
||||
nuke: true
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -429,7 +419,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false
|
||||
integrity: false
|
||||
nuke: true
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
@@ -464,7 +453,6 @@ recipe:
|
||||
enable: true
|
||||
ephemeral: false
|
||||
integrity: false
|
||||
nuke: true
|
||||
cipher: "aes-xts-plain64"
|
||||
hash: "sha512"
|
||||
itertime: "3000"
|
||||
|
||||
1
.preseed/password_luks_common.txt
Normal file
1
.preseed/password_luks_common.txt
Normal file
@@ -0,0 +1 @@
|
||||
Ceterum_censeo_Bruxellam_et_Berolinum_delenda_esse!
|
||||
@@ -14,7 +14,7 @@ include_toc: true
|
||||
|
||||
This is an automatically generated overview of the secure ``Centurion Net`` ``CISS.debian.installer`` building system.
|
||||
|
||||

|
||||

|
||||
|
||||
---
|
||||
**[no tracking | no logging | no advertising | no profiling | no bullshit](https://coresecret.eu/)**
|
||||
|
||||
37
docs/graphviz/ciss.debian.installer.bootflow.dot
Normal file
37
docs/graphviz/ciss.debian.installer.bootflow.dot
Normal file
@@ -0,0 +1,37 @@
|
||||
// SPDX-Version: 3.0
|
||||
// SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
// SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
|
||||
// SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
|
||||
// SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
// SPDX-FileType: SOURCE
|
||||
// SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
|
||||
// SPDX-Comment: This file is part of the CISS.debian.installer.secure framework.
|
||||
// SPDX-PackageName: CISS.debian.installer
|
||||
// SPDX-Security-Contact: security@coresecret.eu
|
||||
|
||||
digraph CISS_debian_installer_bootflow {
|
||||
rankdir=LR;
|
||||
node [shape=box, style=filled, fillcolor=lightgray, fontname="Helvetica"];
|
||||
|
||||
Initramfs [label="initramfs boot", fillcolor=lightblue];
|
||||
Crypttab [label="/etc/crypttab", fillcolor=lightblue];
|
||||
CryptrootScript [label="local-top/cryptroot", fillcolor=lightblue];
|
||||
Cryptsetup [label="cryptsetup luksOpen", fillcolor=orange];
|
||||
Keyscript [label="keyscript (e.g. nuke_aware.sh)", fillcolor=yellow];
|
||||
Askpass [label="askpass (console/GUI/Dropbear)", fillcolor=white];
|
||||
NukeCheck [label="if password matches NUKE_HASH → nuke()", fillcolor=red, fontcolor=white];
|
||||
PASSPHRASEOut [label="printf '%s' \"$PASSPHRASE\" + exit 0", fillcolor=green];
|
||||
Decryption [label="LUKS device unlocked", fillcolor=darkgreen, fontcolor=white];
|
||||
RootFS [label="mount /dev/mapper/cryptroot → /", fillcolor=lightblue];
|
||||
|
||||
Initramfs -> Crypttab;
|
||||
Crypttab -> CryptrootScript;
|
||||
CryptrootScript -> Cryptsetup;
|
||||
Cryptsetup -> Keyscript;
|
||||
Keyscript -> Askpass;
|
||||
Askpass -> NukeCheck;
|
||||
NukeCheck -> PASSPHRASEOut [label="if no match"];
|
||||
PASSPHRASEOut -> Cryptsetup [label="stdin"];
|
||||
Cryptsetup -> Decryption;
|
||||
Decryption -> RootFS;
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
// SPDX-PackageName: CISS.debian.installer
|
||||
// SPDX-Security-Contact: security@coresecret.eu
|
||||
|
||||
digraph CISS_debian_live_builder {
|
||||
digraph CISS_debian_installer {
|
||||
// -----------------------------
|
||||
// General settings
|
||||
// -----------------------------
|
||||
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
@@ -44,8 +44,9 @@ yaml_parser() {
|
||||
esac
|
||||
done < "${VAR_PRESEED}"
|
||||
|
||||
sed -i '/^software_[0-9]\+=/d' "${VAR_PRESEED}"
|
||||
sed -i '/^grub_parameter_[0-9]\+=/d' "${VAR_PRESEED}"
|
||||
sed -i '/^ntp_server_[0-9]\+=/d' "${VAR_PRESEED}"
|
||||
sed -i '/^software_[0-9]\+=/d' "${VAR_PRESEED}"
|
||||
|
||||
### Substitute all key= by key=""
|
||||
sed -i -E 's/^(.*)=\s*$/\1=""/' "${VAR_PRESEED}"
|
||||
|
||||
@@ -47,10 +47,10 @@ yaml_reader() {
|
||||
fi
|
||||
done < "${var_if}"
|
||||
|
||||
if [[ -n ${VAR_RECIPE_STRING} ]]; then
|
||||
do_log "info" "false" "Found active recipe string: '${VAR_RECIPE_STRING}'."
|
||||
if [[ -n "${VAR_RECIPE_STRING}" ]]; then
|
||||
do_log "info" "true" "Found active recipe string: '${VAR_RECIPE_STRING}'."
|
||||
else
|
||||
do_log "fatal" "false" "Found NO active recipe string: '${VAR_RECIPE_STRING}'." >&2
|
||||
do_log "fatal" "true" "Found NO active recipe string: '${VAR_RECIPE_STRING}'." >&2
|
||||
exit "${ERR_NO_VALID_RECIPE}"
|
||||
fi
|
||||
|
||||
@@ -79,9 +79,9 @@ END { print max }
|
||||
declare -gx VAR_RECIPE_DEV_COUNTER="${var_highest_dev}"
|
||||
|
||||
if [[ -n ${VAR_RECIPE_DEV_COUNTER} ]]; then
|
||||
do_log "info" "false" "Found highest recipe device: '${VAR_RECIPE_DEV_COUNTER}'."
|
||||
do_log "info" "true" "Found highest recipe device: '${VAR_RECIPE_DEV_COUNTER}'."
|
||||
else
|
||||
do_log "fatal" "false" "Found NO highest recipe device: '${VAR_RECIPE_DEV_COUNTER}'." >&2
|
||||
do_log "fatal" "true" "Found NO highest recipe device: '${VAR_RECIPE_DEV_COUNTER}'." >&2
|
||||
exit "${ERR_NO_VALID_RECIPE}"
|
||||
fi
|
||||
|
||||
@@ -115,6 +115,10 @@ END { print max }
|
||||
do_log "info" "false" "Highest number of partitions for ${var_device}: ${HMP_RECIPE_DEV_PARTITIONS[${var_device}]}"
|
||||
done
|
||||
|
||||
### Extract the chosen Nuke mechanism
|
||||
declare recipe_nuke_var="recipe_${VAR_RECIPE_STRING}_control_nuke"
|
||||
declare -gx VAR_NUKE="${!recipe_nuke_var}"
|
||||
|
||||
### Extract chosen partition table
|
||||
declare recipe_table_var="recipe_${VAR_RECIPE_STRING}_control_table"
|
||||
declare -gx VAR_RECIPE_TABLE="${!recipe_table_var}"
|
||||
|
||||
@@ -34,10 +34,10 @@ partition_encryption() {
|
||||
### Declare Arrays and Variables.
|
||||
declare -Agx HMP_EPHEMERAL_DEV HMP_EPHEMERAL_ENCLABEL HMP_EPHEMERAL_FS_LABEL HMP_PATH_LUKSUUID HMP_PATH_ENCLABEL
|
||||
declare var_dev var_part \
|
||||
var_encryption_enable var_encryption_ephemeral var_encryption_integrity var_encryption_nuke var_encryption_cipher \
|
||||
var_encryption_enable var_encryption_ephemeral var_encryption_integrity var_encryption_cipher \
|
||||
var_encryption_hash var_encryption_iter var_encryption_key var_encryption_label var_encryption_meta \
|
||||
var_encryption_pbkdf var_encryption_rng var_filesystem_label var_mount_path var_uuid
|
||||
declare -a ary_devs ary_parts
|
||||
declare -a ary_devs=() ary_parts=() ary_luks_opts=()
|
||||
|
||||
### Iterate over all devices in the recipe.
|
||||
readarray -t ary_devs < <(yq e -r ".recipe.${VAR_RECIPE_STRING}.dev | keys | .[]" "${VAR_SETUP_PART}")
|
||||
@@ -51,7 +51,6 @@ partition_encryption() {
|
||||
var_encryption_enable=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.enable" "${VAR_SETUP_PART}")
|
||||
var_encryption_ephemeral=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.ephemeral" "${VAR_SETUP_PART}")
|
||||
var_encryption_integrity=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.integrity" "${VAR_SETUP_PART}")
|
||||
var_encryption_nuke=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.nuke" "${VAR_SETUP_PART}")
|
||||
var_encryption_cipher=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.cipher" "${VAR_SETUP_PART}")
|
||||
var_encryption_hash=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.hash" "${VAR_SETUP_PART}")
|
||||
var_encryption_iter=$(yq_val ".recipe.${VAR_RECIPE_STRING}.dev.${var_dev}.${var_part}.encryption.itertime" "${VAR_SETUP_PART}")
|
||||
@@ -67,21 +66,26 @@ partition_encryption() {
|
||||
continue
|
||||
fi
|
||||
|
||||
declare -a ary_luks_opts=(
|
||||
--key-file="${DIR_CNF}/password.txt"
|
||||
--type luks2
|
||||
--cipher "${var_encryption_cipher}"
|
||||
--hash "${var_encryption_hash}"
|
||||
--iter-time "${var_encryption_iter}"
|
||||
--key-size "${var_encryption_key}"
|
||||
--label "${var_encryption_label}"
|
||||
--luks2-metadata-size "${var_encryption_meta}"
|
||||
--pbkdf "${var_encryption_pbkdf}"
|
||||
--"${var_encryption_rng}"
|
||||
--batch-mode --verbose
|
||||
if [[ "${var_mount_path,,}" == "/boot" ]]; then
|
||||
ary_luks_opts=( "--key-file=${DIR_CNF}/password_luks_boot.txt" )
|
||||
else
|
||||
ary_luks_opts=( "--key-file=${DIR_CNF}/password_luks_common.txt" )
|
||||
fi
|
||||
|
||||
ary_luks_opts+=(
|
||||
"--type luks2"
|
||||
"--cipher ${var_encryption_cipher}"
|
||||
"--hash ${var_encryption_hash}"
|
||||
"--iter-time ${var_encryption_iter}"
|
||||
"--key-size ${var_encryption_key}"
|
||||
"--label ${var_encryption_label}"
|
||||
"--luks2-metadata-size ${var_encryption_meta}"
|
||||
"--pbkdf ${var_encryption_pbkdf}"
|
||||
"--${var_encryption_rng}"
|
||||
"--batch-mode --verbose"
|
||||
)
|
||||
|
||||
[[ "${var_encryption_integrity,,}" == "true" ]] && ary_luks_opts+=(--integrity hmac-sha512)
|
||||
[[ "${var_encryption_integrity,,}" == "true" ]] && ary_luks_opts+=( "--integrity hmac-sha512" )
|
||||
|
||||
if [[ "${var_encryption_ephemeral,,}" == "true" ]]; then
|
||||
|
||||
@@ -113,22 +117,28 @@ partition_encryption() {
|
||||
|
||||
if [[ "${var_encryption_integrity,,}" == "true" ]]; then
|
||||
|
||||
do_log "info" "false" "Partition: '/dev/${var_dev}${var_part}' dm-integrity encrypted."
|
||||
do_log "info" "true" "Partition: '/dev/${var_dev}${var_part}' dm-integrity encrypted."
|
||||
|
||||
else
|
||||
|
||||
do_log "info" "false" "Partition: '/dev/${var_dev}${var_part}' encrypted."
|
||||
do_log "info" "true" "Partition: '/dev/${var_dev}${var_part}' encrypted."
|
||||
|
||||
fi
|
||||
|
||||
cryptsetup luksHeaderBackup --header-backup-file="${DIR_BAK}/luks_header_${var_dev}${var_part}.bak" "/dev/${var_dev}${var_part}"
|
||||
do_log "info" "false" "Partition: '/dev/${var_dev}${var_part}' LUKS Header saved: '${DIR_BAK}/luks_header_${var_dev}${var_part}.bak'."
|
||||
do_log "info" "true" "Partition: '/dev/${var_dev}${var_part}' LUKS Header saved: '${DIR_BAK}/luks_header_${var_dev}${var_part}.bak'."
|
||||
|
||||
### Opening encrypted container.
|
||||
if [[ "${var_mount_path,,}" == "/boot" ]]; then
|
||||
cryptsetup luksOpen "/dev/${var_dev}${var_part}" \
|
||||
--key-file="${DIR_CNF}/password.txt" \
|
||||
--key-file="${DIR_CNF}/password_luks_boot.txt" \
|
||||
"${var_encryption_label}"
|
||||
do_log "info" "false" "Partition: '/dev/${var_dev}${var_part}' opened as '/dev/mapper/${var_encryption_label}'."
|
||||
else
|
||||
cryptsetup luksOpen "/dev/${var_dev}${var_part}" \
|
||||
--key-file="${DIR_CNF}/password_luks_common.txt" \
|
||||
"${var_encryption_label}"
|
||||
fi
|
||||
do_log "info" "true" "Partition: '/dev/${var_dev}${var_part}' opened as '/dev/mapper/${var_encryption_label}'."
|
||||
|
||||
### Store UUID of the LUKS container.
|
||||
var_uuid=$(blkid -s UUID -o value "/dev/mapper/${var_encryption_label}")
|
||||
|
||||
@@ -39,6 +39,7 @@ write_crypttab() {
|
||||
# HMP_PATH_ENCLABEL
|
||||
# HMP_PATH_LUKSUUID
|
||||
# TARGET
|
||||
# VAR_NUKE
|
||||
# dropbear_boot
|
||||
# Arguments:
|
||||
# None
|
||||
@@ -49,6 +50,7 @@ generate_crypttab() {
|
||||
declare var_key var_encryption_label var_luks_uuid
|
||||
|
||||
### Generate '${TARGET}/etc/crypttab' header.
|
||||
install -d -m 0755 "${TARGET}/etc"
|
||||
: >| "${TARGET}/etc/crypttab"
|
||||
chmod 0600 "${TARGET}/etc/crypttab"
|
||||
|
||||
@@ -79,6 +81,13 @@ EOF
|
||||
|
||||
if [[ "${dropbear_boot,,}" == "true" ]]; then
|
||||
|
||||
if [[ "${VAR_NUKE,,}" == "true" && "${var_key,,}" == "/" ]]; then
|
||||
|
||||
write_crypttab "${var_encryption_label}" "UUID=${var_luks_uuid}" "none" "luks,discard,initramfs,keyscript=/lib/cryptsetup/scripts/unlock_wrapper.sh"
|
||||
continue
|
||||
|
||||
fi
|
||||
|
||||
write_crypttab "${var_encryption_label}" "UUID=${var_luks_uuid}" "none" "luks,discard,initramfs"
|
||||
|
||||
else
|
||||
@@ -98,14 +107,13 @@ EOF
|
||||
case "${var_key}" in
|
||||
SWAP)
|
||||
write_crypttab "${var_ephemeral_enclabel}" "LABEL=${var_ephemeral_fs_label}" "/dev/random" "swap,offset=2048,cipher=aes-xts-plain64,size=512,sector-size=4096"
|
||||
continue
|
||||
;;
|
||||
/tmp)
|
||||
write_crypttab "${var_ephemeral_enclabel}" "LABEL=${var_ephemeral_fs_label}" "/dev/random" "offset=2048,cipher=aes-xts-plain64,size=512,sector-size=4096,tmp=ext4"
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
do_log "error" "false" "Only 'SWAP' and '/tmp' are valid Partitions for Ephemeral Encryption. Given value was: '${var_key}'."
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
@@ -58,16 +58,16 @@ setup_network() {
|
||||
declare -a ary_ipv4_ns ary_ipv6_ns
|
||||
|
||||
ary_ipv4_ns+=("${network_static_ipv4nameserver_0}")
|
||||
[[ -v "${network_static_ipv4nameserver_1}" ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_1}")
|
||||
[[ -v "${network_static_ipv4nameserver_2}" ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_2}")
|
||||
[[ -v "${network_static_ipv4nameserver_fallback_0}" ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_fallback_0}")
|
||||
[[ -v "${network_static_ipv4nameserver_fallback_1}" ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_fallback_1}")
|
||||
[[ -v network_static_ipv4nameserver_1 ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_1}")
|
||||
[[ -v network_static_ipv4nameserver_2 ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_2}")
|
||||
[[ -v network_static_ipv4nameserver_fallback_0 ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_fallback_0}")
|
||||
[[ -v network_static_ipv4nameserver_fallback_1 ]] && ary_ipv4_ns+=("${network_static_ipv4nameserver_fallback_1}")
|
||||
|
||||
ary_ipv6_ns+=("${network_static_ipv6nameserver_0}")
|
||||
[[ -v "${network_static_ipv6nameserver_1}" ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_1}")
|
||||
[[ -v "${network_static_ipv6nameserver_2}" ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_2}")
|
||||
[[ -v "${network_static_ipv6nameserver_fallback_0}" ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_fallback_0}")
|
||||
[[ -v "${network_static_ipv6nameserver_fallback_1}" ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_fallback_1}")
|
||||
[[ -v network_static_ipv6nameserver_1 ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_1}")
|
||||
[[ -v network_static_ipv6nameserver_2 ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_2}")
|
||||
[[ -v network_static_ipv6nameserver_fallback_0 ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_fallback_0}")
|
||||
[[ -v network_static_ipv6nameserver_fallback_1 ]] && ary_ipv6_ns+=("${network_static_ipv6nameserver_fallback_1}")
|
||||
|
||||
### Check current network connection and configure variables
|
||||
var_auto_nic=$(ip -o link show | awk -F': ' '/state UP/ && $2!="lo" {print $2; exit}')
|
||||
|
||||
@@ -118,7 +118,7 @@ GRUB_BACKGROUND="/etc/default/grub.d/${var_background}"
|
||||
# The resolution used on graphical terminal
|
||||
# note that you can use only modes which your graphic card supports via VBE
|
||||
# you can see them in real GRUB with the command 'vbeinfo'
|
||||
GRUB_GFXMODE=1920x1080,1280x1024,800x600
|
||||
GRUB_GFXMODE=1920x1080,1280x1024,1024x768,800x600
|
||||
GRUB_GFXPAYLOAD_LINUX=keep
|
||||
|
||||
EOF
|
||||
@@ -166,6 +166,11 @@ EOF
|
||||
|
||||
[[ "${var_update_grub_required}" == "true" ]] && do_in_target "${TARGET}" update-grub
|
||||
|
||||
### Setting the permissions to read and write for root only prevents non-root users from seeing the boot parameters or changing them.
|
||||
chown root:root "${TARGET}/boot/grub/grub.cfg"
|
||||
chmod 0600 "${TARGET}/boot/grub/grub.cfg"
|
||||
chmod -R 0700 "${TARGET}/etc/grub.d"
|
||||
|
||||
return 0
|
||||
}
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
|
||||
95
func/4155_setup_grub_password.sh
Normal file
95
func/4155_setup_grub_password.sh
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/bin/bash
|
||||
# SPDX-Version: 3.0
|
||||
# SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
|
||||
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
|
||||
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
# SPDX-FileType: SOURCE
|
||||
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
|
||||
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
|
||||
# SPDX-PackageName: CISS.debian.installer
|
||||
# SPDX-Security-Contact: security@coresecret.eu
|
||||
|
||||
guard_sourcing
|
||||
|
||||
#######################################
|
||||
# Append GRUB superuser block to 40_custom.
|
||||
# Arguments:
|
||||
# 1: Username
|
||||
# 2: Password
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Append GRUB superuser block to '/etc/grub.d/40_custom'.
|
||||
# Globals:
|
||||
# DIR_CNF
|
||||
# ERR_READ_GRUB_FILE
|
||||
# TARGET
|
||||
# VAR_DEBUG_TRACE
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_READ_GRUB_FILE
|
||||
#######################################
|
||||
setup_grub_password() {
|
||||
declare var_username="superadmin"
|
||||
declare var_password=""
|
||||
declare var_password_file="${DIR_CNF}/password_grub.txt"
|
||||
declare var_of="${TARGET}/etc/grub.d/40_custom"
|
||||
declare var_grub_entry
|
||||
|
||||
### No tracing for security reasons
|
||||
[[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set +x
|
||||
if [[ ! -f "${var_password_file}" ]] || ! IFS= read -r var_password < "${var_password_file}"; then
|
||||
return "${ERR_READ_GRUB_FILE}"
|
||||
fi
|
||||
### Turn on tracing again
|
||||
[[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set -x
|
||||
|
||||
var_grub_entry=$(generate_grub_password_pbkdf2 "${var_username}" "${var_password}")
|
||||
|
||||
### Append if not already present
|
||||
if ! grep -q "set superusers=" "${var_of}"; then
|
||||
{
|
||||
echo ""
|
||||
echo "### Added by CISS.debian.installer ###"
|
||||
echo "$var_grub_entry"
|
||||
echo "### End by CISS.debian.installer ###"
|
||||
} >> "$var_of"
|
||||
fi
|
||||
|
||||
do_in_target "${TARGET}" update-grub
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Generate PBKDF2 password hash for GRUB.
|
||||
# Arguments:
|
||||
# 1: Username (default to superadmin).
|
||||
# 2: User password.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
generate_grub_password_pbkdf2() {
|
||||
declare var_user="${1:-superadmin}"
|
||||
declare var_pass="${2:?error: password required}"
|
||||
|
||||
expect <<EOF
|
||||
log_user 0
|
||||
spawn grub-mkpasswd-pbkdf2
|
||||
expect "Enter password:"
|
||||
send "$var_pass\r"
|
||||
expect "Reenter password:"
|
||||
send "$var_pass\r"
|
||||
expect {
|
||||
-re {PBKDF2 hash of your password is (\S+)} {
|
||||
puts "set superusers=\"$var_user\"\npassword_pbkdf2 $var_user \$expect_out(1,string)"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
return 0
|
||||
}
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
@@ -27,7 +27,7 @@ guard_sourcing
|
||||
# 0: on success
|
||||
#######################################
|
||||
setup_grub_bootparameter() {
|
||||
declare var_param
|
||||
declare var_nuke_string="" var_param=""
|
||||
|
||||
grub_extract_current_string
|
||||
|
||||
@@ -47,6 +47,11 @@ setup_grub_bootparameter() {
|
||||
|
||||
done
|
||||
|
||||
if [[ "${VAR_NUKE}" == "true" ]]; then
|
||||
var_nuke_string="nuke=${VAR_NUKE_HASH}"
|
||||
VAR_GRUB_CMDLINE_LINUX+=" ${var_nuke_string}"
|
||||
fi
|
||||
|
||||
grub_finalize_string
|
||||
|
||||
do_in_target "${TARGET}" update-grub
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
# SPDX-PackageName: CISS.debian.installer
|
||||
# SPDX-Security-Contact: security@coresecret.eu
|
||||
|
||||
### Options in "GRUB_CMDLINE_LINUX" are always effective.
|
||||
### Options in "GRUB_CMDLINE_LINUX_DEFAULT" are effective ONLY during normal boot (NOT during recovery mode).
|
||||
|
||||
guard_sourcing
|
||||
|
||||
#######################################
|
||||
@@ -28,6 +25,13 @@ setup_kernel_modules() {
|
||||
### Entropy collection improvements
|
||||
mkdir -p "${TARGET}/usr/lib/modules-load.d"
|
||||
cat << EOF >| "${TARGET}/usr/lib/modules-load.d/30_security-misc.conf"
|
||||
## The jitterentropy_rng kernel module provides a reliable and hardware-independent source of cryptographic entropy by measuring
|
||||
## minute variations in CPU execution timing (jitter). These microsecond-level differences are unpredictable and rooted in
|
||||
## physical randomness, making them suitable for high-quality entropy generation. Unlike other RNG methods that rely on hardware
|
||||
## features like TPMs or Intel's RDRAND—which may not be available or trusted—jitterentropy_rng works across all platforms,
|
||||
## including virtual machines and air-gapped systems. It is compliant with NIST SP 800-90B and BSI TR-02102-4, ensuring secure
|
||||
## entropy even during early boot stages, such as in initramfs or before full userland is available. It is the most secure,
|
||||
## standards-compliant, and universally applicable entropy source for hardened Linux environments.
|
||||
## https://www.whonix.org/wiki/Dev/Entropy
|
||||
## https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=927972
|
||||
## https://forums.whonix.org/t/jitterentropy-rngd/7204
|
||||
@@ -37,4 +41,21 @@ EOF
|
||||
do_log "info" "true" "Installed: '/usr/lib/modules-load.d/30_security-misc.conf'."
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Blacklist some kind of potential hazardous modules via '/etc/modprobe.d/0000_ciss_debian_installer.conf'.
|
||||
# Globals:
|
||||
# TARGET
|
||||
# VAR_SETUP_PATH
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
setup_modprobe() {
|
||||
install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/etc/modprobe.d/0000_ciss_debian_installer.cnf" \
|
||||
"${TARGET}/etc/modprobe.d/0000_ciss_debian_installer.conf"
|
||||
do_log "info" "true" "Installed: '/etc/modprobe.d/0000_ciss_debian_installer.conf'."
|
||||
return 0
|
||||
}
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
# SPDX-PackageName: CISS.debian.installer
|
||||
# SPDX-Security-Contact: security@coresecret.eu
|
||||
|
||||
### Options in "GRUB_CMDLINE_LINUX" are always effective.
|
||||
### Options in "GRUB_CMDLINE_LINUX_DEFAULT" are effective ONLY during normal boot (NOT during recovery mode).
|
||||
|
||||
guard_sourcing
|
||||
|
||||
#######################################
|
||||
|
||||
@@ -53,9 +53,9 @@ setup_dropbear() {
|
||||
### Prepare dropbear authorized_keys
|
||||
declare -a ary_user=()
|
||||
ary_user+=("${user_root_ssh_pubkeys_0}")
|
||||
[[ -v "${user_root_ssh_pubkeys_1}" ]] && ary_user+=("${user_root_ssh_pubkeys_1}")
|
||||
[[ -v "${user_root_ssh_pubkeys_2}" ]] && ary_user+=("${user_root_ssh_pubkeys_2}")
|
||||
[[ -v "${user_root_ssh_pubkeys_3}" ]] && ary_user+=("${user_root_ssh_pubkeys_3}")
|
||||
[[ -v user_root_ssh_pubkeys_1 ]] && ary_user+=("${user_root_ssh_pubkeys_1}")
|
||||
[[ -v user_root_ssh_pubkeys_2 ]] && ary_user+=("${user_root_ssh_pubkeys_2}")
|
||||
[[ -v user_root_ssh_pubkeys_3 ]] && ary_user+=("${user_root_ssh_pubkeys_3}")
|
||||
|
||||
touch "${TARGET}/etc/dropbear/initramfs/authorized_keys" && chmod 0600 "${TARGET}/etc/dropbear/initramfs/authorized_keys"
|
||||
printf "%s\n" "${ary_user[@]}" > "${TARGET}/etc/dropbear/initramfs/authorized_keys"
|
||||
@@ -106,6 +106,8 @@ setup_dropbear() {
|
||||
### Install the script to be called inside initramfs environment for unlocking LUKS and NUKE Devices.
|
||||
install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/unlock_wrapper.sh" \
|
||||
"${TARGET}/includes/initramfs-tools/files/"
|
||||
install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/unlock_wrapper.sh" \
|
||||
"${TARGET}/usr/lib/cryptsetup/scripts/"
|
||||
|
||||
### Install the script to be called inside Host environment for signing 'unlock_wrapper.sh'-script.
|
||||
install -D -m 0700 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/unlock_wrapper_signer.sh" \
|
||||
@@ -131,7 +133,7 @@ EOF
|
||||
|
||||
### Install the variable file to be called inside initramfs environment for setting up dropbear firewall.
|
||||
install -D -m 0600 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/dropbear_fw.cnf" \
|
||||
"${TARGET}/includes/initramfs-tools/files/"
|
||||
"${TARGET}/includes/initramfs-tools/files/dropbear_fw.conf"
|
||||
|
||||
### Install the firewall script to be called inside initramfs environment for setting up dropbear firewall.
|
||||
install -D -m 0755 -o root -g root "${VAR_SETUP_PATH}/includes/initramfs-tools/files/dropbear_fw.sh" \
|
||||
@@ -169,6 +171,8 @@ EOF
|
||||
# 0: on success
|
||||
#######################################
|
||||
write_dropbear_conf() {
|
||||
[[ -z "${dropbear_port:-}" ]] && dropbear_port="2222"
|
||||
|
||||
cat << EOF >| "${TARGET}/etc/dropbear/initramfs/dropbear.conf"
|
||||
#
|
||||
# Configuration options for the dropbear-initramfs boot scripts.
|
||||
@@ -185,7 +189,7 @@ write_dropbear_conf() {
|
||||
# -K: Keepalive interval in seconds
|
||||
# -p: Specify port (and optionally address)
|
||||
# -w: Disable root login (SHOULD NOT be implemented for initramfs)
|
||||
DROPBEAR_OPTIONS="-b /etc/dropbear/initramfs/banner -c /usr/local/bin/unlock_wrapper.sh -E -I 300 -K 60 -p ${dropbear_port:-2222}"
|
||||
DROPBEAR_OPTIONS="-b /etc/dropbear/banner -c /usr/local/bin/unlock_wrapper.sh -E -I 300 -K 60 -p ${dropbear_port}"
|
||||
|
||||
#
|
||||
# On local (non-NFS) mounts, interfaces matching this pattern are
|
||||
|
||||
124
includes/etc/modprobe.d/0000_ciss_debian_installer.cnf
Normal file
124
includes/etc/modprobe.d/0000_ciss_debian_installer.cnf
Normal file
@@ -0,0 +1,124 @@
|
||||
# SPDX-Version: 3.0
|
||||
# SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
|
||||
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
|
||||
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
# SPDX-FileType: SOURCE
|
||||
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
|
||||
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
|
||||
# SPDX-PackageName: CISS.debian.installer
|
||||
# SPDX-Security-Contact: security@coresecret.eu
|
||||
|
||||
### Version Master V8.03.864.2025.07.15
|
||||
|
||||
# The kernel allows unprivileged users to indirectly cause certain modules to be loaded via module auto-loading. This allows an
|
||||
# attacker to auto-load a vulnerable module which is then exploited. One such example is CVE-2017-6074, in which an attacker
|
||||
# could trigger the DCCP kernel module to be loaded by initiating a DCCP connection and then exploit a vulnerability in said
|
||||
# kernel module. Specific kernel modules can be blacklisted by inserting files into '/etc/modprobe.d' with instructions on which
|
||||
# kernel modules to blacklist.
|
||||
|
||||
##### Disable Uncommon Network Protocols #####
|
||||
|
||||
install dccp /bin/true
|
||||
install sctp /bin/true
|
||||
install rds /bin/true
|
||||
install tipc /bin/true
|
||||
install n-hdlc /bin/true
|
||||
install ax25 /bin/true
|
||||
install netrom /bin/true
|
||||
install x25 /bin/true
|
||||
install rose /bin/true
|
||||
install decnet /bin/true
|
||||
install econet /bin/true
|
||||
install af_802154 /bin/true
|
||||
install ipx /bin/true
|
||||
install appletalk /bin/true
|
||||
install psnap /bin/true
|
||||
install p8023 /bin/true
|
||||
install p8022 /bin/true
|
||||
install can /bin/true
|
||||
install atm /bin/true
|
||||
|
||||
# DCCP Datagram Congestion Control Protocol
|
||||
# SCTP Stream Control Transmission Protocol
|
||||
# RDS Reliable Datagram Sockets
|
||||
# TIPC Transparent Inter-process Communication
|
||||
# HDLC High-Level Data Link Control
|
||||
# AX25 Amateur X.25
|
||||
# NetRom
|
||||
# X25
|
||||
# ROSE
|
||||
# DECnet
|
||||
# Econet
|
||||
# af_802154 IEEE 802.15.4
|
||||
# IPX Internetwork Packet Exchange
|
||||
# AppleTalk
|
||||
# PSNAP Subnetwork Access Protocol
|
||||
# p8023 Novell raw IEEE 802.3
|
||||
# p8022 IEEE 802.2
|
||||
# CAN Controller Area Network
|
||||
# ATM
|
||||
|
||||
|
||||
##### Disable Uncommon Filesystems #####
|
||||
install cramfs /bin/true
|
||||
install freevxfs /bin/true
|
||||
install jffs2 /bin/true
|
||||
install hfs /bin/true
|
||||
install hfsplus /bin/true
|
||||
install squashfs /bin/true
|
||||
install udf /bin/true
|
||||
|
||||
blacklist cramfs
|
||||
blacklist freevxfs
|
||||
blacklist jffs2
|
||||
blacklist hfs
|
||||
blacklist hfsplus
|
||||
blacklist squashfs
|
||||
blacklist udf
|
||||
|
||||
|
||||
##### Disable Uncommon Network Filesystems #####
|
||||
install cifs /bin/true
|
||||
install nfs /bin/true
|
||||
install nfsv3 /bin/true
|
||||
install nfsv4 /bin/true
|
||||
install ksmbd /bin/true
|
||||
install gfs2 /bin/true
|
||||
|
||||
blacklist cifs
|
||||
blacklist nfs
|
||||
blacklist nfsv3
|
||||
blacklist nfsv4
|
||||
blacklist ksmbd
|
||||
blacklist gfs2
|
||||
|
||||
|
||||
# The vivid driver is only useful for testing purposes and has been the cause of privilege escalation vulnerabilities, so it should be disabled.
|
||||
install vivid /bin/true
|
||||
|
||||
|
||||
##### Disable access to USB #####
|
||||
install usb_storage /bin/true
|
||||
blacklist usb-storage
|
||||
|
||||
|
||||
##### Disable access to IEEE1394 #####
|
||||
install firewire-core /bin/true
|
||||
|
||||
|
||||
##### Blacklist automatic loading of miscellaneous modules #####
|
||||
##### https://git.launchpad.net/ubuntu/+source/kmod/tree/debian/modprobe.d/blacklist.conf?h=ubuntu/disco #####
|
||||
# evbug is a debug tool that should be loaded explicitly
|
||||
blacklist evbug
|
||||
# these drivers are very simple
|
||||
blacklist usbmouse
|
||||
blacklist usbkbd
|
||||
# causes no end of confusion by creating unexpected network interfaces
|
||||
blacklist eth1394
|
||||
# ugly and loud noise, getting on everyone's nerves
|
||||
blacklist pcspkr
|
||||
|
||||
# Descriptions partly Copyright (c) 2022 madaidan, https://madaidans-insecurities.github.io/index.html
|
||||
# Descriptions partly Copyright https://git.launchpad.net/ubuntu/+source/kmod/tree/debian/modprobe.d/blacklist.conf?h=ubuntu/disco
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=conf
|
||||
@@ -9,14 +9,184 @@
|
||||
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
|
||||
# SPDX-PackageName: CISS.debian.installer
|
||||
# SPDX-Security-Contact: security@coresecret.eu
|
||||
# SPDX-Comment: unlock_wrapper.sh to be executed after dropbear SSH login as forced command
|
||||
# SPDX-Comment: unlock_wrapper.sh to be executed as '/etc/crypttab' keyscript and as dropbear SSH forced command.
|
||||
|
||||
set -Ceuo pipefail
|
||||
IFS=$(printf ' \n\t')
|
||||
|
||||
#######################################
|
||||
# Variable declaration
|
||||
#######################################
|
||||
declare -r ASKPASS='/lib/cryptsetup/askpass'
|
||||
declare -r REGEX='^\$[a-z0-9]+\$[./A-Za-z0-9]+\$[./A-Za-z0-9]+$'
|
||||
# shellcheck disable=SC2155
|
||||
declare -gr CURRENTDATE=$(date +"%F %T")
|
||||
declare -gir MAX_RETRIES=2
|
||||
declare -r CURRENTDATE=$(date +"%F %T")
|
||||
declare -r GRE='\e[0;92m'
|
||||
declare -r MAG='\e[0;95m'
|
||||
declare -r RED='\e[0;91m'
|
||||
declare -r RES='\e[0m'
|
||||
declare -r NL='\n'
|
||||
declare -g NUKE_ENABLED='false'
|
||||
declare -g NUKE_HASH=''
|
||||
declare -g PASSPHRASE=''
|
||||
|
||||
#######################################
|
||||
# Print-colored text.
|
||||
# Arguments:
|
||||
# 1: Color code.
|
||||
# *: Text to print.
|
||||
#######################################
|
||||
color_echo() { declare c="$1"; shift; declare msg="${*}"; printf "%s%s %s%s" "${c}" "${msg}" "${RES}" "${NL}"; }
|
||||
|
||||
#######################################
|
||||
# Die helper: print and exit hard.
|
||||
# Globals:
|
||||
# NC
|
||||
# RED
|
||||
# Arguments:
|
||||
# 1: Message string to print.
|
||||
#######################################
|
||||
die() { printf "%s✘ %s%s\n" "${RED}" "$1" "${RES}" >&2; power_off 3; }
|
||||
|
||||
#######################################
|
||||
# Drop to bash environment.
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
drop_bash() { stty echo; prompt_string; exec /bin/bash -i; }
|
||||
|
||||
#######################################
|
||||
# Extract the 'nuke='-parameter from '/proc/cmdline'.
|
||||
# Globals:
|
||||
# NUKE_ENABLED
|
||||
# NUKE_HASH
|
||||
# RED
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0: if 'nuke=' was found and extracted.
|
||||
# 1: if not found.
|
||||
#######################################
|
||||
extract_nuke_hash() {
|
||||
declare ARG="" CMDLINE=""
|
||||
|
||||
### Read '/proc/cmdline' into a single line safely.
|
||||
read -r CMDLINE < /proc/cmdline
|
||||
for ARG in ${CMDLINE}; do
|
||||
case "${ARG}" in
|
||||
nuke=*)
|
||||
NUKE_HASH="${ARG#nuke=}"
|
||||
if [[ "${NUKE_HASH}" =~ ${REGEX} ]]; then
|
||||
NUKE_ENABLED="true"
|
||||
return 0
|
||||
else
|
||||
### If there is a malformed Grub Bootparameter 'nuke=HASH', drop to bash.
|
||||
color_echo "${RED}" "✘ Nuke Hash Malformat : [${REGEX}] [${NUKE_HASH}]." >&2
|
||||
color_echo "${RED}" "✘ Dropping to bash ...:" >&2
|
||||
drop_bash
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
### No 'nuke=HASH' entry found.
|
||||
return 1
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Gather information of all LUKS Devices available on the system.
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
gather_luks_devices() {
|
||||
declare prev=() curr=()
|
||||
declare -i tries=0
|
||||
|
||||
while ((tries < 10)); do
|
||||
|
||||
mapfile -t curr < <(blkid -t TYPE=crypto_LUKS -o device | sort)
|
||||
|
||||
if cmp <(printf '%s\n' "${curr[@]}") <(printf '%s\n' "${prev[@]}") >/dev/null; then
|
||||
break
|
||||
fi
|
||||
|
||||
prev=("${curr[@]}")
|
||||
tries=$((tries + 1))
|
||||
sleep 1
|
||||
|
||||
done
|
||||
|
||||
printf '%s\n' "${curr[@]}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Erase LUKS headers on all LUKS devices and shutdown system.
|
||||
# Globals:
|
||||
# DEVICES_LUKS
|
||||
# RED
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
nuke() {
|
||||
declare dev=""
|
||||
for dev in "${DEVICES_LUKS[@]}"; do
|
||||
cryptsetup erase --batch-mode "${dev}" || true
|
||||
color_echo "${RED}" "✘ Error: LUKS Device Header malfunction: [${dev}]."
|
||||
done
|
||||
secure_unset_pass
|
||||
color_echo "${RED}" "✘ Error: LUKS Device malfunction. System Power Off in 16 seconds."
|
||||
power_off 16
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Unified power-off routine.
|
||||
# Arguments:
|
||||
# 1: Sleep time before power-off in seconds (Default to 0 seconds).
|
||||
#######################################
|
||||
power_off() {
|
||||
declare -r wait="${1:-0}"
|
||||
sleep "${wait}"
|
||||
sync
|
||||
echo 1 >| /proc/sys/kernel/sysrq
|
||||
echo o >| /proc/sysrq-trigger
|
||||
### The System powers off immediately; no further code is executed.
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Print Error Message for Trap on 'ERR' on Terminal.
|
||||
# Globals:
|
||||
# NL
|
||||
# RED
|
||||
# Arguments:
|
||||
# 1: ${?}
|
||||
# 2: ${BASH_SOURCE[0]}
|
||||
# 3: ${LINENO}
|
||||
# 4: ${FUNCNAME[0]:-main}
|
||||
# 5: ${BASH_COMMAND}
|
||||
#######################################
|
||||
print_scr_err() {
|
||||
declare -r scr_err_errcode="$1"
|
||||
declare -r scr_err_errscrt="$2"
|
||||
declare -r scr_err_errline="$3"
|
||||
declare -r scr_err_errfunc="$4"
|
||||
declare -r scr_err_errcmmd="$5"
|
||||
printf "%s" "${NL}"
|
||||
color_echo "${RED}" "✘ System caught an 'ERROR'. System Power Off in 16 seconds." >&2
|
||||
printf "%s" "${NL}"
|
||||
color_echo "${RED}" "✘ Error : [${scr_err_errcode}]" >&2
|
||||
color_echo "${RED}" "✘ Line : [${scr_err_errline}]" >&2
|
||||
color_echo "${RED}" "✘ Script : [${scr_err_errscrt}]" >&2
|
||||
color_echo "${RED}" "✘ Function : [${scr_err_errfunc}]" >&2
|
||||
color_echo "${RED}" "✘ Command : [${scr_err_errcmmd}]" >&2
|
||||
printf "%s" "${NL}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Print Error Message for '0'-Exit-Code on Terminal.
|
||||
# Globals:
|
||||
# GRE
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
print_scr_scc() { color_echo "${GRE}" "✅ Script exited successfully. Proceeding with booting."; }
|
||||
|
||||
#######################################
|
||||
# Generates informative shell prompt.
|
||||
@@ -40,14 +210,56 @@ fi)\
|
||||
|~\$ "
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Read Passphrase interactively.
|
||||
# Globals:
|
||||
# ASKPASS
|
||||
# NUKE_ENABLED
|
||||
# NUKE_HASH
|
||||
# PASSPHRASE
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
read_passphrase() {
|
||||
declare -a METHODS=("sha512crypt" "yescrypt" "scrypt" "bcrypt")
|
||||
declare METHOD="" SALT=""
|
||||
|
||||
PASSPHRASE="$(${ASKPASS} "Enter passphrase: ")"
|
||||
|
||||
if [[ "${NUKE_ENABLED,,}" == 'true' ]]; then
|
||||
### Validate NUKE_HASH format (e.g., $id$salt$hash)
|
||||
if [[ "${NUKE_HASH}" =~ ${REGEX} ]]; then
|
||||
SALT="$(cut -d'$' -f3 <<< "${NUKE_HASH}")"
|
||||
for METHOD in "${METHODS[@]}"; do
|
||||
if mkpasswd -m "${METHOD}" -S "${SALT}" "${PASSPHRASE}" 2>/dev/null | grep -qF -- "${NUKE_HASH}"; then
|
||||
nuke
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Securely unset the passphrase variable.
|
||||
# Globals:
|
||||
# PASSPHRASE
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
secure_unset_pass() { unset PASSPHRASE; PASSPHRASE=""; }
|
||||
|
||||
#######################################
|
||||
# Trap function to be called on 'ERR'.
|
||||
# Arguments:
|
||||
# $1: ${?}
|
||||
# $2: ${BASH_SOURCE[0]}
|
||||
# $3: ${LINENO}
|
||||
# $4: ${FUNCNAME[0]:-main}
|
||||
# $5: ${BASH_COMMAND}
|
||||
# 1: ${?}
|
||||
# 2: ${BASH_SOURCE[0]}
|
||||
# 3: ${LINENO}
|
||||
# 4: ${FUNCNAME[0]:-main}
|
||||
# 5: ${BASH_COMMAND}
|
||||
#######################################
|
||||
trap_on_err() {
|
||||
declare -r errcode="$1"
|
||||
@@ -55,322 +267,127 @@ trap_on_err() {
|
||||
declare -r errline="$3"
|
||||
declare -r errfunc="$4"
|
||||
declare -r errcmmd="$5"
|
||||
trap - ERR
|
||||
trap - ERR INT TERM
|
||||
stty echo
|
||||
if [[ ${errcode} -eq 0 ]]; then
|
||||
print_scr_scc
|
||||
prompt_string
|
||||
exit 0
|
||||
else
|
||||
print_scr_err "${errcode}" "${errscrt}" "${errline}" "${errfunc}" "${errcmmd}"
|
||||
sleep 15
|
||||
sync
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
fi
|
||||
power_off 16
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Security Trap on 'INT' and 'TERM' to provide a deterministic way to not circumvent the Nuke Routine
|
||||
# Security Trap on 'INT' and 'TERM' to provide a deterministic way to not circumvent the nuke routine.
|
||||
# Globals:
|
||||
# DEVICES_LUKS
|
||||
# DEVICES_NUKE
|
||||
# NL
|
||||
# RED
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
trap_on_term() {
|
||||
trap - INT
|
||||
trap - ERR INT TERM
|
||||
stty echo
|
||||
printf "\n"
|
||||
printf "\e[0;91m✘ System caught a 'SIGINT'. System Power Off in 3 seconds. \e[0m\n" >&2
|
||||
sync
|
||||
sleep 3
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Print Error Message for 'non-0' Trap on 'EXIT' on Terminal.
|
||||
# Arguments:
|
||||
# $1: ${?}
|
||||
# $2: ${BASH_SOURCE[0]}
|
||||
# $3: ${LINENO}
|
||||
# $4: ${FUNCNAME[0]:-main}
|
||||
# $5: ${BASH_COMMAND}
|
||||
#######################################
|
||||
print_scr_err() {
|
||||
declare -r scr_err_errcode="$1"
|
||||
declare -r scr_err_errscrt="$2"
|
||||
declare -r scr_err_errline="$3"
|
||||
declare -r scr_err_errfunc="$4"
|
||||
declare -r scr_err_errcmmd="$5"
|
||||
printf "\n"
|
||||
printf "\e[0;91m✘ System caught an 'ERROR'. System Power Off in 15 seconds. \e[0m\n" >&2
|
||||
printf "\n"
|
||||
printf "\e[0;91m✘ Error : %s \e[0m\n" "${scr_err_errcode}" >&2
|
||||
printf "\e[0;91m✘ Line : %s \e[0m\n" "${scr_err_errline}" >&2
|
||||
printf "\e[0;91m✘ Script : %s \e[0m\n" "${scr_err_errscrt}" >&2
|
||||
printf "\e[0;91m✘ Function : %s \e[0m\n" "${scr_err_errfunc}" >&2
|
||||
printf "\e[0;91m✘ Command : %s \e[0m\n" "${scr_err_errcmmd}" >&2
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Print Error Message for '0' Trap on 'ERR' on Terminal.
|
||||
# Arguments:
|
||||
# none
|
||||
#######################################
|
||||
print_scr_scc() {
|
||||
printf "\e[0;92m✅ Script exited successfully. Proceeding with booting. \e[0m\n"
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Gather information of all LUKS Devices available on the system
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
gather_luks_devices() {
|
||||
declare prev=() curr=() dev="" tries=0
|
||||
|
||||
while ((tries < 10)); do
|
||||
mapfile -t curr < <(blkid -t TYPE=crypto_LUKS -o device)
|
||||
|
||||
if [[ ${curr[*]} == "${prev[*]}" ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
prev=("${curr[@]}")
|
||||
tries=$((tries + 1))
|
||||
sleep 1
|
||||
done
|
||||
|
||||
### Print one device per line for mapfile compatibility
|
||||
for dev in "${curr[@]}"; do
|
||||
printf '%s\n' "${dev}"
|
||||
done
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Gather information of all NUKE Devices available on the system
|
||||
# Globals:
|
||||
# DEVICES_LUKS
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
gather_nuke_devices() {
|
||||
### 'DEVICES_LUKS' must already be a bash array of device paths
|
||||
declare dev=""
|
||||
declare result=()
|
||||
|
||||
for dev in "${DEVICES_LUKS[@]}"; do
|
||||
### Check slot 31 for 'luks2'
|
||||
if cryptsetup luksDump "${dev}" 2> /dev/null | grep -qE '^[[:space:]]*31: luks2'; then
|
||||
result+=("${dev}")
|
||||
fi
|
||||
done
|
||||
|
||||
### Print one device per line for mapfile compatibility
|
||||
for dev in "${result[@]}"; do
|
||||
printf '%s\n' "${dev}"
|
||||
done
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Read passphrase interactively.
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
passphrase_ask() {
|
||||
declare -g PASSPHRASE=""
|
||||
printf "\n"
|
||||
stty -echo
|
||||
printf "\e[0;95m🔐 Enter passphrase for decryption: \e[0m\n"
|
||||
read -r PASSPHRASE
|
||||
stty echo
|
||||
printf "\n"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Test the entered passphrase against the dedicated Nuke Keyslot #31.
|
||||
# Arguments:
|
||||
# $1: DEVICE
|
||||
# $2: PASSWD
|
||||
#######################################
|
||||
passphrase_test() {
|
||||
declare -r DEVICE="$1"
|
||||
declare -r PASPHR="$2"
|
||||
printf '%s' "${PASPHR}" | cryptsetup open --batch-mode --test-passphrase --key-slot 31 "${DEVICE}" > /dev/null 2>&1
|
||||
printf "%s" "${NL}"
|
||||
color_echo "${RED}" "✘ Received termination signal. System Power Off in 3 seconds." >&2
|
||||
power_off 3
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Check the integrity and authenticity of this script itself.
|
||||
# Globals:
|
||||
# GRE
|
||||
# MAG
|
||||
# RED
|
||||
# Arguments:
|
||||
# $0: Script Name
|
||||
# 0: Script Name
|
||||
#######################################
|
||||
verify_coresecret() {
|
||||
### Directory of this script
|
||||
# shellcheck disable=SC2155
|
||||
declare dir="$(dirname "$(readlink -f "${0}")")"
|
||||
# shellcheck disable=SC2155
|
||||
declare script="$(basename "${0}")"
|
||||
declare algo
|
||||
verify_script() {
|
||||
declare dir; dir="$(dirname "$(readlink -f "${0}")")"
|
||||
declare script; script="$(basename "${0}")"
|
||||
declare -a algo=("sha512" "sha384")
|
||||
declare cmd="" computed="" expected="" hashfile="" item="" sigfile=""
|
||||
|
||||
for algo in sha512 sha384; do
|
||||
# shellcheck disable=SC2155
|
||||
declare hashfile="${dir}/${script}.${algo}"
|
||||
# shellcheck disable=SC2155
|
||||
declare sigfile="${hashfile}.sig"
|
||||
# shellcheck disable=SC2155
|
||||
declare cmd="${algo}sum"
|
||||
for item in "${algo[@]}"; do
|
||||
hashfile="${dir}/${script}.${item}"
|
||||
sigfile="${hashfile}.sig"
|
||||
cmd="${item}sum"
|
||||
|
||||
printf "\e[0;95m🔏 Verifying signature of: [%s] \e[0m\n" "${hashfile}"
|
||||
color_echo "${MAG}" "🔏 Verifying signature of: [${hashfile}]"
|
||||
gpgv --keyring /etc/keys/pubring.gpg "${sigfile}" "${hashfile}" || {
|
||||
printf "\e[0;91m✘ Signature verification failed for: [%s] \e[0m\n" "${hashfile}" >&2
|
||||
printf "\e[0;91m✘ System Power Off in 3 seconds. \e[0m\n" >&2
|
||||
sync
|
||||
sleep 3
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
color_echo "${RED}" "✘ Signature verification failed for: [${hashfile}]"
|
||||
color_echo "${RED}" "✘ System Power Off in 3 seconds ...."
|
||||
power_off 3
|
||||
}
|
||||
printf "\e[0;92m🔏 Verifying signature of: [%s] successful. \e[0m\n" "${hashfile}"
|
||||
color_echo "${GRE}" "🔏 Verifying signature of: [${hashfile}] successful."
|
||||
|
||||
printf "\e[0;95m🔢 Recomputing Hash: [%s] \e[0m\n" "${algo}"
|
||||
# shellcheck disable=SC2155
|
||||
declare computed=$($cmd "${dir}/${script}" | awk '{print $1}')
|
||||
# shellcheck disable=SC2155
|
||||
declare expected=$(cat "${hashfile}")
|
||||
color_echo "${MAG}" "🔢 Recomputing Hash: [${item}]"
|
||||
computed=$(${cmd} "${dir}/${script}" | awk '{print $1}')
|
||||
expected=$(cat "${hashfile}")
|
||||
|
||||
if [[ ${computed} != "${expected}" ]]; then
|
||||
printf "\e[0;91m✘ Hash mismatch for: [%s] \e[0m\n" "${algo}" >&2
|
||||
printf "\e[0;91m✘ System Power Off in 3 seconds. \e[0m\n" >&2
|
||||
sync
|
||||
sleep 3
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
if [[ "${computed}" != "${expected}" ]]; then
|
||||
color_echo "${RED}" "✘ Recomputed hash mismatch for : [${item}]" >&2
|
||||
color_echo "${RED}" "✘ System Power Off in 3 seconds ...." >&2
|
||||
power_off 3
|
||||
fi
|
||||
printf "\e[0;92m🔢 Recomputing Hash: [%s] successful. \e[0m\n" "${algo}"
|
||||
color_echo "${GRE}" "🔢 Recomputing Hash: [${item}] successful."
|
||||
done
|
||||
|
||||
printf "\e[0;92m🔏 All signatures and hashes verified successfully. Proceeding. \e[0m\n"
|
||||
color_echo "${GRE}" "🔏 All signatures and hashes verified successfully. Proceeding."
|
||||
}
|
||||
|
||||
### Main Programm
|
||||
#######################################
|
||||
# Main Programm Sequence
|
||||
# Globals:
|
||||
# CURRENTDATE
|
||||
# DEVICES_LUKS
|
||||
# GRE
|
||||
# MAG
|
||||
# NL
|
||||
# PASSPHRASE
|
||||
# RED
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
main() {
|
||||
trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR
|
||||
trap 'trap_on_term' INT TERM
|
||||
|
||||
printf "\e[0;91mCoresecret Connection established.\e[0m\n"
|
||||
printf "\e[0;91mStarting Time: %s\e[0m\n" "${CURRENTDATE}"
|
||||
printf "\n"
|
||||
color_echo "${RED}" "Coresecret Connection established."
|
||||
color_echo "${RED}" "Starting Time: ${CURRENTDATE}"
|
||||
color_echo "${MAG}" "Integrity self-check ..."
|
||||
printf "%s" "${NL}"
|
||||
|
||||
verify_coresecret
|
||||
verify_script
|
||||
|
||||
### Read newline-separated output into an array
|
||||
### Read newline-separated output into an array.
|
||||
color_echo "${MAG}" "Scanning for LUKS devices ..."
|
||||
printf "%s" "${NL}"
|
||||
mapfile -t DEVICES_LUKS < <(gather_luks_devices)
|
||||
mapfile -t DEVICES_NUKE < <(gather_nuke_devices)
|
||||
|
||||
### Debug output: list each element with its index
|
||||
#for idx in "${!DEVICES_LUKS[@]}"; do
|
||||
# printf 'Luks[%d]: %s\n' "${idx}" "${DEVICES_LUKS[${idx}]}"
|
||||
#done
|
||||
### If there are no LUKS devices at all, drop to bash.
|
||||
if (( ${#DEVICES_LUKS[@]} == 0 )); then
|
||||
color_echo "${RED}" "✘ No LUKS Devices found. Dropping to bash ..."
|
||||
drop_bash
|
||||
fi
|
||||
|
||||
### Debug output: list each element with its index
|
||||
#for idx in "${!DEVICES_NUKE[@]}"; do
|
||||
# printf 'Nuke[%d]: %s\n' "${idx}" "${DEVICES_NUKE[${idx}]}"
|
||||
#done
|
||||
### Extract the 'nuke='-parameter from '/proc/cmdline'.
|
||||
extract_nuke_hash
|
||||
|
||||
### # If there are no LUKS devices at all, drop to bash
|
||||
[[ -n ${DEVICES_LUKS[*]} ]] || {
|
||||
printf "\e[0;92m✘ No LUKS Devices found. Dropping to bash ... \e[0m\n"
|
||||
prompt_string
|
||||
exec /bin/bash -i
|
||||
### Read passphrase interactively.
|
||||
read_passphrase
|
||||
|
||||
if printf "%s" "${PASSPHRASE}" | cryptroot-unlock; then
|
||||
|
||||
secure_unset_pass
|
||||
exit 0
|
||||
|
||||
else
|
||||
|
||||
printf "%s" "${NL}"
|
||||
color_echo "${RED}" "✘ Unsuccessful command 'cryptroot-unlock'."
|
||||
color_echo "${GRE}" "✘ No LUKS operations performed. Dropping to bash ..."
|
||||
color_echo "${GRE}" "✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'."
|
||||
drop_bash
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
### If there are LUKS devices but no Nuke devices, try unlocking flow
|
||||
if [[ -n ${DEVICES_LUKS[*]} ]] && [[ -z ${DEVICES_NUKE[*]} ]]; then
|
||||
### Attempt interactive unlock with cryptroot-unlock
|
||||
if cryptroot-unlock; then
|
||||
|
||||
exit 0
|
||||
|
||||
else
|
||||
|
||||
printf "\n"
|
||||
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
|
||||
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
|
||||
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
|
||||
prompt_string
|
||||
exec /bin/bash -i
|
||||
|
||||
fi
|
||||
|
||||
elif [[ -n ${DEVICES_LUKS[*]} ]] && [[ -n ${DEVICES_NUKE[*]} ]]; then
|
||||
|
||||
declare -i attempt=1
|
||||
declare NUKED=false
|
||||
declare TEST_DEV="${DEVICES_NUKE[0]}"
|
||||
|
||||
while ((attempt <= MAX_RETRIES)); do
|
||||
|
||||
printf "\e[0;95m🔐Attempt %s/%s: \e[0m\n" "${attempt}" "${MAX_RETRIES}"
|
||||
|
||||
passphrase_ask
|
||||
declare -g PASSWD="${PASSPHRASE}"
|
||||
|
||||
if passphrase_test "${TEST_DEV}" "${PASSWD}"; then
|
||||
|
||||
for dev in "${DEVICES_NUKE[@]}"; do
|
||||
cryptsetup erase --batch-mode "${dev}" > /dev/null 2>&1
|
||||
printf "%s:\e[0;95m✘ LUKS Device Header malfunction. \e[0m\n" "${dev}"
|
||||
done
|
||||
|
||||
declare -r NUKED=true
|
||||
unset PASSWD
|
||||
break
|
||||
|
||||
else
|
||||
|
||||
declare code="$?"
|
||||
|
||||
case "${code}" in
|
||||
1) printf "\e[0;91m✘ No usable key slot is available. \e[0m\n" ;;
|
||||
2) printf "\e[0;91m✘ No key available with this passphrase. \e[0m\n" ;;
|
||||
3) printf "\e[0;93m✘ Out of memory. \e[0m\n" ;;
|
||||
*) printf "\e[0;91m✘ Unexpected Return Code. \e[0m\n" ;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
attempt=$((attempt + 1))
|
||||
|
||||
done
|
||||
|
||||
if [[ ${NUKED} == true ]]; then
|
||||
stty echo
|
||||
sleep 3
|
||||
sync
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
fi
|
||||
|
||||
if cryptroot-unlock; then
|
||||
|
||||
exit 0
|
||||
|
||||
else
|
||||
|
||||
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
|
||||
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
|
||||
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
|
||||
prompt_string
|
||||
exec /bin/bash -i
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
main "${@}"
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
|
||||
@@ -1,447 +0,0 @@
|
||||
#!/bin/bash
|
||||
# SPDX-Version: 3.0
|
||||
# SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git
|
||||
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
|
||||
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||
# SPDX-FileType: SOURCE
|
||||
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
|
||||
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
|
||||
# SPDX-PackageName: CISS.debian.installer
|
||||
# SPDX-Security-Contact: security@coresecret.eu
|
||||
# SPDX-Comment: unlock_wrapper_advanced.sh to be executed as '/etc/crypttab' keyscript and as dropbear SSH forced command.
|
||||
|
||||
set -Ceuo pipefail
|
||||
|
||||
#######################################
|
||||
# Variable declaration
|
||||
#######################################
|
||||
declare -ir MAX_RETRIES=2
|
||||
declare -r ASKPASS='/lib/cryptsetup/askpass'
|
||||
# shellcheck disable=SC2155
|
||||
declare -r CURRENTDATE=$(date +"%F %T")
|
||||
# shellcheck disable=SC2155
|
||||
declare -r IFS=$(printf ' \n\t')
|
||||
declare -r GRE='\e[0;92m'
|
||||
declare -r MAG='\e[0;95m'
|
||||
declare -r RED='\e[0;91m'
|
||||
declare -r RES='\e[0m'
|
||||
declare -r NL='\n'
|
||||
declare -g NUKE_ENABLED='false'
|
||||
declare -g NUKE_HASH=''
|
||||
declare -g PASSPHRASE=''
|
||||
|
||||
#######################################
|
||||
# Print-colored text.
|
||||
# Arguments:
|
||||
# $1 - color code
|
||||
# $@ - text to print
|
||||
#######################################
|
||||
color_echo() { declare c="$1"; shift; printf "%s%s %s%s" "${c}" "${*}" "${RES}" "${NL}"; }
|
||||
|
||||
#######################################
|
||||
# Die helper: print and exit hard.
|
||||
# Globals:
|
||||
# NC
|
||||
# RED
|
||||
# Arguments:
|
||||
# 1: Message string to print.
|
||||
#######################################
|
||||
die() { printf "%s✘ %s%s\n" "${RED}" "$1" "${RES}" >&2; power_off 3; }
|
||||
|
||||
#######################################
|
||||
# Drop to bash environment.
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
drop_bash() { prompt_string; exec /bin/bash -i; }
|
||||
|
||||
#######################################
|
||||
# Extract the 'nuke='-parameter from '/proc/cmdline'.
|
||||
# Globals:
|
||||
# NL
|
||||
# NUKE_ENABLED
|
||||
# NUKE_HASH
|
||||
# RED
|
||||
# RES
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0: if 'nuke=' was found and extracted.
|
||||
# 1: if not found.
|
||||
#######################################
|
||||
extract_nuke_hash() {
|
||||
declare ARG="" CMDLINE="" REGEX='(\$[^$]+){3,}'
|
||||
|
||||
### Read '/proc/cmdline' into a single line safely.
|
||||
read -r CMDLINE < /proc/cmdline
|
||||
for ARG in ${CMDLINE}; do
|
||||
case "${ARG}" in
|
||||
nuke=*)
|
||||
NUKE_HASH="${ARG#nuke=}"
|
||||
if echo "${NUKE_HASH}" | grep -qE "${REGEX}"; then
|
||||
NUKE_ENABLED="true"
|
||||
return 0
|
||||
else
|
||||
### If there is a malformed Grub Bootparameter 'nuke=HASH', drop to bash.
|
||||
color_echo "${RED}" "✘ Nuke Hash Malformat : [${REGEX}] [${NUKE_HASH}]." >&2
|
||||
color_echo "${RED}" "✘ Dropping to bash ...:" >&2
|
||||
drop_bash
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
### No 'nuke=HASH' entry found.
|
||||
return 1
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Gather information of all LUKS Devices available on the system.
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
gather_luks_devices() {
|
||||
declare prev=() curr=()
|
||||
declare -i tries=0
|
||||
|
||||
while ((tries < 10)); do
|
||||
|
||||
mapfile -t curr < <(blkid -t TYPE=crypto_LUKS -o device | sort)
|
||||
|
||||
if cmp <(printf '%s\n' "${curr[@]}") <(printf '%s\n' "${prev[@]}") >/dev/null; then
|
||||
break
|
||||
fi
|
||||
|
||||
prev=("${curr[@]}")
|
||||
tries=$((tries + 1))
|
||||
sleep 1
|
||||
|
||||
done
|
||||
|
||||
printf '%s\n' "${curr[@]}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Erase LUKS headers on all LUKS devices and shutdown system.
|
||||
# Globals:
|
||||
# NUKE_DEVICES
|
||||
#######################################
|
||||
nuke() {
|
||||
declare dev=""
|
||||
for dev in "${DEVICES_LUKS[@]}"; do
|
||||
cryptsetup erase --batch-mode "${dev}" || true
|
||||
color_echo "${RED}" "✘ Error: LUKS Device Header malfunction: [${dev}]."
|
||||
done
|
||||
secure_unset_pass
|
||||
color_echo "${RED}" "✘ Error: LUKS Device malfunction. System Power Off in 16 seconds."
|
||||
power_off 16
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Unified power-off routine.
|
||||
# Arguments:
|
||||
# 1: Sleep time before power-off in seconds (Default to 0 seconds).
|
||||
#######################################
|
||||
power_off() {
|
||||
declare -r wait="${1:-0}"
|
||||
sleep "${wait}"
|
||||
sync
|
||||
echo 1 >| /proc/sys/kernel/sysrq
|
||||
echo o >| /proc/sysrq-trigger
|
||||
# The System powers off immediately; no further code is executed.
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Generates informative shell prompt.
|
||||
# Globals:
|
||||
# PS1
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
prompt_string() {
|
||||
declare -gx PS1="\
|
||||
\[\033[1;91m\]\d\[\033[0m\]|\[\033[1;91m\]\u\[\033[0m\]@\
|
||||
\[\033[1;95m\]\h\[\033[0m\]:\
|
||||
\[\033[1;96m\]\w\[\033[0m\]/>>\
|
||||
\$(if [[ \$? -eq 0 ]]; then \
|
||||
# Show exit status in green if zero
|
||||
echo -e \"\[\033[1;92m\]\$?\[\033[0m\]\"; \
|
||||
else \
|
||||
# Show exit status in red otherwise
|
||||
echo -e \"\[\033[1;91m\]\$?\[\033[0m\]\"; \
|
||||
fi)\
|
||||
|~\$ "
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Trap function to be called on 'ERR'.
|
||||
# Arguments:
|
||||
# 1: ${?}
|
||||
# 2: ${BASH_SOURCE[0]}
|
||||
# 3: ${LINENO}
|
||||
# 4: ${FUNCNAME[0]:-main}
|
||||
# 5: ${BASH_COMMAND}
|
||||
#######################################
|
||||
trap_on_err() {
|
||||
declare -r errcode="$1"
|
||||
declare -r errscrt="$2"
|
||||
declare -r errline="$3"
|
||||
declare -r errfunc="$4"
|
||||
declare -r errcmmd="$5"
|
||||
trap - ERR INT TERM
|
||||
stty echo
|
||||
print_scr_err "${errcode}" "${errscrt}" "${errline}" "${errfunc}" "${errcmmd}"
|
||||
power_off 16
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Security Trap on 'INT' and 'TERM' to provide a deterministic way to not circumvent the nuke routine.
|
||||
# Globals:
|
||||
# NL
|
||||
# RED
|
||||
# RES
|
||||
# Arguments:
|
||||
# None
|
||||
#######################################
|
||||
trap_on_term() {
|
||||
trap - ERR INT TERM
|
||||
stty echo
|
||||
printf "%s" "${NL}"
|
||||
color_echo "${RED}" "✘ System caught a 'SIGINT'. System Power Off in 3 seconds." >&2
|
||||
power_off 3
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Print Error Message for Trap on 'ERR' on Terminal.
|
||||
# Globals:
|
||||
# NL
|
||||
# RED
|
||||
# RES
|
||||
# Arguments:
|
||||
# 1: ${?}
|
||||
# 2: ${BASH_SOURCE[0]}
|
||||
# 3: ${LINENO}
|
||||
# 4: ${FUNCNAME[0]:-main}
|
||||
# 5: ${BASH_COMMAND}
|
||||
#######################################
|
||||
print_scr_err() {
|
||||
declare -r scr_err_errcode="$1"
|
||||
declare -r scr_err_errscrt="$2"
|
||||
declare -r scr_err_errline="$3"
|
||||
declare -r scr_err_errfunc="$4"
|
||||
declare -r scr_err_errcmmd="$5"
|
||||
printf "%s" "${NL}"
|
||||
color_echo "${RED}" "✘ System caught an 'ERROR'. System Power Off in 16 seconds." >&2
|
||||
printf "%s" "${NL}"
|
||||
color_echo "${RED}" "✘ Error : [${scr_err_errcode}]" >&2
|
||||
color_echo "${RED}" "✘ Line : [${scr_err_errline}]" >&2
|
||||
color_echo "${RED}" "✘ Script : [${scr_err_errscrt}]" >&2
|
||||
color_echo "${RED}" "✘ Function : [${scr_err_errfunc}]" >&2
|
||||
color_echo "${RED}" "✘ Command : [${scr_err_errcmmd}]" >&2
|
||||
printf "%s" "${NL}"
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Print Error Message for '0'-Exit-Code on Terminal.
|
||||
# Arguments:
|
||||
# none
|
||||
#######################################
|
||||
print_scr_scc() { color_echo "${GRE}" "✅ Script exited successfully. Proceeding with booting."; }
|
||||
|
||||
#######################################
|
||||
# Read Passphrase interactively.
|
||||
# Globals:
|
||||
# ASKPASS
|
||||
# NUKE_ENABLED
|
||||
# NUKE_HASH
|
||||
# PASSPHRASE
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
read_passphrase() {
|
||||
declare -a METHODS=("sha512crypt" "yescrypt" "scrypt" "bcrypt")
|
||||
declare METHOD="" SALT=""
|
||||
|
||||
PASSPHRASE="$(${ASKPASS} "Enter passphrase: ")"
|
||||
|
||||
if [[ "${NUKE_ENABLED,,}" == 'true' ]]; then
|
||||
### Validate NUKE_HASH format (e.g., $id$salt$hash)
|
||||
if [[ "${NUKE_HASH}" =~ ^\$[a-z0-9]+\$[a-zA-Z0-9./]+\$ ]]; then
|
||||
SALT="$(cut -d'$' -f3 <<< "${NUKE_HASH}")"
|
||||
for METHOD in "${METHODS[@]}"; do
|
||||
if mkpasswd -m "${METHOD}" -S "${SALT}" "${PASSPHRASE}" 2>/dev/null | grep -qF -- "${NUKE_HASH}"; then
|
||||
nuke
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
printf "%s" "${PASSPHRASE}"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Securely unset the passphrase variable.
|
||||
# Globals:
|
||||
# PASSPHRASE
|
||||
#######################################
|
||||
secure_unset_pass() { unset PASSPHRASE; PASSPHRASE=""; }
|
||||
|
||||
#######################################
|
||||
# Check the integrity and authenticity of this script itself.
|
||||
# Arguments:
|
||||
# 0: Script Name
|
||||
#######################################
|
||||
verify_script() {
|
||||
declare dir; dir="$(dirname "$(readlink -f "${0}")")"
|
||||
declare script; script="$(basename "${0}")"
|
||||
declare -a algo=("sha512" "sha384")
|
||||
declare cmd="" computed="" expected="" hashfile="" item="" sigfile=""
|
||||
|
||||
for item in "${algo[@]}"; do
|
||||
hashfile="${dir}/${script}.${item}"
|
||||
sigfile="${hashfile}.sig"
|
||||
cmd="${item}sum"
|
||||
|
||||
color_echo "${MAG}" "🔏 Verifying signature of: [${hashfile}]"
|
||||
gpgv --keyring /etc/keys/pubring.gpg "${sigfile}" "${hashfile}" || {
|
||||
color_echo "${RED}" "✘ Signature verification failed for: [${hashfile}]"
|
||||
color_echo "${RED}" "✘ System Power Off in 3 seconds ...."
|
||||
power_off 3
|
||||
}
|
||||
color_echo "${GRE}" "🔏 Verifying signature of: [${hashfile}] successful."
|
||||
|
||||
color_echo "${MAG}" "🔢 Recomputing Hash: [${item}]"
|
||||
computed=$(${cmd} "${dir}/${script}" | awk '{print $1}')
|
||||
expected=$(cat "${hashfile}")
|
||||
|
||||
if [[ "${computed}" != "${expected}" ]]; then
|
||||
color_echo "${RED}" "✘ Recomputed hash mismatch for : [${item}]" >&2
|
||||
color_echo "${RED}" "✘ System Power Off in 3 seconds ...." >&2
|
||||
power_off 3
|
||||
fi
|
||||
color_echo "${GRE}" "🔢 Recomputing Hash: [${item}] successful."
|
||||
done
|
||||
|
||||
color_echo "${GRE}" "🔏 All signatures and hashes verified successfully. Proceeding."
|
||||
}
|
||||
|
||||
### Main Programm Sequence ###
|
||||
main() {
|
||||
trap 'trap_on_err "$?" "${BASH_SOURCE[0]}" "${LINENO}" "${FUNCNAME[0]:-main}" "${BASH_COMMAND}"' ERR
|
||||
trap 'trap_on_term' INT TERM
|
||||
|
||||
color_echo "${RED}" "Coresecret Connection established."
|
||||
color_echo "${RED}" "Starting Time: ${CURRENTDATE}"
|
||||
color_echo "${MAG}" "Integrity self-check ..."
|
||||
printf "%s" "${NL}"
|
||||
|
||||
verify_script
|
||||
|
||||
### Read newline-separated output into an array.
|
||||
color_echo "${MAG}" "Scanning for LUKS devices ..."
|
||||
printf "%s" "${NL}"
|
||||
mapfile -t DEVICES_LUKS < <(gather_luks_devices)
|
||||
|
||||
### If there are no LUKS devices at all, drop to bash.
|
||||
if (( ${#DEVICES_LUKS[@]} == 0 )); then
|
||||
printf "%s✘ No LUKS Devices found. Dropping to bash ... %s %s" "${RED}" "${RES}" "${NC}"
|
||||
drop_bash
|
||||
fi
|
||||
|
||||
### Extract the 'nuke='-parameter from '/proc/cmdline'.
|
||||
extract_nuke_hash
|
||||
|
||||
### Read passphrase interactively.
|
||||
read_passphrase
|
||||
|
||||
### If there are LUKS devices but no Nuke devices, try unlocking flow
|
||||
if [[ -n ${DEVICES_LUKS[*]} ]] && [[ -z ${DEVICES_NUKE[*]} ]]; then
|
||||
### Attempt interactive unlock with cryptroot-unlock
|
||||
if cryptroot-unlock; then
|
||||
|
||||
exit 0
|
||||
|
||||
else
|
||||
|
||||
printf "\n"
|
||||
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
|
||||
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
|
||||
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
|
||||
prompt_string
|
||||
exec /bin/bash -i
|
||||
|
||||
fi
|
||||
|
||||
elif [[ -n ${DEVICES_LUKS[*]} ]] && [[ -n ${DEVICES_NUKE[*]} ]]; then
|
||||
|
||||
declare -i attempt=1
|
||||
declare NUKED=false
|
||||
declare TEST_DEV="${DEVICES_NUKE[0]}"
|
||||
|
||||
while ((attempt <= MAX_RETRIES)); do
|
||||
|
||||
printf "\e[0;95m🔐Attempt %s/%s: \e[0m\n" "${attempt}" "${MAX_RETRIES}"
|
||||
|
||||
passphrase_ask
|
||||
declare -g PASSWD="${PASSPHRASE}"
|
||||
|
||||
if passphrase_test "${TEST_DEV}" "${PASSWD}"; then
|
||||
|
||||
for dev in "${DEVICES_NUKE[@]}"; do
|
||||
cryptsetup erase --batch-mode "${dev}" > /dev/null 2>&1
|
||||
printf "%s:\e[0;95m✘ LUKS Device Header malfunction. \e[0m\n" "${dev}"
|
||||
done
|
||||
|
||||
declare -r NUKED=true
|
||||
unset PASSWD
|
||||
break
|
||||
|
||||
else
|
||||
|
||||
declare code="$?"
|
||||
|
||||
case "${code}" in
|
||||
1) printf "\e[0;91m✘ No usable key slot is available. \e[0m\n" ;;
|
||||
2) printf "\e[0;91m✘ No key available with this passphrase. \e[0m\n" ;;
|
||||
3) printf "\e[0;93m✘ Out of memory. \e[0m\n" ;;
|
||||
*) printf "\e[0;91m✘ Unexpected Return Code. \e[0m\n" ;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
attempt=$((attempt + 1))
|
||||
|
||||
done
|
||||
|
||||
if [[ ${NUKED} == true ]]; then
|
||||
stty echo
|
||||
sleep 3
|
||||
sync
|
||||
set +C
|
||||
echo 1 > /proc/sys/kernel/sysrq
|
||||
echo o > /proc/sysrq-trigger
|
||||
fi
|
||||
|
||||
if cryptroot-unlock; then
|
||||
|
||||
exit 0
|
||||
|
||||
else
|
||||
|
||||
printf "\e[0;91m✘ Unsuccessful command 'cryptroot-unlock'. \e[0m\n"
|
||||
printf "\e[0;92m✘ No LUKS operations performed. Dropping to bash ... \e[0m\n"
|
||||
printf "\e[0;92m✘ To unlock 'root' partition, and maybe others like 'swap', run 'cryptroot-unlock'. \e[0m\n"
|
||||
prompt_string
|
||||
exec /bin/bash -i
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
@@ -9,6 +9,7 @@
|
||||
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
|
||||
# SPDX-PackageName: CISS.debian.installer
|
||||
# SPDX-Security-Contact: security@coresecret.eu
|
||||
# SPDX-Comment: Hook script (initramfs) for setting up the CISS.debian.installer hardened dropbear environment, incl. Luks Nuke.
|
||||
|
||||
set -e
|
||||
|
||||
@@ -20,6 +21,11 @@ esac
|
||||
|
||||
. /usr/share/initramfs-tools/hook-functions
|
||||
|
||||
if [ ! -e /etc/initramfs-tools/files/unlock-wrapper.sh ]; then
|
||||
echo "Missing unlock-wrapper.sh in /etc/initramfs-tools/files/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
### Ensure directory structure in initramfs
|
||||
mkdir -p "${DESTDIR}/etc/dropbear"
|
||||
mkdir -p "${DESTDIR}/etc/keys"
|
||||
@@ -76,6 +82,6 @@ install -m 0444 /etc/initramfs-tools/files/unlock-wrapper.sh.sha512.sig "${DESTD
|
||||
install -m 0444 /root/.ciss/keys/pubring.gpg "${DESTDIR}/etc/keys/pubring.gpg"
|
||||
|
||||
### Install Dropbear Banner
|
||||
install -m 0444 /etc/dropbear/initramfs/banner "${DESTDIR}/etc/dropbear/initramfs/banner"
|
||||
install -m 0444 /etc/dropbear/initramfs/banner "${DESTDIR}/etc/dropbear/banner"
|
||||
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
|
||||
@@ -12,100 +12,54 @@
|
||||
|
||||
guard_sourcing
|
||||
|
||||
#######################################
|
||||
# Generates 'nuke=HASH' Bootparameter.
|
||||
# Globals:
|
||||
# DIR_CNF
|
||||
# ERR_READ_NUKE_FILE
|
||||
# VAR_DEBUG_TRACE
|
||||
# VAR_NUKE_HASH
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_READ_NUKE_FILE
|
||||
#######################################
|
||||
nuke_passphrase() {
|
||||
declare -r var_nuke_pwd_file="${DIR_CNF}/password_luks_nuke.txt"
|
||||
declare var_temp_nuke_hash="" var_temp_plain_nuke_pwd="" var_salt=""
|
||||
|
||||
declare pw_file="${2}"
|
||||
if [[ -z "${pw_file}" ]]; then
|
||||
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
|
||||
printf "%s❌ Error: --root-password-file missing password file path argument.%s%s" "${C_RED}" "${C_RES}" "${NL}" >&2
|
||||
# shellcheck disable=SC2162
|
||||
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s' ${C_GRE}" "${C_RES}"
|
||||
exit "${ERR_MISS_PWD_P}"
|
||||
### No tracing for security reasons
|
||||
[[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set +x
|
||||
if [[ ! -f "${var_nuke_pwd_file}" ]] || ! IFS= read -r var_temp_plain_nuke_pwd < "${var_nuke_pwd_file}"; then
|
||||
return "${ERR_READ_NUKE_FILE}"
|
||||
fi
|
||||
### Turn on tracing again
|
||||
[[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set -x
|
||||
|
||||
if [[ ! -f "${pw_file}" ]]; then
|
||||
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
|
||||
printf "%s❌ Error: --root-password-file password file '%s' does not exist.%s%s" "${pw_file}" >&2
|
||||
# shellcheck disable=SC2162
|
||||
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
|
||||
exit "${ERR_MISS_PWD_F}"
|
||||
fi
|
||||
var_salt=$(tr -dc 'A-Za-z0-9' < /dev/random | head -c 16)
|
||||
|
||||
declare owner
|
||||
owner=$(stat -c '%U:%G' "${pw_file}")
|
||||
if [[ "${owner}" != "root:root" ]]; then
|
||||
chown root:root "${pw_file}" || {
|
||||
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
|
||||
printf "%s❌ Error: --root-password-file failed to set owner root:root on '%s'.%s%s" "${pw_file}" >&2
|
||||
# shellcheck disable=SC2162
|
||||
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
|
||||
exit "${ERR_OWNS_PWD_F}"
|
||||
}
|
||||
fi
|
||||
### No tracing for security reasons
|
||||
[[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set +x
|
||||
var_temp_nuke_hash=$(mkpasswd --method=sha-512 --salt="${var_salt}" --rounds=8388608 "${var_temp_plain_nuke_pwd}")
|
||||
### Turn on tracing again
|
||||
[[ "${VAR_DEBUG_TRACE,,}" == "true" ]] && set -x
|
||||
|
||||
declare perms
|
||||
perms=$(stat -c '%a' "${pw_file}")
|
||||
if [[ "${perms}" -ne 400 ]]; then
|
||||
chmod 400 "${pw_file}" || {
|
||||
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
|
||||
printf "%s❌ Error: --root-password-file failed to set permissions 0400 on '%s'.%s%s" "${pw_file}" >&2
|
||||
# shellcheck disable=SC2162
|
||||
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
|
||||
exit "${ERR_RGHT_PWD_F}"
|
||||
}
|
||||
fi
|
||||
declare -grx VAR_NUKE_HASH="${var_temp_nuke_hash}"
|
||||
unset var_temp_nuke_hash var_temp_plain_nuke_pwd
|
||||
|
||||
declare plaintext_pw
|
||||
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x # No tracing for security reasons
|
||||
if ! IFS= read -r plaintext_pw < "${pw_file}"; then
|
||||
:
|
||||
fi
|
||||
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
|
||||
|
||||
declare pw_length
|
||||
pw_length=${#plaintext_pw}
|
||||
if (( pw_length < 20 || pw_length > 64 )); then
|
||||
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
|
||||
printf "%s❌ Error: --root-password-file password MUST be between 20 and 64 characters (got %d).%s%s" "${pw_length}" >&2
|
||||
# shellcheck disable=SC2162
|
||||
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
|
||||
exit "${ERR_PASS_LENGH}"
|
||||
fi
|
||||
|
||||
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x # No tracing for security reasons
|
||||
if [[ "${plaintext_pw}" == *\"* ]]; then
|
||||
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
|
||||
if ! $VAR_HANDLER_AUTOBUILD; then boot_screen_cleaner; fi
|
||||
printf "%s❌ Error: --root-password-file password MUST NOT contain double quotes (\").%s%s" >&2
|
||||
# shellcheck disable=SC2162
|
||||
read -p $'%s✅ Press \'ENTER\' to exit the script ... %s'
|
||||
exit "${ERR_PASS_PLICY}"
|
||||
fi
|
||||
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
|
||||
|
||||
declare salt
|
||||
set +o pipefail
|
||||
while :; do
|
||||
salt=$(tr -dc 'A-Za-z0-9' </dev/random | head -c 16)
|
||||
[[ ${#salt} -eq 16 ]] && break
|
||||
done
|
||||
set -o pipefail
|
||||
|
||||
declare hash_temp
|
||||
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set +x # No tracing for security reasons
|
||||
hash_temp=$(mkpasswd --method=sha-512 --salt="${salt}" --rounds=8388608 "${plaintext_pw}")
|
||||
[[ "${VAR_EARLY_DEBUG}" == "true" ]] && set -x # Turn on tracing again
|
||||
|
||||
declare -g VAR_HASHED_PWD="${hash_temp}"
|
||||
unset hash_temp plaintext_pw
|
||||
do_log "debug" "true" "NUKE hash starts with: ${VAR_NUKE_HASH:0:12}..."
|
||||
|
||||
sync
|
||||
if shred -vfzu -n 5 "${pw_file}" > /dev/null 2>&1; then
|
||||
printf "%s✅ Password file '%s': shred -vfzu -n 5 >> done. %s%s" "${pw_file}" > /dev/null 2>&1
|
||||
if shred -vfzu -n 5 "${var_nuke_pwd_file}" > /dev/null 2>&1; then
|
||||
do_log "info" "false" "✅ Password file '${var_nuke_pwd_file}': shred -vfzu -n 5 >> done."
|
||||
else
|
||||
printf "%s❌ Password file '%s': shred -vfzu -n 5 >> NOT successful. %s%s" "${pw_file}" > /dev/null 2>&1
|
||||
do_log "warn" "false" "❌ Password file '${var_nuke_pwd_file}': shred -vfzu -n 5 >> NOT successful."
|
||||
fi
|
||||
sync
|
||||
|
||||
|
||||
do_log "info" "false" "Nuke Hash generated."
|
||||
return 0
|
||||
}
|
||||
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
|
||||
@@ -43,7 +43,8 @@ declare -girx ERR_CHRT_COMMAND=227 # Failure occurred while executing chroo
|
||||
declare -girx ERR_GRUB_EFI_FORCE=226 # Invalid combination of Partition Table and grub_force_efi.
|
||||
declare -girx ERR_GRUB_BACKGROUND=225 # Failure occurred on setting up the GRUB-background.
|
||||
declare -girx ERR_PATH_NOT_VALID=224 # Specific path is not existing.
|
||||
|
||||
declare -girx ERR_READ_NUKE_FILE=223 # Error reading Luks Nuke password file.
|
||||
declare -girx ERR_READ_GRUB_FILE=222 # Error reading Grub password file.
|
||||
|
||||
### Definition of error trap vars
|
||||
declare -gx ERRCODE="" # = $? = $1 = ERRCODE
|
||||
@@ -51,20 +52,4 @@ declare -gx ERRSCRT="" # = ${BASH_SOURCE[0]} = $2 = ERRSCRT
|
||||
declare -gx ERRLINE="" # = ${LINENO} = $3 = ERRLINE
|
||||
declare -gx ERRFUNC="" # = ${FUNCNAME[0]:-main} = $4 = ERRFUNC
|
||||
declare -gx ERRCMMD="" # = ${$BASH_COMMAND} = $5 = ERRCMMD
|
||||
|
||||
|
||||
declare -gir ERR_SPLASH_PNG=200 # --change-splash MUST be 'club' or 'hexagon'
|
||||
declare -gir ERR_CONTROL_CT=201 # --control MUST be an integer between '1' and '65535'
|
||||
declare -gir ERR_RENICE_PRI=202 # --renice-priority MUST an integer between '-19' and '19'
|
||||
declare -gir ERR_REIONICE_P=203 # --reionice-priority no values provided.
|
||||
declare -gir ERR_REIO_P_VAL=204 # --reionice-priority PRIORITY MUST be an integer between '0' and '7'
|
||||
declare -gir ERR_REIO_C_VAL=205 # --reionice-priority CLASS MUST be an integer between '1' and '3'
|
||||
declare -gir ERR_MISS_PWD_P=206 # --root-password-file missing password file path argument
|
||||
declare -gir ERR_MISS_PWD_F=207 # --root-password-file password file does not exist
|
||||
declare -gir ERR_OWNS_PWD_F=208 # --root-password-file failed to set owner root:root on the PWD file
|
||||
declare -gir ERR_RGHT_PWD_F=209 # --root-password-file failed to set permissions 0400 on the PWD file
|
||||
declare -gir ERR_PASS_LENGH=210 # --root-password-file password MUST be between 20 and 64 characters
|
||||
declare -gir ERR_PASS_PLICY=211 # --root-password-file password MUST NOT contain double quotes
|
||||
declare -gir ERR__SSH__PORT=212 # --ssh-port MUST be an integer between '1' and '65535'
|
||||
declare -gir ERR_NOTABSPATH=252 # Not an absolute path
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
|
||||
Reference in New Issue
Block a user