| Index: chrome/browser/ui/crypto_module_password_dialog_nss.cc | 
| diff --git a/chrome/browser/ui/crypto_module_password_dialog_nss.cc b/chrome/browser/ui/crypto_module_password_dialog_nss.cc | 
| index e2b6bb3c3bf3a451e3cf3fb7d465d65b4ac95996..44bf47bd22badf04ff8c31a8a54f6de2c3777eec 100644 | 
| --- a/chrome/browser/ui/crypto_module_password_dialog_nss.cc | 
| +++ b/chrome/browser/ui/crypto_module_password_dialog_nss.cc | 
| @@ -13,12 +13,18 @@ | 
|  | 
| namespace { | 
|  | 
| +bool ShouldShowDialog(const net::CryptoModule* module) { | 
| +  // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc. | 
| +  return (PK11_NeedLogin(module->os_module_handle()) && | 
| +          !PK11_IsLoggedIn(module->os_module_handle(), NULL /* wincx */)); | 
| +} | 
| + | 
| // Basically an asynchronous implementation of NSS's PK11_DoPassword. | 
| // Note: This currently handles only the simple case.  See the TODOs in | 
| // GotPassword for what is yet unimplemented. | 
| class SlotUnlocker { | 
| public: | 
| -  SlotUnlocker(net::CryptoModule* module, | 
| +  SlotUnlocker(const net::CryptoModuleList& modules, | 
| browser::CryptoModulePasswordReason reason, | 
| const std::string& host, | 
| Callback0::Type* callback); | 
| @@ -29,18 +35,20 @@ class SlotUnlocker { | 
| void GotPassword(const char* password); | 
| void Done(); | 
|  | 
| -  scoped_refptr<net::CryptoModule> module_; | 
| +  size_t current_; | 
| +  net::CryptoModuleList modules_; | 
| browser::CryptoModulePasswordReason reason_; | 
| std::string host_; | 
| Callback0::Type* callback_; | 
| PRBool retry_; | 
| }; | 
|  | 
| -SlotUnlocker::SlotUnlocker(net::CryptoModule* module, | 
| +SlotUnlocker::SlotUnlocker(const net::CryptoModuleList& modules, | 
| browser::CryptoModulePasswordReason reason, | 
| const std::string& host, | 
| Callback0::Type* callback) | 
| -    : module_(module), | 
| +    : current_(0), | 
| +      modules_(modules), | 
| reason_(reason), | 
| host_(host), | 
| callback_(callback), | 
| @@ -51,12 +59,18 @@ SlotUnlocker::SlotUnlocker(net::CryptoModule* module, | 
| void SlotUnlocker::Start() { | 
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
|  | 
| -  ShowCryptoModulePasswordDialog( | 
| -      module_->GetTokenName(), | 
| -      retry_, | 
| -      reason_, | 
| -      host_, | 
| -      NewCallback(this, &SlotUnlocker::GotPassword)); | 
| +  for (; current_ < modules_.size(); ++current_) { | 
| +    if (ShouldShowDialog(modules_[current_].get())) { | 
| +      ShowCryptoModulePasswordDialog( | 
| +          modules_[current_]->GetTokenName(), | 
| +          retry_, | 
| +          reason_, | 
| +          host_, | 
| +          NewCallback(this, &SlotUnlocker::GotPassword)); | 
| +      return; | 
| +    } | 
| +  } | 
| +  Done(); | 
| } | 
|  | 
| void SlotUnlocker::GotPassword(const char* password) { | 
| @@ -66,12 +80,13 @@ void SlotUnlocker::GotPassword(const char* password) { | 
|  | 
| if (!password) { | 
| // User cancelled entering password.  Oh well. | 
| -    Done(); | 
| +    ++current_; | 
| +    Start(); | 
| return; | 
| } | 
|  | 
| // TODO(mattm): handle protectedAuthPath | 
| -  SECStatus rv = PK11_CheckUserPassword(module_->os_module_handle(), | 
| +  SECStatus rv = PK11_CheckUserPassword(modules_[current_]->os_module_handle(), | 
| password); | 
| if (rv == SECWouldBlock) { | 
| // Incorrect password.  Try again. | 
| @@ -84,11 +99,13 @@ void SlotUnlocker::GotPassword(const char* password) { | 
| // non-friendly slots.  How important is that? | 
|  | 
| // Correct password (SECSuccess) or too many attempts/other failure | 
| -  // (SECFailure).  Either way we're done. | 
| -  Done(); | 
| +  // (SECFailure).  Either way we're done with this slot. | 
| +  ++current_; | 
| +  Start(); | 
| } | 
|  | 
| void SlotUnlocker::Done() { | 
| +  DCHECK_EQ(current_, modules_.size()); | 
| callback_->Run(); | 
| delete this; | 
| } | 
| @@ -97,27 +114,28 @@ void SlotUnlocker::Done() { | 
|  | 
| namespace browser { | 
|  | 
| -void UnlockSlotIfNecessary(net::CryptoModule* module, | 
| -                           browser::CryptoModulePasswordReason reason, | 
| -                           const std::string& host, | 
| -                           Callback0::Type* callback) { | 
| +void UnlockSlotsIfNecessary(const net::CryptoModuleList& modules, | 
| +                            browser::CryptoModulePasswordReason reason, | 
| +                            const std::string& host, | 
| +                            Callback0::Type* callback) { | 
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 
| -  // The wincx arg is unused since we don't call PK11_SetIsLoggedInFunc. | 
| -  if (PK11_NeedLogin(module->os_module_handle()) && | 
| -      !PK11_IsLoggedIn(module->os_module_handle(), NULL /* wincx */)) { | 
| -    (new SlotUnlocker(module, reason, host, callback))->Start(); | 
| -  } else { | 
| -    callback->Run(); | 
| +  for (size_t i = 0; i < modules.size(); ++i) { | 
| +    if (ShouldShowDialog(modules[i].get())) { | 
| +      (new SlotUnlocker(modules, reason, host, callback))->Start(); | 
| +      return; | 
| +    } | 
| } | 
| +  callback->Run(); | 
| } | 
|  | 
| void UnlockCertSlotIfNecessary(net::X509Certificate* cert, | 
| browser::CryptoModulePasswordReason reason, | 
| const std::string& host, | 
| Callback0::Type* callback) { | 
| -  scoped_refptr<net::CryptoModule> module(net::CryptoModule::CreateFromHandle( | 
| +  net::CryptoModuleList modules; | 
| +  modules.push_back(net::CryptoModule::CreateFromHandle( | 
| cert->os_cert_handle()->slot)); | 
| -  UnlockSlotIfNecessary(module.get(), reason, host, callback); | 
| +  UnlockSlotsIfNecessary(modules, reason, host, callback); | 
| } | 
|  | 
| }  // namespace browser | 
|  |