Merge lp:~freerdp-remote-team/libpam-freerdp/ubuntu into lp:~ubuntu-desktop/libpam-freerdp/ubuntu

Proposed by Ted Gould on 2012-09-05
Status: Merged
Merged at revision: 14
Proposed branch: lp:~freerdp-remote-team/libpam-freerdp/ubuntu
Merge into: lp:~ubuntu-desktop/libpam-freerdp/ubuntu
Diff against target: 753 lines (+423/-119)
7 files modified
ChangeLog (+96/-0)
configure (+10/-10)
configure.ac (+1/-1)
debian/changelog (+10/-0)
debian/source/format (+0/-1)
src/freerdp-auth-check.c (+11/-4)
src/pam-freerdp.c (+295/-103)
To merge this branch: bzr merge lp:~freerdp-remote-team/libpam-freerdp/ubuntu
Reviewer Review Type Date Requested Status
Ubuntu Desktop 2012-09-05 Pending
Review via email: mp+122947@code.launchpad.net

Description of the Change

0.4.0

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2012-08-29 15:31:18 +0000
3+++ ChangeLog 2012-09-05 20:59:30 +0000
4@@ -1,5 +1,101 @@
5 # Generated by Makefile. Do not edit.
6
7+2012-09-05 Ted Gould <ted@gould.cx>
8+
9+ 0.4.0
10+
11+2012-09-04 Ted Gould <ted@gould.cx>
12+
13+ Making the open_session kill also unpriv. Approved by Albert Astals Cid, jenkins.
14+
15+2012-09-04 Ted Gould <ted@gould.cx>
16+
17+ Using the new function in the open_session function instead of killing directly.
18+
19+2012-09-04 Ted Gould <ted@gould.cx>
20+
21+ Moving the kill code into a function
22+
23+2012-08-31 Ted Gould <ted@gould.cx>
24+
25+ Resolving concerns of the security team. Fixes: https://bugs.launchpad.net/bugs/1039634. Approved by Albert Astals Cid, jenkins.
26+
27+2012-08-30 Ted Gould <ted@gould.cx>
28+
29+ Clearing the groups, but handling the EPERM issue with not being root
30+
31+2012-08-30 Ted Gould <ted@gould.cx>
32+
33+ Attaching bug
34+
35+2012-08-30 Ted Gould <ted@gould.cx>
36+
37+ Removing setgroups as it doesn't seem to be working
38+
39+2012-08-30 Ted Gould <ted@gould.cx>
40+
41+ Clear the session_pid after trying to kill it.
42+
43+2012-08-30 Ted Gould <ted@gould.cx>
44+
45+ Making sure to kill as the user so that if there is PID wrap or something else we won't kill the wrong thing
46+
47+2012-08-30 Ted Gould <ted@gould.cx>
48+
49+ Make sure to change the working directory for the subprocesses to the guest user's home directory
50+
51+2012-08-30 Ted Gould <ted@gould.cx>
52+
53+ Dropping the ignoring of the cert
54+
55+2012-08-30 Ted Gould <ted@gould.cx>
56+
57+ Make sure to lock the password buffer
58+
59+2012-08-30 Ted Gould <ted@gould.cx>
60+
61+ Clear the groups when dropping privs
62+
63+2012-08-30 Ted Gould <ted@gould.cx>
64+
65+ Make sure to clear the environments
66+
67+2012-08-30 Ted Gould <ted@gould.cx>
68+
69+ Locking memory if we expect the prompt to be returning a password
70+
71+2012-08-30 Ted Gould <ted@gould.cx>
72+
73+ Checking the return value of the mlock
74+
75+2012-08-30 Ted Gould <ted@gould.cx>
76+
77+ Use the pipe to signal when the subprocess has gotten to a point where it can opperate.
78+
79+2012-08-30 Ted Gould <ted@gould.cx>
80+
81+ Setting up a pipe to communicate with the sub process
82+
83+2012-08-30 Ted Gould <ted@gould.cx>
84+
85+ Checking the return for mlock and snprintf
86+
87+2012-08-30 Ted Gould <ted@gould.cx>
88+
89+ Restructure so that clean up is all at the end of the function
90+
91+2012-08-30 Ted Gould <ted@gould.cx>
92+
93+ Moving buffer allocation into the function
94+
95+2012-08-30 Ted Gould <ted@gould.cx>
96+
97+ Move the socket creation into the fork'd function
98+
99+2012-08-30 Ted Gould <ted@gould.cx>
100+
101+ Refactor to pull the long running stuff out of the if statement and into a function
102+
103 2012-08-29 Ted Gould <ted@gould.cx>
104
105 0.3.0
106
107=== modified file 'configure'
108--- configure 2012-08-29 15:31:18 +0000
109+++ configure 2012-09-05 20:59:30 +0000
110@@ -1,6 +1,6 @@
111 #! /bin/sh
112 # Guess values for system-dependent variables and create Makefiles.
113-# Generated by GNU Autoconf 2.69 for libpam-freerdp 0.3.0.
114+# Generated by GNU Autoconf 2.69 for libpam-freerdp 0.4.0.
115 #
116 #
117 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
118@@ -587,8 +587,8 @@
119 # Identity of this package.
120 PACKAGE_NAME='libpam-freerdp'
121 PACKAGE_TARNAME='libpam-freerdp'
122-PACKAGE_VERSION='0.3.0'
123-PACKAGE_STRING='libpam-freerdp 0.3.0'
124+PACKAGE_VERSION='0.4.0'
125+PACKAGE_STRING='libpam-freerdp 0.4.0'
126 PACKAGE_BUGREPORT=''
127 PACKAGE_URL=''
128
129@@ -1318,7 +1318,7 @@
130 # Omit some internal or obsolete options to make the list less imposing.
131 # This message is too long to be a string in the A/UX 3.1 sh.
132 cat <<_ACEOF
133-\`configure' configures libpam-freerdp 0.3.0 to adapt to many kinds of systems.
134+\`configure' configures libpam-freerdp 0.4.0 to adapt to many kinds of systems.
135
136 Usage: $0 [OPTION]... [VAR=VALUE]...
137
138@@ -1388,7 +1388,7 @@
139
140 if test -n "$ac_init_help"; then
141 case $ac_init_help in
142- short | recursive ) echo "Configuration of libpam-freerdp 0.3.0:";;
143+ short | recursive ) echo "Configuration of libpam-freerdp 0.4.0:";;
144 esac
145 cat <<\_ACEOF
146
147@@ -1501,7 +1501,7 @@
148 test -n "$ac_init_help" && exit $ac_status
149 if $ac_init_version; then
150 cat <<\_ACEOF
151-libpam-freerdp configure 0.3.0
152+libpam-freerdp configure 0.4.0
153 generated by GNU Autoconf 2.69
154
155 Copyright (C) 2012 Free Software Foundation, Inc.
156@@ -1779,7 +1779,7 @@
157 This file contains any messages produced by compilers while
158 running configure, to aid debugging if configure makes a mistake.
159
160-It was created by libpam-freerdp $as_me 0.3.0, which was
161+It was created by libpam-freerdp $as_me 0.4.0, which was
162 generated by GNU Autoconf 2.69. Invocation command line was
163
164 $ $0 $@
165@@ -2597,7 +2597,7 @@
166
167 # Define the identity of the package.
168 PACKAGE='libpam-freerdp'
169- VERSION='0.3.0'
170+ VERSION='0.4.0'
171
172
173 cat >>confdefs.h <<_ACEOF
174@@ -12068,7 +12068,7 @@
175 # report actual input values of CONFIG_FILES etc. instead of their
176 # values after options handling.
177 ac_log="
178-This file was extended by libpam-freerdp $as_me 0.3.0, which was
179+This file was extended by libpam-freerdp $as_me 0.4.0, which was
180 generated by GNU Autoconf 2.69. Invocation command line was
181
182 CONFIG_FILES = $CONFIG_FILES
183@@ -12134,7 +12134,7 @@
184 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
185 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
186 ac_cs_version="\\
187-libpam-freerdp config.status 0.3.0
188+libpam-freerdp config.status 0.4.0
189 configured by $0, generated by GNU Autoconf 2.69,
190 with options \\"\$ac_cs_config\\"
191
192
193=== modified file 'configure.ac'
194--- configure.ac 2012-08-29 15:28:35 +0000
195+++ configure.ac 2012-09-05 20:59:30 +0000
196@@ -1,4 +1,4 @@
197-AC_INIT([libpam-freerdp], [0.3.0])
198+AC_INIT([libpam-freerdp], [0.4.0])
199 AC_CONFIG_HEADERS([config.h])
200
201 AM_INIT_AUTOMAKE([1.11 -Wno-portability])
202
203=== modified file 'debian/changelog'
204--- debian/changelog 2012-08-29 17:37:03 +0000
205+++ debian/changelog 2012-09-05 20:59:30 +0000
206@@ -1,3 +1,13 @@
207+libpam-freerdp (0.4.0-0ubuntu1~ppa1) quantal; urgency=low
208+
209+ * New upstream release.
210+ * Security fixes for priviledged kill of PID
211+ * Ensuring return values are trapped
212+ * Binding port after dropping permissions
213+ * Handling more corner cases
214+
215+ -- Ted Gould <ted@ubuntu.com> Wed, 05 Sep 2012 15:57:55 -0500
216+
217 libpam-freerdp (0.3.0-0ubuntu1) quantal; urgency=low
218
219 * New upstream release.
220
221=== removed directory 'debian/source'
222=== removed file 'debian/source/format'
223--- debian/source/format 2012-08-21 15:48:21 +0000
224+++ debian/source/format 1970-01-01 00:00:00 +0000
225@@ -1,1 +0,0 @@
226-3.0 (quilt)
227
228=== modified file 'src/freerdp-auth-check.c'
229--- src/freerdp-auth-check.c 2012-08-27 20:07:36 +0000
230+++ src/freerdp-auth-check.c 2012-09-05 20:59:30 +0000
231@@ -60,6 +60,10 @@
232 return -1;
233 }
234
235+ if (mlock(password, sizeof(password)) != 0) {
236+ return -1;
237+ }
238+
239 freerdp_channels_global_init();
240
241 freerdp * instance = freerdp_new();
242@@ -77,7 +81,6 @@
243 instance->settings->username = argv[2];
244 instance->settings->domain = argv[3];
245 instance->settings->password = password;
246- instance->settings->ignore_certificate = true;
247
248 char * colonloc = strstr(argv[1], ":");
249 if (colonloc != NULL) {
250@@ -88,10 +91,14 @@
251 instance->settings->port = strtoul(colonloc, NULL, 10);
252 }
253
254+ int retval = -1;
255 if (freerdp_connect(instance)) {
256 freerdp_disconnect(instance);
257- return 0;
258- } else {
259- return -1;
260+ retval = 0;
261 }
262+
263+ memset(password, 0, sizeof(password));
264+ munlock(password, sizeof(password));
265+
266+ return retval;
267 }
268
269=== modified file 'src/pam-freerdp.c'
270--- src/pam-freerdp.c 2012-08-29 15:34:27 +0000
271+++ src/pam-freerdp.c 2012-09-05 20:59:30 +0000
272@@ -27,12 +27,17 @@
273 #include <sys/mman.h>
274 #include <sys/un.h>
275 #include <pwd.h>
276+#include <grp.h>
277+#include <errno.h>
278
279 #include <security/pam_modules.h>
280 #include <security/pam_modutil.h>
281 #include <security/pam_appl.h>
282
283 #define PAM_TYPE_DOMAIN 1234
284+#define ALL_GOOD_SIGNAL "Ar, ready to authenticate cap'n"
285+
286+static int unpriveleged_kill (struct passwd * pwdent);
287
288 static char * global_domain = NULL;
289 /* FIXME? This is a work around to the fact that PAM seems to be clearing
290@@ -109,6 +114,18 @@
291 char * promptval = responses->resp;
292 free(responses);
293
294+ /* If we didn't get anything, just move on */
295+ if (promptval == NULL) {
296+ return NULL;
297+ }
298+
299+ if (type == PAM_AUTHTOK) {
300+ if (mlock(promptval, strlen(promptval) + 1) != 0) {
301+ free(promptval);
302+ return NULL;
303+ }
304+ }
305+
306 if (type == PAM_RHOST) {
307 char * subloc = strstr(promptval, "://");
308 if (subloc != NULL) {
309@@ -145,12 +162,22 @@
310 /* We also save the password globally if we've got one */
311 if (global_password != NULL) {
312 memset(global_password, 0, strlen(global_password));
313- munlock(global_password, strlen(global_password));
314+ munlock(global_password, strlen(global_password) + 1);
315 free(global_password);
316 }
317 global_password = strdup(promptval);
318- mlock(global_password, strlen(global_password));
319- retval = global_password;
320+ if (mlock(global_password, strlen(global_password) + 1) != 0) {
321+ /* Woah, can't lock it. Can't keep it. */
322+ free(global_password);
323+ global_password = NULL;
324+ } else {
325+ retval = global_password;
326+ }
327+ }
328+
329+ if (type == PAM_AUTHTOK) {
330+ memset(promptval, 0, strlen(promptval) + 1);
331+ munlock(promptval, strlen(promptval) + 1);
332 }
333
334 free(promptval);
335@@ -210,11 +237,25 @@
336 _exit(EXIT_FAILURE);
337 }
338
339+ /* Setting groups, but allowing EPERM as if we're not 100% root
340+ we might not be able to do this */
341+ if (setgroups(1, &pwdent->pw_gid) != 0 && errno != EPERM) {
342+ _exit(EXIT_FAILURE);
343+ }
344+
345 if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 ||
346 setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) {
347 _exit(EXIT_FAILURE);
348 }
349
350+ if (clearenv() != 0) {
351+ _exit(EXIT_FAILURE);
352+ }
353+
354+ if (chdir(pwdent->pw_dir) != 0) {
355+ _exit(EXIT_FAILURE);
356+ }
357+
358 setenv("HOME", pwdent->pw_dir, 1);
359
360 execvp(args[0], args);
361@@ -249,47 +290,88 @@
362 return retval;
363 }
364
365-pid_t session_pid = 0;
366-/* Open Session. Here we need to fork a little process so that we can
367- give the credentials to the session itself so that it can startup the
368- xfreerdp viewer for the login */
369-PAM_EXTERN int
370-pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, const char ** argv)
371+static int
372+session_socket_handler (struct passwd * pwdent, int readypipe, const char * ruser, const char * rhost, const char * rdomain, const char * password)
373 {
374- if (session_pid != 0) {
375- kill(session_pid, SIGKILL);
376- session_pid = 0;
377- }
378-
379- char * username = NULL;
380- char * password = NULL;
381- char * ruser = NULL;
382- char * rhost = NULL;
383- char * rdomain = NULL;
384- int retval = PAM_SUCCESS;
385-
386- /* Get all the values, or prompt for them, or return with
387- an auth error */
388- GET_ITEM(username, PAM_USER);
389- GET_ITEM(ruser, PAM_RUSER);
390- GET_ITEM(rhost, PAM_RHOST);
391- GET_ITEM(rdomain, PAM_TYPE_DOMAIN);
392- GET_ITEM(password, PAM_AUTHTOK);
393-
394- struct passwd * pwdent = getpwnam(username);
395- if (pwdent == NULL) {
396- retval = PAM_SYSTEM_ERR;
397- goto done;
398- }
399-
400+ /* Socket stuff */
401+ int socketfd = 0;
402+ struct sockaddr_un socket_addr;
403+
404+ /* Connected user */
405+ socklen_t connected_addr_size;
406+ int connectfd = 0;
407+ struct sockaddr_un connected_addr;
408+
409+ /* Our buffer */
410+ char * buffer = NULL;
411+ int buffer_len = 0;
412+ int buffer_fill = 0;
413+
414+ /* Track write out */
415+ int writedata = 0;
416+
417+ /* Track ready writing */
418+ int readywrite = 0;
419+
420+ /* Setting groups, but allowing EPERM as if we're not 100% root
421+ we might not be able to do this */
422+ if (setgroups(1, &pwdent->pw_gid) != 0 && errno != EPERM) {
423+ _exit(EXIT_FAILURE);
424+ }
425+
426+ if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 ||
427+ setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) {
428+ /* Don't need to clean up yet */
429+ return EXIT_FAILURE;
430+ }
431+
432+ if (clearenv() != 0) {
433+ /* Don't need to clean up yet */
434+ return EXIT_FAILURE;
435+ }
436+
437+ if (chdir(pwdent->pw_dir) != 0) {
438+ /* Don't need to clean up yet */
439+ return EXIT_FAILURE;
440+ }
441+
442+ /* Build this up as a buffer so we can just write it and see that
443+ very, very clearly */
444+ buffer_len += strlen(ruser) + 1; /* Add one for the space */
445+ buffer_len += strlen(rhost) + 1; /* Add one for the space */
446+ buffer_len += strlen(rdomain) + 1; /* Add one for the space */
447+ buffer_len += strlen(password) + 1; /* Add one for the NULL */
448+
449+ if (buffer_len < 5) {
450+ /* Don't need to clean up yet */
451+ return EXIT_FAILURE;
452+ }
453+
454+ buffer = malloc(buffer_len);
455+
456+ if (buffer == NULL) {
457+ /* Don't need to clean up yet */
458+ return EXIT_FAILURE;
459+ }
460+
461+ /* Lock the buffer before writing */
462+ if (mlock(buffer, buffer_len) != 0) {
463+ /* We can't lock, we go home */
464+ goto cleanup;
465+ }
466+
467+ buffer_fill = snprintf(buffer, buffer_len, "%s %s %s %s", ruser, password, rdomain, rhost);
468+ if (buffer_fill > buffer_len) {
469+ /* This really shouldn't happen, but if for some reason we have an
470+ difference between they way that the lengths are calculated we want
471+ to catch that. */
472+ goto cleanup;
473+ }
474+
475 /* Make our socket and bind it */
476- int socketfd;
477- struct sockaddr_un socket_addr;
478-
479 socketfd = socket(AF_UNIX, SOCK_STREAM, 0);
480 if (socketfd < 0) {
481- retval = PAM_SYSTEM_ERR;
482- goto done;
483+ goto cleanup;
484 }
485
486 memset(&socket_addr, 0, sizeof(struct sockaddr_un));
487@@ -301,80 +383,123 @@
488 there isn't a race condition to get to it. Things will block
489 otherwise. */
490 if (bind(socketfd, (struct sockaddr *)&socket_addr, sizeof(struct sockaddr_un)) < 0) {
491- close(socketfd);
492- retval = PAM_SYSTEM_ERR;
493- goto done;
494+ goto cleanup;
495 }
496
497 /* Set the socket file permissions to be 600 and the user and group
498 to be the guest user. NOTE: This won't protect on BSD */
499 if (chmod(socket_addr.sun_path, S_IRUSR | S_IWUSR) != 0 ||
500 chown(socket_addr.sun_path, pwdent->pw_uid, pwdent->pw_gid) != 0) {
501+ goto cleanup;
502+ }
503+
504+ if (listen(socketfd, 1) < 0) {
505+ goto cleanup;
506+ }
507+
508+ readywrite = write(readypipe, ALL_GOOD_SIGNAL, strlen(ALL_GOOD_SIGNAL) + 1);
509+ if (readywrite != strlen(ALL_GOOD_SIGNAL) + 1) {
510+ goto cleanup;
511+ }
512+
513+ connected_addr_size = sizeof(struct sockaddr_un);
514+ connectfd = accept(socketfd, (struct sockaddr *)&connected_addr, &connected_addr_size);
515+ if (connectfd < 0) {
516+ goto cleanup;
517+ }
518+
519+ writedata = write(connectfd, buffer, buffer_len);
520+
521+cleanup:
522+ if (socketfd != 0) {
523 close(socketfd);
524- retval = PAM_SYSTEM_ERR;
525- goto done;
526 }
527-
528- /* Build this up as a buffer so we can just write it and see that
529- very, very clearly */
530- int buffer_len = 0;
531- buffer_len += strlen(ruser) + 1; /* Add one for the space */
532- buffer_len += strlen(rhost) + 1; /* Add one for the space */
533- buffer_len += strlen(rdomain) + 1; /* Add one for the space */
534- buffer_len += strlen(password) + 1; /* Add one for the NULL */
535-
536- char * buffer = malloc(buffer_len);
537- /* Lock the buffer before writing */
538- mlock(buffer, buffer_len);
539- snprintf(buffer, buffer_len, "%s %s %s %s", ruser, password, rdomain, rhost);
540-
541- pid_t pid = fork();
542- if (pid == 0) {
543- /* Locks to carry over */
544- mlock(buffer, buffer_len);
545-
546- if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 ||
547- setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) {
548- _exit(EXIT_FAILURE);
549- }
550-
551- if (listen(socketfd, 1) < 0) {
552- _exit(EXIT_FAILURE);
553- }
554-
555- socklen_t connected_addr_size;
556- int connectfd;
557- struct sockaddr_un connected_addr;
558-
559- connected_addr_size = sizeof(struct sockaddr_un);
560- connectfd = accept(socketfd, (struct sockaddr *)&connected_addr, &connected_addr_size);
561- if (connectfd < 0) {
562- _exit(EXIT_FAILURE);
563- }
564-
565- int writedata;
566- writedata = write(connectfd, buffer, buffer_len);
567-
568+ if (connectfd != 0) {
569 close(connectfd);
570- close(socketfd);
571+ }
572+
573+ if (buffer != NULL) {
574+ memset(buffer, 0, buffer_len);
575+ munlock(buffer, buffer_len);
576 free(buffer);
577-
578- if (writedata == buffer_len) {
579- _exit(0);
580+ buffer = NULL;
581+ }
582+
583+ /* This should be only true on the write, so we can use this to check
584+ out as writedata is init to 0 */
585+ if (writedata == buffer_len) {
586+ return 0;
587+ }
588+
589+ return EXIT_FAILURE;
590+}
591+
592+pid_t session_pid = 0;
593+/* Open Session. Here we need to fork a little process so that we can
594+ give the credentials to the session itself so that it can startup the
595+ xfreerdp viewer for the login */
596+PAM_EXTERN int
597+pam_sm_open_session (pam_handle_t *pamh, int flags, int argc, const char ** argv)
598+{
599+ char * username = NULL;
600+ char * password = NULL;
601+ char * ruser = NULL;
602+ char * rhost = NULL;
603+ char * rdomain = NULL;
604+ int retval = PAM_SUCCESS;
605+
606+ /* Get all the values, or prompt for them, or return with
607+ an auth error */
608+ GET_ITEM(username, PAM_USER);
609+ GET_ITEM(ruser, PAM_RUSER);
610+ GET_ITEM(rhost, PAM_RHOST);
611+ GET_ITEM(rdomain, PAM_TYPE_DOMAIN);
612+ GET_ITEM(password, PAM_AUTHTOK);
613+
614+ struct passwd * pwdent = getpwnam(username);
615+ if (pwdent == NULL) {
616+ retval = PAM_SYSTEM_ERR;
617+ goto done;
618+ }
619+
620+ if (session_pid != 0) {
621+ unpriveleged_kill(pwdent);
622+ }
623+
624+ int sessionready[2];
625+ if (pipe(sessionready) != 0) {
626+ retval = PAM_SYSTEM_ERR;
627+ goto done;
628+ }
629+
630+ pid_t pid = fork();
631+ if (pid == 0) {
632+ int retval = 0;
633+
634+ retval = session_socket_handler(pwdent, sessionready[1], ruser, rhost, rdomain, password);
635+
636+ close(sessionready[1]);
637+ _exit(retval);
638+ } else if (pid < 0) {
639+ close(sessionready[0]);
640+ close(sessionready[1]);
641+
642+ retval = PAM_SYSTEM_ERR;
643+ } else {
644+ char readbuffer[strlen(ALL_GOOD_SIGNAL) + 1];
645+ int readlen = 0;
646+
647+ readlen = read(sessionready[0], readbuffer, strlen(ALL_GOOD_SIGNAL) + 1);
648+
649+ close(sessionready[0]);
650+
651+ if (readlen == strlen(ALL_GOOD_SIGNAL) + 1) {
652+ session_pid = pid;
653 } else {
654- _exit(EXIT_FAILURE);
655+ retval = PAM_SYSTEM_ERR;
656 }
657- } else if (pid < 0) {
658- retval = PAM_SYSTEM_ERR;
659- close(socketfd);
660- } else {
661- session_pid = pid;
662 }
663
664- memset(buffer, 0, buffer_len);
665- munlock(buffer, buffer_len);
666- free(buffer);
667-
668 done:
669 return retval;
670 }
671@@ -384,12 +509,79 @@
672 PAM_EXTERN int
673 pam_sm_close_session (pam_handle_t *pamh, int flags, int argc, const char **argv)
674 {
675- if (session_pid != 0) {
676- kill(session_pid, SIGKILL);
677+ if (session_pid == 0) {
678+ return PAM_IGNORE;
679+ }
680+
681+ char * username = NULL;
682+ int retval = PAM_SUCCESS;
683+
684+ GET_ITEM(username, PAM_USER);
685+
686+ struct passwd * pwdent = getpwnam(username);
687+ if (pwdent == NULL) {
688+ retval = PAM_SYSTEM_ERR;
689+ goto done;
690+ }
691+
692+ retval = unpriveleged_kill(pwdent);
693+
694+done:
695+ return retval;
696+}
697+
698+/* Drop privs and try to kill the process with the PID of session_pid.
699+ This ensures that we don't kill something important if there is PID wrap
700+ around. */
701+static int
702+unpriveleged_kill (struct passwd * pwdent)
703+{
704+ int retval = PAM_SUCCESS;
705+
706+ pid_t pid = fork();
707+ if (pid == 0) {
708+ /* Setting groups, but allowing EPERM as if we're not 100% root
709+ we might not be able to do this */
710+ if (setgroups(1, &pwdent->pw_gid) != 0 && errno != EPERM) {
711+ _exit(EXIT_FAILURE);
712+ }
713+
714+ if (setgid(pwdent->pw_gid) < 0 || setuid(pwdent->pw_uid) < 0 ||
715+ setegid(pwdent->pw_gid) < 0 || seteuid(pwdent->pw_uid) < 0) {
716+ _exit(EXIT_FAILURE);
717+ }
718+
719+ if (clearenv() != 0) {
720+ _exit(EXIT_FAILURE);
721+ }
722+
723+ int killval = kill(session_pid, SIGKILL);
724 session_pid = 0;
725+
726+ if (killval != 0) {
727+ printf("Unable to kill\n");
728+ }
729+
730+ /* NOTE: We're ignoring whether we could kill it or not. It'd be nice to
731+ track that but there are a lot of reason that we could fail there and
732+ it's not a bad thing. Really we're attempting a best effort to clean up
733+ we won't be able to gaurantee it. */
734+ _exit(EXIT_SUCCESS);
735+ } else if (pid < 0) {
736+ retval = PAM_SYSTEM_ERR;
737+ } else {
738+ int forkret = 0;
739+
740+ if (waitpid(pid, &forkret, 0) < 0) {
741+ retval = PAM_SYSTEM_ERR;
742+ }
743 }
744
745- return PAM_IGNORE;
746+ /* We reset this no matter. If we error'd trying to do it, we don't
747+ want to try again. We'll just return the error for this time. */
748+ session_pid = 0;
749+
750+ return retval;
751 }
752
753 /* LightDM likes to have this function around, but we don't need it as we

Subscribers

People subscribed via source and target branches