#!/usr/local/bin/perl

# Display impact of security problems by following trust relationships.
# Optional arguments are a compromised host and the severity level
# (default root shell access).

require 'misc.pl';
require 'yagrip.pl';

#
# Do JCL stuff.
#
$usage = "Usage: $0 [compromised_host] [severity]\n";
&getopt("v");

if ($#ARGV > 2) {
    print $usage;
    exit 1;
}elsif ($#ARGV == 1) {
    $impact{$ARGV[0]} = $ARGV[1];
    $reason{$ARGV[0]} = "break-in by hypothesis";
} elsif ($#ARGV == 0) {
    $impact{$ARGV[0]} = "rs";	# default severity is root shell
    $reason{$ARGV[0]} = "break-in by hypothesis";
}
$#ARGV = -1;

# Severity levels run from "nobody file read" to "root shell" access.
# What we have here can probably be improved upon.

@severities = split(/ /,"nr ur rr nw uw rw ns us rs");
for ($i = 0; $i <= $#severities; $i++) {
    $level{$severities[$i]} = $i;
}

# Pass one: find hosts that are vulnerable to the world. Toss anything
# that does not have some trust relationship info. Keep the rest in
# core since we are going to make multiple passes over the data.

while (<>) {
    chop;
    &satan_split($_);
    next if ($status ne "a");
    if ($severity eq "x" || $severity eq "l") {
	if ($trustee && $trusted) {
	    $pile{$_} = 0;
	    print "stash: $_\n" if (defined($opt_v));
	}
    } elsif (/ANY/ || defined($level{$severity})) {
	if (!defined($impact{$target})
	|| $level{$severity} > $impact{$target}) {
	    $impact{$target} = $severity;
	    $reason{$target} = $text;
	    # &impact_print($target, $severity, $text);
	    print "adopt: $_\n" if (defined($opt_v));
	}
    } elsif (defined($opt_v)) {
	print "toss: $_\n";
    }
	
}
close(SATAN);

# Propagation pass: a system is vulnerable when it trusts a vurlnerable
# system.

do {
    $changes = 0;
    foreach $line (keys %pile) {
	&satan_split($line);
	if (($severity eq "x" || $severity eq "l") && $trusted && $trustee) {
	    ($trusted_user, $trusted_host) = split(/@/, $trusted);
	    ($trustee_user, $trustee_host) = split(/@/, $trustee);
	    if (defined($impact{$trusted_host})) {
		if (!defined($impact{$trustee_host})) {
		    $impact{$trustee_host} = "later";
		    $reason{$trustee_host} = 
			"$trustee_host somehow trusts vulnerable $trusted_host";
		    $changes++;
		}
	    }
	}
    }
} until ($changes == 0);

foreach $target(keys %impact) {
    &impact_print($target, $impact{$target}, $reason{$target});
}

sub impact_print {
    local($target,$severity,$text) = @_;

    print "$target|$severity|$text\n";
}
