v21i024: System ecurity analysis tool, Part02/05

Rich Salz rsalz at bbn.com
Fri Mar 23 04:56:27 AEST 1990


Submitted-by: Dan Farmer <df at sei.cmu.edu>
Posting-number: Volume 21, Issue 24
Archive-name: cops/part02

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
mkdir cops 2>/dev/null
mkdir cops/docs 2>/dev/null
mkdir cops/src 2>/dev/null
mkdir cops/extensions 2>/dev/null
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	cops/src/addto.c
#	cops/src/clearfiles.c
#	cops/src/filewriters.c
#	cops/src/home.chk.c
#	cops/src/is_readable.c
#	cops/src/is_writable.c
#	cops/src/members.c
#	cops/src/pass.c
#	cops/src/tilde.c
#	cops/src/user.chk.c
#	cops/extensions/THINGS_2_DO
#	cops/extensions/YAR
#	cops/extensions/netstuff
#	cops/extensions/passwords
#	cops/extensions/questions
# This archive created: Tue Jan 30 23:26:43 1990
# By:	dan (Purdue University)
echo shar: extracting cops/src/addto.c '(3254 characters)'
cat << \SHAR_EOF > cops/src/addto.c
/* Copyright 1985 Robert W. Baldwin */
/* Copyright 1986 Robert W. Baldwin */
static	char	*notice85 = "Copyright 1985 Robert W. Baldwin";
static	char	*notice86 = "Copyright 1986 Robert W. Baldwin";

/*
  August 15, added "Warning!"  To prepend warning messages.
    -- dan farmer
*/


/* 
 * Add a goal, check for duplicates and completions.
 * Trace messages written to stdout, success messages written to stderr.
 * Usage: addto fileroot key comments
 * Files are arranged in families based on a root name; for example,
 *    uids.k  -- uids we Know how to access
 *    uids.n  -- uids to process Next
 *    uids.p  -- uids Pending results (for duplicate detection)
 *    uids.x  -- uids being eXamined currently
 */


#include	<stdio.h>

#define	LINELEN	600		/* Max chars in a line. */
#define	SUCCESS	"Success"	/* Filename to put success messages. */

main(argc, argv)
int	argc;
char	*argv[];
{
	char	*type = argv[1];
	char	*key = argv[2];
	int	i;
	char	linebuf[LINELEN];
 	char	keypending[150];
	char	filename[150];
	FILE	*tmpfile;

	if (argc < 3)  {
		fprintf(stderr, "addto: missing arguments\n");
		exit(1);
		}
		
	tmpfile = NULL;
		
 	keypending[0] = NULL;
	strcat(keypending, key);
	strcat(keypending, " ");
/*
 * If the uid is known, print out the comments and exit.
 */
	filename[0] = NULL;
	strcat(filename, type);
	strcat(filename, ".k");
	if ((tmpfile = fopen(filename, "r")) == NULL)  {
		fprintf(stderr, "addto: can't open %s.\n", filename);
		exit(1);
		}
	while (fgets(linebuf, LINELEN, tmpfile) != NULL)  {
		if (strncmp(linebuf, key, strlen(key)) == 0)  {
			if ((tmpfile = freopen(SUCCESS,"a",tmpfile)) == NULL) {
				fprintf(stderr, "addto: can't open %s.\n",
					SUCCESS);
				exit(1);
				}
			fprintf(stderr, "Success^G^G\t");
			fprintf(tmpfile, "Warning!  ");
			for (i = 1 ; i < argc ; i++)  {
				fprintf(tmpfile, argv[i]);
				fprintf(tmpfile, " ");
				fprintf(stderr, argv[i]);
				fprintf(stderr, " ");
				}
			fprintf(tmpfile, "\n");
			fprintf(stderr, "\n");
			
			exit(0);
			}
		}
/*
 * If a duplicate, don't add it.
 */
	filename[0] = NULL;
	strcat(filename, type);
	strcat(filename, ".p");
	if (freopen(filename, "r", tmpfile) == NULL)  {
		fprintf(stderr, "addto: can't open %s.\n", filename);
		exit(1);
		}
	while (fgets(linebuf, LINELEN, tmpfile) != NULL)  {
		if (strncmp(linebuf, keypending, strlen(keypending)) == 0)  {
			exit(0);	/* Its a duplicate. */
			}
		}
/*
 * Add the goal to the pending file. 
 */
	filename[0] = NULL;
	strcat(filename, type);
	strcat(filename, ".p");
	if (freopen(filename, "a", tmpfile) == NULL)  {
		fprintf(stderr,"addto: can't open %s for append.\n", filename);
		exit(1);
		}
	fprintf(tmpfile, keypending);
	fprintf(tmpfile, "\n");
/*
 * Add the goal to the next goal (type) file.
 */
	filename[0] = NULL;
	strcat(filename, type);
	strcat(filename, ".n");
	if (freopen(filename, "a", tmpfile) == NULL)  {
		fprintf(stderr,"addto: can't open %s for append.\n", filename);
		exit(1);
		}
	fprintf(stdout, "        ");
	fprintf(stdout, "%s %s ", argv[0], argv[1]);
	for (i = 2 ; i < argc ; i++)  {
		fprintf(tmpfile, argv[i]);
		fprintf(tmpfile, " ");
		fprintf(stdout, argv[i]);
		fprintf(stdout, " ");
		}
	fprintf(tmpfile, "\n");
	fprintf(stdout, "\n");
	exit(0);
}



SHAR_EOF
echo shar: extracting cops/src/clearfiles.c '(702 characters)'
cat << \SHAR_EOF > cops/src/clearfiles.c
/* Copyright 1985 Robert W. Baldwin */
/* Copyright 1986 Robert W. Baldwin */
static	char	*notice85 = "Copyright 1985 Robert W. Baldwin";
static	char	*notice86 = "Copyright 1986 Robert W. Baldwin";

/*
 * Reset the info files used by Kuang.
 */


#include	<stdio.h>

char	*filelist[] = {
	"uids.k",
	"Success",
	"uids.k",
	"uids.p",
	"uids.n",
	"uids.x",
	"gids.k",
	"gids.p",
	"gids.n",
	"gids.x",
	"files.k",
	"files.p",
	"files.n",
	"files.x",
	"",
	};

main(argc, argv)
int	argc;
char	*argv[];
{
	int	i;

	for (i = 0 ; filelist[i][0] != NULL ; i++)  {
		if (freopen(filelist[i], "w", stdout) == NULL)  {
			fprintf(stderr, "%s: can't open %s.\n",
				argv[0], filelist[i]);
			exit(1);
			}
		}
}

SHAR_EOF
echo shar: extracting cops/src/filewriters.c '(2374 characters)'
cat << \SHAR_EOF > cops/src/filewriters.c
/* Copyright 1985 Robert W. Baldwin */
/* Copyright 1986 Robert W. Baldwin */

/*
   August 15, 1989: Dan Farmer
   One line changed -- #38 is the old line, #41 is my version.
   See comment for details...
*/
static	char	*notice85 = "Copyright 1985 Robert W. Baldwin";
static	char	*notice86 = "Copyright 1986 Robert W. Baldwin";

/*
 * Useage: filewriters pathname
 * Writes on stdout the list of people who can write the file.
 * This writer's list contains three tokens, the owner, the group, and
 * the 'all others' group, respectively.
 * If either group does not have write access, then that token is
 * replace with the token "NONE".  If the 'all others' group has
 * write access then that token is "OTHER".
 *
 * Notice that the owner of a file can always write it because the
 * owner can change the file access mode.
 *
 * BUG: should handle links correctly.
 */

#include	<stdio.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<grp.h>
#include	<pwd.h>

/*
  changed this line from upper to lower case 's'.
  Ultrix barfed 'cause already defined in sys/stat.h,
  no one else seemed to mind...

#define	S_GWRITE	(S_IWRITE >> 3)
*/

#define	s_GWRITE	(S_IWRITE >> 3)		/* Group write access. */
#define	S_OWRITE	(S_IWRITE >> 6)		/* Other write access. */


main(argc, argv)
int	argc;
char	*argv[];
{
	int	i;
	struct	stat	buf;

/*
 * Make sure the file exists.
 */
 	if (argc != 2)  {
		fprintf(stderr, "%s: wrong number of args.\n", argv[0]);
		exit(1);
		}
	if (stat(argv[1], &buf) != 0)  {
		fprintf(stderr, "%s: File %s does not exist.\n",
			argv[0], argv[1]);
		exit(1);
		}
/*
 * Produce list of writers.
 * Owner can always write.
 */
	printf("        ");
	print_uid(stdout, buf.st_uid);
	printf(" ");
	if (s_GWRITE & (buf.st_mode))  {
		print_gid(stdout, buf.st_gid);
		}
	else {
		printf("NONE");
		}
	printf(" ");
	if (S_OWRITE & buf.st_mode)  {
		printf("OTHER");
		}
	else {
		printf("NONE");
		}
	printf("\n");
	exit(0);
}


print_uid(out, uid)
FILE	*out;
int	uid;
{
	struct	passwd	*pwent;
	
	if ((pwent = getpwuid(uid)) == NULL)  {
		fprintf(stderr, "Bad user id %d.\n", uid);
		exit(1);
		}
	fprintf(out, "%s", pwent->pw_name);
}


print_gid(out, gid)
FILE	*out;
int	gid;
{
	struct	group	*grpent;
	
	if ((grpent = getgrgid(gid)) == NULL)  {
		fprintf(stderr, "Bad group id %d.\n", gid);
		exit(1);
		}
	fprintf(out, "%s", grpent->gr_name);

}

SHAR_EOF
echo shar: extracting cops/src/home.chk.c '(2916 characters)'
cat << \SHAR_EOF > cops/src/home.chk.c
/*

-------------------------------------------------------------------------
Modification: Aug 2, 1989
Author: Dan Farmer

  I made a minor change to this; it uses a bit mask instead of comparing
to various ok modes.  Otherwise it is unchanged....
-------------------------------------------------------------------------

Original Comment:

This was posted to comp.unix.wizards and net.sources, but I also wanted to
send it here, both for those that don't read or get news, and so that it
will be in the archives for posterity....

On the UNIX Security list, quite a while back, mention was made of
problems that could occur when home directories of users are writable.
(Installing |"some command" in ~uucp/.forward remotely and things like
that.)  This prompted me to write the enclosed program, both to check
for this, and to help protect users against themselves.

The program looks at all the home directories listed in /etc/passwd,
and prints a message if they don't exist, are not directories, or
their mode is not in the "table" of "OK" modes.  I'm using stat()
instead of lstat(), so symbolic links are perfectly acceptable, as
long as they point to directories....  This program should run on any
version of UNIX that I can think of; if it doesn't, please let me
know.

The list of good modes is, of course, subjective.  I initially used
the first set, then added the second set based on the output of the
first run.  I didn't add all the mismatched modes I found; just the
ones that were fairly normal and that I didn't want to hear about....

The program is surprisingly (to me) fast.  It took under a second on
our decently loaded VAX-11/785 running 4.3BSD with 501 passwd entries!

This program is placed in the public domain - you have only your
conscience to stop you from saying "hey, look at this neat program I
wrote"....

	Enjoy!

John Owens		Old Dominion University - Norfolk, Virginia, USA
john at ODU.EDU		old arpa: john%odu.edu at RELAY.CS.NET
+1 804 440 3915		old uucp: {seismo,harvard,sun,hoptoad}!xanth!john
*/

#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>


/* mask for modes.... (world writable) */
#define DMODE 002

main(argc,argv)
char **argv;
{
	register int mode;
	register int *p;
	struct passwd *pp;
	static struct stat statb;

	if (argc != 1) {
		printf("Usage: %s\n",argv[0]);
		exit(1);
	}

	while ((pp = getpwent()) != (struct passwd *)0) {
		if (stat(pp->pw_dir,&statb) < 0) {
		/*
			perror(pp->pw_dir);
		*/
			continue;
		}

		if ((statb.st_mode & S_IFMT) != S_IFDIR) {
			printf("Warning!  User %s's home directory %s is not a directory! (mode 0%o)\n",
				pp->pw_name,pp->pw_dir,statb.st_mode);
			continue;
		}

		mode = statb.st_mode & ~S_IFMT;

		if (!(mode & DMODE)) goto ok;

				/* note that 3.3 will print 4 if needed */
		printf("Warning!  User %s's home directory %s is mode 0%3.3o!\n",
		       pp->pw_name,pp->pw_dir,mode);
ok:	;
	}

	exit(0);

}
SHAR_EOF
echo shar: extracting cops/src/is_readable.c '(562 characters)'
cat << \SHAR_EOF > cops/src/is_readable.c
#include <sys/types.h>
#include <math.h>
#include <sys/stat.h>

#define G_WRITE 0040	/* group readable */
#define W_WRITE 0004	/* world readable */

main(argc,argv)
char **argv;
{
	register int group = 0, xmode = 0;
	static struct stat statb;

	if (argc < 2) {
		printf("Usage: %s [-g] file\n",argv[0]);
		exit(0);
	}

	if (argc > 2) {
		if (!strcmp(argv[1], "-g")) {
			group = 1;
			argc--;
			argv++;
		}
	}

	if (stat(*++argv,&statb) < 0) {
		exit(2);
	}

	if (group) xmode = statb.st_mode & G_WRITE;
	else xmode = statb.st_mode & W_WRITE;

	exit(!xmode);
}
SHAR_EOF
echo shar: extracting cops/src/is_writable.c '(563 characters)'
cat << \SHAR_EOF > cops/src/is_writable.c
#include <sys/types.h>
#include <math.h>
#include <sys/stat.h>

#define G_WRITE 0020	/* group writable */
#define W_WRITE 0002	/* world writable */

main(argc,argv)
char **argv;
{
	register int group = 0, xmode = 0;
	static struct stat statb;

	if (argc < 2) {
		printf("Usage: %s [-g] file\n",argv[0]);
		exit(0);
	}

	if (argc > 2) {
		if (!strcmp(argv[1], "-g")) {
			group = 1;
			argc--;
			argv++;
		}
	}

	if (stat(*++argv,&statb) < 0) {
		exit(2);
	}

	if (group) xmode = statb.st_mode & G_WRITE;
	else xmode = statb.st_mode & W_WRITE;

	exit(!xmode);
}

SHAR_EOF
echo shar: extracting cops/src/members.c '(1213 characters)'
cat << \SHAR_EOF > cops/src/members.c
/* Copyright 1985 Robert W. Baldwin */
/* Copyright 1986 Robert W. Baldwin */
static	char	*notice85 = "Copyright 1985 Robert W. Baldwin";
static	char	*notice86 = "Copyright 1986 Robert W. Baldwin";

/*
 * useage: members GroupName
 * Writes to stdout the list of UserNames that are in the given group.
 * The UserNames are separated by space or newline characters.
 *
 */

#include	<stdio.h>
#include	<grp.h>
#include	<pwd.h>



main(argc, argv)
int	argc;
char	*argv[];
{
	int	i;
	int	gid;
	struct	group	*grent;
	struct	passwd	*pwent;
	char	**user;

/*
 * Print the list of group members from /etc/group.
 */
	if ((grent = getgrnam(argv[1])) == NULL)  {
		fprintf(stderr, "%s: Bad group name %s.\n",
			argv[0], argv[1]);
		exit(1);
		}
	gid = grent->gr_gid;
	for (user = grent->gr_mem ; *user != NULL ; user++)  {
		fprintf(stdout, "%s ", *user);
		}
	fprintf(stdout, "\n");
	endgrent();
/*
 * The passwd file must also be examined to find members of the group.
 * Duplicates may occur, but the higher level code shouldn't care about them.
 */
	while ((pwent = getpwent()) != NULL)  {
		if (pwent->pw_gid != gid)
			continue;
		fprintf(stdout, "%s ", pwent->pw_name);
		}
	fprintf(stdout, "\n");
	endpwent();
}

SHAR_EOF
echo shar: extracting cops/src/pass.c '(12598 characters)'
cat << \SHAR_EOF > cops/src/pass.c
#include <stdio.h>
#include <pwd.h>
#include <ctype.h>

#ifndef lint
static char *rcsid = "$Header: pwchkr.c,v 1.1 85/09/10 16:00:56 root Exp $";
#endif

/*
 * Warning: this program burns a lot of cpu.
 */
/*
 * Insecure - find accounts with poor passwords
	Date: Tue, 29 Nov 83 18:19:32 pst
	From: leres%ucbarpa at Berkeley (Craig Leres)
	    Modified by Seth Alford, Roger Southwick, Steve Dum, and
	    Rick Lindsley for Tektronix
 */

/*
 *	$Log:	pwchkr.c,v $
 *	Revision 1.1  85/09/10  16:00:56  root
 *	Initial revision
 *	
 *
 * By default, this program only checks for accounts with passwords the same
 * as the login name. The following options add more extensive checking. (The
 * tradeoff is cpu time -- with all options enabled it can run into the 100's
 * of MINUTES.) Any argument that does not begin with a "-" is assumed to be
 * a file name. (A single '-' means stdin.) If no file name is given,
 * /etc/passwd is used.
 *
 * Options:
 *
 *		-v:	verbose -- list all guesses on stdout
 *		-u:	output the username on the line of the password file
 *			currently being checked. If the program stops
 *			abruptly you will then know how far it got.
 *		-w file: use the list of words contained in "file" as likely
 *			passwords. Words in the file are one to a line.
 *		-b: 	check all guesses backwards too
 *		-g:	use the Full Name portion of the gecos field to
 *			generate more guesses
 *		-s:	check the single letters a-z, A-Z, 0-9 as passwords
 *		-c:	with each guess, check for all-lowercase and
 *			all-uppercase versions too.
 *		-n:	complain about null passwords (default is to keep quiet)
 *		-p:	print the password when guessed
 */

int verbose = 0, singles = 0, backwards = 0, checkgecos = 0, checkcase = 0,
    chknulls = 0, printit = 0, users = 0, chkwords = 0;

char *my_index(), *reverse();
long atol();
FILE *fopen();
char *fgets();

char PASSWD[] = "/etc/passwd";
char EMPTY[] = "";
static FILE *pwf = NULL, *wlf = NULL;
char line[BUFSIZ+1];
struct passwd passwd;
char	*Curpw, *Wordlist = NULL;

main(argc, argv)
char **argv;
{
    register int i;
    register char *arg;
    int onedone = 0;

    /*
    You have to decide whether or not to include these lines....

    if (getuid()) {
	printf("Did you really think we would let you run this?\n");
	exit(1);
	}

    */

    for (i = 1; i < argc; i++)
	if ((arg = argv[i]) && *arg == '-')
	    while (*++arg) {
		switch (*arg) {
		    case 'n':
			/*
			 * complain about null passwords
			 */
			chknulls++;
			break;
		    case 'c':
			/*
			 * check cases
			 */
			checkcase++;
			break;
		    case 'g':
			/*
			 * use gecos
			 */
			checkgecos++;
			break;
		    case 'v':
			/*
			 * turn on motormouth
			 */
			verbose++;
			break;
		    case 'b':
			/*
			 * check all attempts forwards and backwards
			 */
			backwards++;
			break;
		    case 's':
			/*
			 * carry out a more intensive search, checking for
			 * single letter passwords
			 */
			singles++;
			break;
		    case 'p':
			/*
			 * print out the password when found
			 */
			printit++;
			break;
		    case 'u':
			/*
			 * print out users as testing
			 */
			users++;
			break;
		    case 'w':
			/*
			 * consult word list of likely passwords
			 */
			if ((Wordlist = argv[i+1]) == NULL) {
			    fprintf(stderr,
				"%s: No file supplied with -w option\n",
				argv[0]);
			    exit (1);
			    }
			argv[i+1] = NULL;
			break;
		    case '\0':
			/*
			 * read from stdin
			 */
			break;
		    default:
			fprintf(stderr,
			    "%s: unknown option '%c'. Options are:\n",argv[0],
			    *arg);
			/* FALL THRU */
		    case '-':
			fprintf(stderr,"-v:\t\tverbose -- list all guesses on stdout\n");
			fprintf(stderr,"-u:\t\toutput the username currently being checked\n");
			fprintf(stderr,"-w file:\tconsult the indicated file for words to check as passwords\n");
			fprintf(stderr,"-b:\t\tcheck all guesses forwards and backwards\n");
			fprintf(stderr,"-g:\t\tuse the Full name portion of the gecos field for more guesses\n");
			fprintf(stderr,"-s:\t\tcheck the single letters a-z, A-Z, 0-9 as passwords\n");
			fprintf(stderr,"-c:\t\tcheck the all-upper and all-lower case version of each guess\n");
			fprintf(stderr,"-n:\t\tcomplain about null passwords\n");
			fprintf(stderr,"-p:\t\tprint the password when guessed\n");
			exit(1);
		    }
		argv[i] = NULL;
		}
    
    for (i = 1; i < argc; i++) {
	if (argv[i] == NULL) continue;
	onedone++;
	if (*(argv[i]) == '-') {
	    /*
	     * read from stdin; we'll cheat and set pwf directly
	     */
	    pwf = stdin;
	    chkpw();
	    /*
	     * don't fclose stdin!
	     */
	    clearerr(stdin);
	    }
	else {
	    if (setpwent(argv[i])) {
		perror(argv[i]);
		continue;
		}
	    Curpw = argv[i];
	    chkpw();
	    endpwent();
	    }
	}
    if (!onedone) {
	Curpw = NULL;
	chkpw();
	}
    exit(0);
}

/*
 * Added by Jacob Gore, March 12, 1987.
 *
 * Finds the pointer of the leftmost occurance within the character string
 * 'string' of any character found within the character string 'chars'.
 *
 * If none of the characters in 'chars' appear in 'string', NULL is retutned.
 *
 */
char *
indexm (string, chars)
    char *string, *chars;
{
    while (*string) {
	if (my_index(chars, *string) != NULL) {
	    return string;
	}
	string++;
    }
    return NULL;
}

#define ARB_CONST	80

chkpw()

{
    register char	*cp, *cp2;
    register struct passwd *pwd;
    struct passwd	*getpwent();
    char		guess[100];
    char		*wordarray[ARB_CONST];
    char		*malloc(), **wordptr, **endptr;
    int			done = 0;


    if (Wordlist)
    {
	if ((wlf = fopen(Wordlist,"r")) == NULL)
	{
	    perror(Wordlist);
	    exit(1);
	}

	wordptr = wordarray;
	/*
	 * note that endptr points to space OUTSIDE of wordarray
	 */
	endptr = wordarray + (sizeof(wordarray)/sizeof(char *));

	while (fscanf(wlf,"%[^\n]\n",guess) != EOF)
	{
  /* SunOs 4.03 on a Sun 3/80 didn't work properly, needed this one line fix */
	    if (feof(wlf)) break;

	    if (wordptr == endptr)
	    {
		fprintf(stderr,"Ran out of wordlist space. ARB_CONST %d must be too small.\n", ARB_CONST);
		exit(1);
	    }
	    if ((*wordptr = malloc(1+strlen(guess))) == NULL)
	    {
		fprintf(stderr,"malloc: no more memory for wordlist\n");
		exit (1);
	    }
	    strcpy(*wordptr,guess);
	    wordptr++;
	}
	*wordptr = NULL;
    }

    while ((pwd = getpwent()) != 0 ) {

	if (verbose || users) {
	    if (Curpw == NULL)
		printf("\t%s \"%s\"\n", pwd->pw_name, pwd->pw_gecos);
	    else
		printf("%s -- \t%s \"%s\"\n", Curpw, pwd->pw_name,
		    pwd->pw_gecos);
	    fflush(stdout);
	    }
	if (*pwd->pw_passwd == '\0') {
	    if (chknulls) {
		if (Curpw == NULL)
		    printf("Warning!  Password Problem: null passwd:\t%s\tshell: %s\n",
			pwd->pw_name, pwd->pw_shell);
		else
		    printf("Warning!  %s -- Password Problem: null passwd:\t%s\tshell: %s\n",
			Curpw, pwd->pw_name, pwd->pw_shell);
		fflush(stdout);
		}
	    continue;
	}
	/*
	 * Try the user's login name
	 */
	if (uandltry(pwd,pwd->pw_name))
	    continue;

	/*
	 * Try names from the gecos field
	 */
	if (checkgecos) {
	    strcpy(guess, pwd->pw_gecos);
	    cp = guess;
	    if (*cp == '-') cp++;		/* special gecos field */
	    if ((cp2 = my_index(cp, ';')) != NULL)
		*cp2 = '\0';

	    for (;;) {
		/* use both ' ' and ',' as delimiters -- Jacob */
		if ((cp2 = indexm(cp, " ,")) == NULL) {
		    if (uandltry(pwd,cp))
			done++;
		    break;
		    }

		*cp2 = '\0';

		if (uandltry(pwd,cp)) {
		    done++;
		    break;
		    }
		cp = ++cp2;
		}
	    }
	    
	if (!done && Wordlist)
	{
	    /*
	     * try the words in the wordlist
	     */
	    wordptr = wordarray;
	    while (endptr != wordptr)
	    {
		if (*wordptr == NULL)
		    break;
		if (uandltry(pwd,*wordptr++))
		{
		    done++;
		    break;
		}
	    }
	}
	if (!done && singles) {
	    /*
	     * Try all single letters
	     * (try digits too .  --Seth)
	     */
	    guess[1] = '\0';
	    for (guess[0]='a'; guess[0] <= 'z'; guess[0]++)
		if (try(pwd,guess))
		    break;
	    for (guess[0]='A'; guess[0] <= 'Z'; guess[0]++)
		if (try(pwd,guess))
		    break;
	    for (guess[0]='0'; guess[0] <= '9'; guess[0]++)
		if (try(pwd,guess))
		    break;
	    }
    }
}

/*
 * Stands for "upper and lower" try.  Calls the "real" try, below,
 * with the supplied version of the password, and with
 * an upper and lowercase version of the password. If the user doesn't
 * want to try upper and lower case then we just return after the one
 * check.
*/

uandltry (pwd,guess)
char *guess;
struct passwd *pwd;
{
    register char *cp;
    char buf[100];
    int alllower, allupper;

    alllower = allupper = 1;

    if (try(pwd,guess) || (backwards && try(pwd,reverse(guess)))) return (1);

    if (!checkcase) return(0);

    strcpy (buf, guess);
    cp = buf-1;
    while (*++cp) {
	if (isupper(*cp))
	    alllower = 0;
	if (islower(*cp))
	    allupper = 0;
	}

    if (!allupper) {
	for ( cp=buf; *cp != '\0'; cp++)
	    if (islower (*cp))
		*cp += 'A' - 'a';

	if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
	}

    if (!alllower) {
	for ( cp = buf; *cp != '\0'; cp++)
	    if (isupper (*cp))
		*cp += 'a' - 'A';

	if (try(pwd,buf) || (backwards && try(pwd,reverse(buf)))) return (1);
	}
    return (0);
}

try(pwd,guess)
char *guess;
register struct passwd *pwd;
{
    register char  *cp;
    char   *crypt ();

    if (verbose) {
	if (Curpw == NULL)
	    printf ("Trying \"%s\" on %s\n", guess, pwd -> pw_name);
	else
	    printf ("%s -- Trying \"%s\" on %s\n", Curpw, guess,
		pwd -> pw_name);
	fflush (stdout);
	}
    if (! guess || ! *guess) return(0);
    cp = crypt (guess, pwd -> pw_passwd);
    if (strcmp (cp, pwd -> pw_passwd))
	return (0);
    if (Curpw == NULL)
	if (printit)
	    printf ("Warning!  Password Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
		pwd -> pw_name, pwd -> pw_shell, guess);
	else
	    printf ("Warning!  Password Problem: Guessed:\t%s\tshell: %s\n", pwd -> pw_name,
		pwd -> pw_shell);
    else
	if (printit)
	    printf ("Warning!  %s -- Password Problem: Guessed:\t%s\tshell: %s passwd: %s\n",
		Curpw, pwd -> pw_name, pwd -> pw_shell, guess);
	else
	    printf ("Warning!  %s -- Password Problem: Guessed:\t%s\tshell: %s\n",
		Curpw, pwd -> pw_name, pwd -> pw_shell);
    fflush (stdout);
    return (1);
}
/* end of PW guessing program */

#define MAXUID 0x7fff	/* added by tonyb 12/29/83 */
			/* altered to a reasonable number - mae 8/20/84 */

/*
 * Add a parameter to "setpwent" so I can override the file name.
 */

setpwent(file)
char *file;
{
	if ((pwf = fopen(file,"r")) == NULL)
	    return(1);
	return(0);
}

endpwent()

{
    fclose(pwf);
    pwf = NULL;
}

char *
pwskip(p)
register char *p;
{
	while(*p && *p != ':' && *p != '\n')
		++p;
	if(*p == '\n')
		*p = '\0';
	else if(*p)
		*p++ = '\0';
	return(p);
}

struct passwd *
getpwent()
{
	register char *p;
	long	x;

	if(pwf == NULL)
	    if (setpwent(PASSWD)) {
		perror(PASSWD);
		return(NULL);
		}
	p = fgets(line, BUFSIZ, pwf);
	if(p == NULL)
		return(0);
	passwd.pw_name = p;
	p = pwskip(p);
	passwd.pw_passwd = p;
	p = pwskip(p);
	x = atol(p);	
	passwd.pw_uid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
	p = pwskip(p);
	x = atol(p);
	passwd.pw_gid = (x < 0 || x > MAXUID)? (MAXUID+1): x;
	passwd.pw_comment = EMPTY;
	p = pwskip(p);
	passwd.pw_gecos = p;
	p = pwskip(p);
	passwd.pw_dir = p;
	p = pwskip(p);
	passwd.pw_shell = p;
	(void) pwskip(p);

	p = passwd.pw_passwd;
 
	return(&passwd);

}


/*
 * reverse a string
 */
char *reverse(str)
char *str;

{
    register char *ptr;
    register int len;
    char	*malloc();

    if ((ptr = malloc((len = strlen(str))+1)) == NULL)
	return(NULL);
    ptr += len;
    *ptr = '\0';
    while (*str && (*--ptr = *str++))
	;
    return(ptr);
}
/* taken from comp.binaries.ibm.pc.d:
Some users have reported trouble compiling the freely distributable
uudecode I posted.  It seems that Berkeley moved the "index" function
to one of their system libraries and some systems don't have it.
Here is the missing "index" function, excerpted from an earlier freely
distributable uudecode.  Just add it on the end of the uudecode I posted.
*/
/*
--Keith Petersen
Maintainer of SIMTEL20's CP/M, MSDOS, & MISC archives [IP address 26.2.0.74]
Internet: w8sdz at WSMR-SIMTEL20.Army.Mil, w8sdz at brl.arpa  BITNET: w8sdz at NDSUVM1
Uucp: {ames,decwrl,harvard,rutgers,ucbvax,uunet}!wsmr-simtel20.army.mil!w8sdz
*/

/*
 * Return the ptr in sp at which the character c appears;
 * NULL if not found
 */

#define	NULL	0

char *
my_index(sp, c)
register char *sp, c;
{
	do {
		if (*sp == c)
			return(sp);
	} while (*sp++);
	return(NULL);
}


SHAR_EOF
echo shar: extracting cops/src/tilde.c '(401 characters)'
cat << \SHAR_EOF > cops/src/tilde.c
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>

main(argc,argv)
int argc;
char **argv;
{
struct passwd *pp;

if (argc != 2) {
	printf("Usage: %s\n",argv[0]);
	exit(1);
}

/* print directory of user, else "Error"  -- need to print
  something, or kuang won't parse dir correctly */
if ((pp = getpwnam(argv[1])) != (struct passwd *)0)
	printf("%s", pp->pw_dir);
else
	printf("Error");

}
SHAR_EOF
echo shar: extracting cops/src/user.chk.c '(1411 characters)'
cat << \SHAR_EOF > cops/src/user.chk.c
#include <stdio.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>

/* Any file writable by all will be flagged */
#define DMODE 002

/* #define DMODE2 020 */

/* potentially dangerous files */
char *ftable[] = {
	"rhost",
	"profile",
	"login",
	"cshrc",
	"bashrc",
	"kshrc",
	"tcshrc",
	"rhost",
	"netrc",
	"forward",
	"dbxinit",
	"distfile",
	"exrc",
	"emacsrc"
};
char *ft;
char *ftr, *malloc();

char generic_file[100];

main(argc,argv)
int argc;
char **argv;
{
register int fmode;
/*
int index;
*/
register int index;
struct passwd *pp;
static struct stat statb;

if (argc != 1) {
	printf("Usage: %s\n",argv[0]);
	exit(1);
}

ft = malloc(100);
ftr = malloc(100);

while ((pp = getpwent()) != (struct passwd *)0) {
	if (stat(pp->pw_dir,&statb) < 0) {
		continue;
	}

	index = 0;
	/*
	 *   Use the home-dir, and add on each potential security threat
	 * file to the path one at a time.  Then check each file to see
	 * if it breaks with the modes established up above
	 *
	*/
	for (ft = ftable[index]; index < 13; ft = ftable[++index]) {
		if (strlen(pp->pw_dir) != 1)
			sprintf(generic_file, "%s/.%s", pp->pw_dir,ft);
		else 
			sprintf(generic_file, "%s.%s", pp->pw_dir,ft);

		if (stat(generic_file,&statb) < 0)
			continue;

		if (statb.st_mode & DMODE) 
			printf("Warning!  User %s:\t%s is mode \t0%3.3o!\n",
	       		pp->pw_name,generic_file,statb.st_mode&~S_IFMT);

	}

}

exit(0);
}
SHAR_EOF
echo shar: extracting cops/extensions/THINGS_2_DO '(1515 characters)'
cat << \SHAR_EOF > cops/extensions/THINGS_2_DO

 Possible improvements/extensions of the COPS package might (will?) include
(other than merely fixing bugs existing in the package) :

 0) Smarter detection of problems -- a lot of problems can be found in
configuration files; the way they are set up, not merely if they are
writable.  These aren't neccessarily hard to check for, but take someone
with a good understanding for the file to write.

 1) Detecting Bugs.  A very touchy subject, with so many sites without
source code to fix the bugs.  Depends a lot on how people react to this
package, and what the demand is for a package that finds bugs.  It would
be similar to the approach used in the rest of the package in that it
would point out the bugs, not tell how to exploit them.  For instance,
an example would be "Warning!  fingerd bug present!"

 2) Better and more thorough Yellow Pages checking.

 3) Ditto for UUCP stuff.

 4) Once again for NFS things.

 5) Problems that are specific to a certain flavor of UNIX.  For
instance, HP-UX has different files in different places.  Perhaps
the system could look for and hunt for the vital files in the various
places rather than having to be put in a configuration file.  Also
support for various secure UNIX varieties; e.g. C2 level Sun, IBM's
secure AIX, etc.

 6) More problems to be added; by no means are all security problems detected
by COPS.  More potential hazards should not be difficult to detect -- merely
adding another module to the system or simply modifying what is here might
suffice.
SHAR_EOF
echo shar: extracting cops/extensions/YAR '(377 characters)'
cat << \SHAR_EOF > cops/extensions/YAR


  (YAR -- Yet Another README file)

    This is where the odds 'n ends go.
    "THINGS_2_DO" is a file that says what I'd like to see done, either
in COPS or in other packages.
    "questions" is a questionaire and some answers I recieved about
computer security.  It might prove of interest for general reading.
    "netstuff" is a short list of net.references for further information.
    "passwords" gives a reference for fast password cracking.

SHAR_EOF
echo shar: extracting cops/extensions/netstuff '(1717 characters)'
cat << \SHAR_EOF > cops/extensions/netstuff


    For additional information, help on various subjects, etc., there
are various resources available on the net.  By no means is this list
exclusive:

   comp.risks -- a moderated newsgroup that talks about the risks of
computing, often discussing computer security.

   comp.unix.wizards -- a high noise free-for-all group that has
some choice tidbits of information.

   Security Mailing list -- moderated by Neil Gorsuch, fits and bursts
of information that can be gotten nowhere else.  Hard to join the elite
who are on the list, and a long wait for acceptance.  Security programs
can be snarfed off of this list at times.

   CERT -- the Computer Emergency Response Team has a mailling list
devoted to the development of security tools.  As quoted from
their initial mailing:

"The Computer Emergency Response Team Coordination Center (CERT/CC) has
established a new Internet mailing list named CERT-TOOLS.  This new
mailing list is now available.

The purpose of this new mailing list is to encourage the exchange of
information on security tools and security techniques.  The list
should not be used for security problem reports.
[...]
Mailing list problems, additions, changes, and deletions requests should
be sent to:
        cert-tools-request at cert.sei.cmu.edu

[...]
CERT/CC is planning to collect many of the tools and will make the
archive available via anonymous ftp on the cert.sei.cmu.edu system.
A trusted archive service will also be available for tools not intended
for general public usage.

All mail intended to be redistributed should be mailed to:
	cert-tools at cert.sei.cmu.edu

Computer Emergency Response Team
Email: cert at cert.sei.cmu.edu
Telephone: 412-268-7090 (answers 24 hours a day)"
SHAR_EOF
echo shar: extracting cops/extensions/passwords '(432 characters)'
cat << \SHAR_EOF > cops/extensions/passwords

   For those who need _fast_ password cracking, for whatever reason,
Matt Bishop wrote a fairly incredible password cracking engine, which
is detailed in:

"An Application of a Fast Data Encryption Standard Implementation",
Matt Bishop, Computing Systems 1(3) pp. 221-254 (Summer 1988).

  If you have a valid reason for using it, you can mail to Matt at:
    
   bishop at bear.dartmouth.edu

  for more information on his package.

SHAR_EOF
echo shar: extracting cops/extensions/questions '(13339 characters)'
cat << \SHAR_EOF > cops/extensions/questions
   
   I polled a security mailing list and got about 40 responses to a
selected number of questions dealing with security; it might be useful
for inclusion on how the net (at least some of the security minded ones)
view security.  The answers to these questions shaped some of the philosophies
of COPS and might be indicative of the type of security tools to be
developed in the future.  My questions start with a number and a ")".

   1)  What kinds of problems should a software security system (SSS)
   such as COPS check for? (Mention specific examples, if you can.)

  Just about everyone agreed that the more things checked, the better.
Some specific wants of items I didn't mention, more or less in the order
of # of requests:

  Some kind of _secure_ checksum method for checking up on binary files.

  Checking binaries for known security problems - sendmail, fingerd,
ftpd, ect.

  Checking the validity of the _format_ of key files rather than merely
checking if they are writable.

  Checking for potential trojan horses; files such as "ls" in a users
account.

  Finding things hidden under mount points.

  Keeping track of accounts in a seperate file from /etc/passwd and
run periodic checks to see if any accounts have been added by any
unauthorized user.
  
  Report unusual system activity, such as burning lots of CPU time.

  Record unsuccessful login attempts and su's to root, when and by whom
if possible.


   2)  Are there any security problems too sensitive to be checked
   by a SSS?  That is, what things should *not* be built into a SSS?

     Boy, this was a landslide.  Over 90% said NO, and not only no,
but basically "Hell No".  The only concerns I got were against password
cracking and problems that could not be easily fixed.  There was also
a small amount of concern about limiting access to root, but most realized
that no matter what, the benifits would outweigh any losses if the programs
were put out.

   3) What should the primary goal of a SSS be -- discovering as many
   security holes as possible in a given system (including bugs or
   design flaws that may not be easily fixed -- especially without
   source code), or merely uncovering correctable errors (due to
   ignorance, carelessness, etc)?

     Another landslide.  Of all the responses, only one person objected
to finding all holes, although a few did say that finding the fixable
holes was top priority.

    One view:

  My use for an SSS is as a system monitor, not as a diagnostic tool.
I suppose the diagnostic version also has its uses, but writing and
distributing such a program is asking for trouble.  I don't see
anything wrong with writing it and distributing only the binaries.


   4)  Do you feel that SSS are a security threat themselves?

     Some dissent begins to show.... It was almost even here, with the
no's beating out the yes's by a single vote.  However, 2/3 of the yes
votes qualified there answer by stating something like "a tool can be
misused" and whatnot.  Here are some typical responses:

Of course.  They point to way for bad guys.  Such is life.
They are a tool.  They have the potential for anything.  The
security threat lies in how they are used....

No, as long as they don't breed complacency. Just by running
a SSS each night should not make you thinks your systems are
secure.

Fire is also dangerous but VERY useful.


   5) Do you think that the SSS should be restricted to be used only
   by system administrators (or other people in charge), or should
   they be accessible to all?

     Here's where the problems start :-)  Everyone wants as many
features as possible, but quite a few of you don't want anyone else
to have it.  Hmm...   Out of 35 responses on this question:
  12 - Yes, only SA's.
  10 - No.
   6 - It would be nice to have it restricted, but... How?
   5 - Have two versions; one restricted, one not.  Needless to say,
        the dangerous stuff should go in the first.
   1 - Restrict only parts that detect bugs/whatever that cannot be
        repaired.
   1 - Argh!  Help!

     Some quotable quotes:

I don't see how it could be restricted.

Admins, etc only. (possibly said because I'm an admin. From an
intellectual standpoint, I would want to know about this stuff even
if I was just a user)

I think the SSS should be restricted to system
administrators with the realisation that others can probably
get their hands on the code if they want to. 

Definitely available to all, SA's can be as lazy as anyone and should not be 
allowed to hide behind a veil of secrecy if, in doing so, they expose the 
systems they administer.

It seems to me that only an "administrator type" will have sufficient
privilege levels to make _effective_ use of such a tool.  Ordinary users
may be able to garner _some_ benefit though, if run on their own files.
If possible, can there be an "administrator" mode and a (restriced/limited)
"user" mode?

(and finally, my personal favorite...)

I think that a check for a hole that can't be closed shouldn't be a part of
the check, if that hole is widespread.  I have no examples of any such hole,
but a weak spot that can't be closed and has no workaround is one of the few
candidates for the security by secrecy concept.  I have mixed feelings about
this, but if I can't fix the hole, I'd rather not have it's existence be
"public" knowledge.  A freely available routine to locate the hole would
spread it's existence far and wide.....(?)
But, if I didn't know about it beforehand then it would be good to have a
tool to tell me it existed.  Gads, I hate moral conflicts!
 

   6) When a SSS finds a security flaw in a system, do you want it to 
   indicate how they flaw could be used to compromise your system, or
   would you just accept the conclusion and apply a fix?

      This question was ill worded and gramatically incorrect, but still
managed to conjure up a lot of comments.  Some thought it was asking if
the system should apply a fix.
      In any case, almost 3/4 said Yes, indicate exactly how to exploit
any potential hole.  As usual, there were a few with reservations about
the info getting out, but.... 
   Here are some of the more interesting comments:

                (Think about this one!)
  *I* would like to know to futher my knowledge of Unix, but more importantly
to make sure that the version I have was not modified by a cracker to
put security holes *into* a system.  (That'd be sneaky :-)

   Security by obfuscation doesn't work.

   By definition, a SSS is a software system, and therefore has bugs in it.
If it reported a problem which would cause quite a bit of inconvenience if
fixed, or would be difficult to fix, then I would be much more apt to make
the fix if I knew how the problem could be exploited.  This is important,
because many, if not most, sites require only a moderate level of security,
and many security holes are fiendishly difficult to exploit.

   We cannot assume that end-purchasers of a system can be as aware of 
the internal workings of a system as the designers of the system (or SSS)
are.  If a security flaw is discovered, the administrators need to be
informed about what changes are necessary to remove that flaw, and what
repercussions they may have.
   [...]
   Imagine a SSS that knew sendmail(8) was a security flaw
allowing a worm to enter systems.  It would report that sendmail is a 
security flaw, please disable it like....  If the vendor had released
a patch, and the SSS didn't know how it, the administrator (in blind
faith to this SSS program) might disable a *very* useful program
unnecessarily.


   7)  Do you think that there is too much, not enough, or just about
   the right amount of concern over computer security?  How about at 
   your computer site?  At other sites?

      The "not enough"s won, but not by much.  I thought that given
the paranoia of a security group, this would be a larger victory.
Lots of people said it depends -- on the type of facility, the size, etc.
Large sites seem to have a healthier view of security (paranoia :-)) than
smaller/non-governmental.  Only 4 or 5 said there was enough concern.
A couple of people mentioned _The Cuckoo's Egg_ as suggested reading
(I heartily agree.)

   More quotes:

  (I don't know if the next answer is true, but I like it anyway!)

  This is really a deep philosophical question---something to talk about
over a few beers at the bar, but not here.

  I think it's a site dependent problem, and all the above are
true: too much, too little, and just right. Computer is not a
"one size fits all" situation. Having offered that opinion, I
think an assessment of my site or other sites is extraneous, and I
will reserve that opinion.

  ... more attention to unauthorized use of the networks.

   8)  Do you think that there should be a ruling body that governs
   and enforces rules and regulations of the net -- sort of a net.police?

     Some of you wondered what this had to do with software security, but
just about everyone answered anyway.  This one scared me!  The "No's" only
beat out the "yes's" by one vote.  Yikes!  Maybe I'm from the old school
of thought, but....  Several people said that it couldn't be done anyway;
a couple mentioned they a CERT-like agency to help out, but not control,
and finally two said that the laws and government were already there to
do this.

   It's there, defacto.  The free market is working pretty well.

   Absolutely. I quarrel with the "net.police" designation, per se, of
course, as do many others. But perhaps something more like a recognized
trade association, and providing similar services. Also, it is time that
the basic duties which must be reasonably performed by a site in order for
it to remain on the net should become a requirement rather than a matter
of individual whim.

   Yuck!  This is very distasteful to me.  It will probably be necessary
though as more and more people participate in the net.  Enforcement will
have to be judicious until secure networking is developed and implemented
generally.

   No.  Aside from the fact that it'd never work, I like Usenet as an
anarchy.  It has some rough edges, but for the most part it works.  What
does this question have to do with SSS-type programs?

   Enforcement will be tough and may hold back legitimate users.  But
we have to start somewhere.  So I suppose that I agree with having
net.police, as long as they don't turn things into a police.state.net. 


   9)  Do you believe that breaking into other people's systems should
   continue to be against the law?

      Only one said "no", and s/he had a smiley following the answer.
But there were some of you who voiced concern that it wasn't really
against the law to begin with.  In _The Cuckoo's Nest_, Cliff Stoll talked
about a (Canadian, I think) case that the only reason the cracker was
prosecuted was for stealing electricity!  Less than a watt or something.
A few of you mentioned denial of services as being a just reason, but
what if they break in only at night, when no one else is on, and they
really don't take anything at all?  Should that be less punishable than
someone who sucks away user CPU/disk/whatever?

   Breakins should be encouraged and rewarded (1/2 :-).

   Yes.  Unquestionably.  However, those laws should not attempt to regulate
inter-system traffic to cause these things to happen.

   Yes - and as a felony in all cases, without exception.

   Yes but murder, rape, robbery... are more important and laws and
sentencing should reflect this. There are some around who want to treat
cracking as a capital crime!

   Yes, from the denial of services standpoint.  I pay $XXX,XXX.XX for a
system, and joe blow slides in and sucks away at those resources, there
should be a nontrivial penalty for getting caught.  Don't behead the guy,
but monetary fines or community service would be just fine.


   I don't know.  I'm not a philosopher.  Certainly causing
damage to others is wrong, including denial of service,
compromising sensitive info, or whatever.  I'm concerned
though that clamping down on young kids will discourage them
from becoming computer geeks.  I think we need to encourage
our young people to become technically literate.  If we
don't become a more expert society we can kiss it goodbye;
all we'll have left is our military solutions, like some
brainless jock bully...

   I'm not sure that it is everywhere - but: Yes.  Should attempting 
to break in be against the law: No.  Is this vague: Yes.

   I did not know that it was. The laws about it have not been tested and 
are vague and unclear. You need to be very clear about what the laws
are going to do. 

   **HELL FUCKING YES** Those of us who started in UNIX years ago have
for the most part *always* respected others!! This I can't stress strong
enough.


  10)  Is your site academic, government, or commercial in nature?

      Just over 1/2 of those that answered claimed university ties,
with about 1/4 being commercial, 1/6 government, a few research sites,
and a couple that were a mixture.  Sites included Sun, AT&T, SCO (Xenix),
the DoD, and the Army, among others.

(Guess where this one came from :-)

Research.  We invented Unix.

Academic with commercial applications.

Primarily academic, but we are part of the government.

Academic, except when collecting student fees *) *)
SHAR_EOF
#	End of shell archive
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list