#!/usr/bin/perl
#
#   clamdwatch v0.7test1, Copyright (C) Mike Cathey
#
#   ChangeLog
#
#   v0.7test1 - 01/22/2004 - added support for clamd on a TCP socket
#
#   v0.6 - 01/09/2004 - changed exit codes so that it can be used in
#       cron with && (as shown in the INSTALL file)
#                      - added -q switch for same reason as above
#
#   v0.5 - 01/09/2004 - another attempt at fixing the path finding code
#
#   v0.4 - 01/08/2004 - fixed the code that finds the path of the script
#
#   v0.3 - 01/07/2004 - added a timeout for the result from the RAWSCAN
#
#   v0.2 - 01/07/2004 - added the Eicar signature and the code to have
#       clamd scan the script itself
#
#   v0.1 - 01/07/2004 - initial hack
#
#   Use this at your own risk!
#
#   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.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#   EICAR Test "file"
#   X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*

use IO::Socket::UNIX;
use File::Spec::Functions qw(rel2abs);
use File::Basename;


# "CONFIG" section
#
# $Socket values:
#   = "3310" (as in the tcp port; make sure $ip is correct if you use this)
#   = "/path/to/clamd/socket"
my $Socket = "/var/amavis/clamd";
my $ip = "127.0.0.1";
my $timeout = 15;
my $sock;


# get the script's full path/name
#  is there a cleaner way to do this?
#
my $scriptTemp = $0;
$scriptTemp =~ s/.*\/(.*)/$1/;
my $script = dirname(rel2abs($0)) . "/" .  $scriptTemp;

# why waste time creating the IO::Socket instance if the socket isn't there
#
if ( $Socket !~ /^[0-9]+$/ ) {

    if ( ! -e $Socket ) {
        print "$Socket missing! It doesn't look like clamd running.\n";
        exit 0;
    } else {
        $sock = new IO::Socket::UNIX(Type => SOCK_STREAM,
                                        Timeout => $timeout,
                                        Peer => $Socket );
    }
} else {
    $sock = IO::Socket::INET->new( PeerAddr => $ip,
                                   PeerPort => $Socket,
                                   Proto     => 'tcp');
}

if (!$sock || $@ ) { # there could be a stale file from a dead clamd
    print "Clamd Not Running\n";
    exit 0;
}

if ( $sock->connected ) { 

    my $err = "";

    # ask clamd to scan the script
    $sock->send("RAWSCAN $script");

    # set the $timeout and die with a useful error if
    # clamd isn't responsive
    eval {
        local $SIG{ALRM} = sub { die "timeout\n" };
	alarm($timeout);
        $sock->recv($err, 200);
	alarm(0);
    };
    if ($@) {

    	die unless $@ eq "timeout\n";
        print "Clamd not responding to RAWSCAN request\n";
	exit 0;

    } else { # clamd responded to the request

        if ( $err =~ /.*Eicar.*FOUND/i ) { # everything is good
	    if ($ARGV[0] ne "-q" ) {
                print "Clamd Running\n";
	    }
            exit 1;
        } elsif ( $err =~ /OK$/ ) { # it didn't find the virus
            print "Clamd didn't find the EICAR pattern. Your virus database(s) could be borked!\n";
            exit 0;
        } else {
	    # you should never get here
	    print "Clamd is in an unknown state.\n";
	    print "It returned: $err";
            exit 0;
	}

    }

} else {
    # you should never get here either
    print "Unknown State (Clamd Useless)\n";
    exit 0;
}
