Enclosed is a script that checks if your Solaris system has the latest security patches applied. It FTP's the status file from Sun's site, caches a local copy, does a "showrev -a", compares the two, and reports out-of-date patches. This is not a perfect test, but it is quick and easy, and some might find it useful. If the local copy is old, you either get a warning, or a forced update of the patch information file. (A configuration option). The package requires expect and perl 5 (no perl modules need be installed). The enclosed README file has more information. Cheers #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README CheckPatches Fetch.expect # Wrapped by barnett@grymoire on Wed Jan 6 10:28:09 1999 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(1678 characters\) sed "s/^X//" >README <<'END_OF_README' XIt is designed to server the following purpose: X X Check if the recent Solaris security patches have been applied. X If not, it reports those missing patches to standard output X XSample output looks like this: X XPatch 103959-6 should be updated to 103959-8 XPatch 103743-1 missing X XUsage: ./CheckPatches [-vdaf] X -v => Enable Verbose mode X -d => Enable Debug mode X -f => Force fetches the security report file for this Operating System X -a => Fetches ALL of the security report files (assumes -f) X XRequires: X X perl X expect X X Ability to ftp to sunsolve.sun.com X XFunction: X X The program FTP's the appropriate security file from sunsolve.sun.com. XThe file is cached on the local file system. If the file is old, you Xeither get a warning, or a forced update. (The two values can be modified). X XIf you want to, you can force the system to FTP the report file Xwith the -f option. If you want to FTP all of the report files for ALL Xflavors of Solaris, use -a. X XInstallation: X X 1. Make sure perl and expect are installed. I use perl 5, but X do not require any modules to be installed. X 2. Examine CheckPatches and modify the variables at X the top of the script. X 3. If ftp does not work without a proxy, you may have X to modify the Fetch.expect script. Perhaps use the socks X version of ftp. X X X XWarning: X X This script bases it's decision on the file from Sun's FTP X site, and the results of the showrev command. Neither of these X sources are authenticated, and either may be X spoofed/intercepted/modified/etc. X X This package is offered AS IS, with no guarantee or X warrantee. Use at your own risk. X XComments/enhancements are welcome. XBruce Barnett <barnettat_private> END_OF_README if test 1678 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f CheckPatches -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"CheckPatches\" else echo shar: Extracting \"CheckPatches\" \(6977 characters\) sed "s/^X//" >CheckPatches <<'END_OF_CheckPatches' X#!/bin/sh -- # perl Xeval 'exec perl -S $0 ${1+"$@"}' # wish I were -*-Perl-*- X if 0; X#!/usr/bin/perl X# X# @(#)CheckPatches 1.9 01/05/99 X# Maintained by Bruce Barnett <barnettat_private> X# Please send all updates to the above address X# X# This program checks if the latest security patches have been applied X# to a Solaris workstation. Since it uses showrev(1) to determine X# this, and doesn't verify the integrity of the data, it is possible X# to fool this check. A more complete check would examine each file X# in the patch, and verify that file. X# X# This software is offered AS IS. No guarrantees are implied. X# Use at your own risk X# X# This package requires expect and perl to be available and in the searchpath X# X Xeval('use strict'); # Use eval, In case it is not there X X############################## X# You must specify your hostname so that anonymous FTP works. Xmy $HOSTNAME="hostname.com"; X X# External Commands used (you may need to modify these); Xmy $UNAME="uname -a"; Xmy $SHOWREV = "showrev -a"; Xmy $REMOTE="sunsolve.sun.com"; X#my $REMOTE="sunsolve1.sun.com"; Xmy $E_FETCH = "./Fetch.expect"; # Name of the Expect script X X# User e-mail name used for password with anonymous FTP Xmy $EMAIL = $ENV{"LOGNAME"} . "@". $HOSTNAME; X X# How old can the local report file be? X$somewhat_old = 3; # Number of days before I complain X$real_old = 10; # Number of days before I force the file to be updated X X# End of section of user-specified code X# You should not have to change anything else X# X############################## X# Global variables Xmy $program = "CheckPatches"; # Name of the program X X############################## X# command line options - modified by command line arguments Xmy $debug = 0; Xmy $verbose = 0; Xmy $fetch = 0; # fetch the file Xmy $fetch_all = 0; # fetch all of the files Xmy $expect = 1; # which method shall I use? X Xsub getswitches { # get command line arguments X # parse arguments X my ($usage) = 0; X while ($#ARGV>=0 && $ARGV[0] =~ /^-/) { X my ($arg) = shift(@ARGV); X $arg =~ /^-v$/ && ($verbose++,next); X $arg =~ /^-d$/ && ($debug++,next); X $arg =~ /^-f$/ && ($fetch++,next); X $arg =~ /^-a$/ && ($fetch_all++,$fetch++,next); X $arg =~ /^-/ && X (printf(STDERR "Ignoring unknown option '%s'\n", $arg),$usage++,next); X last; X } X while ($#ARGV >=0) { X printf(STDERR "Ignoring argument %s\n", $ARGV[0]); X shift (@ARGV); X $usage++; X } X if ($usage) { X printf(STDERR "Usage: %s [-vdaf]\n", $program); X printf(STDERR "\t-v => Enable Verbose mode\n"); X printf(STDERR "\t-d => Enable Debug mode\n"); X printf(STDERR "\t-f => Fetch the security report file for this Operating System\n"); X printf(STDERR "\t-a => Fetch ALL of the security report files (assumes -f)\n"); X exit 1; X } X} X Xsub fetch { X my ($rev) = @_; X my $ans; X # Fetch the file using various mechanisms - eventually X # Just use expect for now X # Add more options later X X my $pfile; X X if ($fetch_all) { X $pfile= sprintf("Solaris*.PatchReport"); X } else { X $pfile= sprintf("Solaris%s.PatchReport", $rev); X } X if ($expect && -f $E_FETCH) { X $ans = `$E_FETCH $pfile $EMAIL $REMOTE </dev/null 2>&1`; X } X $verbose && printf(STDERR "Expect Results: $ans\n"); X} X Xsub main { X my $uname; # UNIX name X my $osrev; # OS Revision (e.g. 5.6) X my $Sosrev; # Solaris Revision (w.g. 2.6) X my $line; # X my $file; # The file that contains the patch report X my $mtime; # Modified time of the above file X my $patch; X my $rev; X my %expect; X my %found; X my $i; X X (defined($0)) && ($program = $0); X $uname=`$UNAME`; X X # Should I run at all? (I only handle Solaris systems) X chomp $uname; X if ($uname =~ /SunOS \S+ (\d+)\.([\d.]+)/) { X chop $uname; X $osrev = "$1.$2"; # e.g. 5.5.1 X if ($1 == 4 || $1 == 5) { # SunOS 4 or SunOS 5 X $Sosrev = sprintf("%s.%s", $1-3, $2); # e.g. 2.5.1 X } else { X $Sosrev=$osrev; X } X } else { X printf(STDERR "I don't know how to check the patches of this system: %s\n", $uname); X exit 1; X } X X &getswitches(); X X # The security report is in this file X $file = "Solaris$Sosrev.PatchReport"; X X if ($fetch) { X # Then I already decided! :-) X } elsif ( ! -f $file) { X $verbose && printf(STDERR "Cannot find file '%s', fetching....\n", $file); X $fetch++; X } else { # file exists. Do I need to fetch? X $mtime=(stat $file)[9]; X # Get the age of the file (time-$mtime) is in minutes. We want days X my $file_age = (time-$mtime)/(60*60*24); X X if ($file_age > $real_old) { X $fetch++; # REAL OLD - better fetch X } elsif ($file_age > $somewhat_old) { X printf(STDERR "Warning, file '%s' is %4.2f days old\n", $file, $file_age); X printf(STDERR "Suggestion: use '%s -f' to get more recent version of file %s\n", X $program, $file); X } else { X # Not that old, Only mention it if asked. X $verbose && printf(STDERR "File '%s' is %4.2f days old\n", $file, $file_age); X } X } X # Do I need to fetch a fresh copy of the security report files? X if ($fetch) { X $verbose && printf("Fetching...\n"); X &fetch($Sosrev); X } X X open(P,"$file") || die "cannot open file: $file: $!\n"; X my $in_section=0; X while (defined($line=<P>)) { X chop $line; X if ($line =~ /^\s+ as of\s+(\d\d\/[A-Z][a-z][a-z]\/\d\d)$/) { X $verbose && printf("Security report file '$file' dated %s\n", $1); X } elsif ($line =~ /Solaris $Sosrev Patches Containing Security Fixes/) { X $in_section=1; # start of section X } elsif ($line =~ /Solaris $Sosrev Obsoleted Patches/) { X $in_section=0; # send of section X } elsif ($in_section && $line =~ /^(\d+)-(\d+)/) { X $patch=$1; X $rev=$2; X $expect{$patch}=$rev; X } else { X $debug && $verbose && printf(STDERR "I am ignoring this line in file '%s': %s\n", X $file, $line); X } X } X close(P); X X# Okay - now phase 2 X my $patches_read = 0; X open(R, "$SHOWREV |") || die "cannot open pipe to '$SHOWREV': $!\n"; X while (defined($line=<R>)) { X if ($line =~ /^Patch:\s(\d+)-(\d+)/) { X $patches_read++; X $patch=$1; X $rev=$2; X if (!defined($found{$patch})) { X $found{$patch}=$rev; X } elsif( $found{$patch} < $rev) { X $found{$patch}=$rev; X } else { X $verbose && $debug && printf("Strange... '$SHOWREV' is listing patches in a strange order. First %s-%s, then %s-%s\n", X $patch, $found{$patch}, $patch, $rev); X } X X } X } X X if ($patches_read == 0) { X if ($< != 0) { X printf(STDERR "Unable to read '$SHOWREV,' Re-execute script as root\n"); X } else { X printf(STDERR "'$SHOWREV' didn't tell me anything about the installed patches. Strange\n"); X } X } else { X foreach $i (sort keys %expect) { X if (!defined($found{$i})) { X printf("Patch %d-%d missing\n", $i, $expect{$i}); X } else { X if ($expect{$i} > $found{$i}) { X printf("Patch %d-%d should be updated to %d-%d\n", X $i, $found{$i}, $i, $expect{$i}); X } X } X } X } X} X X X&main(); X X X END_OF_CheckPatches if test 6977 -ne `wc -c <CheckPatches`; then echo shar: \"CheckPatches\" unpacked with wrong size! fi chmod +x CheckPatches # end of overwriting check fi if test -f Fetch.expect -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Fetch.expect\" else echo shar: Extracting \"Fetch.expect\" \(858 characters\) sed "s/^X//" >Fetch.expect <<'END_OF_Fetch.expect' X#!/bin/sh X X# This script FTPs a file from the Sun patch directory using expect X# and anonymous FTP X# @(#)Fetch.expect 1.4 01/05/99 X# Bruce Barnett <barnettat_private> -*-Shell-script-*- X# X# Argument 1= filename X# Argument 2 = password to use for anonymous ftp X# Argument 3 = site to FTP the file from X XFILE=${1:?'Missing argument 1 - filename'} XUSER=${2:?'Missing argument 2 - password'} X#REMOTE=${3:-'sunsolve1.sun.com'} XREMOTE=${3:?'Missing argument 3 - site name'} X Xexpect <<EOF Xset timeout -1 Xspawn ftp -n $REMOTE X expect { X ftp> {send "user ftp\r"} X } X expect { X word: {send "$USER\r"} X } X expect { X ftp> {send "bin\r"} X } X expect { X ftp> {send "cd /pub/patches\r"} X } X expect { X ftp> {send "prompt\r"} X } X expect { X ftp> {send "mget $FILE\r"} X } X expect { X ftp> {send "quit\r"} X } XEOF END_OF_Fetch.expect if test 858 -ne `wc -c <Fetch.expect`; then echo shar: \"Fetch.expect\" unpacked with wrong size! fi chmod +x Fetch.expect # end of overwriting check fi echo shar: End of shell archive. exit 0
This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:27:35 PDT