qmail patches

Here you can find my patches for qmail 1.03. If you are interested in a modern SMTP engine for qmail featuring IPv6 support and everything below have a look at Qsmtp.

Another small thing that may help you today is my qmail-send.service file for systemd.

I've put some of the fixes below as well as some other fixes into a GitHub repository.

baduser - reject nonexistent users in SMTP dialog (requires vpopmail)
This patch looks up /home/vpopmail/domains/domainname/* if the user exists, it finds user directories and users with .qmail-user file. There are most likely some bugs: .qmail-foo files for user names containing dots are not found, it does not use /var/qmail/users/assign to find out the directory but guesses and maybe the handling of .qmail-foo-default is a bit broken if the username contains a hyphen (in this case it tries foo-bar, foo-bar-default and foo-default but maybe misses a hyphen in one of these contructs). You must make the domains directory, the subdirectories of the domains and the user directories (not their contents) as well as all .qmail-files in the domain subdirectory readable for qmaild.
baduser2 - reject nonexistent users in SMTP dialog (requires vpopmail)
This patch looks up /home/vpopmail/domains/domainname/* if the user exists, it finds user directories and users with .qmail-user file. These version is improved and looks up the domain directory in /var/qmail/users/cdb instead of guessing, so it does not need to be recompiled if you change your vpopmail directory (and can handle alias domains properly). The dot bug should be fixed now, the hyphen thing is still untested. In fact, this patch is entirely untested. This will happen some time but I'm busy with other things at the moment. You have been warned. You must make the domains directory, the subdirectories of the domains and the user directories (not their contents) as well as all .qmail-files in the domain subdirectory readable for qmaild.
qmail-remote ESMTP v0.04
This patch enables qmail-remote to use the ESMTP SIZE extension defined in RfC 1870. qmail-remote now uses EHLO by default and only falls back to HELO if the server rejects the EHLO. A modified version of this patch is tested at 2 servers and successfully sent more than 30.000 mails in the last year. This patch does not apply cleanly if you have applied the STARTTLS patch (and vice versa).
qmail-remote ESMTP v0.05
This patch contains everything in v0.04 plus the PIPELINING extension defined in RfC 2920. If the remote server announces PIPELINING the MAIL FROM:, RCPT TO: and DATA commands are sent as a single batch and the return codes are checked after this. This reduced the penalty of a high latency connection and avoids sending many small TCP packets for this commands. There are now also some extra checks for what the server returns, v0.04 would use SIZE even if the server only announces SIZEFOO.
This patch does not apply cleanly if you have applied the STARTTLS patch (and vice versa). You have to kill the first patch to qmail-remote.c from the TLS diff (this one adds another type of EHLO support). If you are using netqmail you can apply the rest of the TLS patch now. There will be 3 rejects, the first one can be completely ignored, the second can be ignored if you don't plan to use SMTPS on port 465 (else you have to apply the first half of the second reject by hand), the third one is a only three lines long and can easily be applied by hand. (tested with netqmail-1.05 and netqmail-1.05-tls-20040419.patch).
Then you have to remove this part of the function tls_init():
  if (!smtps) {
    stralloc *sa = ehlokw.sa;
    unsigned int len = ehlokw.len;
    /* look for STARTTLS among EHLO keywords */
    for ( ; len && case_diffs(sa->s, "STARTTLS"); ++sa, --len) ;
    if (!len) {
      if (!servercert) return 0;
      out("ZNo TLS achieved while "); out(servercert);
      out(" exists"); smtptext.len = 0; TLS_QUIT;
    }
  }

qmail-remote CRLF
If qmail-remote get's a '\r' (CR, carriage return) in it's input stream (which means that a mail injected into qmail-queue contained a '\r') it will send this unmasked to the network. This patch works this way: if there is a single '\r' somewhere in the input stream it is handled as a line break, so it is send as CRLF to the network. If there is a CRLF sequence in the input stream (normally there should only be bare LFs) it will not double the CR (like qmail-remote normally does) but send this CRLF sequence as is.
qmail-send bouncesize
This patch reduces the maximum size of a bounce generated by qmail-send to 32 KiB (only counting the size of the data copied from the original mail). This prevents qmail-send to be used for DoS attacks by huge bounces.
qmail-inject no parse unneeded header recipients

qmail-inject can parse the message header to determine the recipients of a mail. You can also pass it a list of recipients on command line so it will ignore the recipients stated in the header. This is e.g. used when you redirect a mail by a .qmail file. But even if those recipients will not be used the header fields will still be parsed and a bounce is generated on failure.

If a mail is injected from network with the broken header field "To: foo: bar, baz" then this would be delivered fine as the recipient is given in the SMTP transmission. If it could not be directly delivered but is forwarded to another user by a .qmail file or a virtualdomain alias then this mail is passed through "qmail-inject -a newrecipient". Nevertheless the header fields are parsed, the error is raised and the message is bounced. This leads to ugly bounces with the message "qmail-inject: fatal: unable to parse this line:". Since the message is of course spam the bounce will bounce again and annoy the postmaster. This patch changes qmail-inject to totally ignore the lines with recipients (To:, Cc:, Bcc) if the recipients were passed as arguments. In this case the mail will be routed to the original recipient and can there be handled.