V8.00.000.2025.06.17
All checks were successful
🛡️ Retrieve DNSSEC status of coresecret.dev. / 🛡️ Retrieve DNSSEC status of coresecret.dev. (push) Successful in 34s
🔁 Render Graphviz Diagrams. / 🔁 Render Graphviz Diagrams. (push) Successful in 24s
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 1m35s

Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
This commit is contained in:
2025-06-25 10:10:41 +02:00
parent 9c19212c00
commit e8d85a39ae
134 changed files with 13933 additions and 41 deletions

102
func/2010_validation_ip.sh Normal file
View File

@@ -0,0 +1,102 @@
#!/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
#######################################
# IPv4 validation.
# Globals:
# ERR_INVALID_IPV4
# Arguments:
# $1: IPv4 to validate.
#######################################
validation_ipv4() {
declare var_ip="$1"
### Single-pass check: 4 octets, each 0-255, no leading zeros (unless the octet is exactly "0")
if [[ "${var_ip}" =~ ^((25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})$ ]]; then
do_log "info" "true" "'${var_ip}' seems to be a valid IPv4."
else
exit "${ERR_INVALID_IPV4}"
fi
}
#######################################
# IPv6 validation, including
# - Standard IPv6 notation with eight groups such as 2001:0db8:85a3:0000:0000:8a2e:0370:7334
# - Shortened notation with :: like 2001:db8::1
# - Addresses with embedded IPv4 addresses like ::ffff:192.0.2.128
# - Link-local addresses like fe80::1%eth0
# Globals:
# ERR_INVALID_IPV6
# Arguments:
# $1: IPv6 address
#######################################
validation_ipv6() {
### Original input (may include %zone).
declare var_ip="$1"
### Strip optional zone id, e.g. fe80::1%eth0 -> fe80::1
declare var_addr="${var_ip%%\%*}"
declare var_has_double_colon=0
### Step 1 IPv4-mapped / -embedded addresses (::ffff:192.0.2.1)
if [[ "${var_addr}" == *.* ]]; then
declare var_ipv4_part="${var_addr##*:}"
validation_ipv4 "${var_ipv4_part}" || exit "${ERR_INVALID_IPV6}"
### Replace IPv4 part by a placeholder, so we can count hextets later
var_addr="${var_addr%:*}:0:0"
fi
### Step 2 Detect forbidden multiple '::'
if [[ "${var_addr}" == *::* ]]; then
var_has_double_colon=1
### Remove first '::' and check there is no second one.
[[ ${var_addr#*::*} == *::* ]] && exit "${ERR_INVALID_IPV6}"
fi
### Step 3 Split into hextets and validate format.
declare var_hextet
declare -a var_segments
IFS=':' read -ra var_segments <<< "${var_addr}"
declare seg_count=${#var_segments[@]}
for var_hextet in "${var_segments[@]}"; do
### Empty ⇔ part of '::' compression
[[ -z "${var_hextet}" ]] && continue
[[ "${var_hextet}" =~ ^[0-9a-fA-F]{1,4}$ ]] || exit "${ERR_INVALID_IPV6}"
done
### Step 4 Check total hextet count.
if (( var_has_double_colon )); then
(( seg_count <= 8 )) || exit "${ERR_INVALID_IPV6}"
else
(( seg_count == 8 )) || exit "${ERR_INVALID_IPV6}"
fi
### Success
do_log "info" "true" "'${var_ip}' seems to be a valid IPv6."
}
#######################################
# Port validation.
# Globals:
# ERR_INVALID_PORT
# Arguments:
# $1: Port number
#######################################
validation_port() {
declare var_port="$1"
if [[ "${var_port}" =~ ^[0-9]+$ ]] && (( var_port >= 1 && var_port <= 65535 )); then
do_log "info" "true" "'${var_port}' seems to be a valid port."
else
do_log "error" "false" "'${var_port}' seems to be NOT a valid port."
exit "${ERR_INVALID_PORT}"
fi
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

211
func/2015_helper_modules.sh Normal file
View File

@@ -0,0 +1,211 @@
#!/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
#######################################
# Wrapper for executing commands in the desired chroot environment.
# Globals:
# TERM
# Arguments:
# $1: Target of the chroot environment.
# $@: Commands and options and parameters to be executed in chroot.
#######################################
do_in_target() {
declare var_chroot_target="$1"; shift
declare ary_chroot_command=("$@")
do_log "info" "false" "Executing in the target system '${var_chroot_target}' command: '${ary_chroot_command[*]}'."
chroot "${var_chroot_target}" /usr/bin/env -i \
HOME=/root \
PATH=/usr/sbin:/usr/bin:/sbin:/bin \
TERM="${TERM}" \
"${ary_chroot_command[@]}"
}
#######################################
# Wrapper around 'printf' for clean code.
# Globals:
# C_RES
# Arguments:
# $1: One of "${C_BLA}" | "${C_RED}" | "${C_GRE}" | "${C_YEL}" | "${C_BLU}" | "${C_MAG}" | "${C_CYA}" | "${C_WHI}"
# $2: Text string to print on terminal.
#######################################
do_print_color() {
printf "%s\n" "${1}${2}${C_RES}"
}
#######################################
# Wrapper around 'printf' for clean, uniform terminal output and line fold for long text strings for better readability.
# Globals:
# C_RES
# Arguments:
# $1: One of "${C_BLA}" | "${C_RED}" | "${C_GRE}" | "${C_YEL}" | "${C_BLU}" | "${C_MAG}" | "${C_CYA}" | "${C_WHI}"
# $2: Text string to print on terminal.
#######################################
do_print_fold() {
declare var_color="$1"; shift
declare var_msg_string="$*"
declare var_formatted_String="${var_color}${var_msg_string}${C_RES}"
printf "%b\n" "${var_formatted_String}" | fold -s -w 76 | sed '1! s/^/ /'
}
#######################################
# Wrapper around 'printf' for logfile redirect.
# Arguments:
# $1: Text string to redirect to a log file.
#######################################
do_print_log() {
printf "%s\n" "${1}"
}
#######################################
# Helper Module to generate a Subnet Mask out of an IP in CCDIR Notation.
# Arguments:
# $1: IPv4 in CCDIR Notation, e.g.,: 192.168.128.128/24
# Returns:
# 0 : In every case a zero return value is delivered.
#######################################
generate_subnetmask() {
declare var_arg="$1"
declare var_prefix="${var_arg#*/}"
declare var_mask_int=""
declare var_has_ipv4_subnet=""
var_mask_int=$((0xFFFFFFFF << (32 - var_prefix) & 0xFFFFFFFF))
var_has_ipv4_subnet=$(printf "%d.%d.%d.%d" \
$(((var_mask_int >> 24) & 0xFF)) \
$(((var_mask_int >> 16) & 0xFF)) \
$(((var_mask_int >> 8) & 0xFF)) \
$((var_mask_int & 0xFF)))
echo "${var_has_ipv4_subnet}"
return 0
}
#######################################
# Converts characters such as spaces, inverted commas, backslashes, and other special
# characters so that they can be safely used as arguments in a shell command.
# Arguments:
# $1: String to sanitize.
#######################################
sanitize_input() {
# shellcheck disable=SC2155
declare var_safe_out=$(printf "%q" "$1")
echo "${var_safe_out}"
}
#######################################
# Remove any leading or trailing whitespace.
# Arguments:
# $1: String to clean.
#######################################
remove_whitespace() {
# shellcheck disable=SC2155
declare var_out=$(printf "%s" "$1" | xargs)
echo "${var_out}"
}
#######################################
# Function to escape all shell metacharacters
# Arguments:
# $1: String to Sanitize
#######################################
sanitize_shell_literal() {
declare input="$1"
### %q quotes the string so that the shell re-reads it as the original literal
printf '%q' "${input}"
}
#######################################
# Function to remove any character not in the allowed set
# Arguments:
# $1: String to Sanitize
#######################################
sanitize_string() {
declare input="$1"
### Define allowed characters:
### letters, digits, dot, underscore, slash, equals, [, ], colon, double-quote, hyphen, space.
declare allowed='a-zA-Z0-9._/=\[\]:"\-+ '
printf '%s' "${input}" | tr -cd "${allowed}"
}
#######################################
# Helper module for full upgrade, autoremove and autoclean.
# Arguments:
# None
#######################################
update_upgrade() {
apt-get update -y
apt-get upgrade -y
apt-get autoclean -y
apt-get autopurge -y
apt-get autoremove -y
}
#######################################
# Wrapper for secure curl.
# Globals:
# ERR_DOWNLOAD_FAILED
# ERR_NO_DOWNLOAD_ARG
# Arguments:
# $1: URL from which to download a specific file.
# $2: /path/to/file to be saved to.
# Returns:
# ${ERR_DOWNLOAD_FAILED}: Download failed.
# ${ERR_NO_DOWNLOAD_ARG}: No arguments specified.
#######################################
scurl() {
if [[ $# -ne 2 ]]; then
do_log "error" "false" "Usage: scurl <URL> <path/to/file>"
return "${ERR_NO_DOWNLOAD_ARG}"
fi
declare url="$1"
declare output_path="$2"
if ! curl --doh-url "https://dns01.eddns.eu/dns-query" \
--doh-cert-status \
--tlsv1.3 \
-sSf \
-o "${output_path}" \
"${url}"
then
do_log "error" "false" "Download failed for URL: '${1}'."
return "${ERR_DOWNLOAD_FAILED}"
fi
}
#######################################
# Wrapper for secure wget.
# Globals:
# ERR_DOWNLOAD_FAILED
# ERR_NO_DOWNLOAD_ARG
# Arguments:
# $1: URL from which to download a specific file.
# $2: /path/to/file to be saved to.
# Returns:
# ${ERR_DOWNLOAD_FAILED}: Download failed.
# ${ERR_NO_DOWNLOAD_ARG}: No arguments specified.
#######################################
swget() {
if [[ $# -ne 2 ]]; then
do_log "error" "false" "Usage: swget <URL> <path/to/file>"
return "${ERR_NO_DOWNLOAD_ARG}"
fi
declare url="$1"
declare output_path="$2"
if ! wget --show-progress \
--no-clobber \
--https-only \
--secure-protocol=TLSv1_3 \
-qO "${output_path}" \
"${url}"
then
do_log "error" "false" "Download failed for URL: '${1}'."
return "${ERR_DOWNLOAD_FAILED}"
fi
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -0,0 +1,133 @@
#!/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
#######################################
# Log level values for comparison.
# Arguments:
# $1: "${LOG_LEVEL}" one of: "debug" | "info" | "notice" | "warn" | "error" | "critical" | "fatal" | "emergency"
#######################################
log_level_value() {
case "${1,,}" in
debug) echo 0 ;;
info) echo 1 ;;
notice) echo 2 ;;
warn) echo 3 ;;
error) echo 4 ;;
critical) echo 5 ;;
fatal) echo 6 ;;
emergency) echo 7 ;;
*) echo 0 ;;
esac
}
#######################################
# Filter and compare log levels.
# Globals:
# DEFAULT_LOG_LEVEL
# Arguments:
# $1: "${LOG_LEVEL}" one of: "debug" | "info" | "notice" | "warn" | "error" | "critical" | "fatal" | "emergency"
#######################################
do_should_log() {
# shellcheck disable=SC2155
declare var_desired_log_value=$(log_level_value "$1")
# shellcheck disable=SC2155
declare var_default_log_value=$(log_level_value "${DEFAULT_LOG_LEVEL}")
if [[ ${var_desired_log_value} -ge ${var_default_log_value} ]]; then
return 0
else
return 1
fi
}
#######################################
# Log level color retriever.
# Globals:
# C_BLU
# C_GRN
# C_MAG
# C_RED
# C_YEL
# Arguments:
# $1: "${LOG_LEVEL}" one of: "debug" | "info" | "notice" | "warn" | "error" | "critical" | "fatal" | "emergency"
#######################################
do_get_log_color() {
case "${1,,}" in
debug) echo "${C_WHI}" ;;
info) echo "${C_GRN}" ;;
notice) echo "${C_YEL}" ;;
warn | error | critical) echo "${C_RED}" ;;
fatal | emergency) echo "${C_MAG}" ;;
*) echo "${C_BLU}" ;;
esac
}
#######################################
# Main logger wrapper.
# Globals:
# LOG_ERR
# LOG_INS
# Arguments:
# $1: "${LOG_LEVEL}" one of: "debug" | "info" | "notice" | "warn" | "error" | "critical" | "fatal" | "emergency"
# $2: "${LOG_ONLY}" boolean "true" | "false"
# $@: "${MESSAGE[*]}" arbitrary text string to log.
#######################################
do_log() {
declare var_log_level="$1"; shift
declare var_log_only="$2"; shift
declare ary_message=("$@")
declare var_msg_string="${ary_message[*]}"
# shellcheck disable=SC2155
declare var_color=$(do_get_log_color "${var_log_level}")
# shellcheck disable=SC2155
declare var_ts="$(date -u '+%Y-%m-%dT%H:%M:%S.%4N%z')"
declare var_log_entry=("${var_ts} [${var_log_level}]: ${ary_message[*]}")
if do_should_log "${var_log_level}"; then
if [[ "${var_log_only,,}" == true ]]; then
case "${var_log_level,,}" in
debug | info | notice) do_print_log "${var_log_entry[*]}" >> "${LOG_INS}" ;;
warn | error | critical | fatal | emergency ) do_print_log "${var_log_entry[*]}" >> "${LOG_ERR}" ;;
esac
elif [[ ${var_log_only,,} == false ]]; then
case "${var_log_level,,}" in
debug | info | notice)
if [[ ${#var_msg_string} -le 76 ]]; then
do_print_color "${var_color}" "${var_log_entry[*]}"
do_print_log "${var_log_entry[*]}" >> "${LOG_INS}"
else
do_print_fold "${var_color}" "${var_log_entry[*]}"
do_print_log "${var_log_entry[*]}" >> "${LOG_INS}"
fi
;;
warn | error | critical | fatal | emergency)
if [[ ${#var_msg_string} -le 76 ]]; then
do_print_color "${var_color}" "${var_log_entry[*]}"
do_print_log "${var_log_entry[*]}" >> "${LOG_ERR}"
else
do_print_fold "${var_color}" "${var_log_entry[*]}"
do_print_log "${var_log_entry[*]}" >> "${LOG_ERR}"
fi
;;
*)
if [[ ${#var_msg_string} -le 76 ]]; then
do_print_color "${var_color}" "${var_log_entry[*]}"
do_print_log "${var_log_entry[*]}" >> "${LOG_INS}"
else
do_print_fold "${var_color}" "${var_log_entry[*]}"
do_print_log "${var_log_entry[*]}" >> "${LOG_INS}"
fi
;;
esac
fi
fi
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

38
func/2030_check_nic.sh Normal file
View File

@@ -0,0 +1,38 @@
#!/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
#######################################
# Specify the NIC interactively for setup.
# Globals:
# DIR_TMP
# Arguments:
# None
#######################################
2030_check_nic() {
ip -o link show | awk -F': ' '{print $2}' | sed 's!lo!!' | sed '/^$/d' | awk '{$1=$1};1' >| "${DIR_TMP}nic.tmp"
declare var_counter=1
declare var_line=""
declare var_nic=""
declare var_radiolist=""
while IFS= read -r var_line; do
var_radiolist="${var_radiolist} ${var_line} ${var_counter} on "
((var_counter++))
done < "${DIR_TMP}nic.tmp"
# shellcheck disable=SC2086 disable=SC2248
var_nic=$(dialog --ascii-lines --clear --backtitle "Specify the NIC for setup" --radiolist "NIC available" 0 0 ${var_counter} ${var_radiolist} 3>&1 1>&2 2>&3)
clear
do_log "info" "false" "You have selected: '${var_nic}' - proceeding with setup."
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

56
func/2040_grub_helper.sh Normal file
View File

@@ -0,0 +1,56 @@
#!/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
### Options in "VAR_GRUB_CMDLINE_LINUX" are always effective.
### Options in "VAR_GRUB_CMDLINE_LINUX_DEFAULT" are effective ONLY during normal boot (NOT during recovery mode).
#######################################
# Helper module to extract the current GRUB CMDLINE strings.
# Globals:
# TARGET
# VAR_GRUB_CMDLINE_LINUX
# VAR_GRUB_CMDLINE_LINUX_DEFAULT
# VAR_ORIG_GRUB_CMDLINE_LINUX
# VAR_ORIG_GRUB_CMDLINE_LINUX_DEFAULT
# Arguments:
# None
#######################################
2040_grub_extract_current_string() {
# shellcheck disable=SC2155
declare -gx VAR_ORIG_GRUB_CMDLINE_LINUX=$(grep -E 'VAR_GRUB_CMDLINE_LINUX=' "${TARGET}/etc/default/grub")
# shellcheck disable=SC2155
declare -gx VAR_ORIG_GRUB_CMDLINE_LINUX_DEFAULT=$(grep -E 'VAR_GRUB_CMDLINE_LINUX_DEFAULT=' "${TARGET}/etc/default/grub")
# shellcheck disable=SC2155
declare -gx VAR_GRUB_CMDLINE_LINUX=$(grep -E 'VAR_GRUB_CMDLINE_LINUX=' "${TARGET}/etc/default/grub" | sed 's/.$//')
# shellcheck disable=SC2155
declare -gx VAR_GRUB_CMDLINE_LINUX_DEFAULT=$(grep -E 'VAR_GRUB_CMDLINE_LINUX_DEFAULT=' "${TARGET}/etc/default/grub" | sed 's/.$//')
}
#######################################
# Helper module to finish the modified GRUB CMDLINE strings.
# Globals:
# TARGET
# VAR_GRUB_CMDLINE_LINUX
# VAR_GRUB_CMDLINE_LINUX_DEFAULT
# VAR_H
# VAR_ORIG_GRUB_CMDLINE_LINUX
# VAR_ORIG_GRUB_CMDLINE_LINUX_DEFAULT
# Arguments:
# None
#######################################
2040_grub_finalize_string() {
VAR_GRUB_CMDLINE_LINUX="${VAR_GRUB_CMDLINE_LINUX}${VAR_H}"
VAR_GRUB_CMDLINE_LINUX_DEFAULT="${VAR_GRUB_CMDLINE_LINUX_DEFAULT}${VAR_H}"
sed -i "s/$VAR_ORIG_GRUB_CMDLINE_LINUX/$VAR_GRUB_CMDLINE_LINUX/" "${TARGET}/etc/default/grub"
sed -i "s/$VAR_ORIG_GRUB_CMDLINE_LINUX_DEFAULT/$VAR_GRUB_CMDLINE_LINUX_DEFAULT/" "${TARGET}/etc/default/grub"
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

56
func/2050_yaml_parser.sh Normal file
View File

@@ -0,0 +1,56 @@
#!/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
#######################################
# Parsing './.preseed/preseed.yaml'.
# Globals:
# ARY_NTPSRVR
# ARY_PACKAGES
# DIR_CNF
# DIR_TMP
# VAR_PRESEED
# Arguments:
# None
#######################################
yaml_parser() {
cat "${DIR_CNF}/preseed.yaml" "${DIR_CNF}/partitioning.yaml" >| "${DIR_TMP}/combined.yaml"
yq -o=shell "${DIR_TMP}/combined.yaml" >| "${VAR_PRESEED}"
declare var_key var_value
while IFS='=' read -r var_key var_value; do
if [[ ${var_key} =~ ^ntp_server_[0-9]+$ ]]; then
var_value=${var_value#\'}
var_value=${var_value%\'}
declare -agx ARY_NTPSRVR+=("${var_value}")
fi
done < "${VAR_PRESEED}"
while IFS='=' read -r var_key var_value; do
if [[ ${var_key} =~ ^software_[0-9]+$ ]]; then
var_value=${var_value#\'}
var_value=${var_value%\'}
declare -agx ARY_PACKAGES+=("${var_value}")
fi
done < "${VAR_PRESEED}"
sed -i '/^software_[0-9]\+=/d' "${VAR_PRESEED}"
sed -i '/^ntp_server_[0-9]\+=/d' "${VAR_PRESEED}"
### Substitute all key= by key=""
sed -i -E 's/^(.*)=\s*$/\1=""/' "${VAR_PRESEED}"
### Wrap each key=value by '' e.g., key='value'
sed -i -E "s/^(.*)=([^'\"]+)$/\1='\2'/" "${VAR_PRESEED}"
return 0
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

140
func/2051_yaml_reader.sh Normal file
View File

@@ -0,0 +1,140 @@
#!/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
#######################################
# Reading and extracting variables from "${PRESEED}".
# Globals:
# ERR_NO_VALID_RECIPE
# HMP_RECIPE_DEV_PARTITIONS
# VAR_PRESEED
# VAR_RECIPE_DEV_COUNTER
# VAR_RECIPE_FIRMWARE
# VAR_RECIPE_STRING
# VAR_RECIPE_TABLE
# Arguments:
# None
#######################################
yaml_reader() {
### Declare and substitute input files
declare -r var_if="${VAR_PRESEED}"
### Search pattern for variables (recipe_<string>_active='true')
declare -r var_search_pattern="^recipe_.*_active='true'"
declare var_line=""
declare var_middle_part=""
### Read "${var_if}" line by line
while IFS= read -r var_line; do
### Check, if line matches the search pattern
if [[ "${var_line}" =~ ${var_search_pattern} ]]; then
### Extract the middle part or second position
var_middle_part=$(echo "${var_line}" | sed -E "s/^recipe_([^_]+)_active='true'/\1/")
declare -gx VAR_RECIPE_STRING="${var_middle_part}"
### Exit after first occurrence
break
fi
done < "${var_if}"
if [[ -n ${VAR_RECIPE_STRING} ]]; then
do_log "info" "false" "Found active recipe string: '${VAR_RECIPE_STRING}'."
else
do_log "fatal" "false" "Found NO active recipe string: '${VAR_RECIPE_STRING}'." >&2
exit "${ERR_NO_VALID_RECIPE}"
fi
### Variable for highest device count e.g., /dev/sdf = "f"
declare var_highest_dev
### Search "${var_if}" for matching recipe_${VAR_RECIPE_STRING}_dev_* entries and find the highest dev letter
var_highest_dev=$(grep -E "^recipe_${VAR_RECIPE_STRING}_dev_" "${var_if}" | awk -F'_' '
{
if (NF >= 4) {
### Extract 4th position (e.g., "recipe_${VAR_RECIPE_STRING}_dev_sda" or "recipe_${VAR_RECIPE_STRING}_dev_vda")
device_field = $4
### Check, if field is at least 3 char wide and last char contains a letter
if (length(device_field) >= 3) {
last_char = substr(device_field, length(device_field), 1) ### Extract last letter of respective field
if (last_char ~ /^[a-z]$/ && last_char > max) {
max = last_char
}
}
}
}
END { print max }
')
### Save the result in VAR_RECIPE_DEV_COUNTER
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}'."
else
do_log "fatal" "false" "Found NO highest recipe device: '${VAR_RECIPE_DEV_COUNTER}'." >&2
exit "${ERR_NO_VALID_RECIPE}"
fi
declare var_device="" var_fields="" var_line="" var_partition=""
declare -Agx HMP_RECIPE_DEV_PARTITIONS=()
### Read var_if and iterate through all matching entries without executing in a subshell
while read -r var_line; do
### Extract fields of line
IFS='_' read -ra var_fields <<< "${var_line}"
### Check that enough fields are available
if [[ "${#var_fields[@]}" -ge 5 ]]; then
var_device="${var_fields[3]}" ### The fourth position includes the device (e.g., sda, vda, xvda)
var_partition="${var_fields[4]}" ### The fifth position includes the partition (e.g., 13)
### Check, if the partition is a number and higher than the current value
if [[ "${var_partition}" =~ ^[0-9]+$ ]]; then
if [[ -z "${HMP_RECIPE_DEV_PARTITIONS[${var_device}]}" || "${var_partition}" -gt ${HMP_RECIPE_DEV_PARTITIONS[${var_device}]} ]]; then
# shellcheck disable=SC2004
HMP_RECIPE_DEV_PARTITIONS[${var_device}]="${var_partition}"
fi
fi
fi
done < <(grep -E "^recipe_${VAR_RECIPE_STRING}_dev_" "${var_if}")
for var_device in "${!HMP_RECIPE_DEV_PARTITIONS[@]}"; do
do_log "info" "false" "Highest number of partitions for ${var_device}: ${HMP_RECIPE_DEV_PARTITIONS[${var_device}]}"
done
### Extract chosen partition table
declare recipe_table_var="recipe_${VAR_RECIPE_STRING}_control_table"
declare -gx VAR_RECIPE_TABLE="${!recipe_table_var}"
### Extract chosen firmware
declare recipe_firmware_var="recipe_${VAR_RECIPE_STRING}_control_firmware"
declare -gx VAR_RECIPE_FIRMWARE="${!recipe_firmware_var}"
if [[ ${VAR_RECIPE_TABLE,,} == "gpt" && ${VAR_RECIPE_FIRMWARE,,} == "uefi" ]]; then
do_log "info" "false" "Partition table: '${VAR_RECIPE_TABLE}' and firmware: '${VAR_RECIPE_FIRMWARE}' > ESP 'EF00' necessary."
elif [[ ${VAR_RECIPE_TABLE,,} == "gpt" && ${VAR_RECIPE_FIRMWARE,,} == "bios" ]]; then
do_log "info" "false" "Partition table: '${VAR_RECIPE_TABLE}' and firmware: '${VAR_RECIPE_FIRMWARE}' > BIOS Boot Partition 'EF02' necessary."
elif [[ ${VAR_RECIPE_TABLE,,} == "msdos" && ${VAR_RECIPE_FIRMWARE,,} == "uefi" ]]; then
do_log "info" "false" "Partition table: '${VAR_RECIPE_TABLE}' and firmware: '${VAR_RECIPE_FIRMWARE}' > ESP on MBR needs partition type '0xEF'."
elif [[ ${VAR_RECIPE_TABLE,,} == "msdos" && ${VAR_RECIPE_FIRMWARE,,} == "bios" ]]; then
do_log "info" "false" "Partition table: '${VAR_RECIPE_TABLE}' and firmware: '${VAR_RECIPE_FIRMWARE}' > No special firmware partition necessary."
fi
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -0,0 +1,59 @@
#!/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
#######################################
# Validate all preseed network variables (IPv4 & IPv6)
# Arguments:
# None
#######################################
validation_preseed() {
declare var value
### --- IPv4 variables ------------------------------------------------------
declare -a ipv4_vars=(
network_static_ipv4nameserver_0
network_static_ipv4nameserver_1
network_static_ipv4nameserver_fallback_0
network_static_ipv4nameserver_fallback_1
network_static_ipv4address
network_static_ipv4gateway
)
### --- IPv6 variables ------------------------------------------------------
declare -a ipv6_vars=(
network_static_ipv6nameserver_0
network_static_ipv6nameserver_1
network_static_ipv6nameserver_fallback_0
network_static_ipv6nameserver_fallback_1
network_static_ipv6address
)
### --- loop over both groups ----------------------------------------------
for var in "${ipv4_vars[@]}"; do
value="${!var}"
if [[ -n "${value}" ]]; then
validation_ipv4 "${value}"
else
do_log "info" "true" "'${var}' is not set."
fi
done
for var in "${ipv6_vars[@]}"; do
value="${!var}"
if [[ -n "${value}" ]]; then
validation_ipv6 "${value}"
else
do_log "info" "false" "'${var}' is not set."
fi
done
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh:

108
func/3200_partitioning.sh Normal file
View File

@@ -0,0 +1,108 @@
#!/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
#######################################
# Function that generates each partition on each device according to the chosen recipe string.
# Globals:
# ERR_PARTITIONTBL
# HMP_RECIPE_DEV_PARTITIONS
# HMP_UUID_PARTITION
# RECIPE_STRING
# RECIPE_TABLE
# VAR_RECIPE_TABLE
# Arguments:
# None
#######################################
partitioning() {
### REMINDER
# HashMap : "${!HMP_RECIPE_DEV_PARTITIONS[@]}"
# ${DEVICE}: "${HMP_RECIPE_DEV_PARTITIONS[$DEVICE]}"
declare var_dev var_partition var_partition_number
### Iterate through each device.
for var_dev in "${!HMP_RECIPE_DEV_PARTITIONS[@]}"; do
var_partition_number=${HMP_RECIPE_DEV_PARTITIONS[${var_dev}]}
### All current data for the respective device will be deleted.
blkdiscard /dev/"${var_dev}"
do_log "info" "false" "Partition table of '/dev/${var_dev}' discarded."
if [[ ${VAR_RECIPE_TABLE} == "gpt" ]]; then
parted -s /dev/"${var_dev}" mklabel gpt
do_log "info" "false" "Partition table '${VAR_RECIPE_TABLE}' of '/dev/${var_dev}' generated."
elif [[ ${VAR_RECIPE_TABLE} == "mbr" ]]; then
parted -s /dev/"${var_dev}" mklabel mbr
do_log "info" "false" "Partition table '${VAR_RECIPE_TABLE}' of '/dev/${var_dev}' generated."
else
do_log "fatal" "false" "No valid partition table chosen. String was '${VAR_RECIPE_TABLE}'. Exiting setup."
exit "${ERR_PARTITIONTBL}"
fi
### Iterate through each partition on the current device.
for (( var_partition=1; var_partition<=var_partition_number; var_partition++ )); do
#for var_partition in $(seq 1 "${var_partition_number}"); do
### Generate variables for the current partition.
declare begin_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_begin"
declare end_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_end"
declare bootable_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_bootable"
declare primary_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_primary"
declare filesystem_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_filesystem_version"
### Initialise variables.
declare BEGIN=${!begin_var}
declare END=${!end_var}
declare BOOTABLE=${!bootable_var}
declare PRIMARY=${!primary_var}
declare FILESYSTEM=${!filesystem_var}
### Generate partition.
if [[ ${END} == "-1" ]]; then
parted -s /dev/"${var_dev}" mkpart "${PRIMARY}" "${FILESYSTEM}" "${BEGIN}" 100%
do_log "info" "false" "Partition generated: '${var_partition}' | on device '/dev/${var_dev}' | begin: '${BEGIN}' | end: 100 % of remaining disk."
else
parted -s /dev/"${var_dev}" mkpart "${PRIMARY}" "${FILESYSTEM}" "${BEGIN}" "${END}"
do_log "info" "false" "Partition generated: '${var_partition}' | on device '/dev/${var_dev}' | begin: '${BEGIN}' | end: '${END}'."
fi
### Set the bootable flag if necessary.
if [[ "${BOOTABLE,,}" == true ]]; then
parted -s "/dev/${var_dev}" set "${var_partition}" boot on
do_log "info" "false" "Partition: '/dev/${var_dev}${var_partition}' marked as bootable."
fi
if [[ "${PRIMARY,,}" == logical ]]; then
parted -s "/dev/${var_dev}" set "${var_partition}" "${FILESYSTEM}" on
fi
### Save UUID of the generated partition
# shellcheck disable=SC2155
declare UUID=$(blkid -s UUID -o value "/dev/${var_dev}${var_partition}")
HMP_UUID_PARTITION["UUID_${var_dev}${var_partition}"]="${UUID}"
do_log "info" "false" "Saved in HashMap HMP_UUID_PARTITION: 'UUID_${var_dev}${var_partition}' -> '${HMP_UUID_PARTITION["UUID_${var_dev}${var_partition}"]}'"
done
done
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh

View File

@@ -0,0 +1,108 @@
#!/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
#######################################
# Function that generates each partition on each device according to the chosen recipe string.
# Globals:
# ERR_PARTITIONTBL
# HMP_RECIPE_DEV_PARTITIONS
# HMP_UUID_PARTITION
# RECIPE_STRING
# RECIPE_TABLE
# VAR_RECIPE_TABLE
# Arguments:
# None
#######################################
partitioning() {
### REMINDER
# HashMap : "${!HMP_RECIPE_DEV_PARTITIONS[@]}"
# ${DEVICE}: "${HMP_RECIPE_DEV_PARTITIONS[$DEVICE]}"
declare var_dev var_partition var_partition_number
### Iterate through each device.
for var_dev in "${!HMP_RECIPE_DEV_PARTITIONS[@]}"; do
var_partition_number=${HMP_RECIPE_DEV_PARTITIONS[${var_dev}]}
### All current data for the respective device will be deleted.
blkdiscard /dev/"${var_dev}"
do_log "info" "false" "Partition table of '/dev/${var_dev}' discarded."
if [[ ${VAR_RECIPE_TABLE} == "gpt" ]]; then
parted -s /dev/"${var_dev}" mklabel gpt
do_log "info" "false" "Partition table '${VAR_RECIPE_TABLE}' of '/dev/${var_dev}' generated."
elif [[ ${VAR_RECIPE_TABLE} == "mbr" ]]; then
parted -s /dev/"${var_dev}" mklabel mbr
do_log "info" "false" "Partition table '${VAR_RECIPE_TABLE}' of '/dev/${var_dev}' generated."
else
do_log "fatal" "false" "No valid partition table chosen. String was '${VAR_RECIPE_TABLE}'. Exiting setup."
exit "${ERR_PARTITIONTBL}"
fi
### Iterate through each partition on the current device.
for (( var_partition=1; var_partition<=var_partition_number; var_partition++ )); do
#for var_partition in $(seq 1 "${var_partition_number}"); do
### Generate variables for the current partition.
declare begin_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_begin"
declare end_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_end"
declare bootable_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_bootable"
declare primary_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_primary"
declare filesystem_var="recipe_${RECIPE_STRING}_dev_${var_dev}_${var_partition}_filesystem_version"
### Initialise variables.
declare BEGIN=${!begin_var}
declare END=${!end_var}
declare BOOTABLE=${!bootable_var}
declare PRIMARY=${!primary_var}
declare FILESYSTEM=${!filesystem_var}
### Generate partition.
if [[ ${END} == "-1" ]]; then
parted -s /dev/"${var_dev}" mkpart "${PRIMARY}" "${FILESYSTEM}" "${BEGIN}" 100%
do_log "info" "false" "Partition generated: '${var_partition}' | on device '/dev/${var_dev}' | begin: '${BEGIN}' | end: 100 % of remaining disk."
else
parted -s /dev/"${var_dev}" mkpart "${PRIMARY}" "${FILESYSTEM}" "${BEGIN}" "${END}"
do_log "info" "false" "Partition generated: '${var_partition}' | on device '/dev/${var_dev}' | begin: '${BEGIN}' | end: '${END}'."
fi
### Set the bootable flag if necessary.
if [[ "${BOOTABLE,,}" == true ]]; then
parted -s "/dev/${var_dev}" set "${var_partition}" boot on
do_log "info" "false" "Partition: '/dev/${var_dev}${var_partition}' marked as bootable."
fi
if [[ "${PRIMARY,,}" == logical ]]; then
parted -s "/dev/${var_dev}" set "${var_partition}" "${FILESYSTEM}" on
fi
### Save UUID of the generated partition
# shellcheck disable=SC2155
declare UUID=$(blkid -s UUID -o value "/dev/${var_dev}${var_partition}")
HMP_UUID_PARTITION["UUID_${var_dev}${var_partition}"]="${UUID}"
do_log "info" "false" "Saved in HashMap HMP_UUID_PARTITION: 'UUID_${var_dev}${var_partition}' -> '${HMP_UUID_PARTITION["UUID_${var_dev}${var_partition}"]}'"
done
done
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh