Skip to content

Commit

Permalink
* various FTP fixes
Browse files Browse the repository at this point in the history
* added more shell escaping to bin/BackupPC_archiveHost

* updates to FTP conf/config.pl comments

* minor path change to configure.pl
  • Loading branch information
cbarratt committed Apr 5, 2009
1 parent 0e6be99 commit fb14ecb
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 50 deletions.
3 changes: 2 additions & 1 deletion ChangeLog
Expand Up @@ -75,7 +75,8 @@

* Modified bin/BackupPC_archiveHost to shell escape the output file
name. That allows it to contain spaces and other special characters.
Requested by Toni Van Remortel.
Requested by Toni Van Remortel. Also updated bin/BackupPC_archiveHost
to shell escape and check other arguments.

* Added $Conf{CmdQueueNice} to specify nice level for command queue
commands (eg: BackupPC_link and BackupPC_nightly). Suggested by
Expand Down
16 changes: 12 additions & 4 deletions bin/BackupPC_archiveHost
@@ -1,4 +1,4 @@
#!/bin/perl
#!/usr/bin/perl
#=============================================================
#
# BackupPC_archiveHost: Archive files for a single host
Expand Down Expand Up @@ -38,7 +38,7 @@
#
#========================================================================
#
# Version 3.1.0, released 25 Nov 2007.
# Version 3.2.0beta0, released 29 Mar 2009.
#
# See http://backuppc.sourceforge.net.
#
Expand Down Expand Up @@ -77,6 +77,10 @@ die("BackupPC::Lib->new failed\n") if ( !(my $bpc = BackupPC::Lib->new) );
# Make sure the specified programs are executable
#
foreach my $prog ( ($tarCreate, $compPath, $splitPath, $parPath) ) {
if ( $prog =~ /[][;&()<>{}|^\n\r\t *\$\\'"`?]/ ) {
print("Error: executable path $prog contains suspicious characters\n");
exit(1);
}
next if ( $prog eq "" || -x $prog );
print("Error: $prog is not an executable program\n");
exit(1);
Expand All @@ -88,6 +92,10 @@ my $mesg = "Writing tar archive for host $host, backup #$bkupNum";
#
$share = $bpc->shellEscape($share);
$host = $bpc->shellEscape($host);
$bkupNum = $bpc->shellEscape($bkupNum);
$fileExt = $bpc->shellEscape($fileExt);
$splitSize = $bpc->shellEscape($splitSize);
$parfile = $bpc->shellEscape($parfile);
my $outLocE = $bpc->shellEscape($outLoc);

#
Expand All @@ -114,7 +122,7 @@ if ( -b $outLoc || -c $outLoc || -f $outLoc ) {
# Output file is a device or a regular file, so don't use split
#
$cmd .= ">> $outLocE";
$mesg .= " to $outLocE";
$mesg .= " to $outLoc";
} else {
mkpath($outLoc) if ( !-d $outLoc );
if ( !-d $outLoc ) {
Expand Down Expand Up @@ -146,7 +154,7 @@ if ( $ret ) {
# ie: not a tape device).
#
if ( -d $outLoc && -x $parPath ) {
if ( $parfile != 0 ) {
if ( length($parfile) ) {
print("Running $parPath to create parity files\n");
my $parCmd = "$parPath c -r$parfile $outLocE/$host.$bkupNum.tar$fileExt.par2 $outLocE/$host.$bkupNum.tar$fileExt*";
$ret = system($parCmd);
Expand Down
35 changes: 31 additions & 4 deletions conf/config.pl
Expand Up @@ -717,6 +717,12 @@
# Users report that for smbclient you should specify a directory
# followed by "/*", eg: "/proc/*", instead of just "/proc".
#
# FTP servers are traversed recursively so excluding directories will
# also exclude its contents. You can use the wildcard characters "*"
# and "?" to define files for inclusion and exclusion. Both
# attributes $Conf{BackupFilesOnly} and $Conf{BackupFilesExclude} can
# be defined for the same share.
#
# If a hash is used, a special key "*" means it applies to all
# shares that don't have a specific entry.
#
Expand Down Expand Up @@ -1384,12 +1390,33 @@
# (can be overwritten in the per-PC log file)
##########################################################################
#
# Name of the host share that is backed up when using FTP. This can be a
# Which host directories to backup when using FTP. This can be a
# string or an array of strings if there are multiple shares per host.
# Examples:
#
# $Conf{FtpShareName} = 'c'; # backup 'c' share
# $Conf{FtpShareName} = ['c', 'd']; # backup 'c' and 'd' shares
# This value must be specified in one of two ways: either as a
# subdirectory of the 'share root' on the server, or as the absolute
# path of the directory.
#
# In the following example, if the directory /home/username is the
# root share of the ftp server with the given username, the following
# two values will back up the same directory:
#
# $Conf{FtpShareName} = 'www'; # www directory
# $Conf{FtpShareName} = '/home/username/www'; # same directory
#
# Path resolution is not supported; i.e.; you may not have an ftp
# share path defined as '../otheruser' or '~/games'.
#
# Multiple shares may also be specified, as with other protocols:
#
# $Conf{FtpShareName} = [ 'www',
# 'bin',
# 'config' ];
#
# Note also that you can also use $Conf{BackupFilesOnly} to specify
# a specific list of directories to backup. It's more efficient to
# use this option instead of $Conf{FtpShareName} since a new tar is
# run for each entry in $Conf{FtpShareName}.
#
# This setting only matters if $Conf{XferMethod} = 'ftp'.
#
Expand Down
2 changes: 1 addition & 1 deletion configure.pl
Expand Up @@ -266,7 +266,7 @@
foreach my $prog ( sort(keys(%Programs)) ) {
my $path;
foreach my $subProg ( split(/\//, $prog) ) {
$path = FindProgram("$ENV{PATH}:/bin:/usr/bin:/sbin:/usr/sbin",
$path = FindProgram("$ENV{PATH}:/usr/bin:/bin:/sbin:/usr/sbin",
$subProg) if ( !length($path) );
}
$Conf{$Programs{$prog}} = $path if ( !length($Conf{$Programs{$prog}}) );
Expand Down
91 changes: 51 additions & 40 deletions lib/BackupPC/Xfer/Ftp.pm
Expand Up @@ -168,7 +168,7 @@ sub start
# Convert the encoding type of the names if at all possible
#
from_to( $args->{shareName}, "utf8", $conf->{ClientCharset} )
if ( $conf->{ClientCharset} ne "" );
if ( $conf->{ClientCharset} ne "" );

#
# Collect FTP configuration arguments and translate them for
Expand All @@ -187,7 +187,7 @@ sub start
: Net::FTP->new(%$args);
};
if ($@) {
$t->{_errStr} = "Can't open connection to $args->{Host}: $!";
$t->{_errStr} = "Can't open connection to $args->{host}: $!";
$t->{xferErrCnt}++;
return;
}
Expand All @@ -198,7 +198,7 @@ sub start
undef $@;
eval { $t->{ftp}->login( $conf->{FtpUserName}, $conf->{FtpPasswd} ); };
if ( $@ ) {
$t->{_errStr} = "Can't login to $args->{Host}: $!";
$t->{_errStr} = "Can't login to $args->{host}: $!";
$t->{xferErrCnt}++;
return;
}
Expand All @@ -207,7 +207,7 @@ sub start
eval { $t->{ftp}->binary(); };
if ($@) {
$t->{_errStr} =
"Can't enable binary transfer mode to $args->{Host}: $!";
"Can't enable binary transfer mode to $args->{host}: $!";
$t->{xferErrCnt}++;
return;
}
Expand All @@ -234,36 +234,38 @@ sub start
# log the beginning of action based on type
#
if ( $t->{type} eq 'restore' ) {
$logMsg = "restore started on directory $t->{shareName}";
$logMsg = "ftp restore for host $t->{host} started on directory "
. "$t->{shareName}\n";

} elsif ( $t->{type} eq 'full' ) {
$logMsg = "full backup started on directory $t->{shareName}";
$logMsg = "ftp full backup for host $t->{host} started on directory "
. "$t->{shareName}\n";

} elsif ( $t->{type} eq 'incr' ) {

$incrDate = $bpc->timeStamp( $t->{incrBaseTime} - 3600, 1 );
$logMsg = "incremental backup started back to $incrDate" .
" (backup #$t->{incrBaseBkupNum}) for directory" . "
$t->{shareName}";
$logMsg = "ftp incremental backup for $t->{host} started back to "
. "$incrDate (backup #$t->{incrBaseBkupNum}) for directory "
. "$t->{shareName}\n";
}
$t->logWrite($logMsg, 1);

#
# call the recursive function based on the type of action
#
if ( $t->{type} eq 'restore' ) {

$t->restore();
$logMsg = "Restore of $args->{Host} complete";
$logMsg = "Restore of $t->{host} complete";

} elsif ( $t->{type} eq 'incr' ) {

$t->backup();
$logMsg = "Incremental backup of $args->{Host} complete";
$logMsg = "Incremental backup of $t->{host} complete";

} elsif ( $t->{type} eq 'full' ) {

$t->backup();
$logMsg = "Full backup of $args->{Host} complete";
$logMsg = "Full backup of $t->{host} complete";
}

delete $t->{_errStr};
Expand Down Expand Up @@ -297,8 +299,8 @@ sub run
return ( $t->{fileCnt}, $t->{byteCnt}, 0, 0 );

} else {
return \( $tarErrs, $nFilesExist, $sizeExist,
$sizeExistCom, $nFilesTotal, $sizeTotal );
return ( $tarErrs, $nFilesExist, $sizeExist,
$sizeExistCom, $nFilesTotal, $sizeTotal );
}
}

Expand Down Expand Up @@ -587,7 +589,8 @@ sub remotels
};

$f->{utf8name} = $f->{name};
from_to( $f->{utf8name}, $conf->{ClientCharset}, "utf8" );
from_to( $f->{utf8name}, $conf->{ClientCharset}, "utf8" )
if ( $conf->{ClientCharset} ne "" );

$f->{fullName} = "$t->{sharePath}/$path/$f->{name}";
$f->{fullName} =~ s/\/+/\//g;
Expand Down Expand Up @@ -709,7 +712,8 @@ sub handleSymFile
};

$f->{utf8name} = $fSym->{name};
from_to( $f->{utf8name}, $conf->{ClientCharset}, "utf8" );
from_to( $f->{utf8name}, $conf->{ClientCharset}, "utf8" )
if ( $conf->{ClientCharset} ne "" );

$f->{relPath} = $fSym->{relPath};
$f->{fullName} = "$t->{shareName}/$fSym->{relPath}/$fSym->{name}";
Expand Down Expand Up @@ -755,7 +759,7 @@ sub handleDir
}
}

$attrib = BackupPC::Attrib->new( { compress => $t->{Compress} } );
$attrib = BackupPC::Attrib->new( { compress => $t->{compress} } );
$remoteDir = $t->remotels( $dir->{relPath} );

if ( $t->{type} eq "incr" ) {
Expand Down Expand Up @@ -828,7 +832,7 @@ sub handleDir
my $data = $attrib->writeData();

$poolWrite = BackupPC::PoolWrite->new( $bpc, $fileName, length($data),
$t->{Compress} );
$t->{compress} );
$poolWrite->write( \$data );
( $exists, $digest, $outSize, $errs ) = $poolWrite->close();

Expand Down Expand Up @@ -867,13 +871,12 @@ sub handleFile
}

my $attribInfo = {
type => BPC_FTYPE_FILE,
mode => $f->{mode},
uid => undef, # unsupported
gid => undef, # unsupported
size => $f->{size},
mtime => $f->{mtime},
};
%$f,
type => BPC_FTYPE_FILE,
uid => undef, # unsupported
gid => undef, # unsupported
};
delete $attribInfo->{utf8name}; # unused value

#
# If this is a full backup or the file has changed on the host,
Expand All @@ -882,15 +885,15 @@ sub handleFile
undef $@;
eval { tie ( *FTP, 'Net::FTP::RetrHandle', $ftp, $f->{fullName} ); };
if ( !*FTP || $@ ) {
$t->handleFileAction( "fail", $attribInfo );
$t->logFileAction( "fail", $f->{utf8name}, $attribInfo );
$t->{xferBadFileCnt}++;
$stats->{errCnt}++;
return;
}

$poolFile = $OutDir . "/" . $bpc->fileNameMangle( $f->{name} );
$poolWrite = BackupPC::PoolWrite->new( $bpc, $poolFile, $f->{size},
$bpc->{xfer}{compress} );
$poolFile = $OutDir . "/" . $bpc->fileNameMangle( $f->{name} );
$poolWrite = BackupPC::PoolWrite->new( $bpc, $poolFile, $f->{size},
$t->{compress} );

$localSize = 0;

Expand All @@ -916,7 +919,7 @@ sub handleFile
#
if ( $localSize != $f->{size} ) {
$t->logFileAction( "fail", $f->{utf8name}, $attribInfo );
unklink($poolFile);
unlink($poolFile);
$stats->{xferBadFileCnt}++;
$stats->{errCnt}++;
return;
Expand All @@ -928,7 +931,12 @@ sub handleFile
$attrib->set( $f->{utf8name}, $attribInfo );
$t->logFileAction( $exists ? "pool" : "create",
$f->{utf8name}, $attribInfo );
print $newFilesFH "$digest $f->{size} $poolFile\n" unless $exists;

my $relPoolFile = $bpc->fileNameEltMangle( $t->{shareName} )
. "/"
. $bpc->fileNameMangle($attribInfo->{relPath});

print $newFilesFH "$digest $f->{size} $relPoolFile\n" unless $exists;

#
# Cumulate the stats
Expand All @@ -955,12 +963,13 @@ sub incrFileExistCheck
my $view = $t->{view};

my $oldAttribInfo = $view->fileAttrib( $t->{incrBaseBkupNum},
$t->{shareName}, $f->{relPath} );
$t->{shareName}, "/" . $f->{relPath} );

#print STDERR "*" x 50 . "\n";
#print STDERR "Old data:\n" . Dumper($oldAttribInfo);
#print STDERR "New data:\n" . Dumper($f);
#print STDERR "$f->{fullName}: $oldAttribInfo->{mtime} ?= $f->{mtime}, $oldAttribInfo->{size} ?= $f->{size}\n";
##$t->logWrite( "Old attrib:\n" . Dumper($oldAttribInfo), 1 );
##$t->logWrite( "New attrib:\n" . Dumper($f), 1 );
##$t->logWrite( sprintf("%s: mtime %d vs %d, size %d vs %d\n", $f->{fullName},
## $oldAttribInfo->{mtime}, $f->{mtime},
## $oldAttribInfo->{size}, $f->{size}), 1);

return ( $oldAttribInfo->{mtime} == $f->{mtime}
&& $oldAttribInfo->{size} == $f->{size} );
Expand All @@ -983,9 +992,11 @@ sub logFileAction
$name = "." if ( $name eq "" );
$owner = "-/-" if ( $owner eq "/" );

my $fileAction = sprintf( " %-6s %1s%4o %9s %11.0f %s\n",
$action, $type, $attrib->{mode} & 07777,
$owner, $attrib->{size}, $name );
my $fileAction = sprintf(
" %-6s %1s%4o %9s %11.0f %s\n",
$action, $type, $attrib->{mode} & 07777,
$owner, $attrib->{size}, $attrib->{relPath}
);

return $t->logWrite( $fileAction, 1 );
}
Expand Down

0 comments on commit fb14ecb

Please sign in to comment.