Based on your comments to the bug I filed against gdm, here's a patch
that disables the SIGCHLD handler while waiting for the helper process
to exit. This seems to be the approach favoured by upstream; the same
modifications were made to pam_unix and pam_pwdb:
<https://www.redhat.com/archives/pam-list/2002-September/msg00040.html>.

I also changed from wait(2) to waitpid(2) in case the authenticating
process has other children that happen to change state while pam_tmpdir
is waiting on the helper process.

--
Sam Morris
http://robots.org.uk/

PGP key id 5EA01078
3412 EA18 1277 354B 991B  C869 B219 7FDB 5EA0 1078

--- pam-tmpdir-0.05/pam_tmpdir.c        2006-03-07 17:52:16.000000000 +0000
+++ pam-tmpdir-0.05+sam/pam_tmpdir.c    2006-03-07 19:41:07.000000000 +0000
@@ -15,6 +15,7 @@
 #include <ctype.h>
 #include <errno.h>
 #include <pwd.h>
+#include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -94,6 +95,19 @@
   int ret = 0;
   int status;
   pid_t pid;
+  struct sigaction old, new;
+
+  new.sa_handler = SIG_DFL;
+  sigemptyset(&new.sa_mask);
+  new.sa_flags = 0;
+
+  /* save old signal handler */
+  ret = sigaction(SIGCHLD, &new, &old);
+  if (ret == -1) {
+    _log_err(LOG_WARNING, "could not save SIGCHLD handler");
+    return 1;
+  }
+
   /* Do fork and exec by hand.. */
   pid = fork();
   if (!pid) {
@@ -101,8 +115,21 @@
     if (geteuid() == 0)
       setuid(get_user_id(pamh));
     execl(PAM_TMPDIR_HELPER,PAM_TMPDIR_HELPER,NULL);
-    }
-  wait(&status);
+  }
+
+  ret = waitpid(pid, &status, 0);
+  if (ret == -1) {
+    _log_err(LOG_ERR, "error waiting for helper binary (%d)\n", errno);
+    return 1;
+  }
+
+  /* restore old signal handler */
+  ret = sigaction(SIGCHLD, &old, NULL);
+  if (ret == -1) {
+    _log_err(LOG_WARNING, "could not restore SIGCHLD handler");
+    return 1;
+  }
+
   return WEXITSTATUS(status);
 }

Reply via email to