The first example is simple to set up. Postfix receives
unfiltered mail from the network with the
smtpd(8) server, and
delivers unfiltered mail to a content filter with the Postfix
pipe(8) delivery agent. The content filter injects filtered mail
back into Postfix with the Postfix
sendmail(1) command, so that
Postfix can deliver it to the final destination.
This means that mail submitted via the Postfix
sendmail(1)
command cannot be content filtered.
In the figure below, names followed by a number represent
Postfix commands or daemon programs. See the
OVERVIEW
document for an introduction to the Postfix architecture.
The content filter can be a simple shell script like this:
1 #!/bin/sh
2
3 # Simple shell-based filter. It is meant to be invoked as follows:
4 # /path/to/script -f sender recipients...
5
6 # Localize these. The -G option does nothing before Postfix 2.3.
7 INSPECT_DIR=/var/spool/filter
8 SENDMAIL="/usr/sbin/sendmail -G -i" # NEVER NEVER NEVER use "-t" here.
9
10 # Exit codes from <sysexits.h>
11 EX_TEMPFAIL=75
12 EX_UNAVAILABLE=69
13
14 # Clean up when done or when aborting.
15 trap "rm -f in.$$" 0 1 2 3 15
16
17 # Start processing.
18 cd $INSPECT_DIR || {
19 echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; }
20
21 cat >in.$$ || {
22 echo Cannot save mail to file; exit $EX_TEMPFAIL; }
23
24 # Specify your content filter here.
25 # filter <in.$$ || {
26 # echo Message content rejected; exit $EX_UNAVAILABLE; }
27
28 $SENDMAIL "$@" <in.$$
29
30 exit $?
Notes:
-
Line 8: The -G option does nothing before Postfix 2.3,
otherwise it disables address rewriting of message headers.
-
Line 8: The -i option says don't stop reading input when
a line contains "." only.
-
Line 8: NEVER NEVER NEVER use the "-t" command-line option
here. It will mis-deliver mail, like sending mailing list mail back
to the mailing list.
-
Line 21: The idea is to first capture the message to
file and then run the content through a third-party content filter
program.
-
Line 22: If the mail cannot be captured to file, mail
delivery is deferred by terminating with exit status 75 (EX_TEMPFAIL).
Postfix places the message in the deferred mail queue and tries
again later.
-
Line 25: You will need to specify a real content filter
program here that receives the content on standard input.
-
Line 26: If the content filter program finds a problem,
the mail is bounced by terminating with exit status 69 (EX_UNAVAILABLE).
Postfix will return the message to the sender as undeliverable.
-
Note: in this time of mail worms and spam, it is a BAD
IDEA to send known viruses or spam back to the sender, because that
address is likely to be forged. It is safer to discard known to be
bad content and to quarantine suspicious content so that it can
be inspected by a human being.
-
Line 28: If the content is OK, it is given as input to
the Postfix sendmail command, and the exit status of the filter
command is whatever exit status the Postfix sendmail command
produces. Postfix will deliver the message as usual.
-
Line 30: Postfix returns the exit status of the Postfix
sendmail command.
I suggest that you first run this script by hand until you are
satisfied with the results. Run it with a real message (headers+body)
as input:
% /path/to/script -f sender recipient... <message-file
Once you're satisfied with the content filtering script:
-
Create a dedicated local user account called "filter". This
user handles all potentially dangerous mail content - that is
why it should be a separate account. Do not use "nobody", and
most certainly do not use "root" or "postfix".
-
Create a directory /var/spool/filter that is accessible only
to the "filter" user. This is where the content filtering script
is supposed to store its temporary files.
-
Configure Postfix to deliver mail to the content filter
with the
pipe(8) delivery agent.
/etc/postfix/
master.cf:
# =============================================================
# service type private unpriv chroot wakeup maxproc command
# (yes) (yes) (yes) (never) (100)
# =============================================================
filter unix - n n - 10 pipe
flags=Rq user=filter argv=/path/to/script -f ${sender} -- ${recipient}
This runs up to 10 content filters in parallel. Instead of a
limit of 10 concurrent processes, use whatever process limit is
feasible for your machine. Content inspection software can gobble
up a lot of system resources, so you don't want to have too much
of it running at the same time.
-
To turn on content filtering for mail arriving via SMTP
only, append "-o
content_filter=filter:dummy" to the
master.cf
entry that defines the Postfix SMTP server:
/etc/postfix/
master.cf:
# =============================================================
# service type private unpriv chroot wakeup maxproc command
# (yes) (yes) (yes) (never) (100)
# =============================================================
smtp inet ...other stuff here, do not change... smtpd
-o
content_filter=filter:dummy
The "
content_filter" line causes Postfix to add one content
filter request record to each incoming mail message, with content
"filter:dummy". This record overrides the normal mail routing
and causes mail to be given to the content filter instead.
The
content_filter configuration parameter accepts the same syntax
as the right-hand side in a Postfix transport table.
-
Execute "postfix reload" to complete the change.