Skip to content

Commit

Permalink
Fix: Enhance TLS handling and simplify response checks
Browse files Browse the repository at this point in the history
Added TLS minimum version enforcement to improve security. Refactored the sieve response parsing to centralize logic and streamline error handling, improving maintainability and reducing redundancy.

Signed-off-by: Christian Roessner <[email protected]>
  • Loading branch information
Christian Roessner committed Dec 6, 2024
1 parent 94880b3 commit 143b813
Showing 1 changed file with 27 additions and 21 deletions.
48 changes: 27 additions & 21 deletions server/monitoring/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ func checkBackendConnection(server *config.BackendServer) error {
tlsConfig := &tls.Config{
InsecureSkipVerify: server.TLSSkipVerify,
ServerName: server.Host,
MinVersion: tls.VersionTLS12,
}

tlsConn := tls.Client(conn, tlsConfig)
Expand Down Expand Up @@ -336,46 +337,41 @@ func checkSieve(conn net.Conn, hostname, username, password string, tlsSkipVerif

defer fmt.Fprintf(conn, "LOGOUT\r\n")

// Read server greeting
greeting, err := tp.ReadLine()
if err != nil {
// Wait for initial greeting
if response, err := isOkResponseSieve(tp); err != nil {
return err
}

if !isOkResponseSieve(greeting) {
} else if response != "OK" {
//goland:noinspection GoErrorStringFormat
return fmt.Errorf("Sieve greeting failed: %s", greeting)
return fmt.Errorf("Sieve greeting failed: %s", response)
}

// Send STARTTLS command
fmt.Fprintf(conn, "STARTTLS\r\n")

// Read STARTTLS response
response, err := tp.ReadLine()
if err != nil {
if response, err := isOkResponseSieve(tp); err != nil {
return err
}

if !isOkResponseSieve(response) {
} else if response != "OK" {
return fmt.Errorf("STARTTLS command failed: %s", response)
}

// Upgrade to TLS connection
tlsConfig := &tls.Config{
InsecureSkipVerify: tlsSkipVerify,
ServerName: hostname,
MinVersion: tls.VersionTLS12,
}

tlsConn := tls.Client(conn, tlsConfig)
if err = tlsConn.Handshake(); err != nil {
if err := tlsConn.Handshake(); err != nil {
return fmt.Errorf("TLS handshake failed: %s", err)
}

if username == "" || password == "" {
return nil
}

if !isTLSConnection(conn) {
if !isTLSConnection(tlsConn) {
return errors.ErrMissingTLS
}

Expand All @@ -388,12 +384,9 @@ func checkSieve(conn net.Conn, hostname, username, password string, tlsSkipVerif
authString := fmt.Sprintf("\x00%s\x00%s", username, password)
fmt.Fprintf(conn, "AUTHENTICATE \"PLAIN\" {%d+}\r\n%s", len(authString), authString)

response, err = tp.ReadLine()
if err != nil {
if response, err := isOkResponseSieve(tp); err != nil {
return err
}

if !isOkResponseSieve(response) {
} else if response != "OK" {
//goland:noinspection GoErrorStringFormat
return fmt.Errorf("Sieve AUTHENTICATE command failed: %s", response)
}
Expand All @@ -402,8 +395,21 @@ func checkSieve(conn net.Conn, hostname, username, password string, tlsSkipVerif
}

// isOkResponseSieve checks if the Sieve server response starts with "OK", indicating a successful operation.
func isOkResponseSieve(response string) bool {
return response[:2] == "OK"
func isOkResponseSieve(tp *textproto.Reader) (response string, err error) {
for {
response, err = tp.ReadLine()
if err != nil {
return "", err
}

if response[:2] == "OK" {
return response[:2], nil
}

if response[:2] == "NO" {
return response, nil
}
}
}

// checkHTTP performs an HTTP GET request with Basic Authentication using a given username and password.
Expand Down

0 comments on commit 143b813

Please sign in to comment.