
Listing 1: Changes in the password file can be
detected with diff and report generated by postprocessing
the diff output.
A. Listing of the passwdchng program:
1 #!/usr/bin/perl
2 # @(#) passwdchng Report changes to password file since last run
3 # Author: Chris Wharton, December 1993
4 # Modified by: Becca Thomas, March 1994
5
6 # Configuration section:
7 $display_passwd = "cat /etc/passwd"; # Use "ypcat passwd" for NIS
8 $logdir = "$ENV{'HOME'}/admin/logs"; # Log file directory
9 $old = "$logdir/passwd.old"; # File from previous run
10 $new = "$logdir/passwd.new"; # File obtained this run
11
12 # Check logging directory:
13 die "\"$logdir\" is not a writable directory\n"
14 unless (-d $logdir && -w _);
15
16 # Check for previous password file; if none, create it and abort:
17 unless (-f $old) {
18 system "$display_passwd > $old";
19 die "Can't run \"$display_passwd\" and save output in $old" if $?;
20 die "Run again; no previous passwd file saved for comparison!\n";
21 }
22
23 # Get current copy of password file:
24 system "$display_passwd > $new";
25 die "Can't run \"$display_passwd\" and save output in $new" if $?;
26
27 # Make sure both password file copies are readable:
28 die "Can't read \"$old\" file!\n" unless (-r $old);
29 die "Can't read \"$new\" file!\n" unless (-r $new);
30
31 # Obtain differences between old and new password file:
32 open(DIFF, "diff $old $new |") || die "Can't run diff: $!: stopped";
33
34 # Store changed lines in one of two associative arrays:
35 while (<DIFF>) {
36 next unless (/^</ || /^>/); # ignore non-file lines
37 (/^</) ? ($entry = "old") : ($entry = "new"); # old or new entry?
38 chop; # remove newline from $_
39 ($line = $_) =~ s/^[<>] //; # remove angle bracket, save result
40 ($name = $line) =~ s/:.*//; # store user name
41 ($entry eq "old") ? ($old{$name} = $line) : ($new{$name} = $line);
42 }
43 close(DIFF);
44
45 # Find old entries with no corresponding new entry (line removed):
46 foreach $name (keys(%old)) {
47 &show($name, "removed") unless ($new{$name});
48 }
49
50 # Now for each new entry we show any changes from old entry:
51 foreach $name (keys(%new)) {
52 $old{$name} ? &get_changes($old{$name}, $new{$name}) :
53 &show($name, "new entry");
54 }
55
56 # Overwrite the old copy with the new one to prepare for next run:
57 rename($new, $old) || die "Can't rename $new to $old: $!: stopped";
58
59 # Display changes between new and old entries:
60 sub get_changes {
61 local($oline, $nline) = @_; # store parameters as local var.
62
63 # Split entries into fields:
64 ($oname, $opass, $ouid, $ogid, $ogcos, $ohome, $oshell)
65 = split(":", $oline);
66 ($nname, $npass, $nuid, $ngid, $ngcos, $nhome, $nshell)
67 = split(":", $nline);
68 ($oname ne $nname) && die "$oname != $nname\n"; # names must match
69
70 # Display changes:
71 ($opass ne $npass) && &show($name, "password", $opass, $npass);
72 ($ouid ne $nuid) && &show($name, "user id" , $ouid, $nuid);
73 ($ogid ne $ngid) && &show($name, "group id" , $ogid, $ngid);
74 ($ogcos ne $ngcos) && &show($name, "gcos field", $ogcos, $ngcos);
75 ($ohome ne $nhome) && &show($name, "home dir", $ohome, $nhome);
76 ($oshell ne $nshell) && &show($name, "shell", $oshell, $nshell);
77 }
78
79 # Show user what happened:
80 sub show {
81 local($name, $reason, $old, $new) = @_;
82
83 print "$name: $reason";
84 (@_ == 4) ? (print " was '$old', now '$new'\n") : (print "\n");
85 }
B. Some sample output:
dept: gcos field was 'dept. test login', now 'dept. system login'
dmv: shell was '/bin/false', now '/bin/bash'
tbaker: gcos field was 'Tony Baker 61-89-895256', now 'Tony Baker'
picasso: new entry
|