CryptoManager: add fileSystemIsSetup()
[accounts-sso:vitalyrepins-signon.git] / src / signond / credentialsaccessmanager.cpp
1 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of signon
4  *
5  * Copyright (C) 2009-2010 Nokia Corporation.
6  *
7  * Contact: Aurel Popirtac <mailto:ext-Aurel.Popirtac@nokia.com>
8  * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * version 2.1 as published by the Free Software Foundation.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  */
24
25
26 #include "credentialsaccessmanager.h"
27
28 #include "signond-common.h"
29
30 #include <QFile>
31 #include <QBuffer>
32
33
34 #define RETURN_IF_NOT_INITIALIZED(return_value)                  \
35     do {                                                         \
36         if (!m_isInitialized) {                                  \
37             m_error = NotInitialized;                            \
38             TRACE() << "CredentialsAccessManager not initialized."; \
39             return return_value;                                \
40         }                                                       \
41     } while (0)
42
43 using namespace SignonDaemonNS;
44
45 /* ---------------------- CAMConfiguration ---------------------- */
46
47 CAMConfiguration::CAMConfiguration()
48         : m_storagePath(QLatin1String(signonDefaultStoragePath)),
49           m_dbName(QLatin1String(signonDefaultDbName)),
50           m_useEncryption(signonDefaultUseEncryption),
51           m_fileSystemType(QLatin1String(signonDefaultFileSystemType)),
52           m_fileSystemSize(signonMinumumDbSize),
53           m_encryptionPassphrase(QByteArray())
54 {}
55
56 void CAMConfiguration::serialize(QIODevice *device)
57 {
58     if (device == NULL)
59         return;
60
61     if (!device->open(QIODevice::ReadWrite)) {
62         return;
63     }
64
65     QString buffer;
66     QTextStream stream(&buffer);
67     stream << "\n\n====== Credentials Access Manager Configuration ======\n\n";
68     stream << "File system mount name " << encryptedFSPath() << '\n';
69     stream << "File system format: " << m_fileSystemType << '\n';
70     stream << "File system size:" << m_fileSystemSize << "megabytes\n";
71
72     const char *usingEncryption = m_useEncryption ? "true" : "false";
73     stream << "Using encryption: " << usingEncryption << '\n';
74     stream << "Credentials database name: " << m_dbName << '\n';
75     stream << "======================================================\n\n";
76     device->write(buffer.toUtf8());
77     device->close();
78 }
79
80 QString CAMConfiguration::metadataDBPath() const
81 {
82     return m_storagePath + QDir::separator() + m_dbName;
83 }
84
85 QString CAMConfiguration::encryptedFSPath() const
86 {
87     return m_storagePath +
88         QDir::separator() +
89         QLatin1String(signonDefaultFileSystemName);
90 }
91
92 /* ---------------------- CredentialsAccessManager ---------------------- */
93
94 CredentialsAccessManager *CredentialsAccessManager::m_pInstance = NULL;
95
96 CredentialsAccessManager::CredentialsAccessManager(QObject *parent)
97         : QObject(parent),
98           m_isInitialized(false),
99           m_systemOpened(false),
100           m_systemReady(false),
101           m_error(NoError),
102           keyManagers(),
103           readyKeyManagersCounter(0),
104           processingSecureStorageEvent(false),
105           keySwapAuthorizingMechanism(Disabled),
106           m_pCredentialsDB(NULL),
107           m_pCryptoFileSystemManager(NULL),
108           m_CAMConfiguration(CAMConfiguration()),
109           m_secureStorageUiAdaptor(NULL)
110 {
111 }
112
113 CredentialsAccessManager::~CredentialsAccessManager()
114 {
115     closeCredentialsSystem();
116
117     m_pInstance = NULL;
118 }
119
120 CredentialsAccessManager *CredentialsAccessManager::instance(QObject *parent)
121 {
122     if (!m_pInstance)
123         m_pInstance = new CredentialsAccessManager(parent);
124
125     return m_pInstance;
126 }
127
128 void CredentialsAccessManager::finalize()
129 {
130     if (m_systemOpened)
131         closeCredentialsSystem();
132
133     if (m_pCryptoFileSystemManager)
134         delete m_pCryptoFileSystemManager;
135
136     // Disconnect all key managers
137     foreach (SignOn::AbstractKeyManager *keyManager, keyManagers)
138         keyManager->disconnect();
139
140     m_isInitialized = false;
141     m_systemReady = false;
142     m_error = NoError;
143 }
144
145 bool CredentialsAccessManager::init(const CAMConfiguration &camConfiguration)
146 {
147     if (m_isInitialized) {
148         TRACE() << "CAM already initialized.";
149         m_error = AlreadyInitialized;
150         return false;
151     }
152
153     m_CAMConfiguration = camConfiguration;
154
155     QBuffer config;
156     m_CAMConfiguration.serialize(&config);
157     TRACE() << "\n\nInitualizing CredentialsAccessManager with configuration: " << config.data();
158
159     m_systemReady = true;
160
161     if (m_CAMConfiguration.m_useEncryption) {
162         //Initialize CryptoManager
163         m_pCryptoFileSystemManager = new CryptoManager(this);
164         QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemMounted()),
165                          this, SLOT(onEncryptedFSMounted()));
166         QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemUnmounting()),
167                          this, SLOT(onEncryptedFSUnmounting()));
168         m_pCryptoFileSystemManager->setFileSystemPath(m_CAMConfiguration.encryptedFSPath());
169         m_pCryptoFileSystemManager->setFileSystemSize(m_CAMConfiguration.m_fileSystemSize);
170         m_pCryptoFileSystemManager->setFileSystemType(m_CAMConfiguration.m_fileSystemType);
171
172         initKeyManagers();
173     }
174
175     m_isInitialized = true;
176     m_error = NoError;
177
178     TRACE() << "CredentialsAccessManager successfully initialized...";
179     return true;
180 }
181
182 void CredentialsAccessManager::initKeyManagers()
183 {
184     if (keyManagers.isEmpty()) {
185         BLAME() << "NO Key Manager was subscribed to the CAM.";
186         return;
187     }
188     m_systemReady = false;
189
190     foreach (SignOn::AbstractKeyManager *keyManager, keyManagers) {
191         connect(keyManager,
192                 SIGNAL(keyInserted(const SignOn::Key)),
193                 SLOT(onKeyInserted(const SignOn::Key)));
194         connect(keyManager,
195                 SIGNAL(keyDisabled(const SignOn::Key)),
196                 SLOT(onKeyDisabled(const SignOn::Key)));
197         connect(keyManager,
198                 SIGNAL(keyRemoved(const SignOn::Key)),
199                 SLOT(onKeyRemoved(const SignOn::Key)));
200         if (keyManager->supportsKeyAuthorization()) {
201             connect(keyManager,
202                     SIGNAL(keyAuthorized(const SignOn::Key, bool)),
203                     SLOT(onKeyAuthorized(const SignOn::Key, bool)));
204         }
205         keyManager->setup();
206     }
207 }
208
209 void CredentialsAccessManager::addKeyManager(
210     SignOn::AbstractKeyManager *keyManager)
211 {
212     keyManagers.append(keyManager);
213 }
214
215 bool CredentialsAccessManager::openSecretsDB()
216 {
217     //todo remove this variable after LUKS implementation becomes stable.
218     QString dbPath;
219
220     if (m_CAMConfiguration.m_useEncryption) {
221         dbPath = m_pCryptoFileSystemManager->fileSystemMountPath()
222             + QDir::separator()
223             + m_CAMConfiguration.m_dbName;
224
225         if (!m_pCryptoFileSystemManager->fileSystemIsMounted()) {
226             /* Do not attempt to mount the FS; we know that it will be mounted
227              * automatically, as soon as some encryption keys are provided */
228             m_error = CredentialsDbNotMounted;
229             return false;
230         }
231     } else {
232         dbPath = m_CAMConfiguration.metadataDBPath() + QLatin1String(".creds");
233     }
234
235     TRACE() << "Database name: [" << dbPath << "]";
236
237     if (!m_pCredentialsDB->openSecretsDB(dbPath))
238         return false;
239
240     m_error = NoError;
241     return true;
242 }
243
244 bool CredentialsAccessManager::isSecretsDBOpen()
245 {
246     return m_pCredentialsDB->isSecretsDBOpen();
247 }
248
249 bool CredentialsAccessManager::closeSecretsDB()
250 {
251     m_pCredentialsDB->closeSecretsDB();
252
253     if (m_CAMConfiguration.m_useEncryption) {
254         if (!m_pCryptoFileSystemManager->unmountFileSystem()) {
255             m_error = CredentialsDbUnmountFailed;
256             return false;
257         }
258     }
259
260     return true;
261 }
262
263 bool CredentialsAccessManager::openMetaDataDB()
264 {
265     QString dbPath = m_CAMConfiguration.metadataDBPath();
266     QFileInfo fileInfo(dbPath);
267     if (!fileInfo.exists()) {
268         QDir storageDir(fileInfo.dir());
269         if (!storageDir.mkpath(storageDir.path())) {
270             BLAME() << "Could not create storage directory:" <<
271                 storageDir.path();
272             m_error = CredentialsDbSetupFailed;
273             return false;
274         }
275         //Set the right permissions for the storage directory
276         QFile storageDirAsFile(storageDir.path());
277         QFile::Permissions permissions = storageDirAsFile.permissions();
278         QFile::Permissions desiredPermissions = permissions
279             | QFile::WriteGroup | QFile::ReadGroup
280             | QFile::WriteOther | QFile::ReadOther;
281
282         if (permissions != desiredPermissions)
283             storageDirAsFile.setPermissions(desiredPermissions);
284     }
285
286     m_pCredentialsDB = new CredentialsDB(dbPath);
287
288     if (!m_pCredentialsDB->init()) {
289         m_error = CredentialsDbConnectionError;
290         return false;
291     }
292
293     return true;
294 }
295
296 void CredentialsAccessManager::closeMetaDataDB()
297 {
298     if (m_pCredentialsDB) {
299         delete m_pCredentialsDB;
300         m_pCredentialsDB = NULL;
301     }
302 }
303
304 bool CredentialsAccessManager::openCredentialsSystem()
305 {
306     RETURN_IF_NOT_INITIALIZED(false);
307
308     if (!openMetaDataDB()) {
309         BLAME() << "Couldn't open metadata DB!";
310         return false;
311     }
312
313     if (!openSecretsDB()) {
314         BLAME() << "Failed to open secrets DB.";
315         /* Even if the secrets DB couldn't be opened, signond is still usable:
316          * that's why we return "true" anyways. */
317     }
318
319     m_systemOpened = true;
320     return true;
321 }
322
323 bool CredentialsAccessManager::closeCredentialsSystem()
324 {
325     RETURN_IF_NOT_INITIALIZED(false);
326
327     if (!credentialsSystemOpened())
328         return true;
329
330     bool allClosed = true;
331     if (isSecretsDBOpen() && !closeSecretsDB())
332         allClosed = false;
333
334     closeMetaDataDB();
335
336     m_error = NoError;
337     m_systemOpened = false;
338     return allClosed;
339 }
340
341 bool CredentialsAccessManager::deleteCredentialsSystem()
342 {
343     RETURN_IF_NOT_INITIALIZED(false);
344
345     if (m_systemOpened && !closeCredentialsSystem()) {
346         /* The close operation failed: we cannot proceed */
347         return false;
348     }
349
350     m_error = NoError;
351
352     if (m_CAMConfiguration.m_useEncryption) {
353         if (!m_pCryptoFileSystemManager->deleteFileSystem())
354             m_error = CredentialsDbDeletionFailed;
355     } else {
356         QFile dbFile(m_CAMConfiguration.m_dbName);
357         if (dbFile.exists()) {
358             if (!dbFile.remove())
359                 m_error = CredentialsDbDeletionFailed;
360         }
361     }
362
363     return m_error == NoError;
364 }
365
366 CredentialsDB *CredentialsAccessManager::credentialsDB() const
367 {
368     RETURN_IF_NOT_INITIALIZED(NULL);
369
370     return m_pCredentialsDB;
371 }
372
373 bool CredentialsAccessManager::deployCredentialsSystem()
374 {
375     if (m_CAMConfiguration.m_useEncryption) {
376         if (!m_pCryptoFileSystemManager->setupFileSystem()) {
377             m_error = CredentialsDbSetupFailed;
378             return false;
379         }
380     }
381     return true;
382 }
383
384 bool CredentialsAccessManager::encryptionKeyCanOpenStorage(const QByteArray &key)
385 {
386     if (!m_pCryptoFileSystemManager->fileSystemIsSetup()) {
387         TRACE() << "Secure FS not deployed, deploying now...";
388         m_pCryptoFileSystemManager->setEncryptionKey(key);
389
390         if (!deployCredentialsSystem()) {
391             BLAME() << "Could not deploy encrypted file system.";
392             return false;
393         }
394     }
395
396     if (m_pCryptoFileSystemManager->encryptionKeyInUse(key)) {
397         TRACE() << "Key already in use.";
398         return true;
399     }
400
401     return false;
402 }
403
404 void CredentialsAccessManager::onKeyInserted(const SignOn::Key key)
405 {
406     TRACE() << "Key inserted.";
407
408     if (!m_systemReady) {
409         /* Check that at least one non empty key was signaled or if not so,
410          * that all key managers have signaled at least one key. */
411         ++readyKeyManagersCounter;
412         if (!key.isEmpty() || (readyKeyManagersCounter == keyManagers.count())) {
413             m_systemReady = true;
414             emit credentialsSystemReady();
415         }
416     }
417
418     if (key.isEmpty()) return;
419
420     //Close the secure storage UI 1st
421     if (m_secureStorageUiAdaptor)
422         m_secureStorageUiAdaptor->closeUi();
423
424     insertedKeys.append(key);
425
426     /* The `key in use` check will attempt to mount using the new key if
427        the file system is not already mounted
428     */
429     if (encryptionKeyCanOpenStorage(key)) {
430         TRACE() << "Key already in use.";
431         if (!authorizedKeys.contains(key))
432             authorizedKeys << key;
433
434         if (coreKeyAuthorizingEnabled(UnauthorizedKeyRemovedFirst))
435             onKeyAuthorized(cachedUnauthorizedKey, true);
436
437         return;
438     }
439
440     if (coreKeyAuthorizingEnabled(AuthorizedKeyRemovedFirst)) {
441         onKeyAuthorized(key, true);
442     } else {
443         /* We got here because the inserted key is totally new to the CAM
444          * and the core key authizing mechanisms were disabled.
445          * Let's see if any key manager wants to authorize it: we call
446          * authorizeKey() on each of the key mangers that support
447          * authorizing keys, and continue processing the key when
448          * the keyAuthorized() signal comes.
449          */
450         foreach (SignOn::AbstractKeyManager *keyManager, keyManagers) {
451             if (keyManager->supportsKeyAuthorization())
452                 keyManager->authorizeKey(key);
453         }
454     }
455 }
456
457 void CredentialsAccessManager::onKeyDisabled(const SignOn::Key key)
458 {
459     TRACE() << "Key disabled.";
460
461     insertedKeys.removeAll(key);
462
463     /* If no authorized inserted keys left, enable the suitable core key
464      * authorizing mechanism and close the secure storage. */
465     if (authorizedInsertedKeys().isEmpty()) {
466         if (processingSecureStorageEvent) {
467             /* If while processing a secure storage event, cache the disabled
468              * key if it was unauthorized and enable the
469              * `UnauthorizedKeyRemovedFirst` mechanism. */
470             if (!authorizedKeys.contains(key)) {
471                 setCoreKeyAuthorizationMech(UnauthorizedKeyRemovedFirst);
472                 cachedUnauthorizedKey = key;
473             }
474         } else  if (authorizedKeys.contains(key)) {
475             /* If the last disabled key was an authorized one enable the
476                `AuthorizedKeyRemovedFirst` mechanism and notify the user. */
477             TRACE() << "All inserted keys disabled, notifying user.";
478             if (m_secureStorageUiAdaptor == 0) {
479                 m_secureStorageUiAdaptor =
480                     new SignonSecureStorageUiAdaptor(
481                         SIGNON_UI_SERVICE,
482                         SIGNON_UI_DAEMON_OBJECTPATH,
483                         SIGNOND_BUS);
484             }
485
486             connect(m_secureStorageUiAdaptor,
487                     SIGNAL(noKeyPresentAccepted()),
488                     SLOT(onNoKeyPresentAccepted()));
489             connect(m_secureStorageUiAdaptor,
490                     SIGNAL(uiRejected()),
491                     SLOT(onSecureStorageUiRejected()));
492             connect(m_secureStorageUiAdaptor,
493                     SIGNAL(error()),
494                     SLOT(onSecureStorageUiRejected()));
495
496             m_secureStorageUiAdaptor->notifyNoKeyPresent();
497             setCoreKeyAuthorizationMech(AuthorizedKeyRemovedFirst);
498         }
499
500         TRACE() << "All keys disabled. Closing secure storage.";
501         if (isSecretsDBOpen() || m_pCryptoFileSystemManager->fileSystemIsMounted())
502             if (!closeSecretsDB())
503                 BLAME() << "Error occurred while closing secure storage.";
504
505         TRACE() << "Querying for keys.";
506         queryEncryptionKeys();
507     }
508 }
509
510 void CredentialsAccessManager::onKeyRemoved(const SignOn::Key key)
511 {
512     TRACE() << "Key removed.";
513
514     // Make sure the key is disabled:
515     onKeyDisabled(key);
516
517     if (authorizedKeys.isEmpty()) {
518         BLAME() << "Cannot remove key: no authorized keys";
519         return;
520     }
521
522     if (!encryptionKeyCanOpenStorage(key)) {
523         TRACE() << "Key is not known to the CryptoManager.";
524         return;
525     }
526
527     SignOn::Key authorizedKey = authorizedKeys.first();
528     if (!m_pCryptoFileSystemManager->removeEncryptionKey(key, authorizedKey)) {
529         BLAME() << "Failed to remove key.";
530     } else {
531         TRACE() << "Key successfully removed.";
532     }
533 }
534
535 void CredentialsAccessManager::onKeyAuthorized(const SignOn::Key key,
536                                                bool authorized)
537 {
538     TRACE() << "Key authorized:" << authorized;
539
540     if (!authorized || key.isEmpty()) return;
541
542     if (encryptionKeyCanOpenStorage(key)) {
543         TRACE() << "Encryption key already in use.";
544         if (!authorizedKeys.contains(key))
545             authorizedKeys << key;
546
547         return;
548     }
549
550     /* Make sure that the secure file system is mounted, so that the key `key`
551      * can be successfully authorized by the encryption backend.
552      */
553     if (!m_pCryptoFileSystemManager->fileSystemIsMounted()) {
554
555         m_pCryptoFileSystemManager->setEncryptionKey(authorizedKeys.first());
556     }
557
558     if (m_pCryptoFileSystemManager->fileSystemIsMounted()) {
559         /* if the secure FS is already mounted, add the new key to it */
560         if (authorizedKeys.isEmpty()) {
561             BLAME() << "No authorized keys: cannot add new key";
562             return;
563         }
564
565         SignOn::Key authorizedKey = authorizedKeys.first();
566         if (m_pCryptoFileSystemManager->addEncryptionKey(key, authorizedKey)) {
567             TRACE() << "Encryption key successfullyadded into the CryptoManager.";
568             m_pCryptoFileSystemManager->setEncryptionKey(key);
569             authorizedKeys << key;
570         } else {
571             BLAME() << "Could not store encryption key.";
572         }
573
574         /* If the key was authorized through the `UnauthorizedKeyRemovedFirst`
575          * mechanism notify the user. */
576         if (coreKeyAuthorizingEnabled(UnauthorizedKeyRemovedFirst)) {
577             //Notify only if indeed key was authorized
578             if (m_secureStorageUiAdaptor && authorizedKeys.contains(key))
579                 m_secureStorageUiAdaptor->notifyKeyAuthorized();
580
581             //cleanup secure storage ui related data
582             onSecureStorageUiClosed(DisableCoreKeyAuthorization);
583         }
584     } else if (!m_pCryptoFileSystemManager->fileSystemIsSetup()) {
585         /* if the secure FS does not exist, create it and use this new key to
586          * initialize it */
587         m_pCryptoFileSystemManager->setEncryptionKey(key);
588         if (!authorizedKeys.contains(key)) {
589             authorizedKeys << key;
590         } else {
591             BLAME() << "Couldn't create the secure FS";
592         }
593     } else  {
594         TRACE() << "Secure FS already created with another set of keys.";
595     }
596 }
597
598 void CredentialsAccessManager::queryEncryptionKeys()
599 {
600     /* TODO extend the KeyManager interface to specify if querying or authorizing
601      *      keys implies the usage of a UI, and implement a Publish/subscribe
602      *      serialized/chained pattern to remove the possibility of displaying
603      *      multiple UIs at once. */
604     foreach (SignOn::AbstractKeyManager *keyManager, keyManagers)
605         keyManager->queryKeys();
606 }
607
608 bool CredentialsAccessManager::keysAvailable() const
609 {
610     return insertedKeys.count() > 0;
611 }
612
613 void
614 CredentialsAccessManager::setCoreKeyAuthorizationMech(
615     const KeySwapAuthorizingMech mech)
616 {
617     keySwapAuthorizingMechanism = mech;
618 }
619
620 bool
621 CredentialsAccessManager::coreKeyAuthorizingEnabled(
622     const KeySwapAuthorizingMech mech) const
623 {
624     /* All flags/values checked in this method are subject to
625      * change based on secure storage UI user actions, or based
626      * on physically inserting/removing keys without any prior
627      * secure storage UI user actions. */
628
629     /* Always return false if the internal mechanism is disabled. */
630     if (keySwapAuthorizingMechanism == Disabled)
631         return false;
632
633     /* If key swapping is:
634      *      1) Remove authorized key
635      *      2) Insert unauthorized key */
636     if (mech == AuthorizedKeyRemovedFirst)
637         return keySwapAuthorizingMechanism == AuthorizedKeyRemovedFirst;
638
639     /* If key swapping is:
640      *      1) Remove unauthorized key
641      *      2) Insert authorized key */
642     if (mech == UnauthorizedKeyRemovedFirst)
643         return (keySwapAuthorizingMechanism == UnauthorizedKeyRemovedFirst)
644                && (!cachedUnauthorizedKey.isEmpty());
645
646     return false;
647 }
648
649 QSet<SignOn::Key> CredentialsAccessManager::authorizedInsertedKeys() const
650 {
651     return insertedKeys.toSet().
652         intersect(authorizedKeys.toSet());
653 }
654
655 void CredentialsAccessManager::onNoKeyPresentAccepted()
656 {
657     onSecureStorageUiClosed();
658     //enforce the setting of the core key authorization mechanism
659     setCoreKeyAuthorizationMech(AuthorizedKeyRemovedFirst);
660 }
661
662 void CredentialsAccessManager::onClearPasswordsStorage()
663 {
664     if (insertedKeys.isEmpty()) {
665         TRACE() << "No keys available. The reformatting of the secure storage skipped.";
666         onSecureStorageUiClosed(DisableCoreKeyAuthorization);
667         return;
668     }
669
670     TRACE() << "Reformatting secure storage.";
671
672     /* Here we use the 1st inserted unauthorized key for storage reformatting.
673      * This key was present before the emitting of the secure storage event that
674      * lead to the UI decision to reformat the passwords storage. */
675     m_pCryptoFileSystemManager->setEncryptionKey(insertedKeys.first());
676     if (m_pCryptoFileSystemManager->setupFileSystem()) {
677         authorizedKeys.clear();
678         authorizedKeys << insertedKeys.first();
679
680         if (m_secureStorageUiAdaptor) {
681             m_secureStorageUiAdaptor->notifyStorageCleared();
682         }
683
684     } else {
685         BLAME() << "Failed to reformat secure storage file system.";
686     }
687
688     onSecureStorageUiClosed(DisableCoreKeyAuthorization);
689 }
690
691 void
692 CredentialsAccessManager::onSecureStorageUiClosed(
693     const StorageUiCleanupFlags options)
694 {
695     if (m_secureStorageUiAdaptor) {
696         delete m_secureStorageUiAdaptor;
697         m_secureStorageUiAdaptor = 0;
698     }
699
700     if (processingSecureStorageEvent) {
701         processingSecureStorageEvent = false;
702         replyToSecureStorageEventNotifiers();
703     }
704
705     if (options.testFlag(DisableCoreKeyAuthorization)) {
706         setCoreKeyAuthorizationMech(Disabled);
707         cachedUnauthorizedKey.clear();
708     }
709 }
710
711 void CredentialsAccessManager::onSecureStorageUiRejected()
712 {
713     onSecureStorageUiClosed(DisableCoreKeyAuthorization);
714 }
715
716 void CredentialsAccessManager::replyToSecureStorageEventNotifiers()
717 {
718     TRACE();
719     //Notify secure storage notifiers if any.
720     int eventType = SIGNON_SECURE_STORAGE_NOT_AVAILABLE;
721     if (m_pCredentialsDB->isSecretsDBOpen())
722         eventType = SIGNON_SECURE_STORAGE_AVAILABLE;
723
724     // Signal objects that posted secure storage not available events
725     foreach (EventSender object, m_secureStorageEventNotifiers) {
726         if (object.isNull())
727             continue;
728
729         SecureStorageEvent *secureStorageEvent =
730             new SecureStorageEvent((QEvent::Type)eventType);
731
732         QCoreApplication::postEvent(
733             object.data(),
734             secureStorageEvent,
735             Qt::HighEventPriority);
736     }
737
738     m_secureStorageEventNotifiers.clear();
739 }
740
741 bool CredentialsAccessManager::processSecureStorageEvent()
742 {
743     /* If keys have been inserted but none authorized notify the signon UI.
744      * If keys are not present at all - the scenario is not handled
745      * by this event hander, as Signon UI was already informed about
746      * this in the creadentials query dilog display context. */
747     if (!insertedKeys.isEmpty()) {
748         TRACE() << "Secure Storage not available notifying user.";
749         if (m_secureStorageUiAdaptor == 0) {
750             m_secureStorageUiAdaptor =
751                 new SignonSecureStorageUiAdaptor(
752                     SIGNON_UI_SERVICE,
753                     SIGNON_UI_DAEMON_OBJECTPATH,
754                     SIGNOND_BUS);
755         }
756
757         connect(m_secureStorageUiAdaptor,
758                 SIGNAL(clearPasswordsStorage()),
759                 SLOT(onClearPasswordsStorage()));
760         connect(m_secureStorageUiAdaptor,
761                 SIGNAL(uiRejected()),
762                 SLOT(onSecureStorageUiRejected()));
763         connect(m_secureStorageUiAdaptor,
764                 SIGNAL(error()),
765                 SLOT(onSecureStorageUiRejected()));
766
767         m_secureStorageUiAdaptor->notifyNoAuthorizedKeyPresent();
768         processingSecureStorageEvent = true;
769         return true;
770     }
771     return false;
772 }
773
774
775 void CredentialsAccessManager::customEvent(QEvent *event)
776 {
777     TRACE() << "Custom event received.";
778     if (event->type() != SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
779         QObject::customEvent(event);
780         return;
781     }
782
783     SecureStorageEvent *localEvent =
784         static_cast<SecureStorageEvent *>(event);
785
786     /* All senders of this event will receive a reply when
787      * the secure storage becomes available or an error occurs. */
788     m_secureStorageEventNotifiers.append(localEvent->m_sender);
789
790     TRACE() << "Processing secure storage not available event.";
791     if ((localEvent == 0) || (m_pCredentialsDB == 0)) {
792         replyToSecureStorageEventNotifiers();
793         QObject::customEvent(event);
794         return;
795     }
796
797     //Double check if the secrets DB is indeed unavailable
798     if (m_pCredentialsDB->isSecretsDBOpen()) {
799         replyToSecureStorageEventNotifiers();
800         QObject::customEvent(event);
801         return;
802     }
803
804     if (!processingSecureStorageEvent) {
805         if (!processSecureStorageEvent()) {
806             /* If by any chance the event wasn't properly processed
807              * reply immediately. */
808             replyToSecureStorageEventNotifiers();
809         }
810     } else {
811         TRACE() << "Already processing a secure storage not available event.";
812     }
813
814     QObject::customEvent(event);
815 }
816
817 void CredentialsAccessManager::onEncryptedFSMounted()
818 {
819     TRACE();
820     if (!isSecretsDBOpen()) {
821         if (openSecretsDB()) {
822             TRACE() << "Secrets DB opened.";
823         } else {
824             BLAME() << "Failed to open secrets DB.";
825         }
826     } else {
827         BLAME() << "Secrets DB already opened?";
828     }
829 }
830
831 void CredentialsAccessManager::onEncryptedFSUnmounting()
832 {
833     TRACE();
834     if (isSecretsDBOpen()) {
835         m_pCredentialsDB->closeSecretsDB();
836     }
837 }
838