diff --git a/mailnews/local/src/nsPop3Protocol.cpp b/mailnews/local/src/nsPop3Protocol.cpp index 75e65cf0d48..68cad978f6b 100644 --- a/mailnews/local/src/nsPop3Protocol.cpp +++ b/mailnews/local/src/nsPop3Protocol.cpp @@ -833,7 +833,7 @@ nsresult nsPop3Protocol::LoadUrl(nsIURI* aURL, nsISupports * /* aConsumer */) } const char* uidl = PL_strcasestr(queryPart.get(), "uidl="); PR_FREEIF(m_pop3ConData->only_uidl); - + if (uidl) { uidl += 5; @@ -1074,7 +1074,7 @@ PRInt32 nsPop3Protocol::SendAuth() if(!m_pop3ConData->command_succeeded) return(Error(POP3_SERVER_ERROR)); - nsCAutoString command("AUTH"CRLF); + nsCAutoString command("AUTH" CRLF); m_pop3ConData->next_state_after_response = POP3_AUTH_RESPONSE; return SendData(m_url, command.get()); @@ -1118,35 +1118,25 @@ PRInt32 nsPop3Protocol::AuthResponse(nsIInputStream* inputStream, if (!PL_strcmp(line, ".")) { + m_pop3Server->SetPop3CapabilityFlags(m_pop3ConData->capability_flags); + // now that we've read all the AUTH responses, go for it m_pop3ConData->next_state = POP3_SEND_CAPA; m_pop3ConData->pause_for_read = PR_FALSE; /* don't pause */ } - else - if (!PL_strcasecmp (line, "CRAM-MD5")) + else if (!PL_strcasecmp (line, "CRAM-MD5")) { nsCOMPtr verifier = do_GetService(SIGNATURE_VERIFIER_CONTRACTID, &rv); // this checks if psm is installed... if (NS_SUCCEEDED(rv)) - { SetCapFlag(POP3_HAS_AUTH_CRAM_MD5); - m_pop3Server->SetPop3CapabilityFlags(m_pop3ConData->capability_flags); } - } - else - if (!PL_strcasecmp (line, "PLAIN")) - { + else if (!PL_strcasecmp (line, "PLAIN")) SetCapFlag(POP3_HAS_AUTH_PLAIN); - m_pop3Server->SetPop3CapabilityFlags(m_pop3ConData->capability_flags); - } - else - if (!PL_strcasecmp (line, "LOGIN")) - { + else if (!PL_strcasecmp (line, "LOGIN")) SetCapFlag(POP3_HAS_AUTH_LOGIN); - m_pop3Server->SetPop3CapabilityFlags(m_pop3ConData->capability_flags); - } - PR_Free(line); + PR_Free(line); return 0; } @@ -1159,6 +1149,11 @@ PRInt32 nsPop3Protocol::SendCapa() if(!m_pop3ConData->command_succeeded) return(Error(POP3_SERVER_ERROR)); + // for use after mechs disabled fallbacks when login failed + // should better live in AuthResponse(), but it would only + // be called the first time then + BackupAuthFlags(); + nsCAutoString command("CAPA" CRLF); m_pop3ConData->next_state_after_response = POP3_CAPA_RESPONSE; @@ -1219,6 +1214,8 @@ PRInt32 nsPop3Protocol::CapaResponse(nsIInputStream* inputStream, PRInt32 nsPop3Protocol::ProcessAuth() { + m_password_already_sent = PR_FALSE; + if(m_useSecAuth) { if (TestCapFlag(POP3_HAS_AUTH_CRAM_MD5)) @@ -1248,37 +1245,107 @@ PRInt32 nsPop3Protocol::ProcessAuth() return 0; } +void nsPop3Protocol::BackupAuthFlags() +{ + m_origAuthFlags = m_pop3ConData->capability_flags & + (POP3_HAS_AUTH_ANY | POP3_HAS_AUTH_ANY_SEC); +} + +void nsPop3Protocol::RestoreAuthFlags() +{ + m_pop3ConData->capability_flags |= m_origAuthFlags; +} + PRInt32 nsPop3Protocol::AuthFallback() { if (m_pop3ConData->command_succeeded) - m_pop3ConData->next_state = POP3_SEND_PASSWORD; + if(m_password_already_sent) + { + m_nsIPop3Sink->SetUserAuthenticated(PR_TRUE); + + m_pop3ConData->next_state = (m_pop3ConData->get_url) + ? POP3_SEND_GURL : POP3_SEND_STAT; + } + else + m_pop3ConData->next_state = POP3_SEND_PASSWORD; else { // response code received, - // login failed not because of wrong password + // login failed not because of wrong credential if(TestFlag(POP3_STOPLOGIN) || TestCapFlag(POP3_HAS_AUTH_RESP_CODE) && !TestFlag(POP3_AUTH_FAILURE)) - return(Error(POP3_USERNAME_FAILURE)); + return(Error((m_password_already_sent) + ? POP3_PASSWORD_FAILURE : POP3_USERNAME_FAILURE)); - // If one authentication failed, we're going to - // fall back on a less secure login method. - if (TestCapFlag(POP3_HAS_AUTH_CRAM_MD5)) - // if CRAM-MD5 enabled, disable it - ClearCapFlag(POP3_HAS_AUTH_CRAM_MD5); + if (m_useSecAuth) + { + // If one authentication failed, we're going to + // fall back on a less secure login method. + if (TestCapFlag(POP3_HAS_AUTH_CRAM_MD5)) + // if CRAM-MD5 enabled, disable it + ClearCapFlag(POP3_HAS_AUTH_CRAM_MD5); + else if (TestCapFlag(POP3_HAS_AUTH_APOP)) + { + // if APOP enabled, disable it + ClearCapFlag(POP3_HAS_AUTH_APOP); + // unsure because APOP failed and we can't determine why + Error(CANNOT_PROCESS_APOP_AUTH); + } + } else - if (TestCapFlag(POP3_HAS_AUTH_APOP)) - // if APOP enabled, disable it - ClearCapFlag(POP3_HAS_AUTH_APOP); - else - if (TestCapFlag(POP3_HAS_AUTH_PLAIN)) - // if PLAIN enabled, disable it - ClearCapFlag(POP3_HAS_AUTH_PLAIN); - else - if(TestCapFlag(POP3_HAS_AUTH_LOGIN | POP3_HAS_AUTH_USER)) - // if LOGIN or USER enabled, - // it was the username which was wrong - - // no fallback but return error - return(Error(POP3_USERNAME_FAILURE)); + { + if (TestCapFlag(POP3_HAS_AUTH_PLAIN)) + // if PLAIN enabled, disable it + ClearCapFlag(POP3_HAS_AUTH_PLAIN); + else if(TestCapFlag(POP3_HAS_AUTH_LOGIN)) + // if LOGIN enabled, disable it + ClearCapFlag(POP3_HAS_AUTH_LOGIN); + else if(TestCapFlag(POP3_HAS_AUTH_USER)) + { + if(m_password_already_sent) + // if USER enabled, disable it + ClearCapFlag(POP3_HAS_AUTH_USER); + else + // if USER enabled, + // it was the username which was wrong - + // no fallback but return error + return(Error(POP3_USERNAME_FAILURE)); + } + } + + // Only forget the password if we've no mechanism left. + if (m_useSecAuth && !TestCapFlag(POP3_HAS_AUTH_ANY_SEC) || + !m_useSecAuth && !TestCapFlag(POP3_HAS_AUTH_ANY)) + { + // Let's restore the original auth flags from SendEhloResponse so we can + // try them again with new password and username + RestoreAuthFlags(); + m_pop3Server->SetPop3CapabilityFlags(m_pop3ConData->capability_flags); + + Error(POP3_PASSWORD_FAILURE); + /* The password failed. + + Sever the connection and go back to the `read password' state, + which, upon success, will re-open the connection. Set a flag + which causes the prompt to be different that time (to indicate + that the old password was bogus.) + + But if we're just checking for new mail (biff) then don't bother + prompting the user for a password: just fail silently. + */ + + SetFlag(POP3_PASSWORD_FAILED); + m_pop3ConData->logonFailureCount++; + + // libmsg event sink + if (m_nsIPop3Sink) + { + m_nsIPop3Sink->SetUserAuthenticated(PR_FALSE); + m_nsIPop3Sink->SetMailAccountURL(NULL); + } + + return 0; + } m_pop3Server->SetPop3CapabilityFlags(m_pop3ConData->capability_flags); @@ -1346,8 +1413,7 @@ PRInt32 nsPop3Protocol::SendUsername() { if (TestCapFlag(POP3_HAS_AUTH_PLAIN)) cmd = "AUTH PLAIN"; - else - if (TestCapFlag(POP3_HAS_AUTH_LOGIN)) + else if (TestCapFlag(POP3_HAS_AUTH_LOGIN)) { char *base64Str = PL_Base64Encode(m_username.get(), m_username.Length(), nsnull); @@ -1422,7 +1488,7 @@ PRInt32 nsPop3Protocol::SendPassword() } if (NS_FAILED(rv)) - ClearFlag(POP3_HAS_AUTH_CRAM_MD5); + cmd = "*"; } else if (TestCapFlag(POP3_HAS_AUTH_APOP)) @@ -1448,7 +1514,7 @@ PRInt32 nsPop3Protocol::SendPassword() } if (NS_FAILED(rv)) - ClearFlag(POP3_HAS_AUTH_APOP); + cmd = "*"; } } else @@ -1480,70 +1546,24 @@ PRInt32 nsPop3Protocol::SendPassword() else { cmd = "PASS "; - cmd += (const char *) password; + cmd += password; } } cmd += CRLF; m_pop3Server->SetPop3CapabilityFlags(m_pop3ConData->capability_flags); - m_pop3ConData->next_state_after_response = (m_pop3ConData->get_url) - ? POP3_SEND_GURL : POP3_SEND_STAT; + m_pop3ConData->next_state_after_response = POP3_AUTH_FALLBACK; m_pop3ConData->pause_for_read = PR_TRUE; + m_password_already_sent = PR_TRUE; + return SendData(m_url, cmd.get(), PR_TRUE); } PRInt32 nsPop3Protocol::SendStatOrGurl(PRBool sendStat) { - /* check password response */ - if(!m_pop3ConData->command_succeeded) - { - // response code received, - // login failed not because of wrong password - if(TestFlag(POP3_STOPLOGIN) || - TestCapFlag(POP3_HAS_AUTH_RESP_CODE) && !TestFlag(POP3_AUTH_FAILURE)) - return(Error(POP3_PASSWORD_FAILURE)); - - if(!TestCapFlag(POP3_HAS_AUTH_CRAM_MD5) && - TestCapFlag(POP3_HAS_AUTH_APOP)) - // unsure because APOP failed and we can't determine why - Error(CANNOT_PROCESS_APOP_AUTH); - else - Error(POP3_PASSWORD_FAILURE); - /* The password failed. - - Sever the connection and go back to the `read password' state, - which, upon success, will re-open the connection. Set a flag - which causes the prompt to be different that time (to indicate - that the old password was bogus.) - - But if we're just checking for new mail (biff) then don't bother - prompting the user for a password: just fail silently. - */ - - SetFlag(POP3_PASSWORD_FAILED); - m_pop3ConData->logonFailureCount++; - - // libmsg event sink - if (m_nsIPop3Sink) - { - m_nsIPop3Sink->SetUserAuthenticated(PR_FALSE); - m_nsIPop3Sink->SetMailAccountURL(NULL); - } - - /* clear the bogus password in case - * we need to sync with auth smtp password - */ - return 0; - } - else - { - m_nsIPop3Sink->SetUserAuthenticated(PR_TRUE); - } - - nsCAutoString cmd; if (sendStat) { diff --git a/mailnews/local/src/nsPop3Protocol.h b/mailnews/local/src/nsPop3Protocol.h index f39fe8f91fe..558bc62fc37 100644 --- a/mailnews/local/src/nsPop3Protocol.h +++ b/mailnews/local/src/nsPop3Protocol.h @@ -108,6 +108,9 @@ enum Pop3CapabilityEnum { POP3_HAS_AUTH_RESP_CODE = 0x00020000 }; +#define POP3_HAS_AUTH_ANY 0x00009002 +#define POP3_HAS_AUTH_ANY_SEC 0x00006000 + enum Pop3StatesEnum { POP3_READ_PASSWORD, // 0 // @@ -164,9 +167,9 @@ enum Pop3StatesEnum { }; -#define KEEP 'k' /* If we want to keep this item on server. */ -#define DELETE_CHAR 'd' /* If we want to delete this item. */ -#define TOO_BIG 'b' /* item left on server because it was too big */ +#define KEEP 'k' /* If we want to keep this item on server. */ +#define DELETE_CHAR 'd' /* If we want to delete this item. */ +#define TOO_BIG 'b' /* item left on server because it was too big */ typedef struct Pop3UidlEntry { /* information about this message */ char* uidl; @@ -238,9 +241,9 @@ typedef struct _Pop3ConData { /* the current message that we are retrieving with the TOP command */ PRInt32 current_msg_to_top; - + /* we will download this many in - POP3_GET_MSG */ + POP3_GET_MSG */ PRInt32 number_of_messages_not_seen_before; /* reached when we have TOPped all of the new messages */ @@ -284,7 +287,7 @@ public: NS_IMETHOD OnStopRequest(nsIRequest *request, nsISupports * aContext, nsresult aStatus); NS_IMETHOD Cancel(nsresult status); - // for nsMsgLineBuffer + // for nsMsgLineBuffer virtual PRInt32 HandleLine(char *line, PRUint32 line_length); private: @@ -309,25 +312,30 @@ private: PRInt32 m_totalBytesReceived; // total # bytes received for the connection virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream, - PRUint32 sourceOffset, PRUint32 length); + PRUint32 sourceOffset, PRUint32 length); virtual nsresult CloseSocket(); virtual PRInt32 SendData(nsIURI * aURL, const char * dataBuffer, PRBool aSuppressLogging = PR_FALSE); nsCOMPtr m_url; nsCOMPtr m_nsIPop3Sink; nsCOMPtr m_pop3Server; - + nsMsgLineStreamBuffer * m_lineStreamBuffer; // used to efficiently extract lines from the incoming data stream Pop3ConData* m_pop3ConData; void FreeMsgInfo(); void Abort(); PRBool m_useSecAuth; + PRBool m_password_already_sent; void SetCapFlag(PRUint32 flag); void ClearCapFlag(PRUint32 flag); PRBool TestCapFlag(PRUint32 flag); + void BackupAuthFlags(); + void RestoreAuthFlags(); + PRInt32 m_origAuthFlags; + ////////////////////////////////////////////////////////////////////////////////////////// // Begin Pop3 protocol state handlers //////////////////////////////////////////////////////////////////////////////////////////