25 #include <sys/socket.h>
27 #include <sys/types.h>
32 #include <QDBusConnection>
33 #include <QDBusMessage>
34 #include <QDBusMetaType>
35 #include <QPluginLoader>
36 #include <QProcessEnvironment>
37 #include <QSocketNotifier>
39 #include "SignOn/misc.h"
50 #define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_) do { \
51 if (m_pCAMManager && !m_pCAMManager->credentialsSystemOpened()) { \
52 sendErrorReply(internalServerErrName, \
53 internalServerErrStr + \
54 QLatin1String("Could not access Signon " \
60 #define BACKUP_DIR_NAME() \
61 (QDir::separator() + QLatin1String("backup"))
63 using namespace SignOn;
65 namespace SignonDaemonNS {
69 SignonDaemonConfiguration::SignonDaemonConfiguration():
71 m_extensionsDir(QLatin1String(SIGNOND_EXTENSIONS_DIR)),
74 m_identityTimeout(300),
75 m_authSessionTimeout(300)
105 QSettings::setPath(QSettings::NativeFormat, QSettings::SystemScope,
106 QLatin1String(
"/etc"));
108 QSettings settings(QLatin1String(
"signond"));
111 settings.value(QLatin1String(
"LoggingLevel"), 1).toInt();
112 setLoggingLevel(loggingLevel);
114 QString cfgStoragePath =
115 settings.value(QLatin1String(
"StoragePath")).toString();
116 if (!cfgStoragePath.isEmpty()) {
117 QString storagePath = QDir(cfgStoragePath).path();
120 QString xdgConfigHome = QLatin1String(qgetenv(
"XDG_CONFIG_HOME"));
121 if (xdgConfigHome.isEmpty())
122 xdgConfigHome = QDir::homePath() + QLatin1String(
"/.config");
124 QLatin1String(
"/signond"));
130 QString useSecureStorage =
131 settings.value(QLatin1String(
"UseSecureStorage")).toString();
132 if (useSecureStorage == QLatin1String(
"yes") ||
133 useSecureStorage == QLatin1String(
"true")) {
134 m_camConfiguration.
addSetting(QLatin1String(
"CryptoManager"),
135 QLatin1String(
"cryptsetup"));
138 settings.beginGroup(QLatin1String(
"SecureStorage"));
140 QVariantMap storageOptions;
141 foreach (
const QString &key, settings.childKeys()) {
142 m_camConfiguration.
addSetting(key, settings.value(key));
148 settings.beginGroup(QLatin1String(
"ObjectTimeouts"));
151 uint aux = settings.value(QLatin1String(
"Identity")).toUInt(&isOk);
153 m_identityTimeout = aux;
155 aux = settings.value(QLatin1String(
"AuthSession")).toUInt(&isOk);
157 m_authSessionTimeout = aux;
163 QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
165 if (environment.contains(QLatin1String(
"SSO_DAEMON_TIMEOUT"))) {
166 value = environment.value(
167 QLatin1String(
"SSO_DAEMON_TIMEOUT")).toInt(&isOk);
168 if (value > 0 && isOk) m_daemonTimeout = value;
171 if (environment.contains(QLatin1String(
"SSO_IDENTITY_TIMEOUT"))) {
172 value = environment.value(
173 QLatin1String(
"SSO_IDENTITY_TIMEOUT")).toInt(&isOk);
174 if (value > 0 && isOk) m_identityTimeout = value;
177 if (environment.contains(QLatin1String(
"SSO_AUTHSESSION_TIMEOUT"))) {
178 value = environment.value(
179 QLatin1String(
"SSO_AUTHSESSION_TIMEOUT")).toInt(&isOk);
180 if (value > 0 && isOk) m_authSessionTimeout = value;
183 if (environment.contains(QLatin1String(
"SSO_LOGGING_LEVEL"))) {
184 value = environment.value(
185 QLatin1String(
"SSO_LOGGING_LEVEL")).toInt(&isOk);
187 setLoggingLevel(value);
190 QString logOutput = environment.value(QLatin1String(
"SSO_LOGGING_OUTPUT"),
191 QLatin1String(
"syslog"));
192 SignonTrace::initialize(logOutput == QLatin1String(
"syslog") ?
193 SignonTrace::Syslog : SignonTrace::Stdout);
195 if (environment.contains(QLatin1String(
"SSO_STORAGE_PATH"))) {
197 environment.value(QLatin1String(
"SSO_STORAGE_PATH")));
200 if (environment.contains(QLatin1String(
"SSO_PLUGINS_DIR"))) {
201 m_pluginsDir = environment.value(QLatin1String(
"SSO_PLUGINS_DIR"));
204 if (environment.contains(QLatin1String(
"SSO_EXTENSIONS_DIR"))) {
206 environment.value(QLatin1String(
"SSO_EXTENSIONS_DIR"));
219 SignonDaemon::SignonDaemon(QObject *parent) : QObject(parent)
220 , m_configuration(NULL)
223 umask(S_IROTH | S_IWOTH);
226 qDBusRegisterMetaType<MethodMap>();
227 qDBusRegisterMetaType<MapList>();
230 SignonDaemon::~SignonDaemon()
239 SignonAuthSession::stopAllAuthSessions();
240 m_storedIdentities.clear();
241 m_unstoredIdentities.clear();
244 m_pCAMManager->closeCredentialsSystem();
245 delete m_pCAMManager;
248 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
250 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH
251 + QLatin1String(
"/Backup"));
252 sessionConnection.unregisterService(SIGNOND_SERVICE
253 + QLatin1String(
".Backup"));
254 if (m_backup ==
false)
256 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH);
257 sessionConnection.unregisterService(SIGNOND_SERVICE);
260 delete m_configuration;
262 QMetaObject::invokeMethod(QCoreApplication::instance(),
264 Qt::QueuedConnection);
267 void SignonDaemon::setupSignalHandlers()
269 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0)
270 BLAME() <<
"Couldn't create HUP socketpair";
272 m_sigSn =
new QSocketNotifier(sigFd[1], QSocketNotifier::Read,
this);
273 connect(m_sigSn, SIGNAL(activated(
int)),
274 this, SLOT(handleUnixSignal()));
277 void SignonDaemon::signalHandler(
int signal)
279 int ret = ::write(sigFd[0], &signal,
sizeof(signal));
283 void SignonDaemon::handleUnixSignal()
285 m_sigSn->setEnabled(
false);
288 int ret = read(sigFd[1], &signal,
sizeof(signal));
291 TRACE() <<
"signal received: " << signal;
295 TRACE() <<
"\n\n SIGHUP \n\n";
301 QMetaObject::invokeMethod(instance(),
303 Qt::QueuedConnection);
307 TRACE() <<
"\n\n SIGTERM \n\n";
310 QMetaObject::invokeMethod(QCoreApplication::instance(),
312 Qt::QueuedConnection);
316 TRACE() <<
"\n\n SIGINT \n\n";
319 QMetaObject::invokeMethod(QCoreApplication::instance(),
321 Qt::QueuedConnection);
327 m_sigSn->setEnabled(
true);
332 if (m_instance != NULL)
335 QCoreApplication *app = QCoreApplication::instance();
338 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
339 "constructed first");
341 TRACE() <<
"Creating new daemon instance.";
346 void SignonDaemon::init()
349 qWarning(
"SignonDaemon could not create the configuration object.");
351 m_configuration->load();
354 BLAME() <<
"Failed to SUID root. Secure storage will not be available.";
357 QCoreApplication *app = QCoreApplication::instance();
359 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
360 "constructed first");
362 setupSignalHandlers();
363 m_backup = app->arguments().contains(QLatin1String(
"-backup"));
368 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
370 if (!sessionConnection.isConnected()) {
371 QDBusError err = sessionConnection.lastError();
372 TRACE() <<
"Session connection cannot be established:" <<
373 err.errorString(err.type());
374 TRACE() << err.message();
376 qFatal(
"SignonDaemon requires session bus to start working");
379 QDBusConnection::RegisterOptions registerSessionOptions =
380 QDBusConnection::ExportAdaptors;
384 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
385 + QLatin1String(
"/Backup"),
386 this, registerSessionOptions)) {
387 TRACE() <<
"Object cannot be registered";
389 qFatal(
"SignonDaemon requires to register backup object");
392 if (!sessionConnection.registerService(SIGNOND_SERVICE +
393 QLatin1String(
".Backup"))) {
394 QDBusError err = sessionConnection.lastError();
395 TRACE() <<
"Service cannot be registered: " <<
396 err.errorString(err.type());
398 qFatal(
"SignonDaemon requires to register backup service");
402 TRACE() <<
"Signond initialized in backup mode.";
408 QDBusConnection connection = SIGNOND_BUS;
410 if (!connection.isConnected()) {
411 QDBusError err = connection.lastError();
412 TRACE() <<
"Connection cannot be established:" <<
413 err.errorString(err.type());
414 TRACE() << err.message();
416 qFatal(
"SignonDaemon requires DBus to start working");
419 QDBusConnection::RegisterOptions registerOptions =
420 QDBusConnection::ExportAllContents;
423 registerOptions = QDBusConnection::ExportAdaptors;
425 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
426 this, registerOptions)) {
427 TRACE() <<
"Object cannot be registered";
429 qFatal(
"SignonDaemon requires to register daemon's object");
432 if (!connection.registerService(SIGNOND_SERVICE)) {
433 QDBusError err = connection.lastError();
434 TRACE() <<
"Service cannot be registered: " <<
435 err.errorString(err.type());
437 qFatal(
"SignonDaemon requires to register daemon's service");
441 connection.connect(QString(),
442 QLatin1String(
"/org/freedesktop/DBus/Local"),
443 QLatin1String(
"org.freedesktop.DBus.Local"),
444 QLatin1String(
"Disconnected"),
445 this, SLOT(onDisconnected()));
450 BLAME() <<
"Signond: Cannot initialize credentials storage.";
452 if (m_configuration->daemonTimeout() > 0) {
453 SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(),
454 this, SLOT(deleteLater()));
457 TRACE() <<
"Signond SUCCESSFULLY initialized.";
460 void SignonDaemon::initExtensions()
465 QDir dir(m_configuration->extensionsDir());
466 QStringList filters(QLatin1String(
"lib*.so"));
467 QStringList extensionList = dir.entryList(filters, QDir::Files);
468 foreach(QString filename, extensionList)
469 initExtension(dir.filePath(filename));
472 void SignonDaemon::initExtension(
const QString &filePath)
474 TRACE() <<
"Loading plugin " << filePath;
476 QPluginLoader pluginLoader(filePath);
477 QObject *plugin = pluginLoader.instance();
479 qWarning() <<
"Couldn't load plugin:" << pluginLoader.errorString();
485 bool extensionInUse =
false;
486 if (m_pCAMManager->initExtension(plugin))
487 extensionInUse =
true;
489 if (!extensionInUse) {
490 pluginLoader.unload();
494 bool SignonDaemon::initStorage()
496 if (!m_pCAMManager->credentialsSystemOpened()) {
497 m_pCAMManager->finalize();
499 if (!m_pCAMManager->init()) {
500 BLAME() <<
"CAM initialization failed";
505 if (!m_pCAMManager->openCredentialsSystem()) {
506 qCritical(
"Signond: Cannot open CAM credentials system...");
510 TRACE() <<
"Secure storage already initialized...";
517 void SignonDaemon::identityStored(SignonIdentity *identity)
519 if (m_unstoredIdentities.contains(identity->objectName())) {
520 m_unstoredIdentities.remove(identity->objectName());
521 m_storedIdentities.insert(identity->id(), identity);
525 void SignonDaemon::registerNewIdentity(QDBusObjectPath &objectPath)
527 TRACE() <<
"Registering new identity:";
530 SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY,
this);
532 if (identity == NULL) {
535 QLatin1String(
"Could not create remote Identity "
540 m_unstoredIdentities.insert(identity->objectName(), identity);
542 objectPath = QDBusObjectPath(identity->objectName());
545 int SignonDaemon::identityTimeout()
const
547 return (m_configuration == NULL ?
549 m_configuration->identityTimeout());
552 int SignonDaemon::authSessionTimeout()
const
554 return (m_configuration == NULL ?
556 m_configuration->authSessionTimeout());
559 void SignonDaemon::getIdentity(
const quint32
id,
560 QDBusObjectPath &objectPath,
561 QVariantMap &identityData)
565 TRACE() <<
"Registering identity:" << id;
571 if (identity == NULL)
572 identity = SignonIdentity::createIdentity(
id,
this);
574 if (identity == NULL)
578 QLatin1String(
"Could not create remote Identity "
588 sendErrorReply(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
589 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
594 m_storedIdentities.insert(identity->
id(), identity);
597 identityData = info.
toMap();
599 TRACE() <<
"DONE REGISTERING IDENTITY";
600 objectPath = QDBusObjectPath(identity->objectName());
603 QStringList SignonDaemon::queryMethods()
605 QDir pluginsDir(m_configuration->pluginsDir());
607 QStringList fileNames = pluginsDir.entryList(
608 QStringList() << QLatin1String(
"*.so*"),
609 QDir::Files | QDir::NoDotAndDotDot);
613 foreach (fileName, fileNames) {
614 if (fileName.startsWith(QLatin1String(
"lib"))) {
616 fileName.mid(3, fileName.indexOf(QLatin1String(
"plugin")) -3);
617 if ((fileName.length() > 0) && !ret.contains(fileName))
625 QStringList SignonDaemon::queryMechanisms(
const QString &method)
627 TRACE() <<
"\n\n\n Querying mechanisms\n\n";
629 QStringList mechs = SignonSessionCore::loadedPluginMethods(method);
634 PluginProxy *plugin = PluginProxy::createNewPluginProxy(method);
637 TRACE() <<
"Could not load plugin of type: " << method;
638 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
639 SIGNOND_METHOD_NOT_KNOWN_ERR_STR +
640 QString::fromLatin1(
"Method %1 is not known or could "
641 "not load specific configuration.").
643 return QStringList();
656 TRACE() <<
"Querying identities";
660 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
665 QMapIterator<QString, QVariant> it(filter);
666 while (it.hasNext()) {
668 filterLocal.insert(it.key(), it.value().toString());
676 QLatin1String(
"Querying database error occurred."));
682 mapList.append(info.
toMap());
687 bool SignonDaemon::clear()
691 TRACE() <<
"\n\n\n Clearing DB\n\n";
694 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
699 sendErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME,
700 SIGNOND_INTERNAL_SERVER_ERR_STR +
701 QLatin1String(
"Database error occurred."));
707 QString SignonDaemon::getAuthSessionObjectPath(
const quint32
id,
710 bool supportsAuthMethod =
false;
711 pid_t ownerPid = AccessControlManagerHelper::pidOfPeer(*
this);
713 SignonAuthSession::getAuthSessionObjectPath(
id, type,
this,
716 if (objectPath.isEmpty() && !supportsAuthMethod) {
717 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
718 SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
724 void SignonDaemon::eraseBackupDir()
const
729 QDir target(backupRoot);
730 if (!target.exists())
return;
732 QStringList targetEntries = target.entryList(QDir::Files);
733 foreach (QString entry, targetEntries) {
734 target.remove(entry);
737 target.rmdir(backupRoot);
740 bool SignonDaemon::copyToBackupDir(
const QStringList &fileNames)
const
742 const CAMConfiguration config = m_configuration->camConfiguration();
745 QDir target(backupRoot);
746 if (!target.exists() && !target.mkpath(backupRoot)) {
747 qCritical() <<
"Cannot create target directory";
755 foreach (QString fileName, fileNames) {
757 if (target.exists(fileName))
758 target.remove(fileName);
761 QString source = config.m_storagePath + QDir::separator() + fileName;
762 if (!QFile::exists(source))
continue;
764 QString destination = backupRoot + QDir::separator() + fileName;
765 ok = QFile::copy(source, destination);
767 BLAME() <<
"Copying" << source <<
"to" << destination <<
"failed";
777 bool SignonDaemon::copyFromBackupDir(
const QStringList &fileNames)
const
779 const CAMConfiguration config = m_configuration->camConfiguration();
782 QDir sourceDir(backupRoot);
783 if (!sourceDir.exists()) {
784 TRACE() <<
"Backup directory does not exist!";
787 if (!sourceDir.exists(config.m_dbName)) {
788 TRACE() <<
"Backup does not contain DB:" << config.m_dbName;
793 QDir target(config.m_storagePath);
794 QStringList movedFiles, copiedFiles;
795 foreach (QString fileName, fileNames) {
797 if (target.exists(fileName)) {
798 if (target.rename(fileName, fileName + QLatin1String(
".bak")))
799 movedFiles += fileName;
803 QString source = backupRoot + QDir::separator() + fileName;
804 if (!QFile::exists(source)) {
805 TRACE() <<
"Ignoring file not present in backup:" << source;
809 QString destination =
810 config.m_storagePath + QDir::separator() + fileName;
812 ok = QFile::copy(source, destination);
814 copiedFiles << fileName;
816 qWarning() <<
"Copy failed for:" << source;
822 qWarning() <<
"Restore failed, recovering previous DB";
824 foreach (QString fileName, copiedFiles) {
825 target.remove(fileName);
828 foreach (QString fileName, movedFiles) {
829 if (!target.rename(fileName + QLatin1String(
".bak"), fileName)) {
830 qCritical() <<
"Could not recover:" << fileName;
835 foreach (QString fileName, movedFiles) {
836 target.remove(fileName + QLatin1String(
".bak"));
843 bool SignonDaemon::createStorageFileTree(
const QStringList &backupFiles)
const
845 QString storageDirPath = m_configuration->camConfiguration().m_storagePath;
846 QDir storageDir(storageDirPath);
848 if (!storageDir.exists()) {
849 if (!storageDir.mkpath(storageDirPath)) {
850 qCritical() <<
"Could not create storage dir for backup.";
855 foreach (QString fileName, backupFiles) {
856 if (storageDir.exists(fileName))
continue;
858 QString filePath = storageDir.path() + QDir::separator() + fileName;
859 QFile file(filePath);
860 if (!file.open(QIODevice::WriteOnly)) {
861 qCritical() <<
"Failed to create empty file for backup:" << filePath;
871 uchar SignonDaemon::backupStarts()
874 if (!m_backup && m_pCAMManager->credentialsSystemOpened())
876 m_pCAMManager->closeCredentialsSystem();
877 if (m_pCAMManager->credentialsSystemOpened())
879 qCritical() <<
"Cannot close credentials database";
887 QStringList backupFiles;
889 backupFiles << m_pCAMManager->backupFiles();
894 if (!createStorageFileTree(backupFiles)) {
895 qCritical() <<
"Cannot create backup file tree.";
901 if (!copyToBackupDir(backupFiles)) {
902 qCritical() <<
"Cannot copy database";
904 m_pCAMManager->openCredentialsSystem();
911 if (!m_pCAMManager->openCredentialsSystem()) {
912 qCritical() <<
"Cannot reopen database";
918 uchar SignonDaemon::backupFinished()
927 TRACE() <<
"close daemon";
937 uchar SignonDaemon::restoreStarts()
943 uchar SignonDaemon::restoreFinished()
945 TRACE() <<
"restore";
947 if (m_pCAMManager->credentialsSystemOpened())
950 if (!m_pCAMManager->closeCredentialsSystem())
952 qCritical() <<
"database cannot be closed";
959 QStringList backupFiles;
961 backupFiles << m_pCAMManager->backupFiles();
964 if (!copyFromBackupDir(backupFiles)) {
965 qCritical() <<
"Cannot copy database";
966 m_pCAMManager->openCredentialsSystem();
976 if (!m_pCAMManager->openCredentialsSystem())
983 void SignonDaemon::onDisconnected()
985 TRACE() <<
"Disconnected from session bus: exiting";
987 QMetaObject::invokeMethod(QCoreApplication::instance(),
989 Qt::QueuedConnection);