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
DEBUGlevel the server writes every line it receives, and the inline forms ofAUTHcarry 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
DEBUGand acceptAUTH. Passwords in them must be changed. -
STARTTLSdiscards what the client said before the handshake.Peer.HeloName,Peer.ProtocolandPeer.Usernameare 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 aHeloNamethat 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.
WithGreylistMaxEntriessets another cap.
Availability
-
A panic in a
Handleror 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, replies421, and closes that connection.PanicErrorcarries the panic to theDisconnecthooks. -
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
DataTimeoutallows. It stops at twiceMaxMessageSizenow. -
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
XCLIENTdecodes its attribute values. They come in the xtext encoding of RFC 1891, and the server read them as they came, soLOGIN=user+40example.comgaveuser+40example.cominstead ofuser@example.com.XCLIENTreads[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.XCLIENTaccepts a value that carries an equals sign, such as the padding of base64 inLOGIN=dXNlcg==.- A panic in
BaseContextstopsServewith aPanicErrorinstead of stopping the process. A panic inConnContextdrops that connection only.
Added
PanicError, with the value given topanicand the stack trace. TheDisconnecthooks receive it through theirerrargument.
Full changelog: v2.2.0...v2.3.0