signon  8.40
credentialsaccessmanager.cpp
Go to the documentation of this file.
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"),
00095                             QLatin1String("default")).toString();
00096 }
00097 
00098 QString CAMConfiguration::accessControlManagerName() const
00099 {
00100     return m_settings.value(QLatin1String("AccessControlManager"),
00101                             QLatin1String("default")).toString();
00102 }
00103 
00104 bool CAMConfiguration::useEncryption() const
00105 {
00106     return cryptoManagerName() != QLatin1String("default");
00107 }
00108 
00109 QString CAMConfiguration::secretsStorageName() const
00110 {
00111     return m_settings.value(QLatin1String("SecretsStorage"),
00112                             QLatin1String("default")).toString();
00113 }
00114 
00115 void CAMConfiguration::setStoragePath(const QString &storagePath) {
00116     m_storagePath = storagePath;
00117     if (m_storagePath.startsWith(QLatin1Char('~')))
00118         m_storagePath.replace(0, 1, QDir::homePath());
00119     // CryptoSetup extensions are given the m_settings dictionary only
00120     addSetting(QLatin1String("StoragePath"), m_storagePath);
00121 }
00122 
00123 /* ---------------------- CredentialsAccessManager ---------------------- */
00124 
00125 CredentialsAccessManager *CredentialsAccessManager::m_pInstance = NULL;
00126 
00127 CredentialsAccessManager::CredentialsAccessManager(
00128                                           const CAMConfiguration &configuration,
00129                                           QObject *parent):
00130     QObject(parent),
00131     m_isInitialized(false),
00132     m_systemOpened(false),
00133     m_error(NoError),
00134     keyManagers(),
00135     m_pCredentialsDB(NULL),
00136     m_cryptoManager(NULL),
00137     m_keyHandler(NULL),
00138     m_keyAuthorizer(NULL),
00139     m_secretsStorage(NULL),
00140     m_CAMConfiguration(configuration),
00141     m_acManager(NULL),
00142     m_acManagerHelper(NULL)
00143 {
00144     if (!m_pInstance) {
00145         m_pInstance = this;
00146     } else {
00147         BLAME() << "Creating a second instance of the CAM";
00148     }
00149 
00150     m_keyHandler = new SignOn::KeyHandler(this);
00151 }
00152 
00153 CredentialsAccessManager::~CredentialsAccessManager()
00154 {
00155     closeCredentialsSystem();
00156 
00157     m_pInstance = NULL;
00158 }
00159 
00160 CredentialsAccessManager *CredentialsAccessManager::instance()
00161 {
00162     return m_pInstance;
00163 }
00164 
00165 void CredentialsAccessManager::finalize()
00166 {
00167     TRACE() << "Enter";
00168 
00169     if (m_systemOpened)
00170         closeCredentialsSystem();
00171 
00172     // Disconnect all key managers
00173     foreach (SignOn::AbstractKeyManager *keyManager, keyManagers)
00174         keyManager->disconnect();
00175 
00176     m_isInitialized = false;
00177     m_error = NoError;
00178 }
00179 
00180 bool CredentialsAccessManager::init()
00181 {
00182     if (m_isInitialized) {
00183         TRACE() << "CAM already initialized.";
00184         m_error = AlreadyInitialized;
00185         return false;
00186     }
00187 
00188     QBuffer config;
00189     m_CAMConfiguration.serialize(&config);
00190     TRACE() << "Initializing CredentialsAccessManager with configuration: " <<
00191         config.data();
00192 
00193     if (!createStorageDir()) {
00194         BLAME() << "Failed to create storage directory.";
00195         return false;
00196     }
00197 
00198     if (m_secretsStorage == 0) {
00199         QString name = m_CAMConfiguration.secretsStorageName();
00200         if (name != QLatin1String("default")) {
00201             BLAME() << "Couldn't load SecretsStorage:" << name;
00202         }
00203         TRACE() << "No SecretsStorage set, using default (dummy)";
00204         m_secretsStorage = new DefaultSecretsStorage(this);
00205     }
00206 
00207     //Initialize AccessControlManager
00208     if (m_acManager == 0) {
00209         QString name = m_CAMConfiguration.accessControlManagerName();
00210         if (name != QLatin1String("default")) {
00211             BLAME() << "Couldn't load AccessControlManager:" << name;
00212         }
00213         TRACE() << "No AccessControlManager set, using default (dummy)";
00214         m_acManager = new SignOn::AbstractAccessControlManager(this);
00215     }
00216 
00217     //Initialize AccessControlManagerHelper
00218     if (m_acManagerHelper == 0) {
00219         m_acManagerHelper = new AccessControlManagerHelper(m_acManager);
00220     }
00221 
00222     //Initialize CryptoManager
00223     if (m_cryptoManager == 0) {
00224         QString name = m_CAMConfiguration.cryptoManagerName();
00225         if (name != QLatin1String("default")) {
00226             BLAME() << "Couldn't load CryptoManager:" << name;
00227         }
00228         TRACE() << "No CryptoManager set, using default (dummy)";
00229         m_cryptoManager = new DefaultCryptoManager(this);
00230     }
00231     QObject::connect(m_cryptoManager, SIGNAL(fileSystemMounted()),
00232                      this, SLOT(onEncryptedFSMounted()));
00233     QObject::connect(m_cryptoManager, SIGNAL(fileSystemUnmounting()),
00234                      this, SLOT(onEncryptedFSUnmounting()));
00235     m_cryptoManager->initialize(m_CAMConfiguration.m_settings);
00236 
00237     /* This check is an optimization: instantiating the KeyAuthorizer is
00238      * probably not harmful if useEncryption() is false, but it's certainly
00239      * useless. */
00240     if (m_CAMConfiguration.useEncryption()) {
00241         if (m_keyAuthorizer == 0) {
00242             TRACE() << "No key authorizer set, using default";
00243             m_keyAuthorizer = new DefaultKeyAuthorizer(m_keyHandler, this);
00244         }
00245         QObject::connect(m_keyAuthorizer,
00246                          SIGNAL(keyAuthorizationQueried(const SignOn::Key,int)),
00247                          this,
00248                          SLOT(onKeyAuthorizationQueried(const SignOn::Key,int)));
00249 
00250         /* These signal connections should be done after instantiating the
00251          * KeyAuthorizer, so that the KeyAuthorizer's slot will be called
00252          * first (or we could connect to them in queued mode)
00253          */
00254         QObject::connect(m_keyHandler, SIGNAL(ready()),
00255                          this, SIGNAL(credentialsSystemReady()));
00256         QObject::connect(m_keyHandler, SIGNAL(keyInserted(SignOn::Key)),
00257                          this, SLOT(onKeyInserted(SignOn::Key)));
00258         QObject::connect(m_keyHandler,
00259                          SIGNAL(lastAuthorizedKeyRemoved(SignOn::Key)),
00260                          this,
00261                          SLOT(onLastAuthorizedKeyRemoved(SignOn::Key)));
00262         QObject::connect(m_keyHandler, SIGNAL(keyRemoved(SignOn::Key)),
00263                          this, SLOT(onKeyRemoved(SignOn::Key)));
00264         m_keyHandler->initialize(m_cryptoManager, keyManagers);
00265     }
00266 
00267     m_isInitialized = true;
00268     m_error = NoError;
00269 
00270     TRACE() << "CredentialsAccessManager successfully initialized...";
00271     return true;
00272 }
00273 
00274 void CredentialsAccessManager::addKeyManager(
00275     SignOn::AbstractKeyManager *keyManager)
00276 {
00277     keyManagers.append(keyManager);
00278 }
00279 
00280 bool CredentialsAccessManager::initExtension(QObject *plugin)
00281 {
00282     bool extensionInUse = false;
00283 
00284     SignOn::ExtensionInterface *extension;
00285     SignOn::ExtensionInterface2 *extension2;
00286     SignOn::ExtensionInterface3 *extension3;
00287 
00288     extension3 = qobject_cast<SignOn::ExtensionInterface3 *>(plugin);
00289 
00290     if (extension3 != 0)
00291         extension2 = extension3;
00292     else
00293         extension2 = qobject_cast<SignOn::ExtensionInterface2 *>(plugin);
00294 
00295     if (extension2 != 0)
00296         extension = extension2;
00297     else
00298         extension = qobject_cast<SignOn::ExtensionInterface *>(plugin);
00299 
00300     if (extension == 0) {
00301         qWarning() << "Plugin instance is not an ExtensionInterface";
00302         return false;
00303     }
00304 
00305     SignOn::AbstractKeyManager *keyManager = extension->keyManager(this);
00306     if (keyManager) {
00307         addKeyManager(keyManager);
00308         extensionInUse = true;
00309     }
00310 
00311     /* Check if the extension implements the new interface and provides a key
00312      * authorizer. */
00313     if (extension2 != 0) {
00314         SignOn::AbstractKeyAuthorizer *keyAuthorizer =
00315             extension2->keyAuthorizer(m_keyHandler, this);
00316         if (keyAuthorizer != 0) {
00317             if (m_keyAuthorizer == 0) {
00318                 m_keyAuthorizer = keyAuthorizer;
00319                 extensionInUse = true;
00320             } else {
00321                 TRACE() << "Key authorizer already set";
00322                 delete keyAuthorizer;
00323             }
00324         }
00325     }
00326 
00327     if (extension3 != 0) {
00328         /* Instantiate this plugin's CryptoManager only if it's the plugin
00329          * requested in the config file. */
00330         if (plugin->objectName() == m_CAMConfiguration.cryptoManagerName()) {
00331             SignOn::AbstractCryptoManager *cryptoManager =
00332                 extension3->cryptoManager(this);
00333             if (cryptoManager != 0) {
00334                 if (m_cryptoManager == 0) {
00335                     m_cryptoManager = cryptoManager;
00336                     extensionInUse = true;
00337                 } else {
00338                     TRACE() << "Crypto manager already set";
00339                     delete cryptoManager;
00340                 }
00341             }
00342         }
00343 
00344         if (plugin->objectName() == m_CAMConfiguration.secretsStorageName()) {
00345             SignOn::AbstractSecretsStorage *secretsStorage =
00346                 extension3->secretsStorage(this);
00347             if (secretsStorage != 0) {
00348                 if (m_secretsStorage == 0) {
00349                     m_secretsStorage = secretsStorage;
00350                     extensionInUse = true;
00351                 } else {
00352                     TRACE() << "SecretsStorage already set";
00353                     delete secretsStorage;
00354                 }
00355             }
00356         }
00357 
00358         /* Instantiate this plugin's AccessControlManager only if it's the
00359          * plugin requested in the config file. */
00360         if (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 }