signon  8.58
signondaemon.cpp
Go to the documentation of this file.
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