Files
CISS.debian.installer/func/cdi_4500_user/4500_installation_accounts.sh
Marc S. Weidner d43638d262
All checks were successful
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 1m41s
V8.00.000.2025.06.17
Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
2025-08-28 17:40:06 +02:00

289 lines
9.5 KiB
Bash

#!/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
#######################################
# Updating user accounts.
# Globals:
# TARGET
# VAR_SETUP_PATH
# VAR_USER_MAX
# user_root_authentication_access_ssh
# user_root_password
# user_root_shell
# user_root_sshpubkey
# Arguments:
# None
# Returns:
# 0: on success
#######################################
installation_accounts() {
### Declare Arrays, HashMaps, and Variables.
declare -i i
declare tmp_username="" tmp_fullname="" tmp_uid="" tmp_gid="" tmp_shell="" tmp_password="" tmp_sshpubkey="" tmp_sudo="" \
tmp_restricted=""
declare var_username="" var_fullname="" var_uid="" var_gid="" var_shell="" var_password="" var_sshpubkey="" var_sudo="" \
var_restricted="" var_chpasswd="" var_sshdir=""
### Hardening '/etc/login.defs'
rm -f "${TARGET}/etc/login.defs"
insert_header "${TARGET}/etc/login.defs"
insert_comments "${TARGET}/etc/login.defs"
cat "${VAR_SETUP_PATH}/includes/target/etc/login.defs" >> "${TARGET}/etc/login.defs"
### Hardening '/etc/security/pwquality.conf'
rm -f "${TARGET}/etc/security/pwquality.conf"
insert_header "${TARGET}/etc/security/pwquality.conf"
insert_comments "${TARGET}/etc/security/pwquality.conf"
cat "${VAR_SETUP_PATH}/includes/target/etc/security/pwquality.cnf" >> "${TARGET}/etc/security/pwquality.conf"
### Preparing the root account
chown root:root "${TARGET}/etc/passwd" "${TARGET}/etc/shadow" "${TARGET}/etc/group" "${TARGET}/etc/gshadow"
chmod 0644 "${TARGET}/etc/passwd" "${TARGET}/etc/group"
chmod 0600 "${TARGET}/etc/shadow" "${TARGET}/etc/gshadow"
if [[ -x "${TARGET}${user_root_shell}" ]]; then
chroot_exec "${TARGET}" chsh -s "${user_root_shell}" root
else
do_log "warn" "file_only" "4500() Shell: '${user_root_shell}' not found for: 'root'. Using '/bin/bash' instead."
fi
var_chpasswd="root:${user_root_password}"
chroot_script "${TARGET}" "echo \"${var_chpasswd}\" | chpasswd -e"
var_chpasswd=""
install -d -m 0700 -o root -g root "${TARGET}/root/.ssh"
install -m 0600 -o root -g root /dev/null "${TARGET}/root/.ssh/authorized_keys"
grep -qxF "${user_root_sshpubkey}" "${TARGET}/root/.ssh/authorized_keys" || \
printf "%s\n" "${user_root_sshpubkey}" >> "${TARGET}/root/.ssh/authorized_keys"
if [[ "${user_root_authentication_access_ssh}" == "false" ]]; then
if grep -q '^\s*PermitRootLogin' "${TARGET}/etc/ssh/sshd_config"; then
sed -i 's/^\s*PermitRootLogin\s\+.*/PermitRootLogin no/' "${TARGET}/etc/ssh/sshd_config"
else
echo 'PermitRootLogin no' >> "${TARGET}/etc/ssh/sshd_config"
fi
fi
install -D -m 0600 -o root -g root "${VAR_SETUP_PATH}/includes/target/etc/skel/.bashrc" "${TARGET}/root/"
install -D -m 0600 -o root -g root "${VAR_SETUP_PATH}/includes/target/etc/skel/.zshrc" "${TARGET}/root/"
install -D -m 0600 -o root -g root "${VAR_SETUP_PATH}/includes/target/root/.ciss/alias" "${TARGET}/root/.ciss/"
install -D -m 0700 -o root -g root "${VAR_SETUP_PATH}/includes/target/root/.ciss/clean_logout.sh" "${TARGET}/root/.ciss/"
install -D -m 0600 -o root -g root "${VAR_SETUP_PATH}/includes/target/root/.ciss/shortcuts" "${TARGET}/root/.ciss/"
# To be able to copy/paste from vim, one needs to create a '.vimrc' with the following content:
echo 'set clipboard=unnamed' >| "${TARGET}/root/.vimrc"
chmod 0600 "${TARGET}/root/.vimrc"
do_log "info" "file_only" "User: 'root' updated."
### Install all user accounts.
for ((i = 0; i <= VAR_USER_MAX; i++)); do
tmp_username="user_user${i}_name"
tmp_fullname="user_user${i}_fullname"
tmp_uid="user_user${i}_uid"
tmp_gid="user_user${i}_gid"
tmp_shell="user_user${i}_shell"
tmp_password="user_user${i}_password"
tmp_sshpubkey="user_user${i}_sshpubkey"
tmp_sudo="user_user${i}_privileges_sudo"
tmp_restricted="user_user${i}_privileges_restricted"
var_username="${!tmp_username}"
var_fullname="${!tmp_fullname}"
var_uid="${!tmp_uid}"
var_gid="${!tmp_gid}"
var_shell="${!tmp_shell}"
var_password="${!tmp_password}"
var_sshpubkey="${!tmp_sshpubkey}"
var_sudo="${!tmp_sudo}"
var_restricted="${!tmp_restricted}"
chroot_exec "${TARGET}" getent group "${var_username}" >/dev/null || \
chroot_exec "${TARGET}" groupadd --gid "${var_gid}" "${var_username}"
if [[ "${var_restricted}" == "false" ]]; then
chroot_exec "${TARGET}" useradd \
--comment "${var_fullname}" \
--create-home \
--expiredate 2102-12-31 \
--gid "${var_gid}" \
--home-dir /home/"${var_username}" \
--inactive 0 \
--shell "${var_shell}" \
--uid "${var_uid}" \
"${var_username}"
else
chroot_exec "${TARGET}" useradd \
--comment "${var_fullname}" \
--expiredate 2102-12-31 \
--gid "${var_gid}" \
--home-dir /home/"${var_username}" \
--inactive 0 \
--no-create-home \
--shell "${var_shell}" \
--uid "${var_uid}" \
"${var_username}"
fi
var_chpasswd="${var_username}:${var_password}"
chroot_script "${TARGET}" "echo \"${var_chpasswd}\" | chpasswd -e"
var_chpasswd=""
if [[ "${var_sudo}" == "true" ]]; then
chroot_exec "${TARGET}" usermod -aG sudo "${var_username}"
fi
if [[ -n "${var_sshpubkey}" ]]; then
var_sshdir="${TARGET}/home/${var_username}/.ssh"
install -d -m 0700 -o "${var_username}" -g "${var_username}" "${var_sshdir}"
install -m 0600 -o "${var_username}" -g "${var_username}" /dev/null "${var_sshdir}/authorized_keys"
grep -qxF "${var_sshpubkey}" "${var_sshdir}/authorized_keys" || \
printf "%s\n" "${var_sshpubkey}" >> "${var_sshdir}/authorized_keys"
fi
do_log "info" "file_only" "Created user: [${var_username}] UID: [${var_uid}], GID: [${var_gid}]"
done
unset VAR_TEMP_PLAIN_MFA_SEED
guard_dir && return 0
}
#######################################
# Writes '.google_authenticator'-file for the respective user.
# Globals:
# RANDOM
# TARGET
# Arguments:
# 1: Username
# Returns:
# 0: on success
#######################################
write_google_authenticator_file() {
### Declare Arrays, HashMaps, and Variables.
declare var_user="${1}" var_secret=""
case "${1}" in
root) declare var_base="${TARGET}/root" ;;
*) declare var_base="${TARGET}/home/${var_user}" ;;
esac
declare -i i=0
### TODO: PASSWORD REMINDER START:NOT ACTIVE
#guard_trace on
var_secret="$(generate_totp_secret "${var_user}")"
umask 0077
{
printf '%s\n' "${var_secret}"
printf '"RATE_LIMIT 3 30"\n'
printf '"WINDOW 10"\n'
printf '"DISALLOW_REUSE"\n'
printf '"TOTP_AUTH"\n'
### Emergency Codes:
for i in {0..7}; do printf '%08d\n' "$(( RANDOM % 100000000 ))"; done
} >| "${var_base}/.google_authenticator"
### TODO: PASSWORD REMINDER STOP:NOT ACTIVE
#guard_trace off
chown "${var_user}:${var_user}" "${var_base}/.google_authenticator"
chmod 0600 "${var_base}/.google_authenticator"
umask 0022
return 0
}
#######################################
# Generates a deterministic TOTP secret based on:
# Username, FQDN, MFA salt, MFA master seed
# Globals:
# VAR_FINAL_FQDN
# VAR_TEMP_PLAIN_MFA_SEED
# user_mfa_info
# user_mfa_salt
# Arguments:
# 1: Username
# Returns:
# 0: on success
#######################################
generate_totp_secret() {
### Declare Arrays, HashMaps, and Variables.
declare var_user="${1}"
declare var_host_id="${VAR_FINAL_FQDN}"
declare var_salt="${user_mfa_salt}:${var_host_id}:${var_user}"
declare var_info="${user_mfa_info}"
declare var_secret=""
### TODO: PASSWORD REMINDER START:NOT ACTIVE
#guard_trace on
### Derive 20 bytes via HKDF-SHA256 using OpenSSL 3 kdf, output as raw, then base32 (uppercase, no padding).
# 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:]'
)"
### TODO: PASSWORD REMINDER STOP:NOT ACTIVE
#guard_trace off
printf '%s\n' "${var_secret}"
return 0
}
#######################################
# Reads a 256-bit seed from '${DIR_CNF}/mfa_master.txt' (64 hex chars) into VAR_TEMP_PLAIN_MFA_SEED.
# Globals:
# DIR_CNF
# VAR_TEMP_PLAIN_MFA_SEED
# Arguments:
# None
# Returns:
# 0: on success
# ERR_READ_SEED_FILE
#######################################
read_totp_seed(){
### Declare Arrays, HashMaps, and Variables.
declare -r var_mfa_seed_file="${DIR_CNF}/mfa_master.txt"
declare -g VAR_TEMP_PLAIN_MFA_SEED=""
### TODO: PASSWORD REMINDER START:NOT ACTIVE
#guard_trace on
if ! read_password_file "${var_mfa_seed_file}" VAR_TEMP_PLAIN_MFA_SEED; then
return "${ERR_READ_SEED_FILE}"
fi
### Validate: exactly 64 hex.
[[ "${VAR_TEMP_PLAIN_MFA_SEED}" =~ ^[0-9a-fA-F]{64}$ ]] || return "${ERR_READ_SEED_FILE}"
### TODO: PASSWORD REMINDER STOP:NOT ACTIVE
#guard_trace off
return 0
}
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh