Commit message: Ensure IMAP connection is closed after a connection error.

During connection, if the server provided an illegal initial response,
Mutt "bailed", but did not actually close the connection.  The calling
code unfortunately relied on the connection status to decide to
continue with authentication, instead of checking the "bail" return
value.

This could result in authentication credentials being sent over an
unencrypted connection, without $ssl_force_tls being consulted.

Fix this by strictly closing the connection on any invalid response
during connection.  The fix is intentionally small, to ease
backporting.  A better fix would include removing the 'err_close_conn'
label, and perhaps adding return value checking in the caller (though
this change obviates the need for that).

This addresses CVE-2020-28896.  Thanks to Gabriel Salles-Loustau for
reporting the problem, and providing test cases to reproduce.
CVE: CVE-2020-28896
CWE: CWE-287
Vulnerability description: Mutt before 2.0.2 and NeoMutt before 2020-11-20 did not ensure that $ssl_force_tls was processed if an IMAP server's initial server response was invalid. The connection was not properly closed, and the code could continue attempting to authenticate. This could result in authentication credentials being exposed on an unencrypted connection, or to a machine-in-the-middle.

Project: mutt

int imap_open_connection (IMAP_DATA* idata)
{
  if (mutt_socket_open (idata->conn) < 0)
    return -1;

  idata->state = IMAP_CONNECTED;

  if (imap_cmd_step (idata) != IMAP_CMD_OK)
  {
    imap_close_connection (idata);
    return -1;
  }

  if (ascii_strncasecmp ("* OK", idata->buf, 4) == 0)
  {
    if (ascii_strncasecmp ("* OK [CAPABILITY", idata->buf, 16)
        && imap_check_capabilities (idata))
      goto bail;
#if defined(USE_SSL)
    /* Attempt STARTTLS if available and desired. */
    if (!idata->conn->ssf && (option(OPTSSLFORCETLS) ||
                              mutt_bit_isset (idata->capabilities, STARTTLS)))
    {
      int rc;

      if (option(OPTSSLFORCETLS))
        rc = MUTT_YES;
      else if ((rc = query_quadoption (OPT_SSLSTARTTLS,
                                       _("Secure connection with TLS?"))) == -1)
	goto err_close_conn;
      if (rc == MUTT_YES)
      {
	if ((rc = imap_exec (idata, "STARTTLS", IMAP_CMD_FAIL_OK)) == -1)
	  goto bail;
	if (rc != -2)
	{
	  if (mutt_ssl_starttls (idata->conn))
	  {
	    mutt_error (_("Could not negotiate TLS connection"));
	    mutt_sleep (1);
	    goto err_close_conn;
	  }
	  else
	  {
	    /* RFC 2595 demands we recheck CAPABILITY after TLS completes. */
	    if (imap_exec (idata, "CAPABILITY", 0))
	      goto bail;
	  }
	}
      }
    }

    if (option(OPTSSLFORCETLS) && ! idata->conn->ssf)
    {
      mutt_error _("Encrypted connection unavailable");
      mutt_sleep (1);
      goto err_close_conn;
    }
#endif
  }
  else if (ascii_strncasecmp ("* PREAUTH", idata->buf, 9) == 0)
  {
#if defined(USE_SSL)
    /* Unless using a secure $tunnel, an unencrypted PREAUTH response
     * may be a MITM attack.  The only way to stop "STARTTLS" MITM
     * attacks is via $ssl_force_tls: an attacker can easily spoof
     * "* OK" and strip the STARTTLS capability.  So consult
     * $ssl_force_tls, not $ssl_starttls, to decide whether to
     * abort. Note that if using $tunnel and $tunnel_is_secure,
     * conn->ssf will be set to 1. */
    if (!idata->conn->ssf && option(OPTSSLFORCETLS))
    {
      mutt_error _("Encrypted connection unavailable");
      mutt_sleep (1);
      goto err_close_conn;
    }
#endif

    idata->state = IMAP_AUTHENTICATED;
    if (imap_check_capabilities (idata) != 0)
      goto bail;
    FREE (&idata->capstr);
  }
  else
  {
    imap_error ("imap_open_connection()", idata->buf);
    goto bail;
  }

  return 0;

#if defined(USE_SSL)
err_close_conn:
  imap_close_connection (idata);
#endif
bail:
  FREE (&idata->capstr);
  return -1;
}