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:
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user