1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

Let scdaemon call a script on status changes

This commit is contained in:
Werner Koch 2006-09-07 15:13:33 +00:00
parent 44393f2ce7
commit 6374763c98
12 changed files with 355 additions and 49 deletions

View file

@ -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.

View file

@ -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*/
}

View file

@ -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*/