|
signon
8.40
|
00001 /* 00002 * This file is part of signon 00003 * 00004 * Copyright (C) 2009-2010 Nokia Corporation. 00005 * 00006 * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com> 00007 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public License 00011 * version 2.1 as published by the Free Software Foundation. 00012 * 00013 * This library is distributed in the hope that it will be useful, but 00014 * WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00021 * 02110-1301 USA 00022 */ 00023 00024 extern "C" { 00025 #include <sys/socket.h> 00026 #include <sys/stat.h> 00027 #include <sys/types.h> 00028 } 00029 00030 #include <QtDebug> 00031 #include <QDir> 00032 #include <QDBusConnection> 00033 #include <QDBusMessage> 00034 #include <QDBusMetaType> 00035 #include <QPluginLoader> 00036 #include <QProcessEnvironment> 00037 #include <QSocketNotifier> 00038 00039 #include "SignOn/misc.h" 00040 00041 #include "signondaemon.h" 00042 #include "signond-common.h" 00043 #include "signontrace.h" 00044 #include "signondaemonadaptor.h" 00045 #include "signonidentity.h" 00046 #include "signonauthsession.h" 00047 #include "accesscontrolmanagerhelper.h" 00048 #include "backupifadaptor.h" 00049 00050 #define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_) do { \ 00051 if (m_pCAMManager && !m_pCAMManager->credentialsSystemOpened()) { \ 00052 sendErrorReply(internalServerErrName, \ 00053 internalServerErrStr + \ 00054 QLatin1String("Could not access Signon " \ 00055 "Database.")); \ 00056 return _ret_arg_; \ 00057 } \ 00058 } while(0) 00059 00060 #define BACKUP_DIR_NAME() \ 00061 (QDir::separator() + QLatin1String("backup")) 00062 00063 using namespace SignOn; 00064 00065 namespace SignonDaemonNS { 00066 00067 /* ---------------------- SignonDaemonConfiguration ---------------------- */ 00068 00069 SignonDaemonConfiguration::SignonDaemonConfiguration(): 00070 m_pluginsDir(QLatin1String(SIGNOND_PLUGINS_DIR)), 00071 m_extensionsDir(QLatin1String(SIGNOND_EXTENSIONS_DIR)), 00072 m_camConfiguration(), 00073 m_daemonTimeout(0), // 0 = no timeout 00074 m_identityTimeout(300),//secs 00075 m_authSessionTimeout(300)//secs 00076 {} 00077 00078 SignonDaemonConfiguration::~SignonDaemonConfiguration() 00079 { 00080 TRACE(); 00081 } 00082 00083 /* 00084 --- Configuration file template --- 00085 00086 [General] 00087 UseSecureStorage=yes 00088 StoragePath=~/.signon/ 00089 ;0 - fatal, 1 - critical(default), 2 - info/debug 00090 LoggingLevel=1 00091 00092 [SecureStorage] 00093 FileSystemName=signonfs 00094 Size=8 00095 FileSystemType=ext2 00096 00097 [ObjectTimeouts] 00098 IdentityTimeout=300 00099 AuthSessionTimeout=300 00100 */ 00101 void SignonDaemonConfiguration::load() 00102 { 00103 //Daemon configuration file 00104 00105 QSettings::setPath(QSettings::NativeFormat, QSettings::SystemScope, 00106 QLatin1String("/etc")); 00107 00108 QSettings settings(QLatin1String("signond")); 00109 00110 int loggingLevel = 00111 settings.value(QLatin1String("LoggingLevel"), 1).toInt(); 00112 setLoggingLevel(loggingLevel); 00113 00114 QString storagePath = 00115 QDir(settings.value(QLatin1String("StoragePath")).toString()).path(); 00116 m_camConfiguration.setStoragePath(storagePath); 00117 00118 // Secure storage 00119 00120 // Support legacy setting "UseSecureStorage" 00121 QString useSecureStorage = 00122 settings.value(QLatin1String("UseSecureStorage")).toString(); 00123 if (useSecureStorage == QLatin1String("yes") || 00124 useSecureStorage == QLatin1String("true")) { 00125 m_camConfiguration.addSetting(QLatin1String("CryptoManager"), 00126 QLatin1String("cryptsetup")); 00127 } 00128 00129 settings.beginGroup(QLatin1String("SecureStorage")); 00130 00131 QVariantMap storageOptions; 00132 foreach (const QString &key, settings.childKeys()) { 00133 m_camConfiguration.addSetting(key, settings.value(key)); 00134 } 00135 00136 settings.endGroup(); 00137 00138 //Timeouts 00139 settings.beginGroup(QLatin1String("ObjectTimeouts")); 00140 00141 bool isOk = false; 00142 uint aux = settings.value(QLatin1String("Identity")).toUInt(&isOk); 00143 if (isOk) 00144 m_identityTimeout = aux; 00145 00146 aux = settings.value(QLatin1String("AuthSession")).toUInt(&isOk); 00147 if (isOk) 00148 m_authSessionTimeout = aux; 00149 00150 settings.endGroup(); 00151 00152 //Environment variables 00153 00154 QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); 00155 int value = 0; 00156 if (environment.contains(QLatin1String("SSO_DAEMON_TIMEOUT"))) { 00157 value = environment.value( 00158 QLatin1String("SSO_DAEMON_TIMEOUT")).toInt(&isOk); 00159 if (value > 0 && isOk) m_daemonTimeout = value; 00160 } 00161 00162 if (environment.contains(QLatin1String("SSO_IDENTITY_TIMEOUT"))) { 00163 value = environment.value( 00164 QLatin1String("SSO_IDENTITY_TIMEOUT")).toInt(&isOk); 00165 if (value > 0 && isOk) m_identityTimeout = value; 00166 } 00167 00168 if (environment.contains(QLatin1String("SSO_AUTHSESSION_TIMEOUT"))) { 00169 value = environment.value( 00170 QLatin1String("SSO_AUTHSESSION_TIMEOUT")).toInt(&isOk); 00171 if (value > 0 && isOk) m_authSessionTimeout = value; 00172 } 00173 00174 if (environment.contains(QLatin1String("SSO_LOGGING_LEVEL"))) { 00175 value = environment.value( 00176 QLatin1String("SSO_LOGGING_LEVEL")).toInt(&isOk); 00177 if (isOk) 00178 setLoggingLevel(value); 00179 } 00180 00181 if (environment.contains(QLatin1String("SSO_STORAGE_PATH"))) { 00182 m_camConfiguration.setStoragePath( 00183 environment.value(QLatin1String("SSO_STORAGE_PATH"))); 00184 } 00185 00186 if (environment.contains(QLatin1String("SSO_PLUGINS_DIR"))) { 00187 m_pluginsDir = environment.value(QLatin1String("SSO_PLUGINS_DIR")); 00188 } 00189 00190 if (environment.contains(QLatin1String("SSO_EXTENSIONS_DIR"))) { 00191 m_extensionsDir = 00192 environment.value(QLatin1String("SSO_EXTENSIONS_DIR")); 00193 } 00194 } 00195 00196 /* ---------------------- SignonDaemon ---------------------- */ 00197 00198 const QString internalServerErrName = SIGNOND_INTERNAL_SERVER_ERR_NAME; 00199 const QString internalServerErrStr = SIGNOND_INTERNAL_SERVER_ERR_STR; 00200 00201 static int sigFd[2]; 00202 00203 SignonDaemon *SignonDaemon::m_instance = NULL; 00204 00205 SignonDaemon::SignonDaemon(QObject *parent) : QObject(parent) 00206 , m_configuration(NULL) 00207 { 00208 // Files created by signond must be unreadable by "other" 00209 umask(S_IROTH | S_IWOTH); 00210 00211 // Register D-Bus meta types 00212 qDBusRegisterMetaType<MethodMap>(); 00213 qDBusRegisterMetaType<MapList>(); 00214 } 00215 00216 SignonDaemon::~SignonDaemon() 00217 { 00218 ::close(sigFd[0]); 00219 ::close(sigFd[1]); 00220 00221 if (m_backup) { 00222 exit(0); 00223 } 00224 00225 SignonAuthSession::stopAllAuthSessions(); 00226 m_storedIdentities.clear(); 00227 m_unstoredIdentities.clear(); 00228 00229 if (m_pCAMManager) { 00230 m_pCAMManager->closeCredentialsSystem(); 00231 delete m_pCAMManager; 00232 } 00233 00234 QDBusConnection sessionConnection = QDBusConnection::sessionBus(); 00235 00236 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH 00237 + QLatin1String("/Backup")); 00238 sessionConnection.unregisterService(SIGNOND_SERVICE 00239 + QLatin1String(".Backup")); 00240 if (m_backup == false) 00241 { 00242 sessionConnection.unregisterObject(SIGNOND_DAEMON_OBJECTPATH); 00243 sessionConnection.unregisterService(SIGNOND_SERVICE); 00244 } 00245 00246 delete m_configuration; 00247 00248 QMetaObject::invokeMethod(QCoreApplication::instance(), 00249 "quit", 00250 Qt::QueuedConnection); 00251 } 00252 00253 void SignonDaemon::setupSignalHandlers() 00254 { 00255 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigFd) != 0) 00256 BLAME() << "Couldn't create HUP socketpair"; 00257 00258 m_sigSn = new QSocketNotifier(sigFd[1], QSocketNotifier::Read, this); 00259 connect(m_sigSn, SIGNAL(activated(int)), 00260 this, SLOT(handleUnixSignal())); 00261 } 00262 00263 void SignonDaemon::signalHandler(int signal) 00264 { 00265 int ret = ::write(sigFd[0], &signal, sizeof(signal)); 00266 Q_UNUSED(ret); 00267 } 00268 00269 void SignonDaemon::handleUnixSignal() 00270 { 00271 m_sigSn->setEnabled(false); 00272 00273 int signal; 00274 int ret = read(sigFd[1], &signal, sizeof(signal)); 00275 Q_UNUSED(ret); 00276 00277 TRACE() << "signal received: " << signal; 00278 00279 switch (signal) { 00280 case SIGHUP: { 00281 TRACE() << "\n\n SIGHUP \n\n"; 00282 //todo restart daemon 00283 deleteLater(); 00284 00285 // reset the m_instance 00286 m_instance = NULL; 00287 QMetaObject::invokeMethod(instance(), 00288 "init", 00289 Qt::QueuedConnection); 00290 break; 00291 } 00292 case SIGTERM: { 00293 TRACE() << "\n\n SIGTERM \n\n"; 00294 //gently stop daemon 00295 deleteLater(); 00296 QMetaObject::invokeMethod(QCoreApplication::instance(), 00297 "quit", 00298 Qt::QueuedConnection); 00299 break; 00300 } 00301 case SIGINT: { 00302 TRACE() << "\n\n SIGINT \n\n"; 00303 //gently stop daemon 00304 deleteLater(); 00305 QMetaObject::invokeMethod(QCoreApplication::instance(), 00306 "quit", 00307 Qt::QueuedConnection); 00308 break; 00309 } 00310 default: break; 00311 } 00312 00313 m_sigSn->setEnabled(true); 00314 } 00315 00316 SignonDaemon *SignonDaemon::instance() 00317 { 00318 if (m_instance != NULL) 00319 return m_instance; 00320 00321 QCoreApplication *app = QCoreApplication::instance(); 00322 00323 if (!app) 00324 qFatal("SignonDaemon requires a QCoreApplication instance to be " 00325 "constructed first"); 00326 00327 TRACE() << "Creating new daemon instance."; 00328 m_instance = new SignonDaemon(app); 00329 return m_instance; 00330 } 00331 00332 void SignonDaemon::init() 00333 { 00334 if (!(m_configuration = new SignonDaemonConfiguration)) 00335 qWarning("SignonDaemon could not create the configuration object."); 00336 00337 m_configuration->load(); 00338 00339 SIGNOND_INITIALIZE_TRACE() 00340 00341 if (getuid() != 0) { 00342 BLAME() << "Failed to SUID root. Secure storage will not be available."; 00343 } 00344 00345 QCoreApplication *app = QCoreApplication::instance(); 00346 if (!app) 00347 qFatal("SignonDaemon requires a QCoreApplication instance to be " 00348 "constructed first"); 00349 00350 setupSignalHandlers(); 00351 m_backup = app->arguments().contains(QLatin1String("-backup")); 00352 m_pCAMManager = 00353 new CredentialsAccessManager(m_configuration->camConfiguration()); 00354 00355 /* backup dbus interface */ 00356 QDBusConnection sessionConnection = QDBusConnection::sessionBus(); 00357 00358 if (!sessionConnection.isConnected()) { 00359 QDBusError err = sessionConnection.lastError(); 00360 TRACE() << "Session connection cannot be established:" << 00361 err.errorString(err.type()); 00362 TRACE() << err.message(); 00363 00364 qFatal("SignonDaemon requires session bus to start working"); 00365 } 00366 00367 QDBusConnection::RegisterOptions registerSessionOptions = 00368 QDBusConnection::ExportAdaptors; 00369 00370 (void)new BackupIfAdaptor(this); 00371 00372 if (!sessionConnection.registerObject(SIGNOND_DAEMON_OBJECTPATH 00373 + QLatin1String("/Backup"), 00374 this, registerSessionOptions)) { 00375 TRACE() << "Object cannot be registered"; 00376 00377 qFatal("SignonDaemon requires to register backup object"); 00378 } 00379 00380 if (!sessionConnection.registerService(SIGNOND_SERVICE + 00381 QLatin1String(".Backup"))) { 00382 QDBusError err = sessionConnection.lastError(); 00383 TRACE() << "Service cannot be registered: " << 00384 err.errorString(err.type()); 00385 00386 qFatal("SignonDaemon requires to register backup service"); 00387 } 00388 00389 if (m_backup) { 00390 TRACE() << "Signond initialized in backup mode."; 00391 //skip rest of initialization in backup mode 00392 return; 00393 } 00394 00395 /* DBus Service init */ 00396 QDBusConnection connection = SIGNOND_BUS; 00397 00398 if (!connection.isConnected()) { 00399 QDBusError err = connection.lastError(); 00400 TRACE() << "Connection cannot be established:" << 00401 err.errorString(err.type()); 00402 TRACE() << err.message(); 00403 00404 qFatal("SignonDaemon requires DBus to start working"); 00405 } 00406 00407 QDBusConnection::RegisterOptions registerOptions = 00408 QDBusConnection::ExportAllContents; 00409 00410 (void)new SignonDaemonAdaptor(this); 00411 registerOptions = QDBusConnection::ExportAdaptors; 00412 00413 if (!connection.registerObject(SIGNOND_DAEMON_OBJECTPATH, 00414 this, registerOptions)) { 00415 TRACE() << "Object cannot be registered"; 00416 00417 qFatal("SignonDaemon requires to register daemon's object"); 00418 } 00419 00420 if (!connection.registerService(SIGNOND_SERVICE)) { 00421 QDBusError err = connection.lastError(); 00422 TRACE() << "Service cannot be registered: " << 00423 err.errorString(err.type()); 00424 00425 qFatal("SignonDaemon requires to register daemon's service"); 00426 } 00427 00428 // handle D-Bus disconnection 00429 connection.connect(QString(), 00430 QLatin1String("/org/freedesktop/DBus/Local"), 00431 QLatin1String("org.freedesktop.DBus.Local"), 00432 QLatin1String("Disconnected"), 00433 this, SLOT(onDisconnected())); 00434 00435 initExtensions(); 00436 00437 if (!initStorage()) 00438 BLAME() << "Signond: Cannot initialize credentials storage."; 00439 00440 Q_UNUSED(AuthCoreCache::instance(this)); 00441 00442 if (m_configuration->daemonTimeout() > 0) { 00443 SignonDisposable::invokeOnIdle(m_configuration->daemonTimeout(), 00444 this, SLOT(deleteLater())); 00445 } 00446 00447 TRACE() << "Signond SUCCESSFULLY initialized."; 00448 } 00449 00450 void SignonDaemon::initExtensions() 00451 { 00452 /* Scan the directory containing signond extensions and attempt loading 00453 * all of them. 00454 */ 00455 QDir dir(m_configuration->extensionsDir()); 00456 QStringList filters(QLatin1String("lib*.so")); 00457 QStringList extensionList = dir.entryList(filters, QDir::Files); 00458 foreach(QString filename, extensionList) 00459 initExtension(dir.filePath(filename)); 00460 } 00461 00462 void SignonDaemon::initExtension(const QString &filePath) 00463 { 00464 TRACE() << "Loading plugin " << filePath; 00465 00466 QPluginLoader pluginLoader(filePath); 00467 QObject *plugin = pluginLoader.instance(); 00468 if (plugin == 0) { 00469 qWarning() << "Couldn't load plugin:" << pluginLoader.errorString(); 00470 return; 00471 } 00472 00473 /* Check whether the extension implements some useful objects; if not, 00474 * unload it. */ 00475 bool extensionInUse = false; 00476 if (m_pCAMManager->initExtension(plugin)) 00477 extensionInUse = true; 00478 00479 if (!extensionInUse) { 00480 pluginLoader.unload(); 00481 } 00482 } 00483 00484 bool SignonDaemon::initStorage() 00485 { 00486 if (!m_pCAMManager->credentialsSystemOpened()) { 00487 m_pCAMManager->finalize(); 00488 00489 if (!m_pCAMManager->init()) { 00490 BLAME() << "CAM initialization failed"; 00491 return false; 00492 } 00493 00494 // If encryption is in use this will just open the metadata DB 00495 if (!m_pCAMManager->openCredentialsSystem()) { 00496 qCritical("Signond: Cannot open CAM credentials system..."); 00497 return false; 00498 } 00499 } else { 00500 TRACE() << "Secure storage already initialized..."; 00501 return false; 00502 } 00503 00504 return true; 00505 } 00506 00507 void SignonDaemon::identityStored(SignonIdentity *identity) 00508 { 00509 if (m_unstoredIdentities.contains(identity->objectName())) { 00510 m_unstoredIdentities.remove(identity->objectName()); 00511 m_storedIdentities.insert(identity->id(), identity); 00512 } 00513 } 00514 00515 void SignonDaemon::registerNewIdentity(QDBusObjectPath &objectPath) 00516 { 00517 TRACE() << "Registering new identity:"; 00518 00519 SignonIdentity *identity = 00520 SignonIdentity::createIdentity(SIGNOND_NEW_IDENTITY, this); 00521 00522 if (identity == NULL) { 00523 sendErrorReply(internalServerErrName, 00524 internalServerErrStr + 00525 QLatin1String("Could not create remote Identity " 00526 "object.")); 00527 return; 00528 } 00529 00530 m_unstoredIdentities.insert(identity->objectName(), identity); 00531 00532 objectPath = QDBusObjectPath(identity->objectName()); 00533 } 00534 00535 int SignonDaemon::identityTimeout() const 00536 { 00537 return (m_configuration == NULL ? 00538 300 : 00539 m_configuration->identityTimeout()); 00540 } 00541 00542 int SignonDaemon::authSessionTimeout() const 00543 { 00544 return (m_configuration == NULL ? 00545 300 : 00546 m_configuration->authSessionTimeout()); 00547 } 00548 00549 void SignonDaemon::getIdentity(const quint32 id, 00550 QDBusObjectPath &objectPath, 00551 QVariantMap &identityData) 00552 { 00553 SIGNON_RETURN_IF_CAM_UNAVAILABLE(); 00554 00555 TRACE() << "Registering identity:" << id; 00556 00557 //1st check if the existing identity is in cache 00558 SignonIdentity *identity = m_storedIdentities.value(id, NULL); 00559 00560 //if not create it 00561 if (identity == NULL) 00562 identity = SignonIdentity::createIdentity(id, this); 00563 00564 if (identity == NULL) 00565 { 00566 sendErrorReply(internalServerErrName, 00567 internalServerErrStr + 00568 QLatin1String("Could not create remote Identity " 00569 "object.")); 00570 return; 00571 } 00572 00573 bool ok; 00574 SignonIdentityInfo info = identity->queryInfo(ok, false); 00575 00576 if (info.isNew()) 00577 { 00578 sendErrorReply(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME, 00579 SIGNOND_IDENTITY_NOT_FOUND_ERR_STR); 00580 return; 00581 } 00582 00583 //cache the identity as stored 00584 m_storedIdentities.insert(identity->id(), identity); 00585 identity->keepInUse(); 00586 00587 identityData = info.toMap(); 00588 00589 TRACE() << "DONE REGISTERING IDENTITY"; 00590 objectPath = QDBusObjectPath(identity->objectName()); 00591 } 00592 00593 QStringList SignonDaemon::queryMethods() 00594 { 00595 QDir pluginsDir(m_configuration->pluginsDir()); 00596 //TODO: in the future remove the sym links comment 00597 QStringList fileNames = pluginsDir.entryList( 00598 QStringList() << QLatin1String("*.so*"), 00599 QDir::Files | QDir::NoDotAndDotDot); 00600 00601 QStringList ret; 00602 QString fileName; 00603 foreach (fileName, fileNames) { 00604 if (fileName.startsWith(QLatin1String("lib"))) { 00605 fileName = 00606 fileName.mid(3, fileName.indexOf(QLatin1String("plugin")) -3); 00607 if ((fileName.length() > 0) && !ret.contains(fileName)) 00608 ret << fileName; 00609 } 00610 } 00611 00612 return ret; 00613 } 00614 00615 QStringList SignonDaemon::queryMechanisms(const QString &method) 00616 { 00617 TRACE() << "\n\n\n Querying mechanisms\n\n"; 00618 00619 QStringList mechs = SignonSessionCore::loadedPluginMethods(method); 00620 00621 if (mechs.size()) 00622 return mechs; 00623 00624 PluginProxy *plugin = PluginProxy::createNewPluginProxy(method); 00625 00626 if (!plugin) { 00627 TRACE() << "Could not load plugin of type: " << method; 00628 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME, 00629 SIGNOND_METHOD_NOT_KNOWN_ERR_STR + 00630 QString::fromLatin1("Method %1 is not known or could " 00631 "not load specific configuration."). 00632 arg(method)); 00633 return QStringList(); 00634 } 00635 00636 mechs = plugin->mechanisms(); 00637 delete plugin; 00638 00639 return mechs; 00640 } 00641 00642 QList<QVariantMap> SignonDaemon::queryIdentities(const QVariantMap &filter) 00643 { 00644 SIGNON_RETURN_IF_CAM_UNAVAILABLE(QList<QVariantMap>()); 00645 00646 TRACE() << "Querying identities"; 00647 00648 CredentialsDB *db = m_pCAMManager->credentialsDB(); 00649 if (!db) { 00650 qCritical() << Q_FUNC_INFO << m_pCAMManager->lastError(); 00651 return QList<QVariantMap>(); 00652 } 00653 00654 QMap<QString, QString> filterLocal; 00655 QMapIterator<QString, QVariant> it(filter); 00656 while (it.hasNext()) { 00657 it.next(); 00658 filterLocal.insert(it.key(), it.value().toString()); 00659 } 00660 00661 QList<SignonIdentityInfo> credentials = db->credentials(filterLocal); 00662 00663 if (db->errorOccurred()) { 00664 sendErrorReply(internalServerErrName, 00665 internalServerErrStr + 00666 QLatin1String("Querying database error occurred.")); 00667 return QList<QVariantMap>(); 00668 } 00669 00670 QList<QVariantMap> mapList; 00671 foreach (SignonIdentityInfo info, credentials) { 00672 mapList.append(info.toMap()); 00673 } 00674 return mapList; 00675 } 00676 00677 bool SignonDaemon::clear() 00678 { 00679 SIGNON_RETURN_IF_CAM_UNAVAILABLE(false); 00680 00681 TRACE() << "\n\n\n Clearing DB\n\n"; 00682 CredentialsDB *db = m_pCAMManager->credentialsDB(); 00683 if (!db) { 00684 qCritical() << Q_FUNC_INFO << m_pCAMManager->lastError(); 00685 return false; 00686 } 00687 00688 if (!db->clear()) { 00689 sendErrorReply(SIGNOND_INTERNAL_SERVER_ERR_NAME, 00690 SIGNOND_INTERNAL_SERVER_ERR_STR + 00691 QLatin1String("Database error occurred.")); 00692 return false; 00693 } 00694 return true; 00695 } 00696 00697 QString SignonDaemon::getAuthSessionObjectPath(const quint32 id, 00698 const QString type) 00699 { 00700 bool supportsAuthMethod = false; 00701 pid_t ownerPid = AccessControlManagerHelper::pidOfPeer(*this); 00702 QString objectPath = 00703 SignonAuthSession::getAuthSessionObjectPath(id, type, this, 00704 supportsAuthMethod, 00705 ownerPid); 00706 if (objectPath.isEmpty() && !supportsAuthMethod) { 00707 sendErrorReply(SIGNOND_METHOD_NOT_KNOWN_ERR_NAME, 00708 SIGNOND_METHOD_NOT_KNOWN_ERR_STR); 00709 return QString(); 00710 } 00711 return objectPath; 00712 } 00713 00714 void SignonDaemon::eraseBackupDir() const 00715 { 00716 const CAMConfiguration config = m_configuration->camConfiguration(); 00717 QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME(); 00718 00719 QDir target(backupRoot); 00720 if (!target.exists()) return; 00721 00722 QStringList targetEntries = target.entryList(QDir::Files); 00723 foreach (QString entry, targetEntries) { 00724 target.remove(entry); 00725 } 00726 00727 target.rmdir(backupRoot); 00728 } 00729 00730 bool SignonDaemon::copyToBackupDir(const QStringList &fileNames) const 00731 { 00732 const CAMConfiguration config = m_configuration->camConfiguration(); 00733 QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME(); 00734 00735 QDir target(backupRoot); 00736 if (!target.exists() && !target.mkpath(backupRoot)) { 00737 qCritical() << "Cannot create target directory"; 00738 return false; 00739 } 00740 00741 setUserOwnership(backupRoot); 00742 00743 /* Now copy the files to be backed up */ 00744 bool ok = true; 00745 foreach (QString fileName, fileNames) { 00746 /* Remove the target file, if it exists */ 00747 if (target.exists(fileName)) 00748 target.remove(fileName); 00749 00750 /* Copy the source into the target directory */ 00751 QString source = config.m_storagePath + QDir::separator() + fileName; 00752 if (!QFile::exists(source)) continue; 00753 00754 QString destination = backupRoot + QDir::separator() + fileName; 00755 ok = QFile::copy(source, destination); 00756 if (!ok) { 00757 BLAME() << "Copying" << source << "to" << destination << "failed"; 00758 break; 00759 } 00760 00761 setUserOwnership(destination); 00762 } 00763 00764 return ok; 00765 } 00766 00767 bool SignonDaemon::copyFromBackupDir(const QStringList &fileNames) const 00768 { 00769 const CAMConfiguration config = m_configuration->camConfiguration(); 00770 QString backupRoot = config.m_storagePath + BACKUP_DIR_NAME(); 00771 00772 QDir sourceDir(backupRoot); 00773 if (!sourceDir.exists()) { 00774 TRACE() << "Backup directory does not exist!"; 00775 } 00776 00777 if (!sourceDir.exists(config.m_dbName)) { 00778 TRACE() << "Backup does not contain DB:" << config.m_dbName; 00779 } 00780 00781 /* Now restore the files from the backup */ 00782 bool ok = true; 00783 QDir target(config.m_storagePath); 00784 QStringList movedFiles, copiedFiles; 00785 foreach (QString fileName, fileNames) { 00786 /* Remove the target file, if it exists */ 00787 if (target.exists(fileName)) { 00788 if (target.rename(fileName, fileName + QLatin1String(".bak"))) 00789 movedFiles += fileName; 00790 } 00791 00792 /* Copy the source into the target directory */ 00793 QString source = backupRoot + QDir::separator() + fileName; 00794 if (!QFile::exists(source)) { 00795 TRACE() << "Ignoring file not present in backup:" << source; 00796 continue; 00797 } 00798 00799 QString destination = 00800 config.m_storagePath + QDir::separator() + fileName; 00801 00802 ok = QFile::copy(source, destination); 00803 if (ok) { 00804 copiedFiles << fileName; 00805 } else { 00806 qWarning() << "Copy failed for:" << source; 00807 break; 00808 } 00809 } 00810 00811 if (!ok) { 00812 qWarning() << "Restore failed, recovering previous DB"; 00813 00814 foreach (QString fileName, copiedFiles) { 00815 target.remove(fileName); 00816 } 00817 00818 foreach (QString fileName, movedFiles) { 00819 if (!target.rename(fileName + QLatin1String(".bak"), fileName)) { 00820 qCritical() << "Could not recover:" << fileName; 00821 } 00822 } 00823 } else { 00824 /* delete ".bak" files */ 00825 foreach (QString fileName, movedFiles) { 00826 target.remove(fileName + QLatin1String(".bak")); 00827 } 00828 00829 } 00830 return ok; 00831 } 00832 00833 bool SignonDaemon::createStorageFileTree(const QStringList &backupFiles) const 00834 { 00835 QString storageDirPath = m_configuration->camConfiguration().m_storagePath; 00836 QDir storageDir(storageDirPath); 00837 00838 if (!storageDir.exists()) { 00839 if (!storageDir.mkpath(storageDirPath)) { 00840 qCritical() << "Could not create storage dir for backup."; 00841 return false; 00842 } 00843 } 00844 00845 foreach (QString fileName, backupFiles) { 00846 if (storageDir.exists(fileName)) continue; 00847 00848 QString filePath = storageDir.path() + QDir::separator() + fileName; 00849 QFile file(filePath); 00850 if (!file.open(QIODevice::WriteOnly)) { 00851 qCritical() << "Failed to create empty file for backup:" << filePath; 00852 return false; 00853 } else { 00854 file.close(); 00855 } 00856 } 00857 00858 return true; 00859 } 00860 00861 uchar SignonDaemon::backupStarts() 00862 { 00863 TRACE() << "backup"; 00864 if (!m_backup && m_pCAMManager->credentialsSystemOpened()) 00865 { 00866 m_pCAMManager->closeCredentialsSystem(); 00867 if (m_pCAMManager->credentialsSystemOpened()) 00868 { 00869 qCritical() << "Cannot close credentials database"; 00870 return 2; 00871 } 00872 } 00873 00874 const CAMConfiguration config = m_configuration->camConfiguration(); 00875 00876 /* do backup copy: prepare the list of files to be backed up */ 00877 QStringList backupFiles; 00878 backupFiles << config.m_dbName; 00879 backupFiles << m_pCAMManager->backupFiles(); 00880 00881 /* make sure that all the backup files and storage directory exist: 00882 create storage dir and empty files if not so, as backup/restore 00883 operations must be consistent */ 00884 if (!createStorageFileTree(backupFiles)) { 00885 qCritical() << "Cannot create backup file tree."; 00886 return 2; 00887 } 00888 00889 /* perform the copy */ 00890 eraseBackupDir(); 00891 if (!copyToBackupDir(backupFiles)) { 00892 qCritical() << "Cannot copy database"; 00893 if (!m_backup) 00894 m_pCAMManager->openCredentialsSystem(); 00895 return 2; 00896 } 00897 00898 if (!m_backup) 00899 { 00900 //mount file system back 00901 if (!m_pCAMManager->openCredentialsSystem()) { 00902 qCritical() << "Cannot reopen database"; 00903 } 00904 } 00905 return 0; 00906 } 00907 00908 uchar SignonDaemon::backupFinished() 00909 { 00910 TRACE() << "close"; 00911 00912 eraseBackupDir(); 00913 00914 if (m_backup) 00915 { 00916 //close daemon 00917 TRACE() << "close daemon"; 00918 this->deleteLater(); 00919 } 00920 00921 return 0; 00922 } 00923 00924 /* 00925 * Does nothing but start-on-demand 00926 * */ 00927 uchar SignonDaemon::restoreStarts() 00928 { 00929 TRACE(); 00930 return 0; 00931 } 00932 00933 uchar SignonDaemon::restoreFinished() 00934 { 00935 TRACE() << "restore"; 00936 //restore requested 00937 if (m_pCAMManager->credentialsSystemOpened()) 00938 { 00939 //umount file system 00940 if (!m_pCAMManager->closeCredentialsSystem()) 00941 { 00942 qCritical() << "database cannot be closed"; 00943 return 2; 00944 } 00945 } 00946 00947 const CAMConfiguration config = m_configuration->camConfiguration(); 00948 00949 QStringList backupFiles; 00950 backupFiles << config.m_dbName; 00951 backupFiles << m_pCAMManager->backupFiles(); 00952 00953 /* perform the copy */ 00954 if (!copyFromBackupDir(backupFiles)) { 00955 qCritical() << "Cannot copy database"; 00956 m_pCAMManager->openCredentialsSystem(); 00957 return 2; 00958 } 00959 00960 eraseBackupDir(); 00961 00962 //TODO check database integrity 00963 if (!m_backup) 00964 { 00965 //mount file system back 00966 if (!m_pCAMManager->openCredentialsSystem()) 00967 return 2; 00968 } 00969 00970 return 0; 00971 } 00972 00973 void SignonDaemon::onDisconnected() 00974 { 00975 TRACE() << "Disconnected from session bus: exiting"; 00976 this->deleteLater(); 00977 QMetaObject::invokeMethod(QCoreApplication::instance(), 00978 "quit", 00979 Qt::QueuedConnection); 00980 } 00981 00982 } //namespace SignonDaemonNS