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/sshdRETVAL=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.pidrunlevel=$(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):
- http://www.brandonhutchinson.com/chroot_ssh.html
- http://chrootssh.sourceforge.net/docs/chrootedsftp.html
- http://www.netadmintools.com/art294.html
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).
7 Comments;
Hi,
In case it helps, I went through so much trouble with this method, because of all the libraries you have to keep updated within the chroot jail when software changes. In the end, I came up with an alternative solution that gives users SFTP access, but *no* shell.
See here if you’re interested.
—
Minstrel
Thanks, Minstrel.
I actually tried the sftpsh approach but couldn’t get it to work. Perhaps it was all related to my not copying over /etc/passwd? I’ll give that a try. I certainly like your method in that there’s little maintenance.
The method I describe on my site doesn’t require any tinkering about with libraries or /etc/passwd – there are no system files at all in the chroot jail you configure for the users.
Did you get errors, or was it the end result that simply didn’t function?
—
Minstrel
I followed your instructions and everything worked perfectly. I did do a couple of things differently:
./configure \
–prefix=/usr \
–sysconfdir=/etc/ssh \
–with-pam \
–with-tcp-wrappers \
–with-md5-passwords \
–with-pid-dir=/var/run
echo /bin/sftpsh >>/etc/shells
Thanks very much!!
Ah, I can see I forgot the /etc/shells instruction (which is required for all this to work!). I’ve now added this in to my page.
Thanks for the feedback – glad it all worked in the end!
—
Minstrel
Since version 4.9 of OpenSSH, this is now a built-in feature. I have written up the method I’ve used to migrate to it, in case it’s of use to others:
http://www.minstrel.org.uk/papers/sftp/builtin.html
Nice not to have to custom-code each time there’s an update to OpenSSH!
Hope this helps.
—
Minstrel
http://www.minstrel.org.uk/
good site kmhjgo