diff options
author | Werner Koch <wk@gnupg.org> | 2006-09-07 17:13:33 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2006-09-07 17:13:33 +0200 |
commit | 6374763c985a36c25d3cea9a8a83b51f42708160 (patch) | |
tree | 901f4d3762afff15b6adc1dc9f8c21b8b16be617 /common | |
parent | Added missing file (diff) | |
download | gnupg2-6374763c985a36c25d3cea9a8a83b51f42708160.tar.xz gnupg2-6374763c985a36c25d3cea9a8a83b51f42708160.zip |
Let scdaemon call a script on status changes
Diffstat (limited to 'common')
-rw-r--r-- | common/ChangeLog | 7 | ||||
-rw-r--r-- | common/exechelp.c | 168 | ||||
-rw-r--r-- | common/exechelp.h | 12 |
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*/ |