Header problem, part 2

Tony Finch dot at DOTAT.AT
Tue Mar 2 18:11:06 GMT 2004


I've written an auxiliary script to go with uvscan-update that finds
fetches and installs extra.dat files from NAI. This should give you
some useful additional protection from new viruses.

Included below are my current uvscan-update and uvscan-extra scripts.

Tony.
--
f.a.n.finch  <dot at dotat.at>  http://dotat.at/
BERWICK ON TWEED TO WHITBY: WEST BACKING SOUTH 4 OR 5, DECREASING 3 AT TIMES.
FAIR. GOOD. SLIGHT.

------------------------------------------------------------------------
#!/bin/sh -e
#
# Update the McAfee data files.
#
# $Cambridge: hermes/build/bin/uvscan-update,v 1.42 2004/03/02 18:03:11 fanf2 Exp $

# $PREFIX is the directory where the uvscan binary is (NOT a symlink to
# the binary), which is where it looks for its dat files. You may run
# uvscan via a symlink to this place (e.g. from /usr/local/bin/uvscan)
# and it will still look for the dat files here. If uvscan's library
# dependencies can be found in a standard place (e.g. /usr/local/lib)
# then you don't need a wrapper script to set LD_LIBRARY_PATH before
# running it.
#
# The dat files are installed in a subdirectory of $DATDIR named
# according to their version number, with symlinks from $PREFIX into
# the subdirectory via a current link. The current link is updated
# without locking on the assumption that this is sufficiently unlikely
# to cause a problem.

# defaults
OPTS=""
PREFIX=/opt/uvscan
FTPDIR=http://download.nai.com/products/datfiles/4.x/nai

# handle the command line
usage () {
        echo "usage: $0 [-dfrtv] [prefix]"
        echo "  -d      delete old files"
        echo "  -e      get extra.dat"
        echo "  -f      force update"
        echo "  -r      show README"
        echo "  -t      timestamp output"
        echo "  -v      verbose"
        echo "  prefix  uvscan installation directory"
        exit 1
}
case $# in
0|1|2)  : ok
        ;;
*)      usage
        ;;
esac
for arg in "$@"
do
        case $arg in
        -*)     OPTS=$arg
                ;;
        /*)     PREFIX=$arg
                ;;
        *)      usage
                ;;
        esac
done
case $OPTS in
*[!-dfrtv]*)
        usage
esac
option () {
        case $OPTS in
        -*$1*)  eval $2=yes
                ;;
        *)      eval $2=no
                ;;
        esac
}
option d DELETE
option e EXTRA
option f FORCE
option r README
option t TIME
option v VERBOSE
case $FORCE in
yes)    VERBOSE=yes
esac

# look for binaries and libraris in plausible places
PATH=$PREFIX:/usr/local/bin:/usr/bin:/bin
# this is only necessary for broken setups
LD_LIBRARY_PATH=$PREFIX
export PATH LD_LIBRARY_PATH

# where this script finds things
DATDIR=$PREFIX/datfiles
SUBDIR=datfiles/current
LINK=$PREFIX/$SUBDIR

# wrapper functions for echo etc.
timestamp () {
        case $TIME in
        yes)    date "+%Y-%m-%d %H:%M:%S "
        esac
}
say () {
        case $VERBOSE in
        yes)    echo "`timestamp`$*"
        esac
}
run () {
        say "> $*"
        "$@"
}
say Starting $0
say DELETE=$DELETE
say FORCE=$FORCE
say README=$README
say TIME=$TIME
say VERBOSE=$VERBOSE
say PREFIX=$PREFIX

if [ ! -h $LINK ]
then
        INIT=yes
        VERBOSE=yes
        say Initial setup of $0
        run mkdir -p $DATDIR
fi
run cd $DATDIR

# version number pattern
MATCH="[0-9][0-9][0-9][0-9]"

# work out latest dat version
CMD="wget --passive-ftp $FTPDIR/update.ini 2>update.err"
say "> $CMD"
if eval "$CMD"
then
        VERSION=`cat update.ini | sed "/^DATVersion=\($MATCH\).$/!d;s//\1/;q"`
else
        cat update.err
        VERSION=UNKNOWN
fi
run rm -f update.*

badversion () {
        VERBOSE=yes
        say "Failed to get McAfee datfile update from $FTPDIR"
        say "FTP version number \"$VERSION\" $*"
        run exit 1
}

# check the format of the version number
case $VERSION in
$MATCH) : ok
        ;;
*)      badversion does not match "$MATCH"
        ;;
esac

# already got it?
if [ -d $VERSION ]
then
        case $FORCE in
        yes)    say Forced removal of $VERSION
                run rm -rf $VERSION
                ;;
        *)      say Already have $VERSION
                case $EXTRA in
                yes)    say Checking for extra.dat file
                        if [ ! -f $DATDIR/$VERSION/extra.dat ]
                        then    run uvscan-extra $PREFIX
                        fi
                esac
                run exit 0
                ;;
        esac
fi

# work out installed dat version
PREVIOUS=`(ls -d $MATCH 2>/dev/null || echo 0000) | tail -1`

# check new version is actually newer
if [ $PREVIOUS -gt $VERSION ]
then
        badversion older than installed $PREVIOUS
fi

VERBOSE=yes

say Installed dat file is $PREVIOUS
say Latest dat file is $VERSION

# protect against failure
fail () {
        trap EXIT
        echo "$OUT"
        say Fetch or test failed -- removing bad McAfee data files
        run cd $DATDIR
        run rm -rf $VERSION
        run exit 1
}
trap fail EXIT

# fetch and extract dat files
TARFILE=dat-$VERSION.tar
run mkdir $VERSION
run cd $VERSION
run wget --passive-ftp --progress=dot:mega $FTPDIR/$TARFILE
run tar xvf $TARFILE

# verify the contents
CMD="uvscan --version --dat ."
say "> $CMD"
OUT=`$CMD 2>&1`
case "$OUT" in
*"Missing or invalid DAT"* | \
*"Data file not found"* | \
*"Removal datafile clean.dat not found"* | \
*"Unable to remove viruses"* )
        fail
esac

# protection not needed now
trap '' EXIT

echo "$OUT"
say Update OK

# show information on this update?
case $README in
yes)    run sed 's/[[:cntrl:]]//g
                1,/^====================/d
                /^====================/,/^NEW VIRUSES DETECTED/d
                /^UNDERSTANDING VIRUS NAMES/,$d
                s/^/# /;/@MM/s/$/ <--/' readme.txt
esac
# remove some crap
run rm -f *.diz *.exe *.ini *.lst *.tar *.txt

# do remaining part of initial setup
case $INIT in
yes)    for file in *.dat extra.dat
        do
                run rm -f $PREFIX/$file
                run ln -s $SUBDIR/$file $PREFIX/$file
        done
esac

# update the current version link
run rm -f $LINK
run ln -s $VERSION $LINK

# maybe delete old dat files
case $DELETE in
yes)    run cd $DATDIR
        run rm -rf $PREVIOUS
esac

say Completed OK
run exit 0

# done
------------------------------------------------------------------------
#!/usr/bin/perl -Tw
#
# Try to obtain McAfee extra.dat file.
#
# $Cambridge: hermes/build/bin/uvscan-extra,v 1.3 2004/03/02 17:34:12 fanf2 Exp $

use strict;
use POSIX;
use LWP::UserAgent;
use HTTP::Status;

# taint safety
undef %ENV;

# external requirements
my $UNZIP = '/usr/local/bin/unzip';
my $VIL = 'http://vil.nai.com/vil';
my $VILNEW = "$VIL/newly-discovered-viruses.asp";

# uvscan directories and files
my $PREFIX = @ARGV ? $ARGV[0] : '/opt/uvscan';
my $UVSCAN = "$PREFIX/uvscan";
my $DATDIR = "$PREFIX/datfiles";
my $SUBDIR = "datfiles/current";
my $LINK   = "$PREFIX/$SUBDIR";

# find active dat directory
my $CURDAT = do {
        my $link = readlink $LINK
            or die "readlink $LINK: $!\n";
        $link =~ /^([0-9]{4})$/
            or die "readlink $LINK: $link is not four digits\n";
        $1; };
my $CURDIR = "$DATDIR/$CURDAT";
my $EXTRADAT = "$CURDIR/extra.dat";

# HTTP things
my $ua = LWP::UserAgent->new;
sub get ($) {
        my $url = shift;
        my $r = $ua->get($url);
        if ($r->code != RC_OK) {
                my $e = $r->status_line;
                die "GET $url: $e\n"
        }
        return $r->content;
}

# extract list of new viruses
my @v;
my $vilnew = get $VILNEW;
while ($vilnew !~ m|^<td |s) {
        $vilnew =~ s|^[^\n]*\n||s;
}
while ($vilnew =~ s|
        ^<td[^>]*>\s*
          <font[^>]*>\s*
           <a \s+ href="/vil/(content/v_[0-9]+[.]htm)">
            ([^<]+)                                        # name
           </a>\s*
          </font>\s*
         </td>\s*
         <td[^>]*>\s*
          <font[^>]*>\s*
           ([0-9]{2})/([0-9]{2})/([0-9]{4})\s*         # date
          </font>\s*
         </td>\s*
         <td[^>]*>\s*
          <font[^>]*>\s*
           <a[^>]*>\s*
            [^<]*                                  # risk 1
           </a>\s*
          </font>\s*
         </td>\s*
         <td[^>]*>\s*
          <font[^>]*>\s*
           <a[^>]*>\s*
            [^<]*                              # risk 2
           </a>\s*
          </font>\s*
         </td>\s*
         <td[^>]*>\s*
          <font[^>]*>\s*
           <a[^>]*>\s*
            ([0-9]+)\s*                    # datnum
           </a>\s*
          </font>\s*
         </td>\s*
        </tr>\s*
        <tr[^>]*>\s*
       ||sx) {
        push @v, { url => $1,
                   name => $2,
                   date => "$5-$3-$4",
                   datnum => $6 };
}
undef $vilnew;

# find out which ones have useful extra.dat files
my $extraurl;
for my $v (@v) {
        next unless $v->{datnum} > $CURDAT;
        $v->{page} = get "$VIL/$v->{url}";
        if ($v->{page} =~ m|<a href\="([^"]*)">EXTRA.DAT</a>|) {
                if (defined $extraurl) {
                        warn "ignoring additional extra.dat $1\n"
                            unless $extraurl eq $1;
                } else {
                        $extraurl = $1;
                }
        }
}
exit unless defined $extraurl;

warn "fetching $extraurl\n";
my $zipdata = get $extraurl;
my $zipname = "$DATDIR/extra.zip";
my $datname = "$DATDIR/extra.dat";

if (not defined eval {
        chdir "$DATDIR"
            or die "chdir $DATDIR: $!\n";

        # note the zip file is used to prevent concurrent running
        # so it is removed last
        sysopen ZIPFILE, $zipname, O_RDWR|O_CREAT|O_EXCL
            or die "open $zipname: $!\n";
        syswrite ZIPFILE, $zipdata
            or die "write $zipname: $!\n";
        close ZIPFILE
            or die "close $zipname: $!\n";

        system $UNZIP, $zipname, 'extra.dat', '-d', $DATDIR
            and die "$UNZIP $zipname to $datname failed\n";
        system $UVSCAN, '--extra', $datname, '--version'
            and die "$UVSCAN failed\n";
        rename $datname, $EXTRADAT
            or die "rename $datname to $EXTRADAT: $!";
        unlink $zipname
            or die "remove $zipname: $!";

        print "Extra dat file installed OK.\n";
        exit 0;
}){
        warn $@;
        unlink $datname
            or warn "remove $datname: $!\n";
        unlink $zipname
            or warn "remove $zipname: $!\n";
        exit 1;
}
------------------------------------------------------------------------



More information about the MailScanner mailing list