attempt at improving interoperability of with outlook 365 using the smtp "login" sasl auth mechanism

by sending the (encoded) string "User Name" as mentioned by the internet-draft,
https://datatracker.ietf.org/doc/html/draft-murchison-sasl-login-00#section-2.1

that document says clients should ignore the challenge (which is why were were
not doing any effort and sending an empty challenge). but it also says some
clients require the challenge "Username:" instead of "User Name", implying that
it's important to not send an empty challenge. we can't send both challenges
though...

for issue #51
This commit is contained in:
Mechiel Lukkien 2024-07-18 21:17:33 +02:00
parent c629ae26af
commit aead738836
No known key found for this signature in database

View file

@ -1018,10 +1018,12 @@ func (c *conn) cmdAuth(p *parser) {
p.xspace()
mech := p.xsaslMech()
xreadInitial := func() []byte {
// Read the first parameter, either as initial parameter or by sending a
// continuation with the optional encChal (must already be base64-encoded).
xreadInitial := func(encChal string) []byte {
var auth string
if p.empty() {
c.writelinef("%d ", smtp.C334ContinueAuth) // ../rfc/4954:205
c.writelinef("%d %s", smtp.C334ContinueAuth, encChal) // ../rfc/4954:205
// todo future: handle max length of 12288 octets and return proper responde codes otherwise ../rfc/4954:253
auth = c.readline()
if auth == "*" {
@ -1080,7 +1082,7 @@ func (c *conn) cmdAuth(p *parser) {
// Password is in line in plain text, so hide it.
defer c.xtrace(mlog.LevelTraceauth)()
buf := xreadInitial()
buf := xreadInitial("")
c.xtrace(mlog.LevelTrace) // Restore.
plain := bytes.Split(buf, []byte{0})
if len(plain) != 3 {
@ -1125,11 +1127,13 @@ func (c *conn) cmdAuth(p *parser) {
xsmtpUserErrorf(smtp.C538EncReqForAuth, smtp.SePol7EncReqForAuth11, "authentication requires tls")
}
// Read user name. The I-D says the client should ignore the server challenge, we
// send an empty one.
// Read user name. The I-D says the client should ignore the server challenge, but
// also that some clients may require challenge "Username:" instead of "User
// Name". We can't sent both...
// I-D says maximum length must be 64 bytes. We allow more, for long user names
// (domains).
username := string(xreadInitial())
encChal := base64.StdEncoding.EncodeToString([]byte("User Name"))
username := string(xreadInitial(encChal))
username = norm.NFC.String(username)
// Again, client should ignore the challenge, we send the same as the example in
@ -1258,7 +1262,7 @@ func (c *conn) cmdAuth(p *parser) {
xcs := c.conn.(*tls.Conn).ConnectionState()
cs = &xcs
}
c0 := xreadInitial()
c0 := xreadInitial("")
ss, err := scram.NewServer(h, c0, cs, channelBindingRequired)
xcheckf(err, "starting scram")
authc := norm.NFC.String(ss.Authentication)