Bug 1629669 - Rework nsImapProtocol::GetPassword to avoid deadlock, and better protect m_passwordObtained/m_passwordStatus. r=benc,mkmelin

Differential Revision: https://phabricator.services.mozilla.com/D154019

--HG--
extra : amend_source : e2bd2d6e89ca13e20a20e66567fc161ed060b4ce
This commit is contained in:
Kai Engert 2022-08-10 20:28:41 +10:00
Родитель eaf331b7a4
Коммит 9a93867602
1 изменённых файлов: 48 добавлений и 15 удалений

Просмотреть файл

@ -8355,27 +8355,54 @@ nsresult nsImapProtocol::GetPassword(nsString& password,
NS_ENSURE_TRUE(m_server, NS_ERROR_NULL_POINTER); NS_ENSURE_TRUE(m_server, NS_ERROR_NULL_POINTER);
nsresult rv; nsresult rv;
password = nsString();
// Get the password already stored in mem // Get the password already stored in mem
rv = m_imapServerSink->GetServerPassword(password); rv = m_imapServerSink->GetServerPassword(password);
if (NS_FAILED(rv) || password.IsEmpty()) { if (NS_FAILED(rv) || password.IsEmpty()) {
AutoProxyReleaseMsgWindow msgWindow; AutoProxyReleaseMsgWindow msgWindow;
GetMsgWindow(getter_AddRefs(msgWindow)); GetMsgWindow(getter_AddRefs(msgWindow));
NS_ENSURE_TRUE(msgWindow, NS_ERROR_NOT_AVAILABLE); // biff case NS_ENSURE_TRUE(msgWindow, NS_ERROR_NOT_AVAILABLE); // biff case
m_passwordStatus = NS_OK;
m_passwordObtained = false;
// Get the password from pw manager (harddisk) or user (dialog) // Get the password from pw manager (harddisk) or user (dialog)
m_passwordObtained = false;
rv = m_imapServerSink->AsyncGetPassword(this, newPasswordRequested, rv = m_imapServerSink->AsyncGetPassword(this, newPasswordRequested,
password); password);
if (password.IsEmpty()) {
PRIntervalTime sleepTime = kImapSleepTime; if (NS_SUCCEEDED(rv)) {
m_passwordStatus = NS_OK; while (password.IsEmpty()) {
ReentrantMonitorAutoEnter mon(m_passwordReadyMonitor); bool shuttingDown = false;
while (!m_passwordObtained && !NS_FAILED(m_passwordStatus) && (void)m_imapServerSink->GetServerShuttingDown(&shuttingDown);
m_passwordStatus != NS_MSG_PASSWORD_PROMPT_CANCELLED && if (shuttingDown) {
!DeathSignalReceived()) // Note: If we fix bug 1783573 this check could be ditched.
mon.Wait(sleepTime); rv = NS_ERROR_FAILURE;
rv = m_passwordStatus; break;
password = m_password; }
ReentrantMonitorAutoEnter mon(m_passwordReadyMonitor);
if (!m_passwordObtained && !NS_FAILED(m_passwordStatus) &&
m_passwordStatus != NS_MSG_PASSWORD_PROMPT_CANCELLED &&
!DeathSignalReceived()) {
mon.Wait(PR_MillisecondsToInterval(1000));
}
if (NS_FAILED(m_passwordStatus) ||
m_passwordStatus == NS_MSG_PASSWORD_PROMPT_CANCELLED) {
rv = m_passwordStatus;
break;
}
if (DeathSignalReceived()) {
rv = NS_ERROR_FAILURE;
break;
}
if (m_passwordObtained) {
rv = m_passwordStatus;
password = m_password;
break;
}
}
} }
} }
if (!password.IsEmpty()) m_lastPasswordSent = password; if (!password.IsEmpty()) m_lastPasswordSent = password;
@ -8401,13 +8428,15 @@ nsImapProtocol::OnPromptStart(bool* aResult) {
GetMsgWindow(getter_AddRefs(msgWindow)); GetMsgWindow(getter_AddRefs(msgWindow));
nsString password = m_lastPasswordSent; nsString password = m_lastPasswordSent;
rv = imapServer->PromptPassword(msgWindow, password); rv = imapServer->PromptPassword(msgWindow, password);
ReentrantMonitorAutoEnter passwordMon(m_passwordReadyMonitor);
m_password = password; m_password = password;
m_passwordStatus = rv; m_passwordStatus = rv;
if (!m_password.IsEmpty()) *aResult = true; if (!m_password.IsEmpty()) *aResult = true;
// Notify the imap thread that we have a password. // Notify the imap thread that we have a password.
m_passwordObtained = true; m_passwordObtained = true;
ReentrantMonitorAutoEnter passwordMon(m_passwordReadyMonitor);
passwordMon.Notify(); passwordMon.Notify();
return rv; return rv;
} }
@ -8417,10 +8446,14 @@ nsImapProtocol::OnPromptAuthAvailable() {
nsresult rv; nsresult rv;
nsCOMPtr<nsIMsgIncomingServer> imapServer = do_QueryReferent(m_server, &rv); nsCOMPtr<nsIMsgIncomingServer> imapServer = do_QueryReferent(m_server, &rv);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
m_passwordStatus = imapServer->GetPassword(m_password);
nsresult status = imapServer->GetPassword(m_password);
ReentrantMonitorAutoEnter passwordMon(m_passwordReadyMonitor);
m_passwordStatus = status;
// Notify the imap thread that we have a password. // Notify the imap thread that we have a password.
m_passwordObtained = true; m_passwordObtained = true;
ReentrantMonitorAutoEnter passwordMon(m_passwordReadyMonitor);
passwordMon.Notify(); passwordMon.Notify();
return m_passwordStatus; return m_passwordStatus;
} }
@ -8428,8 +8461,8 @@ nsImapProtocol::OnPromptAuthAvailable() {
NS_IMETHODIMP NS_IMETHODIMP
nsImapProtocol::OnPromptCanceled() { nsImapProtocol::OnPromptCanceled() {
// A prompt was cancelled, so notify the imap thread. // A prompt was cancelled, so notify the imap thread.
m_passwordStatus = NS_MSG_PASSWORD_PROMPT_CANCELLED;
ReentrantMonitorAutoEnter passwordMon(m_passwordReadyMonitor); ReentrantMonitorAutoEnter passwordMon(m_passwordReadyMonitor);
m_passwordStatus = NS_MSG_PASSWORD_PROMPT_CANCELLED;
passwordMon.Notify(); passwordMon.Notify();
return NS_OK; return NS_OK;
} }