diff --git a/sddmauthhelper.cpp b/sddmauthhelper.cpp index c8682ee..502a94c 100644 --- a/sddmauthhelper.cpp +++ b/sddmauthhelper.cpp @@ -1,398 +1,399 @@ /* Copyright 2019 Filip Fila Copyright 2013 by Reza Fatahilah Shah Copyright 2011, 2012 David Edmundson This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "sddmauthhelper.h" +#include "src/config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static QSharedPointer openConfig(const QString &filePath) { QFile file(filePath); if(!file.exists()) { // If we are creating the config file, ensure it is world-readable: if // we don't do that, KConfig will create a file which is only readable // by root file.open(QIODevice::WriteOnly); file.close(); file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther); } return QSharedPointer(new KConfig(file.fileName(), KConfig::SimpleConfig)); } void SddmAuthHelper::copyFile(const QString &source, const QString &destination) { KUser sddmUser(QStringLiteral("sddm")); if (QFile::exists(destination)) { QFile::remove(destination); } QFile::copy(source, destination); const char* destinationConverted = destination.toLocal8Bit().data(); if (chown(destinationConverted, sddmUser.userId().nativeId(), sddmUser.groupId().nativeId())) { return; } } ActionReply SddmAuthHelper::sync(const QVariantMap &args) { // initial check for sddm user; abort if user not present // we have to check with QString and isEmpty() instead of QDir and exists() because // QDir returns "." and true for exists() in the case of a non-existent user; QString sddmHomeDirPath = KUser("sddm").homeDir(); if (sddmHomeDirPath.isEmpty()) { qDebug() << "Cannot proceed, user 'sddm' does not exist. Please check your SDDM install."; return ActionReply::HelperErrorReply(); } // create SDDM config directory if it does not exist QDir sddmConfigLocation(sddmHomeDirPath + QStringLiteral("/.config")); if (!sddmConfigLocation.exists()) { QDir().mkpath(sddmConfigLocation.path()); } // copy fontconfig (font, font rendering) if (!args[QStringLiteral("fontconfig")].isNull()) { QDir fontconfigSource(args[QStringLiteral("fontconfig")].toString()); QStringList sourceFileEntries = fontconfigSource.entryList (QDir::Files); QStringList sourceDirEntries = fontconfigSource.entryList (QDir::AllDirs); QDir fontconfigDestination(sddmConfigLocation.path() + QStringLiteral("/fontconfig")); if (!fontconfigDestination.exists()) { QDir().mkpath(fontconfigDestination.path()); } if (sourceDirEntries.count() != 0) { for (int i = 0; i sddmConfig = openConfig(args[QStringLiteral("kde_settings.conf")].toString()); QSharedPointer sddmOldConfig = openConfig(args[QStringLiteral("sddm.conf")].toString()); QMap::const_iterator iterator; for (iterator = args.constBegin() ; iterator != args.constEnd() ; ++iterator) { if (iterator.key() == QLatin1String("kde_settings.conf")) continue; QStringList configFields = iterator.key().split(QLatin1Char('/')); if (configFields.size() != 3) { continue; } QSharedPointer config; QString fileName = configFields[0]; QString groupName = configFields[1]; QString keyName = configFields[2]; if (fileName == QLatin1String("kde_settings.conf") && iterator.value().isValid()) { sddmConfig->group(groupName).writeEntry(keyName, iterator.value()); sddmOldConfig->group(groupName).deleteEntry(keyName); } } sddmOldConfig->sync(); sddmConfig->sync(); return ActionReply::SuccessReply(); } ActionReply SddmAuthHelper::reset(const QVariantMap &args) { // initial check for sddm user; abort if user not present // we have to check with QString and isEmpty() instead of QDir and exists() because // QDir returns "." and true for exists() in the case of a non-existent user; QString sddmHomeDirPath = KUser("sddm").homeDir(); if (sddmHomeDirPath.isEmpty()) { qDebug() << "Cannot proceed, user 'sddm' does not exist. Please check your SDDM install."; return ActionReply::HelperErrorReply(); } QDir sddmConfigLocation(sddmHomeDirPath + QStringLiteral("/.config")); QDir fontconfigDir(args[QStringLiteral("sddmUserConfig")].toString() + QStringLiteral("/fontconfig")); fontconfigDir.removeRecursively(); QFile::remove(sddmConfigLocation.path() + QStringLiteral("/kdeglobals")); QFile::remove(sddmConfigLocation.path() + QStringLiteral("/plasmarc")); // remove cursor theme, NumLock preference, and scaling DPI from config file ActionReply reply = ActionReply::HelperErrorReply(); QSharedPointer sddmConfig = openConfig(args[QStringLiteral("kde_settings.conf")].toString()); QSharedPointer sddmOldConfig = openConfig(args[QStringLiteral("sddm.conf")].toString()); QMap::const_iterator iterator; for (iterator = args.constBegin() ; iterator != args.constEnd() ; ++iterator) { if (iterator.key() == QLatin1String("kde_settings.conf")) continue; QStringList configFields = iterator.key().split(QLatin1Char('/')); if (configFields.size() != 3) { continue; } QSharedPointer config; QString fileName = configFields[0]; QString groupName = configFields[1]; QString keyName = configFields[2]; if (fileName == QLatin1String("kde_settings.conf")) { sddmConfig->group(groupName).deleteEntry(keyName); sddmOldConfig->group(groupName).deleteEntry(keyName); } } sddmOldConfig->sync(); sddmConfig->sync(); return ActionReply::SuccessReply(); } ActionReply SddmAuthHelper::save(const QVariantMap &args) { ActionReply reply = ActionReply::HelperErrorReply(); - QSharedPointer sddmConfig = openConfig(args[QStringLiteral("kde_settings.conf")].toString()); - QSharedPointer sddmOldConfig = openConfig(args[QStringLiteral("sddm.conf")].toString()); + QSharedPointer sddmConfig = openConfig(QString {QLatin1String(SDDM_CONFIG_DIR "/") + QStringLiteral("kde_settings.conf")}); + QSharedPointer sddmOldConfig = openConfig(QLatin1String(SDDM_CONFIG_FILE)); QSharedPointer themeConfig; QString themeConfigFile = args[QStringLiteral("theme.conf.user")].toString(); if (!themeConfigFile.isEmpty()) { themeConfig = openConfig(themeConfigFile); } QMap::const_iterator iterator; for (iterator = args.constBegin() ; iterator != args.constEnd() ; ++iterator) { if (iterator.key() == QLatin1String("kde_settings.conf") || iterator.key() == QLatin1String("theme.conf.user")) continue; QStringList configFields = iterator.key().split(QLatin1Char('/')); if (configFields.size() != 3) { continue; } QSharedPointer config; QString fileName = configFields[0]; QString groupName = configFields[1]; QString keyName = configFields[2]; // if there is an identical keyName in "sddm.conf" we want to delete it so SDDM doesn't read from the old file // hierarchically SDDM prefers "etc/sddm.conf" to "/etc/sddm.conf.d/some_file.conf" if (fileName == QLatin1String("kde_settings.conf")) { sddmConfig->group(groupName).writeEntry(keyName, iterator.value()); sddmOldConfig->group(groupName).deleteEntry(keyName); } else if (fileName == QLatin1String("theme.conf.user") && !themeConfig.isNull()) { QFileInfo themeConfigFileInfo(themeConfigFile); QDir configRootDirectory = themeConfigFileInfo.absoluteDir(); if (keyName == QLatin1String("background")) { QFileInfo newBackgroundFileInfo(iterator.value().toString()); QString previousBackground = themeConfig->group(groupName).readEntry(keyName); bool backgroundChanged = newBackgroundFileInfo.fileName() != previousBackground; if (backgroundChanged) { if (!previousBackground.isEmpty()) { QString previousBackgroundPath = configRootDirectory.filePath(previousBackground); if (QFile::remove(previousBackgroundPath)) { qDebug() << "Removed previous background " << previousBackgroundPath; } } if (newBackgroundFileInfo.exists()) { QString newBackgroundPath = configRootDirectory.filePath(newBackgroundFileInfo.fileName()); qDebug() << "Copying background from " << newBackgroundFileInfo.absoluteFilePath() << " to " << newBackgroundPath; if (QFile::copy(newBackgroundFileInfo.absoluteFilePath(), newBackgroundPath)) { QFile::setPermissions(newBackgroundPath, QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther); themeConfig->group(groupName).writeEntry(keyName, newBackgroundFileInfo.fileName()); } } else { themeConfig->group(groupName).deleteEntry(keyName); } } } else { themeConfig->group(groupName).writeEntry(keyName, iterator.value()); } } } sddmOldConfig->sync(); sddmConfig->sync(); if (!themeConfig.isNull()) themeConfig->sync(); return ActionReply::SuccessReply(); } ActionReply SddmAuthHelper::installtheme(const QVariantMap &args) { const QString filePath = args[QStringLiteral("filePath")].toString(); if (filePath.isEmpty()) { return ActionReply::HelperErrorReply(); } const QString themesBaseDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("sddm/themes"), QStandardPaths::LocateDirectory); QDir dir(themesBaseDir); if (!dir.exists()) { return ActionReply::HelperErrorReply(); } qDebug() << "Installing " << filePath << " into " << themesBaseDir; if (!QFile::exists(filePath)) { return ActionReply::HelperErrorReply(); } QMimeDatabase db; QMimeType mimeType = db.mimeTypeForFile(filePath); qWarning() << "Postinstallation: uncompress the file"; QScopedPointer archive; //there must be a better way to do this? If not, make a static bool KZip::supportsMimeType(const QMimeType &type); ? //or even a factory class in KArchive if (mimeType.inherits(QStringLiteral("application/zip"))) { archive.reset(new KZip(filePath)); } else if (mimeType.inherits(QStringLiteral("application/tar")) || mimeType.inherits(QStringLiteral("application/x-gzip")) || mimeType.inherits(QStringLiteral("application/x-bzip")) || mimeType.inherits(QStringLiteral("application/x-lzma")) || mimeType.inherits(QStringLiteral("application/x-xz")) || mimeType.inherits(QStringLiteral("application/x-bzip-compressed-tar")) || mimeType.inherits(QStringLiteral("application/x-compressed-tar"))) { archive.reset(new KTar(filePath)); } else { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Invalid theme package")); return e; } if (!archive->open(QIODevice::ReadOnly)) { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Could not open file")); return e; } auto directory = archive->directory(); QStringList installedPaths; //some basic validation //the top level should only have folders, and those folders should contain a valid metadata.desktop file //if we get anything else, abort everything before copying for(const QString &name: directory->entries()) { auto entry = directory->entry(name); if (!entry->isDirectory()) { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Invalid theme package")); return e; } auto subDirectory = static_cast(entry); auto metadataFile = subDirectory->file(QStringLiteral("metadata.desktop")); if(!metadataFile || !metadataFile->data().contains("[SddmGreeterTheme]")) { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Invalid theme package")); return e; } installedPaths.append(themesBaseDir + QLatin1Char('/') + name); } if (!directory->copyTo(themesBaseDir)) { auto e = ActionReply::HelperErrorReply(); e.setErrorDescription(i18n("Could not decompress archive")); return e; } auto rc = ActionReply::SuccessReply(); rc.addData(QStringLiteral("installedPaths"), installedPaths); return rc; } ActionReply SddmAuthHelper::uninstalltheme(const QVariantMap &args) { const QString themePath = args[QStringLiteral("filePath")].toString(); const QString themesBaseDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("sddm/themes"), QStandardPaths::LocateDirectory); QDir dir(themePath); if (!dir.exists()) { return ActionReply::HelperErrorReply(); } //validate the themePath is directly inside the themesBaseDir QDir baseDir(themesBaseDir); if(baseDir.absoluteFilePath(dir.dirName()) != dir.absolutePath()) { return ActionReply::HelperErrorReply(); } if (!dir.removeRecursively()) { return ActionReply::HelperErrorReply(); } return ActionReply::SuccessReply(); } KAUTH_HELPER_MAIN("org.kde.kcontrol.kcmsddm", SddmAuthHelper) #include "moc_sddmauthhelper.cpp" diff --git a/src/sddmkcm.cpp b/src/sddmkcm.cpp index 3adaff3..8fefb19 100644 --- a/src/sddmkcm.cpp +++ b/src/sddmkcm.cpp @@ -1,130 +1,124 @@ /* Copyright 2013 by Reza Fatahilah Shah This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "advancedconfig.h" #include "config.h" #include "sddmkcm.h" #include "themeconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(SddmKcmFactory, registerPlugin();) SddmKcm::SddmKcm(QWidget *parent, const QVariantList &args) : KCModule(parent, args) { KAboutData* aboutData = new KAboutData(QStringLiteral("kcmsddm"), i18n("SDDM KDE Config"), QLatin1String(PROJECT_VERSION)); aboutData->setShortDescription(i18n("Login screen using the SDDM")); aboutData->setLicense(KAboutLicense::GPL_V2); aboutData->setHomepage(QStringLiteral("https://projects.kde.org/projects/kde/workspace/sddm-kcm")); aboutData->addAuthor(QStringLiteral("Reza Fatahilah Shah"), i18n("Author"), QStringLiteral("rshah0385@kireihana.com")); aboutData->addAuthor(QStringLiteral("David Edmundson"), i18n("Author"), QStringLiteral("davidedmundson@kde.org")); setAboutData(aboutData); setNeedsAuthorization(true); mSddmConfig = KSharedConfig::openConfig(QStringLiteral(SDDM_CONFIG_FILE), KConfig::CascadeConfig); - mSddmOldConfig = KSharedConfig::openConfig(QStringLiteral("sddm.conf"), KConfig::CascadeConfig); - // This does not listen for new config files in the directory. QStringList configFiles = QDir(QLatin1String(SDDM_CONFIG_DIR)).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::LocaleAware), systemConfigFiles = QDir(QLatin1String(SDDM_SYSTEM_CONFIG_DIR)).entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::LocaleAware); // QStringBuilder keeps dangling references, so force return of QString (QTBUG-47066) std::transform(systemConfigFiles.begin(), systemConfigFiles.end(), systemConfigFiles.begin(), [](const QString &filename) -> QString { return QStringLiteral(SDDM_SYSTEM_CONFIG_DIR "/") + filename; }); std::transform(configFiles.begin(), configFiles.end(), configFiles.begin(), [](const QString &filename) -> QString { return QStringLiteral(SDDM_CONFIG_DIR "/") + filename; }); mSddmConfig->addConfigSources(systemConfigFiles + configFiles); - mSddmOldConfig->addConfigSources(systemConfigFiles + configFiles); prepareUi(); } SddmKcm::~SddmKcm() { } void SddmKcm::save() { QVariantMap args; - args[QStringLiteral("kde_settings.conf")] = QString {QLatin1String(SDDM_CONFIG_DIR "/") + QStringLiteral("kde_settings.conf")}; - args[QStringLiteral("sddm.conf")] = QLatin1String(SDDM_CONFIG_FILE); - if (!mThemeConfig->themeConfigPath().isEmpty()) { args[QStringLiteral("theme.conf.user")] = QString(mThemeConfig->themeConfigPath() + QLatin1String(".user")); } qDebug() << "Ovr:" << args[QStringLiteral("theme.conf.user")].toString(); args.unite(mThemeConfig->save()); args.unite(mAdvancedConfig->save()); KAuth::Action saveAction = authAction(); saveAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmsddm")); saveAction.setArguments(args); auto job = saveAction.execute(); job->exec(); if (job->error()){ qDebug() << "Save Failed"; qDebug() << job->errorString(); qDebug() << job->errorText(); } else { changed(false); qDebug() << "Option saved"; } } void SddmKcm::prepareUi() { QHBoxLayout* layout = new QHBoxLayout(this); QTabWidget* tabHolder = new QTabWidget(this); layout->addWidget(tabHolder); mThemeConfig = new ThemeConfig(mSddmConfig, this); connect(mThemeConfig, SIGNAL(changed(bool)), SIGNAL(changed(bool))); tabHolder->addTab(mThemeConfig, i18n("Theme")); mAdvancedConfig = new AdvancedConfig(mSddmConfig, this); connect(mAdvancedConfig, SIGNAL(changed(bool)), SIGNAL(changed(bool))); tabHolder->addTab(mAdvancedConfig, i18n("Advanced")); } #include "sddmkcm.moc" diff --git a/src/sddmkcm.h b/src/sddmkcm.h index cc76252..1e9486a 100644 --- a/src/sddmkcm.h +++ b/src/sddmkcm.h @@ -1,46 +1,45 @@ /* Copyright 2013 by Reza Fatahilah Shah This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef SDDMKCM_H #define SDDMKCM_H #include #include class ThemeConfig; class AdvancedConfig; class SddmKcm : public KCModule { Q_OBJECT public: explicit SddmKcm(QWidget *parent, const QVariantList &args); ~SddmKcm() Q_DECL_OVERRIDE; public Q_SLOTS: void save() Q_DECL_OVERRIDE; private: void prepareUi(); private: KSharedConfigPtr mSddmConfig; - KSharedConfigPtr mSddmOldConfig; ThemeConfig *mThemeConfig; AdvancedConfig *mAdvancedConfig; }; #endif // SDDMKCM_H