1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 17:47:03 +00:00

Fix command line length bug (#221)

* handler: Don't fail on 8 character command lines

Fixes #214

* handler: Test that STARTTLS is parsed correctly.
This commit is contained in:
James Hillyerd
2021-07-11 12:00:28 -07:00
committed by GitHub
parent 11f3879442
commit 985f2702f2
2 changed files with 33 additions and 19 deletions

View File

@@ -243,7 +243,7 @@ func (s *Server) startSession(id int, conn net.Conn) {
} }
break break
} }
// not an EOF // Not an EOF
ssn.logger.Warn().Msgf("Connection error: %v", err) ssn.logger.Warn().Msgf("Connection error: %v", err)
if netErr, ok := err.(net.Error); ok { if netErr, ok := err.(net.Error); ok {
if netErr.Timeout() { if netErr.Timeout() {
@@ -281,7 +281,7 @@ func (s *Session) greetHandler(cmd string, arg string) {
return return
} }
s.remoteDomain = domain s.remoteDomain = domain
// features before SIZE per RFC // Features before SIZE per RFC
s.send("250-" + readyBanner) s.send("250-" + readyBanner)
s.send("250-8BITMIME") s.send("250-8BITMIME")
s.send("250-AUTH PLAIN LOGIN") s.send("250-AUTH PLAIN LOGIN")
@@ -331,20 +331,21 @@ func (s *Session) passwordHandler(line string) {
func (s *Session) readyHandler(cmd string, arg string) { func (s *Session) readyHandler(cmd string, arg string) {
if cmd == "STARTTLS" { if cmd == "STARTTLS" {
if !s.Server.config.TLSEnabled { if !s.Server.config.TLSEnabled {
// invalid command since unconfigured // Invalid command since TLS unconfigured.
s.logger.Debug().Msgf("454 TLS unavailable on the server") s.logger.Debug().Msgf("454 TLS unavailable on the server")
s.send("454 TLS unavailable on the server") s.send("454 TLS unavailable on the server")
return return
} }
if s.tlsState != nil { if s.tlsState != nil {
// tls state previously valid // TLS state previously valid.
s.logger.Debug().Msg("454 A TLS session already agreed upon.") s.logger.Debug().Msg("454 A TLS session already agreed upon.")
s.send("454 A TLS session already agreed upon.") s.send("454 A TLS session already agreed upon.")
return return
} }
s.logger.Debug().Msg("Initiating TLS context.") s.logger.Debug().Msg("Initiating TLS context.")
// Start TLS connection handshake.
s.send("220 STARTTLS") s.send("220 STARTTLS")
// start tls connection handshake
tlsConn := tls.Server(s.conn, s.Server.tlsConfig) tlsConn := tls.Server(s.conn, s.Server.tlsConfig)
s.conn = tlsConn s.conn = tlsConn
s.text = textproto.NewConn(s.conn) s.text = textproto.NewConn(s.conn)
@@ -591,30 +592,28 @@ func (s *Session) readLine() (line string, err error) {
func (s *Session) parseCmd(line string) (cmd string, arg string, ok bool) { func (s *Session) parseCmd(line string) (cmd string, arg string, ok bool) {
line = strings.TrimRight(line, "\r\n") line = strings.TrimRight(line, "\r\n")
l := len(line)
// Find length of command or entire line.
hasArg := true
l := strings.IndexByte(line, ' ')
if l == -1 {
hasArg = false
l = len(line)
}
switch { switch {
case l == 0: case l == 0:
return "", "", true return "", "", true
case l < 4: case l < 4:
s.logger.Warn().Msgf("Command too short: %q", line) s.logger.Warn().Msgf("Command too short: %q", line)
return "", "", false return "", "", false
case l == 4 || l == 8:
return strings.ToUpper(line), "", true
case l == 5:
// Too long to be only command, too short to have args
s.logger.Warn().Msgf("Mangled command: %q", line)
return "", "", false
} }
// If we made it here, command is long enough to have args if hasArg {
if line[4] != ' ' { return strings.ToUpper(line[0:l]), strings.Trim(line[l+1:], " "), true
// There wasn't a space after the command?
s.logger.Warn().Msgf("Mangled command: %q", line)
return "", "", false
} }
// I'm not sure if we should trim the args or not, but we will for now return strings.ToUpper(line), "", true
return strings.ToUpper(line[0:4]), strings.Trim(line[5:], " "), true
} }
// parseArgs takes the arguments proceeding a command and files them // parseArgs takes the arguments proceeding a command and files them

View File

@@ -56,6 +56,9 @@ func TestGreetState(t *testing.T) {
if err := playSession(t, server, []scriptStep{{"helo 127.0.0.1", 250}}); err != nil { if err := playSession(t, server, []scriptStep{{"helo 127.0.0.1", 250}}); err != nil {
t.Error(err) t.Error(err)
} }
if err := playSession(t, server, []scriptStep{{"HELO ABC", 250}}); err != nil {
t.Error(err)
}
// Valid EHLOs // Valid EHLOs
if err := playSession(t, server, []scriptStep{{"EHLO mydomain", 250}}); err != nil { if err := playSession(t, server, []scriptStep{{"EHLO mydomain", 250}}); err != nil {
@@ -70,6 +73,9 @@ func TestGreetState(t *testing.T) {
if err := playSession(t, server, []scriptStep{{"ehlo 127.0.0.1", 250}}); err != nil { if err := playSession(t, server, []scriptStep{{"ehlo 127.0.0.1", 250}}); err != nil {
t.Error(err) t.Error(err)
} }
if err := playSession(t, server, []scriptStep{{"EHLO a", 250}}); err != nil {
t.Error(err)
}
if t.Failed() { if t.Failed() {
// Wait for handler to finish logging // Wait for handler to finish logging
@@ -199,6 +205,15 @@ func TestReadyState(t *testing.T) {
t.Error(err) t.Error(err)
} }
// Test Start TLS parsing.
script = []scriptStep{
{"HELO localhost", 250},
{"STARTTLS", 454}, // TLS unconfigured.
}
if err := playSession(t, server, script); err != nil {
t.Error(err)
}
if t.Failed() { if t.Failed() {
// Wait for handler to finish logging // Wait for handler to finish logging
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)