94 lines
3.3 KiB
Bash
94 lines
3.3 KiB
Bash
#!/usr/bin/env bash
|
||
|
||
# Wonder Cohen - The Hague The Netherlands
|
||
# shell_history_audit.sh – put in /etc/profile.d
|
||
# Logs every interactive-bash command (including within sudo) to /var/log/history
|
||
# Author: Roy Cohen <roy@wondercohen.nl> Last-update: 2025-06-23
|
||
|
||
### Installation notes:
|
||
## Create the script
|
||
# /etc/profile.d/shell_history_audit.sh
|
||
|
||
## Create log directory and group
|
||
# sudo groupadd -f historylog
|
||
# sudo mkdir -p /var/log/history
|
||
# sudo chown root:historylog /var/log/history
|
||
# sudo chmod 1770 /var/log/history
|
||
|
||
## Create the error log
|
||
# sudo touch /var/log/history_audit_errors.log
|
||
# sudo chown root:historylog /var/log/history_audit_errors.log
|
||
# sudo chmod 666 /var/log/history_audit_errors.log
|
||
|
||
## Secure script
|
||
# sudo chmod 644 /etc/profile.d/shell_history_audit.sh
|
||
# sudo chown root:root /etc/profile.d/shell_history_audit.sh
|
||
|
||
## Make log files append-only (optional)
|
||
# sudo find /var/log/history -type f -exec chattr +a {} \;
|
||
#
|
||
## Sudo environment setting
|
||
# visudo
|
||
# Defaults env_keep += "HISTFILE HISTTIMEFORMAT"
|
||
#
|
||
|
||
##############################################################################
|
||
# Config – change these once
|
||
HISTDIR="/var/log/history"
|
||
AUDITGROUP="historylog" # group allowed to read the logs
|
||
LOG_MODE=0640 # -rw-r----- root:historylog
|
||
DIR_MODE=1770 # drwxrwx--T root:historylog
|
||
AUTO_LOGOUT=3600 # seconds
|
||
ERRLOG="/var/log/history_audit_errors.log"
|
||
|
||
##############################################################################
|
||
# Skip for non-interactive shells
|
||
[[ $- != *i* ]] && return
|
||
|
||
##############################################################################
|
||
# Auto-logout
|
||
readonly TMOUT="$AUTO_LOGOUT"
|
||
export TMOUT
|
||
|
||
##############################################################################
|
||
# Determine source user (for sudo tracking)
|
||
if [[ -n "${SUDO_USER:-}" && $SUDO_USER != "$USER" ]]; then
|
||
SRC="$SUDO_USER"
|
||
else
|
||
SRC=$(logname 2>/dev/null || echo "$USER")
|
||
fi
|
||
|
||
LOGFILE="$HISTDIR/${USER}_${SRC}.log"
|
||
|
||
##############################################################################
|
||
# Create logfile if directory is writable and it doesn't exist
|
||
if [[ -w "$HISTDIR" && ! -e "$LOGFILE" ]]; then
|
||
touch "$LOGFILE" # we have permission
|
||
chmod "$LOG_MODE" "$LOGFILE" 2>/dev/null || true
|
||
chown "$USER:$AUDITGROUP" "$LOGFILE" 2>/dev/null || true
|
||
fi
|
||
##############################################################################
|
||
# Check group membership (user must be in $AUDITGROUP)
|
||
if ! id -nG "$USER" | grep -qw "$AUDITGROUP"; then
|
||
logger -t shell_history_audit "DENIED: $USER is not in $AUDITGROUP group. History logging skipped."
|
||
return 0
|
||
fi
|
||
##############################################################################
|
||
# Activate history logging only when logfile exists & is writable
|
||
if [[ -w "$LOGFILE" ]]; then
|
||
export HISTFILE="$LOGFILE"
|
||
export HISTSIZE=
|
||
export HISTFILESIZE=
|
||
export HISTIGNORE=''
|
||
export HISTCONTROL='ignoreboth'
|
||
export HISTTIMEFORMAT='%F %T '
|
||
|
||
shopt -s histappend
|
||
case "${PROMPT_COMMAND:-}" in
|
||
*history\ -a*) : ;;
|
||
*) PROMPT_COMMAND="history -a${PROMPT_COMMAND:+; $PROMPT_COMMAND}" ;;
|
||
esac
|
||
else
|
||
# Log error (optional)
|
||
echo "$(date '+%F %T') WARN: Could not activate logging for $USER to $LOGFILE" >> "$ERRLOG" 2>/dev/null || true
|
||
fi |