|
signon
8.40
|
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 }