#!/bin/ash # # fsavp: Pipe wrapper for F-Secure Anti-Virus. # # This script wraps FSAV so that it may be used as a pipe filter with MTAs like # Courier and Exim. FSAV 4.51 recognizes most MIME encodings and can # transparently unpack a variety of archive formats, so you can use this script # as a lightweight substitute for AMaViS. # # The munpack utility handles poorly-formed MIME parts better than FSAV, so it # is used if it is available. # # # Result Codes: # # 0 Success, the output is well-formed and may be delivered. # # !0 Failure, the output may not be well-formed and should not be delivered. # # # Example Usage (Shell): # # cat Maildir/new/message | fsavp | grep '^X-Virus-Flag: YES' # # Example Usage (Courier Maildrop Mailfilter): # # xfilter "/usr/local/bin/fsavp" # # Example Usage (Exim Transport Filter): # # transport_filter = "/usr/local/bin/fsavp" # # F-Secure Anti-Virus for Linux can be purchased online at: # http://www.f-secure.com/estore/fsavlinuxwks.shtml # # # Changes: # # 2003-10-18: Fixed bash'isms, fsavp now works with ash. # 2003-10-18: Save fsav output to a file instead of a variable. # 2003-10-18: Save stderr to a file. # 2003-10-18: Added TNEF support. # # Create a temporary directory. FSAVP_TEMP_DIRECTORY=$(mktemp -d -t fsavp-XXXXXX) || exit $? # Change directory. cd "$FSAVP_TEMP_DIRECTORY" # Redirect the standard error into a file for logging purposes, and to avoid # any potential output corruption. exec 2>"$FSAVP_TEMP_DIRECTORY/stderr.out" # ... # The F-Secure Anti-Virus scanner for Linux. FSAV=$(which fsav) # The MIME unpacker. MUNPACK=$(which munpack) # The TNEF unpacker. TNEF=$(which tnef) # Initialize the header flag. FSAVP_HEADER_INHIBIT=0 # A flag to indicate whether the temporary directory should be removed. FSAVP_RM_INHIBIT=0 # ... fsavp_exit() { if [ "$FSAVP_RM_INHIBIT" -eq "0" ] then # Remove the temporary directory. rm -r "$FSAVP_TEMP_DIRECTORY" fi exit $1 } # ... # Set the message file name. FSAVP_MESSAGE_FILE="$FSAVP_TEMP_DIRECTORY/message.txt" # Set the FSAV output file. FSAV_OUTPUT_FILE="$FSAVP_TEMP_DIRECTORY/fsav.txt" # Set the directory name for message parts. FSAVP_PARTS_DIRECTORY="$FSAVP_TEMP_DIRECTORY/parts" # Set the directory name for TNEF encoded parts. FSAVP_TNEF_DIRECTORY="$FSAVP_PARTS_DIRECTORY/tnef" # Create directories for upacking the message. mkdir "$FSAVP_PARTS_DIRECTORY" "$FSAVP_TNEF_DIRECTORY" || fsavp_exit $? # The default IFS will cause the ash read builtin to strip heading and tailing # whitespace from lines, which will munge message headers. IFS=' ' # Copy the message from the input pipe to the temporary file. while read -r REPLY do echo "$REPLY" >> "$FSAVP_MESSAGE_FILE" || fsavp_exit $? done if [ -x "$MUNPACK" ] then # Unpack mime attachments into the temporary directory. "$MUNPACK" -C "$FSAVP_PARTS_DIRECTORY" "$FSAVP_MESSAGE_FILE" >/dev/null MUNPACK_RESULT=$? fi # Run the virus scanner against the message file and parts directory. "$FSAV" --archive --dumb --list "$FSAVP_MESSAGE_FILE" "$FSAVP_PARTS_DIRECTORY" 2>&1 >"$FSAV_OUTPUT_FILE" FSAV_RESULT=$? # Obtain interesting details from the scanner output. FSAV_VERSION=$(sed -n -e '/^F-Secure/p' "$FSAV_OUTPUT_FILE") FSAV_DATABASE=$(sed -n -e 's/^Database version: \([^[:space:]]*\).*$/\1/p' "$FSAV_OUTPUT_FILE") FSAV_INFECTED=$(sed -n -e 's/^.*Infected: \(.*\)$/\1/p' "$FSAV_OUTPUT_FILE" | sort -u) FSAV_SUSPECTED=$(sed -n -e 's/^.*Suspected: \(.*\)$/\1/p' "$FSAV_OUTPUT_FILE" | sort -u) # Copy the message from the temporary file to the output pipe. while read -r REPLY do # Check whether we should append headers. if [ "$FSAVP_HEADER_INHIBIT" -eq "0" ] && echo "$REPLY" | grep '^[[:space:]]*$' > /dev/null then # Insert headers into the message. echo "X-Virus-Scanner-Version: $FSAV_VERSION" echo "X-Virus-Scanner-Database: $FSAV_DATABASE" echo "X-Virus-Scanner-Result: $FSAV_RESULT" # Check the scanner result code. if [ "$FSAV_RESULT" -eq "3" -o "$FSAV_RESULT" -eq "8" ] then # Insert a header that flags infection, like the way SpamAssassin does it. echo "X-Virus-Flag: YES" # Insert headers with the names of identified viruses. for i in $FSAV_INFECTED; do echo "X-Virus-Infected: $i"; done # Insert headers with the names of suspected viruses. for i in $FSAV_SUSPECTED; do echo "X-Virus-Suspected: $i"; done fi # Set the flag to indicate that we have appended headers. FSAVP_HEADER_INHIBIT=1 fi echo "$REPLY" done < "$FSAVP_MESSAGE_FILE" # Cleanup and exit. fsavp_exit # eof