#!/bin/bash # --- # badmsg: script to find and delete malformed messages CODER="badmsg@chamorro.us" # Mario Chamorro # company: http://www.rackspace.com/ # --- # version: date - comment # 0.0: Saturday 20 March 2004 ( original / RH8 ) # 0.1: Sunday 21 March 2004 ( added timestamp ) # 0.2: Sunday 21 March 2004 ( minor ) # 0.3: Sunday 21 March 2004 ( fixed for RHEL2.1 ) # 0.4: Monday 22 March 2004 ( To !Date||From ) # 0.5: Thursday 25 March 2004 ( cleanup ) # 0.6: Thursday 15 April 2004 ( mail message ) # 0.7: Sunday 9 May 2004 ( integrate with weekly script ) # 0.8: Friday 25 June 2004 ( find optimization ) # version 1 Alpha # .9a: F27Aug2004 ( merge / updater ) # .9b: U19Sep2004 ( execute / options ) # .9e: M20Sep2004 ( upgrade ) # .9f: U03Oct2004 ( cleanup installations and pray ) # version 2 Bravo # .10: U02Jan2005 ( archive deletion ) # .11: R10Mar2005 ( upgrade cronjob cwd fix ) # --- # To Do # --- # b: remove all instances of badmsg.install from top to root ( Reverse of find / -name badmsg.install ) # c: implement uninstallation # --- PROGRAM_ORIGINAL=$0 PROGRAM=`basename $0` PROGRAM_DIR=`dirname $0` PROGRAM_RUN="badmsg.default" PROGRAM_VERSION="3" PROGRAM_VERSION_RELEASE="charlie" RUNTIME_DIR=`pwd` BADCONFIG="/etc/badmsg.conf" DATESTAMP=`/bin/date +%Y%m%d` TIMESTAMP=`/bin/date +%H%M%S` FILEWEEKLY=$DATESTAMP.txt UPDATE_HOST="www.chamorro.us" UPDATE_PATH="rrr" UPDATE_FILE="badmsg" UPDATE_VERSION="badmsg.version" BADTOTAL="0" GOOD="0" BAD="1" # --- CMDFIND="/usr/bin/find" CMDGREP="/bin/grep" CMDMOVE="/bin/mv" CMDTAR="/bin/tar" CMDRM="/bin/rm" CMDTARBALL="$CMDTAR -czf" CMDCHECK="$CMDGREP -L ^To" # --- # user modifiable - should be done in $BADCONFIG # --- BADROOT="/root/badmsg.d" BADARCHIVE="$BADROOT/ar" BADBOX="$BADROOT/box" MAILROOT="/var/qmail/mailnames" MAILSUBJ="BADMSG: Weekly Message Summary" MAILTO='root@localhost' MAXSIZE="500" MAXWEEKS="13" let MAXDAYS=$MAXWEEKS*7 # --- # --- # make sure everything is working # --- check_sanity() { [ -x $CMDFIND ] || { echo "$PROGRAM: $CMDFIND not executable"; exit 1; } [ -x $CMDMOVE ] || { echo "$PROGRAM: $CMDMOVE not executable"; exit 1; } [ -x $CMDGREP ] || { echo "$PROGRAM: $CMDGREP not executable"; exit 1; } [ -x $CMDTAR ] || { echo "$PROGRAM: $CMDTAR not executable"; exit 1; } [ -x $CMDRM ] || { echo "$PROGRAM: $CMDRM not executable"; exit 1; } [ -x /bin/ls ] || { echo "$PROGRAM: /bin/ls not executable"; exit 1; } [ -x /bin/sed ] || { echo "$PROGRAM: /bin/sed not executable"; exit 1; } [ -x /bin/ping ] || { echo "$PROGRAM: /bin/ping not executable"; exit 1; } [ -x /bin/chmod ] || { echo "$PROGRAM: /bin/chmod not executable"; exit 1; } [ -x /usr/bin/wc ] || { echo "$PROGRAM: /usr/bin/wc not executable"; exit 1; } } usage() { echo "usage: $PROGRAM -xhiauvVU -c -d -m -r -s " } usage_extended() { echo "" echo "Find and move malformed messages from a mail root to a destination directory" echo "" echo " -x - ( eXecute ) run the bad message removal script as is" echo " -i - ( Install ) make hourly/weekly/monthly cron entries and make directories" echo " -U - ( Uninstall ) remove cron directory entries and badmsg files" echo " -a - ( Archive ) archive all bad messages and send the summary to the recipient" echo " -u - ( Upgrade ) fetch and install latest version of badmsg from $UPDATE_HOST"; echo " -v - ( Verbose ) display bad message filenames when found" echo " -V - ( Version ) display script version" echo " -h - ( Help ) display extended help / usage statement" echo " -c - use this configuration file after /etc/badmsg.conf" echo " -d - place bad messages in this directory" echo " -r - send summary to this recipient" echo " -m - use this mailroot instead of /var/qmail/mailnames" echo " -s - check messages smaller than this size" echo "" echo "version $PROGRAM_VERSION - $PROGRAM_VERSION_RELEASE :: report bugs to: $CODER" } # --- # command line check # --- check_command_line() { if [ $# -eq 0 ] then usage; exit 1; else while getopts ":xhaiuUvVc:d:m:r:s:" Option do case $Option in c ) BADCONFIG=$OPTARG;; d ) BADBOX=$OPTARG;; m ) MAILROOT=$OPTARG;; r ) MAILTO=$OPTARG;; s ) MAXSIZE=$OPTARG;; v ) VERBOSE=1;; h ) PROGRAM_RUN="badmsg.help";; V ) PROGRAM_RUN="badmsg.version";; x ) PROGRAM_RUN="badmsg.execute";; U ) PROGRAM_RUN="badmsg.uninstall";; i ) PROGRAM_RUN="badmsg.install";; a ) PROGRAM_RUN="badmsg.archive";; u ) PROGRAM_RUN="badmsg.upgrade";; * ) echo "$Option: invalid option";; # DEFAULT esac done shift $(($OPTIND - 1)) fi } # --- # main fx: check all messages smaller than MAXSIZE for a bad one and move out # --- badmessage_execute() { for DIRECTORY in `$CMDFIND $MAILROOT -type d -name Maildir -print` do for SUBDIR in new cur do for MESSAGE in `$CMDFIND $DIRECTORY/$SUBDIR -type f -size -${MAXSIZE}c -print` do RETURN=`$CMDCHECK $MESSAGE`; THISONE=$?; if [ $THISONE -eq $BAD ] then [ $VERBOSE ] && echo "$PROGRAM: found: $MESSAGE"; MESSAGEBASE=`basename $MESSAGE` MESSAGENEW=$MESSAGEBASE; while [ -e $BADBOX/$MESSAGENEW ] do /bin/sleep 1; DATESTAMP=`/bin/date +%Y%m%d`; TIMESTAMP=`/bin/date +%H%M%S`; MESSAGENEW="$MESSAGEBASE.$DATESTAMP.$TIMESTAMP"; done $CMDMOVE $MESSAGE $BADBOX/$MESSAGENEW let BADTOTAL++ fi done done done } # --- # badmsg archiver / summary # --- badmessage_archive() { [ -e $BADBOX ] || ( echo "$PROGRAM: $BADBOX does not exist"; exit 1; ) [ -e $BADARCHIVE ] || ( echo "$PROGRAM: $BADARCHIVE does not exist"; exit 1; ) DIREMPTY=`/usr/bin/find $BADBOX -type f -print | /usr/bin/wc -l` if [ $DIREMPTY -eq 0 ] then MAILBODY="$PROGRAM: $BADBOX is empty. No bad messages to archive." echo "$MAILBODY" | /bin/mail -s "$MAILSUBJ" $MAILTO echo "$MAILBODY"; exit 1; fi # --- make sure we don't overwrite something while [ -e $BADARCHIVE/$FILEWEEKLY ] do TIMESTAMP=`/bin/date +%H%M%S`; FILEWEEKLY="$DATESTAMP.$TIMESTAMP.txt" done # --- compile messages into one file, compress it and mail it $CMDFIND $BADBOX -type f -exec /bin/cat '{}' >> $BADARCHIVE/$FILEWEEKLY \; /bin/gzip $BADARCHIVE/$FILEWEEKLY /bin/mail -s "$MAILSUBJ" $MAILTO < $BADARCHIVE/$FILEWEEKLY.gz $CMDFIND $BADBOX -type f -exec $CMDRM '{}' \; # --- remove any tarballs older than $MAXWEEKS ( in $MAXDAYS ) let MAXDAYS=$MAXWEEKS*7; [ $MAXDAYS -ne 0 ] && $CMDFIND $BADARCHIVE -type f -mtime +$MAXDAYS -exec /bin/rm '{}' \; } # --- # installation function - run as root # --- badmessage_install() { # check OS / Plesk [ -e /etc/redhat-release ] || ( echo "$PROGRAM: requires Red Hat Enterprise Linux"; exit 1; ) [ -e $BADROOT ] || /bin/mkdir -p $BADROOT [ -e $BADBOX ] || /bin/mkdir -p $BADBOX [ -e $BADARCHIVE ] || /bin/mkdir -p $BADARCHIVE /bin/mv $PROGRAM_ORIGINAL $BADROOT/$PROGRAM /bin/chmod 755 $BADROOT/$PROGRAM # --- hourly execution if [ -w /etc/cron.hourly ] then CH="/etc/cron.hourly/badmsg" echo "#!/bin/bash" > $CH echo "# ---" >> $CH echo "# bad message removal script" >> $CH echo "# ---" >> $CH echo "$BADROOT/badmsg -x" >> $CH /bin/chmod 755 $CH else echo "$PROGRAM: $CH not created - use crontab" fi # --- weekly execution if [ -w /etc/cron.weekly ] then CH="/etc/cron.weekly/badmsg" echo "#!/bin/bash" > $CH echo "# ---" >> $CH echo "# bad message archive script" >> $CH echo "# ---" >> $CH echo "$BADROOT/badmsg -a" >> $CH /bin/chmod 755 $CH else echo "$PROGRAM: $CH not created - use crontab" fi # --- monthly execution if [ -w /etc/cron.monthly ] then CH="/etc/cron.monthly/badmsg" echo "#!/bin/bash" > $CH echo "# ---" >> $CH echo "# bad message upgrade script" >> $CH echo "# ---" >> $CH echo "$BADROOT/badmsg -u" >> $CH /bin/chmod 755 $CH else echo "$PROGRAM: $CH not created - use crontab" fi } # --- # UNinstallation function # --- badmessage_uninstall() { echo "$PROGRAM: uninstallation function not implemented"; exit 99; # --- MMM --- cronjob and directory removal # [ -e $BADROOT ] || /bin/mkdir $BADROOT # [ -e $BADBOX ] || /bin/mkdir -p $BADBOX # [ -e $BADARCHIVE ] || /bin/mkdir -p $BADARCHIVE } # --- # update / upgrade function # --- badmessage_upgrade() { # --- check internet connection PINGED=`/bin/ping -c 1 $UPDATE_HOST >& /dev/null`; SIGNAL=$?; if [ $SIGNAL -eq $GOOD ] then WGET=`/usr/bin/wget http://$UPDATE_HOST/$UPDATE_PATH/$UPDATE_VERSION >& /dev/null`; WGOT=$?; if [ $WGOT -eq $BAD ] then echo "$PROGRAM: connection failed. no upgrade possible"; exit 1; elif [ $PROGRAM_VERSION -lt `cat $UPDATE_VERSION` ] then # --- upgrade program --- # [ $VERBOSE ] && echo "$PROGRAM: upgrade available" /bin/rm $UPDATE_VERSION # --- rename self DATESTAMP=`/bin/date +%Y%m%d`; TIMESTAMP=`/bin/date +%H%M%S`; PROGRAM_NEW=$PROGRAM.$DATESTAMP.$TIMESTAMP; while [ -e $PROGRAM_DIR/$PROGRAM_NEW ] do /bin/sleep 1; DATESTAMP=`/bin/date +%Y%m%d`; TIMESTAMP=`/bin/date +%H%M%S`; PROGRAM_NEW=$PROGRAM.$DATESTAMP.$TIMESTAMP; done /bin/mv $PROGRAM_ORIGINAL $PROGRAM_DIR/$PROGRAM_NEW; [ $VERBOSE ] && echo "$PROGRAM: renamed $PROGRAM_NEW" # --- remove crond execution [ $VERBOSE ] && echo "$PROGRAM_NEW: removing cron scripts" [ -e /etc/cron.hourly/badmsg ] && ( /bin/rm /etc/cron.hourly/badmsg ) [ -e /etc/cron.weekly/badmsg ] && ( /bin/rm /etc/cron.weekly/badmsg ) [ -e /etc/cron.monthly/badmsg ] && ( /bin/rm /etc/cron.monthly/badmsg ) # --- move over if pre-existing upgrade file if [ -e $UPDATE_FILE ] then DATESTAMP=`/bin/date +%Y%m%d`; TIMESTAMP=`/bin/date +%H%M%S`; UPDATE_FILE_NEW=$UPDATE_FILE.$DATESTAMP.$TIMESTAMP; while [ -e $UPDATE_FILE_NEW ] do /bin/sleep 1; DATESTAMP=`/bin/date +%Y%m%d`; TIMESTAMP=`/bin/date +%H%M%S`; PROGRAM_NEW=$PROGRAM.$DATESTAMP.$TIMESTAMP; done /bin/mv $UPDATE_FILE $UPDATE_FILE_NEW; [ $VERBOSE ] && echo "$PROGRAM_NEW: $UPDATE_FILE renamed $UPDATE_FILE_NEW" fi # --- download upgrade [ $VERBOSE ] && echo "$PROGRAM_NEW: downloading upgrade" WGET=`/usr/bin/wget -O $BADROOT/$UPDATE_FILE http://$UPDATE_HOST/$UPDATE_PATH/$UPDATE_FILE >& /dev/null`; WGOT=$?; if [ $WGOT -eq $BAD ] then echo "$PROGRAM_NEW: connection failed. no upgrade possible"; /bin/mv $PROGRAM_DIR/$PROGRAM_NEW $PROGRAM_ORIGINAL; [ $VERBOSE ] && echo "$PROGRAM_NEW: renamed $PROGRAM" exit 1; else # --- run new installation - exit [ $VERBOSE ] && echo "$PROGRAM_NEW: download successful - installing NOW" /bin/chmod 755 $BADROOT/$UPDATE_FILE INSTALL_UPGRADE=`$BADROOT/$UPDATE_FILE -i`; INSTALLATION=$?; if [ $INSTALLATION -eq $GOOD ] then [ $VERBOSE ] && echo "$PROGRAM_NEW: upgrade successful" [ $VERBOSE ] && echo "$PROGRAM_NEW: $INSTALL_UPGRADE" exit 0; else echo "$PROGRAM_NEW: upgrade UNSUCCESSFUL" echo "$PROGRAM_NEW: contact $CODER" exit 2; fi fi else [ $VERBOSE ] && echo "$PROGRAM: upgrade not available" /bin/rm $UPDATE_VERSION fi else echo "$PROGRAM: $UPDATE_HOST unavailable. no upgrade possible" exit 1; fi } # ---[ BADMSG MAIN SCRIPT ]--------------------------------------------------- # check_sanity check_command_line $* # --- read local configuration if [ -r $BADCONFIG ] then . $BADCONFIG fi # --- switch run commands case "$PROGRAM_RUN" in badmsg.execute) badmessage_execute ;; badmsg.archive) badmessage_archive ;; badmsg.upgrade) badmessage_upgrade ;; badmsg.install) badmessage_install ;; badmsg.uninstall) badmessage_uninstall ;; badmsg.version) echo "$PROGRAM: version $PROGRAM_VERSION - $PROGRAM_VERSION_RELEASE" ;; badmsg.help) usage; usage_extended ;; badmsg.default) usage ;; *) usage; esac # exit $BADTOTAL # EOF