#!/usr/bin/perl
##
my $revision = '$Id: sanitizer.pl,v 1.76 2006/01/03 13:16:35 bre Exp $';
my $version = 'Anomy 0.0.0 : sanitizer.pl';
#
##  Copyright (c) 2000-2005 Bjarni R. Einarsson. All rights reserved.
##  This program is free software; you can redistribute it and/or modify
##  it under the terms of the GNU General Public License as published by
##  the Free Software Foundation; either version 2 of the License, or
##  (at your option) any later version.
#
##############################################################################
#
# NOTE:  Sanitizer development is for the most part sponsored by
#        FRISK Software International, http://www.f-prot.com/.  Please
#        consider buying their anti-virus products to show your 
#        appreciation.
#
##############################################################################
#
# This is an email sanitizer.  Stick it in your .procmailrc!
# Implemented features:
#
#   + Minimal resource consumption (I hope).
#   + Can truncates all MIME headers to a reasonable length, to avoid 
#     buffer overflows in buggy mail readers.  Also attempts to protect
#     against overflows based on information parsed from other headers.
#   + Can renames attachments so they won't get auto-executed by naughty
#     mail readers.
#   + Defangs active HTML content.
#   + Can attach a log of what was done to the message (if anything
#     interesting was done, that is, and we can find a place to put
#     the log w/o breaking the message).
#   + Supports external virus scanners.
#   + Includes a crude built in scanner designed to guess whether macros in 
#     Microsoft documents are hostile or not.
#
# TODO:
#
#   + More flexible logging, e.g. by email, files or syslog.
#   + Allow rejection of messages, resulting in replies etc.
#
BEGIN { push @INC, $ENV{"ANOMY"} . "/bin" };
use strict;
use Anomy::Sanitizer;

# Create new Sanitizer engine object.
my @SCANNER_CONF = ( );
my $engine = new Anomy::Sanitizer;
if (my $e = $engine->error())
{
    print STDERR $e;
    exit(1);
}

# Pick up a few arguments from the command line...
my $no_fprotd = 1;
my $no_fprotc = 0;
my $no_macro  = 0;
while ($ARGV[0] =~ /^-/)
{
    my $arg = shift @ARGV;
    $no_fprotd = 0 if (lc($arg) eq "-fprotd");
    $no_fprotc = 1 if (lc($arg) eq "-nofprot");
    $no_macro  = 1 if (lc($arg) eq "-nomacro");
}

# This will enable support for the daemonized version of F-Prot Antivirus 
# for Linux.
if (!$no_fprotd)
{
    print STDERR "Loading support for the F-Prot scanner daemon.\n" if ($ENV{SANITIZER_DEBUG});
    eval 'use Anomy::Sanitizer::FProt;';
    die $@ if ($@);
    my $fprot = new Anomy::Sanitizer::FProt;
    $engine->register_scanner("fprotd", $fprot->get_sanitizer_callback());
    if (my $e = $engine->error())
    {
        print STDERR $e;
	exit(1);
    }
    
    # F-Prot daemon default configuration:
    #  - Scan everything with F-Prot.
    #  - Mangle infected attachments (they are still delivered).
    push @SCANNER_CONF,
         ('file_list_2_scanner = 0:1:2:builtin/fprotd %FILENAME -archive -ai -dumb',
          'file_list_2_policy  = unknown:mangle:mangle:defang',
          'file_list_2 = .*',
	  'header_rev += \nX-Antivirus: Scanned by F-Prot Antivirus (http://www.f-prot.com/)');
}
elsif ((!$no_fprotc) && (-e "/usr/local/bin/f-prot"))
{
    # F-Prot daemon default configuration:
    #  - Scan everything with F-Prot.
    #  - Mangle infected attachments (they are still delivered).
    print STDERR "Configuring F-Prot command line scanner.\n" if ($ENV{SANITIZER_DEBUG});
    push @SCANNER_CONF,
	 ('file_list_2_scanner = 0:6:3,8:/usr/local/bin/f-prot -ai -archive -dumb %FILENAME',
          'file_list_2_policy  = unknown:unknown:mangle:defang',
          'file_list_2 = .*',
	  'header_rev += \nX-Antivirus: Scanned by F-Prot Antivirus (http://www.f-prot.com/)');
}

# Register John's Macro scanner as builtin/macro.
unless ($no_macro)
{
    print STDERR "Loading Macro scanner.\n" if ($ENV{SANITIZER_DEBUG});
    eval 'use Anomy::Sanitizer::MacroScanner;';
    die $@ if ($@);
    $engine->register_scanner("macro", \&MacroScanner);
    if (my $e = $engine->error())
    {
        print STDERR $e;
	exit(1);
    }
    
    # Macro scanner default configuration.
    #  - Scan everything with John Hardin's macro scanner.
    #  - Mangle infected attachments (they are still delivered).
    push @SCANNER_CONF,
         ('file_list_5_scanner = 0:1:2:builtin/macro 25',
          'file_list_5_policy  = unknown:mangle:mangle:defang',
          'file_list_5 = (?i)\.(do[tc]|xl[aswct]|p[po]t|pps|rtf|md[abw])$');
}

# Configure engine using stuff on command line.
$engine->configure(@SCANNER_CONF, @ARGV);
if (my $e = $engine->error())
{
    print STDERR $engine->get_msg("usage"), "\n";
    print STDERR $engine->get_msg("current"), "\n";
    print STDERR $engine->get_config_text();
    print STDERR "\n", $e, "\n";
    exit(1);
}

# Go!
my $ret = $engine->sanitize(*STDIN, *STDOUT);
if (my $e = $engine->error())
{
    print STDERR $e;
}
exit($ret);

