KWallet

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

KDE's Doxygen guidelines are available online.