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 storagePath =
115 QDir(settings.value(QLatin1String(
"StoragePath")).toString()).path();
121 QString useSecureStorage =
122 settings.value(QLatin1String(
"UseSecureStorage")).toString();
123 if (useSecureStorage == QLatin1String(
"yes") ||
124 useSecureStorage == QLatin1String(
"true")) {
125 m_camConfiguration.
addSetting(QLatin1String(
"CryptoManager"),
126 QLatin1String(
"cryptsetup"));
129 settings.beginGroup(QLatin1String(
"SecureStorage"));
131 QVariantMap storageOptions;
132 foreach (
const QString &key, settings.childKeys()) {
133 m_camConfiguration.
addSetting(key, settings.value(key));
139 settings.beginGroup(QLatin1String(
"ObjectTimeouts"));
142 uint aux = settings.value(QLatin1String(
"Identity")).toUInt(&isOk);
144 m_identityTimeout = aux;
146 aux = settings.value(QLatin1String(
"AuthSession")).toUInt(&isOk);
148 m_authSessionTimeout = aux;
154 QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
156 if (environment.contains(QLatin1String(
"SSO_DAEMON_TIMEOUT"))) {
157 value = environment.value(
158 QLatin1String(
"SSO_DAEMON_TIMEOUT")).toInt(&isOk);
159 if (value > 0 && isOk) m_daemonTimeout = value;
162 if (environment.contains(QLatin1String(
"SSO_IDENTITY_TIMEOUT"))) {
163 value = environment.value(
164 QLatin1String(
"SSO_IDENTITY_TIMEOUT")).toInt(&isOk);
165 if (value > 0 && isOk) m_identityTimeout = value;
168 if (environment.contains(QLatin1String(
"SSO_AUTHSESSION_TIMEOUT"))) {
169 value = environment.value(
170 QLatin1String(
"SSO_AUTHSESSION_TIMEOUT")).toInt(&isOk);
171 if (value > 0 && isOk) m_authSessionTimeout = value;
174 if (environment.contains(QLatin1String(
"SSO_LOGGING_LEVEL"))) {
175 value = environment.value(
176 QLatin1String(
"SSO_LOGGING_LEVEL")).toInt(&isOk);
178 setLoggingLevel(value);
181 QString logOutput = environment.value(QLatin1String(
"SSO_LOGGING_OUTPUT"),
182 QLatin1String(
"syslog"));
183 SignonTrace::initialize(logOutput == QLatin1String(
"syslog") ?
184 SignonTrace::Syslog : SignonTrace::Stdout);
186 if (environment.contains(QLatin1String(
"SSO_STORAGE_PATH"))) {
188 environment.value(QLatin1String(
"SSO_STORAGE_PATH")));
191 if (environment.contains(QLatin1String(
"SSO_PLUGINS_DIR"))) {
192 m_pluginsDir = environment.value(QLatin1String(
"SSO_PLUGINS_DIR"));
195 if (environment.contains(QLatin1String(
"SSO_EXTENSIONS_DIR"))) {
197 environment.value(QLatin1String(
"SSO_EXTENSIONS_DIR"));
210 SignonDaemon::SignonDaemon(QObject *parent) : QObject(parent)
211 , m_configuration(NULL)
214 umask(S_IROTH | S_IWOTH);
217 qDBusRegisterMetaType<MethodMap>();
218 qDBusRegisterMetaType<MapList>();
221 SignonDaemon::~SignonDaemon()
230 SignonAuthSession::stopAllAuthSessions();
231 m_storedIdentities.clear();
232 m_unstoredIdentities.clear();
235 m_pCAMManager->closeCredentialsSystem();
236 delete m_pCAMManager;
239 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
241 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH
242 + QLatin1String(
"/Backup"));
243 sessionConnection.unregisterService(SIGNOND_SERVICE
244 + QLatin1String(
".Backup"));
245 if (m_backup ==
false)
247 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH);
248 sessionConnection.unregisterService(SIGNOND_SERVICE);
251 delete m_configuration;
253 QMetaObject::invokeMethod(QCoreApplication::instance(),
255 Qt::QueuedConnection);
258 void SignonDaemon::setupSignalHandlers()
260 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0)
261 BLAME() <<
"Couldn't create HUP socketpair";
263 m_sigSn =
new QSocketNotifier(sigFd[1], QSocketNotifier::Read,
this);
264 connect(m_sigSn, SIGNAL(activated(
int)),
265 this, SLOT(handleUnixSignal()));
268 void SignonDaemon::signalHandler(
int signal)
270 int ret = ::write(sigFd[0], &signal,
sizeof(signal));
274 void SignonDaemon::handleUnixSignal()
276 m_sigSn->setEnabled(
false);
279 int ret = read(sigFd[1], &signal,
sizeof(signal));
282 TRACE() <<
"signal received: " << signal;
286 TRACE() <<
"\n\n SIGHUP \n\n";
292 QMetaObject::invokeMethod(instance(),
294 Qt::QueuedConnection);
298 TRACE() <<
"\n\n SIGTERM \n\n";
301 QMetaObject::invokeMethod(QCoreApplication::instance(),
303 Qt::QueuedConnection);
307 TRACE() <<
"\n\n SIGINT \n\n";
310 QMetaObject::invokeMethod(QCoreApplication::instance(),
312 Qt::QueuedConnection);
318 m_sigSn->setEnabled(
true);
323 if (m_instance != NULL)
326 QCoreApplication *app = QCoreApplication::instance();
329 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
330 "constructed first");
332 TRACE() <<
"Creating new daemon instance.";
337 void SignonDaemon::init()
340 qWarning(
"SignonDaemon could not create the configuration object.");
342 m_configuration->load();
345 BLAME() <<
"Failed to SUID root. Secure storage will not be available.";
348 QCoreApplication *app = QCoreApplication::instance();
350 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
351 "constructed first");
353 setupSignalHandlers();
354 m_backup = app->arguments().contains(QLatin1String(
"-backup"));
359 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
361 if (!sessionConnection.isConnected()) {
362 QDBusError err = sessionConnection.lastError();
363 TRACE() <<
"Session connection cannot be established:" <<
364 err.errorString(err.type());
365 TRACE() << err.message();
367 qFatal(
"SignonDaemon requires session bus to start working");
370 QDBusConnection::RegisterOptions registerSessionOptions =
371 QDBusConnection::ExportAdaptors;
375 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
376 + QLatin1String(
"/Backup"),
377 this, registerSessionOptions)) {
378 TRACE() <<
"Object cannot be registered";
380 qFatal(
"SignonDaemon requires to register backup object");
383 if (!sessionConnection.registerService(SIGNOND_SERVICE +
384 QLatin1String(
".Backup"))) {
385 QDBusError err = sessionConnection.lastError();
386 TRACE() <<
"Service cannot be registered: " <<
387 err.errorString(err.type());
389 qFatal(
"SignonDaemon requires to register backup service");
393 TRACE() <<
"Signond initialized in backup mode.";
399 QDBusConnection connection = SIGNOND_BUS;
401 if (!connection.isConnected()) {
402 QDBusError err = connection.lastError();
403 TRACE() <<
"Connection cannot be established:" <<
404 err.errorString(err.type());
405 TRACE() << err.message();
407 qFatal(
"SignonDaemon requires DBus to start working");
410 QDBusConnection::RegisterOptions registerOptions =
411 QDBusConnection::ExportAllContents;
414 registerOptions = QDBusConnection::ExportAdaptors;
416 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
417 this, registerOptions)) {
418 TRACE() <<
"Object cannot be registered";
420 qFatal(
"SignonDaemon requires to register daemon's object");
423 if (!connection.registerService(SIGNOND_SERVICE)) {
424 QDBusError err = connection.lastError();
425 TRACE() <<
"Service cannot be registered: " <<
426 err.errorString(err.type());
428 qFatal(
"SignonDaemon requires to register daemon's service");
432 connection.connect(QString(),
433 QLatin1String(
"/org/freedesktop/DBus/Local"),
434 QLatin1String(
"org.freedesktop.DBus.Local"),
435 QLatin1String(
"Disconnected"),
436 this, SLOT(onDisconnected()));
441 BLAME() <<
"Signond: Cannot initialize credentials storage.";
443 if (m_configuration->daemonTimeout() > 0) {
444 SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(),
445 this, SLOT(deleteLater()));
448 TRACE() <<
"Signond SUCCESSFULLY initialized.";
451 void SignonDaemon::initExtensions()
456 QDir dir(m_configuration->extensionsDir());
457 QStringList filters(QLatin1String(
"lib*.so"));
458 QStringList extensionList = dir.entryList(filters, QDir::Files);
459 foreach(QString filename, extensionList)
460 initExtension(dir.filePath(filename));
463 void SignonDaemon::initExtension(
const QString &filePath)
465 TRACE() <<
"Loading plugin " << filePath;
467 QPluginLoader pluginLoader(filePath);
468 QObject *plugin = pluginLoader.instance();
470 qWarning() <<
"Couldn't load plugin:" << pluginLoader.errorString();
476 bool extensionInUse =
false;
477 if (m_pCAMManager->initExtension(plugin))
478 extensionInUse =
true;
480 if (!extensionInUse) {
481 pluginLoader.unload();
485 bool SignonDaemon::initStorage()
487 if (!m_pCAMManager->credentialsSystemOpened()) {
488 m_pCAMManager->finalize();
490 if (!m_pCAMManager->init()) {
491 BLAME() <<
"CAM initialization failed";
496 if (!m_pCAMManager->openCredentialsSystem()) {
497 qCritical(
"Signond: Cannot open CAM credentials system...");
501 TRACE() <<
"Secure storage already initialized...";
508 void SignonDaemon::identityStored(SignonIdentity *identity)
510 if (m_unstoredIdentities.contains(identity->objectName())) {
511 m_unstoredIdentities.remove(identity->objectName());
512 m_storedIdentities.insert(identity->id(), identity);
516 void SignonDaemon::registerNewIdentity(QDBusObjectPath &objectPath)
518 TRACE() <<
"Registering new identity:";
521 SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY,
this);
523 if (identity == NULL) {
526 QLatin1String(
"Could not create remote Identity "
531 m_unstoredIdentities.insert(identity->objectName(), identity);
533 objectPath = QDBusObjectPath(identity->objectName());
536 int SignonDaemon::identityTimeout()
const
538 return (m_configuration == NULL ?
540 m_configuration->identityTimeout());
543 int SignonDaemon::authSessionTimeout()
const
545 return (m_configuration == NULL ?
547 m_configuration->authSessionTimeout());
550 void SignonDaemon::getIdentity(
const quint32
id,
551 QDBusObjectPath &objectPath,
552 QVariantMap &identityData)
556 TRACE() <<
"Registering identity:" << id;
562 if (identity == NULL)
563 identity = SignonIdentity::createIdentity(
id,
this);
565 if (identity == NULL)
569 QLatin1String(
"Could not create remote Identity "
579 sendErrorReply(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
580 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
585 m_storedIdentities.insert(identity->
id(), identity);
588 identityData = info.
toMap();
590 TRACE() <<
"DONE REGISTERING IDENTITY";
591 objectPath = QDBusObjectPath(identity->objectName());
594 QStringList SignonDaemon::queryMethods()
596 QDir pluginsDir(m_configuration->pluginsDir());
598 QStringList fileNames = pluginsDir.entryList(
599 QStringList() << QLatin1String(
"*.so*"),
600 QDir::Files | QDir::NoDotAndDotDot);
604 foreach (fileName, fileNames) {
605 if (fileName.startsWith(QLatin1String(
"lib"))) {
607 fileName.mid(3, fileName.indexOf(QLatin1String(
"plugin")) -3);
608 if ((fileName.length() > 0) && !ret.contains(fileName))
616 QStringList SignonDaemon::queryMechanisms(
const QString &method)
618 TRACE() <<
"\n\n\n Querying mechanisms\n\n";
620 QStringList mechs = SignonSessionCore::loadedPluginMethods(method);
625 PluginProxy *plugin = PluginProxy::createNewPluginProxy(method);
628 TRACE() <<
"Could not load plugin of type: " << method;
629 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
630 SIGNOND_METHOD_NOT_KNOWN_ERR_STR +
631 QString::fromLatin1(
"Method %1 is not known or could "
632 "not load specific configuration.").
634 return QStringList();
643 QList<QVariantMap> SignonDaemon::queryIdentities(
const QVariantMap &filter)
647 TRACE() <<
"Querying identities";
651 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
652 return QList<QVariantMap>();
655 QMap<QString, QString> filterLocal;
656 QMapIterator<QString, QVariant> it(filter);
657 while (it.hasNext()) {
659 filterLocal.insert(it.key(), it.value().toString());
662 QList<SignonIdentityInfo> credentials = db->
credentials(filterLocal);
667 QLatin1String(
"Querying database error occurred."));
668 return QList<QVariantMap>();
671 QList<QVariantMap> mapList;
673 mapList.append(info.
toMap());
678 bool SignonDaemon::clear()
682 TRACE() <<
"\n\n\n Clearing DB\n\n";
685 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
690 sendErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME,
691 SIGNOND_INTERNAL_SERVER_ERR_STR +
692 QLatin1String(
"Database error occurred."));
698 QString SignonDaemon::getAuthSessionObjectPath(
const quint32
id,
701 bool supportsAuthMethod =
false;
702 pid_t ownerPid = AccessControlManagerHelper::pidOfPeer(*
this);
704 SignonAuthSession::getAuthSessionObjectPath(
id, type,
this,
707 if (objectPath.isEmpty() && !supportsAuthMethod) {
708 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
709 SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
715 void SignonDaemon::eraseBackupDir()
const
720 QDir target(backupRoot);
721 if (!target.exists())
return;
723 QStringList targetEntries = target.entryList(QDir::Files);
724 foreach (QString entry, targetEntries) {
725 target.remove(entry);
728 target.rmdir(backupRoot);
731 bool SignonDaemon::copyToBackupDir(
const QStringList &fileNames)
const
733 const CAMConfiguration config = m_configuration->camConfiguration();
736 QDir target(backupRoot);
737 if (!target.exists() && !target.mkpath(backupRoot)) {
738 qCritical() <<
"Cannot create target directory";
746 foreach (QString fileName, fileNames) {
748 if (target.exists(fileName))
749 target.remove(fileName);
752 QString source = config.m_storagePath + QDir::separator() + fileName;
753 if (!QFile::exists(source))
continue;
755 QString destination = backupRoot + QDir::separator() + fileName;
756 ok = QFile::copy(source, destination);
758 BLAME() <<
"Copying" << source <<
"to" << destination <<
"failed";
768 bool SignonDaemon::copyFromBackupDir(
const QStringList &fileNames)
const
770 const CAMConfiguration config = m_configuration->camConfiguration();
773 QDir sourceDir(backupRoot);
774 if (!sourceDir.exists()) {
775 TRACE() <<
"Backup directory does not exist!";
778 if (!sourceDir.exists(config.m_dbName)) {
779 TRACE() <<
"Backup does not contain DB:" << config.m_dbName;
784 QDir target(config.m_storagePath);
785 QStringList movedFiles, copiedFiles;
786 foreach (QString fileName, fileNames) {
788 if (target.exists(fileName)) {
789 if (target.rename(fileName, fileName + QLatin1String(
".bak")))
790 movedFiles += fileName;
794 QString source = backupRoot + QDir::separator() + fileName;
795 if (!QFile::exists(source)) {
796 TRACE() <<
"Ignoring file not present in backup:" << source;
800 QString destination =
801 config.m_storagePath + QDir::separator() + fileName;
803 ok = QFile::copy(source, destination);
805 copiedFiles << fileName;
807 qWarning() <<
"Copy failed for:" << source;
813 qWarning() <<
"Restore failed, recovering previous DB";
815 foreach (QString fileName, copiedFiles) {
816 target.remove(fileName);
819 foreach (QString fileName, movedFiles) {
820 if (!target.rename(fileName + QLatin1String(
".bak"), fileName)) {
821 qCritical() <<
"Could not recover:" << fileName;
826 foreach (QString fileName, movedFiles) {
827 target.remove(fileName + QLatin1String(
".bak"));
834 bool SignonDaemon::createStorageFileTree(
const QStringList &backupFiles)
const
836 QString storageDirPath = m_configuration->camConfiguration().m_storagePath;
837 QDir storageDir(storageDirPath);
839 if (!storageDir.exists()) {
840 if (!storageDir.mkpath(storageDirPath)) {
841 qCritical() <<
"Could not create storage dir for backup.";
846 foreach (QString fileName, backupFiles) {
847 if (storageDir.exists(fileName))
continue;
849 QString filePath = storageDir.path() + QDir::separator() + fileName;
850 QFile file(filePath);
851 if (!file.open(QIODevice::WriteOnly)) {
852 qCritical() <<
"Failed to create empty file for backup:" << filePath;
862 uchar SignonDaemon::backupStarts()
865 if (!m_backup && m_pCAMManager->credentialsSystemOpened())
867 m_pCAMManager->closeCredentialsSystem();
868 if (m_pCAMManager->credentialsSystemOpened())
870 qCritical() <<
"Cannot close credentials database";
878 QStringList backupFiles;
880 backupFiles << m_pCAMManager->backupFiles();
885 if (!createStorageFileTree(backupFiles)) {
886 qCritical() <<
"Cannot create backup file tree.";
892 if (!copyToBackupDir(backupFiles)) {
893 qCritical() <<
"Cannot copy database";
895 m_pCAMManager->openCredentialsSystem();
902 if (!m_pCAMManager->openCredentialsSystem()) {
903 qCritical() <<
"Cannot reopen database";
909 uchar SignonDaemon::backupFinished()
918 TRACE() <<
"close daemon";
928 uchar SignonDaemon::restoreStarts()
934 uchar SignonDaemon::restoreFinished()
936 TRACE() <<
"restore";
938 if (m_pCAMManager->credentialsSystemOpened())
941 if (!m_pCAMManager->closeCredentialsSystem())
943 qCritical() <<
"database cannot be closed";
950 QStringList backupFiles;
952 backupFiles << m_pCAMManager->backupFiles();
955 if (!copyFromBackupDir(backupFiles)) {
956 qCritical() <<
"Cannot copy database";
957 m_pCAMManager->openCredentialsSystem();
967 if (!m_pCAMManager->openCredentialsSystem())
974 void SignonDaemon::onDisconnected()
976 TRACE() <<
"Disconnected from session bus: exiting";
978 QMetaObject::invokeMethod(QCoreApplication::instance(),
980 Qt::QueuedConnection);