Procmail: A Pretty Good Mail Filter
On the server side, the system is required to continuously download email with a program such as fetchmail
running as a daemon. Then the messages have to be dispatched by the running MTA (Mail Transport Agent) to a MDA (Mail Delivery Agent) or mail filter such as procmail. Procmail, a mail filter largely used on UNIX systems, is an event-driven email processor invoked by the MTA. Because its rules are based on regular expressions, many consider procmail a complex application, but I consider regular expressions its strength.
Procmail works using a configuration file with recipes, where each recipe consists of three parts. Without going too deeply in procmail details, here are the steps required for using it in this example. If you already have a working procmail installation, you can include the required recipe by using the following statement in the existing procmail configuration file:
Otherwise, you have to install procmail and then write the bare minimum configuration file under your home directory (file: .procmailrc). The required recipe for this example is as follows (file: rc.machine):
This recipe tells procmail to filter all incoming emails and select those whose "To:" address matches firstname.lastname@example.org. These messages have to be redirected as input (piped) to a PHP script named cmdproc.php.
The Answering Process
PHP is a very good scripting language that is useful for implementing command line programs. I used it to build the core of the automatic reply system. I installed it together with the PHP PEAR library package Mail_Mime as follows:
apt-get install php5-cli
pear install Mail_mime
The main file, cmdproc.php in the downloadable code for this example, includes two other files:
- inc.vars.php: This file contains the includes for PEAR libraries and some global variable assignments that are installation-specific (e.g., the SMTP server for replying and the parametric variables in Table 1).
|Table 1. Parametric Variables for Remote Server Control|
||SMTP server used by the server
||server email address
||Authorized user email address (used only in cmdsend.php)
||Path for GnuPG keyring
||Command maximum execution time
||Character used in line beginning to select special commands
- inc.util.php: This file is a little collection of utility functions to improve the readability of the main file.
As previously stated, procmail redirects the messages sent to a specific machine address to the script that reads them in an array from standard input:
$msg_arr = file("php://stdin");
Next, the procedure extracts some pieces of information from the message:
- The sender email address (this information is used to verify the identity of the message sender analyzing the signature)
- The signed and encrypted part of the message
The following steps are then necessary:
- Verify that the public key of the sender's email address is one of those in the server keyring.
- Verify the real identity of the sender expressed by the signature that seals the encrypted message.
- Decrypt the garbled part of the message with the server's secret key and obtain the command to run.
It is then time to run the GnuPG command gpg within the PHP script. This is possible using the Program Execution Functions (i.e., proc_* functions), which allow you to execute programs inside a PHP script with a high degree of control over input/output structures). The utility function gpg_cmd inside the file inc.util.php runs the gpg command without using any temporary files. Rather, it manages all input and output data exchanges in memory.
With the right gpg parameters, steps 1, 2, and 3 from above are checked. If all tests are passed, the command is sent to the server in the variable $cmd_arr['out'] (see Sidebar 2. The Problem of Hanging Commands). The command could fit into one of the following two scenarios:
- A standard Linux command, including any executable script: The script runs this command (see std_cmd utility function) and collects the outputs (stdout and stderr) in the two variables $run_arr['out'] and $run_arr['err']. These outputs will be separately signed and encrypted before being embedded in the body of email reply.
- A special command: You can run special commands using a special character, which you can customize by setting the variable $special_first_chr in position 0. I use the '#' character and, as an example, I implement the special command 'get' to ask the server to send me back a file. That is a kind of get ftp command run in batch mode. For this special case, if the file requested exists, it will be signed and encrypted before being attached to the email reply.