+2008-06-25 Marcus Brinkmann <marcus@g10code.de>
+
+ * assuan-pipe-connect.c (struct spawn_fd_item_s): Add new members.
+ (HANDLE_TRANSLATION): New macro.
+ (pipe_connect_gpgme): Adjust caller of _gpgme_io_spawn.
+ [HANDLE_TRANSLATION]: Return translated handles.
+
2008-02-14 Werner Koch <wk@g10code.com>
* assuan-pipe-connect.c (_gpgme_io_spawn): Adjust prototype.
#ifdef _ASSUAN_IN_GPGME_BUILD_ASSUAN
+/* From GPGME priv-io.h */
+struct spawn_fd_item_s
+{
+ int fd;
+ int dup_to;
+ int peer_name;
+ int arg_loc;
+};
+
+
int _gpgme_io_pipe (int filedes[2], int inherit_idx);
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);
#endif
/* Hacks for Slowaris. */
#define pipe_connect pipe_connect_gpgme
-/* From GPGME priv-io.h */
-struct spawn_fd_item_s
-{
- int fd;
- int dup_to;
-};
-
/* W32 version of the pipe connection code. */
static assuan_error_t
pipe_connect_gpgme (assuan_context_t *ctx,
{
assuan_error_t err;
int res;
+ int idx;
+ int nr;
int rp[2];
int wp[2];
char mypidstr[50];
- struct spawn_fd_item_s child_fds[3]; /* stdin, stdout, terminating -1 */
+ struct spawn_fd_item_s *child_fds;
if (!ctx || !name || !argv || !argv[0])
return _assuan_error (ASSUAN_Invalid_Value);
+ /* stdin, stdout, terminating -1 */
+ nr = 3;
+ for (idx = 0; fd_child_list[idx] != -1; idx++)
+ nr++;
+
+ child_fds = calloc (nr, sizeof *child_fds);
+ if (! child_fds)
+ return _assuan_error (ASSUAN_Out_Of_Core);
+
/* Actually, GPGME does this for us. But we plan to reuse this code
in the generic assuan. */
fix_signals ();
the old value, changeit, create proces and restore it, is not
thread safe. */
- /* Parent list is same as client list. Note that GPGME will dup nul
- to stderr even if the caller wants to inherit the handle for
- it. */
+ nr = 0;
/* Server stdout is its write end of our read pipe. */
- child_fds[0].fd = rp[1];
- child_fds[0].dup_to = 1;
+ child_fds[nr].fd = rp[1];
+ child_fds[nr].dup_to = 1;
+ nr++;
/* Server stdin is its read end of our write pipe. */
- child_fds[1].fd = wp[0];
- child_fds[1].dup_to = 0;
- child_fds[2].fd = -1;
+ child_fds[nr].fd = wp[0];
+ child_fds[nr].dup_to = 0;
+ nr++;
+
+ for (idx = 0; fd_child_list[idx] != -1; idx++)
+ {
+ child_fds[nr].fd = fd_child_list[idx];
+ child_fds[nr].dup_to = -1;
+ nr++;
+ }
+
+ child_fds[nr].fd = -1;
+ child_fds[nr].dup_to = -1;
/* Start the process. */
- res = _gpgme_io_spawn (name, argv, child_fds, child_fds, NULL);
+ res = _gpgme_io_spawn (name, argv, child_fds, NULL);
if (res == -1)
{
_assuan_log_printf ("CreateProcess failed: %s\n", strerror (errno));
_gpgme_io_close (wp[1]);
return _assuan_error (ASSUAN_General_Error);
}
+ else
+ {
+ /* For W32, the user needs to know the server-local names of the
+ inherited handles. Return them here. */
+ for (idx = 0; fd_child_list[idx] != -1; idx++)
+ /* We add 2 to skip over the stdin/stdout pair. */
+ fd_child_list[idx] = child_fds[idx + 2].peer_name;
+ }
(*ctx)->pid = 0; /* We don't use the PID. */
+2008-06-25 Marcus Brinkmann <marcus@g10code.de>
+
+ * gpgme-w32spawn.c: New file.
+ * Makefile.am (libexec_PROGRAMS) [HAVE_W32_SYSTEM]: New variable
+ with gpgme-w32spawn.
+ * engine-gpgsm.c (gpgsm_new): Use server translated handles.
+ (gpgsm_set_locale): Return early if locale value is NULL.
+ * util.h (_gpgme_mkstemp)
+ (_gpgme_get_w32spawn_path) [HAVE_W32_SYSTEM]: New function
+ prototypes.
+ * w32-util.c: Include <stdint.h>, <sys/stat.h> and <unistd.h>.
+ (letters, mkstemp, _gpgme_mkstemp, _gpgme_get_w32spawn_path): New
+ functions.
+ * rungpg.c (gpg_decrypt, gpg_encrypt, gpg_encrypt_sign)
+ (gpg_genkey, gpg_import, gpg_verify, gpg_sign): Pass data over
+ special filename FD rather than stdin.
+ (struct arg_and_data_s): Add member ARG_LOCP.
+ (struct fd_data_map_s): Add member ARG_LOC.
+ (struct engine_gpg): Add member ARG_LOC to status and colon.
+ (_add_arg, add_arg_with_locp): New function.
+ (add_arg_ext): Reimplement in terms of _add_arg.
+ (gpg_new): Remember argument location for status FD.
+ (build_argv): Set argument location if requested. Also set
+ argument location of fd_data_map for data items.
+ (start): Adjust caller of _gpgme_io_spawn.
+ * priv-io.h (struct spawn_fd_item_s): Add members peer_name and
+ arg_loc.
+ (_gpgme_io_spawn): Remove parent fd list argument.
+ * posix-io.c (get_max_fds): New function.
+ (_gpgme_io_dup): Add tracing.
+ (_gpgme_io_spawn): Remove parent fd list. Change meaning of child
+ fd list to contain all child fds that should be inherited. Close
+ all other file descriptors after fork.
+ * w32-io.c, w32-glib-io.c, w32-qt-io.c(_gpgme_io_spawn): Remove
+ parent fd list. Change meaning of child fd list to contain all
+ child fds that should be inherited. Do not inherit any file
+ descriptors, but DuplicateHandle them. Spawn process through
+ wrapper process. Provide wrapper process with a temporary file
+ containing handle translation data. Return translated handle
+ names.
+ * w32-io.c (reader): Add more tracing output.
+ (_gpgme_io_read): Likewise.
+ * engine-gpgconf.c (gpgconf_read): Adjust caller of
+ _gpgme_io_spawn.
+ * version.c (_gpgme_get_program_version): Likewise.
+
2008-06-20 Werner Koch <wk@g10code.com>
* engine-gpgconf.c (gpgconf_read): Change ARGV initialization for
if HAVE_W32_SYSTEM
+# Windows provides us with an endless stream of Tough Love. To spawn
+# processes with a controlled set of inherited handles, we need a
+# wrapper process.
+libexec_PROGRAMS = gpgme-w32spawn
+
+
LTRCCOMPILE = $(LIBTOOL) --mode=compile $(RC) \
`echo $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) | \
sed -e 's/-I/--include-dir /g;s/-D/--define /g'`
int linelen = 0;
char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
int rp[2];
- struct spawn_fd_item_s pfd[] = { {0, -1}, {-1, -1} };
- struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */}, {-1, -1} };
+ struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
+ {-1, -1} };
int status;
int nread;
char *mark = NULL;
if (_gpgme_io_pipe (rp, 1) < 0)
return gpg_error_from_syserror ();
- pfd[0].fd = rp[1];
cfd[0].fd = rp[1];
- status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, pfd, NULL);
+ status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, NULL);
if (status < 0)
{
_gpgme_io_close (rp[0]);
int buflen = 0;
char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
int rp[2];
- struct spawn_fd_item_s pfd[] = { {1, -1}, {-1, -1} };
struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
int status;
int nwrite;
if (_gpgme_io_pipe (rp, 0) < 0)
return gpg_error_from_syserror ();
- pfd[0].fd = rp[0];
cfd[0].fd = rp[0];
- status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, pfd, NULL);
+ status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, NULL);
if (status < 0)
{
_gpgme_io_close (rp[0]);
}
gpgsm->input_cb.fd = fds[1];
gpgsm->input_cb.server_fd = fds[0];
- _gpgme_io_fd2str (gpgsm->input_cb.server_fd_str,
- sizeof gpgsm->input_cb.server_fd_str,
- gpgsm->input_cb.server_fd);
if (_gpgme_io_pipe (fds, 1) < 0)
{
}
gpgsm->output_cb.fd = fds[0];
gpgsm->output_cb.server_fd = fds[1];
- _gpgme_io_fd2str (gpgsm->output_cb.server_fd_str,
- sizeof gpgsm->output_cb.server_fd_str,
- gpgsm->output_cb.server_fd);
if (_gpgme_io_pipe (fds, 0) < 0)
{
}
gpgsm->message_cb.fd = fds[1];
gpgsm->message_cb.server_fd = fds[0];
- _gpgme_io_fd2str (gpgsm->message_cb.server_fd_str,
- sizeof gpgsm->message_cb.server_fd_str,
- gpgsm->message_cb.server_fd);
child_fds[0] = gpgsm->input_cb.server_fd;
child_fds[1] = gpgsm->output_cb.server_fd;
err = assuan_pipe_connect
(&gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
argv, child_fds);
+
+ /* On Windows, handles are inserted in the spawned process with
+ DuplicateHandle, and child_fds contains the server-local names
+ for the inserted handles when assuan_pipe_connect returns. */
+ if (!err)
+ {
+ /* Note: We don't use _gpgme_io_fd2str here. On W32 the
+ returned handles are real W32 system handles, not whatever
+ GPGME uses internally (which may be a system handle, a C
+ library handle or a GLib/Qt channel. Confusing, yes, but
+ remember these are server-local names, so they are not part
+ of GPGME at all. */
+ snprintf (gpgsm->input_cb.server_fd_str,
+ sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
+ snprintf (gpgsm->output_cb.server_fd_str,
+ sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
+ snprintf (gpgsm->message_cb.server_fd_str,
+ sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
+ }
#endif
if (err)
goto leave;
+ /* assuan_pipe_connect in this case uses _gpgme_io_spawn which
+ closes the child fds for us. */
+ gpgsm->input_cb.server_fd = -1;
+ gpgsm->output_cb.server_fd = -1;
+ gpgsm->message_cb.server_fd = -1;
+
err = _gpgme_getenv ("DISPLAY", &dft_display);
if (err)
goto leave;
else
return gpg_error (GPG_ERR_INV_VALUE);
+ /* FIXME: Reset value to default. */
+ if (!value)
+ return 0;
+
if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
err = gpg_error_from_errno (errno);
else
if (err)
err = map_assuan_error (err);
}
+
return err;
}
--- /dev/null
+/* gpgme-w32spawn.c - Wrapper to spawn a process under Windows.
+ Copyright (C) 2008 g10 Code GmbH
+
+ This file is part of GPGME.
+
+ GPGME is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of
+ the License, or (at your option) any later version.
+
+ GPGME 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <process.h>
+#include <windows.h>
+
+
+\f
+struct spawn_fd_item_s
+{
+ int handle;
+ int dup_to;
+ int peer_name;
+ int arg_loc;
+};
+
+
+static char *
+build_commandline (char **argv)
+{
+ int i;
+ int n = 0;
+ char *buf;
+ char *p;
+
+ /* We have to quote some things because under Windows the program
+ parses the commandline and does some unquoting. We enclose the
+ whole argument in double-quotes, and escape literal double-quotes
+ as well as backslashes with a backslash. We end up with a
+ trailing space at the end of the line, but that is harmless. */
+ for (i = 0; argv[i]; i++)
+ {
+ p = argv[i];
+ /* The leading double-quote. */
+ n++;
+ while (*p)
+ {
+ /* An extra one for each literal that must be escaped. */
+ if (*p == '\\' || *p == '"')
+ n++;
+ n++;
+ p++;
+ }
+ /* The trailing double-quote and the delimiter. */
+ n += 2;
+ }
+ /* And a trailing zero. */
+ n++;
+
+ buf = p = malloc (n);
+ if (!buf)
+ return NULL;
+ for (i = 0; argv[i]; i++)
+ {
+ char *argvp = argv[i];
+
+ *(p++) = '"';
+ while (*argvp)
+ {
+ if (*argvp == '\\' || *argvp == '"')
+ *(p++) = '\\';
+ *(p++) = *(argvp++);
+ }
+ *(p++) = '"';
+ *(p++) = ' ';
+ }
+ *(p++) = 0;
+
+ return buf;
+}
+
+
+int
+my_spawn (char **argv, struct spawn_fd_item_s *fd_list)
+{
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi =
+ {
+ NULL, /* returns process handle */
+ 0, /* returns primary thread handle */
+ 0, /* returns pid */
+ 0 /* returns tid */
+ };
+ STARTUPINFO si;
+ char *envblock = NULL;
+ int cr_flags = CREATE_DEFAULT_ERROR_MODE
+ | GetPriorityClass (GetCurrentProcess ());
+ int i;
+ char *arg_string;
+ int duped_stdin = 0;
+ int duped_stdout = 0;
+ int duped_stderr = 0;
+ HANDLE hnul = INVALID_HANDLE_VALUE;
+ /* FIXME. */
+ int debug_me = 0;
+
+ i = 0;
+ while (argv[i])
+ {
+ fprintf (stderr, "argv[%2i] = %s\n", i, argv[i]);
+ i++;
+ }
+
+ memset (&sec_attr, 0, sizeof sec_attr);
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ arg_string = build_commandline (argv);
+ if (!arg_string)
+ return -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);
+
+ fprintf (stderr, "spawning: %s\n", arg_string);
+
+ for (i = 0; fd_list[i].handle != -1; i++)
+ {
+ /* The handle already is inheritable. */
+ if (fd_list[i].dup_to == 0)
+ {
+ si.hStdInput = (HANDLE) fd_list[i].peer_name;
+ duped_stdin = 1;
+ fprintf (stderr, "dup 0x%x to stdin\n", fd_list[i].peer_name);
+ }
+ else if (fd_list[i].dup_to == 1)
+ {
+ si.hStdOutput = (HANDLE) fd_list[i].peer_name;
+ duped_stdout = 1;
+ fprintf (stderr, "dup 0x%x to stdout\n", fd_list[i].peer_name);
+ }
+ else if (fd_list[i].dup_to == 2)
+ {
+ si.hStdError = (HANDLE) fd_list[i].peer_name;
+ duped_stderr = 1;
+ fprintf (stderr, "dup 0x%x to stderr\n", fd_list[i].peer_name);
+ }
+ }
+
+ if (!duped_stdin || !duped_stdout || !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)
+ {
+ free (arg_string);
+ /* FIXME: Should translate the error code. */
+ errno = EIO;
+ return -1;
+ }
+ /* Make sure that the process has a connected stdin. */
+ if (!duped_stdin)
+ si.hStdInput = hnul;
+ /* Make sure that the process has a connected stdout. */
+ if (!duped_stdout)
+ si.hStdOutput = hnul;
+ /* We normally don't want all the normal output. */
+ if (!duped_stderr)
+ si.hStdError = hnul;
+ }
+
+ cr_flags |= CREATE_SUSPENDED;
+ cr_flags |= DETACHED_PROCESS;
+ if (!CreateProcessA (argv[0],
+ arg_string,
+ &sec_attr, /* process security attributes */
+ &sec_attr, /* thread security attributes */
+ TRUE, /* inherit handles */
+ cr_flags, /* creation flags */
+ envblock, /* environment */
+ NULL, /* use current drive/directory */
+ &si, /* startup information */
+ &pi)) /* returns process information */
+ {
+ free (arg_string);
+ /* FIXME: Should translate the error code. */
+ errno = EIO;
+ return -1;
+ }
+
+ free (arg_string);
+
+ /* Close the /dev/nul handle if used. */
+ if (hnul != INVALID_HANDLE_VALUE)
+ CloseHandle (hnul);
+
+ for (i = 0; fd_list[i].handle != -1; i++)
+ CloseHandle ((HANDLE) fd_list[i].handle);
+
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+ CloseHandle (pi.hProcess);
+
+ return 0;
+}
+
+\f
+#define MAX_TRANS 10
+
+int
+translate_get_from_file (const char *trans_file,
+ struct spawn_fd_item_s *fd_list)
+{
+ /* Hold roughly MAX_TRANS triplets of 64 bit numbers in hex
+ notation: "0xFEDCBA9876543210". 10*19*4 - 1 = 759. This plans
+ ahead for a time when a HANDLE is 64 bit. */
+#define BUFFER_MAX 800
+
+ char line[BUFFER_MAX + 1];
+ char *linep;
+ int idx;
+ int res;
+ int fd;
+
+ fd = open (trans_file, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ /* We always read one line from stdin. */
+ res = read (fd, line, BUFFER_MAX);
+ close (fd);
+ if (res < 0)
+ return -1;
+
+ line[BUFFER_MAX] = '\0';
+ linep = strchr (line, '\n');
+ if (linep > line && linep[-1] == '\r')
+ linep--;
+ *linep = '\0';
+
+ linep = line;
+
+ /* Now start to read mapping pairs. */
+ for (idx = 0; idx < MAX_TRANS; idx++)
+ {
+ unsigned long from;
+ long dup_to;
+ unsigned long to;
+ unsigned long loc;
+ char *tail;
+
+ /* FIXME: Maybe could use scanf. */
+ while (isspace (*((unsigned char *)linep)))
+ linep++;
+ if (*linep == '\0')
+ break;
+ from = strtoul (linep, &tail, 0);
+ if (tail == NULL || ! (*tail == '\0' || isspace (*tail)))
+ break;
+ linep = tail;
+
+ while (isspace (*linep))
+ linep++;
+ if (*linep == '\0')
+ break;
+ dup_to = strtol (linep, &tail, 0);
+ if (tail == NULL || ! (*tail == '\0' || isspace (*tail)))
+ break;
+ linep = tail;
+
+ while (isspace (*linep))
+ linep++;
+ if (*linep == '\0')
+ break;
+ to = strtoul (linep, &tail, 0);
+ if (tail == NULL || ! (*tail == '\0' || isspace (*tail)))
+ break;
+ linep = tail;
+
+ while (isspace (*linep))
+ linep++;
+ if (*linep == '\0')
+ break;
+ loc = strtoul (linep, &tail, 0);
+ if (tail == NULL || ! (*tail == '\0' || isspace (*tail)))
+ break;
+ linep = tail;
+
+ fd_list[idx].handle = from;
+ fd_list[idx].dup_to = dup_to;
+ fd_list[idx].peer_name = to;
+ fd_list[idx].arg_loc = loc;
+ }
+ fd_list[idx].handle = -1;
+ fd_list[idx].dup_to = -1;
+ fd_list[idx].peer_name = -1;
+ fd_list[idx].arg_loc = 0;
+ return 0;
+}
+
+
+/* Read the translated handles from TRANS_FILE and do a substitution
+ in ARGV. Returns the new argv and the list of substitutions in
+ FD_LIST (which must be MAX_TRANS+1 large). */
+char **
+translate_handles (const char *trans_file, const char * const *argv,
+ struct spawn_fd_item_s *fd_list)
+{
+ int res;
+ int idx;
+ char **args;
+
+ res = translate_get_from_file (trans_file, fd_list);
+ if (res < 0)
+ return NULL;
+
+ for (idx = 0; argv[idx]; idx++)
+ ;
+ args = malloc (sizeof (*args) * (idx + 1));
+ for (idx = 0; argv[idx]; idx++)
+ {
+ args[idx] = strdup (argv[idx]);
+ if (!args[idx])
+ return NULL;
+ }
+ args[idx] = NULL;
+
+ for (idx = 0; fd_list[idx].handle != -1; idx++)
+ {
+ char buf[25];
+ int aidx;
+
+ aidx = fd_list[idx].arg_loc;
+ if (aidx == 0)
+ continue;
+
+ args[aidx] = malloc (sizeof (buf));
+ /* We currently disable translation for stdin/stdout/stderr. We
+ assume that the spawned program handles 0/1/2 specially
+ already. FIXME: Check if this is true. */
+ if (!args[idx] || fd_list[idx].dup_to != -1)
+ return NULL;
+
+ /* NOTE: Here is the part where application specific knowledge
+ comes in. GPGME/GnuPG uses two forms of descriptor
+ specification, a plain number and a "-&" form. */
+ if (argv[aidx][0] == '-' && argv[aidx][1] == '&')
+ snprintf (args[aidx], sizeof (buf), "-&%d", fd_list[idx].peer_name);
+ else
+ snprintf (args[aidx], sizeof (buf), "%d", fd_list[idx].peer_name);
+ }
+ return args;
+}
+
+
+int
+main (int argc, const char * const *argv)
+{
+ int rc = 0;
+ char **argv_spawn;
+ struct spawn_fd_item_s fd_list[MAX_TRANS + 1];
+
+ if (argc < 3)
+ {
+ rc = 2;
+ goto leave;
+ }
+
+ argv_spawn = translate_handles (argv[1], &argv[2], fd_list);
+ if (!argv_spawn)
+ {
+ rc = 2;
+ goto leave;
+ }
+
+ /* Using execv does not replace the existing program image, but
+ spawns a new one and daemonizes it, confusing the command line
+ interpreter. So we have to use spawnv. */
+ rc = my_spawn (argv_spawn, fd_list);
+ if (rc < 0)
+ {
+ fprintf (stderr, "gpgwrap: executing `%s' failed: %s\n",
+ argv[0], strerror (errno));
+ rc = 2;
+ goto leave;
+ }
+
+ leave:
+ if (rc)
+ fprintf (stderr, "gpg-w32spawn: internal error\n");
+ /* Always try to delete the temporary file. */
+ if (argc >= 2)
+ {
+ if (DeleteFile (argv[1]) == 0)
+ fprintf (stderr, "Failed to delete %s: ec=%ld\n",
+ argv[1], GetLastError ());
+ }
+ return rc;
+}
AM_PATH_GPGME macro) check that this header matches the installed
library. Warning: Do not edit the next line. configure will do
that for you! */
-#define GPGME_VERSION "1.1.7-svn1313"
+#define GPGME_VERSION "1.1.7-svn1315"
\f
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
+#include <sys/resource.h>
+#include <unistd.h>
#include "util.h"
#include "priv-io.h"
}
+static long int
+get_max_fds (void)
+{
+ char *source = NULL;
+ long int fds = -1;
+ int rc;
+
+#ifdef RLIMIT_NOFILE
+ {
+ struct rlimit rl;
+ rc = getrlimit (RLIMIT_NOFILE, &rl);
+ if (rc == 0)
+ {
+ source = "RLIMIT_NOFILE";
+ fds = rl.rlim_max;
+ }
+ }
+#endif
+#ifdef RLIMIT_OFILE
+ if (fds == -1)
+ {
+ struct rlimit rl;
+ rc = getrlimit (RLIMIT_OFILE, &rl);
+ if (rc == 0)
+ {
+ source = "RLIMIT_OFILE";
+ fds = rl.rlim_max;
+ }
+ }
+#endif
+#ifdef _SC_OPEN_MAX
+ if (fds == -1)
+ {
+ long int scres;
+ scres = sysconf (_SC_OPEN_MAX);
+ if (scres >= 0)
+ {
+ source = "_SC_OPEN_MAX";
+ return scres;
+ }
+ }
+#endif
+#ifdef OPEN_MAX
+ if (fds == -1)
+ {
+ source = "OPEN_MAX";
+ fds = OPEN_MAX;
+ }
+#endif
+
+#if !defined(RLIMIT_NOFILE) && !defined(RLIMIT_OFILE) \
+ && !defined(_SC_OPEN_MAX) && !defined(OPEN_MAX)
+#warning "No known way to get the maximum number of file descriptors."
+#endif
+ if (fds == -1)
+ {
+ source = "arbitrary";
+ /* Arbitrary limit. */
+ fds = 1024;
+ }
+
+ TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", NULL, "max fds=%i (%s)", fds, source);
+ return fds;
+}
+
+
static int
_gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
{
/* Returns 0 on success, -1 on error. */
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)
{
pid_t pid;
int i;
TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
i++;
}
-
+ for (i = 0; fd_list[i].fd != -1; i++)
+ if (fd_list[i].dup_to == -1)
+ TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
+ else
+ TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
+
pid = fork ();
if (pid == -1)
return TRACE_SYSRES (-1);
-
+
if (!pid)
{
/* Intermediate child to prevent zombie processes. */
if ((pid = fork ()) == 0)
{
+ int max_fds = get_max_fds ();
+ int fd;
+
/* Child. */
- int duped_stdin = 0;
- int duped_stderr = 0;
+ int seen_stdin = 0;
+ int seen_stderr = 0;
- /* First close all fds which will not be duped. */
- for (i=0; fd_child_list[i].fd != -1; i++)
- if (fd_child_list[i].dup_to == -1)
- close (fd_child_list[i].fd);
+ /* First close all fds which will not be inherited. */
+ for (fd = 0; fd < max_fds; fd++)
+ {
+ for (i = 0; fd_list[i].fd != -1; i++)
+ if (fd_list[i].fd == fd)
+ break;
+ if (fd_list[i].fd == -1)
+ close (fd);
+ }
- /* And now dup and close the rest. */
- for (i=0; fd_child_list[i].fd != -1; i++)
+ /* And now dup and close those to be duplicated. */
+ for (i = 0; fd_list[i].fd != -1; i++)
{
- if (fd_child_list[i].dup_to != -1)
+ int child_fd;
+ int res;
+
+ if (fd_list[i].dup_to != -1)
+ child_fd = fd_list[i].dup_to;
+ else
+ child_fd = fd_list[i].fd;
+
+ if (child_fd == 0)
+ seen_stdin = 1;
+ else if (child_fd == 2)
+ seen_stderr = 1;
+
+ if (fd_list[i].dup_to == -1)
+ continue;
+
+ res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
+ if (res < 0)
{
- if (dup2 (fd_child_list[i].fd,
- fd_child_list[i].dup_to) == -1)
- {
#if 0
- /* FIXME: The debug file descriptor is not
- dup'ed anyway, so we can't see this. */
- TRACE_LOG1 ("dup2 failed in child: %s\n",
- strerror (errno));
+ /* FIXME: The debug file descriptor is not
+ dup'ed anyway, so we can't see this. */
+ TRACE_LOG1 ("dup2 failed in child: %s\n",
+ strerror (errno));
#endif
- _exit (8);
- }
- if (fd_child_list[i].dup_to == 0)
- duped_stdin=1;
- if (fd_child_list[i].dup_to == 2)
- duped_stderr=1;
- close (fd_child_list[i].fd);
+ _exit (8);
}
+
+ close (fd_list[i].fd);
}
- if (!duped_stdin || !duped_stderr)
+ if (! seen_stdin || ! seen_stderr)
{
- int fd = open ("/dev/null", O_RDWR);
+ fd = open ("/dev/null", O_RDWR);
if (fd == -1)
{
#if 0
_exit (8);
}
/* Make sure that the process has a connected stdin. */
- if (!duped_stdin)
+ if (! seen_stdin && fd != 0)
{
if (dup2 (fd, 0) == -1)
{
_exit (8);
}
}
- if (!duped_stderr)
+ if (! seen_stderr && fd != 2)
if (dup2 (fd, 2) == -1)
{
#if 0
#endif
_exit (8);
}
- close (fd);
+ if (fd != 0 && fd != 2)
+ close (fd);
}
- execv ( path, argv );
+ execv (path, argv);
/* Hmm: in that case we could write a special status code to the
status-pipe. */
#if 0
TRACE_LOG1 ("exec of `%s' failed\n", path);
#endif
_exit (8);
- } /* End child. */
+ /* End child. */
+ }
if (pid == -1)
_exit (1);
else
if (status)
return TRACE_SYSRES (-1);
- /* .dup_to is not used in the parent list. */
- for (i = 0; fd_parent_list[i].fd != -1; i++)
- _gpgme_io_close (fd_parent_list[i].fd);
+ for (i = 0; fd_list[i].fd != -1; i++)
+ {
+ _gpgme_io_close (fd_list[i].fd);
+ /* No handle translation. */
+ fd_list[i].peer_name = fd_list[i].fd;
+ }
if (r_pid)
*r_pid = pid;
int
_gpgme_io_dup (int fd)
{
- return dup (fd);
+ int new_fd = dup (fd);
+
+ TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
+
+ return new_fd;
}
/* A single file descriptor passed to spawn. For child fds, dup_to
- specifies the fd it should become in the child. */
+ specifies the fd it should become in the child, but only 0, 1 and 2
+ are valid values (due to a limitation in the W32 code). As return
+ value, the PEER_NAME fields specify the name of the file
+ descriptor in the spawned process, or -1 if no change. If ARG_LOC
+ is not 0, it specifies the index in the argument vector of the
+ program which contains a numerical representation of the file
+ descriptor for translation purposes. */
struct spawn_fd_item_s
{
int fd;
int dup_to;
+ int peer_name;
+ int arg_loc;
};
struct io_select_fd_s
void *value);
int _gpgme_io_set_nonblocking (int fd);
-/* Spawn the executable PATH with ARGV as arguments, after forking
- close all fds in FD_PARENT_LIST in the parent and close or dup all
- fds in FD_CHILD_LIST in the child. */
+/* Spawn the executable PATH with ARGV as arguments. After forking
+ close all fds except for those in FD_LIST in the child, then
+ optionally dup() the child fds. Finally, all fds in the list are
+ closed in the parent. */
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);
+
int _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock);
/* Write the printable version of FD to the buffer BUF of length
int inbound; /* True if this is used for reading from gpg. */
int dup_to;
int print_fd; /* Print the fd number and not the special form of it. */
+ int *arg_locp; /* Write back the argv idx of this argument when
+ building command line to this location. */
char arg[1]; /* Used if data above is not used. */
};
int inbound; /* true if this is used for reading from gpg */
int dup_to;
int fd; /* the fd to use */
- int peer_fd; /* the outher side of the pipe */
+ int peer_fd; /* the other side of the pipe */
+ int arg_loc; /* The index into the argv for translation purposes. */
void *tag;
};
struct
{
int fd[2];
+ int arg_loc;
size_t bufsize;
char *buffer;
size_t readpos;
struct
{
int fd[2];
+ int arg_loc;
size_t bufsize;
char *buffer;
size_t readpos;
/* If FRONT is true, push at the front of the list. Use this for
options added late in the process. */
static gpgme_error_t
-add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
+_add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
{
struct arg_and_data_s *a;
a->data = NULL;
a->dup_to = -1;
+ a->arg_locp = arg_locp;
+
strcpy (a->arg, arg);
if (front)
{
return 0;
}
+static gpgme_error_t
+add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
+{
+ return _add_arg (gpg, arg, front, NULL);
+}
+
+
+static gpgme_error_t
+add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp)
+{
+ return _add_arg (gpg, arg, 0, locp);
+}
+
+
static gpgme_error_t
add_arg (engine_gpg_t gpg, const char *arg)
{
return add_arg_ext (gpg, arg, 0);
}
+
static gpgme_error_t
add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
{
a->next = NULL;
a->data = data;
a->inbound = inbound;
+ a->arg_locp = NULL;
+
if (dup_to == -2)
{
a->print_fd = 1;
{
char buf[25];
_gpgme_io_fd2str (buf, sizeof (buf), gpg->status.fd[1]);
- rc = add_arg (gpg, buf);
+ rc = add_arg_with_locp (gpg, buf, &gpg->status.arg_loc);
if (rc)
goto leave;
}
argc++;
for (a = gpg->arglist; a; a = a->next)
{
+ if (a->arg_locp)
+ *(a->arg_locp) = argc;
+
if (a->data)
{
/* Create a pipe to pass it down to gpg. */
fd_data_map[datac].data = a->data;
fd_data_map[datac].dup_to = a->dup_to;
+
if (a->dup_to == -1)
{
char *ptr;
*(ptr++) = '&';
buflen -= 2;
}
-
+
_gpgme_io_fd2str (ptr, buflen, fd_data_map[datac].peer_fd);
+ fd_data_map[datac].arg_loc = argc;
argc++;
}
datac++;
int saved_errno;
int i, n;
int status;
- struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
+ struct spawn_fd_item_s *fd_list;
pid_t pid;
if (!gpg)
if (rc)
return rc;
- n = 3; /* status_fd, colon_fd and end of list */
+ /* status_fd, colon_fd and end of list. */
+ n = 3;
for (i = 0; gpg->fd_data_map[i].data; i++)
n++;
- fd_child_list = calloc (n + n, sizeof *fd_child_list);
- if (!fd_child_list)
+ fd_list = calloc (n, sizeof *fd_list);
+ if (! fd_list)
return gpg_error_from_errno (errno);
- fd_parent_list = fd_child_list + n;
- /* build the fd list for the child */
+ /* Build the fd list for the child. */
n = 0;
- /* The status fd is never dup'ed, so do not include it in the list. */
+ fd_list[n].fd = gpg->status.fd[1];
+ fd_list[n].dup_to = -1;
+ fd_list[n].arg_loc = gpg->status.arg_loc;
+ n++;
if (gpg->colon.fnc)
{
- fd_child_list[n].fd = gpg->colon.fd[1];
- fd_child_list[n].dup_to = 1; /* dup to stdout */
+ fd_list[n].fd = gpg->colon.fd[1];
+ fd_list[n].dup_to = 1;
n++;
}
for (i = 0; gpg->fd_data_map[i].data; i++)
{
- if (gpg->fd_data_map[i].dup_to != -1)
- {
- fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
- fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
- n++;
- }
- }
- fd_child_list[n].fd = -1;
- fd_child_list[n].dup_to = -1;
-
- /* Build the fd list for the parent. */
- n = 0;
- if (gpg->status.fd[1] != -1)
- {
- fd_parent_list[n].fd = gpg->status.fd[1];
- fd_parent_list[n].dup_to = -1;
- n++;
- }
- if (gpg->colon.fd[1] != -1)
- {
- fd_parent_list[n].fd = gpg->colon.fd[1];
- fd_parent_list[n].dup_to = -1;
+ fd_list[n].fd = gpg->fd_data_map[i].peer_fd;
+ fd_list[n].dup_to = gpg->fd_data_map[i].dup_to;
+ fd_list[n].arg_loc = gpg->fd_data_map[i].arg_loc;
n++;
}
- for (i = 0; gpg->fd_data_map[i].data; i++)
- {
- fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
- fd_parent_list[n].dup_to = -1;
- n++;
- }
- fd_parent_list[n].fd = -1;
- fd_parent_list[n].dup_to = -1;
+ fd_list[n].fd = -1;
+ fd_list[n].dup_to = -1;
status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name :
- _gpgme_get_gpg_path (),
- gpg->argv, fd_child_list, fd_parent_list, &pid);
+ _gpgme_get_gpg_path (), gpg->argv, fd_list, &pid);
saved_errno = errno;
- free (fd_child_list);
+
+ free (fd_list);
if (status == -1)
return gpg_error_from_errno (saved_errno);
if (!err)
err = add_data (gpg, plain, 1, 1);
if (!err)
- err = add_data (gpg, ciph, 0, 0);
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_data (gpg, ciph, -1, 0);
if (!err)
start (gpg);
if (!err)
err = add_arg (gpg, "--");
if (!err)
- err = add_data (gpg, plain, 0, 0);
+ err = add_data (gpg, plain, -1, 0);
if (!err)
err = start (gpg);
if (!err)
err = add_arg (gpg, "--");
if (!err)
- err = add_data (gpg, plain, 0, 0);
+ err = add_data (gpg, plain, -1, 0);
if (!err)
err = start (gpg);
if (!err && use_armor)
err = add_arg (gpg, "--armor");
if (!err)
- err = add_data (gpg, help_data, 0, 0);
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_data (gpg, help_data, -1, 0);
if (!err)
err = start (gpg);
err = add_arg (gpg, "--import");
if (!err)
- err = add_data (gpg, keydata, 0, 0);
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_data (gpg, keydata, -1, 0);
if (!err)
err = start (gpg);
/* Tell the gpg object about the data. */
if (!err)
- err = add_data (gpg, in, 0, 0);
+ err = add_arg (gpg, "--");
+ if (!err)
+ err = add_data (gpg, in, -1, 0);
if (!err)
err = add_data (gpg, out, 1, 1);
if (!err)
err = add_arg (gpg, "--");
if (!err)
- err = add_data (gpg, sig, 0, 0);
+ err = add_data (gpg, sig, -1, 0);
if (!err)
err = add_data (gpg, plaintext, 1, 1);
}
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, sig, -1, 0);
- if (signed_text)
- {
- if (!err)
- err = add_arg (gpg, "-");
- if (!err)
- err = add_data (gpg, signed_text, 0, 0);
- }
+ if (!err && signed_text)
+ err = add_data (gpg, signed_text, -1, 0);
}
if (!err)
set, return NULL in *VALUE. */
gpgme_error_t _gpgme_getenv (const char *name, char **value);
+\f
+#ifdef HAVE_W32_SYSTEM
+int _gpgme_mkstemp (int *fd, char **name);
+const char *_gpgme_get_w32spawn_path (void);
+#endif
+
#endif /* UTIL_H */
int rp[2];
int nread;
char *argv[] = {NULL /* file_name */, "--version", 0};
- struct spawn_fd_item_s pfd[] = { {0, -1}, {-1, -1} };
- struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */}, {-1, -1} };
+ struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
+ {-1, -1} };
int status;
if (!file_name)
if (_gpgme_io_pipe (rp, 1) < 0)
return NULL;
- pfd[0].fd = rp[1];
cfd[0].fd = rp[1];
- status = _gpgme_io_spawn (file_name, argv, cfd, pfd, NULL);
+ status = _gpgme_io_spawn (file_name, argv, cfd, NULL);
if (status < 0)
{
_gpgme_io_close (rp[0]);
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 =
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;
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);
-
- for (i = 0; fd_child_list[i].fd != -1; i++)
- {
- if (fd_child_list[i].dup_to == 0)
- {
- si.hStdInput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
- TRACE_LOG2 ("using 0x%x/%p for stdin", fd_child_list[i].fd,
- _get_osfhandle (fd_child_list[i].fd));
- duped_stdin = 1;
- }
- else if (fd_child_list[i].dup_to == 1)
- {
- si.hStdOutput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
- TRACE_LOG2 ("using 0x%x/%p for stdout", fd_child_list[i].fd,
- _get_osfhandle (fd_child_list[i].fd));
- }
- else if (fd_child_list[i].dup_to == 2)
- {
- si.hStdError = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
- TRACE_LOG2 ("using 0x%x/%p for stderr", fd_child_list[i].fd,
- _get_osfhandle (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 %d for dummy stderr", (int)hnul);
- }
- }
-
+ si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
+ si.hStdInput = INVALID_HANDLE_VALUE;
+ si.hStdOutput = INVALID_HANDLE_VALUE;
+ si.hStdError = INVALID_HANDLE_VALUE;
+
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);
}
+
+ free (arg_string);
- /* Close the /dev/nul handle if used. */
- if (hnul != INVALID_HANDLE_VALUE)
+ /* 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(), _get_osfhandle (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 = (int) 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;
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);
}
#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
}
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 ();
}
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;
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 =
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;
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;
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);
}
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 =
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;
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 = (char **) calloc (2 + i + 1, sizeof (*args));
+ args[0] = (char *) _gpgme_get_w32spawn_path ();
+ args[1] = tmp_name;
+ args[2] = const_cast<char *>(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);
-
- for (i = 0; fd_child_list[i].fd != -1; i++)
- {
- if (fd_child_list[i].dup_to == 0)
- {
- si.hStdInput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
- TRACE_LOG2 ("using 0x%x/%p for stdin", fd_child_list[i].fd,
- _get_osfhandle (fd_child_list[i].fd));
- duped_stdin = 1;
- }
- else if (fd_child_list[i].dup_to == 1)
- {
- si.hStdOutput = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
- TRACE_LOG2 ("using 0x%x/%p for stdout", fd_child_list[i].fd,
- _get_osfhandle (fd_child_list[i].fd));
- }
- else if (fd_child_list[i].dup_to == 2)
- {
- si.hStdError = (HANDLE) _get_osfhandle (fd_child_list[i].fd);
- TRACE_LOG2 ("using 0x%x/%p for stderr", fd_child_list[i].fd,
- _get_osfhandle (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 %d for dummy stderr", (int)hnul);
- }
- }
-
+ si.wShowWindow = debug_me ? SW_SHOW : SW_HIDE;
+ si.hStdInput = INVALID_HANDLE_VALUE;
+ si.hStdOutput = INVALID_HANDLE_VALUE;
+ si.hStdError = INVALID_HANDLE_VALUE;
+
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 ());
- }
-
- /* 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);
+ HANDLE hd;
+
+ if (!DuplicateHandle (GetCurrentProcess(),
+ (HANDLE) _get_osfhandle (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 = (int) hd;
+ }
+
+ /* 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;
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);
}
#include <string.h>
#include <assert.h>
#include <errno.h>
+#include <stdint.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <windows.h>
char *tmp;
tmp = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
- "Software\\GNU\\GnuPG",
- "Install Directory");
+ "Software\\GNU\\GnuPG",
+ "Install Directory");
if (!tmp)
return NULL;
}
+const char *
+_gpgme_get_w32spawn_path (void)
+{
+ static char *w32spawn_program;
+
+ LOCK (get_path_lock);
+ if (!w32spawn_program)
+ w32spawn_program = find_program_in_inst_dir ("gpgme-w32spawn.exe");
+ if (!w32spawn_program)
+ w32spawn_program
+ = find_program_at_standard_place ("GNU\\GnuPG\\gpgme-w32spawn.exe");
+ UNLOCK (get_path_lock);
+ return w32spawn_program;
+}
+
+
/* Return an integer value from gpgme specific configuration
entries. VALUE receives that value; function returns true if a value
has been configured and false if not. */
}
+
+\f
+/* mkstemp extracted from libc/sysdeps/posix/tempname.c. Copyright
+ (C) 1991-1999, 2000, 2001, 2006 Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version. */
+
+static const char letters[] =
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Generate a temporary file name based on TMPL. TMPL must match the
+ rules for mk[s]temp (i.e. end in "XXXXXX"). The name constructed
+ does not exist at the time of the call to mkstemp. TMPL is
+ overwritten with the result. */
+static int
+mkstemp (char *tmpl)
+{
+ int len;
+ char *XXXXXX;
+ static uint64_t value;
+ uint64_t random_time_bits;
+ unsigned int count;
+ int fd = -1;
+ int save_errno = errno;
+
+ /* A lower bound on the number of temporary files to attempt to
+ generate. The maximum total number of temporary file names that
+ can exist for a given template is 62**6. It should never be
+ necessary to try all these combinations. Instead if a reasonable
+ number of names is tried (we define reasonable as 62**3) fail to
+ give the system administrator the chance to remove the problems. */
+#define ATTEMPTS_MIN (62 * 62 * 62)
+
+ /* The number of times to attempt to generate a temporary file. To
+ conform to POSIX, this must be no smaller than TMP_MAX. */
+#if ATTEMPTS_MIN < TMP_MAX
+ unsigned int attempts = TMP_MAX;
+#else
+ unsigned int attempts = ATTEMPTS_MIN;
+#endif
+
+ len = strlen (tmpl);
+ if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* This is where the Xs start. */
+ XXXXXX = &tmpl[len - 6];
+
+ /* Get some more or less random data. */
+ {
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec;
+ }
+ value += random_time_bits ^ getpid ();
+
+ for (count = 0; count < attempts; value += 7777, ++count)
+ {
+ uint64_t v = value;
+
+ /* Fill in the random bits. */
+ XXXXXX[0] = letters[v % 62];
+ v /= 62;
+ XXXXXX[1] = letters[v % 62];
+ v /= 62;
+ XXXXXX[2] = letters[v % 62];
+ v /= 62;
+ XXXXXX[3] = letters[v % 62];
+ v /= 62;
+ XXXXXX[4] = letters[v % 62];
+ v /= 62;
+ XXXXXX[5] = letters[v % 62];
+
+ fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+ if (fd >= 0)
+ {
+ errno = save_errno;
+ return fd;
+ }
+ else if (errno != EEXIST)
+ return -1;
+ }
+
+ /* We got out of the loop because we ran out of combinations to try. */
+ errno = EEXIST;
+ return -1;
+}
+
+\f
+int
+_gpgme_mkstemp (int *fd, char **name)
+{
+ char tmp[MAX_PATH + 2];
+ char *tmpname;
+ int err;
+
+ *fd = -1;
+ *name = NULL;
+
+ err = GetTempPath (MAX_PATH + 1, tmp);
+ if (err == 0 || err > MAX_PATH + 1)
+ strcpy (tmp,"c:\\windows\\temp");
+ else
+ {
+ int len = strlen(tmp);
+
+ /* GetTempPath may return with \ on the end */
+ while(len > 0 && tmp[len - 1] == '\\')
+ {
+ tmp[len-1] = '\0';
+ len--;
+ }
+ }
+
+ tmpname = malloc (strlen (tmp) + 13 + 1);
+ if (!tmpname)
+ return -1;
+ sprintf (tmpname, "%s\\gpgme-XXXXXX", tmp);
+ *fd = mkstemp (tmpname);
+ if (fd < 0)
+ return -1;
+
+ *name = tmpname;
+ return 0;
+}