diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp index 8c1b5ea9a8e3..82ca0567a337 100644 --- a/security/manager/ssl/src/nsNSSComponent.cpp +++ b/security/manager/ssl/src/nsNSSComponent.cpp @@ -770,6 +770,7 @@ nsNSSComponent::InstallLoadableRoots() if (RootsModule) { // found a module, no need to try other directories + SECMOD_DestroyModule(RootsModule); break; } } @@ -1863,69 +1864,34 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData) { if (nsCRT::strcmp(aTopic, PROFILE_APPROVE_CHANGE_TOPIC) == 0) { - if (mShutdownObjectList->isUIActive()) { - ShowAlert(ai_crypto_ui_active); - nsCOMPtr status = do_QueryInterface(aSubject); - if (status) { - status->VetoChange(); - } - } + DoProfileApproveChange(aSubject); } else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_TEARDOWN_TOPIC) == 0) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("in PSM code, receiving change-teardown\n")); - - PRBool callVeto = PR_FALSE; - - if (!mShutdownObjectList->ifPossibleDisallowUI()) { - callVeto = PR_TRUE; - ShowAlert(ai_crypto_ui_active); - } - else if (mShutdownObjectList->areSSLSocketsActive()) { - callVeto = PR_TRUE; - ShowAlert(ai_sockets_still_active); - } - - if (callVeto) { - nsCOMPtr status = do_QueryInterface(aSubject); - if (status) { - status->VetoChange(); - } - } + DoProfileChangeTeardown(aSubject); } else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_TEARDOWN_VETO_TOPIC) == 0) { mShutdownObjectList->allowUI(); } else if (nsCRT::strcmp(aTopic, PROFILE_BEFORE_CHANGE_TOPIC) == 0) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving profile change topic\n")); - NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity"); - - PRBool needsCleanup = PR_TRUE; - - { - nsAutoLock lock(mutex); - - if (!mNSSInitialized) { - // Make sure we don't try to cleanup if we have already done so. - // This makes sure we behave safely, in case we are notified - // multiple times. - needsCleanup = PR_FALSE; - } - } - - StopCRLUpdateTimer(); - - if (needsCleanup) { - if (NS_FAILED(ShutdownNSS())) { - nsCOMPtr status = do_QueryInterface(aSubject); - if (status) { - status->ChangeFailed(); - } - } - } - mShutdownObjectList->allowUI(); - + DoProfileBeforeChange(aSubject); } else if (nsCRT::strcmp(aTopic, PROFILE_AFTER_CHANGE_TOPIC) == 0) { + if (someData && NS_LITERAL_STRING("startup").Equals(someData)) { + // The application is initializing against a known profile directory for + // the first time during process execution. + // However, earlier code execution might have already triggered NSS init. + // We must ensure that NSS gets shut down prior to any attempt to init + // it again. We use the same cleanup functionality used when switching + // profiles. The order of function calls must correspond to the order + // of notifications sent by Profile Manager (nsProfile). + DoProfileApproveChange(aSubject); + DoProfileChangeNetTeardown(); + DoProfileChangeTeardown(aSubject); + DoProfileBeforeChange(aSubject); + DoProfileChangeNetRestore(); + } PRBool needsInit = PR_TRUE; @@ -2021,23 +1987,11 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic, } else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_TEARDOWN_TOPIC) == 0) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network teardown topic\n")); - if (mSSLThread) - mSSLThread->requestExit(); - if (mCertVerificationThread) - mCertVerificationThread->requestExit(); - mIsNetworkDown = PR_TRUE; + DoProfileChangeNetTeardown(); } else if (nsCRT::strcmp(aTopic, PROFILE_CHANGE_NET_RESTORE_TOPIC) == 0) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("receiving network restore topic\n")); - delete mSSLThread; - mSSLThread = new nsSSLThread(); - if (mSSLThread) - mSSLThread->startThread(); - delete mCertVerificationThread; - mCertVerificationThread = new nsCertVerificationThread(); - if (mCertVerificationThread) - mCertVerificationThread->startThread(); - mIsNetworkDown = PR_FALSE; + DoProfileChangeNetRestore(); } return NS_OK; @@ -2232,6 +2186,95 @@ nsNSSComponent::GetErrorMessage(nsresult aXPCOMErrorCode, nsAString &aErrorMessa return rv; } +void +nsNSSComponent::DoProfileApproveChange(nsISupports* aSubject) +{ + if (mShutdownObjectList->isUIActive()) { + ShowAlert(ai_crypto_ui_active); + nsCOMPtr status = do_QueryInterface(aSubject); + if (status) { + status->VetoChange(); + } + } +} + +void +nsNSSComponent::DoProfileChangeNetTeardown() +{ + if (mSSLThread) + mSSLThread->requestExit(); + if (mCertVerificationThread) + mCertVerificationThread->requestExit(); + mIsNetworkDown = PR_TRUE; +} + +void +nsNSSComponent::DoProfileChangeTeardown(nsISupports* aSubject) +{ + PRBool callVeto = PR_FALSE; + + if (!mShutdownObjectList->ifPossibleDisallowUI()) { + callVeto = PR_TRUE; + ShowAlert(ai_crypto_ui_active); + } + else if (mShutdownObjectList->areSSLSocketsActive()) { + callVeto = PR_TRUE; + ShowAlert(ai_sockets_still_active); + } + + if (callVeto) { + nsCOMPtr status = do_QueryInterface(aSubject); + if (status) { + status->VetoChange(); + } + } +} + +void +nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject) +{ + NS_ASSERTION(mIsNetworkDown, "nsNSSComponent relies on profile manager to wait for synchronous shutdown of all network activity"); + + PRBool needsCleanup = PR_TRUE; + + { + nsAutoLock lock(mutex); + + if (!mNSSInitialized) { + // Make sure we don't try to cleanup if we have already done so. + // This makes sure we behave safely, in case we are notified + // multiple times. + needsCleanup = PR_FALSE; + } + } + + StopCRLUpdateTimer(); + + if (needsCleanup) { + if (NS_FAILED(ShutdownNSS())) { + nsCOMPtr status = do_QueryInterface(aSubject); + if (status) { + status->ChangeFailed(); + } + } + } + mShutdownObjectList->allowUI(); +} + +void +nsNSSComponent::DoProfileChangeNetRestore() +{ + delete mSSLThread; + mSSLThread = new nsSSLThread(); + if (mSSLThread) + mSSLThread->startThread(); + delete mCertVerificationThread; + mCertVerificationThread = new nsCertVerificationThread(); + if (mCertVerificationThread) + mCertVerificationThread->startThread(); + mIsNetworkDown = PR_FALSE; +} + //--------------------------------------------- // Implementing nsICryptoHash //--------------------------------------------- diff --git a/security/manager/ssl/src/nsNSSComponent.h b/security/manager/ssl/src/nsNSSComponent.h index ea255ccc2674..1e2b459ffc8e 100644 --- a/security/manager/ssl/src/nsNSSComponent.h +++ b/security/manager/ssl/src/nsNSSComponent.h @@ -257,6 +257,15 @@ private: nsresult PostCRLImportEvent(const nsCSubstring &urlString, nsIStreamListener *psmDownloader); nsresult getParamsForNextCrlToDownload(nsAutoString *url, PRTime *time, nsAutoString *key); nsresult DispatchEventToWindow(nsIDOMWindow *domWin, const nsAString &eventType, const nsAString &token); + + // Methods that we use to handle the profile change notifications (and to + // synthesize a full profile change when we're just doing a profile startup): + void DoProfileApproveChange(nsISupports* aSubject); + void DoProfileChangeNetTeardown(); + void DoProfileChangeTeardown(nsISupports* aSubject); + void DoProfileBeforeChange(nsISupports* aSubject); + void DoProfileChangeNetRestore(); + PRLock *mutex; nsCOMPtr mScriptSecurityManager;