1 |
commit: de57d49c49b3497e738dd0b32c4c0a00fb3e3f41 |
2 |
Author: Andreas Sturmlechner <asturm <AT> gentoo <DOT> org> |
3 |
AuthorDate: Thu Aug 31 19:50:00 2017 +0000 |
4 |
Commit: Andreas Sturmlechner <asturm <AT> gentoo <DOT> org> |
5 |
CommitDate: Thu Aug 31 20:53:51 2017 +0000 |
6 |
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=de57d49c |
7 |
|
8 |
kde-plasma/kwallet-pam: Fix memleaks and dropping privileges |
9 |
|
10 |
Package-Manager: Portage-2.3.8, Repoman-2.3.3 |
11 |
|
12 |
.../files/kwallet-pam-5.10.5-check-graphical.patch | 87 +++++++++++ |
13 |
.../files/kwallet-pam-5.10.5-cleanups.patch | 173 +++++++++++++++++++++ |
14 |
.../files/kwallet-pam-5.10.5-privileges.patch | 49 ++++++ |
15 |
.../kwallet-pam/kwallet-pam-5.10.5-r1.ebuild | 59 +++++++ |
16 |
4 files changed, 368 insertions(+) |
17 |
|
18 |
diff --git a/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-check-graphical.patch b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-check-graphical.patch |
19 |
new file mode 100644 |
20 |
index 00000000000..61ea4604586 |
21 |
--- /dev/null |
22 |
+++ b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-check-graphical.patch |
23 |
@@ -0,0 +1,87 @@ |
24 |
+From f3b230f7f3bf39dc46b97a216aa7c28595d20a7a Mon Sep 17 00:00:00 2001 |
25 |
+From: Fabian Vogt <fabian@×××××××××××.de> |
26 |
+Date: Thu, 3 Aug 2017 09:50:30 +0200 |
27 |
+Subject: Check for a graphical session |
28 |
+ |
29 |
+Summary: |
30 |
+Avoid running if it detects a text session. This can be overridden by adding |
31 |
+"force_run" as argument. |
32 |
+ |
33 |
+Test Plan: |
34 |
+Put pam_kwallet5.so as optional in a global common-session pam file |
35 |
+that is included by all other services. It is not invoked when logging in from |
36 |
+a tty with getty, sudo or su and still works when using SDDM. When adding |
37 |
+force_run it runs in all cases. |
38 |
+ |
39 |
+Reviewers: #plasma |
40 |
+ |
41 |
+Subscribers: plasma-devel |
42 |
+ |
43 |
+Tags: #plasma |
44 |
+ |
45 |
+Differential Revision: https://phabricator.kde.org/D7125 |
46 |
+--- |
47 |
+ pam_kwallet.c | 26 ++++++++++++++++++++++++++ |
48 |
+ 1 file changed, 26 insertions(+) |
49 |
+ |
50 |
+diff --git a/pam_kwallet.c b/pam_kwallet.c |
51 |
+index cba57e7..46720a5 100644 |
52 |
+--- a/pam_kwallet.c |
53 |
++++ b/pam_kwallet.c |
54 |
+@@ -72,6 +72,7 @@ const static char *kwalletd = NULL; |
55 |
+ const static char *socketPath = NULL; |
56 |
+ const static char *kwalletPamDataKey = NULL; |
57 |
+ const static char *logPrefix = NULL; |
58 |
++static int force_run = 0; |
59 |
+ |
60 |
+ #ifdef KWALLET5 |
61 |
+ const static char *envVar = "PAM_KWALLET5_LOGIN"; |
62 |
+@@ -98,6 +99,8 @@ static void parseArguments(int argc, const char **argv) |
63 |
+ kwalletd = argv[x] + 9; |
64 |
+ } else if (strstr(argv[x], "socketPath=") != NULL) { |
65 |
+ socketPath= argv[x] + 11; |
66 |
++ } else if (strcmp(argv[x], "force_run") == 0) { |
67 |
++ force_run = 1; |
68 |
+ } |
69 |
+ } |
70 |
+ #ifdef KWALLET5 |
71 |
+@@ -246,6 +249,24 @@ static void cleanup_free(pam_handle_t *pamh, void *ptr, int error_status) |
72 |
+ free(ptr); |
73 |
+ } |
74 |
+ |
75 |
++static int is_graphical_session(pam_handle_t *pamh) |
76 |
++{ |
77 |
++ //Detect a graphical session |
78 |
++ const char *pam_tty = NULL, *pam_xdisplay = NULL, |
79 |
++ *xdg_session_type = NULL, *display = NULL; |
80 |
++ |
81 |
++ pam_get_item(pamh, PAM_TTY, (const void**) &pam_tty); |
82 |
++#ifdef PAM_XDISPLAY |
83 |
++ pam_get_item(pamh, PAM_XDISPLAY, (const void**) &pam_xdisplay); |
84 |
++#endif |
85 |
++ xdg_session_type = get_env(pamh, "XDG_SESSION_TYPE"); |
86 |
++ |
87 |
++ return (pam_xdisplay && strlen(pam_xdisplay) != 0) |
88 |
++ || (pam_tty && pam_tty[0] == ':') |
89 |
++ || (xdg_session_type && strcmp(xdg_session_type, "x11") == 0) |
90 |
++ || (xdg_session_type && strcmp(xdg_session_type, "wayland") == 0); |
91 |
++} |
92 |
++ |
93 |
+ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) |
94 |
+ { |
95 |
+ pam_syslog(pamh, LOG_INFO, "%s: pam_sm_authenticate\n", logPrefix); |
96 |
+@@ -537,6 +558,11 @@ PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, cons |
97 |
+ |
98 |
+ parseArguments(argc, argv); |
99 |
+ |
100 |
++ if (!force_run && !is_graphical_session(pamh)) { |
101 |
++ pam_syslog(pamh, LOG_INFO, "%s: not a graphical session, skipping. Use force_run parameter to ignore this.", logPrefix); |
102 |
++ return PAM_IGNORE; |
103 |
++ } |
104 |
++ |
105 |
+ int result; |
106 |
+ result = pam_set_data(pamh, "sm_open_session", "1", NULL); |
107 |
+ if (result != PAM_SUCCESS) { |
108 |
+-- |
109 |
+cgit v0.11.2 |
110 |
+ |
111 |
|
112 |
diff --git a/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-cleanups.patch b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-cleanups.patch |
113 |
new file mode 100644 |
114 |
index 00000000000..38a333131e9 |
115 |
--- /dev/null |
116 |
+++ b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-cleanups.patch |
117 |
@@ -0,0 +1,173 @@ |
118 |
+From a33ec22b96e837899528b05963eae8ea6b01171a Mon Sep 17 00:00:00 2001 |
119 |
+From: Fabian Vogt <fabian@×××××××××××.de> |
120 |
+Date: Thu, 3 Aug 2017 09:02:14 +0200 |
121 |
+Subject: Several cleanups |
122 |
+ |
123 |
+Summary: |
124 |
+- No cppcheck warnings anymore |
125 |
+- Use snprintf everywhere |
126 |
+- Avoid pointless multiplication with sizeof(char) |
127 |
+- Avoid memory leaks |
128 |
+ |
129 |
+Test Plan: Still builds, works the same as before. |
130 |
+ |
131 |
+Reviewers: #plasma |
132 |
+ |
133 |
+Subscribers: plasma-devel |
134 |
+ |
135 |
+Tags: #plasma |
136 |
+ |
137 |
+Differential Revision: https://phabricator.kde.org/D7123 |
138 |
+--- |
139 |
+ pam_kwallet.c | 44 ++++++++++++++++++++++++++++++++------------ |
140 |
+ 1 file changed, 32 insertions(+), 12 deletions(-) |
141 |
+ |
142 |
+diff --git a/pam_kwallet.c b/pam_kwallet.c |
143 |
+index d88c5e0..cba57e7 100644 |
144 |
+--- a/pam_kwallet.c |
145 |
++++ b/pam_kwallet.c |
146 |
+@@ -151,13 +151,14 @@ static int set_env(pam_handle_t *pamh, const char *name, const char *value) |
147 |
+ //We do not return because pam_putenv might work |
148 |
+ } |
149 |
+ |
150 |
+- char *pamEnv = malloc(strlen(name) + strlen(value) + 2); //2 is for = and \0 |
151 |
++ size_t pamEnvSize = strlen(name) + strlen(value) + 2; //2 is for = and \0 |
152 |
++ char *pamEnv = malloc(pamEnvSize); |
153 |
+ if (!pamEnv) { |
154 |
+ pam_syslog(pamh, LOG_WARNING, "%s: Impossible to allocate memory for pamEnv", logPrefix); |
155 |
+ return -1; |
156 |
+ } |
157 |
+ |
158 |
+- sprintf (pamEnv, "%s=%s", name, value); |
159 |
++ snprintf (pamEnv, pamEnvSize, "%s=%s", name, value); |
160 |
+ int ret = pam_putenv(pamh, pamEnv); |
161 |
+ free(pamEnv); |
162 |
+ |
163 |
+@@ -240,6 +241,11 @@ cleanup: |
164 |
+ return result; |
165 |
+ } |
166 |
+ |
167 |
++static void cleanup_free(pam_handle_t *pamh, void *ptr, int error_status) |
168 |
++{ |
169 |
++ free(ptr); |
170 |
++} |
171 |
++ |
172 |
+ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) |
173 |
+ { |
174 |
+ pam_syslog(pamh, LOG_INFO, "%s: pam_sm_authenticate\n", logPrefix); |
175 |
+@@ -297,14 +303,17 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, cons |
176 |
+ return PAM_IGNORE; |
177 |
+ } |
178 |
+ |
179 |
+- char *key = malloc(sizeof(char) * KWALLET_PAM_KEYSIZE); |
180 |
+- if (kwallet_hash(password, userInfo, key) != 0) { |
181 |
++ char *key = malloc(KWALLET_PAM_KEYSIZE); |
182 |
++ if (!key || kwallet_hash(password, userInfo, key) != 0) { |
183 |
++ free(key); |
184 |
+ pam_syslog(pamh, LOG_ERR, "%s: Fail into creating the hash", logPrefix); |
185 |
+ return PAM_IGNORE; |
186 |
+ } |
187 |
+ |
188 |
+- result = pam_set_data(pamh, kwalletPamDataKey, key, NULL); |
189 |
++ result = pam_set_data(pamh, kwalletPamDataKey, key, cleanup_free); |
190 |
++ |
191 |
+ if (result != PAM_SUCCESS) { |
192 |
++ free(key); |
193 |
+ pam_syslog(pamh, LOG_ERR, "%s: Impossible to store the hashed password: %s", logPrefix |
194 |
+ , pam_strerror(pamh, result)); |
195 |
+ return PAM_IGNORE; |
196 |
+@@ -385,9 +394,8 @@ cleanup: |
197 |
+ static int better_write(int fd, const char *buffer, int len) |
198 |
+ { |
199 |
+ size_t writtenBytes = 0; |
200 |
+- int result; |
201 |
+ while(writtenBytes < len) { |
202 |
+- result = write(fd, buffer + writtenBytes, len - writtenBytes); |
203 |
++ int result = write(fd, buffer + writtenBytes, len - writtenBytes); |
204 |
+ if (result < 0) { |
205 |
+ if (errno != EAGAIN && errno != EINTR) { |
206 |
+ return -1; |
207 |
+@@ -450,6 +458,7 @@ static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const cha |
208 |
+ if (result != PAM_SUCCESS) { |
209 |
+ pam_syslog(pamh, LOG_ERR, "%s: Impossible to set %s env, %s", |
210 |
+ logPrefix, envVar, pam_strerror(pamh, result)); |
211 |
++ free(fullSocket); |
212 |
+ return; |
213 |
+ } |
214 |
+ |
215 |
+@@ -459,12 +468,15 @@ static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const cha |
216 |
+ if (strlen(fullSocket) > sizeof(local.sun_path)) { |
217 |
+ pam_syslog(pamh, LOG_ERR, "%s: socket path %s too long to open", |
218 |
+ logPrefix, fullSocket); |
219 |
++ free(fullSocket); |
220 |
+ return; |
221 |
+ } |
222 |
+ strcpy(local.sun_path, fullSocket); |
223 |
++ free(fullSocket); |
224 |
++ fullSocket = NULL; |
225 |
+ unlink(local.sun_path);//Just in case it exists from a previous login |
226 |
+ |
227 |
+- pam_syslog(pamh, LOG_INFO, "%s: final socket path: %s", logPrefix, fullSocket); |
228 |
++ pam_syslog(pamh, LOG_INFO, "%s: final socket path: %s", logPrefix, local.sun_path); |
229 |
+ |
230 |
+ size_t len = strlen(local.sun_path) + sizeof(local.sun_family); |
231 |
+ if (bind(envSocket, (struct sockaddr *)&local, len) == -1) { |
232 |
+@@ -477,7 +489,7 @@ static void start_kwallet(pam_handle_t *pamh, struct passwd *userInfo, const cha |
233 |
+ return; |
234 |
+ } |
235 |
+ |
236 |
+- if (chown(fullSocket, userInfo->pw_uid, userInfo->pw_gid) == -1) { |
237 |
++ if (chown(local.sun_path, userInfo->pw_uid, userInfo->pw_gid) == -1) { |
238 |
+ pam_syslog(pamh, LOG_INFO, "%s: Couldn't change ownership of the socket", logPrefix); |
239 |
+ return; |
240 |
+ } |
241 |
+@@ -655,7 +667,8 @@ int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key) |
242 |
+ #else |
243 |
+ char *fixpath = "share/apps/kwallet/kdewallet.salt"; |
244 |
+ #endif |
245 |
+- char *path = (char*) malloc(strlen(userInfo->pw_dir) + strlen(kdehome) + strlen(fixpath) + 3);//3 == / and \0 |
246 |
++ size_t pathSize = strlen(userInfo->pw_dir) + strlen(kdehome) + strlen(fixpath) + 3;//3 == /, / and \0 |
247 |
++ char *path = (char*) malloc(pathSize); |
248 |
+ sprintf(path, "%s/%s/%s", userInfo->pw_dir, kdehome, fixpath); |
249 |
+ |
250 |
+ struct stat info; |
251 |
+@@ -666,21 +679,26 @@ int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key) |
252 |
+ FILE *fd = fopen(path, "r"); |
253 |
+ if (fd == NULL) { |
254 |
+ syslog(LOG_ERR, "%s: Couldn't open file: %s because: %d-%s", logPrefix, path, errno, strerror(errno)); |
255 |
++ free(path); |
256 |
+ return 1; |
257 |
+ } |
258 |
+- salt = (char*) malloc(sizeof(char) * KWALLET_PAM_SALTSIZE); |
259 |
++ salt = (char*) malloc(KWALLET_PAM_SALTSIZE); |
260 |
+ memset(salt, '\0', KWALLET_PAM_SALTSIZE); |
261 |
+ fread(salt, KWALLET_PAM_SALTSIZE, 1, fd); |
262 |
+ fclose(fd); |
263 |
+ } |
264 |
++ free(path); |
265 |
++ |
266 |
+ if (salt == NULL) { |
267 |
+ syslog(LOG_ERR, "%s-kwalletd: Couldn't create or read the salt file", logPrefix); |
268 |
+ return 1; |
269 |
+ } |
270 |
+ |
271 |
+ gcry_error_t error; |
272 |
++ |
273 |
+ error = gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0); |
274 |
+ if (error != 0) { |
275 |
++ free(salt); |
276 |
+ syslog(LOG_ERR, "%s-kwalletd: Can't get secure memory: %d", logPrefix, error); |
277 |
+ return 1; |
278 |
+ } |
279 |
+@@ -691,5 +709,7 @@ int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key) |
280 |
+ GCRY_KDF_PBKDF2, GCRY_MD_SHA512, |
281 |
+ salt, KWALLET_PAM_SALTSIZE, |
282 |
+ KWALLET_PAM_ITERATIONS,KWALLET_PAM_KEYSIZE, key); |
283 |
+- return 0; |
284 |
++ |
285 |
++ free(salt); |
286 |
++ return (int) error; // gcry_kdf_derive returns 0 on success |
287 |
+ } |
288 |
+-- |
289 |
+cgit v0.11.2 |
290 |
+ |
291 |
|
292 |
diff --git a/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-privileges.patch b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-privileges.patch |
293 |
new file mode 100644 |
294 |
index 00000000000..8b45b293bbf |
295 |
--- /dev/null |
296 |
+++ b/kde-plasma/kwallet-pam/files/kwallet-pam-5.10.5-privileges.patch |
297 |
@@ -0,0 +1,49 @@ |
298 |
+From 1a01e1eb870e1ab1d96a8641f1f3500af646c974 Mon Sep 17 00:00:00 2001 |
299 |
+From: Fabian Vogt <fabian@×××××××××××.de> |
300 |
+Date: Thu, 3 Aug 2017 09:27:10 +0200 |
301 |
+Subject: Avoid dropping privileges by initializing gcrypt secmem |
302 |
+ |
303 |
+Summary: |
304 |
+It's a documented side effect that initialization of secure memory in gcrypt |
305 |
+drops privileges if getuid() != geteuid(). This results in breaking setuid |
306 |
+callers, like sudo or su. |
307 |
+ |
308 |
+Test Plan: Can use sudo again when pam_kwallet is involved. |
309 |
+ |
310 |
+Reviewers: #plasma |
311 |
+ |
312 |
+Subscribers: plasma-devel |
313 |
+ |
314 |
+Tags: #plasma |
315 |
+ |
316 |
+Differential Revision: https://phabricator.kde.org/D7124 |
317 |
+--- |
318 |
+ pam_kwallet.c | 6 ++++++ |
319 |
+ 1 file changed, 6 insertions(+) |
320 |
+ |
321 |
+diff --git a/pam_kwallet.c b/pam_kwallet.c |
322 |
+index 46720a5..20d9603 100644 |
323 |
+--- a/pam_kwallet.c |
324 |
++++ b/pam_kwallet.c |
325 |
+@@ -722,12 +722,18 @@ int kwallet_hash(const char *passphrase, struct passwd *userInfo, char *key) |
326 |
+ |
327 |
+ gcry_error_t error; |
328 |
+ |
329 |
++ /* We cannot call GCRYCTL_INIT_SECMEM as it drops privileges if getuid() != geteuid(). |
330 |
++ * PAM modules are in many cases executed through setuid binaries, which this call |
331 |
++ * would break. |
332 |
++ * It was never effective anyway as neither key nor passphrase are in secure memory, |
333 |
++ * which is a prerequisite for secure operation... |
334 |
+ error = gcry_control(GCRYCTL_INIT_SECMEM, 32768, 0); |
335 |
+ if (error != 0) { |
336 |
+ free(salt); |
337 |
+ syslog(LOG_ERR, "%s-kwalletd: Can't get secure memory: %d", logPrefix, error); |
338 |
+ return 1; |
339 |
+ } |
340 |
++ */ |
341 |
+ |
342 |
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); |
343 |
+ |
344 |
+-- |
345 |
+cgit v0.11.2 |
346 |
+ |
347 |
|
348 |
diff --git a/kde-plasma/kwallet-pam/kwallet-pam-5.10.5-r1.ebuild b/kde-plasma/kwallet-pam/kwallet-pam-5.10.5-r1.ebuild |
349 |
new file mode 100644 |
350 |
index 00000000000..5798e8eaed5 |
351 |
--- /dev/null |
352 |
+++ b/kde-plasma/kwallet-pam/kwallet-pam-5.10.5-r1.ebuild |
353 |
@@ -0,0 +1,59 @@ |
354 |
+# Copyright 1999-2017 Gentoo Foundation |
355 |
+# Distributed under the terms of the GNU General Public License v2 |
356 |
+ |
357 |
+EAPI=6 |
358 |
+ |
359 |
+inherit kde5 |
360 |
+ |
361 |
+DESCRIPTION="KWallet PAM module to not enter password again" |
362 |
+LICENSE="LGPL-2.1" |
363 |
+KEYWORDS="~amd64 ~arm ~x86" |
364 |
+IUSE="" |
365 |
+ |
366 |
+DEPEND=" |
367 |
+ dev-libs/libgcrypt:0= |
368 |
+ virtual/pam |
369 |
+" |
370 |
+RDEPEND="${DEPEND} |
371 |
+ net-misc/socat |
372 |
+" |
373 |
+ |
374 |
+PATCHES=( |
375 |
+ "${FILESDIR}/${P}-cleanups.patch" |
376 |
+ "${FILESDIR}/${P}-check-graphical.patch" |
377 |
+ "${FILESDIR}/${P}-privileges.patch" |
378 |
+) |
379 |
+ |
380 |
+src_configure() { |
381 |
+ local mycmakeargs=( |
382 |
+ -DCMAKE_INSTALL_LIBDIR="/$(get_libdir)" |
383 |
+ -DKWALLET4=0 |
384 |
+ ) |
385 |
+ kde5_src_configure |
386 |
+} |
387 |
+ |
388 |
+pkg_postinst() { |
389 |
+ check_dm() { |
390 |
+ if [[ -e "${ROOT}${2}" ]] ; then |
391 |
+ if grep -Eq "auth\s+optional\s+pam_kwallet5.so" "${ROOT}${2}" && \ |
392 |
+ grep -Eq "session\s+optional\s+pam_kwallet5.so" "${ROOT}${2}" ; then |
393 |
+ elog " ${1} - ${2} ...GOOD" |
394 |
+ else |
395 |
+ ewarn " ${1} - ${2} ...BAD" |
396 |
+ fi |
397 |
+ fi |
398 |
+ } |
399 |
+ elog "This package enables auto-unlocking of kde-frameworks/kwallet:5." |
400 |
+ elog "List of things to make it work:" |
401 |
+ elog "1. Use standard blowfish encryption instead of GPG" |
402 |
+ elog "2. Use same password for login and kwallet" |
403 |
+ elog "3. A display manager with support for PAM" |
404 |
+ elog "4.a Have the following lines in the display manager's pam.d file:" |
405 |
+ elog " -auth optional pam_kwallet5.so" |
406 |
+ elog " -session optional pam_kwallet5.so auto_start" |
407 |
+ elog "4.b Checking installed DMs..." |
408 |
+ has_version "x11-misc/sddm" && check_dm "SDDM" "/etc/pam.d/sddm" |
409 |
+ has_version "x11-misc/lightdm" && check_dm "LightDM" "/etc/pam.d/lightdm" |
410 |
+ elog |
411 |
+ elog "See also: https://wiki.gentoo.org/wiki/KDE#KWallet_auto-unlocking" |
412 |
+} |