signon  8.54
signondaemon.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of signon
3  *
4  * Copyright (C) 2009-2010 Nokia Corporation.
5  * Copyright (C) 2013 Canonical Ltd.
6  *
7  * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
8  * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * version 2.1 as published by the Free Software Foundation.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22  * 02110-1301 USA
23  */
24 
25 extern "C" {
26  #include <sys/socket.h>
27  #include <sys/stat.h>
28  #include <sys/types.h>
29 }
30 
31 #define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(4, 0, 0)
32 
33 #include <QtDebug>
34 #include <QDir>
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>
43 #endif
44 
45 #include "SignOn/misc.h"
46 
47 #include "signondaemon.h"
48 #include "signond-common.h"
49 #include "signontrace.h"
50 #include "signondaemonadaptor.h"
51 #include "signonidentity.h"
52 #include "signonauthsession.h"
54 #include "backupifadaptor.h"
55 
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 " \
61  "Database.")); \
62  return _ret_arg_; \
63  } \
64  } while(0)
65 
66 #define BACKUP_DIR_NAME() \
67  (QDir::separator() + QLatin1String("backup"))
68 
69 using namespace SignOn;
70 
71 namespace SignonDaemonNS {
72 
73 /* ---------------------- SignonDaemonConfiguration ---------------------- */
74 
75 SignonDaemonConfiguration::SignonDaemonConfiguration():
76  m_pluginsDir(QLatin1String(SIGNOND_PLUGINS_DIR)),
77  m_extensionsDir(QLatin1String(SIGNOND_EXTENSIONS_DIR)),
78  m_camConfiguration(),
79  m_daemonTimeout(0), // 0 = no timeout
80  m_identityTimeout(300),//secs
81  m_authSessionTimeout(300)//secs
82 {}
83 
85 {
86  TRACE();
87 }
88 
89 /*
90  --- Configuration file template ---
91 
92  [General]
93  UseSecureStorage=yes
94  StoragePath=~/.signon/
95  ;0 - fatal, 1 - critical(default), 2 - info/debug
96  LoggingLevel=1
97 
98  [SecureStorage]
99  FileSystemName=signonfs
100  Size=8
101  FileSystemType=ext2
102 
103  [ObjectTimeouts]
104  IdentityTimeout=300
105  AuthSessionTimeout=300
106  */
108 {
109  QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
110 
111  //Daemon configuration file
112 
113  QSettings::setPath(QSettings::NativeFormat, QSettings::SystemScope,
114  environment.value(QLatin1String("SSO_CONFIG_FILE_DIR"),
115  QLatin1String("/etc")));
116 
117  QSettings settings(QLatin1String("signond"));
118 
119  int loggingLevel =
120  settings.value(QLatin1String("LoggingLevel"), 1).toInt();
121  setLoggingLevel(loggingLevel);
122 
123  QString cfgStoragePath =
124  settings.value(QLatin1String("StoragePath")).toString();
125  if (!cfgStoragePath.isEmpty()) {
126  QString storagePath = QDir(cfgStoragePath).path();
127  m_camConfiguration.setStoragePath(storagePath);
128  } else {
129  QString xdgConfigHome = QLatin1String(qgetenv("XDG_CONFIG_HOME"));
130  if (xdgConfigHome.isEmpty())
131  xdgConfigHome = QDir::homePath() + QLatin1String("/.config");
132  m_camConfiguration.setStoragePath(xdgConfigHome +
133  QLatin1String("/signond"));
134  }
135 
136  // Secure storage
137 
138  // Support legacy setting "UseSecureStorage"
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"));
145  }
146 
147  settings.beginGroup(QLatin1String("SecureStorage"));
148 
149  QVariantMap storageOptions;
150  foreach (const QString &key, settings.childKeys()) {
151  m_camConfiguration.addSetting(key, settings.value(key));
152  }
153 
154  settings.endGroup();
155 
156  //Timeouts
157  settings.beginGroup(QLatin1String("ObjectTimeouts"));
158 
159  bool isOk = false;
160  uint aux = settings.value(QLatin1String("IdentityTimeout")).toUInt(&isOk);
161  if (isOk)
162  m_identityTimeout = aux;
163 
164  aux = settings.value(QLatin1String("AuthSessionTimeout")).toUInt(&isOk);
165  if (isOk)
166  m_authSessionTimeout = aux;
167 
168  aux = settings.value(QLatin1String("DaemonTimeout")).toUInt(&isOk);
169  if (isOk)
170  m_daemonTimeout = aux;
171 
172  settings.endGroup();
173 
174  //Environment variables
175 
176  int value = 0;
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;
181  }
182 
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;
187  }
188 
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;
193  }
194 
195  if (environment.contains(QLatin1String("SSO_LOGGING_LEVEL"))) {
196  value = environment.value(
197  QLatin1String("SSO_LOGGING_LEVEL")).toInt(&isOk);
198  if (isOk)
199  setLoggingLevel(value);
200  }
201 
202  QString logOutput = environment.value(QLatin1String("SSO_LOGGING_OUTPUT"),
203  QLatin1String("syslog"));
204  SignonTrace::initialize(logOutput == QLatin1String("syslog") ?
205  SignonTrace::Syslog : SignonTrace::Stdout);
206 
207  if (environment.contains(QLatin1String("SSO_STORAGE_PATH"))) {
208  m_camConfiguration.setStoragePath(
209  environment.value(QLatin1String("SSO_STORAGE_PATH")));
210  }
211 
212  if (environment.contains(QLatin1String("SSO_PLUGINS_DIR"))) {
213  m_pluginsDir = environment.value(QLatin1String("SSO_PLUGINS_DIR"));
214  }
215 
216  if (environment.contains(QLatin1String("SSO_EXTENSIONS_DIR"))) {
217  m_extensionsDir =
218  environment.value(QLatin1String("SSO_EXTENSIONS_DIR"));
219  }
220 
221 #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
222  QString runtimeDir =
223  QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
224 #else
225  QString runtimeDir = environment.value(QLatin1String("XDG_RUNTIME_DIR"));
226 #endif
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;
233  } else {
234  m_busAddress =
235  QString::fromLatin1("unix:path=%1").arg(socketFileName);
236  }
237  } else {
238  BLAME() << "XDG_RUNTIME_DIR unset, disabling p2p bus";
239  }
240 }
241 
242 /* ---------------------- SignonDaemon ---------------------- */
243 
244 const QString internalServerErrName = SIGNOND_INTERNAL_SERVER_ERR_NAME;
245 const QString internalServerErrStr = SIGNOND_INTERNAL_SERVER_ERR_STR;
246 
247 static int sigFd[2];
248 
249 SignonDaemon *SignonDaemon::m_instance = NULL;
250 
251 SignonDaemon::SignonDaemon(QObject *parent):
252  QObject(parent),
253  m_configuration(0),
254  m_pCAMManager(0),
255  m_dbusServer(0)
256 {
257  // Files created by signond must be unreadable by "other"
258  umask(S_IROTH | S_IWOTH);
259 
260  // Register D-Bus meta types
261  qDBusRegisterMetaType<MethodMap>();
262  qDBusRegisterMetaType<MapList>();
263 }
264 
265 SignonDaemon::~SignonDaemon()
266 {
267  ::close(sigFd[0]);
268  ::close(sigFd[1]);
269 
270  if (m_backup) {
271  exit(0);
272  }
273 
274  SignonAuthSession::stopAllAuthSessions();
275  m_storedIdentities.clear();
276 
277  if (m_pCAMManager) {
278  m_pCAMManager->closeCredentialsSystem();
279  delete m_pCAMManager;
280  }
281 
282  QDBusConnection sessionConnection = QDBusConnection::sessionBus();
283 
284  sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH
285  + QLatin1String("/Backup"));
286  sessionConnection.unregisterService(SIGNOND_SERVICE
287  + QLatin1String(".Backup"));
288  if (m_backup == false)
289  {
290  sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH);
291  sessionConnection.unregisterService(SIGNOND_SERVICE);
292  }
293 
294  delete m_configuration;
295 
296  QMetaObject::invokeMethod(QCoreApplication::instance(),
297  "quit",
298  Qt::QueuedConnection);
299 }
300 
301 void SignonDaemon::setupSignalHandlers()
302 {
303  if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0)
304  BLAME() << "Couldn't create HUP socketpair";
305 
306  m_sigSn = new QSocketNotifier(sigFd[1], QSocketNotifier::Read, this);
307  connect(m_sigSn, SIGNAL(activated(int)),
308  this, SLOT(handleUnixSignal()));
309 }
310 
311 void SignonDaemon::signalHandler(int signal)
312 {
313  int ret = ::write(sigFd[0], &signal, sizeof(signal));
314  Q_UNUSED(ret);
315 }
316 
317 void SignonDaemon::handleUnixSignal()
318 {
319  m_sigSn->setEnabled(false);
320 
321  int signal;
322  int ret = read(sigFd[1], &signal, sizeof(signal));
323  Q_UNUSED(ret);
324 
325  TRACE() << "signal received: " << signal;
326 
327  switch (signal) {
328  case SIGHUP: {
329  TRACE() << "\n\n SIGHUP \n\n";
330  //todo restart daemon
331  deleteLater();
332 
333  // reset the m_instance
334  m_instance = NULL;
335  QMetaObject::invokeMethod(instance(),
336  "init",
337  Qt::QueuedConnection);
338  break;
339  }
340  case SIGTERM: {
341  TRACE() << "\n\n SIGTERM \n\n";
342  //gently stop daemon
343  deleteLater();
344  QMetaObject::invokeMethod(QCoreApplication::instance(),
345  "quit",
346  Qt::QueuedConnection);
347  break;
348  }
349  case SIGINT: {
350  TRACE() << "\n\n SIGINT \n\n";
351  //gently stop daemon
352  deleteLater();
353  QMetaObject::invokeMethod(QCoreApplication::instance(),
354  "quit",
355  Qt::QueuedConnection);
356  break;
357  }
358  default: break;
359  }
360 
361  m_sigSn->setEnabled(true);
362 }
363 
364 SignonDaemon *SignonDaemon::instance()
365 {
366  if (m_instance != NULL)
367  return m_instance;
368 
369  QCoreApplication *app = QCoreApplication::instance();
370 
371  if (!app)
372  qFatal("SignonDaemon requires a QCoreApplication instance to be "
373  "constructed first");
374 
375  TRACE() << "Creating new daemon instance.";
376  m_instance = new SignonDaemon(app);
377  return m_instance;
378 }
379 
380 void SignonDaemon::init()
381 {
382  if (!(m_configuration = new SignonDaemonConfiguration))
383  qWarning("SignonDaemon could not create the configuration object.");
384 
385  m_configuration->load();
386 
387  if (getuid() != 0) {
388  BLAME() << "Failed to SUID root. Secure storage will not be available.";
389  }
390 
391  QCoreApplication *app = QCoreApplication::instance();
392  if (!app)
393  qFatal("SignonDaemon requires a QCoreApplication instance to be "
394  "constructed first");
395 
396  setupSignalHandlers();
397  m_backup = app->arguments().contains(QLatin1String("-backup"));
398  m_pCAMManager =
399  new CredentialsAccessManager(m_configuration->camConfiguration());
400 
401  /* backup dbus interface */
402  QDBusConnection sessionConnection = QDBusConnection::sessionBus();
403 
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();
409 
410  qFatal("SignonDaemon requires session bus to start working");
411  }
412 
413  QDBusConnection::RegisterOptions registerSessionOptions =
414  QDBusConnection::ExportAdaptors;
415 
416  (void)new BackupIfAdaptor(this);
417 
418  if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
419  + QLatin1String("/Backup"),
420  this, registerSessionOptions)) {
421  TRACE() << "Object cannot be registered";
422 
423  qFatal("SignonDaemon requires to register backup object");
424  }
425 
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());
431 
432  qFatal("SignonDaemon requires to register backup service");
433  }
434 
435  if (m_backup) {
436  TRACE() << "Signond initialized in backup mode.";
437  //skip rest of initialization in backup mode
438  return;
439  }
440 
441  /* DBus Service init */
442  QDBusConnection connection = SIGNOND_BUS;
443 
444  if (!connection.isConnected()) {
445  QDBusError err = connection.lastError();
446  TRACE() << "Connection cannot be established:" <<
447  err.errorString(err.type());
448  TRACE() << err.message();
449 
450  qFatal("SignonDaemon requires DBus to start working");
451  }
452 
453  QDBusConnection::RegisterOptions registerOptions =
454  QDBusConnection::ExportAllContents;
455 
456  (void)new SignonDaemonAdaptor(this);
457  registerOptions = QDBusConnection::ExportAdaptors;
458 
459  // p2p connection
460 #ifdef ENABLE_P2P
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 &)));
465 #endif
466 
467  // session bus
468  if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
469  this, registerOptions)) {
470  TRACE() << "Object cannot be registered";
471 
472  qFatal("SignonDaemon requires to register daemon's object");
473  }
474 
475  if (!connection.registerService(SIGNOND_SERVICE)) {
476  QDBusError err = connection.lastError();
477  TRACE() << "Service cannot be registered: " <<
478  err.errorString(err.type());
479 
480  qFatal("SignonDaemon requires to register daemon's service");
481  }
482 
483  // handle D-Bus disconnection
484  connection.connect(QString(),
485  QLatin1String("/org/freedesktop/DBus/Local"),
486  QLatin1String("org.freedesktop.DBus.Local"),
487  QLatin1String("Disconnected"),
488  this, SLOT(onDisconnected()));
489 
490  initExtensions();
491 
492  if (!initStorage())
493  BLAME() << "Signond: Cannot initialize credentials storage.";
494 
495  if (m_configuration->daemonTimeout() > 0) {
496  SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(),
497  this, SLOT(deleteLater()));
498  }
499 
500  TRACE() << "Signond SUCCESSFULLY initialized.";
501 }
502 
503 void SignonDaemon::onNewConnection(const QDBusConnection &connection)
504 {
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");
510  }
511 }
512 
513 void SignonDaemon::initExtensions()
514 {
515  /* Scan the directory containing signond extensions and attempt loading
516  * all of them.
517  */
518  QDir dir(m_configuration->extensionsDir());
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));
523 }
524 
525 void SignonDaemon::initExtension(const QString &filePath)
526 {
527  TRACE() << "Loading plugin " << filePath;
528 
529  QPluginLoader pluginLoader(filePath);
530  QObject *plugin = pluginLoader.instance();
531  if (!plugin) {
532  qWarning() << "Couldn't load plugin:" << pluginLoader.errorString();
533  return;
534  }
535 
536  /* Check whether the extension implements some useful objects; if not,
537  * unload it. */
538  if (!m_pCAMManager->initExtension(plugin))
539  pluginLoader.unload();
540 }
541 
542 bool SignonDaemon::initStorage()
543 {
544  if (!m_pCAMManager->credentialsSystemOpened()) {
545  m_pCAMManager->finalize();
546 
547  if (!m_pCAMManager->init()) {
548  BLAME() << "CAM initialization failed";
549  return false;
550  }
551 
552  // If encryption is in use this will just open the metadata DB
553  if (!m_pCAMManager->openCredentialsSystem()) {
554  qCritical("Signond: Cannot open CAM credentials system...");
555  return false;
556  }
557  } else {
558  TRACE() << "Secure storage already initialized...";
559  return false;
560  }
561 
562  return true;
563 }
564 
565 void SignonDaemon::onIdentityStored(SignonIdentity *identity)
566 {
567  m_storedIdentities.insert(identity->id(), identity);
568 }
569 
570 void SignonDaemon::onIdentityDestroyed()
571 {
572  SignonIdentity *identity = qobject_cast<SignonIdentity*>(sender());
573  m_storedIdentities.remove(identity->id());
574 }
575 
576 void SignonDaemon::watchIdentity(SignonIdentity *identity)
577 {
578  QObject::connect(identity, SIGNAL(stored(SignonIdentity*)),
579  this, SLOT(onIdentityStored(SignonIdentity*)));
580  QObject::connect(identity, SIGNAL(unregistered()),
581  this, SLOT(onIdentityDestroyed()));
582 
583  if (identity->id() != SIGNOND_NEW_IDENTITY) {
584  m_storedIdentities.insert(identity->id(), identity);
585  }
586 }
587 
588 QObject *SignonDaemon::registerNewIdentity()
589 {
590  clearLastError();
591 
592  TRACE() << "Registering new identity:";
593 
594  SignonIdentity *identity =
595  SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY, this);
596 
597  Q_ASSERT(identity != NULL);
598  watchIdentity(identity);
599 
600  return identity;
601 }
602 
603 int SignonDaemon::identityTimeout() const
604 {
605  return (m_configuration == NULL ?
606  300 :
607  m_configuration->identityTimeout());
608 }
609 
610 int SignonDaemon::authSessionTimeout() const
611 {
612  return (m_configuration == NULL ?
613  300 :
614  m_configuration->authSessionTimeout());
615 }
616 
617 QObject *SignonDaemon::getIdentity(const quint32 id,
618  QVariantMap &identityData)
619 {
620  clearLastError();
621 
623 
624  TRACE() << "Registering identity:" << id;
625 
626  //1st check if the existing identity is in cache
627  SignonIdentity *identity = m_storedIdentities.value(id, NULL);
628 
629  //if not create it
630  if (identity == NULL)
631  identity = SignonIdentity::createIdentity(id, this);
632  Q_ASSERT(identity != NULL);
633 
634  bool ok;
635  SignonIdentityInfo info = identity->queryInfo(ok, false);
636 
637  if (info.isNew())
638  {
639  setLastError(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
640  SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
641  identity->destroy();
642  return 0;
643  }
644 
645  watchIdentity(identity);
646  identity->keepInUse();
647 
648  identityData = info.toMap();
649 
650  TRACE() << "DONE REGISTERING IDENTITY";
651  return identity;
652 }
653 
654 QStringList SignonDaemon::queryMethods()
655 {
656  QDir pluginsDir(m_configuration->pluginsDir());
657  //TODO: in the future remove the sym links comment
658  QStringList fileNames = pluginsDir.entryList(
659  QStringList() << QLatin1String("*.so*"),
660  QDir::Files | QDir::NoDotAndDotDot);
661 
662  QStringList ret;
663  QString fileName;
664  foreach (fileName, fileNames) {
665  if (fileName.startsWith(QLatin1String("lib"))) {
666  fileName =
667  fileName.mid(3, fileName.indexOf(QLatin1String("plugin")) -3);
668  if ((fileName.length() > 0) && !ret.contains(fileName))
669  ret << fileName;
670  }
671  }
672 
673  return ret;
674 }
675 
676 QStringList SignonDaemon::queryMechanisms(const QString &method)
677 {
678  clearLastError();
679 
680  TRACE() << method;
681 
682  QStringList mechs = SignonSessionCore::loadedPluginMethods(method);
683 
684  if (!mechs.isEmpty())
685  return mechs;
686 
687  PluginProxy *plugin = PluginProxy::createNewPluginProxy(method);
688 
689  if (!plugin) {
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.").
695  arg(method));
696  return QStringList();
697  }
698 
699  mechs = plugin->mechanisms();
700  delete plugin;
701 
702  return mechs;
703 }
704 
705 QList<QVariantMap> SignonDaemon::queryIdentities(const QVariantMap &filter)
706 {
707  clearLastError();
708 
710 
711  TRACE() << "Querying identities";
712 
713  CredentialsDB *db = m_pCAMManager->credentialsDB();
714  if (!db) {
715  qCritical() << Q_FUNC_INFO << m_pCAMManager->lastError();
716  return QList<QVariantMap>();
717  }
718 
719  QMap<QString, QString> filterLocal;
720  QMapIterator<QString, QVariant> it(filter);
721  while (it.hasNext()) {
722  it.next();
723  filterLocal.insert(it.key(), it.value().toString());
724  }
725 
726  QList<SignonIdentityInfo> credentials = db->credentials(filterLocal);
727 
728  if (db->errorOccurred()) {
729  setLastError(internalServerErrName,
731  QLatin1String("Querying database error occurred."));
732  return QList<QVariantMap>();
733  }
734 
735  QList<QVariantMap> mapList;
736  foreach (const SignonIdentityInfo &info, credentials) {
737  mapList.append(info.toMap());
738  }
739  return mapList;
740 }
741 
742 bool SignonDaemon::clear()
743 {
744  clearLastError();
745 
747 
748  TRACE() << "\n\n\n Clearing DB\n\n";
749  CredentialsDB *db = m_pCAMManager->credentialsDB();
750  if (!db) {
751  qCritical() << Q_FUNC_INFO << m_pCAMManager->lastError();
752  return false;
753  }
754 
755  if (!db->clear()) {
756  setLastError(SIGNOND_INTERNAL_SERVER_ERR_NAME,
757  SIGNOND_INTERNAL_SERVER_ERR_STR +
758  QLatin1String("Database error occurred."));
759  return false;
760  }
761  return true;
762 }
763 
764 QObject *SignonDaemon::getAuthSession(const quint32 id,
765  const QString type,
766  pid_t ownerPid)
767 {
768  clearLastError();
769 
770  SignonAuthSession *authSession =
771  SignonAuthSession::createAuthSession(id, type, this, ownerPid);
772  if (authSession == NULL) {
773  setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
774  SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
775  return 0;
776  }
777 
778  return authSession;
779 }
780 
781 void SignonDaemon::eraseBackupDir() const
782 {
783  const CAMConfiguration config = m_configuration->camConfiguration();
784  QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME();
785 
786  QDir target(backupRoot);
787  if (!target.exists()) return;
788 
789  QStringList targetEntries = target.entryList(QDir::Files);
790  foreach (QString entry, targetEntries) {
791  target.remove(entry);
792  }
793 
794  target.rmdir(backupRoot);
795 }
796 
797 bool SignonDaemon::copyToBackupDir(const QStringList &fileNames) const
798 {
799  const CAMConfiguration config = m_configuration->camConfiguration();
800  QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME();
801 
802  QDir target(backupRoot);
803  if (!target.exists() && !target.mkpath(backupRoot)) {
804  qCritical() << "Cannot create target directory";
805  return false;
806  }
807 
808  setUserOwnership(backupRoot);
809 
810  /* Now copy the files to be backed up */
811  bool ok = true;
812  foreach (const QString &fileName, fileNames) {
813  /* Remove the target file, if it exists */
814  if (target.exists(fileName))
815  target.remove(fileName);
816 
817  /* Copy the source into the target directory */
818  QString source = config.m_storagePath + QDir::separator() + fileName;
819  if (!QFile::exists(source)) continue;
820 
821  QString destination = backupRoot + QDir::separator() + fileName;
822  ok = QFile::copy(source, destination);
823  if (!ok) {
824  BLAME() << "Copying" << source << "to" << destination << "failed";
825  break;
826  }
827 
828  setUserOwnership(destination);
829  }
830 
831  return ok;
832 }
833 
834 bool SignonDaemon::copyFromBackupDir(const QStringList &fileNames) const
835 {
836  const CAMConfiguration config = m_configuration->camConfiguration();
837  QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME();
838 
839  QDir sourceDir(backupRoot);
840  if (!sourceDir.exists()) {
841  TRACE() << "Backup directory does not exist!";
842  }
843 
844  if (!sourceDir.exists(config.m_dbName)) {
845  TRACE() << "Backup does not contain DB:" << config.m_dbName;
846  }
847 
848  /* Now restore the files from the backup */
849  bool ok = true;
850  QDir target(config.m_storagePath);
851  QStringList movedFiles, copiedFiles;
852  foreach (const QString &fileName, fileNames) {
853  /* Remove the target file, if it exists */
854  if (target.exists(fileName)) {
855  if (target.rename(fileName, fileName + QLatin1String(".bak")))
856  movedFiles += fileName;
857  }
858 
859  /* Copy the source into the target directory */
860  QString source = backupRoot + QDir::separator() + fileName;
861  if (!QFile::exists(source)) {
862  TRACE() << "Ignoring file not present in backup:" << source;
863  continue;
864  }
865 
866  QString destination =
867  config.m_storagePath + QDir::separator() + fileName;
868 
869  ok = QFile::copy(source, destination);
870  if (ok) {
871  copiedFiles << fileName;
872  } else {
873  qWarning() << "Copy failed for:" << source;
874  break;
875  }
876  }
877 
878  if (!ok) {
879  qWarning() << "Restore failed, recovering previous DB";
880 
881  foreach (const QString &fileName, copiedFiles) {
882  target.remove(fileName);
883  }
884 
885  foreach (const QString &fileName, movedFiles) {
886  if (!target.rename(fileName + QLatin1String(".bak"), fileName)) {
887  qCritical() << "Could not recover:" << fileName;
888  }
889  }
890  } else {
891  /* delete ".bak" files */
892  foreach (const QString &fileName, movedFiles) {
893  target.remove(fileName + QLatin1String(".bak"));
894  }
895 
896  }
897  return ok;
898 }
899 
900 bool SignonDaemon::createStorageFileTree(const QStringList &backupFiles) const
901 {
902  QString storageDirPath = m_configuration->camConfiguration().m_storagePath;
903  QDir storageDir(storageDirPath);
904 
905  if (!storageDir.exists()) {
906  if (!storageDir.mkpath(storageDirPath)) {
907  qCritical() << "Could not create storage dir for backup.";
908  return false;
909  }
910  }
911 
912  foreach (const QString &fileName, backupFiles) {
913  if (storageDir.exists(fileName)) continue;
914 
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;
919  return false;
920  } else {
921  file.close();
922  }
923  }
924 
925  return true;
926 }
927 
928 uchar SignonDaemon::backupStarts()
929 {
930  TRACE() << "backup";
931  if (!m_backup && m_pCAMManager->credentialsSystemOpened())
932  {
933  m_pCAMManager->closeCredentialsSystem();
934  if (m_pCAMManager->credentialsSystemOpened())
935  {
936  qCritical() << "Cannot close credentials database";
937  return 2;
938  }
939  }
940 
941  const CAMConfiguration config = m_configuration->camConfiguration();
942 
943  /* do backup copy: prepare the list of files to be backed up */
944  QStringList backupFiles;
945  backupFiles << config.m_dbName;
946  backupFiles << m_pCAMManager->backupFiles();
947 
948  /* make sure that all the backup files and storage directory exist:
949  create storage dir and empty files if not so, as backup/restore
950  operations must be consistent */
951  if (!createStorageFileTree(backupFiles)) {
952  qCritical() << "Cannot create backup file tree.";
953  return 2;
954  }
955 
956  /* perform the copy */
957  eraseBackupDir();
958  if (!copyToBackupDir(backupFiles)) {
959  qCritical() << "Cannot copy database";
960  if (!m_backup)
961  m_pCAMManager->openCredentialsSystem();
962  return 2;
963  }
964 
965  if (!m_backup)
966  {
967  //mount file system back
968  if (!m_pCAMManager->openCredentialsSystem()) {
969  qCritical() << "Cannot reopen database";
970  }
971  }
972  return 0;
973 }
974 
975 uchar SignonDaemon::backupFinished()
976 {
977  TRACE() << "close";
978 
979  eraseBackupDir();
980 
981  if (m_backup)
982  {
983  //close daemon
984  TRACE() << "close daemon";
985  this->deleteLater();
986  }
987 
988  return 0;
989  }
990 
991 /*
992  * Does nothing but start-on-demand
993  * */
994 uchar SignonDaemon::restoreStarts()
995 {
996  TRACE();
997  return 0;
998 }
999 
1000 uchar SignonDaemon::restoreFinished()
1001 {
1002  TRACE() << "restore";
1003  //restore requested
1004  if (m_pCAMManager->credentialsSystemOpened())
1005  {
1006  //umount file system
1007  if (!m_pCAMManager->closeCredentialsSystem())
1008  {
1009  qCritical() << "database cannot be closed";
1010  return 2;
1011  }
1012  }
1013 
1014  const CAMConfiguration config = m_configuration->camConfiguration();
1015 
1016  QStringList backupFiles;
1017  backupFiles << config.m_dbName;
1018  backupFiles << m_pCAMManager->backupFiles();
1019 
1020  /* perform the copy */
1021  if (!copyFromBackupDir(backupFiles)) {
1022  qCritical() << "Cannot copy database";
1023  m_pCAMManager->openCredentialsSystem();
1024  return 2;
1025  }
1026 
1027  eraseBackupDir();
1028 
1029  //TODO check database integrity
1030  if (!m_backup)
1031  {
1032  //mount file system back
1033  if (!m_pCAMManager->openCredentialsSystem())
1034  return 2;
1035  }
1036 
1037  return 0;
1038 }
1039 
1040 void SignonDaemon::onDisconnected()
1041 {
1042  TRACE() << "Disconnected from session bus: exiting";
1043  this->deleteLater();
1044  QMetaObject::invokeMethod(QCoreApplication::instance(),
1045  "quit",
1046  Qt::QueuedConnection);
1047 }
1048 
1049 void SignonDaemon::setLastError(const QString &name, const QString &msg)
1050 {
1051  m_lastErrorName = name;
1052  m_lastErrorMessage = msg;
1053 }
1054 
1055 void SignonDaemon::clearLastError()
1056 {
1057  m_lastErrorName = QString();
1058  m_lastErrorMessage = QString();
1059 }
1060 
1061 } //namespace SignonDaemonNS
const QString internalServerErrName
void addSetting(const QString &key, const QVariant &value)
Daemon side representation of authentication session.
QString m_dbName
The database file name.
#define BLAME()
Definition: debug.h:32
void destroy()
Performs any predestruction operations and the destruction itself.
SignOn::CredentialsDBError lastError() const
#define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_)
void setStoragePath(const QString &storagePath)
QString m_storagePath
The base directory for storage.
SignonIdentityInfo credentials(const quint32 id, bool queryPassword=true)
QStringList mechanisms() const
Definition: pluginproxy.h:72
Main singleton and manager object of the credentials database system.
#define BACKUP_DIR_NAME()
bool setUserOwnership(const QString &filePath)
Definition: misc.cpp:33
const QString internalServerErrStr
#define TRACE()
Definition: debug.h:28
Daemon side representation of identity.
Daemon side representation of identity information.
Manages the credentials I/O.
Definition: credentialsdb.h:66
Configuration object for the CredentialsAccessManager - CAM.
Helper class for access control-related functionality.
The daemon&#39;s configuration object; loads date from the daemon configuration file. ...
Definition: signondaemon.h:62
SignonIdentityInfo queryInfo(bool &ok, bool queryPassword=true)
void keepInUse() const
Mark the object as used.
#define SIGNOND_PLUGINS_DIR