qmail.st-combo.15.patch (c) 2003-2012 Salvatore Toribio for this combo-patch (toribio - pusc.it) This cumulative patch for qmail comes with NO WARRANTY, you can redistribute and modify it freely, just put a link to this page. Original qmail-1.03 from Daniel J. Bernstein could be download from: qmail-1.03.tar.gz. At the end I have included all the patches already included in netqmail-1.05 TO APPLY THE PATCH Download it (qmail.st-combo.15.patch) or: wget http://cr.yp.to/software/qmail-1.03.tar.gz wget http://toribio.apollinare.org/qmail/qmail.st-combo.15.patch tar xzf qmail-1.03.tar.gz -C /var/tmp cp qmail.st-combo.15.patch /var/tmp/ cd /var/tmp patch -p0 < qmail.st-combo.15.patch PATCHES INCLUDED I have added the patches in this order: qmailqueue-patch from Bruce Guenter http://www.qmail.org/qmailqueue-patch qmail-1.03-mfcheck.4.patch from Balazs Nagy http://js.hu/package/qmail/qmail-1.03-mfcheck.4.patch The conection is closed after the 553 code is sent. Modified the qmail.c and qmail-smtpd.c to send the code "553 We have reasons to believe this mail is spam (#5.7.1)" when rejecting spam-mails with qmail-scanner st. accept-5xx.patch from Adrian Ho http://www.qmail.org/accept-5xx.patch qregex.patch-20040601 (with some modifications) http://www.arda.homeunix.net/store/qmail/ Badmailto blocks after the DATA command and close the conection. Badmailfrom skips empty return-paths an qmail bounces (#@[]). Added some logs to qmail-smtpd that help me to track some messages arriving to qmail-scanner without sender and recipients. qmail-1.03.errno.patch and qmail-1.03.qmail_local.patch from Mate Wierdl (and Erik Sjoelund) http://djbware.csi.hu/patches/ outgoingip.patch from Andy Repton and Sergio Gelato http://www.qmail.org/outgoingip.patch sendmail-flagf.patch from David Phillips http://david.acz.org/software/sendmail-flagf.patch qmail-0.0.0.0.patch from Scott Gifford http://www.suspectclass.com/~sgifford/qmail/qmail-0.0.0.0.patch qmail-isoc.patch from James Craig Burley http://www.jcb-sc.com/qmail/patches/ qmail-queue-custom-error.patch from Flavio Curti Allows qmail-queue to exit using custom error-messages, which can be displayed on SMTP connections. See file README.qq-custom-error after patching for details. https://no-way.org/qmail-error/ Oversize DNS packets patch from Christopher K. Davis I found that qmail-send sometimes is not able to send messages to some servers due to the dns response for that servers is bigger than 512 bytes, and then qmail-send exits with a temporary failiure, but it is not really temporary... http://www.ckdhr.com/ckd/qmail-103.patch Lately (20120911) some broken dns drop the connection when they receive a T_ANY question, that qmail uses to check for CNAME (and old feature that maybe nobody is using nowadays), so, even with the patch for 'oversize DNS packets', it is not possible to send emails to some domains, and in the qmail-send log you'll find 'CNAME lookup failed temporarily'. So I added a small patch that skips the error. http://toribio.apollinare.org/qmail/qmail-st-cname.patch There is also an ucspi.st-patch, that could be found at: http://toribio.apollinare.org/qmail/ Salvatore Toribio 20120911 diff -Naur qmail-1.03.orig/FILES qmail-1.03/FILES --- qmail-1.03.orig/FILES 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/FILES 2007-07-11 19:46:12.000000000 +0000 @@ -3,6 +3,10 @@ BLURB3 BLURB4 README +README.qq-custom-error +README.isoc.patch +README.qregex +README.st-patch FAQ INSTALL INSTALL.alias @@ -101,6 +105,8 @@ qmail-users.9 qmail.7 qreceipt.1 +qregex.c +qregex.h splogger.8 tcp-env.1 config.sh diff -Naur qmail-1.03.orig/Makefile qmail-1.03/Makefile --- qmail-1.03.orig/Makefile 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/Makefile 2007-07-11 19:46:12.000000000 +0000 @@ -263,7 +263,7 @@ cdbmake_add.o cdbmake_add.o: \ -compile cdbmake_add.c cdbmake.h uint32.h +compile cdbmake_add.c cdbmake.h alloc.h uint32.h ./compile cdbmake_add.c cdbmake_hash.o: \ @@ -1483,12 +1483,12 @@ trigger.o fmtqfn.o quote.o now.o readsubdir.o qmail.o date822fmt.o \ datetime.a case.a ndelay.a getln.a wait.a seek.a fd.a sig.a open.a \ lock.a stralloc.a alloc.a substdio.a error.a str.a fs.a auto_qmail.o \ -auto_split.o +auto_split.o env.a ./load qmail-send qsutil.o control.o constmap.o newfield.o \ prioq.o trigger.o fmtqfn.o quote.o now.o readsubdir.o \ qmail.o date822fmt.o datetime.a case.a ndelay.a getln.a \ wait.a seek.a fd.a sig.a open.a lock.a stralloc.a alloc.a \ - substdio.a error.a str.a fs.a auto_qmail.o auto_split.o + substdio.a error.a str.a fs.a auto_qmail.o auto_split.o env.a qmail-send.0: \ qmail-send.8 @@ -1532,17 +1532,17 @@ ./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 \ +fs.a auto_qmail.o socket.lib dns.o dns.lib + ./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 \ alloc.a substdio.a error.a str.a fs.a auto_qmail.o `cat \ - socket.lib` + socket.lib` dns.o `cat dns.lib` qmail-smtpd.0: \ qmail-smtpd.8 @@ -1681,6 +1681,10 @@ 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 \ auto_split.h @@ -1892,7 +1896,7 @@ spawn.o: \ compile chkspawn spawn.c sig.h wait.h substdio.h byte.h str.h \ -stralloc.h gen_alloc.h select.h exit.h coe.h open.h error.h \ +stralloc.h gen_alloc.h select.h exit.h alloc.h coe.h open.h error.h \ auto_qmail.h auto_uids.h auto_spawn.h ./chkspawn ./compile spawn.c diff -Naur qmail-1.03.orig/README.isoc.patch qmail-1.03/README.isoc.patch --- qmail-1.03.orig/README.isoc.patch 1970-01-01 00:00:00.000000000 +0000 +++ qmail-1.03/README.isoc.patch 2007-07-11 19:46:12.000000000 +0000 @@ -0,0 +1,45 @@ +This patch is Copyright (C) 2004 by James Craig Burley. License +below. + +2004-01-19 0040 EST James Craig Burley + +This patch improves ISO C conformance of qmail code -- specifically, +of qmail-lspawn, qmail-newmrh, qmail-newu, qmail-pop3d, qmail-popup, +qmail-rspawn, and qmail-smtpd. This fixes two known bugs: + + - qmail-smtpd can be crashed by a client sending a sufficiently + long (e.g. 2GB) header line in an email. + + - qmail_lspawn, qmail-newmrh, qmail-newu, and qmail-rspawn might + crash or otherwise misbehave on hosts with a smaller "int" type + than "char *" type, e.g. 64-bit hosts with 32-bit "int"s. + +The other changes are unlikely to have any effect, except possibly on +unusual architectures and/or in the presence of rare optimizations. + +This is Version 1 of this patch. It adds the changes to +cdbmake_add.c, spawn.c, and, correspondingly, Makefile, which pertain +to the second bug listed above. + +See all my qmail patches at . + +License: + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -Naur qmail-1.03.orig/README.qq-custom-error qmail-1.03/README.qq-custom-error --- qmail-1.03.orig/README.qq-custom-error 1970-01-01 00:00:00.000000000 +0000 +++ qmail-1.03/README.qq-custom-error 2007-07-11 19:46:12.000000000 +0000 @@ -0,0 +1,53 @@ + qmail-queue-custom-error.patch + +WARNING, NEW BEHAVIOUR: The patch is using descriptor 4 instead of +STDERR now! + +Adds the possibility for a qmail-queue-replacement to offer custom +error (=bounce) messages. + +You have to write the error message to filedescriptor 4 and exit 82, +in order to use the custom message. Format of the message: + +Dthis is a custom fatal error message +Zthis is a custom temporary failure message + +Thanks to Richard Lyons for spotting a +wrong errstr declaration. + +Thanks to Jeremy Hinton for noting that I forget to include the patch to +qmail.h + +This patch has been made by Flavio Curti and is +provided AS IS. Do with it as you wish, I'm not responsible for anything that +breaks because of this patch. + +https://no-way.org/software +https://no-way.org/uploads/6/28/qmail-queue-custom-error.patch + +--------------- + +EXAMPLES + +Perl: +open(FD,">&4"); +print FD "Ztemporary failure message"; +close(FD); +exit(82); + +Shell: +echo -n "Zpermanent failure after data" >&4 +exit 82; + +C (non-djb-style): +#include +#include +#include + +char err[] = "Zpermanently refusing"; + +int main() { + write(4,err,(strlen(err)+1)); + exit(82); +} + diff -Naur qmail-1.03.orig/README.qregex qmail-1.03/README.qregex --- qmail-1.03.orig/README.qregex 1970-01-01 00:00:00.000000000 +0000 +++ qmail-1.03/README.qregex 2007-07-11 19:46:12.000000000 +0000 @@ -0,0 +1,173 @@ +QREGEX (v2) 20040601 - README June 1, 2004 +A Regular Expression matching patch for qmail 1.03 and netqmail + + +OVERVIEW: + +qregex adds the ability to match address evelopes via Regular Expressions (REs) +in the qmail-smtpd process. It has the abiltiy to match `helo/ehlo` (host name), +`mail from` (envelope sender), and `rcpt to` (envelope recipient) commands. +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 is specified because qregex was +re-written to better conform to the security guarantee set forth by the author +of qmail. The original version used stdio.h and stdlib.h for reading the +control files whereas v2 now uses all stralloc functions which are much more +regulated against buffer overruns and the like. +See: http://cr.yp.to/qmail/guarantee.html + +NEW FEATURES: + +Features added to qregex since its creation are: + +1. Performs pattern matching on the helo/ehlo host name. Setting the + NOBADHELO environment variable prevents the host name from being + compared to the patterns in the badhelo control file. + +2. Matches to patterns in the badhelo, badmailfrom, and badmailto control + files are logged. + +3. Matching is case insensitive. + +4. qregex ignores empty envelope senders. An empty envelope sender is not + compared to the patterns in the badmailfrom control file and is always + accepted. + + + +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 have +a regex interface) but if you run into problems let me know. + + - OpenBSD 3.x + - FreeBSD 4.x + - Mandrake Linux 9.x + - SuSE Linux 8.x + + + +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 it is installed as 'gpatch') + +- If this is a new setup. +Unpack the qmail archive, cd into the qmail-1.03 directory and run +"patch < /path/to/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 you are using netqmail, then unpack the netqmail archive. Run the collate.sh +script and cd into the resulting netqmail- directory. From there, run +"patch < /path/to/qregex-.patch". Complete the netqmail installation +normally. 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). +cd into your existing qmail or netqmail source directory. Run +"patch < /path/to/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) + +You can also optionally just run "make setup check" as it will install the +updated documentation and man pages provided with this patch. Stopping qmail +before doing the "make setup check" is always a good idea. + + +LOGGING: + +qregex will log matches to the patterns in the badhelo, badmailfrom, and +badmailto control files. Log messages will take these three forms depending +on which control file was matched: + +qmail-smtpd: badhelo: at + +qmail-smtpd: badmailfrom: at + +qmail-smtpd: badmailto: at + + +CONTROL FILES: + +qregex provides you with three new control files. +The first (which really isn't new) is "control/badmailfrom". This file +originally matched addresses statically and now contains your REs for matching +from the 'mail from' command. +The other two are "control/badmailto" and "control/badhelo". They are exactly +the same as the first except that they match against the 'rcpt to' and +'helo/ehlo' commands respectively. + +If you prefer you can symlink the badmailfrom and badmailto control files +(ln -s badmailfrom badmailto) and only maintain two sets of rules. Beware +this might cause problems in certain setups. + + Here's an example "badhelo" file. + ----------------------------------- + # block host strings with no dot (not a FQDN) + !\. + ----------------------------------- + + An example "badmailfrom" file. + ----------------------------------- + # this will drop everything containing the string + # bad.domain.com or Bad.Domain.Com or BAD.domain.COM + bad\.domain\.com + # force users to fully qualify themselves + # (i.e. deny "user", accept "user@domain") + !@ + ----------------------------------- + + And "badmailto" (a litte more interesting) + ----------------------------------- + # must not contain invalid characters, brakets or multiple @'s + [!%#:*^(){}] + @.*@ + ----------------------------------- + +Also you can use the non-RE character '!' to start an RE as a 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. When used inside a bracket expression, +the '!' character looses this special meaning. This is shown in the badmailto +example. + + +INTERNALS: + +qregex (or regexmatch as the function is called) will be called during the +`helo/ehlo`, `rcpt to` and `mail from` handling routines in "qmail-smtpd.c". +When called, it will read the proper control file then one by one compile and +execute the regex on the string 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: +qregex is maintained by: + Andrew St. Jean + andrew@arda.homeunix.net + www.arda.homeunix.net/store/qmail/ + +Documentation (manpage updates) and qmail-showctl patch added by: + Jeremy Kitchen + kitchen at scriptkitchen dot com + http://www.scriptkitchen.com/qmail + +badhelo additions supplied by: + Alex Pleiner + alex@zeitform.de + zeitform Internet Dienste + http://www.zeitform.de/ + +Original qregex patch written by: + Evan Borgstrom + evan at unixpimps dot org diff -Naur qmail-1.03.orig/README.st-patch qmail-1.03/README.st-patch --- qmail-1.03.orig/README.st-patch 1970-01-01 00:00:00.000000000 +0000 +++ qmail-1.03/README.st-patch 2012-09-11 14:34:22.000000000 +0000 @@ -0,0 +1,167 @@ + README.qmail.st15-patch + +(c) 2003-2012 Salvatore Toribio for this combo-patch (toribio - pusc.it) + +This cumulative patch for qmail comes with NO WARRANTY, you can redistribute and modify it freely, just put a link to this page. + +Original qmail-1.03 from Daniel J. Bernstein could be download from: qmail-1.03.tar.gz. + +I started working in this patch in July 2003 for my own use, I tried to apply some patches that I wanted to use as antispam tools and I found that some of them were no compatible so I added them manually, then I started to add some logs by my own and fix some cosmetic things like qmail-showctl, some man pages and the documentation's install. And added other patches. + +At the end I have included all the patches already included in netqmail-1.05 + +TO APPLY THE PATCH + +Download it (qmail.st-combo.15.patch) or: + +wget http://cr.yp.to/software/qmail-1.03.tar.gz +wget http://toribio.apollinare.org/qmail/qmail.st-combo.15.patch + +tar xzf qmail-1.03.tar.gz -C /var/tmp +cp qmail.st-combo.15.patch /var/tmp/ + +cd /var/tmp + +patch -p0 < qmail.st-combo.15.patch + +You will get this output: + +patching file qmail-1.03/FILES +patching file qmail-1.03/Makefile +patching file qmail-1.03/README.isoc.patch +patching file qmail-1.03/README.qq-custom-error +patching file qmail-1.03/README.qregex +patching file qmail-1.03/README.st-patch +patching file qmail-1.03/TARGETS +patching file qmail-1.03/VERSION +patching file qmail-1.03/cdb_seek.c +patching file qmail-1.03/cdbmake_add.c +patching file qmail-1.03/dns.c +patching file qmail-1.03/error.3 +patching file qmail-1.03/error.h +patching file qmail-1.03/hier.c +patching file qmail-1.03/install-big.c +patching file qmail-1.03/ipme.c +patching file qmail-1.03/qmail-control.9 +patching file qmail-1.03/qmail-local.c +patching file qmail-1.03/qmail-pop3d.c +patching file qmail-1.03/qmail-popup.c +patching file qmail-1.03/qmail-remote.8 +patching file qmail-1.03/qmail-remote.c +patching file qmail-1.03/qmail-showctl.c +patching file qmail-1.03/qmail-smtpd.8 +patching file qmail-1.03/qmail-smtpd.c +patching file qmail-1.03/qmail.c +patching file qmail-1.03/qmail.h +patching file qmail-1.03/qregex.c +patching file qmail-1.03/qregex.h +patching file qmail-1.03/remoteinfo.c +patching file qmail-1.03/sendmail.c +patching file qmail-1.03/spawn.c +patching file qmail-1.03/timeoutconn.c + +PATCHES INCLUDED + +I have added the patches in this order: + +qmailqueue-patch from Bruce Guenter +http://www.qmail.org/qmailqueue-patch + +qmail-1.03-mfcheck.4.patch from Balazs Nagy +http://js.hu/package/qmail/qmail-1.03-mfcheck.4.patch +The conection is closed after the 553 code is sent. + +Modified the qmail.c and qmail-smtpd.c to send the code +"553 We have reassons to believe this mail is spam (#5.7.1)" +when rejecting spam-mails with qmail-scanner st. + +accept-5xx.patch from Adrian Ho +http://www.qmail.org/accept-5xx.patch + +qregex.patch-20040601 (with some modifications) +http://www.arda.homeunix.net/store/qmail/ +Badmailto blocks after the DATA command and close the conection. +Badmailfrom skips empty return-paths an qmail bounces (#@[]). + +Added some logs to qmail-smtpd that help me to track some messages arriving to qmail-scanner without sender and recipients. + +qmail-1.03.errno.patch and qmail-1.03.qmail_local.patch from Mate Wierdl (and Erik Sjoelund) +http://djbware.csi.hu/patches/ + +outgoingip.patch from Andy Repton and Sergio Gelato +http://www.qmail.org/outgoingip.patch + +sendmail-flagf.patch from David Phillips +http://david.acz.org/software/sendmail-flagf.patch + +qmail-0.0.0.0.patch from Scott Gifford +http://www.suspectclass.com/~sgifford/qmail/qmail-0.0.0.0.patch + +qmail-isoc.patch from James Craig Burley +http://www.jcb-sc.com/qmail/patches/ + +qmail-queue-custom-error.patch from Flavio Curti +Allows qmail-queue to exit using custom error-messages, which can be displayed on SMTP connections. +See file README.qq-custom-error after patching for details. +https://no-way.org/software + +Oversize DNS packets patch from Christopher K. Davis +I found that qmail-send sometimes is not able to send messages to some servers due to the dns response for that servers is bigger than 512 bytes, and then qmail-send exits with a temporary failiure, but it is not really temporary... +http://www.ckdhr.com/ckd/qmail-103.patch + +Lately (20120911) some broken dns drop the connection when they receive a T_ANY question, that qmail uses to check for CNAME (and old feature that maybe nobody is using nowadays), so, even with the patch for 'oversize DNS packets', it is not possible to send emails to some domains, and in the qmail-send log you'll find 'CNAME lookup failed temporarily'. So I added a small patch that skips the error. +http://toribio.apollinare.org/qmail/qmail-st-cname.patch + +NEW QMAIL CONTROL FILES + +outgoingip In a multihomed box, the ip qmail-send will use. + +mfcheck Set it to '1' to check if the domain in the envelope sender + address exists. Set it to '0' or remove it to disable + the check. + It could also be enabled/disabled setting the enviroment + variabile MFCHECK in the tcp.rules file. + +badmailfrom +badmailto +badhelo This three files contains regex that will be matched against + envelope addresses and the helo to reject mails. + They could be skipped for certains IPs setting the 'empty' + enviroment variables BADMAILFROM, BADMAILTO and NOBADHELO in + the tcp.rules file. + See README.qregex or qmail-smtpd man page for more information. + +LOG LINES ADDED TO qmail-smtpd + +Accepted messsages will log: + +mailfrom_ user@domain _to_ localuser@localdomain +(if there are multiples recipients only logs the first one...) + +Rejected messages could log: + +Bare LFs in SMTP, rejecting (451) +envelope sender domain_ user@domain _doesn't exist rejecting (553) +mfcheck - DNS temporary failure (451) +badhelo_ helo spamhost _at 1.1.1.1, rejecting (553) +envelope sender_ user@domain _in my badmailfrom list, rejecting (553) +envelope rcptto_ user@domain _in my badmailto list, rejecting (553) +envelope rcptto_ user@domain _isn't in my rcpthost, rejecting (553) +too many hops, this message is looping (554) +message size exceeds my databytes limit (552) +qq error - 'qmail-queue error code...' + +ENVIRONMENT VARIABLE + +If the environment variable QSLOG is set to '1', the log format will change to be more likely qmail-scanner log format: + +pid smtpd: the_above_log_messages + +The QSLOG environment variable could also be set using the '-L' option in the tcpserver of ucspi.st-patch, see below for the link. + +There is also an ucspi.st-patch, that could be found at: +http://toribio.apollinare.org/qmail/ + +Salvatore Toribio + +20120911 diff -Naur qmail-1.03.orig/TARGETS qmail-1.03/TARGETS --- qmail-1.03.orig/TARGETS 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/TARGETS 2007-07-11 19:46:12.000000000 +0000 @@ -252,6 +252,7 @@ qmail-qmtpd qmail-smtpd.o qmail-smtpd +qregex.o sendmail.o sendmail tcp-env.o diff -Naur qmail-1.03.orig/VERSION qmail-1.03/VERSION --- qmail-1.03.orig/VERSION 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/VERSION 2012-09-10 15:06:36.000000000 +0000 @@ -1 +1 @@ -qmail 1.03 +qmail-1.03st15 diff -Naur qmail-1.03.orig/cdb_seek.c qmail-1.03/cdb_seek.c --- qmail-1.03.orig/cdb_seek.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/cdb_seek.c 2007-07-11 19:46:12.000000000 +0000 @@ -1,6 +1,5 @@ #include #include -extern int errno; #include "cdb.h" #ifndef SEEK_SET diff -Naur qmail-1.03.orig/cdbmake_add.c qmail-1.03/cdbmake_add.c --- qmail-1.03.orig/cdbmake_add.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/cdbmake_add.c 2007-07-11 19:46:12.000000000 +0000 @@ -1,3 +1,4 @@ +#include "alloc.h" #include "cdbmake.h" void cdbmake_init(cdbm) diff -Naur qmail-1.03.orig/dns.c qmail-1.03/dns.c --- qmail-1.03.orig/dns.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/dns.c 2007-07-11 19:46:12.000000000 +0000 @@ -7,8 +7,6 @@ #include extern int res_query(); extern int res_search(); -extern int errno; -extern int h_errno; #include "ip.h" #include "ipalloc.h" #include "fmt.h" @@ -21,10 +19,12 @@ static unsigned short getshort(c) unsigned char *c; { unsigned short u; u = c[0]; return (u << 8) + c[1]; } -static union { HEADER hdr; unsigned char buf[PACKETSZ]; } response; +static struct { unsigned char *buf; } response; +static int responsebuflen = 0; static int responselen; static unsigned char *responseend; static unsigned char *responsepos; +static u_long saveresoptions; static int numanswers; static char name[MAXDNAME]; @@ -45,18 +45,33 @@ errno = 0; if (!stralloc_copy(&glue,domain)) return DNS_MEM; if (!stralloc_0(&glue)) return DNS_MEM; - responselen = lookup(glue.s,C_IN,type,response.buf,sizeof(response)); + if (!responsebuflen) + if (response.buf = (unsigned char *)alloc(PACKETSZ+1)) + responsebuflen = PACKETSZ+1; + else return DNS_MEM; + + responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); + if ((responselen >= responsebuflen) || + (responselen > 0 && (((HEADER *)response.buf)->tc))) + { + if (responsebuflen < 65536) + if (alloc_re(&response.buf, responsebuflen, 65536)) + responsebuflen = 65536; + else return DNS_MEM; + saveresoptions = _res.options; + _res.options |= RES_USEVC; + responselen = lookup(glue.s,C_IN,type,response.buf,responsebuflen); + _res.options = saveresoptions; + } if (responselen <= 0) { if (errno == ECONNREFUSED) return DNS_SOFT; if (h_errno == TRY_AGAIN) return DNS_SOFT; return DNS_HARD; } - if (responselen >= sizeof(response)) - responselen = sizeof(response); responseend = response.buf + responselen; responsepos = response.buf + sizeof(HEADER); - n = ntohs(response.hdr.qdcount); + n = ntohs(((HEADER *)response.buf)->qdcount); while (n-- > 0) { i = dn_expand(response.buf,responseend,responsepos,name,MAXDNAME); @@ -66,7 +81,7 @@ if (i < QFIXEDSZ) return DNS_SOFT; responsepos += QFIXEDSZ; } - numanswers = ntohs(response.hdr.ancount); + numanswers = ntohs(((HEADER *)response.buf)->ancount); return 0; } diff -Naur qmail-1.03.orig/error.3 qmail-1.03/error.3 --- qmail-1.03.orig/error.3 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/error.3 2007-07-11 19:46:12.000000000 +0000 @@ -4,8 +4,6 @@ .SH SYNTAX .B #include -extern int \fBerrno\fP; - extern int \fBerror_intr\fP; .br extern int \fBerror_nomem\fP; diff -Naur qmail-1.03.orig/error.h qmail-1.03/error.h --- qmail-1.03.orig/error.h 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/error.h 2007-07-11 19:46:12.000000000 +0000 @@ -1,7 +1,7 @@ #ifndef ERROR_H #define ERROR_H -extern int errno; +#include extern int error_intr; extern int error_nomem; diff -Naur qmail-1.03.orig/hier.c qmail-1.03/hier.c --- qmail-1.03.orig/hier.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/hier.c 2007-07-11 19:46:12.000000000 +0000 @@ -76,6 +76,10 @@ c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755); c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","README.isoc.patch",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","README.st-patch",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","VERSION",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644); diff -Naur qmail-1.03.orig/install-big.c qmail-1.03/install-big.c --- qmail-1.03.orig/install-big.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/install-big.c 2007-07-11 19:46:12.000000000 +0000 @@ -76,6 +76,11 @@ c(auto_qmail,"boot","binm3+df",auto_uido,auto_gidq,0755); c(auto_qmail,"doc","FAQ",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","README.qregex",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","README.isoc.patch",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","README.qq-custom-error",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","README.st-patch",auto_uido,auto_gidq,0644); + c(auto_qmail,"doc","VERSION",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","UPGRADE",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","SENDMAIL",auto_uido,auto_gidq,0644); c(auto_qmail,"doc","INSTALL",auto_uido,auto_gidq,0644); diff -Naur qmail-1.03.orig/ipme.c qmail-1.03/ipme.c --- qmail-1.03.orig/ipme.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/ipme.c 2007-07-11 19:46:12.000000000 +0000 @@ -46,6 +46,11 @@ ipme.len = 0; ix.pref = 0; + /* 0.0.0.0 is a special address which always refers to + * "this host, this network", according to RFC 1122, Sec. 3.2.1.3a. + */ + byte_copy(&ix.ip,4,"\0\0\0\0"); + if (!ipalloc_append(&ipme,&ix)) { return 0; } if ((s = socket(AF_INET,SOCK_STREAM,0)) == -1) return -1; len = 256; diff -Naur qmail-1.03.orig/qmail-control.9 qmail-1.03/qmail-control.9 --- qmail-1.03.orig/qmail-control.9 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail-control.9 2007-07-11 19:46:12.000000000 +0000 @@ -20,7 +20,9 @@ Comments are allowed in +.IR badhelo , .IR badmailfrom , +.IR badmailto , .IR locals , .IR percenthack , .IR qmqpservers , @@ -40,7 +42,9 @@ .ta 5c 10c control default used by +.I badhelo \fR(none) \fRqmail-smtpd .I badmailfrom \fR(none) \fRqmail-smtpd +.I badmailto \fR(none) \fRqmail-smtpd .I bouncefrom \fRMAILER-DAEMON \fRqmail-send .I bouncehost \fIme \fRqmail-send .I concurrencylocal \fR10 \fRqmail-send @@ -55,7 +59,9 @@ .I idhost \fIme \fRqmail-inject .I localiphost \fIme \fRqmail-smtpd .I locals \fIme \fRqmail-send +.I mfcheck \fR0 \fRqmail-smtpd .I morercpthosts \fR(none) \fRqmail-smtpd +.I outgoingip \fR0.0.0.0 \fRqmail-remote .I percenthack \fR(none) \fRqmail-send .I plusdomain \fIme \fRqmail-inject .I qmqpservers \fR(none) \fRqmail-qmqpc diff -Naur qmail-1.03.orig/qmail-local.c qmail-1.03/qmail-local.c --- qmail-1.03.orig/qmail-local.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail-local.c 2007-07-11 19:46:12.000000000 +0000 @@ -645,7 +645,7 @@ { cmds.s[j] = 0; k = j; - while ((k > i) && (cmds.s[k - 1] == ' ') || (cmds.s[k - 1] == '\t')) + while ((k > i) && ((cmds.s[k - 1] == ' ') || (cmds.s[k - 1] == '\t'))) cmds.s[--k] = 0; switch(cmds.s[i]) { diff -Naur qmail-1.03.orig/qmail-pop3d.c qmail-1.03/qmail-pop3d.c --- qmail-1.03.orig/qmail-pop3d.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail-pop3d.c 2007-07-11 19:46:12.000000000 +0000 @@ -66,14 +66,14 @@ void die_scan() { err("unable to scan $HOME/Maildir"); die(); } void err_syntax() { err("syntax error"); } -void err_unimpl() { err("unimplemented"); } +void err_unimpl(arg) char *arg; { err("unimplemented"); } void err_deleted() { err("already deleted"); } void err_nozero() { err("messages are counted from 1"); } void err_toobig() { err("not that many messages"); } void err_nosuch() { err("unable to open that message"); } void err_nounlink() { err("unable to unlink all deleted messages"); } -void okay() { puts("+OK \r\n"); flush(); } +void okay(arg) char *arg; { puts("+OK \r\n"); flush(); } void printfn(fn) char *fn; { @@ -146,7 +146,7 @@ } } -void pop3_stat() +void pop3_stat(arg) char *arg; { int i; unsigned long total; @@ -161,15 +161,15 @@ flush(); } -void pop3_rset() +void pop3_rset(arg) char *arg; { int i; for (i = 0;i < numm;++i) m[i].flagdeleted = 0; last = 0; - okay(); + okay(0); } -void pop3_last() +void pop3_last(arg) char *arg; { puts("+OK "); put(strnum,fmt_uint(strnum,last)); @@ -177,7 +177,7 @@ flush(); } -void pop3_quit() +void pop3_quit(arg) char *arg; { int i; for (i = 0;i < numm;++i) @@ -192,7 +192,7 @@ if (!stralloc_0(&line)) die_nomem(); rename(m[i].fn,line.s); /* if it fails, bummer */ } - okay(); + okay(0); die(); } @@ -214,7 +214,7 @@ if (i == -1) return; m[i].flagdeleted = 1; if (i + 1 > last) last = i + 1; - okay(); + okay(0); } void list(i,flaguidl) @@ -238,7 +238,7 @@ list(i,flaguidl); } else { - okay(); + okay(0); for (i = 0;i < numm;++i) if (!m[i].flagdeleted) list(i,flaguidl); @@ -267,7 +267,7 @@ fd = open_read(m[i].fn); if (fd == -1) { err_nosuch(); return; } - okay(); + okay(0); substdio_fdbuf(&ssmsg,read,fd,ssmsgbuf,sizeof(ssmsgbuf)); blast(&ssmsg,limit); close(fd); @@ -299,7 +299,7 @@ getlist(); - okay(); + okay(0); commands(&ssin,pop3commands); die(); } diff -Naur qmail-1.03.orig/qmail-popup.c qmail-1.03/qmail-popup.c --- qmail-1.03.orig/qmail-popup.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail-popup.c 2007-07-11 19:46:12.000000000 +0000 @@ -64,10 +64,10 @@ void err_syntax() { err("syntax error"); } void err_wantuser() { err("USER first"); } -void err_authoriz() { err("authorization first"); } +void err_authoriz(arg) char *arg; { err("authorization first"); } -void okay() { puts("+OK \r\n"); flush(); } -void pop3_quit() { okay(); die(); } +void okay(arg) char *arg; { puts("+OK \r\n"); flush(); } +void pop3_quit(arg) char *arg; { okay(0); die(); } char unique[FMT_ULONG + FMT_ULONG + 3]; @@ -136,7 +136,7 @@ void pop3_user(arg) char *arg; { if (!*arg) { err_syntax(); return; } - okay(); + okay(0); seenuser = 1; if (!stralloc_copys(&username,arg)) die_nomem(); if (!stralloc_0(&username)) die_nomem(); diff -Naur qmail-1.03.orig/qmail-remote.8 qmail-1.03/qmail-remote.8 --- qmail-1.03.orig/qmail-remote.8 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail-remote.8 2007-07-11 19:46:12.000000000 +0000 @@ -124,6 +124,13 @@ .B qmail-remote refuses to run. .TP 5 +.I outgoingip +IP address to be used on outgoing connections. +Default: system-defined. +The value +.IR 0.0.0.0 +is equivalent to the system default. +.TP 5 .I smtproutes Artificial SMTP routes. Each route has the form diff -Naur qmail-1.03.orig/qmail-remote.c qmail-1.03/qmail-remote.c --- qmail-1.03.orig/qmail-remote.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail-remote.c 2012-09-11 14:54:58.000000000 +0000 @@ -39,6 +39,7 @@ static stralloc sauninit = {0}; stralloc helohost = {0}; +stralloc outgoingip = {0}; stralloc routes = {0}; struct constmap maproutes; stralloc host = {0}; @@ -47,6 +48,7 @@ saa reciplist = {0}; struct ip_address partner; +struct ip_address outip; void out(s) char *s; { if (substdio_puts(subfdoutsmall,s) == -1) _exit(0); } void zero() { if (substdio_put(subfdoutsmall,"\0",1) == -1) _exit(0); } @@ -56,14 +58,13 @@ ch = sa->s[i]; if (ch < 33) ch = '?'; if (ch > 126) ch = '?'; if (substdio_put(subfdoutsmall,&ch,1) == -1) _exit(0); } } +void temp_noip() { out("Zinvalid ipaddr in control/outgoingip (#4.3.0)\n"); zerodie(); } void temp_nomem() { out("ZOut of memory. (#4.3.0)\n"); zerodie(); } void temp_oserr() { out("Z\ System resources temporarily unavailable. (#4.3.0)\n"); zerodie(); } void temp_noconn() { out("Z\ Sorry, I wasn't able to establish an SMTP connection. (#4.4.1)\n"); zerodie(); } void temp_read() { out("ZUnable to read message. (#4.3.0)\n"); zerodie(); } -void temp_dnscanon() { out("Z\ -CNAME lookup failed temporarily. (#4.4.3)\n"); zerodie(); } void temp_dns() { out("Z\ Sorry, I couldn't find any host by that name. (#4.1.2)\n"); zerodie(); } void temp_chdir() { out("Z\ @@ -222,13 +223,18 @@ int flagbother; int i; - if (smtpcode() != 220) quit("ZConnected to "," but greeting failed"); + code = smtpcode(); + if (code >= 500) quit("DConnected to "," but greeting failed"); + if (code >= 400) return; + if (code != 220) quit("ZConnected to "," but greeting failed"); substdio_puts(&smtpto,"HELO "); substdio_put(&smtpto,helohost.s,helohost.len); substdio_puts(&smtpto,"\r\n"); substdio_flush(&smtpto); - if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected"); + code = smtpcode(); + if (code >= 500) quit("DConnected to "," but my name was rejected"); + if (code != 250) quit("ZConnected to "," but my name was rejected"); substdio_puts(&smtpto,"MAIL FROM:<"); substdio_put(&smtpto,sender.s,sender.len); @@ -301,7 +307,7 @@ switch(dns_cname(&canonhost)) { case 0: *flagalias = 0; break; case DNS_MEM: temp_nomem(); - case DNS_SOFT: temp_dnscanon(); + case DNS_SOFT: ; /* st: if the dns answer is wrong for T_ANY go ahead */ case DNS_HARD: ; /* alias loop, not our problem */ } @@ -310,6 +316,7 @@ void getcontrols() { + int r; if (control_init() == -1) temp_control(); if (control_readint(&timeout,"control/timeoutremote") == -1) temp_control(); if (control_readint(&timeoutconnect,"control/timeoutconnect") == -1) @@ -324,6 +331,12 @@ case 1: if (!constmap_init(&maproutes,routes.s,routes.len,1)) temp_nomem(); break; } + r = control_readline(&outgoingip,"control/outgoingip"); + if (-1 == r) { if (errno == error_nomem) temp_nomem(); temp_control(); } + if (0 == r && !stralloc_copys(&outgoingip, "0.0.0.0")) temp_nomem(); + if (str_equal(outgoingip.s, "0.0.0.0")) + { outip.d[0]=outip.d[1]=outip.d[2]=outip.d[3]=(unsigned long) 0; } + else if (!ip_scan(outgoingip.s, &outip)) temp_noip(); } void main(argc,argv) @@ -414,7 +427,7 @@ smtpfd = socket(AF_INET,SOCK_STREAM,0); if (smtpfd == -1) temp_oserr(); - if (timeoutconn(smtpfd,&ip.ix[i].ip,(unsigned int) port,timeoutconnect) == 0) { + if (timeoutconn(smtpfd,&ip.ix[i].ip,&outip,(unsigned int) port,timeoutconnect) == 0) { tcpto_err(&ip.ix[i].ip,0); partner = ip.ix[i].ip; smtp(); /* does not return */ diff -Naur qmail-1.03.orig/qmail-showctl.c qmail-1.03/qmail-showctl.c --- qmail-1.03.orig/qmail-showctl.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail-showctl.c 2007-07-11 19:46:12.000000000 +0000 @@ -214,7 +214,9 @@ _exit(111); } - do_lst("badmailfrom","Any MAIL FROM is allowed.",""," not accepted in MAIL FROM."); + do_lst("badhelo","Any HELO host name is allowed.",""," HELO host name denied if it matches this pattern."); + do_lst("badmailfrom","Any MAIL FROM is allowed.",""," MAIL FROM denied if it matches this pattern."); + do_lst("badmailto","No RCPT TO are specifically denied.",""," RCPT TO denied if it matches this pattern."); do_str("bouncefrom",0,"MAILER-DAEMON","Bounce user name is "); do_str("bouncehost",1,"bouncehost","Bounce host name is "); do_int("concurrencylocal","10","Local concurrency is ",""); @@ -229,7 +231,9 @@ do_str("idhost",1,"idhost","Message-ID host name is "); do_str("localiphost",1,"localiphost","Local IP address becomes "); do_lst("locals","Messages for me are delivered locally.","Messages for "," are delivered locally."); + do_str("mfcheck",0,"Mail From dns check disabled","Mail From dns check (1 enabled/0 disabled) "); do_str("me",0,"undefined! Uh-oh","My name is "); + do_str("outgoingip",0,"0.0.0.0","Outgoing IP address is "); do_lst("percenthack","The percent hack is not allowed.","The percent hack is allowed for user%host@","."); do_str("plusdomain",1,"plusdomain","Plus domain name is "); do_lst("qmqpservers","No QMQP servers.","QMQP server: ","."); @@ -267,7 +271,9 @@ if (str_equal(d->d_name,"..")) continue; if (str_equal(d->d_name,"bouncefrom")) continue; if (str_equal(d->d_name,"bouncehost")) continue; + if (str_equal(d->d_name,"badhelo")) continue; if (str_equal(d->d_name,"badmailfrom")) continue; + if (str_equal(d->d_name,"badmailto")) continue; if (str_equal(d->d_name,"bouncefrom")) continue; if (str_equal(d->d_name,"bouncehost")) continue; if (str_equal(d->d_name,"concurrencylocal")) continue; @@ -282,6 +288,7 @@ if (str_equal(d->d_name,"idhost")) continue; if (str_equal(d->d_name,"localiphost")) continue; if (str_equal(d->d_name,"locals")) continue; + if (str_equal(d->d_name,"mfcheck")) continue; if (str_equal(d->d_name,"me")) continue; if (str_equal(d->d_name,"morercpthosts")) continue; if (str_equal(d->d_name,"morercpthosts.cdb")) continue; diff -Naur qmail-1.03.orig/qmail-smtpd.8 qmail-1.03/qmail-smtpd.8 --- qmail-1.03.orig/qmail-smtpd.8 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail-smtpd.8 2007-07-11 19:46:12.000000000 +0000 @@ -37,11 +37,25 @@ even though such messages violate the SMTP protocol. .SH "CONTROL FILES" .TP 5 +.I badhelo +Unacceptable HELO/EHLO host names. +.B qmail-smtpd +will reject every recipient address for a message if +the host name is listed in, +or matches a POSIX regular expression pattern listed in, +.IR badhelo . +If the NOBADHELO environment variable is set, then the +contents of +.IR badhelo +will be ignored. +For more information, please have a look at doc/README.qregex. +.TP 5 .I badmailfrom Unacceptable envelope sender addresses. .B qmail-smtpd will reject every recipient address for a message -if the envelope sender address is listed in +if the envelope sender address is listed in, or matches a POSIX regular expression +pattern listed in, .IR badmailfrom . A line in .I badmailfrom @@ -49,6 +63,36 @@ .BR @\fIhost , meaning every address at .IR host . +A line in +.I badmailfrom +may be a regex: + +.EX + .*spam.* drop everything containing the word spam. +.EE + +For more information, please have a look at doc/README.qregex. +.TP 5 +.I badmailto +Do not accept mails for this addresses. May be a regex: + +i.e.: Must not contain invalid characters, brakets or multiple @'s + +.EX + [!%#:*^(){}] + @.*@ +.EE + +i.e.: Must be fully qualified (interesting for a mailhub) by negating +a symbol this will be mandatory + +.EX + !@ +.EE + +If one address of a mail with multiple recipients is rejected, the +whole message will be rejected. +For more information, please have a look at doc/README.qregex. .TP 5 .I databytes Maximum number of bytes allowed in a message, @@ -97,6 +141,14 @@ This is done before .IR rcpthosts . .TP 5 +.I mfcheck +If set, +.B qmail-smtpd +tries to resolve the domain of the envelope from address. It can be +handy when you want to filter out spamhosts (1/0). It is possible to +enalble/disable this feature defining the variable MFCHECK for certains +IPs in the tcp.smtp rules. +.TP 5 .I morercpthosts Extra allowed RCPT domains. If diff -Naur qmail-1.03.orig/qmail-smtpd.c qmail-1.03/qmail-smtpd.c --- qmail-1.03.orig/qmail-smtpd.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail-smtpd.c 2012-09-10 15:06:19.000000000 +0000 @@ -23,9 +23,17 @@ #include "timeoutread.h" #include "timeoutwrite.h" #include "commands.h" +#include "dns.h" +#include "qregex.h" + +#define BMCHECK_BMF 0 +#define BMCHECK_BMT 1 +#define BMCHECK_BHELO 2 #define MAXHOPS 100 unsigned int databytes = 0; +unsigned int mfchk = 0; +unsigned int qslog = 0; int timeout = 1200; int safewrite(fd,buf,len) int fd; char *buf; int len; @@ -42,21 +50,65 @@ void flush() { substdio_flush(&ssout); } void out(s) char *s; { substdio_puts(&ssout,s); } +/* st: log some information */ +char strnum[FMT_ULONG]; + +static char llogbuf[1]; +static struct substdio llog = SUBSTDIO_FDBUF(write,2,llogbuf,1); + +/* st: miglioriamo i log */ +void logpid() { + if (qslog) { + substdio_putsflush(&llog,strnum); + substdio_putsflush(&llog," smtpd: "); + } else { + substdio_putsflush(&llog,"smtpd: pid "); + substdio_putsflush(&llog,strnum); + substdio_putsflush(&llog,": "); + } +} + +void log1(s1) char *s1; { + logpid(); + substdio_putsflush(&llog,s1); } + +void log3(s1,s2,s3) char *s1; char *s2; char *s3; { + logpid(); + substdio_putsflush(&llog,s1); + substdio_putsflush(&llog,s2); + substdio_putsflush(&llog,s3); } + +void log5(s1,s2,s3,s4,s5) char *s1; char *s2; char *s3; char *s4; char *s5; { + logpid(); + substdio_putsflush(&llog,s1); + substdio_putsflush(&llog,s2); + substdio_putsflush(&llog,s3); + substdio_putsflush(&llog,s4); + substdio_putsflush(&llog,s5); } + void die_read() { _exit(1); } void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); } void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); } void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); } 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 straynewline() { + log1("Bare LFs in SMTP, rejecting (451)\n"); + out("451 See http://cr.yp.to/docs/smtplf.html (#4.5.4)\r\n"); flush(); _exit(1); } + +void err_bmf() { out("553 sorry, your envelope sender has been denied (#5.7.1)\r\n"); } +void err_bmt() { out("553 sorry, your envelope recipient has been denied (#5.7.1)\r\n"); } +void err_bhelo() { out("553 sorry, your HELO host name has been denied (#5.7.1)\r\n"); } +void err_hmf() { out("553 sorry, your envelope sender domain must exist (#5.7.1)\r\n"); } +void err_smf() { + log1("mfcheck - DNS temporary failure (451)\n"); + out("451 DNS temporary failure (#4.3.0)\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_unimpl(arg) char *arg; { out("502 unimplemented (#5.5.1)\r\n"); } void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); } void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); } void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); } -void err_noop() { out("250 ok\r\n"); } -void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); } +void err_noop(arg) char *arg; { out("250 ok\r\n"); } +void err_vrfy(arg) char *arg; { out("252 send some mail, i'll try my best\r\n"); } void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); } @@ -67,11 +119,11 @@ substdio_puts(&ssout,code); substdio_put(&ssout,greeting.s,greeting.len); } -void smtp_help() +void smtp_help(arg) char *arg; { out("214 qmail home page: http://pobox.com/~djb/qmail.html\r\n"); } -void smtp_quit() +void smtp_quit(arg) char *arg; { smtp_greet("221 "); out("\r\n"); flush(); _exit(0); } @@ -93,9 +145,15 @@ int liphostok = 0; stralloc liphost = {0}; + int bmfok = 0; stralloc bmf = {0}; -struct constmap mapbmf; + +int bmtok = 0; +stralloc bmt = {0}; + +int bhelook = 0; +stralloc bhelo = {0}; void setup() { @@ -110,13 +168,29 @@ if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control(); if (timeout <= 0) timeout = 1; + x = env_get("QSLOG"); + if (x) { scan_ulong(x,&u); qslog = u; } + if (rcpthosts_init() == -1) die_control(); + if (control_readint(&mfchk,"control/mfcheck") == -1) die_control(); + x = env_get("MFCHECK"); + if (x) { scan_ulong(x,&u); mfchk = u; } + 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(); + /* st: disable bmf for certains IPs */ + if (env_get("NOBADMAILFROM")) bmfok = 0; + + bmtok = control_readfile(&bmt,"control/badmailto",0); + if (bmtok == -1) die_control(); + /* st: disable bmf for certains IPs */ + if (env_get("NOBADMAILTO")) bmtok = 0; + bhelook = control_readfile(&bhelo, "control/badhelo",0); + if (bhelook == -1) die_control(); + if (env_get("NOBADHELO")) bhelook = 0; + if (control_readint(&databytes,"control/databytes") == -1) die_control(); x = env_get("DATABYTES"); if (x) { scan_ulong(x,&u); databytes = u; } @@ -197,14 +271,67 @@ return 1; } -int bmfcheck() +int bmcheck(which) int which; +{ + int i = 0; + int j = 0; + int x = 0; + int negate = 0; + static stralloc bmb = {0}; + static 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 if (which == BMCHECK_BHELO) { + if (!stralloc_copy(&bmb,&bhelo)) 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++; + } + if (!stralloc_copyb(&curregex,bmb.s + j,(i - j))) die_nomem(); + if (!stralloc_0(&curregex)) die_nomem(); + if (which == BMCHECK_BHELO) { + x = matchregex(helohost.s, curregex.s); + } else { + 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; +} + +int mfcheck() { + stralloc sa = {0}; + ipalloc ia = {0}; + unsigned int random; 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; + + if (!mfchk) return 0; + /* st: do not reject mails from '#@[]' */ + if (str_equal(addr.s,"#@[]")) return 0; + random = now() + (getpid() << 16); + j = byte_rchr(addr.s,addr.len,'@') + 1; + if (j < addr.len) { + stralloc_copys(&sa, addr.s + j); + dns_init(0); + j = dns_mxip(&ia,&sa,random); + if (j < 0) { + return j; + } + } return 0; } @@ -218,7 +345,9 @@ int seenmail = 0; -int flagbarf; /* defined if seenmail */ +int flagbarfbmf; /* defined if seenmail */ +int flagbarfbmt; +int flagbarfbhelo; stralloc mailfrom = {0}; stralloc rcptto = {0}; @@ -226,13 +355,15 @@ { smtp_greet("250 "); out("\r\n"); seenmail = 0; dohelo(arg); + if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO); } void smtp_ehlo(arg) char *arg; { smtp_greet("250-"); out("\r\n250-PIPELINING\r\n250 8BITMIME\r\n"); seenmail = 0; dohelo(arg); + if (bhelook) flagbarfbhelo = bmcheck(BMCHECK_BHELO); } -void smtp_rset() +void smtp_rset(arg) char *arg; { seenmail = 0; out("250 flushed\r\n"); @@ -240,7 +371,22 @@ void smtp_mail(arg) char *arg; { if (!addrparse(arg)) { err_syntax(); return; } - flagbarf = bmfcheck(); + /* st: do not reject mails from '#@[]' */ + if (bmfok && addr.len > 1 && str_diff(addr.s,"#@[]")) { + flagbarfbmf = bmcheck(BMCHECK_BMF); + if (flagbarfbmf) { + log3("envelope sender_ ",addr.s," _in my badmailfrom list, rejecting (553)\n"); + err_bmf(); + return; + } + } + switch(mfcheck()) { + case DNS_HARD: + log3("envelope sender domain_ ",addr.s," _doesn't exist rejecting (553)\n"); + err_hmf(); flush(); _exit(1); + case DNS_SOFT: err_smf(); return; + case DNS_MEM: die_nomem(); + } seenmail = 1; if (!stralloc_copys(&rcptto,"")) die_nomem(); if (!stralloc_copys(&mailfrom,addr.s)) die_nomem(); @@ -250,14 +396,36 @@ void smtp_rcpt(arg) char *arg; { if (!seenmail) { err_wantmail(); return; } if (!addrparse(arg)) { err_syntax(); return; } - if (flagbarf) { err_bmf(); return; } + if (flagbarfbhelo) { + log5("badhelo_ ",helohost.s," _at ",remoteip,", rejecting (553)\n"); + err_bhelo(); + return; + } + if ((!flagbarfbmt) && (bmtok)) { + flagbarfbmt = bmcheck(BMCHECK_BMT); + if (flagbarfbmt) { + /* st: bmt is blocked after the DATA command */ + log3("envelope rcptto_ ",addr.s," _in my badmailto list, rejecting (553)\n"); + } + } + /* st: check mailfrom.len, otherwise there some problems with mailer-daemon + if ((flagbarfbmf) && (mailfrom.len > 1)) { + log3("envelope sender_ ",mailfrom.s," _in my badmailfrom list, rejecting (553)\n"); + err_bmf(); + return; + } + */ if (relayclient) { --addr.len; if (!stralloc_cats(&addr,relayclient)) die_nomem(); if (!stralloc_0(&addr)) die_nomem(); } else - if (!addrallowed()) { err_nogateway(); return; } + if (!addrallowed()) { + log3("envelope rcptto_ ",addr.s," _isn't in my rcpthost, rejecting (553)\n"); + err_nogateway(); + return; + } if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem(); @@ -316,8 +484,8 @@ if (flagmaybex) if (pos == 7) ++*hops; if (pos < 2) if (ch != "\r\n"[pos]) flagmaybey = 0; if (flagmaybey) if (pos == 1) flaginheader = 0; + ++pos; } - ++pos; if (ch == '\n') { pos = 0; flagmaybex = flagmaybey = flagmaybez = 1; } } switch(state) { @@ -365,16 +533,19 @@ out("\r\n"); } -void smtp_data() { +void smtp_data(arg) char *arg; { int hops; unsigned long qp; char *qqx; if (!seenmail) { err_wantmail(); return; } if (!rcptto.len) { err_wantrcpt(); return; } + if (flagbarfbmt) { err_bmt(); flush(); _exit(1); } seenmail = 0; if (databytes) bytestooverflow = databytes + 1; if (qmail_open(&qqt) == -1) { err_qqt(); return; } + /* st: minimal log, if multiple rcptto only one is logged */ + log5("(st15) mailfrom_ ",mailfrom.s," _to_ ",addr.s,"\n"); qp = qmail_qp(&qqt); out("354 go ahead\r\n"); @@ -387,9 +558,23 @@ qqx = qmail_close(&qqt); if (!*qqx) { acceptmessage(qp); return; } - if (hops) { out("554 too many hops, this message is looping (#5.4.6)\r\n"); return; } - if (databytes) if (!bytestooverflow) { out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return; } + if (hops) { + log1("too many hops, this message is looping (554)\n"); + out("554 too many hops, this message is looping (#5.4.6)\r\n"); + return; + } + if (databytes) if (!bytestooverflow) { + log1("message size exceeds my databytes limit (552)\n"); + out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); + return; + } + if (*qqx == 'G') { + out("553 "); + log3("qq error - ",qqx + 1," (553)\n"); + out(qqx + 1); out("\r\n"); flush(); _exit(1); + } if (*qqx == 'D') out("554 "); else out("451 "); + log3("qq error - ",qqx + 1,"\n"); out(qqx + 1); out("\r\n"); } @@ -410,6 +595,8 @@ void main() { + /* st: getpid for the log */ + strnum[fmt_ulong(strnum,getpid())] = 0; sig_pipeignore(); if (chdir(auto_qmail) == -1) die_control(); setup(); diff -Naur qmail-1.03.orig/qmail.c qmail-1.03/qmail.c --- qmail-1.03.orig/qmail.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail.c 2007-07-11 19:46:12.000000000 +0000 @@ -6,28 +6,48 @@ #include "fd.h" #include "qmail.h" #include "auto_qmail.h" +#include "env.h" -static char *binqqargs[2] = { "bin/qmail-queue", 0 } ; +static char *binqqargs[2] = { 0, 0 } ; + +static void setup_qqargs() +{ + if(!binqqargs[0]) + binqqargs[0] = env_get("QMAILQUEUE"); + if(!binqqargs[0]) + binqqargs[0] = "bin/qmail-queue"; +} int qmail_open(qq) struct qmail *qq; { int pim[2]; int pie[2]; + int pierr[2]; + + setup_qqargs(); if (pipe(pim) == -1) return -1; if (pipe(pie) == -1) { close(pim[0]); close(pim[1]); return -1; } + if (pipe(pierr) == -1) { + close(pim[0]); close(pim[1]); + close(pierr[0]); close(pierr[1]); + return -1; + } switch(qq->pid = vfork()) { case -1: + close(pierr[0]); close(pierr[1]); close(pim[0]); close(pim[1]); close(pie[0]); close(pie[1]); return -1; case 0: close(pim[1]); close(pie[1]); + close(pierr[0]); /* we want to receive data */ if (fd_move(0,pim[0]) == -1) _exit(120); if (fd_move(1,pie[0]) == -1) _exit(120); + if (fd_move(4,pierr[1]) == -1) _exit(120); if (chdir(auto_qmail) == -1) _exit(61); execv(*binqqargs,binqqargs); _exit(120); @@ -35,6 +55,7 @@ qq->fdm = pim[1]; close(pim[0]); qq->fde = pie[1]; close(pie[0]); + qq->fderr = pierr[0]; close(pierr[1]); substdio_fdbuf(&qq->ss,write,qq->fdm,qq->buf,sizeof(qq->buf)); qq->flagerr = 0; return 0; @@ -82,10 +103,22 @@ { int wstat; int exitcode; + int match; + char ch; + static char errstr[256]; + int len = 0; qmail_put(qq,"",1); if (!qq->flagerr) if (substdio_flush(&qq->ss) == -1) qq->flagerr = 1; close(qq->fde); + substdio_fdbuf(&qq->ss,read,qq->fderr,qq->buf,sizeof(qq->buf)); + while( substdio_bget(&qq->ss,&ch,1) && len < 255){ + errstr[len]=ch; + len++; + } + if (len > 0) errstr[len]='\0'; /* add str-term */ + + close(qq->fderr); if (wait_pid(&wstat,qq->pid) != qq->pid) return "Zqq waitpid surprise (#4.3.0)"; @@ -96,7 +129,7 @@ switch(exitcode) { case 115: /* compatibility */ case 11: return "Denvelope address too long for qq (#5.1.3)"; - case 31: return "Dmail server permanently rejected message (#5.3.0)"; + case 31: return "GWe have reassons to believe this mail is spam (#5.7.1)"; case 51: return "Zqq out of memory (#4.3.0)"; case 52: return "Zqq timeout (#4.3.0)"; case 53: return "Zqq write error or disk full (#4.3.0)"; @@ -118,6 +151,9 @@ case 81: return "Zqq internal bug (#4.3.0)"; case 120: return "Zunable to exec qq (#4.3.0)"; default: + if (exitcode == 82 && len > 2){ + return errstr; + } if ((exitcode >= 11) && (exitcode <= 40)) return "Dqq permanent problem (#5.3.0)"; return "Zqq temporary problem (#4.3.0)"; diff -Naur qmail-1.03.orig/qmail.h qmail-1.03/qmail.h --- qmail-1.03.orig/qmail.h 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/qmail.h 2007-07-11 19:46:12.000000000 +0000 @@ -8,6 +8,7 @@ unsigned long pid; int fdm; int fde; + int fderr; substdio ss; char buf[1024]; } ; diff -Naur qmail-1.03.orig/qregex.c qmail-1.03/qregex.c --- qmail-1.03.orig/qregex.c 1970-01-01 00:00:00.000000000 +0000 +++ qmail-1.03/qregex.c 2007-07-11 19:46:12.000000000 +0000 @@ -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 +#include +#include "qregex.h" + +#define REGCOMP(X,Y) regcomp(&X, Y, REG_EXTENDED|REG_ICASE) +#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); +} diff -Naur qmail-1.03.orig/qregex.h qmail-1.03/qregex.h --- qmail-1.03.orig/qregex.h 1970-01-01 00:00:00.000000000 +0000 +++ qmail-1.03/qregex.h 2007-07-11 19:46:12.000000000 +0000 @@ -0,0 +1,5 @@ +/* simple header file for the matchregex prototype */ +#ifndef _QREGEX_H_ +#define _QREGEX_H_ +int matchregex(char *text, char *regex); +#endif diff -Naur qmail-1.03.orig/remoteinfo.c qmail-1.03/remoteinfo.c --- qmail-1.03.orig/remoteinfo.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/remoteinfo.c 2007-07-11 19:46:12.000000000 +0000 @@ -44,12 +44,12 @@ s = socket(AF_INET,SOCK_STREAM,0); if (s == -1) return 0; - byte_zero(&sin,sizeof(sin)); +/* byte_zero(&sin,sizeof(sin)); sin.sin_family = AF_INET; byte_copy(&sin.sin_addr,4,ipl); sin.sin_port = 0; - if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; } - if (timeoutconn(s,ipr,113,timeout) == -1) { close(s); return 0; } + if (bind(s,(struct sockaddr *) &sin,sizeof(sin)) == -1) { close(s); return 0; } */ + if (timeoutconn(s,ipr,ipl,113,timeout) == -1) { close(s); return 0; } fcntl(s,F_SETFL,fcntl(s,F_GETFL,0) & ~O_NDELAY); len = 0; diff -Naur qmail-1.03.orig/sendmail.c qmail-1.03/sendmail.c --- qmail-1.03.orig/sendmail.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/sendmail.c 2007-07-11 19:46:12.000000000 +0000 @@ -45,6 +45,38 @@ _exit(111); } +void do_sender(s) +const char *s; +{ + char *x; + int n; + int a; + int i; + + env_unset("QMAILNAME"); + env_unset("MAILNAME"); + env_unset("NAME"); + env_unset("QMAILHOST"); + env_unset("MAILHOST"); + + n = str_len(s); + a = str_rchr(s, '@'); + if (a == n) + { + env_put2("QMAILUSER", s); + return; + } + env_put2("QMAILHOST", s + a + 1); + + x = (char *) alloc((a + 1) * sizeof(char)); + if (!x) nomem(); + for (i = 0; i < a; i++) + x[i] = s[i]; + x[i] = 0; + env_put2("QMAILUSER", x); + alloc_free(x); +} + int flagh; char *sender; @@ -118,6 +150,7 @@ if (sender) { *arg++ = "-f"; *arg++ = sender; + do_sender(sender); } *arg++ = "--"; for (i = 0;i < argc;++i) *arg++ = argv[i]; diff -Naur qmail-1.03.orig/spawn.c qmail-1.03/spawn.c --- qmail-1.03.orig/spawn.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/spawn.c 2007-07-11 19:46:12.000000000 +0000 @@ -5,6 +5,7 @@ #include "substdio.h" #include "byte.h" #include "str.h" +#include "alloc.h" #include "stralloc.h" #include "select.h" #include "exit.h" diff -Naur qmail-1.03.orig/timeoutconn.c qmail-1.03/timeoutconn.c --- qmail-1.03.orig/timeoutconn.c 1998-06-15 10:53:16.000000000 +0000 +++ qmail-1.03/timeoutconn.c 2007-07-11 19:46:12.000000000 +0000 @@ -10,9 +10,10 @@ #include "byte.h" #include "timeoutconn.h" -int timeoutconn(s,ip,port,timeout) +int timeoutconn(s,ip,outip,port,timeout) int s; struct ip_address *ip; +struct ip_address *outip; unsigned int port; int timeout; { @@ -22,6 +23,13 @@ fd_set wfds; struct timeval tv; + /* bind() an outgoing ipaddr */ + byte_zero(&sin,sizeof(sin)); + byte_copy(&sin.sin_addr.s_addr,4,outip); + sin.sin_family = AF_INET; + + if (-1 == bind(s,(struct sockaddr *) &sin,sizeof(sin))) return -1; + byte_zero(&sin,sizeof(sin)); byte_copy(&sin.sin_addr,4,ip); x = (char *) &sin.sin_port;