diff --git a/res/values/strings.xml b/res/values/strings.xml index 8e592c38a..9de519bd3 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -385,7 +385,6 @@ Please submit bug reports, contribute new features and ask questions at IMAP Exchange (WebDAV) - Automatic Normal password Encrypted password diff --git a/src/com/fsck/k9/mail/AuthType.java b/src/com/fsck/k9/mail/AuthType.java index 9c2425e3c..c77371661 100644 --- a/src/com/fsck/k9/mail/AuthType.java +++ b/src/com/fsck/k9/mail/AuthType.java @@ -6,13 +6,27 @@ import com.fsck.k9.R; public enum AuthType { /* - * The names of these auth. types are saved as strings when settings are - * exported, and are also saved as part of the Server URI saved in the - * account settings. + * The names of these authentication types are saved as strings when + * settings are exported and are also saved as part of the Server URI stored + * in the account settings. + * + * PLAIN and CRAM_MD5 originally referred to specific SASL authentication + * mechanisms. Their meaning has since been broadened to mean authentication + * with unencrypted and encrypted passwords, respectively. Nonetheless, + * their original names have been retained for backward compatibility with + * user settings. */ - AUTOMATIC(R.string.account_setup_auth_type_automatic), PLAIN(R.string.account_setup_auth_type_normal_password), CRAM_MD5(R.string.account_setup_auth_type_encrypted_password), + + /* + * The following are obsolete authentication settings that were used with + * SMTP. They are no longer presented to the user as options, but they may + * still exist in a user's settings from a previous version or may be found + * when importing settings. + */ + AUTOMATIC(0), + LOGIN(0); private final int mResourceId; diff --git a/src/com/fsck/k9/mail/transport/SmtpTransport.java b/src/com/fsck/k9/mail/transport/SmtpTransport.java index a52873595..4c5101ff0 100644 --- a/src/com/fsck/k9/mail/transport/SmtpTransport.java +++ b/src/com/fsck/k9/mail/transport/SmtpTransport.java @@ -49,7 +49,7 @@ public class SmtpTransport extends Transport { String host; int port; ConnectionSecurity connectionSecurity; - AuthType authType = AuthType.AUTOMATIC; + AuthType authType = AuthType.PLAIN; String username = null; String password = null; @@ -197,6 +197,7 @@ public class SmtpTransport extends Transport { @Override public void open() throws MessagingException { try { + boolean secureConnection = false; InetAddress[] addresses = InetAddress.getAllByName(mHost); for (int i = 0; i < addresses.length; i++) { try { @@ -211,6 +212,7 @@ public class SmtpTransport extends Transport { new SecureRandom()); mSocket = TrustedSocketFactory.createSocket(sslContext); mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); + secureConnection = true; } else { mSocket = new Socket(); mSocket.connect(socketAddress, SOCKET_CONNECT_TIMEOUT); @@ -278,17 +280,12 @@ public class SmtpTransport extends Transport { * Exim. */ extensions = sendHello(localHost); + secureConnection = true; } else if (mConnectionSecurity == ConnectionSecurity.STARTTLS_REQUIRED) { throw new MessagingException("TLS not supported but required"); } } - boolean useAuthPlain = AuthType.PLAIN.equals(mAuthType) || AuthType.LOGIN.equals(mAuthType); - boolean useAuthCramMD5 = AuthType.CRAM_MD5.equals(mAuthType); - - // Automatically choose best authentication method if none was explicitly selected - boolean useAutomaticAuth = !(useAuthPlain || useAuthCramMD5); - boolean authLoginSupported = false; boolean authPlainSupported = false; boolean authCramMD5Supported = false; @@ -310,37 +307,69 @@ public class SmtpTransport extends Transport { if (mUsername != null && mUsername.length() > 0 && mPassword != null && mPassword.length() > 0) { - if (useAuthCramMD5 || (useAutomaticAuth && authCramMD5Supported)) { - if (!authCramMD5Supported && K9.DEBUG && K9.DEBUG_PROTOCOL_SMTP) { - Log.d(K9.LOG_TAG, "Using CRAM_MD5 as authentication method although the " + - "server didn't advertise support for it in EHLO response."); - } - saslAuthCramMD5(mUsername, mPassword); - } else if (useAuthPlain || (useAutomaticAuth && authPlainSupported)) { - if (!authPlainSupported && K9.DEBUG && K9.DEBUG_PROTOCOL_SMTP) { - Log.d(K9.LOG_TAG, "Using PLAIN as authentication method although the " + - "server didn't advertise support for it in EHLO response."); - } - try { + + switch (mAuthType) { + + /* + * LOGIN is an obsolete option which is unavailable to users, + * but it still may exist in a user's settings from a previous + * version, or it may have been imported. + */ + case LOGIN: + case PLAIN: + // try saslAuthPlain first, because it supports UTF-8 explicitly + if (authPlainSupported) { saslAuthPlain(mUsername, mPassword); - } catch (MessagingException ex) { - // PLAIN is a special case. Historically, PLAIN has represented both PLAIN and LOGIN; only the - // protocol being advertised by the server would be used, with PLAIN taking precedence. Instead - // of using only the requested protocol, we'll try PLAIN and then try LOGIN. - if (useAuthPlain && authLoginSupported) { - if (K9.DEBUG && K9.DEBUG_PROTOCOL_SMTP) { - Log.d(K9.LOG_TAG, "Using legacy PLAIN authentication behavior and trying LOGIN."); - } + } else if (authLoginSupported) { + saslAuthLogin(mUsername, mPassword); + } else { + throw new MessagingException("Authentication methods SASL PLAIN and LOGIN are unavailable."); + } + break; + + case CRAM_MD5: + if (authCramMD5Supported) { + saslAuthCramMD5(mUsername, mPassword); + } else { + throw new MessagingException("Authentication method CRAM-MD5 is unavailable."); + } + break; + + /* + * AUTOMATIC is an obsolete option which is unavailable to users, + * but it still may exist in a user's settings from a previous + * version, or it may have been imported. + */ + case AUTOMATIC: + if (secureConnection) { + // try saslAuthPlain first, because it supports UTF-8 explicitly + if (authPlainSupported) { + saslAuthPlain(mUsername, mPassword); + } else if (authLoginSupported) { saslAuthLogin(mUsername, mPassword); + } else if (authCramMD5Supported) { + saslAuthCramMD5(mUsername, mPassword); } else { - // If it was auto detected and failed, continue throwing the exception back up. - throw ex; + throw new MessagingException("No supported authentication methods available."); + } + } else { + if (authCramMD5Supported) { + saslAuthCramMD5(mUsername, mPassword); + } else { + /* + * We refuse to insecurely transmit the password + * using the obsolete AUTOMATIC setting because of + * the potential for a MITM attack. Affected users + * must choose a different setting. + */ + throw new MessagingException( + "Update your outgoing server authentication setting. AUTOMATIC auth. is unavailable."); } } - } else if (useAutomaticAuth && authLoginSupported) { - saslAuthLogin(mUsername, mPassword); - } else { - throw new MessagingException("No valid authentication mechanism found."); + break; + + default: + throw new MessagingException("Unhandled authentication method found in the server settings (bug)."); } } } catch (SSLException e) {