use rrsync to restrict rsync access
authorRalf Jung <post@ralfj.de>
Sat, 22 Feb 2014 10:25:20 +0000 (11:25 +0100)
committerRalf Jung <post@ralfj.de>
Sat, 22 Feb 2014 10:25:20 +0000 (11:25 +0100)
Makefile
makeschsh
schsh
schsh-rrsync [changed mode: 0755->0644]

index 83397e764a4e069c48f599c06d50917eda4ec685..531c14f7d8199de0542ad043b20f191aa0753b4e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ TARGET := /usr/local
 SCHROOT := /etc/schroot
 
 install:
 SCHROOT := /etc/schroot
 
 install:
-       install -o root -g root schsh makeschsh $(TARGET)/bin/
+       install -o root -g root schsh makeschsh schsh-rrsync $(TARGET)/bin/
        install -o root -g root -d $(SCHROOT)/schsh/
        install -o root -g root -m 644 schroot/schsh/* $(SCHROOT)/schsh/
        install -o root -g root -d /var/lib/schsh/
        install -o root -g root -d $(SCHROOT)/schsh/
        install -o root -g root -m 644 schroot/schsh/* $(SCHROOT)/schsh/
        install -o root -g root -d /var/lib/schsh/
index 54766877ace130069e449f83688063bbac844739..0c661452ea12015f6685e7ed1aae69620bde28db 100755 (executable)
--- a/makeschsh
+++ b/makeschsh
@@ -35,7 +35,7 @@ setup.fstab=schsh/{0}.fstab
                # no spaces, schroot does not like them
                print("# <file system> <mount point>   <type>  <options>       <dump>  <pass>", file=f)
                # system folders
                # no spaces, schroot does not like them
                print("# <file system> <mount point>   <type>  <options>       <dump>  <pass>", file=f)
                # system folders
-               for folder in ("/lib", "/lib64", "/usr/bin", "/usr/lib", "/usr/lib64"):
+               for folder in ("/lib", "/lib64", "/usr/bin", "/usr/lib", "/usr/lib64", "/usr/share/", "/usr/local/bin"):
                        if os.path.exists(folder):
                                print("{0}\t{0}\tnone\trw,bind\t0\t0".format(folder), file=f)
                # user folder
                        if os.path.exists(folder):
                                print("{0}\t{0}\tnone\trw,bind\t0\t0".format(folder), file=f)
                # user folder
@@ -43,7 +43,7 @@ setup.fstab=schsh/{0}.fstab
        
        # setup the schroot directory
        os.mkdir(chroot)
        
        # setup the schroot directory
        os.mkdir(chroot)
-       for folder in ["etc", "dev", "bin", "usr", "data"]:
+       for folder in ["etc", "dev", "data"]:
                os.mkdir(os.path.join(chroot, folder))
        
        # setup /etc/passwd and /etc/group
                os.mkdir(os.path.join(chroot, folder))
        
        # setup /etc/passwd and /etc/group
diff --git a/schsh b/schsh
index f96e69564275e9c47115217f9dc3fbd01cff438f..823eeaa70cfcf710311451f5ae610dfa0769d888 100755 (executable)
--- a/schsh
+++ b/schsh
@@ -1,7 +1,10 @@
 #!/usr/bin/python3
 #!/usr/bin/python3
+import logging, logging.handlers
+import os, sys, shlex, pwd
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
 # Configuration
 shell = None # set to "/bin/bash" or similar to allow shell access
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
 # Configuration
 shell = None # set to "/bin/bash" or similar to allow shell access
+rrsync = "/usr/local/bin/schsh-rrsync" # path to the restricted rsync script - if available, it will be used to further restrict rsync access
 
 def allowSCP(run, runstr):
        if len(run) != 3: return False
 
 def allowSCP(run, runstr):
        if len(run) != 3: return False
@@ -15,7 +18,11 @@ def allowRSync(run, runstr):
        if len(run) < 3: return False
        if run[0] != "rsync": return False
        if run[1] != "--server": return False
        if len(run) < 3: return False
        if run[0] != "rsync": return False
        if run[1] != "--server": return False
-       run[0] = "/usr/bin/rsync"
+       if rrsync is None:
+               # rrsync is not available, let's hope this is enough protection
+               run[0] = "/usr/bin/rsync"
+               return True
+       run[:] = [rrsync, "/", runstr] # allow access to the entire chroot
        return True
 
 def allowSFTP(run, runstr):
        return True
 
 def allowSFTP(run, runstr):
@@ -27,8 +34,6 @@ allowCommands = [allowSCP, allowRSync, allowSFTP]
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
 # DO NOT TOUCH ANYTHING BELOW THIS LINE
 
 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
 # DO NOT TOUCH ANYTHING BELOW THIS LINE
 
-import logging, logging.handlers
-import os, sys, shlex, pwd
 
 logger = logging.getLogger("schsh")
 logger.setLevel(logging.INFO)
 
 logger = logging.getLogger("schsh")
 logger.setLevel(logging.INFO)
old mode 100755 (executable)
new mode 100644 (file)
index bb51629..75c252b
@@ -3,16 +3,16 @@
 # Purpose: Restricts rsync to subdirectory declared in .ssh/authorized_keys
 # Author: Joe Smith <js-cgi@inwap.com> 30-Sep-2004
 # Modified by: Wayne Davison <wayned@samba.org>
 # Purpose: Restricts rsync to subdirectory declared in .ssh/authorized_keys
 # Author: Joe Smith <js-cgi@inwap.com> 30-Sep-2004
 # Modified by: Wayne Davison <wayned@samba.org>
+# Modified by: Ralf Jung <post@ralfj.de>
 use strict;
 
 use strict;
 
-use Socket;
+use Socket;
 use Cwd 'abs_path';
 use File::Glob ':glob';
 
 # 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 Cwd 'abs_path';
 use File::Glob ':glob';
 
 # 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';
 
 my $Usage = <<EOM;
 Use 'command="$0 [-ro] SUBDIR"'
 
 my $Usage = <<EOM;
 Use 'command="$0 [-ro] SUBDIR"'
@@ -25,18 +25,13 @@ die "$0: No subdirectory specified\n$Usage" unless defined $subdir;
 $subdir = abs_path($subdir);
 die "$0: Restricted directory does not exist!\n" if $subdir ne '/' && !-d $subdir;
 
 $subdir = abs_path($subdir);
 die "$0: Restricted directory does not exist!\n" if $subdir ne '/' && !-d $subdir;
 
-# 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...
-#
-# Format of the environment variables set by sshd:
-# SSH_ORIGINAL_COMMAND=rsync --server          -vlogDtpr --partial . ARG # push
-# SSH_ORIGINAL_COMMAND=rsync --server --sender -vlogDtpr --partial . ARGS # pull
-# SSH_CONNECTION=client_addr client_port server_port
-
-my $command = $ENV{SSH_ORIGINAL_COMMAND};
+# The client uses "rsync -av -e ssh src/ server:dir/", and schsh makes the entire rsync call
+# the third argument to rrsnc: rrsync (-ro)? SUBDIR COMMAND
+# Format of the COMMAND:
+# COMMAND=rsync --server          -vlogDtpr --partial . ARG # push
+# COMMAND=rsync --server --sender -vlogDtpr --partial . ARGS # pull
+
+my $command = shift;
 die "$0: Not invoked via sshd\n$Usage" unless defined $command;
 die "$0: SSH_ORIGINAL_COMMAND='$command' is not rsync\n" unless $command =~ s/^rsync\s+//;
 die "$0: --server option is not first\n" unless $command =~ /^--server\s/;
 die "$0: Not invoked via sshd\n$Usage" unless defined $command;
 die "$0: SSH_ORIGINAL_COMMAND='$command' is not rsync\n" unless $command =~ s/^rsync\s+//;
 die "$0: --server option is not first\n" unless $command =~ /^--server\s/;
@@ -129,10 +124,6 @@ if ($short_disabled ne '') {
 $short_no_arg = "[$short_no_arg]" if length($short_no_arg) > 1;
 $short_with_num = "[$short_with_num]" if length($short_with_num) > 1;
 
 $short_no_arg = "[$short_no_arg]" if length($short_no_arg) > 1;
 $short_with_num = "[$short_with_num]" if length($short_with_num) > 1;
 
-my $write_log = -f LOGFILE && open(LOG, '>>', LOGFILE);
-
-chdir($subdir) or die "$0: Unable to chdir to restricted dir: $!\n";
-
 my(@opts, @args);
 my $in_options = 1;
 my $last_opt = '';
 my(@opts, @args);
 my $in_options = 1;
 my $last_opt = '';
@@ -191,16 +182,6 @@ die "$0: invalid rsync-command syntax or options\n" if $in_options;
 
 @args = ( '.' ) if !@args;
 
 
 @args = ( '.' ) if !@args;
 
-if ($write_log) {
-  my ($mm,$hh) = (localtime)[1,2];
-  my $host = $ENV{SSH_CONNECTION} || 'unknown';
-  $host =~ s/ .*//; # Keep only the client's IP addr
-  $host =~ s/^::ffff://;
-  $host = gethostbyaddr(inet_aton($host),AF_INET) || $host;
-  printf LOG "%02d:%02d %-13s [%s]\n", $hh, $mm, $host, "@opts @args";
-  close LOG;
-}
-
 # Note: This assumes that the rsync protocol will not be maliciously hijacked.
 exec(RSYNC, @opts, @args) or die "exec(rsync @opts @args) failed: $? $!";
 
 # Note: This assumes that the rsync protocol will not be maliciously hijacked.
 exec(RSYNC, @opts, @args) or die "exec(rsync @opts @args) failed: $? $!";