signon
8.58
|
00001 /* 00002 * This file is part of signon 00003 * 00004 * Copyright (C) 2009-2010 Nokia Corporation. 00005 * Copyright (C) 2013-2015 Canonical Ltd. 00006 * 00007 * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com> 00008 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> 00009 * 00010 * This library is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public License 00012 * version 2.1 as published by the Free Software Foundation. 00013 * 00014 * This library is distributed in the hope that it will be useful, but 00015 * WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00022 * 02110-1301 USA 00023 */ 00024 00025 extern "C" { 00026 #include <sys/socket.h> 00027 #include <sys/stat.h> 00028 #include <sys/types.h> 00029 } 00030 00031 #define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(4, 0, 0) 00032 00033 #include <QtDebug> 00034 #include <QDir> 00035 #include <QDBusConnection> 00036 #include <QDBusMessage> 00037 #include <QDBusMetaType> 00038 #include <QPluginLoader> 00039 #include <QProcessEnvironment> 00040 #include <QSocketNotifier> 00041 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) 00042 #include <QStandardPaths> 00043 #endif 00044 00045 #include "SignOn/misc.h" 00046 00047 #include "signondaemon.h" 00048 #include "signond-common.h" 00049 #include "signontrace.h" 00050 #include "signondaemonadaptor.h" 00051 #include "signonidentity.h" 00052 #include "signonauthsession.h" 00053 #include "accesscontrolmanagerhelper.h" 00054 #include "backupifadaptor.h" 00055 00056 #define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_) do { \ 00057 if (m_pCAMManager && !m_pCAMManager->credentialsSystemOpened()) { \ 00058 setLastError(internalServerErrName, \ 00059 internalServerErrStr + \ 00060 QLatin1String("Could not access Signon " \ 00061 "Database.")); \ 00062 return _ret_arg_; \ 00063 } \ 00064 } while(0) 00065 00066 #define BACKUP_DIR_NAME() \ 00067 (QDir::separator() + QLatin1String("backup")) 00068 00069 using namespace SignOn; 00070 00071 namespace SignonDaemonNS { 00072 00073 /* ---------------------- SignonDaemonConfiguration ---------------------- */ 00074 00075 SignonDaemonConfiguration::SignonDaemonConfiguration(): 00076 m_pluginsDir(QLatin1String(SIGNOND_PLUGINS_DIR)), 00077 m_extensionsDir(QLatin1String(SIGNOND_EXTENSIONS_DIR)), 00078 m_camConfiguration(), 00079 m_daemonTimeout(0), // 0 = no timeout 00080 m_identityTimeout(300),//secs 00081 m_authSessionTimeout(300)//secs 00082 {} 00083 00084 SignonDaemonConfiguration::~SignonDaemonConfiguration() 00085 { 00086 TRACE(); 00087 } 00088 00089 /* 00090 --- Configuration file template --- 00091 00092 [General] 00093 UseSecureStorage=yes 00094 StoragePath=~/.signon/ 00095 ;0 - fatal, 1 - critical(default), 2 - info/debug 00096 LoggingLevel=1 00097 00098 [SecureStorage] 00099 FileSystemName=signonfs 00100 Size=8 00101 FileSystemType=ext2 00102 00103 [ObjectTimeouts] 00104 IdentityTimeout=300 00105 AuthSessionTimeout=300 00106 */ 00107 void SignonDaemonConfiguration::load() 00108 { 00109 QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); 00110 00111 //Daemon configuration file 00112 00113 QSettings::setPath(QSettings::NativeFormat, QSettings::SystemScope, 00114 environment.value(QLatin1String("SSO_CONFIG_FILE_DIR"), 00115 QLatin1String("/etc"))); 00116 00117 QSettings settings(QLatin1String("signond")); 00118 00119 int loggingLevel = 00120 settings.value(QLatin1String("LoggingLevel"), 1).toInt(); 00121 setLoggingLevel(loggingLevel); 00122 00123 QString cfgStoragePath = 00124 settings.value(QLatin1String("StoragePath")).toString(); 00125 if (!cfgStoragePath.isEmpty()) { 00126 QString storagePath = QDir(cfgStoragePath).path(); 00127 m_camConfiguration.setStoragePath(storagePath); 00128 } else { 00129 QString xdgConfigHome = QLatin1String(qgetenv("XDG_CONFIG_HOME")); 00130 if (xdgConfigHome.isEmpty()) 00131 xdgConfigHome = QDir::homePath() + QLatin1String("/.config"); 00132 m_camConfiguration.setStoragePath(xdgConfigHome + 00133 QLatin1String("/signond")); 00134 } 00135 00136 // Secure storage 00137 00138 // Support legacy setting "UseSecureStorage" 00139 QString useSecureStorage = 00140 settings.value(QLatin1String("UseSecureStorage")).toString(); 00141 if (useSecureStorage == QLatin1String("yes") || 00142 useSecureStorage == QLatin1String("true")) { 00143 m_camConfiguration.addSetting(QLatin1String("CryptoManager"), 00144 QLatin1String("cryptsetup")); 00145 } 00146 00147 settings.beginGroup(QLatin1String("SecureStorage")); 00148 00149 QVariantMap storageOptions; 00150 foreach (const QString &key, settings.childKeys()) { 00151 m_camConfiguration.addSetting(key, settings.value(key)); 00152 } 00153 00154 settings.endGroup(); 00155 00156 //Timeouts 00157 settings.beginGroup(QLatin1String("ObjectTimeouts")); 00158 00159 bool isOk = false; 00160 uint aux = settings.value(QLatin1String("IdentityTimeout")).toUInt(&isOk); 00161 if (isOk) 00162 m_identityTimeout = aux; 00163 00164 aux = settings.value(QLatin1String("AuthSessionTimeout")).toUInt(&isOk); 00165 if (isOk) 00166 m_authSessionTimeout = aux; 00167 00168 aux = settings.value(QLatin1String("DaemonTimeout")).toUInt(&isOk); 00169 if (isOk) 00170 m_daemonTimeout = aux; 00171 00172 settings.endGroup(); 00173 00174 //Environment variables 00175 00176 int value = 0; 00177 if (environment.contains(QLatin1String("SSO_DAEMON_TIMEOUT"))) { 00178 value = environment.value( 00179 QLatin1String("SSO_DAEMON_TIMEOUT")).toInt(&isOk); 00180 if (value > 0 && isOk) m_daemonTimeout = value; 00181 } 00182 00183 if (environment.contains(QLatin1String("SSO_IDENTITY_TIMEOUT"))) { 00184 value = environment.value( 00185 QLatin1String("SSO_IDENTITY_TIMEOUT")).toInt(&isOk); 00186 if (value > 0 && isOk) m_identityTimeout = value; 00187 } 00188 00189 if (environment.contains(QLatin1String("SSO_AUTHSESSION_TIMEOUT"))) { 00190 value = environment.value( 00191 QLatin1String("SSO_AUTHSESSION_TIMEOUT")).toInt(&isOk); 00192 if (value > 0 && isOk) m_authSessionTimeout = value; 00193 } 00194 00195 if (environment.contains(QLatin1String("SSO_LOGGING_LEVEL"))) { 00196 value = environment.value( 00197 QLatin1String("SSO_LOGGING_LEVEL")).toInt(&isOk); 00198 if (isOk) 00199 setLoggingLevel(value); 00200 } 00201 00202 QString logOutput = environment.value(QLatin1String("SSO_LOGGING_OUTPUT"), 00203 QLatin1String("syslog")); 00204 SignonTrace::initialize(logOutput == QLatin1String("syslog") ? 00205 SignonTrace::Syslog : SignonTrace::Stdout); 00206 00207 if (environment.contains(QLatin1String("SSO_STORAGE_PATH"))) { 00208 m_camConfiguration.setStoragePath( 00209 environment.value(QLatin1String("SSO_STORAGE_PATH"))); 00210 } 00211 00212 if (environment.contains(QLatin1String("SSO_PLUGINS_DIR"))) { 00213 m_pluginsDir = environment.value(QLatin1String("SSO_PLUGINS_DIR")); 00214 } 00215 00216 if (environment.contains(QLatin1String("SSO_EXTENSIONS_DIR"))) { 00217 m_extensionsDir = 00218 environment.value(QLatin1String("SSO_EXTENSIONS_DIR")); 00219 } 00220 00221 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) 00222 QString runtimeDir = 00223 QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation); 00224 #else 00225 QString runtimeDir = environment.value(QLatin1String("XDG_RUNTIME_DIR")); 00226 #endif 00227 if (!runtimeDir.isEmpty()) { 00228 QString socketFileName = 00229 QString::fromLatin1("%1/" SIGNOND_SOCKET_FILENAME).arg(runtimeDir); 00230 QDir socketDir = QFileInfo(socketFileName).absoluteDir(); 00231 if (!socketDir.exists() && !socketDir.mkpath(socketDir.path())) { 00232 BLAME() << "Cannot create socket directory" << socketDir; 00233 } else { 00234 m_busAddress = 00235 QString::fromLatin1("unix:path=%1").arg(socketFileName); 00236 } 00237 } else { 00238 BLAME() << "XDG_RUNTIME_DIR unset, disabling p2p bus"; 00239 } 00240 } 00241 00242 /* ---------------------- SignonDaemon ---------------------- */ 00243 00244 const QString internalServerErrName = SIGNOND_INTERNAL_SERVER_ERR_NAME; 00245 const QString internalServerErrStr = SIGNOND_INTERNAL_SERVER_ERR_STR; 00246 00247 static int sigFd[2]; 00248 00249 SignonDaemon *SignonDaemon::m_instance = NULL; 00250 00251 SignonDaemon::SignonDaemon(QObject *parent): 00252 QObject(parent), 00253 m_configuration(0), 00254 m_pCAMManager(0), 00255 m_dbusServer(0) 00256 { 00257 // Files created by signond must be unreadable by "other" 00258 umask(S_IROTH | S_IWOTH); 00259 00260 // Register D-Bus meta types 00261 qDBusRegisterMetaType<MethodMap>(); 00262 qDBusRegisterMetaType<MapList>(); 00263 } 00264 00265 SignonDaemon::~SignonDaemon() 00266 { 00267 ::close(sigFd[0]); 00268 ::close(sigFd[1]); 00269 00270 if (m_backup) { 00271 exit(0); 00272 } 00273 00274 delete m_dbusServer; 00275 00276 SignonAuthSession::stopAllAuthSessions(); 00277 m_storedIdentities.clear(); 00278 00279 if (m_pCAMManager) { 00280 m_pCAMManager->closeCredentialsSystem(); 00281 delete m_pCAMManager; 00282 } 00283 00284 QDBusConnection sessionConnection = QDBusConnection::sessionBus(); 00285 00286 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH 00287 + QLatin1String("/Backup")); 00288 sessionConnection.unregisterService(SIGNOND_SERVICE 00289 + QLatin1String(".Backup")); 00290 if (m_backup == false) 00291 { 00292 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH); 00293 sessionConnection.unregisterService(SIGNOND_SERVICE); 00294 } 00295 00296 delete m_configuration; 00297 00298 QMetaObject::invokeMethod(QCoreApplication::instance(), 00299 "quit", 00300 Qt::QueuedConnection); 00301 } 00302 00303 void SignonDaemon::setupSignalHandlers() 00304 { 00305 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0) 00306 BLAME() << "Couldn't create HUP socketpair"; 00307 00308 m_sigSn = new QSocketNotifier(sigFd[1], QSocketNotifier::Read, this); 00309 connect(m_sigSn, SIGNAL(activated(int)), 00310 this, SLOT(handleUnixSignal())); 00311 } 00312 00313 void SignonDaemon::signalHandler(int signal) 00314 { 00315 int ret = ::write(sigFd[0], &signal, sizeof(signal)); 00316 Q_UNUSED(ret); 00317 } 00318 00319 void SignonDaemon::handleUnixSignal() 00320 { 00321 m_sigSn->setEnabled(false); 00322 00323 int signal; 00324 int ret = read(sigFd[1], &signal, sizeof(signal)); 00325 Q_UNUSED(ret); 00326 00327 TRACE() << "signal received: " << signal; 00328 00329 switch (signal) { 00330 case SIGHUP: { 00331 TRACE() << "\n\n SIGHUP \n\n"; 00332 //todo restart daemon 00333 deleteLater(); 00334 00335 // reset the m_instance 00336 m_instance = NULL; 00337 QMetaObject::invokeMethod(instance(), 00338 "init", 00339 Qt::QueuedConnection); 00340 break; 00341 } 00342 case SIGTERM: { 00343 TRACE() << "\n\n SIGTERM \n\n"; 00344 //gently stop daemon 00345 deleteLater(); 00346 QMetaObject::invokeMethod(QCoreApplication::instance(), 00347 "quit", 00348 Qt::QueuedConnection); 00349 break; 00350 } 00351 case SIGINT: { 00352 TRACE() << "\n\n SIGINT \n\n"; 00353 //gently stop daemon 00354 deleteLater(); 00355 QMetaObject::invokeMethod(QCoreApplication::instance(), 00356 "quit", 00357 Qt::QueuedConnection); 00358 break; 00359 } 00360 default: break; 00361 } 00362 00363 m_sigSn->setEnabled(true); 00364 } 00365 00366 SignonDaemon *SignonDaemon::instance() 00367 { 00368 if (m_instance != NULL) 00369 return m_instance; 00370 00371 QCoreApplication *app = QCoreApplication::instance(); 00372 00373 if (!app) 00374 qFatal("SignonDaemon requires a QCoreApplication instance to be " 00375 "constructed first"); 00376 00377 TRACE() << "Creating new daemon instance."; 00378 m_instance = new SignonDaemon(app); 00379 return m_instance; 00380 } 00381 00382 void SignonDaemon::init() 00383 { 00384 if (!(m_configuration = new SignonDaemonConfiguration)) 00385 qWarning("SignonDaemon could not create the configuration object."); 00386 00387 m_configuration->load(); 00388 00389 QCoreApplication *app = QCoreApplication::instance(); 00390 if (!app) 00391 qFatal("SignonDaemon requires a QCoreApplication instance to be " 00392 "constructed first"); 00393 00394 setupSignalHandlers(); 00395 m_backup = app->arguments().contains(QLatin1String("-backup")); 00396 m_pCAMManager = 00397 new CredentialsAccessManager(m_configuration->camConfiguration()); 00398 00399 /* backup dbus interface */ 00400 QDBusConnection sessionConnection = QDBusConnection::sessionBus(); 00401 00402 if (!sessionConnection.isConnected()) { 00403 QDBusError err = sessionConnection.lastError(); 00404 TRACE() << "Session connection cannot be established:" << 00405 err.errorString(err.type()); 00406 TRACE() << err.message(); 00407 00408 qFatal("SignonDaemon requires session bus to start working"); 00409 } 00410 00411 QDBusConnection::RegisterOptions registerSessionOptions = 00412 QDBusConnection::ExportAdaptors; 00413 00414 (void)new BackupIfAdaptor(this); 00415 00416 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH 00417 + QLatin1String("/Backup"), 00418 this, registerSessionOptions)) { 00419 TRACE() << "Object cannot be registered"; 00420 00421 qFatal("SignonDaemon requires to register backup object"); 00422 } 00423 00424 if (!sessionConnection.registerService(SIGNOND_SERVICE + 00425 QLatin1String(".Backup"))) { 00426 QDBusError err = sessionConnection.lastError(); 00427 TRACE() << "Service cannot be registered: " << 00428 err.errorString(err.type()); 00429 00430 qFatal("SignonDaemon requires to register backup service"); 00431 } 00432 00433 if (m_backup) { 00434 TRACE() << "Signond initialized in backup mode."; 00435 //skip rest of initialization in backup mode 00436 return; 00437 } 00438 00439 /* DBus Service init */ 00440 QDBusConnection connection = SIGNOND_BUS; 00441 00442 if (!connection.isConnected()) { 00443 QDBusError err = connection.lastError(); 00444 TRACE() << "Connection cannot be established:" << 00445 err.errorString(err.type()); 00446 TRACE() << err.message(); 00447 00448 qFatal("SignonDaemon requires DBus to start working"); 00449 } 00450 00451 QDBusConnection::RegisterOptions registerOptions = 00452 QDBusConnection::ExportAllContents; 00453 00454 (void)new SignonDaemonAdaptor(this); 00455 registerOptions = QDBusConnection::ExportAdaptors; 00456 00457 // p2p connection 00458 #ifdef ENABLE_P2P 00459 m_dbusServer = new QDBusServer(m_configuration->busAddress(), this); 00460 QObject::connect(m_dbusServer, 00461 SIGNAL(newConnection(const QDBusConnection &)), 00462 this, SLOT(onNewConnection(const QDBusConnection &))); 00463 #endif 00464 00465 // session bus 00466 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH, 00467 this, registerOptions)) { 00468 TRACE() << "Object cannot be registered"; 00469 00470 qFatal("SignonDaemon requires to register daemon's object"); 00471 } 00472 00473 if (!connection.registerService(SIGNOND_SERVICE)) { 00474 QDBusError err = connection.lastError(); 00475 TRACE() << "Service cannot be registered: " << 00476 err.errorString(err.type()); 00477 00478 qFatal("SignonDaemon requires to register daemon's service"); 00479 } 00480 00481 // handle D-Bus disconnection 00482 connection.connect(QString(), 00483 QLatin1String("/org/freedesktop/DBus/Local"), 00484 QLatin1String("org.freedesktop.DBus.Local"), 00485 QLatin1String("Disconnected"), 00486 this, SLOT(onDisconnected())); 00487 00488 initExtensions(); 00489 00490 if (!initStorage()) 00491 BLAME() << "Signond: Cannot initialize credentials storage."; 00492 00493 if (m_configuration->daemonTimeout() > 0) { 00494 SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(), 00495 this, SLOT(deleteLater())); 00496 } 00497 00498 TRACE() << "Signond SUCCESSFULLY initialized."; 00499 } 00500 00501 void SignonDaemon::onNewConnection(const QDBusConnection &connection) 00502 { 00503 TRACE() << "New p2p connection" << connection.name(); 00504 QDBusConnection conn(connection); 00505 if (!conn.registerObject(SIGNOND_DAEMON_OBJECTPATH, 00506 this, QDBusConnection::ExportAdaptors)) { 00507 qFatal("Failed to register SignonDaemon object"); 00508 } 00509 } 00510 00511 void SignonDaemon::initExtensions() 00512 { 00513 /* Scan the directory containing signond extensions and attempt loading 00514 * all of them. 00515 */ 00516 QDir dir(m_configuration->extensionsDir()); 00517 QStringList filters(QLatin1String("lib*.so")); 00518 QStringList extensionList = dir.entryList(filters, QDir::Files); 00519 foreach(const QString &filename, extensionList) 00520 initExtension(dir.filePath(filename)); 00521 } 00522 00523 void SignonDaemon::initExtension(const QString &filePath) 00524 { 00525 TRACE() << "Loading plugin " << filePath; 00526 00527 QPluginLoader pluginLoader(filePath); 00528 QObject *plugin = pluginLoader.instance(); 00529 if (!plugin) { 00530 qWarning() << "Couldn't load plugin:" << pluginLoader.errorString(); 00531 return; 00532 } 00533 00534 /* Check whether the extension implements some useful objects; if not, 00535 * unload it. */ 00536 if (!m_pCAMManager->initExtension(plugin)) 00537 pluginLoader.unload(); 00538 } 00539 00540 bool SignonDaemon::initStorage() 00541 { 00542 if (!m_pCAMManager->credentialsSystemOpened()) { 00543 m_pCAMManager->finalize(); 00544 00545 if (!m_pCAMManager->init()) { 00546 BLAME() << "CAM initialization failed"; 00547 return false; 00548 } 00549 00550 // If encryption is in use this will just open the metadata DB 00551 if (!m_pCAMManager->openCredentialsSystem()) { 00552 qCritical("Signond: Cannot open CAM credentials system..."); 00553 return false; 00554 } 00555 } else { 00556 TRACE() << "Secure storage already initialized..."; 00557 return false; 00558 } 00559 00560 return true; 00561 } 00562 00563 void SignonDaemon::onIdentityStored(SignonIdentity *identity) 00564 { 00565 m_storedIdentities.insert(identity->id(), identity); 00566 } 00567 00568 void SignonDaemon::onIdentityDestroyed() 00569 { 00570 SignonIdentity *identity = qobject_cast<SignonIdentity*>(sender()); 00571 m_storedIdentities.remove(identity->id()); 00572 } 00573 00574 void SignonDaemon::watchIdentity(SignonIdentity *identity) 00575 { 00576 QObject::connect(identity, SIGNAL(stored(SignonIdentity*)), 00577 this, SLOT(onIdentityStored(SignonIdentity*))); 00578 QObject::connect(identity, SIGNAL(unregistered()), 00579 this, SLOT(onIdentityDestroyed())); 00580 00581 if (identity->id() != SIGNOND_NEW_IDENTITY) { 00582 m_storedIdentities.insert(identity->id(), identity); 00583 } 00584 } 00585 00586 QObject *SignonDaemon::registerNewIdentity() 00587 { 00588 clearLastError(); 00589 00590 TRACE() << "Registering new identity:"; 00591 00592 SignonIdentity *identity = 00593 SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY, this); 00594 00595 Q_ASSERT(identity != NULL); 00596 watchIdentity(identity); 00597 00598 return identity; 00599 } 00600 00601 int SignonDaemon::identityTimeout() const 00602 { 00603 return (m_configuration == NULL ? 00604 300 : 00605 m_configuration->identityTimeout()); 00606 } 00607 00608 int SignonDaemon::authSessionTimeout() const 00609 { 00610 return (m_configuration == NULL ? 00611 300 : 00612 m_configuration->authSessionTimeout()); 00613 } 00614 00615 QObject *SignonDaemon::getIdentity(const quint32 id, 00616 QVariantMap &identityData) 00617 { 00618 clearLastError(); 00619 00620 SIGNON_RETURN_IF_CAM_UNAVAILABLE(0); 00621 00622 TRACE() << "Registering identity:" << id; 00623 00624 //1st check if the existing identity is in cache 00625 SignonIdentity *identity = m_storedIdentities.value(id, NULL); 00626 00627 //if not create it 00628 if (identity == NULL) 00629 identity = SignonIdentity::createIdentity(id, this); 00630 Q_ASSERT(identity != NULL); 00631 00632 bool ok; 00633 SignonIdentityInfo info = identity->queryInfo(ok, false); 00634 00635 if (info.isNew()) 00636 { 00637 setLastError(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME, 00638 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR); 00639 identity->destroy(); 00640 return 0; 00641 } 00642 00643 watchIdentity(identity); 00644 identity->keepInUse(); 00645 00646 identityData = info.toMap(); 00647 00648 TRACE() << "DONE REGISTERING IDENTITY"; 00649 return identity; 00650 } 00651 00652 QStringList SignonDaemon::queryMethods() 00653 { 00654 QDir pluginsDir(m_configuration->pluginsDir()); 00655 //TODO: in the future remove the sym links comment 00656 QStringList fileNames = pluginsDir.entryList( 00657 QStringList() << QLatin1String("*.so*"), 00658 QDir::Files | QDir::NoDotAndDotDot); 00659 00660 QStringList ret; 00661 QString fileName; 00662 foreach (fileName, fileNames) { 00663 if (fileName.startsWith(QLatin1String("lib"))) { 00664 fileName = 00665 fileName.mid(3, fileName.indexOf(QLatin1String("plugin")) -3); 00666 if ((fileName.length() > 0) && !ret.contains(fileName)) 00667 ret << fileName; 00668 } 00669 } 00670 00671 return ret; 00672 } 00673 00674 QStringList SignonDaemon::queryMechanisms(const QString &method) 00675 { 00676 clearLastError(); 00677 00678 TRACE() << method; 00679 00680 QStringList mechs = SignonSessionCore::loadedPluginMethods(method); 00681 00682 if (!mechs.isEmpty()) 00683 return mechs; 00684 00685 PluginProxy *plugin = PluginProxy::createNewPluginProxy(method); 00686 00687 if (!plugin) { 00688 TRACE() << "Could not load plugin of type: " << method; 00689 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME, 00690 SIGNOND_METHOD_NOT_KNOWN_ERR_STR + 00691 QString::fromLatin1("Method %1 is not known or could " 00692 "not load specific configuration."). 00693 arg(method)); 00694 return QStringList(); 00695 } 00696 00697 mechs = plugin->mechanisms(); 00698 delete plugin; 00699 00700 return mechs; 00701 } 00702 00703 QList<QVariantMap> SignonDaemon::queryIdentities(const QVariantMap &filter) 00704 { 00705 clearLastError(); 00706 00707 SIGNON_RETURN_IF_CAM_UNAVAILABLE(QList<QVariantMap>()); 00708 00709 TRACE() << "Querying identities"; 00710 00711 CredentialsDB *db = m_pCAMManager->credentialsDB(); 00712 if (!db) { 00713 qCritical() << Q_FUNC_INFO << m_pCAMManager->lastError(); 00714 return QList<QVariantMap>(); 00715 } 00716 00717 QMap<QString, QString> filterLocal; 00718 QMapIterator<QString, QVariant> it(filter); 00719 while (it.hasNext()) { 00720 it.next(); 00721 filterLocal.insert(it.key(), it.value().toString()); 00722 } 00723 00724 QList<SignonIdentityInfo> credentials = db->credentials(filterLocal); 00725 00726 if (db->errorOccurred()) { 00727 setLastError(internalServerErrName, 00728 internalServerErrStr + 00729 QLatin1String("Querying database error occurred.")); 00730 return QList<QVariantMap>(); 00731 } 00732 00733 QList<QVariantMap> mapList; 00734 foreach (const SignonIdentityInfo &info, credentials) { 00735 mapList.append(info.toMap()); 00736 } 00737 return mapList; 00738 } 00739 00740 bool SignonDaemon::clear() 00741 { 00742 clearLastError(); 00743 00744 SIGNON_RETURN_IF_CAM_UNAVAILABLE(false); 00745 00746 TRACE() << "\n\n\n Clearing DB\n\n"; 00747 CredentialsDB *db = m_pCAMManager->credentialsDB(); 00748 if (!db) { 00749 qCritical() << Q_FUNC_INFO << m_pCAMManager->lastError(); 00750 return false; 00751 } 00752 00753 if (!db->clear()) { 00754 setLastError(SIGNOND_INTERNAL_SERVER_ERR_NAME, 00755 SIGNOND_INTERNAL_SERVER_ERR_STR + 00756 QLatin1String("Database error occurred.")); 00757 return false; 00758 } 00759 return true; 00760 } 00761 00762 QObject *SignonDaemon::getAuthSession(const quint32 id, 00763 const QString type, 00764 pid_t ownerPid) 00765 { 00766 clearLastError(); 00767 00768 SignonAuthSession *authSession = 00769 SignonAuthSession::createAuthSession(id, type, this, ownerPid); 00770 if (authSession == NULL) { 00771 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME, 00772 SIGNOND_METHOD_NOT_KNOWN_ERR_STR); 00773 return 0; 00774 } 00775 00776 return authSession; 00777 } 00778 00779 void SignonDaemon::eraseBackupDir() const 00780 { 00781 const CAMConfiguration config = m_configuration->camConfiguration(); 00782 QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME(); 00783 00784 QDir target(backupRoot); 00785 if (!target.exists()) return; 00786 00787 QStringList targetEntries = target.entryList(QDir::Files); 00788 foreach (QString entry, targetEntries) { 00789 target.remove(entry); 00790 } 00791 00792 target.rmdir(backupRoot); 00793 } 00794 00795 bool SignonDaemon::copyToBackupDir(const QStringList &fileNames) const 00796 { 00797 const CAMConfiguration config = m_configuration->camConfiguration(); 00798 QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME(); 00799 00800 QDir target(backupRoot); 00801 if (!target.exists() && !target.mkpath(backupRoot)) { 00802 qCritical() << "Cannot create target directory"; 00803 return false; 00804 } 00805 00806 setUserOwnership(backupRoot); 00807 00808 /* Now copy the files to be backed up */ 00809 bool ok = true; 00810 foreach (const QString &fileName, fileNames) { 00811 /* Remove the target file, if it exists */ 00812 if (target.exists(fileName)) 00813 target.remove(fileName); 00814 00815 /* Copy the source into the target directory */ 00816 QString source = config.m_storagePath + QDir::separator() + fileName; 00817 if (!QFile::exists(source)) continue; 00818 00819 QString destination = backupRoot + QDir::separator() + fileName; 00820 ok = QFile::copy(source, destination); 00821 if (!ok) { 00822 BLAME() << "Copying" << source << "to" << destination << "failed"; 00823 break; 00824 } 00825 00826 setUserOwnership(destination); 00827 } 00828 00829 return ok; 00830 } 00831 00832 bool SignonDaemon::copyFromBackupDir(const QStringList &fileNames) const 00833 { 00834 const CAMConfiguration config = m_configuration->camConfiguration(); 00835 QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME(); 00836 00837 QDir sourceDir(backupRoot); 00838 if (!sourceDir.exists()) { 00839 TRACE() << "Backup directory does not exist!"; 00840 } 00841 00842 if (!sourceDir.exists(config.m_dbName)) { 00843 TRACE() << "Backup does not contain DB:" << config.m_dbName; 00844 } 00845 00846 /* Now restore the files from the backup */ 00847 bool ok = true; 00848 QDir target(config.m_storagePath); 00849 QStringList movedFiles, copiedFiles; 00850 foreach (const QString &fileName, fileNames) { 00851 /* Remove the target file, if it exists */ 00852 if (target.exists(fileName)) { 00853 if (target.rename(fileName, fileName + QLatin1String(".bak"))) 00854 movedFiles += fileName; 00855 } 00856 00857 /* Copy the source into the target directory */ 00858 QString source = backupRoot + QDir::separator() + fileName; 00859 if (!QFile::exists(source)) { 00860 TRACE() << "Ignoring file not present in backup:" << source; 00861 continue; 00862 } 00863 00864 QString destination = 00865 config.m_storagePath + QDir::separator() + fileName; 00866 00867 ok = QFile::copy(source, destination); 00868 if (ok) { 00869 copiedFiles << fileName; 00870 } else { 00871 qWarning() << "Copy failed for:" << source; 00872 break; 00873 } 00874 } 00875 00876 if (!ok) { 00877 qWarning() << "Restore failed, recovering previous DB"; 00878 00879 foreach (const QString &fileName, copiedFiles) { 00880 target.remove(fileName); 00881 } 00882 00883 foreach (const QString &fileName, movedFiles) { 00884 if (!target.rename(fileName + QLatin1String(".bak"), fileName)) { 00885 qCritical() << "Could not recover:" << fileName; 00886 } 00887 } 00888 } else { 00889 /* delete ".bak" files */ 00890 foreach (const QString &fileName, movedFiles) { 00891 target.remove(fileName + QLatin1String(".bak")); 00892 } 00893 00894 } 00895 return ok; 00896 } 00897 00898 bool SignonDaemon::createStorageFileTree(const QStringList &backupFiles) const 00899 { 00900 QString storageDirPath = m_configuration->camConfiguration().m_storagePath; 00901 QDir storageDir(storageDirPath); 00902 00903 if (!storageDir.exists()) { 00904 if (!storageDir.mkpath(storageDirPath)) { 00905 qCritical() << "Could not create storage dir for backup."; 00906 return false; 00907 } 00908 } 00909 00910 foreach (const QString &fileName, backupFiles) { 00911 if (storageDir.exists(fileName)) continue; 00912 00913 QString filePath = storageDir.path() + QDir::separator() + fileName; 00914 QFile file(filePath); 00915 if (!file.open(QIODevice::WriteOnly)) { 00916 qCritical() << "Failed to create empty file for backup:" << filePath; 00917 return false; 00918 } else { 00919 file.close(); 00920 } 00921 } 00922 00923 return true; 00924 } 00925 00926 uchar SignonDaemon::backupStarts() 00927 { 00928 TRACE() << "backup"; 00929 if (!m_backup && m_pCAMManager->credentialsSystemOpened()) 00930 { 00931 m_pCAMManager->closeCredentialsSystem(); 00932 if (m_pCAMManager->credentialsSystemOpened()) 00933 { 00934 qCritical() << "Cannot close credentials database"; 00935 return 2; 00936 } 00937 } 00938 00939 const CAMConfiguration config = m_configuration->camConfiguration(); 00940 00941 /* do backup copy: prepare the list of files to be backed up */ 00942 QStringList backupFiles; 00943 backupFiles << config.m_dbName; 00944 backupFiles << m_pCAMManager->backupFiles(); 00945 00946 /* make sure that all the backup files and storage directory exist: 00947 create storage dir and empty files if not so, as backup/restore 00948 operations must be consistent */ 00949 if (!createStorageFileTree(backupFiles)) { 00950 qCritical() << "Cannot create backup file tree."; 00951 return 2; 00952 } 00953 00954 /* perform the copy */ 00955 eraseBackupDir(); 00956 if (!copyToBackupDir(backupFiles)) { 00957 qCritical() << "Cannot copy database"; 00958 if (!m_backup) 00959 m_pCAMManager->openCredentialsSystem(); 00960 return 2; 00961 } 00962 00963 if (!m_backup) 00964 { 00965 //mount file system back 00966 if (!m_pCAMManager->openCredentialsSystem()) { 00967 qCritical() << "Cannot reopen database"; 00968 } 00969 } 00970 return 0; 00971 } 00972 00973 uchar SignonDaemon::backupFinished() 00974 { 00975 TRACE() << "close"; 00976 00977 eraseBackupDir(); 00978 00979 if (m_backup) 00980 { 00981 //close daemon 00982 TRACE() << "close daemon"; 00983 this->deleteLater(); 00984 } 00985 00986 return 0; 00987 } 00988 00989 /* 00990 * Does nothing but start-on-demand 00991 * */ 00992 uchar SignonDaemon::restoreStarts() 00993 { 00994 TRACE(); 00995 return 0; 00996 } 00997 00998 uchar SignonDaemon::restoreFinished() 00999 { 01000 TRACE() << "restore"; 01001 //restore requested 01002 if (m_pCAMManager->credentialsSystemOpened()) 01003 { 01004 //umount file system 01005 if (!m_pCAMManager->closeCredentialsSystem()) 01006 { 01007 qCritical() << "database cannot be closed"; 01008 return 2; 01009 } 01010 } 01011 01012 const CAMConfiguration config = m_configuration->camConfiguration(); 01013 01014 QStringList backupFiles; 01015 backupFiles << config.m_dbName; 01016 backupFiles << m_pCAMManager->backupFiles(); 01017 01018 /* perform the copy */ 01019 if (!copyFromBackupDir(backupFiles)) { 01020 qCritical() << "Cannot copy database"; 01021 m_pCAMManager->openCredentialsSystem(); 01022 return 2; 01023 } 01024 01025 eraseBackupDir(); 01026 01027 //TODO check database integrity 01028 if (!m_backup) 01029 { 01030 //mount file system back 01031 if (!m_pCAMManager->openCredentialsSystem()) 01032 return 2; 01033 } 01034 01035 return 0; 01036 } 01037 01038 void SignonDaemon::onDisconnected() 01039 { 01040 TRACE() << "Disconnected from session bus: exiting"; 01041 this->deleteLater(); 01042 QMetaObject::invokeMethod(QCoreApplication::instance(), 01043 "quit", 01044 Qt::QueuedConnection); 01045 } 01046 01047 void SignonDaemon::setLastError(const QString &name, const QString &msg) 01048 { 01049 m_lastErrorName = name; 01050 m_lastErrorMessage = msg; 01051 } 01052 01053 void SignonDaemon::clearLastError() 01054 { 01055 m_lastErrorName = QString(); 01056 m_lastErrorMessage = QString(); 01057 } 01058 01059 } //namespace SignonDaemonNS