Gentoo Wiki


Please improve it in any way that you see fit, and remove this notice {{Cleanup}} from the article. For tips on cleaning and formatting see Cleanup process


Installing and Configuring rssh

You'll need to emerge the restricted rssh shell, and then add it to the list of accepted shells:

emerge rssh
echo /usr/bin/rssh >> /etc/shells

and you'll want to modify the rssh config and make some minor changes to enable chrooting, scp, and sftp.

File: /etc/rssh.conf
logfacility = LOG_USER
umask = 022

If you wish to disable scp, or sftp independently, just remove the line or comment it out with a #.

What is SCP/SFTP?

FTP transmits data in "cleartext," meaning anyone between your computer and the host server you're connected to can potentially intercept critical information such as passwords. Fortunately, there are several file transfer standards (Scp and Sftp, for example) that are similar in function to FTP but utilize Secure Shell encryption to protect your information in transit. If you use a Unix-based server, you should be able to invoke either sftp or scp from the command line. GL cluster servers have scp installed on them.

Building the Chrooted Environment

This involves copying a few files to our chrooted folder (/home).

Code: copying essential files into chroot
cd /home/
mkdir -p usr/bin
cp /usr/bin/scp usr/bin 
cp /usr/bin/rssh usr/bin 
mkdir -p usr/libexec
mkdir -p usr/lib/misc
cp /usr/lib/misc/rssh_chroot_helper usr/lib/misc
cp /usr/lib/misc/sftp-server usr/lib/misc

Though we're not quite done copying files yet. Now we need to copy the dependencies of those files. ldd will tell us what files are needed

Code: Finding dependent libraries
# ldd /usr/bin/scp => /lib/ (0x4001c000) => /usr/lib/ (0x4001f000) => /lib/ (0x4002d000) => /usr/lib/ (0x40042000) => /lib/ (0x40106000) => /lib/ (0x40235000) 
       /lib/ => /lib/ (0x40000000)

So now we need to make the necessary folders, and copy the libs needed for scp.

Code: copying libraries
# cd /home 
# mkdir lib 
# cp /lib/ lib 
# cp /lib/ lib 
# cp /lib/ lib 
# cp /lib/ lib 
# cp /lib/ lib 
# mkdir -p usr/lib 
# cp /usr/lib/ usr/lib 
# cp /usr/lib/ usr/lib 

Now run ldd on the other files we copied into our chroot environment.

Code: Finding other essential libraries
# ldd /usr/bin/rssh 
# ldd /usr/lib/misc/rssh_chroot_helper 
# ldd /usr/lib/misc/sftp-server

Copy the libraries associated with those files if there are any we didn't already get from scp. Note: for me, there were no other dependencies. copying all the dependencies for scp was enough for me. This should be the case for you as well unless your configuration is very different.

Or you can run the following copy these dependency files to your chroot for you

Code: Script to finding and install other essential libraries
# chroot=`sed -ne's/^chrootpath[^=]*=[^"/]*\(\|"\)\([^"]*\).*/\2/p' /etc/rssh.conf`
# for f in `ldd /usr/bin/rssh /usr/lib/misc/rssh_chroot_helper /usr/lib/misc/sftp-server /usr/bin/scp | sed -ne's/.*=> \([^ ]*\).*/\1/p' | sort -u | grep -v "^$"`; do echo "Copying $f to ${chroot}${f}"; cp $f ${chroot}${f}; done

Note: You must have the destination directories setup before hand

Finally add the also required and libraries to the jail (otherwise sftp/scp won't work).

Code: copying
# cp /lib/ lib
# cp /lib/ lib

Note:If you are using /dev/log don`t forget to mkdir dev in your chroot and edit /etc/syslog-ng/syslog-ng.conf accordingly.

rssh_chroot_helper & suid

You have to check the rssh_chroot_helper to ensure it has SUID perm:

Code: Setting Suid in rssh_chroot_helper
# chmod u+s rssh_chroot_helper
# ls -alh rssh_chroot_helper
-rwsr-xr-x 1 root root 19K 2007-02-16 05:39 rssh_chroot_helper

If SUID is not set, the chroot() call will not work and you will see this in /var/log/messages :

Code: chroot() call fails if not suid
Sep 27 09:17:14 server2 rssh_chroot_helper[26106]: chroot() failed, 2: Operation not permitted

Note for AMD64 Users

AMD64 users need to have libraries in /lib64 and /usr/lib64. I made this work by:

Code: Adding AMD64 links
# ln -s lib lib64
# cd usr; ln -s lib lib64; cd ..

Defining Users

# emerge superadduser
# superadduser 
Login name for new user []: testuser 
User ID ('UID') [ defaults to next available ]: 
Initial group [ users ]: 
Additional groups (comma separated) []: 
Home directory [ /home/testuser ] 
- Warning: '/home/testuser' already exists ! 
Do you wish to change the home directory path? (Y/n)  n 
Shell [ /bin/bash ] /usr/bin/rssh 
Expiry date (YYYY-MM-DD) []:

or simply modify an existing user account
# usermod -s /usr/bin/rssh testuser

Starting the Daemon and Testing

Code: checking sshd
 # /etc/init.d/sshd status
: * status:  started

if not, run #/etc/init.d/sshd start and try connecting:

Code: testing your connection
# sftp
Connecting to's password: 
sftp> ls 
sftp> pwd 
Remote working directory: /testuser 
sftp> exit 
ssh's password: 

This account is restricted to scp or sftp. 
If you believe this is in error, please contact your system administrator. 
Connection to closed.

Voilà! sftp with chrooting, and no shell allowed!

Possible problems: a user can create .ssh unless it already exists and add some LD_PRELOAD stuff to .ssh/environment resulting in arbitrary code execution (within the chroot). Also tools like courier-maildrop might induce problems, because .mailfilter may contain shell commands.

See Also

Original Forum Post

Getting scp to work

To get scp working I have learned you must copy these files too:

cd /home
cp /lib/ lib
mkdir etc cp /etc/passwd etc ### Be sure to edit the password after copying! ### Leave only the user needed to login with.

Easier passwd example

cd /home/(user)
mkdir etc
cd etc
getent passwd (user) > passwd

Solution to "connection closed"

If you get "connection closed" when trying to log on via sftp, try:

mkdir /your/chroot/dir/dev
mknod -m 666 /your/chroot/dir/dev/null c 1 3

Sometimes one of /lib/libnss_* files may be required. In my case it was /lib/

cp /lib/ /your/chroot/dir/lib/

If you are using one chroot per user wrong permissions in rssh.conf can also cause "connection closed":


in my case mis-typing 077 as 0077 or 00010 as 0010 or 000010

Any idea how to have one chroot per user?

This is done by creating separate chroot directories for each user. Let's take our user Adam as an example.

First, make a parent chroot dir. Nothing will actually chroot to this, it's just a tidy way to do this. You can use regular home dirs if you want, it really doesn't matter. I do it this way so I know at a glance that these users are rssh chroot'ed users.

  1. mkdir /home/rssh_chroot

Now create Adam's dir:

  1. mkdir -p /home/rssh_chroot/adam
  2. chown adam:adam /home/rssh_chroot/adam
  3. chmod 770 /home/rssh_chroot/adam

Now, follow the above instructions for creating a chroot WITHIN the adam directory, replacing "/home" with "/home/rssh_chroot/adam" in the procedures. Add the following line, edited as you want, to /etc/rssh.conf:


Once the files necessary for a chroot are in place:

  1. cd /home/rssh_chroot
  2. chown -R root:root adam/lib
  3. chmod –R 755 adam/lib
  4. chown -R root:root adam/usr
  5. chmod –R 755 adam/usr
  6. chown adam:adam /home/rssh_chroot/adam
  7. chmod 770 /home/rssh_chroot/adam

You can now repeat this for any other user. Each will have a separate copy of the necessary libraries, but this is the only way to accomplish this. I would start by copying the entire adam dir to a new name, and simply chown-ing the dir to the new user:

  1. cp –Rp adam betty
  2. chown betty:betty betty

Then add the right line to /etc/rssh.conf:


Rinse. Repeat.

Additional tips and tricks

There were a few other things I had to do to get this working. I was having a problem that appears to be common: you get a "connection closed" with no other hint of what's going wrong and you are positive that your shared libs are set up correctly. Well, I figured it out!

First, you definitely want to set things up so that you can see the log messages that rssh_chroot_helper will log while executing in the jail. This was the key to solving the problem. For syslog-ng, this is easy; look for the source src section in the /etc/syslog-ng/syslog-ng.conf file and add unix-string("/chroot/jail/dev/log"); just after the unix-string("/dev/log"); line. Be sure to restart syslog-ng.

Once I did this, I started seeing log messages from rssh_chroot_helper in /var/log/messages, and in fact saw this nasty one: sftp-server[4589]: fatal: No user found for uid xxxx. This indicated that I was missing an /etc/passwd file in the chroot jail. I copied a minimal version of my system /etc/passwd to /chroot/jail/etc/passwd, and also a minimal /etc/group to /chroot/jail/etc/group and wonder of wonders, it all worked perfectly.

A few additional things I noticed after getting the basic configuration working:

And that's it! Hope that helps. pumpichank on gentoo forums

Alternative (Simpler) Solution

I used a similar method to the above for a long time, but got tired of having to update libraries within the chroot'd jail every time I updated OpenSSL, OpenSSH and a variety of other bits and pieces. Also, the users themselves had a habit of breaking things, as they had access to the library directories, which only confused them!

In the end, I cobbled a better solution together from a variety of papers out there on the 'net, and came up with a chroot'd SFTP solution (no SCP, unfortunately) that requires no messing about with libraries and so forth.

I've written this up:

Note: my system runs Solaris, but I've had feedback from others that have successfully followed the instructions on a variety of Linux-based systems. The page has recently been updated to include detailed instructions for OpenBSD, and I have had reports of successful builds on SuSE (with minor tweaks), RedHat and, of course, Gentoo!

Hope this helps.

Yet Another (Simpler) Alternative Solution

Building a simplified chroot jail with static builds of rssh and openssh.

The hardest (time consuming) part about the setup discussed above is chasing dynamic libraries around with ldd and getting them into the chroot jail. This especially messy if you have a separate jail for each user. To get around this we compile rssh and sftp-server as static binaries. Download openssh and rssh. Configure them as:

 CC='gcc -static' ./configure your-args-here && make

Then copy (or hardlink) and setuid rssh_chroot_helper

   mkdir -p /chroot/user/usr/libexec/openssh
   ln sftp-server /chroot/user/usr/libexec/openssh/
   ln rssh_chroot_helper /chroot/user/usr/libexec/
   chmod 4755 /chroot/user/usr/libexec/rssh_chroot_helper

I recommend that you use your distro version of openssh and rssh for everything except the files which need to be in the jail. There is no need to 'make install' as we don't wish to install openssh or rssh over our existing distro copies. Just copy the ones out of the static-build tree and use 'em in the chroot jail!

Sure enough, sftp-server and rssh_chroot_helper are static:

 [root@backup1 testuser]# find usr/ -type f -print -exec ldd {} \;
       not a dynamic executable
       not a dynamic executable

Since sftp-server calls getpwnam(), glibc still dynamic links in the libnss code for doing password file lookups. For this reason, you will still need all the libraries referenced by, in addition to itself:

       [root@backup1 testuser]# ldd /lib64/ => /lib64/ (0x00002aaaaacc6000)
       /lib64/ (0x00002aaaaaaab000)

These files you will need to copy to your /chroot/user/lib(64) directory or sftp-server will complain in a hard-to-troubleshoot way:

 sftp-server[2361]: fatal: No user found for uid 501

We also added "-a /chroot/user/dev/log" to syslogd's command line so that jailed users can still log to syslog. Your syslog may be configured differently here.

Below are all of the files in our jail, most of which can be hard-linked. etc/passwd must contain at least the line(s) of the user(s) logging into jail.

[root@backup1 testuser]# find dev/ etc/ lib64/ usr/ -not -type d

Our (simple) /etc/rssh.conf:

[root@backup1 testuser]# cat /etc/rssh.conf  | grep -v \# | grep .
logfacility = LOG_USER
umask = 022

That's it! I hope this helps simplify the task of chrooting SFTP!

The Simplest Solution of Them All

Apparently the newest OpenSSH CVS already contains support for chrooting SFTP users (ChroootDirectory directive):

There is only support for SFTP though (no SCP). This appeared in OpenSSH 4.9 and higher

I've had issues with this - I can't seem to get chroot working. Although with
ForceCommand internal-sftp it seems users can't get a shell anyway, so this is
an OK intermediate solution (without functional chroot) for the moment. I'd
really like to get it working, if anyone has any tips then let me know. The
server confirms authentication (LogLevel DEBUG in /etc/ssh/sshd_config) and
the client receives "Request for subsystem 'sftp' failed on channel 0".

Last modified: Thu, 25 Sep 2008 03:51:00 +0000 Hits: 71,252