Subject: v21i023: System ecurity analysis tool, Part01/05 Newsgroups: comp.sources.unix Approved: rsalz@uunet.UU.NET X-Checksum-Snefru: 03f906ff a4064d7a 431652ed 3dcdc63e Submitted-by: Dan Farmer Posting-number: Volume 21, Issue 23 Archive-name: cops/part01 COPS is a security tool that is useful to system administrators, system programmers, or for anyone who would like to learn about UNIX security. It does not restrict a system's environment by placing constraints on activity; it is a purely diagnostic tool that checks and reports on the current status of a given UNIX machine. Written in Bourne shell, generic commands (awk, sed, etc.) and some C, the system is basically a shell script that runs several small security programs. Theoretically (at least), it attempts to find the following problems (among others) on a generic UNIX system, and then mails or saves the results, if indeed any problems do exist: --Checks /dev/*mem and all devs listed in "/etc/fstab" for world read/writability. --Checks special/important directories and files for "bad" (world writable, whatever) modes. (/etc/passwd, /bin, etc.) --Checks against /etc/passwd for crummy passwords (user selectable, it can be as vigorous or as lax as you wish.) --Checks /etc/passwd for non-unique uids, invalid fields, non-numeric user ids, etc. Also includes a password checker. --Checks /etc/group for non-unique groups, invalid fields, non-numeric group ids, etc. --Checks all users' home directories and their .login/.cshrc/.rhosts/.profile/etc. files --Checks all commands and paths listed in /etc/rc* and crontabs for world writability. --Checks for bad root paths, world exportable NFS systems, some other misc stuff. --Includes the Kuang expert system. Written by Robert Baldwin, this basically checks to see if a given user (by default root) is compromisible, given that certain rules are true. Kind of hard to explain in a sentence, but worth the price of admission. --Checks the system for _changes_ in SUID status. This is the one (the only) program that should be run as superuser, because it runs a "find" on all SUID programs from the / directory, and then uses that as a reference file for future runs. The "README" file tells how to install, run, and interpret any results found by COPS. # 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/MANIFEST # cops/README # cops/XTRA_CREDIT # cops/chk_strings # cops/cops # cops/cron.chk # cops/dev.chk # cops/dir.chk # cops/dir.chklst # cops/disclaimer # cops/file.chk # cops/file.chklst # cops/group.chk # cops/init_kuang # cops/kuang # cops/makefile # cops/pass.words # cops/passwd.chk # This archive created: Tue Jan 30 23:35:07 1990 # By: dan (Purdue University) echo shar: extracting cops/MANIFEST '(763 characters)' cat << \SHAR_EOF > cops/MANIFEST File Name ================== MANIFEST README XTRA_CREDIT chk_strings cops cron.chk dev.chk dir.chk dir.chklst docs file.chk file.chklst group.chk init_kuang kuang makefile pass.words passwd.chk rc.chk reconfig root.chk stop.sample suid.chk docs/COPS.report docs/KUANG.README docs/SUID.README docs/cops docs/cron docs/dev docs/dir docs/file docs/group docs/home docs/is_able docs/kuang.1 docs/kuang.man docs/pass docs/passwd docs/rc docs/release.notes docs/root docs/suid.man docs/tilde docs/user docs/warnings extensions/THINGS_2_DO extensions/YAR extensions/netstuff extensions/passwords extensions/questions src/addto.c src/clearfiles.c src/filewriters.c src/home.chk.c src/is_readable.c src/is_writable.c src/members.c src/pass.c src/tilde.c src/user.chk.c SHAR_EOF echo shar: extracting cops/README '(14146 characters)' cat << \SHAR_EOF > cops/README Welcome! You now hold in your hands (terminal?) a collection of security tools that are designed specifically to aid the typical UNIX systems administrator, programmer, operator, or consultant in the oft neglected area of computer security. The package, which will be henceforth be referred to as COPS (Computer Oracle and Password System), can be broken down into three key parts. The first is the actual set of programs that attempt to automate security checks that are often performed manually (or perhaps with self written short shell scripts or programs) by a systems administrator. The second part is the documentation, which details how to set up, operate, and to interpret any results given by the programs. Finally, COPS is an evolving beast. It includes a list of possible extensions that might appear in future releases, as well as pointers to other works in UNIX security that could not be included at this time, due to space or other restrictions. This document contains six sections: 1) What is COPS? 2) What COPS is _not_ 3) How to Configure/Install COPS 4) Running COPS for the 1st Time 5) Continued Use of COPS 6) Disclaimer and End Notes 1) What is COPS? ----------------- COPS is a collection of about a dozen programs that each attempt to tackle a different problem area of UNIX security. Among the areas checked are file, directory, and device permissions/modes, passwords, contents of password and group files, the contents of /etc/rc && cron files, changes in SUID status, the writability of users home directories and startup files (.profile, .cshrc, etc), and a few others as well. It also includes the Kuang expert system, written by Bob Baldwin, that takes a set of rules and tries to determine if your system can be compromised. For a more complete list of all of the checks, look at the file "release.notes" or "cops.report." All of the programs merely warn the user of a potential problem -- COPS DOES NOT ATTEMPT TO CORRECT OR EXPLOIT ANY OF THE POTENTIAL PROBLEMS IT FINDS! COPS either mails or creates a file (user selectable) of any of the problems it finds while running on your system. And because COPS does not correct potential hazards it finds, it does _not_ have to be run by a privileged account (i.e. root or whomever.) The only security check that should be run by root to get maximum results is the SUID checker; although it can be run as an unprivileged user, to find all the SUID files in a system, it should be run as root. The programs are mostly written in Bourne shell (using awk, sed, grep, etc. as well) for (hopefully) maximum portability. A few are written in C for speed (most notably the Kuang expert system and for implementing fast user home directory searching), but the entire system should run on most BSD and System V machines with a minimum of tweaking. 2) What COPS is _not_ ---------------------- COPS merely provides a method of checking for common procedural errors. It is not meant to be used as a replacement for common sense or user/ operator/administrative alertness! Think of it as an aid, a first line of defense -- not as an impenetrable shield against security woes. An experienced wrong-doer could easily circumnavigate _any_ protection that COPS can give. However, COPS _can_ aid a system in protecting its users from (their own?) ignorance, carelessness, and the occasional malcontent user. Once again, COPS does not correct any errors found. There are several reasons for this; first and foremost, computer security is a slippery beast. What is a major breach in security at one site may be a standard policy of openness at another site. Additionally, in order to correct all problems it finds, it would have to be run as a privileged user; and I'm not going to go into the myriad problems of running SUID shell scripts (See the bibliography at the end of the technical report "cops.report" for pointer to a good paper on this subject by Matt Bishop.) At this time, COPS does not attempt to detect bugs or features (such as infamous ftpd, fingerd, etc) that may cause security problems. Although this may change in future versions, the current line of reasoning to avoid general publication of programs such as these is that all the problems that COPS detects can be repaired on any system it runs on. However, many bugs can be readily repaired only be having source code (and possibly a good vendor to repair it), and many sites would have serious troubles if they suddenly discovered unrepairable problems that could compromise their livelihood. It is possible that a more controlled release may come out in the future to address such problems (but don't mail to me about getting them -- unless you want to help write them! :-)) 3) How to Configure/Install COPS --------------------------------- System V users, other Non-BSD systems, or sites with commands in strange places -- you may have to run a shell script called "reconfig" to change the pathnames of the executable programs called when using COPS. If your system does not use the paths listed in the shell scripts, try running "reconfig". This will reconfigure the pathnames used by COPS to your system; COPS should run fine then, if it can find all of the commands (reconfig should tell you if it cannot.) If trouble persists, you will have to change the paths to your executable files (awk, sed, etc) by hand. A drag, I know. This all may change without notice, anyway. 4) Running COPS for the 1st Time --------------------------------- Since most of COPS was written and tested mostly on just a few machines (at least compared to the total number out there!), you may have significant differences that were not anticipated -- unfortunately, or fortunately, UNIX is not quite standardized yet. COPS is run by simply typing "cops". "cops" is a Bourne shell script that runs each of the smaller programs, accumulates the output, and then mails or stores any results. "suid.chk", since it can take a long, long time to run, is the only "standalone" program in the COPS package; look at suid.man for more information. To run COPS for the first time, I suggest doing the following: -- Look at the disclaimer, file "disclaimer". Don't sue me. Actually, this holds for all the times you use COPS (1/4 :-)) -- Type "make" to create the formatted manual pages, to compile the C programs, and to make the shell programs executable. -- Read the technical report to understand what COPS is doing and what is going on -- "cops.report". This gives a look at the philosophies, design notes, and finally a general outlay of the COPS system and UNIX security. -- Next, change lines 36 and 37 in the "cops" shell file from: SECURE=/usr/foo/bar SECURE_USERS="foo@bar.edu" SECURE should be the same directory as the directory that contains the cops programs, and SECURE_USERS should be your own login id, or to whomever you designate as the recipient of the output (your enemy?) -- Set "MAIL=NO" in the "cops" shell file (line 22). This will prevent a large mail file from choking the mailer. All of the output will be put into a file called "report.$$", where $$ is the process number that cops had while running. -- Look at the directory and file configuration files, "dir.chklst" and "file.chklst". They contain critical files that COPS checks for world writability. Add or delete whatever files/directories you wish; if a file doesn't exist, COPS will effectively ignore it. (If you don't know or are uncertain what files/directories are important, what is given there is a good set to start with on most systems. -- You may wish to comment out the password checker (line 72 in the "cops" shell file). Although this is not necessary, it will speed up the package if you wish for immediate gratification. You should be ready to roll. COPS is run by simply typing "cops" (you may wish to put in the background....) If you followed my advice and set "MAIL=NO" in the "cops" shell file, after COPS is finished, there will be a report file created "report.$$" that lists the time and machine it was created on. Otherwise, COPS mails the report to the user listed on the line 'SECURE_USERS="foo@bar.edu"'. There is a file "warnings", which contains most of the warning messages COPS uses, as well as a brief explanation of how the message might pertain to your system as well as how to "fix" any problem. NOTE: Change the shell script "cops" to reflect who you want the output sent to and where the location of the program is BEFORE running the program. 5) Continued Use of COPS ------------------------- Once you are satisfied that COPS indeed does something useful (hopefully this will occur :-)), a good way to use it is to run it on at least a semi-regular basis. Even if it doesn't find any problems immediately, the types of problems and holes it can detect are of the sort that can pop up at any given time. One way of running COPS might be to run it as an "at" job or by cron. I highly advise that whatever directory COPS is placed in is to be readable, writable, and executable only by the owner (typing "chmod 700 /usr/foo/bar" or whatever the name is will do this) of the directory. This is to prevent prying eyes from seeing any security problems your site may have. Even if you don't think of them as important, someone else might come around and change your mind. Since COPS is fairly configurable, an intruder could easily change the paths and files that COPS checks for, hence making it fairly worthless. Again, this comes back to the point that COPS is only a tool -- don't put down your defensive shields merely because COPS says "all clear". If this sounds paranoid, it is! Security people are traditionally paranoid, for a reason.... In any case, it is probably not a good idea to advertise any (even) potential weaknesses. After running COPS, if any warnings are given that compromise any individual users accounts (such as world writable .profiles, home directories, guessed passwords, etc.), and the warnings are not corrected immediately (or you are not sure whether or not it is worth hassling the user to change it), try this: Edit the file "init_kuang", and add the compromised user(s) uids and groups in their respective target lines (below lines 21 and 27, respectively), and run kuang again to see if the users can compromise the entire system. You may change your mind about not thinking they are a problem! In addition, kuang does not have to have "root" as a target (the last line). Try putting in system administrators or other powerful figures to see if they are in danger as well. 6) Disclaimer and End Notes ---------------------------- COPS is meant to be a tool to aid in the tightening of security, not as a weapon to be used by an enemy to find security flaws in a system. It may be argued that allowing anyone to have access to such a tool may be dangerous. But hopefully the overall benefit for systems that use this package will outweigh any negative impact. To me it is akin to a law enforcement problem -- that although telling the public how to break into a house may foster a slight rise in break-in attempts, the overall rise in public awareness on how to defend themselves would actually result in a drop in break-ins. The crackers with black hats already know how to crush system defenses and have similar tools, I'm sure. It's time we fought back. COPS is not the final answer to anyone's security woes. You can use the system as long as you realize that COPS has no warranty, implied or otherwise, and that any problems that you may have with it are not my or any of the other authors fault. I will certainly attempt to help you solve them, if I am able, but please don't try to sue me or anything... Let's all make COPS a collective effort that helps people, ok? If you have ideas for additional programs, or a better implementation of any of the programs here, I would be very interested in seeing them. COPS was the work of a LOT of people, both in writing code and in the testing phase (thanks beta testers!). For a complete list of contributors, look at the file "XTRA_CREDIT". So good luck, and I hope you find COPS useful as we plunge into UNIX of the 1990's. dan farmer January 31, 1989 # include "disclaimer.h" -------------------- Cut here for disclaimer ------------------------- /*********************************************************************** * Copyright 1989, 1990 by Purdue University and Dan Farmer. All rights * reserved. Some individual files may be covered by other copyrights. * * This material was written and compiled by Dan Farmer while at Purdue * University in 1989 and 1990, under the direction and sponsorship of * Professor Gene Spafford. Other material was contributed as noted * elsewhere. * Redistribution and use in source and binary forms are permitted * provided that this entire copyright notice is duplicated in all such * copies, and that any documentation, announcements, and other * materials related to such distribution and use acknowledge that the * software was developed at Purdue University, W. Lafayette, IN. No * charge, other than an "at-cost" distribution fee, may be charged for * copies, derivations, or distributions of this material without the * express written consent of the copyright holders. Neither the * name of the University, the name of the author, nor the name of this * project's sponsor may be used to endorse or promote products * derived from this material without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. ************************************************************************/ ---------------------- End disclaimer ------------------------------- SHAR_EOF echo shar: extracting cops/XTRA_CREDIT '(2063 characters)' cat << \SHAR_EOF > cops/XTRA_CREDIT Code credits are where code credits are due. If I miss anyone, please forgive (and notify) me! Gene Spafford -- overall design help. Robert Baldwin -- the kuang package. Craig Leres, Seth Alford, Roger Southwick, Steve Dum, and Rick Lindsley all get credit for the password guessing program. Prentiss Riddle -- the suid checker. And of course lots of credit goes to my great Beta-release sweatshop team; especially Adri Verhoef for tightening up lots of my crummy code (cops, group.chk, root.chk, is_writable, dev.chk, dir.chk & file.chk among others), Steve Romig for good ideas _and_ letting me use a system V machine to test on (how many people do you know that would let you test a security system on their system with no strings attached!) Jason Levitt, Jim Kimble, Jim Rowan, Stefan Vorkoetter, Judy Scheltema, Pete Troxell (all the Sun C2 stuff....), Dennis Conley, and of course John Sechrest. Tony Petrost pointed out some of my incorrect assumptions and helped fix cron.chk. Kudos also to Bruce Spence for giving me some good implementation ideas at LISA II. If strings is not available to you, a version is available on uunet; also a nifty install program written by Kevin Braunsdorf that can be used as a super directory/file mode checker/security device should be available soon in comp.sources.unix (these programs large sizes preculudes their inclusion in COPS, but I recommend looking into them.) Both can be gotten via anonymous ftp. Strings is in comp.unix.sources directory, install should be in the same. Everything else not explicitely mentioned in the COPS.report.ms paper or here was written by me. Not mentioned execpt in the source code are some small changes made by myself to make everything fit in as a cohesive whole; I tried to make comments in the source code if I changed it (never to drastic in any case.) For a good story on the subject, you might want to read _The Cuckoo's Egg_, by Clifford Stoll. This is a true tale of a sysadmin's fight against beaurocracy and a hacker (the bad kind.) Good stuff. SHAR_EOF echo shar: extracting cops/chk_strings '(1559 characters)' cat << \SHAR_EOF > cops/chk_strings #!/bin/sh # # Usage: chk_strings filename # # This will check pathnames inside executable files for writability, # using the "strings" command and egrep. # # I have identified three basic types of strings containing paths to files: # 1) # /path1/path2/file /* standard */ # 2) # '/path1/path2/file' /* standard, in single quotes */ # 3) # :/path1/file1:/path2/file2 /* a path for searching */ # # For the first two, I simply test the writability; for the last, I # parse it into seperate paths and check each one in turn. # AWK=/bin/awk EGREP=/usr/bin/egrep TEST=/bin/test ECHO=/bin/echo SORT=/usr/bin/sort STRINGS=/usr/ucb/strings if test ! -s $STRINGS then exit 0 fi if test $# -eq 0 then $ECHO "Usage: $0 file" exit 2 fi while test 0 -ne $# do # $ECHO Checking $1... # get the first two types: test_files=`$STRINGS $1 | $EGREP "/.*/" | $AWK '{for (i=1;i<=NF;i++) if ((res=substr($i,1,1))=="/") printf("%s\n",$i) else if ((res!=":") && (res=substr($i,2,1))=="/") printf("%s\n",substr($i,2,length($i)-2))}'| $SORT -u` # and type number three, parse into separate paths as well: paths=`$STRINGS $1|$EGREP "/.*/" |$AWK '{for (i=1;i<=NF;i++) if ((substr($i,1,1)==":") && (substr($i,2,1))=="/") printf("%s",$i)}'` paths=`$ECHO $paths | $AWK -F: '{for (i=1;i<=NF;i++) printf("%s\n",$i)}'| $SORT -u` all_files=$test_files$paths for i in $all_files do if ./is_writable $i then $ECHO " Warning! File $i (inside root executed file $1) is _World_ writable!" fi done shift done # end of script SHAR_EOF echo shar: extracting cops/cops '(2872 characters)' cat << \SHAR_EOF > cops/cops #!/bin/sh # # Usage: cops # # This will change into the $SECURE directory, ensure all the security # programs (listed below) indeed do exist, and run all of the security # programs. If any of the programs find any security problems, they # send mail to everyone in the $SECURE_USERS list. It then destroys all # temporary files, and exits the program. Programs that are run # (besides this one): # # root.chk dev.chk dir.chk # file.chk group.chk home.chk # rc.chk passwd.chk pass.chk # user.chk cron.chk # The U-kuang system runs these additional programs: # init_kuang kuang addto # clearfiles filewriters members # # If this is changed to "NO", the report that cops creates # will not be deleted and the results will not be mailed to anyone. MMAIL="YES" # Where is everyone? ECHO=/bin/echo TEST=/bin/test RM=/bin/rm CAT=/bin/cat MAIL=/bin/mail DATE=/bin/date CHMOD=/bin/chmod ###################### # Change these lines! ###################### SECURE=/usr/foo/bar SECURE_USERS="foo@bar.edu" ###################### SECURE_PROGRAMS="root.chk dev.chk dir.chk file.chk group.chk \ home.chk rc.chk passwd.chk pass.chk \ cron.chk user.chk init_kuang kuang addto \ clearfiles filewriters members" if $TEST ! -d "$SECURE" then $ECHO "Error -- Security directory $SECURE doesn't exist" exit 1 fi $CHMOD 700 $SECURE cd $SECURE for i in $SECURE_PROGRAMS do if $TEST ! -s "$i" then $ECHO "Error -- Security program $i doesn't exist" exit 1 fi done $SECURE/root.chk > $SECURE/result.$$ 2> /dev/null $SECURE/dev.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/dir.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/file.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/rc.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/cron.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/group.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/home.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/passwd.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/pass.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/user.chk >> $SECURE/result.$$ 2> /dev/null $SECURE/kuang > /dev/null 2> /dev/null if $TEST -s "$SECURE/Success" then $CAT $SECURE/Success >> $SECURE/result.$$ fi $RM -f $SECURE/Success # # Mail the final report to $SECURE_USERS and remove the evidence if $TEST -s "$SECURE/result.$$" then $ECHO ATTENTION: > $SECURE/report.$$ $ECHO "Security Report for "`$DATE` >> $SECURE/report.$$ # # Thanks to arbitron for this idea... HOSTNAME=`/bin/sh -c "/bin/uname -n || /usr/bin/uuname -l || /bin/hostname" 2>&-` $ECHO "from host $HOSTNAME" >> $SECURE/report.$$ $ECHO >> $SECURE/report.$$ $ECHO >> $SECURE/report.$$ $CAT $SECURE/result.$$ >> $SECURE/report.$$ if $TEST "$MMAIL" = "YES" then $MAIL $SECURE_USERS < $SECURE/report.$$ $RM -f $SECURE/report.$$ fi fi $RM -f $SECURE/result.$$ # end it all.... exit 0 SHAR_EOF echo shar: extracting cops/cron.chk '(2248 characters)' cat << \SHAR_EOF > cops/cron.chk #!/bin/sh # # Usage: cron.chk # # This checks pathnames and files inside the cron files /usr/lib/crontab # for writability. # # Mechanism: The commands inside the file /usr/lib/crontab are executed # by root. This shell script greps for commands/paths that begins with # "/" and takes each potential problem-string and uses the program # "is_writable" to determine if it is world writable. All results are # echoed to standard output. # In addition, it throws away everything that has a /tmp, /dev/null, or # tty in the writable string, and everything after a ">"; e.g. if crontab # is writing to a file it doesn't care. # # Cron.chk will try to find a file in /usr/lib/crontab first (bsd), # and then if it isn't there, it will look in the any alternate # possible locations next -- right now, /usr/spool/cron/crontab -- to # see if a directory exists, and, if it does, it checks all the cron # files in turn. # # WARNING! # # Spurious messages can occur; a more stringent method (if perhaps less # careful of a check) would be to test just the 6th field, instead of # all the fields after the fifth. Also throwing away /tmp, etc. could # be a mistake. # # Location of stuff: AWK=/bin/awk SED=/bin/sed ECHO=/bin/echo EGREP=/usr/bin/egrep TEST=/bin/test CAT=/bin/cat # Possible location of crontab file: cron=/usr/lib/crontab # alternate reality locations of crontab file: alt_cron="/usr/spool/cron/crontabs" if $TEST ! -s $cron then cron="" for i in "$alt_cron" do if $TEST -d $i then cron=`$ECHO $alt_cron/*` fi done if $TEST -z "$cron" then exit fi fi # finally, do the checking -- maybe for one, maybe for lots of # cron-ites: for cron_kid in $cron do # A typical crontab entry might look something like this: # # 0,15,30,45 * * * * /bin/sh /usr/adm/newsyslog # risky_stuff=`$AWK '{for (i=6;i.*//' | $AWK '{for (i=1;i<=NF;i++) if (substr($i,1,1)=="/") print $i}'` for i in $risky_stuff do if $TEST `echo $i | $EGREP "/tmp|/dev/null|tty"` then continue fi if ./is_writable $i then $ECHO "Warning! $i (in $cron_kid) is World writable!" fi done done # for all the cron-kids SHAR_EOF echo shar: extracting cops/dev.chk '(2691 characters)' cat << \SHAR_EOF > cops/dev.chk #!/bin/sh # # dev.chk [-g] # # This shell script checks the permissions of /dev/mem, /dev/kmem, and # all devs listed in the file /etc/fstab (the "mount" command would be # a preferable way of getting the file system name, but the syntax of the # output is variable from machine to machine), and flags them if they are # readable by using the "is_readable" command. It also checks for # unrestricted NFS mountings. By default, dev_check will flag devs only # if world readable or writable. The -g option tells it to print out devs # that are also group readable/writable. # AWK=/bin/awk LS=/bin/ls ECHO=/bin/echo TEST=/bin/test # locations of vital stuff... mtab=/etc/fstab exports=/etc/exports # Optional List of assorted files that shouldn't be # readable (mix 'n match; add to the list as desired): opt_files='/usr/adm/sulog /etc/btmp /.netrc' group=no if $TEST $# -gt 1 then $ECHO "Usage: $0 [-g]" exit 2 fi if $TEST $# -eq 1 then if $TEST "X$1" = "X-g" then group=yes else $ECHO "Usage: $0 [-g]" exit 2 fi fi # Testing filesystems and devices for improper read/write permissions... # NEVER want these readable! always_crit_files="/dev/kmem /dev/mem" # grab devices from "/etc/fstab".... # # Format of /etc/fstab: /dev/zd0e +junk(:-) # # Or NFS mounted: uther:/usr/spaf +junk(:-) # # Not sure what to do with NFS stuff, so we'll ignore it. Seems that # this doesn't tell us anything about what we want anyway.... crit_devs=$always_crit_files" "`$AWK 'index($1, "/")==1 {print $1}' $mtab` # Alternate way; grab devices from "mount [-p]".... # Format of output from mount (some machines use -p option, some # don't. Check your local man page... : # crit_devs=$always_crit_files" "`/etc/mount -p|$AWK 'index($1, "/")==1 # {print $1} \ # }'` # # However, do check for single line entries in /etc/exports: if $TEST -s $exports then $AWK '{while(getline >0) if ($0 !~ /^#/ && NF == 1) \ printf("Warning! NFS file system %s exported with no restrictions.\n",$0)}' $exports fi for i in $crit_devs do if ./is_readable $i then $ECHO Warning! $i is _World_ readable! fi if ./is_writable $i then $ECHO Warning! $i is _World_ writable! fi if $TEST "$group" = "yes" then if ./is_readable -g $i then $ECHO Warning! $i is group readable! fi if ./is_writable -g $i then $ECHO Warning! $i is group readable! fi fi done # Do the mix 'n match assorted no-read files: for i in $opt_files do if ./is_readable $i then $ECHO Warning! $i is _World_ readable! fi if $TEST "$group" = "yes" then if ./is_readable -g $i then $ECHO Warning! $i is group readable! fi fi done # end of script SHAR_EOF echo shar: extracting cops/dir.chk '(1459 characters)' cat << \SHAR_EOF > cops/dir.chk #!/bin/sh # # dir.chk [-g] # # This shell script checks the permissions of all directories listed # in the configuration file "dirs.755.dirlist", and flags them if they # are world-writable. The -g option tells it to print out directories # that are also group writable. See the config file for the format of # the configuration file. # # Mechanism: This shell script simply takes each line from the # configure file and uses the "is_writable" program to check if any of # the directories in question are writable by world/group. All results # are written to standard output. # AWK=/bin/awk TEST=/bin/test ECHO=/bin/echo dir_list=dir.chklst group=no if $TEST $# -gt 1 then $ECHO "Usage: $0 [-g]" exit 2 fi if $TEST $# -eq 1 then if $TEST "X$1" = "X-g" then group=yes else $ECHO "Usage: $0 [-g]" exit 2 fi fi # Testing directories in file $dir_list for potential write mode problems # Read from $dir_list (e.g. "dirs.755.dirlist") what dirs to check. # # Comments are lines starting with a "#". # while read i do case $i in "#"* | "" ) continue;; esac # exit code 0 is writable, 1 is not dirs=`$ECHO $i` for d in $dirs do if ./is_writable $d then echo "Warning! Directory $d is _World_ writable!" fi done if $TEST "$group" = "yes" then for d in $dirs do if ./is_writable -g $d then echo "Warning! Directory $d is group writable!" fi done fi done < $dir_list # end of script SHAR_EOF echo shar: extracting cops/dir.chklst '(377 characters)' cat << \SHAR_EOF > cops/dir.chklst # # This lists any/all sensitive files the administration wants to ensure # non-writability of. Comments are lines starting with a "#". # # Lines are of the format: # # /path/to/file # / # /* /etc /usr /bin /usr/spool /usr/adm /usr/etc /usr/lib /usr/local /usr/local/bin /usr/local/lib /usr/bin /usr/etc /usr/spool/mail /usr/spool/news /usr/spool/uucp /usr/spool/at /Mail SHAR_EOF echo shar: extracting cops/disclaimer '(1468 characters)' cat << \SHAR_EOF > cops/disclaimer /*********************************************************************** * Copyright 1989, 1990 by Purdue University and Dan Farmer. All rights * reserved. Some individual files may be covered by other copyrights. * * This material was written and compiled by Dan Farmer while at Purdue * University in 1989 and 1990, under the direction and sponsorship of * Professor Gene Spafford. Other material was contributed as noted * elsewhere. * Redistribution and use in source and binary forms are permitted * provided that this entire copyright notice is duplicated in all such * copies, and that any documentation, announcements, and other * materials related to such distribution and use acknowledge that the * software was developed at Purdue University, W. Lafayette, IN. No * charge, other than an "at-cost" distribution fee, may be charged for * copies, derivations, or distributions of this material without the * express written consent of the copyright holders. Neither the * name of the University, the name of the author, nor the name of this * project's sponsor may be used to endorse or promote products * derived from this material without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. ************************************************************************/ SHAR_EOF echo shar: extracting cops/file.chk '(1423 characters)' cat << \SHAR_EOF > cops/file.chk #!/bin/sh # # file.chk [-g] # # This shell script checks the permissions of all files listed # in the configuration file "files.chklst", and flags them if they # are world-writable. The -g option tells it to print out files # that are also group writable. See the config file the format of # the configuration file. # # Mechanism: This shell script simply takes each line from the # configure file and uses the "is_writable" program to check if any of # the files in question are writable by world/group. All results # are written to standard output. # AWK=/bin/awk TEST=/bin/test ECHO=/bin/echo file_list=file.chklst group=no if $TEST $# -gt 1 then $ECHO "Usage: $0 [-g]" exit 2 fi if $TEST $# -eq 1 then if $TEST "X$1" = "X-g" then group=yes else $ECHO "Usage: $0 [-g]" exit 2 fi fi # Checking files in file $file_list for potential write mode problems # Read from $file_list (e.g. "files.chklst") what files to check. # # Comments are lines starting with a "#". # while read i do case $i in "#"* | "" ) continue;; esac # exit code 0 is writable, 1 is not files=`$ECHO $i` for f in $files do if ./is_writable $f then echo "Warning! File $f is _World_ writable!" fi done if $TEST "$group" = "yes" then for f in $files do if ./is_writable -g $f then echo "Warning! File $f is group writable!" fi done fi done < $file_list # end of script SHAR_EOF echo shar: extracting cops/file.chklst '(523 characters)' cat << \SHAR_EOF > cops/file.chklst # # This lists any/all sensitive files the administration wants to ensure # non-writability of. Comments are lines starting with a "#". # # Lines are of the format: # # /path/to/file # /.* # /.login # /.profile # /.cshrc # /.crontab # /.rhost /etc/* # /etc/passwd # /etc/group # /etc/inittab # /etc/rc # /etc/rc.local # /etc/rc.boot # /etc/hosts.equiv # /etc/profile # /etc/syslog.conf # /etc/export /usr/etc/yp* /usr/lib/crontab /usr/lib/aliases /usr/lib/sendmail # /usr/spool/L.sys # /usr/adm/sulog /usr/adm/* /bin/* SHAR_EOF echo shar: extracting cops/group.chk '(5099 characters)' cat << \SHAR_EOF > cops/group.chk #!/bin/sh # # group.chk # # Check group file -- /etc/group -- for incorrect number of fields, # duplicate groups, non-alphanumeric group names, and non-numeric group # id's. # # Awk part based on _passwd_ from _The AWK Programming Language_, page 78 # # Mechanism: Group.check uses awk to ensure that each line of the group # has 4 fields, as well as examining each line for any duplicate groups or # any duplicate user id's in a given group by using "sort -u" to ferret # out any duplications. It also checks to make sure that the password # field (the second one) is a "*", meaning the group has no password (a # group password is usually not necessary because each member listed on # the line has all the privilages that the group has.) All results are # echoed to standard output. Finally it ensures that the group names # are alphanumeric, that the group id's are numeric, and that there are # no blank lines. For yellow pages groups, it does the same checking, # but in order to get a listing of all members of the groups, it does a # "ypcat group > ./$$" and uses that temporary file for a groupfile. # It removes the tmp file after using it, of course. # The /etc/group file has a very specific format, making the task # fairly simple. Normally it has lines with 4 fields, each field # separated by a colon (:). The first field is the group name, the second # field is the encrypted password (an asterix (*) means the group has no # password, otherwise the first two characters are the salt), the third # field is the group id number, and the fourth field is a list of user # ids in the group. If a line begins with a plus sign (+), it is a yellow # pages entry. See group(5) for more information. # # AWK=/bin/awk SED=/bin/sed ECHO=/bin/echo TEST=/bin/test SORT=/usr/bin/sort UNIQ=/usr/bin/uniq YPCAT=/usr/bin/ypcat RM=/bin/rm # Used for Sun C2 security group file. FALSE (default) will flag # valid C2 group syntax as an error, TRUE attempts to validate it. # Thanks to Pete Troxell for pointing this out. C2=FALSE etc_group=/etc/group yp_group=./$$ yp=false if $TEST -f $YPCAT then if $TEST -s $YPCAT then $YPCAT group > $yp_group if $TEST $? -eq 0 then yp=true fi fi fi # Testing $etc_group for potential problems.... # First line is for a yellow pages entry in the group file. # It really should check for correct yellow pages syntax.... $AWK 'BEGIN {FS = ":" } { if (substr($1,1,1) != "+") { \ if ($0 ~ /^[ ]*$/) { printf("Warning! Group file, line %d, is blank\n", NR) } else { if (NF != 4) { printf("Warning! Group file, line %d, does not have 4 fields: %s\n", NR, $0) } \ if ($1 !~ /[A-Za-z0-9]/) { printf("Warning! Group file, line %d, nonalphanumeric user id: %s\n", NR, $0) } \ if ($2 != "" && $2 != "*") { if ("'$C2'" != "TRUE") printf("Warning! Group file, line %d, group has password: %s\n", NR, $0) else { if ("#$"$1 != $2) printf("Warning! Group file, line %d, group has invalid field for C2:\n%s\n", NR, $0) } \ } \ if ($3 !~ /[0-9]/) { printf("Warning! Group file, line %d, nonnumeric group id: %s\n", NR, $0) }}}} ' $etc_group # # Look for duplications in groups in $etc_group # result=`$AWK -F: '{print $1}' $etc_group | $SORT |$UNIQ -d` if $TEST "$result" then $ECHO "Warning! Duplicate Group(s) found in $etc_group:" $ECHO $result fi # # Next, check for duplicate users in a group in /etc/group. Let # awk do all the work (thanks, adri!) # # Ignore all groups with less than two members. # awk -F: ' split($4, users, ",") > 1 { ct = 0 for (i in users) { curuser = users[i] for (j in users) { if (j > i && curuser == users[j]) { if (ct++ == 0) print "Warning! Group "$1" has duplicate user(s):" print curuser } } } } ' $etc_group # # Test yellow pages groups as well if $TEST "$yp" = "true" then $AWK 'BEGIN {FS = ":" } { if ($0 ~ /^[ ]*$/) { printf("Warning! YGroup file, line %d, is blank\n", NR) } else { if (NF != 4) { printf("Warning! YGroup file, line %d, does not have 4 fields: %s\n", NR, $0) } \ if ($1 !~ /[A-Za-z0-9]/) { printf("Warning! YGroup file, line %d, nonalphanumeric user id: %s\n", NR, $0) } \ if ($2 != "" && $2 != "*") { printf("Warning! YGroup file, line %d, group has password: %s\n", NR, $0) } \ if ($3 !~ /[0-9]/) { printf("Warning! YGroup file, line %d, nonnumeric group id: %s\n", NR, $0) }}} ' $yp_group # # Look for duplications in groups in yellow pages groups # yresult=`$AWK -F: '{print $1}' $yp_group | $SORT |$UNIQ -d` if $TEST "$yresult" then $ECHO "Warning! Duplicate Group(s) found in yellow pages group:" $ECHO $result fi # # Next, check for duplicate users in a group in yellow groups. Let # awk do all the work (thanks, adri!) # ignore all groups with one member. # awk -F: ' split($4, users, ",") > 1 { ct = 0 for (i in users) { curuser = users[i] for (j in users) { if (j > i && curuser == users[j]) { if (ct++ == 0) print "Warning! YGroup "$1" has duplicate user(s):" print curuser } } } } ' $yp_group fi $RM -f $yp_group # end SHAR_EOF echo shar: extracting cops/init_kuang '(773 characters)' cat << \SHAR_EOF > cops/init_kuang # /* Copyright 1985 Robert W. Baldwin */ # /* Copyright 1986 Robert W. Baldwin */ ############################################### # Kuang: Rule based computer security checker. ############################################### CAT=/bin/cat ECHO=/bin/echo # # Initialization. # ./clearfiles # # First setup what we have access to. # The uids.k file must include the user 'OTHER' meaning the world access bits. # Add any other UIDs accessible to the attacker (e.g., ftp, daemon). # # Directly accessible user IDs. $CAT >uids.k <gids.k </dev/tty ./addto uids root DO ANYTHING SHAR_EOF echo shar: extracting cops/kuang '(5967 characters)' cat << \SHAR_EOF > cops/kuang # /* Copyright 1985 Robert W. Baldwin */ # /* Copyright 1986 Robert W. Baldwin */ # # Jan 1990, Ported to bourne shell from Csh. Dan Farmer # # Took out some comments, combined four of Bob's shell # scripts into one (the target script remains separate for # easy editing of targets.) More or less a straight line # for line translation; a rewrite that goes for speed will # come later. Maybe just rewrite it in C. Yeah, that's it.... ############################################### # Kuang: Rule based computer security checker. ############################################### # commands used.... SH=/bin/sh MV=/bin/mv TEST=/bin/test ECHO=/bin/echo AWK=/bin/awk RM=/bin/rm # Initialization. $SH ./init_kuang # Main loop # $ECHO Starting main loop #>/dev/tty while $TEST -f uids.n -o -f gids.n -o -f files.n do if $TEST -f uids.n ; then $MV uids.n uids.x # Process a list of uids from stdin. # Usage: douids username comments $ECHO Called douids #>/dev/tty i=1 while $TEST "1" do nextuid=`$AWK '{if (NR=="'$i'") print $0}' uids.x` i=`expr $i + 1` if $TEST -z "$nextuid" ; then break; fi user=`$ECHO $nextuid | $AWK '{print $1}'` $ECHO " " User $user #>/dev/tty # Rules mapping uids to files. # next=`$ECHO $nextuid | $AWK '{for (i=2;i<=NF;i++) printf("%s ", $i)}'` ./addto files /etc/passwd replace grant $user $next ./addto files /usr/lib/aliases replace trojan $user $next # hsh = home sweet home = home directory of $user hsh=`./tilde $user` if $TEST -f $hsh/.rhosts ; then ./addto files $hsh/.rhosts write grant $user $next fi if $TEST -f $hsh/.login ; then ./addto files $hsh/.login replace trojan $user $next fi if $TEST -f $hsh/.cshrc ; then ./addto files $hsh/.cshrc replace trojan $user $next fi if $TEST -f $hsh/.profile ; then ./addto files $hsh/.profile replace trojan $user $next fi if $TEST "$user" = "root" ; then if $TEST -f /usr/lib/crontab ; then ./addto files /usr/lib/crontab replace create supershell $next else ./addto files /usr/spool/cron/crontabs replace create supershell $next fi ./addto files /etc/rc replace trojan $user $next ./addto files /etc/rc.local replace trojan $user $next fi if $TEST "$user" != "root" ; then ./addto files /etc/hosts.equiv replace allow rlogin $next fi if $TEST "$user" != "root" -a -f /etc/hosts.equiv -a -s /etc/hosts.equiv then ./addto files /etc/hosts replace fake HostAddress $next fi done fi if $TEST -f gids.n ; then $MV gids.n gids.x $ECHO Called dogids #>/dev/tty i=1 while $TEST "1" do nextgid=`$AWK '{if (NR=="'$i'") print $0}' gids.x` i=`expr $i + 1` if $TEST -z "$nextgid" ; then break; fi group=`$ECHO $nextgid | $AWK '{print $1}'` $ECHO " " Group $group #>/dev/tty # Rules mapping gids to uids. # next=`$ECHO $nextgid | $AWK '{for (i=2;i<=NF;i++) printf("%s ", $i)}'` use=`./members $group` for user in $use do ./addto uids $user grant $group $next done # Rules mapping gids to files. # ./addto files /etc/group replace grant $group $next done fi if $TEST -f files.n ; then $MV files.n files.x # A list of file names is read from successive lines of stdin. # Each file is examined for ways to access it. # The input format is: # # The is either "write" or "replace". # $ECHO Called dofiles. #>/dev/tty i=1 while $TEST "1" do nextfile=`$AWK '{if (NR=='"$i"') print $0}' files.x` i=`expr $i + 1` if $TEST -z "$nextfile" ; then break; fi file=`$ECHO $nextfile | $AWK '{print $1}'` mode=`$ECHO $nextfile | $AWK '{print $2}'` $ECHO " File $file, mode $mode" #>/dev/tty # Rules converting filename goals into UserName or GroupName goals. # next=`$ECHO $nextfile | $AWK '{for (i=3;i<=NF;i++) printf("%s ", $i)}'` writers=`./filewriters $file` numwriters=`$ECHO $writers | $AWK '{print NF}'` if $TEST "$numwriters" = "3" ; then owner=`$ECHO $writers | $AWK '{print $1}'` group=`$ECHO $writers | $AWK '{print $2}'` other=`$ECHO $writers | $AWK '{print $3}'` $ECHO " Writers are $owner $group $other" #>/dev/tty ./addto uids $owner $mode $file $next if $TEST "$group" != "NONE" ; then ./addto gids $group $mode $file $next fi if $TEST "$other" != "NONE" ; then ./addto uids $other $mode $file $next fi else $ECHO " $file does not exist" #>/dev/tty continue fi # Rules converting filename goals into other filename goals. # if $TEST "$mode" != "replace" ; then continue fi parent=`$ECHO $file | $AWK -F/ '{if (NF == 2) { printf("/%s", $1)} else if (NF>2) {for (i=2;i/dev/tty $ECHO ", " basename is $basename #>/dev/tty if $TEST -n "$parent" ; then ./addto files $parent write replace $basename $next fi done fi done # destroy the evidence.... Need "Success" file for report, though. $RM files.? gids.? uids.? SHAR_EOF echo shar: extracting cops/makefile '(2721 characters)' cat << \SHAR_EOF > cops/makefile # Simple Makefile for the COPS system; compiles, and chmods # the programs. # # make all -- makes everything # make -- make a given program EXECUTABLE = home.chk user.chk is_readable is_writable pass.chk \ addto clearfiles filewriters members tilde C_SRC = home.chk.c user.chk.c is_readable.c is_writable.c pass.c \ addto.c clearfiles.c filewriters.c members.c tilde.c SHELL_PROGS= chk_strings root.chk dev.chk dir.chk cron.chk \ file.chk cops group.chk rc.chk passwd.chk \ suid.chk kuang init_kuang reconfig SUPPORT = dir.chklst file.chklst makefile stop.sample \ COPS.READ.1ST Beta.info SUID.README MANIFEST DOCS = COPS.report.ms suid.man.ms kuang.man.ms MAN = cops.1 cron.1 dev.1 dir.1 file.1 group.1 passwd.1 \ is_able.1 home.1 user.1 pass.1 CFLAGS = -O ROFFLAGS = -ms # # Where the programs are.... # CHMOD=/bin/chmod MKDIR=/bin/mkdir CP=/bin/cp CC=/bin/cc NROFF=/usr/bin/nroff # make all all: $(EXECUTABLE) $(DOCS) $(MAN) $(CHMOD) 700 $(SHELL_PROGS) # make the programs addto: src/addto.c $(CC) $(CFLAGS) -o addto src/addto.c clearfiles: src/clearfiles.c $(CC) $(CFLAGS) -o clearfiles src/clearfiles.c filewriters: src/filewriters.c $(CC) $(CFLAGS) -o filewriters src/filewriters.c members: src/members.c $(CC) $(CFLAGS) -o members src/members.c home.chk: src/home.chk.c $(CC) $(CFLAGS) -o home.chk src/home.chk.c user.chk: src/user.chk.c $(CC) $(CFLAGS) -o user.chk src/user.chk.c is_readable: src/is_readable.c $(CC) $(CFLAGS) -o is_readable src/is_readable.c is_writable: src/is_writable.c $(CC) $(CFLAGS) -o is_writable src/is_writable.c pass.chk: src/pass.c $(CC) $(CFLAGS) -o pass.chk src/pass.c tilde: src/tilde.c $(CC) $(CFLAGS) -o tilde src/tilde.c # 'roff out those docs COPS.report.ms: docs/COPS.report $(NROFF) $(ROFFLAGS) docs/COPS.report > docs/COPS.report.ms kuang.man.ms: docs/kuang.man $(NROFF) $(ROFFLAGS) docs/kuang.man > docs/kuang.man.ms suid.man.ms: docs/suid.man $(NROFF) $(ROFFLAGS) docs/suid.man > docs/suid.man.ms cops.1: docs/cops $(NROFF) -man docs/cops > docs/cops.1 cron.1: docs/cron $(NROFF) -man docs/cron > docs/cron.1 dev.1: docs/dev $(NROFF) -man docs/dev > docs/dev.1 dir.1: docs/dir $(NROFF) -man docs/dir > docs/dir.1 file.1: docs/file $(NROFF) -man docs/file > docs/file.1 group.1: docs/group $(NROFF) -man docs/group > docs/group.1 passwd.1: docs/passwd $(NROFF) -man docs/passwd > docs/passwd.1 pass.1: docs/pass $(NROFF) -man docs/pass > docs/pass.1 is_able.1: docs/is_able $(NROFF) -man docs/is_able > docs/is_able.1 home.1: docs/home $(NROFF) -man docs/home > docs/home.1 user.1: docs/user $(NROFF) -man docs/user > docs/user.1 # the end SHAR_EOF echo shar: extracting cops/pass.words '(3278 characters)' cat << \SHAR_EOF > cops/pass.words aaa academia aerobics airplane albany albatross albert alex alexander algebra aliases alphabet ama amorphous analog anchor andromache animals answer anthropogenic anvils anything aria ariadne arrow arthur athena atmosphere aztecs azure bacchus bailey banana bananas bandit banks barber baritone bass bassoon batman beater beauty beethoven beloved benz beowulf berkeley berliner beryl beverly bicameral bob brenda brian bridget broadway bumbling burgess campanile cantor cardinal carmen carolina caroline cascades castle cat cayuga celtics cerulean change charles charming charon chester cigar classic clusters coffee coke collins commrades computer condo cookie cooper cornelius couscous creation creosote cretin daemon dancer daniel danny dave december defoe deluge desperate develop dieter digital discovery disney dog drought duncan eager easier edges edinburgh edwin edwina egghead eiderdown eileen einstein elephant elizabeth ellen emerald engine engineer enterprise enzyme ersatz establish estate euclid evelyn extension fairway felicia fender fermat fidelity finite fishers flakes float flower flowers foolproof football foresight format forsythe fourier fred friend frighten fun fungible gabriel gardner garfield gauss george gertrude ginger glacier gnu golfer gorgeous gorges gosling gouge graham gryphon guest guitar gumption guntis hacker hamlet handily happening harmony harold harvey hebrides heinlein hello help herbert hiawatha hibernia honey horse horus hutchins imbroglio imperial include ingres inna innocuous irishman isis japan jessica jester jixian johnny joseph joshua judith juggle julia kathleen kermit kernel kirkland knight ladle lambda lamination larkin larry lazarus lebesgue lee leland leroy lewis light lisa louis lynne macintosh mack maggot magic malcolm mark markus marty marvin master maurice mellon merlin mets michael michelle mike minimum minsky moguls moose morley mozart nancy napoleon nepenthe ness network newton next noxious nutrition nyquist oceanography ocelot olivetti olivia oracle orca orwell osiris outlaw oxford pacific painless pakistan pam papers password patricia penguin peoria percolate persimmon persona pete peter philip phoenix pierre pizza plover plymouth polynomial pondering pork poster praise precious prelude prince princeton protect protozoa pumpkin puneet puppet rabbit rachmaninoff rainbow raindrop raleigh random rascal really rebecca remote rick ripple robotics rochester rolex romano ronald rosebud rosemary roses ruben rules ruth sal saxon scamper scheme scott scotty secret sensor serenity sharks sharon sheffield sheldon shiva shivers shuttle signature simon simple singer single smile smiles smooch smother snatch snoopy soap socrates sossina sparrows spit spring springer squires strangle stratford stuttgart subway success summer super superstage support supported surfer suzanne swearer symmetry tangerine tape target tarragon taylor telephone temptation thailand tiger toggle tomato topography tortoise toyota trails trivial trombone tubas tuttle umesh unhappy unicorn unknown urchin utility vasant vertigo vicky village virginia warren water weenie whatnot whiting whitney will william williamsburg willie winston wisconsin wizard wombat woodwind wormwood yacov yang yellowstone yosemite zap zimmerman SHAR_EOF echo shar: extracting cops/passwd.chk '(5023 characters)' cat << \SHAR_EOF > cops/passwd.chk #!/bin/sh # # passswd.chk # # Check passsword file -- /etc/passswd -- for incorrect number of fields, # duplicate uid's, non-alphanumeric uids, and non-numeric group id's. # # Awk part from _The AWK Programming Language_, page 78 # # Mechanism: Passwd.check uses awk to ensure that each line of the file # has 7 fields, as well as examining the file for any duplicate users # by using "sort -u". It also checks to make sure that the password # field (the second one) is either a "*", meaning the group has no password, # or a non-null field (which would mean that the account has a null # password.) It then checks to ensure that all uids are alphanumeric, # and that all user id numbers are indeed numeric. For yellow pages # passwords, it does the same checking, but in order to get a listing of # all members of the password file, it does a "ypcat passwd > ./$$" and # uses that temporary file for a passfile. It removes the tmp file after # using it, of course. # The /etc/passwd file has a very specific format, making the task # fairly simple. Normally it has lines with 7 fields, each field # separated by a colon (:). The first field is the user id, the second # field is the encrypted password (an asterix (*) means the group has no # password, otherwise the first two characters are the salt), the third # field is the user id number, the fourth field is the group id number, # the fifth field is the GECOS field (basically holds miscellaneous # information, varying from site to site), the sixth field is the home # directory of the user, and lastly the seventh field is the login shell # of the user. No blank lines should be present. # If a line begins with a plus sign (+), it is a yellow pages entry. # See passwd(5) for more information, if this applies to your site. # AWK=/bin/awk TEST=/bin/test ECHO=/bin/echo SORT=/usr/bin/sort UNIQ=/usr/bin/uniq RM=/bin/rm YPCAT=/usr/bin/ypcat # Used for Sun C2 security group file. FALSE (default) will flag # valid C2 passwd syntax as an error, TRUE attempts to validate it. # Thanks to Pete Troxell for pointing this out. C2=FALSE # # Important files: etc_passwd=/etc/passwd yp_passwd=./$$ yp=false # Testing $etc_passwd for potential problems.... if $TEST -f $YPCAT then if $TEST -s $YPCAT then $YPCAT passwd > $yp_passwd if $TEST $? -eq 0 then yp=true fi fi fi result=`$AWK -F: '{print $1}' $etc_passwd | $SORT |$UNIQ -d` if $TEST "$result" then $ECHO "Warning! Duplicate uid(s) found in $etc_passwd:" $ECHO $result fi # First line is for a yellow pages entry in the password file. # It really should check for correct yellow pages syntax.... $AWK 'BEGIN {FS = ":" } \ {if (substr($1,1,1) != "+") { \ if ($0 ~ /^[ ]*$/) { printf("Warning! Password file, line %d, is blank\n", NR) } else { if (NF != 7) { printf("Warning! Password file, line %d, does not have 7 fields: \n\t%s\n", NR, $0) } \ if ($1 !~ /[A-Za-z0-9]/) { printf("Warning! Password file, line %d, nonalphanumeric login: \n\t%s\n", NR, $0) } \ if ($2 == "") { printf("Warning! Password file, line %d, no password: \n\t%s\n", NR, $0) } \ if ("'$C2'" == "TRUE" && $2 ~ /^##/ && "##"$1 != $2) { printf("Warning! Password file, line %d, invalid password field for C2: \n\t%s\n", NR, $0) } \ if ($3 !~ /[0-9]/) { printf("Warning! Password file, line %d, nonnumeric user id: \n\t%s\n", NR, $0) } \ if ($3 == "0" && $1 != "root") { printf("Warning! Password file, line %d, user %s has uid = 0 and is not root\n\t%s\n", NR, $1, $0) } \ if ($4 !~ /[0-9]/) { printf("Warning! Password file, line %d, nonnumeric group id: \n\t%s\n", NR, $0) } \ if ($6 !~ /^\//) { printf("Warning! Password file, line %d, invalid login directory: \n\t%s\n", NR, $0) } \ }}}' $etc_passwd # # Test yellow pages passwords as well if $TEST "$yp" = "true" then yresult=`$AWK -F: '{print $1}' $yp_passwd | $SORT |$UNIQ -d` if $TEST "$yresult" then $ECHO "Warning! Duplicate uid(s) found in yellow page passwords:" $ECHO $yresult fi $AWK 'BEGIN {FS = ":" } \ { if ($0 ~ /^[ ]*$/) { printf("Warning! YPassword file, line %d, is blank\n", NR) } else { if (NF != 7) { printf("Warning! YPassword file, line %d, does not have 7 fields: \n\t%s\n", NR, $0) } \ if ($1 !~ /[A-Za-z0-9]/) { printf("Warning! YPassword file, line %d, nonalphanumeric login: \n\t%s\n", NR, $0) } \ if ($2 == "") { printf("Warning! YPassword file, line %d, no password: \n\t%s\n", NR, $0) } \ if ($3 !~ /[0-9]/ && $3 != "-2") { printf("Warning! YPassword file, line %d, nonnumeric user id: \n\t%s\n", NR, $0) } \ if ($3 == "0" && $1 != "root") { printf("Warning! YPassword file, line %d, user %s has uid = 0 and is not root\n\t%s\n", NR, $1, $0) } \ if ($4 !~ /[0-9]/ && $4 != "-2") { printf("Warning! YPassword file, line %d, nonnumeric group id: \n\t%s\n", NR, $0) } \ if ($6 !~ /^\//) { printf("Warning! YPassword file, line %d, invalid login directory: \n\t%s\n", NR, $0) } \ }}' $yp_passwd fi $RM -f $yp_passwd # end SHAR_EOF # End of shell archive exit 0