User Tools

Site Tools


efficient_backups_with_rsnapshot

Efficient backups with rsnapshot

Basically, do this: http://troy.jdmz.net/rsnapshot/

Reminder: on debian/ubuntu, you need to "sudo apt-get install liblchown-perl" so rsnapshot can set symlink ownership.

In place of his rickety validate-rsync script, use this rrsync script on clients:

#!/usr/bin/perl
# Name: /usr/local/bin/rrsync (should have a symlink in /usr/bin)
# Purpose: Restricts rsync to subdirectory declared in .ssh/authorized_keys
#
# The client uses "rsync -av -e ssh src/ server:dir/", and sshd on the server
# executes this program when .ssh/authorized_keys has 'command="..."'.
#       For example:
# command="rrsync logs/client" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAzGhEeNlPr...
# command="rrsync -ro results" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAmkHG1WCjC...
#   The former limits the remote client to a specific subdirectory of "logs"
#   and the latter allows read-only access to a different dirctory.
 
use Socket;
use constant LOGFILE => '/home/tkbletsc/rrsync.log';
my $Usage = <<EOM;
Use 'command="$0 [-ro] subdir"'
        in front of lines in $ENV{HOME}/.ssh/authorized_keys
EOM
 
# Format of the envrionment variables set by sshd:
# SSH_ORIGINAL_COMMAND=rsync --server          -vlogDtpr --partial . dir # push
# SSH_ORIGINAL_COMMAND=rsync --server --sender -vlogDtpr --partial . dir # pull
# SSH_CLIENT=client_addr client_port server_port
 
my $ro = (@ARGV and $ARGV[0] eq '-ro') ? shift : '';    # -ro = Read-Only
my $top1 = shift;
die "No subdirectory specified\n$Usage" unless defined $top1;
my $top2 = "$top1/";
 
my $command = $ENV{SSH_ORIGINAL_COMMAND};
die "Not invoked via sshd\n$Usage"      unless defined $command;
 
my ($cmd,$requested_target) = $command =~ /(.* \.) ?(.*)/;
die "SSH_ORIGINAL_COMMAND='$command' is not rsync\n" unless $cmd =~ /^rsync\s/;
die "$0 -ro: sending to read-only directory $requested_target not allowed\n"
        if $ro and $cmd !~ /^rsync --server --sender /;
 
my $dir = $requested_target;
$dir =~ tr|-~\\ _/a-zA-Z0-9.,:@|_|c;    # Don't allow ;|][}{*?
$dir =~ s%/\.\.(?=/)%__%g;              # Don't allow foo/../../etc
 
# For "foo", allow "foo", "foo/" and "foo/anything".
# For "foo/bar" and "foo/anything/bar", interpret "bar" to be the specified
# path and "bar/" to be the specified path with trailing slash supplied.
 
my($target,$forced);
if      ("/$dir" eq substr($top1,-length("/$dir"))) {
  $target = $top1;                      # Matched end of path
} elsif ("/$dir" eq substr($top2,-length("/$dir"))) {
  $target = $top2;                      # End of path plus trailing slash
} elsif ($dir eq $top1 or index($dir,$top2) == 0) {
  $target = $dir;                       # Exact match or subdirectory
} elsif (substr($dir,0,1) eq '/') {
  $target = "$top1$dir";                # Nonmatching absolute path
  $forced = 1;
} else {
  $target = "$top2$dir";                # Nonmatching relative path
  $forced = 1;
}
 
$target =~ s#^//#/#; # program is dumb and sets root to '//' sometimes, which confuses windows/cygwin hosts into looking for a share
 
if (-f LOGFILE and open LOG,'>>',LOGFILE) {
  my $hhmm = sprintf "%02d:%02d",(localtime)[2,1];
  my $host = $ENV{SSH_CLIENT} || 'unknown';
  $host =~ s/ .*//;                     # Keep only the client's IP addr
  $host = gethostbyaddr(inet_aton($host),AF_INET) || $host;
  $_ = sprintf "%-13s",$host;
  print LOG "$hhmm $_ [$command] =",($forced ? "> $target" : ' OK'),"\n";
  close LOG;
}
 
exec "$cmd $target" or die "exec($cmd $target) failed: $? $!";
# Note: This assumes that the rsync protocol will not be maliciously hijacked.

For Windows targets, install cygwin's SSH and rsync as per this guide. The rsnapshot.conf lines for such hosts should look something like:

backup	windowsuser@windowsbox-rsnapshot:/d/Documents	windowsbox/	rsync_long_args=--no-numeric-ids --delete --relative --delete-excluded
efficient_backups_with_rsnapshot.txt · Last modified: 2010/07/12 06:04 by tkbletsc