#!/usr/local/bin/perl

# Display what hosts will be affected when one is compromised. This tool
# follows login/nis/nfs relationships.

do 'yagrip.pl' ||
  die "can't do yagrip.pl";

$options = "k:lf:vw";
$usage = "usage: impact [-f datadir] [-v] [-w] host";

#
# Defaults for the -d and -f options. By default, the host data is kept
# in files named hosts/fully.qualified.host.
#
$data_dir = "rip_data";

#
# addto - add plan to list
#
sub addto {
    local($host, $user, $plan) = @_;

    #
    # Check to see if it's a duplicate - if so, don't need to do anything.
    #
    if (defined($hosts_pending{$host})) {
	$u_info = $user_info{$host};
	# $user is a duplicate of an older entry.
	if ($user eq $u_info) {
	    return;
	}
	# $user is less powerful than an older entry.
	if ($u_info =~ /[0-9]/ && $u_info lt $user) {
	    return;
	}
    }
    #
    # Add to pending list 
    #
    $hosts_pending{$host} = $plan;

    #
    # Add to next plan list
    #
    $hosts_new{$host} = $plan;
    $user_info{$host} = $user;

    if (defined($opt_v)) {
	printf "addto: $user@$host $plan\n";
    }
}

#
# Initializations...
#
sub init_impact {

    %hosts_new = ();

    #
    # Deal with args...
    #

    (&getopt($options) && ($#ARGV == 0)) ||
      die $usage;

    $host = $ARGV[0];
    &addto($host, 0, "grant 0@$host.");

    if (defined($opt_f)) {
	$data_dir = $opt_f;
    }

    #
    # All per-host data is kept below a separate directory.
    #
    foreach $path ("", "/hosts", "/grant") {
	if (! -d "$data_dir$path") {
	    die "Unable to access the $data_dir$path directory. Giving up."
	}
    }
}

#
#----------------------------------------------------------------------
#Main program follows...initialize and loop till we're done.
#

&init_impact();

#
# While there's still something to pursue...
#
while(&sizeof(*hosts_new) != 0) {
    %hosts_old = %hosts_new;
    %hosts_new = ();

    foreach $host (keys %hosts_old) {
	$plan = $hosts_old{$host};
	$user = $user_info{$host};
	if (defined($opt_v)) {
	    printf "eval[$depth]: $user@$host `$plan'\n";
	}
	$grant_data = "$data_dir/grant_src/$host";
	if (-s $grant_data) {
	    open(RIP_DATA, $grant_data);
	loop:
	    while (<RIP_DATA>) {
		chop;
		($pre_user, $post_host, $post_user, $why) = split(/[|]/);
		if ($why =~ /exports/) {
		    next loop;
		}
		if ($pre_user == 2		# No privs needed
		|| ($pre_user eq $user)		# Sufficient privilege
		|| ($user =~ /[0-9]/ && $user lt $pre_user)) {
		    &addto($post_host, $post_user, 
			"grant $post_user@$post_host. $why.");
		}
	    }
	    close(RIP_DATA);
	}
    }
}

foreach $host (keys %hosts_pending) {
    $plan = $hosts_pending{$host};
    printf("$plan\n");
}

sub sizeof {
    local(*which) = @_;
    local(@keywords);

    @keywords = keys %which;
    return($#keywords + 1);
}
