Hi,

I have a locally developed milter using the python-milter bindings which seems to trigger a Postfix bug.

The milter in question uses the smfi_setmlreply() command to set a multiline response as defined in rfc5321.

Multiline replies should result in the smtpd replying with something like the following to e.g. a rejected DATA command:

450-4.7.1 Line 1
450-4.7.1 Line 2
450 4.7.1 Line 3

Postfix however seems to fold the reply into a single line:

450-4.7.1 Line 1  450-4.7.1 Line 2  450 4.7.1 Line 3

SMTP clients like swaks will now run into a timeout as the response indicates a multiline response (XXX-) but no further lines are coming.

I did test my milter using the Net::Milter Perl package which simulates a Milter-enabled MTA as well as actually running it against sendmail as well as postfix.

Net::Milter and sendmail to reply correctly using well-formed multiline responses while postfix does line-folding and thus breaks the SMTP specs.

The python code to trigger such a multiline response is super simple:

  def eom(self):
      self.setreply('550', '5.7.1', 'Test Milter rejection Reason',
          'Test Milter rejection Reason 01',
          'Test Milter rejection Reason 02')
      return Milter.TEMPFAIL

In order to rule out a problem in the Python implementation, I also tested a sample milter written in C using the libmilter library directly. Modifying the sendmail-8.15.2/libmilter/example.c file to have the following eom handler:

sfsistat
mlfi_eom(ctx)
        SMFICTX *ctx;
{
        char *rcode = "450";
        char *xcode = "4.7.1";
        char *reason = "Test Milter rejection Reason";
        char *reason01 = "Test Milter rejection Reason 01";
        char *reason02 = "Test Milter rejection Reason 02";


        (void) mlfi_cleanup(ctx, false);
        smfi_setmlreply(ctx, rcode, xcode, reason, reason01, reason02);
        return SMFIS_TEMPFAIL;
}

Compiling the milter using gcc -o sample_milter example.c -lmilter -lpthread and then starting it using ./sample_milter -p inet:10020@localhost gives the following output in sendmail:

 -> DATA
  > 0000: 44 41 54 41  0D 0A                                    DATA..
<   0000: 33 35 34 20  45 6E 74 65  72 20 6D 61  69 6C 2C 20    354.Enter.mail,.
<   0016: 65 6E 64 20  77 69 74 68  20 22 2E 22  20 6F 6E 20    end.with.".".on.
<   0032: 61 20 6C 69  6E 65 20 62  79 20 69 74  73 65 6C 66    a.line.by.itself
<   0048: 0D 0A                                                 ..
<-  354 Enter mail, end with "." on a line by itself
 ->
 -> .
  > 0000: 0D 0A 2E 0D  0A                                       .....
<   0000: 34 35 30 2D  34 2E 37 2E  31 20 54 65  73 74 20 4D    450-4.7.1.Test.M
<   0016: 69 6C 74 65  72 20 72 65  6A 65 63 74  69 6F 6E 20    ilter.rejection.
<   0032: 52 65 61 73  6F 6E 0D 0A  34 35 30 2D  34 2E 37 2E    Reason..450-4.7.
<   0048: 31 20 54 65  73 74 20 4D  69 6C 74 65  72 20 72 65    1.Test.Milter.re
<   0064: 6A 65 63 74  69 6F 6E 20  52 65 61 73  6F 6E 20 30    jection.Reason.0
<   0080: 31 0D 0A 34  35 30 20 34  2E 37 2E 31  20 54 65 73    1..450.4.7.1.Tes
<   0096: 74 20 4D 69  6C 74 65 72  20 72 65 6A  65 63 74 69    t.Milter.rejecti
<   0112: 6F 6E 20 52  65 61 73 6F  6E 20 30 32  0D 0A          on.Reason.02..
<** 450-4.7.1 Test Milter rejection Reason
<** 450-4.7.1 Test Milter rejection Reason 01
<** 450 4.7.1 Test Milter rejection Reason 02
 -> QUIT
  > 0000: 51 55 49 54  0D 0A                                    QUIT..
<   0000: 32 32 31 20  32 2E 30 2E  30 20 6D 61  69 6C 69 6E    221.2.0.0.mailin
<   0016: 30 31 2E 6D  78 2E 62 61  77 75 65 2E  6E 65 74 20    01.mx.bawue.net.
<   0032: 63 6C 6F 73  69 6E 67 20  63 6F 6E 6E  65 63 74 69    closing.connecti
<   0048: 6F 6E 0D 0A                                           on..
<-  221 2.0.0 mailin01.mx.bawue.net closing connection
=== Connection closed with remote host.


The comparable postfix output:

$ swaks --server localhost --from '<>' --to test@localhost -d '.' --raw
[...]
 -> DATA
  > 0000: 44 41 54 41  0D 0A                                    DATA..
<   0000: 33 35 34 20  45 6E 64 20  64 61 74 61  20 77 69 74    354.End.data.wit
<   0016: 68 20 3C 43  52 3E 3C 4C  46 3E 2E 3C  43 52 3E 3C    h.<CR><LF>.<CR><
<   0032: 4C 46 3E 0D  0A                                       LF>..
<-  354 End data with <CR><LF>.<CR><LF>
 ->
 -> .
  > 0000: 0D 0A 2E 0D  0A                                       .....
<   0000: 34 35 30 2D  34 2E 37 2E  31 20 54 65  73 74 20 4D    450-4.7.1.Test.M
<   0016: 69 6C 74 65  72 20 72 65  6A 65 63 74  69 6F 6E 20    ilter.rejection.
<   0032: 52 65 61 73  6F 6E 20 20  34 35 30 2D  34 2E 37 2E    Reason..450-4.7.
<   0048: 31 20 54 65  73 74 20 4D  69 6C 74 65  72 20 72 65    1.Test.Milter.re
<   0064: 6A 65 63 74  69 6F 6E 20  52 65 61 73  6F 6E 20 30    jection.Reason.0
<   0080: 31 20 20 34  35 30 20 34  2E 37 2E 31  20 54 65 73    1..450.4.7.1.Tes
<   0096: 74 20 4D 69  6C 74 65 72  20 72 65 6A  65 63 74 69    t.Milter.rejecti
<   0112: 6F 6E 20 52  65 61 73 6F  6E 20 30 32  0D 0A          on.Reason.02..
<** Timeout (30 secs) waiting for server response
 -> QUIT
  > 0000: 51 55 49 54  0D 0A                                    QUIT..
< 0000: 32 32 31 20 32 2E 30 2E 30 20 42 79 65 0D 0A 221.2.0.0.Bye..
<-  221 2.0.0 Bye
=== Connection closed with remote host.

The lines are separated by 0x20, 0x20 ([space][space]) rather than 0x0d, 0x0a (\n\r).

I had a quick look at the postfix source but did not find the right codepath where this happens.

Any ideas if this really is a bug in Postfix or am I making a mistake somewhere in my milter?

cheers,
 Andreas

Reply via email to