V8.00.000.2025.06.17
All checks were successful
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 59s
All checks were successful
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 59s
Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
This commit is contained in:
@@ -154,7 +154,7 @@ chroot_script() {
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Run the installer-desired code via stdin inside the chroot with bash -s.
|
||||
# Run the installer-desired code incl. positional arguments via stdin (HEREDEC) inside the chroot with bash -s.
|
||||
# Globals:
|
||||
# BASH_SOURCE
|
||||
# TERM
|
||||
@@ -163,9 +163,9 @@ chroot_script() {
|
||||
# VAR_DEBUG_TRAP
|
||||
# VAR_IN_DIALOG_WR
|
||||
# Arguments:
|
||||
# 1: Target of the chroot environment
|
||||
# 2: Command string to execute inside a shell (quoted)
|
||||
# 3: Log level of command pipeline to be executed.
|
||||
# 1: Target of chroot environment
|
||||
# 2: Command string to execute inside a shell (HEREDOC):
|
||||
# chroot_stdin "${TARGET}" "__payload__" -- "${ARG1}" "${ARG2}" ... <<'EOF' ... EOF
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_CHRT_COMMAND: on failure
|
||||
@@ -193,7 +193,7 @@ chroot_stdin() {
|
||||
DEBIAN_FRONTEND="noninteractive" \
|
||||
APT_LISTCHANGES_FRONTEND="none" \
|
||||
/bin/bash -o errexit -o errtrace -o functrace -o nounset -o pipefail \
|
||||
-O inherit_errexit -O failglob -O lastpipe -s
|
||||
-O inherit_errexit -O failglob -O lastpipe -s -- "$@"
|
||||
|
||||
then
|
||||
|
||||
|
||||
@@ -401,10 +401,18 @@ generate_totp_secret() {
|
||||
guard_trace on
|
||||
|
||||
### Derive 20 bytes via HKDF-SHA256 using OpenSSL 3 kdf, output as raw, then base32 (uppercase, no padding).
|
||||
### NOTE: 'key' must be provided via '-kdfopt key:hex:<STRING>'; expects a hexstring (no spaces).
|
||||
# shellcheck disable=SC2312
|
||||
var_secret="$(
|
||||
printf '%s' "${VAR_TEMP_PLAIN_MFA_SEED}" | xxd -r -p | openssl kdf -keylen 20 -kdfopt digest:SHA256 \
|
||||
-kdfopt salt:"${var_salt}" -kdfopt info:"${var_info}" -binary HKDF | base32 | tr -d '=' | tr '[:lower:]' '[:upper:]'
|
||||
openssl kdf -keylen 20 \
|
||||
-kdfopt digest:SHA256 \
|
||||
-kdfopt key:hex:"${VAR_TEMP_PLAIN_MFA_SEED}" \
|
||||
-kdfopt salt:"${var_salt}" \
|
||||
-kdfopt info:"${var_info}" \
|
||||
-binary HKDF \
|
||||
| base32 \
|
||||
| tr -d '=' \
|
||||
| tr '[:lower:]' '[:upper:]'
|
||||
)"
|
||||
|
||||
printf '%s\n' "${var_secret}"
|
||||
@@ -427,31 +435,39 @@ hardening_su() {
|
||||
### Declare Arrays, HashMaps, and Variables.
|
||||
declare -r pam_su="/etc/pam.d/su"
|
||||
|
||||
[[ -f "${pam_su}" ]] || return 0
|
||||
[[ -f "${TARGET}${pam_su}" ]] || return 0
|
||||
|
||||
### If the pam_wheel line already exists with the group=sudo and use_uid, then do nothing.
|
||||
if grep -Eq '^[[:space:]]*auth[[:space:]]+required[[:space:]]+pam_wheel\.so([[:space:]].*)?\bgroup=sudo\b([[:space:]].*)?\buse_uid\b' "${pam_su}"; then
|
||||
return 0
|
||||
fi
|
||||
chroot_stdin "${TARGET}" "__payload__" -- "${pam_su}" <<'EOF'
|
||||
export LC_ALL=C
|
||||
pam="$1"
|
||||
|
||||
### Insert 'auth required pam_wheel.so use_uid group=sudo' before pam_unix/rootok (fail early).
|
||||
if grep -Eq '^[[:space:]]*auth[[:space:]]+required[[:space:]]+pam_wheel[.]so([[:space:]].*)?group=sudo([[:space:]].*)?use_uid' "${pam}"; then
|
||||
:
|
||||
else
|
||||
tmp="$(mktemp "${pam}.XXXXXX")"
|
||||
### 1) Insert rule before pam_unix.so or pam_rootok.so (fail early). Fallback: append.
|
||||
awk '
|
||||
BEGIN{ins=0}
|
||||
BEGIN { ins=0 }
|
||||
{
|
||||
### Insert just before the first pam_unix or pam_rootok auth line.
|
||||
if (!ins && $0 ~ /^[[:space:]]*auth[[:space:]]+.*pam_(unix|rootok)\.so/) {
|
||||
if (!ins && $0 ~ /^[[:space:]]*auth[[:space:]]+.*pam_(unix|rootok)[.]so/ ) {
|
||||
print "auth required pam_wheel.so use_uid group=sudo"
|
||||
ins=1
|
||||
}
|
||||
print
|
||||
}
|
||||
END{
|
||||
END {
|
||||
if (!ins) {
|
||||
### Fallback: append if no anchor found
|
||||
print "auth required pam_wheel.so use_uid group=sudo"
|
||||
}
|
||||
}
|
||||
' "${pam_su}" > "${pam_su}.new" && mv -f "${pam_su}.new" "${pam_su}"
|
||||
' "${pam}" >| "${tmp}"
|
||||
|
||||
test -s "${tmp}"
|
||||
mv -f "${tmp}" "${pam}"
|
||||
rm -f -- "${tmp}" || :
|
||||
fi
|
||||
:
|
||||
EOF
|
||||
|
||||
return 0
|
||||
}
|
||||
@@ -502,7 +518,7 @@ EOF
|
||||
|
||||
if [[ ! -f "${var_sudoers_winscp_global}" ]]; then
|
||||
|
||||
cat << EOF > "${var_sudoers_winscp_global}"
|
||||
cat << EOF >| "${var_sudoers_winscp_global}"
|
||||
### Added by CISS.debian.installer. WinSCP SFTP-as-root (least privilege).
|
||||
### Allow exactly the sftp-server binary, optionally with -e (stderr logging).
|
||||
Cmnd_Alias CISS_SFTPROOT = ${var_sftp_bin}, ${var_sftp_bin} -e
|
||||
@@ -668,11 +684,12 @@ pam_access_totp_enable() {
|
||||
declare var_module="$2"
|
||||
declare var_pam_file="/etc/pam.d/${var_module}"
|
||||
declare var_users_file="${TARGET}/etc/ciss/2fa.users"
|
||||
declare var_allowlist="/etc/ciss/2fa.users"
|
||||
|
||||
### Basic sanitation; module must be a safe 'pam.d' filename.
|
||||
[[ -n "${var_user:-}" && -n "${var_module:-}" ]] || return 0
|
||||
[[ "${var_module}" =~ ^[A-Za-z0-9._+-]+$ ]] || return 0
|
||||
[[ -f "${var_pam_file}" ]] || return 0
|
||||
[[ -f "${TARGET}${var_pam_file}" ]] || return 0
|
||||
|
||||
### 0) Ensure the allowlist file contains the user (deduplicated).
|
||||
if ! grep -Fxq "${var_user}" "${var_users_file}"; then
|
||||
@@ -682,44 +699,66 @@ pam_access_totp_enable() {
|
||||
### 1) Ensure a single CISS TOTP framework block is present in the PAM file.
|
||||
### The block gates GA by pam_listfile over '/etc/ciss/2fa.users'.
|
||||
### We place it right after pam_unix.so or @include common-auth; fallback: append.
|
||||
if ! grep -q '^# CISS TOTP START$' "${var_pam_file}"; then
|
||||
awk -v START='# CISS TOTP START' -v END='# CISS TOTP END' '
|
||||
BEGIN{ins=0}
|
||||
{
|
||||
print
|
||||
if (!ins && ($0 ~ /^[[:space:]]*auth[[:space:]]+.*pam_unix\.so/ || $0 ~ /^[[:space:]]*@include[[:space:]]+common-auth/)) {
|
||||
print START
|
||||
print "auth [success=1 default=ignore] pam_listfile.so item=user sense=deny file=/etc/ciss/2fa.users onerr=ignore"
|
||||
print "auth required pam_google_authenticator.so"
|
||||
print END
|
||||
ins=1
|
||||
}
|
||||
}
|
||||
END{
|
||||
if (!ins) {
|
||||
print START
|
||||
print "auth [success=1 default=ignore] pam_listfile.so item=user sense=allow file=/etc/ciss/2fa.users onerr=ignore"
|
||||
print "auth required pam_google_authenticator.so"
|
||||
print END
|
||||
}
|
||||
}
|
||||
' "${var_pam_file}" > "${var_pam_file}.new" && mv -f "${var_pam_file}.new" "${var_pam_file}"
|
||||
fi
|
||||
chroot_stdin "${TARGET}" "__payload__" -- "${var_pam_file}" "${var_allowlist}" <<'EOF'
|
||||
export LC_ALL=C
|
||||
pam="$1"
|
||||
allowlist="$2"
|
||||
tmp="$(mktemp "${pam}.XXXXXX")"
|
||||
|
||||
awk -v START='# CISS TOTP START' -v END='# CISS TOTP END' -v allowlist="${allowlist}" '
|
||||
BEGIN { ins=0 }
|
||||
{
|
||||
print
|
||||
if (!ins && ($0 ~ /^[[:space:]]*auth[[:space:]]+.*pam_unix[.]so/ \
|
||||
|| $0 ~ /^[[:space:]]*@include[[:space:]]+common-auth/)) {
|
||||
print START
|
||||
# Only users in allowlist must pass GA:
|
||||
# pam_listfile sense=deny succeeds for non-listed → skip next line (GA)
|
||||
print "auth [success=1 default=ignore] pam_listfile.so item=user sense=deny file=" allowlist " onerr=ignore"
|
||||
print "auth required pam_google_authenticator.so"
|
||||
print END
|
||||
ins=1
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (!ins) {
|
||||
print START
|
||||
print "auth [success=1 default=ignore] pam_listfile.so item=user sense=deny file=" allowlist " onerr=ignore"
|
||||
print "auth required pam_google_authenticator.so"
|
||||
print END
|
||||
}
|
||||
}
|
||||
' "${pam}" >| "${tmp}"
|
||||
|
||||
test -s "${tmp}"
|
||||
mv -f "${tmp}" "${pam}"
|
||||
rm -f -- "${tmp}" || :
|
||||
:
|
||||
EOF
|
||||
|
||||
### 2) Comment out any other active GA lines to avoid double prompts.
|
||||
### We keep the CISS block intact (recognized by the START/END markers).
|
||||
awk '
|
||||
BEGIN{in_ciss=0}
|
||||
/^# CISS TOTP START$/ { in_ciss=1; print; next }
|
||||
/^# CISS TOTP END$/ { in_ciss=0; print; next }
|
||||
{
|
||||
if (!in_ciss && $0 ~ /^[[:space:]]*auth[[:space:]]+.*pam_google_authenticator\.so/ && $0 !~ /^[[:space:]]*#/) {
|
||||
print "# " $0
|
||||
} else {
|
||||
print
|
||||
}
|
||||
chroot_stdin "${TARGET}" "__payload__" -- "${var_pam_file}" <<'EOF'
|
||||
export LC_ALL=C
|
||||
pam="$1"
|
||||
tmp="$(mktemp "${pam}.XXXXXX")"
|
||||
awk '
|
||||
BEGIN { in_ciss=0 }
|
||||
/^# CISS TOTP START$/ { in_ciss=1; print; next }
|
||||
/^# CISS TOTP END$/ { in_ciss=0; print; next }
|
||||
{
|
||||
if (!in_ciss && $0 ~ /^[[:space:]]*auth[[:space:]]+.*pam_google_authenticator[.]so/ && $0 !~ /^[[:space:]]*#/) {
|
||||
print "# " $0
|
||||
} else {
|
||||
print
|
||||
}
|
||||
' "${var_pam_file}" > "${var_pam_file}.new" && mv -f "${var_pam_file}.new" "${var_pam_file}"
|
||||
}
|
||||
' "${pam}" >| "${tmp}"
|
||||
|
||||
test -s "${tmp}"
|
||||
mv -f "${tmp}" "${pam}"
|
||||
rm -f -- "${tmp}" || :
|
||||
:
|
||||
EOF
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user