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); }