From:	MERC::"uunet!Dayton.SAIC.COM!ake" 12-MAY-1992 18:21:27.32
To:	everhart
CC:	
Subj:	COPS  10/18

#!/bin/sh
# this is p4.shar.10 (part 10 of a multipart archive)
# do not concatenate these parts, unpack them in order with /bin/sh
# file cops_104/src/crc.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 10; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping cops_104/src/crc.c'
else
echo 'x - continuing file cops_104/src/crc.c'
sed 's/^X//' << 'SHAR_EOF' >> 'cops_104/src/crc.c' &&
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
X
SHAR_EOF
echo 'File cops_104/src/crc.c is complete' &&
chmod 0600 cops_104/src/crc.c ||
echo 'restore of cops_104/src/crc.c failed'
Wc_c="`wc -c < 'cops_104/src/crc.c'`"
test 9920 -eq "$Wc_c" ||
	echo 'cops_104/src/crc.c: original size 9920, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/crc_check.c ==============
if test -f 'cops_104/src/crc_check.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/crc_check.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/crc_check.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/crc_check.c' &&
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/*
X sequent stuff -- may or may not need it?  Worked fine without it
Xon a sequent I had, but others claim they need it.  Go figure.
X
X#ifdef sequent
X#define strrchr(s, c)	rindex(s,c)
X#endif
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
X
SHAR_EOF
chmod 0600 cops_104/src/crc_check.c ||
echo 'restore of cops_104/src/crc_check.c failed'
Wc_c="`wc -c < 'cops_104/src/crc_check.c'`"
test 4261 -eq "$Wc_c" ||
	echo 'cops_104/src/crc_check.c: original size 4261, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/filewriters.c ==============
if test -f 'cops_104/src/filewriters.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/filewriters.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/filewriters.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/filewriters.c' &&
X/* Copyright 1985 Robert W. Baldwin */
X/* Copyright 1986 Robert W. Baldwin */
X
X/*
X   August 15, 1989: Dan Farmer
X   One line changed -- #38 is the old line, #41 is my version.
X   See comment for details...
X*/
Xstatic	char	*notice85 = "Copyright 1985 Robert W. Baldwin";
Xstatic	char	*notice86 = "Copyright 1986 Robert W. Baldwin";
X
X/*
X * Useage: filewriters pathname
X * Writes on stdout the list of people who can write the file.
X * This writer's list contains three tokens, the owner, the group, and
X * the 'all others' group, respectively.
X * If either group does not have write access, then that token is
X * replace with the token "NONE".  If the 'all others' group has
X * write access then that token is "OTHER".
X *
X * Notice that the owner of a file can always write it because the
X * owner can change the file access mode.
X *
X * BUG: should handle links correctly.
X */
X
X#include	<stdio.h>
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#include	<grp.h>
X#include	<pwd.h>
X
X/*
X  changed this line from upper to lower case 's'.
X  Ultrix barfed 'cause already defined in sys/stat.h,
X  no one else seemed to mind...
X
X#define	S_GWRITE	(S_IWRITE >> 3)
X*/
X
X#ifdef cray
Xstruct group *getgrgid();
X#endif
X
X#define	s_GWRITE	(S_IWRITE >> 3)		/* Group write access. */
X#define	S_OWRITE	(S_IWRITE >> 6)		/* Other write access. */
X
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X	int	i;
X	struct	stat	buf;
X
X/*
X * Make sure the file exists.
X */
X 	if (argc != 2)  {
X		fprintf(stderr, "%s: wrong number of args.\n", argv[0]);
X		exit(1);
X		}
X	if (stat(argv[1], &buf) != 0)  {
X		fprintf(stderr, "%s: File %s does not exist.\n",
X			argv[0], argv[1]);
X		exit(1);
X		}
X/*
X * Produce list of writers.
X * Owner can always write.
X */
X	printf("        ");
X	print_uid(stdout, buf.st_uid);
X	printf(" ");
X	if (s_GWRITE & (buf.st_mode))  {
X		print_gid(stdout, buf.st_gid);
X		}
X	else {
X		printf("NONE");
X		}
X	printf(" ");
X	if (S_OWRITE & buf.st_mode)  {
X		printf("OTHER");
X		}
X	else {
X		printf("NONE");
X		}
X	printf("\n");
X	exit(0);
X}
X
X
Xprint_uid(out, uid)
XFILE	*out;
Xint	uid;
X{
X	struct	passwd	*pwent;
X	
X	if ((pwent = getpwuid(uid)) == NULL)  {
X		fprintf(stderr, "Bad user id %d.\n", uid);
X		exit(1);
X		}
X	fprintf(out, "%s", pwent->pw_name);
X}
X
X
Xprint_gid(out, gid)
XFILE	*out;
Xint	gid;
X{
X	struct	group	*grpent;
X	
X	if ((grpent = getgrgid(gid)) == NULL)  {
X		fprintf(stderr, "Bad group id %d.\n", gid);
X		exit(1);
X		}
X	fprintf(out, "%s", grpent->gr_name);
X
X}
X
SHAR_EOF
chmod 0600 cops_104/src/filewriters.c ||
echo 'restore of cops_104/src/filewriters.c failed'
Wc_c="`wc -c < 'cops_104/src/filewriters.c'`"
test 2420 -eq "$Wc_c" ||
	echo 'cops_104/src/filewriters.c: original size 2420, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/home.chk.c ==============
if test -f 'cops_104/src/home.chk.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/home.chk.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/home.chk.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/home.chk.c' &&
X/*
X
X-------------------------------------------------------------------------
XModification: Aug 2, 1989
XAuthor: Dan Farmer
X
X  I made a minor change to this; it uses a bit mask instead of comparing
Xto various ok modes.  Otherwise it is unchanged....
X-------------------------------------------------------------------------
X
XOriginal Comment:
X
XThis was posted to comp.unix.wizards and net.sources, but I also wanted to
Xsend it here, both for those that don't read or get news, and so that it
Xwill be in the archives for posterity....
X
XOn the UNIX Security list, quite a while back, mention was made of
Xproblems that could occur when home directories of users are writable.
X(Installing |"some command" in ~uucp/.forward remotely and things like
Xthat.)  This prompted me to write the enclosed program, both to check
Xfor this, and to help protect users against themselves.
X
XThe program looks at all the home directories listed in /etc/passwd,
Xand prints a message if they don't exist, are not directories, or
Xtheir mode is not in the "table" of "OK" modes.  I'm using stat()
Xinstead of lstat(), so symbolic links are perfectly acceptable, as
Xlong as they point to directories....  This program should run on any
Xversion of UNIX that I can think of; if it doesn't, please let me
Xknow.
X
XThe list of good modes is, of course, subjective.  I initially used
Xthe first set, then added the second set based on the output of the
Xfirst run.  I didn't add all the mismatched modes I found; just the
Xones that were fairly normal and that I didn't want to hear about....
X
XThe program is surprisingly (to me) fast.  It took under a second on
Xour decently loaded VAX-11/785 running 4.3BSD with 501 passwd entries!
X
XThis program is placed in the public domain - you have only your
Xconscience to stop you from saying "hey, look at this neat program I
Xwrote"....
X
X	Enjoy!
X
XJohn Owens		Old Dominion University - Norfolk, Virginia, USA
Xjohn@ODU.EDU		old arpa: john%odu.edu@RELAY.CS.NET
X+1 804 440 3915		old uucp: {seismo,harvard,sun,hoptoad}!xanth!john
X*/
X
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X
X/* mask for modes.... (world writable) */
X#define DMODE 002
X
Xmain(argc,argv)
Xchar **argv;
X{
X	register int mode;
X	register int *p;
X	struct passwd *pp;
X	static struct stat statb;
X
X	if (argc != 1) {
X		printf("Usage: %s\n",argv[0]);
X		exit(1);
X	}
X
X	while ((pp = getpwent()) != (struct passwd *)0) {
X		if (stat(pp->pw_dir,&statb) < 0) {
X		/*
X			perror(pp->pw_dir);
X		*/
X			continue;
X		}
X
X		if ((statb.st_mode & S_IFMT) != S_IFDIR) {
X			printf("Warning!  User %s's home directory %s is not a directory! (mode 0%o)\n",
X				pp->pw_name,pp->pw_dir,statb.st_mode);
X			continue;
X		}
X
X		mode = statb.st_mode & ~S_IFMT;
X
X		if (!(mode & DMODE)) goto ok;
X
X				/* note that 3.3 will print 4 if needed */
X		printf("Warning!  User %s's home directory %s is mode 0%3.3o!\n",
X		       pp->pw_name,pp->pw_dir,mode);
Xok:	;
X	}
X
X	exit(0);
X
X}
SHAR_EOF
chmod 0600 cops_104/src/home.chk.c ||
echo 'restore of cops_104/src/home.chk.c failed'
Wc_c="`wc -c < 'cops_104/src/home.chk.c'`"
test 2916 -eq "$Wc_c" ||
	echo 'cops_104/src/home.chk.c: original size 2916, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/is_able.c ==============
if test -f 'cops_104/src/is_able.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/is_able.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/is_able.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/is_able.c' &&
X/*
X    Usage:
X
X is_able filename {w|g|s|S}       {r|w|B|b|s}
X         (world/group/SUID/SGID   read/write/{read&write}/{suid&write}/s[ug]id)
X
X    The second arg of {r|w} determines whether a file is (group or world
X  depending on the first arg of {w|g}) writable/readable, or if it is
X  SUID/SGID (first arg, either s or S, respectively), and prints out a
X  short message to that effect.
X
X So:
X    is_able w w		# checks if world writable
X    is_able g r		# checks if group readable
X    is_able s s		# checks if SUID
X    is_able S b		# checks if world writable and SGID
X
X  	Permissions bits:		  vvv--- Permission bits
X   	        1 = execute		00000
X   	        2 = writable		 ^
X   	        4 = readable		 + Setuid bits
X
X  	Setuid bits:
X   	        1 = sticky
X   	        2 = set group id
X   	        4 = set user od
X
X    Pete Shipley (shipley@mica.berkeley.edu) gutted my original code,
X  made in cleaner and smarter, and combined everything into one compact
X  file.  What a deal, huh?  Then I came along and beat up his code and
X  made it look ugly again (I changed the is_writeable option to return
X  true if _any_ parent directories are writable, not just the target.  So
X  you can blame me if you want.  Better yet, just send me a patch if I
X  blew it.)
X
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <ctype.h>
X#include <stdio.h>
X
X#define G_READ_TEST 00044	/* group (or world) readable */
X#define W_READ_TEST 00004	/* world readable */
X#define G_READ_STRING	"Warning!  %s is group readable!\n"
X#define W_READ_STRING	"Warning!  %s is _World_ readable!\n"
X
X#define G_WRITE_TEST 00022	/* group (or world) writable */
X#define W_WRITE_TEST 00002	/* world writable */
X#define G_WRITE_STRING	"Warning!  %s is group writable!\n"
X#define G_WRITE_TREE	"Warning!  %s is group writable! (*)\n"
X#define W_WRITE_STRING	"Warning!  %s is _World_ writable!\n"
X#define W_WRITE_TREE	"Warning!  %s is _World_ writable! (*)\n"
X
X#define SGID_TEST 02000		/* set group id */
X#define SUID_TEST 04000		/* set user id */
X#define SUID_STRING	"Warning!  %s is SUID!\n"
X#define SGID_STRING	"Warning!  %s is SGID!\n"
X
Xchar usage[]="Usage: is_able file {w|g|S|s} {r|w|B|b|}\n";
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
Xchar file[256],wg,rwb,gstring[35],wstring[35],wstring_tree[50],
X	gstring_tree[50], suidstring[35];
Xregister int group, read, write, both, suid, sgid, verbose, xmode;
Xstatic struct stat statb;
X
Xgroup=read=write=suid=sgid=both=verbose=xmode=0;
X
X/* check out arguments */
Xif (argc != 4) {
X	fprintf(stderr, usage);
X	exit(1);
X	}
X
X/* parse arguments */
Xstrcpy(file, argv[1]);
X
X/* get stats on file in question -- if doesn't exist, exit */
Xif (stat(file,&statb) < 0) {
X	fprintf(stderr, file);
X	exit(2);
X	}
X
Xwg   = argv[2][0];		/* world or group */
Xrwb  = argv[3][0];		/* read/write/both */
X
X/* set the report string and some flags */
Xif (wg == 'g') group = 1;
Xelse if (wg == 's') suid = 1;
Xelse if (wg == 'S') sgid = 1;
X
Xif (rwb == 'r') {
X	if (group) strcpy(gstring, G_READ_STRING);
X	else strcpy(wstring, W_READ_STRING);
X	read = 1;
X	}
Xelse if (rwb == 's')
X	(suid?strcpy(suidstring,SUID_STRING):strcpy(suidstring,SGID_STRING));
X
Xelse if (rwb == 'w') {
X	if (group) {
X		strcpy(gstring, G_WRITE_STRING);
X		strcpy(gstring_tree, G_WRITE_TREE);
X		}
X	else {
X		strcpy(wstring, W_WRITE_STRING);
X		strcpy(wstring_tree, W_WRITE_TREE);
X		}
X	write = 1;
X	}
Xelse if (rwb == 'b') {
X	/* do the write first, then read check */
X	if (group) strcpy(gstring, G_WRITE_STRING);
X	else strcpy(wstring, W_WRITE_STRING);
X	if (suid) strcpy(suidstring,SUID_STRING);
X	both = read = write = 1;
X	}
Xelse if (rwb == 'B') {
X	/* do the write first, then s[ug]id check */
X	if (suid) strcpy(suidstring, SUID_STRING);
X	else if (sgid) strcpy(suidstring, SGID_STRING);
X	else {
X		fprintf(stderr, usage);
X		exit(1);
X		}
X	both = write = 1;
X	}
Xelse {
X	fprintf(stderr, usage);
X	exit(1);
X	}
X
X/*
X *         the write stuff, so to speak...
X *   What I'm doing in this mess is to parse the file in question, check out
X * whole path; 'cause if anything is world writable, you can compromise.
X * For instance, if /usr is world writable, then /usr/spool/mail is
X * compromisable, no matter what its permissions are.
X *
X*/
Xif (write) {
X	/* 256 levels of dirs, max len each 256 chars */
X	char foo_dirs[256][256];
X	char *foo_file;
X	int i = 0, j;
X
X	foo_file = file;
X	strcpy(foo_dirs[i++], foo_file);
X
X	j=strlen(foo_file) - 1;
X	do {
X		if (foo_file[j] == '/')
X			strncpy(foo_dirs[i++], foo_file, j);
X	} while (--j > 0);
X
X	for (j = 0; j < i; j++) {
X		if (stat(foo_dirs[j],&statb) < 0)
X			continue;
X		xmode=statb.st_mode;
X		if (!group) {
X			if (xmode & W_WRITE_TEST) {
X				/* want to distinguish between file being
X				   writable and directory tree being
X				   writable; j==0 means actual file */
X				if (!j) printf( wstring, file);
X				else printf( wstring_tree, file);
X				if (both) goto bboth;
X				exit(!xmode);
X				}
X			}
X		else if (xmode & G_WRITE_TEST) {
X			if (!j) printf( gstring, file);
X			else printf( gstring_tree, file);
X			if (both) goto bboth;
X			exit(!xmode);
X			}
X		}
X
Xif (!both) exit(!xmode);
X}
X
Xbboth:
Xif (both) if (stat(file,&statb) < 0) {
X		fprintf(stderr, file);
X		exit(2);
X		}
X
X/* find premissions on file in question */
Xif (group)
X	xmode = statb.st_mode & G_READ_TEST;
Xelse
X	xmode = statb.st_mode & W_READ_TEST;
X
Xif (wg == 's') {
X	/* check SUID */
X	xmode = statb.st_mode & SUID_TEST;
X	if (xmode) printf( suidstring, file);
X	exit (!xmode);
X	}
Xif (wg == 'S') {
X	/* check SGID */
X	xmode = statb.st_mode & SGID_TEST;
X	if (xmode) printf( suidstring, file);
X	exit (!xmode);
X	}
X
Xif (rwb == 'b') {
X	/* do the read now */
X	if (group) strcpy(gstring, G_READ_STRING);
X	else strcpy(wstring, W_READ_STRING);
X	}
X
X/* report finding */
Xif (xmode) printf( (group ? gstring : wstring), file);
X
Xexit(!xmode);
X}
SHAR_EOF
chmod 0600 cops_104/src/is_able.c ||
echo 'restore of cops_104/src/is_able.c failed'
Wc_c="`wc -c < 'cops_104/src/is_able.c'`"
test 5750 -eq "$Wc_c" ||
	echo 'cops_104/src/is_able.c: original size 5750, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/is_something.c ==============
if test -f 'cops_104/src/is_something.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/is_something.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/is_something.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/is_something.c' &&
X/*
X    Usage: is_xxx [-gv] <filename>
X
X    This checks determines whether a file is (group or world)
X  writable, readable, or SUID, and returns a 0 if false, 1 if true.
X  The -g option checks for group status, the -v option prints out
X  the result as well.
X
X  	Permissions bits:		  vvv--- Permission bits
X   	        1 = execute		00000
X   	        2 = writable		 ^
X   	        4 = readable		 + Setuid bits
X
X  	Setuid bits:
X   	        1 = sticky
X   	        2 = set group id
X   	        4 = set user od
X
X    Pete Shipley (shipley@mica.berkeley.edu) gutted my original code,
X  made in cleaner and smarter, and combined everything into one compact
X  file.  What a deal, huh?  Then I came along and beat up his code and
X  made it look ugly again (I changed the is_writeable option to return
X  true if _any_ parent directories are writable, not just the target.  So
X  you can blame me if you want.  Better yet, just send me a patch if I
X  blew it.)
X
X*/
X
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#ifdef SETUID
X#define G_TEST 02000	/* set group id */
X#define W_TEST 04000	/* set user id */
X#define G_REPORT_STRING	"%s is set gid\n"
X#define W_REPORT_STRING	"%s is set uid\n"
X#endif SETUID
X
X#ifdef READABLE
X#define G_TEST 00040	/* group readable */
X#define W_TEST 00004	/* world readable */
X#define G_REPORT_STRING	"%s is group readable\n"
X#define W_REPORT_STRING	"%s is world readable\n"
X#endif READABLE
X
X#ifdef WRITABLE
X#define G_TEST 00020	/* group writable */
X#define W_TEST 00002	/* world writable */
X#define G_REPORT_STRING	"%s is group writable\n"
X#define W_REPORT_STRING	"%s is world writable\n"
X#endif WRITABLE
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X    register int group = 0,
X	    verbose = 0,
X	    xmode;
X
X    static struct stat statb;
X
X    /* check out arguments */
X    if (argc < 2) {
X	(void) printf("Usage: %s [-gv] file\n",argv[0]);
X	exit(0);
X    }
X
X    /* parse arguments */
X    if (argc > 2) {
X	while (argv[1][0] == '-' && argv[1][1] != '\0') {
X	    if (argv[1][1] == 'g') { group++; argv++; }
X	    if (argv[1][1] == 'v') { verbose++; argv++; }
X	}
X    }
X
X    /* get stats on file in question */
X    if (stat(*++argv,&statb) < 0) {
X	perror(*argv);
X	exit(2);
X    }
X
X/*
X           the write stuff, so to speak...
X     What I'm doing in this mess is to parse the file in question, check out
X   whole path; 'cause if anything is world writable, you can compromise.
X
X*/
X#ifdef WRITABLE
X{
Xchar foo_dirs[256][256];  /* 256 levels of dirs, max len each 256 chars */
Xchar *foo_file;
Xint i = 0, j;
X
X	foo_file = *argv;
X	strcpy(foo_dirs[i++], foo_file);
X
X	j=strlen(foo_file) - 1;
X	do {
X		if (foo_file[j] == '/')
X			strncpy(foo_dirs[i++], foo_file, j);
X	} while (--j > 0);
X
X	for (j = 0; j < i; j++)
X		{
X		if (stat(foo_dirs[j],&statb) < 0)
X			continue;
X		else if (!group) {
X			if (statb.st_mode & W_TEST)
X				exit(0);
X			}
X		else if (statb.st_mode & G_TEST)
X			exit(0);
X		}
X
X	exit(1);
X}
X#endif WRITABLE
X
X    /* test premissions on file in question */
X    if (group) {
X	xmode = statb.st_mode & G_TEST;
X    } else {
X	xmode = statb.st_mode & W_TEST;
X    }
X
X    /* report finding */
X
X    if(verbose && xmode) {
X	(void) printf( (group ? G_REPORT_STRING : W_REPORT_STRING), *argv);
X    }
X
X    exit(!xmode);
X}
SHAR_EOF
chmod 0600 cops_104/src/is_something.c ||
echo 'restore of cops_104/src/is_something.c failed'
Wc_c="`wc -c < 'cops_104/src/is_something.c'`"
test 3206 -eq "$Wc_c" ||
	echo 'cops_104/src/is_something.c: original size 3206, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/members.c ==============
if test -f 'cops_104/src/members.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/members.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/members.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/members.c' &&
X/* Copyright 1985 Robert W. Baldwin */
X/* Copyright 1986 Robert W. Baldwin */
Xstatic	char	*notice85 = "Copyright 1985 Robert W. Baldwin";
Xstatic	char	*notice86 = "Copyright 1986 Robert W. Baldwin";
X
X/*
X * useage: members GroupName
X * Writes to stdout the list of UserNames that are in the given group.
X * The UserNames are separated by space or newline characters.
X *
X */
X
X#include	<stdio.h>
X#include	<grp.h>
X#include	<pwd.h>
X
X
X#ifdef cray
Xstruct	group	*getgrnam();
X#endif
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X	int	i;
X	int	gid;
X	struct	group	*grent;
X	struct	passwd	*pwent;
X	char	**user;
X
X/*
X * Print the list of group members from /etc/group.
X */
X	if ((grent = getgrnam(argv[1])) == NULL)  {
X		fprintf(stderr, "%s: Bad group name %s.\n",
X			argv[0], argv[1]);
X		exit(1);
X		}
X	gid = grent->gr_gid;
X	for (user = grent->gr_mem ; *user != NULL ; user++)  {
X		fprintf(stdout, "%s ", *user);
X		}
X	fprintf(stdout, "\n");
X	endgrent();
X/*
X * The passwd file must also be examined to find members of the group.
X * Duplicates may occur, but the higher level code shouldn't care about them.
X */
X	while ((pwent = getpwent()) != NULL)  {
X		if (pwent->pw_gid != gid)
X			continue;
X		fprintf(stdout, "%s ", pwent->pw_name);
X		}
X	fprintf(stdout, "\n");
X	endpwent();
X}
X
SHAR_EOF
chmod 0600 cops_104/src/members.c ||
echo 'restore of cops_104/src/members.c failed'
Wc_c="`wc -c < 'cops_104/src/members.c'`"
test 1258 -eq "$Wc_c" ||
	echo 'cops_104/src/members.c: original size 1258, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/pass.c ==============
if test -f 'cops_104/src/pass.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/pass.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/pass.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/pass.c' &&
X#include <stdio.h>
X#include <pwd.h>
X#include <ctype.h>
X
X/* C2 stuff by Ole H. Nielsen */
X#ifdef C2
X#include <sys/label.h>
X#include <sys/audit.h>
X#include <pwdadj.h>
X#endif C2
X
X/* number of words the dictionary can suck up */
X#define ARB_CONST	32000
X
X#ifndef lint
Xstatic char *rcsid = "$Header: pwchkr.c,v 1.1 85/09/10 16:00:56 root Exp $";
X#endif
X
X/*
X * Warning: this program burns a lot of cpu.
X */
X/*
X * Insecure - find accounts with poor passwords
X	Date: Tue, 29 Nov 83 18:19:32 pst
X	From: leres%ucbarpa@Berkeley (Craig Leres)
X
X	Insecure is something that Jef Poskanzer and I wrote to rid a
X	local system of an overly persistent ankle-biting adolescent.
X	It was a quick hack we whipped up in just a few minutes and was
X	never intended to be publically distributed. Unfortunately, I
X	made the mistake of giving a copy to an associate at UC
X	Berkeley. Apparently, he incorporated it in a security package
X	he later developed for use at Berkeley. Someone else
X	distributed it outside Berkeley which explains why it's been
X	publically distributed.
X
X
X	    Modified by Seth Alford, Roger Southwick, Steve Dum, and
X	    Rick Lindsley for Tektronix
X
X      Bits and pieces hacked by me and others, 1/4/91... df
X */
X
X/*
X *	$Log:	pwchkr.c,v $
X *	Revision 1.1  85/09/10  16:00:56  root
X *	Initial revision
X *	
X *
X * By default, this program only checks for accounts with passwords the same
X * as the login name. The following options add more extensive checking. (The
X * tradeoff is cpu time -- with all options enabled it can run into the 100's
X * of MINUTES.) Any argument that does not begin with a "-" is assumed to be
X * a file name. (A single '-' means stdin.) If no file name is given,
X * /etc/passwd is used.
X *
X * Options:
X *
X *		-v:	verbose -- list all guesses on stdout
X *		-u:	output the username on the line of the password file
X *			currently being checked. If the program stops
X *			abruptly you will then know how far it got.
X *		-w file: use the list of words contained in "file" as likely
X *			passwords. Words in the file are one to a line.
X *		-b: 	check all guesses backwards too
X *		-g:	use the Full Name portion of the gecos field to
X *			generate more guesses; also check .plan, .signature
X *			and .project files.
X *		-s:	check the single letters a-z, A-Z, 0-9 as passwords
X *		-c:	with each guess, check for all-lowercase and
X *			all-uppercase versions too.
X *		-d:     check the doubling of the username
X *		-n:	complain about null passwords (default is to keep quiet)
X *		-p:	print the password when guessed
X *		-P:	use alternate password file
X */
X
Xint verbose = 0, singles = 0, backwards = 0, checkgecos = 0, checkcase = 0,
X    chknulls = 0, printit = 0, users = 0, chkwords = 0, checkdouble = 0;
X
Xchar *my_index(), *reverse();
Xlong atol();
XFILE *fopen();
Xchar *fgets();
X
X/* char PASSWD[] = "/etc/passwd"; */
Xchar PASSWD[256];
X
Xchar EMPTY[] = "";
Xstatic FILE *pwf = NULL, *wlf = NULL;
Xchar line[BUFSIZ+1];
Xstruct passwd passwd;
Xchar	*Curpw, *Wordlist = NULL;
X
Xmain(argc, argv)
Xchar **argv;
X{
X    register int i;
X    register char *arg;
X    int onedone = 0;
X
X    /*
X    You have to decide whether or not to include these lines....
X
X    if (getuid()) {
X	printf("Did you really think we would let you run this?\n");
X	exit(1);
X	}
X
X    */
X    strcpy(PASSWD, "/etc/passwd");
X
X    for (i = 1; i < argc; i++)
X	if ((arg = argv[i]) && *arg == '-')
X	    while (*++arg) {
X		switch (*arg) {
X		    case 'n':
X			/*
X			 * complain about null passwords
X			 */
X			chknulls++;
X			break;
X		    case 'c':
X			/*
X			 * check cases
X			 */
X			checkcase++;
X			break;
X		    case 'g':
X			/*
X			 * use gecos
X			 */
X			checkgecos++;
X			break;
X		    case 'v':
X			/*
X			 * turn on motormouth
X			 */
X			verbose++;
X			break;
X		    case 'b':
X			/*
X			 * check all attempts forwards and backwards
X			 */
X			backwards++;
X			break;
X		    case 'd':
X			/*
X			* check the doubling of the username
X			*/
X			checkdouble++;
X			break;
X		    case 's':
X			/*
X			 * carry out a more intensive search, checking for
X			 * single letter passwords
X			 */
X			singles++;
X			break;
X		    case 'p':
X			/*
X			 * print out the password when found
X			 */
X			printit++;
X			break;
X		    case 'u':
X			/*
X			 * print out users as testing
X			 */
X			users++;
X			break;
X		    case 'P':
X			/*
X			 * use alternate passwd file
X			 */
X			if (argv[i+1] == NULL) {
X			    fprintf(stderr,
X				"%s: No file supplied with -P option\n",
X				argv[0]);
X			    exit (1);
X			    }
X			strcpy(PASSWD, argv[i+1]);
X			argv[i+1] = NULL;
X			break;
X		    case 'w':
X			/*
X			 * consult word list of likely passwords
X			 */
X			if ((Wordlist = argv[i+1]) == NULL) {
X			    fprintf(stderr,
X				"%s: No file supplied with -w option\n",
X				argv[0]);
X			    exit (1);
X			    }
X			argv[i+1] = NULL;
X			break;
X		    case '\0':
X			/*
X			 * read from stdin
X			 */
X			break;
X		    default:
X			fprintf(stderr,
X			    "%s: unknown option '%c'. Options are:\n",argv[0],
X			    *arg);
X			/* FALL THRU */
X		    case '-':
X			fprintf(stderr,"-v:\t\tverbose -- list all guesses on stdout\n");
X			fprintf(stderr,"-u:\t\toutput the username currently being checked\n");
X			fprintf(stderr,"-w file:\tconsult the indicated file for words to check as passwords\n");
X			fprintf(stderr,"-b:\t\tcheck all guesses forwards and backwards\n");
X			fprintf(stderr,"-g:\t\tuse the Full name portion of the gecos field for more guesses\n");
X			fprintf(stderr,"-s:\t\tcheck the single letters a-z, A-Z, 0-9 as passwords\n");
X			fprintf(stderr,"-c:\t\tcheck the all-upper and all-lower case version of each guess\n");
X			fprintf(stderr,"-d:\t\tcheck for double repetition of the username\n");
X			fprintf(stderr,"-n:\t\tcomplain about null passwords\n");
X			fprintf(stderr,"-p:\t\tprint the password when guessed\n");
X			exit(1);
X		    }
X		argv[i] = NULL;
X		}
X    
X#ifdef FCRYPT
Xinit_des();
X#endif
X
X    for (i = 1; i < argc; i++) {
X	if (argv[i] == NULL) continue;
X	onedone++;
X	if (*(argv[i]) == '-') {
X	    /*
X	     * read from stdin; we'll cheat and set pwf directly
X	     */
X	    pwf = stdin;
X	    chkpw();
X	    /*
X	     * don't fclose stdin!
X	     */
X	    clearerr(stdin);
X	    }
X	else {
X	    if ((pwf=fopen(argv[i],"r")) == NULL) {
X		perror(argv[i]);
X		continue;
X		}
X	    Curpw = argv[i];
X	    chkpw();
X	    end2pwent();
X	    }
X	}
X    if (!onedone) {
X	Curpw = NULL;
X	chkpw();
X	}
X    exit(0);
X}
X
X/*
X * Added by Jacob Gore, March 12, 1987.
X *
X * Finds the pointer of the leftmost occurance within the character string
X * 'string' of any character found within the character string 'chars'.
X *
X * If none of the characters in 'chars' appear in 'string', NULL is retutned.
X *
X */
Xchar *
Xindexm (string, chars)
X    char *string, *chars;
X{
X    while (*string) {
X	if (my_index(chars, *string) != NULL) {
X	    return string;
X	}
X	string++;
X    }
X    return NULL;
X}
X
Xchkpw()
X{
X#ifdef C2
X    struct passwd_adjunct *pwdadj;
X    struct passwd_adjunct *getpwanam();
X#endif C2
X    register char	*cp, *cp2;
X    struct passwd	*pwd;
X    struct passwd	*getpwent();
X    char		guess[100];
X    char		*wordarray[ARB_CONST];
X    char		*malloc(), **wordptr, **endptr;
X    int			done = 0;
X
X
X    if (Wordlist) {
X	if ((wlf = fopen(Wordlist,"r")) == NULL) {
X	    perror(Wordlist);
X	    exit(1);
X	}
X
X	wordptr = wordarray;
X	/*
X	 * note that endptr points to space OUTSIDE of wordarray
X	 */
X	endptr = wordarray + (sizeof(wordarray)/sizeof(char *));
X
X/* printf("testing words...\n"); */
X	while (fscanf(wlf,"%[^\n]\n",guess) != EOF) {
Xint i;
X/* printf("%d => %s\n", ++i, guess); */
X
X	    if (wordptr == endptr) {
X		fprintf(stderr,"Ran out of wordlist space. ARB_CONST %d must be too small.\n", ARB_CONST);
X		exit(1);
X	    }
X	    if ((*wordptr = malloc(1+strlen(guess))) == NULL) {
X		fprintf(stderr,"malloc: no more memory for wordlist\n");
X		exit (1);
X	    }
X	    strcpy(*wordptr,guess);
X	    wordptr++;
X  /* SunOs 4.03 on a Sun 3/80 didn't work properly, needed this one line fix */
X	    if (feof(wlf)) break;
X	}
X	*wordptr = NULL;
X	fclose(wlf);
X    }
X
X    while ((pwd = getpwent()) != 0 ) {
X
X        done = 0;
X	if (verbose || users) {
X	    if (Curpw == NULL)
X		printf("\t%s \"%s\"\n", pwd->pw_name, pwd->pw_gecos);
X	    else
X		printf("%s -- \t%s \"%s\"\n", Curpw, pwd->pw_name,
X		    pwd->pw_gecos);
X	    fflush(stdout);
X	    }
X#ifdef C2
X	(void) sprintf (guess, "##%s", pwd->pw_name);
X	if (strcmp (guess, pwd->pw_passwd)) {
X		/* Standard /etc/passwd entry */
X		if (verbose || users) {
X			if (*pwd->pw_passwd != '*' && *pwd->pw_passwd != '\0')
X				printf ("\tC2 Warning!  user password %s is in the regular passwd file\n",
X					pwd->pw_passwd);
X			fflush(stdout);
X		}
X	} else {
X		/* Entry in /etc/security/passwd.adjunct (C2 security) */
X		/* Extract the C2 security password */
X		if (Curpw == NULL)
X			pwdadj = getpwanam(pwd->pw_name);
X		else
X			pwdadj = getpwanam(Curpw);
X		if (pwdadj == (struct passwd_adjunct *)NULL) {
X			fprintf (stderr, "Failed to get the C2 secure passwd for %s\n", pwd->pw_name);
X			fflush(stderr);
X			continue;
X		} else
X			/* Substitute the C2 secure password */
X			pwd->pw_passwd = pwdadj->pwa_passwd;
X	}
X#endif C2
X
X	if (*pwd->pw_passwd == '\0') {
X	    if (chknulls) {
X		if (Curpw == NULL)
X		    printf("Warning!  Password Problem: null passwd:\t%s\tshell: %s\n",
X			pwd->pw_name, pwd->pw_shell);
X		else
X		    printf("Warning!  %s -- Password Problem: null passwd:\t%s\tshell: %s\n",
X			Curpw, pwd->pw_name, pwd->pw_shell);
X		fflush(stdout);
X		}
X	    continue;
X	}
X
X	/* if (strlen(pwd->pw_passwd) != 13) { continue; } */
X	/* common way of disabling account is a "*" in the first char of p/w */
X	if (*pwd->pw_passwd == '*' || strlen(pwd->pw_passwd) < 13) continue;
X	if (strlen(pwd->pw_passwd) > 13)
X		 strncpy(pwd->pw_passwd, pwd->pw_passwd, 13);
X
X	/*
X	 * Try the user's login name
X	 */
X	if (uandltry(pwd,pwd->pw_name))
X	    continue;
X
X	if (checkdouble) {
X		strcpy(guess,pwd->pw_name);
X		strcat(guess,pwd->pw_name);
X		if (uandltry(pwd,guess))
X			continue;
X		}
X
X	/*
X	 * Try names from the gecos field
X	 */
X	if (checkgecos) {
X	    /* Check extra files as well */
X	    if (srch_aux_files(pwd->pw_dir, pwd)) {
X		done++;
X		continue;
X	    }
X	    strcpy(guess, pwd->pw_gecos);
X	    cp = guess;
X	    if (*cp == '-') cp++;		/* special gecos field */
X	    if ((cp2 = my_index(cp, ';')) != NULL)
X		*cp2 = '\0';
X
X	    for (;;) {
X		/* use both ' ' and ',' as delimiters -- Jacob */
X		if ((cp2 = indexm(cp, " ,")) == NULL) {
X		    if (uandltry(pwd,cp))
X			done++;
X		    break;
X		    }
X
X		*cp2 = '\0';
X
X		if (uandltry(pwd,cp)) {
X		    done++;
X		    break;
X		    }
X		cp = ++cp2;
X		}
X	    }
X	    
X	if (!done && Wordlist)
X	{
X	    /*
X	     * try the words in the wordlist
X	     */
X	    wordptr = wordarray;
X	    while (endptr != wordptr)
X	    {
X		if (*wordptr == NULL)
X		    break;
X		if (uandltry(pwd,*wordptr++))
X		{
X		    done++;
X		    break;
X		}
X	    }
X	}
X	if (!done && singles) {
X	    /*
X	     * Try all single letters
X	     * (try digits too .  --Seth)
X	     */
X	    guess[1] = '\0';
X	    for (guess[0]='a'; guess[0] <= 'z'; guess[0]++)
X		if (try(pwd,guess))
X		    break;
X	    for (guess[0]='A'; guess[0] <= 'Z'; guess[0]++)
X		if (try(pwd,guess))
X		    break;
X	    for (guess[0]='0'; guess[0] <= '9'; guess[0]++)
X		if (try(pwd,guess))
X		    break;
X	    }
X    }
X}
X
X/*
X * Stands for "upper and lower" try.  Calls the "real" try, below,
X * with the supplied version of the password, and with
X * an upper and lowercase version of the password. If the user doesn't
X * want to try upper and lower case then we just return after the one
X * check.
X*/
X
Xuandltry (pwd,guess)
Xchar *guess;
Xstruct passwd *pwd;
X{
X    register char *cp;
X    char buf[100];
X    int alllower, allupper;
X
X    alllower = allupper = 1;
X
X    if (try(pwd,guess) || (backwards && try(pwd,reverse(guess)))) return (1);
X
X    if (!checkcase) return(0);
X
X    strcpy (buf, guess);
X    cp = buf-1;
X    while (*++cp) {
X	if (isupper(*cp))
X	    alllower = 0;
X	if (islower(*cp))
X	    allupper = 0;
X	}
X
X    if (!allupper) {
X	for ( cp=buf; *cp != '\0'; cp++)
X	    if (islower (*cp))
X		*cp += 'A' - 'a';
X
X	if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
X	}
X
X    if (!alllower) {
X	for ( cp = buf; *cp != '\0'; cp++)
X	    if (isupper (*cp))
X		*cp += 'a' - 'A';
X
X	if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
X	}
X    return (0);
X}
X
Xtry(pwd,guess)
Xchar *guess;
Xregister struct passwd *pwd;
X{
X    register char  *cp;
X    char   *crypt ();
X
X    if (verbose) {
X	if (Curpw == NULL)
X	    printf ("Trying \"%s\" on %s\n", guess, pwd -> pw_name);
X	else
X	    printf ("%s -- Trying \"%s\" on %s\n", Curpw, guess,
X		pwd -> pw_name);
X	fflush (stdout);
X	}
X    if (! guess || ! *guess) return(0);
X    cp = crypt (guess, pwd -> pw_passwd);
X
X/* silly sun tries to fool us by adding extra chars in their passwd field! */
X/* but laddie, we're too smart for 'em, eh?!?  Kudos to Bernard Wilson */
X    if (strncmp (cp, pwd -> pw_passwd, 13))
X	return (0);
X    if (Curpw == NULL)
X	if (printit)
X	    printf ("Warning!  Password Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
X		pwd -> pw_name, pwd -> pw_shell, guess);
X	else
X	    printf ("Warning!  Password Problem: Guessed:\t%s\tshell: %s\n", pwd -> pw_name,
X		pwd -> pw_shell);
X    else
X	if (printit)
X	    printf ("Warning!  %s -- Password Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
X		Curpw, pwd -> pw_name, pwd -> pw_shell, guess);
X	else
X	    printf ("Warning!  %s -- Password Problem: Guessed:\t%s\tshell: %s\n",
X		Curpw, pwd -> pw_name, pwd -> pw_shell);
X    fflush (stdout);
X    return (1);
X}
X/* end of PW guessing program */
X
X#define MAXUID 0x7fff	/* added by tonyb 12/29/83 */
X			/* altered to a reasonable number - mae 8/20/84 */
X
Xend2pwent()
X{
X    fclose(pwf);
X    pwf = NULL;
X}
X
Xchar *
Xpwskip(p)
Xregister char *p;
X{
X	while(*p && *p != ':' && *p != '\n')
X		++p;
X	if(*p == '\n')
X		*p = '\0';
X	else if(*p)
X		*p++ = '\0';
X	return(p);
X}
X
Xstruct passwd *
Xgetpwent()
X{
X	register char *p;
X	long	x;
X
X	if(pwf == NULL)
X	    if ((pwf = fopen(PASSWD,"r")) == NULL) {
X		perror(PASSWD);
X		return(NULL);
X		}
X	p = fgets(line, BUFSIZ, pwf);
X	if(p == NULL)
X		return(0);
X	passwd.pw_name = p;
X	p = pwskip(p);
X	passwd.pw_passwd = p;
X	p = pwskip(p);
X	x = atol(p);	
X	passwd.pw_uid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
X	p = pwskip(p);
X	x = atol(p);
X	passwd.pw_gid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
X/*	passwd.pw_comment = EMPTY; */
X	p = pwskip(p);
X	passwd.pw_gecos = p;
X	p = pwskip(p);
X	passwd.pw_dir = p;
X	p = pwskip(p);
X	passwd.pw_shell = p;
X	(void) pwskip(p);
X
X	p = passwd.pw_passwd;
X 
X	return(&passwd);
X
X}
X
X
X/*
X * reverse a string
X */
Xchar *reverse(str)
Xchar *str;
X
X{
X    register char *ptr;
X    char	*malloc();
X    static char buf[100];
X
X    ptr = buf + strlen(str);
X    *ptr = '\0';
X    while (*str && (*--ptr = *str++))
X	;
X    return(ptr);
X
X}
X
X
X/* Guess passwords using additional files for guesses. Returns 1 (true) if
X * a match was found, otherwise 0 (false). The parameters to be passed to
X * this function are a character pointer to the directory in which the files
X * reside. This function access the "uandltry" routine from other 
X * sections of the code.
X */
X#define MAXWORD 15		/* Maximum word length allow for guess */
X
X#include <stdio.h>
X#include <ctype.h>
X
Xstatic char *file[] = { "/.project",		/* These are the extra files */
X			"/.plan",		/* to be searched for */
X			"/.signature",		/* prospective passwords */
X			"" };			/* Note the initial "/" */
X
Xint
Xsrch_aux_files(dir, pwd)
X	char *dir;	/* Directory in which to search */
X	struct passwd *pwd;	/* Encrypted password */
X{
X	char path[100];		/* Complete path */
X	FILE *fp;
X	char *wp;
X	char *getword();
X	char **p;
X
X	p = file;
X	while (**p != NULL) {
X		strcpy(path, dir);	/* Make complete path name */
X		strcat(path, *p++);
X		if ((fp = fopen(path, "r")) == NULL)
X			continue;	/* If we can't open the file, skip it */
X		while ((wp = getword(fp)) != NULL)
X			if (uandltry(pwd, wp))
X				return(1);
X		fclose(fp);
X	}
X	return(0);
X}
X
X/* Get a word from a stream. Word separators are user definable in "is_sep".
X * Maximum word size is MAXWORD characters. If a word reaches it's maximum
X * limit, we choose not to flush the rest of the word. Returns NULL on EOF.
X */
Xchar *
Xgetword(fp)
X	FILE *fp;
X{
X	static char word[MAXWORD + 1];
X	char *p = word;
X	int c;
X	int is_sep();
X
X	while ((c = fgetc(fp)) != EOF && !isalnum(c))
X		;		/* Skip over word separators */
X	if (c == EOF)
X	       return(NULL);
X	*p++ = c;
X	while ((c = fgetc(fp)) != EOF && isalnum(c) && p != &(word[MAXWORD])) {
X		*p++ = c;	/* Quit when a word separator is encountered
X				 * or we reach maximum word length
X				 */
X	}
X	*p = '\0';		/* Mustn't forget that word terminator */
X	return ((c == EOF) ? NULL : word);
X}
X/* taken from comp.binaries.ibm.pc.d:
XSome users have reported trouble compiling the freely distributable
Xuudecode I posted.  It seems that Berkeley moved the "index" function
Xto one of their system libraries and some systems don't have it.
XHere is the missing "index" function, excerpted from an earlier freely
Xdistributable uudecode.  Just add it on the end of the uudecode I posted.
X*/
X/*
X--Keith Petersen
XMaintainer of SIMTEL20's CP/M, MSDOS, & MISC archives [IP address 26.2.0.74]
XInternet: w8sdz@WSMR-SIMTEL20.Army.Mil, w8sdz@brl.arpa  BITNET: w8sdz@NDSUVM1
XUucp: {ames,decwrl,harvard,rutgers,ucbvax,uunet}!wsmr-simtel20.army.mil!w8sdz
X*/
X
X/*
X * Return the ptr in sp at which the character c appears;
X * NULL if not found
X */
X
X#define	NULL	0
X
Xchar *
Xmy_index(sp, c)
Xregister char *sp, c;
X{
X	do {
X		if (*sp == c)
X			return(sp);
X	} while (*sp++);
X	return(NULL);
X}
X
X
SHAR_EOF
chmod 0600 cops_104/src/pass.c ||
echo 'restore of cops_104/src/pass.c failed'
Wc_c="`wc -c < 'cops_104/src/pass.c'`"
test 17403 -eq "$Wc_c" ||
	echo 'cops_104/src/pass.c: original size 17403, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/tilde.c ==============
if test -f 'cops_104/src/tilde.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/tilde.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/tilde.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/tilde.c' &&
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
Xstruct passwd *pp;
X
Xif (argc != 2) {
X	printf("Usage: %s\n",argv[0]);
X	exit(1);
X}
X
X/* print directory of user, else "Error"  -- need to print
X  something, or kuang won't parse dir correctly */
Xif ((pp = getpwnam(argv[1])) != (struct passwd *)0)
X	printf("%s", pp->pw_dir);
Xelse
X	printf("Error");
X
X}
SHAR_EOF
chmod 0600 cops_104/src/tilde.c ||
echo 'restore of cops_104/src/tilde.c failed'
Wc_c="`wc -c < 'cops_104/src/tilde.c'`"
test 401 -eq "$Wc_c" ||
	echo 'cops_104/src/tilde.c: original size 401, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/user.chk.c ==============
if test -f 'cops_104/src/user.chk.c' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/user.chk.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/user.chk.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/user.chk.c' &&
X#include <stdio.h>
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X/* Any file writable by all will be flagged */
X#define DMODE 002
X
X#define MODE1 004
X#define MODE2 040
X
X/* #define DMODE2 020 */
X
X/* potentially dangerous files */
Xchar *ftable[] = {
X	"rhosts",
X	"profile",
X	"login",
X	"logout",
X	"cshrc",
X	"bashrc",
X	"kshrc",
X	"tcshrc",
X	"netrc",
X	"forward",
X	"dbxinit",
X	"distfile",
X	"exrc",
X	"emacsrc"
X};
Xchar *ft;
Xchar *ftr, *malloc();
X
Xchar generic_file[100];
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
Xregister int fmode;
Xregister int index;
Xstruct passwd *pp;
Xstatic struct stat statb;
X
Xif (argc != 1) {
X	printf("Usage: %s\n",argv[0]);
X	exit(1);
X	}
X
Xft = malloc(100);
Xftr = malloc(100);
X
Xwhile ((pp = getpwent()) != (struct passwd *)0) {
X	if (stat(pp->pw_dir,&statb) < 0) {
X		continue;
X		}
X
X	index = 0;
X	/*
X	 *   Use the home-dir, and add on each potential security threat
X	 * file to the path one at a time.  Then check each file to see
X	 * if it breaks with the modes established up above
X	 *
X	*/
X	for (ft = ftable[index]; index < 14; ft = ftable[++index]) {
X		if (strlen(pp->pw_dir) != 1)
X			sprintf(generic_file, "%s/.%s", pp->pw_dir,ft);
X		else 
X			sprintf(generic_file, "%s.%s", pp->pw_dir,ft);
X
X		if (stat(generic_file,&statb) < 0)
X			continue;
X
X		if (statb.st_mode & DMODE) 
X			printf("Warning!  User %s:\t%s is mode \t0%3.3o!\n",
X	       		pp->pw_name,generic_file,statb.st_mode&~S_IFMT);
X
X		/* check for mode on .netrc files; should be non-readable */
X		if (!strcmp("netrc", ftable[index]))
X			if (statb.st_mode & MODE1 || statb.st_mode & MODE2)
X				printf("Warning!  User %s:\t%s is readable; mode \t0%3.3o!\n",
X	       			pp->pw_name,generic_file,statb.st_mode&~S_IFMT);
X		}
X
X	}
X
Xexit(0);
X}
SHAR_EOF
chmod 0600 cops_104/src/user.chk.c ||
echo 'restore of cops_104/src/user.chk.c failed'
Wc_c="`wc -c < 'cops_104/src/user.chk.c'`"
test 1721 -eq "$Wc_c" ||
	echo 'cops_104/src/user.chk.c: original size 1721, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= cops_104/src/conf.h ==============
if test -f 'cops_104/src/conf.h' -a X"$1" != X"-c"; then
	echo 'x - skipping cops_104/src/conf.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting cops_104/src/conf.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'cops_104/src/conf.h' &&
X/*
X * This program is copyright Alec Muffett 1991 except for some portions of
X * code in "crack-fcrypt.c" which are copyright Robert Baldwin, Icarus
X * Sparry and Alec Muffett.  The author(s) disclaims all responsibility or
X * liability with respect to it's usage or its effect upon hardware or
X * computer systems, and maintain copyright as set out in the "LICENCE"
X * document which accompanies distributions of Crack v4.0 and upwards.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <pwd.h>
X#include <signal.h>
X
X/*
X * Undefine this symbol if your name is not Alec David Edward Muffett
X */
X
X#undef DEVELOPMENT_VERSION
X
X/*
X * define this symbol if you are on a system where you don't have the
X * strchr() function in your standard library (usually this means you are on
X * a BSD based system with no System Visms) but instead, you DO have the
X * equivalent index() function.
X */
X
X#undef INDEX_NOT_STRCHR
X
X/*
X * What bytesex is your machine ? Select one of the two below, if you have
X * some really weird machine - otherwise the program should be able to work
X * it out itself.
X */
X
X#undef BIG_ENDIAN
X#undef LITTLE_ENDIAN
X
X/* If you haven't selected one of the above options... */
X#if	!defined(BIG_ENDIAN) && !defined(LITTLE_ENDIAN)
X
X/* Can we work out if we are little endian ? */
X#if 	defined(vax) || defined(ns32000) || defined(sun386) || \
X	defined(i386) || defined(MIPSEL) || defined(BIT_ZERO_ON_RIGHT)
X#define LITTLE_ENDIAN		/* YES */
X#endif
X
X/* Can we work out if we are bigendian ? */
X#if	defined(sel) || defined(pyr) || defined(mc68000) || \
X	defined(sparc) || defined(is68k) || defined(tahoe) || \
X	defined(ibm032) || defined(ibm370) || defined(MIPSEB) || \
X	defined(__convex__) || defined(hpux) || defined(apollo) || \
X	defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(m88k) || \
X	defined(_IBMR2) || defined(AMIGA) /* yes, an Amiga A500... */
X#define BIG_ENDIAN		/* YES */
X#endif
X
X/* end of trying to guess things */
X#endif
X
X/* are we schitzophrenic ? */
SHAR_EOF
true || echo 'restore of cops_104/src/conf.h failed'
fi
echo 'End of  part 10'
echo 'File cops_104/src/conf.h is continued in part 11'
echo 11 > _shar_seq_.tmp
exit 0

