332 lines
14 KiB
Bash
332 lines
14 KiB
Bash
#!/bin/bash
|
|
set -euo pipefail
|
|
# http://www.postfix.org/FILTER_README.html
|
|
# Clean up when done or when aborting.
|
|
finished=false
|
|
|
|
SENDMAIL=$(which sendmail)
|
|
if [ -z ${SENDMAIL} ]; then
|
|
if [ -x "/usr/sbin/sendmail" ]; then
|
|
SENDMAIL="/usr/sbin/sendmail"
|
|
else
|
|
nessage "Sendmail command not found"
|
|
fi
|
|
fi
|
|
|
|
function finish {
|
|
${finished} || logger -t disclaimer "Disclaimer script not finished cleanly."
|
|
message "Sendmail command: ${SENDMAIL} -v -v ${ARGUMENTS} <in.$$"
|
|
# shellcheck disable=SC2086
|
|
result=$("${SENDMAIL}" -v -v ${ARGUMENTS} <"in.$$")
|
|
return_code="${?}"
|
|
if [[ "${return_code}" != "0" ]]; then
|
|
message "Error ${return_code} sending file to sendmail"
|
|
message "result: ${result}"
|
|
echo "Error ${return_code} sending file to sendmail with disclaimer.sh. result: ${result}" | mail -s "Error in disclaimer.sh filter" ad@susurrando.com
|
|
exit ${return_code}
|
|
fi
|
|
}
|
|
#trap "$SENDMAIL '$@' <in.$$" 0 1 2 3 15
|
|
trap finish exit
|
|
|
|
LOGFILE=/var/log/disclaimer.log
|
|
if [ ! -w "${LOGFILE}" ]; then
|
|
LOGFILE="${HOME}/log/disclaimer.log"
|
|
if [ ! -w "${LOGFILE}" ]; then
|
|
LOGFILE="./disclaimer.log"
|
|
fi
|
|
fi
|
|
function message() {
|
|
HIDE="${2}"
|
|
CDATE=$(date '+%Y-%m-%d %H:%M:%S')
|
|
APP=$(basename "${0}")
|
|
MSG="[$$] ${1}"
|
|
if [[ "${HIDE}" != "true" ]]; then
|
|
echo "${MSG}"
|
|
fi
|
|
/usr/bin/logger -t "${APP}" "${MSG}"
|
|
echo "${CDATE} ${MSG}" >> "${LOGFILE}"
|
|
}
|
|
ARGUMENTS=${*}
|
|
|
|
inspect_dir=/var/spool/filter
|
|
export HOME="${inspect_dir}"
|
|
out_stat_folder="${inspect_dir}/out.stats"
|
|
mkdir -p "${out_stat_folder}"
|
|
in_stat_folder="${inspect_dir}/in.stats"
|
|
mkdir -p "${in_stat_folder}"
|
|
|
|
DISCLAIMER_ADDRESSES=/etc/postfix/disclaimer_addresses
|
|
|
|
TEXT_DISCLAIMER=/etc/postfix/text_disclaimer.txt
|
|
HTML_DISCLAIMER_FILE=/etc/postfix/html_disclaimer.htm
|
|
|
|
# Exit codes from <sysexits.h>
|
|
EX_TEMPFAIL=75
|
|
EX_UNAVAILABLE=69
|
|
|
|
DATE=$(date +%s)
|
|
|
|
#GetRecordID $FROM mail_addresses mail_address mail
|
|
function GetRecordID() {
|
|
TEXT=$(echo "$1" | sed "s/'/\'/g" -)
|
|
ERR="${?}"
|
|
if [[ "$ERR" != "0" ]]
|
|
then
|
|
message "Error $ERR escaping single quotes from TEXT in GetRecordID"
|
|
fi
|
|
if [[ "$TEXT" == "" ]]; then
|
|
echo NULL
|
|
else
|
|
TABLE=$(echo "$2" | sed "s/'/\'/g" -)
|
|
ERR="${?}"
|
|
if [[ "$ERR" != "0" ]]
|
|
then
|
|
message "Error $ERR escaping single quotes from TABLE in GetRecordID"
|
|
fi
|
|
FIELD=$(echo "$3" | sed "s/'/\'/g" -)
|
|
ERR="${?}"
|
|
if [[ "$ERR" != "0" ]]
|
|
then
|
|
message "Error $ERR escaping single quotes from FIELD in GetRecordID"
|
|
fi
|
|
DATABASE=$(echo "$4" | sed "s/'/\'/g" -)
|
|
ERR="${?}"
|
|
if [[ "$ERR" != "0" ]]
|
|
then
|
|
message "Error $ERR escaping single quotes from DATABASE in GetRecordID"
|
|
fi
|
|
if [[ "$DATABASE" == "" ]]; then
|
|
message "No database indicated." true
|
|
else
|
|
ACTION=$(echo "$5" | sed "s/'/\'/g" -)
|
|
ERR="${?}"
|
|
if [[ "$ERR" != "0" ]]
|
|
then
|
|
message "Error $ERR escaping single quotes from $ACTION in GetRecordID"
|
|
fi
|
|
QUERY="SELECT id FROM $TABLE WHERE $FIELD='$TEXT';"
|
|
result=$(echo "$QUERY" | /usr/bin/env mysql "$DATABASE")
|
|
resultID=$(echo "$result" | grep -v id)
|
|
return_code="${?}"
|
|
if [[ "$return_code" != "0" ]]; then
|
|
message "Error getting $FIELD id for $TEXT from database with query '$QUERY'. result: $result" true
|
|
else
|
|
if [[ "$resultID" == "" ]]; then
|
|
message "The field '$TABLE.$FIELD' in database '$DATABASE' doesn't contain a record '$TEXT', adding it."
|
|
QUERY="INSERT INTO $TABLE (id, $FIELD) VALUES (NULL, '$TEXT');"
|
|
temp_file=$(mktemp /tmp/tmp.XXXXX)
|
|
echo "$QUERY" | /usr/bin/env mysql -v -v -v "$DATABASE" &> "${temp_file}"
|
|
return_code="${?}"
|
|
result=$(cat "${temp_file}")
|
|
if [[ "$return_code" != "0" ]]; then
|
|
message "Error $return_code adding $FIELD to database '$DATABASE' with query '$QUERY'. result: $result" true
|
|
else
|
|
QUERY="SELECT id FROM $TABLE WHERE $FIELD='$FROM';"
|
|
result=$(echo "$QUERY" | /usr/bin/env mysql "${DATABASE}")
|
|
resultID=$(echo "$result" | grep -v id)
|
|
return_code="${?}"
|
|
if [[ "$return_code" != "0" ]]; then
|
|
message "Error $return_code obtaining $FIELD id with query '$QUERY'. result: $result" true
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
echo "${resultID}"
|
|
fi
|
|
fi
|
|
}
|
|
function FromID() {
|
|
FROM="$1"
|
|
SENDER_ID=$(GetRecordID "$FROM" senders sender mail "Getting Id for From $1")
|
|
echo "${SENDER_ID}"
|
|
}
|
|
function RecipientID() {
|
|
RECIPIENT="$1"
|
|
RECIPIENT_ID=$(GetRecordID "$FROM" recipients recipient mail "Getting Id for To $1")
|
|
echo "${RECIPIENT_ID}"
|
|
}
|
|
# Start processing.
|
|
|
|
message "Processing message 'in.$$' as user '$(whoami)'..."
|
|
|
|
cd "${inspect_dir}" || exit
|
|
return_code="${?}"
|
|
if [[ "$return_code" != "0" ]]; then
|
|
message "Error $return_code changing to directory '$inspect_dir'"
|
|
exit $EX_TEMPFAIL;
|
|
fi
|
|
|
|
cat >in.$$
|
|
return_code="${?}"
|
|
if [[ "$return_code" != "0" ]]; then
|
|
message "Cannot save mail to file"
|
|
exit $EX_TEMPFAIL
|
|
fi
|
|
message "Adding labels..."
|
|
/usr/bin/env python3 /etc/postfix/labeler.py in.$$ > in.$$.labeler.log
|
|
cp in.$$.labeler.log /var/spool/filter/last_message.eml.labeler.log -rfp
|
|
#Save last message
|
|
message "Saving as last_message.eml..."
|
|
cp in.$$ /var/spool/filter/last_message.eml -rfp
|
|
#Save copy of the messages. DANGEROUS!! Will consumpt disk space
|
|
message "Saving copy of message (this might fill the disk)..."
|
|
mkdir -p "/var/spool/filter/$(date +%Y%m%d)/"
|
|
cp in.$$ "/var/spool/filter/$(date +%Y%m%d)/$(date +%Y%m%d%H%M%S%N).eml" -rfp
|
|
# obtain headers
|
|
message "Obtaining headers..."
|
|
HEADERS=$(sed ':a;N;$!ba;s/\n\n.*//g' in.$$)
|
|
messageID=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 -i "^message-id: " | sed 's/^message-id: //g' | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "message ID: '$messageID'"
|
|
FROMLONG=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^From:" | sed "s/From: //" -)
|
|
SENDER_ID=$(FromID "$FROM")
|
|
message "From(long): '${FROMLONG}' (Id: $SENDER_ID)"
|
|
FROM=$(echo "${FROMLONG}" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "From(short): '${FROM}'"
|
|
SUBJECT=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^Subject:" | sed "s/Subject: //" - | sed "s/'/\'/g" - )
|
|
message "Subject: '$SUBJECT'"
|
|
RECIPIENT=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^To:" | sed "s/To: //g" - | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
RECIPIENT_ID=$(RecipientID "$RECIPIENT")
|
|
message "TO: '$RECIPIENT'"
|
|
CCRECIPIENT=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^Cc:" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "CC: '$CCRECIPIENT'"
|
|
BCRECIPIENT=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^Bcc:" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "CCO: '$BCRECIPIENT'"
|
|
DELIVEREDTO=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^Delivered-To:" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "Delivered to: '$DELIVEREDTO'"
|
|
RETURNPATH=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^Return-Path:" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "Return path: '$RETURNPATH'"
|
|
REPLYTO=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^Reply-To:" | sed "s/Sender: //g" - | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "Reply to: '$REPLYTO'"
|
|
XORIGINALSENDER=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' |grep -m 1 "^X-Original-Sender:" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "Reply to (original sender): '$XORIGINALSENDER'"
|
|
SENDER=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^Sender:" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "Reply to (sender): '$SENDER'"
|
|
XFORWARDEDTO=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^X-Forwarded-To:" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "Reply to (forwarded to): '$XFORWARDEDTO'"
|
|
XFORWARDEDFOR=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' |grep -m 1 "^X-Forwarded-For:" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "Reply to (forwarded for): '$XFORWARDEDFOR'"
|
|
XBEENTHERE=$(echo "$HEADERS" | sed ':a;N;$!ba;s/\n\s/ /g' | grep -m 1 "^X-BeenThere:" | cut -d "<" -f 2 | cut -d ">" -f 1 | sed "s/'/\'/g" - )
|
|
message "Reply to (been there): '$XBEENTHERE'"
|
|
|
|
if grep -qi "^${FROM}$" "${DISCLAIMER_ADDRESSES}"; then
|
|
message "This is a mail from a local user '$FROM' with a disclaimer text, adding it to the message..."
|
|
DIRECTION=0
|
|
CURHOUR=$(date +%Y%m%d%H)
|
|
if [[ -e $in_stat_folder/$CURHOUR.stats ]]; then
|
|
CURHOURSTAT=$(cat "$in_stat_folder/$CURHOUR.stats")
|
|
else
|
|
CURHOURSTAT=0
|
|
fi
|
|
CURHOURSTAT=$((CURHOURSTAT + 1))
|
|
echo "$CURHOURSTAT" > "$in_stat_folder/$CURHOUR.stats"
|
|
QUERY="INSERT INTO messages (id, sender_id, subject, date, messageid) VALUES (NULL, '$SENDER_ID', '$SUBJECT', '$DATE', '$messageID');"
|
|
temp_file=$(mktemp /tmp/tmp.XXXX)
|
|
echo "$QUERY" | /usr/bin/env mysql -v -v -v mailview &> "${temp_file}"
|
|
return_code="${?}"
|
|
result=$(cat "${temp_file}")
|
|
if [[ "$return_code" != "0" ]]; then
|
|
message "Error $return_code while adding message to database 'mailview' with query '$QUERY'. result: '${result}'"
|
|
fi
|
|
QUERY="SELECT id FROM messages WHERE sender_id='$SENDER_ID' AND subject='$SUBJECT' AND date='$DATE';"
|
|
# MSG_ID=$(echo "$QUERY" | /usr/bin/env mysql mailview | grep -v id)
|
|
return_code="${?}"
|
|
if [[ "$return_code" != "0" ]]; then
|
|
message "Error $return_code while obtaining message id with query '$QUERY' from database 'mailview'"
|
|
fi
|
|
|
|
TMP_HTML_DISCLAIMER_FILE=$(/bin/mktemp /tmp/disclaimer.XXXXX)
|
|
if [[ -r /etc/postfix/$FROM.disclaimer.html ]]; then
|
|
HTML_DISCLAIMER="/etc/postfix/$FROM.disclaimer.html"
|
|
echo "${HTML_DISCLAIMER}" > /dev/null
|
|
fi
|
|
sed "s/id=MSGID/id=$DB_MSG_ID/g" $HTML_DISCLAIMER_FILE > "$TMP_HTML_DISCLAIMER_FILE"
|
|
TMP_HTML_DISCLAIMER_FILE_BIS=$(/bin/mktemp /tmp/disclaimer.XXXXX)
|
|
sed "s/SENDERID/$SENDER_ID/g" "$TMP_HTML_DISCLAIMER_FILE" > "$TMP_HTML_DISCLAIMER_FILE_BIS"
|
|
sed "s/RECIPIENTID/$RECIPIENT_ID/g" "$TMP_HTML_DISCLAIMER_FILE_BIS" > "$TMP_HTML_DISCLAIMER_FILE"
|
|
message "Disclaimer HTML at '$TMP_HTML_DISCLAIMER_FILE'"
|
|
if [[ -r /etc/postfix/$FROM.disclaimer.txt ]]; then
|
|
TEXT_DISCLAIMER=/etc/postfix/$FROM.disclaimer.txt
|
|
fi
|
|
|
|
message "Running altermime with: /usr/bin/altermime --input=in.$$ --log-syslog --log-stdout --disclaimer=$TEXT_DISCLAIMER --disclaimer-html=$TMP_HTML_DISCLAIMER_FILE --xheader=\"X-MTA: $(cat /etc/mailname)\""
|
|
ALTERMIMEresult=$(/usr/bin/altermime --input=in.$$ --log-syslog --log-stdout --disclaimer="$TEXT_DISCLAIMER" --disclaimer-html="$TMP_HTML_DISCLAIMER_FILE" --xheader="X-MTA: $(cat /etc/mailname)")
|
|
message "altermime result: $ALTERMIMEresult"
|
|
return_code="${?}"
|
|
if [[ "$return_code" != "0" ]]; then
|
|
message "Error $return_code message content rejected."
|
|
exit $EX_UNAVAILABLE;
|
|
fi
|
|
else
|
|
DIRECTION=1
|
|
message "Sender '$FROMLONG' ($FROM) is NOT in disclaimer addresses file"
|
|
CURHOUR=$(date +%Y%m%d%H)
|
|
if [[ -e $out_stat_folder/$CURHOUR.stats ]]; then
|
|
CURHOURSTAT=$(cat "$out_stat_folder/$CURHOUR.stats")
|
|
else
|
|
CURHOURSTAT=0
|
|
fi
|
|
CURHOURSTAT=$((CURHOURSTAT + 1))
|
|
echo $CURHOURSTAT > "$out_stat_folder/$CURHOUR.stats"
|
|
fi
|
|
|
|
#Stats
|
|
FROMID=$(GetRecordID "$FROM" mail_addresses mail_address mail "Get ID of From $FROM")
|
|
message "From $FROM with ID $FROMID"
|
|
if [[ "$RECIPIENT" != "" ]]; then
|
|
TOID=$(GetRecordID "$RECIPIENT" mail_addresses mail_address mail "Get ID of To $TO")
|
|
else
|
|
TOID="0"
|
|
fi
|
|
message "To $RECIPIENT with ID $TOID"
|
|
if [[ -z "$CCRECIPIENT" ]]; then
|
|
CCID=$(GetRecordID "$CCRECIPIENT" mail_addresses mail_address mail "Get ID of CC")
|
|
else
|
|
CCID="0"
|
|
fi
|
|
if [[ -z "$BCRECIPIENT" ]]; then
|
|
CCOID=$(GetRecordID "$BCRECIPIENT" mail_addresses mail_address mail "Get ID of BCC")
|
|
else
|
|
CCOID="0"
|
|
fi
|
|
if [[ -z "$DELIVEREDTO" ]]; then
|
|
DTID=$(GetRecordID "$DELIVEREDTO" mail_addresses mail_address mail "Get ID of DeliveredTo")
|
|
else
|
|
DTID="0"
|
|
fi
|
|
if [[ -z "$RETURNPATH" ]]; then
|
|
RPID=$(GetRecordID "$RETURNPATH" mail_addresses mail_address mail)
|
|
else
|
|
RPID="0"
|
|
fi
|
|
if [[ -z "$XORIGINALSENDER" ]]; then
|
|
XOSID=$(GetRecordID "$XORIGINALSENDER" mail_addresses mail_address mail)
|
|
else
|
|
XOSID="0"
|
|
fi
|
|
if [[ -z "$SENDER" ]]; then
|
|
SID=$(GetRecordID "$SENDER" mail_addresses mail_address mail)
|
|
else
|
|
SID="0"
|
|
fi
|
|
if [[ -z "$XFORWARDEDTO" ]]; then
|
|
XFTID=$(GetRecordID "$XFORWARDEDTO" mail_addresses mail_address mail)
|
|
else
|
|
XFTID="0"
|
|
fi
|
|
if [[ -z "$XFORWARDEDFOR" ]]; then
|
|
XFFID=$(GetRecordID "$XFORWARDEDFOR" mail_addresses mail_address mail)
|
|
else
|
|
XFFID="0"
|
|
fi
|
|
|
|
QUERY="INSERT INTO stats (msgid, from_id, to_id,cc_id, cco_id, subject, direction, delivered_to_id, return_path_id, s_original_sender_id, sender_id, x_forwarded_to, x_forwarded_for) VALUES ('$messageID',$FROMID, $TOID, $CCID, $CCOID, '$SUBJECT', $DIRECTION, $DTID, $RPID, $XOSID, $SID, $XFTID, $XFFID);"
|
|
temp_file=$(mktemp /tmp/tmp.XXXX)
|
|
echo "${QUERY}" | /usr/bin/env mysql -v -v -v mail &> "${temp_file}"
|
|
return_code="${?}"
|
|
result=$(cat "${temp_file}")
|
|
if [[ "${return_code}" != "0" ]]; then
|
|
message "Error ${return_code} saving stats with query '${QUERY}'. result: ${result}"
|
|
fi
|
|
finished=true
|