This is currently proof-of-concept. Well, it works somehow, but there needs to be more work done to have a smooth solution
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”
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
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 /
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.
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
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