signon  8.57
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  delete m_dbusServer;
275 
276  SignonAuthSession::stopAllAuthSessions();
277  m_storedIdentities.clear();
278 
279  if (m_pCAMManager) {
280  m_pCAMManager->closeCredentialsSystem();
281  delete m_pCAMManager;
282  }
283 
284  QDBusConnection sessionConnection = QDBusConnection::sessionBus();
285 
286  sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH
287  + QLatin1String("/Backup"));
288  sessionConnection.unregisterService(SIGNOND_SERVICE
289  + QLatin1String(".Backup"));
290  if (m_backup == false)
291  {
292  sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH);
293  sessionConnection.unregisterService(SIGNOND_SERVICE);
294  }
295 
296  delete m_configuration;
297 
298  QMetaObject::invokeMethod(QCoreApplication::instance(),
299  "quit",
300  Qt::QueuedConnection);
301 }
302 
303 void SignonDaemon::setupSignalHandlers()
304 {
305  if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0)
306  BLAME() << "Couldn't create HUP socketpair";
307 
308  m_sigSn = new QSocketNotifier(sigFd[1], QSocketNotifier::Read, this);
309  connect(m_sigSn, SIGNAL(activated(int)),
310  this, SLOT(handleUnixSignal()));
311 }
312 
313 void SignonDaemon::signalHandler(int signal)
314 {
315  int ret = ::write(sigFd[0], &signal, sizeof(signal));
316  Q_UNUSED(ret);
317 }
318 
319 void SignonDaemon::handleUnixSignal()
320 {
321  m_sigSn->setEnabled(false);
322 
323  int signal;
324  int ret = read(sigFd[1], &signal, sizeof(signal));
325  Q_UNUSED(ret);
326 
327  TRACE() << "signal received: " << signal;
328 
329  switch (signal) {
330  case SIGHUP: {
331  TRACE() << "\n\n SIGHUP \n\n";
332  //todo restart daemon
333  deleteLater();
334 
335  // reset the m_instance
336  m_instance = NULL;
337  QMetaObject::invokeMethod(instance(),
338  "init",
339  Qt::QueuedConnection);
340  break;
341  }
342  case SIGTERM: {
343  TRACE() << "\n\n SIGTERM \n\n";
344  //gently stop daemon
345  deleteLater();
346  QMetaObject::invokeMethod(QCoreApplication::instance(),
347  "quit",
348  Qt::QueuedConnection);
349  break;
350  }
351  case SIGINT: {
352  TRACE() << "\n\n SIGINT \n\n";
353  //gently stop daemon
354  deleteLater();
355  QMetaObject::invokeMethod(QCoreApplication::instance(),
356  "quit",
357  Qt::QueuedConnection);
358  break;
359  }
360  default: break;
361  }
362 
363  m_sigSn->setEnabled(true);
364 }
365 
366 SignonDaemon *SignonDaemon::instance()
367 {
368  if (m_instance != NULL)
369  return m_instance;
370 
371  QCoreApplication *app = QCoreApplication::instance();
372 
373  if (!app)
374  qFatal("SignonDaemon requires a QCoreApplication instance to be "
375  "constructed first");
376 
377  TRACE() << "Creating new daemon instance.";
378  m_instance = new SignonDaemon(app);
379  return m_instance;
380 }
381 
382 void SignonDaemon::init()
383 {
384  if (!(m_configuration = new SignonDaemonConfiguration))
385  qWarning("SignonDaemon could not create the configuration object.");
386 
387  m_configuration->load();
388 
389  if (getuid() != 0) {
390  BLAME() << "Failed to SUID root. Secure storage will not be available.";
391  }
392 
393  QCoreApplication *app = QCoreApplication::instance();
394  if (!app)
395  qFatal("SignonDaemon requires a QCoreApplication instance to be "
396  "constructed first");
397 
398  setupSignalHandlers();
399  m_backup = app->arguments().contains(QLatin1String("-backup"));
400  m_pCAMManager =
401  new CredentialsAccessManager(m_configuration->camConfiguration());
402 
403  /* backup dbus interface */
404  QDBusConnection sessionConnection = QDBusConnection::sessionBus();
405 
406  if (!sessionConnection.isConnected()) {
407  QDBusError err = sessionConnection.lastError();
408  TRACE() << "Session connection cannot be established:" <<
409  err.errorString(err.type());
410  TRACE() << err.message();
411 
412  qFatal("SignonDaemon requires session bus to start working");
413  }
414 
415  QDBusConnection::RegisterOptions registerSessionOptions =
416  QDBusConnection::ExportAdaptors;
417 
418  (void)new BackupIfAdaptor(this);
419 
420  if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH
421  + QLatin1String("/Backup"),
422  this, registerSessionOptions)) {
423  TRACE() << "Object cannot be registered";
424 
425  qFatal("SignonDaemon requires to register backup object");
426  }
427 
428  if (!sessionConnection.registerService(SIGNOND_SERVICE +
429  QLatin1String(".Backup"))) {
430  QDBusError err = sessionConnection.lastError();
431  TRACE() << "Service cannot be registered: " <<
432  err.errorString(err.type());
433 
434  qFatal("SignonDaemon requires to register backup service");
435  }
436 
437  if (m_backup) {
438  TRACE() << "Signond initialized in backup mode.";
439  //skip rest of initialization in backup mode
440  return;
441  }
442 
443  /* DBus Service init */
444  QDBusConnection connection = SIGNOND_BUS;
445 
446  if (!connection.isConnected()) {
447  QDBusError err = connection.lastError();
448  TRACE() << "Connection cannot be established:" <<
449  err.errorString(err.type());
450  TRACE() << err.message();
451 
452  qFatal("SignonDaemon requires DBus to start working");
453  }
454 
455  QDBusConnection::RegisterOptions registerOptions =
456  QDBusConnection::ExportAllContents;
457 
458  (void)new SignonDaemonAdaptor(this);
459  registerOptions = QDBusConnection::ExportAdaptors;
460 
461  // p2p connection
462 #ifdef ENABLE_P2P
463  m_dbusServer = new QDBusServer(m_configuration->busAddress(), this);
464  QObject::connect(m_dbusServer,
465  SIGNAL(newConnection(const QDBusConnection &)),
466  this, SLOT(onNewConnection(const QDBusConnection &)));
467 #endif
468 
469  // session bus
470  if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH,
471  this, registerOptions)) {
472  TRACE() << "Object cannot be registered";
473 
474  qFatal("SignonDaemon requires to register daemon's object");
475  }
476 
477  if (!connection.registerService(SIGNOND_SERVICE)) {
478  QDBusError err = connection.lastError();
479  TRACE() << "Service cannot be registered: " <<
480  err.errorString(err.type());
481 
482  qFatal("SignonDaemon requires to register daemon's service");
483  }
484 
485  // handle D-Bus disconnection
486  connection.connect(QString(),
487  QLatin1String("/org/freedesktop/DBus/Local"),
488  QLatin1String("org.freedesktop.DBus.Local"),
489  QLatin1String("Disconnected"),
490  this, SLOT(onDisconnected()));
491 
492  initExtensions();
493 
494  if (!initStorage())
495  BLAME() << "Signond: Cannot initialize credentials storage.";
496 
497  if (m_configuration->daemonTimeout() > 0) {
498  SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(),
499  this, SLOT(deleteLater()));
500  }
501 
502  TRACE() << "Signond SUCCESSFULLY initialized.";
503 }
504 
505 void SignonDaemon::onNewConnection(const QDBusConnection &connection)
506 {
507  TRACE() << "New p2p connection" << connection.name();
508  QDBusConnection conn(connection);
509  if (!conn.registerObject(SIGNOND_DAEMON_OBJECTPATH,
510  this, QDBusConnection::ExportAdaptors)) {
511  qFatal("Failed to register SignonDaemon object");
512  }
513 }
514 
515 void SignonDaemon::initExtensions()
516 {
517  /* Scan the directory containing signond extensions and attempt loading
518  * all of them.
519  */
520  QDir dir(m_configuration->extensionsDir());
521  QStringList filters(QLatin1String("lib*.so"));
522  QStringList extensionList = dir.entryList(filters, QDir::Files);
523  foreach(const QString &filename, extensionList)
524  initExtension(dir.filePath(filename));
525 }
526 
527 void SignonDaemon::initExtension(const QString &filePath)
528 {
529  TRACE() << "Loading plugin " << filePath;
530 
531  QPluginLoader pluginLoader(filePath);
532  QObject *plugin = pluginLoader.instance();
533  if (!plugin) {
534  qWarning() << "Couldn't load plugin:" << pluginLoader.errorString();
535  return;
536  }
537 
538  /* Check whether the extension implements some useful objects; if not,
539  * unload it. */
540  if (!m_pCAMManager->initExtension(plugin))
541  pluginLoader.unload();
542 }
543 
544 bool SignonDaemon::initStorage()
545 {
546  if (!m_pCAMManager->credentialsSystemOpened()) {
547  m_pCAMManager->finalize();
548 
549  if (!m_pCAMManager->init()) {
550  BLAME() << "CAM initialization failed";
551  return false;
552  }
553 
554  // If encryption is in use this will just open the metadata DB
555  if (!m_pCAMManager->openCredentialsSystem()) {
556  qCritical("Signond: Cannot open CAM credentials system...");
557  return false;
558  }
559  } else {
560  TRACE() << "Secure storage already initialized...";
561  return false;
562  }
563 
564  return true;
565 }
566 
567 void SignonDaemon::onIdentityStored(SignonIdentity *identity)
568 {
569  m_storedIdentities.insert(identity->id(), identity);
570 }
571 
572 void SignonDaemon::onIdentityDestroyed()
573 {
574  SignonIdentity *identity = qobject_cast<SignonIdentity*>(sender());
575  m_storedIdentities.remove(identity->id());
576 }
577 
578 void SignonDaemon::watchIdentity(SignonIdentity *identity)
579 {
580  QObject::connect(identity, SIGNAL(stored(SignonIdentity*)),
581  this, SLOT(onIdentityStored(SignonIdentity*)));
582  QObject::connect(identity, SIGNAL(unregistered()),
583  this, SLOT(onIdentityDestroyed()));
584 
585  if (identity->id() != SIGNOND_NEW_IDENTITY) {
586  m_storedIdentities.insert(identity->id(), identity);
587  }
588 }
589 
590 QObject *SignonDaemon::registerNewIdentity()
591 {
592  clearLastError();
593 
594  TRACE() << "Registering new identity:";
595 
596  SignonIdentity *identity =
597  SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY, this);
598 
599  Q_ASSERT(identity != NULL);
600  watchIdentity(identity);
601 
602  return identity;
603 }
604 
605 int SignonDaemon::identityTimeout() const
606 {
607  return (m_configuration == NULL ?
608  300 :
609  m_configuration->identityTimeout());
610 }
611 
612 int SignonDaemon::authSessionTimeout() const
613 {
614  return (m_configuration == NULL ?
615  300 :
616  m_configuration->authSessionTimeout());
617 }
618 
619 QObject *SignonDaemon::getIdentity(const quint32 id,
620  QVariantMap &identityData)
621 {
622  clearLastError();
623 
625 
626  TRACE() << "Registering identity:" << id;
627 
628  //1st check if the existing identity is in cache
629  SignonIdentity *identity = m_storedIdentities.value(id, NULL);
630 
631  //if not create it
632  if (identity == NULL)
633  identity = SignonIdentity::createIdentity(id, this);
634  Q_ASSERT(identity != NULL);
635 
636  bool ok;
637  SignonIdentityInfo info = identity->queryInfo(ok, false);
638 
639  if (info.isNew())
640  {
641  setLastError(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
642  SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
643  identity->destroy();
644  return 0;
645  }
646 
647  watchIdentity(identity);
648  identity->keepInUse();
649 
650  identityData = info.toMap();
651 
652  TRACE() << "DONE REGISTERING IDENTITY";
653  return identity;
654 }
655 
656 QStringList SignonDaemon::queryMethods()
657 {
658  QDir pluginsDir(m_configuration->pluginsDir());
659  //TODO: in the future remove the sym links comment
660  QStringList fileNames = pluginsDir.entryList(
661  QStringList() << QLatin1String("*.so*"),
662  QDir::Files | QDir::NoDotAndDotDot);
663 
664  QStringList ret;
665  QString fileName;
666  foreach (fileName, fileNames) {
667  if (fileName.startsWith(QLatin1String("lib"))) {
668  fileName =
669  fileName.mid(3, fileName.indexOf(QLatin1String("plugin")) -3);
670  if ((fileName.length() > 0) && !ret.contains(fileName))
671  ret << fileName;
672  }
673  }
674 
675  return ret;
676 }
677 
678 QStringList SignonDaemon::queryMechanisms(const QString &method)
679 {
680  clearLastError();
681 
682  TRACE() << method;
683 
684  QStringList mechs = SignonSessionCore::loadedPluginMethods(method);
685 
686  if (!mechs.isEmpty())
687  return mechs;
688 
689  PluginProxy *plugin = PluginProxy::createNewPluginProxy(method);
690 
691  if (!plugin) {
692  TRACE() << "Could not load plugin of type: " << method;
693  setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
694  SIGNOND_METHOD_NOT_KNOWN_ERR_STR +
695  QString::fromLatin1("Method %1 is not known or could "
696  "not load specific configuration.").
697  arg(method));
698  return QStringList();
699  }
700 
701  mechs = plugin->mechanisms();
702  delete plugin;
703 
704  return mechs;
705 }
706 
707 QList<QVariantMap> SignonDaemon::queryIdentities(const QVariantMap &filter)
708 {
709  clearLastError();
710 
712 
713  TRACE() << "Querying identities";
714 
715  CredentialsDB *db = m_pCAMManager->credentialsDB();
716  if (!db) {
717  qCritical() << Q_FUNC_INFO << m_pCAMManager->lastError();
718  return QList<QVariantMap>();
719  }
720 
721  QMap<QString, QString> filterLocal;
722  QMapIterator<QString, QVariant> it(filter);
723  while (it.hasNext()) {
724  it.next();
725  filterLocal.insert(it.key(), it.value().toString());
726  }
727 
728  QList<SignonIdentityInfo> credentials = db->credentials(filterLocal);
729 
730  if (db->errorOccurred()) {
731  setLastError(internalServerErrName,
732  internalServerErrStr +
733  QLatin1String("Querying database error occurred."));
734  return QList<QVariantMap>();
735  }
736 
737  QList<QVariantMap> mapList;
738  foreach (const SignonIdentityInfo &info, credentials) {
739  mapList.append(info.toMap());
740  }
741  return mapList;
742 }
743 
744 bool SignonDaemon::clear()
745 {
746  clearLastError();
747 
749 
750  TRACE() << "\n\n\n Clearing DB\n\n";
751  CredentialsDB *db = m_pCAMManager->credentialsDB();
752  if (!db) {
753  qCritical() << Q_FUNC_INFO << m_pCAMManager->lastError();
754  return false;
755  }
756 
757  if (!db->clear()) {
758  setLastError(SIGNOND_INTERNAL_SERVER_ERR_NAME,
759  SIGNOND_INTERNAL_SERVER_ERR_STR +
760  QLatin1String("Database error occurred."));
761  return false;
762  }
763  return true;
764 }
765 
766 QObject *SignonDaemon::getAuthSession(const quint32 id,
767  const QString type,
768  pid_t ownerPid)
769 {
770  clearLastError();
771 
772  SignonAuthSession *authSession =
773  SignonAuthSession::createAuthSession(id, type, this, ownerPid);
774  if (authSession == NULL) {
775  setLastError(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME,
776  SIGNOND_METHOD_NOT_KNOWN_ERR_STR);
777  return 0;
778  }
779 
780  return authSession;
781 }
782 
783 void SignonDaemon::eraseBackupDir() const
784 {
785  const CAMConfiguration config = m_configuration->camConfiguration();
786  QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME();
787 
788  QDir target(backupRoot);
789  if (!target.exists()) return;
790 
791  QStringList targetEntries = target.entryList(QDir::Files);
792  foreach (QString entry, targetEntries) {
793  target.remove(entry);
794  }
795 
796  target.rmdir(backupRoot);
797 }
798 
799 bool SignonDaemon::copyToBackupDir(const QStringList &fileNames) const
800 {
801  const CAMConfiguration config = m_configuration->camConfiguration();
802  QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME();
803 
804  QDir target(backupRoot);
805  if (!target.exists() && !target.mkpath(backupRoot)) {
806  qCritical() << "Cannot create target directory";
807  return false;
808  }
809 
810  setUserOwnership(backupRoot);
811 
812  /* Now copy the files to be backed up */
813  bool ok = true;
814  foreach (const QString &fileName, fileNames) {
815  /* Remove the target file, if it exists */
816  if (target.exists(fileName))
817  target.remove(fileName);
818 
819  /* Copy the source into the target directory */
820  QString source = config.m_storagePath + QDir::separator() + fileName;
821  if (!QFile::exists(source)) continue;
822 
823  QString destination = backupRoot + QDir::separator() + fileName;
824  ok = QFile::copy(source, destination);
825  if (!ok) {
826  BLAME() << "Copying" << source << "to" << destination << "failed";
827  break;
828  }
829 
830  setUserOwnership(destination);
831  }
832 
833  return ok;
834 }
835 
836 bool SignonDaemon::copyFromBackupDir(const QStringList &fileNames) const
837 {
838  const CAMConfiguration config = m_configuration->camConfiguration();
839  QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME();
840 
841  QDir sourceDir(backupRoot);
842  if (!sourceDir.exists()) {
843  TRACE() << "Backup directory does not exist!";
844  }
845 
846  if (!sourceDir.exists(config.m_dbName)) {
847  TRACE() << "Backup does not contain DB:" << config.m_dbName;
848  }
849 
850  /* Now restore the files from the backup */
851  bool ok = true;
852  QDir target(config.m_storagePath);
853  QStringList movedFiles, copiedFiles;
854  foreach (const QString &fileName, fileNames) {
855  /* Remove the target file, if it exists */
856  if (target.exists(fileName)) {
857  if (target.rename(fileName, fileName + QLatin1String(".bak")))
858  movedFiles += fileName;
859  }
860 
861  /* Copy the source into the target directory */
862  QString source = backupRoot + QDir::separator() + fileName;
863  if (!QFile::exists(source)) {
864  TRACE() << "Ignoring file not present in backup:" << source;
865  continue;
866  }
867 
868  QString destination =
869  config.m_storagePath + QDir::separator() + fileName;
870 
871  ok = QFile::copy(source, destination);
872  if (ok) {
873  copiedFiles << fileName;
874  } else {
875  qWarning() << "Copy failed for:" << source;
876  break;
877  }
878  }
879 
880  if (!ok) {
881  qWarning() << "Restore failed, recovering previous DB";
882 
883  foreach (const QString &fileName, copiedFiles) {
884  target.remove(fileName);
885  }
886 
887  foreach (const QString &fileName, movedFiles) {
888  if (!target.rename(fileName + QLatin1String(".bak"), fileName)) {
889  qCritical() << "Could not recover:" << fileName;
890  }
891  }
892  } else {
893  /* delete ".bak" files */
894  foreach (const QString &fileName, movedFiles) {
895  target.remove(fileName + QLatin1String(".bak"));
896  }
897 
898  }
899  return ok;
900 }
901 
902 bool SignonDaemon::createStorageFileTree(const QStringList &backupFiles) const
903 {
904  QString storageDirPath = m_configuration->camConfiguration().m_storagePath;
905  QDir storageDir(storageDirPath);
906 
907  if (!storageDir.exists()) {
908  if (!storageDir.mkpath(storageDirPath)) {
909  qCritical() << "Could not create storage dir for backup.";
910  return false;
911  }
912  }
913 
914  foreach (const QString &fileName, backupFiles) {
915  if (storageDir.exists(fileName)) continue;
916 
917  QString filePath = storageDir.path() + QDir::separator() + fileName;
918  QFile file(filePath);
919  if (!file.open(QIODevice::WriteOnly)) {
920  qCritical() << "Failed to create empty file for backup:" << filePath;
921  return false;
922  } else {
923  file.close();
924  }
925  }
926 
927  return true;
928 }
929 
930 uchar SignonDaemon::backupStarts()
931 {
932  TRACE() << "backup";
933  if (!m_backup && m_pCAMManager->credentialsSystemOpened())
934  {
935  m_pCAMManager->closeCredentialsSystem();
936  if (m_pCAMManager->credentialsSystemOpened())
937  {
938  qCritical() << "Cannot close credentials database";
939  return 2;
940  }
941  }
942 
943  const CAMConfiguration config = m_configuration->camConfiguration();
944 
945  /* do backup copy: prepare the list of files to be backed up */
946  QStringList backupFiles;
947  backupFiles << config.m_dbName;
948  backupFiles << m_pCAMManager->backupFiles();
949 
950  /* make sure that all the backup files and storage directory exist:
951  create storage dir and empty files if not so, as backup/restore
952  operations must be consistent */
953  if (!createStorageFileTree(backupFiles)) {
954  qCritical() << "Cannot create backup file tree.";
955  return 2;
956  }
957 
958  /* perform the copy */
959  eraseBackupDir();
960  if (!copyToBackupDir(backupFiles)) {
961  qCritical() << "Cannot copy database";
962  if (!m_backup)
963  m_pCAMManager->openCredentialsSystem();
964  return 2;
965  }
966 
967  if (!m_backup)
968  {
969  //mount file system back
970  if (!m_pCAMManager->openCredentialsSystem()) {
971  qCritical() << "Cannot reopen database";
972  }
973  }
974  return 0;
975 }
976 
977 uchar SignonDaemon::backupFinished()
978 {
979  TRACE() << "close";
980 
981  eraseBackupDir();
982 
983  if (m_backup)
984  {
985  //close daemon
986  TRACE() << "close daemon";
987  this->deleteLater();
988  }
989 
990  return 0;
991  }
992 
993 /*
994  * Does nothing but start-on-demand
995  * */
996 uchar SignonDaemon::restoreStarts()
997 {
998  TRACE();
999  return 0;
1000 }
1001 
1002 uchar SignonDaemon::restoreFinished()
1003 {
1004  TRACE() << "restore";
1005  //restore requested
1006  if (m_pCAMManager->credentialsSystemOpened())
1007  {
1008  //umount file system
1009  if (!m_pCAMManager->closeCredentialsSystem())
1010  {
1011  qCritical() << "database cannot be closed";
1012  return 2;
1013  }
1014  }
1015 
1016  const CAMConfiguration config = m_configuration->camConfiguration();
1017 
1018  QStringList backupFiles;
1019  backupFiles << config.m_dbName;
1020  backupFiles << m_pCAMManager->backupFiles();
1021 
1022  /* perform the copy */
1023  if (!copyFromBackupDir(backupFiles)) {
1024  qCritical() << "Cannot copy database";
1025  m_pCAMManager->openCredentialsSystem();
1026  return 2;
1027  }
1028 
1029  eraseBackupDir();
1030 
1031  //TODO check database integrity
1032  if (!m_backup)
1033  {
1034  //mount file system back
1035  if (!m_pCAMManager->openCredentialsSystem())
1036  return 2;
1037  }
1038 
1039  return 0;
1040 }
1041 
1042 void SignonDaemon::onDisconnected()
1043 {
1044  TRACE() << "Disconnected from session bus: exiting";
1045  this->deleteLater();
1046  QMetaObject::invokeMethod(QCoreApplication::instance(),
1047  "quit",
1048  Qt::QueuedConnection);
1049 }
1050 
1051 void SignonDaemon::setLastError(const QString &name, const QString &msg)
1052 {
1053  m_lastErrorName = name;
1054  m_lastErrorMessage = msg;
1055 }
1056 
1057 void SignonDaemon::clearLastError()
1058 {
1059  m_lastErrorName = QString();
1060  m_lastErrorMessage = QString();
1061 }
1062 
1063 } //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's configuration object; loads date from the daemon configuration file. ...
Definition: signondaemon.h:62
SignonIdentityInfo queryInfo(bool &ok, bool queryPassword=true)
const QVariantMap toMap() const
void keepInUse() const
Mark the object as used.
#define SIGNOND_PLUGINS_DIR