1/**
2 * This file is part of the KDE project
3 * Copyright (C) 2008 Michael Leupold <lemma@confuego.org>
4 * Copyright (C) 2014 Alejandro Fiestas Olivares <afiestas@kde.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License version 2 as published by the Free Software Foundation.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include <kuniqueapplication.h>
22#include <kaboutdata.h>
23#include <kcmdlineargs.h>
24#include <kdebug.h>
25#include <kconfig.h>
26#include <kconfiggroup.h>
27#include <klocale.h>
28#include <stdio.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/un.h>
32#include <unistd.h>
33#include "kwalletd.h"
34#include "backend/kwalletbackend.h" //For the hash size
35
36#define BSIZE 1000
37static int pipefd = 0;
38static int socketfd = 0;
39static bool isWalletEnabled()
40{
41 KConfig cfg("kwalletrc");
42 KConfigGroup walletGroup(&cfg, "Wallet");
43 return walletGroup.readEntry("Enabled", true);
44}
45
46//Waits until the PAM_MODULE sends the hash
47static char *waitForHash()
48{
49 printf("kwalletd: Waiting for hash on %d-\n", pipefd);
50 int totalRead = 0;
51 int readBytes = 0;
52 int attemps = 0;
53 char *buf = (char*)malloc(sizeof(char) * PBKDF2_SHA512_KEYSIZE);
54 memset(buf, '\0', PBKDF2_SHA512_KEYSIZE);
55 while(totalRead != PBKDF2_SHA512_KEYSIZE) {
56 readBytes = read(pipefd, buf + totalRead, PBKDF2_SHA512_KEYSIZE - totalRead);
57 if (readBytes == -1 || attemps > 5) {
58 free(buf);
59 return NULL;
60 }
61 totalRead += readBytes;
62 ++attemps;
63 }
64
65 close(pipefd);
66 return buf;
67}
68
69//Waits until startkde sends the environment variables
70static int waitForEnvironment()
71{
72 printf("kwalletd: waitingForEnvironment on: %d\n", socketfd);
73
74 int s2;
75 socklen_t t;
76 struct sockaddr_un remote;
77 if ((s2 = accept(socketfd, (struct sockaddr *)&remote, &t)) == -1) {
78 fprintf(stdout, "kwalletd: Couldn't accept incoming connection\n");
79 return -1;
80 }
81 printf("kwalletd: client connected\n");
82
83 char str[BSIZE];
84 memset(str, '\0', sizeof(char) * BSIZE);
85
86 int chop = 0;
87 FILE *s3 = fdopen(s2, "r");
88 while(!feof(s3)) {
89 if (fgets(str, BSIZE, s3)) {
90 chop = strlen(str) - 1;
91 str[chop] = '\0';
92 putenv(strdup(str));
93 }
94 }
95 printf("kwalletd: client disconnected\n");
96 close(socketfd);
97 return 1;
98}
99
100char* checkPamModule(int argc, char **argv)
101{
102 printf("Checking for pam module\n");
103 char *hash = NULL;
104 int x = 1;
105 for (; x < argc; ++x) {
106 if (strcmp(argv[x], "--pam-login") != 0) {
107 continue;
108 }
109 printf("Got pam-login\n");
110 argv[x] = NULL;
111 x++;
112 //We need at least 2 extra arguments after --pam-login
113 if (x + 1 > argc) {
114 printf("Invalid arguments (less than needed)\n");
115 return NULL;
116 }
117
118 //first socket for the hash, comes from a pipe
119 pipefd = atoi(argv[x]);
120 argv[x] = NULL;
121 x++;
122 //second socket for environemtn, comes from a localsock
123 socketfd = atoi(argv[x]);
124 argv[x] = NULL;
125 break;
126 }
127
128 if (!pipefd || !socketfd) {
129 printf("Lacking a socket, pipe: %d, env:%d\n", pipefd, socketfd);
130 return NULL;
131 }
132
133 hash = waitForHash();
134
135 if (hash == NULL || waitForEnvironment() == -1) {
136 printf("Hash or environment not received\n");
137 return NULL;
138 }
139
140 return hash;
141}
142
143extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
144{
145 char *hash = NULL;
146 if (getenv("PAM_KWALLET_LOGIN")) {
147 hash = checkPamModule(argc, argv);
148 }
149
150 KAboutData aboutdata("kwalletd", 0, ki18n("KDE Wallet Service"),
151 "0.2", ki18n("KDE Wallet Service"),
152 KAboutData::License_LGPL, ki18n("(C) 2002-2008 George Staikos, Michael Leupold, Thiago Maceira, Valentin Rusu"));
153 aboutdata.addAuthor(ki18n("Michael Leupold"),ki18n("Maintainer"),"lemma@confuego.org");
154 aboutdata.addAuthor(ki18n("George Staikos"),ki18n("Former maintainer"),"staikos@kde.org");
155 aboutdata.addAuthor(ki18n("Thiago Maceira"),ki18n("D-Bus Interface"),"thiago@kde.org");
156 aboutdata.addAuthor(ki18n("Valentin Rusu"),ki18n("GPG backend support"),"kde@rusu.info");
157
158 aboutdata.setProgramIconName("kwalletmanager");
159
160 KCmdLineArgs::init( argc, argv, &aboutdata );
161 KUniqueApplication::addCmdLineOptions();
162 KUniqueApplication app;
163
164 // This app is started automatically, no need for session management
165 app.disableSessionManagement();
166 app.setQuitOnLastWindowClosed( false );
167
168 // check if kwallet is disabled
169 if (!isWalletEnabled()) {
170 kDebug() << "kwalletd is disabled!";
171 return (0);
172 }
173
174 if (!KUniqueApplication::start())
175 {
176 kDebug() << "kwalletd is already running!";
177 return (0);
178 }
179
180 kDebug() << "kwalletd started";
181 KWalletD walletd;
182 if (hash) {
183 kDebug() << "LOGIN INSIDE!";
184 QByteArray passHash(hash, PBKDF2_SHA512_KEYSIZE);
185 int wallet = walletd.pamOpen(KWallet::Wallet::LocalWallet(), passHash, 0);
186 kDebug() << "Wallet handler: " << wallet;
187 free(hash);
188 } else {
189 kDebug() << "Not pam login";
190 }
191 return app.exec();
192}
193