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 
266 {
267  ::close(sigFd[0]);
268  ::close(sigFd[1]);
269 
270  if (m_backup) {
271  exit(0);
272  }
273 
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 
312 {
313  int ret = ::write(sigFd[0], &signal, sizeof(signal));
314  Q_UNUSED(ret);
315 }
316 
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 
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 
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) {
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 
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 
604 {
605  return (m_configuration == NULL ?
606  300 :
607  m_configuration->identityTimeout());
608 }
609 
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 
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 
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 
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,
730  internalServerErrStr +
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 
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 
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 
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  * */
995 {
996  TRACE();
997  return 0;
998 }
999 
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
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...
const CAMConfiguration & camConfiguration() const
Definition: signondaemon.h:68
QStringList mechanisms() const
Definition: pluginproxy.h:72
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)
Main singleton and manager object of the credentials database system.
#define BACKUP_DIR_NAME()
bool credentialsSystemOpened() const
For convenience method.
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.
void keepInUse() const
Mark the object as used.
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)
int identityTimeout() const
Returns the number of seconds of inactivity after which identity objects might be automatically delet...
QStringList queryMechanisms(const QString &method)
SignonIdentityInfo queryInfo(bool &ok, bool queryPassword=true)
#define SIGNOND_PLUGINS_DIR