diff --git a/conf/whitelist_mb_google_sigs.conf.sample b/conf/whitelist_mb_google_sigs.conf.sample new file mode 100644 index 0000000..de38a39 --- /dev/null +++ b/conf/whitelist_mb_google_sigs.conf.sample @@ -0,0 +1,28 @@ +# ============================================================== +# --- +# Parameter Settings for Script 'whitelist_mb_google_sigs.conf' +# --- +# ============================================================== + +# QUARANTINE_BASE_DIR +# +# Base directory where amavis stores quarantined e-mails, mostly in +# +# virus e-mails: $QUARANTINE_BASE_DIR/virus +# spam emails: $QUARANTINE_BASE_DIR/spam +# .. +# +# Defaults to: +# QUARANTINE_BASE_DIR="/var/QUARANTINE" +# +#QUARANTINE_BASE_DIR="/var/QUARANTINE" + + +# CLAMAV_VIRUS_WHITE_LIST +# +# Full path to clamav's (personal) white list file +# +# Defaults to: +# CLAMAV_VIRUS_WHITE_LIST="/var/lib/clamav/my_whitelist.ign2" +# +#CLAMAV_VIRUS_WHITE_LIST="/var/lib/clamav/my_whitelist.ign2" diff --git a/whitelist_mb_google_sigs.sh b/whitelist_mb_google_sigs.sh new file mode 100755 index 0000000..b5c1f44 --- /dev/null +++ b/whitelist_mb_google_sigs.sh @@ -0,0 +1,545 @@ +#!/usr/bin/env bash + +script_name="$(basename $(realpath $0))" +working_dir="$(dirname $(realpath $0))" + +conf_file="${working_dir}/conf/${script_name%%.*}.conf" + +log_file="$(mktemp)" +random_prefix="$(head -c 300 /dev/urandom | tr -cd 'a-zA-Z0-9' | head -c 8)" + +backup_date=$(date +%Y-%m-%d-%H%M) + + +# ============= +# --- Some functions +# ============= + +clean_up() { + + + if [[ -f "$_backup_crontab_file" ]]; then + + blank_line + echononl " (Re)Install Crontab from previously saved crontab file + '$_backup_crontab_file'.." + + crontab $_backup_crontab_file >> $log_file 2>&1 + + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + + fi + + # Perform program exit housekeeping + rm -f $log_file + rm -rf /tmp/*.${random_prefix} + blank_line + exit $1 +} + +echononl(){ + if $terminal ; then + echo X\\c > /tmp/shprompt$$ + if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then + echo -e -n " $*\\c" 1>&2 + else + echo -e -n " $*" 1>&2 + fi + rm /tmp/shprompt$$ + fi +} +echo_done() { + if $terminal ; then + echo -e "\033[80G[ \033[32mdone\033[m ]" + fi +} +echo_ok() { + if $terminal ; then + echo -e "\033[80G[ \033[32mok\033[m ]" + fi +} +echo_ignore() { + if $terminal ; then + echo -e "\033[80G[ \033[33mignore\033[m ]" + fi +} +echo_warning() { + if $terminal ; then + echo -e "\033[80G[ \033[33m\033[1mwarn\033[m ]" + fi +} +echo_failed(){ + if $terminal ; then + echo -e "\033[80G[ \033[1;31mfailed\033[m ]" + fi +} +echo_skipped() { + if $terminal ; then + echo -e "\033[80G[ \033[37mskipped\033[m ]" + fi +} + +fatal (){ + blank_line + if $terminal ; then + echo -e " [ \033[31m\033[1mFatal\033[m ]: \033[37m\033[1m$*\033[m" + echo "" + echo -e " \033[31m\033[1m Script will be interrupted..\033[m\033[m" + else + echo "fatal: $*" + echo "Script will be interrupted.." + fi + clean_up 1 +} +error(){ + blank_line + if $terminal ; then + echo -e " [ \033[31m\033[1mFehler\033[m ]: $*" + else + echo "Error: $*" + fi + blank_line +} + +warn (){ + blank_line + if $terminal ; then + echo -e " [ \033[33m\033[1mWarning\033[m ]: $*" + else + echo "Warning: $*" + fi + blank_line +} + +info (){ + if $terminal ; then + echo "" + echo -e " [ \033[32m\033[1mInfo\033[m ]: $*" + echo "" + fi +} + +## - Check if a given array (parameter 2) contains a given string (parameter 1) +## - +containsElement () { + local e + for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done + return 1 +} + +trim() { + local var="$*" + var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters + var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters + echo -n "$var" +} + +blank_line() { + if $terminal ; then + echo "" + fi +} + + + +# ---------- +# - Jobhandling +# ---------- + +# - Run 'clean_up' for signals SIGHUP SIGINT SIGTERM +# - +trap clean_up SIGHUP SIGINT SIGTERM + + +# ============= +# --- Some +# ============= + +# - Support systemd ? +# - +if [[ "X$(which systemd)" = "X" ]]; then + SYSTEMD_EXISTS=false +else + SYSTEMD_EXISTS=true +fi + +# - Running in a terminal? +# - +if [[ -t 1 ]] ; then + terminal=true +else + terminal=false +fi +#terminal=false + + +# ---------- +# Read Configurations from $conf_file +# ---------- + + +# - Give your default values here +# - +DEFAULT_QUARANTINE_BASE_DIR="/var/QUARANTINE" +DEFAULT_CLAMAV_VIRUS_WHITE_LIST="/var/lib/clamav/my_whitelist.ign2" + +blank_line +echononl "Include Configuration file.." +if [[ ! -f $conf_file ]]; then + echo_skipped + warn "No configuration file '$conf_file' found!\n + Loading default values.." +else + source $conf_file + echo_done +fi +blank_line + +[[ -z "$QUARANTINE_BASE_DIR" ]] && QUARANTINE_BASE_DIR="$DEFAULT_QUARANTINE_BASE_DIR" + +Q_VIRUS_DIR="${QUARANTINE_BASE_DIR}/virus" + +[[ -z "$CLAMAV_VIRUS_WHITE_LIST" ]] && CLAMAV_VIRUS_WHITE_LIST="$DEFAULT_CLAMAV_VIRUS_WHITE_LIST" + +# ----- +# - Doing some pre-script tasks +# ----- + +if $terminal ; then + echo "" + echo "" + echo -e "\033[37m\033[1mDoing some pre-script tasks..\033[m" + echo "" +fi + +if $terminal ; then + echo -e " \033[32mFind/Manage signatures that have already whitelistet\033[m..\n" +fi + +# - List of already whitelistet signatures +# - +_found=false +declare -a white_list=() +if [[ ! -f "$CLAMAV_VIRUS_WHITE_LIST" ]] ; then + if $terminal ; then + echo -e " \033[33mNo whitelist file present\033[m..\n" + fi +else + for _sig in $(grep -E "^MBL_" $CLAMAV_VIRUS_WHITE_LIST | sort -u) ; do + + _found=true + _failed=false + + # Decode Signatures, save output in file + # + echononl "Decode Signature \033[1m$_sig\033[m .." + sigtool --find-sigs=$_sig | sigtool --decode-sigs > /tmp/${_sig}.${random_prefix} 2> $log_file + [[ $? -ne 0 ]] && _failed=true + + # Remove blank lines and lines that only contain whitespaces + # + sed -i '/^[[:space:]]*$/d' /tmp/${_sig}.${random_prefix} >> $log_file 2>&1 + [[ $? -ne 0 ]] && _failed=true + + if $_failed ; then + echo_failed + error "$(cat $log_file)" + continue + else + echo_ok + fi + + if [[ -s "/tmp/${_sig}.${random_prefix}" ]]; then + echononl "Add signature '$_sig' whitelist array.." + white_list+=("$_sig") + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + else + echononl "Signature '$_sig' is NOT decodable.." + echo_ignore + rm -f /tmp/${_sig}.${random_prefix} > /dev/null 2>&1 + #echononl "Delete '$_sig' from whitelist '$CLAMAV_VIRUS_WHITE_LIST'.." + #sed -i "/$_sig/d" "$CLAMAV_VIRUS_WHITE_LIST" > $log_file 2>&1 + #if [[ $? -eq 0 ]]; then + # echo_ok + #else + # echo_failed + # error "$(cat $log_file)" + #fi + fi + blank_line + done + + if ! $_found ; then + if $terminal ; then + echo -e " \033[33mNo already whitelistet signature present\033[m..\n" + fi + fi +fi + + +blank_line + + +if $terminal ; then + echo -e " \033[32mGathering/Manage signatures starting with 'MBL_' from quarantined e-mails\033[m..\n" +fi + +# - Get signarures starting with "MBL_" found +# - +echononl "Gather signatures from quarantined e-mails .." +found_sigs="$(grep -o -E " MBL_[[:digit:]]*" ${Q_VIRUS_DIR}/* 2> $log_file | cut -d ' ' -f2 | sort -u)" +if [[ $? -eq 0 ]]; then + echo_done +else + echo_failed + error "$(cat $log_file)" +fi + +blank_line + +if [[ -z "$found_sigs" ]]; then + if $terminal ; then + echononl "\033[33mNo quarantined e-mails with \033[1mMBL_\033[signatures found.\033[m\n" + fi +else + declare -a google_sig_arr=() + declare -A virus_emails=() + _failed=false + for _sig in $found_sigs ; do + if $(sigtool --find-sigs=$_sig | sigtool --decode-sigs | grep -q "google.com" 2> $log_file) ; then + if containsElement "$_sig" "${white_list[@]}" ; then + echononl "Signature \033[1m$_sig\033[m already whitelisted.." + echo_ignore + else + blank_line + echononl "Mark (google) signatur \033[1m$_sig\033[m for whitelisting.." + google_sig_arr+=("$_sig") + if [[ $? -eq 0 ]]; then + echo_ok + + echononl "Decode Signature \033[1m$_sig\033[m .." + sigtool --find-sigs=$_sig | sigtool --decode-sigs > /tmp/${_sig}.${random_prefix} 2> $log_file + [[ $? -ne 0 ]] && _failed=true + + # Remove blank lines and lines that only contain whitespaces + # + sed -i '/^[[:space:]]*$/d' /tmp/${_sig}.${random_prefix} >> $log_file 2>&1 + [[ $? -ne 0 ]] && _failed=true + + if $_failed ; then + echo_failed + error "$(cat $log_file)" + _failed=false + continue + else + echo_ok + fi + + else + echo_failed + error "Adding signatur \033[1m$_sig\033[m to array 'google_sig_arr' failed!" + fi + blank_line + fi + else + echononl "Signature \033[1m$_sig\033[m does not affect google.com.." + echo_ignore + fi + done +fi + + +blank_line +if [[ ${#google_sig_arr[@]} -lt 1 ]]; then + if $terminal ; then + info "No quarantined e-mails with google.com signature found. + + Nothing do to, exit now.." + fi + clean_up 0 +fi + + +if $terminal ; then + echo -e " \033[32mGather/Manage quarantined e-mails with detected google signature\033[m..\n" +fi + +for _sig in ${google_sig_arr[@]}; do + #_emails="$(grep INFECTED ${Q_VIRUS_DIR}/* | grep "$_sig" | cut -d ':' -f1 | sed -e "s#^${QUARANTINE_BASE_DIR}/##")" + _emails="$(grep INFECTED ${Q_VIRUS_DIR}/* | grep "$_sig" | cut -d ':' -f1)" + for _email in $_emails ; do + _email="${_email#"${QUARANTINE_BASE_DIR}/virus/"}" + echononl "Add \033[1m$_email\033[m with signatur \033[1m$_sig\033[m to list.." + virus_emails+=(["$_email"]="$_sig") + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + echononl "Add signature \033[1m$_sig\033[m to whitelist array.." + if containsElement "$_sig" "${white_list[@]}" ; then + echo_skipped + else + white_list+=("$_sig") + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + fi + done +done + + + +# ----- +# - Main Part of Script +# ----- + +if $terminal ; then + echo "" + echo "" + echo -e "\033[37m\033[1mMain Part of Script.\033[m" + echo "" +fi + +if $terminal ; then + echo -e " \033[32mWrite new whitelist file\033[m..\n" +fi + +tmp_whitelist_file="/tmp/$(basename "${CLAMAV_VIRUS_WHITE_LIST}").${random_prefix}" +:> "$tmp_whitelist_file" +for _sig in ${white_list[@]} ; do + _failed=false + echononl "Add signatur \033[1m$_sig\033[m to clamav's whitelist file" + while IFS='' read -r line || [[ -n "$line" ]] ; do + echo "# $line" >> "$tmp_whitelist_file" 2>> "$log_file" + [[ $? -ne 0 ]] && _failed=true + done < "/tmp/${_sig}.${random_prefix}" + echo "$_sig" >> "$tmp_whitelist_file" 2>> "$log_file" + [[ $? -ne 0 ]] && _failed=true + if $_failed ; then + echo_failed + error "$(cat $log_file)" + _failed=false + else + echo_ok + if ! $terminal ; then + echo "" + echo " Add Signatur "$_sig" to clamav's whitelist \"${CLAMAV_VIRUS_WHITE_LIST}\"" + fi + fi +done + +blank_line + +echononl "Copy the temporary whitelist file to the designated location.." +cp "$tmp_whitelist_file" "${CLAMAV_VIRUS_WHITE_LIST}" > "$log_file" 2>&1 +if [[ $? -eq 0 ]]; then + echo_ok +else + echo_failed + error "$(cat $log_file)" +fi + +# Remove blank lines and lines that only contain whitespaces +# +echononl "Remove empty lines from whitelist file.." +sed -i '/^[[:space:]]*$/d' "${CLAMAV_VIRUS_WHITE_LIST}" > "$log_file" 2>&1 +if [[ $? -eq 0 ]]; then + echo_ok +else + echo_failed + error "$(cat $log_file)" +fi + + +blank_line + +if $terminal ; then + echo -e " \033[32mResend quarantined e-mails with detected google signature\033[m..\n" +fi + +if [[ ${#virus_emails[@]} -lt 1 ]]; then + error "No quarantined e-mails with detected google signature found." +else + for _virus_email in "${!virus_emails[@]}"; do + _recipient="$( + grep "X-Envelope-To-Blocked:" ${Q_VIRUS_DIR}/${_virus_email} 2> "$log_file" \ + | grep -o -E "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" + )" + + echononl "Resend blocked e-mail with signatur \033[1m${virus_emails[$_virus_email]}\033[m + to \033[1m$_recipient\033[m" + + amavisd-release virus/${_virus_email} > "$log_file" 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + + echononl "Remove \033[1mvirus/${_virus_email}\033[m from QUARANTINE directory.." + rm "${Q_VIRUS_DIR}/${_virus_email}" > "$log_file" 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi + else + echo_failed + error "$(cat $log_file)" + fi + blank_line + + done +fi + + +if $terminal ; then + echo "" + echo "" + echo -e "\033[37m\033[1mDoing some post-script tasks..\033[m" + echo "" +fi + +echononl "Restart ClamAV Daemon" +if $SYSTEMD_EXISTS ; then + systemctl restart clamav-daemon > "$log_file" 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi +else + /etc/init.d/clamav-daemon restart > "$log_file" 2>&1 + if [[ $? -eq 0 ]]; then + echo_ok + else + echo_failed + error "$(cat $log_file)" + fi +fi + + +blank_line + +clean_up 1 + + +# ----- +# - Doing some post-script tasks +# ----- + +