Fixed onKeyDisabled algorhythm. Core key authorizing mechanisms get enabled upon
[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_error = NoError;
142 }
143
144 bool CredentialsAccessManager::init(const CAMConfiguration &camConfiguration)
145 {
146     if (m_isInitialized) {
147         TRACE() << "CAM already initialized.";
148         m_error = AlreadyInitialized;
149         return false;
150     }
151
152     m_CAMConfiguration = camConfiguration;
153
154     QBuffer config;
155     m_CAMConfiguration.serialize(&config);
156     TRACE() << "\n\nInitualizing CredentialsAccessManager with configuration: " << config.data();
157
158     if (m_CAMConfiguration.m_useEncryption) {
159         //Initialize CryptoManager
160         m_pCryptoFileSystemManager = new CryptoManager(this);
161         m_pCryptoFileSystemManager->setFileSystemPath(m_CAMConfiguration.encryptedFSPath());
162         m_pCryptoFileSystemManager->setFileSystemSize(m_CAMConfiguration.m_fileSystemSize);
163         m_pCryptoFileSystemManager->setFileSystemType(m_CAMConfiguration.m_fileSystemType);
164
165         // Initialize all key managers
166         foreach (SignOn::AbstractKeyManager *keyManager, keyManagers) {
167             connect(keyManager,
168                     SIGNAL(keyInserted(const SignOn::Key)),
169                     SLOT(onKeyInserted(const SignOn::Key)));
170             connect(keyManager,
171                     SIGNAL(keyDisabled(const SignOn::Key)),
172                     SLOT(onKeyDisabled(const SignOn::Key)));
173             connect(keyManager,
174                     SIGNAL(keyRemoved(const SignOn::Key)),
175                     SLOT(onKeyRemoved(const SignOn::Key)));
176             if (keyManager->supportsKeyAuthorization()) {
177                 connect(keyManager,
178                         SIGNAL(keyAuthorized(const SignOn::Key, bool)),
179                         SLOT(onKeyAuthorized(const SignOn::Key, bool)));
180             }
181             keyManager->setup();
182         }
183     }
184
185     m_isInitialized = true;
186     m_error = NoError;
187
188     TRACE() << "CredentialsAccessManager successfully initialized...";
189     return true;
190 }
191
192 void CredentialsAccessManager::addKeyManager(
193     SignOn::AbstractKeyManager *keyManager)
194 {
195     keyManagers.append(keyManager);
196 }
197
198 bool CredentialsAccessManager::openSecretsDB()
199 {
200     //todo remove this variable after LUKS implementation becomes stable.
201     QString dbPath;
202
203     if (m_CAMConfiguration.m_useEncryption) {
204         dbPath = m_pCryptoFileSystemManager->fileSystemMountPath()
205             + QDir::separator()
206             + m_CAMConfiguration.m_dbName;
207
208         if (!fileSystemDeployed()) {
209             if (!deployCredentialsSystem())
210                 return false;
211         }
212
213         if (!m_pCryptoFileSystemManager->fileSystemMounted()) {
214             if (!m_pCryptoFileSystemManager->mountFileSystem()) {
215                 m_error = CredentialsDbMountFailed;
216                 return false;
217             }
218         }
219     } else {
220         dbPath = m_CAMConfiguration.metadataDBPath() + QLatin1String(".creds");
221     }
222
223     TRACE() << "Database name: [" << dbPath << "]";
224
225     if (!m_pCredentialsDB->openSecretsDB(dbPath))
226         return false;
227
228     m_error = NoError;
229     return true;
230 }
231
232 bool CredentialsAccessManager::isSecretsDBOpen()
233 {
234     return m_pCredentialsDB->isSecretsDBOpen();
235 }
236
237 bool CredentialsAccessManager::closeSecretsDB()
238 {
239     m_pCredentialsDB->closeSecretsDB();
240
241     if (m_CAMConfiguration.m_useEncryption) {
242         if (!m_pCryptoFileSystemManager->unmountFileSystem()) {
243             m_error = CredentialsDbUnmountFailed;
244             return false;
245         }
246     }
247
248     return true;
249 }
250
251 bool CredentialsAccessManager::openMetaDataDB()
252 {
253     QString dbPath = m_CAMConfiguration.metadataDBPath();
254     QFileInfo fileInfo(dbPath);
255     if (!fileInfo.exists()) {
256         QDir storageDir(fileInfo.dir());
257         if (!storageDir.mkpath(storageDir.path())) {
258             BLAME() << "Could not create storage directory:" <<
259                 storageDir.path();
260             m_error = CredentialsDbSetupFailed;
261             return false;
262         }
263     }
264
265     m_pCredentialsDB = new CredentialsDB(dbPath);
266
267     if (!m_pCredentialsDB->init()) {
268         m_error = CredentialsDbConnectionError;
269         return false;
270     }
271
272     return true;
273 }
274
275 void CredentialsAccessManager::closeMetaDataDB()
276 {
277     if (m_pCredentialsDB) {
278         delete m_pCredentialsDB;
279         m_pCredentialsDB = NULL;
280     }
281 }
282
283 bool CredentialsAccessManager::openCredentialsSystem()
284 {
285     RETURN_IF_NOT_INITIALIZED(false);
286
287     if (!openMetaDataDB()) {
288         BLAME() << "Couldn't open metadata DB!";
289         return false;
290     }
291
292     if (!openSecretsDB()) {
293         BLAME() << "Failed to open secrets DB.";
294         /* Even if the secrets DB couldn't be opened, signond is still usable:
295          * that's why we return "true" anyways. */
296     }
297
298     m_systemOpened = true;
299     return true;
300 }
301
302 bool CredentialsAccessManager::closeCredentialsSystem()
303 {
304     RETURN_IF_NOT_INITIALIZED(false);
305
306     if (!credentialsSystemOpened())
307         return true;
308
309     bool allClosed = true;
310     if (isSecretsDBOpen() && !closeSecretsDB())
311         allClosed = false;
312
313     closeMetaDataDB();
314
315     m_error = NoError;
316     m_systemOpened = false;
317     return allClosed;
318 }
319
320 bool CredentialsAccessManager::deleteCredentialsSystem()
321 {
322     RETURN_IF_NOT_INITIALIZED(false);
323
324     if (m_systemOpened && !closeCredentialsSystem()) {
325         /* The close operation failed: we cannot proceed */
326         return false;
327     }
328
329     m_error = NoError;
330
331     if (m_CAMConfiguration.m_useEncryption) {
332         if (!m_pCryptoFileSystemManager->deleteFileSystem())
333             m_error = CredentialsDbDeletionFailed;
334     } else {
335         QFile dbFile(m_CAMConfiguration.m_dbName);
336         if (dbFile.exists()) {
337             if (!dbFile.remove())
338                 m_error = CredentialsDbDeletionFailed;
339         }
340     }
341
342     return m_error == NoError;
343 }
344
345 CredentialsDB *CredentialsAccessManager::credentialsDB() const
346 {
347     RETURN_IF_NOT_INITIALIZED(NULL);
348
349     return m_pCredentialsDB;
350 }
351
352 bool CredentialsAccessManager::deployCredentialsSystem()
353 {
354     if (m_CAMConfiguration.m_useEncryption) {
355         if (!m_pCryptoFileSystemManager->setupFileSystem()) {
356             m_error = CredentialsDbSetupFailed;
357             return false;
358         }
359     }
360     return true;
361 }
362
363 bool CredentialsAccessManager::fileSystemDeployed()
364 {
365     return QFile::exists(m_pCryptoFileSystemManager->fileSystemPath());
366 }
367
368 bool CredentialsAccessManager::encryptionKeyCanOpenStorage(const QByteArray &key)
369 {
370     if (!fileSystemDeployed()) {
371         TRACE() << "Secure FS not deployed, deploying now...";
372         m_pCryptoFileSystemManager->setEncryptionKey(key);
373
374         if (!deployCredentialsSystem()) {
375             BLAME() << "Could not deploy encrypted file system.";
376             return false;
377         }
378     }
379
380     if (m_pCryptoFileSystemManager->encryptionKeyInUse(key)) {
381         TRACE() << "Key already in use.";
382         if (!isSecretsDBOpen()) {
383             if (openSecretsDB()) {
384                 TRACE() << "Secrets DB opened.";
385             } else {
386                 BLAME() << "Failed to open secrets DB.";
387             }
388         } else {
389             TRACE() << "Secrets DB already opened.";
390         }
391
392         return true;
393     }
394
395     return false;
396 }
397
398 void CredentialsAccessManager::onKeyInserted(const SignOn::Key key)
399 {
400     TRACE() << "Key inserted.";
401
402     if (!m_systemReady) {
403         /* Check that at least one non empty key was signaled or if not so,
404          * that all key managers have signaled at least one key. */
405         ++readyKeyManagersCounter;
406         if (!key.isEmpty() || (readyKeyManagersCounter == keyManagers.count())) {
407             m_systemReady = true;
408             emit credentialsSystemReadySignal();
409         }
410     }
411
412     if (key.isEmpty()) return;
413
414     //Close the secure storage UI 1st
415     if (m_secureStorageUiAdaptor)
416         m_secureStorageUiAdaptor->closeUi();
417
418     insertedKeys.append(key);
419
420     /* The `key in use` check will attempt to mount using the new key if
421        the file system is not already mounted
422     */
423     if (encryptionKeyCanOpenStorage(key)) {
424         TRACE() << "Key already in use.";
425         if (!authorizedKeys.contains(key))
426             authorizedKeys << key;
427
428         if (coreKeyAuthorizingEnabled(UnauthorizedKeyRemovedFirst))
429             onKeyAuthorized(cachedUnauthorizedKey, true);
430
431         return;
432     }
433
434     if (coreKeyAuthorizingEnabled(AuthorizedKeyRemovedFirst)) {
435         onKeyAuthorized(key, true);
436     } else {
437         /* We got here because the inserted key is totally new to the CAM
438          * and the core key authizing mechanisms were disabled.
439          * Let's see if any key manager wants to authorize it: we call
440          * authorizeKey() on each of the key mangers that support
441          * authorizing keys, and continue processing the key when
442          * the keyAuthorized() signal comes.
443          */
444         foreach (SignOn::AbstractKeyManager *keyManager, keyManagers) {
445             if (keyManager->supportsKeyAuthorization())
446                 keyManager->authorizeKey(key);
447         }
448     }
449 }
450
451 void CredentialsAccessManager::onKeyDisabled(const SignOn::Key key)
452 {
453     TRACE() << "Key disabled.";
454
455     insertedKeys.removeAll(key);
456
457     /* If no authorized inserted keys left, enable the suitable core key
458      * authorizing mechanism and close the secure storage. */
459     if (authorizedInsertedKeys().isEmpty()) {
460         if (processingSecureStorageEvent) {
461             /* If while processing a secure storage event, cache the disabled
462              * key if it was unauthorized and enable the
463              * `UnauthorizedKeyRemovedFirst` mechanism. */
464             if (!authorizedKeys.contains(key)) {
465                 setCoreKeyAuthorizationMech(UnauthorizedKeyRemovedFirst);
466                 cachedUnauthorizedKey = key;
467             }
468         } else  if (authorizedKeys.contains(key)) {
469             /* If the last disabled key was an authorized one enable the
470                `AuthorizedKeyRemovedFirst` mechanism and notify the user. */
471             TRACE() << "All inserted keys disabled, notifying user.";
472             if (m_secureStorageUiAdaptor == 0) {
473                 m_secureStorageUiAdaptor =
474                     new SignonSecureStorageUiAdaptor(
475                         SIGNON_UI_SERVICE,
476                         SIGNON_UI_DAEMON_OBJECTPATH,
477                         SIGNOND_BUS);
478             }
479
480             connect(m_secureStorageUiAdaptor,
481                     SIGNAL(uiClosed()),
482                     SLOT(onSecureStorageUiClosed()));
483             connect(m_secureStorageUiAdaptor,
484                     SIGNAL(error()),
485                     SLOT(onSecureStorageUiClosed()));
486
487             m_secureStorageUiAdaptor->notifyNoKeyPresent();
488             setCoreKeyAuthorizationMech(AuthorizedKeyRemovedFirst);
489         }
490
491         TRACE() << "All keys disabled. Closing secure storage.";
492         if (isSecretsDBOpen() || m_pCryptoFileSystemManager->fileSystemMounted())
493             if (!closeSecretsDB())
494                 BLAME() << "Error occurred while closing secure storage.";
495
496         TRACE() << "Querying for keys.";
497         queryEncryptionKeys();
498     }
499 }
500
501 void CredentialsAccessManager::onKeyRemoved(const SignOn::Key key)
502 {
503     TRACE() << "Key removed.";
504
505     // Make sure the key is disabled:
506     onKeyDisabled(key);
507
508     if (authorizedKeys.isEmpty()) {
509         BLAME() << "Cannot remove key: no authorized keys";
510         return;
511     }
512
513     if (!encryptionKeyCanOpenStorage(key)) {
514         TRACE() << "Key is not known to the CryptoManager.";
515         return;
516     }
517
518     SignOn::Key authorizedKey = authorizedKeys.first();
519     if (!m_pCryptoFileSystemManager->removeEncryptionKey(key, authorizedKey)) {
520         BLAME() << "Failed to remove key.";
521     } else {
522         TRACE() << "Key successfully removed.";
523     }
524 }
525
526 void CredentialsAccessManager::onKeyAuthorized(const SignOn::Key key,
527                                                bool authorized)
528 {
529     TRACE() << "Key authorized:" << authorized;
530
531     if (!authorized || key.isEmpty()) return;
532
533     if (encryptionKeyCanOpenStorage(key)) {
534         TRACE() << "Encryption key already in use.";
535         if (!authorizedKeys.contains(key))
536             authorizedKeys << key;
537
538         return;
539     }
540
541     /* Make sure that the secure file system is mounted, so that the key `key`
542      * can be successfully authorized by the encryption backend.
543      */
544     if (!m_pCryptoFileSystemManager->fileSystemMounted()) {
545
546         m_pCryptoFileSystemManager->setEncryptionKey(authorizedKeys.first());
547         if (openSecretsDB()) {
548             TRACE() << "Secrets DB opened.";
549         } else {
550             BLAME() << "Failed to open secrets DB.";
551         }
552     }
553
554     if (m_pCryptoFileSystemManager->fileSystemMounted()) {
555         /* if the secure FS is already mounted, add the new key to it */
556         if (authorizedKeys.isEmpty()) {
557             BLAME() << "No authorized keys: cannot add new key";
558             return;
559         }
560
561         SignOn::Key authorizedKey = authorizedKeys.first();
562         if (m_pCryptoFileSystemManager->addEncryptionKey(key, authorizedKey)) {
563             TRACE() << "Encryption key successfullyadded into the CryptoManager.";
564             m_pCryptoFileSystemManager->setEncryptionKey(key);
565             authorizedKeys << key;
566         } else {
567             BLAME() << "Could not store encryption key.";
568         }
569
570         /* If the key was authorized through the `UnauthorizedKeyRemovedFirst`
571          * mechanism notify the user. */
572         if (coreKeyAuthorizingEnabled(UnauthorizedKeyRemovedFirst)) {
573             //Notify only if indeed key was authorized
574             if (m_secureStorageUiAdaptor && authorizedKeys.contains(key))
575                 m_secureStorageUiAdaptor->notifyKeyAuthorized();
576
577             //reset secure storage ui related data
578             onSecureStorageUiClosed();
579         }
580     } else if (!fileSystemDeployed()) {
581         /* if the secure FS does not exist, create it and use this new key to
582          * initialize it */
583         m_pCryptoFileSystemManager->setEncryptionKey(key);
584         if (openSecretsDB() && !authorizedKeys.contains(key)) {
585             authorizedKeys << key;
586         } else {
587             BLAME() << "Couldn't create the secure FS";
588         }
589     } else  {
590         TRACE() << "Secure FS already created with another set of keys.";
591     }
592 }
593
594 void CredentialsAccessManager::queryEncryptionKeys()
595 {
596     /* TODO extend the KeyManager interface to specify if querying or authorizing
597      *      keys implies the usage of a UI, and implement a Publish/subscribe
598      *      serialized/chained pattern to remove the possibility of displaying
599      *      multiple UIs at once. */
600     foreach (SignOn::AbstractKeyManager *keyManager, keyManagers)
601         keyManager->queryKeys();
602 }
603
604 bool CredentialsAccessManager::keysAvailable() const
605 {
606     return insertedKeys.count() > 0;
607 }
608
609 void
610 CredentialsAccessManager::setCoreKeyAuthorizationMech(
611     const KeySwapAuthorizingMech mech)
612 {
613     keySwapAuthorizingMechanism = mech;
614 }
615
616 bool
617 CredentialsAccessManager::coreKeyAuthorizingEnabled(
618     const KeySwapAuthorizingMech mech) const
619 {
620     /* All flags/values checked in this method are subject to
621      * change based on secure storage UI user actions, or based
622      * on physically inserting/removing keys without any prior
623      * secure storage UI user actions. */
624
625     /* Always return false if the internal mechanism is disabled. */
626     if (keySwapAuthorizingMechanism == Disabled)
627         return false;
628
629     /* If key swapping is:
630      *      1) Remove authorized key
631      *      2) Insert unauthorized key */
632     if (mech == AuthorizedKeyRemovedFirst)
633         return keySwapAuthorizingMechanism == AuthorizedKeyRemovedFirst;
634
635     /* If key swapping is:
636      *      1) Remove unauthorized key
637      *      2) Insert authorized key */
638     if (mech == UnauthorizedKeyRemovedFirst)
639         return (keySwapAuthorizingMechanism == UnauthorizedKeyRemovedFirst)
640                && (!cachedUnauthorizedKey.isEmpty());
641
642     return false;
643 }
644
645 QSet<SignOn::Key> CredentialsAccessManager::authorizedInsertedKeys() const
646 {
647     return insertedKeys.toSet().
648         intersect(authorizedKeys.toSet());
649 }
650
651 void CredentialsAccessManager::onClearPasswordsStorage()
652 {
653     if (insertedKeys.isEmpty()) {
654         TRACE() << "No keys available. The reformatting of the secure storage skipped.";
655         onSecureStorageUiClosed();
656         return;
657     }
658
659     TRACE() << "Reformatting secure storage.";
660
661     /* Here we use the 1st inserted unauthorized key for storage reformatting.
662      * This key was present before the emitting of the secure storage event that
663      * lead to the UI decision to reformat the passwords storage. */
664     m_pCryptoFileSystemManager->setEncryptionKey(insertedKeys.first());
665     if (m_pCryptoFileSystemManager->setupFileSystem()) {
666         authorizedKeys.clear();
667         authorizedKeys << insertedKeys.first();
668
669         if (!openSecretsDB())
670             BLAME() << "Couldn't open secreds DB.";
671
672         if (m_secureStorageUiAdaptor) {
673             m_secureStorageUiAdaptor->notifyStorageCleared();
674         }
675
676     } else {
677         BLAME() << "Failed to reformat secure storage file system.";
678     }
679
680     onSecureStorageUiClosed();
681 }
682
683 void CredentialsAccessManager::onSecureStorageUiClosed()
684 {
685     TRACE();
686     cachedUnauthorizedKey.clear();
687     setCoreKeyAuthorizationMech(Disabled);
688
689     if (m_secureStorageUiAdaptor) {
690         delete m_secureStorageUiAdaptor;
691         m_secureStorageUiAdaptor = 0;
692     }
693
694     if (processingSecureStorageEvent) {
695         processingSecureStorageEvent = false;
696         replyToSecureStorageEventNotifiers();
697     }
698 }
699
700 void CredentialsAccessManager::replyToSecureStorageEventNotifiers()
701 {
702     TRACE();
703     //Notify secure storage notifiers if any.
704     int eventType = SIGNON_SECURE_STORAGE_NOT_AVAILABLE;
705     if (m_pCredentialsDB->isSecretsDBOpen())
706         eventType = SIGNON_SECURE_STORAGE_AVAILABLE;
707
708     // Signal objects that posted secure storage not available events
709     foreach (EventSender object, m_secureStorageEventNotifiers) {
710         if (object.isNull())
711             continue;
712
713         SecureStorageEvent *secureStorageEvent =
714             new SecureStorageEvent((QEvent::Type)eventType);
715
716         QCoreApplication::postEvent(
717             object.data(),
718             secureStorageEvent,
719             Qt::HighEventPriority);
720     }
721
722     m_secureStorageEventNotifiers.clear();
723 }
724
725 bool CredentialsAccessManager::processSecureStorageEvent()
726 {
727     /* If keys have been inserted but none authorized notify the signon UI.
728      * If keys are not present at all - the scenario is not handled
729      * by this event hander, as Signon UI was already informed about
730      * this in the creadentials query dilog display context. */
731     if (!insertedKeys.isEmpty()) {
732         TRACE() << "Secure Storage not available notifying user.";
733         if (m_secureStorageUiAdaptor == 0) {
734             m_secureStorageUiAdaptor =
735                 new SignonSecureStorageUiAdaptor(
736                     SIGNON_UI_SERVICE,
737                     SIGNON_UI_DAEMON_OBJECTPATH,
738                     SIGNOND_BUS);
739         }
740
741         connect(m_secureStorageUiAdaptor,
742                 SIGNAL(clearPasswordsStorage()),
743                 SLOT(onClearPasswordsStorage()));
744         connect(m_secureStorageUiAdaptor,
745                 SIGNAL(uiClosed()),
746                 SLOT(onSecureStorageUiClosed()));
747         connect(m_secureStorageUiAdaptor,
748                 SIGNAL(error()),
749                 SLOT(onSecureStorageUiClosed()));
750
751         m_secureStorageUiAdaptor->notifyNoAuthorizedKeyPresent();
752         processingSecureStorageEvent = true;
753         return true;
754     }
755     return false;
756 }
757
758
759 void CredentialsAccessManager::customEvent(QEvent *event)
760 {
761     TRACE() << "Custom event received.";
762     if (event->type() != SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
763         QObject::customEvent(event);
764         return;
765     }
766
767     SecureStorageEvent *localEvent =
768         static_cast<SecureStorageEvent *>(event);
769
770     /* All senders of this event will receive a reply when
771      * the secure storage becomes available or an error occurs. */
772     m_secureStorageEventNotifiers.append(localEvent->m_sender);
773
774     TRACE() << "Processing secure storage not available event.";
775     if ((localEvent == 0) || (m_pCredentialsDB == 0)) {
776         replyToSecureStorageEventNotifiers();
777         QObject::customEvent(event);
778         return;
779     }
780
781     //Double check if the secrets DB is indeed unavailable
782     if (m_pCredentialsDB->isSecretsDBOpen()) {
783         replyToSecureStorageEventNotifiers();
784         QObject::customEvent(event);
785         return;
786     }
787
788     if (!processingSecureStorageEvent) {
789         if (!processSecureStorageEvent()) {
790             /* If by any chance the event wasn't properly processed
791              * reply immediately. */
792             replyToSecureStorageEventNotifiers();
793         }
794     } else {
795         TRACE() << "Already processing a secure storage not available event.";
796     }
797
798     QObject::customEvent(event);
799 }