#!/usr/bin/perl
#
# The Learning Online Network with CAPA
#
# $Id: lciptables,v 1.2 2010/03/25 01:28:34 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
# lciptables - LONC-CAPA setuid script to:
# o use iptables commands to update Firewall rules for current
# list of IPs for LON-CAPA hosts in server's cluster.
#
use strict;
use lib '/home/httpd/lib/perl/';
use LONCAPA::Firewall;
# ------------------------------------------------------------------ Exit codes
# Exit codes.
# ( (0,"ok"),
# (1,"User ID mismatch. This program must be run as user 'www'"),
# (2,"Missing argument: Usage: this script takes one argument - ".
# " the name of a file in /home/httpd/perl/tmp containing IP addresses."),
# (3,"Missing IP addresses file. The file containing IP addresses is missing."),
# (4,"Error. Only one lciptables script can run at any time."),
#
# ------------------------------------------------------------- Initializations
# Security
$ENV{'PATH'}='/bin/:/usr/bin:/usr/local/sbin:/home/httpd/perl'; # Nullify path
# information
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # nullify potential taints
# Do not print error messages.
my $noprint=1;
print "In lciptables\n" unless $noprint;
# ----------------------------- Make sure this process is running from user=www
my $wwwid=getpwnam('www');
&DisableRoot;
if ($wwwid!=$>) {
print("User ID mismatch. This program must be run as user 'www'\n")
unless $noprint;
&Exit(1);
}
# ----------------------------------- Retrieve IP addreses for hosts in cluster
&DisableRoot;
my %iphost;
if (@ARGV != 1) {
print("Error. this script takes one argument - the name of a file in /home/httpd/perl/tmp containing IP addresses.\n") unless $noprint;
&Exit(2);
}
my $tmpfile = $ARGV[0];
if (-e $tmpfile) {
if (open(my $fh,"<$tmpfile")) {
while(<$fh>) {
chomp();
$iphost{$_} = 1;
}
close($fh);
} else {
&Exit(3);
}
} else {
print "Error. File containing IP addresses of hosts in cluster does not exist\n" unless $noprint;
&Exit(3);
}
# --------------------------- Handle case of another lciptables process (locking)
unless (&try_to_lock("/tmp/lock_lciptables")) {
print "Error. Too many other simultaneous iptables manipulation requests being ".
"made.\n" unless $noprint;
&Exit(4);
}
my $lond_port = &LONCAPA::Firewall::get_lond_port();
($>,$<)=($wwwid,0);
&EnableRoot();
my @fw_chains = &LONCAPA::Firewall::get_fw_chains();
my $iptables = &LONCAPA::Firewall::get_pathto_iptables();
my $firewall_result =
&LONCAPA::Firewall::firewall_close_port($iptables,\@fw_chains,$lond_port,[$lond_port]);
if ($firewall_result) {
print "$firewall_result\n";
}
my $firewall_result = &LONCAPA::Firewall::firewall_open_port($iptables,\@fw_chains,$lond_port,\%iphost,[$lond_port]);
if ($firewall_result) {
print "$firewall_result\n";
}
# -------------------------------------------------------- Exit script
print "lciptables Exiting\n" unless $noprint;
&DisableRoot;
unlink('/tmp/lock_lciptables');
&Exit(0);
sub EnableRoot {
if ($wwwid==$>) {
($<,$>)=($>,$<);
($(,$))=($),$();
}
else {
# root capability is already enabled
}
return $>;
}
sub DisableRoot {
if ($wwwid==$<) {
($<,$>)=($>,$<);
($(,$))=($),$();
}
else {
# root capability is already disabled
}
}
sub try_to_lock {
my ($lockfile)=@_;
my $currentpid;
my $lastpid;
# Do not manipulate lock file as root
if ($>==0) {
return 0;
}
# Try to generate lock file.
# Wait 3 seconds. If same process id is in
# lock file, then assume lock file is stale, and
# go ahead. If process id's fluctuate, try
# for a maximum of 10 times.
for (0..10) {
if (-e $lockfile) {
open(LOCK,"<$lockfile");
$currentpid=<LOCK>;
close LOCK;
if ($currentpid==$lastpid) {
last;
}
sleep 3;
$lastpid=$currentpid;
} else {
last;
}
if ($_==10) {
return 0;
}
}
open(LOCK,">$lockfile");
print LOCK $$;
close LOCK;
return 1;
}
sub Exit {
my ($code) = @_;
&DisableRoot();
print "Exiting with status $code\n" unless $noprint;
exit $code;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>