[Esa-l] Revised sanitizer-on-relay nano-HOWTO

Joe Steele joe at madewell.com
Sun Jul 30 14:49:57 PDT 2000


You requested comments, so here it goes:

> Implementing procmail on a sendmail 8.8.8 gateway:
> (Note: This is still undergoing testing and refinement)
> <jhardin at wolfenet.com>
>
> 1. Add the following delivery agent:
>
> Mprocmail,      P=/usr/bin/procmail, F=DFMmShu, S=11/31, R=21/31,
T=DNS/RFC822/X-Unix,
>                 A=procmail -m MAIL_FROM="$_" MAIL_TO="$u" $h

The above mailer definition sets a variable MAIL_FROM="$_".  I don't see
that this variable is used anywhere else.  I am guessing that your
original intent was to capture the envelope sender address(?)  As I
understand it, $_ contains a validated sender host name, and if the sender
is running an IDENT server, it will include the user name on that host. 
That user's name would be the owner of the TCP connection, which may be
unrelated to the sender of the message. 

> 2. Add the following to ruleset 0, between the "handle virtual
> users" and "short-circuit local delivery" stanzas:
>
> # pipe through procmail for processing
> R$*<@example.com>$*     $#procmail $@/etc/procmail/filter.rc
$:$1 at example.com.procmail$2
> R$*<@$*.procmail>$*     $1<@$2>$3
>

Jason Jordan [guru at pcguru.com.au] has already commented in an earlier post
about the missing "." in the first rule, and I agree with him.  Another
comment I have is that when the sanitized message gets relayed back to
sendmail, the recipient's address (including the trailing ".procmail")
will pass through ruleset 3, and a domain name lookup will be attempted.
This will, of course, fail, since there is no top level domain named
procmail (at least not yet).  A way of avoiding this senseless lookup is
to add "procmail" to class P with the following line early in your config
file:

CPprocmail

The m4-based configuration package uses Class P for pseudo-domains.  No
DNS lookups are performed, and a final "." is appended to the domain to
mark it canonical.  

To summarize, I would use the following rules (these lines have been
wrapped at the tabs):

R$*<@example.com.>$*
     $#procmail $@/etc/procmail/filter.rc $:$1<@example.com.procmail.>$2

R$*<@$*.procmail.>$*
     $1<@$2.>$3

The changes are:
1) The left hand side (lhs) of rule 1 has a "." at the end of example.com
to match one added by ruleset 3.

2) The rhs of rule 1 has "<" & ".>" around the domain name.  These angle
brackets are important, as this user name is passed on to rulesets 2, 21,
and 4 for further processing before assigning the user name to $u which is
passed to procmail.  Without the brackets, you are apt to end up with $u
having the final form $1 at example.com.procmail@$j (courtesy of rulesets 61
and 4). 

3) The lhs of rule 2 has a "." after procmail to match one added by
ruleset 3 in recognition of the pseudo-domain.

4) The rhs of rule 2 has a "." after $2, which restores the address to its
original form.


> 3. Here is a sample filter.rc file:
>
> #
> # procmail rules to filter mail on a gateway
> #
>
> LOGFILE=/var/log/procmail.log
> NL="
> "
> LOGABSTRACT=no
>
> POISONED_EXECUTABLES=/etc/procmail/poisoned
> # other configuration stuff here as well
>
> INCLUDERC=/etc/procmail/html-trap.procmail
>
> :0
> * ^From:.+\/[^ ,]+@[^ ,]+
> {
>         FROM="$MATCH"
> }
>
> :0                              # pass along all other mail
> ! -oi -f "$FROM" "$MAIL_TO"
>

I am puzzled as to why you are grabbing the sender's address from the
"From: " header line, instead of using the envelope sender address.  The
only thing I can figure is that you first tried to use your $MAIL_FROM
variable as the sender's address, but that didn't work, so you opted for
this solution (?)

The procmail man page has an example of a setup very similar to the setup
you have developed here.  Comparing the two, I think that the example in
the procmail man page looks a little cleaner, with sendmail calling
procmail using:
        procmail -m $h $f $u
and with procmail relaying back to sendmail using:
        :0
        ! -oi -f "$@"

One little quirk in the setup that I've noticed is that, upon final
delivery, the message includes a header such as:

Received: (from root at localhost) 
     by example.com
     for joe at example.com.procmail

It would be nice to somehow hide the ".procmail" in this header.

Also, there's been one thing bothering me about this setup.  If a sender
can convince sendmail to accept a message addressed to
"somebody at example.com.procmail", then they will successfully bypass the
sanitation process and deliver a message to somebody at example.com.
Presuming you don't run an open mail relay, the risk is probably not great
-- the only persons who could exploit it are those who have access to the
mail host or those who can relay mail through the host.  Nonetheless, I've
wondered if there's a way to prevent this.

In an earlier post someone mentioned a setup where procmail relays the
message back to sendmail by calling it with a different config file.  Such
an approach should eliminate the vulnerability.  The two config files
would be identical, except that sendmail's "standard" config file would
have the second rule commented out, while the secondary config file would
have the first rule commented out.  And of course, the delivering rule in
/etc/procmail/filter.c would become something like:

        :0
        ! -oi -C /etc/sendmail.cf2 -f "$@"

There is a problem with this, however.  When sendmail receives a message,
it looks at the envelope sender address to see if the sender is a local
user on the host (i.e., parse the sender address as if it were a
recipient, and see if it resolves to a local mailer).  If the sender is
local, then sendmail sets its real uid to that of the sender before it
passes the message on to procmail (Otherwise the uid remains root).
When procmail relays the message back, sendmail gets fussy when called
with a non-root uid and with the -C and -f flags, giving warnings such as: 

sendmail[17237]: UAA17237: Authentication-Warning: example.com: joe set
sender to joe at example.com using -f
sendmail[20323]: NOQUEUE: Authentication-Warning: example.com: Processed
by joe with -C /etc/sendmail.cf2
sendmail[20323]: NOQUEUE: Authentication-Warning: example.com: Processed
from queue /var/spool/mqueue
sendmail[20323]: NOQUEUE: SYSERR(joe): queuename: Cannot create
"qfSAA20323" in "/var/spool/mqueue" (euid=500): Permission denied

So, if there are local users sending mail through the mail host, further
configuration steps might be necessary.  For example, sendmail's
authentication warnings could be disabled, and you could create a separate
world-writeable spool directory.  (I, however, don't find these solutions
appealing.) 

Alternatively, a wrapper program could be used which sets the uid from the
euid before calling procmail (the euid is already root by virtue of the
"S" flag in the mailer definition).  I've tried this and it seems to work
o.k.  I can't see that there is any increased security risk, since
non-local senders are passing their messages through procmail as root
already.  Of course, there may be better solutions that I have
overlooked.

A final note -- If two config files are used, then the quirk with the
"Received:" header could be solved by modifying or eliminating this header
definition in the second config file.

--Joe








More information about the esd-l mailing list