#!/usr/bin/perl # # The Learning Online Network with CAPA # # $Id: lciptables,v 1.4 2010/12/30 18:40:19 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'); 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 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(); &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,\%iphost,[$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=; 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; }