diff options
Diffstat (limited to 'common/exechelp-w32.c')
-rw-r--r-- | common/exechelp-w32.c | 221 |
1 files changed, 147 insertions, 74 deletions
diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c index 297f6f854..13f600716 100644 --- a/common/exechelp-w32.c +++ b/common/exechelp-w32.c @@ -257,7 +257,7 @@ build_w32_commandline (const char *pgmname, const char * const *argv, /* Create pipe where one end is inheritable: With an INHERIT_IDX of 0 the read end is inheritable, with 1 the write end is inheritable. */ static int -create_inheritable_pipe (int filedes[2], int inherit_idx) +create_inheritable_pipe (HANDLE filedes[2], int inherit_idx) { HANDLE r, w, h; SECURITY_ATTRIBUTES sec_attr; @@ -290,8 +290,8 @@ create_inheritable_pipe (int filedes[2], int inherit_idx) r = h; } - filedes[0] = handle_to_fd (r); - filedes[1] = handle_to_fd (w); + filedes[0] = r; + filedes[1] = w; return 0; } @@ -315,27 +315,27 @@ static gpg_error_t do_create_pipe (int filedes[2], int inherit_idx) { gpg_error_t err = 0; - int fds[2]; + HANDLE fds[2]; filedes[0] = filedes[1] = -1; err = gpg_error (GPG_ERR_GENERAL); if (!create_inheritable_pipe (fds, inherit_idx)) { - filedes[0] = _open_osfhandle (fds[0], 0); + filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), 0); if (filedes[0] == -1) { - log_error ("failed to translate osfhandle %p\n", (void*)fds[0]); - CloseHandle (fd_to_handle (fds[1])); + log_error ("failed to translate osfhandle %p\n", fds[0]); + CloseHandle (fds[1]); } else { - filedes[1] = _open_osfhandle (fds[1], 1); + filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), 1); if (filedes[1] == -1) { - log_error ("failed to translate osfhandle %p\n", (void*)fds[1]); + log_error ("failed to translate osfhandle %p\n", fds[1]); close (filedes[0]); filedes[0] = -1; - CloseHandle (fd_to_handle (fds[1])); + CloseHandle (fds[1]); } else err = 0; @@ -365,9 +365,12 @@ gnupg_create_outbound_pipe (int filedes[2]) /* Fork and exec the PGMNAME, see exechelp.h for details. */ gpg_error_t gnupg_spawn_process (const char *pgmname, const char *argv[], - estream_t infile, estream_t outfile, + gpg_err_source_t errsource, void (*preexec)(void), unsigned int flags, - estream_t *statusfile, pid_t *pid) + estream_t infp, + estream_t *r_outfp, + estream_t *r_errfp, + pid_t *pid) { gpg_error_t err; SECURITY_ATTRIBUTES sec_attr; @@ -381,32 +384,103 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], STARTUPINFO si; int cr_flags; char *cmdline; - int fd, fdout, rp[2]; - HANDLE nullhd[2]; + HANDLE inhandle = INVALID_HANDLE_VALUE; + HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; + HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; + estream_t outfp = NULL; + estream_t errfp = NULL; + HANDLE nullhd[3] = {INVALID_HANDLE_VALUE, + INVALID_HANDLE_VALUE, + INVALID_HANDLE_VALUE}; int i; + es_syshd_t syshd; - (void)preexec; - - /* Setup return values. */ - *statusfile = NULL; - *pid = (pid_t)(-1); + if (r_outfp) + *r_outfp = NULL; + if (r_errfp) + *r_errfp = NULL; + *pid = (pid_t)(-1); /* Always required. */ - if (infile) + if (infp) { - es_fflush (infile); - es_rewind (infile); - fd = _get_osfhandle (es_fileno (infile)); + es_fflush (infp); + es_rewind (infp); + es_syshd (infp, &syshd); + switch (syshd.type) + { + case ES_SYSHD_FD: + inhandle = (HANDLE)_get_osfhandle (syshd.u.fd); + break; + case ES_SYSHD_SOCK: + inhandle = (HANDLE)_get_osfhandle (syshd.u.sock); + break; + case ES_SYSHD_HANDLE: + inhandle = syshd.u.handle; + break; + default: + inhandle = INVALID_HANDLE_VALUE; + break; + } + if (inhandle == INVALID_HANDLE_VALUE) + return gpg_err_make (errsource, GPG_ERR_INV_VALUE); + /* FIXME: In case we can't get a system handle (e.g. due to + es_fopencookie we should create a piper and a feeder + thread. */ } - else - fd = -1; - if (outfile) - fdout = _get_osfhandle (es_fileno (outfile)); - else - fdout = -1; + if (r_outfp) + { + if (create_inheritable_pipe (outpipe, 1)) + { + err = gpg_err_make (errsource, GPG_ERR_GENERAL); + log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); + return err; + } - if ( (infile && fd == -1) || (outfile && fdout == -1)) - log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n"); + syshd.type = ES_SYSHD_HANDLE; + syshd.u.handle = outpipe[0]; + outfp = es_sysopen (&syshd, "r"); + if (!outfp) + { + err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); + log_error (_("error creating a stream for a pipe: %s\n"), + gpg_strerror (err)); + CloseHandle (outpipe[0]); + CloseHandle (outpipe[1]); + outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE; + return err; + } + } + + if (r_errfp) + { + if (create_inheritable_pipe (errpipe, 1)) + { + err = gpg_err_make (errsource, GPG_ERR_GENERAL); + log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); + return err; + } + + syshd.type = ES_SYSHD_HANDLE; + syshd.u.handle = errpipe[0]; + errfp = es_sysopen (&syshd, "r"); + if (!errfp) + { + err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); + log_error (_("error creating a stream for a pipe: %s\n"), + gpg_strerror (err)); + CloseHandle (errpipe[0]); + CloseHandle (errpipe[1]); + errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE; + if (outfp) + es_fclose (outfp); + else if (outpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[0]); + if (outpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[1]); + return err; + } + } /* Prepare security attributes. */ memset (&sec_attr, 0, sizeof sec_attr ); @@ -418,27 +492,24 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], if (err) return err; - /* Create a pipe. */ - if (create_inheritable_pipe (rp, 1)) - { - err = gpg_error (GPG_ERR_GENERAL); - log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); - xfree (cmdline); - return err; - } - - nullhd[0] = fd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE; - nullhd[1] = fdout == -1? w32_open_null (1) : INVALID_HANDLE_VALUE; + if (inhandle != INVALID_HANDLE_VALUE) + nullhd[0] = w32_open_null (0); + if (outpipe[1] != INVALID_HANDLE_VALUE) + nullhd[1] = w32_open_null (0); + if (errpipe[1] != INVALID_HANDLE_VALUE) + nullhd[2] = w32_open_null (0); /* Start the process. Note that we can't run the PREEXEC function - because this would change our own environment. */ + because this might change our own environment. */ + (void)preexec; + 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 = fd == -1? nullhd[0] : fd_to_handle (fd); - si.hStdOutput = fdout == -1? nullhd[1] : fd_to_handle (fdout); - si.hStdError = fd_to_handle (rp[1]); + si.hStdInput = inhandle == INVALID_HANDLE_VALUE? nullhd[0] : inhandle; + si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1]; + si.hStdError = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1]; cr_flags = (CREATE_DEFAULT_ERROR_MODE | ((flags & 128)? DETACHED_PROCESS : 0) @@ -459,9 +530,19 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], { log_error ("CreateProcess failed: %s\n", w32_strerror (-1)); xfree (cmdline); - CloseHandle (fd_to_handle (rp[0])); - CloseHandle (fd_to_handle (rp[1])); - return gpg_error (GPG_ERR_GENERAL); + if (outfp) + es_fclose (outfp); + else if (outpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[0]); + if (outpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[1]); + if (errfp) + es_fclose (errfp); + else if (errpipe[0] != INVALID_HANDLE_VALUE) + CloseHandle (errpipe[0]); + if (errpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (errpipe[1]); + return gpg_err_make (errsource, GPG_ERR_GENERAL); } xfree (cmdline); cmdline = NULL; @@ -471,17 +552,21 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], if (nullhd[i] != INVALID_HANDLE_VALUE) CloseHandle (nullhd[i]); - /* Close the other end of the pipe. */ - CloseHandle (fd_to_handle (rp[1])); - -/* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */ -/* " dwProcessID=%d dwThreadId=%d\n", */ -/* pi.hProcess, pi.hThread, */ -/* (int) pi.dwProcessId, (int) pi.dwThreadId); */ + /* Close the inherited ends of the pipes. */ + if (outpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (outpipe[1]); + if (errpipe[1] != INVALID_HANDLE_VALUE) + CloseHandle (errpipe[1]); + /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */ + /* " dwProcessID=%d dwThreadId=%d\n", */ + /* pi.hProcess, pi.hThread, */ + /* (int) pi.dwProcessId, (int) pi.dwThreadId); */ + /* log_debug (" outfp=%p errfp=%p\n", outfp, errfp); */ + /* Fixme: For unknown reasons AllowSetForegroundWindow returns an - invalid argument error if we pass the correct processID to - it. As a workaround we use -1 (ASFW_ANY). */ + invalid argument error if we pass it the correct processID. As a + workaround we use -1 (ASFW_ANY). */ if ( (flags & 64) ) gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/); @@ -489,22 +574,10 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], ResumeThread (pi.hThread); CloseHandle (pi.hThread); - { - int x; - - x = _open_osfhandle (rp[0], 0); - if (x == -1) - log_error ("failed to translate osfhandle %p\n", (void*)rp[0] ); - else - *statusfile = es_fdopen (x, "r"); - } - if (!*statusfile) - { - err = gpg_error_from_syserror (); - log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err)); - CloseHandle (pi.hProcess); - return err; - } + if (r_outfp) + *r_outfp = outfp; + if (r_errfp) + *r_errfp = errfp; *pid = handle_to_pid (pi.hProcess); return 0; |