chroot RSSH on FreeBSD 5.X

Intro

rssh is shell that you can use in tandem with OpenSSH to grant users access which is restricted to sftp and/or scp. It also has the additional feature of allowing you to place the user in a chroot environment.

It is quite nice. A couple of years ago I needed such a chrooted sftp environment and no such solution existed for OpenSSH at the time, so I ended up having to go with SSH Communications' package (on the Linux). Less than thrilling. It made me feel dirty.

This document describes the steps to setup a chrooted rssh user environment on FreeBSD. This work is based on a system running FreeBSD 5.2.1-RELEASE with rssh v2.2.1 as built from source. I would think this should work under all of FreeBSD 5.X... YMMV.

The Problem

rssh comes with some light reading on how to setup chroot users in the CHROOT file in the source tarball. The only problem there is that the docs are Linux specific... they work like a charm on some SuSE systems I have used it with, but no go for FreeBSD. Also, the FreeBSD port is behind the times at this time (v2.1.1) and doesn't add much of anything for docs (if someone finds otherwise, please let me know).

The other problem is that although I have plenty of FreeBSD experience, my knowledge of the chroot system and everything that is generally required to make such an environment complete is pretty minimal. So I had to plod on for quite a bit to make it work, and back out the stuff that didn't. But let my loss of sleep be your gain in knowledge...

The Solution

Build rssh

This is a fairly simple build. Once the source was downloaded and untarred, I configured the build with:
./configure --prefix=/usr/local --with-scp=/usr/bin/scp --with-sftp-server=/usr/libexec/sftp-server

If you try to run make right now the build will fail. Go ahead, try it. Looking in the rssh port, you will see there is a patch to util.c (in v2.1.1) that fixes the culprit, only in v2.2.1 the offending line has been moved to argvec.c. So make the equiv modification there. Here the diff on what I did:

--- argvec.c.orig       Wed Jul 21 16:28:40 2004
+++ argvec.c    Wed Jul 21 16:28:54 2004
@@ -65,7 +65,7 @@
        int             retc;
 
        result.we_offs = reserve;
-       if ( (retc = wordexp(str, &result, WRDE_NOCMD|WRDE_DOOFFS)) ){
+       if ( (retc = wordexp(str, &result, WRDE_NOCMD|WRDE_DOOFS)) ){
                log_set_priority(LOG_ERR);
                switch( retc ){
                case WRDE_BADCHAR:

Now you can do a make and make install.

Chim chimeney, chim chimeney, chim chim chroot

Much of what follows mirrors what is in the CHROOT in the rssh tarball. Please read it first.

For my purposes, I wanted to be able to chroot the sftp for arbitrary users on the system, but I wasn't terribly concerned about them being in individual cells. So I chose to make /home/chroot as the chroot base. Then (after having created all of the appropriate directories) I copied in the required binaries:

# cp /usr/bin/scp /home/chroot/usr/bin/scp
# cp /usr/libexec/sftp-server /home/chroot/usr/libexec/sftp-server
# cp /usr/local/libexec/rssh_chroot_helper /home/chroot/usr/local/libexec/rssh_chroot_helper

We also need all of the libraries moved in that the above are dependent upon:

# ldd /usr/bin/scp
/usr/bin/scp:
        libssh.so.2 => /usr/lib/libssh.so.2 (0x28077000)
        libcrypto.so.3 => /lib/libcrypto.so.3 (0x280a6000)
        libz.so.2 => /lib/libz.so.2 (0x281b4000)
        libc.so.5 => /lib/libc.so.5 (0x281c2000)
# cp /usr/lib/libssh.so.2 /home/chroot/usr/lib/libssh.so.2
# cp /lib/libcrypto.so.3 /home/chroot/lib/libcrypto.so.3
# cp /lib/libz.so.2 /home/chroot/lib/libz.so.2
# cp /lib/libc.so.5 /home/chroot/lib/libc.so.5

The requirements of sftp-helper and rssh_chroot_helper are no greater, so that is it for this step.

In the rssh CHROOT file they mention:

If any of the binaries in question are linked dynamically (and in most cases, this will be true), you need to also copy any configuration files for the dynamic linker into your chroot jail. On Linux, you want the files /etc/ld.so* to be copied.

But this isn't Linux, there is no /etc/ld.so*, and I had no immediate clue as to what the equivalent on FreeBSD was. However, I did figure if things were set up properly that I should be able to use the chroot command to launch one of the chrooted apps... so I try:

# chroot /home/chroot /usr/local/libexec/rssh_chroot_helper 
ELF interpreter /libexec/ld-elf.so.1 not found
Abort

So hey, I learn something new and:

# cp /libexec/ld-elf.so.1 /home/chroot/libexec/ld-elf.so.1

You're not in the clear yet though... security changes made from rssh 2.1.1 to 2.2.1 now require a shell (specifically sh it seems) and a null device, so you need to:

# cp /bin/sh /home/chroot/bin/sh
# cd /home/chroot/dev
# mknod null c 2 2
# chmod 666 null

I suspect someone, somewhere, really wants you to use devfs for /home/chroot/dev, but they haven't documented it clearly enough (for me) to use it without having 3247 different devices listed that I suspect I don't need or want to be hanging out there. Anyways...

And now things work. The remaining bits are to copy over an abridged copy of /etc/passwd to the chroot and modify the syslogd flags. For FreeBSD you need to use the -l flag to listen on an additional log socket, as opposed to -a for Linux. So I added to my /etc/rc.conf:

syslogd_flags="-ss -l /home/chroot/dev/log"

and also killed and relaunched syslogd with my new settings.


techno-obscura : delgado : notes