Mac OS X Server 10.3.9 and the "Chroots of my Labor"
To start, if you've read this far you're probably aware that FTP security implementation on OS X Server is ridiculously awful. A user can view any share point on the box regardless of how permissions are configured. When a user SFTPs into his or her home directory, he or she can effectively "climb the tree" and actually view files at the root directory level of the server. This is the stuff of nightmares for any server administrator! I figured there's got to be a better way to do things.
A google search led me to an interesting discussion on macosxhints.com which describes how a server administrator can affectively "jail" users to their home directories using a chroot patch (see Create a chrooted SSH/SFTP server on OS X). This appeared to be exactly "the better way" I was looking for! It was, but it turned out to require an incredible amount of patience and perseverance to "make it work," as Tim Gunn would say.
I had trouble right from the start because the macosxhints discussion took place over two years ago and many of the resource links posted in the thread led to dead ends. A google search provided no leads as to the whereabouts of the referenced Masaki Ogawa's article. I looked for other information related to chroot jails and OS X but came up empty. Perhaps this would be a project for another day. Then I remembered the waybackmachine on archive.org! I've had muted success with the waybackmachine over the years but this time it worked like a charm. I found the instructions!!
My next obstacle stemmed from the fact that the version of OpenSSH Masaki refers to in his write up is no longer available via cvs at anoncvs.opendarwin.org. Apparently OpenDarwin.org went dark in May 2007— ouch. But, after giving it some thought I decided it wouldn't be that big of a deal and pressed forward. I figured I could download and compile another OpenSSH source from http://www.openssh.com and move along my merry way. Well, this line of thinking didn't prove true because I couldn't get any of the chroot patches (http://chrootssh.sourceforge.net/download/) to apply correctly on any of the sources I grabbed at openssh.com. I kept getting weird error messages similar to this:
Hunk #1 succeeded at 64 with fuzz 2 (offset 6 lines)
Hunk #2 FAILED at 1231
Hunk #3 FAILED at 1275
2 out of 3 hunks FAILED -- saving rejects to file session.c.rej
Hunks? Fuzz? What the #$%@? What type of R-rated material was this patch attempting to apply to my system?! I ran ./configure anyway just to see what would happen, followed the instructions to create a testssh connection on port 10022 but received a complaint that told me ssh_exchange_identification: Connection closed by remote host. Nice.
At this point I almost gave up again but discovered through additional research that the OpenSSH build in Ogawa's instructions WAS available at the Apple Darwin source code releases . This reinvigorated my quest and gave me the opportunity to follow his written directions "to the T" instead of poking along in the dark.
His article was written in 2004, so I tracked the appropriate tarball to OpenSSH-39 (Darwin 7.2 OS 10.3.2) which created a Build directory inside of /tmp just like Ogawa described. I was then able to patch this OpenSSH version with osshChroot-3.6.1.diff and compile accordingly.
It's probably worth noting there were a few other issues I needed to overcome before I was able to successfully compile OpenSSH. First, I needed to install the Xcode 1.5 Developer Tools on my box. I had foolishly assumed I was building these sources with a compatible gcc compiler because I had installed the December 2002 Developer Tools on my server a while ago— but this was not the case. Had I read a follow-up post more closely on the original macosxhints article I would have seen that mwnovak cautioned people that OpenSSH WOULD NOT compile correctly unless Xcode version 1.5 (or above?) was installed (read the post). Like a dummy, I originally glossed over this crucial point and found out for myself the hard way through a series of exasperating trial and error. In fact, as I reflect I'm not sure why I didn't give up at this step in the process. I guess it's my aforementioned persistence that made me read the original discussion over and over again until I finally and fully digested mwnovak's important point.
I also had to also deal with a number of OpenSSL library header conflicts and "library not found" errors when building the patched version of OpenSSH. I ran into errors like these:
checking whether OpenSSL's headers match the library... no
configure: error: Your OpenSSL headers do not match your library
I came across this very helpful discussion on the macosx forums which led me to a stepwise article detailing a tip on how to fix an OpenSSL header mismatch error on OS X (granted, it was written for OS 10.1 but the methodology still worked!) by copying the correct openssl header files into the /usr/local/include/openssl directory. My header version, in case you were interested, was 90702f (OpenSSL 0.9.7b 10 Apr 2003) and my library version was 9070cf (OpenSSL 0.9.7l 28 Sep 2006).
So, I needed to hunt down the correct OpenSSL build on the Apple Darwin source code releases pages which contains the OpenSSL 0.9.7l 28 Sep 2006 headers. Turns out these headers can be found in the OpenSSL-46 tarball (Darwin 9.0) listed under 10.5 source code. This confused me because I'm actually running 10.3.9 on my server. What was a 10.5 Darwin source doing on my box? My best guess is that security updates I've applied through 10.3.9 include the most recent Darwin core build of OpenSSL-46. These updates keep my lower level services up-to-date in spite of my outdated OS. Hmmm.....
After applying the chroot patch and getting the OpenSSH to compile correctly each additional step listed in Ogawa's instructions worked like a charm. As noted in follow-up posts in the macosxhints discussion, I needed to change the chroot server path from /usr/local/sbin/sshd-chroot to /usr/sbin/sshd-chroot and copy the etc, usr and bin directories into each user's home directory.
To execute the chroot jail, it is then as a easy as adding a dot into the user's home directory path in Workgroup Manager (WGM) AFTER the directory level where you wish to cap access. You can then go a step further and create a directory as a symbolic link to refer back to the virtual root of the capped directory. For example, say there is a Web site named chetswebsite which lives in Documents inside my server's WebServer folder which is owned by user "Chet." To cap Chet's access inside his site, I create a symlink inside chetswebsite (e.g. tmp -> / ) and add the following path as Chet's home directory in WGM:
This will cap Chet's access inside chetswebsite to ensure he won't be able to climb any further up the tree. Awesome!!