diff --git a/imapserver/server.go b/imapserver/server.go index d9c3464..5ef6a1f 100644 --- a/imapserver/server.go +++ b/imapserver/server.go @@ -60,6 +60,7 @@ import ( "time" "golang.org/x/exp/maps" + "golang.org/x/text/unicode/norm" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -1921,8 +1922,8 @@ func (c *conn) cmdAuthenticate(tag, cmd string, p *parser) { if len(plain) != 3 { xsyntaxErrorf("bad plain auth data, expected 3 nul-separated tokens, got %d tokens", len(plain)) } - authz := string(plain[0]) - username = string(plain[1]) + authz := norm.NFC.String(string(plain[0])) + username = norm.NFC.String(string(plain[1])) password := string(plain[2]) c.loginAttempt.LoginAddress = username @@ -1956,7 +1957,7 @@ func (c *conn) cmdAuthenticate(tag, cmd string, p *parser) { if len(t) != 2 || len(t[1]) != 2*md5.Size { xsyntaxErrorf("malformed cram-md5 response") } - username = t[0] + username = norm.NFC.String(t[0]) c.loginAttempt.LoginAddress = username c.log.Debug("cram-md5 auth", slog.String("address", username)) var err error @@ -2110,7 +2111,7 @@ func (c *conn) cmdAuthenticate(tag, cmd string, p *parser) { // ../rfc/4422:1618 buf := xreadInitial() - username = string(buf) + username = norm.NFC.String(string(buf)) c.loginAttempt.LoginAddress = username if !c.tls { @@ -2201,7 +2202,7 @@ func (c *conn) cmdLogin(tag, cmd string, p *parser) { // Request syntax: ../rfc/9051:6667 ../rfc/3501:4804 p.xspace() - username := p.xastring() + username := norm.NFC.String(p.xastring()) c.loginAttempt.LoginAddress = username p.xspace() password := p.xastring() diff --git a/smtpserver/server.go b/smtpserver/server.go index d3476e5..8d3eded 100644 --- a/smtpserver/server.go +++ b/smtpserver/server.go @@ -1544,7 +1544,7 @@ func (c *conn) cmdAuth(p *parser) { c.log.Infox("scram protocol error", err, slog.Any("remote", c.remoteIP)) xsmtpUserErrorf(smtp.C455BadParams, smtp.SePol7Other0, "scram protocol error: %s", err) } - username = norm.NFC.String(ss.Authentication) + username = ss.Authentication la.LoginAddress = username c.log.Debug("scram auth", slog.String("authentication", username)) account, la.AccountName, _, err = store.OpenEmail(c.log, username, false) @@ -1620,7 +1620,7 @@ func (c *conn) cmdAuth(p *parser) { // ../rfc/4422:1618 buf := xreadInitial("") - username = string(buf) + username = norm.NFC.String(string(buf)) la.LoginAddress = username if !c.tls { diff --git a/webauth/webauth.go b/webauth/webauth.go index 9728718..a34cdb8 100644 --- a/webauth/webauth.go +++ b/webauth/webauth.go @@ -45,6 +45,8 @@ import ( "strings" "time" + "golang.org/x/text/unicode/norm" + "github.com/mjl-/sherpa" "github.com/mjl-/mox/metrics" @@ -266,6 +268,7 @@ func Login(ctx context.Context, log mlog.Log, sessionAuth SessionAuth, kind, coo return "", &sherpa.Error{Code: "user:error", Message: "too many authentication attempts"} } + username = norm.NFC.String(username) valid, disabled, accountName, err := sessionAuth.login(ctx, log, username, password) la := loginAttempt(r, kind, "weblogin") la.LoginAddress = username