Table of Contents

HowTo use chrooted SSH on ispCP

This is currently proof-of-concept. Well, it works somehow, but there needs to be more work done to have a smooth solution

Preparation and Prerequisites

This HowTo covers Debian Lenny with ispCP 1.0.2. If read carefully it should be portable to any other PAM enabled distribution.

I decided to use libpam-mysql for user authentication and libnss-mysql for session handling and user mapping. Both packages are mature. OpenSSH is able to ChrootDirectory by directive, so this is my first choice.

To have the problems noted before: As it's obviously useful to chroot() into /var/www/virtual/DOMAIN with an enabled FTP user for this directory, OpenSSH refuses to chroot() because /var/www/virtual and /var/www/virtual/DOMAIN are not owned by uid=0 (root) and not umasked 022. It's not possible to change the ownership and umask because we do need access for www-data. I found no way to trick the sshd in a configurable manner, so I patched the OpenSSH package as shown below. If there are better solutions known, any hints are very welcome.

EDIT: As discussed here: http://www.isp-control.net/forum/thread-7948-post-62632.html#pid62632, it is not neccessary to patch OpenSSH. If you change the ownership and umask of the discussed directories, you can skip this step and start with “configuring OpenSSH”

patching OpenSSH

Quick and dirty without and .patch files by now. Warning: As well as this patch isn't done on some sophisticated authentication voodoo code, it affects the whole openssh-server package. You WILL loose the possibility to update openssh-server at ease. If updates and security fixes are available, you'll need to repeat this step.

apt-get install dpkg-dev
cd /usr/local/src
apt-get source openssh-server
apt-get build-dep openssh-server
cd openssh-5.1p1/    # change this to the current version
vi session.c # or use any other editor of your choice
             # navigate to the line containing "bad ownership or modes for chroot "
             # change the word "fatal" to "logit"
             # the line should read like logit("bad ownershiop or modes for chroot "
             # save and exit your editor
dpkg-buildpackage
cd ..
dpkg -i ./openssh-server*deb # this replaces your current sshd!
/etc/init.d/sshd stop && /etc/init.d/sshd start

configuring OpenSSH

The configuration in /etc/ssh/sshd_config needs to be modified:

StrictModes no
PasswordAuthentication yes # this is also the default

# at the end of the file
# Match does not know how to handle negations...
ChrootDirectory %h

Match user root
    ChrootDirectory /

Installing and configuring libpam-mysql

apt-get install libpam-mysql
cp /etc/pam.d/sshd /etc/pam.d/sshd.orig # just to have a backup

Modify your /etc/pam.d/sshd to read as following:

Replace VFTP_PASSWORD by your actual vftp mysql password. The current connection settings can be verified by peeking into /etc/proftpd/proftpd.conf

# PAM configuration for the Secure Shell service

# Read environment variables from /etc/environment and
# /etc/security/pam_env.conf.
auth       required     pam_env.so # [1]
# In Debian 4.0 (etch), locale-related environment variables were moved to
# /etc/default/locale, so read that as well.
auth       required     pam_env.so envfile=/etc/default/locale


auth       optional     pam_mysql.so host=/var/run/mysqld/mysqld.sock user=vftp passwd=VFTP_PASSWORD db=ispcp table=ftp_users usercolumn=userid passwdcolumn=passwd crypt=1
account    optional     pam_mysql.so host=/var/run/mysqld/mysqld.sock user=vftp passwd=VFTP_PASSWORD db=ispcp table=ftp_users usercolumn=userid passwdcolumn=passwd crypt=1

password   sufficient   pam_mysql.so host=/var/run/mysqld/mysqld.sock user=vftp passwd=VFTP_PASSWORD db=ispcp table=ftp_users usercolumn=userid passwdcolumn=passwd crypt=1

session    optional     pam_mysql.so host=/var/run/mysqld/mysqld.sock user=vftp passwd=VFTP_PASSWORD db=ispcp table=ftp_users usercolumn=userid passwdcolumn=passwd crypt=1


# Standard Un*x authentication.
#@include common-auth # this commented out, as common-auth REQUIRES pam_unix.so
auth    sufficient       pam_unix.so nullok_secure

# Disallow non-root logins when /etc/nologin exists.
account    required     pam_nologin.so

# Uncomment and edit /etc/security/access.conf if you need to set complex
# access limits that are hard to express in sshd_config.
# account  required     pam_access.so

# Standard Un*x authorization.
@include common-account

# Standard Un*x session setup and teardown.
@include common-session

# Print the message of the day upon successful login.
session    optional     pam_motd.so # [1]

# Print the status of the user's mailbox upon successful login.
session    optional     pam_mail.so standard noenv # [1]

# Set up user limits from /etc/security/limits.conf.
session    required     pam_limits.so

# Set up SELinux capabilities (need modified pam)
# session  required     pam_selinux.so multiple

# Standard Un*x password updating.
@include common-password

If you're managing this server only via SSH, there's a good reason to check now, if you're able to login as root with an additional session as before. If not, you should NOW move your original /etc/pam.d/sshd.orig to /etc/pam.d/sshd back until you found the bug or typo.

Installing and configuring libnss-mysql

apt-get install libnss-mysql

The configuration files /etc/nss-mysql.conf needs editing. I've stripped off the comments. It should read like below (remind to replace VFTP_PASSWORD to match your configured one)

conf.version = 2;
users.host = unix:/var/run/mysqld/mysqld.sock;
users.database = ispcp;
users.db_user = vftp;
users.db_password = VFTP_PASSWORD;
users.table = ftp_users;
users.user_column = ftp_users.userid;
users.password_column = ftp_users.passwd;
users.userid_column = ftp_users.userid;
users.uid_column = ftp_users.uid;
users.gid_column = ftp_users.gid;
users.realname_column = "ispCP User";
users.homedir_column = ftp_users.homedir;
users.shell_column = ftp_users.shell;

The same needs to be done for /etc/nss-mysql-root.conf. This is for the shadow, I don't know if this is necessary, but I assume it is…

conf.version = 2;
shadow.host = unix:/var/run/mysqld/mysqld.sock;
shadow.database = ispcp;
shadow.db_user = vftp;
shadow.db_password = VFTP_PASSWORD;
shadow.table = ftp_users;
shadow.userid_column = ftp_users.userid;
shadow.user_column = ftp_users.userid;
shadow.password_column = ftp_users.passwd;
shadow.lastchange_column = UNIX_TIMESTAMP()-10;
shadow.min_column = 1;
shadow.max_column = 2;
shadow.warn_column = 7;
shadow.inact_column = -1;
shadow.expire_column = -1;

The file access rights needs to be adjusted:

chmod 640 /etc/nss-mysql.conf /etc/nss-mysql-root.conf

The nss is now capable of identifying users via mysql. Now it should made aware of it by editing /etc/nsswitch.conf

Change the following lines:

#passwd:          compat
passwd:           compat mysql

#shadow:          compat
shadow:           compat mysql

Creating chroot() Environments

Having the above done, every FTP user added via ispCP is now potentially able to connect via ssh.

Small note for console users: If the username contains an @-Sign (as usual for ispCP users) you need to use a more ancient annotation. As ssh exampleuser@example.org@my-ispcp.example.org doesn't work, you need to write it as ssh -l exampleuser@example.org my-ispcp.example.org

If you've tried this, you've noticed that you're not able to reach a shell. Because sshd is configured to ChrootDirectory, the user needs a chroot() environment. At least a statically linked ~/bin/bash and a few devices (~/dev/null, ~/dev/zero, ~/dev/pts/0, ~/dev/pts/1).

To create a chroot environments, I've used a script found here: http://isp-control.net/ispcp/wiki/chroot_wrapper_skript There are small typos in it, a corrected version is shown below.

#!/bin/bash
#
# Distributed under the terms of the GNU General Public License v2
#
# Usage: ./chroot_home username

# These are the needed Apps for the chroot-env
APPS="/bin/bash /bin/cat /usr/bin/cut /usr/bin/id /bin/ls /bin/mkdir /bin/mv /bin/ping /bin/pwd /bin/rm /bin/rm /bin/rmdir /usr/bin/ssh"

# "exit with error"-function
function die() { echo ${*}; exit 1; }

umask 0022

# Check commandline for username
test -z "${1}" && die "Usage: ${0} username"

# set username
USERNAME=${1}

# try to get $HOME
CHROOT=`grep "^${USERNAME}" /etc/passwd |cut -d':' -f 6`
test -z "${CHROOT}" && die "Error: Could not get \$HOME for user \"${USERNAME}\""

cd ${CHROOT} || die "could not change to ${CHROOT}"

# create dirs, set permissions
mkdir -p bin dev etc home/${USERNAME} usr/bin lib lib64 usr/lib/misc \
       || die "error creating dirs"
chown $1:users home/$1

# create some useful devices
mkdir dev/pts
test -c dev/null  || mknod dev/null   c   1 3
test -c dev/zero  || mknod dev/zero   c   1 5
test -c dev/tty   || mknod dev/tty    c   5 0
test -c dev/pts/0 || mknod dev/pts/0  c 136 0
test -c dev/pts/1 || mknod dev/pts/1  c 136 1
chmod 666 dev/null dev/zero dev/tty dev/pts/*

# create short versions of passwd and group
egrep "(^root)|(${USERNAME})" /etc/passwd > etc/passwd
egrep "(^root)|(${USERNAME})" /etc/group  > etc/group

for app in ${APPS};  do # copy apps
       cp ${app} ./${app}
       
       # get needed libs and copy them too
       for lib in `ldd ${app} 2>/dev/null|awk '{ print $3 }'`; do
               mkdir -p ./`dirname ${lib}` || die "error creating dir"
               if [ -e ${lib} ]; then
                  cp ${lib} ./${lib} || die "error copying file"
               fi
       done
done

I've found problems on amd64 platforms, finding ldd connections to /lib64, which are subsequently left alone by this script. At least for /bin/bash you should check by using ldd if all necessary libraries are copied.

As this is not my primary goal, I'll not go further into creating chrooted environments. If you google for it, you'll find plenty of scripts, each with pro's and cons.

Hopefully I've motivated some ispCP developer to think about integration of chrooted environments and having them probably managed via web frontend. As well as I'll continue to integrate the basics, I'll definitely NOT going to add environment creation into ispCPs perl worker scripts.

Cheers,

comments to: s.seitz@netz-haut.de