[svn] dirmngr - r247 - trunk/src

svn author marcus cvs at cvs.gnupg.org
Mon Jul 23 18:22:39 CEST 2007


Author: marcus
Date: 2007-07-23 18:22:05 +0200 (Mon, 23 Jul 2007)
New Revision: 247

Added:
   trunk/src/exechelp.c
   trunk/src/exechelp.h
Modified:
   trunk/src/ChangeLog
   trunk/src/Makefile.am
   trunk/src/ldap.c
Log:
2007-07-23  Marcus Brinkmann  <marcus at g10code.de>

	* Makefile.am (dirmngr_SOURCES): Add exechelp.h and exechelp.c.
	* exechelp.h, exechelp.c: New files.
	* ldap.c: Don't include <sys/wait.h> but "exechelp.h".
	(destroy_wrapper, ldap_wrapper_thread,
	ldap_wrapper_connection_cleanup): Use dirmngr_kill_process instead
	of kill.
	(ldap_wrapper_thread): Use dirmngr_wait_process instead of
	waitpid.
	(ldap_wrapper): Use dirmngr_spawn_process.


Modified: trunk/src/ChangeLog
===================================================================
--- trunk/src/ChangeLog	2007-07-20 15:27:48 UTC (rev 246)
+++ trunk/src/ChangeLog	2007-07-23 16:22:05 UTC (rev 247)
@@ -1,3 +1,15 @@
+2007-07-23  Marcus Brinkmann  <marcus at g10code.de>
+
+	* Makefile.am (dirmngr_SOURCES): Add exechelp.h and exechelp.c.
+	* exechelp.h, exechelp.c: New files.
+	* ldap.c: Don't include <sys/wait.h> but "exechelp.h".
+	(destroy_wrapper, ldap_wrapper_thread,
+	ldap_wrapper_connection_cleanup): Use dirmngr_kill_process instead
+	of kill.
+	(ldap_wrapper_thread): Use dirmngr_wait_process instead of
+	waitpid.
+	(ldap_wrapper): Use dirmngr_spawn_process.
+	
 2007-07-20  Marcus Brinkmann  <marcus at g10code.de>
 
 	* certcache.c (cert_cache_lock): Do not initialize statically.

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2007-07-20 15:27:48 UTC (rev 246)
+++ trunk/src/Makefile.am	2007-07-23 16:22:05 UTC (rev 247)
@@ -43,7 +43,7 @@
 	certcache.c certcache.h i18n.h util.h \
 	cdb.h cdblib.c ldap.c http.c http.h misc.c ocsp.c ocsp.h \
         estream.c estream.h estream-printf.c estream-printf.h \
-	validate.c validate.h
+	validate.c validate.h exechelp.h exechelp.c
 
 dirmngr_LDADD = ../jnlib/libjnlib.a $(LIBOBJS) $(LIBASSUAN_PTH_LIBS)  \
 	$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(PTH_LIBS) $(LIBINTL)

Added: trunk/src/exechelp.c
===================================================================
--- trunk/src/exechelp.c	2007-07-20 15:27:48 UTC (rev 246)
+++ trunk/src/exechelp.c	2007-07-23 16:22:05 UTC (rev 247)
@@ -0,0 +1,545 @@
+/* exechelp.c - fork and exec helpers
+ *      Copyright (C) 2004, 2007 g10 Code GmbH
+ *
+ * This file is part of DirMngr.
+ *
+ * DirMngr 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.
+ *
+ * DirMngr 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> 
+#include <fcntl.h>
+
+#include <pth.h>
+
+#ifndef HAVE_W32_SYSTEM
+#include <sys/wait.h>
+#endif
+
+#include "util.h"
+#include "i18n.h"
+#include "exechelp.h"
+
+/* Define to 1 do enable debugging.  */
+#define DEBUG_W32_SPAWN 0
+
+#ifdef _POSIX_OPEN_MAX
+#define MAX_OPEN_FDS _POSIX_OPEN_MAX
+#else
+#define MAX_OPEN_FDS 20
+#endif
+
+#ifdef HAVE_W32_SYSTEM
+/* We assume that a HANDLE can be represented by an int which should
+   be true for all i386 systems (HANDLE is defined as void *) and
+   these are the only systems for which Windows is available.  Further
+   we assume that -1 denotes an invalid handle.  */
+# define fd_to_handle(a)  ((HANDLE)(a))
+# define handle_to_fd(a)  ((int)(a))
+# define pid_to_handle(a) ((HANDLE)(a))
+# define handle_to_pid(a) ((int)(a))
+#endif
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Helper function to build_w32_commandline. */
+static char *
+build_w32_commandline_copy (char *buffer, const char *string)
+{
+  char *p = buffer;
+  const char *s;
+
+  if (!*string) /* Empty string. */
+    p = stpcpy (p, "\"\"");
+  else if (strpbrk (string, " \t\n\v\f\""))
+    {
+      /* Need top do some kind of quoting.  */
+      p = stpcpy (p, "\"");
+      for (s=string; *s; s++)
+        {
+          *p++ = *s;
+          if (*s == '\"')
+            *p++ = *s;
+        }
+      *p++ = '\"';
+      *p = 0;
+    }
+  else
+    p = stpcpy (p, string);
+
+  return p;
+}
+
+/* Build a command line for use with W32's CreateProcess.  On success
+   CMDLINE gets the address of a newly allocated string.  */
+static gpg_error_t
+build_w32_commandline (const char *pgmname, const char * const *argv, 
+                       char **cmdline)
+{
+  int i, n;
+  const char *s;
+  char *buf, *p;
+
+  *cmdline = NULL;
+  n = 0;
+  s = pgmname;
+  n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
+  for (; *s; s++)
+    if (*s == '\"')
+      n++;  /* Need to double inner quotes.  */
+  for (i=0; (s=argv[i]); i++)
+    {
+      n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
+      for (; *s; s++)
+        if (*s == '\"')
+          n++;  /* Need to double inner quotes.  */
+    }
+  n++;
+
+  buf = p = xtrymalloc (n);
+  if (!buf)
+    return gpg_error_from_syserror ();
+
+  p = build_w32_commandline_copy (p, pgmname);
+  for (i=0; argv[i]; i++) 
+    {
+      *p++ = ' ';
+      p = build_w32_commandline_copy (p, argv[i]);
+    }
+
+  *cmdline= buf;
+  return 0;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+
+#ifdef HAVE_W32_SYSTEM
+/* Create pipe where the write end is inheritable.  */
+static int
+create_inheritable_pipe (int filedes[2])
+{
+  HANDLE r, w, h;
+  SECURITY_ATTRIBUTES sec_attr;
+
+  memset (&sec_attr, 0, sizeof sec_attr );
+  sec_attr.nLength = sizeof sec_attr;
+  sec_attr.bInheritHandle = FALSE;
+    
+  if (!CreatePipe (&r, &w, &sec_attr, 0))
+    return -1;
+
+  if (!DuplicateHandle (GetCurrentProcess(), w,
+                        GetCurrentProcess(), &h, 0,
+                        TRUE, DUPLICATE_SAME_ACCESS ))
+    {
+      log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
+      CloseHandle (r);
+      CloseHandle (w);
+      return -1;
+    }
+  CloseHandle (w);
+  w = h;
+
+  filedes[0] = handle_to_fd (r);
+  filedes[1] = handle_to_fd (w);
+  return 0;
+}
+#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, char *argv[],
+         int fd_in, int fd_out, int fd_err)
+{
+  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;
+  
+  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
+   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
+dirmngr_spawn_process (const char *pgmname, char *argv[],
+		       int *fdout, int *fderr, pid_t *pid)
+{
+#ifdef HAVE_W32_SYSTEM
+  gpg_error_t err;
+  SECURITY_ATTRIBUTES sec_attr;
+  PROCESS_INFORMATION pi = 
+    {
+      NULL,      /* Returns process handle.  */
+      0,         /* Returns primary thread handle.  */
+      0,         /* Returns pid.  */
+      0          /* Returns tid.  */
+    };
+  STARTUPINFO si;
+  int cr_flags;
+  char *cmdline;
+  int rp_stdout[2];
+  int rp_stderr[2];
+  HANDLE hnul = INVALID_HANDLE_VALUE;
+
+  /* Setup return values.  */
+  *fdout = -1;
+  *fderr = -1;
+  *pid = (pid_t)(-1);
+
+  /* Build the command line.  */
+  err = build_w32_commandline (pgmname, argv, &cmdline);
+  if (err)
+    return err; 
+
+  /* Create a pipe.  */
+  if (create_inheritable_pipe (rp_stdout))
+    {
+      err = gpg_error (GPG_ERR_GENERAL);
+      log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+      xfree (cmdline);
+      return err;
+    }
+
+  if (create_inheritable_pipe (rp_stderr))
+    {
+      err = gpg_error (GPG_ERR_GENERAL);
+      log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+      xfree (cmdline);
+      CloseHandle (fd_to_handle (rp_stdout[0]));
+      CloseHandle (fd_to_handle (rp_stdout[1]));
+      return err;
+    }
+  
+  /* Prepare security attributes.  */
+  memset (&sec_attr, 0, sizeof sec_attr);
+  sec_attr.nLength = sizeof sec_attr;
+  sec_attr.bInheritHandle = TRUE;
+  hnul = CreateFile ("nul",
+		     GENERIC_READ|GENERIC_WRITE,
+		     FILE_SHARE_READ|FILE_SHARE_WRITE,
+		     &sec_attr,
+		     OPEN_EXISTING,
+		     FILE_ATTRIBUTE_NORMAL,
+		     NULL);
+  if (hnul == INVALID_HANDLE_VALUE)
+    {
+      err = gpg_error (GPG_ERR_GENERAL);
+      log_error (_("error opening nul: %s\n"), gpg_strerror (err));
+      xfree (cmdline);
+      CloseHandle (fd_to_handle (rp_stdout[0]));
+      CloseHandle (fd_to_handle (rp_stdout[1]));
+      CloseHandle (fd_to_handle (rp_stderr[0]));
+      CloseHandle (fd_to_handle (rp_stderr[1]));
+      return err;
+    }
+  
+  /* Prepare security attributes.  */
+  memset (&sec_attr, 0, sizeof sec_attr );
+  sec_attr.nLength = sizeof sec_attr;
+  sec_attr.bInheritHandle = FALSE;
+  
+  /* Start the process.  Note that we can't run the PREEXEC function
+     because this would change our own environment. */
+  memset (&si, 0, sizeof si);
+  si.cb = sizeof (si);
+  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+  si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
+  si.hStdInput  = hnul;
+  si.hStdOutput = fd_to_handle (rp_stderr[0]);
+  si.hStdError  = fd_to_handle (rp_stderr[1]);
+
+  cr_flags = (CREATE_DEFAULT_ERROR_MODE
+              | GetPriorityClass (GetCurrentProcess ())
+              | CREATE_SUSPENDED); 
+  log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
+  if (!CreateProcess (pgmname,       /* Program to start.  */
+                      cmdline,       /* Command line arguments.  */
+                      &sec_attr,     /* Process security attributes.  */
+                      &sec_attr,     /* Thread security attributes.  */
+                      TRUE,          /* Inherit handles.  */
+                      cr_flags,      /* Creation flags.  */
+                      NULL,          /* Environment.  */
+                      NULL,          /* Use current drive/directory.  */
+                      &si,           /* Startup information. */
+                      &pi            /* Returns process information.  */
+                      ))
+    {
+      log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
+      xfree (cmdline);
+      CloseHandle (fd_to_handle (rp_stdout[0]));
+      CloseHandle (fd_to_handle (rp_stdout[1]));
+      CloseHandle (fd_to_handle (rp_stderr[0]));
+      CloseHandle (fd_to_handle (rp_stderr[1]));
+      CloseHandle (hnul);
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+  xfree (cmdline);
+  cmdline = NULL;
+
+  /* Close the other end of the pipe.  */
+  CloseHandle (fd_to_handle (rp_stdout[1]));
+  CloseHandle (fd_to_handle (rp_stderr[1]));
+  CloseHandle (hnul);
+  
+  log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
+             " dwProcessID=%d dwThreadId=%d\n",
+             pi.hProcess, pi.hThread,
+             (int) pi.dwProcessId, (int) pi.dwThreadId);
+
+  /* Process has been created suspended; resume it now. */
+  ResumeThread (pi.hThread);
+  CloseHandle (pi.hThread); 
+
+  *fdout = handle_to_fd (rp_stdout[0]);
+  *fderr = handle_to_fd (rp_stderr[0]);
+  *pid = handle_to_pid (pi.hProcess);
+  return 0;
+
+#else /* !HAVE_W32_SYSTEM */
+  gpg_error_t err;
+  int rp_stdout[2];
+  int rp_stderr[2];
+
+  *fdout = -1;
+  *fderr = -1;
+  *pid = (pid_t)(-1);
+
+  if (pipe (rp_stdout) == -1)
+    {
+      err = gpg_error_from_syserror ();
+      log_error (_("error creating a pipe: %s\n"), strerror (errno));
+      return err;
+    }
+
+  if (pipe (rp_stderr) == -1)
+    {
+      err = gpg_error_from_syserror ();
+      log_error (_("error creating a pipe: %s\n"), strerror (errno));
+      close (rp_stdout[0]);
+      close (rp_stdout[1]);
+      return err;
+    }
+
+  *pid = pth_fork ();
+  if (*pid == (pid_t)(-1))
+    {
+      err = gpg_error_from_syserror ();
+      log_error (_("error forking process: %s\n"), strerror (errno));
+      close (rp_stdout[0]);
+      close (rp_stdout[1]);
+      close (rp_stderr[0]);
+      close (rp_stderr[1]);
+      return err;
+    }
+
+  if (!*pid)
+    { 
+      /* Run child. */
+      do_exec (pgmname, argv, -1, rp_stdout[1], rp_stderr[1]);
+      /*NOTREACHED*/
+    }
+
+  /* Parent. */
+  close (rp_stdout[1]);
+  close (rp_stderr[1]);
+
+  *fdout = rp_stdout[0];
+  *fderr = rp_stderr[0];
+
+  return 0;
+#endif /* !HAVE_W32_SYSTEM */
+}
+
+
+/* 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
+dirmngr_wait_process (pid_t pid, int hang, int *status)
+{
+  gpg_err_code_t ec;
+
+#ifdef HAVE_W32_SYSTEM
+  HANDLE proc = pid_to_handle (pid);
+  int code;
+  DWORD exc;
+
+  *status = 0;
+  if (pid == (pid_t)(-1))
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* FIXME: We should do a pth_waitpid here.  However this has not yet
+     been implemented.  A special W32 pth system call would even be
+     better.  */
+  code = WaitForSingleObject (proc, hang ? INFINITE : 0);
+  switch (code) 
+    {
+    case WAIT_TIMEOUT:
+      
+      break;
+    case WAIT_FAILED:
+      log_error (_("waiting for process %d to terminate failed: %s\n"),
+		 (int)pid, w32_strerror (-1));
+      ec = GPG_ERR_GENERAL;
+      break;
+      
+    case WAIT_OBJECT_0:
+      if (!GetExitCodeProcess (proc, &exc))
+	{
+	  log_error (_("error getting exit code of process %d: %s\n"),
+		     (int)pid, w32_strerror (-1) );
+	  ec = GPG_ERR_GENERAL;
+	}
+      else if (exc)
+	{
+	  log_error (_("error detected in waitpid: exit status %d\n"),
+		     (int) exc);
+	  ec = GPG_ERR_GENERAL;
+	}
+      else
+	ec = 0;
+      *status = 1;
+      break;
+      
+    default:
+      log_error ("WaitForSingleObject returned unexpected "
+		 "code %d for pid %d\n", code, (int)pid );
+      ec = GPG_ERR_GENERAL;
+      break;
+    }
+  
+#else /* !HAVE_W32_SYSTEM */
+  int i;
+  int r_status;
+
+  *status = 0;
+  if (pid == (pid_t)(-1))
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  i = pth_waitpid (pid, &r_status, 0);
+  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);
+    }
+  if (i == 0)
+    {
+      *status = 0;
+      ec = 0;
+    }
+  else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
+    {
+      log_error (_("error detected: program probably not installed\n"));
+      ec = GPG_ERR_CONFIGURATION;
+    }
+  else if (WIFEXITED (status) && WEXITSTATUS (status))
+    {
+      log_error (_("error detected: exit status %d\n"), WEXITSTATUS (status));
+      ec = GPG_ERR_GENERAL;
+    }
+  else if (!WIFEXITED (status))
+    {
+      log_error (_("error detected: terminated\n"));
+      ec = GPG_ERR_GENERAL;
+    }
+  else 
+    {
+      *status = 1;
+      ec = 0;
+    }
+#endif /* !HAVE_W32_SYSTEM */
+
+  return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+
+}
+
+
+/* Kill the program PID with name PGMNAME (only used for
+   diagnostics).  */
+gpg_error_t
+dirmngr_kill_process (pid_t pid)
+{
+#ifdef HAVE_W32_SYSTEM
+  /* FIXME: Implement something.  */
+  return 0;
+#else
+  return kill (pid, SIGTERM);
+#endif
+}

Added: trunk/src/exechelp.h
===================================================================
--- trunk/src/exechelp.h	2007-07-20 15:27:48 UTC (rev 246)
+++ trunk/src/exechelp.h	2007-07-23 16:22:05 UTC (rev 247)
@@ -0,0 +1,42 @@
+/* exechelp.h - fork and exec helpers
+ *      Copyright (C) 2004, 2007 g10 Code GmbH
+ *
+ * This file is part of DirMngr.
+ *
+ * DirMngr 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.
+ *
+ * DirMngr 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 DIRMNGR_EXECHELP_H
+#define DIRMNGR_EXECHELP_H
+
+/* Fork and exec the PGMNAME with /dev/null as stdin, and pipes for
+   stdout and stderr.  The read ends of these pipes are returned in
+   FDOUT and FDERR, as well as 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.
+   Returns 0 on success or an error code.  */
+gpg_error_t dirmngr_spawn_process (const char *pgmname, char *argv[],
+				   int *fdout, int *fderr, pid_t *pid);
+
+/* Wait for the process identified by PID to terminate.  Returns -1 if
+   an error occurs, if the process succeded, GPG_ERR_GENERAL for any
+   failures of the spawned program or other error codes.  STATUS is
+   set to 0 if timeout occurs.  */
+gpg_error_t dirmngr_wait_process (pid_t pid, int hang, int *status);
+
+/* Kill the program PID.  */
+gpg_error_t dirmngr_kill_process (pid_t pid);
+
+#endif /* DIRMNGR_EXECHELP_H */

Modified: trunk/src/ldap.c
===================================================================
--- trunk/src/ldap.c	2007-07-20 15:27:48 UTC (rev 246)
+++ trunk/src/ldap.c	2007-07-23 16:22:05 UTC (rev 247)
@@ -27,12 +27,12 @@
 #include <errno.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <sys/wait.h>
 #include <time.h>
 #include <ldap.h> /* fixme: remove it */
 #include <pth.h>
 #include <ksba.h> 
 
+#include "exechelp.h"
 #include "crlfetch.h"
 #include "dirmngr.h"
 #include "misc.h"
@@ -159,7 +159,7 @@
 destroy_wrapper (struct wrapper_context_s *ctx) 
 {
   if (ctx->pid != (pid_t)(-1))
-    kill (ctx->pid, SIGTERM);
+    dirmngr_kill_process (ctx->pid);
   ksba_reader_release (ctx->reader);
   if (ctx->fd)
     close (ctx->fd);
@@ -309,25 +309,17 @@
           /* Check whether the process is still running.  */
           if (ctx->pid != (pid_t)(-1))
             {
-              int i, status;
+              gpg_error_t err;
+	      int status;
               
-              while ( (i=waitpid (ctx->pid, &status, WNOHANG)) == -1
-                      && errno == EINTR)
-                ;
-              if (i == -1)
+	      err = dirmngr_wait_process (ctx->pid, 0, &status);
+
+              if (err == -1)
                 log_error (_("waiting for ldap wrapper %d failed: %s\n"),
-                           (int)ctx->pid, strerror (errno));
-              else if (i)
+                           (int)ctx->pid, gpg_strerror (err));
+              else if (status)
                 {
-                  if (!WIFEXITED (status))
-                    log_info (_("ldap wrapper %d ready: terminated\n"),
-                              (int)ctx->pid);
-                  else if (WEXITSTATUS (status) == 10 )
-                    log_info (_("ldap wrapper %d ready: timeout\n"),
-                              (int)ctx->pid);
-                  else 
-                    log_info (_("ldap wrapper %d ready: exit status %d\n"),
-                              (int)ctx->pid, WEXITSTATUS (status));
+		  log_info (_("ldap wrapper %d ready"), (int)ctx->pid);
                   ctx->ready = 1;
                   ctx->pid = (pid_t)(-1);
                 }
@@ -337,7 +329,7 @@
           if (ctx->pid != (pid_t)(-1)
               && ctx->stamp != (time_t)(-1) && ctx->stamp < current_time)
             {
-              if (!kill (ctx->pid, SIGTERM))
+              if (!dirmngr_kill_process (ctx->pid))
                 ctx->stamp = (time_t)(-1);
               log_info (_("ldap wrapper %d stalled - killing\n"),
                         (int)ctx->pid);
@@ -423,7 +415,7 @@
         ctx->ctrl->refcount--;
         ctx->ctrl = NULL;
         if (ctx->pid != (pid_t)(-1))
-          kill (ctx->pid, SIGTERM);
+          dirmngr_kill_process (ctx->pid);
         if (ctx->fd_error)
           log_info (_("reading from ldap wrapper %d failed: %s\n"),
                     ctx->printable_pid, gpg_strerror (ctx->fd_error));
@@ -538,22 +530,26 @@
       a long response, the frok/exec overhead is acceptable.
 
    Special hack to avoid passing a password through the command line
-   which is gloabbally visible: If the first element of ARGV is
-   "--pass" it will be removed and instead the environment variable
+   which is globally visible: If the first element of ARGV is "--pass"
+   it will be removed and instead the environment variable
    DIRMNGR_LDAP_PASS will be set to the next value of ARGV.  On modern
    OSes the environment is not visible to other other user.  For those
    old systems where it can't be avoided, we don't want to go into the
    hassle of passing the password via stdin; it's just too complicated
-   and an LDAP password used for public directory lookups should be
-   that confidential.
-  */
+   and an LDAP password used for public directory lookups should not
+   be that confidential.  */
 static gpg_error_t
 ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
 {
   gpg_error_t err;
   pid_t pid;
-  int rp[2], rp2[2];
   struct wrapper_context_s *ctx;
+  int i;
+  int j;
+  char **arg_list;
+  char *pgmname;
+  int fd_out;
+  int fd_err;
 
   /* It would be too simple to connect stderr just to our logging
      stream.  The problem is that if we are running multi-threaded
@@ -566,127 +562,54 @@
 
   *reader = NULL;
 
-  if (pipe (rp) == -1)
-    {
-      err = gpg_error_from_errno (errno);
-      log_error (_("error creating a pipe: %s\n"), strerror (errno));
-      return err;
-    }
-  if (pipe (rp2) == -1)
-    {
-      err = gpg_error_from_errno (errno);
-      log_error (_("error creating a pipe: %s\n"), strerror (errno));
-      close (rp[0]);
-      close (rp[1]);
-      return err;
-    }
-      
-  pid = pth_fork ();
-  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]);
-      close (rp2[0]);
-      close (rp2[1]);
-      return err;
-    }
+  /* Files: We need to prepare stdin and stdout.  We get stderr from
+     the function.  */
+  if (!opt.ldap_wrapper_program || !*opt.ldap_wrapper_program)
+    pgmname = DIRMNGR_LIBEXECDIR "/dirmngr_ldap";
+  else
+    pgmname = opt.ldap_wrapper_program;
 
-  if (!pid)
-    { /* Child. */
-      char *pgmname;
-      char **arg_list;
-      int n, i, j;
-      int fd;
+  /* Create command line argument array.  */
+  for (i = 0; argv[i]; i++)
+    ;
+  arg_list = xcalloc (i + 3, sizeof *arg_list);
+  arg_list[0] = strrchr (pgmname, '/');
+  if (arg_list[0])
+    arg_list[0]++;
+  else
+    arg_list[0] = pgmname;
+  for (i = 0, j = 1; argv[i]; i++, j++)
+    if (!i && argv[i + 1] && !strcmp (*argv, "--pass"))
+      {
+	arg_list[j] = "--env-pass";
+	setenv ("DIRMNGR_LDAP_PASS", argv[1], 1);
+	i++;
+      }
+    else
+      arg_list[j] = (char*) argv[i];
 
-      if (!opt.ldap_wrapper_program || !*opt.ldap_wrapper_program)
-        pgmname = DIRMNGR_LIBEXECDIR "/dirmngr_ldap";
-      else
-        pgmname = opt.ldap_wrapper_program;
-
-      /* Create command line argument array.  */
-      for (i=0; argv[i]; i++)
-        ;
-      arg_list = xcalloc (i+3, sizeof *arg_list);
-      arg_list[0] = strrchr (pgmname, '/');
-      if (arg_list[0])
-        arg_list[0]++;
-      else
-        arg_list[0] = pgmname;
-      for (i=0,j=1; argv[i]; i++, j++)
-        if (!i && argv[i+1] && !strcmp (*argv, "--pass"))
-          {
-            arg_list[j] = "--env-pass";
-            setenv ("DIRMNGR_LDAP_PASS", argv[1], 1 );
-            i++;
-          }
-        else
-          arg_list[j] = (char*)argv[i];
-
-      /* Connect stdin to /dev/null.  */
-      fd = open ("/dev/null", O_RDONLY);
-      if (fd == -1)
-        {
-          log_error (_("can't open `%s': %s\n"), "/dev/null",strerror (errno));
-          _exit (4);
-        }
-      if (fd != STDIN_FILENO && dup2 (fd, STDIN_FILENO) == -1)
-        {
-          log_error (_("dup2 failed in child: %s\n"), strerror (errno));
-          _exit (4);
-        }
-
-      /* Connect stdout to the first pipe.  */
-      if (rp[1] != STDOUT_FILENO && dup2 (rp[1], STDOUT_FILENO) == -1)
-        {
-          log_error (_("dup2 failed in child: %s\n"), strerror (errno));
-          _exit (4);
-        }
-
-      /* Connect stderr to the second pipe.  */
-      if (rp2[1] != STDERR_FILENO && dup2 (rp2[1], STDERR_FILENO) == -1)
-        {
-          log_error (_("dup2 failed in child: %s\n"), strerror (errno));
-          _exit (4);
-        }
-
-  
-      /* Close all files which will not be duped. */
-      n = sysconf (_SC_OPEN_MAX);
-      if (n < 0)
-        n = MAX_OPEN_FDS;
-      for (i=0; i < n; i++)
-        {
-          if ( i == STDIN_FILENO || i == STDOUT_FILENO || i == STDERR_FILENO)
-            continue;
-          close(i);
-        }
-      errno = 0;
-
-      execv (pgmname, arg_list);
-      log_error (_("error running `%s': %s\n"), pgmname, strerror (errno));
-      _exit (31);
-    }
-
-  /* Parent. */
-  close (rp[1]);
-  close (rp2[1]);
-  
   ctx = xtrycalloc (1, sizeof *ctx);
   if (!ctx)
     {
       err = gpg_error_from_errno (errno);
       log_error (_("error allocating memory: %s\n"), strerror (errno));
-      kill (pid, SIGTERM);
-      close (rp[0]);
-      close (rp2[0]);
+      xfree (arg_list);
       return err;
     }
+
+  err = dirmngr_spawn_process (pgmname, arg_list,
+			       &fd_out, &fd_err, &pid);
+  xfree (arg_list);
+  if (err)
+    {
+      xfree (ctx);
+      return err;
+    }
+
   ctx->pid = pid;
-  ctx->printable_pid = (int)pid;
-  ctx->fd = rp[0];
-  ctx->log_fd = rp2[0];
+  ctx->printable_pid = (int) pid;
+  ctx->fd = fd_out;
+  ctx->log_fd = fd_err;
   ctx->ctrl = ctrl;
   ctrl->refcount++;
   ctx->stamp = time (NULL);




More information about the Gnupg-commits mailing list