Vratenie spamu II

Petr Houstek phoustek-lists na utf.mff.cuni.cz
Úterý Září 7 22:44:44 CEST 2004


On Mon, Sep 06, 2004 at 09:31:02AM +0200, Honza Novacek wrote:

> chtel bych umet na smtp urovni neprijmout mail, tj. nevznikne bounce.
> Umi qmail s tcpserverem odmitnout prijmout zpravu, kdyz e-mail adresa
> neexistuje?

O odmitnuti zpravy primo v SMTP spojeni rozhoduje qmail-smtpd. Ten nevi
nic o lokalnich uzivatelich. Existuje ale mechanismus qmailque, pres
ktery se da definovat urcita akce (napr. kontrola existence uzivatele),
nebo lze pouzit napr. patch badmailto v kombinaci s goodmailto.
Pokud je cilova adresa obsazena v souboru /var/qmail/control/goodmailto
(goodrcptto), je spojeni vzdy povoleno. Pokud je pouze v souboru
badmailto,
je spojeni odmitnuto na SMTP urovni. Pokud je adresa jak v badmailto i v
goodmailto, je spojeni povoleno. Resenim tedy je vsechny platne adresy
pridat do goodmailto a do badmailto pridat pro vsechny domeny toto

@domena\.cz$

Protoze se tento patch mozna spatne hleda, prikladam ho v priloze.
Tento patch je nutne aplikovat po patchi qregex, ktery umoznuje
pouzivani regularnich vyrazu v souborech goodmailto, badmailto a
badmailfrom.

-- 
Petr Houstek

------------- další část ---------------
--- qregex.c-dist	Fri Dec 28 02:08:05 2001
+++ qregex.c	Tue Jan 29 18:57:44 2002
@@ -0,0 +1,57 @@
+/*
+ * qregex (v2)
+ * $Id: qregex.c,v 2.1 2001/12/28 07:05:21 evan Exp $
+ *
+ * Author  : Evan Borgstrom (evan at unixpimps dot org)
+ * Created : 2001/12/14 23:08:16
+ * Modified: $Date: 2001/12/28 07:05:21 $
+ * Revision: $Revision: 2.1 $
+ *
+ * Do POSIX regex matching on addresses for anti-relay / spam control.
+ * It logs to the maillog
+ * See the qregex-readme file included with this tarball.
+ * If you didn't get this file in a tarball please see the following URL:
+ *  http://www.unixpimps.org/software/qregex
+ *
+ * qregex.c is released under a BSD style copyright.
+ * See http://www.unixpimps.org/software/qregex/copyright.html
+ *
+ * Note: this revision follows the coding guidelines set forth by the rest of
+ *       the qmail code and that described at the following URL.
+ *       http://cr.yp.to/qmail/guarantee.html
+ * 
+ */
+
+#include <sys/types.h>
+#include <regex.h>
+#include "qregex.h"
+
+#define REGCOMP(X,Y)    regcomp(&X, Y, REG_EXTENDED)
+#define REGEXEC(X,Y)    regexec(&X, Y, (size_t)0, (regmatch_t *)0, (int)0)
+
+int matchregex(char *text, char *regex) {
+  regex_t qreg;
+  int retval = 0;
+
+
+  /* build the regex */
+  if ((retval = REGCOMP(qreg, regex)) != 0) {
+    regfree(&qreg);
+    return(-retval);
+  }
+
+  /* execute the regex */
+  if ((retval = REGEXEC(qreg, text)) != 0) {
+    /* did we just not match anything? */
+    if (retval == REG_NOMATCH) {
+      regfree(&qreg);
+      return(0);
+    }
+    regfree(&qreg);
+    return(-retval);
+  }
+
+  /* signal the match */
+  regfree(&qreg);
+  return(1);
+}
--- qregex.h-dist	Fri Dec 28 02:08:09 2001
+++ qregex.h	Thu Dec 27 13:04:19 2001
@@ -0,0 +1,5 @@
+/* simple header file for the matchregex prototype */
+#ifndef _QREGEX_H_
+#define _QREGEX_H_
+int matchregex(char *text, char *regex);
+#endif
--- qmail-smtpd.c-dist	Fri Dec 28 01:53:50 2001
+++ qmail-smtpd.c	Tue Jan 29 18:43:09 2002
@@ -23,6 +23,10 @@
 #include "timeoutread.h"
 #include "timeoutwrite.h"
 #include "commands.h"
+#include "qregex.h"
+
+#define BMCHECK_BMF 0
+#define BMCHECK_BMT 1
 
 #define MAXHOPS 100
 unsigned int databytes = 0;
@@ -49,7 +53,8 @@
 void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }
 void straynewline() { out("451 See http://pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }
 
-void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }
+void err_bmf() { out("553 sorry, your envelope sender has been denied (#5.7.1)\r\n"); }
+void err_bmt() { out("533 sorry, your envelope recipient has been denied (#5.7.1)\r\n"); }
 void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }
 void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }
 void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }
@@ -93,10 +98,15 @@
 
 int liphostok = 0;
 stralloc liphost = {0};
+
 int bmfok = 0;
 stralloc bmf = {0};
 struct constmap mapbmf;
 
+int bmtok = 0;
+stralloc bmt = {0};
+struct constmap mapbmt;
+
 void setup()
 {
   char *x;
@@ -114,8 +124,11 @@
 
   bmfok = control_readfile(&bmf,"control/badmailfrom",0);
   if (bmfok == -1) die_control();
-  if (bmfok)
-    if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
+  if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
+
+  bmtok = control_readfile(&bmt,"control/badmailto",0);
+  if (bmtok == -1) die_control();
+  if (!constmap_init(&mapbmt,bmt.s,bmt.len,0)) die_nomem();
  
   if (control_readint(&databytes,"control/databytes") == -1) die_control();
   x = env_get("DATABYTES");
@@ -197,14 +210,38 @@
   return 1;
 }
 
-int bmfcheck()
+int bmcheck(which) int which;
 {
-  int j;
-  if (!bmfok) return 0;
-  if (constmap(&mapbmf,addr.s,addr.len - 1)) return 1;
-  j = byte_rchr(addr.s,addr.len,'@');
-  if (j < addr.len)
-    if (constmap(&mapbmf,addr.s + j,addr.len - j - 1)) return 1;
+  int i = 0;
+  int j = 0;
+  int x = 0;
+  int negate = 0;
+  stralloc bmb = {0};
+  stralloc curregex = {0};
+
+  if (which == BMCHECK_BMF) {
+    if (!stralloc_copy(&bmb,&bmf)) die_nomem();
+  } else if (which == BMCHECK_BMT) {
+    if (!stralloc_copy(&bmb,&bmt)) die_nomem();
+  } else {
+    die_control();
+  }
+
+  while (j < bmb.len) {
+    i = j;
+    while ((bmb.s[i] != '\0') && (i < bmb.len)) i++;
+    if (bmb.s[j] == '!') {
+      negate = 1;
+      j++;
+    }
+    stralloc_copyb(&curregex,bmb.s + j,(i - j));
+    stralloc_0(&curregex);
+    x = matchregex(addr.s, curregex.s);
+    if ((negate) && (x == 0)) return 1;
+    if (!(negate) && (x > 0)) return 1;
+    j = i + 1;
+    negate = 0;
+  }
   return 0;
 }
 
@@ -218,7 +255,8 @@
 
 
 int seenmail = 0;
-int flagbarf; /* defined if seenmail */
+int flagbarfbmf; /* defined if seenmail */
+int flagbarfbmt;
 stralloc mailfrom = {0};
 stralloc rcptto = {0};
 
@@ -240,7 +278,7 @@
 void smtp_mail(arg) char *arg;
 {
   if (!addrparse(arg)) { err_syntax(); return; }
-  flagbarf = bmfcheck();
+  if (bmfok) flagbarfbmf = bmcheck(BMCHECK_BMF);
   seenmail = 1;
   if (!stralloc_copys(&rcptto,"")) die_nomem();
   if (!stralloc_copys(&mailfrom,addr.s)) die_nomem();
@@ -250,7 +288,9 @@
 void smtp_rcpt(arg) char *arg; {
   if (!seenmail) { err_wantmail(); return; }
   if (!addrparse(arg)) { err_syntax(); return; }
-  if (flagbarf) { err_bmf(); return; }
+  if ((!flagbarfbmf) && (bmtok)) { flagbarfbmt = bmcheck(BMCHECK_BMT); }
+  if (flagbarfbmf) { err_bmf(); return; }
+  if (flagbarfbmt) { err_bmt(); return; }
   if (relayclient) {
     --addr.len;
     if (!stralloc_cats(&addr,relayclient)) die_nomem();
--- Makefile-dist	Mon Jun 15 06:53:16 1998
+++ Makefile	Thu Dec 27 14:16:02 2001
@@ -1532,12 +1532,12 @@
 	./compile qmail-showctl.c
 
 qmail-smtpd: \
-load qmail-smtpd.o rcpthosts.o commands.o timeoutread.o \
+load qmail-smtpd.o rcpthosts.o qregex.o commands.o timeoutread.o \
 timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o received.o \
 date822fmt.o now.o qmail.o cdb.a fd.a wait.a datetime.a getln.a \
 open.a sig.a case.a env.a stralloc.a alloc.a substdio.a error.a str.a \
 fs.a auto_qmail.o socket.lib
-	./load qmail-smtpd rcpthosts.o commands.o timeoutread.o \
+	./load qmail-smtpd qregex.o rcpthosts.o commands.o timeoutread.o \
 	timeoutwrite.o ip.o ipme.o ipalloc.o control.o constmap.o \
 	received.o date822fmt.o now.o qmail.o cdb.a fd.a wait.a \
 	datetime.a getln.a open.a sig.a case.a env.a stralloc.a \
@@ -1680,6 +1680,10 @@
 compile rcpthosts.c cdb.h uint32.h byte.h open.h error.h control.h \
 constmap.h stralloc.h gen_alloc.h rcpthosts.h
 	./compile rcpthosts.c
+
+qregex.o: \
+compile qregex.c qregex.h
+	./compile qregex.c
 
 readsubdir.o: \
 compile readsubdir.c readsubdir.h direntry.h fmt.h scan.h str.h \
--- TARGETS-dist	Mon Jun 15 06:53:16 1998
+++ TARGETS	Thu Dec 27 14:16:19 2001
@@ -252,6 +252,7 @@
 qmail-qmtpd
 qmail-smtpd.o
 qmail-smtpd
+qregex.o
 sendmail.o
 sendmail
 tcp-env.o
--- README.qregex-dist	Fri Dec 28 01:53:13 2001
+++ README.qregex	Fri Dec 28 01:48:28 2001
@@ -0,0 +1,110 @@
+QREGEX (v2) - README [12/28/01]
+A Regular Expression matching patch for qmail 1.03
+
+
+OVERVIEW:
+
+qregex adds the ability to match address evelopes via Regular Expressions (REs)
+in the qmail-smtpd process. It has the abiltiy to match both `mail from` and
+`rcpt to` commands with no load at all the parent process. It follows all the
+base rules that are set out with qmail (ie using control files) so it makes for
+easy integretion into an existing setup (see the install instructions for more info).
+The v2 noting is because qregex was re-written to better conform to the security
+gaurantee set forth by the author. The original version used stdio.h and stdlib.h
+for reading the control files where as v2 now uses all stralloc functions which
+are much more regulated against buffer overruns and the likes.
+See: http://cr.yp.to/qmail/guarantee.html
+
+
+
+PLATFORMS:
+
+qregex has been built and tested on the following platforms. I'm sure it won't have
+any problems on any platform that qmail will run on (providing they provide a regex
+interface) but if you run into problems let me know.
+
+        - Solaris 2.7 (7, SunOS 5.7)
+	- Solaris 2.8 (8, SunOS 5.8)
+	- OpenBSD 2.8
+	- OpenBSD 2.9
+	- FreeBSD 4.3-RELEASE
+	- FreeBSD 5.0-CURRENT
+	- Linux
+
+
+
+INSTALLATION INSTRUCTIONS:
+
+Installation is very simple, there is only one requirement. You need to use the GNU
+version of the patch utility (http://www.gnu.org/software/patch/patch.html).
+(For Solaris 8 users like me it is installed as 'gpatch')
+
+- If this is a new setup.
+Uncompress and untar the qmail archive, copy the 'qregex.patch' file into the new
+qmail-1.03 directory and run "patch < qregex.patch"
+Follow the instructions as per the included qmail INSTALL file.
+Once you are done come back to this file and read the section on the control files.
+
+- If this is an existing setup.
+FIRST: create your control files (see below).
+Copy the 'qregex.patch' file into your existing qmail source directory.
+Run "patch < qregex.patch" then "make qmail-smtpd". Now run ./qmail-smtpd and test
+your new rules to make sure they work as expected.
+
+Install the new binary by cd'ing to /var/qmail/bin and as root (in one command)
+copy the existing binary to 'qmail-smtpd.old' and copy the new binary from the 
+source directory to 'qmail-smtpd'.
+(ex. cp qmail-smtpd qmail-smtpd.old && cp ~/qmail-1.03/qmail-smtpd qmail-smtpd)
+
+
+
+CONTROL FILES:
+
+qregex provides you with two new control files.
+The first (which really isn't new) is "control/badmailfrom". This file used to be
+used to statically match addresses and now will contain your REs for matching from 
+the 'mail from' command.
+The second is "control/badmailto", it is the exact same as the first except it matches
+against the 'rcpt to' command.
+
+If you prefer you can symlink the two files (ln -s badmailfrom badmailto) and only
+need to maintain one set of rules. Beware this might cause problems in certian
+setups.
+        
+	Here's an example "badmailfrom" file.
+	-----------------------------------
+	# drop everything containing the word spam
+	.*spam.*
+	# force users to fully qualify themselves (ie deny "user", accept "user na domain")
+	!@
+	-----------------------------------
+
+	And "badmailto" (a litte more interesting)
+	-----------------------------------
+	# must not contain invalid characters, brakets or multiple @'s
+	[\W\D!%#:\*\^]
+	[\(\)]
+	[\{\}]
+	@.*@
+	-----------------------------------
+
+Also you can use the non-RE character '!' to start a RE to signal to qregex to negate the
+action. As used above in the badmailfrom file, by negating the @ symbol qregex will signal
+qmail-smtpd to deny the 'mail from' command whenever the address doesn't contain an @ symbol.
+
+
+INTERNALS:
+
+qregex (or regexmatch as the function is called) will be called during both the
+`rcpt to` and `mail from` handling routenes in "qmail-smtpd.c". When called it will
+read the proper control file then one by one compile and execute the regex on the
+envelope passed into qmail-smtpd. If the regex matches it returns TRUE (1) and the
+qmail-smtpd process will deny the user the ability to continue.
+If you change anything and think it betters this patch please send me a new diff file
+so I can take a peek.
+
+
+CONTACT:
+All comments/questions/critisim welcomed...
+        www  : http://www.unixpimps.org/software/qregex
+	email: evan at unixpimps dot org
------------- další část ---------------
diff -ruN qmail-1.03/qmail-smtpd.8 qmail-1.03-work/qmail-smtpd.8
--- qmail-1.03/qmail-smtpd.8	Mon Aug  2 15:41:59 2004
+++ qmail-1.03-work/qmail-smtpd.8	Mon Aug  2 18:28:09 2004
@@ -50,6 +50,12 @@
 meaning every address at
 .IR host .
 .TP 5
+.I badmailto
+Unacceptable envelope recipient addresses.
+.B qmail-smtpd
+will reject every recipient address listed in
+.IR badmailto .
+.TP 5
 .I databytes
 Maximum number of bytes allowed in a message,
 or 0 for no limit.
@@ -76,6 +82,10 @@
 .B DATABYTES
 is set, it overrides
 .IR databytes .
+.TP 5
+.I goodmailto
+Acceptable envelope recipient addresses. Overrides
+.IR badmailto .
 .TP 5
 .I localiphost
 Replacement host name for local IP addresses.
diff -ruN qmail-1.03/qmail-smtpd.c qmail-1.03-work/qmail-smtpd.c
--- qmail-1.03/qmail-smtpd.c	Mon Aug  2 15:51:48 2004
+++ qmail-1.03-work/qmail-smtpd.c	Mon Aug  2 18:24:23 2004
@@ -27,6 +27,7 @@
 
 #define BMCHECK_BMF 0
 #define BMCHECK_BMT 1
+#define BMCHECK_GMT 2
 
 #define MAXHOPS 100
 unsigned int databytes = 0;
@@ -104,9 +105,9 @@
 stralloc bmf = {0};
 struct constmap mapbmf;
 
-int bmtok = 0;
-stralloc bmt = {0};
-struct constmap mapbmt;
+int gmtok, bmtok = 0;
+stralloc gmt = {0}, bmt = {0};
+struct constmap mapgmt, mapbmt;
 
 void setup()
 {
@@ -127,6 +128,10 @@
   if (bmfok == -1) die_control();
   if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();
 
+  gmtok = control_readfile(&gmt,"control/goodmailto",0);
+  if (gmtok == -1) die_control();
+  if (!constmap_init(&mapgmt,gmt.s,gmt.len,0)) die_nomem();
+
   bmtok = control_readfile(&bmt,"control/badmailto",0);
   if (bmtok == -1) die_control();
   if (!constmap_init(&mapbmt,bmt.s,bmt.len,0)) die_nomem();
@@ -222,6 +227,8 @@
 
   if (which == BMCHECK_BMF) {
     if (!stralloc_copy(&bmb,&bmf)) die_nomem();
+  } else if (which == BMCHECK_GMT) {
+    if (!stralloc_copy(&bmb,&gmt)) die_nomem();
   } else if (which == BMCHECK_BMT) {
     if (!stralloc_copy(&bmb,&bmt)) die_nomem();
   } else {
@@ -257,6 +264,7 @@
 
 int seenmail = 0;
 int flagbarfbmf; /* defined if seenmail */
+int flagbarfgmt;
 int flagbarfbmt;
 stralloc mailfrom = {0};
 stralloc rcptto = {0};
@@ -291,8 +299,9 @@
   if (!seenmail) { err_wantmail(); return; }
   if (!addrparse(arg)) { err_syntax(); return; }
   if ((!flagbarfbmf) && (bmtok)) { flagbarfbmt = bmcheck(BMCHECK_BMT); }
-  if (flagbarfbmf) { err_bmf(); return; }
-  if (flagbarfbmt) { err_bmt(); return; }
+  if (gmtok) flagbarfgmt = bmcheck(BMCHECK_GMT);
+  if ((!flagbarfgmt) && (flagbarfbmf)) { err_bmf(); return; }
+  if ((!flagbarfgmt) && (flagbarfbmt)) { err_bmt(); return; }
   if (rcptlimit < 0) { err_manyrcpts(); return; }
   --rcptlimit;
   if (relayclient) {


Další informace o konferenci Linux