Chinaunix首页 | 论坛 | 博客
  • 博客访问: 236503
  • 博文数量: 59
  • 博客积分: 2016
  • 博客等级: 大尉
  • 技术积分: 660
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-04 17:30
文章分类
文章存档

2013年(1)

2011年(2)

2010年(7)

2009年(30)

2008年(19)

我的朋友

分类: LINUX

2008-08-06 10:10:44

About this document

Original Author:

I installed Dspam 3.2.3 on a Debian GNU/Linux machine. You really should understand what you're doing before embarking on this setup. Debugging it is going to be a pain if you don't know what is going on.

Please note that I can't answer questions about this anymore, since I no longer run dspam. I've had one bug report that email addresses with spaces in them won't work. Caveat emptor.

Requirements

Going into this I had a few requirements:

  • Make it as secure as possible. I want to avoid suid programs as much as possible, requiring instead that the calling program have the right permissions. At the same time, I want to let my users examine my configuration as much as possible.

  • Fit into Postfix as nicely as possible (i.e. use Postfix mechanisms for content filtering).

  • False-positives and False-negatives should be mailed to ham@example.org and spam@example.org, respectively. My users are going to forget to use the spam-username@example.org syntax suggested in Dspam's README.

  • Dspam CGI

    • Users need to authenticate with their login name and password.

    • The CGI should only be accessible using HTTPS, since I don't want cleartext login passwords going across the wire.

    • The CGI needs to run under since I only have a site certificate for that hostname.

Implementation

DSPAM

I compiled Dspam with no configure options aside from the mysql-storage option. After installing it, I removed the setuid bit from the dspam binary, and made it world-executable.

I created a dspam user to run all dspam stuff. Because it has the mysql password, dspam.conf is chmod 600 (I think it installs this way), owned by the dspam user. We want this user to be the "trusted" user to Dspam (the one that can process mail on behalf on any other user), so make sure dspam.conf contains the following lines:

/usr/local/etc/dspam/dspam.conf

Trust root
Trust dspam

I think it's a good idea to trust root, so that's in there too.

Postfix filtering

Postfix provides a "content filter" mechanism for messages to be piped into a program; the program is expected to either drop the message or pipe it back into Postfix using the sendmail command (). Since Dspam is meant to run in this manner, it can be used as a Postfix content filter.

dspam.conf needs to be told to use sendmail as the delivery agent, by adding the following line:

/usr/local/etc/dspam/dspam.conf

TrustedDeliveryAgent "/usr/sbin/sendmail"

We are going to use the content_filter mechanism of Postfix, which will by default try to optimize things by filtering per-message, instead of per-user. This means that if you get a message to two recipients on your box, it will only call Dspam once with both those recipients. Dspam can handle this, but it will call its delivery agent once for each user. On my machine, I use the recipient_delimiter option of Postfix, which presents a problem for Dspam integration:

  1. I can tell Dspam that the users are the full email address (--user ${recipient}), but then it will think "neale-example1@example.org" and "neale-example2@example.org" are different users, and will create different quarantines and training information for each one.

  2. On the other hand, I could tell Dspam that the users are the Postfix users (--user ${user}), but then sendmail won't get the email addresses, and the users won't be able to filter on the delivery address: they'll just get "neale", instead of "neale-example2@example.org".

  3. I could tell Dspam that the users are the Postfix users, and have it call sendmail with the addresses, but since it calls the delivery agent once for each user, each recipient will get as many copies of the message as there are recipients.
    For example, a message to both "neale-example1@example.org" and "someone.else@example.org" will have Postfix users neale and someone.else. Dspam will call sendmail twice, once for each Postfix user, each time sending the message to both addresses.

  4. I could tell Postfix to only run Dspam for one recipient at a time. This will slow things down a bit, since Dspam needs to run once for each address, but it's the only way that will work.

We need to set up the Dspam "transport" in Postfix, and tell Postfix to only give it one address at a time. We can also tell Postfix not to run more than a certain number of Dspam instances at once (I chose 10).

/etc/postfix/master.cf

smtp      inet  n       -       n       -       -       smtpd
dspam   unix    -       n       n       -       10      pipe
  flags=Ru user=dspam argv=/usr/local/bin/dspam --deliver=innocent --user $user -i -f $sender -- $recipient

This creates a new transport which will invoke DSPAM and hand it the current message on standard input. DSPAM will deliver the message by handing it back to Postfix or moving it to quarantine if the message is deemed to be spam.

Next, we need to make sure Dspam only gets one address at a time: /etc/postfix/main.cf

dspam_destination_recipient_limit = 1

Make Postfix filter incoming mail only

The following was added by following a discussion on the dspam-users mailing list (see for the original thread):

In order to avoid that Postfix filters both incoming and outgoing (relayed) mail, we do not invoke the content filter as it is described in the postfix.txt file that comes with DSPAM. Instead, we introduce a special rule into Postfix's client checks that only gets invoked if the mail is not from an authenticated source (which would be e.g. the local network or a SASL authenticated user).

I have not tested it myself but it is reported to work.

Create a file /etc/postfix/dspam_filter_access:

/./   FILTER dspam:dspam

This will match on any mail, so the filter will always be invoked if this rule gets to be checked.

In main.cf, modify your smtpd_client_restrictions:

smtpd_client_restrictions =
       permit_mynetworks,
       [... the rest of your restrictions ...],
       check_client_access pcre:/etc/postfix/dspam_filter_access

The new entry has to be the last one in the list of restrictions!

This rule will only be checked by Postfix if the mail hasn't already been permitted by one of the other rules above it. That way, the filter gets only invoked for mail from unauthorized sources, which will be inbound mail.

We have to go via a separate file with a dummy regexp, because you can't specify a static filter rule (that will always "match") to Postfix in main.cf as of yet. If you prefer you can use any other lookup table type that will match the messages you intend to filter with DSPAM.


No more "aliases" file

Since this all happens before the local agent runs (that's the part of Postfix that writes mail into your inbox, also the part that checks /etc/aliases), you must move all your aliases entries into a virtual file.

/etc/postfix/main.cf

virtual_maps = hash:/etc/postfix/virtual

Now move your aliases into /etc/postfix/virtual (make sure to remove the colons), and run postmap /etc/postfix/virtual. The virtual file allows you to do some neat tricks, it would be a good idea to read up on it.

Reporting mistakes


Note: If you are using Maildirs and IMAP, a nice alternative way to retrain DSPAM is described . With that setup you also do not need any signatures in the message bodies.


Users need a way to report spam that gets through, in order to better train Dspam. The Dspam README suggests creating a "spam" user users can mail, inserting their username into the address somehow, such as "spam-neale@example.org". I just know my users are going to be confused by this, though. Far simpler would be to tell them to forward all their spam to "spam@example.org".

The Dspam README suggests using /etc/aliases for this task. I don't like that suggestion, since Postfix will run commands specified there as nobody, and that would require setuid executables somewhere. Instead, I created a new dspam-retrain transport which, like the dspam transport, is run as the dspam user by Postfix. The is described on its own page, since it can be used with other MDAs.

/etc/postfix/master.cf

dspam-retrain   unix    -       n       n       -       10      pipe
  flags=Ru user=dspam argv=/usr/local/bin/dspam-retrain $nexthop $sender $recipient

I use Postfix's transport mechanism to specify that mail to spam@example.com and ham@example.com should be routed through the dspam-retrain transport. With Postfix after 2.0, this will also get spam+username@example.com like it says in the README (or spam-username@example.com, depending on the value of recipient_delimiter.

/etc/postfix/transport

spam@example.com    dspam-retrain:spam
ham@example.com     dspam-retrain:innocent

The part after the colon (:) is the ${nexthop} specified in the new transport command above.

Now, to tell Postfix to use the transport. We also need to tell it to look in the transport file when deciding whether or not to allow mail to a certain address, and we set the recipient_delimiter to dash (-) to allow things like spam-user@example.com:

/etc/postfix/main.cf

transport_maps = hash:/etc/postfix/transport
local_recipient_maps = proxy:unix:passwd.byname $alias_maps $transport_maps
recipient_delimiter = -

dspam-retrain is described in .

Finally, /usr/local/bin/dspam-retrain is a shell script I created. Since this is run as the dspam user for us by Postfix, there's no need for any Unix permissions magic.

Apache

Need to write this up, but basically:

  • Do what the README says, putting it in the dspam user's public_html/, so you access it as ~dspam/dspam.cgi.

  • Use mod_auth_pam, set up the apache PAM service to use pam_imap (another compile), and then you can avoid permissions hell in Apache, too. An Apache-specific solution is mod_auth_imap.

  • mod_rewrite should make it possible to have a nicer URL.

  • configure.pl:

$CONFIG{'DSPAM_ARGS'}   = "--deliver=innocent --class=innocent " .
                          "--source=error $ENV{'REMOTE_USER'} --user $ENV{'REMOTE_USER'}";
$CONFIG{'LOCAL_DOMAIN'} = "example.org";

I also changed one of the template files to say "spam@example.org" instead of "spam-user@mydomain.com".

Links

Article in Free Software magazine: http://www.freesoftwaremagazine.com/free_issues/issue_02/focus_spam_dspam/


Discussion

Q: You said dspam needs to use sendmail. Why not procmail for the TrustedDeliveryagent?

A: With this method, you're inserting dspam into an earlier stage of processing. sendmail re-injects it into the processing loop at the right stage; check out . The nice thing about doing it this way is that Postfix takes care of setting runtime permissions for you, so you don't need any SUID binaries or special groups. And because dspam sends everything back to postfix, you can let postfix worry about what user id is needed to run procmail.

2006-01-31 23:29:43由编辑

阅读(1200) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:maildrop调用DSPAM

给主人留下些什么吧!~~