SysAdminMag.com
Implementing Rsync-Only Access over Chroot SSH
Julie Wang and Michael Wang
Rsync provides a flexible and efficient way to transfer files. Unlike ftp and scp, it can transfer the subset of files that has changed and only the differences within each file. Rsync can transfer files over SSH protocol, which provides the protection on the contents of the files via encryption. However, rsync over SSH requires a shell account on the remote site. This shell account, if unrestricted, can potentially read and write beyond the intended area. It may fill the /tmp space as a trivial example.
This article presents how to set up rsync over chroot SSH, which limits the access to a designated area, and how to set up rsync-only account with other access methods disabled. With these two security measures, it is expected that rsync-only access over chroot SSH can be used in public networks for data sharing and backup, replacing the application served by traditional FTP with enhanced flexibility and efficiency provided by rsync and security provided by SSH.
Chroot SSH
Chroot() is a system call to make the supplied directory appear as root directory, thus limiting the access beyond the directory. This functionality can be added to the portable OpenSSH release via a 30-line patch. The patch and the patched source are maintained by James Dennis (http://chrootssh.sourceforge.net/). This article is based on OpenSSH_3.9p1 and OpenSSH_4.0p1.
This patch allows sshd to look for "/./" in the user's home directory and perform chroot on the directory before this token. This restricts the user to the area under this directory. The concept is the same as in the Washington University's ftp server.
The installation of chroot SSH is done via the standard command sequence: configure, make, and make install.
In our case, we prefer to have the new SSH server installed on a separate area, /usr/local/ssh, for the ease of maintenance. The new sshd is configured as:
./configure --prefix=/usr/local/sshAfter the software install, the startup script for sshd must be changed to start the new sshd. The change is simple, just replacing the path to various binaries and configuration files. In our case, the new startup script is named new_sshd, and the differences between the old and new script are shown below:
< # Init file for OpenSSH server daemon > # Init file for OpenSSH server daemon (with chroot) < [ -f /etc/sysconfig/sshd ] && . /etc/sysconfig/sshd > [ -f /usr/local/ssh/etc/sysconfig/sshd ] && . \ /usr/local/ssh/etc/sysconfig/sshd < KEYGEN=/usr/bin/ssh-keygen > KEYGEN=/usr/local/ssh/bin/ssh-keygen < SSHD=/usr/sbin/sshd > SSHD=/usr/local/ssh/sbin/sshd < RSA1_KEY=/etc/ssh/ssh_host_key > RSA1_KEY=/usr/local/ssh/etc/ssh_host_key < RSA_KEY=/etc/ssh/ssh_host_rsa_key > RSA_KEY=/usr/local/ssh/etc/ssh_host_rsa_key < DSA_KEY=/etc/ssh/ssh_host_dsa_key > DSA_KEY=/usr/local/ssh/etc/ssh_host_dsa_keyIn a Red Hat-based systems, chkconfig can be used to disable the old startup script and enable the new one as:
# chkconfig --del sshd # chkconfig --add new_sshdOnce you have established a connection, stopping the old sshd daemon does not disconnect the existing session. The switching of the sshd daemon can be simply done as:
./sshd stop ./new_sshd startTo prevent possible lockup -- the old sshd is disabled but the new sshd is not started after reboot, and if you don't have access to the console, it is recommended that the telnet daemon be temporarily enabled. Rsync over Chroot SSH To utilize the chroot feature, the remote user's home directory should contain the magic token "/./", for example:
backup:x:0:0:Backup Account:/apps02/backup/./home:/bin/bashUpon establishing the SSH session, the user's new root directory is "/apps02/backup" in this example. As rsync connects to the remote host via SSH, rsync is started on the fly in server mode (rsync --server). To make rsync work over chroot SSH, rsync must be available under the new root. This can be done simply by copying the rsync binary as well as the dynamic libraries it uses under the new, restricted root with the same directory structure. Besides the rsync command, the shell (and associated libraries) must be available because rsync is run using the user's shell, as documented in session.c:
/* * Execute the command using the user's shell. This uses the -c * option to execute the command. */ argv[0] = (char *) shell0; argv[1] = "-c"; argv[2] = (char *) command; argv[3] = NULL; execve(shell, argv, env);The ldd command will print out the shared libraries that rsync and the shell (in this example, it is bash) use. On Red Hat-based Linux systems (we tested on Red Hat 9 and Fedora Core release 2), the binaries and associated libraries are:
bin/bash usr/bin/rsync lib/ld-linux.so.2 lib/libdl.so.2 lib/libresolv.so.2 lib/libtermcap.so.2 lib/tls/libc.so.6 usr/lib/libpopt.so.0To test that the dependencies of the rsync and shell binaries are complete, we can run them under the chroot environment, like this:
chroot /apps02/backup bash -c "rsync -h"Note that once we are in this chroot environment, the common commands such as ls are not available. We have to use shell built-in's. For example, instead of ls, you can use echo *, and so on. With these files in place, we can run rsync over chroot SSH. Rsync-Only Access over Chroot SSH While we make rsync work under the chroot SSH environment, the SSH and slogin are also available (sftp and scp are not, as the sftp and scp subsystems are not available in the chroot environment). For security reasons, it is recommended to disable the shell access. We note in a previous section that for the rsync access, the only purpose of the full functional login shell is to run the rsync command. This is also revealed by the strace command in Linux:
execve("/bin/bash", ["bash", "-c", "rsync --server ..."])Armed with this knowledge, we will be able to build a dummy shell, named dummysh, which provides this functionality only. A shell version of dummysh is shown as below:
#!/bin/bash if (( $# == 0 )) then printf "%s\n" "shell access is disabled. sorry." exit 1 elif (( $# == 2 )) && [[ $1 == "-c" && $2 == "rsync --server"* ]] then exec $2 fiThe dummy shell can be tuned to enable or disable certain accesses. For example, we can write the conditions as:
$2 == /usr/local/ssh/libexec/sftp-server || $2 == "rsync --server"*to allow sftp and rsync accesses.
To enable dummysh, change the user login shell to /bin/dummysh and copy it to both unrestricted and restricted environments.
A C version of dummy shell would be more secure, and it helps to get rid of the real shell -- bash, in this example -- altogether.
Summary
This setup combines the best features from rsync, SSH, and chroot. Rsync provides the flexibility and efficiency in files transfer, SSH protects the data being transferred, and chroot protects data on the server from unauthorized access. The dummysh limits the access to rsync only.
While rsync server implements chroot, it lacks the SSH protection that is often required. Besides, opening an additional rsync server port presents a security risk and sometimes is not possible either technically or politically. Sftp and scp lack the flexibility and efficiency provided by rsync, especially when a directory tree is involved, such as a Web site.
We hope this setup can find use in public networks, in areas traditionally served by anonymous and private FTP.
Julie Wang works for Independence Air (http://www.flyi.com/). She manages Oracle databases, Unix operating systems, Lawson enterprise systems, among others. She can be reached at: [email protected].
Michael Wang earned his Master Degrees in Physics (Peking) and Statistics (Columbia). Currently, he is applying his knowledge to Unix systems administration, database management, and programming. He can be reached at: [email protected].