#
#  This software was derived from SATAN 1.1.1 by Dan Farmer and Wietse Venema
#  (http://www.porcupine.org/satan).
#
# miscellaneous perl functions that don't belong anywhere else
#

#
# Symbolic offsets for SARA record fields.
#

$TARGET_FIELD = 0;
$SERVICE_FIELD = 1;
$STATUS_FIELD = 2;
$SEVERITY_FIELD = 3;
$TRUSTEE_FIELD = 4;
$TRUSTED_FIELD = 5;
$SERVICE_OUTPUT_FIELD = 6;
$TEXT_FIELD = 7;
$SARA_FIELDS = 8;

# strip leading directory and optional suffix information.
sub basename {
    local($path, $suffix) = @_;

    $path =~ s:.*/::;
    if ($suffix) {
	$path =~ s/$suffix$//;
    }
    return $path;
}

# print to string 

sub sara_string{

    return "$target|$service|$status|$severity|$trustee|$trusted|$service_output|$text";
}

# print the output for the brain/optimizer
sub sara_print {

    print "$target|$service|$status|$severity|$trustee|$trusted|$service_output|$text\n";

}

# format the output for the brain/optimizer
sub sara_text {

    return "$target|$service|$status|$severity|$trustee|$trusted|$service_output|$text";

}

# breakup record into its constituent fields
sub sara_split {
    local ($line) = @_;

    return ((($target,$service,$status,$severity,$trustee,$trusted,$service_output,$text) = split(/\|/, $line)) != $SARA_FIELDS);
}

# count the number of elements in an associative array.
sub sizeof {
    local(*which) = @_;
    local(@keywords);
 
    @keywords = keys %which;
    return($#keywords + 1);
}

#
# ensure that all paths in paths.pl file actually exist and are executable
sub check_paths {
local($caps, $command, $path, $null);

die "Can't open paths.pl\n" unless open(PATHS, "paths.pl");

while (<PATHS>) {
	($caps, $command) = split(/=/, $_);
	($null, $path, $null) = split(/\"/, $command);
	die "$path is *not* executable - necessary for SARA to run\n"
		unless -x $path;
	}

close(PATHS);
}
sub delay_sara {
  local($delay) = 0;
  local($cnt)   = 0;
  $delay_file="rules/timing";
  if (open(DELAY,$delay_file) && $timing) {
     while(<DELAY>) {
      chomp;
      next if /#/ || /^$/;
      $delays[$cnt] = $_;
      local($delay_hours,$delay_days,$delay_dates) = split(/\|/,$delays[$cnt]);
      if($delay_hours!~/[0-2][0-9][0-9][0-9]-[[0-2][0-9][0-9][0-9]/) {
        if ($delay_hours !~ /\*/) {
         print "  Error in rules/timing: illegal entry in hours field\n";
         $delays[$cnt] = "";
       }
      }
      $_ = $delay_days;
      if(!/Sun/i && !/Mon/i && !/Tue/i && !/Wed/i && !/Thu/i) {
        if(!/Fri/ && !/Sat/i && !/\*/){
          print "  Error in rules/timing: illegal entry in days field\n";
          $delays[$cnt] = "";
        }
      }
      $_ = $delay_dates;
      if (!/Jan/i && !/Feb/i && !/Mar/i && !/Apr/i) {
       if (!/May/i && !/Jun/i && !/Jul/i && !/Aug/i) {
        if (!/Sep/i && !/Oct/i && !/Nov/i && !/Dec/i && !/\*/) {
         print "  Error in rules/timing: illegal entry in dates field\n";
         $delays[$cnt] = "";
        }
       }
      }
    $cnt++;
    }
    if (@delays) {
      $doit_delay = 1;
      print STDOUT "  Timing restrictions enforced by rules/timing\n";
      &do_delays();
      return 1;
    } else {
      return 0;
    }
   } else {
     return 0;
   }
}
sub do_delays() {
  $delay_flag = 1;
  $pause_flag = 0;
  $update_flag =0;
  while ($delay_flag == 1) {
   while (-f "sara-pause") {
     &update_status("SARA paused ...") if $pause_flag == 0;
     $pause_flag = 1;
     sleep(60);
   }
   $delay_flag = 0;
   for (@delays) {
    local($delay_hours,$delay_days,$delay_dates) = split(/\|/);
    local($start_hr,$stop_hr) = split(/-/,$delay_hours);
     $tmp=delay_timer("hours");
     if(($tmp >= $start_hr && $tmp <= $stop_hr) || $delay_hours eq "\*") {
      if ($delay_days && $delay_hours && $delay_dates) {
        if($delay_days eq delay_timer("week") || $delay_days eq "\*") {
          if ($delay_dates eq delay_timer("date")|| $delay_dates eq "\*") {
            &update_status("SARA suspended- rules/timing") if $update_flag == 0;
            $update_flag = 1;
            sleep(60);
            $delay_flag = 1;
          }
        }
      }
     } 
   }
  }
}
sub delay_timer() {
  local($arg) = "@_";
  ($now_day_week,$now_month,$now_day,$now_hours)=split(/\s+/,`date`);
  ($tmp_hour, $tmp_min) = split(/\:/,$now_hours);
  $now_date = "$now_day $now_month";
  $now_hours = "$tmp_hour$tmp_min";
  return "$now_date" if $arg eq "date";
  return "$now_hours" if $arg eq "hours";
  return "$now_day_week" if $arg eq "week";
  return 0;
}

sub get_administrator {
#
# Interogate Administrator database for IP matches
# $_ip is the IP to search for
#
  $a = $b = $c = $network = @results = "";
  $admins ="";

  ($a,$b,$c) = split(/\./,$_ip);
  $network = "$a.$b.$c";
  @results = `grep $network rules/administrators/*`;
  for (@results) {
    next if /^#/;
    ($admin, $ip) = split(/:/);
    $ip =~ s/\n//;
    $admin =~ s/administrators\///;
    if ($ip =~ /\-/) {
      ($ip_start,$ip_stop) = split(/\-/,$ip);
      ($dummy,$dummy,$dummy,$start) = split(/\./,$ip_start);
      ($dummy,$dummy,$dummy,$stop)  = split(/\./,$ip_stop);
      ($dummy,$dummy,$dummy,$mine) = split(/\./,$_ip);
      if (($mine >= $start) && ($mine <= $stop)) {
         $admins .= "$admin\;";
      }
    } elsif ($_ip eq $ip) {
      $admins .= "$admin\;";
    }
  }
  $admins =~ s/\;$//;
  return $admins;
}
sub update_mac {
  local($target, $mac) = @_;
  my @buffer, $cnt;
  
  if ($sara_data) {
    open (MAC, "results/$sara_data/.mac_list");
    while (<MAC>) {
      @buffer[$cnt++] = $_ if (!/$target/);
    }
    close(MAC);
    open (MAC, ">results/$sara_data/.mac_list");
    for (@buffer) {
      print MAC "$_";
    }
    print MAC "$target|$mac\n";
    close (MAC);
  }
}  
sub svc2port {
#  Convert a service name to port number
  local($service, $dum) = @_;
  local($port,$svc, $port);
  if ($service =~ /^[0-9]/) {
   ($service,$dum) = split(/:/,$service);
   return "$service";
  }
  open (PORTS,"config/ports");
  while (<PORTS>) {
    ($port,$svc) =split(/\s+/);
    if ($svc eq $service) {
      return $port;
    }
  }
  return "0";
}
sub ip2mac {
#--------------------------------------------------------------------
# Script: ip_to_mac
#
# Author: Dat Duong
#
# Change log:
#  09/10/2002 - DD Initial release
#  09/18/2002 - RT Integrate into SARA
#  09/18/2004 - Added local ARP lookup
#--------------------------------------------------------------------

use IO::Socket;
use IO::Select;

my ($_ip,$dum) =@_;
my ($rc,$socket,$remote,$msg,$port,$ipaddr,$PORT, $timeout);
my $timeout = 10;

if (!$mac_proxy) {
  if ($_ip) {
    $mac = `$ARP $_ip`;
    if( $mac =~ /([0-9A-F]+\:[0-9A-F]+\:[0-9A-F]+\:[0-9A-F]+\:[0-9A-F]+\:[0-9A-F]+)/i) {
      return "$1";
    }
  }
  return "";
} else {
  if ( !valid_ip($mac_proxy) || !valid_ip($_ip) ) {
      return "BadMACServer";
  }
  my $remote = $mac_proxy;
  my $ip_address = $_ip;


  $PORT = 49152;
  $timeout = 10;

  $socket = IO::Socket::INET->new(
        PeerAddr => "$remote",
	PeerPort =>  "$PORT",
	Proto	 => "udp") || return "";

  $socket->send("1,$ip_address");

  my $read_fds = new IO::Select();
  $read_fds->add($socket);
  my $rh_set = IO::Select->select($read_fds,undef,undef, $timeout);
  if ($rh_set > 0) {
      $socket->recv($msg,1024);
      my ($code,$_ip,$mac) = split /,/,$msg;
      if ($code == 2) {
        $mac = "NoMAC" if !$mac;
        return "$mac";
      }    
      elsif ($code == 3) {
          return "macServerRefusing";
      }
      else {
          return "macServerDown";
      }
  } else {
    return "macServerDown";
  }
  return "UnknownError";
}
}
#
# Get the corresponding CVE Vul Class and text
#
sub get_cve {
  $cve_file = "rules/sid.def";
  my $dum  = "";
  my $_cve = "";
  (my $_class, my $_text) = @_;
  $_class =~ s/\(//;
  $_class =~ s/\)//;
  open (CVE, "$cve_file");
  while (<CVE>) {
    chomp;
    ($dum, $dum, my $class, my $text, my $cve) = split(/\|/);
    $class =~ s/\(//;
    $class =~ s/\)//;
    if ("$_class" eq "$class") {
      @text_seg = split(/;/, $text);
      $match = "yes";
      for $text (@text_seg) {
        $match = "" if ($_text !~ /$text/); 
      }
      if ($match) { 
        ($dum, $dum, $dum, $dum, $_cve) = split(/\|/);
        close (CVE);
        return "$cve";
      }
    }
  }
  close (CVE);
  return "";
}

sub get_sans {
  $sans_file = "data/sans.csv";
  (my $_cve, my $dum) = @_;
  open(SANS, "$sans_file");
  while (<SANS>) {
    chomp;
    next if (/^#/);
    (my $_sans, my $_cve_c) = split(/\|/);
    if ($_cve_c =~ /$_cve/) {
      close (SANS);
      return "$_sans";
    }
  }
  return("");
}

sub get_nvd {
  $nvd_file = "data/nvd.csv";
  (my $_cve, my $dum) =@_;
  open (NVD, "$nvd_file");
  while (<NVD>) {
    chomp;
    (my $cve, $dum) = split(/\|/);
    if ($cve =~ /$_cve/) {
      close (NVD);
      return "$_";
    }
  }
  close (NVD);
  return "";
}

#-----------------------------------------------------------------
# Function: valid_ip
#  
# Description: Verify IP address is legal
#        
# Parameter: IP address
# Return   : 0 if invalid >0 if ok
#-----------------------------------------------------------------
sub valid_ip {
    my ($ip) = @_;
    my $rc;
    $rc = inet_aton($ip);
    print "Invalid IP address $ip\n" if (!$rc);
    return $rc;
}
sub get_sid {
    my ($sid) = @_;
    $out[0] = "";
    $out[1] = "Unknown SID $sid";
    $out[2] = "Unknown SID $sid";
    $sid_file = "rules/sid.def";
    open(SID, "$sid_file");
    while (<SID>) {
      if (/^$sid/) {
       ($dum, $out[0],$out[1], $out[2], $out[3]) = split(/\|/);
       $out[1] =~ s/\\\(/(/g;
       $out[1] =~ s/\\\)/)/g;
       $out[2] =~ s/\\\(/(/g;
       $out[2] =~ s/\\\)/)/g;
       $out[3] =~ s/\\\(/(/g;
       $out[3] =~ s/\\\)/)/g;
      }
    }
    return @out;
}
sub credits {

@title = ("  Using SAMBA by \(www.samba.org\)",
          "  Using SQLiX by \(www.osawp.org/index.php/Category:OWASP_SQLiX_Project\)",
          "  Using SQLAT by \(www.cqure.net/sqlat/index.html\)");
@test  = ("$RPCCLIENT",
          "$SQLIX",
          "bin/sqlanlz");
   $i = 0;
   for (@title){
     print STDOUT "$title[$i]\n" if ( -f $test[$i]);
     $i++;
   }
}


