signon
8.58
|
00001 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 00002 /* 00003 * This file is part of signon 00004 * 00005 * Copyright (C) 2009-2010 Nokia Corporation. 00006 * Copyright (C) 2011 Intel Corporation. 00007 * 00008 * Contact: Aurel Popirtac <mailto:ext-Aurel.Popirtac@nokia.com> 00009 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> 00010 * Contact: Jussi Laako <jussi.laako@linux.intel.com> 00011 * 00012 * This library is free software; you can redistribute it and/or 00013 * modify it under the terms of the GNU Lesser General Public License 00014 * version 2.1 as published by the Free Software Foundation. 00015 * 00016 * This library is distributed in the hope that it will be useful, but 00017 * WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with this library; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00024 * 02110-1301 USA 00025 */ 00026 00027 #define SIGNON_ENABLE_UNSTABLE_APIS 00028 #include "credentialsaccessmanager.h" 00029 00030 #include "default-crypto-manager.h" 00031 #include "default-key-authorizer.h" 00032 #include "default-secrets-storage.h" 00033 #include "signond-common.h" 00034 00035 #include "SignOn/ExtensionInterface" 00036 #include "SignOn/misc.h" 00037 00038 #include <QFile> 00039 #include <QBuffer> 00040 00041 00042 #define RETURN_IF_NOT_INITIALIZED(return_value) \ 00043 do { \ 00044 if (!m_isInitialized) { \ 00045 m_error = NotInitialized; \ 00046 TRACE() << "CredentialsAccessManager not initialized."; \ 00047 return return_value; \ 00048 } \ 00049 } while (0) 00050 00051 using namespace SignonDaemonNS; 00052 using namespace SignOn; 00053 00054 /* ---------------------- CAMConfiguration ---------------------- */ 00055 00056 CAMConfiguration::CAMConfiguration(): 00057 m_dbName(QLatin1String(signonDefaultDbName)), 00058 m_secretsDbName(QLatin1String(signonDefaultSecretsDbName)), 00059 m_encryptionPassphrase(QByteArray()) 00060 { 00061 setStoragePath(QLatin1String(signonDefaultStoragePath)); 00062 } 00063 00064 void CAMConfiguration::serialize(QIODevice *device) 00065 { 00066 if (device == NULL) 00067 return; 00068 00069 if (!device->open(QIODevice::ReadWrite)) { 00070 return; 00071 } 00072 00073 QString buffer; 00074 QTextStream stream(&buffer); 00075 stream << "\n\n====== Credentials Access Manager Configuration ======\n\n"; 00076 const char *usingEncryption = useEncryption() ? "true" : "false"; 00077 stream << "Using encryption: " << usingEncryption << '\n'; 00078 stream << "Metadata DB path: " << metadataDBPath() << '\n'; 00079 stream << "Cryptomanager name: " << cryptoManagerName() << '\n'; 00080 stream << "ACL manager name: " << accessControlManagerName() << '\n'; 00081 stream << "Secrets storage name: " << secretsStorageName() << '\n'; 00082 stream << "======================================================\n\n"; 00083 device->write(buffer.toUtf8()); 00084 device->close(); 00085 } 00086 00087 QString CAMConfiguration::metadataDBPath() const 00088 { 00089 return m_storagePath + QDir::separator() + m_dbName; 00090 } 00091 00092 QString CAMConfiguration::cryptoManagerName() const 00093 { 00094 return m_settings.value(QLatin1String("CryptoManager")).toString(); 00095 } 00096 00097 QString CAMConfiguration::accessControlManagerName() const 00098 { 00099 return m_settings.value(QLatin1String("AccessControlManager")).toString(); 00100 } 00101 00102 bool CAMConfiguration::useEncryption() const 00103 { 00104 return cryptoManagerName() != QLatin1String("default"); 00105 } 00106 00107 QString CAMConfiguration::secretsStorageName() const 00108 { 00109 return m_settings.value(QLatin1String("SecretsStorage")).toString(); 00110 } 00111 00112 void CAMConfiguration::setStoragePath(const QString &storagePath) { 00113 m_storagePath = storagePath; 00114 if (m_storagePath.startsWith(QLatin1Char('~'))) 00115 m_storagePath.replace(0, 1, QDir::homePath()); 00116 // CryptoSetup extensions are given the m_settings dictionary only 00117 addSetting(QLatin1String("StoragePath"), m_storagePath); 00118 } 00119 00120 /* ---------------------- CredentialsAccessManager ---------------------- */ 00121 00122 CredentialsAccessManager *CredentialsAccessManager::m_pInstance = NULL; 00123 00124 CredentialsAccessManager::CredentialsAccessManager( 00125 const CAMConfiguration &configuration, 00126 QObject *parent): 00127 QObject(parent), 00128 m_isInitialized(false), 00129 m_systemOpened(false), 00130 m_error(NoError), 00131 keyManagers(), 00132 m_pCredentialsDB(NULL), 00133 m_cryptoManager(NULL), 00134 m_keyHandler(NULL), 00135 m_keyAuthorizer(NULL), 00136 m_secretsStorage(NULL), 00137 m_CAMConfiguration(configuration), 00138 m_acManager(NULL), 00139 m_acManagerHelper(NULL) 00140 { 00141 if (!m_pInstance) { 00142 m_pInstance = this; 00143 } else { 00144 BLAME() << "Creating a second instance of the CAM"; 00145 } 00146 00147 m_keyHandler = new SignOn::KeyHandler(this); 00148 } 00149 00150 CredentialsAccessManager::~CredentialsAccessManager() 00151 { 00152 closeCredentialsSystem(); 00153 00154 m_pInstance = NULL; 00155 } 00156 00157 CredentialsAccessManager *CredentialsAccessManager::instance() 00158 { 00159 return m_pInstance; 00160 } 00161 00162 void CredentialsAccessManager::finalize() 00163 { 00164 TRACE() << "Enter"; 00165 00166 if (m_systemOpened) 00167 closeCredentialsSystem(); 00168 00169 // Disconnect all key managers 00170 foreach (SignOn::AbstractKeyManager *keyManager, keyManagers) 00171 keyManager->disconnect(); 00172 00173 m_isInitialized = false; 00174 m_error = NoError; 00175 } 00176 00177 bool CredentialsAccessManager::init() 00178 { 00179 if (m_isInitialized) { 00180 TRACE() << "CAM already initialized."; 00181 m_error = AlreadyInitialized; 00182 return false; 00183 } 00184 00185 QBuffer config; 00186 m_CAMConfiguration.serialize(&config); 00187 TRACE() << "Initializing CredentialsAccessManager with configuration: " << 00188 config.data(); 00189 00190 if (!createStorageDir()) { 00191 BLAME() << "Failed to create storage directory."; 00192 return false; 00193 } 00194 00195 if (m_secretsStorage == 0) { 00196 QString name = m_CAMConfiguration.secretsStorageName(); 00197 if (!name.isEmpty() && name != QLatin1String("default")) { 00198 BLAME() << "Couldn't load SecretsStorage:" << name; 00199 } 00200 TRACE() << "No SecretsStorage set, using default (dummy)"; 00201 m_secretsStorage = new DefaultSecretsStorage(this); 00202 } 00203 00204 //Initialize AccessControlManager 00205 if (m_acManager == 0) { 00206 QString name = m_CAMConfiguration.accessControlManagerName(); 00207 if (!name.isEmpty() && name != QLatin1String("default")) { 00208 BLAME() << "Couldn't load AccessControlManager:" << name; 00209 } 00210 TRACE() << "No AccessControlManager set, using default (dummy)"; 00211 m_acManager = new SignOn::AbstractAccessControlManager(this); 00212 } 00213 00214 //Initialize AccessControlManagerHelper 00215 if (m_acManagerHelper == 0) { 00216 m_acManagerHelper = new AccessControlManagerHelper(m_acManager); 00217 } 00218 00219 //Initialize CryptoManager 00220 if (m_cryptoManager == 0) { 00221 QString name = m_CAMConfiguration.cryptoManagerName(); 00222 if (!name.isEmpty() && name != QLatin1String("default")) { 00223 BLAME() << "Couldn't load CryptoManager:" << name; 00224 } 00225 TRACE() << "No CryptoManager set, using default (dummy)"; 00226 m_cryptoManager = new DefaultCryptoManager(this); 00227 } 00228 QObject::connect(m_cryptoManager, SIGNAL(fileSystemMounted()), 00229 this, SLOT(onEncryptedFSMounted())); 00230 QObject::connect(m_cryptoManager, SIGNAL(fileSystemUnmounting()), 00231 this, SLOT(onEncryptedFSUnmounting())); 00232 m_cryptoManager->initialize(m_CAMConfiguration.m_settings); 00233 00234 /* This check is an optimization: instantiating the KeyAuthorizer is 00235 * probably not harmful if useEncryption() is false, but it's certainly 00236 * useless. */ 00237 if (m_CAMConfiguration.useEncryption()) { 00238 if (m_keyAuthorizer == 0) { 00239 TRACE() << "No key authorizer set, using default"; 00240 m_keyAuthorizer = new DefaultKeyAuthorizer(m_keyHandler, this); 00241 } 00242 QObject::connect(m_keyAuthorizer, 00243 SIGNAL(keyAuthorizationQueried(const SignOn::Key,int)), 00244 this, 00245 SLOT(onKeyAuthorizationQueried(const SignOn::Key,int))); 00246 00247 /* These signal connections should be done after instantiating the 00248 * KeyAuthorizer, so that the KeyAuthorizer's slot will be called 00249 * first (or we could connect to them in queued mode) 00250 */ 00251 QObject::connect(m_keyHandler, SIGNAL(ready()), 00252 this, SIGNAL(credentialsSystemReady())); 00253 QObject::connect(m_keyHandler, SIGNAL(keyInserted(SignOn::Key)), 00254 this, SLOT(onKeyInserted(SignOn::Key))); 00255 QObject::connect(m_keyHandler, 00256 SIGNAL(lastAuthorizedKeyRemoved(SignOn::Key)), 00257 this, 00258 SLOT(onLastAuthorizedKeyRemoved(SignOn::Key))); 00259 QObject::connect(m_keyHandler, SIGNAL(keyRemoved(SignOn::Key)), 00260 this, SLOT(onKeyRemoved(SignOn::Key))); 00261 m_keyHandler->initialize(m_cryptoManager, keyManagers); 00262 } 00263 00264 m_isInitialized = true; 00265 m_error = NoError; 00266 00267 TRACE() << "CredentialsAccessManager successfully initialized..."; 00268 return true; 00269 } 00270 00271 void CredentialsAccessManager::addKeyManager( 00272 SignOn::AbstractKeyManager *keyManager) 00273 { 00274 keyManagers.append(keyManager); 00275 } 00276 00277 bool CredentialsAccessManager::initExtension(QObject *plugin) 00278 { 00279 bool extensionInUse = false; 00280 00281 SignOn::ExtensionInterface *extension; 00282 SignOn::ExtensionInterface2 *extension2; 00283 SignOn::ExtensionInterface3 *extension3; 00284 00285 extension3 = qobject_cast<SignOn::ExtensionInterface3 *>(plugin); 00286 00287 if (extension3 != 0) 00288 extension2 = extension3; 00289 else 00290 extension2 = qobject_cast<SignOn::ExtensionInterface2 *>(plugin); 00291 00292 if (extension2 != 0) 00293 extension = extension2; 00294 else 00295 extension = qobject_cast<SignOn::ExtensionInterface *>(plugin); 00296 00297 if (extension == 0) { 00298 qWarning() << "Plugin instance is not an ExtensionInterface"; 00299 return false; 00300 } 00301 00302 SignOn::AbstractKeyManager *keyManager = extension->keyManager(this); 00303 if (keyManager) { 00304 addKeyManager(keyManager); 00305 extensionInUse = true; 00306 } 00307 00308 /* Check if the extension implements the new interface and provides a key 00309 * authorizer. */ 00310 if (extension2 != 0) { 00311 SignOn::AbstractKeyAuthorizer *keyAuthorizer = 00312 extension2->keyAuthorizer(m_keyHandler, this); 00313 if (keyAuthorizer != 0) { 00314 if (m_keyAuthorizer == 0) { 00315 m_keyAuthorizer = keyAuthorizer; 00316 extensionInUse = true; 00317 } else { 00318 TRACE() << "Key authorizer already set"; 00319 delete keyAuthorizer; 00320 } 00321 } 00322 } 00323 00324 if (extension3 != 0) { 00325 /* Instantiate this plugin's CryptoManager only if it's the plugin 00326 * requested in the config file. */ 00327 if (m_CAMConfiguration.cryptoManagerName().isEmpty() || 00328 plugin->objectName() == m_CAMConfiguration.cryptoManagerName()) { 00329 SignOn::AbstractCryptoManager *cryptoManager = 00330 extension3->cryptoManager(this); 00331 if (cryptoManager != 0) { 00332 if (m_cryptoManager == 0) { 00333 m_cryptoManager = cryptoManager; 00334 extensionInUse = true; 00335 } else { 00336 TRACE() << "Crypto manager already set"; 00337 delete cryptoManager; 00338 } 00339 } 00340 } 00341 00342 if (m_CAMConfiguration.secretsStorageName().isEmpty() || 00343 plugin->objectName() == m_CAMConfiguration.secretsStorageName()) { 00344 SignOn::AbstractSecretsStorage *secretsStorage = 00345 extension3->secretsStorage(this); 00346 if (secretsStorage != 0) { 00347 if (m_secretsStorage == 0) { 00348 m_secretsStorage = secretsStorage; 00349 extensionInUse = true; 00350 } else { 00351 TRACE() << "SecretsStorage already set"; 00352 delete secretsStorage; 00353 } 00354 } 00355 } 00356 00357 /* Instantiate this plugin's AccessControlManager only if it's the 00358 * plugin requested in the config file. */ 00359 if (m_CAMConfiguration.accessControlManagerName().isEmpty() || 00360 plugin->objectName() == 00361 m_CAMConfiguration.accessControlManagerName()) { 00362 SignOn::AbstractAccessControlManager *acManager = 00363 extension3->accessControlManager(this); 00364 if (acManager != 0) { 00365 if (m_acManager == 0) { 00366 m_acManager = acManager; 00367 extensionInUse = true; 00368 } else { 00369 TRACE() << "Access control manager already set"; 00370 delete acManager; 00371 } 00372 } 00373 } 00374 } 00375 return extensionInUse; 00376 } 00377 00378 QStringList CredentialsAccessManager::backupFiles() const 00379 { 00380 QStringList files; 00381 00382 files << m_cryptoManager->backupFiles(); 00383 return files; 00384 } 00385 00386 bool CredentialsAccessManager::openSecretsDB() 00387 { 00388 if (!m_cryptoManager->fileSystemIsMounted()) { 00389 /* Do not attempt to mount the FS; we know that it will be mounted 00390 * automatically, as soon as some encryption keys are provided */ 00391 m_error = CredentialsDbNotMounted; 00392 return false; 00393 } 00394 00395 QString dbPath = m_cryptoManager->fileSystemMountPath() 00396 + QDir::separator() 00397 + m_CAMConfiguration.m_secretsDbName; 00398 00399 TRACE() << "Database name: [" << dbPath << "]"; 00400 00401 if (!m_pCredentialsDB->openSecretsDB(dbPath)) 00402 return false; 00403 00404 m_error = NoError; 00405 return true; 00406 } 00407 00408 bool CredentialsAccessManager::isSecretsDBOpen() 00409 { 00410 return m_pCredentialsDB->isSecretsDBOpen(); 00411 } 00412 00413 bool CredentialsAccessManager::closeSecretsDB() 00414 { 00415 m_pCredentialsDB->closeSecretsDB(); 00416 00417 if (!m_cryptoManager->unmountFileSystem()) { 00418 m_error = CredentialsDbUnmountFailed; 00419 return false; 00420 } 00421 00422 return true; 00423 } 00424 00425 bool CredentialsAccessManager::createStorageDir() 00426 { 00427 QString dbPath = m_CAMConfiguration.metadataDBPath(); 00428 00429 QFileInfo fileInfo(dbPath); 00430 if (!fileInfo.exists()) { 00431 QDir storageDir(fileInfo.dir()); 00432 if (!storageDir.mkpath(storageDir.path())) { 00433 BLAME() << "Could not create storage directory:" << 00434 storageDir.path(); 00435 m_error = CredentialsDbSetupFailed; 00436 return false; 00437 } 00438 setUserOwnership(storageDir.path()); 00439 } 00440 return true; 00441 00442 } 00443 bool CredentialsAccessManager::openMetaDataDB() 00444 { 00445 QString dbPath = m_CAMConfiguration.metadataDBPath(); 00446 00447 m_pCredentialsDB = new CredentialsDB(dbPath, m_secretsStorage); 00448 00449 if (!m_pCredentialsDB->init()) { 00450 m_error = CredentialsDbConnectionError; 00451 return false; 00452 } 00453 00454 return true; 00455 } 00456 00457 void CredentialsAccessManager::closeMetaDataDB() 00458 { 00459 if (m_pCredentialsDB) { 00460 delete m_pCredentialsDB; 00461 m_pCredentialsDB = NULL; 00462 } 00463 } 00464 00465 bool CredentialsAccessManager::openCredentialsSystem() 00466 { 00467 RETURN_IF_NOT_INITIALIZED(false); 00468 00469 if (!openMetaDataDB()) { 00470 BLAME() << "Couldn't open metadata DB!"; 00471 return false; 00472 } 00473 00474 m_systemOpened = true; 00475 00476 if (m_cryptoManager->fileSystemIsMounted()) { 00477 if (!openSecretsDB()) { 00478 BLAME() << "Failed to open secrets DB."; 00479 /* Even if the secrets DB couldn't be opened, signond is still 00480 * usable: that's why we return "true" anyways. */ 00481 } 00482 } else { 00483 /* The secrets DB will be opened as soon as the encrypted FS is 00484 * mounted. 00485 */ 00486 m_cryptoManager->mountFileSystem(); 00487 } 00488 00489 return true; 00490 } 00491 00492 bool CredentialsAccessManager::closeCredentialsSystem() 00493 { 00494 RETURN_IF_NOT_INITIALIZED(false); 00495 00496 if (!credentialsSystemOpened()) 00497 return true; 00498 00499 bool allClosed = true; 00500 if (isSecretsDBOpen() && !closeSecretsDB()) 00501 allClosed = false; 00502 00503 closeMetaDataDB(); 00504 00505 m_error = NoError; 00506 m_systemOpened = false; 00507 return allClosed; 00508 } 00509 00510 bool CredentialsAccessManager::deleteCredentialsSystem() 00511 { 00512 RETURN_IF_NOT_INITIALIZED(false); 00513 00514 if (m_systemOpened && !closeCredentialsSystem()) { 00515 /* The close operation failed: we cannot proceed */ 00516 return false; 00517 } 00518 00519 BLAME() << "Not implemented"; 00520 return false; 00521 } 00522 00523 CredentialsDB *CredentialsAccessManager::credentialsDB() const 00524 { 00525 RETURN_IF_NOT_INITIALIZED(NULL); 00526 00527 return m_pCredentialsDB; 00528 } 00529 00530 bool CredentialsAccessManager::isCredentialsSystemReady() const 00531 { 00532 return (m_keyHandler != 0) ? m_keyHandler->isReady() : true; 00533 } 00534 00535 void CredentialsAccessManager::onKeyInserted(const SignOn::Key key) 00536 { 00537 TRACE() << "Key inserted."; 00538 00539 if (!m_keyHandler->keyIsAuthorized(key)) 00540 m_keyAuthorizer->queryKeyAuthorization( 00541 key, AbstractKeyAuthorizer::KeyInserted); 00542 } 00543 00544 void CredentialsAccessManager::onLastAuthorizedKeyRemoved(const SignOn::Key key) 00545 { 00546 Q_UNUSED(key); 00547 TRACE() << "All keys disabled. Closing secure storage."; 00548 if (isSecretsDBOpen() || m_cryptoManager->fileSystemIsMounted()) 00549 if (!closeSecretsDB()) 00550 BLAME() << "Error occurred while closing secure storage."; 00551 } 00552 00553 void CredentialsAccessManager::onKeyRemoved(const SignOn::Key key) 00554 { 00555 TRACE() << "Key removed."; 00556 00557 if (m_keyHandler->keyIsAuthorized(key)) { 00558 if (!m_keyHandler->revokeKeyAuthorization(key)) { 00559 BLAME() << "Revoking key authorization failed"; 00560 } 00561 } 00562 } 00563 00564 void CredentialsAccessManager::onKeyAuthorizationQueried(const SignOn::Key key, 00565 int result) 00566 { 00567 TRACE() << "result:" << result; 00568 00569 if (result != AbstractKeyAuthorizer::Denied) { 00570 KeyHandler::AuthorizeFlags flags = KeyHandler::None; 00571 if (result == AbstractKeyAuthorizer::Exclusive) { 00572 TRACE() << "Reformatting secure storage."; 00573 flags |= KeyHandler::FormatStorage; 00574 } 00575 00576 if (!m_keyHandler->authorizeKey(key, flags)) { 00577 BLAME() << "Authorization failed"; 00578 } 00579 } 00580 00581 replyToSecureStorageEventNotifiers(); 00582 } 00583 00584 bool CredentialsAccessManager::keysAvailable() const 00585 { 00586 if (m_keyHandler == 0) return false; 00587 return !m_keyHandler->insertedKeys().isEmpty(); 00588 } 00589 00590 void CredentialsAccessManager::replyToSecureStorageEventNotifiers() 00591 { 00592 TRACE(); 00593 //Notify secure storage notifiers if any. 00594 int eventType = SIGNON_SECURE_STORAGE_NOT_AVAILABLE; 00595 if ((m_pCredentialsDB != 0) && m_pCredentialsDB->isSecretsDBOpen()) 00596 eventType = SIGNON_SECURE_STORAGE_AVAILABLE; 00597 00598 // Signal objects that posted secure storage not available events 00599 foreach (EventSender object, m_secureStorageEventNotifiers) { 00600 if (object.isNull()) 00601 continue; 00602 00603 SecureStorageEvent *secureStorageEvent = 00604 new SecureStorageEvent((QEvent::Type)eventType); 00605 00606 QCoreApplication::postEvent( 00607 object.data(), 00608 secureStorageEvent, 00609 Qt::HighEventPriority); 00610 } 00611 00612 m_secureStorageEventNotifiers.clear(); 00613 } 00614 00615 void CredentialsAccessManager::customEvent(QEvent *event) 00616 { 00617 TRACE() << "Custom event received."; 00618 if (event->type() != SIGNON_SECURE_STORAGE_NOT_AVAILABLE) { 00619 QObject::customEvent(event); 00620 return; 00621 } 00622 00623 SecureStorageEvent *localEvent = 00624 static_cast<SecureStorageEvent *>(event); 00625 00626 /* All senders of this event will receive a reply when 00627 * the secure storage becomes available or an error occurs. */ 00628 m_secureStorageEventNotifiers.append(localEvent->m_sender); 00629 00630 TRACE() << "Processing secure storage not available event."; 00631 if ((localEvent == 0) || (m_pCredentialsDB == 0)) { 00632 replyToSecureStorageEventNotifiers(); 00633 QObject::customEvent(event); 00634 return; 00635 } 00636 00637 //Double check if the secrets DB is indeed unavailable 00638 if (m_pCredentialsDB->isSecretsDBOpen()) { 00639 replyToSecureStorageEventNotifiers(); 00640 QObject::customEvent(event); 00641 return; 00642 } 00643 00644 SignOn::Key key; /* we don't specity any key */ 00645 m_keyAuthorizer->queryKeyAuthorization(key, 00646 AbstractKeyAuthorizer::StorageNeeded); 00647 00648 QObject::customEvent(event); 00649 } 00650 00651 void CredentialsAccessManager::onEncryptedFSMounted() 00652 { 00653 TRACE(); 00654 if (!credentialsSystemOpened()) return; 00655 00656 if (!isSecretsDBOpen()) { 00657 if (openSecretsDB()) { 00658 TRACE() << "Secrets DB opened."; 00659 } else { 00660 BLAME() << "Failed to open secrets DB."; 00661 } 00662 } else { 00663 BLAME() << "Secrets DB already opened?"; 00664 } 00665 } 00666 00667 void CredentialsAccessManager::onEncryptedFSUnmounting() 00668 { 00669 TRACE(); 00670 if (!credentialsSystemOpened()) return; 00671 00672 if (isSecretsDBOpen()) { 00673 m_pCredentialsDB->closeSecretsDB(); 00674 } 00675 }