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>();
277 m_storedIdentities.clear();
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)),
315 int ret = ::write(sigFd[0], &signal,
sizeof(signal));
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.";
385 qWarning(
"SignonDaemon could not create the configuration object.");
387 m_configuration->
load();
389 QCoreApplication *app = QCoreApplication::instance();
391 qFatal(
"SignonDaemon requires a QCoreApplication instance to be " 392 "constructed first");
394 setupSignalHandlers();
395 m_backup = app->arguments().contains(QLatin1String(
"-backup"));
400 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
402 if (!sessionConnection.isConnected()) {
403 QDBusError err = sessionConnection.lastError();
404 TRACE() <<
"Session connection cannot be established:" <<
405 err.errorString(err.type());
406 TRACE() << err.message();
408 qFatal(
"SignonDaemon requires session bus to start working");
411 QDBusConnection::RegisterOptions registerSessionOptions =
412 QDBusConnection::ExportAdaptors;
416 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
417 + QLatin1String(
"/Backup"),
418 this, registerSessionOptions)) {
419 TRACE() <<
"Object cannot be registered";
421 qFatal(
"SignonDaemon requires to register backup object");
424 if (!sessionConnection.registerService(SIGNOND_SERVICE +
425 QLatin1String(
".Backup"))) {
426 QDBusError err = sessionConnection.lastError();
427 TRACE() <<
"Service cannot be registered: " <<
428 err.errorString(err.type());
430 qFatal(
"SignonDaemon requires to register backup service");
434 TRACE() <<
"Signond initialized in backup mode.";
440 QDBusConnection connection = SIGNOND_BUS;
442 if (!connection.isConnected()) {
443 QDBusError err = connection.lastError();
444 TRACE() <<
"Connection cannot be established:" <<
445 err.errorString(err.type());
446 TRACE() << err.message();
448 qFatal(
"SignonDaemon requires DBus to start working");
451 QDBusConnection::RegisterOptions registerOptions =
452 QDBusConnection::ExportAllContents;
455 registerOptions = QDBusConnection::ExportAdaptors;
459 m_dbusServer =
new QDBusServer(m_configuration->
busAddress(),
this);
460 QObject::connect(m_dbusServer,
461 SIGNAL(newConnection(
const QDBusConnection &)),
462 this, SLOT(onNewConnection(
const QDBusConnection &)));
466 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
467 this, registerOptions)) {
468 TRACE() <<
"Object cannot be registered";
470 qFatal(
"SignonDaemon requires to register daemon's object");
473 if (!connection.registerService(SIGNOND_SERVICE)) {
474 QDBusError err = connection.lastError();
475 TRACE() <<
"Service cannot be registered: " <<
476 err.errorString(err.type());
478 qFatal(
"SignonDaemon requires to register daemon's service");
482 connection.connect(QString(),
483 QLatin1String(
"/org/freedesktop/DBus/Local"),
484 QLatin1String(
"org.freedesktop.DBus.Local"),
485 QLatin1String(
"Disconnected"),
486 this, SLOT(onDisconnected()));
491 BLAME() <<
"Signond: Cannot initialize credentials storage.";
495 this, SLOT(deleteLater()));
498 TRACE() <<
"Signond SUCCESSFULLY initialized.";
501 void SignonDaemon::onNewConnection(
const QDBusConnection &connection)
503 TRACE() <<
"New p2p connection" << connection.name();
504 QDBusConnection conn(connection);
505 if (!conn.registerObject(SIGNOND_DAEMON_OBJECTPATH,
506 this, QDBusConnection::ExportAdaptors)) {
507 qFatal(
"Failed to register SignonDaemon object");
511 void SignonDaemon::initExtensions()
517 QStringList filters(QLatin1String(
"lib*.so"));
518 QStringList extensionList = dir.entryList(filters, QDir::Files);
519 foreach(
const QString &filename, extensionList)
520 initExtension(dir.filePath(filename));
523 void SignonDaemon::initExtension(
const QString &filePath)
525 TRACE() <<
"Loading plugin " << filePath;
527 QPluginLoader pluginLoader(filePath);
528 QObject *plugin = pluginLoader.instance();
530 qWarning() <<
"Couldn't load plugin:" << pluginLoader.errorString();
537 pluginLoader.unload();
540 bool SignonDaemon::initStorage()
545 if (!m_pCAMManager->
init()) {
546 BLAME() <<
"CAM initialization failed";
552 qCritical(
"Signond: Cannot open CAM credentials system...");
556 TRACE() <<
"Secure storage already initialized...";
565 m_storedIdentities.insert(identity->
id(), identity);
568 void SignonDaemon::onIdentityDestroyed()
571 m_storedIdentities.remove(identity->
id());
578 QObject::connect(identity, SIGNAL(unregistered()),
579 this, SLOT(onIdentityDestroyed()));
581 if (identity->
id() != SIGNOND_NEW_IDENTITY) {
582 m_storedIdentities.insert(identity->
id(), identity);
590 TRACE() <<
"Registering new identity:";
595 Q_ASSERT(identity != NULL);
596 watchIdentity(identity);
603 return (m_configuration == NULL ?
610 return (m_configuration == NULL ?
616 QVariantMap &identityData)
622 TRACE() <<
"Registering identity:" << id;
628 if (identity == NULL)
630 Q_ASSERT(identity != NULL);
637 setLastError(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
638 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
643 watchIdentity(identity);
646 identityData = info.
toMap();
648 TRACE() <<
"DONE REGISTERING IDENTITY";
654 QDir pluginsDir(m_configuration->
pluginsDir());
656 QStringList fileNames = pluginsDir.entryList(
657 QStringList() << QLatin1String(
"*.so*"),
658 QDir::Files | QDir::NoDotAndDotDot);
662 foreach (fileName, fileNames) {
663 if (fileName.startsWith(QLatin1String(
"lib"))) {
665 fileName.mid(3, fileName.indexOf(QLatin1String(
"plugin")) -3);
666 if ((fileName.length() > 0) && !ret.contains(fileName))
682 if (!mechs.isEmpty())
688 TRACE() <<
"Could not load plugin of type: " << method;
689 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
690 SIGNOND_METHOD_NOT_KNOWN_ERR_STR +
691 QString::fromLatin1(
"Method %1 is not known or could " 692 "not load specific configuration.").
694 return QStringList();
709 TRACE() <<
"Querying identities";
713 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
718 QMapIterator<QString, QVariant> it(filter);
719 while (it.hasNext()) {
721 filterLocal.insert(it.key(), it.value().toString());
727 setLastError(internalServerErrName,
728 internalServerErrStr +
729 QLatin1String(
"Querying database error occurred."));
735 mapList.append(info.
toMap());
746 TRACE() <<
"\n\n\n Clearing DB\n\n";
749 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
754 setLastError(SIGNOND_INTERNAL_SERVER_ERR_NAME,
755 SIGNOND_INTERNAL_SERVER_ERR_STR +
756 QLatin1String(
"Database error occurred."));
770 if (authSession == NULL) {
771 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
772 SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
779 void SignonDaemon::eraseBackupDir()
const 784 QDir target(backupRoot);
785 if (!target.exists())
return;
787 QStringList targetEntries = target.entryList(QDir::Files);
788 foreach (QString entry, targetEntries) {
789 target.remove(entry);
792 target.rmdir(backupRoot);
795 bool SignonDaemon::copyToBackupDir(
const QStringList &fileNames)
const 800 QDir target(backupRoot);
801 if (!target.exists() && !target.mkpath(backupRoot)) {
802 qCritical() <<
"Cannot create target directory";
810 foreach (
const QString &fileName, fileNames) {
812 if (target.exists(fileName))
813 target.remove(fileName);
816 QString source = config.
m_storagePath + QDir::separator() + fileName;
817 if (!QFile::exists(source))
continue;
819 QString destination = backupRoot + QDir::separator() + fileName;
820 ok = QFile::copy(source, destination);
822 BLAME() <<
"Copying" << source <<
"to" << destination <<
"failed";
832 bool SignonDaemon::copyFromBackupDir(
const QStringList &fileNames)
const 837 QDir sourceDir(backupRoot);
838 if (!sourceDir.exists()) {
839 TRACE() <<
"Backup directory does not exist!";
842 if (!sourceDir.exists(config.
m_dbName)) {
849 QStringList movedFiles, copiedFiles;
850 foreach (
const QString &fileName, fileNames) {
852 if (target.exists(fileName)) {
853 if (target.rename(fileName, fileName + QLatin1String(
".bak")))
854 movedFiles += fileName;
858 QString source = backupRoot + QDir::separator() + fileName;
859 if (!QFile::exists(source)) {
860 TRACE() <<
"Ignoring file not present in backup:" << source;
864 QString destination =
867 ok = QFile::copy(source, destination);
869 copiedFiles << fileName;
871 qWarning() <<
"Copy failed for:" << source;
877 qWarning() <<
"Restore failed, recovering previous DB";
879 foreach (
const QString &fileName, copiedFiles) {
880 target.remove(fileName);
883 foreach (
const QString &fileName, movedFiles) {
884 if (!target.rename(fileName + QLatin1String(
".bak"), fileName)) {
885 qCritical() <<
"Could not recover:" << fileName;
890 foreach (
const QString &fileName, movedFiles) {
891 target.remove(fileName + QLatin1String(
".bak"));
898 bool SignonDaemon::createStorageFileTree(
const QStringList &backupFiles)
const 901 QDir storageDir(storageDirPath);
903 if (!storageDir.exists()) {
904 if (!storageDir.mkpath(storageDirPath)) {
905 qCritical() <<
"Could not create storage dir for backup.";
910 foreach (
const QString &fileName, backupFiles) {
911 if (storageDir.exists(fileName))
continue;
913 QString filePath = storageDir.path() + QDir::separator() + fileName;
914 QFile file(filePath);
915 if (!file.open(QIODevice::WriteOnly)) {
916 qCritical() <<
"Failed to create empty file for backup:" << filePath;
934 qCritical() <<
"Cannot close credentials database";
942 QStringList backupFiles;
949 if (!createStorageFileTree(backupFiles)) {
950 qCritical() <<
"Cannot create backup file tree.";
956 if (!copyToBackupDir(backupFiles)) {
957 qCritical() <<
"Cannot copy database";
967 qCritical() <<
"Cannot reopen database";
982 TRACE() <<
"close daemon";
1000 TRACE() <<
"restore";
1007 qCritical() <<
"database cannot be closed";
1014 QStringList backupFiles;
1019 if (!copyFromBackupDir(backupFiles)) {
1020 qCritical() <<
"Cannot copy database";
1038 void SignonDaemon::onDisconnected()
1040 TRACE() <<
"Disconnected from session bus: exiting";
1041 this->deleteLater();
1042 QMetaObject::invokeMethod(QCoreApplication::instance(),
1044 Qt::QueuedConnection);
1047 void SignonDaemon::setLastError(
const QString &name,
const QString &msg)
1049 m_lastErrorName = name;
1050 m_lastErrorMessage = msg;
1053 void SignonDaemon::clearLastError()
1055 m_lastErrorName = QString();
1056 m_lastErrorMessage = QString();
QList< QVariantMap > queryIdentities(const QVariantMap &filter)
static PluginProxy * createNewPluginProxy(const QString &type)
Q_INVOKABLE void handleUnixSignal()
friend class SignonDaemonAdaptor
static SignonDaemon * instance()
const QString internalServerErrName
void addSetting(const QString &key, const QVariant &value)
Daemon side representation of authentication session.
bool closeCredentialsSystem()
Closes the credentials system.
QString m_dbName
The database file name.
bool initExtension(QObject *object)
Initializes know objects from an extension plugin.
static void invokeOnIdle(int maxInactivity, QObject *object, const char *member)
Invoke the specified method on when there are no disposable objects for more than seconds...
static void stopAllAuthSessions()
uint identityTimeout() const
bool credentialsSystemOpened() const
For convenience method.
const CAMConfiguration & camConfiguration() const
void destroy()
Performs any predestruction operations and the destruction itself.
QString extensionsDir() const
QObject * registerNewIdentity()
uint daemonTimeout() const
#define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_)
QObject * getIdentity(const quint32 id, QVariantMap &identityData)
uint authSessionTimeout() const
static SignonIdentity * createIdentity(quint32 id, SignonDaemon *parent)
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()
QObject * getAuthSession(const quint32 id, const QString type, pid_t ownerPid)
bool setUserOwnership(const QString &filePath)
int authSessionTimeout() const
bool init()
Initializes the CAM instance.
const QString internalServerErrStr
bool errorOccurred() const
void finalize()
Finalizes the CAM instance, this could include, closing the credentials system and resetting the conf...
Daemon side representation of identity.
static QStringList loadedPluginMethods(const QString &method)
Daemon side representation of identity information.
CredentialsAccessError lastError() const
CredentialsDB * credentialsDB() const
Manages the credentials I/O.
QString busAddress() const
static void signalHandler(int signal)
Configuration object for the CredentialsAccessManager - CAM.
Helper class for access control-related functionality.
bool openCredentialsSystem()
Opens the credentials system, creates the CreadentialsDB object; if encryption is configured this wil...
QStringList backupFiles() const
The daemon's configuration object; loads date from the daemon configuration file. ...
static SignonAuthSession * createAuthSession(const quint32 id, const QString &method, SignonDaemon *parent, pid_t ownerPid)
QStringList queryMethods()
QStringList queryMechanisms(const QString &method)
SignonIdentityInfo queryInfo(bool &ok, bool queryPassword=true)
QString pluginsDir() const
const QVariantMap toMap() const
void keepInUse() const
Mark the object as used.
int identityTimeout() const
Returns the number of seconds of inactivity after which identity objects might be automatically delet...
#define SIGNOND_PLUGINS_DIR