Handle case-insensitivity properly for SMTP commands.
authorRobert Sesek <rsesek@bluestatic.org>
Wed, 14 Dec 2016 05:52:14 +0000 (00:52 -0500)
committerRobert Sesek <rsesek@bluestatic.org>
Wed, 14 Dec 2016 05:52:14 +0000 (00:52 -0500)
smtp/conn.go
smtp/conn_test.go

index c37948486d40c8e580ebde47c7fa1272ce5c87fe..34858942c70259b4092116595417d608d3d53917 100644 (file)
@@ -5,6 +5,7 @@ import (
        "net"
        "net/mail"
        "net/textproto"
+       "strings"
 )
 
 type state int
@@ -56,7 +57,7 @@ func AcceptConnection(netConn net.Conn, server Server) error {
                        continue
                }
 
-               switch cmd {
+               switch strings.ToUpper(cmd) {
                case "QUIT":
                        conn.writeReply(221, "Goodbye")
                        conn.tp.Close()
@@ -101,6 +102,19 @@ func (conn *connection) writeReply(code int, msg string) {
        }
 }
 
+// parsePath parses out either a forward-, reverse-, or return-path from the
+// current connection line. Returns a (valid-path, ReplyOK) if it was
+// successfully parsed.
+func (conn *connection) parsePath(command string) (string, ReplyLine) {
+       if len(conn.line) < len(command) {
+               return "", ReplyBadSyntax
+       }
+       if strings.ToUpper(command) != strings.ToUpper(conn.line[:len(command)]) {
+               return "", ReplyLine{500, "unrecognized command"}
+       }
+       return conn.line[len(command):], ReplyOK
+}
+
 func (conn *connection) doEHLO() {
        conn.resetBuffers()
 
@@ -130,13 +144,13 @@ func (conn *connection) doMAIL() {
                return
        }
 
-       var mailFrom string
-       _, err := fmt.Sscanf(conn.line, "MAIL FROM:%s", &mailFrom)
-       if err != nil {
-               conn.reply(ReplyBadSyntax)
+       mailFrom, reply := conn.parsePath("MAIL FROM:")
+       if reply != ReplyOK {
+               conn.reply(reply)
                return
        }
 
+       var err error
        conn.mailFrom, err = mail.ParseAddress(mailFrom)
        if err != nil {
                conn.reply(ReplyBadSyntax)
@@ -153,10 +167,9 @@ func (conn *connection) doRCPT() {
                return
        }
 
-       var rcptTo string
-       _, err := fmt.Sscanf(conn.line, "RCPT TO:%s", &rcptTo)
-       if err != nil {
-               conn.reply(ReplyBadSyntax)
+       rcptTo, reply := conn.parsePath("RCPT TO:")
+       if reply != ReplyOK {
+               conn.reply(reply)
                return
        }
 
index 5aa5234c1c25e13dcfcd20ed9db05732e705b190..32ca4849291e98e60a53ffcee5e9a05dcb410c9e 100644 (file)
@@ -164,3 +164,27 @@ func TestVerifyAddress(t *testing.T) {
                {"QUIT", 221, nil},
        })
 }
+
+func TestCaseSensitivty(t *testing.T) {
+       s := &testServer{}
+       l := runServer(t, s)
+       defer l.Close()
+
+       conn := createClient(t, l.Addr())
+       readCodeLine(t, conn, 220)
+
+       runTableTest(t, conn, []requestResponse{
+               {"nOoP", 250, nil},
+               {"ehLO test.TEST", 0, func(t testing.TB, conn *textproto.Conn) { conn.ReadResponse(250) }},
+               {"mail FROM:<sender@example.com>", 250, nil},
+               {"RcPT tO:<receive@mail.com>", 250, nil},
+               {"DATa", 0, func(t testing.TB, conn *textproto.Conn) {
+                       readCodeLine(t, conn, 354)
+
+                       ok(t, conn.PrintfLine("."))
+                       readCodeLine(t, conn, 250)
+               }},
+               {"MAIL FR:", 501, nil},
+               {"QUiT", 221, nil},
+       })
+}