home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3356 < prev    next >
Encoding:
Internet Message Format  |  1991-05-17  |  59.6 KB

  1. From: df@sei.cmu.edu (Dan Farmer)
  2. Newsgroups: alt.sources
  3. Subject: alpha perl-cops, part 1 of 3
  4. Message-ID: <25550@as0c.sei.cmu.edu>
  5. Date: 17 May 91 04:46:08 GMT
  6.  
  7. Submitted-by: df@death.cert.sei.cmu.edu
  8. Archive-name: alpha p-cops/part01
  9.  
  10. #!/bin/sh
  11. # This is alpha p-cops, a shell archive (produced by shar 3.49)
  12. # To extract the files from this archive, save it to a file, remove
  13. # everything above the "!/bin/sh" line above, and type "sh file_name".
  14. #
  15. # made 05/17/1991 04:38 UTC by df@death.cert.sei.cmu.edu
  16. # Source directory /usr/users/df/COPS/perl
  17. #
  18. # existing files will NOT be overwritten unless -c is specified
  19. #
  20. # This is part 1 of a multipart archive                                    
  21. # do not concatenate these parts, unpack them in order with /bin/sh        
  22. #
  23. # This shar contains:
  24. # length  mode       name
  25. # ------ ---------- ------------------------------------------
  26. #   7064 -rwx------ p-cops.alpha/ftp.chk
  27. #   1776 -rwx------ p-cops.alpha/get-cf
  28. #   1292 -rwx------ p-cops.alpha/chk_strings
  29. #   3559 -rwx------ p-cops.alpha/chk_strings.pl
  30. #   2129 -rwx------ p-cops.alpha/cops.cf
  31. #   2399 -rwx------ p-cops.alpha/cron.chk
  32. #   6390 -rwx------ p-cops.alpha/cops
  33. #    463 -rwx------ p-cops.alpha/fgrep.pl
  34. #    413 -rwx------ p-cops.alpha/file_mode.pl
  35. #    398 -rwx------ p-cops.alpha/file_owner.pl
  36. #   2739 -rwx------ p-cops.alpha/dev.chk
  37. #    902 -rwx------ p-cops.alpha/getopts.pl
  38. #   2960 -rwx------ p-cops.alpha/glob.pl
  39. #   5060 -rwx------ p-cops.alpha/group.chk
  40. #    444 -rwx------ p-cops.alpha/hostname.pl
  41. #   1591 -rwx------ p-cops.alpha/is_able.chk
  42. #   1603 -rwx------ p-cops.alpha/is_able.lst
  43. #   2835 -rwx------ p-cops.alpha/is_able.pl
  44. #  14688 -rwx------ p-cops.alpha/kuang
  45. #   4413 -rwx------ p-cops.alpha/misc.chk
  46. #   6730 -rw------- p-cops.alpha/kuang.1
  47. #  10420 -rwx------ p-cops.alpha/pass.cache.pl
  48. #   6684 -rwx------ p-cops.alpha/pass.chk
  49. #   5989 -rwx------ p-cops.alpha/passwd.chk
  50. #    677 -rwx------ p-cops.alpha/pathconf.pl
  51. #    644 -rwx------ p-cops.alpha/pathconf.sh
  52. #   1014 -rwx------ p-cops.alpha/rc.chk
  53. #   3296 -rwx------ p-cops.alpha/reconfig.pl
  54. #   2048 -rwx------ p-cops.alpha/user.chk
  55. #    653 -rwx------ p-cops.alpha/stat.pl
  56. #    229 -rwx------ p-cops.alpha/suckline.pl
  57. #   4477 -rwx------ p-cops.alpha/suid.chk
  58. #   5959 -rwx------ p-cops.alpha/root.chk
  59. #   4848 -rwx------ p-cops.alpha/README.perl
  60. #   6206 -rwx------ p-cops.alpha/root.chk.old
  61. #   9306 -rw------- p-cops.alpha/README.kuang
  62. #      0 -rwx------ p-cops.alpha/suid.stop
  63. #   9915 -rw------- p-cops.alpha/pwgrid.pl
  64. #   6147 -rwx------ p-cops.alpha/root.chk.new
  65. #   2768 -rw------- p-cops.alpha/rules.pl
  66. #
  67. if test -r _shar_seq_.tmp; then
  68.     echo 'Must unpack archives in sequence!'
  69.     echo Please unpack part `cat _shar_seq_.tmp` next
  70.     exit 1
  71. fi
  72. # ============= p-cops.alpha/ftp.chk ==============
  73. if test ! -d 'p-cops.alpha'; then
  74.     echo 'x - creating directory p-cops.alpha'
  75.     mkdir 'p-cops.alpha'
  76. fi
  77. if test -f 'p-cops.alpha/ftp.chk' -a X"$1" != X"-c"; then
  78.     echo 'x - skipping p-cops.alpha/ftp.chk (File already exists)'
  79.     rm -f _shar_wnt_.tmp
  80. else
  81. > _shar_wnt_.tmp
  82. echo 'x - extracting p-cops.alpha/ftp.chk (Text)'
  83. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/ftp.chk' &&
  84. #!/bin/sh  # need to mention perl here to avoid recursion
  85. #
  86. #  Usage: ftp.chk
  87. #
  88. #   This shell script checks to see if you've set up (mainly anonymous)
  89. # ftp correctly.  There seems to be some different types of ftp's 
  90. # around; for instance, some allow "chmod" -- and if the home dir is 
  91. # owned by "ftp", you're toast.  So I've tried to err on the side of
  92. # safety...
  93. #
  94. #   See the man page for a more detailed description, here's what this
  95. # checks for:
  96. #
  97. # - User ftp exists in the password file.
  98. # - root (or all root equivalents) are in ftpusers file.
  99. # - Home directory for ftp should exist, and not be /
  100. # - The ~ftp/etc/{passwd|group} should not be the same as the real ones.
  101. # - Various critical files/directories should exist, and have correct
  102. #   permissions and owners; variables "$primary" and "$secondary" can be set
  103. # to whomever you want owning the files:
  104. #
  105. #  File/Dir          Perms           Owner      Other
  106. #  =========         ======          ======     ======
  107. #  ~ftp              non-w.w.        root
  108. #           or
  109. #  ~ftp              555             ftp    if no chmod command exists
  110. #
  111. #     All of these are ftp owned iff no chmod exists...
  112. #
  113. #  ~ftp/bin          non-w.w.        root/ftp
  114. #  ~ftp/bin/ls       111             root/ftp
  115. #  ~ftp/etc          non-w.w.        root/ftp
  116. #  ~ftp/etc/passwd   non-w.w.        root/ftp   0 size or nonexistant
  117. #  ~ftp/etc/group    non-w.w.        root/ftp   0 size or nonexistant
  118. #  ~ftp/pub          non-w.w.        root/ftp
  119. #  ~ftp/incoming     world-writable  root/ftp   This can be set to "pub"
  120. #  ~ftp/.rhosts      non-w.w.        root       0 size, is optional
  121. #  ~ftp/*            non-w.w.                   other dirs/files in ~ftp
  122. #
  123. #
  124. #  NOTE:
  125. # if you know where perl is and your system groks #!, put its
  126. # pathname at the top to make this a tad faster.
  127. #
  128. # the following magic is from the perl man page
  129. # and should work to get us to run with perl 
  130. # even if invoked as an sh or csh or foosh script.
  131. # notice we don't use full path cause we don't
  132. # know where the user has perl on their system.
  133. #
  134. eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 
  135. & eval 'exec perl -S $0 $argv:q'
  136. X    if $running_under_some_stupid_shell_instead_of_perl;
  137. X
  138. require 'is_able.pl';
  139. require 'file_mode.pl';
  140. require 'glob.pl';
  141. require 'fgrep.pl';
  142. require 'pass.cache.pl';
  143. require 'file_owner.pl';
  144. require 'pathconf.pl';
  145. X
  146. $CMP="/bin/cmp" unless defined $CMP;
  147. X
  148. package ftp;
  149. X
  150. #   Primary and secondary owners of the ftp files/dirs; if you *don't* have
  151. # chmod, you can probably change the secondary owner to "ftp".  If you have
  152. # chmod in your ftp, definitely have secondary to some other account (root
  153. # is fine for this.)
  154. local($primary)="root" unless defined $primary;
  155. local($secondary)="ftp" unless defined $secondary;
  156. X
  157. # some might have this as ftpd; is the account in /etc/passwd
  158. local($ftpuid)="ftp";
  159. X
  160. # system files
  161. local($ftpusers)="/etc/ftpusers";
  162. local($passwd)="/etc/passwd" unless defined $PASSWD;
  163. local($group)="/etc/group" unless defined $GROUP;
  164. X
  165. #   ftp's home:
  166. $ftproot = &'uname2dir($ftpuid);
  167. $anonymous = $ftproot ne '';
  168. X
  169. local($ftprhosts)="$ftproot/.rhosts";
  170. local($ftpbin)="$ftproot/bin";
  171. local($ftpls)="$ftpbin/ls";
  172. local($ftpetc)="$ftproot/etc";
  173. local($ftppasswd)="$ftpetc/passwd";
  174. local($ftpgroup)="$ftpetc/group";
  175. X
  176. local($W) = 'Warning!   ' unless defined $W;
  177. X
  178. #   the pub/incoming stuff; by default, pub is *not* world writable, incoming
  179. # is; if you want pub to be world writable, just change incoming to "pub"
  180. local($incoming)="pub";
  181. X
  182. @crit_files=($ftpgroup,
  183. X         $ftppasswd,
  184. X         $ftpls);
  185. X
  186. if (-s $ftpusers) {
  187. X    # check to see if root (or root equivalents) is in ftpusers file
  188. X    @all_roots = split(" ", $'uid2names{0});
  189. X    if (@all_roots ne "") {
  190. X    for $i (@all_roots) {
  191. X        if (length($user2passwd{$i}) == 13 && ! &'fgrep($ftpusers, "^$i$")) {
  192. X        print "Warning!  $i should be in $ftpusers!\n";
  193. X        }
  194. X    }
  195. X    }
  196. }
  197. X
  198. #  do the anonymous ftp checking stuff now?
  199. die unless $anonymous;
  200. X
  201. #   if the user ftp doesn't exist, no-anon stuff....
  202. # if $TEST -z $ftproot -a "$anonymous" = "yes" ; then
  203. X
  204. die "${W}Need user $ftpuid for anonymous ftp to work!\n" if ($ftpuid eq "");
  205. X
  206. #   if the user ftp doesn't exist, no-anon stuff....
  207. if (! -d $ftproot || $ftproot eq "") {
  208. X    die "${W}Home directory for ftp doesn\'t exist!\n";
  209. }
  210. if ($ftproot eq "/") {
  211. X    print "${W}$ftproot ftp\'s home directory should not be \"/\"!\n";
  212. }
  213. X
  214. #   want to check all the critical files and directories for correct
  215. # ownership.  Some versions of ftp don't need much of anything... no 
  216. # etc directory or password/group files.
  217. #   others need etc directory & password/group files.  Experiment.
  218. #
  219. push(@crit_files, $ftpbin, $ftpetc);
  220. for $i (@crit_files) {
  221. X    $owner = &'Owner($i);
  222. X
  223. X    if ($owner eq 'BOGUS') {
  224. X    print "${W}Critical anon-ftp file $i is missing!\n";
  225. X    next;
  226. X    }
  227. X
  228. X    $owner = $'uid2names{$owner};
  229. X
  230. X    if ($owner ne $primary && $owner ne $secondary) {
  231. X    print "${W}$i should be owned by $primary or $secondary, not $owner!\n";
  232. X    }
  233. }
  234. X
  235. #  Don't want the passwd and group files to be the real ones!
  236. if (&'Owner($ftppasswd) ne 'BOGUS' &&
  237. X    $passwd ne $ftppasswd && 
  238. X    system "$CMP -s $passwd $ftppasswd") 
  239. {
  240. X    print "${W}$ftppasswd and $passwd are the same!\n";
  241. }
  242. X
  243. if (&'Owner($ftpgroup) ne 'BOGUS' &&
  244. X    $group ne $ftpgroup && 
  245. X    system "$CMP -s $passwd $ftpgroup") 
  246. {
  247. X    print "${W}$ftpgroup and $group are the same!\n";
  248. }
  249. X
  250. #   ftproot is special; if owned by root; should be !world writable;
  251. # if owned by ftp, should be mode 555
  252. X
  253. if (&'Owner($ftproot) ne BOGUS) {
  254. X    $owner = $'uid2names{&'Owner($ftproot)};
  255. X    $perms=&'Mode($ftproot);
  256. X    if ($owner ne $primary && $owner ne $secondary) {
  257. X    print "${W}$ftproot should be owned by $primary or $secondary, not $owner!\n";
  258. X    }
  259. X
  260. X    # ftp-root should not be world-writable:
  261. X    &'is_able($ftproot, "w", "w");
  262. X
  263. X    # if ftp owns root-dir, then mode should be 555:
  264. X    if ($owner eq $ftpuid && $perms ne 00555) {
  265. X    print "${W}$ftproot should be mode 555!\n";
  266. X    }
  267. }
  268. X
  269. #
  270. # check the .rhosts file:
  271. if (-f $ftprhosts) {
  272. X    if (-s $ftprhosts) {
  273. X    print "${W}$ftprhosts should be be empty!\n";
  274. X    }
  275. X    $owner=$'uid2names{&'Owner($ftprhosts)};
  276. X    if ($owner ne $primary && $owner ne $secondary) {
  277. X    print "${W}$ftprhosts should be owned by $primary or $secondary!\n";
  278. X    }
  279. }
  280. X
  281. # finally, some permissions of miscellaneous files:
  282. if (($perms=&'Mode($ftpls)) & 0666) {
  283. X    printf "${W}Incorrect permissions (%04o) on $ftpls!\n", $perms;
  284. }
  285. X
  286. if (($perms=&'Mode($ftppasswd)) & 0333) {
  287. X    printf "${W}Incorrect permissions (%04o) on $ftppasswd!\n", $perms;
  288. }
  289. X
  290. X
  291. if (($perms=&'Mode($ftpgroup)) & 0333) {
  292. X    printf "${W}Incorrect permissions (%04o) on $ftpgroup!\n", $perms;
  293. }
  294. X
  295. #   Finally, the ~ftp/{pub|incoming|whatever} stuff:
  296. opendir(FTPDIR, $ftproot) || die "can't opendir $ftproot: $!";
  297. X
  298. @all_dirs=grep(-d, readdir(FTPDIR));
  299. X
  300. local($is_able'silent) = 1;  
  301. for $i (@all_dirs) {
  302. X    if ($i ne $incoming && &'is_able($ftproot . "/$i", "w", "w")) {
  303. X    print "${W}Anon-ftp directory $i is World Writable!\n";
  304. X    }
  305. }
  306. X
  307. 1;
  308. # end of script
  309. SHAR_EOF
  310. chmod 0700 p-cops.alpha/ftp.chk ||
  311. echo 'restore of p-cops.alpha/ftp.chk failed'
  312. Wc_c="`wc -c < 'p-cops.alpha/ftp.chk'`"
  313. test 7064 -eq "$Wc_c" ||
  314.     echo 'p-cops.alpha/ftp.chk: original size 7064, current size' "$Wc_c"
  315. rm -f _shar_wnt_.tmp
  316. fi
  317. # ============= p-cops.alpha/get-cf ==============
  318. if test -f 'p-cops.alpha/get-cf' -a X"$1" != X"-c"; then
  319.     echo 'x - skipping p-cops.alpha/get-cf (File already exists)'
  320.     rm -f _shar_wnt_.tmp
  321. else
  322. > _shar_wnt_.tmp
  323. echo 'x - extracting p-cops.alpha/get-cf (Text)'
  324. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/get-cf' &&
  325. #! /usr/local/bin/perl
  326. X
  327. @dot_files = (
  328. X    ".login", ".logout", ".cshrc",            # csh, cshe or tcsh
  329. X    ".profile",                        # ksh, sh
  330. X    ".env",                        # ksh
  331. X    ".alias", ".aliases",                # common for all shells
  332. X    "user.ps", ".user.ps", "tools.ps", ".tools.ps",
  333. X    "startup.ps", ".startup.ps",            # NeWS
  334. X    ".mgrc",                        # MGR
  335. X    ".X11init", ".awmrc", ".twmrc", ".xinitrc",        # X11
  336. X    ".emacs"                        # emacs
  337. );
  338. X
  339. %seen = {};
  340. X
  341. open(HOST, "/bin/hostname |") || die "can't get the hostname";
  342. chop($hostname=<HOST>);
  343. close(HOST);
  344. X
  345. user_loop:
  346. X    for (($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = getpwent();
  347. X         $name ne "";
  348. X         ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = getpwent()) {
  349. X
  350. X    #
  351. X    # If the user has a home directory on this server, get the info 
  352. X    # about the directory, his CF's and so on.
  353. X    #
  354. X    if ($dir =~ m,^/n/$hostname/,) {
  355. X        if (! -d $dir) {
  356. X        printf(stderr "home directory '%s' for user '%s' doesn't exist.\n",
  357. X            $dir,
  358. X            $name);
  359. X        next user_loop;
  360. X        }
  361. X
  362. X        ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
  363. X                    $atime,$mtime,$ctime,$blksize,$blocks)
  364. X                        = stat(_);
  365. X        $mode = $mode & 07777;
  366. X
  367. X        &spit_it_out("d", $uid, $gid, $mode, $dir);
  368. X
  369. X        foreach $file (@dot_files) {
  370. X        $path = "$dir/$file";
  371. X
  372. X        if (-f $path) {
  373. X            ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
  374. X                        $atime,$mtime,$ctime,$blksize,$blocks)
  375. X                            = stat(_);
  376. X            $mode = $mode & 07777;
  377. X
  378. X            &spit_it_out("f", $uid, $gid, $mode, $dir);
  379. X        }
  380. X        }
  381. X    }
  382. X    }
  383. X
  384. X
  385. X
  386. X
  387. sub spit_it_out {
  388. X    local($type, $uid, $gid, $mode, $name) = @_;
  389. X
  390. X    if (defined($seen{$name})) {
  391. X    return;
  392. X    }
  393. X
  394. X    printf("%s %d %d 0%o %s\n", $type, $uid, $gid, $mode, $name);
  395. X    $seen{$name} = 1;
  396. }
  397. X
  398. SHAR_EOF
  399. chmod 0700 p-cops.alpha/get-cf ||
  400. echo 'restore of p-cops.alpha/get-cf failed'
  401. Wc_c="`wc -c < 'p-cops.alpha/get-cf'`"
  402. test 1776 -eq "$Wc_c" ||
  403.     echo 'p-cops.alpha/get-cf: original size 1776, current size' "$Wc_c"
  404. rm -f _shar_wnt_.tmp
  405. fi
  406. # ============= p-cops.alpha/chk_strings ==============
  407. if test -f 'p-cops.alpha/chk_strings' -a X"$1" != X"-c"; then
  408.     echo 'x - skipping p-cops.alpha/chk_strings (File already exists)'
  409.     rm -f _shar_wnt_.tmp
  410. else
  411. > _shar_wnt_.tmp
  412. echo 'x - extracting p-cops.alpha/chk_strings (Text)'
  413. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/chk_strings' &&
  414. #!/bin/sh  # need to mention perl here to avoid recursion
  415. #
  416. #  Usage: chk_strings filename
  417. #
  418. #  This will check pathnames inside executable files for writability,
  419. # The big string "@ignores" is a list of files that are ignored by
  420. # this; you can set it to whatever you want -- default is:
  421. # '^/tmp/?' and '^/(var|usr)/tmp/?'
  422. #  No program root EVER runs should be show up here.
  423. #
  424. # NOTE:
  425. #   If you know where perl is and your system groks #!, put its
  426. # pathname at the top to make this a tad faster.
  427. #
  428. # the following magic is from the perl man page
  429. # and should work to get us to run with perl 
  430. # even if invoked as an sh or csh or foosh script.
  431. # notice we don't use full path cause we don't
  432. # know where the user has perl on their system.
  433. #
  434. eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 
  435. & eval 'exec perl -S $0 $argv:q'
  436. X    if $running_under_some_stupid_shell_instead_of_perl;
  437. X
  438. package main;
  439. X
  440. $| = 1;
  441. X
  442. require 'getopts.pl';
  443. require 'chk_strings.pl';
  444. X
  445. die "Usage: $0 [-fr] file ...\n" unless &Getopts('rd') && @ARGV;
  446. X
  447. package chk_strings;
  448. X
  449. $debug = $'opt_d;
  450. $recurse = $'opt_r;
  451. @ignores = ( '^/tmp/?', '^/(var|usr)/tmp/?' )
  452. X    unless defined @ignores;
  453. X
  454. #%paths = ();  # faster than local
  455. X
  456. for (@'ARGV) { 
  457. X    (warn("$0: $_: $!\n"), next) unless -e;
  458. X    &'chk_strings($_); 
  459. SHAR_EOF
  460. chmod 0700 p-cops.alpha/chk_strings ||
  461. echo 'restore of p-cops.alpha/chk_strings failed'
  462. Wc_c="`wc -c < 'p-cops.alpha/chk_strings'`"
  463. test 1292 -eq "$Wc_c" ||
  464.     echo 'p-cops.alpha/chk_strings: original size 1292, current size' "$Wc_c"
  465. rm -f _shar_wnt_.tmp
  466. fi
  467. # ============= p-cops.alpha/chk_strings.pl ==============
  468. if test -f 'p-cops.alpha/chk_strings.pl' -a X"$1" != X"-c"; then
  469.     echo 'x - skipping p-cops.alpha/chk_strings.pl (File already exists)'
  470.     rm -f _shar_wnt_.tmp
  471. else
  472. > _shar_wnt_.tmp
  473. echo 'x - extracting p-cops.alpha/chk_strings.pl (Text)'
  474. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/chk_strings.pl' &&
  475. #
  476. #  This is a big one.  Support routines to check for strings 
  477. # that look like pathnames and make sure they're not writable.
  478. # Will recurse if $recurse is set.  the shell version can't do
  479. # this (yet).  call &ignore with list of regexps that you don't
  480. # care about.  (or set @ignores)
  481. #
  482. # originally by Tom Christiansen <tchrist@convex.com>
  483. # since hacked on by parties various and sundry.
  484. X
  485. require 'is_able.pl';
  486. require 'file_mode.pl';
  487. require 'pathconf.pl';
  488. X
  489. package chk_strings;
  490. X
  491. X
  492. $'STRINGS = $'STRINGS || '/usr/ucb/strings';
  493. X
  494. for ( '/dev/null', '/dev/tty' ) {
  495. X    $seen{$_}++;
  496. X
  497. sub main'chk_strings {
  498. X    local($ARGV) = @_;
  499. X    local($_);
  500. X    local($word);
  501. X    local(*STRINGS);  # XXX: might run out of fd's on deep recursion!  -tchrist
  502. X    local(%paths, $text); 
  503. X    local($STRINGS) = "$'STRINGS $ARGV |";
  504. X
  505. X    &ignore(@ignores) if defined @ignores && !$already_ignored;
  506. X
  507. X    $STRINGS="< $ARGV", $text=1 if -T $ARGV;
  508. X    print "Opening via: $STRINGS\n" if $debug;
  509. X
  510. X    open (STRINGS, $STRINGS); 
  511. X    while (<STRINGS>) { 
  512. X    next unless m#/#;   # was m#/.*/#;
  513. #---------------------------------------------------------------------------
  514. # Comments and modifications by Martin Foord (maf%dbsm.oz.au@munnari.oz.au).
  515. X    #s/#.*$// if $text;  # strip out comments if -T file
  516. X    # Comments start in the shell at the beginning of a word or at the
  517. X    # beggining of a line
  518. X    if ($text) {
  519. X        s/\s+#.*$//;
  520. X        s/^#.*$//;
  521. X    }
  522. X
  523. X    # Get rid of semicolons, they can hang around on filenames ...
  524. X    s/;//g;
  525. #---------------------------------------------------------------------------
  526. X
  527. X    s/"([^"]*)"/ $1 /g;
  528. X    s/'([^']*)'/ $1 /g;
  529. X    # See my comments below on how to deal with this stuff ... (line 64).
  530. X    #s/`([^`]*)`/ $1 /g;
  531. X
  532. X
  533. X    s!([<>])\s+/!$1/!g;  # "> /foo" goes to ">foo";
  534. X
  535. X    s/=/ /g;  # warning -- mangled files with = in them
  536. X    for $word (split) {
  537. X        if ($word =~ m#:/#) {
  538. X        @paths{split(/:/, $word)} = ();
  539. X        } elsif ($word =~ m#^[<>]?/#) {
  540. X        print "push $word\n" if $debug;
  541. X        $paths{$word}++;
  542. X        }
  543. X    }
  544. X    }
  545. X    close (STRINGS);
  546. X    push(@files, $ARGV);
  547. X
  548. X    for (keys %paths) {
  549. X    s/\)$//;
  550. X    s/^\(//;
  551. X    s#^/+#/#;
  552. X    s#^(/.*)/$#$1#;        # get rid of trailing slash
  553. X
  554. #---------------------------------------------------------------------------
  555. # Comments and modifications by Martin Foord (maf%dbsm.oz.au@munnari.oz.au).
  556. X    # It's best to evaluate what's in backquotes rather than remove them
  557. X    # as in the substitution above, due to files which
  558. X    # look like this /var/yp/`domainname` (eg in my /etc/rc.local).
  559. X    s`\`(.+)\``$1`; # eval what's in backquotes.
  560. X    chop if /\n$/;    # fang off \n if there ...
  561. #---------------------------------------------------------------------------
  562. X    next if &ignored($_);
  563. X    s/^[<>]//;
  564. X    next if $_ eq '';
  565. X    next unless !$seen{$_}++ && -e && !-S _;
  566. X    print "checking $_\n" if $debug;
  567. X    if ($how = &'is_writable($_)) {
  568. X        print "Warning!  File $_ (inside ",
  569. X            join(' inside ', reverse @files), ") is _World_ $how!\n";
  570. X    } elsif ($recurse && (&'Mode($_) & 0111) && -f _) {
  571. X         print "recursing $_\n" if $debug;
  572. X         &'chk_strings($_);   
  573. X    } 
  574. X    }
  575. X     pop(@files);
  576. X
  577. sub ignore {
  578. X    local($_);
  579. X    local($prog);
  580. X
  581. X    $already_ignored = 1;
  582. X
  583. X    $prog = <<'EOCODE';
  584. X
  585. sub ignored {
  586. X    local($return) = 1;
  587. X    local($prog);
  588. X    local($_) = @_;
  589. X    {
  590. EOCODE
  591. X    for (@_) {
  592. X    $prog .= "\tlast if m\201${_}\201;\n";
  593. X    } 
  594. X    $prog .= <<'EOCODE';
  595. X    $return = 0;
  596. X    }
  597. X    print "$_ IGNORED\n" if $debug && $return;
  598. X    $return;
  599. }
  600. EOCODE
  601. X    
  602. X    print $prog if $debug;
  603. X    eval $prog;
  604. X    die $@ if $@;
  605. X
  606. sub ignored {}; # in case they never ignore anything
  607. X
  608. 1;
  609. SHAR_EOF
  610. chmod 0700 p-cops.alpha/chk_strings.pl ||
  611. echo 'restore of p-cops.alpha/chk_strings.pl failed'
  612. Wc_c="`wc -c < 'p-cops.alpha/chk_strings.pl'`"
  613. test 3559 -eq "$Wc_c" ||
  614.     echo 'p-cops.alpha/chk_strings.pl: original size 3559, current size' "$Wc_c"
  615. rm -f _shar_wnt_.tmp
  616. fi
  617. # ============= p-cops.alpha/cops.cf ==============
  618. if test -f 'p-cops.alpha/cops.cf' -a X"$1" != X"-c"; then
  619.     echo 'x - skipping p-cops.alpha/cops.cf (File already exists)'
  620.     rm -f _shar_wnt_.tmp
  621. else
  622. > _shar_wnt_.tmp
  623. echo 'x - extracting p-cops.alpha/cops.cf (Text)'
  624. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/cops.cf' &&
  625. #
  626. # COPS CONFIGURATION FILE
  627. #
  628. # put user variables here: anything beginning with /^\s*[$@%&]/ will be eval'd
  629. # in general, variables in package main are for cops itself, whereas
  630. # those with package qualifiers are for a particular chk routine or
  631. # for auxiliary routines.
  632. X
  633. # COPS  main variables follow...
  634. $NMAIL         = 0;         # send mail instead of generating reports
  635. $ONLY_DIFF     = 0;          # only send diff from last time
  636. $SECURE_USERS   = "root";     # user to receive mailed report
  637. $C2             = 0;        # Sun c2 security package
  638. X
  639. # these don't really work for pass.cache yet
  640. $IGNORE_YP    = 0;
  641. $PASSWD        = '/etc/passwd';
  642. $GROUP        = '/etc/group';
  643. X
  644. ###############################################################
  645. # many things call &chk_strings (including {cron,misc,rc,root}.chk)
  646. # the following two variable settings affects its behaviour...
  647. # this one says to ignore warnings about paths matching these regexps
  648. X
  649. @chk_strings'ignores = ( '^/tmp/?', '^/(var|usr)/tmp/?' );
  650. X
  651. # this will take a bit longer, but can find dangerous things much better
  652. # the shell cops can't do this.... sigh
  653. X
  654. $chk_strings'recurse = 0;
  655. X
  656. # if we want stat failure warnings from is_able...
  657. X
  658. $is_able'noisy = 0;  
  659. X
  660. ###############################################################
  661. # finally the checks to execute.  these can also all be run 
  662. # stand-alone from the shell.
  663. X
  664. # first test the security of the root account
  665. root.chk
  666. X
  667. # now of the various devices.  -g means to check group writability, too
  668. $MTAB    = '/etc/fstab';
  669. $EXPORTS = '/etc/exports';
  670. $TAB_STYLE = 'new';
  671. dev.chk -g 
  672. X
  673. # exaustive tests for things that shouldn't be readable/writable etc
  674. is_able.chk
  675. X
  676. # check for insecuities in /etc/rc*
  677. rc.chk
  678. X
  679. # and in cron
  680. cron.chk
  681. X
  682. # some consistency and idiocy (null or trivial passwds) in /etc/passwd
  683. passwd.chk
  684. pass.chk
  685. X
  686. # consistency checks in /etc/group
  687. group.chk
  688. X
  689. # make sure user accounts don't have trojanable dot files
  690. user.chk
  691. X
  692. # check ftp security
  693. $ftp'primary = "root";
  694. $ftp'secondary = "ftp";
  695. ftp.chk
  696. X
  697. # and anything else we forgot
  698. X
  699. # Sys V types use /etc/servers here:
  700. $misc'inetd = "/etc/inetd";
  701. misc.chk
  702. X
  703. # Kuang!
  704. kuang
  705. X
  706. # SUID checking
  707. # suid.chk
  708. SHAR_EOF
  709. chmod 0700 p-cops.alpha/cops.cf ||
  710. echo 'restore of p-cops.alpha/cops.cf failed'
  711. Wc_c="`wc -c < 'p-cops.alpha/cops.cf'`"
  712. test 2129 -eq "$Wc_c" ||
  713.     echo 'p-cops.alpha/cops.cf: original size 2129, current size' "$Wc_c"
  714. rm -f _shar_wnt_.tmp
  715. fi
  716. # ============= p-cops.alpha/cron.chk ==============
  717. if test -f 'p-cops.alpha/cron.chk' -a X"$1" != X"-c"; then
  718.     echo 'x - skipping p-cops.alpha/cron.chk (File already exists)'
  719.     rm -f _shar_wnt_.tmp
  720. else
  721. > _shar_wnt_.tmp
  722. echo 'x - extracting p-cops.alpha/cron.chk (Text)'
  723. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/cron.chk' &&
  724. #!/bin/sh  # need to mention perl here to avoid recursion
  725. #
  726. #  Usage: cron.chk.pl [-rd]
  727. #
  728. #  This checks pathnames and files inside the cron files /usr/lib/crontab
  729. # for writability.
  730. #
  731. #  Mechanism:  The commands inside the file /usr/lib/crontab are executed
  732. # by root.  This perl script uses chk_strings.pl for chking for writable
  733. # files/dirs.
  734. #
  735. #  cron.chk.pl will try to find a file in /usr/lib/crontab first (bsd),
  736. # and then if it isn't there, it will look in the any alternate
  737. # possible locations next -- right now, /usr/spool/cron/crontab -- to
  738. # see if a directory exists, and, if it does, it checks all the cron
  739. # files in turn.
  740. #
  741. #  WARNING!
  742. #
  743. #  Spurious messages can occur; a more stringent method (if perhaps less
  744. # careful of a check) would be to test just the 6th field, instead of
  745. # all the fields after the fifth.  Also throwing away /tmp, etc. could
  746. # be a mistake.
  747. #
  748. #  NOTE:
  749. # if you know where perl is and your system groks #!, put its
  750. # pathname at the top to make this a tad faster.
  751. #
  752. # the following magic is from the perl man page
  753. # and should work to get us to run with perl 
  754. # even if invoked as an sh or csh or foosh script.
  755. # notice we don't use full path cause we don't
  756. # know where the user has perl on their system.
  757. #
  758. eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 
  759. & eval 'exec perl -S $0 $argv:q'
  760. X    if $running_under_some_stupid_shell_instead_of_perl;
  761. X
  762. package main;
  763. X
  764. require 'getopts.pl';
  765. require 'glob.pl';
  766. require 'chk_strings.pl';
  767. require 'pathconf.pl';
  768. X
  769. # should also add args to override default crontab locations
  770. die "Usage: $0 [-rd]\n" unless &Getopts('rd') && !@ARGV;
  771. X
  772. $chk_strings'debug = $opt_d;
  773. $chk_strings'recurse = $opt_r;
  774. X
  775. package cron_chk;
  776. X
  777. #  Possible location of crontab file:
  778. $cron = "/usr/lib/crontab";
  779. #  alternate reality locations of crontab file:
  780. @alt_cron = ("/usr/spool/cron/crontabs");
  781. X
  782. if ( ! -s $cron) {
  783. X    for (@alt_cron) {
  784. X    # are there ever multiple crontab directories?
  785. X    (@crons = &'glob("$_/*")), last if -d;
  786. X    }
  787. X    die "No crontabs?\n" if ! @crons;
  788. }
  789. @crons = ($cron) unless @crons;
  790. X
  791. # ignore /tmp /dev/null and tty stuff
  792. # &'chk_strings ignores all of above
  793. # STILL NEED to ignore stuff after `>'
  794. #   when we add @ignore stuff to &'chk_strings
  795. X
  796. # finally, do the checking -- maybe for one, maybe for lots of cron-ites:
  797. for (@crons) {
  798. X    if (! -e) {
  799. X    warn "$0: $_: $!\n";
  800. X    next;
  801. X    }
  802. X    &'chk_strings($_);
  803. }
  804. X
  805. 1;
  806. SHAR_EOF
  807. chmod 0700 p-cops.alpha/cron.chk ||
  808. echo 'restore of p-cops.alpha/cron.chk failed'
  809. Wc_c="`wc -c < 'p-cops.alpha/cron.chk'`"
  810. test 2399 -eq "$Wc_c" ||
  811.     echo 'p-cops.alpha/cron.chk: original size 2399, current size' "$Wc_c"
  812. rm -f _shar_wnt_.tmp
  813. fi
  814. # ============= p-cops.alpha/cops ==============
  815. if test -f 'p-cops.alpha/cops' -a X"$1" != X"-c"; then
  816.     echo 'x - skipping p-cops.alpha/cops (File already exists)'
  817.     rm -f _shar_wnt_.tmp
  818. else
  819. > _shar_wnt_.tmp
  820. echo 'x - extracting p-cops.alpha/cops (Text)'
  821. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/cops' &&
  822. #!/bin/sh  # need to mention perl here to avoid recursion
  823. #
  824. #  Usage: cops [-v] [-c config file] [-s secure_dir] [architecture]
  825. #
  826. #  This will change into the $SECURE/architecture directory, suck lots
  827. # of info and configuration stuff out of "cops.cf", and runs all of the
  828. # security programs in that file.  If any of the programs find any 
  829. # security problems, it either sends mail to everyone in the $SECURE_USERS
  830. # list (see "cops.cf"), or saves the results in a file 
  831. # $SECURE/architecture/hostname.  It then destroys all temporary files, 
  832. # and exits the program.  Programs that are run (besides this one):
  833. #
  834. #    root.chk    dev.chk        group.chk
  835. #    rc.chk        passwd.chk    is_able.chk
  836. #    pass.chk     user.chk    cron.chk
  837. #    misc.chk    ftp.chk
  838. #
  839. #  This -v (verbose) flag prints out the name each program to 
  840. # the results file as it is executed.  The -s and -c flags allow you
  841. # to specify the $SECURE directory and $CONFIG file, respectively.
  842. # NOTE:
  843. #   If you know where perl is and your system groks #!, put its
  844. # pathname at the top to make this a tad faster.
  845. #
  846. # the following magic is from the perl man page
  847. # and should work to get us to run with perl 
  848. # even if invoked as an sh or csh or foosh script.
  849. # notice we don't use full path cause we don't
  850. # know where the user has perl on their system.
  851. #
  852. eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 
  853. & eval 'exec perl -S $0 $argv:q'
  854. X    if $running_under_some_stupid_shell_instead_of_perl;
  855. X
  856. ######################################
  857. # perl COPS main driver.
  858. # tchrist@convex.com
  859. ######################################
  860. X
  861. # security sanity settings
  862. #
  863. $ENV{'IFS'} = '' if $ENV{'IFS'};
  864. $ENV{'PATH'} = '/bin:/usr/bin:/usr/ucb';
  865. $| = 1;
  866. umask 077;
  867. X
  868. #
  869. # Getopts stuff
  870. $usage = "Usage: $0 [-v] [-c config_file] [-s secure_dir] architecture\n";
  871. require 'getopts.pl';
  872. # Process the command args; Either specify verbose or an alternate config file:
  873. die $usage unless &Getopts('vc:s:');
  874. X
  875. if (defined($opt_v)) { $verbose = $opt_v;}
  876. else { $verbose = 0; }
  877. X
  878. if (defined($opt_s)) { $SECURE = $LIBCOPS = $opt_s; }
  879. else { $SECURE = $LIBCOPS = '.'; }
  880. X
  881. if (defined($opt_c)) { $CONFIG = $opt_c; }
  882. else {$CONFIG = "$SECURE/cops.cf"; }
  883. X
  884. if (@ARGV > 1) {
  885. X    die $usage;
  886. } elsif (@ARGV == 1) {
  887. X    $SECURE = shift;
  888. X    die "Architecture directory $SECURE does not exist\n" unless -d $SECURE;
  889. X    chdir($SECURE) || die "can't cd to $SECURE: $!";
  890. X    exec './cops';
  891. X
  892. # internal cops stuff needed
  893. require "$LIBCOPS/pathconf.pl";
  894. require "$LIBCOPS/is_able.pl";
  895. X
  896. chmod 0700, $SECURE;  
  897. chdir ($SECURE) || die "Error -- Security directory $SECURE doesn't exist";
  898. X
  899. #  Read stuff to do from the config file
  900. die "$0: Can't trust $CONFIG to reconfig!"     if &'is_writable($CONFIG);
  901. open CONFIG || die "can't open $CONFIG: $!";
  902. X
  903. &argh unless -s $CONFIG;
  904. X
  905. &init_result;
  906. X
  907. while (<CONFIG>) {
  908. X    next if /^\s*#/;
  909. X    next if /^\s*$/;
  910. X
  911. X    if (/^\s*[\$&\@\%]/) {  #  reset a config variable
  912. X    s/#.*//;
  913. X    eval;
  914. X    warn "Bad config variable at line $. of $CONFIG:\n\t$_\t$@\n" if $@;
  915. X    next;
  916. X    } 
  917. X
  918. X    # must be a program to run
  919. X    chop;
  920. X    s/#.*//;
  921. X    s/;$//;
  922. X    @ARGV=split;
  923. X    $program = shift;
  924. X    if ($verbose) { print "\n******* $program *******\n\n"; }
  925. X    &flush;
  926. X    &run("$LIBCOPS/$program");
  927. X    &flush;
  928. X
  929. X
  930. &save_result;
  931. X
  932. &argh unless $ran_something;
  933. X
  934. Xexit 0;
  935. X
  936. ######################################################################
  937. sub run {
  938. X    local($module) = @_;
  939. X    local($status);
  940. X    local($0) = $module; # so it shows up in ps
  941. X    local($!);
  942. X
  943. X
  944. X    $ran_something++;
  945. X
  946. X    open(STDERR, $COPS_ERRORS ? ">&STDOUT" : ">/dev/null");
  947. X
  948. X    unless ($status = do $module) {
  949. X    if ($@) {
  950. X        warn "cops: unexpected exit from $module:\n\t-> $@\n";
  951. X    } elsif ($! != 0) {
  952. X        warn "cops: couldn't run $module: $!\n";
  953. X    } else {
  954. X        warn "cops: $module returned $status\n";
  955. X    } 
  956. X    }
  957. X
  958. X    # hack for kuang, who doesn't write to STDOUT (yet!)
  959. X    $SUCCESS = "$SECURE/Success";
  960. X    if ($module =~ /^kuang/ && -e $SUCCESS) {
  961. X    if (open SUCCESS) {
  962. X        print while <SUCCESS>;  # STDOUT is $REPORT
  963. X        close SUCCESS;
  964. X        unlink $SUCCESS;
  965. X    } else {
  966. X        warn "can't open $SUCCESS: $!";
  967. X    } 
  968. X    } 
  969. }
  970. ######################################################################
  971. sub init_result {
  972. X    $REPORT = "$SECURE/result.$$";  # global!
  973. X    open (REPORT, ">$REPORT") || die "can't create $REPORT: $!";
  974. X
  975. X    # assume dups work
  976. X    open (STDOUT, ">&REPORT");
  977. X    open (SAVERR, ">&STDERR");
  978. X    open (STDERR, ">&STDOUT");
  979. X
  980. X    ($sec, $min, $hour, $mday, $mon, $year,
  981. X    $wday, $yday, $isdst) = localtime(time);
  982. X
  983. X    $name = sprintf("%s_%s_%s", $year + 1900, 
  984. X    (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)[$mon],
  985. X    $mday);
  986. X
  987. X    $host =  ( -x '/bin/hostname'   && `/bin/hostname` ) 
  988. X      || ( -x '/bin/uname'      && `/bin/uname -n` )
  989. X      || ( -x '/usr/bin/uuname' && `/usr/bin/uuname -l`)
  990. X      || 'Amnesiac!';
  991. X
  992. X    chop $host;
  993. X    $host =~ s/\..*//;
  994. X
  995. X    print "ATTENTION:\nSecurity report for ", `date`;
  996. X    print "\nfrom host $host, $name\n\n";
  997. X    $report = $name;
  998. X
  999. X    &flush;
  1000. }
  1001. ######################################################################
  1002. sub save_result {
  1003. X    open(STDERR, ">&SAVERR");
  1004. X
  1005. X    close REPORT || die "can't close $REPORT: $!";
  1006. X
  1007. X    $dir = "$SECURE/$host";
  1008. X    $report = $dir . "/" . $report;
  1009. X
  1010. X    mkdir($dir,0700) unless -d $dir;
  1011. X
  1012. X    if ($NMAIL) {
  1013. X    system "$MAIL $SECURE_USERS < $REPORT"
  1014. X        unless $ONLY_DIFF && !&different($dir, $REPORT);
  1015. X    } else {
  1016. #    rename ($REPORT, $dir . "/" . $name) ||
  1017. #        die "can't put $REPORT into $dir/$name: $!";
  1018. X    rename ($REPORT, $report) ||
  1019. X        die "can't put $REPORT into $report: $!";
  1020. X    }
  1021. X    unlink $REPORT;
  1022. X
  1023. ######################################################################
  1024. sub different {
  1025. X    local($dir, $FILE1) = @_;
  1026. X    local($FILE2, $f1, $f2, $_);
  1027. X
  1028. X    open (LS, "$LS -t $dir |");
  1029. X    chop($FILE2 = <LS>);
  1030. X    close(LS); # snuff it out
  1031. X
  1032. X
  1033. X    return 1 if !$FILE2 || -s $FILE1 != -s $FILE2;
  1034. X
  1035. X    open FILE1 || die "can't open $FILE1: $!";
  1036. X    open FILE2 || die "can't open $FILE2: $!";
  1037. X
  1038. X    for (1..5) {
  1039. X    $_ = <FILE1>;
  1040. X    $_ = <FILE2>;
  1041. X    } 
  1042. X
  1043. X    while ( ($f1 = <FILE1>), ($f2 = <FILE2>) ) {
  1044. X    last if $f1 ne $f2;
  1045. X    } 
  1046. X
  1047. X    close FILE1;
  1048. X    close FILE2;
  1049. X
  1050. X    defined($f1) || defined($f2);
  1051. X
  1052. ######################################################################
  1053. sub flush {
  1054. X    local($old) = $|;
  1055. X    $| = 1;
  1056. X    print '';
  1057. X    $| = $old;
  1058. X
  1059. sub argh {
  1060. X    die "Argh -- Can't find anything in $CONFIG\n";
  1061. }
  1062. SHAR_EOF
  1063. chmod 0700 p-cops.alpha/cops ||
  1064. echo 'restore of p-cops.alpha/cops failed'
  1065. Wc_c="`wc -c < 'p-cops.alpha/cops'`"
  1066. test 6390 -eq "$Wc_c" ||
  1067.     echo 'p-cops.alpha/cops: original size 6390, current size' "$Wc_c"
  1068. rm -f _shar_wnt_.tmp
  1069. fi
  1070. # ============= p-cops.alpha/fgrep.pl ==============
  1071. if test -f 'p-cops.alpha/fgrep.pl' -a X"$1" != X"-c"; then
  1072.     echo 'x - skipping p-cops.alpha/fgrep.pl (File already exists)'
  1073.     rm -f _shar_wnt_.tmp
  1074. else
  1075. > _shar_wnt_.tmp
  1076. echo 'x - extracting p-cops.alpha/fgrep.pl (Text)'
  1077. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/fgrep.pl' &&
  1078. #
  1079. #  Just a quick perl fgrep...
  1080. #
  1081. package fgrep;
  1082. X
  1083. sub main'fgrep {
  1084. X    local($file, @exprs) = @_;
  1085. X    local(@list);
  1086. X
  1087. X    if (open file) {
  1088. X    $code = "while (<file>) {\n\tchop;\n";
  1089. X    for (@exprs) {
  1090. X        $code .= "\tpush(\@list, \$_), next if m\201${_}\201;\n";
  1091. X    } 
  1092. X    $code .= "}\n";
  1093. X    warn "fgrep code is $code" if $debug;
  1094. X    eval $code;
  1095. X    warn "fgrep @exprs $file: $@\n" if $@;
  1096. X    } elsif ($debug) {
  1097. X    warn "main'fgrep: can't open $file: $!\n";
  1098. X    } 
  1099. X
  1100. X    @list;
  1101. X
  1102. 1;
  1103. SHAR_EOF
  1104. chmod 0700 p-cops.alpha/fgrep.pl ||
  1105. echo 'restore of p-cops.alpha/fgrep.pl failed'
  1106. Wc_c="`wc -c < 'p-cops.alpha/fgrep.pl'`"
  1107. test 463 -eq "$Wc_c" ||
  1108.     echo 'p-cops.alpha/fgrep.pl: original size 463, current size' "$Wc_c"
  1109. rm -f _shar_wnt_.tmp
  1110. fi
  1111. # ============= p-cops.alpha/file_mode.pl ==============
  1112. if test -f 'p-cops.alpha/file_mode.pl' -a X"$1" != X"-c"; then
  1113.     echo 'x - skipping p-cops.alpha/file_mode.pl (File already exists)'
  1114.     rm -f _shar_wnt_.tmp
  1115. else
  1116. > _shar_wnt_.tmp
  1117. echo 'x - extracting p-cops.alpha/file_mode.pl (Text)'
  1118. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/file_mode.pl' &&
  1119. #
  1120. #  This retrieves a possibly cached mode on file.
  1121. # If it returns "BOGUS", it means that the stat failed.
  1122. #
  1123. # tchrist@convx.com
  1124. X
  1125. package main;
  1126. require 'stat.pl';
  1127. X
  1128. package file_mode;
  1129. X
  1130. sub main'Mode {
  1131. X    local($file) = @_;
  1132. X
  1133. X    if (!defined $modes{$file}) {
  1134. X       if (&'Stat($file)) {
  1135. X           $modes{$file} = $'st_mode;
  1136. X       } else {
  1137. X           $modes{$file} = 'BOGUS';
  1138. X       }
  1139. X    }
  1140. X    $modes{$file};
  1141. }
  1142. SHAR_EOF
  1143. chmod 0700 p-cops.alpha/file_mode.pl ||
  1144. echo 'restore of p-cops.alpha/file_mode.pl failed'
  1145. Wc_c="`wc -c < 'p-cops.alpha/file_mode.pl'`"
  1146. test 413 -eq "$Wc_c" ||
  1147.     echo 'p-cops.alpha/file_mode.pl: original size 413, current size' "$Wc_c"
  1148. rm -f _shar_wnt_.tmp
  1149. fi
  1150. # ============= p-cops.alpha/file_owner.pl ==============
  1151. if test -f 'p-cops.alpha/file_owner.pl' -a X"$1" != X"-c"; then
  1152.     echo 'x - skipping p-cops.alpha/file_owner.pl (File already exists)'
  1153.     rm -f _shar_wnt_.tmp
  1154. else
  1155. > _shar_wnt_.tmp
  1156. echo 'x - extracting p-cops.alpha/file_owner.pl (Text)'
  1157. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/file_owner.pl' &&
  1158. #
  1159. #   This retrieves possibly cached owner of a file.
  1160. # If it returns "BOGUS", it means that the stat failed.
  1161. X
  1162. package main;
  1163. require 'stat.pl';
  1164. X
  1165. package file_owner;
  1166. X
  1167. sub main'Owner {
  1168. X    local($file) = @_;
  1169. X
  1170. X    if (!defined $owners{$file}) {
  1171. X       if (&'Stat($file)) {
  1172. X           $owners{$file} = $'st_uid;
  1173. X       } else {
  1174. X           $owners{$file} = 'BOGUS';
  1175. X       }
  1176. X    }
  1177. X    $owners{$file};
  1178. }
  1179. SHAR_EOF
  1180. chmod 0700 p-cops.alpha/file_owner.pl ||
  1181. echo 'restore of p-cops.alpha/file_owner.pl failed'
  1182. Wc_c="`wc -c < 'p-cops.alpha/file_owner.pl'`"
  1183. test 398 -eq "$Wc_c" ||
  1184.     echo 'p-cops.alpha/file_owner.pl: original size 398, current size' "$Wc_c"
  1185. rm -f _shar_wnt_.tmp
  1186. fi
  1187. # ============= p-cops.alpha/dev.chk ==============
  1188. if test -f 'p-cops.alpha/dev.chk' -a X"$1" != X"-c"; then
  1189.     echo 'x - skipping p-cops.alpha/dev.chk (File already exists)'
  1190.     rm -f _shar_wnt_.tmp
  1191. else
  1192. > _shar_wnt_.tmp
  1193. echo 'x - extracting p-cops.alpha/dev.chk (Text)'
  1194. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/dev.chk' &&
  1195. #!/bin/sh  # need to mention perl here to avoid recursion
  1196. #
  1197. #  dev.chk [-g]
  1198. #
  1199. #   This shell script checks the permissions of all devs listed in the
  1200. # file /etc/fstab (the "mount" command would be a preferable way of
  1201. # getting the file system name, but the syntax of the output is variable
  1202. # from machine to machine), and flags them if they are readable by using
  1203. # the "is_readable" command.  It also checks for unrestricted NFS
  1204. # mountings.  By default, dev_check will flag devs only if world readable
  1205. # or writable.  The -g option tells it to print out devs that are also
  1206. # group readable/writable.
  1207. #   As an aside, the fact that NFS mounted dirs are world readable isn't
  1208. # a big deal, but they shouldn't be world writable.  So do two checks here,
  1209. # instead of one.
  1210. #
  1211. #  Two types of /etc/fstab formats I've seen so far:
  1212. #
  1213. # "old" --
  1214. #  spec:file:type:freq:passno:name:options
  1215. #      NFS are indicated by an "@"
  1216. #
  1217. # "new" --
  1218. #  fsname dir type opts freq passno
  1219. #      NFS are indicated by an ":"
  1220. #
  1221. #  NOTE:
  1222. # if you know where perl is and your system groks #!, put its
  1223. # pathname at the top to make this a tad faster.
  1224. #
  1225. # the following magic is from the perl man page
  1226. # and should work to get us to run with perl 
  1227. # even if invoked as an sh or csh or foosh script.
  1228. # notice we don't use full path cause we don't
  1229. # know where the user has perl on their system.
  1230. #
  1231. eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 
  1232. & eval 'exec perl -S $0 $argv:q'
  1233. X    if $running_under_some_stupid_shell_instead_of_perl;
  1234. X
  1235. #
  1236. #  dev.chk [-g]
  1237. # tchrist@convx.com
  1238. #
  1239. X
  1240. require 'is_able.pl';
  1241. X
  1242. $MTAB    = '/etc/fstab' unless defined $MTAB;
  1243. $EXPORTS = '/etc/exports' unless defined $EXPORTS;
  1244. $TAB_STYLE = 'new' unless defined $TAB_STYLE;  # or 'old'  
  1245. X
  1246. &usage if @ARGV > 1;
  1247. X
  1248. sub usage { die "Usage: $0 [-g]\n"; }
  1249. X
  1250. if (@ARGV == 1) {
  1251. X    if ($ARGV[0] eq '-g') {
  1252. X    $group++;
  1253. X    } else {
  1254. X    &usage;
  1255. X    } 
  1256. X
  1257. X
  1258. open MTAB || die "can't open $MTAB: $!";
  1259. X
  1260. while (<MTAB>) {
  1261. X    next if /^#/;
  1262. X    chop;
  1263. X    if ($TAB_STYLE eq 'new') {
  1264. X    ($dev, $fs) = split;
  1265. X    next unless $fs;
  1266. X    if ($dev =~ /:/) {
  1267. X        push(@nfs_devs, $fs);
  1268. X    } else {
  1269. X        push(@local_devs, $dev);
  1270. X    } 
  1271. X    } else {
  1272. X    ($dev, $fs) = split(/:/);
  1273. X    next unless $fs;
  1274. X    if ($dev =~ /@/) {
  1275. X        push(@nfs_devs, $fs);
  1276. X    } else {
  1277. X        push(@local_devs, $dev);
  1278. X    } 
  1279. X    } 
  1280. X
  1281. X
  1282. if (open EXPORTS) {
  1283. X    while (<EXPORTS>) {
  1284. X    next if /^\s*#/;
  1285. X    next if /\S\s+\S/;
  1286. X    chop;
  1287. X    printf "Warning!  NFS file system $_ exported with no restrictions.\n";
  1288. X    } 
  1289. X
  1290. # WARNING: we may hang if server down....
  1291. #
  1292. for (@nfs_devs, @local_devs) {
  1293. X    &is_able($_, 'w', 'w');
  1294. X    next unless $group;
  1295. X    &is_able($_, 'g', 'w');
  1296. X
  1297. for (@local_devs) {
  1298. X    &is_able($_, 'w', 'r');
  1299. X    next unless $group;
  1300. X    &is_able($_, 'g', 'r');
  1301. X
  1302. 1;
  1303. SHAR_EOF
  1304. chmod 0700 p-cops.alpha/dev.chk ||
  1305. echo 'restore of p-cops.alpha/dev.chk failed'
  1306. Wc_c="`wc -c < 'p-cops.alpha/dev.chk'`"
  1307. test 2739 -eq "$Wc_c" ||
  1308.     echo 'p-cops.alpha/dev.chk: original size 2739, current size' "$Wc_c"
  1309. rm -f _shar_wnt_.tmp
  1310. fi
  1311. # ============= p-cops.alpha/getopts.pl ==============
  1312. if test -f 'p-cops.alpha/getopts.pl' -a X"$1" != X"-c"; then
  1313.     echo 'x - skipping p-cops.alpha/getopts.pl (File already exists)'
  1314.     rm -f _shar_wnt_.tmp
  1315. else
  1316. > _shar_wnt_.tmp
  1317. echo 'x - extracting p-cops.alpha/getopts.pl (Text)'
  1318. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/getopts.pl' &&
  1319. ;# getopts.pl - a better getopt.pl
  1320. X
  1321. ;# Usage:
  1322. ;#      do Getopts('a:bc');  # -a takes arg. -b & -c not. Sets opt_* as a
  1323. ;#                           #  side effect.
  1324. X
  1325. sub Getopts {
  1326. X    local($argumentative) = @_;
  1327. X    local(@args,$_,$first,$rest,$errs);
  1328. X    local($[) = 0;
  1329. X
  1330. X    @args = split( / */, $argumentative );
  1331. X    while(($_ = $ARGV[0]) =~ /^-(.)(.*)/) {
  1332. X    ($first,$rest) = ($1,$2);
  1333. X    $pos = index($argumentative,$first);
  1334. X    if($pos >= $[) {
  1335. X        if($args[$pos+1] eq ':') {
  1336. X        shift(@ARGV);
  1337. X        if($rest eq '') {
  1338. X            $rest = shift(@ARGV);
  1339. X        }
  1340. X        eval "\$opt_$first = \$rest;";
  1341. X        }
  1342. X        else {
  1343. X        eval "\$opt_$first = 1";
  1344. X        if($rest eq '') {
  1345. X            shift(@ARGV);
  1346. X        }
  1347. X        else {
  1348. X            $ARGV[0] = "-$rest";
  1349. X        }
  1350. X        }
  1351. X    }
  1352. X    else {
  1353. X        print STDERR "Unknown option: $first\n";
  1354. X        ++$errs;
  1355. X        if($rest ne '') {
  1356. X        $ARGV[0] = "-$rest";
  1357. X        }
  1358. X        else {
  1359. X        shift(@ARGV);
  1360. X        }
  1361. X    }
  1362. X    }
  1363. X    $errs == 0;
  1364. }
  1365. X
  1366. 1;
  1367. SHAR_EOF
  1368. chmod 0700 p-cops.alpha/getopts.pl ||
  1369. echo 'restore of p-cops.alpha/getopts.pl failed'
  1370. Wc_c="`wc -c < 'p-cops.alpha/getopts.pl'`"
  1371. test 902 -eq "$Wc_c" ||
  1372.     echo 'p-cops.alpha/getopts.pl: original size 902, current size' "$Wc_c"
  1373. rm -f _shar_wnt_.tmp
  1374. fi
  1375. # ============= p-cops.alpha/glob.pl ==============
  1376. if test -f 'p-cops.alpha/glob.pl' -a X"$1" != X"-c"; then
  1377.     echo 'x - skipping p-cops.alpha/glob.pl (File already exists)'
  1378.     rm -f _shar_wnt_.tmp
  1379. else
  1380. > _shar_wnt_.tmp
  1381. echo 'x - extracting p-cops.alpha/glob.pl (Text)'
  1382. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/glob.pl' &&
  1383. #
  1384. #  This does shell or perl globbing without resorting
  1385. # to the shell -- we were having problems with the shell blowing
  1386. # up with extra long pathnames and lots of file names.  set $glob'debug 
  1387. # for trace information.
  1388. #
  1389. # tom christiansen <tchrist@convex.com>
  1390. X
  1391. package glob;
  1392. X
  1393. sub main'glob { 
  1394. X    local($expr) = @_;
  1395. X    local(@files);
  1396. X
  1397. X    $? = 0;
  1398. X    open(SAVERR, ">&STDERR"); close(STDERR);  # suppress args too long
  1399. X    @files = <${expr}>;
  1400. X    if ($?) {
  1401. X    print SAVERR "shell glob blew up on $expr\n" if $debug;
  1402. X    @files = &SHglob($expr);
  1403. X    }
  1404. X    open (STDERR, ">&SAVERR");
  1405. X    # if (@files == 1 && $files[0] eq $expr) { @files = ''; } # sh foo
  1406. X    @files;
  1407. }
  1408. X
  1409. sub main'SHglob {
  1410. X    local($expr) = @_;
  1411. X    local(@retlist) = ();
  1412. X    local($dir);
  1413. X
  1414. X    printf "SHglob: globbing $expr\n" if $debug;
  1415. X
  1416. X    $expr =~ s/([.{+\\])/\\$1/g;
  1417. X    $expr =~ s/\*/.*/g;
  1418. X    $expr =~ s/\?/./g;
  1419. X
  1420. X    for $dir (split(' ',$expr)) {
  1421. X    push(@retlist, &main'REglob($dir));
  1422. X    } 
  1423. X
  1424. X    return sort @retlist;
  1425. X
  1426. sub main'REglob {
  1427. X    local($path) = @_;
  1428. X    local($_);
  1429. X    local(@retlist) = ();
  1430. X    local($root,$expr,$pos);
  1431. X    local($relative) = 0;
  1432. X    local(@dirs);
  1433. X    local($user);
  1434. X
  1435. X    $haveglobbed = 0;
  1436. X
  1437. X    @dirs = split(/\/+/, $path);
  1438. X
  1439. X    if ($dirs[$[] =~ m!~(.*)!) {
  1440. X    $dirs[$[] = &homedir($1);
  1441. X    return @retlist unless $dirs[$[];
  1442. X    } elsif ($dirs[$[] eq '') {
  1443. X    $dirs[$[] = '/' unless $dirs[$[] =~ m!^\.{1,2}$!;
  1444. X    } else {
  1445. X    unshift(@dirs, '.');
  1446. X    $relative = 1;
  1447. X    } 
  1448. X
  1449. X    printf "REglob: globbing %s\n", join('/',@dirs) if $debug;
  1450. X
  1451. X    @retlist = &expand(@dirs);
  1452. X
  1453. X    for (@retlist) {
  1454. X    if ($relative) {
  1455. X        s!^\./!!o;
  1456. X    }
  1457. X    s!/{2,}!/!g;
  1458. X    } 
  1459. X
  1460. X    return sort @retlist;
  1461. }
  1462. X
  1463. sub expand {
  1464. X    local($dir, $thisdir, @rest) = @_;
  1465. X    local($nextdir);
  1466. X    local($_);
  1467. X    local(@retlist) = ();
  1468. X    local(*DIR);
  1469. X
  1470. X    unless ($haveglobbed || $thisdir =~ /([^\\]?)[?.*{[+\\]/ && $1 ne '\\') {
  1471. X    @retlist = ($thisdir);
  1472. X    } else {
  1473. X    unless (opendir(DIR,$dir)) {
  1474. X        warn "glob: can't opendir $dir: $!\n" if $debug;
  1475. X    } else {
  1476. X        @retlist = grep(/^$thisdir$/,readdir(DIR));
  1477. X        @retlist = grep(!/^\./, @retlist) unless $thisdir =~ /^\\\./;
  1478. X        $haveglobbed++;
  1479. X    } 
  1480. X    closedir DIR;
  1481. X    } 
  1482. X
  1483. X    for (@retlist) {
  1484. X    $_ = $dir . '/' . $_;
  1485. X    }
  1486. X
  1487. X    if ($nextdir = shift @rest) {
  1488. X    local(@newlist) = ();
  1489. X    for (@retlist) {
  1490. X        push(@newlist,&expand($_,$nextdir,@rest));
  1491. X    } 
  1492. X    @retlist = @newlist;
  1493. X    } 
  1494. X
  1495. X    return @retlist;
  1496. X
  1497. sub homedir {
  1498. X    local($user) = @_;
  1499. X    local(@pwent);
  1500. X    # global %homedir
  1501. X
  1502. X    if (!$user) {
  1503. X    return $ENV{'HOME'}         if $ENV{'HOME'};
  1504. X    ($user = $ENV{'USER'})      || 
  1505. X        ($user = getlogin)         || 
  1506. X        (($user) = getpwnam($>));
  1507. X    warn "glob'homedir: who are you, user #$>?" unless $user;
  1508. X    return '/';
  1509. X    } 
  1510. X    unless (defined $homedir{$user}) {
  1511. X    if (@pwent = getpwnam($user)) {
  1512. X        $homedir{$user} = $pwent[$#pwent - 1];
  1513. X    } else {
  1514. X        warn "glob'homedir: who are you, user #$>?" unless $user;
  1515. X        $homedir{$user} = '/';
  1516. X    }
  1517. X    }
  1518. X    return $homedir{$user};
  1519. X
  1520. X
  1521. 1;
  1522. SHAR_EOF
  1523. chmod 0700 p-cops.alpha/glob.pl ||
  1524. echo 'restore of p-cops.alpha/glob.pl failed'
  1525. Wc_c="`wc -c < 'p-cops.alpha/glob.pl'`"
  1526. test 2960 -eq "$Wc_c" ||
  1527.     echo 'p-cops.alpha/glob.pl: original size 2960, current size' "$Wc_c"
  1528. rm -f _shar_wnt_.tmp
  1529. fi
  1530. # ============= p-cops.alpha/group.chk ==============
  1531. if test -f 'p-cops.alpha/group.chk' -a X"$1" != X"-c"; then
  1532.     echo 'x - skipping p-cops.alpha/group.chk (File already exists)'
  1533.     rm -f _shar_wnt_.tmp
  1534. else
  1535. > _shar_wnt_.tmp
  1536. echo 'x - extracting p-cops.alpha/group.chk (Text)'
  1537. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/group.chk' &&
  1538. #!/bin/sh  # need to mention perl here to avoid recursion
  1539. #
  1540. #   group.chk.pl
  1541. #
  1542. #  Check group file -- /etc/group -- for incorrect number of fields,
  1543. # duplicate groups, non-alphanumeric group names, and non-numeric group
  1544. # id's.
  1545. #
  1546. #   Mechanism:  Group.check uses awk to ensure that each line of the group
  1547. # has 4 fields, as well as examining each line for any duplicate groups or
  1548. # any duplicate user id's in a given group by using "sort -u" to ferret
  1549. # out any duplications.  It also checks to make sure that the password
  1550. # field (the second one) is a "*", meaning the group has no password (a
  1551. # group password is usually not necessary because each member listed on 
  1552. # the line has all the privilages that the group has.)  All results are
  1553. # echoed to standard output.  Finally it ensures that the group names
  1554. # are alphanumeric, that the group id's are numeric, and that there are
  1555. # no blank lines.  For yellow pages groups, it does the same checking,
  1556. # but in order to get a listing of all members of the groups, it does a
  1557. # "ypcat group".
  1558. #
  1559. #   The /etc/group file has a very specific format, making the task
  1560. # fairly simple.  Normally it has lines with 4 fields, each field
  1561. # separated by a colon (:).  The first field is the group name, the second
  1562. # field is the encrypted password (an asterix (*) means the group has no
  1563. # password, otherwise the first two characters are the salt), the third
  1564. # field is the group id number, and the fourth field is a list of user
  1565. # ids in the group.  If a line begins with a plus sign (+), it is a yellow
  1566. # pages entry.  See group(5) for more information.
  1567. #
  1568. # NOTE:
  1569. #   If you know where perl is and your system groks #!, put its
  1570. # pathname at the top to make this a tad faster.
  1571. #
  1572. # the following magic is from the perl man page
  1573. # and should work to get us to run with perl 
  1574. # even if invoked as an sh or csh or foosh script.
  1575. # notice we don't use full path cause we don't
  1576. # know where the user has perl on their system.
  1577. #
  1578. eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 
  1579. & eval 'exec perl -S $0 $argv:q'
  1580. X    if $running_under_some_stupid_shell_instead_of_perl;
  1581. X
  1582. # should get below config stuff from cops.cf file
  1583. package main;
  1584. X
  1585. die "Usage: $0\n" if @ARGV;
  1586. X
  1587. require 'pathconf.pl';
  1588. X
  1589. #   Used for Sun C2 security group file.  FALSE (default) will flag
  1590. # valid C2 group syntax as an error, TRUE attempts to validate it.
  1591. # Thanks to Pete Troxell for pointing this out.
  1592. #
  1593. # moved to cops.cf
  1594. X
  1595. $etc_group=$GROUP || '/etc/group';
  1596. X
  1597. package group_chk;
  1598. X
  1599. $yptmp = "./yptmp.$$";
  1600. X
  1601. # Testing $etc_group for potential problems....
  1602. open (Group, "< $'etc_group") || warn "$0: Can't open $'etc_group: $!\n";
  1603. &chk_group_file_format('Group');
  1604. close Group;
  1605. X
  1606. # Testing ypcat group for potential problems
  1607. $yp=0;
  1608. if (-s $'YPCAT && -x _) {
  1609. X    system("$'YPCAT group >$yptmp 2>/dev/null");  
  1610. X    if (-s $yptmp) {
  1611. X       open(YGroup, "$'YPCAT group |") || die "$0: Can't popen $'YPCAT: $!\n";
  1612. X       &chk_group_file_format('YGroup');
  1613. X       close(YGroup);
  1614. X       $yp=1;
  1615. X   }
  1616. }
  1617. X
  1618. # usage: &chk_group_file_format('Filehandle-name');
  1619. # skips over lines that begin with "+:"
  1620. # It really should check for correct yellow pages syntax....
  1621. #
  1622. # this routine checks lines read from a filehandle for potential format
  1623. # problems .. should be matching group(5)
  1624. #
  1625. # checks for duplicate users in a group as it reads the lines instead
  1626. # of after (as the original shell script does)
  1627. X
  1628. sub chk_group_file_format {
  1629. X    local($file) = @_;
  1630. X    local($W) = "Warning!  $file file,";
  1631. X
  1632. X    while (<$file>) {
  1633. X    next if /^\+:/;
  1634. X    print "$W line $., is blank\n" if /^\s*$/;
  1635. X    split(/:/);
  1636. X    $groups{$_[0]}++;   # keep track of dups
  1637. X    print "$W line $., does not have 4 fields: $_" if (@_ != 4);
  1638. X    print "$W line $., nonalphanumeric group name: $_"
  1639. X        if $_[0] !~ /^[A-Za-z0-9-]+$/;
  1640. X    if ($_[1] && $_[1] ne '*') {
  1641. X        if ( ! $C2 || $yp ) {
  1642. X        print "$W line $., group has password: $_"
  1643. X            if length($_[1]) == 13;
  1644. X        } else {
  1645. X        print "$W line $., group has invalid field for C2:\n$_"
  1646. X            if $_[1] ne "#\$$_[0]";
  1647. X        }
  1648. X    }
  1649. X    print "$W line $., nonnumeric group id: $_" if $_[2] !~ /^\d+$/;
  1650. X
  1651. X    # look for duplicate users in a group
  1652. X    # kinda ugly, but it works .. and I have too much other work right
  1653. X    # now to clean it up.  maybe later.. ;-)
  1654. X    chop($_[3]);    # down here, 'cos split gets rid of final null fields
  1655. X    @users = sort split(/\s*,\s*/, $_[3]);
  1656. X    # %users = # of times user is in group, $dup_user = duplicate found
  1657. X    undef %users;  $dup_user=0;
  1658. X    grep(!$users{$_}++, @users);
  1659. X    for (keys %users) {
  1660. X        (print "Warning!  Group $_[0] has duplicate user(s):\n"),
  1661. X        $dup_user=1 if !$dup_user && $users{$_} > 1;
  1662. X        print "$_ " if $users{$_} > 1;
  1663. X    }
  1664. X    print "\n" if $dup_user;
  1665. X
  1666. X    }
  1667. X    # find duplicate group names 
  1668. X    # not the best way, but it works..
  1669. X    # boy, this is ugly too .. but, not as bad as above.. :)
  1670. X    $dup_warned = 0;
  1671. X    for (sort keys %groups) {
  1672. X    (print "Warning!  Duplicate Group(s) found in $file:\n"), $dup_warned++
  1673. X        if !$dup_warned && $groups{$_} > 1;
  1674. X    print "$_ " if $groups{$_} > 1;
  1675. X    }
  1676. X    print "\n" if $dup_warned;
  1677. }
  1678. X
  1679. unlink $yptmp;
  1680. X
  1681. 1;
  1682. # end
  1683. SHAR_EOF
  1684. chmod 0700 p-cops.alpha/group.chk ||
  1685. echo 'restore of p-cops.alpha/group.chk failed'
  1686. Wc_c="`wc -c < 'p-cops.alpha/group.chk'`"
  1687. test 5060 -eq "$Wc_c" ||
  1688.     echo 'p-cops.alpha/group.chk: original size 5060, current size' "$Wc_c"
  1689. rm -f _shar_wnt_.tmp
  1690. fi
  1691. # ============= p-cops.alpha/hostname.pl ==============
  1692. if test -f 'p-cops.alpha/hostname.pl' -a X"$1" != X"-c"; then
  1693.     echo 'x - skipping p-cops.alpha/hostname.pl (File already exists)'
  1694.     rm -f _shar_wnt_.tmp
  1695. else
  1696. > _shar_wnt_.tmp
  1697. echo 'x - extracting p-cops.alpha/hostname.pl (Text)'
  1698. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/hostname.pl' &&
  1699. #
  1700. # file: hostname.pl
  1701. # usage: $hostname = &'hostname;
  1702. #
  1703. # purpose: get hostname -- try method until we get an answer 
  1704. #    or return "Amnesiac!"
  1705. #
  1706. X
  1707. package hostname;
  1708. X
  1709. sub main'hostname {
  1710. X    if (!defined $hostname) {
  1711. X    $hostname =  ( -x '/bin/hostname'   && `/bin/hostname` ) 
  1712. X          || ( -x '/bin/uname'      && `/bin/uname -n` )
  1713. X          || ( -x '/usr/bin/uuname' && `/usr/bin/uuname -l`)
  1714. X          || 'Amnesiac!';
  1715. X    chop $hostname;
  1716. X    }
  1717. X    $hostname;
  1718. }
  1719. X
  1720. 1;
  1721. SHAR_EOF
  1722. chmod 0700 p-cops.alpha/hostname.pl ||
  1723. echo 'restore of p-cops.alpha/hostname.pl failed'
  1724. Wc_c="`wc -c < 'p-cops.alpha/hostname.pl'`"
  1725. test 444 -eq "$Wc_c" ||
  1726.     echo 'p-cops.alpha/hostname.pl: original size 444, current size' "$Wc_c"
  1727. rm -f _shar_wnt_.tmp
  1728. fi
  1729. # ============= p-cops.alpha/is_able.chk ==============
  1730. if test -f 'p-cops.alpha/is_able.chk' -a X"$1" != X"-c"; then
  1731.     echo 'x - skipping p-cops.alpha/is_able.chk (File already exists)'
  1732.     rm -f _shar_wnt_.tmp
  1733. else
  1734. > _shar_wnt_.tmp
  1735. echo 'x - extracting p-cops.alpha/is_able.chk (Text)'
  1736. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/is_able.chk' &&
  1737. #!/bin/sh  # need to mention perl here to avoid recursion
  1738. #
  1739. #  is_able.chk
  1740. #
  1741. #   This shell script checks the permissions of all files and directories
  1742. # listed in the configuration file "is_able.lst", and prints warning messages
  1743. # according to the status of files.  You can specify world or group readability
  1744. # or writeability.  See the config file for the format of the configuration
  1745. # file.
  1746. #
  1747. #   Mechanism:  This shell script parses each line from the configure file
  1748. # and uses the "is_able.pl" program to check if any of
  1749. # the directories in question are writable by world/group.
  1750. #
  1751. # NOTE:
  1752. #   If you know where perl is and your system groks #!, put its
  1753. # pathname at the top to make this a tad faster.
  1754. #
  1755. # the following magic is from the perl man page
  1756. # and should work to get us to run with perl 
  1757. # even if invoked as an sh or csh or foosh script.
  1758. # notice we don't use full path cause we don't
  1759. # know where the user has perl on their system.
  1760. #
  1761. eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' 
  1762. & eval 'exec perl -S $0 $argv:q'
  1763. X    if $running_under_some_stupid_shell_instead_of_perl;
  1764. require 'is_able.pl';
  1765. require 'file_mode.pl';
  1766. require 'glob.pl';
  1767. X
  1768. if ($ARGV[0] eq '-d') {
  1769. X    shift;
  1770. X    $debug = $glob'debug = 1;  # maybe should turn off glob'debug afterwards
  1771. }
  1772. X
  1773. unshift (@ARGV, "is_able.lst" ) unless @ARGV;
  1774. X
  1775. while (<>) {
  1776. X    next if /^\s*#/;
  1777. X    split;
  1778. X    next unless @_ == 3;
  1779. X    ($file, $x, $y) = @_;
  1780. X    @files = $file =~ /[\[?*]/ ? &'glob($file) : ($file);
  1781. X    for $file (@files) {
  1782. X    print STDERR "is_able $file $x $y\n" if $debug;
  1783. X    &'is_able($file, $x, $y);
  1784. X    }
  1785. }
  1786. X
  1787. 1;
  1788. SHAR_EOF
  1789. chmod 0700 p-cops.alpha/is_able.chk ||
  1790. echo 'restore of p-cops.alpha/is_able.chk failed'
  1791. Wc_c="`wc -c < 'p-cops.alpha/is_able.chk'`"
  1792. test 1591 -eq "$Wc_c" ||
  1793.     echo 'p-cops.alpha/is_able.chk: original size 1591, current size' "$Wc_c"
  1794. rm -f _shar_wnt_.tmp
  1795. fi
  1796. # ============= p-cops.alpha/is_able.lst ==============
  1797. if test -f 'p-cops.alpha/is_able.lst' -a X"$1" != X"-c"; then
  1798.     echo 'x - skipping p-cops.alpha/is_able.lst (File already exists)'
  1799.     rm -f _shar_wnt_.tmp
  1800. else
  1801. > _shar_wnt_.tmp
  1802. echo 'x - extracting p-cops.alpha/is_able.lst (Text)'
  1803. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/is_able.lst' &&
  1804. #  This lists any/all sensitive files the administration wants to ensure
  1805. # non-read/writability of.  Comments are lines starting with a "#".
  1806. #
  1807. # USE FULL PATHNAMES!
  1808. #
  1809. #   Lines are of the format:
  1810. #
  1811. # /path/to/{dir|file}    World/Group    Read/Write/Both
  1812. #
  1813. # as above        {w|g}        {r|w|b}
  1814. #
  1815. /            w        w
  1816. /etc            w        w
  1817. /usr            w        w
  1818. /bin            w        w
  1819. /dev            w        w
  1820. /usr/bin        w        w
  1821. /usr/etc        w        w
  1822. /usr/adm        w        w
  1823. /usr/lib        w        w
  1824. /usr/spool        w        w
  1825. /usr/spool/mail        w        w
  1826. /usr/spool/news        w        w
  1827. /usr/spool/uucp        w        w
  1828. /usr/spool/at        w        w
  1829. /usr/local        w        w
  1830. /usr/local/bin        w        w
  1831. /usr/local/lib        w        w
  1832. /usr/users        w        w
  1833. /Mail            w        w
  1834. X
  1835. # some Un*x's put shadowpass stuff here:
  1836. /etc/security        w        r
  1837. X
  1838. # /.login /.profile /.cshrc /.rhosts
  1839. /.*            w        w
  1840. X
  1841. #   I think everything in /etc should be !world-writable, as a rule; but
  1842. # if you're selecting individual files, do at *least* these:
  1843. #   /etc/passwd /etc/group /etc/inittab /etc/rc /etc/rc.local /etc/rc.boot
  1844. #   /etc/hosts.equiv /etc/profile /etc/syslog.conf /etc/export /etc/utmp
  1845. #   /etc/wtmp
  1846. /etc/*            w        w
  1847. X
  1848. /bin/*            w        w
  1849. /usr/bin/*        w        w
  1850. /usr/etc/*        w        w
  1851. /usr/adm/*        w        w
  1852. /usr/lib/*        w        w
  1853. /usr/local/lib/*    w        w
  1854. /usr/local/bin/*    w        w
  1855. /usr/etc/yp*        w        w
  1856. /usr/etc/yp/*        w        w
  1857. X
  1858. # individual files:
  1859. /usr/lib/crontab    w        b
  1860. /usr/lib/aliases    w        w
  1861. /usr/lib/sendmail    w        w
  1862. /usr/spool/uucp/L.sys    w        b
  1863. X
  1864. #  NEVER want these readable!
  1865. /dev/kmem        w        b
  1866. /dev/mem        w        b
  1867. X
  1868. #   Optional List of assorted files that shouldn't be
  1869. # write/readable (mix 'n match; add to the list as desired):
  1870. /usr/adm/sulog        w        r
  1871. /.netrc            w        b
  1872. # HP-UX and others:
  1873. /etc/btmp        w        b
  1874. /etc/securetty        w        b
  1875. # Sun-fun
  1876. /dev/drum        w        b
  1877. /dev/nit        w        b
  1878. SHAR_EOF
  1879. chmod 0700 p-cops.alpha/is_able.lst ||
  1880. echo 'restore of p-cops.alpha/is_able.lst failed'
  1881. Wc_c="`wc -c < 'p-cops.alpha/is_able.lst'`"
  1882. test 1603 -eq "$Wc_c" ||
  1883.     echo 'p-cops.alpha/is_able.lst: original size 1603, current size' "$Wc_c"
  1884. rm -f _shar_wnt_.tmp
  1885. fi
  1886. # ============= p-cops.alpha/is_able.pl ==============
  1887. if test -f 'p-cops.alpha/is_able.pl' -a X"$1" != X"-c"; then
  1888.     echo 'x - skipping p-cops.alpha/is_able.pl (File already exists)'
  1889.     rm -f _shar_wnt_.tmp
  1890. else
  1891. > _shar_wnt_.tmp
  1892. echo 'x - extracting p-cops.alpha/is_able.pl (Text)'
  1893. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/is_able.pl' &&
  1894. #
  1895. #  (This takes the place of the C program is_able.c, BTW.)
  1896. #  is_able filename {w|g|s|S}       {r|w|B|b|s}
  1897. #      (world/group/SUID/SGID   read/write/{read&write}/{suid&write}/s[ug]id)
  1898. #     The second arg of {r|w} determines whether a file is (group or world
  1899. #   depending on the first arg of {w|g}) writable/readable, or if it is
  1900. #   SUID/SGID (first arg, either s or S, respectively), and prints out a
  1901. #   short message to that effect.
  1902. #  So:
  1903. #     is_able w w        # checks if world writable
  1904. #     is_able g r        # checks if group readable
  1905. #     is_able s s        # checks if SUID
  1906. #     is_able S b        # checks if world writable and SGID
  1907. X
  1908. package main;
  1909. require 'file_mode.pl';
  1910. X
  1911. package is_able;
  1912. X
  1913. # package statics
  1914. #
  1915. %wg = ( 
  1916. X    'w', 00006,
  1917. X    'g', 00060,
  1918. X    's', 04000,
  1919. X    'S', 02000,
  1920. X       );
  1921. X
  1922. %rwb= (
  1923. X    'r', 00044,
  1924. X    'w', 00022,
  1925. X    'B', 00066,
  1926. X    'b', 04022,
  1927. X    's', 06000,
  1928. X      );
  1929. X
  1930. $silent = 0;  # for suppressing diagnostic messages
  1931. X
  1932. X
  1933. sub main'is_able {
  1934. X    local($file, $wg, $rwb) = @_;
  1935. X
  1936. X    local ( 
  1937. X       $mode,             # file mode
  1938. X           $piece,            # 1 directory component
  1939. X       @pieces,             # all the pieces
  1940. X       @dirs,             # all the directories
  1941. X       $p,                 # punctuation; (*) mean writable
  1942. X                       #       due to writable parent
  1943. X       $retval,            # true if vulnerable
  1944. X       $[                # paranoia
  1945. X      );
  1946. X
  1947. X    &usage, return undef    if @_ != 3 || $file eq '';
  1948. X
  1949. X    &usage, return undef    unless defined $wg{$wg} && defined $rwb{$rwb};
  1950. X
  1951. X    if (&'Mode($file) eq 'BOGUS' && $noisy) {
  1952. X    warn "is_able: can't stat $file: $!\n";
  1953. X    return undef;
  1954. X    }
  1955. X
  1956. X    $retval = 0;
  1957. X
  1958. X    if ($rwb{$rwb} & $rwb{'w'}) {
  1959. X    @pieces = split(m#/#, $file);
  1960. X    for ($i = 1; $i <= $#pieces; $i++) {
  1961. X        push(@dirs, join('/', @pieces[0..$i]));
  1962. X    }
  1963. X    } else {
  1964. X    @dirs = ( $file );
  1965. X    } 
  1966. X
  1967. X    for $piece ( reverse @dirs ) {
  1968. X
  1969. X    next unless $mode = &'Mode($piece);
  1970. X    next if $mode eq 'BOGUS';
  1971. X
  1972. X    next unless $mode &= 07777 & $wg{$wg} & $rwb{$rwb};
  1973. X
  1974. X    $retval = 1;
  1975. X
  1976. X    $p = $piece eq $file ? '!' : '! (*)';
  1977. X
  1978. X    $parent_is_writable = $p eq '! (*)'; # for later
  1979. X
  1980. X    next if $silent; # for &is_writable
  1981. X
  1982. X    print "Warning!  $file is group readable$p\n"    if $mode & 00040; 
  1983. X    print "Warning!  $file is _World_ readable$p\n"    if $mode & 00004; 
  1984. X    print "Warning!  $file is group writable$p\n"    if $mode & 00020; 
  1985. X    print "Warning!  $file is _World_ writable$p\n"    if $mode & 00002; 
  1986. X    print "Warning!  $file is SUID!\n"        if $mode & 04000; 
  1987. X    print "Warning!  $file is SGID!\n"        if $mode & 02000; 
  1988. X
  1989. X    last if $piece ne $file;  # only complain on first writable parent
  1990. X    }
  1991. X    $retval;
  1992. }
  1993. X
  1994. sub main'is_writable {
  1995. X    local($silent) = 1;
  1996. X    &'is_able($_[0], 'w', 'w') 
  1997. X    ? $parent_is_writable 
  1998. X         ? "writable (*)"
  1999. X         : "writable" 
  2000. X    : 0;
  2001. X
  2002. sub main'is_readable {
  2003. X    local($silent) = 1;
  2004. X    &'is_able($_[0], 'w', 'r');
  2005. }
  2006. X
  2007. sub usage { 
  2008. X    warn <<EOF;
  2009. Usage: is_able file {w|g|S|s} {r|w|B|b|s}
  2010. X (not: is_able @_)
  2011. EOF
  2012. }
  2013. X
  2014. 1;
  2015. SHAR_EOF
  2016. chmod 0700 p-cops.alpha/is_able.pl ||
  2017. echo 'restore of p-cops.alpha/is_able.pl failed'
  2018. Wc_c="`wc -c < 'p-cops.alpha/is_able.pl'`"
  2019. test 2835 -eq "$Wc_c" ||
  2020.     echo 'p-cops.alpha/is_able.pl: original size 2835, current size' "$Wc_c"
  2021. rm -f _shar_wnt_.tmp
  2022. fi
  2023. # ============= p-cops.alpha/kuang ==============
  2024. if test -f 'p-cops.alpha/kuang' -a X"$1" != X"-c"; then
  2025.     echo 'x - skipping p-cops.alpha/kuang (File already exists)'
  2026.     rm -f _shar_wnt_.tmp
  2027. else
  2028. > _shar_wnt_.tmp
  2029. echo 'x - extracting p-cops.alpha/kuang (Text)'
  2030. sed 's/^X//' << 'SHAR_EOF' > 'p-cops.alpha/kuang' &&
  2031. #! /usr/local/bin/perl
  2032. X
  2033. #
  2034. # kuang - rule based analysis of Unix security
  2035. #
  2036. # Perl version by Steve Romig of the CIS department, The Ohio State
  2037. # University, October 1990. 
  2038. # Based on the shell script version by Dan Farmer from his COPS
  2039. # package, which in turn is based on a shell version by Robert
  2040. # Baldwin. 
  2041. #
  2042. #-----------------------------------------------------------------------------
  2043. # Players:
  2044. #    romig    Steve Romig, romig@cis.ohio-state.edu
  2045. #    tjt    Tim Tessin, tjt@cirrus.com
  2046. #
  2047. # History:
  2048. # 4/25/91  tjt, romig    Various fixes to filewriters (better messages about 
  2049. #            permission problems) and don't update the DBM cache 
  2050. #            with local file info.
  2051. # 11/1/90  romig    Major rewrite - generic lists, nuking get_entry 
  2052. #            and put_entry, moved rules to separate file.
  2053. #
  2054. X
  2055. #
  2056. # Options
  2057. #
  2058. # -l        list uid's that can access the given target, directly
  2059. #        or indirectly
  2060. # -d        debug
  2061. # -v         verbose
  2062. #
  2063. # -k file    load the list of known CO's
  2064. # -f file    preload file information from the named file.
  2065. # -p file    preload passwd info from the named file.
  2066. # -P        preload passwd info from ypcat + /etc/passwd
  2067. # -g group    preload group info from the named file.
  2068. # -G        preload group info from ypcat + /etc/group
  2069. X
  2070. $options = "ldvk:p:g:f:PG";
  2071. $usage = "usage: kuang [-l] [-d] [-v] [-k known] [-f file] [-P] [-G] [-p passwd] [-g group] [u.username|g.groupname]\n";
  2072. X
  2073. $add_files_to_cache = 1;        # Whether to update the %files cache
  2074. X                    # with local file info or not.
  2075. X
  2076. #
  2077. # Terminology:
  2078. #
  2079. #   An "op" is an operation, such as uid, gid, write, or replace. 
  2080. #   'uid' means to gain access to some uid, 'gid' means to gain access 
  2081. #   to some gid.  'write' and 'replace' refer to files - replace means
  2082. #   that we can delete a file and replace it with a new one somehow
  2083. #   (for example, if we could write the directory it is in).
  2084. #
  2085. #   An object is a uid, gid or pathname.  
  2086. #
  2087. #   A Controlling Operation (CO) is a (operation, object) pair
  2088. #   represented as "op object": "uid 216" (become uid 216) or "replace
  2089. #   /.rhosts" (replace file /.rhosts).  These are represented
  2090. #   internally as "c value", where "c" is a character representing an
  2091. SHAR_EOF
  2092. true || echo 'restore of p-cops.alpha/kuang failed'
  2093. fi
  2094. echo 'End of alpha p-cops part 1'
  2095. echo 'File p-cops.alpha/kuang is continued in part 2'
  2096. echo 2 > _shar_seq_.tmp
  2097. exit 0
  2098.