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