for imap/smtp syntax errors, only echo the remaining buffer if the connection is authenticated

This commit is contained in:
Mechiel Lukkien
2023-03-10 11:32:34 +01:00
parent e413c906b1
commit f9eae88aba
6 changed files with 55 additions and 18 deletions

View File

@ -1,6 +1,7 @@
package imapserver
import (
"errors"
"fmt"
)
@ -36,13 +37,14 @@ func xserverErrorf(format string, args ...any) {
}
type syntaxError struct {
line string // Optional line to write before BAD result. For untagged response. CRLF will be added.
code string // Optional result code (between []) to write in BAD result.
err error // BAD response message.
line string // Optional line to write before BAD result. For untagged response. CRLF will be added.
code string // Optional result code (between []) to write in BAD result.
errmsg string // BAD response message.
err error // Typically with same info as errmsg, but sometimes more.
}
func (e syntaxError) Error() string {
s := "bad syntax: " + e.err.Error()
s := "bad syntax: " + e.errmsg
if e.code != "" {
s += " [" + e.code + "]"
}
@ -51,5 +53,7 @@ func (e syntaxError) Error() string {
func (e syntaxError) Unwrap() error { return e.err }
func xsyntaxErrorf(format string, args ...any) {
panic(syntaxError{"", "", fmt.Errorf(format, args...)})
errmsg := fmt.Sprintf(format, args...)
err := errors.New(errmsg)
panic(syntaxError{"", "", errmsg, err})
}

View File

@ -1,6 +1,7 @@
package imapserver
import (
"errors"
"fmt"
"net/textproto"
"strconv"
@ -74,11 +75,20 @@ func newParser(s string, conn *conn) *parser {
}
func (p *parser) xerrorf(format string, args ...any) {
var context string
var err error
errmsg := fmt.Sprintf(format, args...)
remaining := fmt.Sprintf("remaining %q", p.orig[p.o:])
if len(p.contexts) > 0 {
context = strings.Join(p.contexts, ",")
remaining += ", context " + strings.Join(p.contexts, ",")
}
panic(syntaxError{"", "", fmt.Errorf("%s (%sremaining data %q)", fmt.Sprintf(format, args...), context, p.orig[p.o:])})
remaining = " (" + remaining + ")"
if p.conn.account != nil {
errmsg += remaining
err = errors.New(errmsg)
} else {
err = errors.New(errmsg + remaining)
}
panic(syntaxError{"", "", errmsg, err})
}
func (p *parser) context(s string) func() {
@ -724,7 +734,8 @@ func (p *parser) xliteralSize(maxSize int64, lit8 bool) (size int64, sync bool)
if maxSize > 0 && size > maxSize {
// ../rfc/7888:249
line := fmt.Sprintf("* BYE [ALERT] Max literal size %d is larger than allowed %d in this context", size, maxSize)
panic(syntaxError{line, "TOOBIG", fmt.Errorf("literal too big")})
err := errors.New("literal too big")
panic(syntaxError{line, "TOOBIG", err.Error(), err})
}
sync = !p.take("+")

View File

@ -760,14 +760,21 @@ func (c *conn) command() {
c.writelinef("* BYE please try again speaking imap")
panic(errIO)
}
c.log.Debugx("imap command syntax error", err, logFields...)
c.log.Debugx("imap command syntax error", sxerr.err, logFields...)
c.log.Info("imap syntax error", mlog.Field("lastline", c.lastLine))
fatal := strings.HasSuffix(c.lastLine, "+}")
if fatal {
err := c.conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
c.log.Check(err, "setting write deadline")
}
c.bwriteresultf("%s BAD %s unrecognized syntax/command: %v", tag, cmd, err)
if sxerr.line != "" {
c.bwritelinef("%s", sxerr.line)
}
code := ""
if sxerr.code != "" {
code = "[" + sxerr.code + "] "
}
c.bwriteresultf("%s BAD %s%s unrecognized syntax/command: %v", tag, code, cmd, sxerr.errmsg)
if fatal {
c.xflush()
panic(fmt.Errorf("aborting connection after syntax error for command with non-sync literal: %w", errProtocol))
@ -1618,7 +1625,7 @@ func (c *conn) cmdAuthenticate(tag, cmd string, p *parser) {
c0 := xreadInitial()
ss, err := scram.NewServer(h, c0)
if err != nil {
xsyntaxErrorf("starting scram: %w", err)
xsyntaxErrorf("starting scram: %s", err)
}
c.log.Debug("scram auth", mlog.Field("authentication", ss.Authentication))
acc, _, err := store.OpenEmail(ss.Authentication)