Skip to content

v2.3.0

Latest

Choose a tag to compare

@chrj chrj released this 08 Aug 11:37
5c080b5

Security

Upgrade if you run with DEBUG logging, accept AUTH, offer STARTTLS, or use middleware.Greylist.

  • Credentials no longer go to the log. At the DEBUG level the server writes every line it receives, and the inline forms of AUTH carry the credentials on that line. Base64 is not protection, so anybody who read the log had the password. The server now keeps the verb and the mechanism and replaces the rest with [redacted].

    Read your logs if you run with DEBUG and accept AUTH. Passwords in them must be changed.

  • STARTTLS discards what the client said before the handshake. Peer.HeloName, Peer.Protocol and Peer.Username are cleared. Those go over the wire in plain text, where anybody on the path can change them, and RFC 3207 says the server must drop them. A handler could read a HeloName that an attacker in the middle chose.

  • The greylist holds at most 100000 triples and drops the oldest at that point. The map had no bound, so a client that sent many different triples made the server hold all of them for 24 hours. WithGreylistMaxEntries sets another cap.

Availability

  • A panic in a Handler or a hook stops that session only. It stopped the whole process before, so one message from one client took down every other session. The server writes the panic and the stack trace to the log, replies 421, and closes that connection. PanicError carries the panic to the Disconnect hooks.

  • The read after the size limit is bounded. The server read to the end of a message it had already rejected, which let a client hold the session for as long as DataTimeout allows. It stops at twice MaxMessageSize now.

  • A greylist check no longer reads the whole map. The sweep for expired entries ran on every RCPT TO, under the lock. At 20000 entries a check took 271µs; it takes 156ns now, and the cost no longer grows with the map.

Behavior changes

CAUTION: Three changes are visible to a client. Read these before you upgrade a busy server.

A client must greet again after STARTTLS. Without a second EHLO or HELO, MAIL FROM is answered with 503. Client libraries already do this, net/smtp among them. A client of your own that skips it stops working.

Reply codes follow RFC 5321. 502 was the answer to most faults. A command in the wrong order now gets 503, an argument the server could not read gets 501, and a command it does not know gets 500. A client that reads the first digit only sees no change; one that matches the whole code has to be read again.

An oversized message can close the connection. A client that keeps sending after the 552 loses the connection, because the rest of the message would otherwise be read as SMTP commands. A message that ends inside the budget behaves as before.

Fixed

  • XCLIENT decodes its attribute values. They come in the xtext encoding of RFC 1891, and the server read them as they came, so LOGIN=user+40example.com gave user+40example.com instead of user@example.com.
  • XCLIENT reads [UNAVAILABLE] and [TEMPUNAVAIL] as "no information" and leaves that attribute alone. PORT=[UNAVAILABLE] failed the whole command before, which dropped the address of the client with it.
  • XCLIENT accepts a value that carries an equals sign, such as the padding of base64 in LOGIN=dXNlcg==.
  • A panic in BaseContext stops Serve with a PanicError instead of stopping the process. A panic in ConnContext drops that connection only.

Added

  • PanicError, with the value given to panic and the stack trace. The Disconnect hooks receive it through their err argument.

Full changelog: v2.2.0...v2.3.0