pavement

Talk:Qmail, Mail toaster

From FreeBSDwiki
(Difference between revisions)
Jump to: navigation, search
(qmail-queue replacement)
(smartscan.pl)
Line 354: Line 354:
  
 
###
 
###
### Smartscan.pl
+
### Smartscanner.pl
 
###
 
###
### VERSION 2.1
+
### VERSION 2.0
 
### 2006 Feb 23
 
### 2006 Feb 23
 
###
 
###
Line 370: Line 370:
 
#            COULD LOCK UP YOUR SERVER!
 
#            COULD LOCK UP YOUR SERVER!
 
#
 
#
$postmaster = 'postmaster@someother.mailserver.tld';
+
$postmaster = 'postmaster@someotherdomain.tld';
  
# Don't forget to use visudo to allow qmaild to run maildir as vpopmail!
+
# Don't forget to use visudo to allow qmaild to run maildir
#
+
# as vpopmail!
# sudoers format should look like this:
+
# qmaild ALL=(vpopmail) NOPASSWD: /usr/local/bin/maildir
+
 
#
 
#
 
$delivery_agent = "/usr/local/bin/sudo -u vpopmail /usr/local/bin/maildir";
 
$delivery_agent = "/usr/local/bin/sudo -u vpopmail /usr/local/bin/maildir";
Line 385: Line 383:
 
$spam_scan_auth = 0;
 
$spam_scan_auth = 0;
  
# note: quarantine_all will cause copies of GOOD emails to be delivered
+
# note: $quarantine_* does not determine whether mail is delivered
#      to the quarantine directory also.  also note, $quarantine_* does
+
#        to its original destination or not; only whether a copy of
#        not determine whether mail is delivered or not; only whether a
+
#        it is delivered to $quarantine_dir.  The $reject_*
#        copy of it is delivered to $quarantine_dir.  The $bounce_*
+
#        variables below determine delivery or non-delivery to
#        variables below determine delivery options.
+
#        the original recipient and outcome of the SMTP conversation.
 
#
 
#
 
$quarantine_spam = 1;
 
$quarantine_spam = 1;
 
$quarantine_virus = 1;
 
$quarantine_virus = 1;
$quarantine_all = 0;
+
$quarantine_dir = '/usr/local/vpopmail/domains/yourdomain.tld/yourname/Maildir/.INBOX.quarantine';
  
$quarantine_dir = '/usr/local/vpopmail/domains/domain.tld/username/Maildir/.INBOX.quarantine';
+
# note: if $archive_mail is set then copies of ACCEPTED mail - mail
 +
#      which has either not flagged as spam or virus OR mail which
 +
#      has flagged but for which the rejection setting is 0 - will
 +
#      be delivered to $archive_dir.  If you want a single message
 +
#      store with accepted and rejected mail, set $archive_dir and
 +
#      $quarantine_dir to the same destination.
 +
#
 +
$archive_mail = 0;
 +
$archive_dir = '/usr/local/vpopmail/domains/yourdomain.tld/yourname/Maildir/.INBOX.archive';
  
# Bounce detected spams and/or viruses, or deliver them?
+
# Reject detected spams and/or viruses, or deliver them?
#  (in case of double-flag, virus bounce setting takes priority.)
+
#  (in case of double-flag, virus rejection setting takes priority.)
#    0 = no bounce (deliver mail)
+
#    0 = no rejection - accept and deliver (mangled) mail to
#    1 = quiet bounce, aka drop without alerting qmail-queue
+
#        original destination
#    2 = "noisy" bounce, aka drop and pass error message along to qmail-queue
+
#    1 = quiet reject, aka drop without alerting qmail-queue
 +
#    2 = "noisy" reject, aka drop and pass error message along
 +
#        to qmail-queue for an SMTP 554 reject before SMTP
 +
#        conversation completes
 
#
 
#
$bounce_spam = 2;
+
$reject_spam = 2;
$bounce_virus = 2;
+
$reject_virus = 2;
  
 
# set the other basic configuration variables -
 
# set the other basic configuration variables -
Line 465: Line 474:
 
print `chmod -R 777 $temppath/$tempdir`;
 
print `chmod -R 777 $temppath/$tempdir`;
  
# rework bounce_spam and bounce_virus to match desired exit codes:
+
# rework reject_spam and reject_virus to match desired exit codes:
 
# code 31 = SMTP 554, code 99 = silent drop
 
# code 31 = SMTP 554, code 99 = silent drop
 
#
 
#
Line 471: Line 480:
 
# 32 and 33 so we are using those.
 
# 32 and 33 so we are using those.
 
#
 
#
if ($bounce_virus == 1) { $bounce_virus = 99; } elsif ($bounce_virus == 2) { $bounce_virus = 32; }
+
if ($reject_spam == 1) { $reject_spam = 99; } elsif ($reject_spam == 2) { $reject_spam = 33; }
if ($bounce_spam == 1) { $bounce_spam = 99; } elsif ($bounce_spam == 2) { $bounce_spam = 33; }
+
if ($reject_virus == 1) { $reject_virus = 99; } elsif ($reject_virus == 2) { $reject_virus = 32; }
  
 
# only run virus scanning if not using SMTP AUTH or if $virus_scan_auth is set.
 
# only run virus scanning if not using SMTP AUTH or if $virus_scan_auth is set.
#
 
 
if ($tcpremoteinfo=='NONE' || $virus_scan_auth == 1) {
 
if ($tcpremoteinfo=='NONE' || $virus_scan_auth == 1) {
 
         &scan_clamd;
 
         &scan_clamd;
Line 482: Line 490:
 
# no point in wasting resources on spamassassin if we already found a virus;
 
# no point in wasting resources on spamassassin if we already found a virus;
 
# then only run spamassassin if not using SMTP AUTH or if $spam_scan_auth is set.
 
# then only run spamassassin if not using SMTP AUTH or if $spam_scan_auth is set.
#
+
 
 
if ( $virus_found != 1
 
if ( $virus_found != 1
 
     &&
 
     &&
Line 493: Line 501:
 
}
 
}
  
# deliver quarantine copies of email if called for
+
# deliver quarantine copy of email if called for
#
+
if ($quarantine_spam == 1 && $spam_found) || ($quarantine_virus == 1 && $virus_found)
if ($quarantine_all == 1
+
    || ($quarantine_spam == 1 && $spam_found)
+
    || ($quarantine_virus == 1 && $virus_found)
+
  )
+
 
{
 
{
 
         open (FH, "| $delivery_agent $quarantine_dir");
 
         open (FH, "| $delivery_agent $quarantine_dir");
 
         print FH $email;
 
         print FH $email;
 
         close (FH);
 
         close (FH);
         print `echo "Quarantined message to: $qmail_rcpts" | $logging`;
+
         print `echo "Delivered quarantine message copy to: $qmail_rcpts" | $logging`;
 +
}
 +
 
 +
# deliver archive copy of email if called for
 +
if ($archive_mail == 1
 +
    && ($spam_found != 1 || $reject_spam == 0)
 +
    && ($virus_found != 1 || $reject_virus == 0)
 +
  )
 +
{
 +
        open (FH, "| $delivery_agent $archive_dir");
 +
        print FH $email;
 +
        close (FH);
 +
        print `echo "Delivered archive message copy to: $qmail_rcpts" | $logging`;
 
}
 
}
  
Line 511: Line 527:
  
 
# Decide how and if to deliver the message - controlled by exit code
 
# Decide how and if to deliver the message - controlled by exit code
#
 
 
$exit_code = 0;
 
$exit_code = 0;
if ($spam_found == 1) { $exit_code = $bounce_spam; }
+
if ($spam_found == 1) { $exit_code = $reject_spam; }
if ($virus_found == 1) { $exit_code = $bounce_virus; }
+
if ($virus_found == 1) { $exit_code = $reject_virus; }
  
 
# Pass STDOUT and exit status through and back out to qmail-queue
 
# Pass STDOUT and exit status through and back out to qmail-queue
Line 558: Line 573:
 
                 $virus_logstring = "MALWARE_FOUND=$virus_name RECIPIENT=$qmail_rcpts";
 
                 $virus_logstring = "MALWARE_FOUND=$virus_name RECIPIENT=$qmail_rcpts";
 
         } else {
 
         } else {
         $virus_logstring = "WARNING: clamdscan returned error code $virus_found ! Delivering message anyway, and emailing postmaster...";
+
         $virus_logstring = "WARNING: clamdscan returned error code $virus_found";
         print `echo "WARNING: clamdscan returning error code $virus_found on your mailserver.  Please investigate and resolve.  (Is clamd running?)" | mail -s "CLAMD ERRORS!" $postmaster`;
+
        $virus_logstring .= '! Delivering message anyway, and emailing postmaster...';
 +
         $postmaster_mail = "WARNING: clamdscan returning error code $virus_found on your mailserver.  (Is clamd running?)";
 +
        print `echo "$postmaster_mail" | mail -s "CLAMD ERRORS!" $postmaster`;
 
         }
 
         }
 
         # now log the results of the scan
 
         # now log the results of the scan
Line 568: Line 585:
 
         $email = `$antispam_agent < $temppath/$tempdir/email.txt`;
 
         $email = `$antispam_agent < $temppath/$tempdir/email.txt`;
 
         $spam_found = ($? >> 8); # shift value of $? 8 places to get actual exit code
 
         $spam_found = ($? >> 8); # shift value of $? 8 places to get actual exit code
}
+
        if ($spam_found == 0) {
</pre>
+
                $spam_logstring = "no_spam_found";
 +
        } elsif ($spam_found == 1) {
 +
                @spam_body = split(/score=/, $email);
 +
                @spam_body = split(/ /, $spam_body[1]);
 +
                $spam_logstring = "SPAM_FOUND SCORE=$spam_body[0] RECIPIENT=$qmail_rcpts";
 +
        } else {
 +
        $spam_logstring = "WARNING: spamc returned error code $spam_found";
 +
        $spam_logstring .= '! Delivering message anyway, and emailing postmaster...';
 +
        $postmaster_mail = "WARNING: spamc returning error code $spam_found on your mailserver.  (Is clamd running?)";
 +
        print `echo "$postmaster_mail" | mail -s "spamd errors" $postmaster`;
 +
        }
 +
        # now log the results of the scan
 +
        print `echo "$spam_logstring" | $logging`;
 +
 
 +
}</pre>
  
 
== qmail-queue replacement ==
 
== qmail-queue replacement ==

Revision as of 12:59, 25 February 2006

no, really, the comma shouldn't be there. (or the title should be "what it is, and what we are doing here" without the question mark). I used to be a spelling and grammar nazi in a past life.

-d.



You're going to have to back that up with an external link to a well-accepted style guide that clearly states that using a comma there is wrong, and even then I don't promise to care. =) --Jimbo 20:36, 15 Dec 2004 (EST)



http://cctc2.commnet.edu/grammar/commas.htm

while not incorrect to use the comma there, it makes for bad scanning.

-d.



I'm not well up on wiki etiquette so I just thought I'd add a comment here on a small change I made.

I added two /etc/ to the following section to ensure the command will work correctly when executed outside of the /etc directory

ph34r# rehash
ph34r# cat /etc/tcp.smtp | tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp

Also for some reason I couldn't get make enable-qmail to execute. It was probably something I was doing wrong but should anyone run into similar difficulty just check out the file work/qmail-enable inside the qmail+smtp_auth+tls ports directory.

Its easy enough to read what it does and then execute the commands for disabling sendmail and enabling qmail manually.

P.S. Great guide, it was very helpful, Eoin



Huh - that's odd (that make qmail-enable ran into problems). Never seen that before. And your change was good, thanks. =) --Jimbo 10:59, 7 Jun 2005 (EDT)



Contents

oddly enough

so for giggles, i'm installing a listserv (using mailman...i'll let you know how ti works out) and I'm using FreeBSD for the hell of it. and I am also having problems doing a make enable-qmail. going into the work dir doesn't shed any light on the matter as the only thing in there is:

# ls -la
total 28
drwxr-xr-x  3 root  wheel    512 Jul 13 16:18 .
drwxr-xr-x  3 root  wheel    512 Jul 13 16:18 ..
-rw-r--r--  1 root  wheel      0 Jul 13 16:18 .build_done.qmail-smtp_auth+tls-1.03.20020519_1._var_qmail
-rw-r--r--  1 root  wheel      0 Jul 13 16:18 .configure_done.qmail-smtp_auth+tls-1.03.20020519_1._var_qmail
-rw-r--r--  1 root  wheel      0 Jul 13 16:18 .extract_done.qmail-smtp_auth+tls-1.03.20020519_1._var_qmail
-rw-r--r--  1 root  wheel      0 Jul 13 16:18 .patch_done.qmail-smtp_auth+tls-1.03.20020519_1._var_qmail
-rw-r--r--  1 root  wheel    311 Jul 13 16:18 SMTP_AUTH+TLS.readme
-rw-r--r--  1 root  wheel   2639 Jul 13 16:18 pkg-install
drwxr-xr-x  2 root  wheel  16896 Jul 13 16:18 qmail-1.03

so what does enable-qmail do (as a target to make) that just a make install doesn't?



See the directory that I bolded in your ls output there? That's where the goodies are. That's how the work directory from a built port always looks. But in this case, what you actually want to look at is files/enable-qmail.in. What it does is, so far as I can tell, is just make sure that the mail command gets realiased to qmail from whatever it was aliased to before, by the means of copying a conf file. From looking at the Makefile, though, it looks as though the qmail-enable target may not even exist anymore; it looks like an installation of qmail since 1.03_3 will probably make a /var/qmail/scripts directory instead, from which you can run the script /var/qmail/scripts/enable-qmail. Lemme know what you find out, okay? --Jimbo 00:00, 14 Jul 2005 (EDT)



It might be worth mentioning that if vpopmail is ever upgraded then you need to manually reset the file attributes of /usr/local/vpopmail/bin/vchkpw or users will have login troubles.

-Eoin



Great Guide but I am having problems with SqWebmail Portion, it seems now that the in the ports tree when you install sqwebmail you get courier-authdaemond installed instead of sqwebmail-authdaemond, and I can not find anywhere the PREFIX script I need to replace in the .sh files, and I notice that courier-authdaemond has PREFIX already set to /usr/local already.......so I thought I was good to go.

but after I start the daemons and point my browser to Sqwebmail I get a 500 error with: The webmail system is temporarily unavailable. An error occured in function write: Socket is not connected?

I notice that in the courier-authdaemond.sh there is a setting for socket with the base directory being $authbase/run/socket however there is not a socket file or folder in /var/run

Any Thoughts?

- J



are you sure that $authbase == /var/run? I'd do a "find / | grep socket" to see where it might be..

--Dave 23:42, 14 Sep 2005 (EDT)


Here is the output:


 nusparky# find / | grep socket
 /usr/include/netgraph/bluetooth/include/ng_btsocket.h
 /usr/include/netgraph/bluetooth/include/ng_btsocket_hci_raw.h
 /usr/include/netgraph/bluetooth/include/ng_btsocket_l2cap.h
 /usr/include/netgraph/bluetooth/include/ng_btsocket_rfcomm.h
 /usr/include/netgraph/ng_ksocket.h
 /usr/include/netgraph/ng_socket.h
 /usr/include/netgraph/ng_socketvar.h
 /usr/include/sys/socket.h
 /usr/include/sys/socketvar.h
 /usr/local/man/man1/socket.1.gz
 /usr/local/bin/socket
 /usr/local/lib/perl5/site_perl/5.8.7/mach/sys/socket.ph
 /usr/local/lib/perl5/site_perl/5.8.7/mach/sys/socketvar.ph
 /usr/local/share/doc/socket
 /usr/local/share/doc/socket/README
 /
 ......the rest are documents or in the ports tree
 ^C
 nusparky#
 nusparky#
 nusparky#

Any ideas?

-J



maybe something else is holding the socket open? I'm guessing you've got sqwebmail tied into apache -- is your apache config ok? I don't run webmail myself so I probably won't be much help.

--Dave 09:47, 15 Sep 2005 (EDT)

have you tried to ps waux | grep authdaemon?

Try to start the authdaemon - /usr/local/etc/rc.d/(whatever)daemond.sh start - and then ps waux | grep authdaemon. Is it running?

If it isn't, you're going to need to figure out why. Usually the easiest way to deal with that PREFIX crap is just to snip it out and sub in the /usr/local/ hard-coded. --Jimbo 02:07, 16 Sep 2005 (EDT)

lsof to find open sockets maybe

might want to use lsof to see what's holding the socket open too...

--Dave 11:56, 17 Sep 2005 (EDT)

this article should be updated...

...unfortunately, until i reinstall freebsd on a sparc at work, i have no bsd to do it with; the make qmail-enable thing doesn't work (i do the qmailrocks.org install myself....although i've been playing with postfix recently, and i'm going to install zimbra on my new listserver (why i moved my x86-64 box to CentOS instead of FreeBSD)....

--Dave 23:56, 3 Jan 2006 (EST)

Checking Environment Variables

Note to self: checking the environment variable TCPREMOTEINFO is a better way to check for authenticated SMTP, but qsheff doesn't pass that along - you'd need to wrap BEFORE qsheff, not after, in order to pick up on that. Which is beginning to beg the point of using qsheff at all... here is a complete list of environment variables present when qmail-queue is run:

TCPLOCALPORT=2525
USER=yourmom
SSH_CLIENT='24.168.100.50 3295 22'
MACHTYPE=i386
MAIL=/var/mail/mom
TCPREMOTEIP=70.150.138.10
VENDOR=intel
SHLVL=2
HOME=/root
PROTO=TCP
SSH_TTY=/dev/ttyp0
PAGER=more
PS1='$ '
OPTIND=1
PS2='> '
GROUP=wheel
LOGNAME=mom
TERM=xterm
BLOCKSIZE=K
TCPREMOTEPORT=1935
PPID=92605
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin:/root/bin
REMOTEHOST=24.168.100.50
TCPLOCALIP=66.154.114.98
SHELL=/bin/csh
HOST=blackbox.tehinterweb.net
IFS='
'
OSTYPE=FreeBSD
TCPLOCALHOST=mail.jrssystems.net
PWD=/home/mom
TCPREMOTEINFO=jim@jrssystems.net
SSH_CONNECTION='24.168.100.50 3295 66.154.114.98 22'
FTP_PASSIVE_MODE=YES
HOSTTYPE=FreeBSD
EDITOR=vi

No black magic. So - ditch qsheff entirely and simply wrap qmail-queue itself?

ENVs to particularly note: TCPREMOTEINFO, TCPREMOTEIP

Final note for the night: don't see why not do my own standalone wrapper; mail got delivered fine while I was piping environment variables to a text file and piping STDIN to qmail-queue just now. No black magic a'tall, I don't know why wrapping qmail-queue wasn't seeming to work for me the last time I tried it; maybe I just didn't have the permissions set so that my wrapper would execute then?

AHA there is one bit of magic: qmail-queue actually READS its STDOUT to get addressing information normally; that's how bcc works. Example:

open (FH, "<&=1");
  @so = <FH>;
close (FH);

in a wrapper will get you the following in @so, from a message bcc'ed to yourmom@momscrib.com:

Fdad@pimpshack.netTyourmom@momscrib.com

Harrrr....

--Jimbo 02:58, 21 Feb 2006 (EST)

Okay FOR REAL final line for the night: turns out that trying to get Perl to write to a child's STDOUT is beyond fucking painful. However it looks like /usr/ports/mail/qmail-qfilter will do the job nicely, it can be compiled as a plain (brown) wrapper with a minor alteration to the source code and takes a "get out of here you jackass" exit code (31) or a silent drop exit code (99) so there's good range of functionality.

it runs like this: put a shell script in place of qmail-queue like so:

#!/bin/sh
exec /path/to/qmail-qfilter \
       /path/to/spamc -- \
       /path/to/reject-message-with-spamrating-over-5 -- \
       /path/to/reject-message-with-viagra -- \
       /path/to/reject-message-with-sobig

Sheesh. It's 5AM again. =( --Jimbo 05:00, 21 Feb 2006 (EST)

Confirmed. qmail-qfilter works fine. Just need to rework maildump.pl to dump the message to STDOUT instead of trying to feed it to qmail-queue directly by itself. --Jimbo 05:15, 21 Feb 2006 (EST)

SETUID perl

probably will need to compile a new version of Perl from ports with MAKE -DENABLESUIDPERL=yes so's we can run the scanner as vpopmail / vchkpw. At least, if you want its quarantined stuff to be visible from a maildir.

qqxrc.patch

save this (gotten from http://www.wijata.com/software/#QMAIL) as /home/[yourname]/qqxrc.patch

cd /usr/ports/mail/qmail-tls make config : make sure to select the SMTP_AUTH knob and the RCDLINK knob; optionally you may choose to select the local-time knob also make fetch make patch cd work/qmail-1.0.3 patch < /home/[yourname]/qqxrc.patch cd ../.. make install

diff -uPr qmail-1.03-va/Makefile qmail-1.03/Makefile
--- qmail-1.03-va/Makefile      1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/Makefile 2004-06-15 12:27:36.000000000 +0200
@@ -321,9 +321,11 @@

 condredirect: \
 load condredirect.o qmail.o strerr.a fd.a sig.a wait.a seek.a env.a \
-substdio.a error.a str.a fs.a auto_qmail.o
+substdio.a error.a str.a fs.a auto_qmail.o \
+open.a getln.a stralloc.a alloc.a byte_chr.o
        ./load condredirect qmail.o strerr.a fd.a sig.a wait.a \
-       seek.a env.a substdio.a error.a str.a fs.a auto_qmail.o
+       seek.a env.a substdio.a error.a str.a fs.a auto_qmail.o \
+       open.a getln.a stralloc.a alloc.a byte_chr.o

 condredirect.0: \
 condredirect.1
@@ -594,9 +596,11 @@

 forward: \
 load forward.o qmail.o strerr.a alloc.a fd.a wait.a sig.a env.a \
-substdio.a error.a str.a fs.a auto_qmail.o
+substdio.a error.a str.a fs.a auto_qmail.o \
+open.a getln.a stralloc.a alloc.a byte_chr.o
        ./load forward qmail.o strerr.a alloc.a fd.a wait.a sig.a \
-       env.a substdio.a error.a str.a fs.a auto_qmail.o
+       env.a substdio.a error.a str.a fs.a auto_qmail.o \
+       open.a getln.a stralloc.a alloc.a byte_chr.o

 forward.0: \
 forward.1
@@ -1352,10 +1356,11 @@

 qmail-qmqpd: \
 load qmail-qmqpd.o received.o now.o date822fmt.o qmail.o auto_qmail.o \
-env.a substdio.a sig.a error.a wait.a fd.a str.a datetime.a fs.a
+env.a substdio.a sig.a error.a wait.a fd.a str.a datetime.a fs.a open.a \
+getln.a stralloc.a alloc.a
        ./load qmail-qmqpd received.o now.o date822fmt.o qmail.o \
        auto_qmail.o env.a substdio.a sig.a error.a wait.a fd.a \
-       str.a datetime.a fs.a
+       str.a datetime.a fs.a open.a getln.a stralloc.a alloc.a

 qmail-qmqpd.0: \
 qmail-qmqpd.8
@@ -1639,10 +1644,10 @@
 qreceipt: \
 load qreceipt.o headerbody.o hfield.o quote.o token822.o qmail.o \
 getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a substdio.a error.a \
-str.a auto_qmail.o
+str.a auto_qmail.o open.a
        ./load qreceipt headerbody.o hfield.o quote.o token822.o \
        qmail.o getln.a fd.a wait.a sig.a env.a stralloc.a alloc.a \
-       substdio.a error.a str.a auto_qmail.o
+       substdio.a error.a str.a auto_qmail.o open.a

 qreceipt.0: \
 qreceipt.1
diff -uPr qmail-1.03-va/qmail.c qmail-1.03/qmail.c
--- qmail-1.03-va/qmail.c       1998-06-15 12:53:16.000000000 +0200
+++ qmail-1.03/qmail.c  2004-06-15 12:13:21.000000000 +0200
@@ -6,6 +6,7 @@
 #include "fd.h"
 #include "qmail.h"
 #include "auto_qmail.h"
+#include "stralloc.h"

 static char *binqqargs[2] = { "bin/qmail-queue", 0 } ;

@@ -118,6 +119,35 @@
     case 81: return "Zqq internal bug (#4.3.0)";
     case 120: return "Zunable to exec qq (#4.3.0)";
     default:
+       /* QQXRCODE */
+       if (1) {
+        static char rcode[60];
+        char inbuf[60];
+        int rlen, match;
+        substdio ss;
+        stralloc line = {0};
+        int fd = open_read("control/qqxrcode");
+        if (fd >= 0) {
+           rlen = snprintf(rcode, 5, "%d ", exitcode);
+           substdio_fdbuf(&ss,read,fd,inbuf,sizeof(inbuf));
+           for (;;) {
+               if (getln(&ss,&line,&match,'\n') == -1) { match = 0; break; };
+               if (! match) break;
+               while (line.len>0 && line.s[line.len-1]<33) line.len--;
+               if (!stralloc_0(&line)) { match = 0; break; };
+               if (line.len>rlen
+                   && !str_diffn(rcode, line.s, rlen) ) break;
+           };
+           close(fd);
+           if (match) {
+               snprintf(rcode, 59, "%c%s",
+                   ((exitcode >= 11) && (exitcode <= 40) ? 'D':'Z'),
+                   line.s+rlen);
+               return rcode;
+           };
+        };
+       };
+       /* QQXRCODE */
       if ((exitcode >= 11) && (exitcode <= 40))
        return "Dqq permanent problem (#5.3.0)";
       return "Zqq temporary problem (#4.3.0)";

now you can make install as normal

to use it, create /var/qmail/control/qqxrcode and populate it like so:

32 Message permanently rejected (Virus detected)
33 Message permanently rejected (Spam detected)

Net result: exiting from a filter program with a 32 or 33 gets you the above messages.

Normal SMTP 554 is from an exit 31, so I'd recommend sticking stuff in between 32 and 40.

smartscan.pl

#!/usr/bin/perl

###
### Smartscanner.pl
###
### VERSION 2.0
### 2006 Feb 23
###
### (c) 2004,2006 JRS System Solutions
### all rights reserved under BSD license -
### you may use this code as long as this header remains
### intact.
###

# $postmaster is the address which will receive warnings.
#             THIS SHOULD NOT BE AN ADDRESS AT A DOMAIN
#             HANDLED BY THIS MAILSERVER!  ENDLESS LOOPS
#             COULD LOCK UP YOUR SERVER!
#
$postmaster = 'postmaster@someotherdomain.tld';

# Don't forget to use visudo to allow qmaild to run maildir
# as vpopmail!
#
$delivery_agent = "/usr/local/bin/sudo -u vpopmail /usr/local/bin/maildir";

# run antivirus / antispam scanners on mail delivered
# via SMTP AUTH connection?
#
$virus_scan_auth = 1;
$spam_scan_auth = 0;

# note: $quarantine_* does not determine whether mail is delivered
#        to its original destination or not; only whether a copy of
#        it is delivered to $quarantine_dir.  The $reject_*
#        variables below determine delivery or non-delivery to
#        the original recipient and outcome of the SMTP conversation.
#
$quarantine_spam = 1;
$quarantine_virus = 1;
$quarantine_dir = '/usr/local/vpopmail/domains/yourdomain.tld/yourname/Maildir/.INBOX.quarantine';

# note: if $archive_mail is set then copies of ACCEPTED mail - mail
#       which has either not flagged as spam or virus OR mail which
#       has flagged but for which the rejection setting is 0 - will
#       be delivered to $archive_dir.  If you want a single message
#       store with accepted and rejected mail, set $archive_dir and
#       $quarantine_dir to the same destination.
#
$archive_mail = 0;
$archive_dir = '/usr/local/vpopmail/domains/yourdomain.tld/yourname/Maildir/.INBOX.archive';

# Reject detected spams and/or viruses, or deliver them?
#  (in case of double-flag, virus rejection setting takes priority.)
#     0 = no rejection - accept and deliver (mangled) mail to
#         original destination
#     1 = quiet reject, aka drop without alerting qmail-queue
#     2 = "noisy" reject, aka drop and pass error message along
#         to qmail-queue for an SMTP 554 reject before SMTP
#         conversation completes
#
$reject_spam = 2;
$reject_virus = 2;

# set the other basic configuration variables -
# logging, path of the working directory, name
# of the working file.
$logging = "/var/qmail/bin/splogger smartscan.pl";
$antispam_agent = "/usr/local/bin/spamc -E";

# $temppath is where working directories will be created.
$temppath = "/tmp";

################################################################################################
################################################################################################
##      END USER CONFIGURATION VARIABLE SECTION -- PROGRAMMATIC SECTION BEGINS BELOW          ##
################################################################################################
################################################################################################

# read envelope and environment variables
@envelope=(<STDERR>);
$environment=`/usr/bin/env`;
@environment=split(/\n/, $environment);

# Figure out where the SMTP connection came from and whether SMTP_AUTH was used.
$tcpremoteinfo = 'NONE';

foreach $line (@environment) {
        if ($line =~ /^\s*TCPREMOTEINFO/) { $tcpremoteinfo = $line; }
        if ($line =~ /^\s*TCPREMOTEIP/)   { $tcpremoteip = $line; }
        # this handling of QMAILRCPTS is primitive and lazy.
        if ($line =~ /^\s*QMAILRCPTS/)    {
                @rcpt = split (/=/, $line);
                $qmail_rcpts = $rcpt[1];
        }
}

# working filename is a 15-digit random name to avoid overstep issues.
$tempdir = "smartscan_" . &randgen;

# fetch standard input, and rewrite it into a plain
# text file in a unique working directory.
print `mkdir $temppath/$tempdir`;
@in=(<STDIN>);
$email = '';
open (FH, "> $temppath/$tempdir/email.txt");
foreach $line (@in) {
        print FH "$line";
        $email .= $line;
}
close (FH);

# peel off any MIME attachments and make them
# world-readable for benefit of scan daemons
# running under separate UIDs.
#
# note: ripmime is available at /usr/ports/mail/ripmime.
# note2: used to use munpack, but munpack couldn't handle TNEF (MS Outlook) garbage
#        correctly.  so ripmime is (significantly) better.
print `mkdir $temppath/$tempdir/WORKING`;
print `/usr/local/bin/ripmime -i $temppath/$tempdir/email.txt -e -d $temppath/$tempdir/WORKING`;
print `chmod -R 777 $temppath/$tempdir`;

# rework reject_spam and reject_virus to match desired exit codes:
# code 31 = SMTP 554, code 99 = silent drop
#
# in this case, we have a patched qmail with custom error codes for
# 32 and 33 so we are using those.
#
if ($reject_spam == 1) { $reject_spam = 99; } elsif ($reject_spam == 2) { $reject_spam = 33; }
if ($reject_virus == 1) { $reject_virus = 99; } elsif ($reject_virus == 2) { $reject_virus = 32; }

# only run virus scanning if not using SMTP AUTH or if $virus_scan_auth is set.
if ($tcpremoteinfo=='NONE' || $virus_scan_auth == 1) {
        &scan_clamd;
}

# no point in wasting resources on spamassassin if we already found a virus;
# then only run spamassassin if not using SMTP AUTH or if $spam_scan_auth is set.

if ( $virus_found != 1
     &&
       ( $tcpremoteinfo eq 'NONE'
         || $spam_scan_auth == 1
       )
   )
{
        &scan_spamc;
}

# deliver quarantine copy of email if called for
if ($quarantine_spam == 1 && $spam_found) || ($quarantine_virus == 1 && $virus_found)
{
        open (FH, "| $delivery_agent $quarantine_dir");
        print FH $email;
        close (FH);
        print `echo "Delivered quarantine message copy to: $qmail_rcpts" | $logging`;
}

# deliver archive copy of email if called for
if ($archive_mail == 1
    && ($spam_found != 1 || $reject_spam == 0)
    && ($virus_found != 1 || $reject_virus == 0)
   )
{
        open (FH, "| $delivery_agent $archive_dir");
        print FH $email;
        close (FH);
        print `echo "Delivered archive message copy to: $qmail_rcpts" | $logging`;
}

# lose the contents of our unique working directory.
#
print `rm -rf $temppath/$tempdir`;

# Decide how and if to deliver the message - controlled by exit code
$exit_code = 0;
if ($spam_found == 1) { $exit_code = $reject_spam; }
if ($virus_found == 1) { $exit_code = $reject_virus; }

# Pass STDOUT and exit status through and back out to qmail-queue
# No point in passing mail back to STDOUT if it's getting bounced.
if ($exit_code == 0) { print $email; } else { print ''; }

exit $exit_code;


################################################################
################################################################

sub randgen {
        $result="";
        $rndkey="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz";
        $randlength="15";
        while ($randlength) {
                $result.=substr($rndkey,rand(length($rndkey)),1);
                $randlength--;
        }
        return $result;
}

sub scan_fprot {
        $strSCAN = `/usr/local/f-prot/f-prot -packed -ai -archive $temppath/$tempdir/WORKING`;
        $virus_found = ($? == 0);
        if ($virus_found) {
                $virus_logstring = "no_malware_found";
        } else {
                @scan_result = split(/\ /, $strSCAN);
                $virus_logstring = "MALWARE_FOUND=$scan_result[1]";
        }
}

sub scan_clamd {
        $strSCAN = `/usr/local/bin/clamdscan --disable-summary --stdout $temppath/$tempdir/WORKING`;
        $virus_found = ($? >> 8); # shift value of $? 8 places to get actual exit code
        if ($virus_found == 0) {
                $virus_logstring = "no_malware_found";
        } elsif ($virus_found == 1) {
                @scan_result = split(/\ /, $strSCAN);
                $virus_name = $scan_result[@scan_result - 2];
                $virus_logstring = "MALWARE_FOUND=$virus_name RECIPIENT=$qmail_rcpts";
        } else {
        $virus_logstring = "WARNING: clamdscan returned error code $virus_found";
        $virus_logstring .= '! Delivering message anyway, and emailing postmaster...';
        $postmaster_mail = "WARNING: clamdscan returning error code $virus_found on your mailserver.  (Is clamd running?)";
        print `echo "$postmaster_mail" | mail -s "CLAMD ERRORS!" $postmaster`;
        }
        # now log the results of the scan
        print `echo "$virus_logstring" | $logging`;
}

sub scan_spamc {
        $email = `$antispam_agent < $temppath/$tempdir/email.txt`;
        $spam_found = ($? >> 8); # shift value of $? 8 places to get actual exit code
        if ($spam_found == 0) {
                $spam_logstring = "no_spam_found";
        } elsif ($spam_found == 1) {
                @spam_body = split(/score=/, $email);
                @spam_body = split(/ /, $spam_body[1]);
                $spam_logstring = "SPAM_FOUND SCORE=$spam_body[0] RECIPIENT=$qmail_rcpts";
        } else {
        $spam_logstring = "WARNING: spamc returned error code $spam_found";
        $spam_logstring .= '! Delivering message anyway, and emailing postmaster...';
        $postmaster_mail = "WARNING: spamc returning error code $spam_found on your mailserver.  (Is clamd running?)";
        print `echo "$postmaster_mail" | mail -s "spamd errors" $postmaster`;
        }
        # now log the results of the scan
        print `echo "$spam_logstring" | $logging`;

}

qmail-queue replacement

mv qmail-queue qmail-queue.orig

this is the new qmail-queue:

#!/bin/sh
exec /usr/local/bin/qmail-qfilter \
        /var/qmail/bin/qmail-inject -n -- \
        /usr/local/bin/smartscan.pl
Personal tools