SMTP AUTH with XCLIENT - impossible or just difficult?

I have been successful at using nginx as a front end to POP and IMAP
servers to keep mailboxes spread across multiple machines. It also
provided the added benefit of enabling SSL for privacy. I wrote a custom
HTTP based authentication agent to direct to the proper mailbox, and
everything seems to work great. Now I would like to do the same for SMTP
connections, using nginx as both an SSL front end and director to my
SMTP daemons.

However, after implementing XCLIENT in the SMTP daemon, and adding a
simple configuration to nginx, all is not well. After working my way
through the mailing list and trying several configurations, I am left
thinking that XCLIENT with authentication simply does not work. Has
anyone ever managed to get this to work?

Very simple sample configuration:


smtp_auth plain cram-md5;

server {
listen 10.10.10.104:1466;
server_name veyron.karlkraft.com;
protocol smtp;
proxy on;
}

This is an example of a session:

CN - client to nginx
NC - nginx to client
NS - nginx to smtp server
SN - smtp server to nginx

NC: 220 veyron.karlkraft.com ESMTP ready
CN: EHLO client.karlkraft.com
NC: 250 AUTH PLAIN CRAM-MD5
CN: AUTH PLAIN xxxxxxxxxxxxxxxxxxxxxxx

At this point, nginx contacts the authentication agent over HTTP, and is
told to contact explorer on port 1125 as the actual SMTP back end
daemon. Once the connection is successful, it passes back the 235
code for passing authentication:

NS: [Connects to back end SMTP server]

NC: 235 2.0.0 OK

And then nginx proceeds to negotiate with the back end server:

SN: 220 explorer.karlkraft.com. - explorer.karlkraft.com
(NFSmtp/2006q2.1) Authorized network 10.10.0.0/255.255.0.0
NS: EHLO veyron.karlkraft.com
SN: 250-/10.10.10.104
SN: 250-EXPN
SN: 250-NAME ADDR PROTO HELO
SN: 250-SIZE
SN: 250-AUTH CRAM-MD5 PLAIN
SN: 250 HELP

nginx then sends the XCLIENT command. The back end server needs the
information in order to be able to provide the proper routing and QOS
based on the login, as well as performing SPF and DNSBL checks against
the original IP.

NS: XCLIENT ADDR=10.10.10.2 [email protected] NAME=[UNAVAILABLE]
SN: 220 Authenticated via XCLIENT

And here is where it all falls apart, because the response to XCLIENT is
then passed back to the original client, which confuses the client
because it hand’t sent any commands yet.

NC: 220 Authenticated via XCLIENT

Nginx then sends the second EHLO to the server:

NS: EHLO client

The server then responds, and nginx forwards all this response to the
original client as well, leaving the client even more confused:

SN: 250-/10.10.10.104
SN: 250-EXPN
SN: 250-NAME ADDR PROTO HELO
SN: 250-SIZE
SN: 250-AUTH CRAM-MD5 PLAIN
SN: 250 HELP

NC: 250-/10.10.10.104
NC: 250-EXPN
NC: 250-NAME ADDR PROTO HELO
NC: 250-SIZE
NC: 250-AUTH CRAM-MD5 PLAIN
NC: 250 HELP

Since the client has no idea about XCLIENT and the second EHLO, it is
horribly confused. The session from the clients perspective looks like
this:

NC: 220 veyron.karlkraft.com ESMTP ready
CN: EHLO client.karlkraft.com
NC: 250 AUTH PLAIN CRAM-MD5
CN: AUTH PLAIN xxxxxxxxxxxxxxxxxxxxxxx
NC: 235 2.0.0 OK
NC: 220 Authenticated via XCLIENT
NC: 250-/10.10.10.104
NC: 250-EXPN
NC: 250-NAME ADDR PROTO HELO
NC: 250-SIZE
NC: 250-AUTH CRAM-MD5 PLAIN
NC: 250 HELP

The only way I am able to get close to a working connection is with the
following two conditions:

Turn XCLIENT off - this of course makes it impossible for the back end
server to know the authenticated username or source IP address.

Client must send HELO instead of EHLO - controlling all the clients is
out of the question.


Karl Kraft

Hello!

On Wed, Aug 04, 2010 at 08:02:29AM -0500, Karl Kraft wrote:

working my way through the mailing list and trying several
configurations, I am left thinking that XCLIENT with
authentication simply does not work. Has anyone ever managed to
get this to work?

[…]

SN: 220 explorer.karlkraft.com. - explorer.karlkraft.com
(NFSmtp/2006q2.1) Authorized network 10.10.0.0/255.255.0.0
NS: EHLO veyron.karlkraft.com
SN: 250-/10.10.10.104
SN: 250-EXPN
SN: 250-NAME ADDR PROTO HELO
SN: 250-SIZE
SN: 250-AUTH CRAM-MD5 PLAIN
SN: 250 HELP

Here actual problem happens. nginx doesn’t really understand
multiline smtp replies, but usually handles them nicely once they
happen to be in single tcp packet.

Most likely your tcp daemon sends ehlo reply in multiple packets.
This isn’t good from performance point of view but anyway should
be supported. Try the attached patch.

[…]

The only way I am able to get close to a working connection is
with the following two conditions:

Turn XCLIENT off - this of course makes it impossible for the
back end server to know the authenticated username or source IP
address.

Client must send HELO instead of EHLO - controlling all the
clients is out of the question.

While XCLIENT is mostly unrelated - it forces nginx to use ESMTP
with backend, i.e. use EHLO. In your case EHLO reply is multiline
one and split across multiple packets. This in turn causes all
the troubles (and the same thing happens if client itself uses
ESMTP).

Maxim D.

Hello!

On Fri, Aug 06, 2010 at 05:56:36AM +0400, Maxim D. wrote:

[…]

Here actual problem happens. nginx doesn’t really understand
multiline smtp replies, but usually handles them nicely once they
happen to be in single tcp packet.

Most likely your tcp daemon sends ehlo reply in multiple packets.
This isn’t good from performance point of view but anyway should
be supported. Try the attached patch.

Oops, sorry, forgot to attach the patch. Next try… :slight_smile:

Maxim D.