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 if (environment.contains(QLatin1String(
"SSO_STORAGE_PATH"))) {
183 environment.value(QLatin1String(
"SSO_STORAGE_PATH")));
186 if (environment.contains(QLatin1String(
"SSO_PLUGINS_DIR"))) {
187 m_pluginsDir = environment.value(QLatin1String(
"SSO_PLUGINS_DIR"));
190 if (environment.contains(QLatin1String(
"SSO_EXTENSIONS_DIR"))) {
192 environment.value(QLatin1String(
"SSO_EXTENSIONS_DIR"));
205 SignonDaemon::SignonDaemon(QObject *parent) : QObject(parent)
206 , m_configuration(NULL)
209 umask(S_IROTH | S_IWOTH);
212 qDBusRegisterMetaType<MethodMap>();
213 qDBusRegisterMetaType<MapList>();
216 SignonDaemon::~SignonDaemon()
225 SignonAuthSession::stopAllAuthSessions();
226 m_storedIdentities.clear();
227 m_unstoredIdentities.clear();
230 m_pCAMManager->closeCredentialsSystem();
231 delete m_pCAMManager;
234 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
236 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH
237 + QLatin1String(
"/Backup"));
238 sessionConnection.unregisterService(SIGNOND_SERVICE
239 + QLatin1String(
".Backup"));
240 if (m_backup ==
false)
242 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH);
243 sessionConnection.unregisterService(SIGNOND_SERVICE);
246 delete m_configuration;
248 QMetaObject::invokeMethod(QCoreApplication::instance(),
250 Qt::QueuedConnection);
253 void SignonDaemon::setupSignalHandlers()
255 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0)
256 BLAME() <<
"Couldn't create HUP socketpair";
258 m_sigSn =
new QSocketNotifier(sigFd[1], QSocketNotifier::Read,
this);
259 connect(m_sigSn, SIGNAL(activated(
int)),
260 this, SLOT(handleUnixSignal()));
263 void SignonDaemon::signalHandler(
int signal)
265 int ret = ::write(sigFd[0], &signal,
sizeof(signal));
269 void SignonDaemon::handleUnixSignal()
271 m_sigSn->setEnabled(
false);
274 int ret = read(sigFd[1], &signal,
sizeof(signal));
277 TRACE() <<
"signal received: " << signal;
281 TRACE() <<
"\n\n SIGHUP \n\n";
287 QMetaObject::invokeMethod(instance(),
289 Qt::QueuedConnection);
293 TRACE() <<
"\n\n SIGTERM \n\n";
296 QMetaObject::invokeMethod(QCoreApplication::instance(),
298 Qt::QueuedConnection);
302 TRACE() <<
"\n\n SIGINT \n\n";
305 QMetaObject::invokeMethod(QCoreApplication::instance(),
307 Qt::QueuedConnection);
313 m_sigSn->setEnabled(
true);
318 if (m_instance != NULL)
321 QCoreApplication *app = QCoreApplication::instance();
324 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
325 "constructed first");
327 TRACE() <<
"Creating new daemon instance.";
332 void SignonDaemon::init()
335 qWarning(
"SignonDaemon could not create the configuration object.");
337 m_configuration->load();
342 BLAME() <<
"Failed to SUID root. Secure storage will not be available.";
345 QCoreApplication *app = QCoreApplication::instance();
347 qFatal(
"SignonDaemon requires a QCoreApplication instance to be "
348 "constructed first");
350 setupSignalHandlers();
351 m_backup = app->arguments().contains(QLatin1String(
"-backup"));
356 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
358 if (!sessionConnection.isConnected()) {
359 QDBusError err = sessionConnection.lastError();
360 TRACE() <<
"Session connection cannot be established:" <<
361 err.errorString(err.type());
362 TRACE() << err.message();
364 qFatal(
"SignonDaemon requires session bus to start working");
367 QDBusConnection::RegisterOptions registerSessionOptions =
368 QDBusConnection::ExportAdaptors;
372 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
373 + QLatin1String(
"/Backup"),
374 this, registerSessionOptions)) {
375 TRACE() <<
"Object cannot be registered";
377 qFatal(
"SignonDaemon requires to register backup object");
380 if (!sessionConnection.registerService(SIGNOND_SERVICE +
381 QLatin1String(
".Backup"))) {
382 QDBusError err = sessionConnection.lastError();
383 TRACE() <<
"Service cannot be registered: " <<
384 err.errorString(err.type());
386 qFatal(
"SignonDaemon requires to register backup service");
390 TRACE() <<
"Signond initialized in backup mode.";
396 QDBusConnection connection = SIGNOND_BUS;
398 if (!connection.isConnected()) {
399 QDBusError err = connection.lastError();
400 TRACE() <<
"Connection cannot be established:" <<
401 err.errorString(err.type());
402 TRACE() << err.message();
404 qFatal(
"SignonDaemon requires DBus to start working");
407 QDBusConnection::RegisterOptions registerOptions =
408 QDBusConnection::ExportAllContents;
411 registerOptions = QDBusConnection::ExportAdaptors;
413 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
414 this, registerOptions)) {
415 TRACE() <<
"Object cannot be registered";
417 qFatal(
"SignonDaemon requires to register daemon's object");
420 if (!connection.registerService(SIGNOND_SERVICE)) {
421 QDBusError err = connection.lastError();
422 TRACE() <<
"Service cannot be registered: " <<
423 err.errorString(err.type());
425 qFatal(
"SignonDaemon requires to register daemon's service");
429 connection.connect(QString(),
430 QLatin1String(
"/org/freedesktop/DBus/Local"),
431 QLatin1String(
"org.freedesktop.DBus.Local"),
432 QLatin1String(
"Disconnected"),
433 this, SLOT(onDisconnected()));
438 BLAME() <<
"Signond: Cannot initialize credentials storage.";
440 Q_UNUSED(AuthCoreCache::instance(
this));
442 if (m_configuration->daemonTimeout() > 0) {
443 SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(),
444 this, SLOT(deleteLater()));
447 TRACE() <<
"Signond SUCCESSFULLY initialized.";
450 void SignonDaemon::initExtensions()
455 QDir dir(m_configuration->extensionsDir());
456 QStringList filters(QLatin1String(
"lib*.so"));
457 QStringList extensionList = dir.entryList(filters, QDir::Files);
458 foreach(QString filename, extensionList)
459 initExtension(dir.filePath(filename));
462 void SignonDaemon::initExtension(
const QString &filePath)
464 TRACE() <<
"Loading plugin " << filePath;
466 QPluginLoader pluginLoader(filePath);
467 QObject *plugin = pluginLoader.instance();
469 qWarning() <<
"Couldn't load plugin:" << pluginLoader.errorString();
475 bool extensionInUse =
false;
476 if (m_pCAMManager->initExtension(plugin))
477 extensionInUse =
true;
479 if (!extensionInUse) {
480 pluginLoader.unload();
484 bool SignonDaemon::initStorage()
486 if (!m_pCAMManager->credentialsSystemOpened()) {
487 m_pCAMManager->finalize();
489 if (!m_pCAMManager->init()) {
490 BLAME() <<
"CAM initialization failed";
495 if (!m_pCAMManager->openCredentialsSystem()) {
496 qCritical(
"Signond: Cannot open CAM credentials system...");
500 TRACE() <<
"Secure storage already initialized...";
507 void SignonDaemon::identityStored(SignonIdentity *identity)
509 if (m_unstoredIdentities.contains(identity->objectName())) {
510 m_unstoredIdentities.remove(identity->objectName());
511 m_storedIdentities.insert(identity->id(), identity);
515 void SignonDaemon::registerNewIdentity(QDBusObjectPath &objectPath)
517 TRACE() <<
"Registering new identity:";
520 SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY,
this);
522 if (identity == NULL) {
525 QLatin1String(
"Could not create remote Identity "
530 m_unstoredIdentities.insert(identity->objectName(), identity);
532 objectPath = QDBusObjectPath(identity->objectName());
535 int SignonDaemon::identityTimeout()
const
537 return (m_configuration == NULL ?
539 m_configuration->identityTimeout());
542 int SignonDaemon::authSessionTimeout()
const
544 return (m_configuration == NULL ?
546 m_configuration->authSessionTimeout());
549 void SignonDaemon::getIdentity(
const quint32
id,
550 QDBusObjectPath &objectPath,
551 QVariantMap &identityData)
555 TRACE() <<
"Registering identity:" << id;
561 if (identity == NULL)
562 identity = SignonIdentity::createIdentity(
id,
this);
564 if (identity == NULL)
568 QLatin1String(
"Could not create remote Identity "
578 sendErrorReply(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
579 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
584 m_storedIdentities.insert(identity->
id(), identity);
587 identityData = info.
toMap();
589 TRACE() <<
"DONE REGISTERING IDENTITY";
590 objectPath = QDBusObjectPath(identity->objectName());
593 QStringList SignonDaemon::queryMethods()
595 QDir pluginsDir(m_configuration->pluginsDir());
597 QStringList fileNames = pluginsDir.entryList(
598 QStringList() << QLatin1String(
"*.so*"),
599 QDir::Files | QDir::NoDotAndDotDot);
603 foreach (fileName, fileNames) {
604 if (fileName.startsWith(QLatin1String(
"lib"))) {
606 fileName.mid(3, fileName.indexOf(QLatin1String(
"plugin")) -3);
607 if ((fileName.length() > 0) && !ret.contains(fileName))
615 QStringList SignonDaemon::queryMechanisms(
const QString &method)
617 TRACE() <<
"\n\n\n Querying mechanisms\n\n";
619 QStringList mechs = SignonSessionCore::loadedPluginMethods(method);
624 PluginProxy *plugin = PluginProxy::createNewPluginProxy(method);
627 TRACE() <<
"Could not load plugin of type: " << method;
628 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
629 SIGNOND_METHOD_NOT_KNOWN_ERR_STR +
630 QString::fromLatin1(
"Method %1 is not known or could "
631 "not load specific configuration.").
633 return QStringList();
642 QList<QVariantMap> SignonDaemon::queryIdentities(
const QVariantMap &filter)
646 TRACE() <<
"Querying identities";
650 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
651 return QList<QVariantMap>();
654 QMap<QString, QString> filterLocal;
655 QMapIterator<QString, QVariant> it(filter);
656 while (it.hasNext()) {
658 filterLocal.insert(it.key(), it.value().toString());
661 QList<SignonIdentityInfo> credentials = db->
credentials(filterLocal);
666 QLatin1String(
"Querying database error occurred."));
667 return QList<QVariantMap>();
670 QList<QVariantMap> mapList;
672 mapList.append(info.
toMap());
677 bool SignonDaemon::clear()
681 TRACE() <<
"\n\n\n Clearing DB\n\n";
684 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
689 sendErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME,
690 SIGNOND_INTERNAL_SERVER_ERR_STR +
691 QLatin1String(
"Database error occurred."));
697 QString SignonDaemon::getAuthSessionObjectPath(
const quint32
id,
700 bool supportsAuthMethod =
false;
701 pid_t ownerPid = AccessControlManagerHelper::pidOfPeer(*
this);
703 SignonAuthSession::getAuthSessionObjectPath(
id, type,
this,
706 if (objectPath.isEmpty() && !supportsAuthMethod) {
707 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
708 SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
714 void SignonDaemon::eraseBackupDir()
const
719 QDir target(backupRoot);
720 if (!target.exists())
return;
722 QStringList targetEntries = target.entryList(QDir::Files);
723 foreach (QString entry, targetEntries) {
724 target.remove(entry);
727 target.rmdir(backupRoot);
730 bool SignonDaemon::copyToBackupDir(
const QStringList &fileNames)
const
732 const CAMConfiguration config = m_configuration->camConfiguration();
735 QDir target(backupRoot);
736 if (!target.exists() && !target.mkpath(backupRoot)) {
737 qCritical() <<
"Cannot create target directory";
745 foreach (QString fileName, fileNames) {
747 if (target.exists(fileName))
748 target.remove(fileName);
751 QString source = config.m_storagePath + QDir::separator() + fileName;
752 if (!QFile::exists(source))
continue;
754 QString destination = backupRoot + QDir::separator() + fileName;
755 ok = QFile::copy(source, destination);
757 BLAME() <<
"Copying" << source <<
"to" << destination <<
"failed";
767 bool SignonDaemon::copyFromBackupDir(
const QStringList &fileNames)
const
769 const CAMConfiguration config = m_configuration->camConfiguration();
772 QDir sourceDir(backupRoot);
773 if (!sourceDir.exists()) {
774 TRACE() <<
"Backup directory does not exist!";
777 if (!sourceDir.exists(config.m_dbName)) {
778 TRACE() <<
"Backup does not contain DB:" << config.m_dbName;
783 QDir target(config.m_storagePath);
784 QStringList movedFiles, copiedFiles;
785 foreach (QString fileName, fileNames) {
787 if (target.exists(fileName)) {
788 if (target.rename(fileName, fileName + QLatin1String(
".bak")))
789 movedFiles += fileName;
793 QString source = backupRoot + QDir::separator() + fileName;
794 if (!QFile::exists(source)) {
795 TRACE() <<
"Ignoring file not present in backup:" << source;
799 QString destination =
800 config.m_storagePath + QDir::separator() + fileName;
802 ok = QFile::copy(source, destination);
804 copiedFiles << fileName;
806 qWarning() <<
"Copy failed for:" << source;
812 qWarning() <<
"Restore failed, recovering previous DB";
814 foreach (QString fileName, copiedFiles) {
815 target.remove(fileName);
818 foreach (QString fileName, movedFiles) {
819 if (!target.rename(fileName + QLatin1String(
".bak"), fileName)) {
820 qCritical() <<
"Could not recover:" << fileName;
825 foreach (QString fileName, movedFiles) {
826 target.remove(fileName + QLatin1String(
".bak"));
833 bool SignonDaemon::createStorageFileTree(
const QStringList &backupFiles)
const
835 QString storageDirPath = m_configuration->camConfiguration().m_storagePath;
836 QDir storageDir(storageDirPath);
838 if (!storageDir.exists()) {
839 if (!storageDir.mkpath(storageDirPath)) {
840 qCritical() <<
"Could not create storage dir for backup.";
845 foreach (QString fileName, backupFiles) {
846 if (storageDir.exists(fileName))
continue;
848 QString filePath = storageDir.path() + QDir::separator() + fileName;
849 QFile file(filePath);
850 if (!file.open(QIODevice::WriteOnly)) {
851 qCritical() <<
"Failed to create empty file for backup:" << filePath;
861 uchar SignonDaemon::backupStarts()
864 if (!m_backup && m_pCAMManager->credentialsSystemOpened())
866 m_pCAMManager->closeCredentialsSystem();
867 if (m_pCAMManager->credentialsSystemOpened())
869 qCritical() <<
"Cannot close credentials database";
877 QStringList backupFiles;
879 backupFiles << m_pCAMManager->backupFiles();
884 if (!createStorageFileTree(backupFiles)) {
885 qCritical() <<
"Cannot create backup file tree.";
891 if (!copyToBackupDir(backupFiles)) {
892 qCritical() <<
"Cannot copy database";
894 m_pCAMManager->openCredentialsSystem();
901 if (!m_pCAMManager->openCredentialsSystem()) {
902 qCritical() <<
"Cannot reopen database";
908 uchar SignonDaemon::backupFinished()
917 TRACE() <<
"close daemon";
927 uchar SignonDaemon::restoreStarts()
933 uchar SignonDaemon::restoreFinished()
935 TRACE() <<
"restore";
937 if (m_pCAMManager->credentialsSystemOpened())
940 if (!m_pCAMManager->closeCredentialsSystem())
942 qCritical() <<
"database cannot be closed";
949 QStringList backupFiles;
951 backupFiles << m_pCAMManager->backupFiles();
954 if (!copyFromBackupDir(backupFiles)) {
955 qCritical() <<
"Cannot copy database";
956 m_pCAMManager->openCredentialsSystem();
966 if (!m_pCAMManager->openCredentialsSystem())
973 void SignonDaemon::onDisconnected()
975 TRACE() <<
"Disconnected from session bus: exiting";
977 QMetaObject::invokeMethod(QCoreApplication::instance(),
979 Qt::QueuedConnection);