
Creating an SFTP jail
UserSecurity
As gatekeepers of the data center, Unix administrators sometimes receive a request to create a Secure File Transfer Protocol (SFTP) account that will only allow the user to view files within that directory. SFTP is preferred over the standard FTP in most customer-facing environments because the username and password are not transmitted in cleartext, nor is the data in transit. Standard FTP has provisions within the .ftpaccess file to create a more restrictive user environment. However, when using SFTP out of the box, users may change directories (cd) and view (ls) whatever they choose within the server, even /.
Danger
To clamp down on users and thereby restrict them to a specific home directory so they can't operate outside of that home directory requires the creation of a chrooted, or "jailed," directory.
"Chroot" is the term for this type of restricted directory. With chroot, users are unable to move outside their "cell" and can only view their surroundings. Just think of how you feel in a cubicle. On Linux, this setup is fairly straightforward. However, for those of us who are tethered to a Solaris environment, this task requires some configuration gymnastics to actually get it done. Like any good Unix disciple, I trolled the Internet for weeks before I found enough bits and pieces to consolidate the fragmented virtual Google filesystem of information into a more contiguous aggregated cookbook method.
Set Your Environment
Before you proceed, the most important step is to ensure your environment variables are set. For newbies, environment variables tell the current shell where to find everything. I prefer to set mine in .bash_profile in my $HOME directory; thus, with each new instantiation of a shell, the parameters will remain. Listing 1 shows an excerpt of the crucial variables in my .bash_profile. Note that this setup assumes you will later install OpenSSH in /usr/local/.
Listing 1: .bash_profile Variables
01 CC=gcc 02 CPPFLAGS=-I/usr/local/ssl/include 03 EDITOR=vi 04 LD_LIBRARY_PATH=/usr/local/lib:/usr/local/include:/usr/local/lib/sparcv9 05 PATH=/usr/local/bin:/usr/local/mysql:/usr/local/mysql/bin:/usr/local/sparc-sun-solaris2.10/bin:/usr/local/ssl:/usr/local/ssl/lib:/usr/local/sbin:/usr/local/include:/usr/local/include/libxml2:/usr/bin:/usr/sbin:/usr/lib:/usr/openwin/bin 06 LDFLAGS=-lstdc++
You must ensure you have the GNU GCC compiler [1]. Additional dependencies exist, but I'll assume you are familiar with GCC.
Install TCP Wrappers
The next step is to install TCP Wrappers [1], which is a host networking Access Control List (ACL) system used to screen (filter) access to Unix TCP/IP servers. Essentially, this tool enhances the native abilities of inetd, allowing additional logging support and the ability to return messages for each connection. It also permits inetd to accept only specific connections. Inetd [2] is what controls automatic starting of all Internet services, such as FTP, telnet, POP, SMTP, and so on.
Solaris makes installing TCP Wrappers relatively easy if you opt to download the package from the website (Listing 2).
Listing 2: Installing TCP Wrappers
01 bash#> cd /tmp 02 bash#> ls tcp_wrap* 03 tcp_wrappers-7.6.sol10-sparc-local 04 bash#> 05 bash#> pkgadd -d tcp_wrappers-7.6-sol10-sparc-local 06 07 The following packages are available: 08 1 SMCtcpdwr tcp_wrappers 09 (sparc) 7.6 10 11 Select package(s) you wish to process (or 'all' to process all packages). (default: all) [?,??,q]: all 12 13 Processing package instance <SMCtcpdwr> from </home/bpatridge/dev/tcp_wrappers-7.6-sol10-sparc-local> 14 ...
Typically, I'm a source compiling sort of guy, but I found the package more expeditious for TCP Wrappers.
Install and Configure OpenSSH
The next step is to download and install OpenSSH [3]. The OpenSSH suite of software allows you to run an SSL encryption-based web server, allows SSH secure terminal access as opposed to telnet, and provides SFTP, a file- and password-encrypted method of transmitting data between hosts. After downloading, enter:
tar -xzvf openssh-ver.tar.gz
The -xzvf option extracts and gunzips the file in one command. By default, it installs in /usr/local, where you can then enter:
./configure --with-tcp-wrappers make make install
Next, I recommend setting the following options into a new sshd_config. Be sure to back up the original,
cp sshd_config sshd_config.ORIGINAL
which can now be replaced solely with the sshd configuration directives shown in Listing 3. Line 16 specifies that SFTP will listen on port 2202 instead of the default SSH port 22. This option is configurable and left at 2202 for testing. Upon completion of the initial test, you can reset this to Port 22, then restart OpenSSH.
Listing 3: sshd Configuration
01 bash#>cd /usr/local/etc 02 bash#> echo >sshd_config 03 bash#> vi sshd_config 04 AllowTcpForwarding no 05 ClientAliveCountMax 3 06 ClientAliveInterval 0 07 Compression delayed 08 LoginGraceTime 60s 09 LogLevel DEBUG3 10 MaxAuthTries 2 11 PasswordAuthentication yes 12 PermitEmptyPasswords no 13 PermitRootLogin no 14 PermitTunnel no 15 PermitUserEnvironment no 16 Port 2202 17 Protocol 2 18 StrictModes yes 19 SyslogFacility AUTH 20 TCPKeepAlive yes 21 UseDNS no 22 UsePrivilegeSeparation yes 23 Subsystem sftp /usr/local/libexec/sftp-server 24 Match Group sftponly 25 ChrootDirectory /export/home/jail/sftpuser/home/sftpuser 26 ForceCommand internal-sftp 27 X11Forwarding no 28 AllowTcpForwarding no 29 bash#>
The most critical part is the last stanza (lines 24-28). This section specifies the new chroot directory and limits the user to the internal SSH SFTP process. The last two lines disallow X11 (graphical) forwarding and TCP port forwarding.
Information regarding the other directives can be found within the man pages for sshd_config [4].
Add a New SFTP User
After you've completed the preceding steps, you can configure the new SFTP user. As a proud command-line vi junkie, I prefer the old school method of editing /etc/password to add a new user:
sftpuser:x:30680:121213:Jail user :/export/home/jail/sftpuser/./home/sftpuser/:/usr/local/libexec/sftp-server
Appended to the user's home directory is ./home/sftpuser, which is required to signify that the chrooted directory for this user will now be perceived as /home/sftpuser rather than the full path.
Also, the shell is not a login shell (/bin/bash, /bin/sh, etc.) and must be set to the internal sftp-server process (/usr/local/libexec/sftp-server).
Add group 121213 to /etc/group,
sftponly::121213:
then set the password for the user:
passwd sftponly ...
Optionally, you can ensure the default umask is set appropriately, if required (i.e., inside the /etc/default/login).
Create the chrooted Environment
To further simplify the process, create a chrooted environment for your new user, sftpuser, with the jail.ksh script shown in Listing 4. This script was originally published by Kent Cowgill, but the website has since disappeared. Note that you only need to modify lines 32 and 33. The remaining commands in the script create all the devices necessary for a virtual system environment for the chroot user.Because chroot users must not view anything outside of their own directory, they must have available all the tools and devices necessary to execute the commands ls, cd, and the like within their chrooted directory.
Listing 4: jail.ksh
001 #!/bin/ksh
002
003 # script: jail.ksh
004 # version: 1.0
005 # date: 9/27/2002
006 # author: Kent Cowgill
007 #
008 # Description:
009 # This script sets up a minimal jail for chrooted users for ssh and
010 # sftp. Minimal error checking is performed -- Most errors are
011 # harmless: Adding existing groups, creating existing directories,
012 # etc. Please modify the JAILUSER and JAILGROUP variables in the
013 # script according to your specific needs and requirements.
014 #
015 # Disclaimer: Use this script at your own risk. I cannot ensure that
016 # it will perform exactly as described on your system. By using this
017 # script, you acknowledge that you have read and understand all the
018 # commands contained herein, and waive any claim against Kent Cowgill
019 # for any harm to your system.
020 #
021 # (c) 2002 Kent Cowgill. Permission to modify and distribute is
022 # granted on condition the copyright message is included and
023 # modifications are clearly identified.
024 #
025 # For suggestions, additions, and corrections, I thank Alex Kramarov,
026 # Steven M. Christianson, james@firstaidmusic, Gabriele Facciolo,
027 # Eileen Coles, Hugh McLenagh, and Walter G. Aiello.
028 #
029 # For changes, suggestions, corrections, enhancements, comments, or
030 # criticisms, email kent@c2group.net
031 # CHANGE THESE!
032 JAILUSER=jailuser
033 JAILGROUP=jailgroup
034 ####################################################################
035 # DO NOT CHANGE ANYTHING BELOW HERE!
036 ####################################################################
037
038 /usr/sbin/groupadd $JAILGROUP
039
040 mkdir /export/home/jail
041 chown root:$JAILGROUP /export/home/jail
042 chmod 750 /export/home/jail
043
044 /usr/sbin/useradd -g $JAILGROUP -c "Jail user $JAILUSER" \
045 -d /export/home/jail/$JAILUSER/./home/$JAILUSER -s /bin/sh $JAILUSER
046
047 mkdir /export/home/jail/$JAILUSER
048 chown $JAILUSER:$JAILGROUP /export/home/jail/$JAILUSER
049
050 cd /export/home/jail/$JAILUSER
051 mkdir etc
052 mkdir bin
053 mkdir usr
054 mkdir usr/bin
055 mkdir usr/local
056 mkdir usr/local/bin
057 mkdir usr/local/libexec
058 mkdir usr/local/sbin
059 mkdir usr/local/lib
060 mkdir usr/local/ssl
061 mkdir usr/local/ssl/lib
062 mkdir usr/lib
063 mkdir usr/platform
064 mkdir usr/platform/`uname -i`
065 mkdir usr/platform/`uname -i`/lib
066 mkdir dev
067 mkdir devices
068 mkdir devices/pseudo
069 mkdir home
070
071 cd /export/home/jail/$JAILUSER
072 APPS='bin/cp bin/ls bin/mkdir bin/mv bin/pwd bin/rm bin/rmdir bin/sh'
073 for i in $APPS; do
074 cp /$i ./$i
075 LIBS=`ldd ./$i | awk '{print $3}'`
076 for l in $LIBS; do
077 if [[ ! -d ./`dirname $l` ]]; then
078 mkdir ./`dirname $l` > /dev/null
079 fi
080 cp $l .$l
081 done
082 done
083
084 cd /export/home/jail/$JAILUSER/devices/pseudo
085 mknod mm@0:zero c 13 12
086 mknod mm@0:null c 13 2
087 cd /export/home/jail/$JAILUSER/dev
088 ln -s ../devices/psuedo/mm@0:zero zero
089 ln -s ../devices/pseudo/mm@0:null null
090
091 cd /export/home/jail/$JAILUSER
092 BINS="usr/local/bin/ssh usr/local/libexec/sftp-server usr/local/sbin/sshd usr/local/lib/libz.so usr/local/ssl/lib/libcrypto.so.0.9.6 usr/lib/ld.so.1 usr/platform/`uname -i`/lib/libc_psr.so.1 usr/lib/nss_files.so.1"
093 for i in $BINS; do
094 cp /$i ./$i
095 done
096
097 mkdir /export/home/jail/$JAILUSER/home/$JAILUSER
098 chown $JAILUSER:$JAILGROUP /export/home/jail/$JAILUSER/home/$JAILUSER
099
100 touch /export/home/jail/$JAILUSER/etc/passwd
101 touch /export/home/jail/$JAILUSER/etc/group
102
103 echo "$JAILUSER:x:`/usr/xpg4/bin/id -u $JAILUSER`:`/usr/xpg4/bin/id-g $JAILGROUP`::/home/$JAILUSER:/bin/sh" > \
104 /export/home/jail/$JAILUSER/etc/passwd
105
106 echo "$JAILGROUP::`/usr/xpg4/bin/id -g $JAILUSER`:$JAILUSER" > \
107 /export/home/jail/$JAILUSER/etc/group
108
109 echo "done!"
After you have adjusted the file permissions to 755 so the file can be executed, you can issue:
./jail.ksh
At this point, you should have a full chrooted environment in /export/home/jail,
ls -al /export/home|grep jail drwxr-xr-x 3 root root 96 Sep 28 18:52 jail ls -alR /export/home/jail ...
and the permissions should be root:root, 755 all the way down the directory structure.
Next, you should verify that all the correct files were created by typing:
find /export/home/jail
Starting the sshd (SFTP) Daemon
To verify that the server is listening and to watch for any errors, start sshd and verify that it works by starting it in debug mode with the -d option (Listing 5).
Listing 5: Verify sshd
01 bash#> /usr/local/sbin/sshd -d 02 debug1: sshd version OpenSSH_5.6p1 03 debug1: read PEM private key done: type RSA 04 debug1: private host key: #0 type 1 RSA 05 debug1: read PEM private key done: type DSA 06 debug1: private host key: #1 type 2 DSA 07 debug1: rexec_argv[0]='/usr/local/sbin/sshd' 08 debug1: rexec_argv[1]='-d' 09 debug1: Bind to port 2202 on ::. 10 Server listening on :: port 2202. 11 debug1: Bind to port 2202 on 0.0.0.0. 12 Server listening on 0.0.0.0 port 2202.
Now the fun part begins, and you can commence testing:
bash#> sftp -P2202 sftpuser@myserver01
sftpuser@myserver01's password:
Connected to myserver01.
sftp> pwd
Remote working directory: /
sftp> ls
sftp> cd /
sftp> pwd
Remote working directory: /
sftp>quit
#
If all goes well, your users now will be officially chrooted into their own directory, and they will not be able to cd to any other directory outside of /export/home/jail/sftpuser/home/sftpuser.
