$!-------------------------------------------------------------------------o $! ! $! C H E C K S U M M E R ! $! ! $! Author: Franco.Brunetta@libero.it Version 1.0 ! $! Created: 07-JUL-1993 ! $! Last Revision: XX-xxx-XXXX (XX) (XX) ! $! ! $! Users: VMS ! $!-------------------------------------------------------------------------o $! >>>SEE DOCUMENTATION AT THE BOTTOM OF THE PROCEDURE<<< $!-------------------------------------------------------------------------- $! Generic initializations $!-------------------------------------------------------------------------- $ ON ERROR THEN GOTO SOME_Error $ ON CONTROL_Y THEN GOTO Some_Error $! $ WW := Write Sys$Output $ WWE := Write Sys$error $ Resident_dir=F$ELEMENT(0,"]",F$ENVIRONMENT("PROCEDURE"))+"]" $ Node=f$EDIT(F$GETSYI("SCSNODE"),"COLLAPSE") $ PID = F$GETJPI("","PID") $!-------------------------------------------------------------------------- $! Special initialitations $!-------------------------------------------------------------------------- $ CHECKSUM_DB = "''Resident_Dir'''node'_CHECKSUM_DB.DAT" $ IF F$TRNLNM("Checksum_path") .EQS. "" THEN - DEFINE Checksum_Path sys$system,sys$library $ Scratch_report = "SYS$SCRATCH:''Node'_''pid'_chksmmr_report.TMP" $!----------------------------- $! You can use P1 to pass files to search for $!----------------------------- $ IF P1 .nes. "" $ THEN Checksum_Files = P1 $ ELSE Checksum_Files = "*.EXE;*" $ ENDIF $!----------------------------- $! You can use P2 to pass target username for report via mail $!----------------------------- $ IF P2 .EQS. "" $ THEN Checksum_Mgr = "0::SYSTEM" $ ELSE Checksum_Mgr = P2 $ ENDIF $!-------------------------------------------------------------------------- $! Main program. Create a new db and compare it with previous version $! (if any) $!-------------------------------------------------------------------------- $ CALL New_DB $ IF F$SEARCH("''CHECKSUM_DB';-1") .NES."" $ THEN GOSUB Compare_Database $ PURGE/NOLOG/KEEP=3 'Checksum_db' $ ENDIF $ WW "%CHECKSUMMER-I-END, end of operations (''F$time()'" $ EXIT $!-------------------------------------------------------------------------- $! Generic error handling (including signaling from subroutine(s)), and/or $! user abort (^Y) $!-------------------------------------------------------------------------- $Some_Error: $ IF F$TRNLNM("check_db") .NES. "" THEN CLOSE Check_db $ WWE "%CHECKSUMMER-F-ABORTING, some error or CONTROL-Y detected" $ EXIT 44 $!************************************************************************** $! SUBROUTINE: NEW_DB (invoke it with CALL, *NOT* with GOSUB!!!) $! $! Subroutine to create a new db, checksumming files in 'checksum_path'. $! $! Notes: - some .EXE files (for examples, BOOT58.EXE, and PSEUDOLOA.EXE) $! cannot be checksummed using /image qualifiers; so, if $! checksum/image gives an error, I try to checksum WITHOUT /image $! qualifier, but just ONCE (see section "try_again_only_once"): if %! it fails again, checksumming is not performed at all for that file $! $! - TERMTABLE.EXE is a special case: IT CANNOT BE CHECKSUMMED at all, $! so checksumming is not performed on this image $! $!************************************************************************** $!-------------------------------------------------------------------------- $! Initializations $!-------------------------------------------------------------------------- $New_DB: SUBROUTINE $ On Warning then goto Some_Warning $ ON Control_Y THEN GOTO Aborting_SR $ errcounter = 0 $ ww "%CHECKSUMMER-I-CREADB, creating new database..." $!-------------------------------------------------------- $! Create and open new database $!-------------------------------------------------------- $ Create 'Checksum_db' $ Open/append check_db 'checksum_db' $!-------------------------------------------------------- $! give some info to users $!-------------------------------------------------------- $ path_index = 0 $ WW " " $ WW "%CHECKSUMMER-I-STARTSCAN, starting scanning of directory(s):" $! $Path_loop: $ Searchlist_element = f$trnlnm("Checksum_path",,'Path_Index') $ IF Searchlist_Element .EQS. "" THEN GOTO End_Path_Loop $ WW " _Directory path: ",Searchlist_element $ Path_Index = Path_Index + 1 $ GOTO Path_Loop $End_Path_Loop: $! $ WW "_File defaults: ",Checksum_files $ WW " " $ WW " " $ WW "%CHECKSUMMER-I-START, starting checksumming (''f$time()')..." $!-------------------------------------------------------- $! Scan for files. Get some info $!-------------------------------------------------------- $Loop_01: $ Target_file = f$search("Checksum_path:''Checksum_files'") $ IF Target_File .eqs. "" THEN GOTO End_New_db $ Rev_Date = f$file_Attributes("''Target_File'","RDT") $!-------------------------------------------------------- $! IF FID of this target_File is = to sys$system:termtable.exe's $! FID, so THIS Target_file is sys$system:termtable.exe. $! TERMTABLE.EXE is a special case: it cannot be checksummed $! due to its "strange" structure... $!-------------------------------------------------------- $ If F$FILE_ATTRIBUTES("''Target_File'","FID") .EQS. - F$FILE_ATTRIBUTES("SYS$SYSTEM:TERMTABLE.EXE","FID") THEN - GOTO Check_termtable $ GOTO Checksumming $! $!-------------------------------------------------------- $! ...so no checksum is performed for TERMTABLE.EXE. $!-------------------------------------------------------- $Check_Termtable: $ checksum$checksum = "" $ GOTO Trace $! $!-------------------------------------------------------- $! Now, let's try to checksum target_file. Checksum/image if $! it's a .EXE file, otherwise normal checksum is performed. $! Note: some .EXE file cannot be checksummed using /IMAGE, so, $! if checksum/image gives an error, let's repeat it ONCE without $! /image. $!-------------------------------------------------------- $Checksumming: $ DEFINE/USER/NOLOG sys$error nl: $ DEFINE/USER/NOLOG sys$output nl: $ IF F$PARSE(Target_File,,,"TYPE") .EQS. ".EXE" $ THEN SET NOON ! gimme one chance! $ CHECKSUM/IMAGE/OUT=NL: 'Target_File' $ Errstatus = $Status $ SET ON $ IF Errstatus .GT. 1 ! let's try w/o /image qualif. $ THEN DEFINE/USER/NOLOG sys$error nl: $ DEFINE/USER/NOLOG sys$output nl: $ CHECKSUM 'Target_File' $ ENDIF $ ELSE CHECKSUM 'Target_File' $ ENDIF $!-------------------------------------------------------- $! OK, now it's time to report to the database $!-------------------------------------------------------- $Trace: $ WRITE Check_db Target_File," (",checksum$checksum,"), ",Rev_Date $ GOTO loop_01 $! $!-------------------------------------------------------- $! No more file were found; end of this routine $!-------------------------------------------------------- $End_New_DB: $ IF F$TRNLNM("check_db") .NES. "" THEN CLOSE Check_db $ EXIT $! $!-------------------------------------------------------- $! Argh, some warning while processing the file. $!-------------------------------------------------------- $Some_Warning: $ WWE "%CHECKSUMMER-E-SOMEERR, some error, cannot checksum " $ WWE "\''Target_File'"\" $ checksum$checksum = "" $ Rev_Date = " " $ ON WARNING THEN GOTO Some_Warning ! it's valid only ONCE $ GOTO Trace ! write a report line anyway $! $!-------------------------------------------------------- $! A Control_Y was issued; ending subroutine, and give control $! to main program with generic error status (%SYSTEM-F-ABORT) $!-------------------------------------------------------- $Aborting_SR: $ IF F$TRNLNM("check_db") .NES. "" THEN CLOSE Check_db $ EXIT 44 $! $!-------------------------------------------------------- $! $! $! $ ENDSUBROUTINE $!******************************************************************* $!************************************************************************** $! SUBROUTINE: COMPARE_DATABASE (invoke it with GOSUB, *NOT* with CALL!) $! $! Very simple control method: DIFFERENCES between two last version of db, $! sending a MAIL if some difference is found! $! $! DIFFERENCES usually return (in $Status): %X006C8009 (no diff. found) $! %X006C8009 (some diff. found) $! $!************************************************************************** $Compare_Database: $ WW " " $ WW "%CHECKSUMMER-I-COMPARING, comparing two last databases..." $ WW " " $ WW " " $ DIFFERENCES 'Checksum_db'; - /OUTPUT='Scratch_report' $ Result = $Status $ IF Result .EQ. %X006C8009 $ THEN WW "%CHECKSUMMER-I-NODIFF, no differences since last checksum" $ ELSE IF Result .EQ. %X006C8013 $ THEN WW "%CHECKSUMMER-W-SOMEDIFF, some difference found since last checksum!" $ WW " (see MAIL report!!)" $ MAIL/NOSELF - /SUBJ="%CHECKSUMMER-W-SOMEDIFF, warning report from CHECKSUMMER" - 'Scratch_Report' - 'Checksum_Mgr ' $ ELSE WWE "%CHECKSUMMER-F-ERROR, error in DIFFERENCE section!!!) $ ENDIF $ ENDIF $ IF F$SEARCH("''Scratch_Report'") .NES. "" - THEN DELETE/NOLOG 'Scratch_Report';* $ RETURN $!-------------------------------------------------------------------------! $!------------------------D O C U M E N T A T I O N -----------------------! $!-------------------------------------------------------------------------! $! C H E C K S U M M E R ! $! ! $! Simple and easy procedure to control contents of important directories ! $! on your system. ! $! ! $! CHECKSUMMER uses undocumented feature of VMS "CHECKSUM" to control, ! $! day-by-day, contents of important directories on your system and ! $! contents of important files into these important directories. ! $! ! $! CHECKSUMMER looks for every given files in given directories, ! $! performes a Checksum for every files, and keeps all data in a ! $! private database (whose name is: 'Node'_CHECKSUM_DB.DAT in ! $! CHECKSUMMER's resident directory). Then, if a previous version of ! $! this db is present, compares (using DIFFERENCES utility) these two ! $! last versions, signaling to a given user (via mail) any ! $! difference. ! $! ! $! Using CHECKSUMMER *EVERY DAY* to control strategic directories (i.e. ! $! SYS$SYSTEM) may make you able to automatically be notified of every ! $! new file in this directory, as well as of every modification and ! $! deletion of files, improving security of you system, and identifying ! $! virus, troian horses, and so on, as soon as possible. ! $! ! $! You can control operations of CHECKSUMMER: ! $! ! $! - DIRECTORY SCANNING. Predefining a "CHECKSUM_PATH" logical name, you ! $! can tell to CHECKSUMMER what directory(s) to scan. If no lnm is ! $! defined, CHECKSUMMER looks into SYS$SYSTEM AND SYS$LIBRARY ! $! ! $! - FILE SCANNING. Using P1 parameter, you can tell to CHECKSUMMER what ! $! files to checksum. In no P1 is specified, CHECKSUMMER checksums ! $! every "*.EXE;*" file in the Checksum_Path ! $! ! $! - NOTIFIED USER. Checksummer send a mail to a user if any difference ! $! is found between the last two executions. You can use P2 parameter ! $! to tell him the target USERNAME. If no P2 is specified, report is ! $! sent to user SYSTEM on current node. ! $! ! $! Look for further notes in the body of the procedure. ! $! ! $! ! $! ! $! ******************* ! $! D I S C L A I M E R ! $! ******************* ! $! ! $! Author disclaims all warranties with regard to this software, and ! $! cannot be liable for any direct and indirect damages while using ! $! it. It is provided "as is" without express or implied warranty. ! $! ! $! Permission to use, copy, modify and distribute this software is ! $! hereby granted without fee, provided that this notice appear in ! $! supporting documentation. ! $! ! $! ! $!-------------------------------------------------------------------------! $! U P D A T E S ! $! ! $! V1.0 starting version. ! $! ! $!-------------------------------------------------------------------------o