summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2006-09-07 17:13:33 +0200
committerWerner Koch <wk@gnupg.org>2006-09-07 17:13:33 +0200
commit6374763c985a36c25d3cea9a8a83b51f42708160 (patch)
tree901f4d3762afff15b6adc1dc9f8c21b8b16be617 /common
parentAdded missing file (diff)
downloadgnupg2-6374763c985a36c25d3cea9a8a83b51f42708160.tar.xz
gnupg2-6374763c985a36c25d3cea9a8a83b51f42708160.zip
Let scdaemon call a script on status changes
Diffstat (limited to 'common')
-rw-r--r--common/ChangeLog7
-rw-r--r--common/exechelp.c168
-rw-r--r--common/exechelp.h12
3 files changed, 146 insertions, 41 deletions
diff --git a/common/ChangeLog b/common/ChangeLog
index 7a917fdd7..88dfdff9c 100644
--- a/common/ChangeLog
+++ b/common/ChangeLog
@@ -1,3 +1,10 @@
+2006-09-07 Werner Koch <wk@g10code.com>
+
+ * exechelp.c (gnupg_spawn_process): Factor out post fork code to ..
+ (do_exec): .. new function. Allow passing of -1 for the fds.
+ (gnupg_spawn_process): Terminate gcrypt's secure memory in the child.
+ (gnupg_spawn_process_detached): New.
+
2006-09-06 Werner Koch <wk@g10code.com>
* maperror.c: Removed.
diff --git a/common/exechelp.c b/common/exechelp.c
index e64b69022..cfb76c2f5 100644
--- a/common/exechelp.c
+++ b/common/exechelp.c
@@ -28,6 +28,7 @@
#include <assert.h>
#include <signal.h>
#include <unistd.h>
+#include <fcntl.h>
#ifdef USE_GNU_PTH
#include <pth.h>
#endif
@@ -159,6 +160,67 @@ create_inheritable_pipe (int filedes[2])
#endif /*HAVE_W32_SYSTEM*/
+#ifndef HAVE_W32_SYSTEM
+/* The exec core used right after the fork. This will never return. */
+static void
+do_exec (const char *pgmname, const char *argv[],
+ int fd_in, int fd_out, int fd_err,
+ void (*preexec)(void) )
+{
+ char **arg_list;
+ int n, i, j;
+ int fds[3];
+
+ fds[0] = fd_in;
+ fds[1] = fd_out;
+ fds[2] = fd_err;
+
+ /* Create the command line argument array. */
+ i = 0;
+ if (argv)
+ while (argv[i])
+ i++;
+ arg_list = xcalloc (i+2, sizeof *arg_list);
+ arg_list[0] = strrchr (pgmname, '/');
+ if (arg_list[0])
+ arg_list[0]++;
+ else
+ arg_list[0] = xstrdup (pgmname);
+ if (argv)
+ for (i=0,j=1; argv[i]; i++, j++)
+ arg_list[j] = (char*)argv[i];
+
+ /* Connect the standard files. */
+ for (i=0; i <= 2; i++)
+ {
+ if (fds[i] == -1 )
+ {
+ fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
+ if (fds[i] == -1)
+ log_fatal ("failed to open `%s': %s\n",
+ "/dev/null", strerror (errno));
+ }
+ else if (fds[i] != i && dup2 (fds[i], i) == -1)
+ log_fatal ("dup2 std%s failed: %s\n",
+ i==0?"in":i==1?"out":"err", strerror (errno));
+ }
+
+ /* Close all other files. */
+ n = sysconf (_SC_OPEN_MAX);
+ if (n < 0)
+ n = MAX_OPEN_FDS;
+ for (i=3; i < n; i++)
+ close(i);
+ errno = 0;
+
+ if (preexec)
+ preexec ();
+ execv (pgmname, arg_list);
+ /* No way to print anything, as we have closed all streams. */
+ _exit (127);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
/* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
stdin, write the output to OUTFILE, return a new stream in
@@ -325,47 +387,10 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
if (!*pid)
{
- /* Child. */
- char **arg_list;
- int n, i, j;
-
- /* Create the command line argument array. */
- for (i=0; argv[i]; i++)
- ;
- arg_list = xcalloc (i+2, sizeof *arg_list);
- arg_list[0] = strrchr (pgmname, '/');
- if (arg_list[0])
- arg_list[0]++;
- else
- arg_list[0] = xstrdup (pgmname);
- for (i=0,j=1; argv[i]; i++, j++)
- arg_list[j] = (char*)argv[i];
-
- /* Connect the infile to stdin. */
- if (fd != 0 && dup2 (fd, 0) == -1)
- log_fatal ("dup2 stdin failed: %s\n", strerror (errno));
-
- /* Connect the outfile to stdout. */
- if (fdout != 1 && dup2 (fdout, 1) == -1)
- log_fatal ("dup2 stdout failed: %s\n", strerror (errno));
-
- /* Connect stderr to our pipe. */
- if (rp[1] != 2 && dup2 (rp[1], 2) == -1)
- log_fatal ("dup2 stderr failed: %s\n", strerror (errno));
-
- /* Close all other files. */
- n = sysconf (_SC_OPEN_MAX);
- if (n < 0)
- n = MAX_OPEN_FDS;
- for (i=3; i < n; i++)
- close(i);
- errno = 0;
-
- if (preexec)
- preexec ();
- execv (pgmname, arg_list);
- /* No way to print anything, as we have closed all streams. */
- _exit (127);
+ gcry_control (GCRYCTL_TERM_SECMEM);
+ /* Run child. */
+ do_exec (pgmname, argv, fd, fdout, rp[1], preexec);
+ /*NOTREACHED*/
}
/* Parent. */
@@ -481,3 +506,64 @@ gnupg_wait_process (const char *pgmname, pid_t pid)
}
+
+/* Spawn a new process and immediatley detach from it. The name of
+ the program to exec is PGMNAME and its arguments are in ARGV (the
+ programname is automatically passed as first argument).
+ Environment strings in ENVP are set. An error is returned if
+ pgmname is not executable; to make this work it is necessary to
+ provide an absolute file name. All standard file descriptors are
+ connected to /dev/null. */
+gpg_error_t
+gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
+ const char *envp[] )
+{
+#ifdef HAVE_W32_SYSTEM
+ return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#else
+ pid_t pid;
+ int i;
+
+ if (getuid() != geteuid())
+ return gpg_error (GPG_ERR_BUG);
+
+ if (access (pgmname, X_OK))
+ return gpg_error_from_errno (errno);
+
+#ifdef USE_GNU_PTH
+ pid = pth_fork? pth_fork () : fork ();
+#else
+ pid = fork ();
+#endif
+ if (pid == (pid_t)(-1))
+ {
+ log_error (_("error forking process: %s\n"), strerror (errno));
+ return gpg_error_from_errno (errno);
+ }
+ if (!pid)
+ {
+ gcry_control (GCRYCTL_TERM_SECMEM);
+ if (setsid() == -1 || chdir ("/"))
+ _exit (1);
+ pid = fork (); /* Double fork to let init takes over the new child. */
+ if (pid == (pid_t)(-1))
+ _exit (1);
+ if (pid)
+ _exit (0); /* Let the parent exit immediately. */
+
+ if (envp)
+ for (i=0; envp[i]; i++)
+ putenv (xstrdup (envp[i]));
+
+ do_exec (pgmname, argv, -1, -1, -1, NULL);
+
+ /*NOTREACHED*/
+ }
+
+ if (waitpid (pid, NULL, 0) == -1)
+ log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
+ strerror (errno));
+
+ return 0;
+#endif /* !HAVE_W32_SYSTEM*/
+}
diff --git a/common/exechelp.h b/common/exechelp.h
index 1df029b7e..f78a43c6b 100644
--- a/common/exechelp.h
+++ b/common/exechelp.h
@@ -43,4 +43,16 @@ gpg_error_t gnupg_spawn_process (const char *pgmname, const char *argv[],
gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid);
+/* Spawn a new process and immediatley detach from it. The name of
+ the program to exec is PGMNAME and its arguments are in ARGV (the
+ programname is automatically passed as first argument).
+ Environment strings in ENVP are set. An error is returned if
+ pgmname is not executable; to make this work it is necessary to
+ provide an absolute file name. */
+gpg_error_t gnupg_spawn_process_detached (const char *pgmname,
+ const char *argv[],
+ const char *envp[] );
+
+
+
#endif /*GNUPG_COMMON_EXECHELP_H*/