diff options
Diffstat (limited to 'gpgme/w32-io.c')
| -rw-r--r-- | gpgme/w32-io.c | 224 | 
1 files changed, 135 insertions, 89 deletions
| diff --git a/gpgme/w32-io.c b/gpgme/w32-io.c index e7dad2c3..e90f7796 100644 --- a/gpgme/w32-io.c +++ b/gpgme/w32-io.c @@ -39,6 +39,7 @@  #include "priv-io.h"  #include "debug.h" +  /* 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 @@ -242,12 +243,14 @@ reader (void *arg)          }        ctx->writepos = (ctx->writepos + nread) % READBUF_SIZE;        if (!SetEvent (ctx->have_data_ev)) -	TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ()); +	TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev, +		    (int) GetLastError ());        UNLOCK (ctx->mutex);      }    /* Indicate that we have an error or EOF.  */    if (!SetEvent (ctx->have_data_ev)) -    TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ()); +	TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", ctx->have_data_ev, +		    (int) GetLastError ());    SetEvent (ctx->stopped);    return TRACE_SUC (); @@ -479,7 +482,8 @@ _gpgme_io_read (int fd, void *buffer, size_t count)      }    if (!SetEvent (ctx->have_space_ev))      { -      TRACE_LOG1 ("SetEvent failed: ec=%d", (int) GetLastError ()); +      TRACE_LOG2 ("SetEvent (0x%x) failed: ec=%d", +		  ctx->have_space_ev, (int) GetLastError ());        UNLOCK (ctx->mutex);        /* FIXME: Should translate the error code.  */        errno = EIO; @@ -1006,8 +1010,7 @@ build_commandline (char **argv)  int  _gpgme_io_spawn (const char *path, char **argv, -		 struct spawn_fd_item_s *fd_child_list, -		 struct spawn_fd_item_s *fd_parent_list, pid_t *r_pid) +		 struct spawn_fd_item_s *fd_list, pid_t *r_pid)  {    SECURITY_ATTRIBUTES sec_attr;    PROCESS_INFORMATION pi = @@ -1018,16 +1021,16 @@ _gpgme_io_spawn (const char *path, char **argv,        0          /* returns tid */      };    STARTUPINFO si; -  char *envblock = NULL;    int cr_flags = CREATE_DEFAULT_ERROR_MODE      | GetPriorityClass (GetCurrentProcess ());    int i; +  char **args;    char *arg_string; -  int duped_stdin = 0; -  int duped_stderr = 0; -  HANDLE hnul = INVALID_HANDLE_VALUE;    /* FIXME.  */    int debug_me = 0; +  int tmp_fd; +  char *tmp_name; +    TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,  	      "path=%s", path);    i = 0; @@ -1037,116 +1040,145 @@ _gpgme_io_spawn (const char *path, char **argv,        i++;      } +  /* We do not inherit any handles by default, and just insert those +     handles we want the child to have afterwards.  But some handle +     values occur on the command line, and we need to move +     stdin/out/err to the right location.  So we use a wrapper program +     which gets the information from a temporary file.  */ +  if (_gpgme_mkstemp (&tmp_fd, &tmp_name) < 0) +    { +      TRACE_LOG1 ("_gpgme_mkstemp failed: %s", strerror (errno)); +      return TRACE_SYSRES (-1); +    } +  TRACE_LOG1 ("tmp_name = %s", tmp_name); + +  args = calloc (2 + i + 1, sizeof (*args)); +  args[0] = (char *) _gpgme_get_w32spawn_path (); +  args[1] = tmp_name; +  args[2] = path; +  memcpy (&args[3], &argv[1], i * sizeof (*args)); +    memset (&sec_attr, 0, sizeof sec_attr);    sec_attr.nLength = sizeof sec_attr;    sec_attr.bInheritHandle = FALSE; -   -  arg_string = build_commandline (argv); +  +  arg_string = build_commandline (args); +  free (args);    if (!arg_string) -    return TRACE_SYSRES (-1); -   +    { +      close (tmp_fd); +      DeleteFile (tmp_name); +      return TRACE_SYSRES (-1); +    } +    memset (&si, 0, sizeof si);    si.cb = sizeof (si);    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;    si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE; -  si.hStdInput = GetStdHandle (STD_INPUT_HANDLE); -  si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE); -  si.hStdError = GetStdHandle (STD_ERROR_HANDLE); +  si.hStdInput = INVALID_HANDLE_VALUE; +  si.hStdOutput = INVALID_HANDLE_VALUE; +  si.hStdError = INVALID_HANDLE_VALUE; -  for (i = 0; fd_child_list[i].fd != -1; i++) -    { -      if (fd_child_list[i].dup_to == 0) -	{ -	  si.hStdInput = fd_to_handle (fd_child_list[i].fd); -	  TRACE_LOG1 ("using 0x%x for stdin", fd_child_list[i].fd); -	  duped_stdin = 1; -        } -      else if (fd_child_list[i].dup_to == 1) -	{ -	  si.hStdOutput = fd_to_handle (fd_child_list[i].fd); -	  TRACE_LOG1 ("using 0x%x for stdout", fd_child_list[i].fd); -        } -      else if (fd_child_list[i].dup_to == 2) -	{ -	  si.hStdError = fd_to_handle (fd_child_list[i].fd); -	  TRACE_LOG1 ("using 0x%x for stderr", fd_child_list[i].fd); -	  duped_stderr = 1; -        } -    } -   -  if (!duped_stdin || !duped_stderr) -    { -      SECURITY_ATTRIBUTES sa; -       -      memset (&sa, 0, sizeof sa); -      sa.nLength = sizeof sa; -      sa.bInheritHandle = TRUE; -      hnul = CreateFile ("nul", -			 GENERIC_READ|GENERIC_WRITE, -			 FILE_SHARE_READ|FILE_SHARE_WRITE, -			 &sa, -			 OPEN_EXISTING, -			 FILE_ATTRIBUTE_NORMAL, -			 NULL); -      if (hnul == INVALID_HANDLE_VALUE) -	{ -	  TRACE_LOG1 ("CreateFile (\"nul\") failed: ec=%d", -		      (int) GetLastError ()); -	  free (arg_string); -	  /* FIXME: Should translate the error code.  */ -	  errno = EIO; -	  return TRACE_SYSRES (-1); -        } -      /* Make sure that the process has a connected stdin.  */ -      if (!duped_stdin) -	{ -	  si.hStdInput = hnul; -	  TRACE_LOG1 ("using 0x%x for dummy stdin", (int) hnul); -        } -      /* We normally don't want all the normal output.  */ -      if (!duped_stderr) -	{ -	  si.hStdError = hnul; -	  TRACE_LOG1 ("using 0x%x for dummy stderr", (int) hnul); -        } -    } -      cr_flags |= CREATE_SUSPENDED;     cr_flags |= DETACHED_PROCESS; -  if (!CreateProcessA (path, +  if (!CreateProcessA (_gpgme_get_w32spawn_path (),  		       arg_string,  		       &sec_attr,     /* process security attributes */  		       &sec_attr,     /* thread security attributes */ -		       TRUE,          /* inherit handles */ +		       FALSE,         /* inherit handles */  		       cr_flags,      /* creation flags */ -		       envblock,      /* environment */ +		       NULL,          /* environment */  		       NULL,          /* use current drive/directory */  		       &si,           /* startup information */  		       &pi))          /* returns process information */      {        TRACE_LOG1 ("CreateProcess failed: ec=%d", (int) GetLastError ());        free (arg_string); +      close (tmp_fd); +      DeleteFile (tmp_name); +        /* FIXME: Should translate the error code.  */        errno = EIO;        return TRACE_SYSRES (-1);      } -  /* Close the /dev/nul handle if used.  */ -  if (hnul != INVALID_HANDLE_VALUE) +  free (arg_string); + +  /* Insert the inherited handles.  */ +  for (i = 0; fd_list[i].fd != -1; i++)      { -      if (!CloseHandle (hnul)) -	TRACE_LOG1 ("CloseHandle (hnul) failed: ec=%d (ignored)", -		    (int) GetLastError ()); +      HANDLE hd; + +      /* Make it inheritable for the wrapper process.  */ +      if (!DuplicateHandle (GetCurrentProcess(), fd_to_handle (fd_list[i].fd), +			    pi.hProcess, &hd, 0, TRUE, DUPLICATE_SAME_ACCESS)) +	{ +	  TRACE_LOG1 ("DuplicateHandle failed: ec=%d", (int) GetLastError ()); +	  TerminateProcess (pi.hProcess, 0); +	  /* Just in case TerminateProcess didn't work, let the +	     process fail on its own.  */ +	  ResumeThread (pi.hThread); +	  CloseHandle (pi.hThread); +	  CloseHandle (pi.hProcess); + +	  close (tmp_fd); +	  DeleteFile (tmp_name); + +	  /* FIXME: Should translate the error code.  */ +	  errno = EIO; +	  return TRACE_SYSRES (-1); +        } +      /* Return the child name of this handle.  */ +      fd_list[i].peer_name = handle_to_fd (hd);      } -  /* Close the other ends of the pipes.  */ -  for (i = 0; fd_parent_list[i].fd != -1; i++) -    _gpgme_io_close (fd_parent_list[i].fd); -   +  /* Write the handle translation information to the temporary +     file.  */ +  { +    /* Hold roughly MAX_TRANS quadruplets of 64 bit numbers in hex +       notation: "0xFEDCBA9876543210" with an extra white space after +       every quadruplet.  10*(19*4 + 1) - 1 = 769.  This plans ahead +       for a time when a HANDLE is 64 bit.  */ +#define BUFFER_MAX 800 +    char line[BUFFER_MAX + 1]; +    int res; +    int written; +    size_t len; + +    line[0] = '\n'; +    line[1] = '\0'; +    for (i = 0; fd_list[i].fd != -1; i++) +      { +	/* Strip the newline.  */ +	len = strlen (line) - 1; +	 +	/* Format is: Local name, stdin/stdout/stderr, peer name, argv idx.  */ +	snprintf (&line[len], BUFFER_MAX - len, "0x%x %d 0x%x %d  \n", +		  fd_list[i].fd, fd_list[i].dup_to, +		  fd_list[i].peer_name, fd_list[i].arg_loc); +	/* Rather safe than sorry.  */ +	line[BUFFER_MAX - 1] = '\n'; +	line[BUFFER_MAX] = '\0'; +      } +    len = strlen (line); +    written = 0; +    do +      { +	res = write (tmp_fd, &line[written], len - written); +	if (res > 0) +	  written += res; +      } +    while (res > 0 || (res < 0 && errno == EAGAIN)); +  } +  close (tmp_fd); +  /* The temporary file is deleted by the gpgme-w32spawn process +     (hopefully).  */ +    TRACE_LOG4 ("CreateProcess ready: hProcess=%p, hThread=%p, "  	      "dwProcessID=%d, dwThreadId=%d",  	      pi.hProcess, pi.hThread,   	      (int) pi.dwProcessId, (int) pi.dwThreadId); +      if (r_pid)      *r_pid = (pid_t)pi.dwProcessId; @@ -1157,10 +1189,24 @@ _gpgme_io_spawn (const char *path, char **argv,      TRACE_LOG1 ("CloseHandle of thread failed: ec=%d",  		(int) GetLastError ()); -  TRACE_SUC1 ("process=%p", pi.hProcess); +  TRACE_LOG1 ("process=%p", pi.hProcess); + +  /* We don't need to wait for the process.  */ +  if (!CloseHandle (pi.hProcess)) +    TRACE_LOG1 ("CloseHandle of process failed: ec=%d", +		(int) GetLastError ()); -  /* We don't need to wait for the process. */ -  CloseHandle (pi.hProcess); +  for (i = 0; fd_list[i].fd != -1; i++) +    _gpgme_io_close (fd_list[i].fd); + +  for (i = 0; fd_list[i].fd != -1; i++) +    if (fd_list[i].dup_to == -1) +      TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, +		  fd_list[i].peer_name); +    else +      TRACE_LOG4 ("fd[%i] = 0x%x -> 0x%x (std%s)", i, fd_list[i].fd, +		  fd_list[i].peer_name, (fd_list[i].dup_to == 0) ? "in" : +		  ((fd_list[i].dup_to == 1) ? "out" : "err"));    return TRACE_SYSRES (0);  } | 
