26 #include <sys/socket.h>
28 #include <sys/types.h>
31 #define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(4, 0, 0)
35 #include <QDBusConnection>
36 #include <QDBusMessage>
37 #include <QDBusMetaType>
38 #include <QPluginLoader>
39 #include <QProcessEnvironment>
40 #include <QSocketNotifier>
41 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
42 #include <QStandardPaths>
45 #include "SignOn/misc.h"
56 #define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_) do { \
57 if (m_pCAMManager && !m_pCAMManager->credentialsSystemOpened()) { \
58 setLastError(internalServerErrName, \
59 internalServerErrStr + \
60 QLatin1String("Could not access Signon " \
66 #define BACKUP_DIR_NAME() \
67 (QDir::separator() + QLatin1String("backup"))
75 SignonDaemonConfiguration::SignonDaemonConfiguration():
77 m_extensionsDir(QLatin1String(SIGNOND_EXTENSIONS_DIR)),
80 m_identityTimeout(300),
81 m_authSessionTimeout(300)
109 QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
113 QSettings::setPath(QSettings::NativeFormat, QSettings::SystemScope,
114 environment.value(QLatin1String(
"SSO_CONFIG_FILE_DIR"),
115 QLatin1String(
"/etc")));
117 QSettings settings(QLatin1String(
"signond"));
120 settings.value(QLatin1String(
"LoggingLevel"), 1).toInt();
121 setLoggingLevel(loggingLevel);
123 QString cfgStoragePath =
124 settings.value(QLatin1String(
"StoragePath")).toString();
125 if (!cfgStoragePath.isEmpty()) {
126 QString storagePath = QDir(cfgStoragePath).path();
129 QString xdgConfigHome = QLatin1String(qgetenv(
"XDG_CONFIG_HOME"));
130 if (xdgConfigHome.isEmpty())
131 xdgConfigHome = QDir::homePath() + QLatin1String(
"/.config");
133 QLatin1String(
"/signond"));
139 QString useSecureStorage =
140 settings.value(QLatin1String(
"UseSecureStorage")).toString();
141 if (useSecureStorage == QLatin1String(
"yes") ||
142 useSecureStorage == QLatin1String(
"true")) {
143 m_camConfiguration.
addSetting(QLatin1String(
"CryptoManager"),
144 QLatin1String(
"cryptsetup"));
147 settings.beginGroup(QLatin1String(
"SecureStorage"));
149 QVariantMap storageOptions;
150 foreach (
const QString &key, settings.childKeys()) {
151 m_camConfiguration.
addSetting(key, settings.value(key));
157 settings.beginGroup(QLatin1String(
"ObjectTimeouts"));
160 uint aux = settings.value(QLatin1String(
"IdentityTimeout")).toUInt(&isOk);
162 m_identityTimeout = aux;
164 aux = settings.value(QLatin1String(
"AuthSessionTimeout")).toUInt(&isOk);
166 m_authSessionTimeout = aux;
168 aux = settings.value(QLatin1String(
"DaemonTimeout")).toUInt(&isOk);
170 m_daemonTimeout = aux;
177 if (environment.contains(QLatin1String(
"SSO_DAEMON_TIMEOUT"))) {
178 value = environment.value(
179 QLatin1String(
"SSO_DAEMON_TIMEOUT")).toInt(&isOk);
180 if (value > 0 && isOk) m_daemonTimeout = value;
183 if (environment.contains(QLatin1String(
"SSO_IDENTITY_TIMEOUT"))) {
184 value = environment.value(
185 QLatin1String(
"SSO_IDENTITY_TIMEOUT")).toInt(&isOk);
186 if (value > 0 && isOk) m_identityTimeout = value;
189 if (environment.contains(QLatin1String(
"SSO_AUTHSESSION_TIMEOUT"))) {
190 value = environment.value(
191 QLatin1String(
"SSO_AUTHSESSION_TIMEOUT")).toInt(&isOk);
192 if (value > 0 && isOk) m_authSessionTimeout = value;
195 if (environment.contains(QLatin1String(
"SSO_LOGGING_LEVEL"))) {
196 value = environment.value(
197 QLatin1String(
"SSO_LOGGING_LEVEL")).toInt(&isOk);
199 setLoggingLevel(value);
202 QString logOutput = environment.value(QLatin1String(
"SSO_LOGGING_OUTPUT"),
203 QLatin1String(
"syslog"));
204 SignonTrace::initialize(logOutput == QLatin1String(
"syslog") ?
205 SignonTrace::Syslog : SignonTrace::Stdout);
207 if (environment.contains(QLatin1String(
"SSO_STORAGE_PATH"))) {
209 environment.value(QLatin1String(
"SSO_STORAGE_PATH")));
212 if (environment.contains(QLatin1String(
"SSO_PLUGINS_DIR"))) {
213 m_pluginsDir = environment.value(QLatin1String(
"SSO_PLUGINS_DIR"));
216 if (environment.contains(QLatin1String(
"SSO_EXTENSIONS_DIR"))) {
218 environment.value(QLatin1String(
"SSO_EXTENSIONS_DIR"));
221 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
223 QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
225 QString runtimeDir = environment.value(QLatin1String(
"XDG_RUNTIME_DIR"));
227 if (!runtimeDir.isEmpty()) {
228 QString socketFileName =
229 QString::fromLatin1(
"%1/" SIGNOND_SOCKET_FILENAME).arg(runtimeDir);
230 QDir socketDir = QFileInfo(socketFileName).absoluteDir();
231 if (!socketDir.exists() && !socketDir.mkpath(socketDir.path())) {
232 BLAME() <<
"Cannot create socket directory" << socketDir;
235 QString::fromLatin1(
"unix:path=%1").arg(socketFileName);
238 BLAME() <<
"XDG_RUNTIME_DIR unset, disabling p2p bus";
251 SignonDaemon::SignonDaemon(QObject *parent):
258 umask(S_IROTH | S_IWOTH);
261 qDBusRegisterMetaType<MethodMap>();
262 qDBusRegisterMetaType<MapList>();
265 SignonDaemon::~SignonDaemon()
276 SignonAuthSession::stopAllAuthSessions();
277 m_storedIdentities.clear();
280 m_pCAMManager->closeCredentialsSystem();
281 delete m_pCAMManager;
284 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
286 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH
287 + QLatin1String(
"/Backup"));
288 sessionConnection.unregisterService(SIGNOND_SERVICE
289 + QLatin1String(
".Backup"));
290 if (m_backup ==
false)
292 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH);
293 sessionConnection.unregisterService(SIGNOND_SERVICE);
296 delete m_configuration;
298 QMetaObject::invokeMethod(QCoreApplication::instance(),
300 Qt::QueuedConnection);
303 void SignonDaemon::setupSignalHandlers()
305 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0)
306 BLAME() <<
"Couldn't create HUP socketpair";
308 m_sigSn =
new QSocketNotifier(sigFd[1], QSocketNotifier::Read,
this);
309 connect(m_sigSn, SIGNAL(activated(
int)),
310 this, SLOT(handleUnixSignal()));
313 void SignonDaemon::signalHandler(
int signal)
315 int ret = ::write(sigFd[0], &signal,
sizeof(signal));
319 void SignonDaemon::handleUnixSignal()
321 m_sigSn->setEnabled(
false);
324 int ret = read(sigFd[1], &signal,
sizeof(signal));
327 TRACE() <<
"signal received: " << signal;
331 TRACE() <<
"\n\n SIGHUP \n\n";
337 QMetaObject::invokeMethod(instance(),
339 Qt::QueuedConnection);
343 TRACE() <<
"\n\n SIGTERM \n\n";
346 QMetaObject::invokeMethod(QCoreApplication::instance(),
348 Qt::QueuedConnection);
352 TRACE() <<
"\n\n SIGINT \n\n";
355 QMetaObject::invokeMethod(QCoreApplication::instance(),
357 Qt::QueuedConnection);
363 m_sigSn->setEnabled(
true);
368 if (m_instance != NULL)
371 QCoreApplication *app = QCoreApplication::instance();
374 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
375 "constructed first");
377 TRACE() <<
"Creating new daemon instance.";
382 void SignonDaemon::init()
385 qWarning(
"SignonDaemon could not create the configuration object.");
387 m_configuration->load();
389 QCoreApplication *app = QCoreApplication::instance();
391 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
392 "constructed first");
394 setupSignalHandlers();
395 m_backup = app->arguments().contains(QLatin1String(
"-backup"));
400 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
402 if (!sessionConnection.isConnected()) {
403 QDBusError err = sessionConnection.lastError();
404 TRACE() <<
"Session connection cannot be established:" <<
405 err.errorString(err.type());
406 TRACE() << err.message();
408 qFatal(
"SignonDaemon requires session bus to start working");
411 QDBusConnection::RegisterOptions registerSessionOptions =
412 QDBusConnection::ExportAdaptors;
416 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
417 + QLatin1String(
"/Backup"),
418 this, registerSessionOptions)) {
419 TRACE() <<
"Object cannot be registered";
421 qFatal(
"SignonDaemon requires to register backup object");
424 if (!sessionConnection.registerService(SIGNOND_SERVICE +
425 QLatin1String(
".Backup"))) {
426 QDBusError err = sessionConnection.lastError();
427 TRACE() <<
"Service cannot be registered: " <<
428 err.errorString(err.type());
430 qFatal(
"SignonDaemon requires to register backup service");
434 TRACE() <<
"Signond initialized in backup mode.";
440 QDBusConnection connection = SIGNOND_BUS;
442 if (!connection.isConnected()) {
443 QDBusError err = connection.lastError();
444 TRACE() <<
"Connection cannot be established:" <<
445 err.errorString(err.type());
446 TRACE() << err.message();
448 qFatal(
"SignonDaemon requires DBus to start working");
451 QDBusConnection::RegisterOptions registerOptions =
452 QDBusConnection::ExportAllContents;
455 registerOptions = QDBusConnection::ExportAdaptors;
459 m_dbusServer =
new QDBusServer(m_configuration->busAddress(),
this);
460 QObject::connect(m_dbusServer,
461 SIGNAL(newConnection(
const QDBusConnection &)),
462 this, SLOT(onNewConnection(
const QDBusConnection &)));
466 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
467 this, registerOptions)) {
468 TRACE() <<
"Object cannot be registered";
470 qFatal(
"SignonDaemon requires to register daemon's object");
473 if (!connection.registerService(SIGNOND_SERVICE)) {
474 QDBusError err = connection.lastError();
475 TRACE() <<
"Service cannot be registered: " <<
476 err.errorString(err.type());
478 qFatal(
"SignonDaemon requires to register daemon's service");
482 connection.connect(QString(),
483 QLatin1String(
"/org/freedesktop/DBus/Local"),
484 QLatin1String(
"org.freedesktop.DBus.Local"),
485 QLatin1String(
"Disconnected"),
486 this, SLOT(onDisconnected()));
491 BLAME() <<
"Signond: Cannot initialize credentials storage.";
493 if (m_configuration->daemonTimeout() > 0) {
494 SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(),
495 this, SLOT(deleteLater()));
498 TRACE() <<
"Signond SUCCESSFULLY initialized.";
501 void SignonDaemon::onNewConnection(
const QDBusConnection &connection)
503 TRACE() <<
"New p2p connection" << connection.name();
504 QDBusConnection conn(connection);
505 if (!conn.registerObject(SIGNOND_DAEMON_OBJECTPATH,
506 this, QDBusConnection::ExportAdaptors)) {
507 qFatal(
"Failed to register SignonDaemon object");
511 void SignonDaemon::initExtensions()
516 QDir dir(m_configuration->extensionsDir());
517 QStringList filters(QLatin1String(
"lib*.so"));
518 QStringList extensionList = dir.entryList(filters, QDir::Files);
519 foreach(
const QString &filename, extensionList)
520 initExtension(dir.filePath(filename));
523 void SignonDaemon::initExtension(
const QString &filePath)
525 TRACE() <<
"Loading plugin " << filePath;
527 QPluginLoader pluginLoader(filePath);
528 QObject *plugin = pluginLoader.instance();
530 qWarning() <<
"Couldn't load plugin:" << pluginLoader.errorString();
536 if (!m_pCAMManager->initExtension(plugin))
537 pluginLoader.unload();
540 bool SignonDaemon::initStorage()
542 if (!m_pCAMManager->credentialsSystemOpened()) {
543 m_pCAMManager->finalize();
545 if (!m_pCAMManager->init()) {
546 BLAME() <<
"CAM initialization failed";
551 if (!m_pCAMManager->openCredentialsSystem()) {
552 qCritical(
"Signond: Cannot open CAM credentials system...");
556 TRACE() <<
"Secure storage already initialized...";
563 void SignonDaemon::onIdentityStored(SignonIdentity *identity)
565 m_storedIdentities.insert(identity->id(), identity);
568 void SignonDaemon::onIdentityDestroyed()
570 SignonIdentity *identity = qobject_cast<SignonIdentity*>(sender());
571 m_storedIdentities.remove(identity->id());
574 void SignonDaemon::watchIdentity(SignonIdentity *identity)
576 QObject::connect(identity, SIGNAL(stored(SignonIdentity*)),
577 this, SLOT(onIdentityStored(SignonIdentity*)));
578 QObject::connect(identity, SIGNAL(unregistered()),
579 this, SLOT(onIdentityDestroyed()));
581 if (identity->id() != SIGNOND_NEW_IDENTITY) {
582 m_storedIdentities.insert(identity->id(), identity);
586 QObject *SignonDaemon::registerNewIdentity()
590 TRACE() <<
"Registering new identity:";
593 SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY,
this);
595 Q_ASSERT(identity != NULL);
596 watchIdentity(identity);
601 int SignonDaemon::identityTimeout()
const
603 return (m_configuration == NULL ?
605 m_configuration->identityTimeout());
608 int SignonDaemon::authSessionTimeout()
const
610 return (m_configuration == NULL ?
612 m_configuration->authSessionTimeout());
615 QObject *SignonDaemon::getIdentity(
const quint32
id,
616 QVariantMap &identityData)
622 TRACE() <<
"Registering identity:" << id;
628 if (identity == NULL)
629 identity = SignonIdentity::createIdentity(
id,
this);
630 Q_ASSERT(identity != NULL);
637 setLastError(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
638 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
643 watchIdentity(identity);
646 identityData = info.
toMap();
648 TRACE() <<
"DONE REGISTERING IDENTITY";
652 QStringList SignonDaemon::queryMethods()
654 QDir pluginsDir(m_configuration->pluginsDir());
656 QStringList fileNames = pluginsDir.entryList(
657 QStringList() << QLatin1String(
"*.so*"),
658 QDir::Files | QDir::NoDotAndDotDot);
662 foreach (fileName, fileNames) {
663 if (fileName.startsWith(QLatin1String(
"lib"))) {
665 fileName.mid(3, fileName.indexOf(QLatin1String(
"plugin")) -3);
666 if ((fileName.length() > 0) && !ret.contains(fileName))
674 QStringList SignonDaemon::queryMechanisms(
const QString &method)
680 QStringList mechs = SignonSessionCore::loadedPluginMethods(method);
682 if (!mechs.isEmpty())
685 PluginProxy *plugin = PluginProxy::createNewPluginProxy(method);
688 TRACE() <<
"Could not load plugin of type: " << method;
689 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
690 SIGNOND_METHOD_NOT_KNOWN_ERR_STR +
691 QString::fromLatin1(
"Method %1 is not known or could "
692 "not load specific configuration.").
694 return QStringList();
709 TRACE() <<
"Querying identities";
713 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
718 QMapIterator<QString, QVariant> it(filter);
719 while (it.hasNext()) {
721 filterLocal.insert(it.key(), it.value().toString());
727 setLastError(internalServerErrName,
728 internalServerErrStr +
729 QLatin1String(
"Querying database error occurred."));
735 mapList.append(info.
toMap());
740 bool SignonDaemon::clear()
746 TRACE() <<
"\n\n\n Clearing DB\n\n";
749 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
754 setLastError(SIGNOND_INTERNAL_SERVER_ERR_NAME,
755 SIGNOND_INTERNAL_SERVER_ERR_STR +
756 QLatin1String(
"Database error occurred."));
762 QObject *SignonDaemon::getAuthSession(
const quint32
id,
769 SignonAuthSession::createAuthSession(
id, type,
this, ownerPid);
770 if (authSession == NULL) {
771 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
772 SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
779 void SignonDaemon::eraseBackupDir()
const
784 QDir target(backupRoot);
785 if (!target.exists())
return;
787 QStringList targetEntries = target.entryList(QDir::Files);
788 foreach (QString entry, targetEntries) {
789 target.remove(entry);
792 target.rmdir(backupRoot);
795 bool SignonDaemon::copyToBackupDir(
const QStringList &fileNames)
const
797 const CAMConfiguration config = m_configuration->camConfiguration();
800 QDir target(backupRoot);
801 if (!target.exists() && !target.mkpath(backupRoot)) {
802 qCritical() <<
"Cannot create target directory";
810 foreach (
const QString &fileName, fileNames) {
812 if (target.exists(fileName))
813 target.remove(fileName);
816 QString source = config.m_storagePath + QDir::separator() + fileName;
817 if (!QFile::exists(source))
continue;
819 QString destination = backupRoot + QDir::separator() + fileName;
820 ok = QFile::copy(source, destination);
822 BLAME() <<
"Copying" << source <<
"to" << destination <<
"failed";
832 bool SignonDaemon::copyFromBackupDir(
const QStringList &fileNames)
const
834 const CAMConfiguration config = m_configuration->camConfiguration();
837 QDir sourceDir(backupRoot);
838 if (!sourceDir.exists()) {
839 TRACE() <<
"Backup directory does not exist!";
842 if (!sourceDir.exists(config.m_dbName)) {
843 TRACE() <<
"Backup does not contain DB:" << config.m_dbName;
848 QDir target(config.m_storagePath);
849 QStringList movedFiles, copiedFiles;
850 foreach (
const QString &fileName, fileNames) {
852 if (target.exists(fileName)) {
853 if (target.rename(fileName, fileName + QLatin1String(
".bak")))
854 movedFiles += fileName;
858 QString source = backupRoot + QDir::separator() + fileName;
859 if (!QFile::exists(source)) {
860 TRACE() <<
"Ignoring file not present in backup:" << source;
864 QString destination =
865 config.m_storagePath + QDir::separator() + fileName;
867 ok = QFile::copy(source, destination);
869 copiedFiles << fileName;
871 qWarning() <<
"Copy failed for:" << source;
877 qWarning() <<
"Restore failed, recovering previous DB";
879 foreach (
const QString &fileName, copiedFiles) {
880 target.remove(fileName);
883 foreach (
const QString &fileName, movedFiles) {
884 if (!target.rename(fileName + QLatin1String(
".bak"), fileName)) {
885 qCritical() <<
"Could not recover:" << fileName;
890 foreach (
const QString &fileName, movedFiles) {
891 target.remove(fileName + QLatin1String(
".bak"));
898 bool SignonDaemon::createStorageFileTree(
const QStringList &backupFiles)
const
900 QString storageDirPath = m_configuration->camConfiguration().m_storagePath;
901 QDir storageDir(storageDirPath);
903 if (!storageDir.exists()) {
904 if (!storageDir.mkpath(storageDirPath)) {
905 qCritical() <<
"Could not create storage dir for backup.";
910 foreach (
const QString &fileName, backupFiles) {
911 if (storageDir.exists(fileName))
continue;
913 QString filePath = storageDir.path() + QDir::separator() + fileName;
914 QFile file(filePath);
915 if (!file.open(QIODevice::WriteOnly)) {
916 qCritical() <<
"Failed to create empty file for backup:" << filePath;
926 uchar SignonDaemon::backupStarts()
929 if (!m_backup && m_pCAMManager->credentialsSystemOpened())
931 m_pCAMManager->closeCredentialsSystem();
932 if (m_pCAMManager->credentialsSystemOpened())
934 qCritical() <<
"Cannot close credentials database";
942 QStringList backupFiles;
944 backupFiles << m_pCAMManager->backupFiles();
949 if (!createStorageFileTree(backupFiles)) {
950 qCritical() <<
"Cannot create backup file tree.";
956 if (!copyToBackupDir(backupFiles)) {
957 qCritical() <<
"Cannot copy database";
959 m_pCAMManager->openCredentialsSystem();
966 if (!m_pCAMManager->openCredentialsSystem()) {
967 qCritical() <<
"Cannot reopen database";
973 uchar SignonDaemon::backupFinished()
982 TRACE() <<
"close daemon";
992 uchar SignonDaemon::restoreStarts()
998 uchar SignonDaemon::restoreFinished()
1000 TRACE() <<
"restore";
1002 if (m_pCAMManager->credentialsSystemOpened())
1005 if (!m_pCAMManager->closeCredentialsSystem())
1007 qCritical() <<
"database cannot be closed";
1014 QStringList backupFiles;
1016 backupFiles << m_pCAMManager->backupFiles();
1019 if (!copyFromBackupDir(backupFiles)) {
1020 qCritical() <<
"Cannot copy database";
1021 m_pCAMManager->openCredentialsSystem();
1031 if (!m_pCAMManager->openCredentialsSystem())
1038 void SignonDaemon::onDisconnected()
1040 TRACE() <<
"Disconnected from session bus: exiting";
1041 this->deleteLater();
1042 QMetaObject::invokeMethod(QCoreApplication::instance(),
1044 Qt::QueuedConnection);
1047 void SignonDaemon::setLastError(
const QString &name,
const QString &msg)
1049 m_lastErrorName = name;
1050 m_lastErrorMessage = msg;
1053 void SignonDaemon::clearLastError()
1055 m_lastErrorName = QString();
1056 m_lastErrorMessage = QString();
const QString internalServerErrName
void addSetting(const QString &key, const QVariant &value)
Daemon side representation of authentication session.
QString m_dbName
The database file name.
void destroy()
Performs any predestruction operations and the destruction itself.
SignOn::CredentialsDBError lastError() const
#define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_)
void setStoragePath(const QString &storagePath)
QString m_storagePath
The base directory for storage.
~SignonDaemonConfiguration()
SignonIdentityInfo credentials(const quint32 id, bool queryPassword=true)
QStringList mechanisms() const
Main singleton and manager object of the credentials database system.
#define BACKUP_DIR_NAME()
bool setUserOwnership(const QString &filePath)
const QString internalServerErrStr
bool errorOccurred() const
Daemon side representation of identity.
Daemon side representation of identity information.
Manages the credentials I/O.
Configuration object for the CredentialsAccessManager - CAM.
Helper class for access control-related functionality.
The daemon's configuration object; loads date from the daemon configuration file. ...
SignonIdentityInfo queryInfo(bool &ok, bool queryPassword=true)
const QVariantMap toMap() const
void keepInUse() const
Mark the object as used.
#define SIGNOND_PLUGINS_DIR