[comp.sources.misc] v06i059: file checker

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (03/08/89)

Posting-number: Volume 6, Issue 59
Submitted-by: zeeff@b-tech.ann-arbor.mi.us (Jon Zeeff)
Archive-name: crc-check

[A set of crc programs.  This came to me labeled as a "file system checker",
but it's no fsck.  ++bsa]

This is a set of programs to check for unexpected file system 
corruption or security breaches.  It's nice to be able to say that you 
know all your files are as they should be.

#! /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:  Makefile README crc.c crc_check.c find_crc
# Wrapped by zeeff@b-tech on Sun Feb 26 12:10:25 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(241 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X
XCC=cc 
XCFLAGS = -O 
XLDFLAGS =
X
X
XSRCS=crc.c crc_check.c
XOBJS=crc.o crc_check.o
X
Xcrc: $(OBJS)
X	$(CC) -o crc crc.o $(CFLAGS) $(LDFLAGS) 
X	$(CC) -o crc_check crc_check.o $(CFLAGS) $(LDFLAGS) 
X
Xclean:
X	rm -f crc.tmp crc.files *.o crc crc_check
X
END_OF_Makefile
if test 241 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(1283 characters\)
sed "s/^X//" >README <<'END_OF_README'
X
XThis is a set of programs to check for unexpected file system 
Xcorruption or security breaches.  It's nice to be able to say that you 
Xknow all your files are as they should be.  Mark Mendel wrote most of 
Xcrc.c and I wrote crc_check.c.  It's written for Sys V, but BSD 
Xshouldn't be hard.  
X
X
XTo use it:
X
X1) you first create a crc list with the script find_crc.  You can
Xmodify it and add grep -v to the pipe to change the file systems that
Xit checks.   The end result is a file "crc.tmp".
X
X2) You can now use crc_check to compare this crc.tmp file to a crc list
Xcreated earlier called crc.files.  If everything is ok, you can mv 
Xcrc.tmp to crc.files.  It is expected that you will want to use grep -v
Xon the output of crc_check to cut down on the noise.
X
XNote that you can use a -i option when running crc to change the 
Xinitial crc value.  If you don't tell anyone what this is, you can 
Xmake it nearly impossible for anyone to modify a file and then adjust 
Xthe crc value to the old one.  To really do it right, you need to 
X
X1) Run find_crc in single user mode (unless you modify the crc source).
X2) Store all crc results offline.
X3) Don't let anyone see your -i value or the crc results.
X
X
XPlease send me any modifications you make.
X
XJon Zeeff
Xzeeff@b-tech.ann-arbor.mi.us
X
X
END_OF_README
if test 1283 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f crc.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"crc.c\"
else
echo shar: Extracting \"crc.c\" \(9918 characters\)
sed "s/^X//" >crc.c <<'END_OF_crc.c'
X/* updcrc(3), crc(1) - calculate crc polynomials
X *
X * Calculate, intelligently, the CRC of a dataset incrementally given a 
X * buffer full at a time.
X * 
X * Usage:
X * 	newcrc = updcrc( oldcrc, bufadr, buflen )
X * 		unsigned int oldcrc, buflen;
X * 		char *bufadr;
X *
X * Compiling with -DTEST creates a program to print the CRC of stdin to stdout.
X * Compile with -DMAKETAB to print values for crctab to stdout.  If you change
X *	the CRC polynomial parameters, be sure to do this and change
X *	crctab's initial value.
X *
X * Notes:
X *  Regards the data stream as an integer whose MSB is the MSB of the first
X *  byte recieved.  This number is 'divided' (using xor instead of subtraction)
X *  by the crc-polynomial P.
X *  XMODEM does things a little differently, essentially treating the LSB of
X * the first data byte as the MSB of the integer. Define SWAPPED to make
X * things behave in this manner.
X *
X * Author:	Mark G. Mendel, 7/86
X *		UUCP: ihnp4!umn-cs!hyper!mark, GEnie: mgm
X */
X
X#define TEST
X
X/* The CRC polynomial.
X * These 4 values define the crc-polynomial.
X * If you change them, you must change crctab[]'s initial value to what is
X * printed by initcrctab() [see 'compile with -DMAKETAB' above].
X */
X
X/* Value used by:	    		CITT	XMODEM	ARC  	*/
X#define	P	 0xA001	 /* the poly:	0x1021	0x1021	A001	*/
X#define INIT_CRC 0L	 /* init value:	-1	0	0	*/
X#define SWAPPED		 /* bit order:	undef	defined	defined */
X#define W	16	 /* bits in CRC:16	16	16	*/
X
X/* data type that holds a W-bit unsigned integer */
X#if W <= 16
X#  define WTYPE	unsigned short
X#else
X#  define WTYPE   unsigned long
X#endif
X
X/* the number of bits per char: don't change it. */
X#define B	8
X
Xstatic WTYPE crctab[1<<B] = /* as calculated by initcrctab() */ {
X   0x0,  0xc0c1,  0xc181,  0x140,  0xc301,  0x3c0,  0x280,  0xc241,
X   0xc601,  0x6c0,  0x780,  0xc741,  0x500,  0xc5c1,  0xc481,  0x440,
X   0xcc01,  0xcc0,  0xd80,  0xcd41,  0xf00,  0xcfc1,  0xce81,  0xe40,
X   0xa00,  0xcac1,  0xcb81,  0xb40,  0xc901,  0x9c0,  0x880,  0xc841,
X   0xd801,  0x18c0,  0x1980,  0xd941,  0x1b00,  0xdbc1,  0xda81,  0x1a40,
X   0x1e00,  0xdec1,  0xdf81,  0x1f40,  0xdd01,  0x1dc0,  0x1c80,  0xdc41,
X   0x1400,  0xd4c1,  0xd581,  0x1540,  0xd701,  0x17c0,  0x1680,  0xd641,
X   0xd201,  0x12c0,  0x1380,  0xd341,  0x1100,  0xd1c1,  0xd081,  0x1040,
X   0xf001,  0x30c0,  0x3180,  0xf141,  0x3300,  0xf3c1,  0xf281,  0x3240,
X   0x3600,  0xf6c1,  0xf781,  0x3740,  0xf501,  0x35c0,  0x3480,  0xf441,
X   0x3c00,  0xfcc1,  0xfd81,  0x3d40,  0xff01,  0x3fc0,  0x3e80,  0xfe41,
X   0xfa01,  0x3ac0,  0x3b80,  0xfb41,  0x3900,  0xf9c1,  0xf881,  0x3840,
X   0x2800,  0xe8c1,  0xe981,  0x2940,  0xeb01,  0x2bc0,  0x2a80,  0xea41,
X   0xee01,  0x2ec0,  0x2f80,  0xef41,  0x2d00,  0xedc1,  0xec81,  0x2c40,
X   0xe401,  0x24c0,  0x2580,  0xe541,  0x2700,  0xe7c1,  0xe681,  0x2640,
X   0x2200,  0xe2c1,  0xe381,  0x2340,  0xe101,  0x21c0,  0x2080,  0xe041,
X   0xa001,  0x60c0,  0x6180,  0xa141,  0x6300,  0xa3c1,  0xa281,  0x6240,
X   0x6600,  0xa6c1,  0xa781,  0x6740,  0xa501,  0x65c0,  0x6480,  0xa441,
X   0x6c00,  0xacc1,  0xad81,  0x6d40,  0xaf01,  0x6fc0,  0x6e80,  0xae41,
X   0xaa01,  0x6ac0,  0x6b80,  0xab41,  0x6900,  0xa9c1,  0xa881,  0x6840,
X   0x7800,  0xb8c1,  0xb981,  0x7940,  0xbb01,  0x7bc0,  0x7a80,  0xba41,
X   0xbe01,  0x7ec0,  0x7f80,  0xbf41,  0x7d00,  0xbdc1,  0xbc81,  0x7c40,
X   0xb401,  0x74c0,  0x7580,  0xb541,  0x7700,  0xb7c1,  0xb681,  0x7640,
X   0x7200,  0xb2c1,  0xb381,  0x7340,  0xb101,  0x71c0,  0x7080,  0xb041,
X   0x5000,  0x90c1,  0x9181,  0x5140,  0x9301,  0x53c0,  0x5280,  0x9241,
X   0x9601,  0x56c0,  0x5780,  0x9741,  0x5500,  0x95c1,  0x9481,  0x5440,
X   0x9c01,  0x5cc0,  0x5d80,  0x9d41,  0x5f00,  0x9fc1,  0x9e81,  0x5e40,
X   0x5a00,  0x9ac1,  0x9b81,  0x5b40,  0x9901,  0x59c0,  0x5880,  0x9841,
X   0x8801,  0x48c0,  0x4980,  0x8941,  0x4b00,  0x8bc1,  0x8a81,  0x4a40,
X   0x4e00,  0x8ec1,  0x8f81,  0x4f40,  0x8d01,  0x4dc0,  0x4c80,  0x8c41,
X   0x4400,  0x84c1,  0x8581,  0x4540,  0x8701,  0x47c0,  0x4680,  0x8641,
X   0x8201,  0x42c0,  0x4380,  0x8341,  0x4100,  0x81c1,  0x8081,  0x4040,
X};
X
X
Xvoid perror();
Xchar *strcpy(); 
Xvoid exit();
X
XWTYPE
Xupdcrc( icrc, icp, icnt )
XWTYPE icrc;
Xunsigned char	*icp;
Xint	icnt;
X{
X   register WTYPE crc = icrc;
X   register unsigned char	*cp = icp;
X   register int	cnt = icnt;
X
X   while ( cnt--) {
X#ifndef SWAPPED
X      crc = (crc << B) ^ crctab[(crc>>(W-B)) ^ *cp++];
X#else
X      crc = (crc >> B) ^ crctab[(crc & ((1<<B)-1)) ^ *cp++];
X#endif 
X   }
X
X   return( crc );
X}
X
X
X#ifdef MAKETAB
X
X#include <stdio.h>
Xmain()
X{
X   initcrctab();
X}
X
X
Xinitcrctab()
X{
X   register int	b, i;
X   WTYPE v;
X
X
X   for ( b = 0; b <= (1 << B) - 1; ++b ) {
X#ifndef SWAPPED
X      for ( v = b << (W - B), i = B; --i >= 0; )
X         v = v & ((WTYPE)1 << (W - 1)) ? (v << 1) ^ P : v << 1;
X#else
X      for ( v = b, i = B; --i >= 0; )
X         v = v & 1 ? (v >> 1) ^ P : v >> 1;
X#endif	    
X      crctab[b] = v;
X
X      (void)  printf( "0x%lx,", v & ((1L << W) - 1L));
X      if ( (b & 7) == 7 )
X         (void)  printf("\n" );
X      else
X         (void)  printf("  ");
X   }
X}
X
X
X#endif
X
X#ifdef TEST
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <pwd.h>
X#include <grp.h>
X#define MAXBUF	4096
X
X#ifndef S_IRGRP
X#define S_IRGRP	(S_IREAD >> 3)
X#define S_IWGRP (S_IWRITE >> 3)
X#define S_IXGRP (S_IEXEC >> 3)
X#define S_IROTH (S_IREAD >> 6)
X#define S_IWOTH (S_IWRITE >> 6)
X#define S_IXOTH (S_IEXEC >> 6)
X#endif
X
Xstruct stat stat_buf;
Xint	initial_crc = INIT_CRC;
X
Xextern char	*optarg;
Xextern int	optind;
Xextern int	opterr;
X
Xmain( argc, argv )
Xint	argc;
Xchar	**argv;
X{
X   int	stats_flag = 0;
X
X   int	c;
X
X   if (argc == 1) {
X      print_crc((char *)0, 0);
X      return 0;
X   }
X
X   /* process all arguments */
X
X   while ((c = getopt(argc, argv, "VvI:i:")) != EOF) {
X
X      switch (c) {
X
X      case 'V':
X      case 'v':
X         stats_flag = 1;
X         break;
X
X      case 'I':
X      case 'i':
X         initial_crc = atoi(optarg);
X         break;
X
X      default:
X         (void) fprintf(stderr, "crc:  -v (verbose listing)\n");
X         (void) fprintf(stderr, "      -i value (initial crc value)\n");
X         exit(1);
X      }
X   }
X
X   for (; optind < argc ; optind++)
X      print_crc(argv[optind], stats_flag);
X
X   return 0;
X}
X
X
Xprint_crc(name, stat_flag)
Xchar	*name;
Xint	stat_flag;
X{
X   int	fd;
X   int	nr;
X   unsigned char	buf[MAXBUF];
X   WTYPE crc;
X#ifdef MAGICCHECK
X   WTYPE crc2;
X#endif
X
X   fd = 0;
X
X   /* quietly ignore files we can't stat */
X
X   if (name != NULL && stat(name, &stat_buf) != 0)
X      return;
X
X   /* don't do a crc on strange files */
X
X   crc = nr = 0;
X
X   if (name == NULL || (stat_buf.st_mode & S_IFMT) == S_IFREG) {
X
X      /* open the file and do a crc on it */
X
X      if (name != NULL && (fd = open( name, O_RDONLY )) < 0 ) {
X         perror( name );
X         exit( -1 );
X      }
X#ifdef MAGICCHECK
X      crc2 = 
X#endif
X      crc = initial_crc;
X
X      while ( (nr = read( fd, (char *)buf, MAXBUF )) > 0 ) {
X         crc = updcrc(crc, buf, nr );
X      }
X      (void) close(fd);
X
X   }
X   if ( nr != 0 ) {
X      perror( "read error" );
X   } else {
X      (void)  printf("%4.4x", (unsigned) crc );
X      if (stat_flag)
X         stats(name);
X      else
X         (void)  printf("\n");
X
X   }
X
X#ifdef MAGICCHECK
X   /* tack one's complement of crc onto data stream, and
X       continue crc calculation.  Should get a constant (magic number)
X       dependent only on P, not the data.
X     */
X   crc2 = crc ^ -1L;
X   for ( nr = W - B; nr >= 0; nr -= B ) {
X      buf[0] = (crc2 >> nr);
X      crc = updcrc(crc, buf, 1);
X   }
X
X   /* crc should now equal magic */
X   buf[0] = buf[1] = buf[2] = buf[3] = 0;
X   (void)  printf( "magic test: %lx =?= %lx\n", crc, updcrc((WTYPE) - 1, buf, W / B));
X#endif 
X
X
X}
X
X
Xstats(name)
Xchar	*name;
X{
X
X   struct passwd *entry;
X   struct group *group_entry;
X   static char	owner[20];
X   static char	group[20];
X   char	a_time[50];
X
X   struct passwd *getpwuid();
X   struct group *getgrgid();
X   char	*ctime();
X
X   static int	prev_uid = -9999;
X   static int	prev_gid = -9999;
X
X   if (stat_buf.st_uid != prev_uid) {
X      entry = getpwuid((int)stat_buf.st_uid);
X      if (entry)
X         (void) strcpy(owner, entry->pw_name);
X      else
X         (void) sprintf(owner, "%d", stat_buf.st_uid);
X      prev_uid = stat_buf.st_uid;
X   }
X   if (stat_buf.st_gid != prev_gid) {
X      group_entry = getgrgid((int)stat_buf.st_gid);
X      if (group_entry)
X         (void) strcpy(group, group_entry->gr_name);
X      else
X         (void) sprintf(group, "%d", stat_buf.st_gid);
X      prev_gid = stat_buf.st_gid;
X   }
X
X   (void) strcpy(a_time, ctime(&stat_buf.st_mtime));
X   a_time[24] = '\0';
X
X   print_perm(stat_buf.st_mode);
X
X   (void)  printf(" %s\t%s\t%s %s\n", owner, group, a_time + 4, name);
X
X}
X
X
Xprint_perm(perm)
Xunsigned int	perm;
X{
X
X   char	string[20];
X   (void) strcpy(string, "----------");
X
X   switch (perm & S_IFMT) {
X
X   case S_IFDIR:
X      string[0] = 'd';
X      break;
X
X   case S_IFBLK:
X      string[0] = 'b';
X      break;
X
X   case S_IFCHR:
X      string[0] = 'c';
X      break;
X
X   case S_IFIFO:
X      string[0] = 'p';
X      break;
X   }
X   if (perm & S_IREAD)
X      string[1] = 'r';
X   if (perm & S_IWRITE)
X      string[2] = 'w';
X   if (perm & S_ISUID && perm & S_IEXEC)
X      string[3] = 's';
X   else if (perm & S_IEXEC)
X      string[3] = 'x';
X   else if (perm & S_ISUID)
X      string[3] = 'S';
X
X   if (perm & S_IRGRP)
X      string[4] = 'r';
X   if (perm & S_IWGRP)
X      string[5] = 'w';
X   if (perm & S_ISUID && perm & S_IXGRP)
X      string[6] = 's';
X   else if (perm & S_IXGRP)
X      string[6] = 'x';
X   else if (perm & S_ISUID)
X      string[6] = 'l';
X
X   if (perm & S_IROTH)
X      string[7] = 'r';
X   if (perm & S_IWOTH)
X      string[8] = 'w';
X   if (perm & S_ISVTX && perm & S_IXOTH)
X      string[9] = 't';
X   else if (perm & S_IXOTH)
X      string[9] = 'x';
X   else if (perm & S_ISVTX)
X      string[9] = 'T';
X
X   (void) printf(" %s", string);
X}
X
X#endif
X
END_OF_crc.c
if test 9918 -ne `wc -c <crc.c`; then
    echo shar: \"crc.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f crc_check.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"crc_check.c\"
else
echo shar: Extracting \"crc_check.c\" \(4067 characters\)
sed "s/^X//" >crc_check.c <<'END_OF_crc_check.c'
X
X/*
X    This progam will compare two crc lists and report the differences.
X    
X    By Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us)
X
X    Permission is granted to use this in any manner provided that    
X    1) the copyright notice is left intact, 
X    2) you don't hold me responsible for any bugs and 
X    3) you mail me any improvements that you make.  
X
X
X    report:
X         corrupt	-	crc changed w/o date change
X         replaced	-	crc + date changed
X         perm		-	permissions changed
X         own/grp	-	owner or group changed
X	 removed	-	
X	 added		-
X
XPrint the info for the new file except for deleted.
X
XUse:
X
Xfind / -print | sort | xargs crc -v > crc_file
X
Xto generate a crc list (crc.c should accompany this source).
X
XAssume that no files have tabs or spaces in the name.
X
X*/
X
X/* max size of line */
X
X#define BUF_SIZE 1124
X
X#include <stdio.h>
X
Xchar	*strrchr();
Xvoid    exit();
X
Xchar	new_line[BUF_SIZE];
Xchar	old_line[BUF_SIZE];
X
XFILE *new_file;
XFILE *old_file;
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X   /*
X
X           If line =, read new line from each file
X           else
X           If date/perm/crc change, report and read new line from each file
X           else
X           If old_line < new_line, report file removed, read old line
X           else
X              report new line as added
X              read new_line
X        loop
X*/
X
X   char	*new_ptr;
X   char	*old_ptr;
X
X   if (argc != 3) {
X      (void) printf("wrong number of arguments\n");
X      (void) printf("crc_check old_crc_file new_crc_file\n");
X      exit(1);
X   }
X   new_file = fopen(argv[2], "r");
X   old_file = fopen(argv[1], "r");
X
X   if (new_file == NULL || old_file == NULL) {
X      (void) printf("can't open input files\n");
X      (void) printf("crc_check old_crc_file new_crc_file\n");
X      exit(1);
X   }
X
X   get_line(new_line);
X   get_line(old_line);
X
X   for (; ; ) {
X
X      check_eof();
X
X      /* If equal, print nothing and get new lines */
X
X      if (strcmp(old_line, new_line) == 0) {
X         get_line(new_line);
X         get_line(old_line);
X         continue;
X      }
X
X      /* Compare just the file names */
X
X      new_ptr = strrchr(new_line, ' ');
X      old_ptr = strrchr(old_line, ' ');
X
X      if (new_ptr == NULL || old_ptr == NULL) {
X         (void) printf("Error in input data\n");
X         exit(1);
X      }
X
X      if (strcmp(old_ptr, new_ptr) == 0) {
X
X         new_ptr = strrchr(new_line, '\t');
X         old_ptr = strrchr(old_line, '\t');
X
X         if (new_ptr == NULL || old_ptr == NULL) {
X            (void) printf("Error in input data\n");
X            exit(1);
X         }
X
X         /* check crc change */
X
X         if (strncmp(new_line, old_line, 4) != 0)
X            if (strcmp(new_ptr, old_ptr) == 0)
X               (void) printf("corrupt  %s", new_line + 5);
X            else
X               (void) printf("replaced %s", new_line + 5);
X
X
X         /* check permission chenage */
X
X         if (strncmp(new_line + 5, old_line + 5, 11) != 0)
X            (void) printf("permiss  %s", new_line + 5);
X
X         /* check  owner/group */
X
X         if (strncmp(new_line+16, old_line+16, new_ptr - new_line - 15) != 0)
X            (void) printf("own/grp  %s", new_line + 5);
X
X         get_line(new_line);
X         get_line(old_line);
X         continue;
X      }
X
X
X      if (strcmp(old_ptr, new_ptr) < 0) {
X         (void) printf("removed  %s", old_line + 5);
X         get_line(old_line);
X         continue;
X      }
X
X      (void) printf("added    %s", new_line + 5);
X      get_line(new_line);
X
X   }
X
X}
X
X
Xget_line(string)
Xchar	*string;
X{
X   if (string == new_line)
X      (void) fgets(string, BUF_SIZE, new_file);
X   else
X      (void) fgets(string, BUF_SIZE, old_file);
X
X}
X
X
Xcheck_eof()
X{
X
X   if (feof(new_file)) {
X
X      while (!feof(old_file)) {
X         (void) printf("removed  %s", old_line + 5);
X         (void) fgets(old_line, BUF_SIZE, old_file);
X      }
X      exit(0);
X   } else if (feof(old_file)) {
X      while (!feof(new_file)) {
X         (void) printf("added    %s", new_line + 5);
X         (void) fgets(new_line, BUF_SIZE, new_file);
X      }
X      exit(0);
X   }
X
X}
X
X
END_OF_crc_check.c
if test 4067 -ne `wc -c <crc_check.c`; then
    echo shar: \"crc_check.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f find_crc -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"find_crc\"
else
echo shar: Extracting \"find_crc\" \(58 characters\)
sed "s/^X//" >find_crc <<'END_OF_find_crc'
X
Xfind / -mount -print | sort | xargs crc -v > crc.tmp  
X
X
END_OF_find_crc
if test 58 -ne `wc -c <find_crc`; then
    echo shar: \"find_crc\" unpacked with wrong size!
fi
chmod +x find_crc
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
-- 
  Jon Zeeff			zeeff@b-tech.ann-arbor.mi.us
  Ann Arbor, MI			mailrus!b-tech!zeeff