Using smrsh

Introduction

The SendMail Restricted SHell (smrsh) enables us to pipe mail to programs and stricts in a safe(r) way. You can place carefully vetted scripts and programs into a specific directory, and then use an alias to have sendmail pipe incoming mail directly to your program. You may then process the mail as you wish (for example, loading messages into a database). This is obviously safer than allowing users to place whatever they want into their ~/.forward file and execute whatever they want, or worse have attackers do the same.

For the purposes of this demonstration we'll start with something simple. I'll show how to enable smrsh into your sendmail configuration, and then write a quick script that will save individual mail messages, as individual files, into the directory of your choice.

I am running 8.12.10 on a Solaris 9 (SPARC) box, but the principles outlined here will be readily transferrable to any relatively new build of sendmail on any UNIX-like OS, although your sendmail configuration build procedure will no-doubt differ.

Enabling smrsh

To start with, we need to ensure that sendmail is configured to use smrsh. To do this, check your sendmail.cf file.

    
# grep "smrsh" /etc/mail/sendmail.cf
    
    

If nothing is returned, you don't have smrsh support configured. You can still pipe mail to programs, but you will not be doing so in a secure way.

To enable smrsh support, the easiest (BY FAR) method is to use the sendmail.mc file and m4 to build your sendmail.cf file. I'm using Solaris 9, so my .mc file is stored in /usr/lib/mail/cf, although the location of this file is really up to you. My .mc file is a derivative of the subsidiary.cf file distributed with Solaris 9, which I have modified to suit my needs, and saved as /usr/lib/mail/cf/hostname.mc.

I will now add smrsh support into this file.

    
# vi /usr/lib/mail/cf/hostname.mc
# grep smrsh /usr/lib/mail/cf/hostname.mc
FEATURE(`smrsh', `/usr/lib/smrsh')dnl
    
    

Now, I can generate the .cf file from this .mc file.

    
# cd /usr/lib/mail/cf
# /usr/ccs/bin/m4 ../m4/cf.m4 hostname.mc > hostname.cf
    
    

I'm now ready to install the new .cf file.

    
# cp -p /etc/mail/sendmail.cf /etc/mail/sendmail.cf.`date +%Y%m%d`
# cp -p /usr/lib/mail/cf/hostname.cf /etc/mail/sendmail.cf
    
    

I can now restart sendmail for the configuration changes to take effect.

    
# /etc/init.d/sendmail restart
    
    

We now need to know where smrsh will look for it's "approved" programs - i.e. programs that are allowed to run in it's restricted environment. If we'd built smrsh from source, we could use the SMRSH_CMDDIR compile time macro to specify this directory ourselves. As we're using "bundled" smrsh the easiest way is to use strings on the smrsh binary, and look for the sm.bin directory.

    
# strings /usr/lib/smrsh | grep 'sm\.bin' | sort | uniq
/var/adm/sm.bin
    
    

Good. Now sendmail is configured to take advantage of smrsh, and we know where smrsh will look for it's approved executables.

Using smrsh: An example

I am going to demonstrate smrsh by creating a script which will read from STDIN, and write to a uniquely named file. Using this technique, you can create a directory and store all mail sent to a particular user in individual files, as opposed to inside one large file (which easily done by specifying the full path to the file in your aliases file).

First, I'll create a script, /var/adm/sm.bin/smrshtests.sh which does nothing more than reads from STDIN and redirects everything to a uniquely named file.

    
#!/bin/bash

BASENAME="/usr/bin/basename"
CAT="/usr/bin/cat"
DATE="/usr/bin/date"
ECHO="/usr/bin/echo"

SPOOLDIR=""

function print_error {
   ${ECHO} "Error: $@" >&2
}

function print_usage {
   {
      ${ECHO} "Usage: $( ${BASENAME} $0 ) [-h] -d <spool_dir>"
      ${ECHO} "   -d <spool_dir> - Specify output spool directory"
      ${ECHO} "   -h             - Display this usage message"
   } >&2
}

function check_spool_dir {
   if [ "${SPOOLDIR}" = "" ]; then
      print_error "Spool directory not specified" && exit 1
   fi
   if [ ! -d "${SPOOLDIR}" ]; then
      print_error "Spool directory does not exist" && exit 1
   fi
}

function create_filename {
   FILENAME="smrshtest_$( ${DATE} +%Y%m%d_%H%M%S )_$$.msg"
}

while getopts ":hd:" OPTION; do
   case ${OPTION} in
      "h")  print_usage && exit 0  ;;
      "d")  SPOOLDIR="${OPTARG}"   ;;
      *  )  print_usage && exit 1  ;;
   esac
done 

shift $(( ${OPTIND} - 1 ))

check_spool_dir
create_filename

# simply dump STDIN to file
${CAT} - > ${SPOOLDIR}/${FILENAME}

exit 0
   
    

Make this script executable

    
# chmod +x /var/adm/sm.bin/smrshtest.sh
   
    

Next, I will create the target spool directory, where I want to store my mail messages. It is important to set the ownership and permissions of this directory correctly so that the messages can be written.

    
# mkdir -p /var/spool/smrshtest
# chown daemon:other /var/spool/smrshtest
# chmod 755 /var/spool/smrshtest
   
    

All that remains is to add an alias (we'll use the "smrshtest" user for this) and test things out

    
# vi /etc/aliases
# grep "smrshtest" /etc/aliases
smrshtest:	|"/var/adm/sm.bin/smrshtest.sh -d /var/spool/smrshtest"
# newaliases
   
    

Now, we're all set to test:

    
# echo "Testing smrshtest" | mailx -s "Testing smrsh" smrshtest@example.com
# ls -l /var/spool/smrshtest
total 2
-rw-r--r--   1 daemon   other        644 Mar 18 21:31 smrshtest_20070318_213116_562.msg
# grep 'Testing' /var/spool/smrshtest/smrshtest_20070318_213116_562.msg
Subject: Testing smrsh
Testing smrshtest
   
    

Good, the message has arrived and been stored in a uniquely named file.

Conclusion

This is only a very basic application of smrsh, but illustrates how easy it is to manipulate incoming mail and process it in any way you wish. You can write scripts to load mail into a database, extract data from the message itself, etc.

Cheers
Kevin Waldron
kevin@zazzybob.com

Disclaimer! - This article is provided for guidance only, and does not replace the relevant official documentation and manuals. I will not be held liable for any hosed systems and/or data.

Valid CSS!

Valid HTML 4.01!