"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "bin/BackupPC_Admin_SCGI" between
BackupPC-4.3.2.tar.gz and BackupPC-4.4.0.tar.gz

About: BackupPC is a high-performance, enterprise-grade system for backing up Linux and WinXX PCs and laptops to a server’s disk (http/cgi user interface).

BackupPC_Admin_SCGI  (BackupPC-4.3.2):BackupPC_Admin_SCGI  (BackupPC-4.4.0)
skipping to change at line 51 skipping to change at line 51
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
#======================================================================== #========================================================================
# #
# Version 4.3.2, released 17 Feb 2020. # Version 4.4.0, released 20 Jun 2020.
# #
# See http://backuppc.sourceforge.net. # See http://backuppc.sourceforge.net.
# #
#======================================================================== #========================================================================
use strict; use strict;
no utf8; no utf8;
use lib "__INSTALLDIR__/lib"; use lib "__INSTALLDIR__/lib";
use IO::Socket; use IO::Socket;
use Data::Dumper; use Data::Dumper;
use POSIX ":sys_wait_h"; use POSIX ":sys_wait_h";
use CGI; use CGI;
use BackupPC::Lib; use BackupPC::Lib;
use BackupPC::XS; use BackupPC::XS;
use BackupPC::CGI::Lib qw(:all); use BackupPC::CGI::Lib qw(:all);
skipping to change at line 80 skipping to change at line 81
use BackupPC::CGI::Archive; use BackupPC::CGI::Archive;
use BackupPC::CGI::ArchiveInfo; use BackupPC::CGI::ArchiveInfo;
use BackupPC::CGI::Browse; use BackupPC::CGI::Browse;
use BackupPC::CGI::DeleteBackup; use BackupPC::CGI::DeleteBackup;
use BackupPC::CGI::DirHistory; use BackupPC::CGI::DirHistory;
use BackupPC::CGI::EditConfig; use BackupPC::CGI::EditConfig;
use BackupPC::CGI::EmailSummary; use BackupPC::CGI::EmailSummary;
use BackupPC::CGI::GeneralInfo; use BackupPC::CGI::GeneralInfo;
use BackupPC::CGI::HostInfo; use BackupPC::CGI::HostInfo;
use BackupPC::CGI::LOGlist; use BackupPC::CGI::LOGlist;
use BackupPC::CGI::Metrics;
use BackupPC::CGI::Queue; use BackupPC::CGI::Queue;
use BackupPC::CGI::ReloadServer; use BackupPC::CGI::ReloadServer;
use BackupPC::CGI::Restore; use BackupPC::CGI::Restore;
use BackupPC::CGI::RestoreFile; use BackupPC::CGI::RestoreFile;
use BackupPC::CGI::RestoreInfo; use BackupPC::CGI::RestoreInfo;
use BackupPC::CGI::StartServer; use BackupPC::CGI::StartServer;
use BackupPC::CGI::StartStopBackup; use BackupPC::CGI::StartStopBackup;
use BackupPC::CGI::StopServer; use BackupPC::CGI::StopServer;
use BackupPC::CGI::Summary; use BackupPC::CGI::Summary;
use BackupPC::CGI::View; use BackupPC::CGI::View;
my %ActionDispatch = ( my %ActionDispatch = (
"deleteBackup" => "DeleteBackup", "summary" => "Summary",
"summary" => "Summary", "Start_Incr_Backup" => "StartStopBackup",
"Start_Incr_Backup" => "StartStopBackup", "Start_Full_Backup" => "StartStopBackup",
"Start_Full_Backup" => "StartStopBackup", "Stop_Dequeue_Backup" => "StartStopBackup",
"Stop_Dequeue_Backup" => "StartStopBackup", "Stop_Dequeue_Archive" => "StartStopBackup",
"Stop_Dequeue_Archive" => "StartStopBackup", "queue" => "Queue",
"queue" => "Queue", "view" => "View",
"view" => "View", "LOGlist" => "LOGlist",
"LOGlist" => "LOGlist", "emailSummary" => "EmailSummary",
"emailSummary" => "EmailSummary", "browse" => "Browse",
"browse" => "Browse", "dirHistory" => "DirHistory",
"dirHistory" => "DirHistory", "Restore" => "Restore",
"Restore" => "Restore", "RestoreFile" => "RestoreFile",
"RestoreFile" => "RestoreFile", "hostInfo" => "HostInfo",
"hostInfo" => "HostInfo", "generalInfo" => "GeneralInfo",
"generalInfo" => "GeneralInfo", "restoreInfo" => "RestoreInfo",
"restoreInfo" => "RestoreInfo", "archiveInfo" => "ArchiveInfo",
"archiveInfo" => "ArchiveInfo", "Start_Archive" => "Archive",
"Start_Archive" => "Archive", "Archive" => "Archive",
"Archive" => "Archive", "Reload" => "ReloadServer",
"Reload" => "ReloadServer", "startServer" => "StartServer",
"startServer" => "StartServer", "Stop" => "StopServer",
"Stop" => "StopServer", "adminOpts" => "AdminOptions",
"adminOpts" => "AdminOptions", "editConfig" => "EditConfig",
"editConfig" => "EditConfig", "deleteBackup" => "DeleteBackup",
"keepBackup" => "HostInfo",
"rss" => "Metrics",
"metrics" => "Metrics",
); );
my %ChildPid2Num; my %ChildPid2Num;
BEGIN { BEGIN {
eval "use SCGI;"; eval "use SCGI;";
if ( $@ ) { if ( $@ ) {
print("BackupPC_Admin_SCGI: can't load perl SCGI module - install via CP AN; exiting in 60 seconds\n"); print("BackupPC_Admin_SCGI: can't load perl SCGI module - install via CP AN; exiting in 60 seconds\n");
# #
# if we exit immediately, BackupPC will restart us immediately # if we exit immediately, BackupPC will restart us immediately
# #
sleep(60); sleep(60);
exit(1); exit(1);
} }
eval "use BackupPC::CGI::RSS;";
if ( !$@ ) {
$ActionDispatch{rss} = "RSS";
}
} }
# #
# Edit this if you want to get more information about each request # Edit this if you want to get more information about each request
# #
my $LogLevel = 0; my $LogLevel = 0;
$Cgi = new CGI; $Cgi = new CGI;
die("BackupPC::Lib->new failed\n") if ( !($bpc = BackupPC::Lib->new) ); die("BackupPC::Lib->new failed\n") if ( !($bpc = BackupPC::Lib->new) );
$TopDir = $bpc->TopDir(); $TopDir = $bpc->TopDir();
$LogDir = $bpc->LogDir(); $LogDir = $bpc->LogDir();
$BinDir = $bpc->BinDir(); $BinDir = $bpc->BinDir();
%Conf = $bpc->Conf(); %Conf = $bpc->Conf();
$Lang = $bpc->Lang(); $Lang = $bpc->Lang();
$ConfigMTime = $bpc->ConfigMTime(); $ConfigMTime = $bpc->ConfigMTime();
umask($Conf{UmaskMode}); umask($Conf{UmaskMode});
my $LockFile = "$LogDir/scgi_lock"; my $LockFile = "$LogDir/scgi_lock";
my $LockFileSz = 2048; my $LockFileSz = 2048;
my $ChildExited = 0; my $ChildExited = 0;
$SIG{INT} = \&childKill; $SIG{INT} = \&childKill;
$SIG{CHLD} = \&childCleanup; $SIG{CHLD} = \&childCleanup;
my $socket = IO::Socket::INET->new(Listen => 5, ReuseAddr => 1, my $socket = IO::Socket::INET->new(
LocalAddr => 'localhost', Listen => 5,
LocalPort => $Conf{SCGIServerPort} || 8199) ReuseAddr => 1,
or die "cannot bind to port $Conf{SCGIServerPort}: $!"; LocalAddr => 'localhost',
LocalPort => $Conf{SCGIServerPort} || 8199
) or die "cannot bind to port $Conf{SCGIServerPort}: $!";
my $scgi = SCGI->new($socket, blocking => 1); my $scgi = SCGI->new($socket, blocking => 1);
# #
# Clean up %ENV for taint checking # Clean up %ENV for taint checking
# #
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};
$ENV{PATH} = $Conf{MyPath}; $ENV{PATH} = $Conf{MyPath};
# #
skipping to change at line 223 skipping to change at line 226
sleep(60); sleep(60);
exit(1); exit(1);
} }
my $LockFdNum = fileno($LockFd); my $LockFdNum = fileno($LockFd);
while ( 1 ) { while ( 1 ) {
if ( BackupPC::XS::DirOps::lockRangeFd($LockFdNum, 1, $MaxChild, 1) ) { if ( BackupPC::XS::DirOps::lockRangeFd($LockFdNum, 1, $MaxChild, 1) ) {
if ( $ChildExited ) { if ( $ChildExited ) {
$ChildExited = 0; $ChildExited = 0;
# #
# If a second child dies while in the signal handler caused by the # If a second child dies while in the signal handler caused by the
# first death, we wont get another signal. So we must do a non-bloc king # first death, we won't get another signal. So we must do a non-bloc king
# loop here else we will leave the unreaped child as a zombie. And # loop here else we will leave the unreaped child as a zombie. And
# the next time two children die we get another zombie. And so on. # the next time two children die we get another zombie. And so on.
# #
# As we reap each child, we start another one in the same slot. # As we reap each child, we start another one in the same slot.
# #
while ( (my $child = waitpid(-1, WNOHANG)) > 0 ) { while ( (my $child = waitpid(-1, WNOHANG)) > 0 ) {
print("BackupPC_Admin_SCGI: child $child exited ($!)\n") print("BackupPC_Admin_SCGI: child $child exited ($!)\n")
if ( $LogLevel >= 3 ); if ( $LogLevel >= 3 );
if ( defined($ChildPid2Num{$child}) ) { if ( defined($ChildPid2Num{$child}) ) {
childRun($ChildPid2Num{$child}); childRun($ChildPid2Num{$child});
} }
} }
next; next;
} }
print("BackupPC_Admin_SCGI: parent lock failed ($!)... continuing\n") print("BackupPC_Admin_SCGI: parent lock failed ($!)... continuing\n")
if ( $LogLevel >= 3 ); if ( $LogLevel >= 3 );
sleep(1); sleep(1);
next; next;
} }
BackupPC::XS::DirOps::unlockRangeFd($LockFdNum, 1, $MaxChild); BackupPC::XS::DirOps::unlockRangeFd($LockFdNum, 1, $MaxChild);
print("BackupPC_Admin_SCGI: all children busy... starting a new child $MaxCh ild\n") print("BackupPC_Admin_SCGI: all children busy... starting a new child $MaxCh ild\n")
if ( $LogLevel >= 5 ); if ( $LogLevel >= 5 );
if ( $MaxChild >= $LockFileSz - 2 ) { if ( $MaxChild >= $LockFileSz - 2 ) {
# #
# Need to extend the lock file size, since we need a lock byte for # Need to extend the lock file size, since we need a lock byte for
# every child, plus one. # every child, plus one.
# #
$LockFileSz *= 2; $LockFileSz *= 2;
print("BackupPC_Admin_SCGI: extending $LockFile to length $LockFileSz\n" ); print("BackupPC_Admin_SCGI: extending $LockFile to length $LockFileSz\n" );
sysseek($LockFd, 0, 0); sysseek($LockFd, 0, 0);
if ( syswrite($LockFd, chr(0) x $LockFileSz) != $LockFileSz ) { if ( syswrite($LockFd, chr(0) x $LockFileSz) != $LockFileSz ) {
print("BackupPC_Admin_SCGI: can't write $LockFileSz bytes to $LockFi print(
le; terminating children and exiting...\n"); "BackupPC_Admin_SCGI: can't write $LockFileSz bytes to $LockFile
; terminating children and exiting...\n"
);
kill 2, keys(%ChildPid2Num); kill 2, keys(%ChildPid2Num);
sleep(1); sleep(1);
kill 9, keys(%ChildPid2Num); kill 9, keys(%ChildPid2Num);
exit(1); exit(1);
} }
sysseek($LockFd, 0, 0); sysseek($LockFd, 0, 0);
} }
childRun($MaxChild++); childRun($MaxChild++);
} }
skipping to change at line 315 skipping to change at line 320
print("BackupPC_Admin_SCGI: child $childNum can't open $LockFile; exitin g\n"); print("BackupPC_Admin_SCGI: child $childNum can't open $LockFile; exitin g\n");
exit(1); exit(1);
} }
$LockFdNum = fileno($LockFd); $LockFdNum = fileno($LockFd);
while ( 1 ) { while ( 1 ) {
# #
# Grab a lock on byte #$childNum to indicate we are idle. # Grab a lock on byte #$childNum to indicate we are idle.
# #
if ( BackupPC::XS::DirOps::lockRangeFd($LockFdNum, 1 + $childNum, 1, 1) ) { if ( BackupPC::XS::DirOps::lockRangeFd($LockFdNum, 1 + $childNum, 1, 1) ) {
print("BackupPC_Admin_SCGI: child $childNum failed to get idle lock ($!)\n") print("BackupPC_Admin_SCGI: child $childNum failed to get idle lock ($!)\n")
if ( $LogLevel >= 3 ) ; if ( $LogLevel >= 3 );
sleep(1); sleep(1);
next; next;
} }
print("BackupPC_Admin_SCGI: child $childNum got idle lock\n") print("BackupPC_Admin_SCGI: child $childNum got idle lock\n")
if ( $LogLevel >= 5 ); if ( $LogLevel >= 5 );
if ( defined($fhWrite) ) { if ( defined($fhWrite) ) {
# #
# Now close the pipe write side, so the parent can safely continue. # Now close the pipe write side, so the parent can safely continue.
# #
close($fhWrite); close($fhWrite);
$fhWrite = undef; $fhWrite = undef;
} }
# #
# We use an exclusive lock on byte 0 of the lock file to make sure # We use an exclusive lock on byte 0 of the lock file to make sure
# only one child does an accept at a time. As we process the # only one child does an accept at a time. As we process the
# request, another child will get the lock on byte 0 and will accept # request, another child will get the lock on byte 0 and will accept
# the next request. # the next request.
# #
if ( BackupPC::XS::DirOps::lockRangeFd($LockFdNum, 0, 1, 1) ) { if ( BackupPC::XS::DirOps::lockRangeFd($LockFdNum, 0, 1, 1) ) {
print("BackupPC_Admin_SCGI: child $childNum lock failed ($!)... cont inuing\n") print("BackupPC_Admin_SCGI: child $childNum lock failed ($!)... cont inuing\n")
if ( $LogLevel >= 3 ); if ( $LogLevel >= 3 );
sleep(1); sleep(1);
next; next;
} }
print("BackupPC_Admin_SCGI: child $childNum got accept lock\n") print("BackupPC_Admin_SCGI: child $childNum got accept lock\n")
if ( $LogLevel >= 5 ); if ( $LogLevel >= 5 );
my $request = $scgi->accept; my $request = $scgi->accept;
BackupPC::XS::DirOps::unlockRangeFd($LockFdNum, 0, 1); BackupPC::XS::DirOps::unlockRangeFd($LockFdNum, 0, 1);
BackupPC::XS::DirOps::unlockRangeFd($LockFdNum, 1 + $childNum, 1); BackupPC::XS::DirOps::unlockRangeFd($LockFdNum, 1 + $childNum, 1);
my $iaddr = $request->connection->peeraddr(); my $iaddr = $request->connection->peeraddr();
if ( ord($iaddr) != 127 ) { if ( ord($iaddr) != 127 ) {
# #
# peer is not a localhost address (ie: 127.0.0.1/8); ignore it # peer is not a localhost address (ie: 127.0.0.1/8); ignore it
# #
my $addrStr = join(".", unpack("C*", $iaddr)); my $addrStr = join(".", unpack("C*", $iaddr));
printf("BackupPC_Admin_SCGI: unexpected connection from $addrStr (%s ) ignored\n", printf("BackupPC_Admin_SCGI: unexpected connection from $addrStr (%s ) ignored\n",
gethostbyaddr($iaddr, AF_INET)); gethostbyaddr($iaddr, AF_INET));
$request = undef; $request = undef;
next; next;
} }
print("BackupPC_Admin_SCGI: child $childNum processing request\n") print("BackupPC_Admin_SCGI: child $childNum processing request\n")
if ( $LogLevel >= 5 ); if ( $LogLevel >= 5 );
handleRequest($request); handleRequest($request);
$request = undef; $request = undef;
select(STDOUT); select(STDOUT);
print("BackupPC_Admin_SCGI: child $childNum finished request\n") print("BackupPC_Admin_SCGI: child $childNum finished request\n")
if ( $LogLevel >= 5 ); if ( $LogLevel >= 5 );
} }
} }
sub handleRequest sub handleRequest
{ {
my($request) = @_; my($request) = @_;
$request->read_env; $request->read_env;
my $con = $request->connection; my $con = $request->connection;
read($con, my $body, $request->env->{CONTENT_LENGTH}); read($con, my $body, $request->env->{CONTENT_LENGTH});
select($con); select($con);
NewRequest($request, $body); NewRequest($request, $body);
if ( $LogLevel >= 4 ) { if ( $LogLevel >= 4 ) {
my $fdDebug; my $fdDebug;
open($fdDebug, ">", "$LogDir/request.txt"); open($fdDebug, ">", "$LogDir/request.txt");
print $fdDebug "Environment: ", Dumper($request->env), "\n\n"; print $fdDebug "Environment: ", Dumper($request->env), "\n\n";
print $fdDebug "Body: ", $body, "\n\n"; print $fdDebug "Body: ", $body, "\n\n";
print $fdDebug "Other: ", "User = $User, MyURL = $MyURL, PID = $$, In = print $fdDebug "Other: ", "User = $User, MyURL = $MyURL, PID = $$, In =
", Dumper(\%In), "Conf = ", Dumper(\%Conf), "\n\n"; ", Dumper(\%In), "Conf = ",
Dumper(\%Conf), "\n\n";
close($fdDebug); close($fdDebug);
} }
if ( !defined($ActionDispatch{$In{action}}) ) { if ( !defined($ActionDispatch{$In{action}}) ) {
$In{action} = defined($In{host}) ? "hostInfo" : "generalInfo"; $In{action} = defined($In{host}) ? "hostInfo" : "generalInfo";
} }
my $action = $ActionDispatch{$In{action}}; my $action = $ActionDispatch{$In{action}};
$BackupPC::CGI::{"${action}::"}{action}(); $BackupPC::CGI::{"${action}::"}{action}();
} }
sub NewRequest sub NewRequest
skipping to change at line 419 skipping to change at line 425
$In{$name} = $2; $In{$name} = $2;
$In{$name} =~ s/\+/ /g; $In{$name} =~ s/\+/ /g;
$In{$name} =~ s{%(..)}{chr(hex($1))}eg; $In{$name} =~ s{%(..)}{chr(hex($1))}eg;
} }
$ENV{SCRIPT_NAME} = $request->env->{SCRIPT_NAME}; $ENV{SCRIPT_NAME} = $request->env->{SCRIPT_NAME};
$ENV{REMOTE_USER} = $request->env->{REMOTE_USER}; $ENV{REMOTE_USER} = $request->env->{REMOTE_USER};
$ENV{REQUEST_URI} = $request->env->{REQUEST_URI}; $ENV{REQUEST_URI} = $request->env->{REQUEST_URI};
if ( $bpc->ConfigMTime() != $ConfigMTime ) { if ( $bpc->ConfigMTime() != $ConfigMTime ) {
$bpc->ConfigRead(); $bpc->ConfigRead();
$TopDir = $bpc->TopDir(); $TopDir = $bpc->TopDir();
$LogDir = $bpc->LogDir(); $LogDir = $bpc->LogDir();
$BinDir = $bpc->BinDir(); $BinDir = $bpc->BinDir();
%Conf = $bpc->Conf(); %Conf = $bpc->Conf();
$Lang = $bpc->Lang(); $Lang = $bpc->Lang();
$ConfigMTime = $bpc->ConfigMTime(); $ConfigMTime = $bpc->ConfigMTime();
umask($Conf{UmaskMode}); umask($Conf{UmaskMode});
} }
# #
# Default REMOTE_USER so in a miminal installation the user # Default REMOTE_USER so in a miminal installation the user
# has a sensible default. # has a sensible default.
# #
$ENV{REMOTE_USER} = $Conf{BackupPCUser} if ( $ENV{REMOTE_USER} eq "" ); $ENV{REMOTE_USER} = $Conf{BackupPCUser} if ( $ENV{REMOTE_USER} eq "" );
# #
# We require that Apache pass in $ENV{SCRIPT_NAME} and $ENV{REMOTE_USER}. # We require that Apache pass in $ENV{SCRIPT_NAME} and $ENV{REMOTE_USER}.
# The latter requires .ht_access style authentication. Replace this # The latter requires .ht_access style authentication. Replace this
# code if you are using some other type of authentication, and have # code if you are using some other type of authentication, and have
# a different way of getting the user name. # a different way of getting the user name.
# #
$MyURL = $ENV{SCRIPT_NAME}; $MyURL = $ENV{SCRIPT_NAME};
$User = $ENV{REMOTE_USER}; $User = $ENV{REMOTE_USER};
# #
# Handle LDAP uid=user when using mod_authz_ldap and otherwise untaint # Handle LDAP uid=user when using mod_authz_ldap and otherwise untaint
# #
$User = $1 if ( $User =~ /uid=([^,]+)/i || $User =~ /(.*)/ ); $User = $1 if ( $User =~ /uid=([^,]+)/i || $User =~ /(.*)/ );
if ( !defined($Hosts) || $bpc->HostsMTime() != $HostsMTime ) { if ( !defined($Hosts) || $bpc->HostsMTime() != $HostsMTime ) {
$HostsMTime = $bpc->HostsMTime(); $HostsMTime = $bpc->HostsMTime();
$Hosts = $bpc->HostInfoRead(); $Hosts = $bpc->HostInfoRead();
# turn moreUsers list into a hash for quick lookups # turn moreUsers list into a hash for quick lookups
foreach my $host (keys %$Hosts) { foreach my $host ( keys %$Hosts ) {
$Hosts->{$host}{moreUsers} = $Hosts->{$host}{moreUsers} =
{map {$_, 1} split(",", $Hosts->{$host}{moreUsers}) } {map { $_, 1 } split(",", $Hosts->{$host}{moreUsers})};
} }
} }
# #
# Untaint the host name # Untaint the host name
# #
if ( $In{host} =~ /^([\w.\s-]+)$/ ) { if ( $In{host} =~ /^([\w.\s-]+)$/ ) {
$In{host} = $1; $In{host} = $1;
} else { } else {
delete($In{host}); delete($In{host});
} }
} }
sub childCleanup sub childCleanup
{ {
$ChildExited = 1; $ChildExited = 1;
$SIG{CHLD} = \&childCleanup; $SIG{CHLD} = \&childCleanup;
} }
sub childKill sub childKill
 End of changes. 28 change blocks. 
77 lines changed or deleted 83 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)