25 #include <sys/socket.h>
27 #include <sys/types.h>
30 #define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(4, 0, 0)
34 #include <QDBusConnection>
35 #include <QDBusMessage>
36 #include <QDBusMetaType>
37 #include <QPluginLoader>
38 #include <QProcessEnvironment>
39 #include <QSocketNotifier>
41 #include "SignOn/misc.h"
52 #define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_) do { \
53 if (m_pCAMManager && !m_pCAMManager->credentialsSystemOpened()) { \
54 sendErrorReply(internalServerErrName, \
55 internalServerErrStr + \
56 QLatin1String("Could not access Signon " \
62 #define BACKUP_DIR_NAME() \
63 (QDir::separator() + QLatin1String("backup"))
65 using namespace SignOn;
67 namespace SignonDaemonNS {
71 SignonDaemonConfiguration::SignonDaemonConfiguration():
73 m_extensionsDir(QLatin1String(SIGNOND_EXTENSIONS_DIR)),
76 m_identityTimeout(300),
77 m_authSessionTimeout(300)
107 QSettings::setPath(QSettings::NativeFormat, QSettings::SystemScope,
108 QLatin1String(
"/etc"));
110 QSettings settings(QLatin1String(
"signond"));
113 settings.value(QLatin1String(
"LoggingLevel"), 1).toInt();
114 setLoggingLevel(loggingLevel);
116 QString cfgStoragePath =
117 settings.value(QLatin1String(
"StoragePath")).toString();
118 if (!cfgStoragePath.isEmpty()) {
119 QString storagePath = QDir(cfgStoragePath).path();
122 QString xdgConfigHome = QLatin1String(qgetenv(
"XDG_CONFIG_HOME"));
123 if (xdgConfigHome.isEmpty())
124 xdgConfigHome = QDir::homePath() + QLatin1String(
"/.config");
126 QLatin1String(
"/signond"));
132 QString useSecureStorage =
133 settings.value(QLatin1String(
"UseSecureStorage")).toString();
134 if (useSecureStorage == QLatin1String(
"yes") ||
135 useSecureStorage == QLatin1String(
"true")) {
136 m_camConfiguration.
addSetting(QLatin1String(
"CryptoManager"),
137 QLatin1String(
"cryptsetup"));
140 settings.beginGroup(QLatin1String(
"SecureStorage"));
142 QVariantMap storageOptions;
143 foreach (
const QString &key, settings.childKeys()) {
144 m_camConfiguration.
addSetting(key, settings.value(key));
150 settings.beginGroup(QLatin1String(
"ObjectTimeouts"));
153 uint aux = settings.value(QLatin1String(
"IdentityTimeout")).toUInt(&isOk);
155 m_identityTimeout = aux;
157 aux = settings.value(QLatin1String(
"AuthSessionTimeout")).toUInt(&isOk);
159 m_authSessionTimeout = aux;
161 aux = settings.value(QLatin1String(
"DaemonTimeout")).toUInt(&isOk);
163 m_daemonTimeout = aux;
169 QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
171 if (environment.contains(QLatin1String(
"SSO_DAEMON_TIMEOUT"))) {
172 value = environment.value(
173 QLatin1String(
"SSO_DAEMON_TIMEOUT")).toInt(&isOk);
174 if (value > 0 && isOk) m_daemonTimeout = value;
177 if (environment.contains(QLatin1String(
"SSO_IDENTITY_TIMEOUT"))) {
178 value = environment.value(
179 QLatin1String(
"SSO_IDENTITY_TIMEOUT")).toInt(&isOk);
180 if (value > 0 && isOk) m_identityTimeout = value;
183 if (environment.contains(QLatin1String(
"SSO_AUTHSESSION_TIMEOUT"))) {
184 value = environment.value(
185 QLatin1String(
"SSO_AUTHSESSION_TIMEOUT")).toInt(&isOk);
186 if (value > 0 && isOk) m_authSessionTimeout = value;
189 if (environment.contains(QLatin1String(
"SSO_LOGGING_LEVEL"))) {
190 value = environment.value(
191 QLatin1String(
"SSO_LOGGING_LEVEL")).toInt(&isOk);
193 setLoggingLevel(value);
196 QString logOutput = environment.value(QLatin1String(
"SSO_LOGGING_OUTPUT"),
197 QLatin1String(
"syslog"));
198 SignonTrace::initialize(logOutput == QLatin1String(
"syslog") ?
199 SignonTrace::Syslog : SignonTrace::Stdout);
201 if (environment.contains(QLatin1String(
"SSO_STORAGE_PATH"))) {
203 environment.value(QLatin1String(
"SSO_STORAGE_PATH")));
206 if (environment.contains(QLatin1String(
"SSO_PLUGINS_DIR"))) {
207 m_pluginsDir = environment.value(QLatin1String(
"SSO_PLUGINS_DIR"));
210 if (environment.contains(QLatin1String(
"SSO_EXTENSIONS_DIR"))) {
212 environment.value(QLatin1String(
"SSO_EXTENSIONS_DIR"));
225 SignonDaemon::SignonDaemon(QObject *parent) : QObject(parent)
226 , m_configuration(NULL)
229 umask(S_IROTH | S_IWOTH);
232 qDBusRegisterMetaType<MethodMap>();
233 qDBusRegisterMetaType<MapList>();
236 SignonDaemon::~SignonDaemon()
245 SignonAuthSession::stopAllAuthSessions();
246 m_storedIdentities.clear();
247 m_unstoredIdentities.clear();
250 m_pCAMManager->closeCredentialsSystem();
251 delete m_pCAMManager;
254 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
256 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH
257 + QLatin1String(
"/Backup"));
258 sessionConnection.unregisterService(SIGNOND_SERVICE
259 + QLatin1String(
".Backup"));
260 if (m_backup ==
false)
262 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH);
263 sessionConnection.unregisterService(SIGNOND_SERVICE);
266 delete m_configuration;
268 QMetaObject::invokeMethod(QCoreApplication::instance(),
270 Qt::QueuedConnection);
273 void SignonDaemon::setupSignalHandlers()
275 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0)
276 BLAME() <<
"Couldn't create HUP socketpair";
278 m_sigSn =
new QSocketNotifier(sigFd[1], QSocketNotifier::Read,
this);
279 connect(m_sigSn, SIGNAL(activated(
int)),
280 this, SLOT(handleUnixSignal()));
283 void SignonDaemon::signalHandler(
int signal)
285 int ret = ::write(sigFd[0], &signal,
sizeof(signal));
289 void SignonDaemon::handleUnixSignal()
291 m_sigSn->setEnabled(
false);
294 int ret = read(sigFd[1], &signal,
sizeof(signal));
297 TRACE() <<
"signal received: " << signal;
301 TRACE() <<
"\n\n SIGHUP \n\n";
307 QMetaObject::invokeMethod(instance(),
309 Qt::QueuedConnection);
313 TRACE() <<
"\n\n SIGTERM \n\n";
316 QMetaObject::invokeMethod(QCoreApplication::instance(),
318 Qt::QueuedConnection);
322 TRACE() <<
"\n\n SIGINT \n\n";
325 QMetaObject::invokeMethod(QCoreApplication::instance(),
327 Qt::QueuedConnection);
333 m_sigSn->setEnabled(
true);
338 if (m_instance != NULL)
341 QCoreApplication *app = QCoreApplication::instance();
344 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
345 "constructed first");
347 TRACE() <<
"Creating new daemon instance.";
352 void SignonDaemon::init()
355 qWarning(
"SignonDaemon could not create the configuration object.");
357 m_configuration->load();
360 BLAME() <<
"Failed to SUID root. Secure storage will not be available.";
363 QCoreApplication *app = QCoreApplication::instance();
365 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
366 "constructed first");
368 setupSignalHandlers();
369 m_backup = app->arguments().contains(QLatin1String(
"-backup"));
374 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
376 if (!sessionConnection.isConnected()) {
377 QDBusError err = sessionConnection.lastError();
378 TRACE() <<
"Session connection cannot be established:" <<
379 err.errorString(err.type());
380 TRACE() << err.message();
382 qFatal(
"SignonDaemon requires session bus to start working");
385 QDBusConnection::RegisterOptions registerSessionOptions =
386 QDBusConnection::ExportAdaptors;
390 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
391 + QLatin1String(
"/Backup"),
392 this, registerSessionOptions)) {
393 TRACE() <<
"Object cannot be registered";
395 qFatal(
"SignonDaemon requires to register backup object");
398 if (!sessionConnection.registerService(SIGNOND_SERVICE +
399 QLatin1String(
".Backup"))) {
400 QDBusError err = sessionConnection.lastError();
401 TRACE() <<
"Service cannot be registered: " <<
402 err.errorString(err.type());
404 qFatal(
"SignonDaemon requires to register backup service");
408 TRACE() <<
"Signond initialized in backup mode.";
414 QDBusConnection connection = SIGNOND_BUS;
416 if (!connection.isConnected()) {
417 QDBusError err = connection.lastError();
418 TRACE() <<
"Connection cannot be established:" <<
419 err.errorString(err.type());
420 TRACE() << err.message();
422 qFatal(
"SignonDaemon requires DBus to start working");
425 QDBusConnection::RegisterOptions registerOptions =
426 QDBusConnection::ExportAllContents;
429 registerOptions = QDBusConnection::ExportAdaptors;
431 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
432 this, registerOptions)) {
433 TRACE() <<
"Object cannot be registered";
435 qFatal(
"SignonDaemon requires to register daemon's object");
438 if (!connection.registerService(SIGNOND_SERVICE)) {
439 QDBusError err = connection.lastError();
440 TRACE() <<
"Service cannot be registered: " <<
441 err.errorString(err.type());
443 qFatal(
"SignonDaemon requires to register daemon's service");
447 connection.connect(QString(),
448 QLatin1String(
"/org/freedesktop/DBus/Local"),
449 QLatin1String(
"org.freedesktop.DBus.Local"),
450 QLatin1String(
"Disconnected"),
451 this, SLOT(onDisconnected()));
456 BLAME() <<
"Signond: Cannot initialize credentials storage.";
458 if (m_configuration->daemonTimeout() > 0) {
459 SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(),
460 this, SLOT(deleteLater()));
463 TRACE() <<
"Signond SUCCESSFULLY initialized.";
466 void SignonDaemon::initExtensions()
471 QDir dir(m_configuration->extensionsDir());
472 QStringList filters(QLatin1String(
"lib*.so"));
473 QStringList extensionList = dir.entryList(filters, QDir::Files);
474 foreach(QString filename, extensionList)
475 initExtension(dir.filePath(filename));
478 void SignonDaemon::initExtension(
const QString &filePath)
480 TRACE() <<
"Loading plugin " << filePath;
482 QPluginLoader pluginLoader(filePath);
483 QObject *plugin = pluginLoader.instance();
485 qWarning() <<
"Couldn't load plugin:" << pluginLoader.errorString();
491 bool extensionInUse =
false;
492 if (m_pCAMManager->initExtension(plugin))
493 extensionInUse =
true;
495 if (!extensionInUse) {
496 pluginLoader.unload();
500 bool SignonDaemon::initStorage()
502 if (!m_pCAMManager->credentialsSystemOpened()) {
503 m_pCAMManager->finalize();
505 if (!m_pCAMManager->init()) {
506 BLAME() <<
"CAM initialization failed";
511 if (!m_pCAMManager->openCredentialsSystem()) {
512 qCritical(
"Signond: Cannot open CAM credentials system...");
516 TRACE() <<
"Secure storage already initialized...";
523 void SignonDaemon::identityStored(SignonIdentity *identity)
525 if (m_unstoredIdentities.contains(identity->objectName())) {
526 m_unstoredIdentities.remove(identity->objectName());
527 m_storedIdentities.insert(identity->id(), identity);
531 void SignonDaemon::registerNewIdentity(QDBusObjectPath &objectPath)
533 TRACE() <<
"Registering new identity:";
536 SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY,
this);
538 if (identity == NULL) {
541 QLatin1String(
"Could not create remote Identity "
546 m_unstoredIdentities.insert(identity->objectName(), identity);
548 objectPath = QDBusObjectPath(identity->objectName());
551 int SignonDaemon::identityTimeout()
const
553 return (m_configuration == NULL ?
555 m_configuration->identityTimeout());
558 int SignonDaemon::authSessionTimeout()
const
560 return (m_configuration == NULL ?
562 m_configuration->authSessionTimeout());
565 void SignonDaemon::getIdentity(
const quint32
id,
566 QDBusObjectPath &objectPath,
567 QVariantMap &identityData)
571 TRACE() <<
"Registering identity:" << id;
577 if (identity == NULL)
578 identity = SignonIdentity::createIdentity(
id,
this);
580 if (identity == NULL)
584 QLatin1String(
"Could not create remote Identity "
594 sendErrorReply(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
595 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
600 m_storedIdentities.insert(identity->
id(), identity);
603 identityData = info.
toMap();
605 TRACE() <<
"DONE REGISTERING IDENTITY";
606 objectPath = QDBusObjectPath(identity->objectName());
609 QStringList SignonDaemon::queryMethods()
611 QDir pluginsDir(m_configuration->pluginsDir());
613 QStringList fileNames = pluginsDir.entryList(
614 QStringList() << QLatin1String(
"*.so*"),
615 QDir::Files | QDir::NoDotAndDotDot);
619 foreach (fileName, fileNames) {
620 if (fileName.startsWith(QLatin1String(
"lib"))) {
622 fileName.mid(3, fileName.indexOf(QLatin1String(
"plugin")) -3);
623 if ((fileName.length() > 0) && !ret.contains(fileName))
631 QStringList SignonDaemon::queryMechanisms(
const QString &method)
633 TRACE() <<
"\n\n\n Querying mechanisms\n\n";
635 QStringList mechs = SignonSessionCore::loadedPluginMethods(method);
640 PluginProxy *plugin = PluginProxy::createNewPluginProxy(method);
643 TRACE() <<
"Could not load plugin of type: " << method;
644 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
645 SIGNOND_METHOD_NOT_KNOWN_ERR_STR +
646 QString::fromLatin1(
"Method %1 is not known or could "
647 "not load specific configuration.").
649 return QStringList();
662 TRACE() <<
"Querying identities";
666 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
671 QMapIterator<QString, QVariant> it(filter);
672 while (it.hasNext()) {
674 filterLocal.insert(it.key(), it.value().toString());
682 QLatin1String(
"Querying database error occurred."));
688 mapList.append(info.
toMap());
693 bool SignonDaemon::clear()
697 TRACE() <<
"\n\n\n Clearing DB\n\n";
700 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
705 sendErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME,
706 SIGNOND_INTERNAL_SERVER_ERR_STR +
707 QLatin1String(
"Database error occurred."));
713 QString SignonDaemon::getAuthSessionObjectPath(
const quint32
id,
716 bool supportsAuthMethod =
false;
717 pid_t ownerPid = AccessControlManagerHelper::pidOfPeer(*
this);
719 SignonAuthSession::getAuthSessionObjectPath(
id, type,
this,
722 if (objectPath.isEmpty() && !supportsAuthMethod) {
723 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
724 SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
730 void SignonDaemon::eraseBackupDir()
const
735 QDir target(backupRoot);
736 if (!target.exists())
return;
738 QStringList targetEntries = target.entryList(QDir::Files);
739 foreach (QString entry, targetEntries) {
740 target.remove(entry);
743 target.rmdir(backupRoot);
746 bool SignonDaemon::copyToBackupDir(
const QStringList &fileNames)
const
748 const CAMConfiguration config = m_configuration->camConfiguration();
751 QDir target(backupRoot);
752 if (!target.exists() && !target.mkpath(backupRoot)) {
753 qCritical() <<
"Cannot create target directory";
761 foreach (QString fileName, fileNames) {
763 if (target.exists(fileName))
764 target.remove(fileName);
767 QString source = config.m_storagePath + QDir::separator() + fileName;
768 if (!QFile::exists(source))
continue;
770 QString destination = backupRoot + QDir::separator() + fileName;
771 ok = QFile::copy(source, destination);
773 BLAME() <<
"Copying" << source <<
"to" << destination <<
"failed";
783 bool SignonDaemon::copyFromBackupDir(
const QStringList &fileNames)
const
785 const CAMConfiguration config = m_configuration->camConfiguration();
788 QDir sourceDir(backupRoot);
789 if (!sourceDir.exists()) {
790 TRACE() <<
"Backup directory does not exist!";
793 if (!sourceDir.exists(config.m_dbName)) {
794 TRACE() <<
"Backup does not contain DB:" << config.m_dbName;
799 QDir target(config.m_storagePath);
800 QStringList movedFiles, copiedFiles;
801 foreach (QString fileName, fileNames) {
803 if (target.exists(fileName)) {
804 if (target.rename(fileName, fileName + QLatin1String(
".bak")))
805 movedFiles += fileName;
809 QString source = backupRoot + QDir::separator() + fileName;
810 if (!QFile::exists(source)) {
811 TRACE() <<
"Ignoring file not present in backup:" << source;
815 QString destination =
816 config.m_storagePath + QDir::separator() + fileName;
818 ok = QFile::copy(source, destination);
820 copiedFiles << fileName;
822 qWarning() <<
"Copy failed for:" << source;
828 qWarning() <<
"Restore failed, recovering previous DB";
830 foreach (QString fileName, copiedFiles) {
831 target.remove(fileName);
834 foreach (QString fileName, movedFiles) {
835 if (!target.rename(fileName + QLatin1String(
".bak"), fileName)) {
836 qCritical() <<
"Could not recover:" << fileName;
841 foreach (QString fileName, movedFiles) {
842 target.remove(fileName + QLatin1String(
".bak"));
849 bool SignonDaemon::createStorageFileTree(
const QStringList &backupFiles)
const
851 QString storageDirPath = m_configuration->camConfiguration().m_storagePath;
852 QDir storageDir(storageDirPath);
854 if (!storageDir.exists()) {
855 if (!storageDir.mkpath(storageDirPath)) {
856 qCritical() <<
"Could not create storage dir for backup.";
861 foreach (QString fileName, backupFiles) {
862 if (storageDir.exists(fileName))
continue;
864 QString filePath = storageDir.path() + QDir::separator() + fileName;
865 QFile file(filePath);
866 if (!file.open(QIODevice::WriteOnly)) {
867 qCritical() <<
"Failed to create empty file for backup:" << filePath;
877 uchar SignonDaemon::backupStarts()
880 if (!m_backup && m_pCAMManager->credentialsSystemOpened())
882 m_pCAMManager->closeCredentialsSystem();
883 if (m_pCAMManager->credentialsSystemOpened())
885 qCritical() <<
"Cannot close credentials database";
893 QStringList backupFiles;
895 backupFiles << m_pCAMManager->backupFiles();
900 if (!createStorageFileTree(backupFiles)) {
901 qCritical() <<
"Cannot create backup file tree.";
907 if (!copyToBackupDir(backupFiles)) {
908 qCritical() <<
"Cannot copy database";
910 m_pCAMManager->openCredentialsSystem();
917 if (!m_pCAMManager->openCredentialsSystem()) {
918 qCritical() <<
"Cannot reopen database";
924 uchar SignonDaemon::backupFinished()
933 TRACE() <<
"close daemon";
943 uchar SignonDaemon::restoreStarts()
949 uchar SignonDaemon::restoreFinished()
951 TRACE() <<
"restore";
953 if (m_pCAMManager->credentialsSystemOpened())
956 if (!m_pCAMManager->closeCredentialsSystem())
958 qCritical() <<
"database cannot be closed";
965 QStringList backupFiles;
967 backupFiles << m_pCAMManager->backupFiles();
970 if (!copyFromBackupDir(backupFiles)) {
971 qCritical() <<
"Cannot copy database";
972 m_pCAMManager->openCredentialsSystem();
982 if (!m_pCAMManager->openCredentialsSystem())
989 void SignonDaemon::onDisconnected()
991 TRACE() <<
"Disconnected from session bus: exiting";
993 QMetaObject::invokeMethod(QCoreApplication::instance(),
995 Qt::QueuedConnection);