EDIT 02/07/2007: I have confirmed that you *may* experience LDAP wierdness using this configuration due to the fact that you may come into contact with a bug in Sol8 causing an LDAP query to be done regardless of it being configured in your jail or even in your server. I have to talk to Sun about this. I’ve seen it happen and it’s weird.
EDIT 07/04/2007: I’ve hear that chrooted FTDd done “my way” may behave erratically when you configure the jail, and then install an LDAP client on the host (at some later date). I have yet to have this quantified, because the people who complained about it have yet to let me look at their servers. So, if *you* happen to be in the know, don’t hesitate to drop me a line at tdc -at- alphanor -dot- org eh. Cheers!
Some time ago I was asked to look at building a possibly anonymous FTP server running in a root jail on Solaris.
I had a short time to study Sun’s built in anonymous server that has it’s own chroot functionality, but the people I was doing it for told me that they wanted control over the usernames and passwords.
Here are the thoughts I had:
Split configuration and data
The FTP server situation I was looking at required as much security as possible, so I chose to keep the configuration and the user’s data on separate logical partitions. Also I chose to mount the data volume with the nosuid option. In fact, I suspect that the configuration volume could be mounted nosuid too (though not read only ofc, because the server will have to write to it’s device nodes), but I seem to recall not checking it at the time.
Using the Solaris FTPd in a root jail
To do this I used the Solaris FTPd manpage almost exclusively. Everything you need is there. I reprodue it here in part:
For anonymous ftp users, in.ftpd takes special measures to
restrict the client’s access privileges. The server performs
a chroot(2) command to the home directory of the “ftp” user.
In order that system security is not breached, it is recom-
mended that the “ftp” subtree be constructed with care; the
following rules are suggested.
~ftp Make the home directory owned by root and unwritable
by anyone.
~ftp/bin
Make this directory owned by the superuser and unwrit-
able by anyone. Make this a symbolic link to
~ftp/usr/bin The program ls(1) must be present to sup-
port the list commands. This program should have mode
111.
~ftp/usr/lib
Make this directory owned by the superuser and unwrit-
able by anyone. Copy the following shared libraries
from /usr/lib into this directory:
ld.so.1*
libc.so.1*
libdl.so.1*
libmp.so.2*
libnsl.so.1*
libsocket.so.1*
nss_compat.so.1*
nss_dns.so.1*
nss_files.so.1*
nss_nis.so.1*
nss_nisplus.so.1*
nss_xfn.so.1*
straddr.so*
straddr.so.2*
~ftp/etc
Make this directory owned by the superuser and unwrit-
able by anyone. Copies of the files passwd(4),
group(4), and netconfig(4) must be present for the
ls(1) command to work properly. These files should be
mode 444.
~ftp/pub
Make this directory mode 755 and owned by root. Users
should then place files which are to be accessible via
the anonymous account in this directory.
~ftp/dev
Make this directory owned by the superuser and unwrit-
able by anyone. First perform ls -lL on the device
files listed below to determine their major and minor
numbers, then use mknod to create them in this direc-
tory.
/dev/zero
/dev/tcp
/dev/udp
/dev/ticotsord
Set the read and write mode on these nodes to 666 so
that passive
ftp will not fail with “permission denied” errors.
~ftp/usr/share/lib/zoneinfo
Make this directory mode 555 and owned by the
superuser. Copy its contents from
/usr/share/lib/zoneinfo. This enables ls -l to
display time and date stamps correctly.
Anonymous or not?
Solaris 8 comes with a reasonably easy to set up ftp server with built in chroot capabilities, but if you want to use this one you will be stuck with two users. Using either of the two to log in will automagically place you in a preconfigured jail.
These predefined users are anonymous and ftp, special users who are defined with a minimum of privileges and configuration to set up ftp sessions. They are not passwordless though, useing them to log on will see a password dialog, though the server doesn’t care what you type as long as there is an at-sign (@) in there somewhere.
It is possible to configure the Solaris FTPd to use a chrooted environment where defined users can log into using actual passwords, though ofc you’d have to decide for yourself weather ot not to deal with the security and technical configuration issues that arrise
Building the jail (please note I was using the Veritas Volume Manager here)
root@testsun # vxassist make ftpchroot 100m
root@testsun # vxassist make ftpchrootdata 500m
root@testsun # newfs /dev/vx/rdsk/ftpchroot
root@testsun # newfs /dev/vx/rdsk/ftpchrootdata
root@testsun # mkdir -p /jail/ftp
root@testsun # chmod -R 700 /jail
root@testsun # mount /dev/vx/dsk/ftpchroot /jail/ftp
root@testsun # cd /jail/ftp
root@testsun # mkdir -p dev etc usr usr/bin usr/sbin usr/lib usr/lib/security upload
root@testsun # chmod -R 555 dev etc usr
root@testsun # ln -s usr/bin bin
Finding the libraries to use
root@testsun # ldd /bin/ls | nawk ‘$3 ~ /lib/ { print $3 }’ | sort | uniq
/usr/lib/libc.so.1
/usr/lib/libdl.so.1
root@testsun # ldd /bin/sh | nawk ‘$3 ~ /lib/ { print $3 }’ | sort | uniq
/usr/lib/libc.so.1
/usr/lib/libcmd.so.1
/usr/lib/libdl.so.1
/usr/lib/libgen.so.1
/usr/lib/libmp.so.2
/usr/lib/libnsl.so.1
/usr/lib/libsecdb.so.1
root@testsun # ldd /usr/sbin/in.ftpd | nawk ‘$3 ~ /lib/ { print $3 }’ | sort | uniq
/usr/lib/libbsm.so.1
/usr/lib/libc.so.1
/usr/lib/libcmd.so.1
/usr/lib/libdl.so.1
/usr/lib/libmp.so.2
/usr/lib/libnsl.so.1
/usr/lib/libpam.so.1
/usr/lib/libsocket.so.1
root@testsun # cp /usr/lib/libnsl.so.1 /usr/lib/libsocket.so.1 /usr/lib/ld.so.1 /usr/lib/nss_* /usr/lib/straddr* /usr/lib/libmp.so* /usr/lib/libc.so.1 /usr/lib/libdl.so.1 /usr/lib/libgen.so.1
/usr/lib/libsecdb.so.1 /usr/lib/libpam.so.1 /usr/lib/libbsm.so.1 /jail/ftp/usr/lib
root@testsun # chmod 555 /jail/ftp/usr/lib/*
root@testsun # cp -R /usr/lib/security/* /jail/ftp/usr/lib/security
root@testsun # chmod -R 555 /jail/ftp/usr/lib/security/*
root@testsun # cp /bin/ls /jail/ftp/bin/
root@testsun # chmod 111 /jail/ftp/bin/ls
root@testsun # cp /bin/sh /jail/ftp/bin
root@testsun # chmod 111 /jail/ftp/bin/sh
root@testsun # cp /usr/sbin/in.ftpd /jail/ftp/usr/sbin/
root@testsun # chmod 111 /jail/ftp/usr/sbin/in.ftpd
root@testsun # cp /etc/passwd /etc/group /etc/shadow /etc/pam.conf /jail/ftp/etc
root@testsun # chmod 444 /jail/ftp/etc/*
root@testsun # mkdir /jail/ftp/etc/default
root@testsun # chmod 555 /jail/ftp/etc/default
root@testsun # echo “/bin/sh” > /jail/ftp/etc/shells
root@testsun # chmod 555 /jail/ftp/etc/shells
root@testsun # cp /etc/default/init /jail/ftp/etc/default/
root@testsun # chmod 444 /jail/ftp/etc/default/init
root@testsun # mkdir –p /jail/ftp/usr/share/lib/zoneinfo
root@testsun # chmod 555 /jail/ftp/usr/share/lib/zoneinfo
root@testsun # cd /usr/share/lib/zoneinfo
root@testsun # tar -cf - .|(cd /jail/ftp/usr/share/lib/zoneinfo; tar -xvf -)
root@testsun # chmod 555 /jail/ftp/usr/share/lib/zoneinfo/*
root@testsun # cd /jail/ftp/dev
Creating device nodes
root@testsun # ls -lL /dev/zero /dev/tcp /dev/udp /dev/ticotsord /dev/ticlts /dev/conslog
crw-rw-rw- 1 root sys 21, 0 Jan 28 2005 /dev/conslog
crw-rw-rw- 1 root sys 42, 0 Jan 28 2005 /dev/tcp
crw-rw-rw- 1 root sys 105, 2 Jan 28 2005 /dev/ticlts
crw-rw-rw- 1 root sys 105, 1 Jan 28 2005 /dev/ticotsord
crw-rw-rw- 1 root sys 41, 0 Jan 28 2005 /dev/udp
crw-rw-rw- 1 root sys 13, 12 Jan 28 2005 /dev/zero
root@testsun # mknod conslog c 21 0
root@testsun # mknod tcp c 42 0
root@testsun # mknod ticlts c 105 2
root@testsun # mknod ticotsord c 105 1
root@testsun # mknod udp c 41 0
root@testsun # mknod zero c 13 12
root@testsun # chmod 666 *
root@testsun # cd ..
root@testsun # mount -o nosuid /dev/vx/dsk/ftpchrootdata /jail/ftp/upload
root@testsun # chmod 1755 upload
Configuring a user
root@testsun # useradd -d / -s /bin/sh ftptest
root@testsun # passwd ftptest
New Password:
Re-enter new Password:
passwd: password successfully changed for ftptest
root@testsun # cat /etc/passwd | grep ftptest > /jail/ftp/etc/passwd
root@testsun # cat /etc/shadow | grep ftptest > /jail/ftp/etc/shadow
Now open /jail/ftp/etc/pam.conf and remove everything. Then add the following:
ftp auth required /usr/lib/security/pam_unix.so.1
ftp account required /usr/lib/security/pam_unix.so.1
ftp session required /usr/lib/security/pam_unix.so.1
Check that /jail/etc/passwd, shadow and group do not contain classified information.
Configuring the service
Open /etc/services and create a service to designate the ftp traffic in the jail so you can tell it from regular ftp traffic (if you so desire ofc)
ftp-jail 2121/tcp
ftp-jail 2121/udp
Now the Sun will designate traffic on port 2121 as “ftp-jail” (Please note that if you’re not going to be quick and dirty like me you prolly should also add 2120 as ftp-jail-data or something)
Open /etc/inetd.conf and define the ftp-jail service and what the superserver has to do about it:
ftp-jail stream tcp nowait root /usr/sbin/chroot chroot /jail/ftp /usr/sbin/in.ftpd -l –d
The options -l and -d tell the FTP server to log near enough everything.
Open /etc/syslog.conf and add the following lines to facilitate the FTP daemon’s logging. Note that I sent it to the general messages file. Ofc you can send it anywhere. A remote loghost being most desireable.
#ftpd
daemon.info /var/adm/messages
daemon.debug /var/adm/messages
daemon.err /var/adm/messages
Now you can kill -HUP inetd and syslogd.
Testing it
root@testsun # ftp testsun.intranet 2121
Connected to testsun.intranet.
220 testsun FTP server (SunOS 5.8) ready.
Name (testsun.intranet:TdC): ftptest
331 Password required for ftptest.
Password:
230 User ftptest logged in.
ftp> ls
200 PORT command successful.
150 ASCII data connection for /bin/ls (192.168.1.10,32999) (0 bytes).
bin
dev
etc
lost+found
upload
usr
226 ASCII Transfer complete.
40 bytes received in 0.0084 seconds (4.65 Kbytes/s)
ftp> bye
221 Goodbye.
Netstat output
testsun.intranet.ftp-jail testsun.intranet.32998 32768 0 32768 0 TIME_WAIT
testsun.intranet.2120 testsun.intranet.32999 32768 0 32768 0 TIME_WAIT
testsun.intranet.33000 testsun.intranet.ftp-jail 32768 0 32768 0 ESTABLISHED
testsun.intranet.ftp-jail testsun.intranet.33000 32768 0 32768 0 ESTABLISHED
Logging output
Nov 3 11:57:14 testsun in.ftpd[26494]: [ID 373804 daemon.info] connection from 10.129.10.114 at Thu Nov 3 11:57:14 2005
Nov 3 11:57:14 testsun in.ftpd[26494]: [ID 988435 daemon.debug] <—- 220
Nov 3 11:57:14 testsun in.ftpd[26494]: [ID 738965 daemon.debug] testsun FTP server (SunOS 5.8) ready.
Nov 3 11:57:18 testsun in.ftpd[26494]: [ID 577562 daemon.debug] command: USER ftptest^M
Nov 3 11:57:18 testsun in.ftpd[26494]: [ID 988435 daemon.debug] <—- 331
Nov 3 11:57:18 testsun in.ftpd[26494]: [ID 337738 daemon.debug] Password required for ftptest.
Nov 3 11:57:21 testsun in.ftpd[26494]: [ID 416587 daemon.debug] command: PASS
Nov 3 11:57:21 testsun in.ftpd[26494]: [ID 988435 daemon.debug] <—- 230
Nov 3 11:57:21 testsun in.ftpd[26494]: [ID 636382 daemon.debug] User ftptest logged in.
Nov 3 11:57:23 testsun in.ftpd[26494]: [ID 577562 daemon.debug] command: PORT 10,129,10,114,128,231^M
Nov 3 11:57:23 testsun in.ftpd[26494]: [ID 988435 daemon.debug] <—- 200
Nov 3 11:57:23 testsun in.ftpd[26494]: [ID 223037 daemon.debug] PORT command successful.
Nov 3 11:57:23 testsun in.ftpd[26494]: [ID 577562 daemon.debug] command: NLST^M
Nov 3 11:57:23 testsun in.ftpd[26494]: [ID 988435 daemon.debug] <—- 150
Nov 3 11:57:23 testsun in.ftpd[26494]: [ID 742713 daemon.debug] ASCII data connection for /bin/ls (10.129.10.114,32999) (0 bytes).
Nov 3 11:57:23 testsun in.ftpd[26494]: [ID 988435 daemon.debug] <—- 226
Nov 3 11:57:23 testsun in.ftpd[26494]: [ID 766787 daemon.debug] ASCII Transfer complete.
Nov 3 11:57:26 testsun in.ftpd[26494]: [ID 577562 daemon.debug] command: QUIT^M
Nov 3 11:57:26 testsun in.ftpd[26494]: [ID 988435 daemon.debug] <—- 221
Nov 3 11:57:26 testsun in.ftpd[26494]: [ID 811691 daemon.debug] Goodbye.
Well that was fun wasn’t it? Just some notes here at the end: this was the quick and dirty method. There are prolly more refined versions out there in google though I didn’t find any tbh. Also, who wants FTP when there is SSH? eh? :-)