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