home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume21 / cops / part01 next >
Encoding:
Internet Message Format  |  1990-03-21  |  58.0 KB

  1. Subject:  v21i023:  System ecurity analysis tool, Part01/05
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: 03f906ff a4064d7a 431652ed 3dcdc63e
  5.  
  6. Submitted-by: Dan Farmer <df@sei.cmu.edu>
  7. Posting-number: Volume 21, Issue 23
  8. Archive-name: cops/part01
  9.  
  10. COPS is a security tool that is useful to system administrators, system
  11. programmers, or for anyone who would like to learn about UNIX security.
  12. It does not restrict a system's environment by placing constraints on
  13. activity; it is a purely diagnostic tool that checks and reports on the
  14. current status of a given UNIX machine.
  15.  
  16. Written in Bourne shell, generic commands (awk, sed, etc.) and some C, the
  17. system is basically a shell script that runs several small security
  18. programs.  Theoretically (at least), it attempts to find the following
  19. problems (among others) on a generic UNIX system, and then mails or saves
  20. the results, if indeed any problems do exist:
  21.   --Checks /dev/*mem and all devs listed in "/etc/fstab" for world
  22.     read/writability.
  23.   --Checks special/important directories and files for "bad" (world
  24.     writable, whatever) modes.  (/etc/passwd, /bin, etc.)
  25.   --Checks against /etc/passwd for crummy passwords (user selectable, it
  26.     can be as vigorous or as lax as you wish.)
  27.   --Checks /etc/passwd for non-unique uids, invalid fields, non-numeric
  28.     user ids, etc.  Also includes a password checker.
  29.   --Checks /etc/group for non-unique groups, invalid fields, non-numeric
  30.     group ids, etc.
  31.   --Checks all users' home directories and their
  32.     .login/.cshrc/.rhosts/.profile/etc. files
  33.   --Checks all commands and paths listed in /etc/rc* and crontabs for
  34.     world writability.
  35.   --Checks for bad root paths, world exportable NFS systems, some other
  36.     misc stuff.
  37.   --Includes the Kuang expert system.  Written by Robert Baldwin, this
  38.     basically checks to see if a given user (by default root) is
  39.     compromisible, given that certain rules are true.  Kind of hard to
  40.     explain in a sentence, but worth the price of admission.
  41.   --Checks the system for _changes_ in SUID status.  This is the one (the
  42.     only) program that should be run as superuser, because it runs a
  43.     "find" on all SUID programs from the / directory, and then uses that as
  44.     a reference file for future runs.
  45.  
  46. The "README" file tells how to install, run, and interpret any results
  47. found by COPS.
  48.  
  49.  
  50. #    This is a shell archive.
  51. #    Remove everything above and including the cut line.
  52. #    Then run the rest of the file through sh.
  53. #----cut here-----cut here-----cut here-----cut here----#
  54. #!/bin/sh
  55. mkdir cops 2>/dev/null
  56. mkdir cops/docs 2>/dev/null
  57. mkdir cops/src 2>/dev/null
  58. mkdir cops/extensions 2>/dev/null
  59. # shar:    Shell Archiver
  60. #    Run the following text with /bin/sh to create:
  61. #    cops/MANIFEST
  62. #    cops/README
  63. #    cops/XTRA_CREDIT
  64. #    cops/chk_strings
  65. #    cops/cops
  66. #    cops/cron.chk
  67. #    cops/dev.chk
  68. #    cops/dir.chk
  69. #    cops/dir.chklst
  70. #    cops/disclaimer
  71. #    cops/file.chk
  72. #    cops/file.chklst
  73. #    cops/group.chk
  74. #    cops/init_kuang
  75. #    cops/kuang
  76. #    cops/makefile
  77. #    cops/pass.words
  78. #    cops/passwd.chk
  79. # This archive created: Tue Jan 30 23:35:07 1990
  80. # By:    dan (Purdue University)
  81. echo shar: extracting cops/MANIFEST '(763 characters)'
  82. cat << \SHAR_EOF > cops/MANIFEST
  83. File Name
  84. ==================
  85. MANIFEST
  86. README
  87. XTRA_CREDIT
  88. chk_strings
  89. cops
  90. cron.chk
  91. dev.chk
  92. dir.chk
  93. dir.chklst
  94. docs
  95. file.chk
  96. file.chklst
  97. group.chk
  98. init_kuang
  99. kuang
  100. makefile
  101. pass.words
  102. passwd.chk
  103. rc.chk
  104. reconfig
  105. root.chk
  106. stop.sample
  107. suid.chk
  108.  
  109. docs/COPS.report
  110. docs/KUANG.README
  111. docs/SUID.README
  112. docs/cops
  113. docs/cron
  114. docs/dev
  115. docs/dir
  116. docs/file
  117. docs/group
  118. docs/home
  119. docs/is_able
  120. docs/kuang.1
  121. docs/kuang.man
  122. docs/pass
  123. docs/passwd
  124. docs/rc
  125. docs/release.notes
  126. docs/root
  127. docs/suid.man
  128. docs/tilde
  129. docs/user
  130. docs/warnings
  131.  
  132. extensions/THINGS_2_DO
  133. extensions/YAR
  134. extensions/netstuff
  135. extensions/passwords
  136. extensions/questions
  137.  
  138. src/addto.c
  139. src/clearfiles.c
  140. src/filewriters.c
  141. src/home.chk.c
  142. src/is_readable.c
  143. src/is_writable.c
  144. src/members.c
  145. src/pass.c
  146. src/tilde.c
  147. src/user.chk.c
  148. SHAR_EOF
  149. echo shar: extracting cops/README '(14146 characters)'
  150. cat << \SHAR_EOF > cops/README
  151.  
  152.    Welcome!  You now hold in your hands (terminal?) a collection
  153. of security tools that are designed specifically to aid the typical
  154. UNIX systems administrator, programmer, operator, or consultant in
  155. the oft neglected area of computer security.
  156.    The package, which will be henceforth be referred to as COPS
  157. (Computer Oracle and Password System), can be broken down into three
  158. key parts.  The first is the actual set of programs that attempt
  159. to automate security checks that are often performed manually (or
  160. perhaps with self written short shell scripts or programs) by a systems
  161. administrator.  The second part is the documentation, which details
  162. how to set up, operate, and to interpret any results given by the
  163. programs.  Finally, COPS is an evolving beast.  It includes a list
  164. of possible extensions that might appear in future releases, as well
  165. as pointers to other works in UNIX security that could not be included
  166. at this time, due to space or other restrictions.
  167.    This document contains six sections:
  168.  
  169.       1) What is COPS?
  170.       2) What COPS is _not_
  171.       3) How to Configure/Install COPS
  172.       4) Running COPS for the 1st Time
  173.       5) Continued Use of COPS
  174.       6) Disclaimer and End Notes
  175.  
  176.  
  177. 1) What is COPS?
  178. -----------------
  179.  
  180.    COPS is a collection of about a dozen programs that each attempt
  181. to tackle a different problem area of UNIX security.  Among the areas
  182. checked are file, directory, and device permissions/modes, passwords,
  183. contents of password and group files, the contents of /etc/rc && cron
  184. files, changes in SUID status, the writability of users home directories
  185. and startup files (.profile, .cshrc, etc), and a few others as well.
  186. It also includes the Kuang expert system, written by Bob Baldwin, that
  187. takes a set of rules and tries to determine if your system can be
  188. compromised.  For a more complete list of all of the checks, look at the
  189. file "release.notes" or "cops.report."
  190.    All of the programs merely warn the user of a potential problem --
  191. COPS DOES NOT ATTEMPT TO CORRECT OR EXPLOIT ANY OF THE POTENTIAL PROBLEMS
  192. IT FINDS!  COPS either mails or creates a file (user selectable) of any
  193. of the problems it finds while running on your system.  And because COPS
  194. does not correct potential hazards it finds, it does _not_ have to be
  195. run by a privileged account (i.e. root or whomever.)  The only security
  196. check that should be run by root to get maximum results is the SUID checker;
  197. although it can be run as an unprivileged user, to find all the SUID files
  198. in a system, it should be run as root.
  199.    The programs are mostly written in Bourne shell (using awk, sed, grep,
  200. etc. as well) for (hopefully) maximum portability.  A few are written
  201. in C for speed (most notably the Kuang expert system and for implementing
  202. fast user home directory searching), but the entire system should run on
  203. most BSD and System V machines with a minimum of tweaking.
  204.  
  205. 2) What COPS is _not_
  206. ----------------------
  207.  
  208.    COPS merely provides a method of checking for common procedural errors.
  209. It is not meant to be used as a replacement for common sense or user/
  210. operator/administrative alertness!  Think of it as an aid, a first line
  211. of defense -- not as an impenetrable shield against security woes.  An
  212. experienced wrong-doer could easily circumnavigate _any_ protection that
  213. COPS can give.  However, COPS _can_ aid a system in protecting its users
  214. from (their own?) ignorance, carelessness, and the occasional malcontent
  215. user.
  216.    Once again, COPS does not correct any errors found.  There are several
  217. reasons for this; first and foremost, computer security is a slippery
  218. beast.  What is a major breach in security at one site may be a standard
  219. policy of openness at another site.  Additionally, in order to correct all
  220. problems it finds, it would have to be run as a privileged user; and I'm
  221. not going to go into the myriad problems of running SUID shell scripts
  222. (See the bibliography at the end of the technical report "cops.report"
  223. for pointer to a good paper on this subject by Matt Bishop.)
  224.    At this time, COPS does not attempt to detect bugs or features (such
  225. as infamous ftpd, fingerd, etc) that may cause security problems.  Although
  226. this may change in future versions, the current line of reasoning to avoid
  227. general publication of programs such as these is that all the problems that
  228. COPS detects can be repaired on any system it runs on.  However, many bugs
  229. can be readily repaired only be having source code (and possibly a good
  230. vendor to repair it), and many sites would have serious troubles if they
  231. suddenly discovered unrepairable problems that could compromise their
  232. livelihood.  It is possible that a more controlled release may come out
  233. in the future to address such problems (but don't mail to me about getting
  234. them -- unless you want to help write them! :-))
  235.  
  236. 3) How to Configure/Install COPS
  237. ---------------------------------
  238.  
  239.   System V users, other Non-BSD systems, or sites with commands in
  240. strange places -- you may have to run a shell script called "reconfig"
  241. to change the pathnames of the executable programs called when using
  242. COPS.  If your system does not use the paths listed in the shell
  243. scripts, try running "reconfig".  This will reconfigure the pathnames
  244. used by COPS to your system; COPS should run fine then, if it
  245. can find all of the commands (reconfig should tell you if it
  246. cannot.)  If trouble persists, you will have to change the paths
  247. to your executable files (awk, sed, etc) by hand.  A drag, I know.
  248. This all may change without notice, anyway.
  249.  
  250. 4) Running COPS for the 1st Time
  251. ---------------------------------
  252.  
  253.    Since most of COPS was written and tested mostly on just a few machines
  254. (at least compared to the total number out there!), you may have significant
  255. differences that were not anticipated -- unfortunately, or fortunately,
  256. UNIX is not quite standardized yet.
  257.    COPS is run by simply typing "cops".  "cops" is a Bourne shell script
  258. that runs each of the smaller programs, accumulates the output, and then
  259. mails or stores any results.  "suid.chk", since it can take a long, long time
  260. to run, is the only "standalone" program in the COPS package; look at
  261. suid.man for more information.
  262.  
  263.    To run COPS for the first time, I suggest doing the following:
  264.  
  265.    -- Look at the disclaimer, file "disclaimer".  Don't sue me.
  266.       Actually, this holds for all the times you use COPS (1/4 :-))
  267.    -- Type "make" to create the formatted manual pages, to compile the
  268.       C programs,  and to make the shell programs executable.
  269.    -- Read the technical report to understand what COPS is doing and
  270.       what is going on -- "cops.report".  This gives a look at the
  271.       philosophies, design notes, and finally a general outlay of the
  272.       COPS system and UNIX security.
  273.    -- Next, change lines 36 and 37 in the "cops" shell file from:
  274.         SECURE=/usr/foo/bar
  275.         SECURE_USERS="foo@bar.edu"
  276.       SECURE should be the same directory as the directory that contains
  277.       the cops programs, and SECURE_USERS should be your own login id, or
  278.       to whomever you designate as the recipient of the output (your enemy?)
  279.    -- Set "MAIL=NO" in the "cops" shell file (line 22).  This will prevent
  280.       a large mail file from choking the mailer.  All of the output will be
  281.       put into a file called "report.$$", where $$ is the process
  282.       number that cops had while running.
  283.    -- Look at the directory and file configuration files, "dir.chklst"
  284.       and "file.chklst".  They contain critical files that COPS checks
  285.       for world writability.  Add or delete whatever files/directories
  286.       you wish; if a file doesn't exist, COPS will effectively ignore it.
  287.       (If you don't know or are uncertain what files/directories are
  288.       important, what is given there is a good set to start with on most
  289.       systems.
  290.    -- You may wish to comment out the password checker (line 72 in the
  291.       "cops" shell file).  Although this is not necessary, it will speed
  292.       up the package if you wish for immediate gratification.
  293.  
  294.   You should be ready to roll.  COPS is run by simply typing "cops" (you
  295. may wish to put in the background....)  If you followed my advice and
  296. set "MAIL=NO" in the "cops" shell file, after COPS is finished, there
  297. will be a report file created "report.$$" that lists the time and machine
  298. it was created on.  Otherwise, COPS mails the report to the user listed
  299. on the line 'SECURE_USERS="foo@bar.edu"'.  There is a file "warnings", which
  300. contains most of the warning messages COPS uses, as well as a brief
  301. explanation of how the message might pertain to your system as well as how
  302. to "fix" any problem.
  303.  
  304.    NOTE: Change the shell script "cops" to reflect who you want the output
  305. sent to and where the location of the program is BEFORE running the program.
  306.  
  307.  
  308. 5) Continued Use of COPS
  309. -------------------------
  310.  
  311.    Once you are satisfied that COPS indeed does something useful
  312. (hopefully this will occur :-)), a good way to use it is to run it
  313. on at least a semi-regular basis.  Even if it doesn't find any problems
  314. immediately, the types of problems and holes it can detect are of the
  315. sort that can pop up at any given time.  One way of running COPS
  316. might be to run it as an "at" job or by cron.
  317.    I highly advise that whatever directory COPS is placed in is to be
  318. readable, writable, and executable only by the owner (typing 
  319. "chmod 700 /usr/foo/bar" or whatever the name is will do this) of the
  320. directory.  This is to prevent prying eyes from seeing any security
  321. problems your site may have.  Even if you don't think of them as
  322. important, someone else might come around and change your mind.  Since
  323. COPS is fairly configurable, an intruder could easily change the paths
  324. and files that COPS checks for, hence making it fairly worthless.  Again,
  325. this comes back to the point that COPS is only a tool -- don't put down
  326. your defensive shields merely because COPS says "all clear".  If this
  327. sounds paranoid, it is!  Security people are traditionally paranoid,
  328. for a reason....  In any case, it is probably not a good idea to advertise
  329. any (even) potential weaknesses.
  330.  
  331.    After running COPS, if any warnings are given that compromise any
  332. individual users accounts (such as world writable .profiles, home
  333. directories, guessed passwords, etc.), and the warnings are not corrected
  334. immediately (or you are not sure whether or not it is worth hassling
  335. the user to change it), try this:
  336.    Edit the file "init_kuang", and add the compromised user(s) uids and
  337. groups in their respective target lines (below lines 21 and 27,
  338. respectively), and run kuang again to see if the users can compromise
  339. the entire system.  You may change your mind about not thinking
  340. they are a problem!  In addition, kuang does not have to have "root" 
  341. as a target (the last line).  Try putting in system administrators or
  342. other powerful figures to see if they are in danger as well.
  343.  
  344. 6) Disclaimer and End Notes
  345. ----------------------------
  346.  
  347.    COPS is meant to be a tool to aid in the tightening of security, not
  348. as a weapon to be used by an enemy to find security flaws in a system.
  349. It may be argued that allowing anyone to have access to such a tool may
  350. be dangerous.  But hopefully the overall benefit for systems that use
  351. this package will outweigh any negative impact.  To me it is akin to a
  352. law enforcement problem -- that although telling the public how to break
  353. into a house may foster a slight rise in break-in attempts, the overall
  354. rise in public awareness on how to defend themselves would actually result
  355. in a drop in break-ins.  The crackers with black hats already know how
  356. to crush system defenses and have similar tools, I'm sure.  It's time
  357. we fought back.
  358.  
  359.   COPS is not the final answer to anyone's security woes.  You can use
  360. the system as long as you realize that COPS has no warranty, implied
  361. or otherwise, and that any problems that you may have with it are
  362. not my or any of the other authors fault.  I will certainly attempt to
  363. help you solve them, if I am able, but please don't try to sue me or
  364. anything...  Let's all make COPS a collective effort that helps people, ok?
  365. If you have ideas for additional programs, or a better implementation of
  366. any of the programs here, I would be very interested in seeing them.
  367. COPS was the work of a LOT of people, both in writing code and in the
  368. testing phase (thanks beta testers!).  For a complete list of contributors,
  369. look at the file "XTRA_CREDIT".
  370.  
  371.    So good luck, and I hope you find COPS useful as we plunge into UNIX
  372. of the 1990's.
  373.  
  374.    dan farmer
  375.    January 31, 1989
  376.  
  377.  
  378. # include "disclaimer.h"
  379.  
  380. -------------------- Cut here for disclaimer -------------------------
  381.  
  382. /***********************************************************************
  383. * Copyright 1989, 1990 by Purdue University and Dan Farmer.  All rights
  384. * reserved.  Some individual files may be covered by other copyrights.
  385. * This material was written and compiled by Dan Farmer while at Purdue
  386. * University in 1989 and 1990, under the direction and sponsorship of
  387. * Professor Gene Spafford.  Other material was contributed as noted
  388. * elsewhere.
  389. * Redistribution and use in source and binary forms are permitted
  390. * provided that this entire copyright notice is duplicated in all such
  391. * copies, and that any documentation, announcements, and other
  392. * materials related to such distribution and use acknowledge that the
  393. * software was developed at Purdue University, W. Lafayette, IN.  No
  394. * charge, other than an "at-cost" distribution fee, may be charged for
  395. * copies, derivations, or distributions of this material without the
  396. * express written consent of the copyright holders.  Neither the
  397. * name of the University, the name of the author, nor the name of this
  398. * project's sponsor may  be used to endorse or promote products
  399. * derived from this material without specific prior written permission.
  400. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  401. * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  402. * MERCHANTIBILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
  403. ************************************************************************/
  404. ---------------------- End disclaimer -------------------------------
  405. SHAR_EOF
  406. echo shar: extracting cops/XTRA_CREDIT '(2063 characters)'
  407. cat << \SHAR_EOF > cops/XTRA_CREDIT
  408.  
  409.   Code credits are where code credits are due.  If I miss anyone, please
  410. forgive (and notify) me!
  411.  
  412. Gene Spafford -- overall design help.
  413.  
  414. Robert Baldwin -- the kuang package.
  415.  
  416. Craig Leres, Seth Alford, Roger Southwick, Steve Dum, and Rick Lindsley
  417. all get credit for the password guessing program.
  418.  
  419. Prentiss Riddle -- the suid checker.
  420.  
  421.   And of course lots of credit goes to my great Beta-release sweatshop team;
  422. especially Adri Verhoef for tightening up lots of my crummy code (cops,
  423. group.chk, root.chk, is_writable, dev.chk, dir.chk & file.chk among others),
  424. Steve Romig for good ideas _and_ letting me use a system V machine to test
  425. on (how many people do you know that would let you test a security
  426. system on their system with no strings attached!) Jason Levitt, Jim
  427. Kimble, Jim Rowan, Stefan Vorkoetter, Judy Scheltema, Pete Troxell (all
  428. the Sun C2 stuff....), Dennis Conley, and of course John Sechrest.
  429. Tony Petrost pointed out some of my incorrect assumptions and helped
  430. fix cron.chk.  Kudos also to Bruce Spence for giving me some good
  431. implementation ideas at LISA II.
  432.  
  433.   If strings is not available to you, a version is available on uunet;
  434. also a nifty install program written by Kevin Braunsdorf that can be used
  435. as a super directory/file mode checker/security device should be
  436. available soon in comp.sources.unix (these programs large sizes preculudes
  437. their inclusion in COPS, but I recommend looking into them.)
  438. Both can be gotten via anonymous ftp.  Strings is in comp.unix.sources
  439. directory, install should be in the same.
  440.   Everything else not explicitely mentioned in the COPS.report.ms paper
  441. or here was written by me.  Not mentioned execpt in the source code are
  442. some small changes made by myself to make everything fit in as a cohesive
  443. whole; I tried to make comments in the source code if I changed it (never
  444. to drastic in any case.)
  445.  
  446.   For a good story on the subject, you might want to read _The Cuckoo's
  447. Egg_, by Clifford Stoll.  This is a true tale of a sysadmin's fight 
  448. against beaurocracy and a hacker (the bad kind.)  Good stuff.
  449.  
  450. SHAR_EOF
  451. echo shar: extracting cops/chk_strings '(1559 characters)'
  452. cat << \SHAR_EOF > cops/chk_strings
  453. #!/bin/sh
  454. #
  455. #  Usage: chk_strings filename
  456. #
  457. #  This will check pathnames inside executable files for writability,
  458. # using the "strings" command and egrep.
  459. #
  460. #  I have identified three basic types of strings containing paths to files:
  461. # 1)
  462. #    /path1/path2/file            /* standard */
  463. # 2) 
  464. #    '/path1/path2/file'        /* standard, in single quotes */
  465. # 3)
  466. #    :/path1/file1:/path2/file2        /* a path for searching */
  467. #
  468. #  For the first two, I simply test the writability; for the last, I
  469. # parse it into seperate paths and check each one in turn.
  470. #
  471. AWK=/bin/awk
  472. EGREP=/usr/bin/egrep
  473. TEST=/bin/test
  474. ECHO=/bin/echo
  475. SORT=/usr/bin/sort
  476. STRINGS=/usr/ucb/strings
  477.  
  478. if test ! -s $STRINGS
  479.     then
  480.     exit 0
  481. fi
  482.  
  483. if test $# -eq 0
  484.     then
  485.     $ECHO "Usage: $0 file"
  486.     exit 2
  487. fi
  488.  
  489. while test 0 -ne $#
  490.     do
  491.     # $ECHO Checking $1...
  492.     # get the first two types:
  493.     test_files=`$STRINGS $1 | $EGREP "/.*/" | $AWK '{for (i=1;i<=NF;i++) 
  494.     if ((res=substr($i,1,1))=="/") 
  495.         printf("%s\n",$i)
  496.     else if ((res!=":") && (res=substr($i,2,1))=="/")
  497.         printf("%s\n",substr($i,2,length($i)-2))}'| $SORT -u`
  498.  
  499.     # and type number three, parse into separate paths as well:
  500.     paths=`$STRINGS $1|$EGREP "/.*/" |$AWK '{for (i=1;i<=NF;i++) 
  501.         if ((substr($i,1,1)==":") && (substr($i,2,1))=="/")
  502.             printf("%s",$i)}'`
  503.     paths=`$ECHO $paths | $AWK -F: '{for (i=1;i<=NF;i++) printf("%s\n",$i)}'| $SORT -u`
  504.  
  505.  
  506.     all_files=$test_files$paths
  507.  
  508.     for i in $all_files
  509.         do
  510.         if ./is_writable $i
  511.             then
  512.             $ECHO "      Warning!  File $i (inside root executed file $1) is _World_ writable!"
  513.         fi
  514.         done
  515.     shift
  516. done
  517.  
  518. # end of script
  519. SHAR_EOF
  520. echo shar: extracting cops/cops '(2872 characters)'
  521. cat << \SHAR_EOF > cops/cops
  522. #!/bin/sh
  523. #
  524. #  Usage: cops
  525. #
  526. #  This will change into the $SECURE directory, ensure all the security
  527. # programs (listed below) indeed do exist, and run all of the security
  528. # programs.  If any of the programs find any security problems, they
  529. # send mail to everyone in the $SECURE_USERS list.  It then destroys all
  530. # temporary files, and exits the program.  Programs that are run
  531. # (besides this one):
  532. #
  533. #    root.chk    dev.chk        dir.chk
  534. #    file.chk    group.chk    home.chk
  535. #    rc.chk        passwd.chk    pass.chk
  536. #    user.chk    cron.chk
  537. # The U-kuang system runs these additional programs:
  538. #    init_kuang    kuang        addto
  539. #    clearfiles    filewriters    members
  540. #
  541. #  If this is changed to "NO", the report that cops creates
  542. # will not be deleted and the results will not be mailed to anyone.
  543. MMAIL="YES"
  544.  
  545. # Where is everyone?
  546. ECHO=/bin/echo
  547. TEST=/bin/test
  548. RM=/bin/rm
  549. CAT=/bin/cat
  550. MAIL=/bin/mail
  551. DATE=/bin/date
  552. CHMOD=/bin/chmod
  553.  
  554. ######################
  555. #  Change these lines!
  556. ######################
  557. SECURE=/usr/foo/bar
  558. SECURE_USERS="foo@bar.edu"
  559. ######################
  560.  
  561. SECURE_PROGRAMS="root.chk dev.chk dir.chk file.chk group.chk \
  562.                  home.chk rc.chk passwd.chk pass.chk \
  563.          cron.chk user.chk init_kuang kuang addto \
  564.          clearfiles filewriters members"
  565.  
  566. if $TEST ! -d "$SECURE"
  567.     then
  568.     $ECHO "Error -- Security directory $SECURE doesn't exist"
  569.     exit 1
  570. fi
  571.  
  572. $CHMOD 700 $SECURE
  573. cd $SECURE
  574.  
  575. for i in $SECURE_PROGRAMS
  576.     do
  577.     if $TEST ! -s "$i"
  578.         then
  579.         $ECHO "Error -- Security program $i doesn't exist"
  580.         exit 1
  581.     fi
  582. done
  583.  
  584. $SECURE/root.chk        >    $SECURE/result.$$ 2> /dev/null
  585. $SECURE/dev.chk            >>    $SECURE/result.$$ 2> /dev/null
  586. $SECURE/dir.chk            >>    $SECURE/result.$$ 2> /dev/null
  587. $SECURE/file.chk        >>    $SECURE/result.$$ 2> /dev/null
  588. $SECURE/rc.chk            >>    $SECURE/result.$$ 2> /dev/null
  589. $SECURE/cron.chk        >>    $SECURE/result.$$ 2> /dev/null
  590. $SECURE/group.chk        >>    $SECURE/result.$$ 2> /dev/null
  591. $SECURE/home.chk        >>    $SECURE/result.$$ 2> /dev/null
  592. $SECURE/passwd.chk        >>    $SECURE/result.$$ 2> /dev/null
  593. $SECURE/pass.chk         >>    $SECURE/result.$$ 2> /dev/null
  594. $SECURE/user.chk        >>    $SECURE/result.$$ 2> /dev/null
  595. $SECURE/kuang            >    /dev/null 2> /dev/null
  596. if $TEST -s "$SECURE/Success"
  597.     then
  598.     $CAT $SECURE/Success >> $SECURE/result.$$
  599. fi
  600. $RM -f $SECURE/Success
  601.  
  602.  
  603. #
  604. #   Mail the final report to $SECURE_USERS and remove the evidence
  605. if $TEST -s "$SECURE/result.$$"
  606.     then
  607.     $ECHO ATTENTION:                >  $SECURE/report.$$
  608.     $ECHO "Security Report for "`$DATE`    >> $SECURE/report.$$
  609.  
  610.     #
  611.     #  Thanks to arbitron for this idea...
  612.     HOSTNAME=`/bin/sh -c "/bin/uname -n || /usr/bin/uuname -l || /bin/hostname" 2>&-`
  613.     $ECHO "from host $HOSTNAME"            >> $SECURE/report.$$
  614.     $ECHO                    >> $SECURE/report.$$
  615.     $ECHO                    >> $SECURE/report.$$
  616.     $CAT $SECURE/result.$$            >> $SECURE/report.$$
  617.  
  618.     if $TEST "$MMAIL" = "YES"
  619.         then
  620.         $MAIL $SECURE_USERS < $SECURE/report.$$
  621.         $RM -f $SECURE/report.$$
  622.     fi
  623.  
  624. fi
  625. $RM -f $SECURE/result.$$
  626.  
  627. #  end it all....
  628. exit 0
  629. SHAR_EOF
  630. echo shar: extracting cops/cron.chk '(2248 characters)'
  631. cat << \SHAR_EOF > cops/cron.chk
  632. #!/bin/sh
  633. #
  634. #  Usage: cron.chk
  635. #
  636. #  This checks pathnames and files inside the cron files /usr/lib/crontab
  637. # for writability.
  638. #
  639. #  Mechanism:  The commands inside the file /usr/lib/crontab are executed
  640. # by root.  This shell script greps for commands/paths that begins with
  641. # "/" and takes each potential problem-string and uses the program
  642. # "is_writable" to determine if it is world writable.  All results are
  643. # echoed to standard output.
  644. #  In addition, it throws away everything that has a /tmp, /dev/null, or
  645. # tty in the writable string, and everything after a ">"; e.g. if crontab
  646. # is writing to a file it doesn't care.
  647. #
  648. #  Cron.chk will try to find a file in /usr/lib/crontab first (bsd),
  649. # and then if it isn't there, it will look in the any alternate
  650. # possible locations next -- right now, /usr/spool/cron/crontab -- to
  651. # see if a directory exists, and, if it does, it checks all the cron
  652. # files in turn.
  653. #
  654. #  WARNING!
  655. #
  656. #  Spurious messages can occur; a more stringent method (if perhaps less
  657. # careful of a check) would be to test just the 6th field, instead of
  658. # all the fields after the fifth.  Also throwing away /tmp, etc. could
  659. # be a mistake.
  660. #
  661.  
  662. #  Location of stuff:
  663. AWK=/bin/awk
  664. SED=/bin/sed
  665. ECHO=/bin/echo
  666. EGREP=/usr/bin/egrep
  667. TEST=/bin/test
  668. CAT=/bin/cat
  669.  
  670. #  Possible location of crontab file:
  671. cron=/usr/lib/crontab
  672. #  alternate reality locations of crontab file:
  673. alt_cron="/usr/spool/cron/crontabs"
  674.  
  675. if $TEST ! -s $cron
  676.     then
  677.     cron=""
  678.     for i in "$alt_cron"
  679.         do
  680.         if $TEST -d $i
  681.             then
  682.             cron=`$ECHO $alt_cron/*`
  683.             fi
  684.         done
  685.  
  686.     if $TEST  -z "$cron"
  687.         then
  688.         exit
  689.         fi
  690.     fi
  691.  
  692. # finally, do the checking -- maybe for one, maybe for lots of
  693. # cron-ites:
  694.  
  695. for cron_kid in $cron
  696.     do
  697.     # A typical crontab entry might look something like this:
  698.     #
  699.     #   0,15,30,45 * * * * /bin/sh /usr/adm/newsyslog
  700.     #
  701.     risky_stuff=`$AWK '{for (i=6;i<NF;i++) printf("%s ", $i);
  702.         if (NF!=6) printf("%s\n",$NF)}' $cron_kid | $SED -e 's/>.*//' |
  703.         $AWK '{for (i=1;i<=NF;i++) if (substr($i,1,1)=="/") print $i}'`
  704.  
  705.     for i in $risky_stuff
  706.         do
  707.         if $TEST `echo $i | $EGREP "/tmp|/dev/null|tty"`
  708.             then
  709.             continue
  710.             fi
  711.         if ./is_writable $i
  712.             then
  713.             $ECHO "Warning!  $i (in $cron_kid) is World writable!"
  714.             fi
  715.         done
  716.     done    # for all the cron-kids
  717. SHAR_EOF
  718. echo shar: extracting cops/dev.chk '(2691 characters)'
  719. cat << \SHAR_EOF > cops/dev.chk
  720. #!/bin/sh
  721. #
  722. #  dev.chk [-g]
  723. #
  724. #   This shell script checks the permissions of /dev/mem, /dev/kmem, and
  725. # all devs listed in the file /etc/fstab (the "mount" command would be
  726. # a preferable way of getting the file system name, but the syntax of the
  727. # output is variable from machine to machine), and flags them if they are
  728. # readable by using the "is_readable" command.  It also checks for
  729. # unrestricted NFS mountings.  By default, dev_check will flag devs only
  730. # if world readable or writable.  The -g option tells it to print out devs
  731. # that are also group readable/writable.
  732. #
  733. AWK=/bin/awk
  734. LS=/bin/ls
  735. ECHO=/bin/echo
  736. TEST=/bin/test
  737.  
  738. # locations of vital stuff...
  739. mtab=/etc/fstab
  740. exports=/etc/exports
  741.  
  742. #   Optional List of assorted files that shouldn't be
  743. # readable (mix 'n match; add to the list as desired):
  744. opt_files='/usr/adm/sulog /etc/btmp /.netrc'
  745.  
  746. group=no
  747.  
  748. if $TEST $# -gt 1
  749.     then
  750.     $ECHO "Usage: $0 [-g]"
  751.     exit 2
  752. fi
  753.  
  754. if $TEST $# -eq 1
  755.     then
  756.     if $TEST "X$1" = "X-g"
  757.         then
  758.         group=yes
  759.     else
  760.         $ECHO "Usage: $0 [-g]"
  761.         exit 2
  762.     fi
  763. fi
  764.  
  765. #  Testing filesystems and devices for improper read/write permissions...
  766.  
  767. #  NEVER want these readable!
  768. always_crit_files="/dev/kmem /dev/mem"
  769.  
  770. # grab devices from "/etc/fstab"....
  771. #
  772. #  Format of /etc/fstab:    /dev/zd0e   +junk(:-)
  773. #
  774. #  Or NFS mounted:        uther:/usr/spaf   +junk(:-)
  775. #
  776. #  Not sure what to do with NFS stuff, so we'll ignore it.  Seems that
  777. # this doesn't tell us anything about what we want anyway....
  778. crit_devs=$always_crit_files" "`$AWK 'index($1, "/")==1 {print $1}' $mtab`
  779.  
  780. # Alternate way; grab devices from "mount [-p]"....
  781. #   Format of output from mount (some machines use -p option, some
  782. # don't.  Check your local man page... :
  783. # crit_devs=$always_crit_files" "`/etc/mount -p|$AWK 'index($1, "/")==1
  784. #                    {print $1} \
  785. #                }'`
  786.  
  787. #
  788. # However, do check for single line entries in /etc/exports:
  789. if $TEST -s $exports
  790.     then
  791.     $AWK '{while(getline >0) if ($0 !~ /^#/ && NF == 1) \
  792.         printf("Warning!  NFS file system %s exported with no restrictions.\n",$0)}' $exports
  793.     fi
  794.  
  795. for i in $crit_devs
  796.     do
  797.     if ./is_readable $i
  798.         then
  799.         $ECHO Warning!  $i is _World_ readable!
  800.     fi
  801.     if ./is_writable $i
  802.         then
  803.         $ECHO Warning!  $i is _World_ writable!
  804.     fi
  805.     if $TEST "$group" = "yes"
  806.         then
  807.         if ./is_readable -g $i
  808.             then
  809.             $ECHO Warning!  $i is group readable!
  810.         fi
  811.         if ./is_writable -g $i
  812.             then
  813.             $ECHO Warning!  $i is group readable!
  814.         fi
  815.     fi
  816. done
  817.  
  818. # Do the mix 'n match assorted no-read files:
  819. for i in $opt_files
  820.     do
  821.     if ./is_readable $i
  822.         then
  823.         $ECHO Warning!  $i is _World_ readable!
  824.     fi
  825.     if $TEST "$group" = "yes"
  826.         then
  827.         if ./is_readable -g $i
  828.             then
  829.             $ECHO Warning!  $i is group readable!
  830.         fi
  831.     fi
  832. done
  833.  
  834. # end of script
  835. SHAR_EOF
  836. echo shar: extracting cops/dir.chk '(1459 characters)'
  837. cat << \SHAR_EOF > cops/dir.chk
  838. #!/bin/sh
  839. #
  840. #  dir.chk [-g]
  841. #
  842. #   This shell script checks the permissions of all directories listed 
  843. # in the configuration file "dirs.755.dirlist",  and flags them if they
  844. # are world-writable.  The -g option tells it to print out directories
  845. # that are also group writable.  See the config file for the format of
  846. # the configuration file.
  847. #
  848. #   Mechanism:  This shell script simply takes each line from the
  849. # configure file and uses the "is_writable" program to check if any of
  850. # the directories in question are writable by world/group.  All results
  851. # are written to standard output.
  852. #
  853. AWK=/bin/awk
  854. TEST=/bin/test
  855. ECHO=/bin/echo
  856.  
  857. dir_list=dir.chklst
  858. group=no
  859.  
  860. if $TEST $# -gt 1
  861.     then
  862.     $ECHO "Usage: $0 [-g]"
  863.     exit 2
  864. fi
  865.  
  866. if $TEST $# -eq 1
  867.     then
  868.     if $TEST "X$1" = "X-g"
  869.         then
  870.         group=yes
  871.     else
  872.         $ECHO "Usage: $0 [-g]"
  873.         exit 2
  874.     fi
  875. fi
  876.  
  877. #  Testing directories in file $dir_list for potential write mode problems
  878.  
  879. #  Read from $dir_list (e.g. "dirs.755.dirlist") what dirs to check.
  880. #
  881. # Comments are lines starting with a "#".
  882. #
  883. while read i
  884. do
  885.     case $i in
  886.      "#"* | "" )
  887.         continue;;
  888.     esac
  889.  
  890.     # exit code 0 is writable, 1 is not
  891.     dirs=`$ECHO $i`
  892.     for d in $dirs
  893.         do
  894.         if ./is_writable $d
  895.             then
  896.             echo "Warning!  Directory $d is _World_ writable!"
  897.         fi
  898.     done
  899.  
  900.     if $TEST "$group" = "yes"
  901.         then
  902.         for d in $dirs
  903.             do
  904.             if ./is_writable -g $d
  905.                 then
  906.                 echo "Warning!  Directory $d is group writable!"
  907.             fi
  908.         done
  909.     fi
  910.  
  911. done < $dir_list
  912.  
  913. # end of script
  914. SHAR_EOF
  915. echo shar: extracting cops/dir.chklst '(377 characters)'
  916. cat << \SHAR_EOF > cops/dir.chklst
  917. #
  918. #  This lists any/all sensitive files the administration wants to ensure
  919. # non-writability of.  Comments are lines starting with a "#".
  920. #
  921. #   Lines are of the format:
  922. #
  923. #    /path/to/file
  924. #
  925. /
  926. # /*
  927. /etc
  928. /usr
  929. /bin
  930.  
  931. /usr/spool
  932. /usr/adm
  933. /usr/etc
  934. /usr/lib
  935. /usr/local
  936. /usr/local/bin
  937. /usr/local/lib
  938. /usr/bin
  939. /usr/etc
  940. /usr/spool/mail
  941. /usr/spool/news
  942. /usr/spool/uucp
  943. /usr/spool/at
  944. /Mail
  945. SHAR_EOF
  946. echo shar: extracting cops/disclaimer '(1468 characters)'
  947. cat << \SHAR_EOF > cops/disclaimer
  948. /***********************************************************************
  949. * Copyright 1989, 1990 by Purdue University and Dan Farmer.  All rights
  950. * reserved.  Some individual files may be covered by other copyrights.
  951. * This material was written and compiled by Dan Farmer while at Purdue
  952. * University in 1989 and 1990, under the direction and sponsorship of
  953. * Professor Gene Spafford.  Other material was contributed as noted
  954. * elsewhere.
  955. * Redistribution and use in source and binary forms are permitted
  956. * provided that this entire copyright notice is duplicated in all such
  957. * copies, and that any documentation, announcements, and other
  958. * materials related to such distribution and use acknowledge that the
  959. * software was developed at Purdue University, W. Lafayette, IN.  No
  960. * charge, other than an "at-cost" distribution fee, may be charged for
  961. * copies, derivations, or distributions of this material without the
  962. * express written consent of the copyright holders.  Neither the
  963. * name of the University, the name of the author, nor the name of this
  964. * project's sponsor may  be used to endorse or promote products
  965. * derived from this material without specific prior written permission.
  966. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  967. * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  968. * MERCHANTIBILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
  969. ************************************************************************/
  970. SHAR_EOF
  971. echo shar: extracting cops/file.chk '(1423 characters)'
  972. cat << \SHAR_EOF > cops/file.chk
  973. #!/bin/sh
  974. #
  975. #  file.chk [-g]
  976. #
  977. #   This shell script checks the permissions of all files listed 
  978. # in the configuration file "files.chklst",  and flags them if they
  979. # are world-writable.  The -g option tells it to print out files
  980. # that are also group writable.  See the config file the format of
  981. # the configuration file.
  982. #
  983. #   Mechanism:  This shell script simply takes each line from the
  984. # configure file and uses the "is_writable" program to check if any of
  985. # the files in question are writable by world/group.  All results
  986. # are written to standard output.
  987. #
  988. AWK=/bin/awk
  989. TEST=/bin/test
  990. ECHO=/bin/echo
  991.  
  992. file_list=file.chklst
  993. group=no
  994.  
  995. if $TEST $# -gt 1
  996.     then
  997.     $ECHO "Usage: $0 [-g]"
  998.     exit 2
  999. fi
  1000.  
  1001. if $TEST $# -eq 1
  1002.     then
  1003.     if $TEST "X$1" = "X-g"
  1004.         then
  1005.         group=yes
  1006.     else
  1007.         $ECHO "Usage: $0 [-g]"
  1008.         exit 2
  1009.     fi
  1010. fi
  1011.  
  1012. # Checking files in file $file_list for potential write mode problems
  1013.  
  1014. #  Read from $file_list (e.g. "files.chklst") what files to check.
  1015. #
  1016. # Comments are lines starting with a "#".
  1017. #
  1018. while read i
  1019. do
  1020.     case $i in
  1021.      "#"* | "" )
  1022.         continue;;
  1023.     esac
  1024.  
  1025.     # exit code 0 is writable, 1 is not
  1026.     files=`$ECHO $i`
  1027.     for f in $files
  1028.         do
  1029.         if ./is_writable $f
  1030.             then
  1031.             echo "Warning!  File $f is _World_ writable!"
  1032.         fi
  1033.     done
  1034.  
  1035.     if $TEST "$group" = "yes"
  1036.         then
  1037.         for f in $files
  1038.             do
  1039.             if ./is_writable -g $f
  1040.                 then
  1041.                 echo "Warning!  File $f is group writable!"
  1042.             fi
  1043.         done
  1044.     fi
  1045.  
  1046. done < $file_list
  1047.  
  1048. # end of script
  1049. SHAR_EOF
  1050. echo shar: extracting cops/file.chklst '(523 characters)'
  1051. cat << \SHAR_EOF > cops/file.chklst
  1052. #
  1053. #  This lists any/all sensitive files the administration wants to ensure
  1054. # non-writability of.  Comments are lines starting with a "#".
  1055. #
  1056. #   Lines are of the format:
  1057. #
  1058. #    /path/to/file
  1059. #
  1060. /.*
  1061. #    /.login
  1062. #    /.profile
  1063. #    /.cshrc
  1064. #    /.crontab
  1065. #    /.rhost
  1066. /etc/*
  1067. #    /etc/passwd
  1068. #    /etc/group
  1069. #    /etc/inittab
  1070. #    /etc/rc
  1071. #    /etc/rc.local
  1072. #    /etc/rc.boot
  1073. #    /etc/hosts.equiv
  1074. #    /etc/profile
  1075. #    /etc/syslog.conf
  1076. #    /etc/export
  1077. /usr/etc/yp*
  1078. /usr/lib/crontab
  1079. /usr/lib/aliases
  1080. /usr/lib/sendmail
  1081. # /usr/spool/L.sys
  1082. # /usr/adm/sulog
  1083. /usr/adm/*
  1084. /bin/*
  1085. SHAR_EOF
  1086. echo shar: extracting cops/group.chk '(5099 characters)'
  1087. cat << \SHAR_EOF > cops/group.chk
  1088. #!/bin/sh
  1089. #
  1090. #   group.chk
  1091. #
  1092. #  Check group file -- /etc/group -- for incorrect number of fields,
  1093. # duplicate groups, non-alphanumeric group names, and non-numeric group
  1094. # id's.
  1095. #
  1096. # Awk part based on _passwd_ from _The AWK Programming Language_, page 78
  1097. #
  1098. #   Mechanism:  Group.check uses awk to ensure that each line of the group
  1099. # has 4 fields, as well as examining each line for any duplicate groups or
  1100. # any duplicate user id's in a given group by using "sort -u" to ferret
  1101. # out any duplications.  It also checks to make sure that the password
  1102. # field (the second one) is a "*", meaning the group has no password (a
  1103. # group password is usually not necessary because each member listed on 
  1104. # the line has all the privilages that the group has.)  All results are
  1105. # echoed to standard output.  Finally it ensures that the group names
  1106. # are alphanumeric, that the group id's are numeric, and that there are
  1107. # no blank lines.  For yellow pages groups, it does the same checking,
  1108. # but in order to get a listing of all members of the groups, it does a
  1109. # "ypcat group > ./$$" and uses that temporary file for a groupfile.
  1110. # It removes the tmp file after using it, of course.
  1111. #   The /etc/group file has a very specific format, making the task
  1112. # fairly simple.  Normally it has lines with 4 fields, each field
  1113. # separated by a colon (:).  The first field is the group name, the second
  1114. # field is the encrypted password (an asterix (*) means the group has no
  1115. # password, otherwise the first two characters are the salt), the third
  1116. # field is the group id number, and the fourth field is a list of user
  1117. # ids in the group.  If a line begins with a plus sign (+), it is a yellow
  1118. # pages entry.  See group(5) for more information.
  1119. #
  1120. #
  1121. AWK=/bin/awk
  1122. SED=/bin/sed
  1123. ECHO=/bin/echo
  1124. TEST=/bin/test
  1125. SORT=/usr/bin/sort
  1126. UNIQ=/usr/bin/uniq
  1127. YPCAT=/usr/bin/ypcat
  1128. RM=/bin/rm
  1129.  
  1130. #   Used for Sun C2 security group file.  FALSE (default) will flag
  1131. # valid C2 group syntax as an error, TRUE attempts to validate it.
  1132. # Thanks to Pete Troxell for pointing this out.
  1133. C2=FALSE
  1134.  
  1135. etc_group=/etc/group
  1136. yp_group=./$$
  1137. yp=false
  1138.  
  1139. if $TEST -f $YPCAT
  1140.     then
  1141. if $TEST -s $YPCAT
  1142.     then
  1143.     $YPCAT group > $yp_group
  1144.     if $TEST $? -eq 0
  1145.         then
  1146.         yp=true
  1147.         fi
  1148.     fi
  1149. fi
  1150.  
  1151. # Testing $etc_group for potential problems....
  1152.  
  1153. #   First line is for a yellow pages entry in the group file.
  1154. # It really should check for correct yellow pages syntax....
  1155. $AWK 'BEGIN {FS = ":" } {
  1156.     if (substr($1,1,1) != "+") { \
  1157.     if ($0 ~ /^[     ]*$/) { printf("Warning!  Group file, line %d, is blank\n", NR) } else {
  1158.     if (NF != 4) { printf("Warning!  Group file, line %d, does not have 4 fields: %s\n", NR, $0) } \
  1159.     if ($1 !~ /[A-Za-z0-9]/) {
  1160.         printf("Warning!  Group file, line %d, nonalphanumeric user id: %s\n", NR, $0) } \
  1161.     if ($2 != "" && $2 != "*") {
  1162.         if ("'$C2'" != "TRUE")
  1163.             printf("Warning!  Group file, line %d, group has password: %s\n", NR, $0)
  1164.         else {
  1165.             if ("#$"$1 != $2)
  1166.                 printf("Warning!  Group file, line %d, group has invalid field for C2:\n%s\n", NR, $0) } \
  1167.         } \
  1168.     if ($3 !~ /[0-9]/) {
  1169.         printf("Warning!  Group file, line %d, nonnumeric group id: %s\n", NR, $0) }}}} ' $etc_group
  1170.  
  1171. #
  1172. #  Look for duplications in groups in $etc_group
  1173. #
  1174. result=`$AWK -F: '{print $1}' $etc_group | $SORT |$UNIQ -d`
  1175. if $TEST "$result"
  1176.     then
  1177.     $ECHO "Warning!  Duplicate Group(s) found in $etc_group:"
  1178.     $ECHO $result
  1179. fi
  1180.  
  1181. #
  1182. #   Next, check for duplicate users in a group in /etc/group.  Let
  1183. # awk do all the work (thanks, adri!)
  1184. #
  1185.  
  1186. # Ignore all groups with less than two members.
  1187. #
  1188. awk -F: '
  1189.     split($4, users, ",") > 1 {
  1190.         ct = 0
  1191.         for (i in users) {
  1192.             curuser = users[i]
  1193.             for (j in users) {
  1194.                 if (j > i && curuser == users[j]) {
  1195.                     if (ct++ == 0) print "Warning!  Group "$1" has duplicate user(s):"
  1196.                     print curuser
  1197.                 }
  1198.             }
  1199.         }
  1200.     }
  1201.     ' $etc_group
  1202.  
  1203.  
  1204. #
  1205. # Test yellow pages groups as well
  1206. if $TEST "$yp" = "true"
  1207.     then
  1208. $AWK 'BEGIN {FS = ":" } {
  1209.     if ($0 ~ /^[     ]*$/) { printf("Warning!  YGroup file, line %d, is blank\n", NR) } else {
  1210.     if (NF != 4) { printf("Warning!  YGroup file, line %d, does not have 4 fields: %s\n", NR, $0) } \
  1211.     if ($1 !~ /[A-Za-z0-9]/) {
  1212.         printf("Warning!  YGroup file, line %d, nonalphanumeric user id: %s\n", NR, $0) } \
  1213.     if ($2 != "" && $2 != "*") {
  1214.         printf("Warning!  YGroup file, line %d, group has password: %s\n", NR, $0) } \
  1215.     if ($3 !~ /[0-9]/) {
  1216.         printf("Warning!  YGroup file, line %d, nonnumeric group id: %s\n", NR, $0) }}} ' $yp_group
  1217.  
  1218. #
  1219. #  Look for duplications in groups in yellow pages groups
  1220. #
  1221.     yresult=`$AWK -F: '{print $1}' $yp_group | $SORT |$UNIQ -d`
  1222.     if $TEST "$yresult"
  1223.         then
  1224.         $ECHO "Warning!  Duplicate Group(s) found in yellow pages group:"
  1225.         $ECHO $result
  1226.     fi
  1227. #
  1228. #   Next, check for duplicate users in a group in yellow groups.  Let
  1229. # awk do all the work (thanks, adri!) 
  1230.  
  1231. # ignore all groups with one member.
  1232. #
  1233.     awk -F: '
  1234.     split($4, users, ",") > 1 {
  1235.         ct = 0
  1236.         for (i in users) {
  1237.             curuser = users[i]
  1238.             for (j in users) {
  1239.                 if (j > i && curuser == users[j]) {
  1240.                     if (ct++ == 0) print "Warning!  YGroup "$1" has duplicate user(s):"
  1241.                     print curuser
  1242.                 }
  1243.             }
  1244.         }
  1245.     }
  1246.     ' $yp_group
  1247.  
  1248. fi
  1249.  
  1250. $RM -f $yp_group
  1251.  
  1252. # end
  1253. SHAR_EOF
  1254. echo shar: extracting cops/init_kuang '(773 characters)'
  1255. cat << \SHAR_EOF > cops/init_kuang
  1256. # /* Copyright 1985 Robert W. Baldwin */
  1257. # /* Copyright 1986 Robert W. Baldwin */
  1258. ###############################################
  1259. # Kuang: Rule based computer security checker.
  1260. ###############################################
  1261.  
  1262. CAT=/bin/cat
  1263. ECHO=/bin/echo
  1264.  
  1265. #
  1266. # Initialization.
  1267. #
  1268. ./clearfiles
  1269. #
  1270. # First setup what we have access to.
  1271. # The uids.k file must include the user 'OTHER' meaning the world access bits.
  1272. # Add any other UIDs accessible to the attacker (e.g., ftp, daemon).
  1273. #
  1274. # Directly accessible user IDs.
  1275. $CAT >uids.k <<END
  1276. OTHER
  1277. END
  1278. #
  1279. # Directly accessible group IDs.
  1280. # This usually includes a group like 'users', which most users are in.
  1281. #
  1282. $CAT >gids.k <<END
  1283. END
  1284. #
  1285. # Setup the primary goal(s).
  1286. #
  1287. $ECHO Setting up goal                        #>/dev/tty
  1288. ./addto uids root DO ANYTHING
  1289. SHAR_EOF
  1290. echo shar: extracting cops/kuang '(5967 characters)'
  1291. cat << \SHAR_EOF > cops/kuang
  1292. # /* Copyright 1985 Robert W. Baldwin */
  1293. # /* Copyright 1986 Robert W. Baldwin */
  1294. #
  1295. # Jan 1990, Ported to bourne shell from Csh.  Dan Farmer
  1296. #
  1297. #   Took out some comments, combined four of Bob's shell
  1298. # scripts into one (the target script remains separate for
  1299. # easy editing of targets.)  More or less a straight line
  1300. # for line translation; a rewrite that goes for speed will
  1301. # come later.  Maybe just rewrite it in C.  Yeah, that's it....
  1302.  
  1303. ###############################################
  1304. # Kuang: Rule based computer security checker.
  1305. ###############################################
  1306.  
  1307. # commands used....
  1308. SH=/bin/sh
  1309. MV=/bin/mv
  1310. TEST=/bin/test
  1311. ECHO=/bin/echo
  1312. AWK=/bin/awk
  1313. RM=/bin/rm
  1314.  
  1315. # Initialization.
  1316. $SH ./init_kuang
  1317.  
  1318. # Main loop
  1319. #
  1320. $ECHO Starting main loop                        #>/dev/tty
  1321. while $TEST -f uids.n -o -f gids.n -o -f files.n
  1322.     do
  1323.     if $TEST -f uids.n ; then
  1324.         $MV uids.n uids.x
  1325.  
  1326. # Process a list of uids from stdin.
  1327. # Usage: douids username comments
  1328.     $ECHO Called douids                        #>/dev/tty
  1329.     i=1
  1330.     while $TEST "1"
  1331.         do
  1332.         nextuid=`$AWK '{if (NR=="'$i'") print $0}' uids.x`
  1333.         i=`expr $i + 1`
  1334.  
  1335.         if $TEST -z "$nextuid"  ; then
  1336.             break;
  1337.         fi
  1338.  
  1339.             user=`$ECHO $nextuid | $AWK '{print $1}'`
  1340.  
  1341.         $ECHO "   " User $user                    #>/dev/tty
  1342.  
  1343. # Rules mapping uids to files.
  1344. #
  1345.         next=`$ECHO $nextuid | $AWK '{for (i=2;i<=NF;i++) printf("%s ", $i)}'`
  1346.         ./addto files /etc/passwd replace grant $user $next
  1347.         ./addto files /usr/lib/aliases replace trojan $user $next
  1348.  
  1349. #   hsh = home sweet home = home directory of $user
  1350.         hsh=`./tilde $user`
  1351.  
  1352.         if $TEST -f $hsh/.rhosts ;  then
  1353.             ./addto files $hsh/.rhosts write grant $user $next
  1354.         fi
  1355.  
  1356.         if $TEST -f $hsh/.login ;  then
  1357.             ./addto files $hsh/.login replace trojan $user $next
  1358.         fi
  1359.  
  1360.         if $TEST -f $hsh/.cshrc ;  then
  1361.             ./addto files $hsh/.cshrc replace trojan $user $next
  1362.         fi
  1363.  
  1364.         if $TEST -f $hsh/.profile ;  then
  1365.             ./addto files $hsh/.profile replace trojan $user $next
  1366.         fi
  1367.  
  1368.         if $TEST "$user" = "root" ;  then
  1369.         if $TEST -f /usr/lib/crontab ; then
  1370.                ./addto files /usr/lib/crontab replace create supershell $next
  1371.         else
  1372.                ./addto files /usr/spool/cron/crontabs replace create supershell $next
  1373.         fi
  1374.             ./addto files /etc/rc replace trojan $user $next
  1375.             ./addto files /etc/rc.local replace trojan $user $next
  1376.         fi
  1377.  
  1378.         if $TEST "$user" != "root" ;  then
  1379.             ./addto files /etc/hosts.equiv replace allow rlogin $next
  1380.         fi
  1381.  
  1382.         if $TEST "$user" != "root" -a -f /etc/hosts.equiv -a -s /etc/hosts.equiv 
  1383.             then
  1384.             ./addto files /etc/hosts replace fake HostAddress $next
  1385.         fi
  1386.  
  1387.     done
  1388. fi
  1389.  
  1390.     if $TEST -f gids.n ; then
  1391.        $MV gids.n gids.x
  1392.  
  1393.     $ECHO Called dogids                        #>/dev/tty
  1394.     i=1
  1395.     while $TEST "1"
  1396.         do
  1397.         nextgid=`$AWK '{if (NR=="'$i'") print $0}' gids.x`
  1398.         i=`expr $i + 1`
  1399.  
  1400.         if $TEST -z "$nextgid" ; then
  1401.             break;
  1402.         fi
  1403.  
  1404.         group=`$ECHO $nextgid | $AWK '{print $1}'`
  1405.         $ECHO "   " Group $group                    #>/dev/tty
  1406.  
  1407. # Rules mapping gids to uids.
  1408. #
  1409.         next=`$ECHO $nextgid | $AWK '{for (i=2;i<=NF;i++) printf("%s ", $i)}'`
  1410.         use=`./members $group`
  1411.         for user in $use
  1412.             do
  1413.             ./addto uids $user grant $group $next
  1414.             done
  1415.  
  1416. # Rules mapping gids to files.
  1417. #
  1418.         ./addto files /etc/group replace grant $group $next
  1419.         done
  1420.     fi
  1421.  
  1422.     if $TEST -f files.n ; then
  1423.        $MV files.n files.x
  1424.  
  1425. # A list of file names is read from successive lines of stdin.
  1426. # Each file is examined for ways to access it.
  1427. # The input format is:
  1428. #    <filename> <whitespace> <mode> <comments>
  1429. # The <mode> is either "write" or "replace".
  1430. #
  1431.     $ECHO Called dofiles.                        #>/dev/tty
  1432.     i=1
  1433.     while $TEST "1"
  1434.         do
  1435.         nextfile=`$AWK '{if (NR=='"$i"') print $0}' files.x`
  1436.         i=`expr $i + 1`
  1437.         if $TEST -z "$nextfile" ; then
  1438.             break;
  1439.         fi
  1440.  
  1441.         file=`$ECHO $nextfile | $AWK '{print $1}'`
  1442.         mode=`$ECHO $nextfile | $AWK '{print $2}'`
  1443.  
  1444.         $ECHO "    File $file, mode $mode"            #>/dev/tty
  1445.  
  1446. # Rules converting filename goals into UserName or GroupName goals.
  1447. #
  1448.         next=`$ECHO $nextfile | $AWK '{for (i=3;i<=NF;i++) printf("%s ", $i)}'`
  1449.  
  1450.         writers=`./filewriters $file`
  1451.         numwriters=`$ECHO $writers | $AWK '{print NF}'`
  1452.         if $TEST "$numwriters" = "3" ; then
  1453.             owner=`$ECHO $writers | $AWK '{print $1}'`
  1454.             group=`$ECHO $writers | $AWK '{print $2}'`
  1455.             other=`$ECHO $writers | $AWK '{print $3}'`
  1456.  
  1457.             $ECHO "        Writers are $owner $group $other"    #>/dev/tty
  1458.                 ./addto uids $owner $mode $file $next
  1459.             if $TEST "$group" != "NONE" ; then
  1460.                 ./addto gids $group $mode $file $next
  1461.             fi
  1462.             if $TEST "$other" != "NONE" ; then
  1463.                 ./addto uids $other $mode $file $next
  1464.             fi
  1465.         else
  1466.             $ECHO "        $file does not exist"        #>/dev/tty
  1467.             continue
  1468.         fi
  1469.  
  1470. # Rules converting filename goals into other filename goals.
  1471. #
  1472.         if $TEST "$mode" != "replace" ; then
  1473.             continue
  1474.         fi
  1475.  
  1476.     parent=`$ECHO $file | $AWK -F/ '{if (NF == 2) {
  1477.         printf("/%s", $1)}
  1478.         else if (NF>2) {for (i=2;i<NF;i++) printf("/%s", $i)} 
  1479.         else printf("")'}`
  1480.  
  1481.     basename=`$ECHO $file | $AWK -F/ '{print $NF}'`
  1482.  
  1483.     $ECHO -n "       " Parent directory is $parent        #>/dev/tty
  1484.     $ECHO ", " basename is $basename                #>/dev/tty
  1485.     if $TEST -n "$parent" ; then
  1486.        ./addto files $parent write replace $basename $next
  1487.         fi
  1488.     done
  1489.  
  1490.     fi
  1491. done
  1492.  
  1493. # destroy the evidence.... Need "Success" file for report, though.
  1494. $RM files.? gids.? uids.?
  1495. SHAR_EOF
  1496. echo shar: extracting cops/makefile '(2721 characters)'
  1497. cat << \SHAR_EOF > cops/makefile
  1498. #  Simple Makefile for the COPS system; compiles, and chmods 
  1499. # the programs.
  1500. #
  1501. #    make all        -- makes everything
  1502. #    make <program_name> -- make a given program
  1503. EXECUTABLE = home.chk user.chk is_readable is_writable pass.chk \
  1504.          addto clearfiles filewriters members tilde
  1505. C_SRC      = home.chk.c user.chk.c is_readable.c is_writable.c pass.c \
  1506.          addto.c clearfiles.c filewriters.c members.c tilde.c
  1507. SHELL_PROGS= chk_strings root.chk dev.chk dir.chk cron.chk \
  1508.          file.chk cops group.chk rc.chk passwd.chk \
  1509.          suid.chk kuang init_kuang reconfig
  1510. SUPPORT    = dir.chklst file.chklst makefile stop.sample \
  1511.          COPS.READ.1ST Beta.info SUID.README MANIFEST
  1512. DOCS       = COPS.report.ms suid.man.ms kuang.man.ms
  1513. MAN        = cops.1 cron.1 dev.1 dir.1 file.1 group.1 passwd.1 \
  1514.          is_able.1 home.1 user.1 pass.1
  1515. CFLAGS     = -O
  1516. ROFFLAGS   = -ms
  1517.  
  1518. #
  1519. # Where the programs are....
  1520. #
  1521. CHMOD=/bin/chmod
  1522. MKDIR=/bin/mkdir
  1523. CP=/bin/cp
  1524. CC=/bin/cc
  1525. NROFF=/usr/bin/nroff
  1526.  
  1527. # make all
  1528. all:    $(EXECUTABLE) $(DOCS) $(MAN)
  1529.     $(CHMOD) 700 $(SHELL_PROGS)
  1530.  
  1531. # make the programs
  1532. addto: src/addto.c
  1533.     $(CC) $(CFLAGS) -o addto src/addto.c
  1534.  
  1535. clearfiles: src/clearfiles.c
  1536.     $(CC) $(CFLAGS) -o clearfiles src/clearfiles.c
  1537.  
  1538. filewriters: src/filewriters.c
  1539.     $(CC) $(CFLAGS) -o filewriters src/filewriters.c
  1540.  
  1541. members: src/members.c
  1542.     $(CC) $(CFLAGS) -o members src/members.c
  1543.  
  1544. home.chk: src/home.chk.c
  1545.     $(CC) $(CFLAGS) -o home.chk src/home.chk.c
  1546.  
  1547. user.chk: src/user.chk.c
  1548.     $(CC) $(CFLAGS) -o user.chk src/user.chk.c
  1549.  
  1550. is_readable: src/is_readable.c
  1551.     $(CC) $(CFLAGS) -o is_readable src/is_readable.c
  1552.  
  1553. is_writable: src/is_writable.c
  1554.     $(CC) $(CFLAGS) -o is_writable src/is_writable.c
  1555.  
  1556. pass.chk: src/pass.c
  1557.     $(CC) $(CFLAGS) -o pass.chk src/pass.c
  1558.  
  1559. tilde: src/tilde.c
  1560.     $(CC) $(CFLAGS) -o tilde src/tilde.c
  1561.  
  1562. # 'roff out those docs
  1563. COPS.report.ms: docs/COPS.report
  1564.     $(NROFF) $(ROFFLAGS) docs/COPS.report > docs/COPS.report.ms
  1565.  
  1566. kuang.man.ms: docs/kuang.man
  1567.     $(NROFF) $(ROFFLAGS) docs/kuang.man > docs/kuang.man.ms
  1568.  
  1569. suid.man.ms: docs/suid.man
  1570.     $(NROFF) $(ROFFLAGS) docs/suid.man > docs/suid.man.ms
  1571.  
  1572. cops.1: docs/cops
  1573.     $(NROFF) -man docs/cops > docs/cops.1
  1574.  
  1575. cron.1: docs/cron
  1576.     $(NROFF) -man docs/cron > docs/cron.1
  1577.  
  1578. dev.1: docs/dev
  1579.     $(NROFF) -man docs/dev > docs/dev.1
  1580.  
  1581. dir.1: docs/dir
  1582.     $(NROFF) -man docs/dir > docs/dir.1
  1583.  
  1584. file.1: docs/file
  1585.     $(NROFF) -man docs/file > docs/file.1
  1586.  
  1587. group.1: docs/group
  1588.     $(NROFF) -man docs/group > docs/group.1
  1589.  
  1590. passwd.1: docs/passwd
  1591.     $(NROFF) -man docs/passwd > docs/passwd.1
  1592.  
  1593. pass.1: docs/pass
  1594.     $(NROFF) -man docs/pass > docs/pass.1
  1595.  
  1596. is_able.1: docs/is_able
  1597.     $(NROFF) -man docs/is_able > docs/is_able.1
  1598.  
  1599. home.1: docs/home
  1600.     $(NROFF) -man docs/home > docs/home.1
  1601.  
  1602. user.1: docs/user
  1603.     $(NROFF) -man docs/user > docs/user.1
  1604.  
  1605. # the end
  1606. SHAR_EOF
  1607. echo shar: extracting cops/pass.words '(3278 characters)'
  1608. cat << \SHAR_EOF > cops/pass.words
  1609. aaa
  1610. academia
  1611. aerobics
  1612. airplane
  1613. albany
  1614. albatross
  1615. albert
  1616. alex
  1617. alexander
  1618. algebra
  1619. aliases
  1620. alphabet
  1621. ama
  1622. amorphous
  1623. analog
  1624. anchor
  1625. andromache
  1626. animals
  1627. answer
  1628. anthropogenic
  1629. anvils
  1630. anything
  1631. aria
  1632. ariadne
  1633. arrow
  1634. arthur
  1635. athena
  1636. atmosphere
  1637. aztecs
  1638. azure
  1639. bacchus
  1640. bailey
  1641. banana
  1642. bananas
  1643. bandit
  1644. banks
  1645. barber
  1646. baritone
  1647. bass
  1648. bassoon
  1649. batman
  1650. beater
  1651. beauty
  1652. beethoven
  1653. beloved
  1654. benz
  1655. beowulf
  1656. berkeley
  1657. berliner
  1658. beryl
  1659. beverly
  1660. bicameral
  1661. bob
  1662. brenda
  1663. brian
  1664. bridget
  1665. broadway
  1666. bumbling
  1667. burgess
  1668. campanile
  1669. cantor
  1670. cardinal
  1671. carmen
  1672. carolina
  1673. caroline
  1674. cascades
  1675. castle
  1676. cat
  1677. cayuga
  1678. celtics
  1679. cerulean
  1680. change
  1681. charles
  1682. charming
  1683. charon
  1684. chester
  1685. cigar
  1686. classic
  1687. clusters
  1688. coffee
  1689. coke
  1690. collins
  1691. commrades
  1692. computer
  1693. condo
  1694. cookie
  1695. cooper
  1696. cornelius
  1697. couscous
  1698. creation
  1699. creosote
  1700. cretin
  1701. daemon
  1702. dancer
  1703. daniel
  1704. danny
  1705. dave
  1706. december
  1707. defoe
  1708. deluge
  1709. desperate
  1710. develop
  1711. dieter
  1712. digital
  1713. discovery
  1714. disney
  1715. dog
  1716. drought
  1717. duncan
  1718. eager
  1719. easier
  1720. edges
  1721. edinburgh
  1722. edwin
  1723. edwina
  1724. egghead
  1725. eiderdown
  1726. eileen
  1727. einstein
  1728. elephant
  1729. elizabeth
  1730. ellen
  1731. emerald
  1732. engine
  1733. engineer
  1734. enterprise
  1735. enzyme
  1736. ersatz
  1737. establish
  1738. estate
  1739. euclid
  1740. evelyn
  1741. extension
  1742. fairway
  1743. felicia
  1744. fender
  1745. fermat
  1746. fidelity
  1747. finite
  1748. fishers
  1749. flakes
  1750. float
  1751. flower
  1752. flowers
  1753. foolproof
  1754. football
  1755. foresight
  1756. format
  1757. forsythe
  1758. fourier
  1759. fred
  1760. friend
  1761. frighten
  1762. fun
  1763. fungible
  1764. gabriel
  1765. gardner
  1766. garfield
  1767. gauss
  1768. george
  1769. gertrude
  1770. ginger
  1771. glacier
  1772. gnu
  1773. golfer
  1774. gorgeous
  1775. gorges
  1776. gosling
  1777. gouge
  1778. graham
  1779. gryphon
  1780. guest
  1781. guitar
  1782. gumption
  1783. guntis
  1784. hacker
  1785. hamlet
  1786. handily
  1787. happening
  1788. harmony
  1789. harold
  1790. harvey
  1791. hebrides
  1792. heinlein
  1793. hello
  1794. help
  1795. herbert
  1796. hiawatha
  1797. hibernia
  1798. honey
  1799. horse
  1800. horus
  1801. hutchins
  1802. imbroglio
  1803. imperial
  1804. include
  1805. ingres
  1806. inna
  1807. innocuous
  1808. irishman
  1809. isis
  1810. japan
  1811. jessica
  1812. jester
  1813. jixian
  1814. johnny
  1815. joseph
  1816. joshua
  1817. judith
  1818. juggle
  1819. julia
  1820. kathleen
  1821. kermit
  1822. kernel
  1823. kirkland
  1824. knight
  1825. ladle
  1826. lambda
  1827. lamination
  1828. larkin
  1829. larry
  1830. lazarus
  1831. lebesgue
  1832. lee
  1833. leland
  1834. leroy
  1835. lewis
  1836. light
  1837. lisa
  1838. louis
  1839. lynne
  1840. macintosh
  1841. mack
  1842. maggot
  1843. magic
  1844. malcolm
  1845. mark
  1846. markus
  1847. marty
  1848. marvin
  1849. master
  1850. maurice
  1851. mellon
  1852. merlin
  1853. mets
  1854. michael
  1855. michelle
  1856. mike
  1857. minimum
  1858. minsky
  1859. moguls
  1860. moose
  1861. morley
  1862. mozart
  1863. nancy
  1864. napoleon
  1865. nepenthe
  1866. ness
  1867. network
  1868. newton
  1869. next
  1870. noxious
  1871. nutrition
  1872. nyquist
  1873. oceanography
  1874. ocelot
  1875. olivetti
  1876. olivia
  1877. oracle
  1878. orca
  1879. orwell
  1880. osiris
  1881. outlaw
  1882. oxford
  1883. pacific
  1884. painless
  1885. pakistan
  1886. pam
  1887. papers
  1888. password
  1889. patricia
  1890. penguin
  1891. peoria
  1892. percolate
  1893. persimmon
  1894. persona
  1895. pete
  1896. peter
  1897. philip
  1898. phoenix
  1899. pierre
  1900. pizza
  1901. plover
  1902. plymouth
  1903. polynomial
  1904. pondering
  1905. pork
  1906. poster
  1907. praise
  1908. precious
  1909. prelude
  1910. prince
  1911. princeton
  1912. protect
  1913. protozoa
  1914. pumpkin
  1915. puneet
  1916. puppet
  1917. rabbit
  1918. rachmaninoff
  1919. rainbow
  1920. raindrop
  1921. raleigh
  1922. random
  1923. rascal
  1924. really
  1925. rebecca
  1926. remote
  1927. rick
  1928. ripple
  1929. robotics
  1930. rochester
  1931. rolex
  1932. romano
  1933. ronald
  1934. rosebud
  1935. rosemary
  1936. roses
  1937. ruben
  1938. rules
  1939. ruth
  1940. sal
  1941. saxon
  1942. scamper
  1943. scheme
  1944. scott
  1945. scotty
  1946. secret
  1947. sensor
  1948. serenity
  1949. sharks
  1950. sharon
  1951. sheffield
  1952. sheldon
  1953. shiva
  1954. shivers
  1955. shuttle
  1956. signature
  1957. simon
  1958. simple
  1959. singer
  1960. single
  1961. smile
  1962. smiles
  1963. smooch
  1964. smother
  1965. snatch
  1966. snoopy
  1967. soap
  1968. socrates
  1969. sossina
  1970. sparrows
  1971. spit
  1972. spring
  1973. springer
  1974. squires
  1975. strangle
  1976. stratford
  1977. stuttgart
  1978. subway
  1979. success
  1980. summer
  1981. super
  1982. superstage
  1983. support
  1984. supported
  1985. surfer
  1986. suzanne
  1987. swearer
  1988. symmetry
  1989. tangerine
  1990. tape
  1991. target
  1992. tarragon
  1993. taylor
  1994. telephone
  1995. temptation
  1996. thailand
  1997. tiger
  1998. toggle
  1999. tomato
  2000. topography
  2001. tortoise
  2002. toyota
  2003. trails
  2004. trivial
  2005. trombone
  2006. tubas
  2007. tuttle
  2008. umesh
  2009. unhappy
  2010. unicorn
  2011. unknown
  2012. urchin
  2013. utility
  2014. vasant
  2015. vertigo
  2016. vicky
  2017. village
  2018. virginia
  2019. warren
  2020. water
  2021. weenie
  2022. whatnot
  2023. whiting
  2024. whitney
  2025. will
  2026. william
  2027. williamsburg
  2028. willie
  2029. winston
  2030. wisconsin
  2031. wizard
  2032. wombat
  2033. woodwind
  2034. wormwood
  2035. yacov
  2036. yang
  2037. yellowstone
  2038. yosemite
  2039. zap
  2040. zimmerman
  2041. SHAR_EOF
  2042. echo shar: extracting cops/passwd.chk '(5023 characters)'
  2043. cat << \SHAR_EOF > cops/passwd.chk
  2044. #!/bin/sh
  2045. #
  2046. #   passswd.chk
  2047. #
  2048. #  Check passsword file -- /etc/passswd -- for incorrect number of fields,
  2049. # duplicate uid's, non-alphanumeric uids, and non-numeric group id's.
  2050. #
  2051. # Awk part from _The AWK Programming Language_, page 78
  2052. #
  2053. #  Mechanism:  Passwd.check uses awk to ensure that each line of the file
  2054. # has 7 fields, as well as examining the file for any duplicate users
  2055. # by using "sort -u".  It also checks to make sure that the password
  2056. # field (the second one) is either a "*", meaning the group has no password,
  2057. # or a non-null field (which would mean that the account has a null
  2058. # password.)  It then checks to ensure that all uids are alphanumeric,
  2059. # and that all user id numbers are indeed numeric.  For yellow pages
  2060. # passwords, it does the same checking, but in order to get a listing of
  2061. # all members of the password file, it does a "ypcat passwd > ./$$" and
  2062. # uses that temporary file for a passfile.  It removes the tmp file after
  2063. # using it, of course.
  2064. #   The /etc/passwd file has a very specific format, making the task
  2065. # fairly simple.  Normally it has lines with 7 fields, each field
  2066. # separated by a colon (:).  The first field is the user id, the second
  2067. # field is the encrypted password (an asterix (*) means the group has no
  2068. # password, otherwise the first two characters are the salt), the third
  2069. # field is the user id number, the fourth field is the group id number,
  2070. # the fifth field is the GECOS field (basically holds miscellaneous
  2071. # information, varying from site to site), the sixth field is the home
  2072. # directory of the user, and lastly the seventh field is the login shell
  2073. # of the user.  No blank lines should be present.
  2074. #   If a line begins with a plus sign (+), it is a yellow pages entry.
  2075. # See passwd(5) for more information, if this applies to your site.
  2076. #
  2077. AWK=/bin/awk
  2078. TEST=/bin/test
  2079. ECHO=/bin/echo
  2080. SORT=/usr/bin/sort
  2081. UNIQ=/usr/bin/uniq
  2082. RM=/bin/rm
  2083. YPCAT=/usr/bin/ypcat
  2084.  
  2085. #   Used for Sun C2 security group file.  FALSE (default) will flag
  2086. # valid C2 passwd syntax as an error, TRUE attempts to validate it.
  2087. # Thanks to Pete Troxell for pointing this out.
  2088. C2=FALSE
  2089.  
  2090. #
  2091. # Important files:
  2092. etc_passwd=/etc/passwd
  2093. yp_passwd=./$$
  2094.  
  2095. yp=false
  2096.  
  2097. # Testing $etc_passwd for potential problems....
  2098. if $TEST -f $YPCAT
  2099.     then
  2100. if $TEST -s $YPCAT
  2101.     then
  2102.     $YPCAT passwd > $yp_passwd
  2103.     if $TEST $? -eq 0
  2104.         then
  2105.         yp=true
  2106.     fi
  2107. fi
  2108. fi
  2109.  
  2110. result=`$AWK -F: '{print $1}' $etc_passwd | $SORT |$UNIQ -d`
  2111. if $TEST "$result"
  2112.     then
  2113.     $ECHO "Warning!  Duplicate uid(s) found in $etc_passwd:"
  2114.     $ECHO $result
  2115. fi
  2116.  
  2117.  
  2118. #   First line is for a yellow pages entry in the password file.
  2119. # It really should check for correct yellow pages syntax....
  2120. $AWK 'BEGIN {FS = ":" } \
  2121.     {if (substr($1,1,1) != "+") { \
  2122.     if ($0 ~ /^[     ]*$/) { printf("Warning!  Password file, line %d, is blank\n", NR) } else {
  2123.     if (NF != 7) {
  2124.         printf("Warning!  Password file, line %d, does not have 7 fields: \n\t%s\n", NR, $0) } \
  2125.     if ($1 !~ /[A-Za-z0-9]/) {
  2126.         printf("Warning!  Password file, line %d, nonalphanumeric login: \n\t%s\n", NR, $0) } \
  2127.     if ($2 == "") {
  2128.         printf("Warning!  Password file, line %d, no password: \n\t%s\n", NR, $0) } \
  2129.      if ("'$C2'" == "TRUE" && $2 ~ /^##/ && "##"$1 != $2) {
  2130.         printf("Warning!  Password file, line %d, invalid password field for C2: \n\t%s\n", NR, $0) } \
  2131.     if ($3 !~ /[0-9]/) {
  2132.         printf("Warning!  Password file, line %d, nonnumeric user id: \n\t%s\n", NR, $0) } \
  2133.     if ($3 == "0" && $1 != "root") {
  2134.         printf("Warning!  Password file, line %d, user %s has uid = 0 and is not root\n\t%s\n", NR, $1, $0) } \
  2135.     if ($4 !~ /[0-9]/) {
  2136.         printf("Warning!  Password file, line %d, nonnumeric group id: \n\t%s\n", NR, $0) } \
  2137.     if ($6 !~ /^\//) {
  2138.         printf("Warning!  Password file, line %d, invalid login directory: \n\t%s\n", NR, $0) } \
  2139.     }}}' $etc_passwd
  2140.  
  2141. #
  2142. # Test yellow pages passwords as well
  2143. if $TEST "$yp" = "true"
  2144.     then
  2145.     yresult=`$AWK -F: '{print $1}' $yp_passwd | $SORT |$UNIQ -d`
  2146.     if $TEST "$yresult"
  2147.         then
  2148.         $ECHO "Warning!  Duplicate uid(s) found in yellow page passwords:"
  2149.         $ECHO $yresult
  2150.     fi
  2151.  
  2152.     $AWK 'BEGIN {FS = ":" } \
  2153.         { if ($0 ~ /^[     ]*$/) { printf("Warning!  YPassword file, line %d, is blank\n", NR) } else {
  2154.         if (NF != 7) {
  2155.             printf("Warning!  YPassword file, line %d, does not have 7 fields: \n\t%s\n", NR, $0) } \
  2156.         if ($1 !~ /[A-Za-z0-9]/) {
  2157.             printf("Warning!  YPassword file, line %d, nonalphanumeric login: \n\t%s\n", NR, $0) } \
  2158.         if ($2 == "") {
  2159.             printf("Warning!  YPassword file, line %d, no password: \n\t%s\n", NR, $0) } \
  2160.         if ($3 !~ /[0-9]/ && $3 != "-2") {
  2161.             printf("Warning!  YPassword file, line %d, nonnumeric user id: \n\t%s\n", NR, $0) } \
  2162.         if ($3 == "0" && $1 != "root") {
  2163.             printf("Warning!  YPassword file, line %d, user %s has uid = 0 and is not root\n\t%s\n", NR, $1, $0) } \
  2164.         if ($4 !~ /[0-9]/ && $4 != "-2") {
  2165.             printf("Warning!  YPassword file, line %d, nonnumeric group id: \n\t%s\n", NR, $0) } \
  2166.         if ($6 !~ /^\//) {
  2167.             printf("Warning!  YPassword file, line %d, invalid login directory: \n\t%s\n", NR, $0) } \
  2168.         }}' $yp_passwd
  2169.     
  2170. fi
  2171.  
  2172. $RM -f $yp_passwd
  2173.  
  2174. # end
  2175. SHAR_EOF
  2176. #    End of shell archive
  2177. exit 0
  2178.  
  2179.