* exechelp.h, exechelp.c: New. Based on code from ../sm/import.c.
authorWerner Koch <wk@gnupg.org>
Mon, 6 Dec 2004 18:28:56 +0000 (18:28 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 6 Dec 2004 18:28:56 +0000 (18:28 +0000)
* gpgsm.c (run_protect_tool) [_WIN32]: Disabled.

* import.c (popen_protect_tool): Simplified by making use of
gnupg_spawn_process.
(parse_p12): Likewise, using gnupg_wait_process.
* export.c (popen_protect_tool): Ditto.
(export_p12): Ditto.

common/ChangeLog
common/Makefile.am
common/exechelp.c [new file with mode: 0644]
common/exechelp.h [new file with mode: 0644]
sm/ChangeLog
sm/export.c
sm/gpgsm.c
sm/import.c

index 3a3d02d..8c311f4 100644 (file)
@@ -1,3 +1,7 @@
+2004-12-06  Werner Koch  <wk@g10code.com>
+
+       * exechelp.h, exechelp.c: New.  Based on code from ../sm/import.c.
+
 2004-12-03  Werner Koch  <wk@g10code.com>
 
        * strsep.c: Fixed copyright comments.
index 12fdf7b..795d66a 100644 (file)
@@ -41,6 +41,7 @@ libcommon_a_SOURCES = \
        iobuf.c iobuf.h \
        ttyio.c ttyio.h \
        asshelp.c asshelp.h \
+       exechelp.c exechelp.h \
        simple-gettext.c \
        w32reg.c \
        signal.c \
diff --git a/common/exechelp.c b/common/exechelp.c
new file mode 100644 (file)
index 0000000..206e16d
--- /dev/null
@@ -0,0 +1,230 @@
+/* exechelp.c - fork and exec helpers
+ *     Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <signal.h>
+#include <unistd.h> 
+#ifdef USE_GNU_PTH      
+#include <pth.h>
+#endif
+#ifdef _WIN32
+#else
+#include <sys/wait.h>
+#endif
+
+#include "util.h"
+#include "i18n.h"
+#include "exechelp.h"
+
+
+#ifdef _POSIX_OPEN_MAX
+#define MAX_OPEN_FDS _POSIX_OPEN_MAX
+#else
+#define MAX_OPEN_FDS 20
+#endif
+
+/* We have the usual problem here: Some modules are linked against pth
+   and some are not.  However we want to use pth_fork and pth_waitpid
+   here. Using a weak symbol works but is not portable - we should
+   provide a an explicit dummy pth module instead of using the
+   pragma.  */ 
+#ifndef _WIN32
+#pragma weak pth_fork
+#pragma weak pth_waitpid
+#endif
+
+
+
+/* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
+   stdin, write the output to OUTFILE, return a new stream in
+   STATUSFILE for stderr and the pid of the process in PID. The
+   arguments for the process are expected in the NULL terminated array
+   ARGV.  The program name itself should not be included there.  if
+   PREEXEC is not NULL, that function will be called right before the
+   exec.
+
+   Returns 0 on success or an error code. */
+gpg_error_t
+gnupg_spawn_process (const char *pgmname, const char *argv[],
+                     FILE *infile, FILE *outfile,
+                     void (*preexec)(void),
+                     FILE **statusfile, pid_t *pid)
+{
+#ifdef _WIN32
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+#else /* !_WIN32 */
+  gpg_error_t err;
+  int fd, fdout, rp[2];
+
+  *statusfile = NULL;
+  *pid = (pid_t)(-1);
+  fflush (infile);
+  rewind (infile);
+  fd = fileno (infile);
+  fdout = fileno (outfile);
+  if (fd == -1 || fdout == -1)
+    log_fatal ("no file descriptor for file passed"
+               " to gnupg_spawn_process: %s\n",  strerror (errno) );
+
+  if (pipe (rp) == -1)
+    {
+      err = gpg_error_from_errno (errno);
+      log_error (_("error creating a pipe: %s\n"), strerror (errno));
+      return err;
+    }
+
+#ifdef USE_GNU_PTH      
+  *pid = pth_fork? pth_fork () : fork ();
+#else
+  *pid = fork ();
+#endif
+  if (*pid == (pid_t)(-1))
+    {
+      err = gpg_error_from_errno (errno);
+      log_error (_("error forking process: %s\n"), strerror (errno));
+      close (rp[0]);
+      close (rp[1]);
+      return err;
+    }
+
+  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);
+    }
+
+  /* Parent. */
+  close (rp[1]);
+
+  *statusfile = fdopen (rp[0], "r");
+  if (!*statusfile)
+    {
+      err = gpg_error_from_errno (errno);
+      log_error (_("can't fdopen pipe for reading: %s\n"), strerror (errno));
+      kill (*pid, SIGTERM);
+      *pid = (pid_t)(-1);
+      return err;
+    }
+
+  return 0;
+#endif /* !_WIN32 */
+}
+
+
+/* Wait for the process identified by PID to terminate. PGMNAME should
+   be the same as suplieed to the spawn fucntion and is only used for
+   diagnostics. Returns 0 if the process succeded, GPG_ERR_GENERAL for
+   any failures of the spawned program or other error codes.*/
+gpg_error_t
+gnupg_wait_process (const char *pgmname, pid_t pid)
+{
+  gpg_err_code_t ec;
+
+#ifdef _WIN32
+  ec = GPG_ERR_NOT_IMPLEMENTED;
+
+#else /* !_WIN32 */
+  int i, status;
+
+  if (pid == (pid_t)(-1))
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+#ifdef USE_GNU_PTH
+  i = pth_waitpid ? pth_waitpid (pid, &status, 0) : waitpid (pid, &status, 0);
+#else
+  while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+    ;
+#endif
+  if (i == (pid_t)(-1))
+    {
+      log_error (_("waiting for process %d to terminate failed: %s\n"),
+                 (int)pid, strerror (errno));
+      ec = gpg_err_code_from_errno (errno);
+    }
+  else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
+    {
+      log_error (_("error running `%s': probably not installed\n"), pgmname);
+      ec = GPG_ERR_CONFIGURATION;
+    }
+  else if (WIFEXITED (status) && WEXITSTATUS (status))
+    {
+      log_error (_("error running `%s': exit status %d\n"), pgmname,
+                 WEXITSTATUS (status));
+      ec = GPG_ERR_GENERAL;
+    }
+  else if (!WIFEXITED (status))
+    {
+      log_error (_("error running `%s': terminated\n"), pgmname);
+      ec = GPG_ERR_GENERAL;
+    }
+  else 
+    ec = 0;
+#endif /* !_WIN32 */
+
+  return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+
+}
+
diff --git a/common/exechelp.h b/common/exechelp.h
new file mode 100644 (file)
index 0000000..f00d18d
--- /dev/null
@@ -0,0 +1,45 @@
+/* exechelp.h - Definitions for the fork and exec helpers
+ *     Copyright (C) 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef GNUPG_COMMON_EXECHELP_H
+#define GNUPG_COMMON_EXECHELP_H
+
+
+
+/* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
+   stdin, write the output to OUTFILE, return a new stream in
+   STATUSFILE for stderr and the pid of the process in PID. The
+   arguments for the process are expected in the NULL terminated array
+   ARGV.  The program name itself should not be included there.  if
+   PREEXEC is not NULL, that function will be called right before the
+   exec.  Returns 0 on success or an error code. */
+gpg_error_t gnupg_spawn_process (const char *pgmname, const char *argv[],
+                                 FILE *infile, FILE *outfile,
+                                 void (*preexec)(void),
+                                 FILE **statusfile, pid_t *pid);
+
+/* Wait for the process identified by PID to terminate. PGMNAME should
+   be the same as suplieed to the spawn fucntion and is only used for
+   diagnostics. Returns 0 if the process succeded, GPG_ERR_GENERAL for
+   any failures of the spawned program or other error codes.*/
+gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid);
+
+
+#endif /*GNUPG_COMMON_EXECHELP_H*/
index a0d5cc0..02f0014 100644 (file)
@@ -1,5 +1,13 @@
 2004-12-06  Werner Koch  <wk@g10code.com>
 
+       * gpgsm.c (run_protect_tool) [_WIN32]: Disabled.
+
+       * import.c (popen_protect_tool): Simplified by making use of
+       gnupg_spawn_process.
+       (parse_p12): Likewise, using gnupg_wait_process.
+       * export.c (popen_protect_tool): Ditto.
+       (export_p12): Ditto.
+
        * keydb.c: Don't define DIRSEP_S here.
 
 2004-12-02  Werner Koch  <wk@g10code.com>
index 15ad87b..b4450b2 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h> 
 #include <time.h>
 #include <assert.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/wait.h>
 
 #include "gpgsm.h"
 #include <gcrypt.h>
 #include <ksba.h>
 
 #include "keydb.h"
+#include "exechelp.h"
 #include "i18n.h"
 
-#ifdef _POSIX_OPEN_MAX
-#define MAX_OPEN_FDS _POSIX_OPEN_MAX
-#else
-#define MAX_OPEN_FDS 20
-#endif
 
 
 /* A table to store a fingerprint as used in a duplicates table.  We
@@ -522,92 +514,23 @@ popen_protect_tool (const char *pgmname,
                     const char *prompt, const char *keygrip,
                     pid_t *pid)
 {
-  gpg_error_t err;
-  int fd, fdout, rp[2];
-  int n, i;
-
-  fflush (infile);
-  rewind (infile);
-  fd = fileno (infile);
-  fdout = fileno (outfile);
-  if (fd == -1 || fdout == -1)
-    log_fatal ("no file descriptor for temporary file: %s\n",
-               strerror (errno));
-
-  /* Now start the protect-tool. */
-  if (pipe (rp) == -1)
-    {
-      err = gpg_error_from_errno (errno);
-      log_error (_("error creating a pipe: %s\n"), strerror (errno));
-      return err;
-    }
-      
-  *pid = fork ();
-  if (*pid == -1)
-    {
-      err = gpg_error_from_errno (errno);
-      log_error (_("error forking process: %s\n"), strerror (errno));
-      close (rp[0]);
-      close (rp[1]);
-      return err;
-    }
-
-  if (!*pid)
-    { /* Child. */
-      const char *arg0;
-
-      arg0 = strrchr (pgmname, '/');
-      if (arg0)
-        arg0++;
-      else
-        arg0 = pgmname;
-
-      /* 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;
-
-      setup_pinentry_env ();
-
-      execlp (pgmname, arg0,
-              "--homedir", opt.homedir,
-              "--p12-export",
-              "--prompt", prompt?prompt:"", 
-              "--enable-status-msg",
-              "--",
-              keygrip,
-              NULL);
-      /* No way to print anything, as we have closed all streams. */
-      _exit (31);
-    }
-
-  /* Parent. */
-  close (rp[1]);
-  *statusfile = fdopen (rp[0], "r");
-  if (!*statusfile)
-    {
-      err = gpg_error_from_errno (errno);
-      log_error ("can't fdopen pipe for reading: %s", strerror (errno));
-      kill (*pid, SIGTERM);
-      return err;
-    }
-
-  return 0;
+  const char *argv[20];
+  int i=0;
+
+  argv[i++] = "--homedir";
+  argv[i++] = opt.homedir;
+  argv[i++] = "--p12-export";
+  argv[i++] = "--prompt";
+  argv[i++] = prompt?prompt:"";
+  argv[i++] = "--enable-status-msg";
+  argv[i++] = "--",
+  argv[i++] = keygrip,
+  argv[i] = NULL;
+  assert (i < sizeof argv);
+
+  return gnupg_spawn_process (pgmname, argv, infile, outfile,
+                              setup_pinentry_env,
+                              statusfile, pid);
 }
 
 
@@ -618,7 +541,7 @@ export_p12 (ctrl_t ctrl, const unsigned char *certimg, size_t certimglen,
 {
   const char *pgmname;
   gpg_error_t err = 0, child_err = 0;
-  int i, c, cont_line;
+  int c, cont_line;
   unsigned int pos;
   FILE *infp = NULL, *outfp = NULL, *fp = NULL;
   char buffer[1024];
@@ -722,21 +645,7 @@ export_p12 (ctrl_t ctrl, const unsigned char *certimg, size_t certimglen,
     fclose (fp);
   if (pid != -1)
     {
-      int status;
-
-      while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
-        ;
-      if (i == -1)
-        log_error (_("waiting for protect-tools to terminate failed: %s\n"),
-                   strerror (errno));
-      else if (WIFEXITED (status) && WEXITSTATUS (status) == 31)
-        log_error (_("error running `%s': probably not installed\n"), pgmname);
-      else if (WIFEXITED (status) && WEXITSTATUS (status))
-        log_error (_("error running `%s': exit status %d\n"), pgmname,
-                     WEXITSTATUS (status));
-      else if (!WIFEXITED (status))
-        log_error (_("error running `%s': terminated\n"), pgmname);
-      else 
+      if (!gnupg_wait_process (pgmname, pid))
         child_err = 0;
     }
   if (!err)
index c96683a..0feca26 100644 (file)
@@ -1688,6 +1688,7 @@ open_fwrite (const char *filename)
 static void
 run_protect_tool (int argc, char **argv)
 {
+#ifndef _WIN32
   const char *pgm;
   char **av;
   int i;
@@ -1706,5 +1707,6 @@ run_protect_tool (int argc, char **argv)
   av[i] = NULL;
   execv (pgm, av); 
   log_error ("error executing `%s': %s\n", pgm, strerror (errno));
+#endif
   gpgsm_exit (2);
 }
index 938bc17..457ef64 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h> 
 #include <time.h>
 #include <assert.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/wait.h>
 
 #include "gpgsm.h"
 #include <gcrypt.h>
 #include <ksba.h>
 
 #include "keydb.h"
+#include "exechelp.h"
 #include "i18n.h"
 
-#ifdef _POSIX_OPEN_MAX
-#define MAX_OPEN_FDS _POSIX_OPEN_MAX
-#else
-#define MAX_OPEN_FDS 20
-#endif
-
-
 struct stats_s {
   unsigned long count;
   unsigned long imported;
@@ -471,103 +461,27 @@ static gpg_error_t
 popen_protect_tool (const char *pgmname,
                     FILE *infile, FILE *outfile, FILE **statusfile, pid_t *pid)
 {
-  gpg_error_t err;
-  int fd, fdout, rp[2];
-  int n, i;
-
-  fflush (infile);
-  rewind (infile);
-  fd = fileno (infile);
-  fdout = fileno (outfile);
-  if (fd == -1 || fdout == -1)
-    log_fatal ("no file descriptor for temporary file: %s\n",
-               strerror (errno));
-
-  /* Now start the protect-tool. */
-  if (pipe (rp) == -1)
-    {
-      err = gpg_error_from_errno (errno);
-      log_error (_("error creating a pipe: %s\n"), strerror (errno));
-      return err;
-    }
-      
-  *pid = fork ();
-  if (*pid == -1)
-    {
-      err = gpg_error_from_errno (errno);
-      log_error (_("error forking process: %s\n"), strerror (errno));
-      close (rp[0]);
-      close (rp[1]);
-      return err;
-    }
-
-  if (!*pid)
-    { /* Child. */
-      const char *arg0;
-
-      arg0 = strrchr (pgmname, '/');
-      if (arg0)
-        arg0++;
-      else
-        arg0 = pgmname;
-
-      /* 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;
-
-      setup_pinentry_env ();
-
-      if (opt.fixed_passphrase)
-        execlp (pgmname, arg0,
-                "--homedir", opt.homedir,
-                "--p12-import",
-                "--store", 
-                "--no-fail-on-exist",
-                "--enable-status-msg",
-                "--passphrase", opt.fixed_passphrase,
-                "--",
-                NULL);
-      else
-        execlp (pgmname, arg0,
-                "--homedir", opt.homedir,
-                "--p12-import",
-                "--store", 
-                "--no-fail-on-exist",
-                "--enable-status-msg",
-                "--",
-                NULL);
-      /* No way to print anything, as we have closed all streams. */
-      _exit (31);
-    }
-
-  /* Parent. */
-  close (rp[1]);
-  *statusfile = fdopen (rp[0], "r");
-  if (!*statusfile)
+  const char *argv[20];
+  int i=0;
+
+  argv[i++] = "--homedir";
+  argv[i++] = opt.homedir;
+  argv[i++] = "--p12-import";
+  argv[i++] = "--store";
+  argv[i++] = "--no-fail-on-exist";
+  argv[i++] = "--enable-status-msg";
+  if (opt.fixed_passphrase)
     {
-      err = gpg_error_from_errno (errno);
-      log_error ("can't fdopen pipe for reading: %s", strerror (errno));
-      kill (*pid, SIGTERM);
-      return err;
+      argv[i++] = "--passphrase";
+      argv[i++] = opt.fixed_passphrase;
     }
+  argv[i++] = "--",
+  argv[i] = NULL;
+  assert (i < sizeof argv);
 
-  return 0;
+  return gnupg_spawn_process (pgmname, argv, infile, outfile,
+                              setup_pinentry_env,
+                              statusfile, pid);
 }
 
 
@@ -583,7 +497,7 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader,
 {
   const char *pgmname;
   gpg_error_t err = 0, child_err = 0;
-  int i, c, cont_line;
+  int c, cont_line;
   unsigned int pos;
   FILE *tmpfp, *certfp = NULL, *fp = NULL;
   char buffer[1024];
@@ -712,7 +626,6 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader,
   if (!child_err)
     child_err = gpg_error (GPG_ERR_DECRYPT_FAILED);
 
-
  cleanup:
   if (tmpfp)
     fclose (tmpfp);
@@ -720,21 +633,7 @@ parse_p12 (ctrl_t ctrl, ksba_reader_t reader,
     fclose (fp);
   if (pid != -1)
     {
-      int status;
-
-      while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
-        ;
-      if (i == -1)
-        log_error (_("waiting for protect-tool to terminate failed: %s\n"),
-                   strerror (errno));
-      else if (WIFEXITED (status) && WEXITSTATUS (status) == 31)
-        log_error (_("error running `%s': probably not installed\n"), pgmname);
-      else if (WIFEXITED (status) && WEXITSTATUS (status))
-        log_error (_("error running `%s': exit status %d\n"), pgmname,
-                     WEXITSTATUS (status));
-      else if (!WIFEXITED (status))
-        log_error (_("error running `%s': terminated\n"), pgmname);
-      else 
+      if (!gnupg_wait_process (pgmname, pid))
         child_err = 0;
     }
   if (!err)