/branches/upstream/4.2.1/accept.c |
---|
0,0 → 1,45 |
/************************************************* |
* Exim - an Internet mail transport agent * |
*************************************************/ |
/* Copyright (c) University of Cambridge 1995 - 2002 */ |
/* See the file NOTICE for conditions of use and distribution. */ |
#include "local_scan.h" |
/* |
* This is a basic version of local_scan that always accepts the messge. |
* It is like the template provided by Philip Hazel, except it is |
* intended to be compiled as a .so and loaded dynamically by the "real" |
* local_scan. |
*/ |
int local_scan_version_major(void) |
{ |
return LOCAL_SCAN_ABI_VERSION_MAJOR; |
} |
int local_scan_version_minor(void) |
{ |
return LOCAL_SCAN_ABI_VERSION_MINOR; |
} |
int local_scan_version( void ) |
{ |
return 1; |
} |
int local_scan(int fd, uschar **return_text) |
{ |
/* Keep pedantic compilers happy */ |
fd = fd; |
return_text = return_text; |
log_write(0, LOG_MAIN, "Message accepted by dynamically loaded dummy local_scan"); |
return LOCAL_SCAN_ACCEPT; |
} |
/* End of local_scan.c */ |
/branches/upstream/4.2.1/sa.html.template |
---|
0,0 → 1,221 |
<html> |
<head> |
<title>Exim SpamAssassin at SMTP time</title> |
</head> |
<body> |
<h1 ALIGN="CENTER">Exim SpamAssassin at SMTP time</h1> |
<h3>What's that?</h3> |
<pre> |
mail from: merlin@gandalf |
250 OK |
rcpt to: merlin@gandalf |
250 Accepted |
data |
354 Enter message, ending with "." on a line by itself |
From: merlin@gandalf |
To: merlin@gandalf |
Subject: $$$ Make Money Fast $$$ !!! |
viagra 100% GARANTEE AMAZING FULL REFUND |
This is not spam |
. |
550 Rejected |
</pre> |
(logs would show something like this: |
<tt>2004-03-10 08:27:18 1B16Y8-0001UP-4R SA: Action: permanently rejected message: hits=14.8 required=7.0 trigger=11.0 ( scanned in 2/2 secs | Message-Id: CCQPVENACPQBFLTRLICXWQVEK@gandalf). From <merlin@gandalf> (host=gandalf [127.0.0.1]) for merlin@gandalf</tt>) |
<P> |
An example of teergrube would return this instead |
<pre> |
data |
354 Enter message, ending with "." on a line by itself |
(...) |
body SEE_FOR_YOURSELF /See (?:for|it) yourself\b/i |
describe SEE_FOR_YOURSELF See for yourself |
body ORDER_NOW /\border (?:now|soon|fast|quickly|while)\b/i |
describe ORDER_NOW Encourages you to waste no time in ordering |
. |
451- wait for more output |
451- wait for more output |
451- wait for more output |
(... one line every 10 secs, 15 minutes elapse ...) |
450 Please try again later |
</pre> |
The idea here is to stall and waste the resources of the remote sender (BTW |
teergrube comes from german, and means tar-pitting, or stopping someone in his |
tracks) |
<BR><BR> |
<h3>Why?</h3> |
SpamAssassin can be run inside exim after the mail has been accepted, as shown |
<a href="http://bogmog.sourceforge.net/document_show.php3?doc_id=28">here</a>, |
but if you're not going to use my patch and you just want to run SA as an exim |
transport, |
<a href="http://dman13.dyndns.org/~dman/config_docs/exim-spamassassin/">this</a> |
version is recommended |
<P> |
Now, while this will work, we can do better, hence the reason for my code |
(just to make things clear, you do not want to run both my code, and dman's |
transports. It'd work, but you'd be scanning the message twice) |
<P> |
The reason why I wanted SpamAssassin in local scan is that I don't want to |
accept the damn spam in the first place. |
<ul> |
<li>While my code lets you do that, I don't like to send mails to the bit |
bucket, so you need to bounce them. |
<li>Once you accept the spam, you can't bounce it half the time, or you |
bounce it to an innocent whose Email was forged as an envelope sender |
(some spam even forges the bounce address to <em>you</em>) |
<li>If I refuse spam at SMTP time, it will remove the spam addresses from at |
least a few lists (they gotta clean their lists eventually otherwise they'd |
spend more time Emailing dead addresses than good ones) |
<li>I have the option of toying with spammers and stall their connections and |
waste their resources (see the following page for details on |
<A HREF="http://www.iks-jena.de/mitarb/lutz/usenet/teergrube.en.html"> |
teergrubing</A> |
</ul> |
Note that you can also use this code to simply run SA on all your mails (or |
portion thereof as configured with SAEximRunCond) without having to configure SA |
in your exim.conf. In other words, this code can be configured to not reject |
any mails. |
<BR><BR> |
<h3>SpamAssassin? What's that?</h3> |
Ah, you need to visit <a href="http://spamassassin.org/">this page</a> first |
then |
<BR><BR> |
<h3>How does it work, what knobs are there?</h3> |
You need to configure spamassassin to flags mails as spam after a certain |
threshold (7 for instance). After that, this code can be configured to |
<ul> |
<li>Pretend to be processing the Email and send continuation lines to the |
remote server until it gives up (aka |
<A HREF="http://www.iks-jena.de/mitarb/lutz/usenet/teergrube.en.html"> |
teergrubing</A>) |
<li>Accept but not deliver mail with a high threshold (i.e. devnull the mail) |
<li>Reject mail with a lower threshold |
<li>Temporarily reject mail with a still lower threshold (you can then inspect |
your logs to decide if you want to tweak SA so that next time the mail |
is sent, you can receive it) |
<li>In all 5 cases, mail can be optionally saved to disk so that you can |
inspect all the mails you've rejected or /dev/nulled |
</ul> |
You can also (and probably should <img src="/gifs/people/smile.happy.gif" alt=":-)" align=TOP WIDTH=16 HEIGHT=16>) use the new greylisting support for even |
better spam control |
<P> |
For more details, you should look at the self-documented |
<a href="files/sa-exim.conf">config file</a> and you can see |
<a href="sa-exim.demo.txt">some sample rejects and what you get in the logs</a> |
<BR><BR> |
<h3><A NAME="greylisting">Greylisting you say?</A></h3> |
While when sa-exim first came out, its strongest point was being one of the |
first programs (if not the first) that let you reject Spam at SMTP time, its |
coolest feature now is adaptive greylisting support<BR> |
In a nutshell, you get the advantages of greylisting without the disadvantages: |
<ul> |
<li>mails with a low spam score are accepted without delay |
<li>mails with an average spam score are greylisted, |
<b>and only those are delayed</b> |
<li>mails with high spam scores are rejected regardless (no greylisting) |
</ul> |
This method is the best combination I've seen out there so far, and |
while I've been talking about it for a while, I don't yet know of other |
programs that implement this method (if you do, please let me know so that |
I can acknowledge them) |
<BR> |
For more details on how this works, check out the <a href="files/sa-exim-cvs/README.greylisting">greylisting README</a> |
<BR><BR> |
<h3>Ok, where's the code? / Downloads</h3> |
<ul> |
<li>The latest version is here (<a href="files/sa-exim-current/">browsable tree</a> or <a href="files/sa-exim-current.tar.gz">tar.gz</a>). You can also |
get it from <A href="http://sourceforge.net/projects/sa-exim/">sf.net</a><BR> |
<li>The CVS version is here (<a href="files/sa-exim-cvs/">browsable tree</a>) |
and you can also get the CVS tree from |
<A HREF="http://sourceforge.net/cvs/?group_id=56124">sf.net</A> |
<li>The latest config file with documentation is |
<a href="files/sa-exim.conf">here</a> |
<li>Debian packages (source and binary) are <a href="files/debian/">here</a> |
</ul> |
<P> |
As explained in the archive, you can either copy <tt>sa-exim.c</tt> over exim's |
<tt>src/local_scan.c</tt> You need to copy local_scan in src in the exim source |
tree and rebuild it, or you can build sa-exim as a loadable module (you need |
to patch exim to support loadable modules though) |
<P> |
You can also browse all my exim files <A HREF="files/">here</A> |
<BR><BR> |
<h3>Mailing list</h3> |
You should probably subscribe to this low traffic |
<a href="http://lists.merlins.org/lists/listinfo/sa-exim">mailing list</a> if |
you download the code to keep apprised of bug fixes and enhancements |
<BR><BR> |
<h3>Integration with Exim 4</h3> |
This code works without anything in the exim conf, but you probably want to use |
some knobs to disable scanning for some users (like setting |
<tt>X-SA-Do-Not-Rej</tt> or <tt>X-SA-Do-Not-Run</tt> in the rcpt ACL and |
removing those headers in the right places).<BR> |
See <A HREF="http://marc.merlins.org/linux/exim/#conf">my exim4 conf tree</a> |
and more specifically the |
<A HREF="http://marc.merlins.org/linux/exim/exim4-conf/exim4.conf">exim4.conf</A> |
file |
<P> |
You can look at the <A HREF="files/sa-exim-cvs/README">README</A> for more |
integration details. |
<BR><BR> |
<h3>Changelog/Download</h3> |
<Changelog> |
</Changelog> |
<P> |
More generally, all the files can also be found <A HREF="files/">here</A> |
<P> |
<A HREF="/perso/contact.html">Feedback is appreciated</A> (but please |
prefer the use of the |
<a href="http://lists.merlins.org/lists/listinfo/sa-exim">sa-exim list</a>) |
<BR><BR> |
<h3>Acknowledgements</h3> |
<Acknowledgements> |
</Acknowledgements> |
<P ALIGN="center"> |
<img src="/gifs/lines/misc/lampline.gif" alt="" WIDTH=720 HEIGHT=14> |
</P> |
<br> |
<img src="/gifs/misc/wizard.gif" alt="" align="middle" WIDTH=72 HEIGHT=61> |
<img src="/gifs/linux/damn-powered.gif" alt="" align="right" WIDTH=170 HEIGHT=29> |
<IMG SRC="/gifs/icons/msfree.gif" ALT="[ms free site]" ALIGN="right" WIDTH=95 HEIGHT=31> |
<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.php?group_id=56124&type=1" width="88" height="31" border="0" align="right" alt="SourceForge.net Logo"></a> |
<A HREF="/perso/contact.html">Email</A><BR> |
<A HREF="/">Link to Home Page</A> |
<P> |
</body> |
</html> |
/branches/upstream/4.2.1/debian/control |
---|
0,0 → 1,18 |
Source: sa-exim |
Section: mail |
Priority: optional |
Maintainer: Sander Smeenk <ssmeenk@debian.org> |
Build-Depends: lynx, debhelper (>= 4.1.16) |
Standards-Version: 3.5.10 |
Package: sa-exim |
Architecture: any |
Depends: exim4-daemon-light (>>4.30-1) | exim4-daemon-heavy (>>4.30-1) | exim4-daemon-custom (>>4.30-1), spamc, ${shlibs:Depends}, debconf (>= 1.2.0) | debconf-2.0 |
Suggests: spamassassin (<< 2.30-2) |
Description: Use spamAssassin at SMTP time with the Exim v4 MTA |
SA-Exim lets you use spamAssassin at SMTP time with the Exim |
v4 MTA, which enables you to do many things with incoming Emails, |
including refusing them before they come in, or even teergrubing the |
sender (i.e. slowing him down, by tying his resources) |
. |
Homepage: http://marc.merlins.org/linux/exim/sa.html |
/branches/upstream/4.2.1/debian/dirs |
---|
0,0 → 1,6 |
usr/lib/exim4/local_scan |
usr/share/doc/sa-exim/patches |
etc/exim4/conf.d/main |
usr/share/perl5/Mail/SpamAssassin/Plugin |
etc/cron.d |
usr/sbin |
/branches/upstream/4.2.1/debian/15_sa-exim_plugin_path |
---|
0,0 → 1,9 |
# This will enable sa-exim, but it won't actually scan and possibly reject |
# messsages before you enable this in sa-exim.conf (see SAEximRunCond) |
# |
# For a starter, you'd probably want to read the documentation at: |
# /usr/share/doc/sa-exim/README.Debian |
# and |
# /usr/share/doc/sa-exim/README.gz |
# |
local_scan_path = /usr/lib/exim4/local_scan/sa-exim.so |
/branches/upstream/4.2.1/debian/compat |
---|
0,0 → 1,0 |
4 |
/branches/upstream/4.2.1/debian/postinst |
---|
0,0 → 1,47 |
#!/bin/sh |
set -e |
. /usr/share/debconf/confmodule |
LOCALSCANCONF=/etc/exim4/conf.d/main/15_sa-exim_plugin_path |
DISABLELOCALSCANTEXT='# sa-exim plugin is disabled, because it was uninstalled' |
DISABLELOCALSCANMD5=`echo "${DISABLELOCALSCANTEXT}" | md5sum | cut -d\ -f1` |
OLDCRONJOB=/etc/cron.hourly/greylistclean |
OLDCRONJOBREN=/etc/cron.hourly/.greylistclean.insecure.deleteme |
if test -f $OLDCRONJOB; then |
echo "disabling old insecure $OLDCRONJOB" |
echo "(renamed to $OLDCRONJOBREN)" |
echo "See new cronjob in /etc/cron.d/greylistclean" |
/bin/mv $OLDCRONJOB $OLDCRONJOBREN |
fi |
case "$1" in |
configure) |
if [ ! -e /var/spool/sa-exim ] ; then |
# Debian-exim should exist as we depend on exim4-base |
install -d -m770 -oDebian-exim -gDebian-exim \ |
/var/spool/sa-exim |
fi |
# Support for greylisting tuplets (written as nobody by spamd) |
if [ ! -e /var/spool/sa-exim/tuplets ] ; then |
install -d -m750 -onobody -gDebian-exim \ |
/var/spool/sa-exim/tuplets |
fi |
# clean up temporary file generated by postrm uninstall |
if [ -e "${LOCALSCANCONF}.rul" ] && \ |
[ "`md5sum ${LOCALSCANCONF}.rul | cut -d\ -f1`" = "${DISABLELOCALSCANMD5}" ]; then |
rm ${LOCALSCANCONF}.rul |
fi |
if [ -x /etc/init.d/exim4 ]; then |
if [ -x /usr/sbin/invoke-rc.d ]; then |
invoke-rc.d exim4 reload || true |
else |
/etc/init.d/exim4 reload || true |
fi |
fi |
;; |
esac |
#DEBHELPER# |
/branches/upstream/4.2.1/debian/postrm |
---|
0,0 → 1,51 |
#!/bin/sh |
set -e |
. /usr/share/debconf/confmodule |
LOCALSCANCONF=/etc/exim4/conf.d/main/15_sa-exim_plugin_path |
DISABLELOCALSCANTEXT='# sa-exim plugin is disabled, because it was uninstalled' |
DISABLELOCALSCANMD5=`echo "${DISABLELOCALSCANTEXT}" | md5sum | cut -d\ -f1` |
case "$1" in |
remove) |
# disable local_scan_path directive to exim working |
if [ -e "$LOCALSCANCONF" ] && [ ! -e "${LOCALSCANCONF}.rul" ]; then |
echo "${DISABLELOCALSCANTEXT}" > ${LOCALSCANCONF}.rul |
fi |
if [ -x /etc/init.d/exim4 ]; then |
if [ -x /usr/sbin/invoke-rc.d ]; then |
invoke-rc.d exim4 reload || true |
else |
/etc/init.d/exim4 reload || true |
fi |
fi |
;; |
purge) |
# clean up temporary file generated by postrm uninstall |
if [ -e "${LOCALSCANCONF}.rul" ] && \ |
[ "`md5sum ${LOCALSCANCONF}.rul | cut -d\ -f1`" = "${DISABLELOCALSCANMD5}" ]; then |
rm ${LOCALSCANCONF}.rul |
fi |
if [ -x /etc/init.d/exim4 ]; then |
if [ -x /usr/sbin/invoke-rc.d ]; then |
invoke-rc.d exim4 reload || true |
else |
/etc/init.d/exim4 reload || true |
fi |
fi |
if [ -e /var/spool/sa-exim ] && ! rmdir /var/spool/sa-exim 2>/dev/null ; then |
db_version 2.0 |
db_input medium sa-exim/purge_spool || true |
db_go || true |
db_get sa-exim/purge_spool |
purge_spool="$RET" |
if [ "x${purge_spool}" = "xtrue" ] ; then |
rm -rf /var/spool/sa-exim |
fi |
fi |
;; |
esac |
#DEBHELPER# |
/branches/upstream/4.2.1/debian/config |
---|
0,0 → 1,5 |
#!/bin/sh -e |
. /usr/share/debconf/confmodule |
exit 0 |
/branches/upstream/4.2.1/debian/changelog |
---|
0,0 → 1,151 |
sa-exim (4.2.1-1) unstable; urgency=high |
* SECURITY: new upstream does a better job at being safe when deleting |
greylisting tuplets |
* Disable former insecure /etc/cron.daily/greylistclean |
-- Marc MERLIN <marc_soft@merlins.org> Mon, 09 Jan 2006 09:01:25 -0800 |
sa-exim (4.2-1) unstable; urgency=high |
* New upstream version |
* Ship new SA-Exim Greylisting plugin for SA 3.0 or better |
* Ship new /etc/cron.daily/greylistclean |
* Updated README.Debian |
-- Marc MERLIN <marc_soft@merlins.org> Mon, 17 Dec 2005 00:14:03 -0800 |
sa-exim (4.1-1) unstable; urgency=high |
* New upstream version |
* SECURITY: new upstream provides SA greylisting patch with shell safe |
filenames and directories (only affected users who use the SA greylisting |
patch _and_ an unsafe shell cron job to delete old files and directories) |
* Updated README.debian to warn that the SA 2.4 greylisting patch is out |
of date and unmaintained. |
-- Marc MERLIN <marc_soft@merlins.org> Mon, 16 Aug 2004 08:32:36 -0700 |
sa-exim (4.0-3) unstable; urgency=low |
+ Changed hard depend on spamc, since that's all sa-exim needs. |
You have to choose to install spamassassin, or run spamc to |
another host. This entry closes: #253393 |
+ Documentation was assed to explain about sa-exim defaulting |
to exim4 configured to use exim4/use_split_config. Devine |
intervention is needed when using monolithic configs. One day |
sa-exim might detect this and act on it? |
This entry closes: #251755, #265820 |
+ Incorrect scoring of messages due to incorrect last-Received: |
header is now fixed by newer versions of the exim4 package. |
Dependencies have been changed. This entry closes: #250726, #246715 |
+ Updated Japanese translations of debconf templates. A typo in the |
english templates has been fixed too. This entry closes: #252341 |
-- Sander Smeenk <ssmeenk@debian.org> Wed, 15 Aug 2004 19:40:05 +0200 |
sa-exim (4.0-2) unstable; urgency=low |
* Clarified SA-greylisting patches in README.Debian |
Closes: #245573 |
+ Added Danish translations |
+ Added French translations |
Closes: #238537, #239258 |
-- Sander Smeenk <ssmeenk@debian.org> Sat, 24 Apr 2004 11:34:35 +0200 |
sa-exim (4.0-1) unstable; urgency=low |
* New upstream version |
* Added new docs (README.greylisting / SA patches) |
* Create /var/spool/sa-exim/tuplets for the new greylisting support |
-- Marc MERLIN <marc_soft@merlins.org> Tue, 03 Mar 2004 08:52:49 -0800 |
sa-exim (3.1-4) unstable; urgency=low |
* Fixed minor packaging bugs. |
* Debconf gettextized for translators (Closes: #237105) |
-- Sander Smeenk <ssmeenk@debian.org> Sun, 07 Mar 2004 15:38:47 +0100 |
sa-exim (3.1-3) unstable; urgency=low |
* Clean up properly on purge, asking per debconf about removing saved mails |
in spool-directory if necessary. |
* Update to work with exim4 running as Debian-exim (don't include |
/var/spool/sa-exim in deb, generate it in postinst; stricter |
dependencies). |
* sa-exim uses spamc - Correct depends accordingly. |
-- Sander Smeenk <ssmeenk@debian.org> Sun, 22 Feb 2004 10:32:03 +0100 |
sa-exim (3.1-2) unstable; urgency=low |
* Minor updates to control suggested by Andreas Metzler |
* Minor updates on upstream source (INSTALL / sa-exim.conf) |
* Uploaded to Debian (Closes: #196100) |
-- Marc MERLIN <marc_soft@merlins.org> Wed, 20 Aug 2003 09:18:42 -0700 |
sa-exim (3.1-1) unstable; urgency=low |
* Upstream update |
-- Marc MERLIN <marc_soft@merlins.org> Tue, 19 Aug 2003 09:48:13 -0700 |
sa-exim (3.0+cvs-20030802) unstable; urgency=low |
* Updated sa-exim to cvs version |
* Restored plugin location to /usr/lib/exim4/local_scan/ |
* Added contrib contents to docs |
-- Marc MERLIN <marc_soft@merlins.org> Sat, 02 Aug 2003 20:57:50 -0700 |
sa-exim (3.0+cvs-20030728) unstable; urgency=low |
* Updated sa-exim to cvs version |
-- Marc MERLIN <marc_soft@merlins.org> Mon, 28 Jul 2003 21:08:24 -0500 |
sa-exim (3.0+cvs-1) unstable; urgency=low |
* Updated sa-exim to cvs version (and new sa-exim.conf config file) |
-- Marc MERLIN <marc_soft@merlins.org> Mon, 08 Jun 2003 23:19:11 -0700 |
sa-exim (3.0-3) unstable; urgency=low |
* Taken over from Andreas, thanks for the template |
* Rewrote description in control |
* Updated docs to contain all the documentation files |
* /var/spool/sa-exim will contain the saved mails and is 770/mail.mail |
* Do not patch sample sa-exim.conf, run sed during the install |
* Removed ${misc:Depends} from control, my dpkg-gencontrol says it's unknown |
* Fixes to debian/control, debian/rules and debian/copyright for policy |
compliance and to make lintian more happy. Increased Standards-Version to |
3.5.10. (Andreas Metzler) |
* Add some magic to maintainerscripts, disabling the sa-exim part of exim's |
main configuration file when sa-exim is uninstalled. (Andreas Metzler) |
-- Marc MERLIN <marc_soft@merlins.org> Mon, 26 May 2003 23:22:56 -0700 |
sa-exim (3.0-2) unstable; urgency=low |
* Small fixes |
-- Andreas Metzler <ametzler@debian.org> Fri, 2 May 2003 20:20:11 +0200 |
sa-exim (3.0-1) unstable; urgency=low |
* renamed package to sa-exim |
* upgrade to 3.0 |
-- Andreas Metzler <ametzler@debian.org> Fri, 2 May 2003 17:36:28 +0200 |
exim4-sa-plugin (2.2-1) unstable; urgency=low |
* Initial Release. |
-- Andreas Metzler <ametzler@debian.org> Thu, 13 Mar 2003 17:16:46 +0100 |
/branches/upstream/4.2.1/debian/copyright |
---|
0,0 → 1,30 |
This package was adopted by Sander Smeenk <ssmeenk@debian.org> |
Tue, 24 Feb 2004 19:47:11 +0100 |
This package was originally debianized by Andreas Metzler <ametzler@debian.org> on |
Thu, 13 Mar 2003 17:16:46 +0100. |
Current Debian maintainer: Marc MERLIN <marc_soft@merlins.org> |
Upstream Author: Marc MERLIN <marc_soft@merlins.org> |
It was downloaded from http://marc.merlins.org/linux/exim/sa.html |
Copyright: |
This package is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; version 2 dated June, 1991. |
This package is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this package; if not, write to the Free Software |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
02111-1307, USA. |
On Debian systems, the complete text of the GNU General |
Public License can be found in `/usr/share/common-licenses/GPL'. |
/branches/upstream/4.2.1/debian/docs |
---|
0,0 → 1,8 |
ACKNOWLEDGEMENTS |
Acknowledgements.html |
README |
README.greylisting |
sa.html |
TODO |
contrib/sa-exim-stats.txt |
contrib/spam_resend.txt |
/branches/upstream/4.2.1/debian/rules |
---|
0,0 → 1,98 |
#!/usr/bin/make -f |
# Sample debian/rules that uses debhelper. |
# GNU copyright 1997 to 1999 by Joey Hess. |
# Uncomment this to turn on verbose mode. |
#export DH_VERBOSE=1 |
CFLAGS = -Wall -g |
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) |
CFLAGS += -O0 |
else |
CFLAGS += -O2 |
endif |
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) |
INSTALL_PROGRAM += -s |
endif |
configure: configure-stamp |
configure-stamp: |
dh_testdir |
touch configure-stamp |
build: build-stamp |
build-stamp: configure-stamp |
dh_testdir |
$(MAKE) LDFLAGS="-shared -fPIC" |
touch build-stamp |
clean: |
dh_testdir |
dh_testroot |
rm -f build-stamp configure-stamp |
-$(MAKE) clean |
dh_clean |
install: build |
dh_testdir |
dh_testroot |
dh_clean -k |
dh_installdirs |
install -m755 sa-exim-*so \ |
$(CURDIR)/debian/sa-exim/usr/lib/exim4/local_scan/sa-exim.so |
install -m755 accept*so \ |
$(CURDIR)/debian/sa-exim/usr/lib/exim4/local_scan/accept.so |
sed "s/\/var\/spool\/exim/\/var\/spool\/sa-exim/" < sa-exim.conf > \ |
$(CURDIR)/debian/sa-exim/etc/exim4/sa-exim.conf |
chmod 644 $(CURDIR)/debian/sa-exim/etc/exim4/sa-exim.conf |
install -m644 debian/15_sa-exim_plugin_path \ |
$(CURDIR)/debian/sa-exim/etc/exim4/conf.d/main |
install -m644 SA-greylisting-2.4x.diff \ |
$(CURDIR)/debian/sa-exim/usr/share/doc/sa-exim/sa2.xpatches |
install -m644 SA-greylisting-2.6.diff \ |
$(CURDIR)/debian/sa-exim/usr/share/doc/sa-exim/sa2.xpatches |
install -m644 Greylisting.pm \ |
$(CURDIR)/debian/sa-exim/usr/share/perl5/Mail/SpamAssassin/Plugin/Greylisting.pm |
install -m644 greylistclean.cron \ |
$(CURDIR)/debian/sa-exim/etc/cron.d/greylistclean |
install -m755 greylistclean \ |
$(CURDIR)/debian/sa-exim/usr/sbin/greylistclean |
# Build architecture-independent files here. |
binary-indep: build install |
# We have nothing to do by default. |
# Build architecture-dependent files here. |
binary-arch: build install |
dh_testdir |
dh_testroot |
dh_installchangelogs Changelog.html |
dh_installdocs |
dh_installexamples |
# dh_install |
# dh_installmenu |
dh_installdebconf |
# dh_installlogrotate |
# dh_installemacsen |
# dh_installpam |
# dh_installmime |
# dh_installinit |
# dh_installcron |
# dh_installinfo |
dh_installman |
dh_link |
dh_strip |
dh_compress |
dh_fixperms -Xvar/spool/sa-exim |
# dh_perl |
# dh_python |
# dh_makeshlibs |
dh_installdeb |
dh_shlibdeps |
dh_gencontrol |
dh_md5sums |
dh_builddeb |
binary: binary-indep binary-arch |
.PHONY: build clean binary-indep binary-arch binary install configure |
Property changes: |
Added: svn:executable |
Index: branches/upstream/4.2.1/debian/README.Debian |
=================================================================== |
--- branches/upstream/4.2.1/debian/README.Debian (nonexistent) |
+++ branches/upstream/4.2.1/debian/README.Debian (revision 2) |
@@ -0,0 +1,107 @@ |
+***************** |
+* CONFIGURATION * |
+***************** |
+ |
+This version of the sa-exim package defaults to placing a configuration |
+sniplet in /etc/exim4/conf.d/. Depending on what you have answered to the |
+DebConf questions while configuring Exim4, the module will be loaded |
+automatically, or human intervention is required. |
+ |
+To find out what configurationfile Exim4 is using, issue: |
+ |
+ $ exim4 -bV | tail -1 |
+ Configuration file is /path/to/configfile |
+ |
+If /path/to/configfile shows: |
+ |
+ - /etc/exim4/exim4.conf |
+ You are using the 'monolithic' configuration file. |
+ See the 'MONOLITHIC' section below. |
+ |
+ - /var/lib/exim4/config.autogenerated |
+ You are using the 'split' configuration file. |
+ See the 'SPLIT' section below. |
+ |
+ |
+MONOLITHIC |
+---------- |
+ |
+Use 'grep "local_scan_path" /etc/exim4/exim4.conf" to see if the sa-exim |
+line is included in the configuration. If grep returns something, check |
+if it matches the following line. If grep returns nothing, you have to |
+manually add the following line to the exim4.conf file and restart exim4. |
+ |
+ local_scan_path = /usr/lib/exim4/local_scan/sa-exim.so |
+ |
+Change or add the line above and manually restart exim4 by issuing |
+'invoke-rc.d exim4 restart' or '/etc/init.d/exim4 restart' as root. |
+ |
+ |
+SPLIT |
+----- |
+ |
+Use 'grep "local_scan_path" /var/lib/exim4/config.autogenerated' to see |
+if the sa-exim line is included in the configuration. If grep returns |
+something, you're set and already using the sa-exim module. If grep |
+returns nothing, we need to figure out a few things: |
+ |
+Issue: |
+ $ grep "use_split_config" /etc/exim4/update-exim4.conf.conf |
+ dc_use_split_config='true' |
+ |
+If your result shows 'false' where mine shows 'true', but the check |
+earlier showed that you *are* in fact using the split configuration, |
+then you have to edit /etc/exim4/update-exim4.conf.conf by hand and |
+change the 'false' to 'true' and issue 'update-exim4.conf' as root. |
+Next, check again if the sa-exim module-line is included. It should. |
+If it still isn't: mail me. If it is, restart exim4 by issuing |
+'invoke-rc.d exim4 restart' or '/etc/init.d/exim4 restart' as root. |
+ |
+Next, read all about greylisting and sa-exim: |
+ |
+*************** |
+* GREYLISTING * |
+*************** |
+Notes on greylisting with sa-exim. |
+ |
+If you use SpamAssassin 3.0 or better, you do not need to patch it, you |
+can just use the Greylisting module shipped with sa-exim. |
+The only thing you need to do to enable it, is to copy the 4 lines below |
+loadplugin in the greylisting README, and adjust the score if you wish (see |
+README.Greylisting for details) |
+ |
+ |
+If you use a version of SA older than 3.0, you will need to patch |
+spamassassin's sources to support greylisting. |
+ |
+There are two versions of the patches: |
+ - /usr/share/doc/sa-exim/patches/SA-greylisting-2.4x.diff |
+ This patch can be applied to versions 2.4x of SpamAssassin. Note |
+ that this patch is not fully functional anymore, it is just left as |
+ a template should you want to backport the current 2.6x patch. |
+ That said, you really ought to upgrade SA to 2.6x or 3.x |
+ |
+ - /usr/share/doc/sa-exim/patches/SA-greylisting-2.6.diff |
+ This patch can be applied to versions 2.6x of SpamAssassin. |
+ |
+Please read README.Greylisting for more information on how to enable |
+this feature, and what further changes are needed. |
+Note that this configuration won't be supported in the future, and you |
+are encouraged to upgrade to SA 3.0 or better. |
+ |
+************* |
+* BE WARNED * |
+************* |
+ |
+By applying these patches, you change the sourcecode of SpamAssassin |
+(again, this is if you use a version of SpamAssassin earlier than 3.0) |
+This also means that when the SpamAssassin package gets upgraded, the |
+changes made by the patch are LOST. |
+This *MIGHT* cause your mail setup to break. It might be best to put |
+SpamAssassin on hold: |
+ |
+ $ echo "spamassassin hold" | dpkg --set-selections |
+ |
+You can later set it to install again with: |
+ |
+ $ echo "spamassassin install" | dpkg --set-selections |
Index: branches/upstream/4.2.1/debian/po/templates.pot |
=================================================================== |
--- branches/upstream/4.2.1/debian/po/templates.pot (nonexistent) |
+++ branches/upstream/4.2.1/debian/po/templates.pot (revision 2) |
@@ -0,0 +1,55 @@ |
+# |
+# Translators, if you are not familiar with the PO format, gettext |
+# documentation is worth reading, especially sections dedicated to |
+# this format, e.g. by running: |
+# info -n '(gettext)PO Files' |
+# info -n '(gettext)Header Entry' |
+# |
+# Some information specific to po-debconf are available at |
+# /usr/share/doc/po-debconf/README-trans |
+# or http://www.debian.org/intl/l10n/po-debconf/README-trans |
+# |
+# Developers do not need to manually edit POT or PO files. |
+# |
+#, fuzzy |
+msgid "" |
+msgstr "" |
+"Project-Id-Version: PACKAGE VERSION\n" |
+"Report-Msgid-Bugs-To: \n" |
+"POT-Creation-Date: 2004-08-15 14:44+0200\n" |
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
+"Language-Team: LANGUAGE <LL@li.org>\n" |
+"MIME-Version: 1.0\n" |
+"Content-Type: text/plain; charset=CHARSET\n" |
+"Content-Transfer-Encoding: 8bit\n" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "Remove saved mails in spool directory?" |
+msgstr "" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "" |
+"There are some saved mails in subdirectories of /var/spool/sa-exim. " |
+"Depending on the configuration sa-exim will save mails matching specific " |
+"criterias (an error occured, rejected as spam, passed through although " |
+"recognized as spam, ...) in subdirectories of /var/spool/sa-exim." |
+msgstr "" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "" |
+"You can keep them for further analysis and later remove them manually or " |
+"decide to delete them now." |
+msgstr "" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "Should they be removed?" |
+msgstr "" |
Index: branches/upstream/4.2.1/debian/po/da.po |
=================================================================== |
--- branches/upstream/4.2.1/debian/po/da.po (nonexistent) |
+++ branches/upstream/4.2.1/debian/po/da.po (revision 2) |
@@ -0,0 +1,64 @@ |
+# translation of sa-exim_3.1-4-da.po to Danish |
+# translation of sa-exim_3.1-4_templates.po to Danish |
+# |
+# Translators, if you are not familiar with the PO format, gettext |
+# documentation is worth reading, especially sections dedicated to |
+# this format, e.g. by running: |
+# info -n '(gettext)PO Files' |
+# info -n '(gettext)Header Entry' |
+# Some information specific to po-debconf are available at |
+# /usr/share/doc/po-debconf/README-trans |
+# or http://www.debian.org/intl/l10n/po-debconf/README-trans# |
+# Developers do not need to manually edit POT or PO files. |
+# Claus Hindsgaul <claus_h@image.dk>, 2004. |
+# |
+msgid "" |
+msgstr "" |
+"Project-Id-Version: sa-exim_3.1-4-da\n" |
+"Report-Msgid-Bugs-To: \n" |
+"POT-Creation-Date: 2004-08-15 14:44+0200\n" |
+"PO-Revision-Date: 2004-03-17 15:55+0100\n" |
+"Last-Translator: Claus Hindsgaul <claus_h@image.dk>\n" |
+"Language-Team: Danish <dansk@klid.dk>\n" |
+"MIME-Version: 1.0\n" |
+"Content-Type: text/plain; charset=ISO-8859-1\n" |
+"Content-Transfer-Encoding: 8bit\n" |
+"X-Generator: KBabel 1.3.1\n" |
+"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "Remove saved mails in spool directory?" |
+msgstr "Fjern gemte breve fra spool-mappen?" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+#, fuzzy |
+msgid "" |
+"There are some saved mails in subdirectories of /var/spool/sa-exim. " |
+"Depending on the configuration sa-exim will save mails matching specific " |
+"criterias (an error occured, rejected as spam, passed through although " |
+"recognized as spam, ...) in subdirectories of /var/spool/sa-exim." |
+msgstr "" |
+"Der er nogle gemte breve i mapperne under /var/spool/sa-exim. Afhængig af " |
+"opsætningen vil sa-exim under bestemte omstændigheder (der opstod en fejl, " |
+"afvist som spam, lod brevet passere på trods af at det blev genkendt som " |
+"spam,...) gemme breve i mapperne under /var/spool/sa-exim." |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "" |
+"You can keep them for further analysis and later remove them manually or " |
+"decide to delete them now." |
+msgstr "" |
+"Du kan beholde dem til yderligere efterforskning og selv fjerne dem senere " |
+"eller vælge at få dem slettet nu." |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "Should they be removed?" |
+msgstr "Skal de slettes?" |
Index: branches/upstream/4.2.1/debian/po/fr.po |
=================================================================== |
--- branches/upstream/4.2.1/debian/po/fr.po (nonexistent) |
+++ branches/upstream/4.2.1/debian/po/fr.po (revision 2) |
@@ -0,0 +1,62 @@ |
+# |
+# Translators, if you are not familiar with the PO format, gettext |
+# documentation is worth reading, especially sections dedicated to |
+# this format, e.g. by running: |
+# info -n '(gettext)PO Files' |
+# info -n '(gettext)Header Entry' |
+# |
+# Some information specific to po-debconf are available at |
+# /usr/share/doc/po-debconf/README-trans |
+# or http://www.debian.org/intl/l10n/po-debconf/README-trans |
+# |
+# Developers do not need to manually edit POT or PO files. |
+# |
+msgid "" |
+msgstr "" |
+"Project-Id-Version: sa-exim\n" |
+"Report-Msgid-Bugs-To: \n" |
+"POT-Creation-Date: 2004-08-15 14:44+0200\n" |
+"PO-Revision-Date: 2004-03-12 22:00+0100\n" |
+"Last-Translator: Eric Madesclair <eric-m@wanadoo.fr>\n" |
+"Language-Team: French <debian-l10n-french@lists.debian.org>\n" |
+"MIME-Version: 1.0\n" |
+"Content-Type: text/plain; charset=ISO-8859-1\n" |
+"Content-Transfer-Encoding: 8bit\n" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "Remove saved mails in spool directory?" |
+msgstr "Faut-il supprimer les courriers du répertoire de dépôt ? " |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+#, fuzzy |
+msgid "" |
+"There are some saved mails in subdirectories of /var/spool/sa-exim. " |
+"Depending on the configuration sa-exim will save mails matching specific " |
+"criterias (an error occured, rejected as spam, passed through although " |
+"recognized as spam, ...) in subdirectories of /var/spool/sa-exim." |
+msgstr "" |
+"Il y a plusieurs courriers sauvegardés dans les sous-répertoires de /var/" |
+"spool/sa-exim. Selon la configuration, sa-exim sauvegarde les courriers " |
+"quicorrespondent à des critères spécifiques (p. ex. une erreur est survenue, " |
+"rejeté comme spam, passé à travers, reconnu comme spam ...) dans des sous-" |
+"répertoires de /var/spool/sa-exim." |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "" |
+"You can keep them for further analysis and later remove them manually or " |
+"decide to delete them now." |
+msgstr "" |
+"Vous pouvez les garder pour des analyses approfondies et les supprimer par " |
+"la suite ou vous pouvez décider de les effacer maintenant." |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "Should they be removed?" |
+msgstr "Vous pouvez les supprimer maintenant." |
Index: branches/upstream/4.2.1/debian/po/ja.po |
=================================================================== |
--- branches/upstream/4.2.1/debian/po/ja.po (nonexistent) |
+++ branches/upstream/4.2.1/debian/po/ja.po (revision 2) |
@@ -0,0 +1,61 @@ |
+# |
+# Translators, if you are not familiar with the PO format, gettext |
+# documentation is worth reading, especially sections dedicated to |
+# this format, e.g. by running: |
+# info -n '(gettext)PO Files' |
+# info -n '(gettext)Header Entry' |
+# |
+# Some information specific to po-debconf are available at |
+# /usr/share/doc/po-debconf/README-trans |
+# or http://www.debian.org/intl/l10n/po-debconf/README-trans |
+# |
+# Developers do not need to manually edit POT or PO files. |
+# |
+# |
+msgid "" |
+msgstr "" |
+"Project-Id-Version: sa-exim 4.0-2\n" |
+"Report-Msgid-Bugs-To: \n" |
+"POT-Creation-Date: 2004-08-15 14:44+0200\n" |
+"PO-Revision-Date: 2004-06-03 00:02+0900\n" |
+"Last-Translator: Hideki Yamane <henrich@samba.gr.jp>\n" |
+"Language-Team: Japanese <debian-japanese@lists.debian.org>\n" |
+"MIME-Version: 1.0\n" |
+"Content-Type: text/plain; charset=EUC-JP\n" |
+"Content-Transfer-Encoding: 8bit\n" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "Remove saved mails in spool directory?" |
+msgstr "¥¹¥×¡¼¥ë¥Ç¥£¥ì¥¯¥È¥ê¤ËÊݸ¤·¤¿¥á¡¼¥ë¤òºï½ü¤·¤Þ¤¹¤«?" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+#, fuzzy |
+msgid "" |
+"There are some saved mails in subdirectories of /var/spool/sa-exim. " |
+"Depending on the configuration sa-exim will save mails matching specific " |
+"criterias (an error occured, rejected as spam, passed through although " |
+"recognized as spam, ...) in subdirectories of /var/spool/sa-exim." |
+msgstr "" |
+"/var/spool/sa-exim ¤Î²¼¤ËÊݸ¤µ¤ì¤¿¥á¡¼¥ë¤¬¤¢¤ê¤Þ¤¹¡£sa-exim ¤ÎÀßÄê¤Ë¤è¤Ã¤Æ¡¢" |
+"sa-exim ¤ÏÆÃÄê¤Î¹àÌÜ (¥¨¥é¡¼¤¬µ¯¤¤¿¡¢spam¤È¤·¤ÆµñÈݤµ¤ì¤¿¡¢spam ¤Èǧ¼±¤µ¤ì¤¿" |
+"¤Ë¤â´Ø¤ï¤é¤ºÄ̤êÈ´¤±¤¿¡¢¤Ê¤É...) ¤Ë¥Þ¥Ã¥Á¤·¤¿¥á¡¼¥ë¤ò /var/spool/sa-exim ¤Î²¼" |
+"¤ËÊݸ¤·¤Þ¤¹¡£" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "" |
+"You can keep them for further analysis and later remove them manually or " |
+"decide to delete them now." |
+msgstr "" |
+"ʬÀϤΤ¿¤á¤Ë»Ä¤·¤Æ¸å¤Ë¼êÆ°¤Çºï½ü¤¹¤ë¤«¡¢º£¤¹¤°ºï½ü¤¹¤ë¤«¤ò·è¤á¤é¤ì¤Þ¤¹¡£" |
+ |
+#. Type: boolean |
+#. Description |
+#: ../templates:4 |
+msgid "Should they be removed?" |
+msgstr "ºï½ü¤·¤Þ¤¹¤«?" |
Index: branches/upstream/4.2.1/debian/po/POTFILES.in |
=================================================================== |
--- branches/upstream/4.2.1/debian/po/POTFILES.in (nonexistent) |
+++ branches/upstream/4.2.1/debian/po/POTFILES.in (revision 2) |
@@ -0,0 +1 @@ |
+[type: gettext/rfc822deb] templates |
Index: branches/upstream/4.2.1/debian/templates |
=================================================================== |
--- branches/upstream/4.2.1/debian/templates (nonexistent) |
+++ branches/upstream/4.2.1/debian/templates (revision 2) |
@@ -0,0 +1,13 @@ |
+Template: sa-exim/purge_spool |
+Type: boolean |
+Default: false |
+_Description: Remove saved mails in spool directory? |
+ There are some saved mails in subdirectories of /var/spool/sa-exim. |
+ Depending on the configuration sa-exim will save mails matching specific |
+ criterias (an error occured, rejected as spam, passed through although |
+ recognized as spam, ...) in subdirectories of /var/spool/sa-exim. |
+ . |
+ You can keep them for further analysis and later remove them manually or |
+ decide to delete them now. |
+ . |
+ Should they be removed? |
Index: branches/upstream/4.2.1/LICENSE |
=================================================================== |
--- branches/upstream/4.2.1/LICENSE (nonexistent) |
+++ branches/upstream/4.2.1/LICENSE (revision 2) |
@@ -0,0 +1 @@ |
+GPL version 2.0 ('nuff said :-D) |
Index: branches/upstream/4.2.1/sa-exim.c |
=================================================================== |
--- branches/upstream/4.2.1/sa-exim.c (nonexistent) |
+++ branches/upstream/4.2.1/sa-exim.c (revision 2) |
@@ -0,0 +1,1514 @@ |
+/* Spamassassin in local_scan by Marc MERLIN <marc_soft@merlins.org> */ |
+/* $Id: sa-exim.c,v 1.71 2005/03/08 20:39:51 marcmerlin Exp $ */ |
+/* |
+ |
+The inline comments and minidocs were moved to the distribution tarball |
+ |
+You can get the up to date version of this file and full tarball here: |
+http://sa-exim.sourceforge.net/ |
+http://marc.merlins.org/linux/exim/sa.html |
+The discussion list is here: |
+http://lists.merlins.org/lists/listinfo/sa-exim |
+*/ |
+ |
+ |
+ |
+#include <stdio.h> |
+#include <unistd.h> |
+#include <fcntl.h> |
+#include <errno.h> |
+#include <string.h> |
+#include <stdlib.h> |
+#include <time.h> |
+#include <ctype.h> |
+#include <signal.h> |
+#include <setjmp.h> |
+#include <sys/wait.h> |
+#include <sys/types.h> |
+#include <sys/stat.h> |
+#include "sa-exim.h" |
+ |
+/* Exim includes */ |
+#include "local_scan.h" |
+extern FILE *smtp_out; /* Exim's incoming SMTP output file */ |
+extern int body_linecount; /* Line count in body */ |
+extern uschar *primary_hostname; |
+ |
+#ifdef DLOPEN_LOCAL_SCAN |
+ |
+/* Karsten Engelke <me@kaeng.org> says this is missing on openbsd */ |
+#ifndef RTLD_NOW |
+#define RTLD_NOW 0x002 |
+#endif |
+ |
+/* Return the verion of the local_scan ABI, if being compiled as a .so */ |
+int local_scan_version_major(void) |
+{ |
+ return LOCAL_SCAN_ABI_VERSION_MAJOR; |
+} |
+ |
+int local_scan_version_minor(void) |
+{ |
+ return LOCAL_SCAN_ABI_VERSION_MINOR; |
+} |
+ |
+/* Left over for compatilibility with old patched exims that didn't have |
+ a version number with minor an major. Keep in mind that it will not work |
+ with older exim4s (I think 4.11 is required) */ |
+#ifdef DLOPEN_LOCAL_SCAN_OLD_API |
+int local_scan_version(void) |
+{ |
+ return 1; |
+} |
+#endif |
+#endif |
+ |
+#ifndef SAFEMESGIDCHARS |
+#define SAFEMESGIDCHARS "!#%( )*+,-.0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~"; |
+#endif |
+ |
+ |
+/******************************/ |
+/* Compile time config values */ |
+/******************************/ |
+#ifndef SPAMC_LOCATION |
+#define SPAMC_LOCATION "/usr/bin/spamc" |
+#endif |
+ |
+#ifndef SPAMASSASSIN_CONF |
+#define SPAMASSASSIN_CONF "/etc/exim4/sa-exim.conf" |
+#endif |
+static const char conffile[]=SPAMASSASSIN_CONF; |
+ |
+ |
+/********************/ |
+/* Code starts here */ |
+/********************/ |
+static const char nospamstatus[]="<error finding status>"; |
+ |
+static char *buffera[4096]; |
+static char *buffer=(char *)buffera; |
+static int SAEximDebug=0; |
+static int SAPrependArchiveWithFrom=1; |
+static jmp_buf jmp_env; |
+ |
+static char *where="Error handler called without error string"; |
+static int line=-1; |
+static char *panicerror; |
+ |
+#define MIN(a,b) (a<b?a:b) |
+ |
+#define CHECKERR(mret, mwhere, mline) \ |
+ if (mret < 0) \ |
+ { \ |
+ where=mwhere; \ |
+ line=mline; \ |
+ goto errexit; \ |
+ } |
+ |
+#define PANIC(merror) \ |
+ panicerror=merror; \ |
+ goto panicexit; |
+ |
+ |
+static void alarm_handler(int sig) |
+{ |
+ sig = sig; /* Keep picky compilers happy */ |
+ longjmp(jmp_env, 1); |
+} |
+ |
+ |
+/* Comparing header lines isn't fun, especially since the comparison has to |
+ be caseless, so we offload this to this function |
+ You can scan on partial headers, just give the root to scan for |
+ Return 1 if the header was found, 0 otherwise */ |
+static int compare_header(char *buffertocompare, char *referenceheader) |
+{ |
+ int idx; |
+ int same=1; |
+ |
+ for (idx=0; idx<strlen(referenceheader); idx++) |
+ { |
+ if ( tolower(referenceheader[idx]) != tolower(buffertocompare[idx]) ) |
+ { |
+ same=0; |
+ break; |
+ } |
+ } |
+ |
+ if (SAEximDebug > 7) |
+ { |
+ if (same) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug8: Found %s in %s", referenceheader, buffertocompare); |
+ } |
+ else if (SAEximDebug > 8) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug9: Did not find %s in %s", referenceheader, buffertocompare); |
+ } |
+ } |
+ |
+ return same; |
+} |
+ |
+ |
+/* returns a header from a buffer line */ |
+static char *get_header(char *buffer) |
+{ |
+ char *start; |
+ char *end; |
+ char *header; |
+ |
+ start=buffer; |
+ end=strstr(buffer, ":"); |
+ |
+ header=string_copyn(start, end-start); |
+ |
+ if (SAEximDebug>5) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug6: Extracted header %s in buffer %s", header, buffer); |
+ } |
+ |
+ return header; |
+} |
+ |
+ |
+/* Rejected mails can be archived in a spool directory */ |
+/* filename will contain a double / before the filename, I prefer two to none */ |
+static int savemail(int readfd, off_t fdstart, char *dir, char *dirvarname, |
+ char *filename, int SAmaxarchivebody, char *condition) |
+{ |
+ header_line *hl; |
+ int writefd=0; |
+ int ret; |
+ ssize_t stret; |
+ off_t otret; |
+ char *expand; |
+ char *fake_env_from; |
+ int towrite; |
+ int chunk; |
+ struct stat bufst; |
+ |
+ if (dir == NULL) |
+ { |
+ if (SAEximDebug>4) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug5: Not saving message because %s in undefined", dirvarname); |
+ } |
+ return 0; |
+ } |
+ |
+ if (condition[0] != '1' || condition[1] != 0) |
+ { |
+ expand=expand_string(condition); |
+ if (expand == NULL) |
+ { |
+ /* Can't use PANIC within this function :( */ |
+ CHECKERR(-1, string_sprintf("savemail condition expansion failure on %s", condition), __LINE__ - 1); |
+ } |
+ |
+ if (SAEximDebug > 2) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug3: savemail condition expand returned: '%s'", expand); |
+ } |
+ |
+ if (expand[0] == 0 || (expand[0] == '0' && expand[1] == 0)) |
+ { |
+ if (SAEximDebug > 1) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug2: savemail condition expanded to false, not saving message to disk"); |
+ } |
+ return 0; |
+ } |
+ } |
+ |
+ if (SAEximDebug) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug: Writing message to %s/new/%s", dir, filename); |
+ |
+ } |
+ |
+ if (stat(string_sprintf("%s/new/", dir), &bufst) == -1) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Notice: creating maildir tree in %s", dir); |
+ if (stat(dir, &bufst) == -1) |
+ { |
+ ret=mkdir (dir, 0770); |
+ CHECKERR(ret,string_sprintf("mkdir %s", dir),__LINE__); |
+ } |
+ ret=mkdir (string_sprintf("%s/new", dir), 0770); |
+ CHECKERR(ret,string_sprintf("mkdir %s/new/", dir),__LINE__); |
+ ret=mkdir (string_sprintf("%s/cur", dir), 0770); |
+ CHECKERR(ret,string_sprintf("mkdir %s/cur/", dir),__LINE__); |
+ ret=mkdir (string_sprintf("%s/tmp", dir), 0770); |
+ CHECKERR(ret,string_sprintf("mkdir %s/tmp/", dir),__LINE__); |
+ } |
+ |
+ /* Let's not worry about you receiving two spams at the same second |
+ * with the same message ID. If you do, the second one will overwrite |
+ * the first one */ |
+ writefd=creat(string_sprintf("%s/new/%s", dir, filename), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); |
+ CHECKERR(writefd, string_sprintf("creat %s/new/%s", dir, filename),__LINE__); |
+ |
+ /* make the file look like a valid mbox -- idea from dman */ |
+ /* Although now that we use maildir format, this isn't really necessary */ |
+ /* Richard Lithvall made this an option */ |
+ if(SAPrependArchiveWithFrom == 1) |
+ { |
+ fake_env_from=string_sprintf("From %s Thu Jan 1 00:00:01 1970\n",sender_address); |
+ stret=write(writefd, fake_env_from, strlen(fake_env_from)); |
+ CHECKERR(stret,string_sprintf("'From ' line write in %s", filename),__LINE__); |
+ } |
+ |
+ /* First we need to get the header lines from exim, and then we can read |
+ the body from writefd */ |
+ hl=header_list; |
+ while (hl != NULL) |
+ { |
+ /* type '*' means the header is internal, don't print it */ |
+ if (hl->type == '*') |
+ { |
+ hl=hl->next; |
+ continue; |
+ } |
+ stret=write(writefd,hl->text,strlen(hl->text)); |
+ CHECKERR(stret,string_sprintf("header line write in %s", filename),__LINE__); |
+ hl=hl->next; |
+ } |
+ stret=write(writefd,"\n",1); |
+ CHECKERR(stret,string_sprintf("header separation write in %s", filename),__LINE__); |
+ |
+ /* Now copy the body to the save file */ |
+ /* we already read from readfd, so we need to reset it */ |
+ otret=lseek(readfd, fdstart, SEEK_SET); |
+ CHECKERR(otret, "lseek reset on spooled message", __LINE__); |
+ |
+ if (SAEximDebug > 8) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug9: Archive body write starts: writing up to %d bytes in %d byte blocks", SAmaxarchivebody, sizeof(buffera)); |
+ } |
+ |
+ towrite=SAmaxarchivebody; |
+ chunk=0; |
+ while (towrite>0 && (stret=read(readfd, buffer, MIN(sizeof(buffera), towrite))) > 0) |
+ { |
+ chunk++; |
+ if (SAEximDebug > 8) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug9: Processing archive body chunk %d (read %.0f, and %.0f can still be written)", chunk, (double)stret, (double)towrite); |
+ } |
+ towrite-=stret; |
+ stret=write(writefd, buffer, stret); |
+ CHECKERR(stret,string_sprintf("body write in %s", filename),__LINE__); |
+ } |
+ CHECKERR(stret, "read body for archival", __LINE__ - 8); |
+ ret=close(writefd); |
+ CHECKERR(ret, "Closing spooled message",__LINE__); |
+ return 0; |
+ |
+ /* catch the global errexit, clean up, and return the error up */ |
+ errexit: |
+ close(writefd); |
+ return -1; |
+} |
+ |
+/* |
+ * let's add the X-SA-Exim-Connect-IP, X-SA-Exim-Rcpt-To, and |
+ * X-SA-Exim-Mail-From headers. |
+ * Those are all required by the greylisting with SA implementation |
+ * And From/Rcpt-To can also be used for personalized SA rules |
+ */ |
+void AddSAEheaders(char *rcptlist, int SAmaxrcptlistlength) |
+{ |
+ if (sender_host_address) |
+ { |
+ header_add(' ', "X-SA-Exim-Connect-IP: %s\n", sender_host_address); |
+ } |
+ else |
+ { |
+ header_add(' ', "X-SA-Exim-Connect-IP: <locally generated>\n"); |
+ } |
+ |
+ /* Create a mega envelope-to header with all the recipients */ |
+ /* Note, if you consider this a privacy violation, you can remove the header |
+ * in exim's system filter. |
+ * This is very useful to see who a message was really sent to, and can |
+ * be used by Spamassassin to do additional scoring */ |
+ if (strlen(rcptlist) <= SAmaxrcptlistlength) |
+ { |
+ header_add(' ', "X-SA-Exim-Rcpt-To: %s\n", rcptlist); |
+ } |
+ /* Therefore SAmaxrcptlistlength set to 0 disables the header completely */ |
+ else if (SAmaxrcptlistlength) |
+ { |
+ header_add(' ', "X-SA-Exim-Rcpt-To: too long (recipient list exceeded maximum allowed size of %d bytes)\n", SAmaxrcptlistlength); |
+ } |
+ |
+ header_add(' ', "X-SA-Exim-Mail-From: %s\n", sender_address); |
+} |
+ |
+void RemoveHeaders(char *headername) |
+{ |
+ header_line *hl; |
+ |
+ /* Remove headers that SA can set */ |
+ hl=header_list; |
+ while (hl != NULL) |
+ { |
+ |
+ /* type '*' means the header is internal or deleted */ |
+ if (hl->type == '*') |
+ { |
+ hl=hl->next; |
+ continue; |
+ } |
+ |
+ /* Strip all SA and SA-Exim headers on incoming mail */ |
+ if ( compare_header((char *)hl->text, headername) ) |
+ { |
+ if (SAEximDebug > 2) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug3: removing header %s on incoming mail '%s'", headername, (char *)hl->text); |
+ } |
+ hl->type = '*'; |
+ } |
+ hl=hl->next; |
+ } |
+} |
+ |
+ |
+/* |
+ * Headers can be multi-line (in theory all of them can I think). Parsing them |
+ * is a little more work than a simple line scan, so we're off-loading this to |
+ * a function |
+ */ |
+int parsemlheader(char *buffer, FILE *readfh, char *headername, char **header) |
+{ |
+ header_line *hl; |
+ char *dummy; |
+ char *foundheadername; |
+ |
+ if (SAEximDebug > 4) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug5: looking for header %s", headername); |
+ } |
+ |
+ if (header == NULL) |
+ { |
+ header=&dummy; |
+ } |
+ |
+ if (compare_header(buffer, string_sprintf("%s", headername))) |
+ { |
+ *header=string_copy(buffer); |
+ |
+ /* Read the next line(s) in case this is a multi-line header */ |
+ while ((fgets((char *)buffer,sizeof(buffera),readfh)) != NULL) |
+ { |
+ /* Remove trailing newline */ |
+ if (buffer[strlen(buffer)-1] == '\n') |
+ { |
+ buffer[strlen(buffer)-1]=0; |
+ } |
+ if (SAEximDebug > 5) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug6: while parsing header %s, read %s", headername, buffer); |
+ } |
+ /* concatenated lines only start with space or tab. right? */ |
+ if (buffer[0] != ' ' && buffer[0] != '\t') |
+ { |
+ break; |
+ } |
+ |
+ /* Guard against humongous header lines */ |
+ if (strlen(*header) < 8000) |
+ { |
+ /* Slight waste of memory here, oh well... */ |
+ *header=string_sprintf("%s\n%s", *header, buffer); |
+ } |
+ else |
+ { |
+ log_write(0, LOG_MAIN, "SA: Warning: while parsing header %s, ignoring the following trailing line due to header size overflow: %s", headername, buffer); |
+ |
+ } |
+ } |
+ if (SAEximDebug > 5) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug6: header pieced up %s as: '%s'", headername, *header); |
+ } |
+ |
+ /* Headers need a newline at the end before being handed out to exim */ |
+ /* Slight waste of memory here, oh well... */ |
+ *header=string_sprintf("%s\n", *header); |
+ |
+ foundheadername=get_header(*header); |
+ |
+ /* Mark the former header as deleted if it's already present */ |
+ /* Note that for X-Spam, it won't since we already deleted it earlier */ |
+ hl=header_list; |
+ while (hl != NULL) |
+ { |
+ /* type '*' means the header is internal or deleted */ |
+ if (hl->type == '*') |
+ { |
+ hl=hl->next; |
+ continue; |
+ } |
+ |
+ if ( compare_header((char *)hl->text, foundheadername) ) |
+ { |
+ if (SAEximDebug > 5) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug6: removing old copy of header '%s' and replacing with new one: '%s'", (char *)hl->text, *header); |
+ } |
+ hl->type = '*'; |
+ break; |
+ } |
+ hl=hl->next; |
+ } |
+ |
+ header_add(' ', "%s", *header); |
+ return 1; |
+ } |
+ return 0; |
+} |
+ |
+ |
+char *cleanmsgid(char *msgid, char *SAsafemesgidchars) |
+{ |
+ char *safemesgid; |
+ char *ptr; |
+ |
+ /* In case the message-Id is too long, let's truncate it */ |
+ safemesgid=string_copyn(msgid, 220); |
+ ptr=safemesgid; |
+ |
+ /* Clean Message-ID to make sure people can't write on our FS */ |
+ while (*ptr) |
+ { |
+ /* This might be more aggressive than you want, but since you |
+ * potentially have shell programs dealing with the resulting filenames |
+ * let's make it a bit safer */ |
+ if (strchr(SAsafemesgidchars, *ptr) == NULL) |
+ { |
+ *ptr='_'; |
+ } |
+ ptr++; |
+ } |
+ |
+ if (SAEximDebug > 1) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug2: Message-Id taken from Exim and cleaned from: %s to: %s", msgid, safemesgid); |
+ } |
+ |
+ return safemesgid; |
+} |
+ |
+ |
+/* Exim calls us here, feeds us a fd on the message body, and expects a return |
+ message in *return_text */ |
+int local_scan(volatile int fd, uschar **return_text) |
+{ |
+#warning you should not worry about the "might be clobbered by longjmp", see source |
+ int ret; |
+ ssize_t stret; |
+ int pid; |
+ int writefd[2]; |
+ int readfd[2]; |
+ int i; |
+ /* These are the only values that we want working after the longjmp |
+ * The automatic ones can be clobbered, but we don't really care */ |
+ volatile FILE *readfh; |
+ volatile char *mesgfn=NULL; |
+ volatile off_t fdsize; |
+ volatile off_t scansize; |
+ volatile off_t fdstart; |
+ volatile char *rcptlist; |
+ volatile void *old_sigchld; |
+ char *safemesgid=NULL; |
+ int isspam=0; |
+ int gotsa=0; |
+ int chunk; |
+ off_t towrite; |
+ char *mailinfo; |
+ float spamvalue=0.0; |
+ char *spamstatus=NULL; |
+ time_t beforescan; |
+ time_t afterscan; |
+ time_t afterwait; |
+ time_t scantime=0; |
+ time_t fulltime=0; |
+ struct stat stbuf; |
+ |
+ uschar *expand; |
+ header_line *hl; |
+ |
+ static int readconffile=0; |
+ static int wrotedebugenabled=0; |
+ |
+ /* Options we read from /etc/exim4/sa-exim.conf */ |
+ static char *SAspamcpath=SPAMC_LOCATION; |
+ static char *SAsafemesgidchars=SAFEMESGIDCHARS |
+ static char *SAspamcSockPath=NULL; |
+ static char *SAspamcPort="783"; |
+ static char *SAspamcHost="127.0.0.1"; |
+ static char *SAEximRunCond="0"; |
+ static char *SAEximRejCond="1"; |
+ static int SAmaxbody=250*1024; |
+ static char *SATruncBodyCond="0"; |
+ static int SARewriteBody=0; |
+ static int SAmaxarchivebody=20*1048576; |
+ static int SAerrmaxarchivebody=1024*1048576; |
+ static int SAmaxrcptlistlength=0; |
+ static int SAaddSAEheaderBeforeSA=1; |
+ static int SAtimeout=240; |
+ static char *SAtimeoutsave=NULL; |
+ static char *SAtimeoutSavCond="1"; |
+ static char *SAerrorsave=NULL; |
+ static char *SAerrorSavCond="1"; |
+ static int SAtemprejectonerror=0; |
+ static char *SAteergrube="1048576"; |
+ static float SAteergrubethreshold; |
+ /* This is obsolete, since SAteergrube (now a condition) can do the same */ |
+ static char *SAteergrubecond="1"; |
+ static int SAteergrubetime=900; |
+ static char *SAteergrubeSavCond="1"; |
+ static char *SAteergrubesave=NULL; |
+ static int SAteergrubeoverwrite=1; |
+ static char *SAdevnull="1048576"; |
+ static float SAdevnullthreshold; |
+ static char *SAdevnullSavCond="1"; |
+ static char *SAdevnullsave=NULL; |
+ static char *SApermreject="1048576"; |
+ static float SApermrejectthreshold; |
+ static char *SApermrejectSavCond="1"; |
+ static char *SApermrejectsave=NULL; |
+ static char *SAtempreject="1048576"; |
+ static float SAtemprejectthreshold; |
+ static char *SAtemprejectSavCond="1"; |
+ static char *SAtemprejectsave=NULL; |
+ static int SAtemprejectoverwrite=1; |
+ static char *SAgreylistiswhitestr="GREYLIST_ISWHITE"; |
+ static float SAgreylistraisetempreject=3.0; |
+ static char *SAspamacceptsave=NULL; |
+ static char *SAspamacceptSavCond="0"; |
+ static char *SAnotspamsave=NULL; |
+ static char *SAnotspamSavCond="0"; |
+ /* Those variables can take a %s to show the spam info */ |
+ static char *SAmsgteergrubewait="wait for more output"; |
+ static char *SAmsgteergruberej="Please try again later"; |
+ static char *SAmsgpermrej="Rejected"; |
+ static char *SAmsgtemprej="Please try again later"; |
+ /* Do not put a %s in there, or you'll segfault */ |
+ static char *SAmsgerror="Temporary local error while processing message, please contact postmaster"; |
+ |
+ /* New values we read from spamassassin */ |
+ char *xspamstatus=NULL; |
+ char *xspamflag=NULL; |
+ |
+ |
+ /* Any error can write the faulty message to mesgfn, so we need to |
+ give it a value right now. We'll set the real value later */ |
+ /* message_id here comes from Exim, it's an internal disk Mesg-Id format |
+ which doesn't correlate to the actual message's Mesg-Id. We shouldn't |
+ need to clean it, and besides, SAsafemesgidchars hasn't been read from |
+ the config file yet, but eh, safety is always a good thing, right? */ |
+ safemesgid=cleanmsgid(message_id, SAsafemesgidchars); |
+ mesgfn=string_sprintf("%d_%s", time(NULL), safemesgid); |
+ |
+ /* We won't scan local messages. I think exim bypasses local_scan for a |
+ * bounce generated after a locally submitted message, but better be safe */ |
+ /* This is commented out now, because you can control it with SAEximRunCond |
+ if (!sender_host_address) |
+ { |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+ */ |
+ |
+ /* If you discard a mail with exim ACLs, we get 0 recipients, so let's just |
+ * accept the mail, which won't matter either way since it'll get dropped |
+ * (thanks to John Horne for reporting this corner case) */ |
+ if (recipients_count == 0) |
+ { |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+ |
+ /* |
+ * We keep track of whether we've alrady read the config file, but since |
+ * exim spawns itself, it will get read by exim children even though you |
+ * didn't restart exim. That said, after you change the config file, you |
+ * should restart exim to make sure all the instances pick up the new |
+ * config file |
+ */ |
+ if (!readconffile) |
+ { |
+ ret=open(conffile, 0); |
+ CHECKERR(ret,string_sprintf("conf file open for %s", conffile),__LINE__); |
+ readfh=fdopen(ret, "r"); |
+ CHECKERR(readfh,"fdopen",__LINE__); |
+ |
+ while ((fgets((char *)buffer, sizeof(buffera), (FILE *)readfh)) != NULL) |
+ { |
+ if (*buffer == '#' || *buffer == '\n' ) |
+ { |
+ continue; |
+ } |
+ |
+ if (*buffer != 'S' || *(buffer+1) != 'A') |
+ { |
+ log_write(0, LOG_MAIN, "SA: Warning: error while reading configuration file %s. Line does not begin with a SA directive: '%s', ignoring", conffile, buffer); |
+ continue; |
+ } |
+ |
+#define M_CHECKFORVAR(VAR, TYPE) \ |
+ if (strstr(buffer, #VAR ": ") == buffer) \ |
+ { \ |
+ if (sscanf(buffer, #VAR ": " TYPE, &VAR)) \ |
+ { \ |
+ if (SAEximDebug > 3) \ |
+ { \ |
+ if (SAEximDebug && ! wrotedebugenabled) \ |
+ { \ |
+ log_write(0, LOG_MAIN, "SA: Debug4: Debug enabled, reading config from file %s", conffile); \ |
+ wrotedebugenabled=1; \ |
+ } \ |
+ else \ |
+ { \ |
+ log_write(0, LOG_MAIN, "SA: Debug4: config read " #VAR " = " TYPE, VAR); \ |
+ }\ |
+ }\ |
+ } \ |
+ else \ |
+ { \ |
+ log_write(0, LOG_MAIN, "SA: Warning: error while reading configuration file %s. Can't parse value in: '%s', ignoring", conffile, buffer); \ |
+ } \ |
+ continue; \ |
+ } |
+ |
+#define M_CHECKFORSTR(VAR) \ |
+ if (strstr(buffer, #VAR ": ") == buffer) \ |
+ { \ |
+ VAR = strdup(buffer+strlen( #VAR )+2); \ |
+ if (VAR == NULL) \ |
+ { \ |
+ log_write(0, LOG_MAIN, "SA: PANIC: malloc failed, quitting..."); \ |
+ exit(-1); \ |
+ } \ |
+ \ |
+ if (VAR[strlen(VAR)-1] == '\n') \ |
+ { \ |
+ VAR[strlen(VAR)-1]=0; \ |
+ } \ |
+ if (SAEximDebug > 3) \ |
+ { \ |
+ log_write(0, LOG_MAIN, "SA: Debug4: config read " #VAR " = %s", VAR); \ |
+ } \ |
+ continue; \ |
+ } |
+ |
+ M_CHECKFORVAR(SAEximDebug, "%d"); |
+ M_CHECKFORSTR(SAspamcpath); |
+ M_CHECKFORSTR(SAsafemesgidchars); |
+ M_CHECKFORSTR(SAspamcSockPath); |
+ M_CHECKFORSTR(SAspamcPort); |
+ M_CHECKFORSTR(SAspamcHost); |
+ M_CHECKFORSTR(SAEximRunCond); |
+ M_CHECKFORSTR(SAEximRejCond); |
+ M_CHECKFORVAR(SAmaxbody, "%d"); |
+ M_CHECKFORSTR(SATruncBodyCond); |
+ M_CHECKFORVAR(SARewriteBody, "%d"); |
+ M_CHECKFORVAR(SAPrependArchiveWithFrom, "%d"); |
+ M_CHECKFORVAR(SAmaxarchivebody, "%d"); |
+ M_CHECKFORVAR(SAerrmaxarchivebody, "%d"); |
+ M_CHECKFORVAR(SAmaxrcptlistlength, "%d"); |
+ M_CHECKFORVAR(SAaddSAEheaderBeforeSA, "%d"); |
+ M_CHECKFORVAR(SAtimeout, "%d"); |
+ M_CHECKFORSTR(SAtimeoutsave); |
+ M_CHECKFORSTR(SAtimeoutSavCond); |
+ M_CHECKFORSTR(SAerrorsave); |
+ M_CHECKFORSTR(SAerrorSavCond); |
+ M_CHECKFORVAR(SAtemprejectonerror, "%d"); |
+ M_CHECKFORSTR(SAteergrube); |
+ M_CHECKFORSTR(SAteergrubecond); |
+ M_CHECKFORVAR(SAteergrubetime, "%d"); |
+ M_CHECKFORSTR(SAteergrubeSavCond); |
+ M_CHECKFORSTR(SAteergrubesave); |
+ M_CHECKFORVAR(SAteergrubeoverwrite, "%d"); |
+ M_CHECKFORSTR(SAdevnull); |
+ M_CHECKFORSTR(SAdevnullSavCond); |
+ M_CHECKFORSTR(SAdevnullsave); |
+ M_CHECKFORSTR(SApermreject); |
+ M_CHECKFORSTR(SApermrejectsave); |
+ M_CHECKFORSTR(SApermrejectSavCond); |
+ M_CHECKFORSTR(SAtempreject); |
+ M_CHECKFORSTR(SAtemprejectSavCond); |
+ M_CHECKFORSTR(SAtemprejectsave); |
+ M_CHECKFORVAR(SAtemprejectoverwrite, "%d"); |
+ M_CHECKFORSTR(SAgreylistiswhitestr); |
+ M_CHECKFORVAR(SAgreylistraisetempreject, "%f"); |
+ M_CHECKFORSTR(SAspamacceptsave); |
+ M_CHECKFORSTR(SAspamacceptSavCond); |
+ M_CHECKFORSTR(SAnotspamsave); |
+ M_CHECKFORSTR(SAnotspamSavCond); |
+ M_CHECKFORSTR(SAmsgteergrubewait); |
+ M_CHECKFORSTR(SAmsgteergruberej); |
+ M_CHECKFORSTR(SAmsgpermrej); |
+ M_CHECKFORSTR(SAmsgtemprej); |
+ M_CHECKFORSTR(SAmsgerror); |
+ |
+ |
+ } |
+ |
+ readconffile=1; |
+ } |
+ |
+#define M_CONDTOFLOAT(VAR) \ |
+ if ((expand=expand_string( VAR )) == NULL) \ |
+ { \ |
+ PANIC(string_sprintf(#VAR " config expansion failure on %s", #VAR ));\ |
+ } \ |
+ sscanf(expand, "%f", &VAR ## threshold); \ |
+ if (SAEximDebug > 2) \ |
+ { \ |
+ log_write(0, LOG_MAIN, "SA: Debug3: expanded " #VAR " = %.2f", VAR ## threshold); \ |
+ }\ |
+ |
+ M_CONDTOFLOAT(SAteergrube); |
+ M_CONDTOFLOAT(SAdevnull); |
+ M_CONDTOFLOAT(SApermreject); |
+ M_CONDTOFLOAT(SAtempreject); |
+ |
+ /* Initialize the list of recipients here */ |
+ rcptlist=string_copy(recipients_list[0].address); |
+ for (i=1; i < recipients_count && strlen((char *)rcptlist) < 7998 - strlen(recipients_list[i].address); i++) |
+ { |
+ rcptlist=string_sprintf("%s, %s", rcptlist, recipients_list[i].address); |
+ } |
+ |
+ if (sender_host_address != NULL) |
+ { |
+ mailinfo=string_sprintf("From <%s> (host=%s [%s]) for", |
+ sender_address, sender_host_name, sender_host_address); |
+ } |
+ else |
+ { |
+ mailinfo=string_sprintf("From <%s> (local) for", sender_address); |
+ } |
+ mailinfo=string_sprintf("%s %s", mailinfo, rcptlist); |
+ |
+ |
+ /* Remove SA-Exim headers that could have been set before we add ours*/ |
+ RemoveHeaders("X-SA-Exim-"); |
+ |
+ if(SAaddSAEheaderBeforeSA) |
+ { |
+ AddSAEheaders((char *)rcptlist, SAmaxrcptlistlength); |
+ } |
+ |
+ /* This is used later if we need to rewind and save the body elsewhere */ |
+ fdstart=lseek(fd, 0, SEEK_CUR); |
+ CHECKERR(fdstart,"lseek SEEK_CUR",__LINE__); |
+ |
+ ret=fstat(fd, &stbuf); |
+ CHECKERR(ret,"fstat fd",__LINE__); |
+ /* this is the body size plus a few bytes (exim msg ID) */ |
+ /* it should be 18 bytes, but I'll assume it could be more or less */ |
+ fdsize=stbuf.st_size; |
+ |
+ if (SAEximDebug > 3) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug4: Message body is about %.0f bytes and the initial offset is %.0f", (double)(fdsize-18), (double)fdstart); |
+ } |
+ |
+ if (fdsize > SAmaxbody) |
+ { |
+ if (SATruncBodyCond[0] != '1' || SATruncBodyCond[1] != 0) |
+ { |
+ expand=expand_string(SATruncBodyCond); |
+ if (expand == NULL) |
+ { |
+ PANIC(string_sprintf("SATruncBodyCond expansion failure on %s", SATruncBodyCond)); |
+ } |
+ |
+ if (SAEximDebug) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug: SATruncBodyCond expand returned: '%s'", expand); |
+ } |
+ |
+ if (expand[0] == 0 || (expand[0] == '0' && expand[1] == 0)) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Action: check skipped due to message size (%.0f bytes) and SATruncBodyCond expanded to false (Message-Id: %s). %s", (double)(fdsize-18), safemesgid, mailinfo); |
+ header_add(' ', "X-SA-Exim-Scanned: No (on %s); Message bigger than SAmaxbody (%d)\n", primary_hostname, SAmaxbody); |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+ } |
+ |
+ if (SAEximDebug > 1) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug2: Message body is about %.0f bytes and SATruncBodyCond expanded to true, will feed a truncated body to SA", (double)(fdsize-18)); |
+ } |
+ |
+ /* Let's feed exactly spamc will accept */ |
+ scansize=SAmaxbody; |
+ header_add(' ', "X-SA-Exim-Scan-Truncated: Fed %.0f bytes of the body to SA instead of %.0f\n", (double)scansize, (double)fdsize); |
+ } |
+ else |
+ { |
+ scansize=fdsize; |
+ } |
+ |
+ expand=expand_string(SAEximRunCond); |
+ if (expand == NULL) |
+ { |
+ PANIC(string_sprintf("SAEximRunCond expansion failure on %s", SAEximRunCond)); |
+ } |
+ |
+ if (SAEximDebug) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug: SAEximRunCond expand returned: '%s'", expand); |
+ } |
+ |
+ |
+ /* Bail from SA if the expansion string says so */ |
+ if (expand[0] == 0 || (expand[0] == '0' && expand[1] == 0)) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Action: Not running SA because SAEximRunCond expanded to false (Message-Id: %s). %s", safemesgid, mailinfo); |
+ header_add(' ', "X-SA-Exim-Scanned: No (on %s); SAEximRunCond expanded to false\n", primary_hostname); |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+ |
+ if (SAEximDebug) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug: check succeeded, running spamc"); |
+ } |
+ |
+ /* Ok, so now that we know we're running SA, we remove the X-Spam headers */ |
+ /* that might have been there */ |
+ RemoveHeaders("X-Spam-"); |
+ |
+ |
+ beforescan=time(NULL); |
+ /* Fork off spamc, and get ready to talk to it */ |
+ ret=pipe(writefd); |
+ CHECKERR(ret,"write pipe",__LINE__); |
+ ret=pipe(readfd); |
+ CHECKERR(ret,"read pipe",__LINE__); |
+ |
+ /* Ensure that SIGCHLD isn't being ignored. */ |
+ old_sigchld = signal(SIGCHLD, SIG_DFL); |
+ |
+ if ((pid=fork()) < 0) |
+ { |
+ CHECKERR(pid, "fork", __LINE__ - 1); |
+ } |
+ |
+ if (pid == 0) |
+ { |
+ close(readfd[0]); |
+ close(writefd[1]); |
+ |
+ ret=dup2(writefd[0],0); |
+ CHECKERR(ret,"dup2 stdin",__LINE__); |
+ ret=dup2(readfd[1],1); |
+ CHECKERR(ret,"dup2 stdout",__LINE__); |
+ ret=dup2(readfd[1],2); |
+ CHECKERR(ret,"dup2 stderr",__LINE__); |
+ |
+ /* |
+ * I could implement the spamc protocol and talk to spamd directly |
+ * instead of forking spamc, but considering the overhead spent |
+ * in spamd, forking off spamc seemed acceptable rather than |
+ * re-implementing and tracking the spamc/spamd protocol or linking |
+ * with a possibly changing library |
+ */ |
+ /* Ok, we cheat, spamc cares about how big the whole message is and |
+ * we only know about the body size, so I'll give an extra 16K |
+ * to account for any headers that can accompany the message */ |
+ if(SAspamcSockPath) |
+ { |
+ ret=execl(SAspamcpath, "spamc", "-s", string_sprintf("%d", SAmaxbody+16384), "-U", SAspamcSockPath, NULL); |
+ CHECKERR(ret,string_sprintf("exec %s", SAspamcpath),__LINE__); |
+ } |
+ else |
+ { |
+ ret=execl(SAspamcpath, "spamc", "-s", string_sprintf("%d", SAmaxbody+16384), "-d", SAspamcHost, "-p", SAspamcPort, NULL); |
+ CHECKERR(ret,string_sprintf("exec %s", SAspamcpath),__LINE__); |
+ } |
+ |
+ } |
+ |
+ if (SAEximDebug > 8) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug9: forked spamc"); |
+ } |
+ |
+ ret=close(readfd[1]); |
+ CHECKERR(ret,"close r",__LINE__); |
+ ret=close(writefd[0]); |
+ CHECKERR(ret,"close w",__LINE__); |
+ readfh=fdopen(readfd[0], "r"); |
+ |
+ if (SAEximDebug > 8) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug9: closed filehandles"); |
+ } |
+ |
+ /* Ok, we're ready for spewing the mail at spamc */ |
+ /* First we need to get the header lines from exim, and then we can read |
+ the body from fd */ |
+ hl=header_list; |
+ while (hl != NULL) |
+ { |
+ /* type '*' means the header is internal, don't print it */ |
+ if (hl->type == '*') |
+ { |
+ hl=hl->next; |
+ continue; |
+ } |
+ |
+ stret=write(writefd[1],hl->text,strlen(hl->text)); |
+ CHECKERR(stret,"header line write",__LINE__); |
+ |
+ hl=hl->next; |
+ } |
+ stret=write(writefd[1],"\n",1); |
+ CHECKERR(stret,"header separation write",__LINE__); |
+ |
+ if (SAEximDebug > 6) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug7: sent headers to spamc pipe. Sending body..."); |
+ } |
+ |
+ towrite=scansize; |
+ chunk=0; |
+ while (towrite>0 && (stret=read(fd, buffer, MIN(sizeof(buffera), towrite))) > 0) |
+ { |
+ chunk++; |
+ if (SAEximDebug > 8) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug9: spamc body going to write chunk %d (read %.0f, %.0f left to write)", chunk, (double)stret, (double)towrite); |
+ } |
+ towrite-=stret; |
+ stret=write(writefd[1], buffer, stret); |
+ CHECKERR(stret,"body write in",__LINE__); |
+ if (SAEximDebug > 8) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug9: Spamc body wrote chunk %d (wrote %.0f, %.0f left to write)", chunk, (double)stret, (double)towrite); |
+ } |
+ } |
+ CHECKERR(stret, "read body", __LINE__ - 14); |
+ close(writefd[1]); |
+ |
+ if (SAEximDebug > 5) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug6: fed spam to spamc, reading result"); |
+ } |
+ |
+ if (SAtimeout) |
+ { |
+ if (SAEximDebug > 2) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug3: Setting timeout of %d secs before reading from spamc", SAtimeout); |
+ } |
+ /* SA can take very long to run for various reasons, let's not wait |
+ * forever, that's just bad at SMTP time */ |
+ if (setjmp(jmp_env) == 0) |
+ { |
+ signal(SIGALRM, alarm_handler); |
+ alarm (SAtimeout); |
+ } |
+ else |
+ { |
+ /* Make sure that all your variables here are volatile or static */ |
+ signal(SIGCHLD, old_sigchld); |
+ fclose((FILE *)readfh); |
+ |
+ header_add(' ', "X-SA-Exim-Scanned: No (on %s); SA Timed out after %d secs\n", primary_hostname, SAtimeout); |
+ |
+ /* We sent it to LOG_REJECT too so that we get a header dump */ |
+ log_write(0, LOG_MAIN | LOG_REJECT, "SA: Action: spamd took more than %d secs to run, accepting message (scanned in %d/%d secs | Message-Id: %s). %s", SAtimeout, scantime, fulltime, safemesgid, mailinfo); |
+ |
+ ret=savemail(fd, fdstart, SAtimeoutsave, "SAtimeoutsave", (char *)mesgfn, SAerrmaxarchivebody, SAtimeoutSavCond); |
+ CHECKERR(ret,where,line); |
+ |
+ /* Make sure we kill spamc in case SIGPIPE from fclose didn't */ |
+ kill(pid, SIGTERM); |
+ return LOCAL_SCAN_ACCEPT; |
+ |
+ } |
+ } |
+ |
+ /* Let's see what SA has to tell us about this mail and store the headers */ |
+ while ((fgets((char *)buffer,sizeof(buffera),(FILE *) readfh)) != NULL) |
+ { |
+ /* Remove trailing newline */ |
+ if (buffer[strlen(buffer)-1] == '\n') |
+ { |
+ buffer[strlen(buffer)-1]=0; |
+ } |
+restart: |
+ if (SAEximDebug > 5) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug6: spamc read: %s", buffer); |
+ } |
+ |
+ /* Let's handle special multi-line headers first, what a pain... */ |
+ /* We feed the one line we read and the filehandle because we'll need |
+ to check whether more lines need to be concatenated */ |
+ /* This is ugly, there is an order dependency so we return to the |
+ beginning of the loop without reading a new line since we already |
+ did that */ |
+ if (parsemlheader(buffer, (FILE *)readfh, "Subject", NULL)) goto restart; |
+ if ((SARewriteBody == 1) && parsemlheader(buffer, (FILE *)readfh, "Content-Type", NULL)) goto restart; |
+ if ((SARewriteBody == 1) && parsemlheader(buffer, (FILE *)readfh, "Content-Transfer-Encoding", NULL)) goto restart; |
+ |
+ if (parsemlheader(buffer, (FILE *)readfh, "X-Spam-Flag", &xspamflag)) |
+ { |
+ if (xspamflag[13] == 'Y') |
+ { |
+ isspam=1; |
+ } |
+ if (SAEximDebug > 2) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug3: isspam read from X-Spam-Flag: %d", isspam); |
+ } |
+ goto restart; |
+ } |
+ |
+ if (parsemlheader(buffer, (FILE *)readfh, "X-Spam-Status", &xspamstatus)) |
+ { |
+ char *start; |
+ char *end; |
+ |
+ gotsa=1; |
+ |
+ /* if we find the preconfigured greylist string (and it is defined |
+ * in sa-exim.conf), we can raise the threshold for tempreject just |
+ * for this mail, since it's been whitelisted */ |
+ if (SAgreylistiswhitestr && strstr(xspamstatus, SAgreylistiswhitestr)) |
+ { |
+ SAtemprejectthreshold+=SAgreylistraisetempreject; |
+ if (SAEximDebug > 2) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug3: read %s string, SAtempreject is now changed to %f", SAgreylistiswhitestr, SAtemprejectthreshold); |
+ } |
+ } |
+ else |
+ { |
+ if (SAEximDebug > 2) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug3: did not find read GREYLIST_ISWHITE string in X-Spam-Status"); |
+ } |
+ } |
+ |
+ start=strstr(xspamstatus, "hits="); |
+ /* Support SA 3.0 format */ |
+ if (start == NULL) |
+ { |
+ start=strstr(xspamstatus, "score="); |
+ } |
+ |
+ end=strstr(xspamstatus, " tests="); |
+ if (end == NULL) |
+ { |
+ if (SAEximDebug > 5) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug6: Could not find old spamstatus format, trying new one..."); |
+ } |
+ end=strstr(xspamstatus, "\n tests="); |
+ } |
+ if (start!=NULL && end!=NULL) |
+ { |
+ spamstatus=string_copyn(start, end-start); |
+ if (SAEximDebug > 2) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug3: Read from X-Spam-Status: %s", spamstatus); |
+ } |
+ } |
+ else |
+ { |
+ PANIC(string_sprintf("SA: could not parse X-Spam-Status: to extract hits and required. Bad!. Got: '%s'", xspamstatus)); |
+ } |
+ |
+ start=strstr(spamstatus, "="); |
+ end=strstr(spamstatus, " "); |
+ if (start!=NULL && end!=NULL) |
+ { |
+ start++; |
+ sscanf(start, "%f", &spamvalue); |
+ } |
+ else |
+ { |
+ PANIC(string_sprintf("SA: spam value extract failed in '%s'. Bad!", xspamstatus)); |
+ } |
+ |
+ goto restart; |
+ } |
+ |
+ if (parsemlheader(buffer, (FILE *)readfh, "X-Spam-", NULL)) goto restart; |
+ |
+ /* Ok, now we can do normal processing */ |
+ |
+ /* If no more headers here, we're done */ |
+ if (buffer[0] == 0) |
+ { |
+ if (SAEximDebug > 5) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug6: spamc read got newline, end of headers", buffer); |
+ } |
+ goto exit; |
+ } |
+ |
+ if (compare_header(buffer, "Message-Id: ")) |
+ { |
+ char *start; |
+ char *end; |
+ char *mesgid=NULL; |
+ |
+ start=strchr(buffer, '<'); |
+ end=strchr(buffer, '>'); |
+ |
+ if (start == NULL || end == NULL) |
+ { |
+ /* we keep the default mesgfn (unix date in seconds) */ |
+ if (SAEximDebug) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug: Could not get Message-Id from %s", buffer); |
+ } |
+ } |
+ else if ((mesgid=string_copyn(start+1,end-start-1)) && mesgid[0]) |
+ { |
+ /* We replace the exim Message-ID with the one read from |
+ the message * as we use this to detect dupes when we |
+ send 45x and get the same * message multiple times */ |
+ safemesgid=cleanmsgid(mesgid, SAsafemesgidchars); |
+ mesgfn=string_sprintf("%d_%s", time(NULL), safemesgid); |
+ |
+ if (SAEximDebug > 5) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug6: Message-Id received and cleaned as: %s", safemesgid); |
+ } |
+ } |
+ continue; |
+ } |
+ } |
+ |
+ exit: |
+ |
+ |
+ if (isspam && SARewriteBody == 1) |
+ { |
+ int line; |
+ |
+ if (SAEximDebug) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug: SARewriteBody == 1, rewriting message body"); |
+ } |
+ |
+ /* already read from fd? Better reset it... */ |
+ ret=lseek(fd, fdstart, SEEK_SET); |
+ CHECKERR(ret, "lseek reset on spooled message", __LINE__); |
+ |
+ line=1; |
+ while ((fgets((char *)buffer,sizeof(buffera),(FILE *) readfh)) != NULL) |
+ { |
+ if (SAEximDebug > 8) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug9: Read body from SA; line %d (read %d)", line, strlen(buffer)); |
+ } |
+ |
+ stret=write(fd, buffer, strlen(buffer)); |
+ CHECKERR(stret,string_sprintf("SA body write to msg"),__LINE__); |
+ if (SAEximDebug > 8) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug9: Wrote to msg; line %d (wrote %d)", line, ret); |
+ } |
+ if (buffer[strlen(buffer)-1] == '\n') |
+ { |
+ line++; |
+ } |
+ } |
+ |
+ if (SAEximDebug > 1) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug2: body_linecount before SA: %d", body_linecount); |
+ } |
+ |
+ /* update global variable $body_linecount to reflect the new body size*/ |
+ body_linecount = (line - 1); |
+ |
+ if (SAEximDebug > 1) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug2: body_linecount after SA: %d", body_linecount); |
+ } |
+ } |
+ |
+ fclose((FILE *)readfh); |
+ |
+ afterscan=time(NULL); |
+ scantime=afterscan-beforescan; |
+ |
+ wait(&ret); |
+ signal(SIGCHLD, old_sigchld); |
+ |
+ if (ret) |
+ { |
+ sprintf(buffer, "%d", ret); |
+ PANIC(string_sprintf("wait on spamc child yielded, %s", buffer)); |
+ } |
+ |
+ afterwait=time(NULL); |
+ fulltime=afterwait-beforescan; |
+ |
+ if(!SAaddSAEheaderBeforeSA) |
+ { |
+ AddSAEheaders((char *)rcptlist, SAmaxrcptlistlength); |
+ } |
+ |
+ header_add(' ', "X-SA-Exim-Version: %s\n",version); |
+ |
+ if (gotsa == 0) |
+ { |
+ header_add(' ', "X-SA-Exim-Scanned: No (on %s); Unknown failure\n", primary_hostname); |
+ log_write(0, LOG_MAIN, "SA: Action: SA didn't successfully run against message, accepting (time: %d/%d secs | Message-Id: %s). %s", scantime, fulltime, safemesgid, mailinfo); |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+ |
+ header_add(' ', "X-SA-Exim-Scanned: Yes (on %s)\n", primary_hostname); |
+ |
+ if (spamstatus == NULL) |
+ { |
+ spamstatus = (char *) nospamstatus; |
+ } |
+ if (isspam) |
+ { |
+ int dorej=1; |
+ int doteergrube=0; |
+ |
+ if (SAEximRejCond[0] != '1' || SAEximRejCond[1] != 0) |
+ { |
+ expand=expand_string(SAEximRejCond); |
+ if (expand == NULL) |
+ { |
+ PANIC(string_sprintf("SAEximRejCond expansion failure on %s", SAEximRejCond)); |
+ } |
+ |
+ if (SAEximDebug) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug: SAEximRejCond expand returned: '%s'", expand); |
+ } |
+ |
+ if (expand[0] == 0 || (expand[0] == '0' && expand[1] == 0)) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Notice: SAEximRejCond expanded to false, not applying reject rules"); |
+ dorej=0; |
+ } |
+ } |
+ |
+ if (dorej && spamvalue >= SAteergrubethreshold) |
+ { |
+ doteergrube=1; |
+ if (SAteergrubecond[0] != '1' || SAteergrubecond[1] != 0) |
+ { |
+ expand=expand_string(SAteergrubecond); |
+ if (expand == NULL) |
+ { |
+ PANIC(string_sprintf("SAteergrubecond expansion failure on %s", SAteergrubecond)); |
+ } |
+ |
+ if (SAEximDebug) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Debug: SAteergrubecond expand returned: '%s'", expand); |
+ } |
+ |
+ if (expand[0] == 0 || (expand[0] == '0' && expand[1] == 0)) |
+ { |
+ log_write(0, LOG_MAIN, "SA: Notice: SAteergrubecond expanded to false, not teergrubing known peer"); |
+ doteergrube=0; |
+ } |
+ } |
+ } |
+ |
+ if (dorej && doteergrube) |
+ { |
+ /* By default, we'll only save temp bounces by message ID so |
+ * that when the same message is submitted several times, we |
+ * overwrite the same file on disk and not create a brand new |
+ * one every single time */ |
+ if (SAteergrubeoverwrite) |
+ { |
+ ret=savemail(fd, fdstart, SAteergrubesave, "SAteergrubesave", safemesgid, SAmaxarchivebody, SAteergrubeSavCond); |
+ CHECKERR(ret,where,line); |
+ } |
+ else |
+ { |
+ ret=savemail(fd, fdstart, SAteergrubesave, "SAteergrubesave", (char *)mesgfn, SAmaxarchivebody, SAteergrubeSavCond); |
+ CHECKERR(ret,where,line); |
+ } |
+ |
+ spamstatus=string_sprintf("%s trigger=%.1f", spamstatus, SAteergrubethreshold); |
+ /* Exim might want to stop us if we run for too long, but that's |
+ * exactly what we're trying to do, so let's override that */ |
+ alarm(0); |
+ |
+ for (i=0;i<SAteergrubetime/10;i++) |
+ { |
+ char *str; |
+ |
+ /* Unfortunately, we can't use exim's smtp_printf because it |
+ * doesn't return an error code if the write gets an EPIPE. |
+ * So, we write ourselves, but this won't work if you have a |
+ * TLS connection opened (that said, if you are teergrubing |
+ * a TLS connection, it's probably a relay host, not a |
+ * spammer, and in this case you should not teergrube a |
+ * friendly relay, so basically we should be ok). |
+ * If you do teergrube an SSL connection with the current |
+ * code, you will break it, but that's acceptable */ |
+ str=string_sprintf(string_sprintf("451- %s\r\n",SAmsgteergrubewait), spamstatus); |
+ fprintf(smtp_out, str); |
+ ret=fflush(smtp_out); |
+ if (ret != 0) |
+ { |
+ log_write(0, LOG_MAIN | LOG_REJECT, "SA: Action: teergrubed sender for %d secs until it closed the connection: %s (scanned in %d/%d secs | Message-Id: %s). %s", i*10, spamstatus, scantime, fulltime, safemesgid, mailinfo); |
+ /* The other side closed the connection, nothing to print */ |
+ *return_text=""; |
+ return LOCAL_SCAN_TEMPREJECT_NOLOGHDR; |
+ } |
+ sleep(10); |
+ } |
+ |
+ log_write(0, LOG_MAIN | LOG_REJECT, "SA: Action: teergrubed sender until full configured duration of %d secs: %s (scanned in %d/%d secs | Message-Id: %s). %s", SAteergrubetime, spamstatus, scantime, fulltime, safemesgid, mailinfo); |
+ *return_text=string_sprintf(SAmsgteergruberej, spamstatus); |
+ return LOCAL_SCAN_TEMPREJECT_NOLOGHDR; |
+ } |
+ else if (dorej && spamvalue >= SAdevnullthreshold) |
+ { |
+ ret=savemail(fd, fdstart, SAdevnullsave, "SAdevnullsave", (char *)mesgfn, SAmaxarchivebody, SAdevnullSavCond); |
+ CHECKERR(ret,where,line); |
+ |
+ recipients_count=0; |
+ spamstatus=string_sprintf("%s trigger=%.1f", spamstatus, SAdevnullthreshold); |
+ log_write(0, LOG_REJECT | LOG_MAIN, "SA: Action: silently tossed message: %s (scanned in %d/%d secs | Message-Id: %s). %s", spamstatus, scantime, fulltime, safemesgid, mailinfo); |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+ else if (dorej && spamvalue >= SApermrejectthreshold) |
+ { |
+ ret=savemail(fd, fdstart, SApermrejectsave, "SApermrejectsave", (char *)mesgfn, SAmaxarchivebody, SApermrejectSavCond); |
+ CHECKERR(ret,where,line); |
+ |
+ spamstatus=string_sprintf("%s trigger=%.1f", spamstatus, SApermrejectthreshold); |
+ log_write(0, LOG_MAIN | LOG_REJECT, "SA: Action: permanently rejected message: %s (scanned in %d/%d secs | Message-Id: %s). %s", spamstatus, scantime, fulltime, safemesgid, mailinfo); |
+ *return_text=string_sprintf(SAmsgpermrej, spamstatus); |
+ return LOCAL_SCAN_REJECT_NOLOGHDR; |
+ } |
+ else if (dorej && spamvalue >= SAtemprejectthreshold) |
+ { |
+ /* Yeah, gotos are harmful, but that'd be a function with a lot |
+ * of options to send, so, here's a small shortcut */ |
+ goto dotempreject; |
+ } |
+ else |
+ { |
+ ret=savemail(fd, fdstart, SAspamacceptsave, "SAspamacceptsave", (char *)mesgfn, SAmaxarchivebody, SAspamacceptSavCond); |
+ CHECKERR(ret,where,line); |
+ log_write(0, LOG_MAIN, "SA: Action: flagged as Spam but accepted: %s (scanned in %d/%d secs | Message-Id: %s). %s", spamstatus, scantime, fulltime, safemesgid, mailinfo); |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+ } |
+ else |
+ { |
+ /* This is an exception to the rule, for grey listing, we allow for |
+ * sending back a tempreject on SA scores that aren't considered as |
+ * spam (greylisting is now done directly in spamassassin though */ |
+ if (spamvalue >= SAtemprejectthreshold) |
+ { |
+ dotempreject: |
+ |
+ /* By default, we'll only save temp bounces by message ID so |
+ * that when the same message is submitted several times, we |
+ * overwrite the same file on disk and not create a brand new |
+ * one every single time */ |
+ if (SAtemprejectoverwrite) |
+ { |
+ ret=savemail(fd, fdstart, SAtemprejectsave, "SAtemprejectsave", safemesgid, SAmaxarchivebody, SAtemprejectSavCond); |
+ CHECKERR(ret,where,line); |
+ } |
+ else |
+ { |
+ ret=savemail(fd, fdstart, SAtemprejectsave, "SAtemprejectsave", (char *)mesgfn, SAmaxarchivebody, SAtemprejectSavCond); |
+ CHECKERR(ret,where,line); |
+ } |
+ |
+ spamstatus=string_sprintf("%s trigger=%.1f", spamstatus, SAtemprejectthreshold); |
+ log_write(0, LOG_MAIN | LOG_REJECT, "SA: Action: temporarily rejected message: %s (scanned in %d/%d secs | Message-Id: %s). %s", spamstatus, scantime, fulltime, safemesgid, mailinfo); |
+ *return_text=string_sprintf(SAmsgtemprej, spamstatus); |
+ return LOCAL_SCAN_TEMPREJECT_NOLOGHDR; |
+ } |
+ else |
+ { |
+ ret=savemail(fd, fdstart, SAnotspamsave, "SAnotspamsave", (char *)mesgfn, SAmaxarchivebody, SAnotspamSavCond); |
+ CHECKERR(ret,where,line); |
+ log_write(0, LOG_MAIN, "SA: Action: scanned but message isn't spam: %s (scanned in %d/%d secs | Message-Id: %s). %s", spamstatus, scantime, fulltime, safemesgid, mailinfo); |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+ } |
+ |
+ |
+ |
+ errexit: |
+ if (SAtemprejectonerror) |
+ { |
+ log_write(0, LOG_MAIN | LOG_PANIC, "SA: PANIC: Unexpected error on %s, file "__FILE__", line %d: %s", where, line-1, strerror(errno)); |
+ } |
+ else |
+ { |
+ log_write(0, LOG_MAIN, "SA: PANIC: Unexpected error on %s (but message was accepted), file "__FILE__", line %d: %s", where, line-1, strerror(errno)); |
+ } |
+ |
+ header_add(' ', "X-SA-Exim-Scanned: No (on %s); Exit with error (see exim mainlog)\n", primary_hostname); |
+ |
+ ret=savemail(fd, fdstart, SAerrorsave, "SAerrorsave", (char *)mesgfn, SAerrmaxarchivebody, SAerrorSavCond); |
+ if (ret < 0) |
+ { |
+ log_write(0, LOG_MAIN | LOG_PANIC, "SA: PANIC: Error in error handler while trying to save mail to %s, file "__FILE__", line %d: %s", string_sprintf("%s/%s", SAerrorsave, mesgfn), __LINE__ - 3, strerror(errno)); |
+ } |
+ |
+ if (SAtemprejectonerror) |
+ { |
+ *return_text=SAmsgerror; |
+ return LOCAL_SCAN_TEMPREJECT_NOLOGHDR; |
+ } |
+ else |
+ { |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+ |
+ |
+ panicexit: |
+ if (SAtemprejectonerror) |
+ { |
+ log_write(0, LOG_MAIN | LOG_PANIC, "SA: PANIC: %s", panicerror); |
+ } |
+ else |
+ { |
+ log_write(0, LOG_MAIN | LOG_PANIC, "SA: PANIC: %s (but message was accepted)", panicerror); |
+ } |
+ |
+ header_add(' ', "X-SA-Exim-Scanned: No (on %s); Panic (see exim mainlog)\n", primary_hostname); |
+ |
+ ret=savemail(fd, fdstart, SAerrorsave, "SAerrorsave", (char *)mesgfn, SAerrmaxarchivebody, SAerrorSavCond); |
+ if (ret < 0) |
+ { |
+ log_write(0, LOG_MAIN | LOG_PANIC , "SA: PANIC: Error in error handler while trying to save mail to %s, file "__FILE__", line %d: %s", string_sprintf("%s/%s", SAerrorsave, mesgfn), __LINE__ - 3, strerror(errno)); |
+ } |
+ |
+ if (SAtemprejectonerror) |
+ { |
+ *return_text=SAmsgerror; |
+ return LOCAL_SCAN_TEMPREJECT_NOLOGHDR; |
+ } |
+ else |
+ { |
+ return LOCAL_SCAN_ACCEPT; |
+ } |
+} |
Index: branches/upstream/4.2.1/version |
=================================================================== |
--- branches/upstream/4.2.1/version (nonexistent) |
+++ branches/upstream/4.2.1/version (revision 2) |
@@ -0,0 +1 @@ |
+4.2.1 |
Index: branches/upstream/4.2.1/sa-exim.conf |
=================================================================== |
--- branches/upstream/4.2.1/sa-exim.conf (nonexistent) |
+++ branches/upstream/4.2.1/sa-exim.conf (revision 2) |
@@ -0,0 +1,358 @@ |
+# Options for spamassassin running in exim's local_scan (SA Exim) |
+# By Marc MERLIN <marc_soft@merlins.org> - Initial version: April 2002 |
+# Sander Smeenk <ssmeenk@freshdot.net> - Improvements: March 2004 |
+# |
+# Sample file version 1.16 for SA-Exim 4.1 - 2005/01/10 |
+# |
+# The parse routine is minimalistic. It expects "option: value" (exactly |
+# one space after the colon, and none before). You should put long lines |
+# on one line. The parser isn't capable of parsing multiline values. |
+# |
+# SA threshold values are parsed as floats and other numerical options |
+# are ints. String options have to be set. To unset them, comment out the |
+# variable, don't set it to nothing. |
+# |
+# READ THIS: |
+# --------- |
+# Watch your logs, you will get errors and your messages will get |
+# temporarily bounced if expansions fail. Watch your logs! |
+# |
+# If you are afraid that spammers might use a header that is used here |
+# as a default, have exim set it to another value than 'Yes' and check |
+# here for that other value. |
+# |
+# For every expansion, anything that doesn't expand to "" or "0" |
+# (without quotes) will be considered true. If you set the string to 1, |
+# it will be true without going through exim's condition evaluator (and |
+# if you leave it unset, it will default to 0) |
+# |
+# You should not put double quotes around expressions! |
+# --- snip --- |
+ |
+# Enable basic verbose output by default. Watch your logs! |
+SAEximDebug: 1 |
+ |
+ |
+# Default path is /usr/bin/spamc, but you can change it here |
+SAspamcpath: /usr/bin/spamc |
+ |
+# Which characters are retained from a Message-Id header (for safety, we |
+# remove characters that might cause problems with shell parsing) |
+# Change the default at your own risk (you also have to change this in |
+# the SA greylisting patch if you use that) |
+#SAsafemesgidchars: !#%( )*+,-.0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~ |
+ |
+# If SAspamcSockPath is set spamc uses socket to connect to spamd, |
+# use --socketpath pathname as argument to spamd (new in SA 2.60). |
+# Leave it unset if you want spamc to connect(AF_INET) to spamd at |
+# 127.0.0.1 (this is the default shown in the options below), but if |
+# you set it, it will override the two TCP connect options below |
+#SAspamcSockPath: /var/run/spamd.sock |
+ |
+# SAspamcHost / SAspamcPort: TCP socket where your spamd is listening |
+# Shown below are the defaults: |
+SAspamcHost: 127.0.0.1 |
+SAspamcPort: 783 |
+ |
+ |
+# Exim configuration string to run before running SA against the message |
+# This decides whether SA gets run against the message or not. This |
+# default will not reject messages if the message had SA headers but |
+# they weren't added by us. |
+SAEximRunCond: ${if and {{def:sender_host_address} {!eq {$sender_host_address}{127.0.0.1}} {!eq {$h_X-SA-Do-Not-Run:}{Yes}} } {1}{0}} |
+# Remove or comment out the following line to enable sa-exim |
+SAEximRunCond: 0 |
+ |
+# If and only if SAEximRunCond was true, and we did run SA, this |
+# expression decides whether we actually consider acting upon SAdevnull, |
+# SApermreject, and SAtempreject if you have them set. |
+# |
+# Use this to tag messages that you shouldn't reject (messages sent to |
+# abuse or postmaster for instance). |
+# |
+# X-SA-Do-Not-Rej should be set as a warn header if mail is sent to |
+# postmaster and abuse (in the RCPT ACL), this way you're not bouncing |
+# spam abuse reports sent to you. This is a RFC guideline. |
+SAEximRejCond: ${if !eq {$h_X-SA-Do-Not-Rej:}{Yes} {1}{0}} |
+ |
+ |
+# How much of the body we feed to spamassassin (in bytes) |
+# Default is 250KB |
+SAmaxbody: 256000 |
+ |
+# Do you want to feed SAmaxbody's worth of the message body if it is too big? |
+# Either, you skip messages that are too big and not scan them, or you can |
+# truncate the body and feed that to SA. |
+# Note that SA will sometimes raise the spam score if it can't parse |
+# the message correctly (since the end is missing, decoding will fail) |
+# Default is 0: do not scan messages that are too big |
+# (note that this is parsed as a condition) |
+SATruncBodyCond: 0 |
+ |
+# If you want SA to report_safe you need sa-exim to rewrite the body of |
+# the message since SA encapsulates the spam as a mime attachment. |
+# You probably want SATruncBodyCond to be 0 or else you'll end up with a |
+# partial message if it's larger than SAmaxbody and it's spam |
+# |
+# Also note that if you enable this option, any saved message will be saved |
+# after the body has been modified by SA. |
+# (this is not a condition as SA's report_safe is not conditional) |
+SARewriteBody: 0 |
+ |
+# Prepend saved messages with an fake From-header to make the file look like a |
+# valid mbox file |
+SAPrependArchiveWithFrom: 1 |
+ |
+# If you are archiving messages that are rejected, how much do you want |
+# to archive? Default is 20MB. |
+SAmaxarchivebody: 20971520 |
+ |
+# On errors, if you are saving messages, you probably want the entire message |
+# Default size saved (if you are saving errors) is 1GB |
+SAerrmaxarchivebody: 1073741824 |
+ |
+# You can have SA-Exim add a X-SA-Exim-Rcpt-To header, which will list all |
+# the recipients for the Email, unless the list gets bigger than |
+# SAmaxrcptlistlength bytes. |
+# The default value of 0 disables the header for privacy reasons (the header |
+# exposes Bcced recipients) |
+# Any value bigger than 8000 will be ignored because there is a limit on the |
+# size of headers that you can have and exim's string_sprintf |
+# Note that if you are planning to use greylisting, you should set this |
+# value to 8000 since SA's greylisting code needs the recipients. |
+SAmaxrcptlistlength: 0 |
+ |
+# Add X-SA-Exim-Rcpt-To and X-SA-Exim-Mail-From headers before SA scans |
+# the message. |
+# If this option is enabled, SARewiteBody is true, and safe_mode is |
+# enabled in SA, you end up with the X-SA-Exim-Rcpt-To/X-SA-Exim-Mail-From in |
+# the attatched message as well without the ability to remove them later in an |
+# exim transport (think privacy). |
+# In real life this is usually not a problem because the message is spam anyway, |
+# and if you turn this off, you lose the option to use those headers to score |
+# the message with SA. |
+SAaddSAEheaderBeforeSA: 1 |
+ |
+# How many seconds you want to allow spamc to run. Exim 4.04 and better will |
+# kill us after a default of 5 minutes. This however is not great, because the |
+# mail gets temporarily rejected |
+# You should set this and have SA Exim handle the timeout itself and accept the |
+# message if spamc takes too long (instead of timing out) |
+# A value of 0 means no timeout, and we run until exim stops us. |
+# I know of at least one mail server (nanog's merit.edu) that will not |
+# wait a full 5mn (which causes tempreject and resends), so the default is 4mn |
+#SAtimeout: 240 |
+ |
+# Do you want to save mails that were accepted because spamc timed out? |
+# Specify a directory to enable the feature. |
+# SA-Exim will try to create the directory if it has the permissions to do so, |
+# check your maillog for failures (or create the directory yourself and make it |
+# writeable by exim) |
+SAtimeoutsave: /var/spool/exim/SAtimeoutsave |
+ |
+# You can optionally save or not save messages that matched the above rule |
+SAtimeoutSavCond: 1 |
+ |
+ |
+# You should really create this directory for local_scan to save messages that |
+# created an error. If you don't want this, comment out this variable |
+# Make sure all these directories are owned by the exim user |
+# SA-Exim will try to create the directory if it has the permissions to do |
+# so, check your maillog for failures (or create the directory yourself and |
+# make it writeable by exim) |
+SAerrorsave: /var/spool/exim/SAerrorsave |
+ |
+# You can optionally save or not save messages that matched the above rule |
+# You should not put double quotes around the expression |
+SAerrorSavCond: 1 |
+ |
+# If you set to 1, SA will temporarily reject messages that generated an error |
+# while they were processed (they'll still be saved if SAerrorsave is set). |
+# Otherwise (0 = false), the messages are just accepted, which seems like a |
+# more sensible default |
+SAtemprejectonerror: 0 |
+ |
+ |
+############################################################################### |
+# NOTE: Spamd needs to tell sa-exim that the message SA-Exim gave spamd |
+# is spam before sa-exim will consider the SA tresholds. |
+# In other words, you cannot reject mails on SA scores if you set that |
+# threshold to a lower threshold than SA's required_hits value. |
+# The one exception to this rule is SAtempreject (in order to let you |
+# temporarily reject mail when you are doing greylisting, see |
+# README.greylisting in the documentation for details) |
+############################################################################### |
+ |
+# SA score when you start stalling the sender by sending many continuation |
+# lines for up to SAteergrubetime |
+# This is now a string (without quotes) that gets evaluated at runtime by exim |
+# but you can still assign a simple float value to it |
+# Note that this is an obvious abuse of SMTP, but eh, they started it :-) |
+# Of course, this means that each incoming spam with the right score threshold |
+# will keep an exim process busy on your machine. Make sure you can afford it. |
+# Default value is 2^20, which should disable the behavior |
+ |
+# Please, don't teergrube people who relay for you or your own MXes :-) |
+# This option is left behind for backward compatibility, but you can now |
+# get the same result by putting a condition string in SAteergrube |
+# The trick is to list your score if the condition succeeds, and a really |
+# high score otherwise. |
+#SAteergrube: ${if and { {!eq {$sender_host_address}{127.0.0.1}} {!eq {$sender_host_address}{127.0.0.2}} } {25}{1048576}} |
+ |
+# SAteergrubecond is deprecated (replaced by SAteergrube) |
+# You used to be say whether you would apply the teergrubing score with this |
+# condition, but now that scores are conditions, it is obsolete |
+#SAteergrubecond: ${if and { {!eq {$sender_host_address}{127.0.0.1}} {!eq {$sender_host_address}{127.0.0.2}} } {1}{0}} |
+ |
+# How long do you want to stall the sender (in seconds) |
+# If you set the value too high, you might get too many exim processes running |
+# and run out of process slots |
+# Remember, don't come crying if playing with this "feature" causes your mail |
+# server to catch fire :-) |
+SAteergrubetime: 900 |
+ |
+# You can optionally save or not save messages that matched the above rule |
+SAteergrubeSavCond: 1 |
+ |
+# Do you want to save mails that you stalled for later analysis? |
+# Specify a directory to enable the feature. |
+# SA-Exim will try to create the directory if it has the permissions to do so, |
+# check your maillog for failures (or create the directory yourself and make it |
+# writeable by exim) |
+SAteergrubesave: /var/spool/exim/SAteergrube |
+ |
+# When you stall the sender, you will probably get the mail again. |
+# By default, we'll only save messages by message ID so that we don't save |
+# multiple copies every time the sender tries again. |
+# Of course, this means someone could fake someone else's message ID to |
+# overwrite the saved copy of another spam. Such is life :-) |
+SAteergrubeoverwrite: 1 |
+ |
+ |
+ |
+# If you reach this score, the mail is accepted and tossed (/dev/nulled). |
+# The default value is 2^20 which should ensure this never happens. |
+# This is now a string (without quotes) that gets evaluated at runtime by exim |
+# but you can still assign a simple float value to it |
+# You should be really sure that the message is spam because the sender will |
+# get no notification |
+#SAdevnull: 20.0 |
+ |
+# You can optionally save or not save messages that matched the above rule |
+SAdevnullSavCond: 1 |
+ |
+# Do you want to save mails that are tossed? |
+# Specify a directory to enable the feature. |
+# This is just in case you do want to keep a copy of the alledge spams somewhere |
+# Messages are saved by unixdate_Message-Id or just unix date if there is no |
+# Message-Id. |
+# SA-Exim will try to create the directory if it has the permissions to do so, |
+# check your maillog for failures (or create the directory yourself and make it |
+# writeable by exim) |
+SAdevnullsave: /var/spool/exim/SAdevnull |
+ |
+ |
+ |
+# SA score when you start rejecting Emails (this is better than the above as |
+# it can notify the sender in case you reject non-spam by mistake) |
+# This is now a string (without quotes) that gets evaluated at runtime by exim |
+# but you can still assign a simple float value to it |
+# Default value is 2^20, which should disable the behavior if you comment out |
+# the line below |
+SApermreject: 12.0 |
+ |
+# You can optionally save or not save messages that matched the above rule |
+SApermrejectSavCond: 1 |
+ |
+# Do you want to save mails that are rejected? |
+# Specify a directory to enable the feature. |
+# SA-Exim will try to create the directory if it has the permissions to do so, |
+# check your maillog for failures (or create the directory yourself and make it |
+# writeable by exim) |
+SApermrejectsave: /var/spool/exim/SApermreject |
+ |
+ |
+ |
+# SA score when you start returning a temporary reject. |
+# There are few reasons to use this, except if you're reading your tempreject |
+# save folder (see below) and ajusting scores on the fly, or if you are using |
+# greylisting |
+# This is now a string (without quotes) that gets evaluated at runtime by exim |
+# but you can still assign a simple float value to it |
+# Default value is 2^20, which should disable the behavior |
+SAtempreject: 9.0 |
+ |
+# You can optionally save or not save messages that matched the above rule |
+SAtemprejectSavCond: 1 |
+ |
+# Do you want to save mails that are temporarily rejected? |
+# Specify a directory to enable the feature. |
+# You could use this to analyse what SA is bouncing and adding an allow rule |
+# to accept the mail next time it is sent back to you |
+# SA-Exim will try to create the directory if it has the permissions to do so, |
+# check your maillog for failures (or create the directory yourself and make it |
+# writeable by exim) |
+SAtemprejectsave: /var/spool/exim/SAtempreject |
+ |
+# When you send back a temp reject code, you will get the mail again. |
+# By default, we'll only save messages by message ID so that we don't save |
+# multiple copies every time the sender tries again. |
+# Of course, this means someone could fake someone else's message ID to |
+# overwrite the saved copy of another spam. Such is life :-) |
+SAtemprejectoverwrite: 1 |
+ |
+# See README.greylisting in the documentation for the following options |
+# This is the string that SpamAssassin adds if the message is whitelisted |
+# We use this to optionally increase the score needed for a tempreject |
+# (in order to let a message through when it would otherwise have been |
+# temprejected) |
+# Default value is "GREYLIST_ISWHITE" (as used in the patch provided by SA-Exim) |
+SAgreylistiswhitestr: GREYLIST_ISWHITE |
+ |
+# By how much do we temporarly raise tempreject to allow a mail in when it |
+# would otherwise have been temp rejected (because SA flagged it was whitelisted |
+# by the greylisting code provided as a patch to SA in the SA-Exim distro) |
+# Note that greylisting will not work in until you patch SA with the greylist |
+# function |
+# Note that you most likely want |
+# SAtempreject + SAgreylistraisetempreject <= SApermreject |
+# Default value is 3.0 but you'd probably to lower the tempreject score and |
+# increase this one (see README.greylisting) |
+SAgreylistraisetempreject: 3.0 |
+ |
+ |
+# Do you want to save mails that are flagged as spam by SA, but not rejected by |
+# any of the above thresholds? Specify a directory to enable the feature. |
+# That's one way to track mails thare are going through even though they were |
+# flagged by SA (note that you could also save them in exim's system_filter, |
+# although copies saved here happen before exim makes modification to the |
+# message like rewriting) |
+# SA-Exim will try to create the directory if it has the permissions to do so, |
+# check your maillog for failures (or create the directory yourself and make it |
+# writeable by exim) |
+SAspamacceptsave: /var/spool/exim/SAspamaccept |
+ |
+# You can control which messages you want saved if you only want a subset |
+SAspamacceptSavCond: 0 |
+ |
+ |
+# Do you want to save mails that are not flagged as spam by SA |
+# Specify a directory to enable the feature. |
+# This is only here for completeness, if you want to save all messages not |
+# flagged as spam by SA (you could also do this in system_filter) |
+# SA-Exim will try to create the directory if it has the permissions to do so, |
+# check your maillog for failures (or create the directory yourself and make it |
+# writeable by exim) |
+SAnotspamsave: /var/spool/exim/SAnotspam |
+ |
+# You can control which messages you want saved if you only want a subset |
+SAnotspamSavCond: 0 |
+ |
+# All the following strings can take one '%s' which will be replaced by |
+# spamstatus: "SA score, trigger score" |
+SAmsgteergrubewait: Wait for more output |
+SAmsgteergruberej: Please try again later |
+SAmsgpermrej: Rejected |
+SAmsgtemprej: Please try again later |
+# This string is a static string, do not include "%s" |
+SAmsgerror: Temporary local error while processing message, please contact postmaster. |
Index: branches/upstream/4.2.1/localscan_dlopen_exim_4.20_or_better.patch |
=================================================================== |
--- branches/upstream/4.2.1/localscan_dlopen_exim_4.20_or_better.patch (nonexistent) |
+++ branches/upstream/4.2.1/localscan_dlopen_exim_4.20_or_better.patch (revision 2) |
@@ -0,0 +1,268 @@ |
+The initial version of this patch was originally posted David Woodhouse, and |
+dman gets the credit for first integrating it with SA-Exim. |
+ |
+I have since then maintained it by first making a few minor changes, and |
+later switching it to a major/minor number scheme to support upgrades in |
+the exim API that don't affect backward compatibility (you can rely on |
+a feature denoted by the minor number and be compatible with future versions |
+of exim until Philip has to break the API and increase the major number) |
+ |
+Marc MERLIN <marc_soft@merlins.org> |
+ |
+diff -urN exim-4.14-0/src/EDITME exim-4.14-1/src/EDITME |
+--- exim-4.14-0/src/EDITME Tue Mar 11 04:20:18 2003 |
++++ exim-4.14-1/src/EDITME Sun Mar 23 15:34:15 2003 |
+@@ -388,6 +388,20 @@ |
+ |
+ |
+ #------------------------------------------------------------------------------ |
++# On systems which support dynamic loading of shared libraries, Exim can |
++# load a local_scan function specified in its config file instead of having |
++# to be recompiled with the desired local_scan function. For a full |
++# description of the API to this function, see the Exim specification. |
++ |
++DLOPEN_LOCAL_SCAN=yes |
++ |
++# If you set DLOPEN_LOCAL_SCAN, then you need to include -rdynamic in the |
++# linker flags. Without it, the loaded .so won't be able to access any |
++# functions from exim. |
++ |
++LFLAGS=-rdynamic -ldl |
++ |
++#------------------------------------------------------------------------------ |
+ # The default distribution of Exim contains only the plain text form of the |
+ # documentation. Other forms are available separately. If you want to install |
+ # the documentation in "info" format, first fetch the Texinfo documentation |
+diff -urNad 50_localscan_dlopen.tmp/src/config.h.defaults 50_localscan_dlopen/src/config.h.defaults |
+--- 50_localscan_dlopen.tmp/src/config.h.defaults Sun Dec 29 11:55:42 2002 |
++++ 50_localscan_dlopen/src/config.h.defaults Sun Dec 29 11:56:44 2002 |
+@@ -17,6 +17,8 @@ |
+ #define AUTH_PLAINTEXT |
+ #define AUTH_SPA |
+ |
++#define DLOPEN_LOCAL_SCAN |
++ |
+ #define BIN_DIRECTORY |
+ |
+ #define CONFIGURE_FILE |
+diff -urN exim-4.14-0/src/globals.c exim-4.14-1/src/globals.c |
+--- exim-4.14-0/src/globals.c Tue Mar 11 04:20:20 2003 |
++++ exim-4.14-1/src/globals.c Sun Mar 23 15:34:15 2003 |
+@@ -103,6 +103,9 @@ |
+ uschar *tls_verify_hosts = NULL; |
+ #endif |
+ |
++#ifdef DLOPEN_LOCAL_SCAN |
++uschar *local_scan_path = NULL; |
++#endif |
+ |
+ /* Input-reading functions for messages, so we can use special ones for |
+ incoming TCP/IP. The defaults use stdin. We never need these for any |
+diff -urN exim-4.14-0/src/globals.h exim-4.14-1/src/globals.h |
+--- exim-4.14-0/src/globals.h Tue Mar 11 04:20:20 2003 |
++++ exim-4.14-1/src/globals.h Sun Mar 23 15:34:15 2003 |
+@@ -67,6 +67,9 @@ |
+ extern uschar *tls_verify_hosts; /* Mandatory client verification */ |
+ #endif |
+ |
++#ifdef DLOPEN_LOCAL_SCAN |
++extern uschar *local_scan_path; /* Path to local_scan() library */ |
++#endif |
+ |
+ /* Input-reading functions for messages, so we can use special ones for |
+ incoming TCP/IP. */ |
+diff -urN exim-4.14-0/src/local_scan.c exim-4.14-1/src/local_scan.c |
+--- exim-4.14-0/src/local_scan.c Tue Mar 11 04:20:20 2003 |
++++ exim-4.14-1/src/local_scan.c Sun Mar 23 15:34:15 2003 |
+@@ -5,60 +5,131 @@ |
+ /* Copyright (c) University of Cambridge 1995 - 2003 */ |
+ /* See the file NOTICE for conditions of use and distribution. */ |
+ |
++#include "exim.h" |
+ |
+-/****************************************************************************** |
+-This file contains a template local_scan() function that just returns ACCEPT. |
+-If you want to implement your own version, you should copy this file to, say |
+-Local/local_scan.c, and edit the copy. To use your version instead of the |
+-default, you must set |
+- |
+-LOCAL_SCAN_SOURCE=Local/local_scan.c |
+- |
+-in your Local/Makefile. This makes it easy to copy your version for use with |
+-subsequent Exim releases. |
+- |
+-For a full description of the API to this function, see the Exim specification. |
+-******************************************************************************/ |
+- |
+- |
+-/* This is the only Exim header that you should include. The effect of |
+-including any other Exim header is not defined, and may change from release to |
+-release. Use only the documented interface! */ |
+- |
+-#include "local_scan.h" |
+- |
+- |
+-/* This is a "do-nothing" version of a local_scan() function. The arguments |
+-are: |
+- |
+- fd The file descriptor of the open -D file, which contains the |
+- body of the message. The file is open for reading and |
+- writing, but modifying it is dangerous and not recommended. |
+- |
+- return_text A pointer to an unsigned char* variable which you can set in |
+- order to return a text string. It is initialized to NULL. |
+- |
+-The return values of this function are: |
+- |
+- LOCAL_SCAN_ACCEPT |
+- The message is to be accepted. The return_text argument is |
+- saved in $local_scan_data. |
+- |
+- LOCAL_SCAN_REJECT |
+- The message is to be rejected. The returned text is used |
+- in the rejection message. |
+- |
+- LOCAL_SCAN_TEMPREJECT |
+- This specifies a temporary rejection. The returned text |
+- is used in the rejection message. |
+-*/ |
++#ifdef DLOPEN_LOCAL_SCAN |
++#include <dlfcn.h> |
++static int (*local_scan_fn)(int fd, uschar **return_text) = NULL; |
++static int load_local_scan_library(void); |
++#endif |
+ |
+ int |
+ local_scan(int fd, uschar **return_text) |
+ { |
+ fd = fd; /* Keep picky compilers happy */ |
+ return_text = return_text; |
+-return LOCAL_SCAN_ACCEPT; |
++#ifdef DLOPEN_LOCAL_SCAN |
++/* local_scan_path is defined AND not the empty string */ |
++if (local_scan_path && *local_scan_path) |
++ { |
++ if (!local_scan_fn) |
++ { |
++ if (!load_local_scan_library()) |
++ { |
++ char *base_msg , *error_msg , *final_msg ; |
++ int final_length = -1 ; |
++ |
++ base_msg=US"Local configuration error - local_scan() library failure\n"; |
++ error_msg = dlerror() ; |
++ |
++ final_length = strlen(base_msg) + strlen(error_msg) + 1 ; |
++ final_msg = (char*)malloc( final_length*sizeof(char) ) ; |
++ *final_msg = '\0' ; |
++ |
++ strcat( final_msg , base_msg ) ; |
++ strcat( final_msg , error_msg ) ; |
++ |
++ *return_text = final_msg ; |
++ return LOCAL_SCAN_TEMPREJECT; |
++ } |
++ } |
++ return local_scan_fn(fd, return_text); |
++ } |
++else |
++#endif |
++ return LOCAL_SCAN_ACCEPT; |
++} |
++ |
++#ifdef DLOPEN_LOCAL_SCAN |
++ |
++static int load_local_scan_library(void) |
++{ |
++/* No point in keeping local_scan_lib since we'll never dlclose() anyway */ |
++void *local_scan_lib = NULL; |
++int (*local_scan_version_fn)(void); |
++int vers_maj; |
++int vers_min; |
++ |
++local_scan_lib = dlopen(local_scan_path, RTLD_NOW); |
++if (!local_scan_lib) |
++ { |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library open failed - " |
++ "message temporarily rejected"); |
++ return FALSE; |
++ } |
++ |
++local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_major"); |
++if (!local_scan_version_fn) |
++ { |
++ dlclose(local_scan_lib); |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain " |
++ "local_scan_version_major() function - message temporarily rejected"); |
++ return FALSE; |
++ } |
++ |
++/* The major number is increased when the ABI is changed in a non |
++ backward compatible way. */ |
++vers_maj = local_scan_version_fn(); |
++ |
++local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_minor"); |
++if (!local_scan_version_fn) |
++ { |
++ dlclose(local_scan_lib); |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain " |
++ "local_scan_version_minor() function - message temporarily rejected"); |
++ return FALSE; |
++ } |
++ |
++/* The minor number is increased each time a new feature is added (in a |
++ way that doesn't break backward compatibility) -- Marc */ |
++vers_min = local_scan_version_fn(); |
++ |
++ |
++if (vers_maj != LOCAL_SCAN_ABI_VERSION_MAJOR) |
++ { |
++ dlclose(local_scan_lib); |
++ local_scan_lib = NULL; |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible major" |
++ "version number, you need to recompile your module for this version" |
++ "of exim (The module was compiled for version %d.%d and this exim provides" |
++ "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR, |
++ LOCAL_SCAN_ABI_VERSION_MINOR); |
++ return FALSE; |
++ } |
++else if (vers_min > LOCAL_SCAN_ABI_VERSION_MINOR) |
++ { |
++ dlclose(local_scan_lib); |
++ local_scan_lib = NULL; |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible minor" |
++ "version number, you need to recompile your module for this version" |
++ "of exim (The module was compiled for version %d.%d and this exim provides" |
++ "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR, |
++ LOCAL_SCAN_ABI_VERSION_MINOR); |
++ return FALSE; |
++ } |
++ |
++local_scan_fn = dlsym(local_scan_lib, "local_scan"); |
++if (!local_scan_fn) |
++ { |
++ dlclose(local_scan_lib); |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain " |
++ "local_scan() function - message temporarily rejected"); |
++ return FALSE; |
++ } |
++ |
++return TRUE; |
+ } |
++ |
++#endif /* DLOPEN_LOCAL_SCAN */ |
+ |
+ /* End of local_scan.c */ |
+diff -urN exim-4.14-0/src/readconf.c exim-4.14-1/src/readconf.c |
+--- exim-4.14-0/src/readconf.c Tue Mar 11 04:20:22 2003 |
++++ exim-4.14-1/src/readconf.c Sun Mar 23 15:34:15 2003 |
+@@ -182,6 +182,9 @@ |
+ { "local_from_prefix", opt_stringptr, &local_from_prefix }, |
+ { "local_from_suffix", opt_stringptr, &local_from_suffix }, |
+ { "local_interfaces", opt_stringptr, &local_interfaces }, |
++#ifdef DLOPEN_LOCAL_SCAN |
++ { "local_scan_path", opt_stringptr, &local_scan_path }, |
++#endif |
+ { "local_scan_timeout", opt_time, &local_scan_timeout }, |
+ { "local_sender_retain", opt_bool, &local_sender_retain }, |
+ { "localhost_number", opt_stringptr, &host_number_string }, |
Index: branches/upstream/4.2.1/Changelog.html |
=================================================================== |
--- branches/upstream/4.2.1/Changelog.html (nonexistent) |
+++ branches/upstream/4.2.1/Changelog.html (revision 2) |
@@ -0,0 +1,291 @@ |
+<!-- <li>2004/08/23 - v4.2.1+cvs (<a href="files/sa-exim-cvs.tar.gz">sa-exim cvs tar.gz</a> |
+ (latest version available via CVS only, or a somewhat recent via |
+ <a href="files/sa-exim-cvs.tar.gz">this link</a>) --> |
+ |
+<li>2006/01/09 - v4.2.1 (<a href="files/sa-exim-4.2.1.tar.gz">sa-exim.tar.gz</a> |
+or <a href="files/local_scan/local_scan.c_4.2.1">local_scan only</a>) |
+ <br><b>Security update</b> (reported by Chris Morris) |
+ <ul> |
+ <li>Modified Greylisting.pm not to generate tuplets with spaces, although |
+ the cleaning cron job is now safe with regard to whitespace |
+ <li>Included Mark Lawrence's perl script to better clean old tuplets |
+ <li>The default config now ships with the greylistclean cronjob running |
+ as nobody (which spamd should be running as, too) |
+ </ul> |
+ |
+<li>2005/01/17 - v4.2 (<a href="files/sa-exim-4.2.tar.gz">sa-exim.tar.gz</a> |
+or <a href="files/local_scan/local_scan.c_4.2">local_scan only</a>) |
+ <br><b>Do not use, greylistclean is insecure, use 4.2.1 instead</b> |
+ <ul> |
+ <li>Fixed code so that it compiles inside the exim tree too (thanks Jason) |
+ <li>Support SA 3.0 new score reporting format (score= instead of hits=) |
+ <li>Proper SA 3.0 plugin support |
+ <li>Documentation updates |
+ <li>greylisting files now also save the last SA score, just in case |
+ <li>Saved files are now group read/write too, if you need to shut off group |
+ access, do it at the directory level |
+ <li>Only rewrite Content-Type/Content-Transfer-Encoding if SARewriteBody is |
+ on now (this used to be useful with old SA versions and defang_mime |
+ but those options are gone). Suggested by Adam Tilghman. |
+ <li>Finally made all score threshold variables exim conditions that are |
+ evaluated at runtime |
+ <li>SAteergrubecond is deprecated as a result |
+ </ul> |
+ |
+<li>2004/08/16 - v4.1 (<a href="files/sa-exim-4.1.tar.gz">sa-exim.tar.gz</a> |
+or <a href="files/local_scan/local_scan.c_4.1">local_scan only</a>) |
+ <b>Please see the mailing list, or use the CVS version if you are compiling |
+ sa-exim inside your exim tree</b> (there is a small mistake in the source |
+ which will prevent proper building) / <b>You also need CVS if you are |
+ using SA 3.0</b> |
+ <ul> |
+ <li>Deal with being called with the number of recipients is 0 (reported by |
+ John Horne) |
+ <li>Made hopefully fully 64 bit clean (well, it was written that way, |
+ except for that pesky printf in C, which got in the way). Kudos go to |
+ Adam D. Barratt for finding and explaining the bug |
+ <li>Switched to using strchr instead of index to remove compilation warnings |
+ on some systems (reported by John Horne/Jeff Carter) |
+ <li>Added SAspamcHost/SAspamcPort at the request of several people |
+ <li>Fixed mbox From file to be standards complaint (reported by Cliff Hones) |
+ <li>Added SAFEMESGIDCHARS option for safer message-id based filenames |
+ <li>New version of the SA patch, with safe file creation (clean env from |
+ and rcpt to before using as directory names) |
+ <li><b>IMPORTANT</b>: if you are using greylisting, and applied the |
+ previous greylisting patch, it didn't create shell safe filenames, |
+ it is therefore highly recommended that you apply the new version |
+ <li>Added a quick patch to sa-exim to deal with headers that are longer |
+ than 8K (and drop the remaining lines) |
+ </ul> |
+ |
+ |
+<li>2004/03/16 - v4.0 (<a href="files/sa-exim-4.0.tar.gz">sa-exim.tar.gz</a> |
+or <a href="files/local_scan/local_scan.c_4.0">local_scan only</a>) |
+ <ul> |
+ <li>Added SAspamcpath (from Richard Lithvall) |
+ <li>Makefile fixes for version.h and dependencies |
+ <li>Added exim acl_m trick from Chirik in README |
+ <li>New code to read and pass on any X-Spam- header from SpamAssassin |
+ <li>Message-Id is now logged in SA log entries to allow you track down |
+ a message in other logfiles, like SA's log |
+ <li>Add X-SA-Exim-Connect-IP header for greylisting |
+ <li>Allow for tempreject on messages not flagged as spam by SA (for |
+ greylisting) |
+ <li>Added greylisting support (see README.greylisting) |
+ <li>Added the following options to sa-exim.conf: |
+ <ul> |
+ <li>SAspamcSockPath |
+ <li>SAgreylistiswhitestr |
+ <li>SAgreylistraisetempreject |
+ </ul> |
+ <li>Lots of documentation fixes and updates |
+ <li>Basic debian tree shipped by default (but real deb package from Sander |
+ Smeenk) |
+ </ul> |
+ |
+<li>2003/08/18 - v3.1 (<a href="files/sa-exim-3.1.tar.gz">sa-exim tar.gz</a> |
+ or <a href="files/local_scan/local_scan.c_3.1">local_scan only</a>) |
+ <ul> |
+ <li>Fixed <em>SA: Action: teergrubed sender until full configured duration</em> output |
+ <li>spamassassin.conf was renamed sa-exim.conf (bad initial name choice) |
+ <li>Changed teergrubing so that it works with exim 4.20 and above |
+ <li>Added the much requested SARewriteBody option for SA 2.50's report_safe |
+ (courtesy of Richard Lithvall) |
+ <li>Added SAaddSAEheaderBeforeSA to deal with SARewriteBody and privacy |
+ <li>Added SAPrependArchiveWithFrom option (Richard Lithvall) |
+ <li>As announced in the previous version, SAStallSender was removed. |
+ Use Teergrubing instead |
+ <li>Message-Id is read directly from Exim now that the API allows for that |
+ (we used to parse the Message-Id header ourselves) -> except that |
+ we don't use this for logging or saving messages: as soon as we can |
+ read the real Message-Id from the headers, we use that Message-Id for |
+ logging (this is to facilitate tracking of messages from the logs and |
+ correlating with something like SA timelog files) |
+ <li>Logging improved some more: Message-Id is added to log entries, as |
+ well as the full mailinfo whether the message is spam or not |
+ </ul> |
+ |
+<li>2003/04/30 - v3.0 (<a href="files/sa-exim-3.0.tar.gz">sa-exim tar.gz</a> |
+ or <a href="files/local_scan/local_scan.c_3.0">local_scan only</a>) |
+ <ul> |
+ <li>Makefile can generate a short sa-exim.conf (for Brian Kendig) |
+ <li>Added a contrib directory with 3rd party scripts |
+ <li>Since we already had X-SA-Exim-Rcpt-To: to show the envelope to |
+ (disabled by default), I added X-SA-Exim-Mail-From: to show the |
+ envelope from (always enabled, but you can delete it in system_filter |
+ if you wish). If you can't easily see or parse the envelope sender |
+ in your mails, this should definitely help |
+ <li>Much improved directory creation and error handling for the reject |
+ save directories |
+ <li>Added SIGCHLD patch from David Woodhouse |
+ <li>Added version header that looks like this: |
+ X-SA-Exim-Version: 2.2.x-cvs (built Tue Apr 22 10:28:25 PDT 2003) |
+ <li>Rewrote pretty much every log message to be more consistent and grepable |
+ (the previous ones were quite bad). Suggested by multiple people |
+ including Brian Kendig |
+ <li>Made the SMTP error messages finally configurable (suggested by |
+ several people). This is now possible since exim lets me output a |
+ different message in the log than in the SMTP session. Consequently, new |
+ default messages do not show the spam score, this only goes to the exim |
+ now. |
+ <li>Made SAmaxrcptlistlength and option to control how long of a |
+ X-SA-Exim-Rcpt-To header you can output if you want to output it at |
+ all |
+ <li>Do not output "savemail condition expanded to false" if not in debug |
+ mode (as reported by Brian Kendig) |
+ <li>Now ships with a sample local_scan.h if we can't find the exim source |
+ <li>Change of logic to delete SA headers that were in the original mail |
+ but weren't outputted by the SA run (like X-Spam-Flag, as reported |
+ by Chad Leigh) |
+ <li>Modified local_scan dlopen patch to deal with updates to the exim |
+ local_scan API |
+ <li>The default location for spamasassin.conf was changed to /etc/exim4 |
+ (debian default) |
+ <li>Updated README and INSTALL |
+ <li>Updated localscan_dlopen.patch to deal with minor/major version numbers |
+ <li>Added X-SA-Exim-Version |
+ </ul> |
+<li>2002/10/28 - v2.2 (<a href="files/sa-exim-2.2.tar.gz">sa-exim tar.gz</a> |
+ or <a href="files/local_scan/local_scan.c_2.2">local_scan only</a>) |
+ <ul> |
+ <li>Fixed a bug that affected all mails bigger than what spamc would |
+ accept. Doh! (it not clear why, but spamc would hang and stop reading |
+ after it had been fed more than it was willing to accept) |
+ <li>Added more debugging code to help track the above problem |
+ <li>Depending on SATruncBodyCond will now either not pass a message that's |
+ too big to spamc, or will optionally truncate it first |
+ <li>Now strips any X-SA-Exim-* headers already present in the message before |
+ scanning it |
+ <li>Added new X-SA-Exim-Rcpt-To: header (see privacy section in README) |
+ after a suggestion from Brian Kendig |
+ <li>Teergrube is now spelled correctly (note that the option names in |
+ sa-exim.conf changed as a result) |
+ <li>Teergrubing has been re-implemented to detect that the other side went |
+ away so that exim doesn't stay around for nothing. |
+ <li>Added SAteergrubecond so that you don't teergrube your neighbours |
+ <li>Small cleanups |
+ </ul> |
+<li>2002/10/13 - v2.1 (buggy) (<a href="files/sa-exim-2.1.tar.gz">sa-exim tar.gz</a> |
+ or <a href="files/local_scan/local_scan.c_2.1">local_scan only</a>) |
+ <ul> |
+ <li>Default mail config is now in /etc/exim instead of /etc/mail |
+ <li>Fixed SAstallsender so that exim doesn't leave spool files behind |
+ <li>Fixed comparison for spam values as suggested by Patrice Fournier |
+ <li>Returned a header saying whether SA-Exim was able to scan the mail |
+ or not (based on a suggestion from Patrice Fournier) |
+ <li>Added support for teergrubing as suggested by Robert Strickler |
+ (see |
+ <A HREF="http://www.iks-jena.de/mitarb/lutz/usenet/teergrube.en.html"> |
+ http://www.iks-jena.de/mitarb/lutz/usenet/teergrube.en.html</A>) |
+ <li>We now make sure that we feed spamc a little more data than it's |
+ willing to accept. That way, we don't feed a truncated message |
+ <li>sa-exim.conf now appends /new on save directories so that they |
+ are valid maildir spool and you can run mutt -f dirname to read |
+ <li>Small cleanups |
+ </ul> |
+ |
+<li>2002/07/07 - v2.0.1 (<a href="files/sa-exim-2.0.1.tar.gz">sa-exim tar.gz</a> |
+ or <a href="files/local_scan/local_scan.c_2.0.1">local_scan only</a>) |
+ <ul> |
+ <li>Removed unneeded ## concatenation in macro |
+ <li>Fixed lseek call, as reported by Peter N Lewis |
+ <li>Improved Makefile for documentation |
+ <li>Suggestion from dman to allow for config options overrides in Makefile |
+ <li>Fixed all the compiler warnings that were fixable |
+ <li>Handle more kinds of Message-Id as suggested by Patrice Fournier |
+ </ul> |
+ |
+<li>2002/06/14 - v2.0 (<a href="files/sa-exim-2.0.tar.gz">sa-exim tar.gz</a> |
+ or <a href="files/local_scan/local_scan.c_2.0">local_scan only</a>) |
+ <ul> |
+ <li>Allow for stalling SMTP sessions from spammers (caution) |
+ <li>Support X-Spam-Status from SA pre 2.30 |
+ <li>Build patches from Norm <norm@sandbox.org.uk> |
+ <li>Documented that spamd shouldn't be run with -c |
+ <li>dman's patch to allow for this to be a shared library |
+ <li>dman's indirect request for saved files to be 660 |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_2.0b1">2002/06/01 - v2.0b1</a><br> |
+ This is how 1.0 would have been if I had done it right :-) |
+ <ul> |
+ <li>We now attempt to create directories we write to |
+ (suggestion from Patrice Fournier) |
+ <li>Log envelope sender, recipients and connecting host |
+ on rejected messages (suggestion from Patrice Fournier) |
+ <li>We can now save non rejected messages whether they were |
+ flagged as spam or not (based on request from Patrice) |
+ <li>Each save rule now has its own condition that lets you |
+ decide which messages you want to save or not |
+ <li>Fixed parsing of Message-Id. May not parse all of them |
+ but won't do anything stupid with bad input |
+ <li>Fixed a buglet where we removed old headers before knowing |
+ whether they were going to be replaced. |
+ <li>Added much needed internal alarm so that we don't run |
+ too long |
+ <li>I added lots of options, but weren't able to test all |
+ of them and their combinations, please reports problems |
+ you may notice and documentation issues (in config file) |
+ <li>Thanks also go to dman for his plentiful feedback |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_1.3">2002/05/21 - v1.3</a> |
+ <ul> |
+ <li>We now close the files we create on disk. Duh! |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_1.2.2">2002/05/17 - v1.2.2</a> |
+ <ul> |
+ <li>SA options are now kept in memory. Small cleanups |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_1.2.1">2002/05/13 - v1.2.1</a> |
+ <ul> |
+ <li>v1.2 (unreleased) didn't work right: it tagged messages |
+ properly, but failed to see what was marked as spam and |
+ couldn't reject messages. Fixed. |
+ <li>Stripped newlines in header lines (better for logging) |
+ <li>fixed header_add bug if headers contained '%' |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_1.2">2002/05/12 - v1.2</a> (unreleased) |
+ <ul> |
+ <li>According to Craig R Hughes, any X-Spam header can be multiline. |
+ Let's parse them accordingly |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_1.1.1">2002/05/08 - v1.1.1</a> |
+ <ul> |
+ <li>Added fake envelope from to mails that we save on disk |
+ so that they can be opened with MUAs (idea from dman) |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_1.1">2002/05/07 - v1.1</a> |
+ <ul> |
+ <li>Cleaned up and fixed multiline header parsing |
+ <li>Added parsing of Subject back from Spamc (suggestion from dman) |
+ <li>We now log how long spamc took, and all messages processed |
+ by spamc get logged in mainlog so that we know the outcome |
+ <li>Added custom header compare function to handle mixed case headers |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_1.0.1">2002/05/06 - v1.0.1</a> |
+ <ul> |
+ <li>Fixed problems with reading Content-Type back from spamc |
+ (we used to read whole body too, ooops...) |
+ <li>Handle multi-line Content-Type headers. |
+ <li>All log entries now start with "SA: " |
+ <li>If SA gets run twice, we drop the previous X-Spam headers |
+ <li>Support for X-Spam-Prev-Content-Transfer-Encoding |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_1.0">2002/05/05 - v1.0</a> |
+ <ul> |
+ <li>*Many* changes. This is now a real program with hopefully |
+ most of the configuration options people could need |
+ <li>Fully configurable through external config file |
+ <li>Condition to run or not run SA against a message |
+ <li>3 Levels of spam handling |
+ <li>Option to save messages that are rejected or cause errors |
+ <li>Very complete error checking |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_0.9.1">2002/04/17 - v0.9.1</a> |
+ <ul> |
+ <li>Added a few checks for possible failures |
+ </ul> |
+<li><a href="files/local_scan/local_scan.c_0.9">2002/04/16 - v0.9</a> |
+ <ul> |
+ <li>Pre-release |
+ </ul> |
+</ul> |
Index: branches/upstream/4.2.1/eximinc/mytypes.h |
=================================================================== |
--- branches/upstream/4.2.1/eximinc/mytypes.h (nonexistent) |
+++ branches/upstream/4.2.1/eximinc/mytypes.h (revision 2) |
@@ -0,0 +1,95 @@ |
+/************************************************* |
+* Exim - an Internet mail transport agent * |
+*************************************************/ |
+ |
+/* Copyright (c) University of Cambridge 1995 - 2003 */ |
+/* See the file NOTICE for conditions of use and distribution. */ |
+ |
+ |
+/* This header file contains type definitions and macros that I use as |
+"standard" in the code of Exim and its utilities. Make it idempotent because |
+local_scan.h includes it and exim.h includes them both (to get this earlier). */ |
+ |
+#ifndef MYTYPES_H |
+#define MYTYPES_H |
+ |
+ |
+#define FALSE 0 |
+#define TRUE 1 |
+#define TRUE_UNSET 2 |
+ |
+ |
+/* If gcc is being used to compile Exim, we can use its facility for checking |
+the arguments of printf-like functions. This is done by a macro. */ |
+ |
+#ifdef __GNUC__ |
+#define PRINTF_FUNCTION __attribute__((format(printf,1,2))) |
+#else |
+#define PRINTF_FUNCTION |
+#endif |
+ |
+ |
+/* Some operating systems (naughtily, imo) include a definition for "uchar" in |
+the standard header files, so we use "uschar". Solaris has u_char in |
+sys/types.h. This is just a typing convenience, of course. */ |
+ |
+typedef int BOOL; |
+typedef unsigned char uschar; |
+ |
+ |
+/* These macros save typing for the casting that is needed to cope with the |
+mess that is "char" in ISO/ANSI C. Having now been bitten enough times by |
+systems where "char" is actually signed, I've converted Exim to use entirely |
+unsigned chars, except in a few special places such as arguments that are |
+almost always literal strings. */ |
+ |
+#define CS (char *) |
+#define CSS (char **) |
+#define US (unsigned char *) |
+#define USS (unsigned char **) |
+ |
+/* The C library string functions expect "char *" arguments. Use macros to |
+avoid having to write a cast each time. We do this for string and file |
+functions; for other calls to external libraries (which are on the whole |
+special-purpose) we just use casts. */ |
+ |
+ |
+#define Uatoi(s) atoi(CS(s)) |
+#define Uatol(s) atol(CS(s)) |
+#define Uchdir(s) chdir(CS(s)) |
+#define Uchmod(s,n) chmod(CS(s),n) |
+#define Uchown(s,n,m) chown(CS(s),n,m) |
+#define Ufgets(b,n,f) fgets(CS(b),n,f) |
+#define Ufopen(s,t) fopen(CS(s),CS(t)) |
+#define Ulink(s,t) link(CS(s),CS(t)) |
+#define Ulstat(s,t) lstat(CS(s),t) |
+#ifdef O_BINARY /* This is for Cygwin, */ |
+#define Uopen(s,n,m) open(CS(s),(n)|O_BINARY,m) /* where all files must */ |
+#else /* be opened as binary */ |
+#define Uopen(s,n,m) open(CS(s),n,m) /* to avoid problems */ |
+#endif /* with CRLF endings. */ |
+#define Uread(f,b,l) read(f,CS(b),l) |
+#define Urename(s,t) rename(CS(s),CS(t)) |
+#define Ustat(s,t) stat(CS(s),t) |
+#define Ustrcat(s,t) strcat(CS(s),CS(t)) |
+#define Ustrchr(s,n) US strchr(CS(s),n) |
+#define Ustrcmp(s,t) strcmp(CS(s),CS(t)) |
+#define Ustrcpy(s,t) strcpy(CS(s),CS(t)) |
+#define Ustrcspn(s,t) strcspn(CS(s),CS(t)) |
+#define Ustrftime(s,m,f,t) strftime(CS(s),m,f,t) |
+#define Ustrlen(s) (int)strlen(CS(s)) |
+#define Ustrncat(s,t,n) strncat(CS(s),CS(t),n) |
+#define Ustrncmp(s,t,n) strncmp(CS(s),CS(t),n) |
+#define Ustrncpy(s,t,n) strncpy(CS(s),CS(t),n) |
+#define Ustrpbrk(s,t) strpbrk(CS(s),CS(t)) |
+#define Ustrrchr(s,n) US strrchr(CS(s),n) |
+#define Ustrspn(s,t) strspn(CS(s),CS(t)) |
+#define Ustrstr(s,t) US strstr(CS(s),CS(t)) |
+#define Ustrtod(s,t) strtod(CS(s),CSS(t)) |
+#define Ustrtol(s,t,b) strtol(CS(s),CSS(t),b) |
+#define Ustrtoul(s,t,b) strtoul(CS(s),CSS(t),b) |
+#define Uunlink(s) unlink(CS(s)) |
+ |
+#endif |
+ |
+/* End of mytypes.h */ |
Index: branches/upstream/4.2.1/eximinc/store.h |
=================================================================== |
--- branches/upstream/4.2.1/eximinc/store.h (nonexistent) |
+++ branches/upstream/4.2.1/eximinc/store.h (revision 2) |
@@ -0,0 +1,53 @@ |
+/************************************************* |
+* Exim - an Internet mail transport agent * |
+*************************************************/ |
+ |
+/* Copyright (c) University of Cambridge 1995 - 2003 */ |
+/* See the file NOTICE for conditions of use and distribution. */ |
+ |
+/* Header for Exim's memory allocation functions */ |
+ |
+#ifndef STORE_H |
+#define STORE_H |
+ |
+/* Define symbols for identifying the two store pools. */ |
+ |
+#define POOL_MAIN 0 |
+#define POOL_PERM 1 |
+ |
+/* This variable is set by store_get() to its yield, and by store_reset() to |
+NULL. This allows string_cat() to optimize its store handling. */ |
+ |
+extern void *store_last_get; |
+ |
+/* This variable contains the current store pool number. */ |
+ |
+extern int store_pool; |
+ |
+/* Macros for calling the memory allocation routines with |
+tracing information for debugging. */ |
+ |
+#define store_extend(addr,old,new) \ |
+ store_extend_3(addr, old, new, __FILE__, __LINE__) |
+ |
+#define store_free(addr) store_free_3(addr, __FILE__, __LINE__) |
+#define store_get(size) store_get_3(size, __FILE__, __LINE__) |
+#define store_get_perm(size) store_get_perm_3(size, __FILE__, __LINE__) |
+#define store_malloc(size) store_malloc_3(size, __FILE__, __LINE__) |
+#define store_release(addr) store_release_3(addr, __FILE__, __LINE__) |
+#define store_reset(addr) store_reset_3(addr, __FILE__, __LINE__) |
+ |
+ |
+/* The real functions */ |
+ |
+extern BOOL store_extend_3(void *, int, int, char *, int); /* These use */ |
+extern void store_free_3(void *, char *, int); /* char * */ |
+extern void *store_get_3(int, char *, int); /* because */ |
+extern void *store_get_perm_3(int, char *, int); /* the */ |
+extern void *store_malloc_3(int, char *, int); /* value is */ |
+extern void store_release_3(void *, char *, int); /* always */ |
+extern void store_reset_3(void *, char *, int); /* __FILE__ */ |
+ |
+#endif /* STORE_H */ |
+ |
+/* End of store.h */ |
Index: branches/upstream/4.2.1/eximinc/local_scan.h |
=================================================================== |
--- branches/upstream/4.2.1/eximinc/local_scan.h (nonexistent) |
+++ branches/upstream/4.2.1/eximinc/local_scan.h (revision 2) |
@@ -0,0 +1,150 @@ |
+/************************************************* |
+* Exim - an Internet mail transport agent * |
+*************************************************/ |
+ |
+/* Copyright (c) University of Cambridge 1995 - 2003 */ |
+/* See the file NOTICE for conditions of use and distribution. */ |
+ |
+/* This file is the header that is the only Exim header to be included in the |
+source for the local_scan.c() function. It contains definitions that are made |
+available for use in that function, and which are documented. */ |
+ |
+ |
+/* Some basic types that make some things easier, and the store functions. */ |
+ |
+#include <sys/types.h> |
+#include "mytypes.h" |
+#include "store.h" |
+ |
+ |
+/* The function and its return codes. */ |
+ |
+extern int local_scan(int, uschar **); |
+ |
+enum { |
+ LOCAL_SCAN_ACCEPT, /* Accept */ |
+ LOCAL_SCAN_ACCEPT_FREEZE, /* Accept, but freeze */ |
+ LOCAL_SCAN_ACCEPT_QUEUE, /* Accept, but no immediate delivery */ |
+ LOCAL_SCAN_REJECT, /* Permanent rejection */ |
+ LOCAL_SCAN_REJECT_NOLOGHDR, /* Permanent rejection, no log header */ |
+ LOCAL_SCAN_TEMPREJECT, /* Temporary rejection */ |
+ LOCAL_SCAN_TEMPREJECT_NOLOGHDR /* Temporary rejection, no log header */ |
+}; |
+ |
+ |
+/* Return codes from the support functions lss_match_xxx(). */ |
+ |
+#define OK 0 /* Successful match */ |
+#define DEFER 1 /* Defer - some problem */ |
+#define FAIL 2 /* Matching failed */ |
+#define ERROR 3 /* Internal or config error */ |
+ |
+ |
+/* Available logging destinations */ |
+ |
+#define LOG_MAIN 1 /* Write to the main log */ |
+#define LOG_PANIC 2 /* Write to the panic log */ |
+#define LOG_REJECT 16 /* Write to the reject log, with headers */ |
+ |
+ |
+/* Accessible debugging bits */ |
+ |
+#define D_v 0x00000001 |
+#define D_local_scan 0x00000002 |
+ |
+ |
+/* Option types that can be used for local_scan_options. The boolean ones |
+MUST be last so that they are contiguous with the internal boolean specials. */ |
+ |
+enum { opt_stringptr, opt_int, opt_octint, opt_mkint, opt_fixed, opt_time, |
+ opt_bool }; |
+ |
+ |
+/* The length of message identification strings. This is the id used internally |
+by exim. The external version for use in Received: strings has a leading 'E' |
+added to ensure it starts with a letter. */ |
+ |
+#define MESSAGE_ID_LENGTH 16 |
+ |
+/* The offset to the start of the data in the data file - this allows for |
+the name of the data file to be present in the first line. */ |
+ |
+#define SPOOL_DATA_START_OFFSET (MESSAGE_ID_LENGTH+3) |
+ |
+/* local_scan() ABI version number for dynamic libraries |
+ The major number is increased when the ABI is changed in a non |
+ backward compatible way. |
+ The minor number is increased each time a new feature is added (in a |
+ way that doesn't break backward compatibility) -- Marc */ |
+#define LOCAL_SCAN_ABI_VERSION_MAJOR 1 |
+#define LOCAL_SCAN_ABI_VERSION_MINOR 0 |
+ |
+/* Structure definitions that are documented as visible in the function. */ |
+ |
+typedef struct header_line { |
+ struct header_line *next; |
+ int type; |
+ int slen; |
+ uschar *text; |
+} header_line; |
+ |
+/* Entries in lists options are in this form. */ |
+ |
+typedef struct { |
+ char *name; |
+ int type; |
+ void *value; |
+} optionlist; |
+ |
+/*Structure for holding information about an envelope address. The errors_to |
+field is always NULL except for one_time aliases that had errors_to on the |
+routers that generated them. */ |
+ |
+typedef struct recipient_item { |
+ uschar *address; /* the recipient address */ |
+ int pno; /* parent number for "one_time" alias, or -1 */ |
+ uschar *errors_to; /* the errors_to address or NULL */ |
+} recipient_item; |
+ |
+ |
+/* Global variables that are documented as visible in the function. */ |
+ |
+extern unsigned int debug_selector; /* Debugging bits */ |
+ |
+extern uschar *expand_string_message; /* Error info for failing expansion */ |
+extern header_line *header_last; /* Final header */ |
+extern header_line *header_list; /* First header */ |
+extern BOOL host_checking; /* Set when checking a host */ |
+extern uschar *interface_address; /* Interface for incoming call */ |
+extern int interface_port; /* Port number for incoming call */ |
+extern uschar *message_id; /* Internal id of message being handled */ |
+extern uschar *received_protocol; /* Name of incoming protocol */ |
+extern int recipients_count; /* Number of recipients */ |
+extern recipient_item *recipients_list;/* List of recipient addresses */ |
+extern unsigned char *sender_address; /* Sender address */ |
+extern uschar *sender_host_address; /* IP address of sender, as chars */ |
+extern uschar *sender_host_authenticated; /* Name of authentication mechanism */ |
+extern uschar *sender_host_name; /* Host name from lookup */ |
+extern int sender_host_port; /* Port number of sender */ |
+ |
+ |
+/* Functions that are documented as visible in local_scan(). */ |
+ |
+extern int child_close(pid_t, int); |
+extern pid_t child_open_exim(int *); |
+extern void debug_printf(char *, ...) PRINTF_FUNCTION; |
+extern uschar *expand_string(uschar *); |
+extern void header_add(int, char *, ...); |
+extern void log_write(unsigned int, int, char *format, ...); |
+extern int lss_b64decode(uschar *, uschar **); |
+extern uschar *lss_b64encode(uschar *, int); |
+extern int lss_match_domain(uschar *, uschar *); |
+extern int lss_match_local_part(uschar *, uschar *, BOOL); |
+extern int lss_match_address(uschar *, uschar *, BOOL); |
+extern int lss_match_host(uschar *, uschar *, uschar *); |
+extern void receive_add_recipient(uschar *, int); |
+extern uschar *string_copy(uschar *); |
+extern uschar *string_copyn(uschar *, int); |
+extern uschar *string_sprintf(char *, ...); |
+ |
+/* End of local_scan.h */ |
Index: branches/upstream/4.2.1/eximinc/version |
=================================================================== |
--- branches/upstream/4.2.1/eximinc/version (nonexistent) |
+++ branches/upstream/4.2.1/eximinc/version (revision 2) |
@@ -0,0 +1 @@ |
+exim-4.14 |
Index: branches/upstream/4.2.1/eximinc/README |
=================================================================== |
--- branches/upstream/4.2.1/eximinc/README (nonexistent) |
+++ branches/upstream/4.2.1/eximinc/README (revision 2) |
@@ -0,0 +1,6 @@ |
+In order to faciliate building on systems that have exim installed but don't |
+have the exim source, I am including includes from a recent exim version. |
+While I am keeping track of which version, this shouldn't be necessary as |
+the local_scan API is supposed to be upward compatible |
+(technically, we should raise LOCAL_SCAN_ABI_VERSION every time Philip |
+adds a feature to the API -- Marc) |
Index: branches/upstream/4.2.1/README.greylisting |
=================================================================== |
--- branches/upstream/4.2.1/README.greylisting (nonexistent) |
+++ branches/upstream/4.2.1/README.greylisting (revision 2) |
@@ -0,0 +1,258 @@ |
+ GREYLISTING with SA-Exim |
+ ------------------------ |
+ |
+ |
+INTRODUCTION |
+------------ |
+SA-Exim allows for intelligent greylisting by combining the idea of greylisting |
+with Spam scores from SpamAssassin |
+ |
+If you don't know what greylisting is, you should probably go read up there: |
+http://projects.puremagic.com/greylisting/ |
+(note that this implementation works differently than the one described there) |
+ |
+So, SA-Exim isn't just yet another greylisting implementation. By tying it |
+into SA-Exim, and especially by running SA at SMTP time, you can do the |
+following things: |
+- do not bother greylisting people who send messages detected as spam by SA |
+ (indeed, regular greylisting will accept mail from a spammer if he retries |
+ or sends it from an open relay) |
+ SA-Exim will never greylist, or whitelist a sender based on a mail clearly |
+ marked as spam by SA. |
+ |
+- do not delay mail from people who aren't spamming you (this one is the most |
+ important feature of SA-Exim greylisting, as it removes the biggest |
+ disadvantage linkes to greylisting) |
+ |
+- only greylist (and maybe later whitelist) hosts that send you mail with |
+ a certain SA score. |
+ |
+ |
+IMPLEMENTATION |
+-------------- |
+So how does this all work? |
+SA comes with a patch for SA 2.x (and a module for SA 3.x) that does the |
+following things: |
+- add a greylisting rule which gets run at the very end, and where if |
+ the score is already higher than a configured value, we do not bother |
+ greylisting the host. We just return a rule failure, which doesn't |
+ change the score and lets SA-Exim reject the mail as usual |
+- if the score is lower than the "surely spam" threshold (shown as 11 in the |
+ example below), check for a file in |
+ /var/spool/sa-exim/messageids/co/nn/ect/ip/envfrom/envto |
+ - if it's there, check if it was written more than x seconds ago (1800s/30mn |
+ in the example below) |
+ - if so, change the status to whitelisted and return true so that SA applies |
+ the whitelist negative score |
+ - if not, simply increase counters, host is still greylisted |
+ - if the file is not there, create it |
+- every x time (like 4 hours or two days), remove all greylist entries that |
+ only saw one mail (i.e. still greylisted, not whitelisted yet). |
+ This is done with a find cron job |
+- every y time (like 1 week), remove whitelisted entries so that your filesystem |
+ doesn't clutter up with hosts you're not going to hear from again in a while |
+ |
+ |
+Then, you call the greylisting rule with this (in SA's local.cf) |
+# reseval is a special eval which only runs after you have the result from |
+# everything else (lets us not greylist a host that is sending spam, otherwise |
+# this rule might set a sufficiently negative score that the next spam would |
+# be allowed in) |
+# Note the 'key' -> 'value'; syntax. It's a special hack to go through SA's |
+# config parser. You need to keep that exact syntax |
+# greylistsecs: how long you greylist a tuplet because whitelisting it |
+# greylistnullfrom: set to 1 to also greylist mail with a null env from |
+# greylistfourthbyte: keep the 4 bytes of the connecting host instead of 3 |
+header GREYLIST_ISWHITE reseval:greylisting("( 'dir' => '/var/spool/sa-exim/tuplets'; 'method' => 'dir'; 'greylistsecs' => '1800'; 'dontgreylistthreshold' => 11; 'connectiphdr' => 'X-SA-Exim-Connect-IP'; 'envfromhdr' => 'X-SA-Exim-Mail-From'; 'rcpttohdr' => 'X-SA-Exim-Rcpt-To'; 'greylistnullfrom' => 0; 'greylistfourthbyte' => 0 )") |
+describe GREYLIST_ISWHITE The incoming server has been whitelisted for this rece |
+ipient and sender |
+score GREYLIST_ISWHITE -1.5 |
+ |
+Note that SA greylisting depends on X-SA-Exim-Rcpt-To, so you have to ensure |
+that SAmaxrcptlistlength is set to a reasonably high value (up to 8000) instead |
+of the current default of 0 (you can remove the header in exim's system_filter |
+or a transport if you don't want it to show in user's mails, see "privacy |
+warning" in README) |
+ |
+ |
+Now, in case you aren't confused yet, you get even more knobs to play with :) |
+If a spammer resends you a spam until it gets whitelisted (or typically, it |
+gets sent to a relay that resends it to you), even if you are setup to |
+accept the spam at the point, you don't want to lower the SA score too much |
+just because the mail was resent to you several times (i.e. a rather negative |
+score for GREYLIST_ISWHITE). So, you can actually configure SA-Exim to temp |
+reject messages on a much higher score than usual, if they don't have the |
+GREYLIST_ISWHITE tag. |
+ |
+In other words, let's say you have this in sa-exim.conf: |
+SApermreject: 11.0 |
+SAtempreject: 3.0 |
+SAgreylistraisetempreject: 6.5 |
+ |
+If a mail comes in at less than 3.0, the SA patch/module remembers the sending |
+server's connecting IP, the env from, and the rcpt to(s), and whitelists those. |
+(those will be referred to as tuplets, one for each rcpt to) |
+ |
+If the score is between 3.0 and 11.0, |
+- if at least one of the tuplets is already whitelisted, SA applies the -1.5 |
+ score and yields an end score below 9.5, Now, at the same time, SAtempreject |
+ is temporarily raised by 6.5, so everything under 9.5 is accepted, which |
+ basically means that the mail goes through. |
+- if none of the tuplets are whitelisted, they get greylisted |
+- if they are greylisted, they can get upgraded to whitelisted status if the |
+ sending server has been trying for long enough (1800secs in the example given |
+ above). At this point the same thing happens as in case #1 and the mail is |
+ accepted |
+ |
+If a tuplet that is going to be whitelisted or greylisted, already is, SA |
+updates counters to let you run reports and anything else you want, like |
+deciding if or when you'd like to expire the entry |
+ |
+If by now you wonder why you would want to both decrease the SA score and |
+increase the maximum score you'll accept mails on, the reason is as follows: |
+You probably don't want to lower the SA score by 8 just because the tuplet |
+is whitelisted (not only does it mess with the SA scoring of messages that used |
+to be flagged as spam, but a spam with a score of 13.5 would then be lowered |
+to 5.5, be temprejected, and be close to the accept range). |
+Instead, giving an SA score of -1.5, a message with 13.5 becomes 12.0 and still |
+gets rejected right away. You also do not overly (and artifically) lower the |
+score of a message, just for SA-Exim's sake |
+ |
+If you so wish, you can also give the SA rule a score of -0.1, and only |
+dynamically raise the tempreject score for messages that are whitelisted. |
+ |
+ |
+SCORE SETUP |
+----------- |
+It makes little sense to have |
+SAtempreject + SAgreylistraisetempreject + SA GREYLIST_ISWHITE > SApermreject |
+as there is little point to raise SAtempreject if the message that's |
+whitelisted still gets refused by the SApermreject score |
+ |
+As to whether you want to put more points into SA GREYLIST_ISWHITE or |
+SAgreylistraisetempreject, this is your call, but as a general rule, you only |
+want to change the SA score in a way that makes sense for spam scoring, |
+as it similarly affects the score of all messages, whether SA-Exim sees them |
+in the non spam range, tempreject range, or "this is spam that I would never |
+let in" range. |
+ |
+ |
+FILE SETUP |
+---------- |
+Make very sure that uid nobody can traverse /var/spool/sa-exim and |
+create tuplets writeable by nobody (or whoever you run SA as) |
+ |
+Then, setup a cron job to delete tuplets that are older than 14 days for |
+whitelisted entries, and 2 days for greylisted entries (or whatever |
+values you fancy). |
+Note that because this implementation does not systematically force the senders to resend you mail, unless they sent something that looks too much like spam, |
+you will typically see few whitelisted entries, and those will either be |
+potential spam that was actually resent to you at least 30mn after the |
+initial copy (or whatever value you setup in "header GREYLIST_ISWHITE"), or |
+people who sent you several Emails (where the second Email will just happen to |
+trigger a whitelisting). |
+ |
+ |
+FILE SETUP |
+---------- |
+You should install greylistclean.cron in /etc/cron.d/ on your system to |
+call greylistclean and clean up greylisted entries and whitelisted entries |
+that haven't been used in a while. |
+You can optionally modify it to tweak the cleanup times. |
+Note that you need to tweak greylistclean.cron to match the user spamd runs |
+as if you aren't using the recommended --username=nobody |
+ |
+ |
+SA PATCH (SA 2.x) |
+----------------- |
+For all this to work, you also need to patch SA with SA-greylist.diff |
+from the source tar (or /usr/share/doc/sa-exim*/ for a precompiled package). |
+This patch never made it to the main SA 2.x branch as the developers had mostly |
+switched to 3.x where you can use plugins. |
+If you still use SA 3.x, you can go to /usr/share/perl5/Mail (or wherever |
+appropriate on your system), and run |
+patch -p0 -s < /path/to/sa-exim/SA-greylisting.diff |
+Note that while the patch works, it will not be maintained anymore since |
+it is deprecated for the SA 3.x plugin |
+ |
+ |
+SA PLUGIN (SA 3.x) |
+------------------ |
+Newer versions of SpamAssassin support plugins, so there is no need to |
+patch SA anymore, you can just install the Greylisting.pm module on your |
+system and get SA to use it |
+This is how you call the module in SA 3.x (i.e. put this in your |
+/etc/spamassassin/local.cf) |
+ |
+# Note the 'key' -> 'value'; syntax. It's a special hack to go through SA's |
+# config parser. You need to keep that exact syntax |
+# greylistsecs: how long you greylist a tuplet because whitelisting it |
+# greylistnullfrom: set to 1 to also greylist mail with a null env from |
+# greylistfourthbyte: keep the 4 bytes of the connecting host instead of 3 |
+loadplugin Greylisting /usr/share/perl5/Mail/SpamAssassin/Plugin/Greylisting.pm |
+header GREYLIST_ISWHITE eval:greylisting("( 'dir' => '/var/spool/sa-exim/tuplets'; 'method' => 'dir'; 'greylistsecs' => '1800'; 'dontgreylistthreshold' => 11; 'connectiphdr' => 'X-SA-Exim-Connect-IP'; 'envfromhdr' => 'X-SA-Exim-Mail-From'; 'rcpttohdr' => 'X-SA-Exim-Rcpt-To'; 'greylistnullfrom' => 1; 'greylistfourthbyte' => 0 )") |
+describe GREYLIST_ISWHITE The incoming server has been whitelisted for this recipient and sender |
+score GREYLIST_ISWHITE -1.5 |
+# Run SpamAssassin last, after all other rules. |
+# (lets us not greylist a host that is sending spam, otherwise this rule might |
+# set a sufficiently negative score that the next spam would be allowed in) |
+priority GREYLIST_ISWHITE 99999 |
+ |
+ |
+SA-EXIM NEW BEHAVIOR CONCERNS |
+----------------------------- |
+What greylisting changes as far as spam accepting or rejection is concerned: |
+Once a tuplet has been whitelisted, spam from that host is more likely |
+to be accepted until the tuplet expires. In the case of a mailing list, |
+unless you run a find / rm based on the creation time and not the last |
+modified time, you will then be a bit more likely to accept spam from |
+that list. |
+If this turns out to not be acceptable in your case, there isn't a whole |
+lot you can do about this, except deleting greylist entries for the host |
+from cron before they get promoted to whitelist. |
+ |
+What you can do on top of the existing greylisting code: |
+Parse the SA-Exim logs and if you get spam from an IP, you can decide |
+to delete greylist entries in /var/spool/sa-exim/tuplets/IP or just |
+/var/spool/sa-exim/tuplets/IP/envfrom |
+This may not may not be a good thing if you receive the occasional spam |
+from a mailing list as you'll then re-delay mail for that list, but then |
+again, it will also remove whitelisting for a host that spammed you once |
+with an Email that managed to get under the SA scoring radar |
+ |
+ |
+GREYLISTING AND MXES |
+-------------------- |
+Depending on your configuration, you may have realized that SA-Exim doesn't |
+play very well with secondary MXes for your domain if they don't run SA-Exim |
+too (for instance, you'd send a tempreject on spam and clog up your |
+secondary, or maybe even teergrube it if you forgot to add your MX's IP |
+in the do not teergrube list. |
+For greylisting, it's even more simple: |
+If your secondary MXes aren't running SA-Exim with greylisting, then |
+greylisting's efficiency will be greatly reduced as most spammers will send |
+their spams to your secondary MXes which will accept the mail for you, |
+even if it's sent only once, and then your MXes will resend the spam to you |
+until you accept it (rendering greylisting useless) |
+ |
+Now, if your secondaries are running greylisting too, most mail will flow |
+through with no delay whatsoever. However, in the worst case scenario, a mail |
+that isn't spam, but triggers greylisting because its score is high enough to |
+generate a tempreject, could be delayed up to twice the whitelisting time |
+if it were to go to your secondary MX first (assuming your primary is |
+unreachable or temporarily overloaded), and then be resent to your primary |
+MX, which would trigger a second greylisting delay |
+FIXME: implement a whitelist of sending IPs so that greylisting returns |
+whitelisted right away |
+ |
+ |
+SECURITY |
+-------- |
+The greylisting function works around the SA parser by sending all the options |
+as a hash inside a string. In turn, greylisting evals the said string. |
+This is a security problem if you allow your users to run custom rules and it |
+gives them access to run spamassassin as a user different from their own, or |
+in a way that they otherwise wouldn't be able to. |
+Do not run greylisting if this a problem for you (in the default SA/SA-Exim |
+setup, this shouldn't be a concern since it doesn't even parse users' config |
+files) |
Index: branches/upstream/4.2.1/localscan_dlopen_up_to_exim_4.14.patch |
=================================================================== |
--- branches/upstream/4.2.1/localscan_dlopen_up_to_exim_4.14.patch (nonexistent) |
+++ branches/upstream/4.2.1/localscan_dlopen_up_to_exim_4.14.patch (revision 2) |
@@ -0,0 +1,287 @@ |
+The initial version of this patch was originally posted David Woodhouse, and |
+dman gets the credit for first integrating it with SA-Exim. |
+ |
+I have since then maintained it by first making a few minor changes, and |
+later switching it to a major/minor number scheme to support upgrades in |
+the exim API that don't affect backward compatibility (you can rely on |
+a feature denoted by the minor number and be compatible with future versions |
+of exim until Philip has to break the API and increase the major number) |
+ |
+Marc MERLIN <marc_soft@merlins.org> |
+ |
+diff -urN exim-4.14-0/src/EDITME exim-4.14-1/src/EDITME |
+--- exim-4.14-0/src/EDITME Tue Mar 11 04:20:18 2003 |
++++ exim-4.14-1/src/EDITME Sun Mar 23 15:34:15 2003 |
+@@ -388,6 +388,20 @@ |
+ |
+ |
+ #------------------------------------------------------------------------------ |
++# On systems which support dynamic loading of shared libraries, Exim can |
++# load a local_scan function specified in its config file instead of having |
++# to be recompiled with the desired local_scan function. For a full |
++# description of the API to this function, see the Exim specification. |
++ |
++DLOPEN_LOCAL_SCAN=yes |
++ |
++# If you set DLOPEN_LOCAL_SCAN, then you need to include -rdynamic in the |
++# linker flags. Without it, the loaded .so won't be able to access any |
++# functions from exim. |
++ |
++LFLAGS=-rdynamic -ldl |
++ |
++#------------------------------------------------------------------------------ |
+ # The default distribution of Exim contains only the plain text form of the |
+ # documentation. Other forms are available separately. If you want to install |
+ # the documentation in "info" format, first fetch the Texinfo documentation |
+diff -urNad 50_localscan_dlopen.tmp/src/config.h.defaults 50_localscan_dlopen/src/config.h.defaults |
+--- 50_localscan_dlopen.tmp/src/config.h.defaults Sun Dec 29 11:55:42 2002 |
++++ 50_localscan_dlopen/src/config.h.defaults Sun Dec 29 11:56:44 2002 |
+@@ -17,6 +17,8 @@ |
+ #define AUTH_PLAINTEXT |
+ #define AUTH_SPA |
+ |
++#define DLOPEN_LOCAL_SCAN |
++ |
+ #define BIN_DIRECTORY |
+ |
+ #define CONFIGURE_FILE |
+diff -urN exim-4.14-0/src/globals.c exim-4.14-1/src/globals.c |
+--- exim-4.14-0/src/globals.c Tue Mar 11 04:20:20 2003 |
++++ exim-4.14-1/src/globals.c Sun Mar 23 15:34:15 2003 |
+@@ -103,6 +103,9 @@ |
+ uschar *tls_verify_hosts = NULL; |
+ #endif |
+ |
++#ifdef DLOPEN_LOCAL_SCAN |
++uschar *local_scan_path = NULL; |
++#endif |
+ |
+ /* Input-reading functions for messages, so we can use special ones for |
+ incoming TCP/IP. The defaults use stdin. We never need these for any |
+diff -urN exim-4.14-0/src/globals.h exim-4.14-1/src/globals.h |
+--- exim-4.14-0/src/globals.h Tue Mar 11 04:20:20 2003 |
++++ exim-4.14-1/src/globals.h Sun Mar 23 15:34:15 2003 |
+@@ -67,6 +67,9 @@ |
+ extern uschar *tls_verify_hosts; /* Mandatory client verification */ |
+ #endif |
+ |
++#ifdef DLOPEN_LOCAL_SCAN |
++extern uschar *local_scan_path; /* Path to local_scan() library */ |
++#endif |
+ |
+ /* Input-reading functions for messages, so we can use special ones for |
+ incoming TCP/IP. */ |
+diff -urN exim-4.14-0/src/local_scan.c exim-4.14-1/src/local_scan.c |
+--- exim-4.14-0/src/local_scan.c Tue Mar 11 04:20:20 2003 |
++++ exim-4.14-1/src/local_scan.c Sun Mar 23 15:34:15 2003 |
+@@ -5,60 +5,131 @@ |
+ /* Copyright (c) University of Cambridge 1995 - 2003 */ |
+ /* See the file NOTICE for conditions of use and distribution. */ |
+ |
++#include "exim.h" |
+ |
+-/****************************************************************************** |
+-This file contains a template local_scan() function that just returns ACCEPT. |
+-If you want to implement your own version, you should copy this file to, say |
+-Local/local_scan.c, and edit the copy. To use your version instead of the |
+-default, you must set |
+- |
+-LOCAL_SCAN_SOURCE=Local/local_scan.c |
+- |
+-in your Local/Makefile. This makes it easy to copy your version for use with |
+-subsequent Exim releases. |
+- |
+-For a full description of the API to this function, see the Exim specification. |
+-******************************************************************************/ |
+- |
+- |
+-/* This is the only Exim header that you should include. The effect of |
+-including any other Exim header is not defined, and may change from release to |
+-release. Use only the documented interface! */ |
+- |
+-#include "local_scan.h" |
+- |
+- |
+-/* This is a "do-nothing" version of a local_scan() function. The arguments |
+-are: |
+- |
+- fd The file descriptor of the open -D file, which contains the |
+- body of the message. The file is open for reading and |
+- writing, but modifying it is dangerous and not recommended. |
+- |
+- return_text A pointer to an unsigned char* variable which you can set in |
+- order to return a text string. It is initialized to NULL. |
+- |
+-The return values of this function are: |
+- |
+- LOCAL_SCAN_ACCEPT |
+- The message is to be accepted. The return_text argument is |
+- saved in $local_scan_data. |
+- |
+- LOCAL_SCAN_REJECT |
+- The message is to be rejected. The returned text is used |
+- in the rejection message. |
+- |
+- LOCAL_SCAN_TEMPREJECT |
+- This specifies a temporary rejection. The returned text |
+- is used in the rejection message. |
+-*/ |
++#ifdef DLOPEN_LOCAL_SCAN |
++#include <dlfcn.h> |
++static int (*local_scan_fn)(int fd, uschar **return_text) = NULL; |
++static int load_local_scan_library(void); |
++#endif |
+ |
+ int |
+ local_scan(int fd, uschar **return_text) |
+ { |
+ fd = fd; /* Keep picky compilers happy */ |
+ return_text = return_text; |
+-return LOCAL_SCAN_ACCEPT; |
++#ifdef DLOPEN_LOCAL_SCAN |
++/* local_scan_path is defined AND not the empty string */ |
++if (local_scan_path && *local_scan_path) |
++ { |
++ if (!local_scan_fn) |
++ { |
++ if (!load_local_scan_library()) |
++ { |
++ char *base_msg , *error_msg , *final_msg ; |
++ int final_length = -1 ; |
++ |
++ base_msg=US"Local configuration error - local_scan() library failure\n"; |
++ error_msg = dlerror() ; |
++ |
++ final_length = strlen(base_msg) + strlen(error_msg) + 1 ; |
++ final_msg = (char*)malloc( final_length*sizeof(char) ) ; |
++ *final_msg = '\0' ; |
++ |
++ strcat( final_msg , base_msg ) ; |
++ strcat( final_msg , error_msg ) ; |
++ |
++ *return_text = final_msg ; |
++ return LOCAL_SCAN_TEMPREJECT; |
++ } |
++ } |
++ return local_scan_fn(fd, return_text); |
++ } |
++else |
++#endif |
++ return LOCAL_SCAN_ACCEPT; |
++} |
++ |
++#ifdef DLOPEN_LOCAL_SCAN |
++ |
++static int load_local_scan_library(void) |
++{ |
++/* No point in keeping local_scan_lib since we'll never dlclose() anyway */ |
++void *local_scan_lib = NULL; |
++int (*local_scan_version_fn)(void); |
++int vers_maj; |
++int vers_min; |
++ |
++local_scan_lib = dlopen(local_scan_path, RTLD_NOW); |
++if (!local_scan_lib) |
++ { |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library open failed - " |
++ "message temporarily rejected"); |
++ return FALSE; |
++ } |
++ |
++local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_major"); |
++if (!local_scan_version_fn) |
++ { |
++ dlclose(local_scan_lib); |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain " |
++ "local_scan_version_major() function - message temporarily rejected"); |
++ return FALSE; |
++ } |
++ |
++/* The major number is increased when the ABI is changed in a non |
++ backward compatible way. */ |
++vers_maj = local_scan_version_fn(); |
++ |
++local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_minor"); |
++if (!local_scan_version_fn) |
++ { |
++ dlclose(local_scan_lib); |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain " |
++ "local_scan_version_minor() function - message temporarily rejected"); |
++ return FALSE; |
++ } |
++ |
++/* The minor number is increased each time a new feature is added (in a |
++ way that doesn't break backward compatibility) -- Marc */ |
++vers_min = local_scan_version_fn(); |
++ |
++ |
++if (vers_maj != LOCAL_SCAN_ABI_VERSION_MAJOR) |
++ { |
++ dlclose(local_scan_lib); |
++ local_scan_lib = NULL; |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible major" |
++ "version number, you need to recompile your module for this version" |
++ "of exim (The module was compiled for version %d.%d and this exim provides" |
++ "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR, |
++ LOCAL_SCAN_ABI_VERSION_MINOR); |
++ return FALSE; |
++ } |
++else if (vers_min > LOCAL_SCAN_ABI_VERSION_MINOR) |
++ { |
++ dlclose(local_scan_lib); |
++ local_scan_lib = NULL; |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible minor" |
++ "version number, you need to recompile your module for this version" |
++ "of exim (The module was compiled for version %d.%d and this exim provides" |
++ "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR, |
++ LOCAL_SCAN_ABI_VERSION_MINOR); |
++ return FALSE; |
++ } |
++ |
++local_scan_fn = dlsym(local_scan_lib, "local_scan"); |
++if (!local_scan_fn) |
++ { |
++ dlclose(local_scan_lib); |
++ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain " |
++ "local_scan() function - message temporarily rejected"); |
++ return FALSE; |
++ } |
++ |
++return TRUE; |
+ } |
++ |
++#endif /* DLOPEN_LOCAL_SCAN */ |
+ |
+ /* End of local_scan.c */ |
+diff -urN exim-4.14-0/src/local_scan.h exim-4.14-1/src/local_scan.h |
+--- exim-4.14-0/src/local_scan.h Tue Mar 11 04:20:20 2003 |
++++ exim-4.14-1/src/local_scan.h Sun Mar 23 15:34:57 2003 |
+@@ -71,6 +71,15 @@ |
+ |
+ #define SPOOL_DATA_START_OFFSET (MESSAGE_ID_LENGTH+3) |
+ |
++/* local_scan() ABI version number for dynamic libraries |
++ The major number is increased when the ABI is changed in a non |
++ backward compatible way. |
++ The minor number is increased each time a new feature is added (in a |
++ way that doesn't break backward compatibility) -- Marc */ |
++#define LOCAL_SCAN_ABI_VERSION_MAJOR 1 |
++#define LOCAL_SCAN_ABI_VERSION_MINOR 0 |
++#define LOCAL_SCAN_ABI_VERSION \ |
++ LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR |
+ |
+ /* Structure definitions that are documented as visible in the function. */ |
+ |
+diff -urN exim-4.14-0/src/readconf.c exim-4.14-1/src/readconf.c |
+--- exim-4.14-0/src/readconf.c Tue Mar 11 04:20:22 2003 |
++++ exim-4.14-1/src/readconf.c Sun Mar 23 15:34:15 2003 |
+@@ -182,6 +182,9 @@ |
+ { "local_from_prefix", opt_stringptr, &local_from_prefix }, |
+ { "local_from_suffix", opt_stringptr, &local_from_suffix }, |
+ { "local_interfaces", opt_stringptr, &local_interfaces }, |
++#ifdef DLOPEN_LOCAL_SCAN |
++ { "local_scan_path", opt_stringptr, &local_scan_path }, |
++#endif |
+ { "local_scan_timeout", opt_time, &local_scan_timeout }, |
+ { "local_sender_retain", opt_bool, &local_sender_retain }, |
+ { "localhost_number", opt_stringptr, &host_number_string }, |
Index: branches/upstream/4.2.1/README |
=================================================================== |
--- branches/upstream/4.2.1/README (nonexistent) |
+++ branches/upstream/4.2.1/README (revision 2) |
@@ -0,0 +1,352 @@ |
+COPYRIGHTS |
+---------- |
+SA-Exim was written by Marc MERLIN <marc_soft@merlins.org> |
+You can find the latest version here: |
+ http://sa-exim.sf.net/ |
+or here: |
+ http://marc.merlins.org/linux/exim/sa.html |
+ |
+greylisting was written by and is copyright Mark Lawrence <nomad@null.net> |
+ |
+ |
+INSTALL |
+------- |
+See the file named INSTALL for installations instructions (either compiled |
+in exim, or as a stand-alone shared library) |
+ |
+If you got sa-exim prepackaged (like on debian), you have to make sure that |
+your exim supports a dynamically loadable local_scan (which is true on debian |
+and probably on other distros too if they shipped sa-exim as a package), and |
+that your exim4.conf file contains the following: |
+local_scan_path = /usr/lib/exim4/local_scan/sa-exim.so |
+If you are using the split configuration file on debian with the sa-exim deb |
+package, you'll be fine. If you're using the monolithic file, you are on your |
+own until/unless the sa-exim packages try to do an in place edit (i.e. you have |
+to add the above configuration line yourself) |
+ |
+ |
+UPGRADING |
+--------- |
+Deleting greylisting tuplets pre-4.2.1: |
+If you are installing this package yourself, and ever installed the old |
+greylistclean.cron which contained the complicated shell commands to clean |
+old tuplets, you should stop using those commands and upgrade to greylistclean. |
+Upgrading Greylisting.pm should also create safer tuplets without whitespace, |
+but it's better to get rid of the old shell cron jobs either way |
+ |
+ |
+PRIVACY WARNING |
+--------------- |
+SA-Exim can add a header with the list of recipients in an Email (including |
+Bcced folks). |
+X-SA-Exim-Rcpt-To is used to allow you to see who a spam went to easily (i.e. |
+without scanning the exim logs), and to write SpamAssassin rules on the envelope |
+To (like adding a score if there were too many recipients or a recipient who you |
+know only receives spam) |
+X-SA-Exim-Rcpt-To is not added anymore by default, you need to enable it by |
+setting SAmaxrcptlistlength to a value up to 8000, but if you do add it, |
+you should consider removing it in exim's system_filter or in a transport. |
+If SARewriteBody is true you should also consider setting |
+SAaddSAEheaderBeforeSA to false (see the config) as all the recipients |
+will be visible in the attached spam, note that this disables the |
+ability to write SpamAssassin rules based on X-SA-Exim-Rcpt-From/To. |
+In real life, who a spam was sent to isn't really a problem, but it could be if |
+a private message is mis-categorized as spam |
+Note however that if you disable X-SA-Exim-Rcpt-To by setting |
+SAmaxrcptlistlength to 0, you will not be able to use greylisting, which |
+depends on this header (however you'd still be welcome to remove the header in |
+system_filter) |
+ |
+ |
+CONFIGURATION |
+------------- |
+You should read sa-exim.conf, all the options there should be well |
+documented. |
+ |
+Note that the code will not act on any mail before it is flagged as SPAM by SA. |
+ |
+Having SA flag the mail however doesn't mean the code rejects it or throws |
+the alleged spam away, you control what you want to do depending on the score. |
+The only restriction is that things happen in this order (for increasing SA |
+scores) |
+ |
+ - Save in SAnotspamsave if enabled |
+ - Save in SAspamacceptsave if enabled |
+ - Temporarily reject and optionally save if enabled |
+ - Permanently reject and optionally save if enabled |
+ - Accept, drop the mail, and optionally save if enabled |
+ - Teergrube (i.e. stall) the sender to waste his resources (and yours) |
+ |
+Note that you cannot set a teergrube threshold of 12, and a permreject |
+threshold of 20 (not that it would make much sense anyway). |
+Threshold scores should decrease as you apply the highest to the lowest penalty |
+(i.e. the rules are run in this order: teergrube, devnull, permreject, |
+tempreject) |
+ |
+Now, as of SA-Exim 4.2, things get slightly more complicated as scores are |
+actually full exim conditions, and therefore you could have: |
+SAteergrube: ${if and { {!eq {$sender_host_address}{127.0.0.1}} {!eq {$sender_host_address}{127.0.0.2}} } {25}{1048576}} |
+This means that if your condition succeeds, the teergrube score is set to 25, |
+and if the condition fails, the teergrube score is set to 2^20, which for all |
+intents and purposes, disables teergrubing. |
+Regardless of what your scores end up being after the conditions are evaluated, |
+sa-exim still tests them in this order: teergrube, devnull, permreject, |
+tempreject) |
+ |
+ |
+ |
+ |
+CONFIGURING SPAMASSASSIN |
+------------------------ |
+A good example of spamassassin configuration would be: |
+ |
+ report_safe 0 |
+ use_terse_report 1 # for SA < 3.x |
+ |
+This will put a non-verbose SPAM-report in the headers, but leave the |
+message itself intact for easy analyzing and for easy feeding to |
+sa-learn when mis-flagged as spam or ham. The only way to see the |
+message is spam, is by looking in the headers. |
+ |
+If you have an older version of SpamAssassin (<= 2.50), you'd probably |
+want to add 'report_header 1' to that list. But this is default and |
+un-needed in new versions of SA) |
+ |
+If you set 'report_safe' to a true value, you might also want to set |
+use_terse_report to a false value, in case you'll get the long header |
+which might be friendlier to your users. |
+ |
+For SA before 3.x, add 'always_add_report 1' to always have a spamcheck report |
+put in the message. This might be useful to test rules. |
+For SA 3.x onward, the syntax you'd want, is: |
+add_header all Report _REPORT_ |
+ |
+Since SA is usually configured to pass messages on that are beyond the SA |
+spam threshold, it can make sense to rewrite the subject line. |
+To achieve this, you would use this for SA 2.x: |
+ rewrite_subject 1 |
+ subject_tag SPAM: _HITS_: |
+ |
+For SA 3.x, the syntax is: |
+ rewrite_header Subject SPAM: _HITS_: |
+ |
+ |
+If you are using SA 2.50 or better, by default, you should probably set: |
+ report_safe 0 |
+ |
+Now, if you are willing to take a small speed and I/O hit, you can have |
+sa-exim read the body back from SA, and replace the original mail with |
+the new body. |
+ |
+You would use this if you want to set SA's report_safe to 1 or 2 (in |
+which case you also have to set SARewriteBody: 1 in SA-Exim's config) |
+ |
+Note that if you do so, unfortunately archived messages will have the |
+body modified by SA. This is not very trivial to fix, so if you archive |
+anything, you may not want to use SARewriteBody |
+ |
+ |
+Important: |
+You want to run spamd as such: |
+/usr/sbin/spamd -d -u nobody -H /var/spool/spamassassin/ |
+ |
+It may not work if you run spamd with -c (debian default), |
+(you shouldn't run spamassassin as root for this purpose anyway (there |
+is no reason to, so why take the risk) |
+ |
+You can edit this in /etc/default/spamassassin (debian) and probably |
+/etc/sysconfig/spamassassin (redhat) |
+ |
+With SA 3.x is better, the updated syntax would look like this: |
+/usr/sbin/spamd --max-children 50 --daemonize --username=nobody --nouser-config --helper-home-dir=/var/spool/spamassassin/ |
+ |
+ |
+ |
+CONFIGURING EXIM4.CONF |
+---------------------- |
+This code works without anything in the exim conf, but you probably want to use |
+some knobs to disable scanning for some users (like setting X-SA-Do-Not-Rej |
+or X-SA-Do-Not-Run in the rcpt ACL and removing those headers in the right |
+places) |
+ |
+See http://marc.merlins.org/linux/exim/#conf and more specifically |
+http://marc.merlins.org/linux/exim/exim4-conf/exim4.conf |
+ |
+Note that obviously if you set those headers, spammers can set them too, so |
+if you are concerned about this, you can either change the header name, or set |
+it to something else than 'Yes' and check for that value in sa-exim.conf |
+(or as a 3rd option, you can use exim ACL variables to pass values to SA-Exim |
+without generating headers; see the section contributed by Chirik, lower in |
+this file) |
+ |
+ |
+ |
+EXIM4 INTEGRATION / NOT SCANNING YOUR OWN MAILS |
+----------------------------------------------- |
+For a very complete exim4 config, including settings for SA, you should |
+look at sa-exim.conf and play with: |
+ |
+SAEximRunCond: ${if and{ \ |
+ {def:sender_host_address} \ |
+ {!eq {$sender_host_address}{127.0.0.1}} \ |
+ {!eq {$h_X-SA-Do-Not-Run:}{Yes}} \ |
+ } \ |
+ {1}{0} \ |
+ } |
+ |
+You may also want to look at my exim4.conf config if you haven't done so yet: |
+http://marc.merlins.org/linux/exim/#conf |
+ |
+The check_rcpt ACL has: |
+ warn message = X-SA-Do-Not-Rej: Yes |
+ local_parts = +nosarej:postmaster:abuse |
+ |
+ warn message = X-SA-Do-Not-Run: Yes |
+ hosts = +relay_from_hosts |
+ |
+ warn message = X-SA-Do-Not-Run: Yes |
+ authenticated = * |
+ |
+Then, you'll want to strip SA headers for messages that aren't local |
+This means you should strip them at least in the remote_smtp transport |
+with this configuration snippet: |
+ |
+ # This is generally set on messages originating from local users and it tells |
+ # SA-Exim not to scan the message or that the message was scanned. |
+ # Let's remove these headers if the message is sent remotely |
+ headers_remove = "X-SA-Do-Not-Run:X-SA-Exim-Scanned:X-SA-Exim-Mail-From:X-SA-Exim-Rcpt-To:X-SA-Exim-Connect-IP" |
+ |
+ |
+You can also use another option, which can't be spoofed by a spammer, but |
+won't show you why a mail didn't get scanned if it was sent to multiple |
+people (which is why I personally prefer the above, even if it's spoofable) |
+ |
+Contributed by Chirik <chirik@castlefur.com>: |
+---------------------------------------------------------------------------- |
+I have the following: |
+ |
+SAEximRunCond: ${if !eq {$acl_m0}{do-not-scan} {1} {0}} |
+SAEximRejCond: ${if !eq {$acl_m0}{do-not-reject} {1} {0}} |
+ |
+Then, in my recipient ACL, I have: |
+ |
+ ##### Checks for postmaster or abuse - we'll scan, still, but not reject |
+ ##### Don't reject for certain users |
+ warn local_parts = postmaster : abuse |
+ set acl_m0 = do-not-reject |
+ |
+ ##### Check for situations we don't even scan (local mail) |
+ ##### Don't scan if hosts we relay for (probably dumb MUAs), |
+ warn hosts = +relay_from_hosts:127.0.0.1/8 |
+ set acl_m0 = do-not-scan |
+ |
+ ##### Don't scan non-smtp connections (empty host list) |
+ warn hosts = : |
+ set acl_m0 = do-not-scan |
+ |
+ ##### Don't scan if authenticated |
+ warn authenticated = * |
+ set acl_m0 = do-not-scan |
+---------------------------------------------------------------------------- |
+ |
+ |
+ |
+TEERGRUBING: SAteergrube |
+------------------------ |
+The idea is for mail that you know for sure is spam (I use a threshold of 25), |
+you can stall the spammer for as long as possible by sending a continuation |
+line every 10 seconds: |
+451- wait for more output |
+451- wait for more output |
+451- wait for more output |
+(...) |
+ |
+You can go there for details: |
+http://www.iks-jena.de/mitarb/lutz/usenet/teergrube.en.html |
+ |
+What should you know? |
+1) This is obviously going to use up some of your resources |
+2) You should not teergrube SMTP servers that relay mail for you, be |
+ courteous (set a condition in SAteergrube like in the example |
+ provided). Besides they are real mail relays, so they will diligently |
+ try to send you the spam over and over for days) |
+ (note that you should probably not teergrube mailling lists you subscribed |
+ to either, or you risk getting unsubscribed) |
+ See a sample in sa-exim.conf for example syntax. |
+3) Because of limitations in the current exim code, teergrubing will not work |
+ over TLS. |
+ This shouldn't be a problem since real spammers should not be using TLS, |
+ and you shouldn't teergrube relays that do TLS with you. |
+ If you do teergrube a TLS connection, it will break the connection and you |
+ will see this in your logs: |
+18640m-0000Vb-00 SSL_write error 5 |
+TLS error (SSL_write): error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number |
+ This is not ideal, but in real life, that's ok. |
+ |
+ |
+ |
+GREYLISTING |
+----------- |
+See README.greylisting |
+ |
+ |
+ |
+READING ARCHIVED SPAMS |
+---------------------- |
+Spams are optionally saved in individual files in a 'new' subdirectory |
+of some place like /var/spool/sa-exim/SAteergrube. |
+ |
+There are two ways to read them: |
+1) cat new/* > /tmp/mailbox, and use the resulting file as a standard |
+ mbox file with any mail client (if SAPrependArchiveWithFrom is true) |
+2) Use a maildir capable mail client, like mutt, and run something like |
+ 'mutt -f /var/spool/sa-exim/SAteergrube'. This will read the messages in |
+ place, since what sa-exim creates looks like a valid Maildir spool. |
+ |
+If you configured SA-Exim to set X-SA-Exim-Rcpt-To, you can even resend |
+archived refused messages to the users they were meant for |
+ |
+Note that sa-exim runs with the same uid/gid than the exim daemon (something |
+like mail, exim, or Debian-Exim), so /var/spool/sa-exim/SAteergrube must exist |
+and be writeable by exim. |
+SA-Exim will then create (sub-)directories with the permissions 0770 as |
+needed (those permissions aren't a configuration option, but you can change |
+them after the fact or pre-create the directories with the permissions of your |
+choice) |
+Files are created with 0664 permissions so that anyone who has directory access |
+can read (and maybe write) the files. |
+If you chgrp the parent 'new' directory to a group of your choice, and give it |
+permissions 2770 or 2775, the files will be created with that group instead of |
+the default exim group |
+ |
+ |
+ |
+LOG AND SMTP OUTPUT |
+------------------- |
+As of SA-Exim 3.0, SMTP output does not contain the spam score anymore, |
+and you can change the messages or re-add the score by changing the |
+runtime SAmsg* variables |
+ |
+All SA-Exim log now looks like this: |
+- "SA: PANIC: " -> severe errors |
+- "SA: Warning: " -> config file parsing errors |
+- "SA: Notice: " -> misc info on what SA-Exim is doing or not doing |
+- "SA: Action: " -> what action SA-Exim took on a mail after scanning |
+- "SA: Debug[X]: " -> misc debug info if enabled |
+ |
+Marin Balvers has written a nice log parser here: |
+http://nossie.addicts.nl/projects/sa-exim-stats/ |
+ |
+ |
+ |
+FAQ |
+--- |
+Why do I get this in my exim logs? |
+ |
+2004-05-15 12:43:57 1BP54T-0002gV-Nu TLS send error on connection from internalmx1.company.tld (internalmx.company.tld) [192.168.1.1]:51552: Error in the push function. |
+2004-05-15 12:43:57 TLS recv error on connection from internalmx1.company.tld (internalmx.company.tld) |
+[192.168.1.1]:51552: The specified session has been invalidated for some reason. |
+ |
+This is because you are teergrubing a host that is doing TLS. Teergrubing does |
+not work with TLS, and people doing TLS with you are probably known relays which |
+you should exclude from your teergrube list (SAteergrubecond) |
Index: branches/upstream/4.2.1/Acknowledgements.html |
=================================================================== |
--- branches/upstream/4.2.1/Acknowledgements.html (nonexistent) |
+++ branches/upstream/4.2.1/Acknowledgements.html (revision 2) |
@@ -0,0 +1,119 @@ |
+While I wrote SA-Exim after realizing that I didn't want to accept Spam in the |
+first place, this package would not have been put together without the help |
+and contributions of the following people: |
+ |
+ |
+<ul> |
+<li>Philip Hazel<BR> |
+ We wouldn't have exim without him :-) |
+ |
+<li>Justin Mason, Craig R Hughes, Dan Quinlan, and the rest of the SpamAssassin |
+ crew<BR> |
+ |
+<li>Derrick 'dman' Hudson<BR> |
+ Early adopter, feedback, ideas, first integration with localscan_dlopen |
+ |
+<li>David Woodhouse<BR> |
+ Excellent original localscan_dlopen patch for exim 4 |
+ SIGCHLD patch (was set to ignore by exim) |
+ |
+<li>Norm<BR> |
+ Build patches and trailing slash problem for mkdir on netbsd |
+ |
+<li>Patrice Fournier<BR> |
+ Several suggestions, including adding the X-SA-Exim-Scanned header |
+ |
+<li>Peter N Lewis<BR> |
+ Spotted a buglet in lseek call |
+ |
+<li>Robert Strickler<BR> |
+ Suggested that I add teergrube support |
+ |
+<li>Tim Jackson<BR> |
+ Narrowed the problem with SA Exim 2.1 to a hang when we feed a message |
+ that's too big to spamc and did a lot of research on the bug |
+ |
+<li>Brian Kendig<BR> |
+ Suggested the functionality behind X-SA-Exim-Rcpt-To: |
+ Noted and requested logging changes |
+ |
+<li>Paul Matthews<BR> |
+ Reported string length problem with X-SA-Exim-Rcpt-To: |
+ |
+<li>Chad Leigh<BR> |
+ Reported that SA-Exim doesn't delete a X-Spam-Flag header in the original |
+ mail if the local config decides that the mail isn't spam |
+ |
+<li>Martin Balvers<BR> |
+ Reported that |
+ SA: Action: teergrubed sender until full configured duration |
+ logging wasn't consistent. |
+ Author of http://nossie.addicts.nl/projects/sa-exim-stats/ |
+ |
+<li>Andreas Metzler<BR> |
+ Has provided invaluable help by being the main maintainer of the exim4 |
+ debian package and doing most of the work for the sa-exim package, while |
+ patiently helping me with my debian build questions |
+ |
+<li>Richard Lithvall<BR> |
+ Added the much requested SARewriteBody option for SA 2.50's report_safe |
+ Also added SAPrependArchiveWithFrom option<BR> |
+ Also added SAspamcSockPath for SA 2.60 and better |
+ |
+<li>Justin F. Knotzke<BR> |
+ Reported that Dec 31st 1969 isn't a good idea and upsets some MUAs like mutt |
+ |
+<li>Norihisa Washitake<BR> |
+ Pointed out that I should be using date -R to override foreign locales |
+ |
+<li>Chirik<BR> |
+ Made suggestions on increasing logging consistency |
+ Gave example on how you can trigger mail scans without using headers |
+ (using internal exim acl variables) |
+ |
+<li>Ross Boylan<BR> |
+ Suggestions for documentation tweaks |
+ |
+<li>Sander Smeenk<BR> |
+ Made sa-exim show up in Debian. Yeah! :) |
+ Major doc diffs |
+ |
+<li>Stéphane MANHES<BR> |
+ Pointed out that greylisting requires X-SA-Exim-Rcpt-To: |
+ |
+<li>John Horne<BR> |
+ Reported crash on discard, due to the number of recipients being 0 |
+ |
+<li>Adam D. Barratt<BR> |
+ Found the problem with sa-exim's indirect use of printf and causing a crash |
+ in exim on 64 bit architectures, and gave a detailed explanation on what |
+ happened and how to fix it |
+ |
+<li>Jeffrey D. Carter<BR> |
+ Suggested strchr instead of index for easier compilation. |
+ |
+<li>Danilo Lotina F. & Others<BR> |
+ Suggested adding a destination host for spamc (I added a port too) |
+ |
+<li>Cliff Hones<BR> |
+ Reported that From mbox line was in an incorrect format |
+ |
+<li>Jason John Schwarz<BR> |
+ Reported compile problem inside the exim tree (i.e. without local_scan) |
+ |
+<li>Kristopher Austin<BR> |
+ Initial port of the SA patch to an SA 3.0 plugin |
+ |
+<li>Adam Tilghman<BR> |
+ Pointed out that I shouldn't be rewriting Content-Type headers if we don't |
+ rewrite the body (and defang_mime is dead now) |
+ |
+<li>Mark Lawrence<BR> |
+ He is the author of the greylistclean cron job |
+ |
+<li>Chris Morris<BR> |
+ Reported the ealier tuplet deletion cronjob in shell as insecure |
+ |
+<li>Your name here<BR> |
+ If you contribute or if you did and I forgot your name (sorry, let me know) |
+</ul> |
Index: branches/upstream/4.2.1/contrib/sa-exim-stats.txt |
=================================================================== |
--- branches/upstream/4.2.1/contrib/sa-exim-stats.txt (nonexistent) |
+++ branches/upstream/4.2.1/contrib/sa-exim-stats.txt (revision 2) |
@@ -0,0 +1,3 @@ |
+See this page: |
+ |
+http://nossie.addicts.nl/projects/sa-exim-stats/ |
Index: branches/upstream/4.2.1/contrib/spam_resend.txt |
=================================================================== |
--- branches/upstream/4.2.1/contrib/spam_resend.txt (nonexistent) |
+++ branches/upstream/4.2.1/contrib/spam_resend.txt (revision 2) |
@@ -0,0 +1,70 @@ |
+From: Richard Lithvall <richard@lithvall.nu> |
+Date: Mon, 24 Mar 2003 16:31:40 +0100 |
+To: sa-exim@lists.merlins.org |
+Subject: [SA-exim] Rejecting spam at SMTP but forward it to its recipients |
+ |
+Hi list members! |
+ |
+As the lazy postmaster I am I don't want to check every mail caught by |
+SA for false positives but I really want to reject the damn spam at SMTP |
+time. |
+Therefore I wrote this little perl hack delegating this responsibilty to |
+my users (they all use exim filters to file mail tagged as spam into a |
+Junk folder). |
+ |
+It works as follows. |
+- Configure SA-exim to save rejected mail into a directory |
+- Run the perl script attatched below from cron, let's say, once an hour |
+(as user mail or whoever that runs your exim) |
+- Inform your users how things work and their responsibilites to check |
+for false positives. |
+ |
+Please comment this script/hack and I'd really love to get some English |
+spelling/grammar check as well :-) |
+ |
+/Richard |
+ |
+ |
+#!/usr/bin/perl |
+$dir = "/var/spool/exim4/SApermrejectsave/new"; |
+foreach $mail (<$dir/*>) { |
+ if(-f $mail){ |
+ open(MAIL, $mail); |
+# print "Working on: " . $mail . "\n"; |
+ $from = <MAIL>; |
+ $from =~ s/^From\s(.+?)\s.+\n/$1/; |
+ while (<MAIL>){ |
+ if(/^X-SA-Exim-Rcpt-To:\s(.+)/){ |
+ @rcpts = split(/, /, $1); |
+ last; |
+ } |
+ if(/^$/){ |
+ last; |
+ } |
+ } |
+ open(BSMTP, "| /usr/sbin/exim4 -bS"); |
+ print BSMTP "mail from:<" . $from . ">\n"; |
+ foreach $rcpt (@rcpts){ |
+ print BSMTP "rcpt to:<" . $rcpt . ">\n"; |
+ } |
+ print BSMTP "data\n"; |
+ print BSMTP "X-Spam-Notice: This mail was rejected |
+during reception due to heuristic check marked it as spam,\n"; |
+ print BSMTP "\tbut forwarded to You for checking for |
+false positives.\n"; |
+ seek(MAIL, 0, 0); |
+ $throw_away_first_from_line = <MAIL>; |
+ while (<MAIL>){ |
+ if(/^\./){ |
+ print BSMTP "."; |
+ } |
+ print BSMTP; |
+ } |
+ close(MAIL); |
+ print BSMTP ".\n"; |
+ print BSMTP "quit\n"; |
+ close(BSMTP); |
+ unlink($mail); |
+ } |
+} |
+ |
Index: branches/upstream/4.2.1/SA-greylisting-2.4x.diff |
=================================================================== |
--- branches/upstream/4.2.1/SA-greylisting-2.4x.diff (nonexistent) |
+++ branches/upstream/4.2.1/SA-greylisting-2.4x.diff (revision 2) |
@@ -0,0 +1,264 @@ |
+Note, this patch is unmaintained. It is not supposed to be functional or |
+safe anymore, but I'm leaving it behind if you'd like to backport the 2.6 |
+patch to SA 2.4 (much easier than with 2.6) |
+ |
+-- Marc |
+ |
+ |
+diff -urN SpamAssassin.orig/Conf.pm SpamAssassin/Conf.pm |
+--- SpamAssassin.orig/Conf.pm Mon Jul 14 11:57:40 2003 |
++++ SpamAssassin/Conf.pm Sun Feb 22 17:17:03 2004 |
+@@ -66,6 +66,9 @@ |
+ use constant TYPE_RBL_EVALS => 0x0013; |
+ # UNUSED => 0x0014 |
+ use constant TYPE_RBL_RES_EVALS => 0x0015; |
++# Need to reserve a number with the SA folks (needs to be odd as it is an |
++# eval test) |
++use constant TYPE_RES_EVALS => 0x0021; |
+ |
+ $VERSION = 'bogus'; # avoid CPAN.pm picking up version strings later |
+ |
+@@ -1507,6 +1510,9 @@ |
+ if (/^header\s+(\S+)\s+rblreseval:(.*)$/) { |
+ $self->add_test ($1, $2, TYPE_RBL_RES_EVALS); next; |
+ } |
++ if (/^header\s+(\S+)\s+reseval:(.*)$/) { |
++ $self->add_test ($1, $2, TYPE_RES_EVALS); next; |
++ } |
+ if (/^header\s+(\S+)\s+eval:(.*)$/) { |
+ my ($name,$rule) = ($1, $2); |
+ # Backward compatibility with old rule names -- Marc |
+@@ -2096,6 +2102,9 @@ |
+ } |
+ elsif ($type == TYPE_RBL_RES_EVALS) { |
+ $self->{rbl_res_evals}->{$name} = \@args; |
++ } |
++ elsif ($type == TYPE_RES_EVALS) { |
++ $self->{res_evals}->{$name} = \@args; |
+ } |
+ elsif ($type == TYPE_RAWBODY_EVALS) { |
+ $self->{rawbody_evals}->{$name} = \@args; |
+diff -urN SpamAssassin.orig/EvalTests.pm SpamAssassin/EvalTests.pm |
+--- SpamAssassin.orig/EvalTests.pm Mon Feb 23 23:28:37 2004 |
++++ SpamAssassin/EvalTests.pm Tue Feb 24 21:34:36 2004 |
+@@ -1863,6 +1863,195 @@ |
+ return 0; |
+ } |
+ |
++ |
++# This was originally written to implement greylisting in SA-Exim, although |
++# I have tried to make it more general and allow for reuse in other MTAs |
++# (although they will need to |
++# 1) be running SA at SMTP time |
++# 2) Provide the list of rcpt to and env from in some headers for SA to read |
++# 3) Provide the IP of the connecting host ) |
++# |
++# This rule should get a negative score so that if we've already seen the |
++# greylisting tuplet before, we lower the score, which hopefully brings us from |
++# a tempreject to an accept (at least that's how sa-exim does it) |
++# -- Marc <marc_soft@merlins.org> 2004/01/19 |
++ |
++sub greylisting { |
++ # db/file/dir / pointer type / how many secs to greylist after 1st connection |
++ # SA score after which we don't bother running / SMTP time data header names |
++ my ($self, $dirorfileordb, $method, $greylisttime, $dontcheckscore, |
++ $connectiphdr, $envfromhdr, $rcpttohdr) = @_; |
++ my $dirorfile = shift @_; |
++ |
++ my $connectip; |
++ my $envfrom; |
++ my $rcptto; |
++ my @rcptto; |
++ my $iswhitelisted=0; |
++ my $err; |
++ my $mesgid = $self->get ('Message-Id')."\n"; |
++ my $tuplet; |
++ |
++ # No newlines, thank you (yes, you need this twice apparently) |
++ chomp ($mesgid); |
++ chomp ($mesgid); |
++ $mesgid =~ s/\012/|/g; |
++ |
++ # For stuff that we know is spam, don't greylist the host |
++ # (that might help later spam with a lower score to come in) |
++ if ($self->{hits} >= $dontcheckscore) |
++ { |
++ #warn "debug: skipping greylisting on $mesgid, since score is already ".$self->{hits}." and you configured greylisting to not bother with anything above $dontcheckscore\n"; |
++ return 0; |
++ } |
++ |
++ |
++ if (not $connectip = $self->get($connectiphdr)) |
++ { |
++ warn "Couldn't get Connecting IP header $connectiphdr for message $mesgid, skipping greylisting call\n"; |
++ return 0; |
++ } |
++ chomp($connectip); |
++ # Clean up input (for security, if you use files/dirs) |
++ $connectip =~ s#/#-#g; |
++ |
++ if (not $envfrom = $self->get($envfromhdr)) |
++ { |
++ warn "Couldn't get Envelope From header $envfromhdr for message $mesgid, skipping greylisting call\n"; |
++ return 0; |
++ } |
++ chomp($envfrom); |
++ # Clean up input (for security, if you use files/dirs) |
++ $envfrom =~ s#/#-#g; |
++ |
++ if (not $rcptto = $self->get($rcpttohdr)) |
++ { |
++ warn "Couldn't get Rcpt To header $rcpttohdr for message $mesgid, skipping greylisting call\n"; |
++ return 0; |
++ } |
++ chomp($rcptto); |
++ # Clean up input (for security, if you use files/dirs) |
++ $rcptto =~ s#/#-#g; |
++ @rcptto = split(/, /, $rcptto); |
++ |
++ umask 0007; |
++ |
++ foreach $rcptto (@rcptto) |
++ { |
++ my $ipdir = "$dirorfileordb/$connectip"; |
++ my $tupletdir = "$ipdir/$envfrom"; |
++ |
++ $tuplet = "$tupletdir/$rcptto"; |
++ |
++ # The dir method is easy to fiddle with and expire records in (with |
++ # a find | rm) but it's probably more I/O extensive than a real DB |
++ # and suffers from directory size problems if a specific IP is sending |
++ # generating tens of thousands of tuplets. -- Marc |
++ # That said, I prefer formats I can easily tinker with, and not having to |
++ # worry about buggy locking and so forth |
++ if ($method eq "dir") |
++ { |
++ # make directory whether it's there or not (faster than test and set) |
++ mkdir $ipdir; |
++ mkdir $tupletdir; |
++ |
++ if (not -e $tuplet) |
++ { |
++ # If the tuplets aren't there, we create them and continue in |
++ # case there are other ones (one of them might be whitelisted already) |
++ $err="creating $tuplet"; |
++ open (TUPLET, ">$tuplet") or goto greylisterror; |
++ print TUPLET time."\n"; |
++ print TUPLET "Status: Greylisted\n"; |
++ print TUPLET "Last Message-Id: $mesgid\n"; |
++ print TUPLET "Whitelisted Count: 0\n"; |
++ print TUPLET "Query Count: 1\n"; |
++ $err="closing first-written $tuplet"; |
++ close TUPLET or goto greylisterror; |
++ } |
++ else |
++ { |
++ my $time; |
++ my $status; |
++ my $whitelistcount; |
++ my $querycount; |
++ |
++ # Take into account race condition of expiring deletes and us running |
++ $err="reading $tuplet"; |
++ open (TUPLET, "<$tuplet") or goto greylisterror; |
++ $err="Couldn't read time"; |
++ $time=<TUPLET> or goto greylisterror; |
++ chomp ($time); |
++ |
++ $err="Couldn't read status"; |
++ $status=<TUPLET> or goto greylisterror; |
++ chomp ($status); |
++ $err="Couldn't extract Status from $status"; |
++ $status =~ s/^Status: // or goto greylisterror; |
++ |
++ # Skip Mesg-Id |
++ $err="Couldn't skip Mesg-Id"; |
++ $_=<TUPLET> or goto greylisterror; |
++ |
++ $err="Couldn't read whitelistcount"; |
++ $whitelistcount=<TUPLET> or goto greylisterror; |
++ chomp ($whitelistcount); |
++ $err="Couldn't extract Whitelisted Count from $whitelistcount"; |
++ $whitelistcount =~ s/^Whitelisted Count: // or goto greylisterror; |
++ |
++ $err="Couldn't read querycount"; |
++ $querycount=<TUPLET> or goto greylisterror; |
++ chomp ($querycount); |
++ $err="Couldn't extract Query Count from $querycount"; |
++ $querycount =~ s/^Query Count: // or goto greylisterror; |
++ close (TUPLET); |
++ |
++ $querycount++; |
++ if ((time - $time) > $greylisttime) |
++ { |
++ $status="Whitelisted"; |
++ $whitelistcount++; |
++ } |
++ |
++ $err="re-writing $tuplet"; |
++ open (TUPLET, ">$tuplet") or goto greylisterror; |
++ print TUPLET "$time\n"; |
++ print TUPLET "Status: $status\n"; |
++ print TUPLET "Last Message-Id: $mesgid\n"; |
++ print TUPLET "Whitelisted Count: $whitelistcount\n"; |
++ print TUPLET "Query Count: $querycount\n"; |
++ $err="closing re-written $tuplet"; |
++ close TUPLET or goto greylisterror; |
++ |
++ # We continue processing the other recipients, to setup or |
++ # update their counters |
++ if ($status="Whitelisted") |
++ { |
++ $iswhitelisted=1; |
++ } |
++ } |
++ } |
++ elsif ($method eq "file") |
++ { |
++ warn "codeme\n"; |
++ } |
++ elsif ($method eq "db") |
++ { |
++ warn "codeme\n"; |
++ } |
++ } |
++ |
++ return $iswhitelisted; |
++ |
++ greylisterror: |
++ warn "Reached greylisterror: $err / $!"; |
++ # delete tuplet since it apparently had issues but don't check for errors |
++ # in case it was a permission denied on write |
++ unlink ($tuplet); |
++ return $iswhitelisted; |
++} |
++ |
++ |
+ ########################################################################### |
+ # BODY TESTS: |
+ ########################################################################### |
+diff -urN SpamAssassin.orig/PerMsgStatus.pm SpamAssassin/PerMsgStatus.pm |
+--- SpamAssassin.orig/PerMsgStatus.pm Mon May 12 12:15:33 2003 |
++++ SpamAssassin/PerMsgStatus.pm Sun Feb 22 17:47:11 2004 |
+@@ -189,6 +189,9 @@ |
+ |
+ # add points from Bayes, before adjusting the AWL |
+ $self->{hits} += $self->{learned_hits}; |
++ |
++ # Now, we can run rules that have to run last |
++ $self->do_res_eval_tests(); |
+ |
+ # Do AWL tests last, since these need the score to have already been |
+ # calculated |
+@@ -1866,6 +1869,11 @@ |
+ my ($self) = @_; |
+ # run_rbl_eval_tests doesn't process check returns unless you set needresult |
+ $self->run_rbl_eval_tests ($self->{conf}->{rbl_res_evals}, 1); |
++} |
++ |
++sub do_res_eval_tests { |
++ my ($self) = @_; |
++ $self->run_eval_tests ($self->{conf}->{res_evals}, ''); |
+ } |
+ |
+ sub do_head_eval_tests { |
Index: branches/upstream/4.2.1/TODO |
=================================================================== |
--- branches/upstream/4.2.1/TODO (nonexistent) |
+++ branches/upstream/4.2.1/TODO (revision 2) |
@@ -0,0 +1 @@ |
+Do per-user SA runs with the exiscan 45x trick |
Index: branches/upstream/4.2.1/greylistclean |
=================================================================== |
--- branches/upstream/4.2.1/greylistclean (nonexistent) |
+++ branches/upstream/4.2.1/greylistclean (revision 2) |
@@ -0,0 +1,177 @@ |
+#!/usr/bin/perl |
+# ---------------------------------------------------------------------- |
+# Copyright (C) 2005 Mark Lawrence <nomad@null.net> |
+# |
+# This program is free software; you can redistribute it and/or modify |
+# it under the terms of the GNU General Public License as published by |
+# the Free Software Foundation; either version 2 of the License, or |
+# (at your option) any later version. |
+# ---------------------------------------------------------------------- |
+# greylistclean - remove expired SA-Exim greylist entries from the filesystem. |
+# |
+# This is basically a perl implementation of the old shell commands that |
+# used to be shipped with sa-exim, combined with simple syslog reporting. |
+# This perl script cleans old tuplets and directories in |
+# /var/spool/sa-exim/tuplets/ |
+# |
+# You can call this script with '-v' to see what files and |
+# directories are being removed (sent to STDERR). |
+# Otherwise during normal operation there is no output. |
+# |
+# To use this in production you either: |
+# 1. Copy this file to your cron.hourly directory if you accept the risk of |
+# running this script as root (it is uncessary) |
+# or |
+# 2. Copy this file to /usr/local/bin and create a crontab entry |
+# that looks something like the following (this works on Debian): |
+# |
+# 33 * * * * debian-exim /usr/local/bin/greylistclean |
+# ^^^^^^^^^^^ |
+# (a) |
+# (a) find out under which user tuplets are created, it could be mail, exim |
+# or something else depending on your system ("debian-exim" on debian) |
+# |
+# Changelog |
+# --------- |
+# 2005-02-14 Original version. Mark Lawrence <nomad@null.net> |
+# 2005-02-21 Added example cron entry comment. Mark Lawrence <nomad@null.net> |
+# 2006-01-09 Added a few comments on how to run without root, inclusion in |
+# sa-exim / verbose is -v ( -d would be debug ) |
+# |
+# ---------------------------------------------------------------------- |
+use strict; |
+use warnings; |
+use Sys::Syslog; |
+use File::Find; |
+use File::stat; |
+ |
+my $tuplet_dir = '/var/spool/sa-exim/tuplets'; |
+ |
+my $max_grey_age = 60*60*24*2; # seconds to keep greylisted entries (2 days) |
+my $max_age = 60*60*24*14; # seconds to keep all entries (14 days) |
+ |
+my $tcount = 0; # total number of tuplets |
+my $rm_tcount = 0; # number of tuplets removed |
+ |
+my $dircount = 0; # total number of directories |
+my $rm_dircount = 0; # number of directories removed |
+ |
+my @empty_dirs = (); # list of empty directories |
+ |
+my $verbose = 0; |
+my $now = time(); |
+ |
+ |
+if (@ARGV == 1 and $ARGV[0] eq '-v') { |
+ $verbose = 1; |
+ print STDERR "$0 running at $now\n" |
+} |
+ |
+ |
+# |
+# Open the reporting channel |
+# |
+openlog('sa-exim', 'pid,ndelay', 'mail'); |
+ |
+# |
+# Process the tuplets |
+# |
+find({wanted => \&prune, postprocess => \&dircheck}, $tuplet_dir); |
+ |
+syslog('info', 'Removed %d of %d greylist tuplets in %d seconds', $rm_tcount, |
+ $tcount, time() - $now); |
+ |
+# |
+# Remove empty directories found by dircheck() |
+# |
+$now = time(); |
+ |
+foreach my $dir (@empty_dirs) { |
+ rmdir $dir && $rm_dircount++; |
+ $verbose && print STDERR "removed empty directory $dir\n"; |
+} |
+ |
+syslog('info', 'Removed %d of %d greylist directories in %d seconds', |
+ $rm_dircount, $dircount, time() - $now); |
+ |
+closelog(); |
+exit; |
+ |
+ |
+ |
+# |
+# Called from File::Find::find() function with $_ set to filename/directory. |
+# Search for the line 'Status: Greylisted' in files modified more than |
+# $max_grey_age seconds ago and remove the files that contain it. |
+# Remove any entry that is older than $max_age seconds ago. |
+# |
+sub prune { |
+ return if (-d $_); # we don't do directories |
+ $tcount++; |
+ |
+ my $file = $_; |
+ my $sb = stat($file); |
+ my $age = $now - $sb->mtime; |
+ |
+ # |
+ # Remove all old entries (older than $max_age) |
+ # |
+ if ($age > $max_age) { |
+ $verbose && print STDERR 'removing old entry ', |
+ "${File::Find::dir}/$file (age: ", |
+ $now - $sb->mtime, " seconds)\n"; |
+ unlink($file); |
+ $rm_tcount++; |
+ return; |
+ } |
+ |
+ # |
+ # Do nothing if not old enough to expire |
+ # |
+ return if ($age < $max_grey_age); |
+ |
+ # |
+ # Check if this tuplet has been 'greylisted'. Use the 3 argument |
+ # form of 'open', because a lot of these files have funny characters |
+ # in their names. |
+ # |
+ if (!open(FH, '<', $file)) { |
+ print STDERR "Could not open ${File::Find::name}: $!\n"; |
+ return; |
+ } |
+ |
+ while (my $line = <FH>) { |
+ if ($line =~ /^Status: Greylisted$/) { |
+ $verbose && print STDERR 'removing greylisted ', |
+ "${File::Find::dir}/$file (age: ", |
+ $now - $sb->mtime, " seconds)\n"; |
+ unlink($file); |
+ $rm_tcount++; |
+ last; |
+ } |
+ } |
+ |
+ close FH; |
+} |
+ |
+ |
+# |
+# Called from File::Find::find() function when all entries in a directory |
+# have been processed. We check if there are any files left in the directory |
+# and if not then add it to a list for later deletion |
+# |
+sub dircheck { |
+ return if ($File::Find::dir eq $tuplet_dir); # don't check top dir. |
+ $dircount++; |
+ |
+ # |
+ # Check if directory is empty and add to $empty_dirs hash |
+ # |
+ if (opendir(DIR, $File::Find::dir)) { |
+ my $files = grep {!/^\./} readdir(DIR); |
+ if ($files == 0) { |
+ push(@empty_dirs, $File::Find::dir); |
+ } |
+ closedir(DIR); |
+ } |
+} |
/branches/upstream/4.2.1/greylistclean |
---|
Property changes: |
Added: svn:executable |
Index: branches/upstream/4.2.1/greylistclean.cron |
=================================================================== |
--- branches/upstream/4.2.1/greylistclean.cron (nonexistent) |
+++ branches/upstream/4.2.1/greylistclean.cron (revision 2) |
@@ -0,0 +1,3 @@ |
+# If you don't run spamd as nobody (you should), change the user below |
+# be smart and don't run this as root, it doesn't need those perms |
+33 * * * * nobody [ -x /usr/sbin/greylistclean ] && /usr/sbin/greylistclean |
Index: branches/upstream/4.2.1/INSTALL |
=================================================================== |
--- branches/upstream/4.2.1/INSTALL (nonexistent) |
+++ branches/upstream/4.2.1/INSTALL (revision 2) |
@@ -0,0 +1,100 @@ |
+READ THIS FIRST |
+--------------- |
+If you try to build with 'make' without editing the makefile for sa-exim to |
+see the exim source, and if you haven't patched your exim source with |
+localscan_dlopen.patch, sa-exim will not build. |
+This is normal, see the BUILDING section below |
+ |
+This version of sa-exim now requires at least exim 4.11 |
+ |
+ |
+ |
+ |
+BUILDING |
+-------- |
+The code can be compiled in two ways: |
+ |
+0) Do not set LOCAL_SCAN_HAS_OPTIONS=yes in exim's Makefile. Leave the |
+ default which is disabled. |
+ |
+1) Unpack exim 4.11 or better, and overwrite src/local_scan.c with |
+ sa-exim.c. |
+ In the sa-exim distribution directory, type make sa-exim.h, and copy |
+ it in the same place than sa-exim.c. |
+ Rebuild exim, and you're done. |
+ Note that if you do this, you are responsible for modifying variables |
+ in sa-exim.c that would normally have been modified by the Makefile. |
+ |
+ This method might seem simpler, but it requires that you rebuild exim every |
+ time you upgrade sa-exim. |
+ |
+2) The better solution is to patch exim with localscan_dlopen.patch originally |
+ from David Woodhouse (provided in this archive), and rebuild exim. |
+ Here are details on how to patch exim if yours needs it (at least debian's |
+ exim4 is prepatched, yours may be too). |
+ Choose the patch for your exim version (Philip included the portion that |
+ sets LOCAL_SCAN_ABI_VERSION_MAJOR and LOCAL_SCAN_ABI_VERSION_MINOR in exim |
+ 4.20) |
+ - localscan_dlopen_exim_4.20_or_better.patch |
+ - localscan_dlopen_up_to_4.14.patch |
+ |
+ |
+ What you gain from doing this is that sa-exim, or another local_scan module |
+ can be plugged into exim without rebuilding exim itself (here too you need |
+ exim 4.11 or better) |
+ |
+ To build, you can edit EXIM_SRC in the Makefile and build sa-exim-x.y.so, |
+ or I have also recently modified the build environment so that you can |
+ now build sa-exim without having the exim sources. |
+ You can look in eximinc/version to see which source I included. While this |
+ should work for the forseable future, the exim local_scan API might change |
+ one day and not building against the current exim sources could cause issues |
+ (hopefully, at worst it will prevent sa-exim from using better functions in |
+ newer versions of the local_scan API). |
+ To be really safe, I modified the localscan_dlopen patch to include a |
+ minor and major version number for the API. Philip has agreed to including |
+ the piece of the patch that says which version of the API exim is using, |
+ so it will be obvious in the future whether exim becomes potentially |
+ incompatible with an older version of sa-exim. Note that when Philip adds |
+ this small portion of the patch, you will have a resulting conflict if |
+ you try to apply it again. This is obviously normal, just remove it :-) |
+ |
+ Once you're done building, you can copy sa-exim-x.y.so and optionally the |
+ dummy/test accept.so in /usr/lib/exim4/local_scan/, and add this to your |
+ exim4.conf (at the beginning of the file) |
+ #local_scan_path = /usr/lib/exim4/local_scan/accept.so |
+ local_scan_path = /usr/lib/exim4/local_scan/sa-exim.so |
+ |
+ If you are a package builder, note that you don't actually have |
+ to edit the values in the Makefile, you can override them as such: |
+ make SACONF=/etc/mail/sa-exim.conf LDFLAGS="-shared -fPIC" |
+ |
+ |
+The following is mostly obsolete, but left here for info purposes |
+----------------------------------------------------------------- |
+I would also recommend to edit exim/src/config.h.defaults as such: |
+#define STRING_SPRINTF_BUFFER_SIZE 32768 |
+The default value is a bit too small for some of the strings that we need to |
+expand from SA. |
+That said, I found out that exim then complaints that the headers |
+it tries to add are too big even after I set "uschar buffer[32768];" in |
+src/header.c. |
+As a result, I haven't quite found out how to deal with more than 8KB worth |
+of SpamAssassin headers, but it may not be a huge deal, 8KB headers are too |
+long anyway. |
+I asked the SA guys not to output such huge headers and I wrote a patch |
+to disable one of the "features" that outputs such huge headers. |
+See: http://bugzilla.spamassassin.org/showattachment.cgi?attach_id=195 |
+This is included and turned on by default in Spamassassin 2.40 and later. |
+ |
+ |
+INSTALL |
+------- |
+Copy sa-exim.conf to /etc/exim4 (or whatever you set SACONF to), |
+and make sure to read it and edit the values to suit your environment. |
+So that you don't make any mistakes, SAEximRunCond is turned off by default. |
+This should force you to scan the docs before potentially shooting yourself |
+in the foot :) |
+ |
+See README for options |
+ |
Index: branches/upstream/4.2.1/SA-greylisting-2.6.diff |
=================================================================== |
--- branches/upstream/4.2.1/SA-greylisting-2.6.diff (nonexistent) |
+++ branches/upstream/4.2.1/SA-greylisting-2.6.diff (revision 2) |
@@ -0,0 +1,304 @@ |
+diff -urN SpamAssassin.orig/Conf.pm SpamAssassin/Conf.pm |
+--- SpamAssassin.orig/Conf.pm Mon Dec 15 22:41:57 2003 |
++++ SpamAssassin/Conf.pm Sun Feb 29 17:42:58 2004 |
+@@ -107,6 +107,10 @@ |
+ use constant TYPE_URI_EVALS => 0x0011; |
+ use constant TYPE_META_TESTS => 0x0012; |
+ use constant TYPE_RBL_EVALS => 0x0013; |
++# Need to reserve a number with the SA folks (needs to be odd as it is an |
++# eval test) |
++use constant TYPE_RES_EVALS => 0x0021; |
++ |
+ |
+ $VERSION = 'bogus'; # avoid CPAN.pm picking up version strings later |
+ |
+@@ -2000,12 +2004,15 @@ |
+ |
+ =cut |
+ |
+- if (/^header\s+(\S+)\s+(?:rbl)?eval:(.*)$/) { |
++ if (/^header\s+(\S+)\s+(?:rbl|res)?eval:(.*)$/) { |
+ my ($name, $fn) = ($1, $2); |
+ |
+ if ($fn =~ /^check_rbl/) { |
+ $self->add_test ($name, $fn, TYPE_RBL_EVALS); |
+ } |
++ elsif (/^header\s+(\S+)\s+reseval:(.*)$/) { |
++ $self->add_test ($name, $fn, TYPE_RES_EVALS); |
++ } |
+ else { |
+ $self->add_test ($name, $fn, TYPE_HEAD_EVALS); |
+ } |
+@@ -2603,6 +2610,9 @@ |
+ } |
+ elsif ($type == TYPE_RBL_EVALS) { |
+ $self->{rbl_evals}->{$name} = \@args; |
++ } |
++ elsif ($type == TYPE_RES_EVALS) { |
++ $self->{res_evals}->{$name} = \@args; |
+ } |
+ elsif ($type == TYPE_RAWBODY_EVALS) { |
+ $self->{rawbody_evals}->{$name} = \@args; |
+diff -urN SpamAssassin.orig/EvalTests.pm SpamAssassin/EvalTests.pm |
+--- SpamAssassin.orig/EvalTests.pm Sat Jan 17 15:56:08 2004 |
++++ SpamAssassin/EvalTests.pm Sun Aug 15 15:47:22 2004 |
+@@ -1941,6 +1941,234 @@ |
+ return $self->{habeas_swe}; |
+ } |
+ |
++ |
++# This was originally written to implement greylisting in SA-Exim, although |
++# I have tried to make it more general and allow for reuse in other MTAs |
++# (although they will need to |
++# 1) be running SA at SMTP time |
++# 2) Provide the list of rcpt to and env from in some headers for SA to read |
++# 3) Provide the IP of the connecting host ) |
++# |
++# This rule should get a negative score so that if we've already seen the |
++# greylisting tuplet before, we lower the score, which hopefully brings us from |
++# a tempreject to an accept (at least that's how sa-exim does it) |
++# -- Marc <marc_soft@merlins.org> 2004/01/19 |
++ |
++sub greylisting { |
++ my ($self, $optionhash) = @_; |
++ |
++ $optionhash =~ s/;/,/g; |
++ # This is safe, right? (users shouldn't be able to set it in their config) |
++ my %option=eval $optionhash; |
++ my $connectip; |
++ my $envfrom; |
++ my $rcptto; |
++ my @rcptto; |
++ my $iswhitelisted=0; |
++ my $err; |
++ my $mesgid = $self->get ('Message-Id')."\n"; |
++ my $mesgidfn; |
++ my $tuplet; |
++ |
++ foreach my $reqoption (qw ( method greylistsecs dontgreylistthreshold |
++ connectiphdr envfromhdr rcpttohdr greylistnullfrom greylistfourthbyte )) |
++ { |
++ die "Greylist option $reqoption missing from SA config" unless (defined $option{$reqoption}); |
++ #warn "found $reqoption -> $option{$reqoption}\n"; |
++ } |
++ |
++ # No newlines, thank you (yes, you need this twice apparently) |
++ chomp ($mesgid); |
++ chomp ($mesgid); |
++ # Newline in the middle mesgids, are you serious? Get rid of them here |
++ $mesgid =~ s/\012/|/g; |
++ |
++ # For stuff that we know is spam, don't greylist the host |
++ # (that might help later spam with a lower score to come in) |
++ if ($self->{hits} >= $option{'dontgreylistthreshold'}) |
++ { |
++ #warn "debug: skipping greylisting on $mesgid, since score is already ".$self->{hits}." and you configured greylisting to not bother with anything above $dontcheckscore\n"; |
++ return 0; |
++ } |
++ |
++ |
++ if (not $connectip = $self->get($option{'connectiphdr'})) |
++ { |
++ warn "Couldn't get Connecting IP header $option{'connectiphdr'} for message $mesgid, skipping greylisting call\n"; |
++ return 0; |
++ } |
++ chomp($connectip); |
++ # Clean up input (for security, if you use files/dirs) |
++ $connectip =~ s#/#-#g; |
++ |
++ # Account for a null envelope from |
++ if (not defined ($envfrom = $self->get($option{'envfromhdr'}))) |
++ { |
++ warn "Couldn't get Envelope From header $option{'envfromhdr'} for message $mesgid, skipping greylisting call\n"; |
++ return 0; |
++ } |
++ chomp($envfrom); |
++ # Clean up input (for security, if you use files/dirs) |
++ $envfrom =~ s#/#-#g; |
++ if (not $envfrom) |
++ { |
++ $envfrom="<>"; |
++ return 0 if (not $option{'greylistnullfrom'}); |
++ } |
++ |
++ if (not $rcptto = $self->get($option{'rcpttohdr'})) |
++ { |
++ warn "Couldn't get Rcpt To header $option{'rcpttohdr'} for message $mesgid, skipping greylisting call\n"; |
++ return 0; |
++ } |
++ chomp($rcptto); |
++ # Clean up input (for security, if you use files/dirs) |
++ $rcptto =~ s#/#-#g; |
++ @rcptto = split(/, /, $rcptto); |
++ |
++ |
++ umask 0007; |
++ |
++ foreach $rcptto (@rcptto) |
++ { |
++ # The dir method is easy to fiddle with and expire records in (with |
++ # a find | rm) but it's probably more I/O extensive than a real DB |
++ # and suffers from directory size problems if a specific IP is sending |
++ # generating tens of thousands of tuplets. -- Marc |
++ # That said, I prefer formats I can easily tinker with, and not having to |
++ # worry about buggy locking and so forth |
++ |
++ if ($option{'method'} eq "dir") |
++ { |
++ # The clean strings are hardcoded because it's hard to do a variable |
++ # substitution within a tr (and using the eval solution is too resource |
++ # expensive) |
++ $envfrom =~ tr/!#%( )*+,-.0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~/_/c; |
++ # clean variables to run properly under -T |
++ $envfrom =~ /(.+)/; |
++ $envfrom = $1; |
++ $rcptto =~ tr/!#%( )*+,-.0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~/_/c; |
++ $rcptto =~ /(.+)/; |
++ $rcptto = $1; |
++ |
++ die "greylist option dir not passed, even though method was set to dir" unless ($option{'dir'}); |
++ my ($ipbyte1, $ipbyte2, $ipbyte3, $ipbyte4) = split(/\./, $connectip); |
++ my $ipdir1 = "$option{'dir'}/$ipbyte1"; |
++ my $ipdir2 = "$ipdir1/$ipbyte2"; |
++ my $ipdir3 = "$ipdir2/$ipbyte3"; |
++ my $ipdir4; |
++ my $tupletdir; |
++ |
++ $ipdir4 = "$ipdir3"; |
++ $ipdir4 .= "/$ipbyte4" if ($option{'greylistfourthbyte'}); |
++ $tupletdir = "$ipdir4/$envfrom"; |
++ |
++ $tuplet = "$tupletdir/$rcptto"; |
++ |
++ # make directory whether it's there or not (faster than test and set) |
++ mkdir $ipdir1; |
++ mkdir $ipdir2; |
++ mkdir $ipdir3; |
++ mkdir $ipdir4; |
++ mkdir $tupletdir; |
++ |
++ if (not -e $tuplet) |
++ { |
++ # If the tuplets aren't there, we create them and continue in |
++ # case there are other ones (one of them might be whitelisted already) |
++ $err="creating $tuplet"; |
++ open (TUPLET, ">$tuplet") or goto greylisterror; |
++ print TUPLET time."\n"; |
++ print TUPLET "Status: Greylisted\n"; |
++ print TUPLET "Last Message-Id: $mesgid\n"; |
++ print TUPLET "Whitelisted Count: 0\n"; |
++ print TUPLET "Query Count: 1\n"; |
++ $err="closing first-written $tuplet"; |
++ close TUPLET or goto greylisterror; |
++ } |
++ else |
++ { |
++ my $time; |
++ my $status; |
++ my $whitelistcount; |
++ my $querycount; |
++ |
++ # Take into account race condition of expiring deletes and us running |
++ $err="reading $tuplet"; |
++ open (TUPLET, "<$tuplet") or goto greylisterror; |
++ $err="Couldn't read time"; |
++ defined ($time=<TUPLET>) or goto greylisterror; |
++ chomp ($time); |
++ |
++ $err="Couldn't read status"; |
++ defined ($status=<TUPLET>) or goto greylisterror; |
++ chomp ($status); |
++ $err="Couldn't extract Status from $status"; |
++ $status =~ s/^Status: // or goto greylisterror; |
++ |
++ # Skip Mesg-Id |
++ $err="Couldn't skip Mesg-Id"; |
++ defined ($_=<TUPLET>) or goto greylisterror; |
++ |
++ $err="Couldn't read whitelistcount"; |
++ defined ($whitelistcount=<TUPLET>) or goto greylisterror; |
++ chomp ($whitelistcount); |
++ $err="Couldn't extract Whitelisted Count from $whitelistcount"; |
++ $whitelistcount =~ s/^Whitelisted Count: // or goto greylisterror; |
++ |
++ $err="Couldn't read querycount"; |
++ defined ($querycount=<TUPLET>) or goto greylisterror; |
++ chomp ($querycount); |
++ $err="Couldn't extract Query Count from $querycount"; |
++ $querycount =~ s/^Query Count: // or goto greylisterror; |
++ close (TUPLET); |
++ |
++ $querycount++; |
++ if ((time - $time) > $option{'greylistsecs'}) |
++ { |
++ $status="Whitelisted"; |
++ $whitelistcount++; |
++ } |
++ |
++ $err="re-writing $tuplet"; |
++ open (TUPLET, ">$tuplet") or goto greylisterror; |
++ print TUPLET "$time\n"; |
++ print TUPLET "Status: $status\n"; |
++ print TUPLET "Last Message-Id: $mesgid\n"; |
++ print TUPLET "Whitelisted Count: $whitelistcount\n"; |
++ print TUPLET "Query Count: $querycount\n"; |
++ $err="closing re-written $tuplet"; |
++ close TUPLET or goto greylisterror; |
++ |
++ # We continue processing the other recipients, to setup or |
++ # update their counters |
++ if ($status eq "Whitelisted") |
++ { |
++ $iswhitelisted=1; |
++ } |
++ } |
++ } |
++ elsif ($option{'method'} eq "file") |
++ { |
++ warn "codeme\n"; |
++ } |
++ elsif ($option{'method'} eq "db") |
++ { |
++ warn "codeme\n"; |
++ } |
++ } |
++ |
++ return $iswhitelisted; |
++ |
++ greylisterror: |
++ warn "Reached greylisterror: $err / $!"; |
++ # delete tuplet since it apparently had issues but don't check for errors |
++ # in case it was a permission denied on write |
++ unlink ($tuplet); |
++ return $iswhitelisted; |
++} |
++ |
++ |
+ ########################################################################### |
+ # BODY TESTS: |
+ ########################################################################### |
+diff -urN SpamAssassin.orig/PerMsgStatus.pm SpamAssassin/PerMsgStatus.pm |
+--- SpamAssassin.orig/PerMsgStatus.pm Tue Jan 20 13:40:04 2004 |
++++ SpamAssassin/PerMsgStatus.pm Sun Feb 29 19:01:19 2004 |
+@@ -184,6 +184,9 @@ |
+ |
+ # add points from Bayes, before adjusting the AWL |
+ $self->{hits} += $self->{learned_hits}; |
++ |
++ # Now, we can run rules that have to run last |
++ $self->do_res_eval_tests(); |
+ |
+ # Do AWL tests last, since these need the score to have already been |
+ # calculated |
+@@ -2010,6 +2013,11 @@ |
+ } |
+ |
+ ########################################################################### |
++ |
++sub do_res_eval_tests { |
++ my ($self) = @_; |
++ $self->run_eval_tests ($self->{conf}->{res_evals}, ''); |
++} |
+ |
+ sub do_head_eval_tests { |
+ my ($self) = @_; |
Index: branches/upstream/4.2.1/Greylisting.pm |
=================================================================== |
--- branches/upstream/4.2.1/Greylisting.pm (nonexistent) |
+++ branches/upstream/4.2.1/Greylisting.pm (revision 2) |
@@ -0,0 +1,296 @@ |
+package Greylisting; |
+# |
+# $Id: Greylisting.pm,v 1.4 2006/01/11 17:17:28 marcmerlin Exp $ |
+# |
+ |
+# General Greylisting Plugin, written by Marc MERLIN <marc_soft@merlins.org> |
+# (Kristopher Austin gets the credit for the original port to an SA 3.0 plugin) |
+# |
+# This was originally written to implement greylisting in SA-Exim, although |
+# I have tried to make it more general and allow for reuse in other MTAs |
+# (although they will need to |
+# 1) be running SA at SMTP time |
+# 2) Provide the list of rcpt to and env from in some headers for SA to read |
+# 3) Provide the IP of the connecting host ) |
+# |
+# This rule should get a negative score so that if we've already seen the |
+# greylisting tuplet before, we lower the score, which hopefully brings us from |
+# a tempreject to an accept (at least that's how sa-exim does it) |
+# |
+# -- Marc 2004/01/19 |
+ |
+use strict; |
+use Mail::SpamAssassin::Plugin; |
+our @ISA = qw(Mail::SpamAssassin::Plugin); |
+ |
+sub new |
+{ |
+ my ($class, $mailsa) = @_; |
+ $class = ref($class) || $class; |
+ my $self = $class->SUPER::new($mailsa); |
+ bless ($self, $class); |
+ $self->register_eval_rule ("greylisting"); |
+ return $self; |
+} |
+ |
+ |
+sub check_end |
+{ |
+ my ($self, $permsgstatus) = @_; |
+ |
+ if (not $self->{'rangreylisting'}) |
+ { |
+ Mail::SpamAssassin::Plugin::dbg("GREYLISTING: greylisting didn't run since the configuration wasn't setup to call us"); |
+ } |
+} |
+ |
+# Greylisting happens depending on the SA score, so we want to run it last, |
+# which is why we give it a high priority |
+sub greylisting |
+{ |
+ my ($self, $permsgstatus, $optionhash) = @_; |
+ |
+ my $connectip; |
+ my $envfrom; |
+ my $rcptto; |
+ my @rcptto; |
+ my $iswhitelisted=0; |
+ my $err; |
+ my $mesgid = $permsgstatus->get('Message-Id')."\n"; |
+ my $mesgidfn; |
+ my $tuplet; |
+ my $sascore = $permsgstatus->get_score(); |
+ my $dontcheckscore; |
+ my %option; |
+ |
+ Mail::SpamAssassin::Plugin::dbg("GREYLISTING: called function"); |
+ |
+ $optionhash =~ s/;/,/g; |
+ # This is safe, right? (users shouldn't be able to set it in their config) |
+ %option=eval $optionhash; |
+ $self->{'rangreylisting'}=1; |
+ |
+ foreach my $reqoption (qw ( method greylistsecs dontgreylistthreshold |
+ connectiphdr envfromhdr rcpttohdr greylistnullfrom greylistfourthbyte )) |
+ { |
+ die "Greylist option $reqoption missing from SA config" unless (defined $option{$reqoption}); |
+ } |
+ |
+ $dontcheckscore = $option{'dontgreylistthreshold'}; |
+ |
+ |
+ # No newlines, thank you (yes, you need this twice apparently) |
+ chomp ($mesgid); |
+ chomp ($mesgid); |
+ # Newline in the middle mesgids, are you serious? Get rid of them here |
+ $mesgid =~ s/\012/|/g; |
+ |
+ # For stuff that we know is spam, don't greylist the host |
+ # (that might help later spam with a lower score to come in) |
+ if ($sascore >= $dontcheckscore) |
+ { |
+ Mail::SpamAssassin::Plugin::dbg("GREYLISTING: skipping greylisting on $mesgid, since score is already $sascore and you configured greylisting not to bother with anything above $dontcheckscore"); |
+ return 0; |
+ } |
+ else |
+ { |
+ Mail::SpamAssassin::Plugin::dbg("GREYLISTING: running greylisting on $mesgid, since score is too low ($sascore) and you configured greylisting to greylist anything under $dontcheckscore"); |
+ } |
+ |
+ if (not $connectip = $permsgstatus->get($option{'connectiphdr'})) |
+ { |
+ warn "Couldn't get Connecting IP header $option{'connectiphdr'} for message $mesgid, skipping greylisting call\n"; |
+ return 0; |
+ } |
+ chomp($connectip); |
+ # Clean up input (for security, if you use files/dirs) |
+ $connectip =~ /([\d.:]+)/; |
+ $connectip = ($1 or ""); |
+ |
+ # Account for a null envelope from |
+ if (not defined ($envfrom = $permsgstatus->get($option{'envfromhdr'}))) |
+ { |
+ warn "Couldn't get Envelope From header $option{'envfromhdr'} for message $mesgid, skipping greylisting call\n"; |
+ return 0; |
+ } |
+ chomp($envfrom); |
+ # Clean up input (for security, if you use files/dirs) |
+ $envfrom =~ s#/#-#g; |
+ if (not $envfrom) |
+ { |
+ $envfrom="<>"; |
+ return 0 if (not $option{'greylistnullfrom'}); |
+ } |
+ |
+ if (not $rcptto = $permsgstatus->get($option{'rcpttohdr'})) |
+ { |
+ warn "Couldn't get Rcpt To header $option{'rcpttohdr'} for message $mesgid, skipping greylisting call\n"; |
+ return 0; |
+ } |
+ chomp($rcptto); |
+ # Clean up input (for security, if you use files/dirs) |
+ $rcptto =~ s#/#-#g; |
+ @rcptto = split(/, /, $rcptto); |
+ |
+ |
+ umask 0007; |
+ |
+ foreach $rcptto (@rcptto) |
+ { |
+ # The dir method is easy to fiddle with and expire records in (with |
+ # a find | rm) but it's probably more I/O extensive than a real DB |
+ # and suffers from directory size problems if a specific IP is sending |
+ # generating tens of thousands of tuplets. -- Marc |
+ # That said, I prefer formats I can easily tinker with, and not having |
+ # to worry about buggy locking and so forth |
+ |
+ if ($option{'method'} eq "dir") |
+ { |
+ my $tmpvar; |
+ |
+ # The clean strings are hardcoded because it's hard to do a variable |
+ # substitution within a tr (and using the eval solution is too |
+ # resource expensive) |
+ # envfrom could be cleaned outside of the loop, but the other method |
+ # options might now want that |
+ $envfrom =~ tr/!#%()*+,-.0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~/_/c; |
+ # clean variables to run properly under -T |
+ $envfrom =~ /(.+)/; |
+ $tmpvar = ($1 or ""); |
+ # work around bug in perl untaint in perl 5.8 |
+ $envfrom=undef; |
+ $envfrom=$tmpvar; |
+ $rcptto =~ tr/!#%()*+,-.0123456789:<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~/_/c; |
+ $rcptto =~ /(.+)/; |
+ $tmpvar = ($1 or ""); |
+ $rcptto=undef; |
+ $rcptto=$tmpvar; |
+ |
+ die "greylist option dir not passed, even though method was set to dir" unless ($option{'dir'}); |
+ |
+ # connectip is supposed to be untainted now, but I was still getting |
+ # some insecure dependecy error messages sometimes (perl 5.8 problem apparently) |
+ $connectip =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/; |
+ my ($ipbyte1, $ipbyte2, $ipbyte3, $ipbyte4) = ($1, $2, $3, $4); |
+ my $ipdir1 = "$option{'dir'}/$ipbyte1"; |
+ my $ipdir2 = "$ipdir1/$ipbyte2"; |
+ my $ipdir3 = "$ipdir2/$ipbyte3"; |
+ my $ipdir4; |
+ my $tupletdir; |
+ |
+ $ipdir4 = "$ipdir3"; |
+ $ipdir4 .= "/$ipbyte4" if ($option{'greylistfourthbyte'}); |
+ $tupletdir = "$ipdir4/$envfrom"; |
+ |
+ $tuplet = "$tupletdir/$rcptto"; |
+ |
+ # make directory whether it's there or not (faster than test and set) |
+ mkdir $ipdir1; |
+ mkdir $ipdir2; |
+ mkdir $ipdir3; |
+ mkdir $ipdir4; |
+ mkdir $tupletdir; |
+ |
+ if (not -e $tuplet) |
+ { |
+ # If the tuplets aren't there, we create them and continue in |
+ # case there are other ones (one of them might be whitelisted |
+ # already) |
+ $err="creating $tuplet"; |
+ open (TUPLET, ">$tuplet") or goto greylisterror; |
+ print TUPLET time."\n"; |
+ print TUPLET "Status: Greylisted\n"; |
+ print TUPLET "Last Message-Id: $mesgid\n"; |
+ print TUPLET "Whitelisted Count: 0\n"; |
+ print TUPLET "Query Count: 1\n"; |
+ print TUPLET "SA Score: $sascore\n"; |
+ $err="closing first-written $tuplet"; |
+ close TUPLET or goto greylisterror; |
+ } |
+ else |
+ { |
+ my $time; |
+ my $status; |
+ my $whitelistcount; |
+ my $querycount; |
+ |
+ # Take into account race condition of expiring deletes and us |
+ # running |
+ $err="reading $tuplet"; |
+ open (TUPLET, "<$tuplet") or goto greylisterror; |
+ $err="Couldn't read time"; |
+ defined ($time=<TUPLET>) or goto greylisterror; |
+ chomp ($time); |
+ |
+ $err="Couldn't read status"; |
+ defined ($status=<TUPLET>) or goto greylisterror; |
+ chomp ($status); |
+ $err="Couldn't extract Status from $status"; |
+ $status =~ s/^Status: // or goto greylisterror; |
+ |
+ # Skip Mesg-Id |
+ $err="Couldn't skip Mesg-Id"; |
+ defined ($_=<TUPLET>) or goto greylisterror; |
+ |
+ $err="Couldn't read whitelistcount"; |
+ defined ($whitelistcount=<TUPLET>) or goto greylisterror; |
+ chomp ($whitelistcount); |
+ $err="Couldn't extract Whitelisted Count from $whitelistcount"; |
+ $whitelistcount =~ s/^Whitelisted Count: // or goto greylisterror; |
+ |
+ $err="Couldn't read querycount"; |
+ defined ($querycount=<TUPLET>) or goto greylisterror; |
+ chomp ($querycount); |
+ $err="Couldn't extract Query Count from $querycount"; |
+ $querycount =~ s/^Query Count: // or goto greylisterror; |
+ close (TUPLET); |
+ |
+ $querycount++; |
+ if ((time - $time) > $option{'greylistsecs'}) |
+ { |
+ $status="Whitelisted"; |
+ $whitelistcount++; |
+ } |
+ |
+ $err="re-writing $tuplet"; |
+ open (TUPLET, ">$tuplet") or goto greylisterror; |
+ print TUPLET "$time\n"; |
+ print TUPLET "Status: $status\n"; |
+ print TUPLET "Last Message-Id: $mesgid\n"; |
+ print TUPLET "Whitelisted Count: $whitelistcount\n"; |
+ print TUPLET "Query Count: $querycount\n"; |
+ print TUPLET "SA Score: $sascore\n"; |
+ $err="closing re-written $tuplet"; |
+ close TUPLET or goto greylisterror; |
+ |
+ # We continue processing the other recipients, to setup or |
+ # update their counters |
+ if ($status eq "Whitelisted") |
+ { |
+ $iswhitelisted=1; |
+ } |
+ } |
+ } |
+ elsif ($option{'method'} eq "file") |
+ { |
+ warn "codeme (file greylisting)\n"; |
+ } |
+ elsif ($option{'method'} eq "db") |
+ { |
+ warn "codeme (db greylisting)\n"; |
+ } |
+ } |
+ |
+ Mail::SpamAssassin::Plugin::dbg("GREYLISTING: computed greylisting on tuplet, saved info in $tuplet and whitelist status is $iswhitelisted"); |
+ return $iswhitelisted; |
+ |
+ greylisterror: |
+ warn "Reached greylisterror: $err / $!"; |
+ # delete tuplet since it apparently had issues but don't check for errors |
+ # in case it was a permission denied on write |
+ unlink ($tuplet); |
+ return $iswhitelisted; |
+} |
+ |
+ |
+1; |
Index: branches/upstream/4.2.1/Makefile |
=================================================================== |
--- branches/upstream/4.2.1/Makefile (nonexistent) |
+++ branches/upstream/4.2.1/Makefile (revision 2) |
@@ -0,0 +1,107 @@ |
+# SA-Exim can be built standalone as a loadable module with this Makefile |
+# or you can copy sa-exim.c over exim's local_scan.c file if you want to |
+# statically build it into exim |
+# |
+ |
+VERSION=$(shell cat version) |
+ |
+# The idea is that you don't have to edit these values, you can override |
+# them on the command line: |
+# make SACONF=/etc/exim/sa-exim.conf LDFLAGS="-shared -fPIC" CC=cc |
+CC=gcc |
+CFLAGS=-O2 -Wall |
+LDFLAGS=-shared |
+SACONF=/etc/exim4/sa-exim.conf |
+SPAMC=/usr/bin/spamc |
+ |
+ |
+# I place the directory in exim/debian/local_scan. Adjust the path as needed |
+# Actually, we will also look for the versions supplied with this source |
+# if we can't find the exim source |
+EXIM_SRC= ../../src |
+EXIM_SRC_LOCAL = ./eximinc |
+SUFF=-$(VERSION) |
+ |
+SAFLAGS=-DSPAMASSASSIN_CONF=\"$(SACONF)\" -DSPAMC_LOCATION=\"$(SPAMC)\" |
+BUILDCFLAGS=-I$(EXIM_SRC) -I$(EXIM_SRC_LOCAL) -DDLOPEN_LOCAL_SCAN $(SAFLAGS) $(CFLAGS) |
+ |
+SONAME=$(subst .so,$(SUFF).so,sa-exim.so) |
+ |
+DOCS=sa.html CHANGELOG ACKNOWLEDGEMENTS |
+OBJECTS=$(SONAME) accept.so sa-exim_short.conf $(DOCS) |
+OTHERTARGETS=sa-exim.h |
+ |
+all: $(OBJECTS) |
+ |
+docs: $(DOCS) |
+ |
+ |
+$(SONAME) : sa-exim.c sa-exim.h |
+ @echo "Building $@" |
+ $(CC) $(BUILDCFLAGS) $(LDFLAGS) -o $@ $< |
+ chmod a+rx $(SONAME) |
+ |
+accept.so: accept.c |
+ @echo "Building $@" |
+ $(CC) $(BUILDCFLAGS) $(LDFLAGS) -o $@ $< |
+ chmod a+rx $@ |
+ |
+ACKNOWLEDGEMENTS: Acknowledgements.html |
+ @echo "Generating $@" |
+ @links -dump $< > $@ |
+ |
+CHANGELOG: Changelog.html |
+ @echo "Generating $@" |
+ @links -dump $< > $@ |
+ |
+sa.html: Changelog.html Acknowledgements.html sa.html.template |
+ @echo "Generating $@" |
+ @bash -c 'sed "/<Changelog>/,$$ d" < sa.html.template; cat Changelog.html; sed "1,/<\/Changelog>/ d; /<Acknowledgements>/,$$ d" < sa.html.template; cat Acknowledgements.html; sed "1,/<\/Acknowledgements>/ d" < sa.html.template' > sa.html |
+ |
+sa-exim_short.conf: sa-exim.conf |
+ @cat sa-exim.conf | sed "/# --- snip ---/,$$ d" > sa-exim_short.conf |
+ @cat sa-exim.conf | grep -v "^#" | tr '\012' 'ÿ' | sed "s/ÿÿÿ*/ÿÿ/g" | tr 'ÿ' '\012' >> sa-exim_short.conf |
+ |
+sa-exim.h: sa-exim.c version |
+ echo "char *version=\"`cat version` (built `date -R 2>/dev/null || date`)\";" > sa-exim.h |
+ |
+clean: |
+ @-rm -rf $(OBJECTS) $(DOCS) $(OTHERTARGETS) build-stamp configure-stamp debian/sa-exim debian/sa-exim.postrm.debhelper debian/sa-exim.substvars debian/files 2>/dev/null |
+ |
+deb: ../sa-exim_$(VERSION).orig.tar.gz debian/* |
+ @make clean |
+ @dpkg-buildpackage -uc -us -sd -rfakeroot |
+ @make clean |
+ |
+../sa-exim_$(VERSION).orig.tar.gz: * */* |
+ @make clean |
+ @( cd ..; tar chvzf sa-exim_$(VERSION).orig.tar.gz sa-exim-$(VERSION) ) |
+ |
+# This didn't work too well, I'll just ship the source with the debian tree |
+#deb: ../sa-exim_$(VERSION).orig.tar.gz debian/rules |
+# @make clean |
+# @dpkg-buildpackage -uc -us -sd -rfakeroot |
+# |
+# |
+#../sa-exim_$(VERSION).tar.gz: * */* |
+# @make clean |
+# @if [ -d debian ]; then echo "Can't rebuild $@ with debian tree unpacked, please remove it"; exit 1; fi |
+# @( cd ..; tar chvzf sa-exim_$(VERSION).tar.gz sa-exim-$(VERSION) ) |
+# |
+# |
+#../sa-exim_$(VERSION).orig.tar.gz: ../sa-exim_$(VERSION).tar.gz |
+# if [ -e ../sa-exim-$(VERSION).tar.gz ] ; then \ |
+# cp -a ../sa-exim-$(VERSION).tar.gz ../sa-exim_$(VERSION).orig.tar.gz ; \ |
+# else \ |
+# wget http://marc.merlins.org/linux/sa-exim-$(VERSION).tar.gz; \ |
+# mv sa-exim-$(VERSION).tar.gz ../sa-exim_$(VERSION).orig.tar.gz; \ |
+# fi |
+# |
+# |
+#debian/rules: |
+# @wget http://marc.merlins.org/linux/exim/files/debian/sa-exim_diff.gz |
+# @zcat sa-exim_diff.gz | patch -s -p1 |
+# @/bin/rm sa-exim_diff.gz |
+# @chmod 755 debian/rules |
+# |
+ |
Index: branches/upstream/4.2.1/.cvsignore |
=================================================================== |
--- branches/upstream/4.2.1/.cvsignore (nonexistent) |
+++ branches/upstream/4.2.1/.cvsignore (revision 2) |
@@ -0,0 +1,7 @@ |
+.* |
+ACKNOWLEDGEMENTS |
+CHANGELOG |
+sa.html |
+sa-exim.h |
+sa-exim_short.conf |
+ |