#!/usr/local/bin/perl -w # # Copyright (c) 2004 Simon L. Nielsen # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $Id: vxcheck,v 1.11 2005/04/16 14:54:40 simon Exp $ use strict; use File::Temp qw(mkstemp); use Getopt::Std; my $pkg_names = "/data/files/FreeBSD/package-names.txt"; my $vulndb = "/usr/ports/security/vuxml/vuln.xml"; my $vxquery = "/usr/local/bin/vxquery"; my $portsdir = $ENV{"PORTSDIR"} || "/usr/ports"; my %options = (); my $tmpdir = $ENV{TMPDIR} || "/tmp"; my $cleanfiles = ""; my %matched_ports = (); my $vid = ""; my $include = ""; ######### # Getopt getopts("hd:e:i:p:r:P:R",\%options); if ($options{h}) { print "$0 [-hR] [-d vuxml] [-e pattern] [-i pattern] [-p package-names] [-r vid]\n"; exit(64); } my $exclude = $options{e} || ""; if ($options{r}) { $vid = $options{r}; } if ($options{i}) { $include = $options{i}; } if ($options{R} && $options{r}) { print "The -r option and -R option are mutually exclusive.\n"; exit(64); } if ($options{R}) { $vid = "FIRST"; } if ($options{d}) { $vulndb = $options{d}; } if ($options{p}) { $pkg_names = $options{p}; } if ($options{P}) { $portsdir = $options{P}; } ######### # Actual script start my $actvuln = $vulndb; if ($vid ne "") { $actvuln = clean_vuln($vid, $vulndb); $cleanfiles = $actvuln; } open(PKGNAMES, $pkg_names) || die("Could not open package name list"); while () { my ($pkg, $port) = split(/ +/); if ($include ne "" && !(($port =~ /$include/) || ($exclude ne "" && ($port =~ /$exclude/)))) { next; } $matched_ports{$port} = 1; check_pkg_print($pkg, $actvuln, $port); } close(PKGNAMES); foreach my $port (sort(keys(%matched_ports))) { my ($pkg); $pkg = `make -C $portsdir/$port -V PKGNAME 2>/dev/null`; if ($? != 0) { $pkg = "NONE - Port does not exist"; } chomp($pkg); check_pkg_print($pkg, $actvuln, $port); } # XXX This will only handle one file in $cleanfiles if ($cleanfiles ne "") { unlink($cleanfiles); } sub check_pkg_print { my ($pkg, $vuln, $port) = @_; if (check_pkg($pkg, $actvuln)) { print "Match : "; } else { print "NO Match : "; } printf("%-35s %s\n", $pkg, $port); } # XXX Hack: This is implemented in a very un-XML'ish way. sub clean_vuln { my ($vid, $vuln) = @_; my ($tmpfh, $tmpfile) = mkstemp("$tmpdir/vxcheckXXXXXXXX"); my $inentry = 0; my $found = 0; print $tmpfh ""; print $tmpfh "\n"; print $tmpfh "\n"; open(VULN, $vuln) || die("Could not open $vuln : $!\n"); while () { if ($vid eq "FIRST" && !$found && //) { $inentry = 1; $found = 1; } elsif (//) { $inentry = 1; $found = 1; } if ($inentry) { print $tmpfh $_; } if (/<\/vuln>/) { $inentry = 0; } } if (!$found) { die("Could not find entry with vid $vid!\n"); } print $tmpfh "\n"; close($tmpfh) || die(); return ($tmpfile); } sub check_pkg { my ($pkg, $vuln) = @_; my ($cmd, $out); $cmd = "$vxquery $vuln $pkg"; $out = `$cmd 2>&1`; if ($? != 0) { die("vxquery failed: $out"); } return ($out ne ""); }