Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F35586714
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
17 KB
Subscribers
None
View Options
diff --git a/src/gpgme-w32spawn.c b/src/gpgme-w32spawn.c
index 8a4ab544..b510ba3a 100644
--- a/src/gpgme-w32spawn.c
+++ b/src/gpgme-w32spawn.c
@@ -1,501 +1,490 @@
/* 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>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <stdint.h>
#include <process.h>
-#include <windows.h>
-/* Flag values as used by gpgme. */
-#define IOSPAWN_FLAG_ALLOW_SET_FG 1
+#include "priv-io.h"
/* Name of this program. */
#define PGM "gpgme-w32spawn"
-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, unsigned int flags)
{
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, PGM": 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, PGM": spawning: %s\n", arg_string);
- for (i = 0; fd_list[i].handle != -1; i++)
+ for (i = 0; fd_list[i].fd != -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, PGM": 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, PGM": 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, PGM":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);
+ for (i = 0; fd_list[i].fd != -1; i++)
+ CloseHandle ((HANDLE) fd_list[i].fd);
if (flags & IOSPAWN_FLAG_ALLOW_SET_FG)
{
static int initialized;
static BOOL (WINAPI * func)(DWORD);
void *handle;
if (!initialized)
{
/* Available since W2000; thus we dynload it. */
initialized = 1;
handle = LoadLibrary ("user32.dll");
if (handle)
{
func = GetProcAddress (handle, "AllowSetForegroundWindow");
if (!func)
FreeLibrary (handle);
}
}
if (func)
{
int rc = func (pi.dwProcessId);
fprintf (stderr, PGM": AllowSetForegroundWindow(%d): rc=%d\n",
(int)pi.dwProcessId, rc);
}
}
ResumeThread (pi.hThread);
CloseHandle (pi.hThread);
CloseHandle (pi.hProcess);
return 0;
}
#define MAX_TRANS 10
int
translate_get_from_file (const char *trans_file,
struct spawn_fd_item_s *fd_list,
unsigned int *r_flags)
{
/* 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 810
char line[BUFFER_MAX + 1];
char *linep;
int idx;
int res;
int fd;
*r_flags = 0;
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)
{
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;
if (!idx && *linep == '~')
{
/* Spawn flags have been passed. */
linep++;
*r_flags = strtoul (linep, &tail, 0);
if (tail == NULL || ! (*tail == '\0' || isspace (*tail)))
break;
linep = tail;
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].fd = 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].fd = -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, unsigned int *r_flags)
{
int res;
int idx;
int n_args;
char **args;
res = translate_get_from_file (trans_file, fd_list, r_flags);
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;
n_args = idx;
- for (idx = 0; fd_list[idx].handle != -1; idx++)
+ for (idx = 0; fd_list[idx].fd != -1; idx++)
{
char buf[25];
int aidx;
aidx = fd_list[idx].arg_loc;
if (aidx == 0)
continue;
if (aidx >= n_args)
{
fprintf (stderr, PGM": translation file does not match args\n");
return NULL;
}
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];
unsigned int flags;
if (argc < 3)
{
rc = 2;
goto leave;
}
argv_spawn = translate_handles (argv[1], &argv[2], fd_list, &flags);
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, flags);
if (rc < 0)
{
fprintf (stderr, PGM": executing `%s' failed: %s\n",
argv[0], strerror (errno));
rc = 2;
goto leave;
}
leave:
if (rc)
fprintf (stderr, PGM": internal error\n");
/* Always try to delete the temporary file. */
if (argc >= 2)
{
if (DeleteFile (argv[1]) == 0)
fprintf (stderr, PGM": failed to delete %s: ec=%ld\n",
argv[1], GetLastError ());
}
return rc;
}
diff --git a/src/priv-io.h b/src/priv-io.h
index 583f06ad..23061756 100644
--- a/src/priv-io.h
+++ b/src/priv-io.h
@@ -1,117 +1,118 @@
/* priv-io.h - Interface to the private I/O functions.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002, 2003, 2004, 2005 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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#ifndef IO_H
#define IO_H
#ifdef HAVE_W32_SYSTEM
# ifdef HAVE_W32CE_SYSTEM
# include "w32-ce.h"
# endif
+# include <winsock2.h>
# include <windows.h>
#else
# include <sys/socket.h>
#endif
/* For pid_t. */
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
/* A single file descriptor passed to spawn. For child fds, dup_to
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
{
int fd;
int for_read;
int for_write;
int signaled;
void *opaque;
};
/* These function are either defined in posix-io.c or w32-io.c. */
void _gpgme_io_subsystem_init (void);
int _gpgme_io_socket (int namespace, int style, int protocol);
int _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen);
int _gpgme_io_read (int fd, void *buffer, size_t count);
int _gpgme_io_write (int fd, const void *buffer, size_t count);
int _gpgme_io_pipe (int filedes[2], int inherit_idx);
int _gpgme_io_close (int fd);
typedef void (*_gpgme_close_notify_handler_t) (int,void*);
int _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
void *value);
int _gpgme_io_set_nonblocking (int fd);
/* Under Windows do not allocate a console. */
#define IOSPAWN_FLAG_DETACHED 1
/* A flag to tell the spawn function to allow the child process to set
the foreground window. */
#define IOSPAWN_FLAG_ALLOW_SET_FG 2
/* Don't close any child FDs. */
#define IOSPAWN_FLAG_NOCLOSE 4
/* 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 *const argv[], unsigned int flags,
struct spawn_fd_item_s *fd_list,
void (*atfork) (void *opaque, int reserved),
void *atforkvalue, 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
BUFLEN. The printable version is the representation on the command
line that the child process expects. */
int _gpgme_io_fd2str (char *buf, int buflen, int fd);
/* Duplicate a file descriptor. This is more restrictive than dup():
it assumes that the resulting file descriptors are essentially
co-equal (for example, no private offset), which is true for pipes
and sockets (but not files) under Unix with the standard dup()
function. Basically, this function is used to reference count the
status output file descriptor shared between GPGME and libassuan
(in engine-gpgsm.c). */
int _gpgme_io_dup (int fd);
#ifndef HAVE_W32_SYSTEM
int _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags);
int _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags);
int _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal);
#endif
#endif /* IO_H */
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Feb 10, 9:30 AM (1 d, 2 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
43/c8/f715470f577bf1064523abf2d3a1
Attached To
rM GPGME
Event Timeline
Log In to Comment