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();
390 BLAME() <<
"Failed to SUID root. Secure storage will not be available.";
393 QCoreApplication *app = QCoreApplication::instance();
395 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
396 "constructed first");
398 setupSignalHandlers();
399 m_backup = app->arguments().contains(QLatin1String(
"-backup"));
404 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
406 if (!sessionConnection.isConnected()) {
407 QDBusError err = sessionConnection.lastError();
408 TRACE() <<
"Session connection cannot be established:" <<
409 err.errorString(err.type());
410 TRACE() << err.message();
412 qFatal(
"SignonDaemon requires session bus to start working");
415 QDBusConnection::RegisterOptions registerSessionOptions =
416 QDBusConnection::ExportAdaptors;
420 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
421 + QLatin1String(
"/Backup"),
422 this, registerSessionOptions)) {
423 TRACE() <<
"Object cannot be registered";
425 qFatal(
"SignonDaemon requires to register backup object");
428 if (!sessionConnection.registerService(SIGNOND_SERVICE +
429 QLatin1String(
".Backup"))) {
430 QDBusError err = sessionConnection.lastError();
431 TRACE() <<
"Service cannot be registered: " <<
432 err.errorString(err.type());
434 qFatal(
"SignonDaemon requires to register backup service");
438 TRACE() <<
"Signond initialized in backup mode.";
444 QDBusConnection connection = SIGNOND_BUS;
446 if (!connection.isConnected()) {
447 QDBusError err = connection.lastError();
448 TRACE() <<
"Connection cannot be established:" <<
449 err.errorString(err.type());
450 TRACE() << err.message();
452 qFatal(
"SignonDaemon requires DBus to start working");
455 QDBusConnection::RegisterOptions registerOptions =
456 QDBusConnection::ExportAllContents;
459 registerOptions = QDBusConnection::ExportAdaptors;
463 m_dbusServer =
new QDBusServer(m_configuration->busAddress(),
this);
464 QObject::connect(m_dbusServer,
465 SIGNAL(newConnection(
const QDBusConnection &)),
466 this, SLOT(onNewConnection(
const QDBusConnection &)));
470 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
471 this, registerOptions)) {
472 TRACE() <<
"Object cannot be registered";
474 qFatal(
"SignonDaemon requires to register daemon's object");
477 if (!connection.registerService(SIGNOND_SERVICE)) {
478 QDBusError err = connection.lastError();
479 TRACE() <<
"Service cannot be registered: " <<
480 err.errorString(err.type());
482 qFatal(
"SignonDaemon requires to register daemon's service");
486 connection.connect(QString(),
487 QLatin1String(
"/org/freedesktop/DBus/Local"),
488 QLatin1String(
"org.freedesktop.DBus.Local"),
489 QLatin1String(
"Disconnected"),
490 this, SLOT(onDisconnected()));
495 BLAME() <<
"Signond: Cannot initialize credentials storage.";
497 if (m_configuration->daemonTimeout() > 0) {
498 SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(),
499 this, SLOT(deleteLater()));
502 TRACE() <<
"Signond SUCCESSFULLY initialized.";
505 void SignonDaemon::onNewConnection(
const QDBusConnection &connection)
507 TRACE() <<
"New p2p connection" << connection.name();
508 QDBusConnection conn(connection);
509 if (!conn.registerObject(SIGNOND_DAEMON_OBJECTPATH,
510 this, QDBusConnection::ExportAdaptors)) {
511 qFatal(
"Failed to register SignonDaemon object");
515 void SignonDaemon::initExtensions()
520 QDir dir(m_configuration->extensionsDir());
521 QStringList filters(QLatin1String(
"lib*.so"));
522 QStringList extensionList = dir.entryList(filters, QDir::Files);
523 foreach(
const QString &filename, extensionList)
524 initExtension(dir.filePath(filename));
527 void SignonDaemon::initExtension(
const QString &filePath)
529 TRACE() <<
"Loading plugin " << filePath;
531 QPluginLoader pluginLoader(filePath);
532 QObject *plugin = pluginLoader.instance();
534 qWarning() <<
"Couldn't load plugin:" << pluginLoader.errorString();
540 if (!m_pCAMManager->initExtension(plugin))
541 pluginLoader.unload();
544 bool SignonDaemon::initStorage()
546 if (!m_pCAMManager->credentialsSystemOpened()) {
547 m_pCAMManager->finalize();
549 if (!m_pCAMManager->init()) {
550 BLAME() <<
"CAM initialization failed";
555 if (!m_pCAMManager->openCredentialsSystem()) {
556 qCritical(
"Signond: Cannot open CAM credentials system...");
560 TRACE() <<
"Secure storage already initialized...";
567 void SignonDaemon::onIdentityStored(SignonIdentity *identity)
569 m_storedIdentities.insert(identity->id(), identity);
572 void SignonDaemon::onIdentityDestroyed()
574 SignonIdentity *identity = qobject_cast<SignonIdentity*>(sender());
575 m_storedIdentities.remove(identity->id());
578 void SignonDaemon::watchIdentity(SignonIdentity *identity)
580 QObject::connect(identity, SIGNAL(stored(SignonIdentity*)),
581 this, SLOT(onIdentityStored(SignonIdentity*)));
582 QObject::connect(identity, SIGNAL(unregistered()),
583 this, SLOT(onIdentityDestroyed()));
585 if (identity->id() != SIGNOND_NEW_IDENTITY) {
586 m_storedIdentities.insert(identity->id(), identity);
590 QObject *SignonDaemon::registerNewIdentity()
594 TRACE() <<
"Registering new identity:";
597 SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY,
this);
599 Q_ASSERT(identity != NULL);
600 watchIdentity(identity);
605 int SignonDaemon::identityTimeout()
const
607 return (m_configuration == NULL ?
609 m_configuration->identityTimeout());
612 int SignonDaemon::authSessionTimeout()
const
614 return (m_configuration == NULL ?
616 m_configuration->authSessionTimeout());
619 QObject *SignonDaemon::getIdentity(
const quint32
id,
620 QVariantMap &identityData)
626 TRACE() <<
"Registering identity:" << id;
632 if (identity == NULL)
633 identity = SignonIdentity::createIdentity(
id,
this);
634 Q_ASSERT(identity != NULL);
641 setLastError(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
642 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
647 watchIdentity(identity);
650 identityData = info.
toMap();
652 TRACE() <<
"DONE REGISTERING IDENTITY";
656 QStringList SignonDaemon::queryMethods()
658 QDir pluginsDir(m_configuration->pluginsDir());
660 QStringList fileNames = pluginsDir.entryList(
661 QStringList() << QLatin1String(
"*.so*"),
662 QDir::Files | QDir::NoDotAndDotDot);
666 foreach (fileName, fileNames) {
667 if (fileName.startsWith(QLatin1String(
"lib"))) {
669 fileName.mid(3, fileName.indexOf(QLatin1String(
"plugin")) -3);
670 if ((fileName.length() > 0) && !ret.contains(fileName))
678 QStringList SignonDaemon::queryMechanisms(
const QString &method)
684 QStringList mechs = SignonSessionCore::loadedPluginMethods(method);
686 if (!mechs.isEmpty())
689 PluginProxy *plugin = PluginProxy::createNewPluginProxy(method);
692 TRACE() <<
"Could not load plugin of type: " << method;
693 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
694 SIGNOND_METHOD_NOT_KNOWN_ERR_STR +
695 QString::fromLatin1(
"Method %1 is not known or could "
696 "not load specific configuration.").
698 return QStringList();
713 TRACE() <<
"Querying identities";
717 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
722 QMapIterator<QString, QVariant> it(filter);
723 while (it.hasNext()) {
725 filterLocal.insert(it.key(), it.value().toString());
731 setLastError(internalServerErrName,
732 internalServerErrStr +
733 QLatin1String(
"Querying database error occurred."));
739 mapList.append(info.
toMap());
744 bool SignonDaemon::clear()
750 TRACE() <<
"\n\n\n Clearing DB\n\n";
753 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
758 setLastError(SIGNOND_INTERNAL_SERVER_ERR_NAME,
759 SIGNOND_INTERNAL_SERVER_ERR_STR +
760 QLatin1String(
"Database error occurred."));
766 QObject *SignonDaemon::getAuthSession(
const quint32
id,
773 SignonAuthSession::createAuthSession(
id, type,
this, ownerPid);
774 if (authSession == NULL) {
775 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
776 SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
783 void SignonDaemon::eraseBackupDir()
const
788 QDir target(backupRoot);
789 if (!target.exists())
return;
791 QStringList targetEntries = target.entryList(QDir::Files);
792 foreach (QString entry, targetEntries) {
793 target.remove(entry);
796 target.rmdir(backupRoot);
799 bool SignonDaemon::copyToBackupDir(
const QStringList &fileNames)
const
801 const CAMConfiguration config = m_configuration->camConfiguration();
804 QDir target(backupRoot);
805 if (!target.exists() && !target.mkpath(backupRoot)) {
806 qCritical() <<
"Cannot create target directory";
814 foreach (
const QString &fileName, fileNames) {
816 if (target.exists(fileName))
817 target.remove(fileName);
820 QString source = config.m_storagePath + QDir::separator() + fileName;
821 if (!QFile::exists(source))
continue;
823 QString destination = backupRoot + QDir::separator() + fileName;
824 ok = QFile::copy(source, destination);
826 BLAME() <<
"Copying" << source <<
"to" << destination <<
"failed";
836 bool SignonDaemon::copyFromBackupDir(
const QStringList &fileNames)
const
838 const CAMConfiguration config = m_configuration->camConfiguration();
841 QDir sourceDir(backupRoot);
842 if (!sourceDir.exists()) {
843 TRACE() <<
"Backup directory does not exist!";
846 if (!sourceDir.exists(config.m_dbName)) {
847 TRACE() <<
"Backup does not contain DB:" << config.m_dbName;
852 QDir target(config.m_storagePath);
853 QStringList movedFiles, copiedFiles;
854 foreach (
const QString &fileName, fileNames) {
856 if (target.exists(fileName)) {
857 if (target.rename(fileName, fileName + QLatin1String(
".bak")))
858 movedFiles += fileName;
862 QString source = backupRoot + QDir::separator() + fileName;
863 if (!QFile::exists(source)) {
864 TRACE() <<
"Ignoring file not present in backup:" << source;
868 QString destination =
869 config.m_storagePath + QDir::separator() + fileName;
871 ok = QFile::copy(source, destination);
873 copiedFiles << fileName;
875 qWarning() <<
"Copy failed for:" << source;
881 qWarning() <<
"Restore failed, recovering previous DB";
883 foreach (
const QString &fileName, copiedFiles) {
884 target.remove(fileName);
887 foreach (
const QString &fileName, movedFiles) {
888 if (!target.rename(fileName + QLatin1String(
".bak"), fileName)) {
889 qCritical() <<
"Could not recover:" << fileName;
894 foreach (
const QString &fileName, movedFiles) {
895 target.remove(fileName + QLatin1String(
".bak"));
902 bool SignonDaemon::createStorageFileTree(
const QStringList &backupFiles)
const
904 QString storageDirPath = m_configuration->camConfiguration().m_storagePath;
905 QDir storageDir(storageDirPath);
907 if (!storageDir.exists()) {
908 if (!storageDir.mkpath(storageDirPath)) {
909 qCritical() <<
"Could not create storage dir for backup.";
914 foreach (
const QString &fileName, backupFiles) {
915 if (storageDir.exists(fileName))
continue;
917 QString filePath = storageDir.path() + QDir::separator() + fileName;
918 QFile file(filePath);
919 if (!file.open(QIODevice::WriteOnly)) {
920 qCritical() <<
"Failed to create empty file for backup:" << filePath;
930 uchar SignonDaemon::backupStarts()
933 if (!m_backup && m_pCAMManager->credentialsSystemOpened())
935 m_pCAMManager->closeCredentialsSystem();
936 if (m_pCAMManager->credentialsSystemOpened())
938 qCritical() <<
"Cannot close credentials database";
946 QStringList backupFiles;
948 backupFiles << m_pCAMManager->backupFiles();
953 if (!createStorageFileTree(backupFiles)) {
954 qCritical() <<
"Cannot create backup file tree.";
960 if (!copyToBackupDir(backupFiles)) {
961 qCritical() <<
"Cannot copy database";
963 m_pCAMManager->openCredentialsSystem();
970 if (!m_pCAMManager->openCredentialsSystem()) {
971 qCritical() <<
"Cannot reopen database";
977 uchar SignonDaemon::backupFinished()
986 TRACE() <<
"close daemon";
996 uchar SignonDaemon::restoreStarts()
1002 uchar SignonDaemon::restoreFinished()
1004 TRACE() <<
"restore";
1006 if (m_pCAMManager->credentialsSystemOpened())
1009 if (!m_pCAMManager->closeCredentialsSystem())
1011 qCritical() <<
"database cannot be closed";
1018 QStringList backupFiles;
1020 backupFiles << m_pCAMManager->backupFiles();
1023 if (!copyFromBackupDir(backupFiles)) {
1024 qCritical() <<
"Cannot copy database";
1025 m_pCAMManager->openCredentialsSystem();
1035 if (!m_pCAMManager->openCredentialsSystem())
1042 void SignonDaemon::onDisconnected()
1044 TRACE() <<
"Disconnected from session bus: exiting";
1045 this->deleteLater();
1046 QMetaObject::invokeMethod(QCoreApplication::instance(),
1048 Qt::QueuedConnection);
1051 void SignonDaemon::setLastError(
const QString &name,
const QString &msg)
1053 m_lastErrorName = name;
1054 m_lastErrorMessage = msg;
1057 void SignonDaemon::clearLastError()
1059 m_lastErrorName = QString();
1060 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