10#include "ksecretd_debug.h"
12#include "kbetterthankdialog.h"
13#include "kwalletfreedesktopcollection.h"
14#include "kwalletfreedesktopitem.h"
15#include "kwalletfreedesktopprompt.h"
16#include "kwalletfreedesktopservice.h"
17#include "kwalletfreedesktopsession.h"
18#include "kwalletportalsecrets.h"
19#include "kwalletwizard.h"
22#include "knewwalletdialog.h"
25#include <KColorScheme>
27#include <KConfigGroup>
29#include <KLocalizedString>
31#include <KNewPasswordDialog>
32#include <KNotification>
33#include <KPasswordDialog>
34#include <KPluginFactory>
35#include <KSharedConfig>
36#include <kwalletentry.h>
37#include <kwindowsystem.h>
39#include <config-ksecretd.h>
45#include <gpgme++/key.h>
48#include <QApplication>
55#include "kwalletadaptor.h"
57static void startManagerForKSecretD()
60 QProcess::startDetached(QStringLiteral(
"kstart"), {QStringLiteral(
"kwalletmanager5"), QStringLiteral(
"--"), QStringLiteral(
"--KSecretD")});
62 QProcess::startDetached(QStringLiteral(
"kstart"), {QStringLiteral(
"kwalletmanager5"), QStringLiteral(
"--"), QStringLiteral(
"--KSecretD")});
68class KWalletTransaction
71 explicit KWalletTransaction(QDBusConnection conn)
72 : tId(nextTransactionId)
79 if (nextTransactionId < 0) {
80 nextTransactionId = 0;
84 static int getTransactionId()
86 return nextTransactionId;
100 Type tType = Unknown;
105 bool cancelled =
false;
110 QDBusMessage message;
111 QDBusConnection connection;
114 static int nextTransactionId;
117int KWalletTransaction::nextTransactionId = 0;
130 srand(time(
nullptr));
131 _showingFailureNotify =
false;
134 connect(&_closeTimers, &KTimeout::timedOut,
this, &KSecretD::timedOutClose);
135 connect(&_syncTimers, &KTimeout::timedOut,
this, &KSecretD::timedOutSync);
137 KConfig kwalletrc(QStringLiteral(
"kwalletrc"));
140 if (cfgWallet.readEntry<
bool>(
"apiEnabled",
true)) {
141 (void)
new KWalletAdaptor(
this);
148 new KWalletPortalSecrets(
this);
158 _dw->setObjectName(QStringLiteral(
"KWallet Directory Watcher"));
160 _dw->addDir(KWallet::Backend::getSaveLocation());
162 _dw->startScan(
true);
169 _fdoService.reset(
new KWalletFreedesktopService(
this));
179 qDeleteAll(_transactions);
184 return KWallet::Backend::encodeWalletName(name);
189 return KWallet::Backend::decodeWalletName(mangledName);
193void KSecretD::connectToScreenSaver()
195 screensaver =
new QDBusInterface(
"org.freedesktop.ScreenSaver",
"/ScreenSaver",
"org.freedesktop.ScreenSaver");
196 if (!screensaver->isValid()) {
197 qCDebug(KSECRETD_LOG) <<
"Service org.freedesktop.ScreenSaver not found. Retrying in 10 seconds...";
201 connect(screensaver, SIGNAL(ActiveChanged(
bool)), SLOT(screenSaverChanged(
bool)));
202 qCDebug(KSECRETD_LOG) <<
"connected to screen saver service.";
207int KSecretD::generateHandle()
214 }
while (_wallets.contains(rc) || rc == 0);
219QPair<int, KWallet::Backend *> KSecretD::findWallet(
const QString &walletName)
const
221 Wallets::const_iterator it = _wallets.constBegin();
222 const Wallets::const_iterator
end = _wallets.constEnd();
223 for (; it !=
end; ++it) {
224 if (it.value()->walletName() == walletName) {
225 return qMakePair(it.key(), it.value());
228 return qMakePair(-1,
static_cast<KWallet::Backend *
>(
nullptr));
231bool KSecretD::_processing =
false;
233void KSecretD::processTransactions()
242 while (!_transactions.isEmpty()) {
243 _curtrans = _transactions.takeFirst();
246 assert(_curtrans->tType != KWalletTransaction::Unknown);
248 switch (_curtrans->tType) {
249 case KWalletTransaction::Open:
250 res = doTransactionOpen(_curtrans->appid, _curtrans->wallet, _curtrans->isPath, _curtrans->wId, _curtrans->modal, _curtrans->service);
256 QList<KWalletTransaction *>::iterator it;
257 for (it = _transactions.begin(); it != _transactions.end(); ++it) {
258 KWalletTransaction *x = *it;
259 if (_curtrans->appid == x->appid && x->tType == KWalletTransaction::Open && x->wallet == _curtrans->wallet && x->wId == _curtrans->wId) {
260 x->tType = KWalletTransaction::OpenFail;
263 }
else if (_curtrans->cancelled) {
266 KWalletTransaction *_xact =
new KWalletTransaction(_curtrans->connection);
267 _xact->tType = KWalletTransaction::CloseCancelled;
268 _xact->appid = _curtrans->appid;
269 _xact->wallet = _curtrans->wallet;
270 _xact->service = _curtrans->service;
271 _transactions.
append(_xact);
275 _curtrans->res = res;
276 Q_EMIT walletAsyncOpened(_curtrans->tId, res);
279 case KWalletTransaction::OpenFail:
282 Q_EMIT walletAsyncOpened(_curtrans->tId, -1);
285 case KWalletTransaction::ChangePassword:
286 doTransactionChangePassword(_curtrans->appid, _curtrans->wallet, _curtrans->wId);
289 case KWalletTransaction::CloseCancelled:
290 doTransactionOpenCancelled(_curtrans->appid, _curtrans->wallet, _curtrans->service);
293 case KWalletTransaction::Unknown:
301 if (_curtrans->connection.isConnected()) {
302 QDBusMessage reply = _curtrans->message.createReply();
303 reply << _curtrans->res;
304 _curtrans->connection.send(reply);
315int KSecretD::openPath(
const QString &path, qlonglong wId,
const QString &appid)
317 int tId = openPathAsync(path, wId, appid,
false);
330int KSecretD::open(
const QString &wallet, qlonglong wId,
const QString &appid)
336 KWalletTransaction *xact =
new KWalletTransaction(
connection());
337 _transactions.append(xact);
343 xact->wallet = wallet;
346 xact->tType = KWalletTransaction::Open;
347 xact->isPath =
false;
356int KSecretD::nextTransactionId()
const
358 return KWalletTransaction::getTransactionId();
361int KSecretD::openAsync(
const QString &wallet,
372 KWalletTransaction *xact =
new KWalletTransaction(
connection);
373 _transactions.append(xact);
376 xact->wallet = wallet;
379 xact->tType = KWalletTransaction::Open;
380 xact->isPath =
false;
382 qCDebug(KSECRETD_LOG) <<
"openAsync for " <<
message.service();
384 _serviceWatcher.addWatchedService(
message.service());
385 xact->service =
message.service();
393int KSecretD::openAsync(
const QString &wallet, qlonglong wId,
const QString &appid,
bool handleSession)
398int KSecretD::openPathAsync(
const QString &path, qlonglong wId,
const QString &appid,
bool handleSession)
404 KWalletTransaction *xact =
new KWalletTransaction(
connection());
405 _transactions.append(xact);
411 xact->tType = KWalletTransaction::Open;
416 _serviceWatcher.addWatchedService(
message().service());
426void KSecretD::setupDialog(
QWidget *dialog, WId wId,
const QString &appid,
bool modal)
434 qWarning() <<
"Using kwallet without parent window!";
436 qWarning() <<
"Application" << appid <<
"using kwallet without parent window!";
454 activeDialog = dialog;
468void KSecretD::checkActiveDialog()
477 activeDialog->
show();
489int KSecretD::doTransactionOpen(
const QString &appid,
const QString &wallet,
bool isPath, qlonglong wId,
bool modal,
const QString &service)
491 if (_firstUse && !isPath) {
495 KConfig kwalletrc(QStringLiteral(
"kwalletrc"));
496 KConfigGroup cfg(&kwalletrc,
"Wallet");
497 cfg.writeEntry(
"Default Wallet", wallet);
500 KConfig kwalletrc(QStringLiteral(
"kwalletrc"));
501 KConfigGroup cfg(&kwalletrc,
"Wallet");
503 cfg.writeEntry(
"First Use",
false);
563 int rc = internalOpen(appid, wallet, isPath, WId(wId), modal, service);
567int KSecretD::internalOpen(
const QString &appid,
const QString &wallet,
bool isPath, WId w,
bool modal,
const QString &service)
569 bool brandNew =
false;
573 thisApp = QStringLiteral(
"KDE System");
578 if (implicitDeny(wallet, thisApp)) {
582 QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
583 int rc = walletInfo.first;
585 if (_wallets.count() > 20) {
586 qCDebug(KSECRETD_LOG) <<
"Too many wallets open.";
590 KWallet::Backend *b =
new KWallet::Backend(wallet, isPath);
592 bool emptyPass =
false;
593 if ((isPath &&
QFile::exists(wallet)) || (!isPath && KWallet::Backend::exists(wallet))) {
596 int pwless = b->open(QByteArray(), w);
598 assert(b->cipherType() != KWallet::BACKEND_CIPHER_UNKNOWN);
599 if (b->cipherType() == KWallet::BACKEND_CIPHER_GPG) {
611 if (0 != pwless || !b->isOpen()) {
615 b =
new KWallet::Backend(wallet, isPath);
617 KPasswordDialog *kpd =
new KPasswordDialog();
619 kpd->
setPrompt(
i18n(
"<qt>KDE has requested to open the wallet '<b>%1</b>'. Please enter the password for this wallet below.</qt>",
623 i18n(
"<qt>The application '<b>%1</b>' has requested to open the wallet '<b>%2</b>'. Please enter the password for this wallet "
644 KNotification *notification =
650 actionText =
i18nc(
"Text of a button for switching to the (unnamed) application requesting a password",
"Switch there");
654 i18nc(
"Text of a button for switching to the application requesting a password",
"Switch to %1", appid.
toHtmlEscaped());
657 KNotificationAction *action = notification->
addAction(actionText);
663 while (!b->isOpen()) {
664 setupDialog(kpd, w, appid, modal);
667 int rc = b->open(password.
toUtf8());
669 const auto errorStr = KWallet::Backend::openRCToString(rc);
670 qCWarning(KSECRETD_LOG) <<
"Failed to open wallet" << wallet << errorStr;
671 kpd->
setPrompt(
i18n(
"<qt>Error opening the wallet '<b>%1</b>'. Please try again.<br />(Error code %2: %3)</qt>",
692 KWallet::BackendCipherType newWalletType = KWallet::BACKEND_CIPHER_UNKNOWN;
694 std::shared_ptr<KWallet::KNewWalletDialog> newWalletDlg(
new KWallet::KNewWalletDialog(appid, wallet,
QWidget::find(w)));
696 setupDialog(newWalletDlg.get(), (WId)w, appid,
true);
698 newWalletType = newWalletDlg->isBlowfish() ? KWallet::BACKEND_CIPHER_BLOWFISH : KWallet::BACKEND_CIPHER_GPG;
699 gpgKey = newWalletDlg->gpgKey();
706 if (newWalletType == KWallet::BACKEND_CIPHER_GPG) {
707 b->setCipherType(newWalletType);
709 }
else if (newWalletType == KWallet::BACKEND_CIPHER_BLOWFISH) {
711 b->setCipherType(KWallet::BACKEND_CIPHER_BLOWFISH);
712 KNewPasswordDialog *kpd =
new KNewPasswordDialog();
719 i18n(
"KDE has requested to open the wallet. This is used to store sensitive data in a "
720 "secure fashion. Please enter a password to use with this wallet or click cancel to "
721 "deny the application's request."));
724 i18n(
"<qt>The application '<b>%1</b>' has requested to open the KDE wallet. This is "
725 "used to store sensitive data in a secure fashion. Please enter a password to use "
726 "with this wallet or click cancel to deny the application's request.</qt>",
730 if (appid.
length() == 0) {
732 i18n(
"<qt>KDE has requested to create a new wallet named '<b>%1</b>'. Please choose a "
733 "password for this wallet, or cancel to deny the application's request.</qt>",
737 i18n(
"<qt>The application '<b>%1</b>' has requested to create a new wallet named '<b>%2</b>'. "
738 "Please choose a password for this wallet, or cancel to deny the application's request.</qt>",
747 while (!b->isOpen()) {
748 setupDialog(kpd, w, appid, modal);
751 int rc = b->open(password.
toUtf8());
753 kpd->
setPrompt(
i18n(
"<qt>Error opening the wallet '<b>%1</b>'. Please try again.<br />(Error code %2: %3)</qt>",
756 KWallet::Backend::openRCToString(rc)));
768 if ((b->cipherType() == KWallet::BACKEND_CIPHER_BLOWFISH) && !emptyPass && (password.
isNull() || !b->isOpen())) {
773 if (emptyPass && !isAuthorizedApp(appid, wallet, w)) {
778 _wallets.insert(rc = generateHandle(), b);
779 _sessions.addSession(appid, service, rc);
780 _syncTimers.addTimer(rc, _syncTime);
789 _closeTimers.addTimer(rc, _idleTime);
792 Q_EMIT walletCreated(wallet);
794 Q_EMIT walletOpened(wallet);
795 if (_wallets.count() == 1 && _launchManager) {
796 startManagerForKSecretD();
802 walletInfo.second->ref();
803 bool isAuthorized = _sessions.hasSession(appid, rc) || isAuthorizedApp(appid, wallet, w);
807 walletInfo = findWallet(wallet);
809 if (walletInfo.first != -1) {
810 walletInfo.second->deref();
812 internalClose(walletInfo.second, walletInfo.first,
false);
816 if (walletInfo.first != -1) {
817 _sessions.addSession(appid, service, rc);
828bool KSecretD::isAuthorizedApp(
const QString &appid,
const QString &wallet, WId w)
838 thisApp = QStringLiteral(
"KDE System");
843 if (!implicitAllow(wallet, thisApp)) {
846 KBetterThanKDialog *dialog =
new KBetterThanKDialog;
849 dialog->setLabel(
i18n(
"<qt>KDE has requested access to the open wallet '<b>%1</b>'.</qt>", wallet.
toHtmlEscaped()));
851 dialog->setLabel(
i18n(
"<qt>The application '<b>%1</b>' has requested access to the open wallet '<b>%2</b>'.</qt>",
855 setupDialog(dialog, w, appid,
false);
856 response = dialog->
exec();
861 if (response == 0 || response == 1) {
864 QStringList apps = cfg.
readEntry(wallet, QStringList());
870 _implicitAllowMap[wallet] += thisApp;
875 }
else if (response == 3) {
877 QStringList apps = cfg.
readEntry(wallet, QStringList());
880 _implicitDenyMap[wallet] += thisApp;
891int KSecretD::deleteWallet(
const QString &wallet)
894 QString
path = KWallet::Backend::getSaveLocation() +
"/" + encodeWalletName(wallet) +
".kwl";
895 QString pathSalt = KWallet::Backend::getSaveLocation() +
"/" + encodeWalletName(wallet) +
".salt";
898 const QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
899 internalClose(walletInfo.second, walletInfo.first,
true);
901 Q_EMIT walletDeleted(wallet);
919void KSecretD::changePassword(
const QString &wallet, qlonglong wId,
const QString &appid)
921 KWalletTransaction *xact =
new KWalletTransaction(
connection());
929 xact->wallet = wallet;
932 xact->tType = KWalletTransaction::ChangePassword;
934 _transactions.append(xact);
941void KSecretD::initiateSync(
int handle)
944 _syncTimers.addTimer(handle, _syncTime);
945 _syncTimers.resetTimer(handle, _syncTime);
948void KSecretD::doTransactionChangePassword(
const QString &appid,
const QString &wallet, qlonglong wId)
950 const QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
951 int handle = walletInfo.first;
952 KWallet::Backend *w = walletInfo.second;
954 bool reclose =
false;
956 handle = doTransactionOpen(appid, wallet,
false, wId,
false, QLatin1String(
""));
959 i18n(
"Unable to open wallet. The wallet must be opened in order to change the password."),
960 i18n(
"KDE Wallet Service"));
964 w = _wallets.value(handle);
971 if (w->cipherType() == KWallet::BACKEND_CIPHER_GPG) {
972 QString keyID = w->gpgKey().shortKeyID();
975 i18n(
"<qt>The <b>%1</b> wallet is encrypted using GPG key <b>%2</b>. Please use <b>GPG</b> tools (such "
976 "as <b>kleopatra</b>) to change the passphrase associated to that key.</qt>",
981 QPointer<KNewPasswordDialog> kpd =
new KNewPasswordDialog();
982 kpd->setPrompt(
i18n(
"<qt>Please choose a new password for the wallet '<b>%1</b>'.</qt>", wallet.
toHtmlEscaped()));
983 kpd->setWindowTitle(
i18n(
"KDE Wallet Service"));
984 kpd->setAllowEmptyPasswords(
true);
987 setupDialog(kpd, (WId)wId, appid,
false);
989 QString p = kpd->password();
991 w->setPassword(p.
toUtf8());
992 int rc = w->close(
true);
1012 internalClose(w, handle,
true);
1016int KSecretD::close(
const QString &wallet,
bool force)
1018 const QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
1019 int handle = walletInfo.first;
1020 KWallet::Backend *w = walletInfo.second;
1022 return internalClose(w, handle, force);
1025int KSecretD::internalClose(KWallet::Backend *
const w,
const int handle,
const bool force,
const bool saveBeforeClose)
1028 const QString &wallet = w->walletName();
1029 if ((w->refCount() == 0 && !_leaveOpen) || force) {
1031 _sessions.removeAllSessions(handle);
1033 _closeTimers.removeTimer(handle);
1035 _syncTimers.removeTimer(handle);
1036 _wallets.remove(handle);
1037 w->close(saveBeforeClose);
1038 doCloseSignals(handle, wallet);
1048int KSecretD::close(
int handle,
bool force,
const QString &appid,
const QDBusMessage &message)
1050 KWallet::Backend *w = _wallets.value(handle);
1053 if (_sessions.hasSession(appid, handle)) {
1055 bool removed = _sessions.removeSession(appid,
message.service(), handle);
1057 if (removed || _sessions.removeSession(appid, QLatin1String(
""), handle)) {
1060 return internalClose(w, handle, force);
1067int KSecretD::close(
int handle,
bool force,
const QString &appid)
1069 return close(handle, force, appid,
message());
1072bool KSecretD::isOpen(
const QString &wallet)
1074 const QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
1075 return walletInfo.second !=
nullptr;
1078bool KSecretD::isOpen(
int handle)
1084 KWallet::Backend *rc = _wallets.value(handle);
1086 if (rc ==
nullptr && ++_failed > 5) {
1089 }
else if (rc !=
nullptr) {
1093 return rc !=
nullptr;
1098 QString
path = KWallet::Backend::getSaveLocation();
1099 QDir
dir(path, QStringLiteral(
"*.kwl"));
1104 const auto list =
dir.entryInfoList();
1105 for (
const QFileInfo &fi : list) {
1106 QString fn = fi.fileName();
1107 if (fn.
endsWith(QLatin1String(
".kwl"))) {
1110 rc += decodeWalletName(fn);
1115void KSecretD::sync(
int handle,
const QString &appid)
1117 KWallet::Backend *b;
1120 if ((b = getWallet(appid, handle))) {
1121 QString wallet = b->walletName();
1126void KSecretD::timedOutSync(
int handle)
1128 _syncTimers.removeTimer(handle);
1129 if (_wallets.contains(handle) && _wallets[handle]) {
1130 _wallets[handle]->sync(0);
1132 qDebug(
"wallet not found for sync!");
1136void KSecretD::doTransactionOpenCancelled(
const QString &appid,
const QString &wallet,
const QString &service)
1141 if (!_sessions.hasSession(appid)) {
1145 const QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
1146 int handle = walletInfo.first;
1147 KWallet::Backend *b = walletInfo.second;
1148 if (handle != -1 && b) {
1150 internalClose(b, handle,
false);
1154 _sessions.removeSession(appid, service, handle);
1159 KWallet::Backend *b;
1161 if ((b = getWallet(appid, handle))) {
1162 return b->folderList();
1165 return QStringList();
1168bool KSecretD::hasFolder(
int handle,
const QString &f,
const QString &appid)
1170 KWallet::Backend *b;
1172 if ((b = getWallet(appid, handle))) {
1173 return b->hasFolder(f);
1179bool KSecretD::removeFolder(
int handle,
const QString &f,
const QString &appid)
1181 KWallet::Backend *b;
1183 if ((b = getWallet(appid, handle))) {
1184 bool rc = b->removeFolder(f);
1185 initiateSync(handle);
1186 Q_EMIT folderListUpdated(b->walletName());
1193bool KSecretD::createFolder(
int handle,
const QString &f,
const QString &appid)
1195 KWallet::Backend *b;
1197 if ((b = getWallet(appid, handle))) {
1198 bool rc = b->createFolder(f);
1199 initiateSync(handle);
1200 Q_EMIT folderListUpdated(b->walletName());
1209 KWallet::Backend *b;
1211 if ((b = getWallet(appid, handle))) {
1212 b->setFolder(folder);
1213 KWallet::Entry *e = b->readEntry(key);
1214 if (e && e->type() == KWallet::Wallet::Map) {
1219 return QByteArray();
1222#if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
1223QVariantMap KSecretD::readMapList(
int handle,
const QString &folder,
const QString &key,
const QString &appid)
1225 KWallet::Backend *b;
1227 if ((b = getWallet(appid, handle))) {
1228 b->setFolder(folder);
1230 const auto lst = b->readEntryList(key);
1231 for (KWallet::Entry *entry : lst) {
1232 if (entry->type() == KWallet::Wallet::Map) {
1233 rc.insert(entry->key(), entry->map());
1239 return QVariantMap();
1243QVariantMap KSecretD::mapList(
int handle,
const QString &folder,
const QString &appid)
1247 KWallet::Backend *backend = getWallet(appid, handle);
1249 backend->setFolder(folder);
1250 const QList<KWallet::Entry *> lst = backend->entriesList();
1251 for (KWallet::Entry *entry : lst) {
1252 if (entry->type() == KWallet::Wallet::Map) {
1253 rc.insert(entry->key(), entry->map());
1263 KWallet::Backend *b;
1265 if ((b = getWallet(appid, handle))) {
1266 b->setFolder(folder);
1267 KWallet::Entry *e = b->readEntry(key);
1273 return QByteArray();
1276#if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
1277QVariantMap KSecretD::readEntryList(
int handle,
const QString &folder,
const QString &key,
const QString &appid)
1279 KWallet::Backend *b;
1281 if ((b = getWallet(appid, handle))) {
1282 b->setFolder(folder);
1284 const auto lst = b->readEntryList(key);
1285 for (KWallet::Entry *entry : lst) {
1286 rc.insert(entry->key(), entry->value());
1291 return QVariantMap();
1295QVariantMap KSecretD::entriesList(
int handle,
const QString &folder,
const QString &appid)
1299 KWallet::Backend *backend = getWallet(appid, handle);
1301 backend->setFolder(folder);
1302 const QList<KWallet::Entry *> lst = backend->entriesList();
1303 for (KWallet::Entry *entry : lst) {
1304 rc.insert(entry->key(), entry->value());
1313 KWallet::Backend *b;
1315 if ((b = getWallet(appid, handle))) {
1316 b->setFolder(folder);
1317 return b->entryList();
1320 return QStringList();
1325 KWallet::Backend *b;
1327 if ((b = getWallet(appid, handle))) {
1328 b->setFolder(folder);
1329 KWallet::Entry *e = b->readEntry(key);
1330 if (e && e->type() == KWallet::Wallet::Password) {
1331 return e->password();
1338#if KWALLET_BUILD_DEPRECATED_SINCE(5, 72)
1339QVariantMap KSecretD::readPasswordList(
int handle,
const QString &folder,
const QString &key,
const QString &appid)
1341 KWallet::Backend *b;
1343 if ((b = getWallet(appid, handle))) {
1344 b->setFolder(folder);
1346 const auto lst = b->readEntryList(key);
1347 for (KWallet::Entry *entry : lst) {
1348 if (entry->type() == KWallet::Wallet::Password) {
1349 rc.insert(entry->key(), entry->password());
1355 return QVariantMap();
1359QVariantMap KSecretD::passwordList(
int handle,
const QString &folder,
const QString &appid)
1363 KWallet::Backend *backend = getWallet(appid, handle);
1365 backend->setFolder(folder);
1366 const QList<KWallet::Entry *> lst = backend->entriesList();
1367 for (KWallet::Entry *entry : lst) {
1368 if (entry->type() == KWallet::Wallet::Password) {
1369 rc.insert(entry->key(), entry->password());
1379 KWallet::Backend *b;
1381 if ((b = getWallet(appid, handle))) {
1382 b->setFolder(folder);
1386 e.setType(KWallet::Wallet::Map);
1388 initiateSync(handle);
1389 emitFolderUpdated(b->walletName(), folder);
1390 emitEntryUpdated(b->walletName(), folder, key);
1399 KWallet::Backend *b;
1401 if ((b = getWallet(appid, handle))) {
1402 b->setFolder(folder);
1406 e.setType(KWallet::Wallet::Stream);
1408 initiateSync(handle);
1409 emitFolderUpdated(b->walletName(), folder);
1410 emitEntryUpdated(b->walletName(), folder, key);
1419 KWallet::Backend *b;
1421 if ((b = getWallet(appid, handle))) {
1422 b->setFolder(folder);
1426 e.setType(KWallet::Wallet::EntryType(entryType));
1428 initiateSync(handle);
1429 emitFolderUpdated(b->walletName(), folder);
1438 KWallet::Backend *b;
1440 if ((b = getWallet(appid, handle))) {
1441 b->setFolder(folder);
1445 e.setType(KWallet::Wallet::Password);
1447 initiateSync(handle);
1448 emitFolderUpdated(b->walletName(), folder);
1449 emitEntryUpdated(b->walletName(), folder, key);
1458 KWallet::Backend *b;
1460 if ((b = getWallet(appid, handle))) {
1461 if (!b->hasFolder(folder)) {
1462 return KWallet::Wallet::Unknown;
1464 b->setFolder(folder);
1465 if (b->hasEntry(key)) {
1466 return b->readEntry(key)->type();
1470 return KWallet::Wallet::Unknown;
1475 KWallet::Backend *b;
1477 if ((b = getWallet(appid, handle))) {
1478 if (!b->hasFolder(folder)) {
1481 b->setFolder(folder);
1482 return b->hasEntry(key);
1488int KSecretD::removeEntry(
int handle,
const QString &folder,
const QString &key,
const QString &appid)
1490 KWallet::Backend *b;
1492 if ((b = getWallet(appid, handle))) {
1493 if (!b->hasFolder(folder)) {
1496 b->setFolder(folder);
1497 bool rc = b->removeEntry(key);
1498 initiateSync(handle);
1499 emitFolderUpdated(b->walletName(), folder);
1500 emitEntryDeleted(b->walletName(), folder, key);
1507void KSecretD::slotServiceOwnerChanged(
const QString &name,
const QString &oldOwner,
const QString &newOwner)
1510 qCDebug(KSECRETD_LOG) <<
"slotServiceOwnerChanged " <<
name <<
", " << oldOwner <<
", " << newOwner;
1519 QString service(oldOwner);
1520 const QList<KWalletAppHandlePair> sessremove(_sessions.findSessions(service));
1521 KWallet::Backend *b =
nullptr;
1524 for (
const KWalletAppHandlePair &s : sessremove) {
1525 b = getWallet(s.first, s.second);
1528 internalClose(b, s.second,
false);
1533 for (
const KWalletAppHandlePair &s : sessremove) {
1534 _sessions.removeSession(s.first, service, s.second);
1538 QList<KWalletTransaction *>::iterator tit;
1539 for (tit = _transactions.begin(); tit != _transactions.end(); ++tit) {
1540 if ((*tit)->tType == KWalletTransaction::Open && (*tit)->service == oldOwner) {
1545 _transactions.removeAll(
nullptr);
1549 if (_curtrans && _curtrans->tType == KWalletTransaction::Open && _curtrans->service == oldOwner) {
1550 qCDebug(KSECRETD_LOG) <<
"Cancelling current transaction!";
1551 _curtrans->cancelled =
true;
1553 _serviceWatcher.removeWatchedService(oldOwner);
1556KWallet::Backend *KSecretD::getWallet(
const QString &appid,
int handle)
1562 KWallet::Backend *w = _wallets.value(handle);
1565 if (_sessions.hasSession(appid, handle)) {
1569 _closeTimers.resetTimer(handle, _idleTime);
1575 if (++_failed > 5) {
1583void KSecretD::notifyFailures()
1585 if (!_showingFailureNotify) {
1586 _showingFailureNotify =
true;
1588 i18n(
"There have been repeated failed attempts to gain access to a wallet. An application may be misbehaving."),
1589 i18n(
"KDE Wallet Service"));
1590 _showingFailureNotify =
false;
1594void KSecretD::doCloseSignals(
int handle,
const QString &wallet)
1596 Q_EMIT walletClosed(handle);
1597 Q_EMIT walletClosedId(handle);
1599 Q_EMIT walletClosed(wallet);
1600 if (_wallets.isEmpty()) {
1601 Q_EMIT allWalletsClosed();
1607 KWallet::Backend *b;
1609 if ((b = getWallet(appid, handle))) {
1610 b->setFolder(folder);
1611 int rc = b->renameEntry(oldName, newName);
1612 initiateSync(handle);
1613 emitFolderUpdated(b->walletName(), folder);
1614 emitEntryRenamed(b->walletName(), folder, oldName, newName);
1621int KSecretD::renameWallet(
const QString &oldName,
const QString &newName)
1623 const QPair<int, KWallet::Backend *> walletInfo = findWallet(oldName);
1624 return walletInfo.second->renameWallet(newName);
1629 const QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
1630 return _sessions.getApplications(walletInfo.first);
1633bool KSecretD::disconnectApplication(
const QString &wallet,
const QString &application)
1635 const QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
1636 int handle = walletInfo.first;
1637 KWallet::Backend *backend = walletInfo.second;
1639 if (handle != -1 && _sessions.hasSession(application, handle)) {
1640 int removed = _sessions.removeAllSessions(application, handle);
1642 for (
int i = 0; i < removed; ++i) {
1645 internalClose(backend, handle,
false);
1647 Q_EMIT applicationDisconnected(wallet, application);
1654void KSecretD::emitFolderUpdated(
const QString &wallet,
const QString &folder)
1656 Q_EMIT folderUpdated(wallet, folder);
1661 Q_EMIT entryUpdated(wallet, folder, key);
1666 Q_EMIT entryRenamed(wallet, folder, oldName, newName);
1671 Q_EMIT entryDeleted(wallet, folder, key);
1674void KSecretD::emitWalletListDirty()
1676 const QStringList walletsInDisk = wallets();
1677 const auto lst = _wallets.values();
1678 for (
auto i : lst) {
1679 if (!walletsInDisk.
contains(i->walletName())) {
1680 internalClose(i, _wallets.key(i),
true,
false);
1683 Q_EMIT walletListDirty();
1686void KSecretD::reconfigure()
1688 KConfig cfg(QStringLiteral(
"kwalletrc"));
1689 KConfigGroup walletGroup(&cfg,
"Wallet");
1690 _firstUse = walletGroup.readEntry(
"First Use",
true);
1691 _launchManager = walletGroup.readEntry(
"Launch Manager",
false);
1692 _leaveOpen = walletGroup.readEntry(
"Leave Open",
true);
1693 bool idleSave = _closeIdle;
1694 _closeIdle = walletGroup.readEntry(
"Close When Idle",
false);
1695 _openPrompt = walletGroup.readEntry(
"Prompt on Open",
false);
1696 int timeSave = _idleTime;
1698 _idleTime = walletGroup.readEntry(
"Idle Timeout", 10) * 60 * 1000;
1700 if (walletGroup.readEntry(
"Close on Screensaver",
false)) {
1707 if (screensaver && screensaver->isValid()) {
1708 screensaver->disconnect(SIGNAL(ActiveChanged(
bool)),
this, SLOT(screenSaverChanged(
bool)));
1716 if (_idleTime != timeSave) {
1717 Wallets::const_iterator it = _wallets.constBegin();
1718 const Wallets::const_iterator
end = _wallets.constEnd();
1719 for (; it !=
end; ++it) {
1720 _closeTimers.resetTimer(it.key(), _idleTime);
1725 Wallets::const_iterator it = _wallets.constBegin();
1726 const Wallets::const_iterator
end = _wallets.constEnd();
1727 for (; it !=
end; ++it) {
1728 _closeTimers.addTimer(it.key(), _idleTime);
1732 _closeTimers.clear();
1736 _implicitAllowMap.clear();
1737 const KConfigGroup autoAllowGroup(&cfg,
"Auto Allow");
1738 QStringList entries = autoAllowGroup.entryMap().keys();
1739 for (QStringList::const_iterator i = entries.
constBegin(); i != entries.
constEnd(); ++i) {
1740 _implicitAllowMap[*i] = autoAllowGroup.readEntry(*i, QStringList());
1744 _implicitDenyMap.clear();
1745 const KConfigGroup autoDenyGroup(&cfg,
"Auto Deny");
1746 entries = autoDenyGroup.entryMap().keys();
1747 for (QStringList::const_iterator i = entries.
constBegin(); i != entries.
constEnd(); ++i) {
1748 _implicitDenyMap[*i] = autoDenyGroup.readEntry(*i, QStringList());
1753 while (!_wallets.isEmpty()) {
1754 Wallets::const_iterator it = _wallets.constBegin();
1755 internalClose(it.value(), it.key(),
true);
1761bool KSecretD::isEnabled()
1763 KConfig cfg(QStringLiteral(
"kwalletrc"));
1764 KConfigGroup walletGroup(&cfg,
"Wallet");
1765 KConfigGroup ksecretdGroup(&cfg,
"KSecretD");
1769 return ksecretdGroup.readEntry(
"Enabled",
true) && walletGroup.readEntry(
"Enabled",
true);
1772bool KSecretD::folderDoesNotExist(
const QString &wallet,
const QString &folder)
1774 if (!wallets().contains(wallet)) {
1778 const QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
1779 if (walletInfo.second) {
1780 return walletInfo.second->folderDoesNotExist(folder);
1783 KWallet::Backend *b =
new KWallet::Backend(wallet);
1784 b->open(QByteArray());
1785 bool rc = b->folderDoesNotExist(folder);
1792 if (!wallets().contains(wallet)) {
1796 const QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
1797 if (walletInfo.second) {
1798 return walletInfo.second->entryDoesNotExist(folder, key);
1801 KWallet::Backend *b =
new KWallet::Backend(wallet);
1802 b->open(QByteArray());
1803 bool rc = b->entryDoesNotExist(folder, key);
1808bool KSecretD::implicitAllow(
const QString &wallet,
const QString &app)
1810 return _implicitAllowMap[wallet].contains(app);
1813bool KSecretD::implicitDeny(
const QString &wallet,
const QString &app)
1815 return _implicitDenyMap[wallet].contains(app);
1818void KSecretD::timedOutClose(
int id)
1820 KWallet::Backend *w = _wallets.value(
id);
1822 internalClose(w,
id,
true);
1826void KSecretD::closeAllWallets()
1828 Wallets walletsCopy = _wallets;
1830 Wallets::const_iterator it = walletsCopy.constBegin();
1831 const Wallets::const_iterator
end = walletsCopy.constEnd();
1832 for (; it !=
end; ++it) {
1833 internalClose(it.value(), it.key(),
true);
1836 walletsCopy.clear();
1842QString KSecretD::networkWallet()
1847QString KSecretD::localWallet()
1852void KSecretD::screenSaverChanged(
bool s)
1859void KSecretD::activatePasswordDialog()
1861 checkActiveDialog();
1864int KSecretD::pamOpen(
const QString &wallet,
const QByteArray &passwordHash,
int sessionTimeout)
1870 bool brandNew =
false;
1873 QPair<int, KWallet::Backend *> walletInfo = findWallet(wallet);
1874 int rc = walletInfo.first;
1878 if (_wallets.count() > 20) {
1882 KWallet::Backend *b =
nullptr;
1885 if (!wallets().contains(wallet)) {
1886 b =
new KWallet::Backend(wallet);
1887 b->setCipherType(KWallet::BACKEND_CIPHER_BLOWFISH);
1890 b =
new KWallet::Backend(wallet);
1893 int openrc = b->openPreHashed(passwordHash);
1894 if (openrc != 0 || !b->isOpen()) {
1900 int handle = generateHandle();
1901 _wallets.insert(handle, b);
1902 _syncTimers.addTimer(handle, _syncTime);
1907 if (sessionTimeout > 0) {
1908 _closeTimers.addTimer(handle, sessionTimeout);
1909 }
else if (_closeIdle) {
1910 _closeTimers.addTimer(handle, _idleTime);
1913 Q_EMIT walletCreated(wallet);
1915 Q_EMIT walletOpened(wallet);
1917 if (_wallets.count() == 1 && _launchManager) {
1918 startManagerForKSecretD();
1926#include "moc_ksecretd.cpp"
KConfigGroup group(const QString &group)
void deleteEntry(const char *key, WriteConfigFlags pFlags=Normal)
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
bool isEntryImmutable(const char *key) const
QString readEntry(const char *key, const char *aDefault=nullptr) const
void deleted(const QString &path)
void dirty(const QString &path)
void setBackgroundWarningColor(const QColor &color)
void setIcon(const QIcon &icon)
void setPrompt(const QString &prompt)
KNotificationAction * addAction(const QString &label)
void setWindow(QWindow *window)
void setText(const QString &text)
void setPrompt(const QString &prompt)
void setIcon(const QIcon &icon)
void setPassword(const QString &password)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
static const QString PasswordFolder()
The standardized name of the password folder.
static const QString NetworkWallet()
The name of the wallet used to store network passwords.
static const QString LocalWallet()
The name of the wallet used to store local passwords.
static const QString FormDataFolder()
The standardized name of the form data folder.
static bool isPlatformX11()
static void setMainWindow(QWindow *subwindow, const QString &mainwindow)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QString path(const QString &relativePath)
void errorWId(WId parent_id, const QString &text, const QString &title=QString(), Options options=Notify)
void information(QWidget *parent, const QString &text, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
KIOCORE_EXPORT QString dir(const QString &fileClass)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardAction id)
const QList< QKeySequence > & end()
void exit(int returnCode)
QDBusConnectionInterface * interface() const const
bool registerObject(const QString &path, QObject *object, RegisterOptions options)
bool registerService(const QString &serviceName)
QDBusConnection sessionBus()
QDBusReply< QDBusConnectionInterface::RegisterServiceReply > registerService(const QString &serviceName, ServiceQueueOptions qoption, ServiceReplacementOptions roption)
QDBusConnection connection() const const
const QDBusMessage & message() const const
QString service() const const
void setDelayedReply(bool enable) const const
void serviceOwnerChanged(const QString &serviceName, const QString &oldOwner, const QString &newOwner)
bool exists() const const
QIcon fromTheme(const QString &name)
const_iterator constBegin() const const
const_iterator constEnd() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
QString findExecutable(const QString &executableName, const QStringList &paths)
QString & append(QChar ch)
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool isNull() const const
qsizetype length() const const
QString toHtmlEscaped() const const
QByteArray toUtf8() const const
void truncate(qsizetype position)
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)