KWallet

ksecretd/main.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2008 Michael Leupold <lemma@confuego.org>
4 SPDX-FileCopyrightText: 2014 Alex Fiestas <afiestas@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-only
7*/
8
9#include "ksecretd_debug.h"
10#include <KAboutData>
11#include <KConfig>
12#include <KConfigGroup>
13#include <KCrash>
14#include <KDBusService>
15#include <KLocalizedString>
16
17#include <QApplication>
18#include <QCommandLineParser>
19#include <QIcon>
20#include <QSessionManager>
21#include <QString>
22
23#include <stdio.h>
24
25#include "../kwalletbackend/kwalletbackend.h" //For the hash size
26#include "ksecretd.h"
27#include "ksecretd_version.h"
28#include "kwalletfreedesktopservice.h"
29
30#ifndef Q_OS_WIN
31#include <sys/socket.h>
32#include <sys/types.h>
33#include <sys/un.h>
34#include <unistd.h>
35
36#define BSIZE 1000
37static int pipefd = 0;
38static int socketfd = 0;
39#endif
40
41#ifndef Q_OS_WIN
42// Waits until the PAM_MODULE sends the hash
43static char *waitForHash()
44{
45 qCDebug(KSECRETD_LOG) << "ksecretd5: Waiting for hash on" << pipefd;
46 int totalRead = 0;
47 int readBytes = 0;
48 int attempts = 0;
49 char *buf = (char *)malloc(sizeof(char) * PBKDF2_SHA512_KEYSIZE);
50 memset(buf, '\0', PBKDF2_SHA512_KEYSIZE);
51 while (totalRead != PBKDF2_SHA512_KEYSIZE) {
52 readBytes = read(pipefd, buf + totalRead, PBKDF2_SHA512_KEYSIZE - totalRead);
53 if (readBytes == -1 || attempts > 5) {
54 free(buf);
55 return nullptr;
56 }
57 totalRead += readBytes;
58 ++attempts;
59 }
60
61 close(pipefd);
62 return buf;
63}
64
65// Waits until startkde sends the environment variables
66static int waitForEnvironment()
67{
68 qCDebug(KSECRETD_LOG) << "ksecretd5: waitingForEnvironment on:" << socketfd;
69
70 int s2;
71 struct sockaddr_un remote;
72 socklen_t t = sizeof(remote);
73 if ((s2 = accept(socketfd, (struct sockaddr *)&remote, &t)) == -1) {
74 qCWarning(KSECRETD_LOG) << "ksecretd5: Couldn't accept incoming connection";
75 return -1;
76 }
77 qCDebug(KSECRETD_LOG) << "ksecretd5: client connected";
78
79 char str[BSIZE] = {'\0'};
80
81 int chop = 0;
82 FILE *s3 = fdopen(dup(s2), "r");
83 while (!feof(s3)) {
84 if (fgets(str, BSIZE, s3)) {
85 chop = strlen(str) - 1;
86 if (str[chop] == '\n') {
87 str[chop] = '\0';
88 }
89 putenv(strdup(str));
90 }
91 }
92 fclose(s3);
93
94 qCDebug(KSECRETD_LOG) << "ksecretd5: client disconnected";
95 close(socketfd);
96 return 1;
97}
98
99char *checkPamModule(int argc, char **argv)
100{
101 qCDebug(KSECRETD_LOG) << "ksecretd5: Checking for pam module";
102 char *hash = nullptr;
103 int x = 1;
104 for (; x < argc; ++x) {
105 if (strcmp(argv[x], "--pam-login") != 0) {
106 continue;
107 }
108 qCDebug(KSECRETD_LOG) << "ksecretd5: Got pam-login param";
109 argv[x] = nullptr;
110 x++;
111 // We need at least 2 extra arguments after --pam-login
112 if (x + 1 > argc) {
113 qCWarning(KSECRETD_LOG) << "ksecretd5: Invalid arguments (less than needed)";
114 return nullptr;
115 }
116
117 // first socket for the hash, comes from a pipe
118 pipefd = atoi(argv[x]);
119 argv[x] = nullptr;
120 x++;
121 // second socket for environment, comes from a localsocket
122 socketfd = atoi(argv[x]);
123 argv[x] = nullptr;
124 break;
125 }
126
127 if (!pipefd || !socketfd) {
128 qCWarning(KSECRETD_LOG) << "Lacking a socket, pipe:" << pipefd << "env:" << socketfd;
129 return nullptr;
130 }
131
132 hash = waitForHash();
133
134 if (hash == nullptr || waitForEnvironment() == -1) {
135 qCWarning(KSECRETD_LOG) << "ksecretd5: Hash or environment not received";
136 free(hash);
137 return nullptr;
138 }
139
140 return hash;
141}
142#endif
143
144int main(int argc, char **argv)
145{
146 char *hash = nullptr;
147#ifndef Q_OS_WIN
148 if (getenv("PAM_KWALLET5_LOGIN")) {
149 hash = checkPamModule(argc, argv);
150 }
151#endif
152
153 QApplication app(argc, argv);
154 app.setWindowIcon(QIcon::fromTheme(QStringLiteral("kwalletmanager")));
155
156 // this ksecretd5 program should be able to start with KDE4's ksecretd
157 // using ksecretd name would prevent KDBusService unique instance to initialize
158 // so we setApplicationName("ksecretd6")
159 KAboutData aboutdata("ksecretd",
160 i18n("KDE Wallet Service"),
161 KSECRETD_VERSION_STRING,
162 i18n("KDE Wallet Service"),
164 i18n("(C) 2002-2025, The KDE Developers"));
165 aboutdata.addAuthor(i18n("Valentin Rusu"), i18n("Former Maintainer, GPG backend support"), QStringLiteral("kde@rusu.info"));
166 aboutdata.addAuthor(i18n("Michael Leupold"), i18n("Former Maintainer"), QStringLiteral("lemma@confuego.org"));
167 aboutdata.addAuthor(i18n("George Staikos"), i18n("Former maintainer"), QStringLiteral("staikos@kde.org"));
168 aboutdata.addAuthor(i18n("Thiago Maceira"), i18n("D-Bus Interface"), QStringLiteral("thiago@kde.org"));
169
171
173
174 KDBusService dbusUniqueInstance(KDBusService::Unique);
175
176 // NOTE: the command should be parsed only after KDBusService instantiation
177 QCommandLineParser cmdParser;
178 aboutdata.setupCommandLine(&cmdParser);
179 cmdParser.process(app);
180
181 app.setQuitOnLastWindowClosed(false);
182 auto disableSessionManagement = [](QSessionManager &sm) {
183 sm.setRestartHint(QSessionManager::RestartNever);
184 };
185 QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement);
186 QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement);
187
188 // check if kwallet is disabled
189 if (!KSecretD::isEnabled()) {
190 qCDebug(KSECRETD_LOG) << "ksecretd is disabled!";
191
192 /* Do not keep dbus-daemon waiting for the org.freedesktop.secrets if kwallet is disabled */
193 KWalletFreedesktopService(nullptr);
194
195 return (0);
196 }
197
198 KSecretD secretd;
199 qCDebug(KSECRETD_LOG) << "ksecretd6 started";
200
201 if (hash) {
202 QByteArray passHash(hash, PBKDF2_SHA512_KEYSIZE);
203 int wallet = secretd.pamOpen(KWallet::Wallet::LocalWallet(), passHash, 0);
204 if (wallet < 0) {
205 qCWarning(KSECRETD_LOG) << "Wallet failed to get opened by PAM, error code is" << wallet;
206 } else {
207 qCDebug(KSECRETD_LOG) << "Wallet opened by PAM";
208 }
209 free(hash);
210 }
211
212 return app.exec();
213}
static void setApplicationData(const KAboutData &aboutData)
static const QString LocalWallet()
The name of the wallet used to store local passwords.
Definition kwallet.cpp:58
QString i18n(const char *text, const TYPE &arg...)
KCRASH_EXPORT void initialize()
QVariant read(const QByteArray &data, int versionOverride=0)
const QList< QKeySequence > & close()
void process(const QCoreApplication &app)
void commitDataRequest(QSessionManager &manager)
void saveStateRequest(QSessionManager &manager)
QIcon fromTheme(const QString &name)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 25 2025 11:53:00 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.