https://bugs.kde.org/show_bug.cgi?id=491898

--- Comment #9 from [email protected] ---
Confirmed and root-caused from source (KDE/kwallet master; kf6-kwallet 6.18.0).

Root cause: src/runtime/kwallet-query/src/querydriver.cpp,
QueryDriver::writeValue().
It selects the write method from the entry's *existing* type:

    Wallet::EntryType kind = theWallet->entryType(entryName);
    if (kind == Wallet::Password) { ... writePassword ... }
    else if (kind == Wallet::Map) { ... writeMap ... }
    quit();   // exit 0

For a brand-new entry the key does not exist yet, so entryType() returns
Wallet::Unknown (= 0). Neither branch matches Unknown, so no write is issued at
all and control falls through to quit() -> exit 0 with no error. Overwriting an
entry that already exists as Password/Map works; creating a new one silently
does
nothing. A direct org.kde.kwalletd6 writePassword() D-Bus call persists
correctly
because it has no such type gate.

This is NOT an async / process-teardown race: the wallet is opened
Asynchronous,
but the write runs inside the walletOpened slot within the running event loop,
and
Wallet::writePassword() is a synchronous QDBusReply whose return code is
checked.
The write is simply never issued for new entries.

Minimal repro:
    ls -la ~/.local/share/kwalletd/kdewallet.kwl
    kwallet-query -f login -w test_entry -v kdewallet <<< "test_value_123"   #
exits 0
    ls -la ~/.local/share/kwalletd/kdewallet.kwl   # size/mtime unchanged
    kwallet-query -f login -l kdewallet            # test_entry absent
The same write over qdbus-qt6 ... org.kde.KWallet.writePassword persists
immediately.

Fix (attached, git am / patch -p1 against master): default a new (Unknown)
entry to
a Password write. The patch also makes the tool fail with a non-zero exit
instead of
reporting a phantom success on an unwritable pre-existing type or invalid map
JSON,
and creates the target folder on demand instead of dropping the write when the
folder does not exist yet.


PATCH:
>From 0017be0a524f8da22a67e080186b5e1f3f8cd44c Mon Sep 17 00:00:00 2001
From: Keeler <[email protected]>
Date: Fri, 3 Jul 2026 12:05:00 +0000
Subject: [PATCH] kwallet-query: persist writes to new entries

writeValue() picked the write method from the entry's *existing* type.
entryType() returns Wallet::Unknown for an entry that does not exist yet,
so for a brand-new entry neither the Wallet::Password nor the Wallet::Map
branch ran: no write was issued and the tool still called quit() and
exited 0. Creating a new secret with `kwallet-query -w` therefore silently
did nothing, while overwriting an already-existing entry worked. A direct
org.kde.kwalletd6 writePassword() D-Bus call persists correctly because it
has no such type gate.

Default a new (Unknown) entry to a Password write, matching writePassword().
While here, fail with a non-zero exit instead of reporting a phantom
success when the entry is an unwritable pre-existing type or the map input
is invalid JSON, and create the target folder on demand rather than
dropping the write when the folder does not exist yet.

BUG: 491898
---
 src/runtime/kwallet-query/src/querydriver.cpp | 58 ++++++++++++++-----
 1 file changed, 42 insertions(+), 16 deletions(-)

diff --git a/src/runtime/kwallet-query/src/querydriver.cpp
b/src/runtime/kwallet-query/src/querydriver.cpp
index de68d0d..67bada1 100644
--- a/src/runtime/kwallet-query/src/querydriver.cpp
+++ b/src/runtime/kwallet-query/src/querydriver.cpp
@@ -172,7 +172,17 @@ void QueryDriver::writeValue()
     if (verbose) {
         qDebug() << "writing" << entryName << "to" << entryFolder << "to" <<
walletName;
     }
-    theWallet->setFolder(entryFolder);
+    // setFolder() fails on a folder that does not exist yet, which would
leave
+    // the write pointed at the wrong (or no) folder. Create it on demand and
+    // bail out loudly if we still cannot select it, instead of silently going
on.
+    if (!theWallet->hasFolder(entryFolder)) {
+        theWallet->createFolder(entryFolder);
+    }
+    if (!theWallet->setFolder(entryFolder)) {
+        std::cout << i18n("The folder %1 does not exist!",
entryFolder).toUtf8().constData() << std::endl;
+        exit(4);
+        return;
+    }

     QString passwordContents;
     for (std::string line; std::getline(std::cin, line);) {
@@ -185,6 +195,13 @@ void QueryDriver::writeValue()
         }
     }
     Wallet::EntryType kind = theWallet->entryType(entryName);
+    // A brand-new entry does not exist yet, so entryType() reports Unknown.
+    // Previously neither branch below matched Unknown, so the write was
silently
+    // dropped while the tool still exited 0 (bug 491898). Default new entries
to
+    // Password, matching a direct writePassword() call over D-Bus.
+    if (kind == Wallet::Unknown) {
+        kind = Wallet::Password;
+    }
     if (kind == Wallet::Password) {
         if (verbose) {
             qDebug() << "about to write" << passwordContents;
@@ -197,22 +214,31 @@ void QueryDriver::writeValue()
         }
     } else if (kind == Wallet::Map) {
         const QJsonDocument json =
QJsonDocument::fromJson(passwordContents.toLatin1());
-        if (!json.isNull()) {
-            QJsonObject values = json.object();
-            QMap<QString, QString> map;
-            for (auto &e : values.keys()) {
-                map.insert(e, values.value(e).toString());
-            }
-            if (verbose) {
-                qDebug() << "about to write" << map;
-            }
-            int rc = theWallet->writeMap(entryName, map);
-            if (rc != 0) {
-                std::cout << i18n("Failed to write entry %1 value to %2
wallet", entryName, walletName).toUtf8().constData() << std::endl;
-                exit(4);
-                return;
-            }
+        if (json.isNull()) {
+            std::cout << i18n("Failed to write entry %1 value to %2 wallet",
entryName, walletName).toUtf8().constData() << std::endl;
+            exit(4);
+            return;
+        }
+        QJsonObject values = json.object();
+        QMap<QString, QString> map;
+        for (auto &e : values.keys()) {
+            map.insert(e, values.value(e).toString());
+        }
+        if (verbose) {
+            qDebug() << "about to write" << map;
+        }
+        int rc = theWallet->writeMap(entryName, map);
+        if (rc != 0) {
+            std::cout << i18n("Failed to write entry %1 value to %2 wallet",
entryName, walletName).toUtf8().constData() << std::endl;
+            exit(4);
+            return;
         }
+    } else {
+        // Any other pre-existing type (e.g. Stream) is not writable here;
fail
+        // rather than reporting a phantom success.
+        std::cout << i18n("Failed to write entry %1 value to %2 wallet",
entryName, walletName).toUtf8().constData() << std::endl;
+        exit(4);
+        return;
     }
     quit();
 }
-- 
2.43.0

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to