[plasma/plasma-login-manager] src/frontend/kcm/auth: kcm: Fix wallpaper permissions

Oliver Beard <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit ab16cf42b2f49303f7c177ec4ff2f1ce3f405884 by Oliver Beard, on behalf of David Edmundson.
Committed on 20/07/2026 at 10:13.
Pushed by olib into branch 'master'.

kcm: Fix wallpaper permissions

Plasmalogin manager changed how the authentication system worked in
7b4a086c71779ebf4df80a2f681928cfeba3bf87. Instead of running as root,
the authentication helper switched user to the plasmalogin user to run
actions.

For clean setups this all works fine, but any stale configuration files
from 6.6 that are root owned now cannot be overridden.

Perform a migration fix in the helper.

BUG: 521008
BUG: 517081

M  +93   -0    src/frontend/kcm/auth/plasmaloginauthhelper.cpp
M  +3    -0    src/frontend/kcm/auth/plasmaloginauthhelper.h

https://invent.kde.org/plasma/plasma-login-manager/-/commit/ab16cf42b2f49303f7c177ec4ff2f1ce3f405884

diff --git a/src/frontend/kcm/auth/plasmaloginauthhelper.cpp b/src/frontend/kcm/auth/plasmaloginauthhelper.cpp
index 1ab88850..bead556b 100644
--- a/src/frontend/kcm/auth/plasmaloginauthhelper.cpp
+++ b/src/frontend/kcm/auth/plasmaloginauthhelper.cpp
@@ -8,6 +8,7 @@
 #include "plasmaloginauthhelper.h"
 #include "config.h"
 
+#include <dirent.h>
 #include <fcntl.h> /* Definition of O_* and S_* constants */
 #include <linux/openat2.h> /* Definition of RESOLVE_* constants */
 #include <sys/stat.h>
@@ -87,6 +88,86 @@ static bool runAsPlasmaLoginUser(Func function)
     }
 }
 
+static bool adjustOwnershipRecursively(int dirFd, uid_t uid, gid_t gid, const QString &path)
+{
+    bool success = true;
+
+    DIR *dir = fdopendir(dirFd);
+    if (!dir) {
+        qWarning() << "Could not open directory stream for" << path << ":" << strerror(errno);
+        close(dirFd);
+        return false;
+    }
+    auto closeDir = qScopeGuard([dir]() {
+        closedir(dir);
+    });
+
+    while (dirent *entry = readdir(dir)) {
+        const QByteArray name(entry->d_name);
+        if (name == "." || name == "..") {
+            continue;
+        }
+
+        struct stat statBuf;
+        if (fstatat(dirFd, name.constData(), &statBuf, AT_SYMLINK_NOFOLLOW) != 0) {
+            qWarning() << "Could not stat" << path + QLatin1Char('/') + QString::fromUtf8(name) << ":" << strerror(errno);
+            success = false;
+            continue;
+        }
+
+        if (S_ISLNK(statBuf.st_mode)) {
+            continue;
+        }
+
+        if (S_ISDIR(statBuf.st_mode)) {
+            struct open_how how = {.flags = O_RDONLY | O_DIRECTORY | O_CLOEXEC,
+                                   .mode = 0,
+                                   .resolve = RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS};
+            const int childFd = syscall(SYS_openat2, dirFd, name.constData(), &how, sizeof(struct open_how));
+            if (childFd < 0) {
+                qWarning() << "Could not open directory" << path + QLatin1Char('/') + QString::fromUtf8(name) << ":" << strerror(errno);
+                success = false;
+                continue;
+            }
+
+            success = adjustOwnershipRecursively(childFd, uid, gid, path + QLatin1Char('/') + QString::fromUtf8(name)) && success;
+        }
+
+        if (fchownat(dirFd, name.constData(), uid, gid, AT_SYMLINK_NOFOLLOW) != 0) {
+            qWarning() << "Could not change owner of" << path + QLatin1Char('/') + QString::fromUtf8(name) << ":" << strerror(errno);
+            success = false;
+        }
+    }
+
+    return success;
+}
+
+bool PlasmaLoginAuthHelper::adjustPermissionsFromPlasma6_6()
+{
+    // Plasma 6.6 ran some things as root. For 6.7 onwards we run them as the
+    // plasmalogin user, so upgraded installations may need ownership repaired.
+    KUser user(QStringLiteral("plasmalogin"));
+    if (!user.isValid()) {
+        qWarning() << "Could not find plasmalogin user";
+        return false;
+    }
+
+    const QString homeDirPath = user.homeDir();
+    if (homeDirPath.isEmpty()) {
+        qWarning() << "Could not determine home directory for plasmalogin user";
+        return false;
+    }
+
+    const QByteArray homeDirPathUtf8 = homeDirPath.toUtf8();
+    const int homeDirFd = open(homeDirPathUtf8.constData(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
+    if (homeDirFd < 0) {
+        qWarning() << "Could not open home directory for plasmalogin user:" << strerror(errno);
+        return false;
+    }
+
+    return adjustOwnershipRecursively(homeDirFd, user.userId().nativeId(), user.groupId().nativeId(), homeDirPath);
+}
+
 ActionReply PlasmaLoginAuthHelper::sync(const QVariantMap &args)
 {
     QString homeDir;
@@ -96,6 +177,10 @@ ActionReply PlasmaLoginAuthHelper::sync(const QVariantMap &args)
         return ActionReply::HelperErrorReply();
     }
 
+    if (!adjustPermissionsFromPlasma6_6()) {
+        return ActionReply::HelperErrorReply();
+    }
+
     bool rc = runAsPlasmaLoginUser([args, homeDir]() {
         // In plasma-framework, ThemePrivate::useCache documents the requirement to
         // clear the cache when colors change while the app that uses them isn't
@@ -168,6 +253,10 @@ ActionReply PlasmaLoginAuthHelper::reset(const QVariantMap &args)
         return ActionReply::HelperErrorReply();
     }
 
+    if (!adjustPermissionsFromPlasma6_6()) {
+        return ActionReply::HelperErrorReply();
+    }
+
     bool rc = runAsPlasmaLoginUser([homeDir]() {
         QDir cacheDir(homeDir + QStringLiteral("/.cache"));
         if (cacheDir.exists()) {
@@ -240,6 +329,10 @@ ActionReply PlasmaLoginAuthHelper::save(const QVariantMap &args)
         return ActionReply::HelperErrorReply();
     }
 
+    if (!adjustPermissionsFromPlasma6_6()) {
+        return ActionReply::HelperErrorReply();
+    }
+
     bool rc = runAsPlasmaLoginUser([homeDirPath, args]() {
         QDir homeDir(homeDirPath);
         QDir wallpaperDir(homeDir.absoluteFilePath("wallpapers"));
diff --git a/src/frontend/kcm/auth/plasmaloginauthhelper.h b/src/frontend/kcm/auth/plasmaloginauthhelper.h
index 3cc3a939..6b7f57c6 100644
--- a/src/frontend/kcm/auth/plasmaloginauthhelper.h
+++ b/src/frontend/kcm/auth/plasmaloginauthhelper.h
@@ -32,4 +32,7 @@ public Q_SLOTS:
      * Update the PLASMALOGIN_CONFIG_FILE with the user's specified settings
      */
     ActionReply save(const QVariantMap &args);
+
+private:
+    bool adjustPermissionsFromPlasma6_6();
 };
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.