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>();
275 m_storedIdentities.clear();
279 delete m_pCAMManager;
282 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
284 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH
285 + QLatin1String(
"/Backup"));
286 sessionConnection.unregisterService(SIGNOND_SERVICE
287 + QLatin1String(
".Backup"));
288 if (m_backup ==
false)
290 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH);
291 sessionConnection.unregisterService(SIGNOND_SERVICE);
294 delete m_configuration;
296 QMetaObject::invokeMethod(QCoreApplication::instance(),
298 Qt::QueuedConnection);
301 void SignonDaemon::setupSignalHandlers()
303 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0)
304 BLAME() <<
"Couldn't create HUP socketpair";
306 m_sigSn =
new QSocketNotifier(sigFd[1], QSocketNotifier::Read,
this);
307 connect(m_sigSn, SIGNAL(activated(
int)),
313 int ret = ::write(sigFd[0], &signal,
sizeof(signal));
319 m_sigSn->setEnabled(
false);
322 int ret = read(sigFd[1], &signal,
sizeof(signal));
325 TRACE() <<
"signal received: " << signal;
329 TRACE() <<
"\n\n SIGHUP \n\n";
335 QMetaObject::invokeMethod(
instance(),
337 Qt::QueuedConnection);
341 TRACE() <<
"\n\n SIGTERM \n\n";
344 QMetaObject::invokeMethod(QCoreApplication::instance(),
346 Qt::QueuedConnection);
350 TRACE() <<
"\n\n SIGINT \n\n";
353 QMetaObject::invokeMethod(QCoreApplication::instance(),
355 Qt::QueuedConnection);
361 m_sigSn->setEnabled(
true);
366 if (m_instance != NULL)
369 QCoreApplication *app = QCoreApplication::instance();
372 qFatal(
"SignonDaemon requires a QCoreApplication instance to be " 373 "constructed first");
375 TRACE() <<
"Creating new daemon instance.";
383 qWarning(
"SignonDaemon could not create the configuration object.");
385 m_configuration->
load();
388 BLAME() <<
"Failed to SUID root. Secure storage will not be available.";
391 QCoreApplication *app = QCoreApplication::instance();
393 qFatal(
"SignonDaemon requires a QCoreApplication instance to be " 394 "constructed first");
396 setupSignalHandlers();
397 m_backup = app->arguments().contains(QLatin1String(
"-backup"));
402 QDBusConnection sessionConnection = QDBusConnection::sessionBus();
404 if (!sessionConnection.isConnected()) {
405 QDBusError err = sessionConnection.lastError();
406 TRACE() <<
"Session connection cannot be established:" <<
407 err.errorString(err.type());
408 TRACE() << err.message();
410 qFatal(
"SignonDaemon requires session bus to start working");
413 QDBusConnection::RegisterOptions registerSessionOptions =
414 QDBusConnection::ExportAdaptors;
418 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
419 + QLatin1String(
"/Backup"),
420 this, registerSessionOptions)) {
421 TRACE() <<
"Object cannot be registered";
423 qFatal(
"SignonDaemon requires to register backup object");
426 if (!sessionConnection.registerService(SIGNOND_SERVICE +
427 QLatin1String(
".Backup"))) {
428 QDBusError err = sessionConnection.lastError();
429 TRACE() <<
"Service cannot be registered: " <<
430 err.errorString(err.type());
432 qFatal(
"SignonDaemon requires to register backup service");
436 TRACE() <<
"Signond initialized in backup mode.";
442 QDBusConnection connection = SIGNOND_BUS;
444 if (!connection.isConnected()) {
445 QDBusError err = connection.lastError();
446 TRACE() <<
"Connection cannot be established:" <<
447 err.errorString(err.type());
448 TRACE() << err.message();
450 qFatal(
"SignonDaemon requires DBus to start working");
453 QDBusConnection::RegisterOptions registerOptions =
454 QDBusConnection::ExportAllContents;
457 registerOptions = QDBusConnection::ExportAdaptors;
461 m_dbusServer =
new QDBusServer(m_configuration->
busAddress(),
this);
462 QObject::connect(m_dbusServer,
463 SIGNAL(newConnection(
const QDBusConnection &)),
464 this, SLOT(onNewConnection(
const QDBusConnection &)));
468 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
469 this, registerOptions)) {
470 TRACE() <<
"Object cannot be registered";
472 qFatal(
"SignonDaemon requires to register daemon's object");
475 if (!connection.registerService(SIGNOND_SERVICE)) {
476 QDBusError err = connection.lastError();
477 TRACE() <<
"Service cannot be registered: " <<
478 err.errorString(err.type());
480 qFatal(
"SignonDaemon requires to register daemon's service");
484 connection.connect(QString(),
485 QLatin1String(
"/org/freedesktop/DBus/Local"),
486 QLatin1String(
"org.freedesktop.DBus.Local"),
487 QLatin1String(
"Disconnected"),
488 this, SLOT(onDisconnected()));
493 BLAME() <<
"Signond: Cannot initialize credentials storage.";
497 this, SLOT(deleteLater()));
500 TRACE() <<
"Signond SUCCESSFULLY initialized.";
503 void SignonDaemon::onNewConnection(
const QDBusConnection &connection)
505 TRACE() <<
"New p2p connection" << connection.name();
506 QDBusConnection conn(connection);
507 if (!conn.registerObject(SIGNOND_DAEMON_OBJECTPATH,
508 this, QDBusConnection::ExportAdaptors)) {
509 qFatal(
"Failed to register SignonDaemon object");
513 void SignonDaemon::initExtensions()
519 QStringList filters(QLatin1String(
"lib*.so"));
520 QStringList extensionList = dir.entryList(filters, QDir::Files);
521 foreach(
const QString &filename, extensionList)
522 initExtension(dir.filePath(filename));
525 void SignonDaemon::initExtension(
const QString &filePath)
527 TRACE() <<
"Loading plugin " << filePath;
529 QPluginLoader pluginLoader(filePath);
530 QObject *plugin = pluginLoader.instance();
532 qWarning() <<
"Couldn't load plugin:" << pluginLoader.errorString();
539 pluginLoader.unload();
542 bool SignonDaemon::initStorage()
547 if (!m_pCAMManager->
init()) {
548 BLAME() <<
"CAM initialization failed";
554 qCritical(
"Signond: Cannot open CAM credentials system...");
558 TRACE() <<
"Secure storage already initialized...";
567 m_storedIdentities.insert(identity->
id(), identity);
570 void SignonDaemon::onIdentityDestroyed()
573 m_storedIdentities.remove(identity->
id());
580 QObject::connect(identity, SIGNAL(unregistered()),
581 this, SLOT(onIdentityDestroyed()));
583 if (identity->
id() != SIGNOND_NEW_IDENTITY) {
584 m_storedIdentities.insert(identity->
id(), identity);
592 TRACE() <<
"Registering new identity:";
597 Q_ASSERT(identity != NULL);
598 watchIdentity(identity);
605 return (m_configuration == NULL ?
612 return (m_configuration == NULL ?
618 QVariantMap &identityData)
624 TRACE() <<
"Registering identity:" << id;
630 if (identity == NULL)
632 Q_ASSERT(identity != NULL);
639 setLastError(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
640 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
645 watchIdentity(identity);
648 identityData = info.
toMap();
650 TRACE() <<
"DONE REGISTERING IDENTITY";
656 QDir pluginsDir(m_configuration->
pluginsDir());
658 QStringList fileNames = pluginsDir.entryList(
659 QStringList() << QLatin1String(
"*.so*"),
660 QDir::Files | QDir::NoDotAndDotDot);
664 foreach (fileName, fileNames) {
665 if (fileName.startsWith(QLatin1String(
"lib"))) {
667 fileName.mid(3, fileName.indexOf(QLatin1String(
"plugin")) -3);
668 if ((fileName.length() > 0) && !ret.contains(fileName))
684 if (!mechs.isEmpty())
690 TRACE() <<
"Could not load plugin of type: " << method;
691 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
692 SIGNOND_METHOD_NOT_KNOWN_ERR_STR +
693 QString::fromLatin1(
"Method %1 is not known or could " 694 "not load specific configuration.").
696 return QStringList();
711 TRACE() <<
"Querying identities";
715 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
720 QMapIterator<QString, QVariant> it(filter);
721 while (it.hasNext()) {
723 filterLocal.insert(it.key(), it.value().toString());
729 setLastError(internalServerErrName,
730 internalServerErrStr +
731 QLatin1String(
"Querying database error occurred."));
737 mapList.append(info.
toMap());
748 TRACE() <<
"\n\n\n Clearing DB\n\n";
751 qCritical() << Q_FUNC_INFO << m_pCAMManager->
lastError();
756 setLastError(SIGNOND_INTERNAL_SERVER_ERR_NAME,
757 SIGNOND_INTERNAL_SERVER_ERR_STR +
758 QLatin1String(
"Database error occurred."));
772 if (authSession == NULL) {
773 setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
774 SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
781 void SignonDaemon::eraseBackupDir()
const 786 QDir target(backupRoot);
787 if (!target.exists())
return;
789 QStringList targetEntries = target.entryList(QDir::Files);
790 foreach (QString entry, targetEntries) {
791 target.remove(entry);
794 target.rmdir(backupRoot);
797 bool SignonDaemon::copyToBackupDir(
const QStringList &fileNames)
const 802 QDir target(backupRoot);
803 if (!target.exists() && !target.mkpath(backupRoot)) {
804 qCritical() <<
"Cannot create target directory";
812 foreach (
const QString &fileName, fileNames) {
814 if (target.exists(fileName))
815 target.remove(fileName);
818 QString source = config.
m_storagePath + QDir::separator() + fileName;
819 if (!QFile::exists(source))
continue;
821 QString destination = backupRoot + QDir::separator() + fileName;
822 ok = QFile::copy(source, destination);
824 BLAME() <<
"Copying" << source <<
"to" << destination <<
"failed";
834 bool SignonDaemon::copyFromBackupDir(
const QStringList &fileNames)
const 839 QDir sourceDir(backupRoot);
840 if (!sourceDir.exists()) {
841 TRACE() <<
"Backup directory does not exist!";
844 if (!sourceDir.exists(config.
m_dbName)) {
851 QStringList movedFiles, copiedFiles;
852 foreach (
const QString &fileName, fileNames) {
854 if (target.exists(fileName)) {
855 if (target.rename(fileName, fileName + QLatin1String(
".bak")))
856 movedFiles += fileName;
860 QString source = backupRoot + QDir::separator() + fileName;
861 if (!QFile::exists(source)) {
862 TRACE() <<
"Ignoring file not present in backup:" << source;
866 QString destination =
869 ok = QFile::copy(source, destination);
871 copiedFiles << fileName;
873 qWarning() <<
"Copy failed for:" << source;
879 qWarning() <<
"Restore failed, recovering previous DB";
881 foreach (
const QString &fileName, copiedFiles) {
882 target.remove(fileName);
885 foreach (
const QString &fileName, movedFiles) {
886 if (!target.rename(fileName + QLatin1String(
".bak"), fileName)) {
887 qCritical() <<
"Could not recover:" << fileName;
892 foreach (
const QString &fileName, movedFiles) {
893 target.remove(fileName + QLatin1String(
".bak"));
900 bool SignonDaemon::createStorageFileTree(
const QStringList &backupFiles)
const 903 QDir storageDir(storageDirPath);
905 if (!storageDir.exists()) {
906 if (!storageDir.mkpath(storageDirPath)) {
907 qCritical() <<
"Could not create storage dir for backup.";
912 foreach (
const QString &fileName, backupFiles) {
913 if (storageDir.exists(fileName))
continue;
915 QString filePath = storageDir.path() + QDir::separator() + fileName;
916 QFile file(filePath);
917 if (!file.open(QIODevice::WriteOnly)) {
918 qCritical() <<
"Failed to create empty file for backup:" << filePath;
936 qCritical() <<
"Cannot close credentials database";
944 QStringList backupFiles;
951 if (!createStorageFileTree(backupFiles)) {
952 qCritical() <<
"Cannot create backup file tree.";
958 if (!copyToBackupDir(backupFiles)) {
959 qCritical() <<
"Cannot copy database";
969 qCritical() <<
"Cannot reopen database";
984 TRACE() <<
"close daemon";
1002 TRACE() <<
"restore";
1009 qCritical() <<
"database cannot be closed";
1016 QStringList backupFiles;
1021 if (!copyFromBackupDir(backupFiles)) {
1022 qCritical() <<
"Cannot copy database";
1040 void SignonDaemon::onDisconnected()
1042 TRACE() <<
"Disconnected from session bus: exiting";
1043 this->deleteLater();
1044 QMetaObject::invokeMethod(QCoreApplication::instance(),
1046 Qt::QueuedConnection);
1049 void SignonDaemon::setLastError(
const QString &name,
const QString &msg)
1051 m_lastErrorName = name;
1052 m_lastErrorMessage = msg;
1055 void SignonDaemon::clearLastError()
1057 m_lastErrorName = QString();
1058 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