• chroot'd SFTP on Mac OS X server

    So here you are finding that you need to grant someone else SFTP access to your server. There are lots of reasons to do this, in my case it’s because I needed to grant access to someone’s web designer. We initially worked it out by him emailing me files and me SFTP’ing them up to the server in the correct location. Now he needs direct access to fix some things and I want to give him only what he needs without compromising security. Enter the chroot jail. After lots of googling and some encouragement from the Mac OS X Server email list, I’ve got it working. Here’s how it works.
    First, you should create the new user in Workgroup Admin and either assign them access privileges for SSH via Server Admin or assign them to a group that has SSH access privileges. Further discussion is below.
    From the Terminal, start off right.

    sudo cp /etc/sshd_config /etc/sshd_config.bkup sudo chown root / sudo chmod 755 / sudo mkdir -p /chroot/user/scratchpad sudo chown -R root /chroot sudo chown user /chroot/user/scratchpad sudo chmod -R 755 /chroot

    Every additional new user added will then be something along the lines of the following.

    sudo mkdir -p /chroot/user2/scratchpad sudo chown root /chroot/user2 sudo chown user2 /chroot/user2/scratchpad sudo chmod -R 755 /chroot/user2

    Every folder in the path to the chroot jail must be owned by root. I don’t think it matters what group the folder is in. What I did above was to

    1. backup /etc/sshd_config
    2. change ownership of the root directory to root
    3. change permissions of the root directory to 755
    4. create a chroot folder
    5. create a user folder inside the chroot folder
    6. create a folder inside the user folder that user can modify
    7. set ownership and permissions

    Now to edit /etc/sshd_config to the following.

    #Subsystem sftp /usr/libexec/sftp-server Subsystem sftp internal-sftp Match User user X11Forwarding no AllowTcpForwarding no ForceCommand internal-sftp ChrootDirectory /chroot/user
    Code language: PHP (php)

    This creates a chroot jail. When the user logs in will drop them into the folder /chroot/user, in that folder is a folder they can add things to /chroot/user/scratchpad.
    If you want to create a Group in Workgroup Admin for ‘Chroot Users’ then add the new users that you created in Workgroup Admin to the Group; you won’t have to keep editing the /etc/sshd_config file. Instead of the above, add the following. Make sure you add the ‘Chroot Users’ group to the SSH access ACL in Server Admin.

    #Subsystem sftp /usr/libexec/sftp-server Subsystem sftp internal-sftp Match Group chrootusers X11Forwarding no AllowTcpForwarding no ForceCommand internal-sftp ChrootDirectory /chroot/%u
    Code language: PHP (php)

    If you have more than one chroot group just repeat the Match Group setup again.
    To test whether the above is working, issue the following from the terminal.

    $ sftp Password: sftp>

    Getting in is one thing. Now you have to mount the folder you want to use. Unfortunately you can’t use a symlink inside of a chroot jail. This is where Homebrew is your best friend. I don’t know why I’ve never seen fit to install this before. After installation just issue the following commands.

    brew install bindfs

    You might have to restart. Now with an empty folder created in /chroot/user you can mount --bind to a folder outside of the chroot jail. For example

    sudo /usr/local/bin/bindfs -u user /Library/Server/Web/Sites/Server/Documents/mysite/yourfolder /chroot/user/scratchpad

    So far this seems to work here.
    Update for Mountain Lion Server
    As I’ve updated my server from Snow Leopard to Mountain Lion, there’s one extra step.
    From Workgroup Manager, you will need to create a home folder. Nothing really has to go into it, but it needs to be present. My settings are as follows.
    Mac OS X Server/Share Point URL:afp://
    Path to Home Folderusername
    Full Path/Network/Servers/
    After setting this up the first time it seems to auto-populate for every other user. You’ll have to go to the Home tab, select it and Save.

  • Fail2ban Problems and Solutions

    If you use Fail2ban then you are probably aware of the fact that you must add a rule number to the ipfw deny rule for actionban in ipfw.conf. If you don’t add a rule number then there is no way for fail2ban to delete the rule after it expires. The problem lies in that you can easily set a different rule number for each filter but if the filter adds many rules within it’s ban time then when that first actionunban gets triggered all rules with the same number are removed, even if there full ban time has not transpired.
    I was looking for an elegant solution to this and finally figured out how to do it myself. What I’ve done is in the ipfw.conf file I’ve added a variable that will create a random number between 10000 and 12000 to use as the rule number.
    The code is pretty simple.

    echo $((RANDOM%2000+10000))

    There needs to be an extra % in there for it to work. I think it has something to do with python. So far it seems to be working pretty good here. While it is possible that I could get a duplicate rule number, it’s unlikely.
    I’ve modified my installation of Fail2ban significantly; but only by adding filters, jails, etc. Here’s a bundled version of all of my modifications. Here are instructions for using my modifications. So far everything seems to be working great. I’ve had to add a few items to ignoreregex so I don’t ban people using their iPhones on 3G or at home from certain dynamic IP cable providers.
    What I’ve done is a host lookup on the IP that’s banned and if I find it’s a local ISP, like Verizon or Time Warner Cable, I add part of their host lookup to the ignoreregex list. So far it seems to be doing the trick.

  • Checking Fail2ban regex

    I’ve just stumbled across a great command in Fail2ban to check whether or not your filter will actually score a hit from your log file.
    From the command line.
    [code lang=bash]
    $ fail2ban-regex /path/to/logfile /etc/fail2ban/filter.d/myfilter.conf regex_to_ignore
    As an example.
    [code lang=bash]
    $ fail2ban-regex /var/log/secure.log /etc/fail2ban/filter.d/sshd.conf (myusername|myIPaddress)
    This seems like a great way to test whether changes to your filters are correct, rather than just waiting to see if anything shows up in fail2ban.log.

  • Server-Side Email Filtering With Sieve

    Another post for the peripheral brain.
    When I first set up my own server lo these years ago, I never really thought about email message filtering. After all, I had rules in that would send my incoming message to wherever I wanted them. Besides, I was much more concerned with eliminating spam.
    Well, that was then and spam seems under control. I was prompted to look at server-side message filtering mostly to help out my mother, who seems determined to have every single store, travel and other consumer site that will happily take your email address and send you messages daily — or more often, have a more controllable experience on her iPhone. When we originally set up her iPhone she told me she didn’t want to use it for email. Silly me, I listened and set her up with a POP account. Well now she wants email. What’s a good son to do. 馃槈
    I changed her POP account to IMAP, copied over all her messages to her new IMAP folders and thought I’d need to solve her impending problem of 100 or so messages every other day choking her inbox.
    After a bit of Googling I found Sieve. I’d actually heard of it before but never really thought about it. The Apple Discussion Forum had a nice start and pointed me on to sources I used to set it up.
    Here are the salient points. From the terminal…

    1. Add the following lines to /etc/services
      sudo pico /etc/services

      Insert the following lines.

      callbook 2000/udp # callbook
      callbook 2000/tcp # callbook
      + sieve 2000/udp # sieve mail filtering
      + sieve 2000/tcp # sieve mail filtering

      You can check to see if it’s running by running

      netstat -an | grep 2000

      with results

      tcp4 0 0 *.2000 *.* LISTEN
      tcp6 0 0 *.2000 *.* LISTEN
    2. Create /usr/sieve
      sudo mkdir /usr/sieve
      sudo chown _cyrus:mail /usr/sieve
    3. Restart mail services
      sudo serveradmin stop mail
      [ some stuff ]
      sudo serveradmin start mail
      [ some stuff ]
    4. Since I’m using OS X Server and SquirrelMail is already running, next was installing and configuring avelsieve.

    I really did try installing the latest development version — 1.9.9 alpha. That should have been a clue. After spending way too much time with it I installed the stable version – avelsieve 1.0.1. Once copied into /usr/share/squirrelmail/plugins run sudo perl /etc/squirrelmail/config/ and activate the plugin.
    Then it’s back to the terminal. These instructions are from AFP548.

        cd /usr/share/squirrelmail/plugins/avelsieve
        sudo cp config-sample.php config.php

    Now set the correct authentication matching SquirrelMail.
    Edit /etc/squirrelmail/plugins/avelsieve/config.php and change:

    $preferred_mech = "PLAIN";


    $preferred_mech = "CRAM-MD5";

    You should be running SquirrelMail with CRAM-MD5 authentication anyway.
    Finally, edit the /etc/squirrelmail/plugins/avelsieve/lib/sieve-php.lib.php file.
    Find the line:

    fputs($this->fp, "PUTSCRIPT "$scriptname" {$len+}rn");

    and change it to :

    fputs($this->fp, "PUTSCRIPT "$scriptname"".' {'."$len+".'}'."rn");

    This fixes an error in the script allowing you to save your changes to the filters. Now go login to webmail and click on the Filter link to start creating your Sieve filters.

  • Poof it's Gone

    OK, I’m only really posting this cause I need it and I just want to put it somewhere to remember it. 馃槈
    To make a file or folder invisible issue the following from the CLI.
    SetFile -a V path/to/fileOrFolder
    To make it visible again…
    SetFile -a v path/to/fileOrFolder
    That’s it. This can be especially useful on shared drives to keep others out of specific folders, etc. BTW, the file or folder still shows up in `ls`, it’s just not visible in Finder.

  • Don’t Send iCal Replies

    I came across a great hint in Mac OS X Hints today. It seems that there’s an easy way to interrupt the process of sending an email reply when accepting iCal invites. As I tend to play around with iCal invites a lot (adding and deleting the same event ad nauseum) — I love this.
    I wrote up a modified script like in the example and bundled it with a shell script, to install and uninstall the modification. You have to run this shell script using sudo from the CLI (Command Line Interface aka
    The zip file contains the shell script, the modified Mail.scpt AppleScript, and the original Mail.scpt AppleScript.
    To install run sudo /path/to/ install
    To uninstall run sudo /path/to/ revert
    To check usage and status, run /path/to/
    If you don’t like messing with the CLI then there’s a great little shareware app, iCal Reply Checker that does it all, and more.
    It seems that neither method interferes with the code signing of iCal as the script in question is not code signed.
    It appears that if you’re using an Exchange account in that this script is being bypassed and this hint won’t work for you. 馃檨