sub usage { die "usage: $0 before after changes\n";}
sub unique {
local(@list) = @_;
local(%ary);
print "unique? ",join(" ",@list),"\n" if $debug;
foreach (@list) {
return(0) if $ary{$_}++;
}
1;
}
$before = shift(@ARGV) || &usage;
$debug++ if $before =~ /^-d/;
$before = shift(@ARGV) || &usage if $debug;
$after = shift(@ARGV) || &usage;
$changes = shift(@ARGV) || &usage;
@ARGV && &usage;
%policy =
(
"FIRST",2,
"pw_min_life",2,
"pw_max_life",3,
"pw_min_length",4,
"pw_min_classes",5,
"pw_history_num",6,
"policy_refcnt",7,
"LAST",7,
);
%princ =
(
"FIRST",2,
"kvno",2,
"mod_name",3,
"max_life",4,
"princ_expire_time",5,
"expiration",5,
"pw_expiration",6,
"attributes",7,
"policy",8,
"aux_attributes",9,
"LAST",9,
);
%keytab =
(
"LAST",-1,
);
sub re { local($cnt, $line) = @_;
local(@fields) = split(' ',$line);
@list = ('\S+') x $cnt;
for $f (@fields[3..$ ($f =~ /=/) || die "Bad field: $f in $_";
if (!defined($this{$`})) { die "Bad parameter $` in $_"; }
if (($list[$this{$`}] = $') eq '\S+') {
$list[$this{$`}] = '[^\s]+';
}
}
join('\s+',@list)."\$";
}
open(CHANGES, $changes) || die "Couldn't open $changes: $!\n";
while(<CHANGES>) {
next if s/^\s*\#\#\!\s*\#//;
next if !s/^\s*\#\#\!\s*//;
split;
if ($_[1] =~ /princ/) {
%this = %princ;
$this = "princ";
} elsif ($_[1] =~ /policy/) {
%this = %policy;
$this = "policy";
} elsif ($_[1] =~ /keytab/) {
%this = %keytab;
$this = $_[1];
} else {
die "Bad line: $_";
}
$cnt = $this{"LAST"}+1;
if ($_[0] =~ /add/) {
$diff{"+$this\t$_[2]"} = &re($cnt,$_);
} elsif ($_[0] =~ /delete/) {
$diff{"-$this\t$_[2]"} = &re($cnt,$_);
} elsif ($_[0] =~ /changefrom/) {
$diff{"-$this\t$_[2]"} = &re($cnt,$_);
} elsif ($_[0] =~ /changeto/) {
$ndiff{"-$this\t$_[2]"} = &re($cnt,$_);
} else {
die "Bad line: $_";
}
}
close(CHANGES);
if ($debug) {
for (keys %diff) {
print " %diff: \"$_\" /$diff{$_}/\n";
}
for (keys %ndiff) {
print "%ndiff: \"$_\" /$ndiff{$_}/\n";
}
print "\n";
}
open(DIFF,"gdiff -u0 $before $after|") || die "Couldn't diff: $!\n";
$warnings = 0;
while(<DIFF>) {
next if /^\+{3}/;
next if /^\-{3}/;
next if /^@@/;
print "LINE: $_" if $debug;
split;
$key = "$_[0]\t$_[1]";
$re = $diff{$key};
delete $diff{$key};
print "%diff: \"$key\" /$re/\n" if $debug;
if (!$re) {
warn "Unexpected: \"$key\"\n";
$warnings++;
next;
}
if (!/$re/) {
warn "Failed: $key\n";
$warnings++;
next;
}
if ($new = $ndiff{$key}) {
delete $ndiff{$key};
@new = split(/\\s\+/, $new);
for ($i=1;$i<@new;$i++) {
print "NEW: $new[$i]\n" if $debug;
if ($new[$i] ne '\S+') {
$_[$i] = $new[$i];
}
}
$_[0] =~ s/^\-//;
$key =~ s/^\-/\+/;
$diff{$key} = join("\t",@_);
}
}
close(DIFF);
open(BEFORE, $before) || die "Couldn't open $before: $!\n";
while(<BEFORE>) {
next if !/^keytab/;
split;
if (!$seen{$key = $_[0]." ".$_[1]}++) {
$key =~ s/-\d+$//;
$ktkeys{$key} .= " ".$_[2];
$kttimes{$key} .= " ".$_[3];
}
}
close(BEFORE);
open(AFTER, $after) || die "Couldn't open $after: $!\n";
while(<AFTER>) {
next if !/^keytab/;
split;
if (!$seen{$key = $_[0]." ".$_[1]}++) {
$key =~ s/-\d+$//;
$ktkeys{$key} .= " ".$_[2];
$kttimes{$key} .= " ".$_[3];
}
}
close(AFTER);
for (keys %diff) {
warn "Unseen: \"$_\" /$diff{$_}/\n";
$warnings++;
}
for (keys %ndiff) {
warn "Unseen changes: \"$_\" /$ndiff{$_}/\n";
$warnings++;
}
for (keys %ktkeys) {
if (!&unique(split(' ',$ktkeys{$_}))) {
warn "Some keys not unique for $_\n";
$warnings++;
}
}
for (keys %kttimes) {
if (!&unique(split(' ',$kttimes{$_}))) {
warn "Some timestamps not unique for $_\n";
$warnings++;
}
}
if ($warnings) {
warn "$warnings warnings.\n";
}
exit($warnings);