Navigation überspringen

Using SSH in a chroot environment

Overview

This document describes how to set up a server with chroot accounts where these accounts are able to connect to the server via ssh, scp and sftp. This is not as trivial as it may sound since at least scp and sftp won't work in a chroot environment by default.

The setup described here is tested with Linux 2.2.x, 2.4.x, 2.6.x and any version of OpenSSH between 3.1p1 and 5.5p1. You should not use any older OpenSSH versions due to several security issues.

Furthermore the setup should work with AIX 4.3.3 (tested) and 5.1 (tested) as long as you use the patch adapted for AIX and OpenSSH 3.4 or higher (thanks to Akos Domjan <a_domjan@hotmail.com>).

Since version 4.9 OpenSSH comes with native chroot support. However, I've never tried this one. Further information can be found on the sshd_config man page.

Setting up the chroot environment

First you’ll have to set up a prototypical home directory for the chroot accounts. This home directory should contain all necessary files a chroot’ed user needs. Typical contents would be a bin directory with a statically compiled shell and other statically compiled tools like GNU filetools and the like. Furthermore you’ll probably need a lib directory for some basic libs (like libc).

Once finished with that you can chroot to this directory and verify that anything works as desired. To find out what’s needed by a certain program ldd and strace come in handy.

Creating User Accounts

After that you can start to create the “real” chroot accounts. To simplify this task I’d recommend to write your own setup script. The following needs to be done.

  • Create the necessary directories with the appropriate permissions as root, e.g.
mkdir -m 755 $HOME/bin
mkdir -m 755 $HOME/lib
# ...
  • Create the /dev directory and necessary devices, e.g.
mkdir -m 755 $HOME/dev
mknod $HOME/dev/null c 1 3 -m 666
# ...
  • Create the /etc directory and add the necessary entries to passwd and group, e.g.
mkdir -m 755 $HOME/etc
echo "root:x:0:0:root:/root:*" > $HOME/etc/passwd
echo "user:x:500:500:A Chroot User:/home/user:/bin/bash" >> $HOME/etc/passwd
echo "root:x:0:root" > $HOME/etc/group
echo "usergroup::500:" >> $HOME/etc/group
chmod 444 $HOME/etc/passwd $HOME/etc/group
  • Hard link the files from you prototypical directory to the new home directory (this will save you disk space), e.g.
ln /home/typical/bin/* $HOME/bin/
ln /home/typical/lib/* $HOME/lib/
# ...

Installing OpenSSH systemwide

Before you build OpenSSH you should apply a patch that enables chroot with OpenSSH. There are various patches around, although the following works with 3.1p1 - 5.5p1 (at least for me and not for AIX; see below):

--- session.c.orig    2009-01-28 06:29:49.000000000 +0100
+++ session.c 2009-02-23 09:01:33.000000000 +0100
@@ -261,6 +261,11 @@
      }
 }
 
+/* CHROOT patch start */
+char *user_dir;
+char *new_root;
+/* CHROOT patch end */
+
 void
 do_authenticated(Authctxt *authctxt)
 {
@@ -1496,6 +1501,27 @@
 
              if (setlogin(pw->pw_name) < 0)
                      error("setlogin failed: %s", strerror(errno));
+                /* CHROOT patch start */
+                user_dir = xstrdup(pw->pw_dir);
+                new_root = user_dir + 1;
+                
+                while((new_root = strchr(new_root, '.')) != NULL) {
+                  new_root--;
+                  if(strncmp(new_root, "/./", 3) == 0) {
+                    *new_root = '\0';
+                    new_root += 2;
+                                             debug("chrooting to user directory %s", user_dir);
+                                                if(chroot(user_dir) != 0)
+                                                  fatal("Couldn't chroot to user directory %s", user_dir);
+                                                pw->pw_dir = new_root;
+                                                if (chdir("/") < 0)
+                                                  fatal("Couldn't cd to / after chroot to user directory %s: %s", 
+                                                        user_dir, strerror(errno));
+                                                break;
+                  }
+                  new_root += 2;
+                }
+                /* CHROOT patch end */
              if (setgid(pw->pw_gid) < 0) {
                      perror("setgid");
                      exit(1);

The diff file is available here. (Older versions of this patch with different offsets are still available: diff for OpenSSH 3.x, diff for OpenSSH 3.1, diff for OpenSSH 4.x.)

Note that the above patch requires that OpenSSH must not be compiled statically. (Thanks to Oliver Gorzellik for the hint.)

Since this patch won’t work on AIX systems due to privilege problems when calling the chroot() function, you will have to use the patch for AIX provided by Akos Domjan <a_domjan@hotmail.com> if you’re running such a system.

Now configure OpenSSH as desired and run make; make install.

Installing OpenSSH inside chroot cages

To install OpenSSH inside your cages copy ssh, scp, sftp and sftp-server to your prototypical directory and hardlink it to the cages bin directory. Note that you might need to create some Symlinks inside your cages because OpenSSH needs to find it’s binaries inside the cage exactly where they’re found systemwide. If you installed OpenSSH (systemwide) to /usr/local you’ll need to do the following:

mkdir -p -m 755 $HOME/usr/local/bin
cd $HOME/usr/local/bin
ln -s ../../bin/ssh .
ln -s ../../bin/scp .
ln -s ../../bin/sftp .

mkdir -p -m 755 $HOME/usr/local/libexec
cd $HOME/usr/local/libexec
ln -s ../../bin/sftp-server .

Once again: Do not compile OpenSSH statically.

The chroot patch to OpenSSH requires a “magic token” in /etc/passwd (you might know this from other servers). Only if that token is found OpenSSH will chroot. So you’ll have to alter the home directory field in /etc/passwd for the appropriate users like that:

# old ->  :$HOME:
# new ->  :$HOME/./:

# e.g.
# :/home/user: ->  :/home/user/./:

At this point ssh, scp and sftp to the chroot box should work. ssh, scp and sftp from the box seem to work, too, as long as you make sure that host name can be resolved within the cage (Alternatively, you can use IP numbers).

Aftermath

Note that X11-Forwarding with OpenSSH is not yet possible with this setup, users have to invoke ssh with the -x option. Since I don’t require this feature I haven’t explored the problem further.

Also note that users might have to upgrade their SSH-Clients on the machine they use to connect to the server. I noticed that this setup using OpenSSH 3.1p1 won’t work with clients using scp or sftp form OpenSSH 2.x.

Please keep in mind that chroot with this setup is performed for SSH connects only. Other services must be configured separately to do a chroot on login. As for telnet I recommend to disable this service. However, you can use changeroot to perform a chroot on telnet logins. This works well with the chroot patch for OpenSSH. Several FTP-Servers are capable of performing a chroot, as well. If you really need FTP (also SFTP obsoletes that) you should have a look at the appropriate documentation.

If you provide SSH for Microsoft Windows™ users, take a look at http://support.zeitform.info/en/server_access/ssh.html.

If you have comments, questions, further hints or whatever don’t hesitate to contact me. You’ll find my e-mail address below.

Author: Ulf Stegemann

Date: 2010-04-27 16:10:12

HTML generated by org-mode 6.35trans in emacs 23

Valid XHTML 1.0 strict! Valid CSS! Org-Mode Gehostet von zeitform Internet Dienste. [FSF Associate Member]