Useful scripts for Sophos AV

Some little scripts schlenk wrote and found useful for working with Sophos Antivirus on Linux:

---

A simple downloader for new IDE files, that checks the Sophos list for duplicates:

 #!/usr/bin/tclsh

 # --------------------------------------------
 # 
 # This script gets the newest virus IDEs from
 # Sophos and installs them in the dirs set in
 # the config vars below.
 #
 # Last Change: 12.Sep.2002 Michael Schlenker
 #              24.Feb 2003 M.S
 #
 # --------------------------------------------

 # used for changing uid/gid
 package require Tclx

 # configuration data

 set config(avupdateuser) avupdate
 set config(avgroup) antivir

 # drop rights instantly 
 id group $config(avgroup)
 id user $config(avupdateuser)

 # needed for http file transfer
 package require http

 # url of the ide file list
 set config(url) http://www.sophos.com/downloads/ide/web_list.txt

 # base url to download ides from
 set config(base_url) http://www.sophos.com/downloads/ide/

 # local sav dir for locally running icheckd (intercheck daemon)
 set config(sav)    /usr/local/sav

 # install dir for W2k clients
 set config(client) /home/sophos/NTInst/i386

 # install dir for Win95 clients
 lappend config(client) /home/sophos/W95Inst

 # get the weblist and check what has to be done
 proc Init {} {
  global config

  set geturls ""
  # get weblist from sophos.com
  set token [http::geturl $config(url)]
  set data [http::data $token]
  http::cleanup $token

  # split list into single lines
  set lines [split $data "\n" ]
  set status ""
  if {[llength $lines] > 0} {
    set lines [lrange $lines 0 end-1]
  }
  # see if we have the ide files already
  set files [glob -nocomplain -directory $config(sav) *.ide]
  foreach file $files {
    set fn [file tail $file]
    lappend status $config(base_url)$fn
  }
  
  foreach line $lines {
    if {[lsearch -exact $status [string trim $line]]== -1} {
            puts stdout "New IDE: [string map [list $config(base_url) {}] $line]"
        lappend geturls $line
        } else {
        set file [string map "$config(base_url) {}" $line]
        set ffile [file join $config(sav) $file]
        set mtime [file mtime $ffile]
        set tok [http::geturl $line -validate 1]
        upvar #0 $tok state
        foreach {tag value} $state(meta) {
            if {[string equal $tag "Last-Modified"]} {
                set wmtime [clock scan $value]
            } 
        }
        http::cleanup $tok
        # is the web server version newer?
        if {$wmtime > $mtime} {
            puts stdout "Updated IDE: $file"
            lappend geturls $line
        }       
    } 
  }
  if {[llength $geturls]==0} {
    puts stdout "No New IDEs found"
  }
  return $geturls 
 }

 # get the ide files from sophos
 proc geturls urllist {
    global config
    foreach url $urllist {
        puts stdout "Getting $url"
        set token [http::geturl $url]
        set data [http::data $token]
        set fn [string map [list $config(base_url) {}] $url]
        set filename [file join $config(sav) $fn]
        set fid [open $filename w+]
        puts $fid $data
        close $fid
        http::cleanup $token
    }
 }

 # copy the ide files to all target locations
 proc copyides {} {
    global config
    set files [glob -directory $config(sav) *.ide]
    # being lazy, copying all ide files to install dir
    foreach file $files {
    foreach dir $config(client) {
        file copy -force $file $dir
            file attributes [file join $dir [file tail $file]] -permissions a+r
            puts stdout "Copying $file to client dir"
        }
    }
 }


 set urls [Init]
 if {[llength $urls] > 0} {
    geturls $urls
    puts stdout "Downloaded [llength $urls] files"
    copyides
 } else {
    puts stdout "Nothing to be done."
 }
 exit 0

---

SGET.EXE style script. Sophos SGET.EXE basically does authenticated HTTP, so not really a problem to get things done:

 #!/usr/bin/tclsh
 # SGET.EXE in tcl
 #
 # (c) 2002,2003 Michael Schlenker
 #
 # last changes: 24.02.2003
 #
 # Sophos Update Program
 #
 #

 # needed packages
 package require Tclx
 package require base64
 package require http

 # configuration data
 #
 # base_url is the url sophos provides the packages
 set config(base_url) http://www.sophos.com/sophos/products/full/ 
 
 # list of products to download
 # -- angz.zip --> W2k Client
 # -- linux.inter... -> linux server icheckd
 # -- a95z.zip --> Win95 Client
 #
 set config(products) [list angz.zip linux.intel.libc6.tar.Z a95z.zip]

 # list of temp dirs for products 
 # This lists the temp directories the packages are downloaded to for all the
 # above products.
 set config(localpath) [list /home/sophos/tmp /home/sophos/tmp /home/sophos/tmp]

 # list of target unzip/uncompress/untar dirs for products
 set config(targetpath) [list /home/sophos/tmp/win2000 /home/sophos /home/sophos/tmp/win95]

 # passwort info
 # the sophos password and user info needed
 set config(user) ""
 set config(passwd) ""

 # user info
 # the local group and user the files should belong to
 set config(sophos_user) sophos
 set config(sophos_group) antivir

 if {[id userid] == 0 || \
    [id effektive userid] == 0} {

    puts stdout "Should not be run by root. Switching to sophos user."
    id group $config(sophos_group)
    id user $config(sophos_user)
    
 }

 # authenticated geturl
 proc geturl_auth {url username password} {
    puts stdout "Getting URL: $url"
    set auth "Basic [base64::encode $username:$password]"
    set headerl [list Authorization $auth]
    set tok [http::geturl $url -headers $headerl -progress progress]
    puts stdout "\nData received: [http::size $tok] bytes total"
    set res [http::data $tok]
    http::cleanup $tok
    return $res
 }

 proc progress {token total count} {
    puts -nonewline stdout "."
    flush stdout
 }

 proc update_files {} {
    global config
    puts stdout "Updating products"
    foreach prod $config(products) path $config(localpath) {
        puts stdout "Getting $prod"
        set data [geturl_auth $config(base_url)$prod $config(user) $config(passwd)]
        set fid [open [file join $path $prod] w+]
        fconfigure $fid -translation binary -encoding binary
        puts -nonewline $fid $data
        close $fid
        puts stdout "Done getting $prod"
    }   
 }

 update_files

A script to scan a Starkit Archive with Sophos sweep:

 #!/usr/bin/env tclsh
 package require vfs::mk4

 if {[llength $argv] != 1} {
   puts stderr "Usage: starscan.tcl <starkit>"
   exit 1
 }
 # path to av scanner (sophos sweep in this case)
 set avscanner /usr/local/bin/sweep
 set tmpdir /var/tmp/starkitav

 puts "Creating tempdir for decompression in $tmpdir"
 if {![file exists $tmpdir]} {
   file mkdir $tmpdir
 }

 file mkdir [file join $tmpdir avarea]

 puts "Mounting virtual filesystem"
 set vfs [vfs::mk4::Mount  $starkit [file join $tmpdir starkit]]

 puts "Copying vfs to local filesystem."
 file copy [file join $tmpdir starkit] [file join $tmpdir avarea]

 # executing av program
 if {[set code [catch {exec $avscanner [file join $tmpdir $avarea]} msg]]} {
    puts "Problem Found in $starkit: $code\n$msg"
 }

 # cleanup
 vfs::mk4::Umount $vfs [file join $tmpdir starkit]
 file delete -force [file join $tmpdir avarea]

 exit $code

 # end of script

But with the source available here, that means that someone might have infected the above code ...


Sure, but its short enough to really do code review ;-)