diff --git a/support/rrsync b/support/rrsync old mode 100644 new mode 100755 index 9195aa2..397b9e6 --- a/support/rrsync +++ b/support/rrsync @@ -8,11 +8,13 @@ use strict; use Socket; use Cwd 'abs_path'; use File::Glob ':glob'; +use Fcntl ':flock'; # You may configure these values to your liking. See also the section # of options if you want to disable any options that rsync accepts. use constant RSYNC => '/usr/bin/rsync'; use constant LOGFILE => 'rrsync.log'; +use constant LOCKFILE => '.rrsync.lock'; my $Usage = <>', LOCKFILE) or die "open lockfile: $!"; +flock LOCK_FH, ($am_sender ? LOCK_SH : LOCK_EX) or die "lock lockfile: $!"; + ### START of options data produced by the cull_options script. ### # These options are the only options that rsync might send to the server, @@ -216,6 +224,11 @@ die "$0: invalid rsync-command syntax or options\n" if $in_options; @args = ( '.' ) if !@args; +for (@args) { + die "$0: do not use .. in any path!\n" if m{(^|/)\.\.(/|$)}; + die "$0: arg not under subdir\n" unless abs_is_under($_, $subdir); +} + if ($write_log) { my ($mm,$hh) = (localtime)[1,2]; my $host = $ENV{SSH_CONNECTION} || 'unknown'; @@ -227,7 +240,19 @@ if ($write_log) { } # Note: This assumes that the rsync protocol will not be maliciously hijacked. -exec(RSYNC, @opts, @args) or die "exec(rsync @opts @args) failed: $? $!"; +exit system(RSYNC, @opts, '--', @args); + +sub abs_is_under { + my ($path, $under_abspath) = @_; + for (;;) { + my $a = abs_path($path); + if (defined $a) { + return $a =~ m{^\Q$under_abspath\E(/|$)}; + } + die "abs_path failed on .: $!" if $path eq '.'; + $path =~ s{/[^/]*$}{} or $path = '.'; + } +} sub check_arg { @@ -238,6 +263,8 @@ sub check_arg die "Do not use .. in --$opt; anchor the path at the root of your restricted dir.\n" if $arg =~ m{(^|/)\.\.(/|$)}; $arg =~ s{^/}{$subdir/}; + die "--$opt value outside restricted dir.\n" + unless abs_is_under($arg, $subdir); } $arg; }