====== 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