#!/usr/bin/perl -w
#  
#  open firewall (one port) for some workstations
#
# Copyright 2000  August Hoerandl (august.hoerandl@gmx.at)
#                 http://elina.htlw16.ac.at/~hoerandl
#
# This program is free software.  You can redistribute it and/or modify
# it under the terms of the GNU General Public License
#
# this script is used
#  - as a selection page (started as cgi from web server)
#  - as the answer page handling the data
#  - as a process to read the pipe and execute the commands (when started by root)
#
#  INSTALL
#   put script onto web server and protect via password
#   create pipe (mkfifo)
#     owner: wwwrun (user which runs httpd)
#     only W for owner od pipe
#      -rwx------   1 wwwrun   root         6334 Mar 16 00:14 ws.cgi
#      p-w-r-----   1 wwwrun   root            0 Mar 16 00:15 ws.pipe 
#   start script as root to read pipe & execute commands 
#
# Sample Apache Config (using Virtual Hosts):
# NameVirtualHost 172.16.1.1
# <VirtualHost  proxy>
#  DocumentRoot /usr/local/httpd/squid
#  CustomLog /var/log/httpd/squid.access_log common
#  <Directory "/usr/local/httpd/squid">
#   AuthType Basic
#   AuthName anything
#   AuthUserFile /etc/squid.passwd
#   require valid-user
#   Options +ExecCGI
#   DirectoryIndex ws.cgi
#  </Directory>
# </VirtualHost>                                                                  
$| = 1;

require "cgi-lib.pl";

$ver = 'v0.3 &copy; 2000 August Hörandl';
# Defaults - Modify to point to the location of your list
$wsfile = "ws.txt";
#$wsfile = "/etc/dhcpd.conf";

$LOG = "log.txt";
#$LOG = /var/log/httpd/squid.access_log

# how to set the rules
$IPCHAINS="/sbin/ipchains";
$DEV = "-i eth0";
$CHAIN = "squid";
$PORT = 3128;

# for auto deactivate
$AT = "/usr/bin/at";

# used to secure the pipe a little
$secret="SX!H-348&§G";
$wspipe="ws.pipe";

# time values - end of classes
$dauer{"Test - 1 Min"} = "now + 1 minutes";
$dauer{"1 Std"} = "now + 1 hours";
$dauer{"2 Std"} = "now + 2 hours";
$dauer{"4 Std"} = "now + 4 hours";

$dauer{"bis  8.40"} = "8:40";
$dauer{"bis  9.40"} = "9:30";
$dauer{"bis 10.30"} = "10:30";
$dauer{"bis 11.20"} = "11:20";
$dauer{"bis 12.10"} = "12:10";
$dauer{"bis 13.00"} = "13:00";
$dauer{"bis 13.50"} = "13:50";
$dauer{"bis 14.50"} = "14:50";
$dauer{"bis 15.40"} = "15:40";
$dauer{"bis 16.30"} = "16:30";
$dauer{"bis 17.20"} = "17:20";
$dauer{"bis 18.15"} = "18:15";
$dauer{"bis 19.00"} = "19:00";
$dauer{"bis 20.00"} = "20:00";
$dauer{"bis 20.45"} = "20:45";
$dauer{"bis 21.30"} = "21:30";

# ------------------------------------------------------------------
# no user serviceable parts below
# ------------------------------------------------------------------

MAIN: 
{
  if ($< == 0) {
    &readpipe;
  }

  # Read in all the variables set by the form
  if (&ReadParse(*input)) {
    &ProcessForm;
  } else {
    &PrintForm;
  }
}

sub ProcessForm {
  # Print the header
  print &PrintHeader;
  print &HtmlTop ("SQUID - Access Control - Result");

  select PIPE; $| = 1; select STDOUT;

  print "<hr>";
  if (defined($input{'action'})) {
    if ($input{'action'} =~ "EIN") {
      print "ON";
      $seton = 1;
    } elsif ($input{'action'} =~ "AUS") {
      print "OFF";
      $seton = 0;
    } elsif ($input{'action'} =~ "RESET") {
      print "RESET";
      $seton = 2;
    } else {  
      &CgiDie("bad action");
    }
  } else {  
    &CgiDie("no action");
  }

  if (defined($input{'dauer'})) {
    $attime = $dauer{$input{'dauer'}};
  } else {
    $attime = "now + 1 hours";
  }
  print "<br> at $attime\n<br>";

  alarm(10);
  open (PIPE, "> $wspipe") || &CgiDie("cannt open $wspipe: $!\n");

  if($seton==2) {
    print "flush\n";
    print PIPE "$secret;flush;x;now\n";
  } else {
    foreach (keys %input) {
      $x = $_;
      next unless (/rechner/i || /reihe/i || /saal/i);
      print "$x = $input{$x}<br>\n";
      if ($seton == 1) {
	print PIPE "$secret;add;$input{$x};$attime\n"; 
      } elsif ($seton == 0) {
	print PIPE "$secret;delete;$input{$x};now\n";
      }
    }
  }

  close PIPE;

  print '<form method=post><input type=submit value="Zurück" action="ws"></form>';
  print "$ver<p>";	
  print &HtmlBot;
  exit;
}

sub PrintForm {
  print &PrintHeader;
  print &HtmlTop ("SQUID - Access Control");
  &readfile();
  print "<hr>$ver<p>";	
  print &HtmlBot;
  exit;
}


sub readfile {
  open (FILE, "< $wsfile") || &CgiDie("cannt open $wsfile: $!\n");

  print "Datafile: $wsfile<p>\n";

  print <<EOT;
 <form >
 <h2>Aktion</h2>
 <select name="action">
  <option selected> EIN - Internet erlauben (für einen oder mehrere Rechner)
  <option> AUS - kein Internet (für einen oder mehrere Rechner)
  <option> RESET - Alles aus (Panikknopf) - Grundzustand: kein Internet für alle
 </select>
  <h2>Dauer</h2>
 <select name="dauer">
 <option selected>1 Std
EOT

  foreach $d (sort keys (%dauer)) {
    print "<option>$d\n";
  }
  print " </select>\n<hr>\n";

  $send = '<input type="submit" value="Senden">';
  print '<input type=reset value="Formular löschen">';
  print "$send<hr>";

  $num="AA";
  while (<FILE>) {
    if (/saal (.+) (.+)/i) {
      $saal .= " <input type=checkbox name=\"saal".$num++.
	"\" value=\"$2\"><a href=\"#$1\">$1</a>\n";
      $reihe .= "<a name=\"$1\"><h3><a href=\"#$1\">$1</a></h3>\n$send\n";
      $rechner .= "<h3>$1</h3>\n";
    }
    if (/reihe (.+) (.+)/i) {
      $reihe .= " <input type=checkbox name=\"reihe".$num++.
	"\" value=\"$2\"><a href=\"#$1\">$1</a>\n";
      $rechner .= "<a name=\"$1\"><h4>$1</h4>\n$send\n";
    }
    if (/rechner (.+) (.+)/i) {
      $rechner .=  " <input type=checkbox name=\"rechner".$num++.
	"\" value=\"$2/32\">$1\n";
    }
  }

  print "\n";
  print "<h2>Saal</h2>$saal\n";
  print '<br><input type="submit" value="Senden">';
  print "<hr>";
  print "<h2>Reihe</h2> $reihe\n";
  print "<hr>";
  print "<h2>Rechner</h2> $rechner\n";
  print "<hr>";

  print '<input type=reset value="Formular löschen">';
  print "</form>\n";

  print "<hr><pre>\n";
  system("tail $LOG");
  print "</pre>";

  close FILE;
}


sub execute {
  local($cmd)=@_;
  print "EXEC: $cmd\n";
  system("$cmd") || print "system: $!\n";
}

sub readpipe {
  open(FILE,"<$wspipe") ||
    die ("Can't open $wspipe; $!");

  while (1) {
    while (<FILE>) {
#      next unless /^$secret/;
      chop;
      local($sec);
      ($sec,$act,$addr,$time) = split(/;/);
      print "$act $addr @ $time\n";
      $rule = "-s $addr -p tcp --destination-port $PORT -y -j ACCEPT";
      $cmdon = "$IPCHAINS -I $CHAIN 1 $rule";
      $cmdoff = "$IPCHAINS -D $CHAIN $rule";
      if ($act eq "add") {
	$cmd = "echo \"$cmdoff \> /dev/null 2\> /dev/null\" | $AT $time";
	&execute("$cmdoff 2\>/dev/null");
	&execute("$cmdon");
	&execute("$cmd");
      } elsif ($act eq "delete") {
	&execute("$cmdoff");
      }  elsif ($act eq "flush") {
	&execute("$IPCHAINS -N $CHAIN");
	&execute("$IPCHAINS -D input -y -p tcp -j $CHAIN $DEV --destination-port $PORT");
	&execute("$IPCHAINS -I input 1 -y -p tcp -j $CHAIN $DEV --destination-port $PORT");
	&execute("$IPCHAINS -F $CHAIN");
	&execute("$IPCHAINS -A $CHAIN -l -p tcp -y -j DENY");
      } else {
	print "$act $addr $time\n";
      }
    }
    sleep(5);
  }
}


