qmail.st-combo.14.patch (c) 2003-2007 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.14.patch) or: wget http://cr.yp.to/software/qmail-1.03.tar.gz wget http://toribio.apollinare.org/qmail/qmail.st-combo.14.patch tar xzf qmail-1.03.tar.gz -C /var/tmp cp qmail.st-combo.14.patch /var/tmp/ cd /var/tmp patch -p0 < qmail.st-combo.14.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 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 There is also an ucspi.st-patch, that could be found at: http://toribio.apollinare.org/qmail/ Salvatore Toribio 20070712 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 2007-07-11 19:46:12.000000000 +0000 @@ -0,0 +1,162 @@ + README.qmail.st-patch + +(c) 2003-2007 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.14.patch) or: + +wget http://cr.yp.to/software/qmail-1.03.tar.gz +wget http://toribio.apollinare.org/qmail/qmail.st-combo.14.patch + +tar xzf qmail-1.03.tar.gz -C /var/tmp +cp qmail.st-combo.14.patch /var/tmp/ + +cd /var/tmp + +patch -p0 < qmail.st-combo.14.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 +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 + +20070712 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 2007-07-11 19:46:12.000000000 +0000 @@ -1 +1 @@ -qmail 1.03 +qmail-1.03st14 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 2007-07-11 19:46:12.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,6 +58,7 @@ 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(); } @@ -222,13 +225,17 @@ 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 != 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); @@ -310,6 +317,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 +332,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 +428,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 2007-07-11 19:46:12.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("(st14) 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;