Yesterday and today I tackled this beast and finally got it working. Here’s what I did:

I had openssh installed via yum, so first I had to uninstall that, along with it’s dependencies:

yum uninstall openssh

Erased: netdump
Erased: openssh-server
Erased: openssh
Erased: openssh-clients
Erased: openssh-askpass

After lots of reading through google post and trying various methods, I went to http://chrootssh.sourceforge.net/. In their downloads section, they now have patched source files for openssh with the ability for chroot already patched. For my server, I used this one. Here are the steps, including the config options I used.

After lots of reading through google post and trying various methods, I went to . In their downloads section, they now have patched source files for openssh with the ability for chroot already patched. For my server, I used . Here are the steps, including the config options I used.

cd /usr/local/src
wget http://chrootssh.sourceforge.net/download/openssh-4.5p1-chroot.tar.bz2
tar xjf openssh-4.5p1-chroot.tar.bz2
cd openssh-4.5p1-chroot
./configure \
       –prefix=/usr \
       –sysconfdir=/etc/ssh \
       –with-pam \
       –with-tcp-wrappers \
       –with-md5-passwords \
       –with-pid-dir=/var/run
make
make install

The install script copies default config files (according to the options I used above) to /etc/ssh directory. Within that directory, I tightened down things slightly by adding these lines to sshd_config:

AllowUsers user1 user2 user3 etc
PermitRootLogin no

This install also doesn’t come with a startup script, so I pulled one over from backup of the yum/rpm install of openssh. My /etc/init.d/sshd looks like this:

#!/bin/bash
#
# Init file for OpenSSH server daemon
#
# chkconfig: 2345 55 25
# description: OpenSSH server daemon
#
# processname: sshd
# config: /etc/ssh/ssh_host_key
# config: /etc/ssh/ssh_host_key.pub
# config: /etc/ssh/ssh_random_seed
# config: /etc/ssh/sshd_config
# pidfile: /var/run/sshd.pid

# source function library
. /etc/rc.d/init.d/functions

# pull in sysconfig settings
[ -f /etc/sysconfig/sshd ] && . /etc/sysconfig/sshd

RETVAL=0
prog=”sshd”

# Some functions to make the below more readable
KEYGEN=/usr/bin/ssh-keygen
SSHD=/usr/sbin/sshd
RSA1_KEY=/etc/ssh/ssh_host_key
RSA_KEY=/etc/ssh/ssh_host_rsa_key
DSA_KEY=/etc/ssh/ssh_host_dsa_key
PID_FILE=/var/run/sshd.pid

runlevel=$(set — $(runlevel); eval “echo \$$#” )

do_rsa1_keygen() {
        if [ ! -s $RSA1_KEY ]; then
                echo -n $”Generating SSH1 RSA host key: ”
                if $KEYGEN -q -t rsa1 -f $RSA1_KEY -C ” -N ” >&/dev/null; then
                        chmod 600 $RSA1_KEY
                        chmod 644 $RSA1_KEY.pub
                        if [ -x /sbin/restorecon ]; then
                            /sbin/restorecon $RSA1_KEY.pub
                        fi
                        success $”RSA1 key generation”
                        echo
                else
                        failure $”RSA1 key generation”
                        echo
                        exit 1
                fi
        fi
}

do_rsa_keygen() {
        if [ ! -s $RSA_KEY ]; then
                echo -n $”Generating SSH2 RSA host key: ”
                if $KEYGEN -q -t rsa -f $RSA_KEY -C ” -N ” >&/dev/null; then
                        chmod 600 $RSA_KEY
                        chmod 644 $RSA_KEY.pub
                        if [ -x /sbin/restorecon ]; then
                            /sbin/restorecon $RSA_KEY.pub
                        fi
                        success $”RSA key generation”
                        echo
                else
                        failure $”RSA key generation”
                        echo
                        exit 1
                fi
        fi
}

do_dsa_keygen() {
        if [ ! -s $DSA_KEY ]; then
                echo -n $”Generating SSH2 DSA host key: ”
                if $KEYGEN -q -t dsa -f $DSA_KEY -C ” -N ” >&/dev/null; then
                        chmod 600 $DSA_KEY
                        chmod 644 $DSA_KEY.pub
                        if [ -x /sbin/restorecon ]; then
                            /sbin/restorecon $DSA_KEY.pub
                        fi
                        success $”DSA key generation”
                        echo
                else
                        failure $”DSA key generation”
                        echo
                        exit 1
                fi
        fi
}

do_restart_sanity_check()
{
        $SSHD -t
        RETVAL=$?
        if [ ! “$RETVAL” = 0 ]; then
                failure $”Configuration file or keys are invalid”
                echo
        fi
}

start()
{
        # Create keys if necessary
        do_rsa1_keygen
        do_rsa_keygen
        do_dsa_keygen

        cp -af /etc/localtime /var/empty/sshd/etc

        echo -n $”Starting $prog: ”
        $SSHD $OPTIONS && success || failure
        RETVAL=$?
        [ “$RETVAL” = 0 ] && touch /var/lock/subsys/sshd
        echo
}

stop()
{
        echo -n $”Stopping $prog: ”
        if [ -n “`pidfileofproc $SSHD`” ] ; then
            killproc $SSHD
        else
            failure $”Stopping $prog”
        fi
        RETVAL=$?
        # if we are in halt or reboot runlevel kill all running sessions
        # so the TCP connections are closed cleanly
        if [ “x$runlevel” = x0 -o “x$runlevel” = x6 ] ; then
            killall $prog 2>/dev/null
        fi
        [ “$RETVAL” = 0 ] && rm -f /var/lock/subsys/sshd
        echo
}

reload()
{
        echo -n $”Reloading $prog: ”
        if [ -n “`pidfileofproc $SSHD`” ] ; then
            killproc $SSHD -HUP
        else
            failure $”Reloading $prog”
        fi
        RETVAL=$?
        echo
}

case “$1” in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart)
                stop
                start
                ;;
        reload)
                reload
                ;;
        condrestart)
                if [ -f /var/lock/subsys/sshd ] ; then
                        do_restart_sanity_check
                        if [ “$RETVAL” = 0 ] ; then
                                stop
                                # avoid race
                                sleep 3
                                start
                        fi
                fi
                ;;
        status)
                status $SSHD
                RETVAL=$?
                ;;
        *)
                echo $”Usage: $0 {start|stop|restart|reload|condrestart|status}”
                RETVAL=1
esac
exit $RETVAL

I was getting an error message using this startup script. I’m not sure what it’s for, but this script wants to copy /etc/localtime to /var/empty/sshd/etc/. Make sure this directory exists:

mkdir /var/empty/sshd
mkdir /var/empty/sshd/etc
cp -af /etc/localtime /var/empty/sshd/etc/

With the above, all the usual ssh stuff works, including sftp without chroot. 

OK, now to set up chroot. This took me forever to figure out, though as listed here it is simple.

First, set the user’s home directory in /etc/passwd. The key is to use a ‘.’ where you want the user’s root directory to be. For example, change the user’s home directory to something like:

/path/to/chroot_dir/./home/user

of course, create the /path/to/chroot_dir/home/user directory first. When the user logs in via ssh (or sftp, etc), he/she will see their home directory only as /home/user, and will be in “jail” within that directory structure. The rest of the system will be off limits.

Sounds easy enough. The problem is that it takes a lot more. Once the user logs in, they have to have access to system commands (like ls, mkdir, etc., as well as a shell like bash). There are several google references to how to do this, including (in no specific order):

The bottom line on all of these is that you have to create /bin, /dev, /etc/, /lib, /usr, and within the new jail, then these should be populated with the appropriate files.

cd /path/to/chroot
mkdir bin dev etc lib usr
mkdir usr/bin usr/lib usr/libexec
cd /bin
cp -a bash cp ls mkdir mv rm rmdir /path/to/chroot/bin
cp -a /usr/bin/ldd /path/to/chroot/usr/bin/
cp -a /usr/libexec/sftp-server /path/to/chroot/usr/libexec/

All web pages now talk about making sure all the appropriate library files are copied over. ldd can tell you which ones you need for each executable (e.g., ‘ldd /bin/cp’ will tell you the libraries needed) for the cp command. These need to be copied to the appropriate directory with the jail. The problem is that ldd apparently doesn’t always tell the whole story, and others are sometimes needed. Symptoms would be that once a connection is made, it immediately drops with an error “Connection closed” with no further explanation, even in the log files. The solution suggested by many is to simply copy over all the lib files:

cp -a /lib/lib*.* /path/to/chroot/lib/
cp -a /usr/lib/lib*.* /path/to/chroot/usr/lib/

On my system, the above steps allow a chroot login to occur via ssh with everything working correctly. Unfortunately, this doesn’t work with sftp, and attempts to connect via sftp with a user in chroot fails with the “Connection closed” error. The secret for me, after a LOT of reading through google posts, was to copy over /etc/passwd to the jail.

cp -a /etc/passwd /path/to/chroot/etc/

Make sure that file is not world-readable:

chmod 640 /path/to/chroot/etc/passwd

OK! Now all seems to work. Hope this helps someone (or me in the future).