summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ChangeLog6
-rw-r--r--src/Makefile.am11
-rw-r--r--src/system-posix.c339
-rw-r--r--src/system-w32.c466
-rw-r--r--src/system-w32ce.c464
-rw-r--r--src/system.c660
6 files changed, 1296 insertions, 650 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index dd71683..1d5ff2e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+2010-03-16 Werner Koch <wk@g10code.com>
+
+ * system.c: For better readability move platform dependend code to ..
+ * system-posix.c, system-w32.c, system-w32ce.c: .. New.
+ * Makefile.am (common_sources): Account for this change.
+
2010-03-11 Werner Koch <wk@g10code.com>
* assuan-defs.h [!HAVE_VASPRINTF]: Add macros vasprintf and asprintf.
diff --git a/src/Makefile.am b/src/Makefile.am
index 6403e79..c946f11 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -57,6 +57,17 @@ common_sources = \
assuan-socket.c
if HAVE_W32_SYSTEM
+if HAVE_W32CE_SYSTEM
+common_sources += system-w32ce.c
+else
+common_sources += system-w32.c
+endif
+else
+common_sources += system-posix.c
+endif
+
+
+if HAVE_W32_SYSTEM
LTRCCOMPILE = $(LIBTOOL) --mode=compile $(RC) \
`echo $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) | \
diff --git a/src/system-posix.c b/src/system-posix.c
new file mode 100644
index 0000000..e36767a
--- /dev/null
+++ b/src/system-posix.c
@@ -0,0 +1,339 @@
+/* system-posix.c - System support functions.
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of Assuan.
+
+ Assuan 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.
+
+ Assuan 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 <stdlib.h>
+#include <errno.h>
+/* Solaris 8 needs sys/types.h before time.h. */
+#include <sys/types.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+
+#include "assuan-defs.h"
+#include "debug.h"
+
+#ifdef _POSIX_OPEN_MAX
+#define MAX_OPEN_FDS _POSIX_OPEN_MAX
+#else
+#define MAX_OPEN_FDS 20
+#endif
+
+
+
+
+assuan_fd_t
+assuan_fdopen (int fd)
+{
+ return dup (fd);
+}
+
+
+
+/* Sleep for the given number of microseconds. Default
+ implementation. */
+void
+__assuan_usleep (assuan_context_t ctx, unsigned int usec)
+{
+ if (! usec)
+ return;
+
+#ifdef HAVE_NANOSLEEP
+ {
+ struct timespec req;
+ struct timespec rem;
+
+ req.tv_sec = 0;
+ req.tv_nsec = usec * 1000;
+
+ while (nanosleep (&req, &rem) < 0 && errno == EINTR)
+ req = rem;
+ }
+#else
+ {
+ struct timeval tv;
+
+ tv.tv_sec = usec / 1000000;
+ tv.tv_usec = usec % 1000000;
+ select (0, NULL, NULL, NULL, &tv);
+ }
+#endif
+}
+
+
+
+/* Create a pipe with one inheritable end. Easy for Posix. */
+int
+__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
+{
+ return pipe (fd);
+}
+
+
+
+/* Close the given file descriptor, created with _assuan_pipe or one
+ of the socket functions. Easy for Posix. */
+int
+__assuan_close (assuan_context_t ctx, assuan_fd_t fd)
+{
+ return close (fd);
+}
+
+
+
+static ssize_t
+__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
+{
+ return read (fd, buffer, size);
+}
+
+
+
+static ssize_t
+__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
+ size_t size)
+{
+ return write (fd, buffer, size);
+}
+
+
+
+static int
+__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+ int flags)
+{
+ int ret;
+
+ do
+ ret = recvmsg (fd, msg, flags);
+ while (ret == -1 && errno == EINTR);
+
+ return ret;
+}
+
+
+
+static int
+__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+ int flags)
+{
+ int ret;
+
+ do
+ ret = sendmsg (fd, msg, flags);
+ while (ret == -1 && errno == EINTR);
+
+ return ret;
+}
+
+
+
+static int
+writen (int fd, const char *buffer, size_t length)
+{
+ while (length)
+ {
+ int nwritten = write (fd, buffer, length);
+
+ if (nwritten < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ return -1; /* write error */
+ }
+ length -= nwritten;
+ buffer += nwritten;
+ }
+ return 0; /* okay */
+}
+
+
+int
+__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
+ const char **argv,
+ assuan_fd_t fd_in, assuan_fd_t fd_out,
+ assuan_fd_t *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue, unsigned int flags)
+{
+ int pid;
+
+ pid = fork ();
+ if (pid < 0)
+ return -1;
+
+ if (pid == 0)
+ {
+ /* Child process (server side). */
+ int i;
+ int n;
+ char errbuf[512];
+ int *fdp;
+ int fdnul;
+
+ if (atfork)
+ atfork (atforkvalue, 0);
+
+ fdnul = open ("/dev/null", O_WRONLY);
+ if (fdnul == -1)
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+ "can't open `/dev/null': %s", strerror (errno));
+ _exit (4);
+ }
+
+ /* Dup handles to stdin/stdout. */
+ if (fd_out != STDOUT_FILENO)
+ {
+ if (dup2 (fd_out == ASSUAN_INVALID_FD ? fdnul : fd_out,
+ STDOUT_FILENO) == -1)
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+ "dup2 failed in child: %s", strerror (errno));
+ _exit (4);
+ }
+ }
+
+ if (fd_in != STDIN_FILENO)
+ {
+ if (dup2 (fd_in == ASSUAN_INVALID_FD ? fdnul : fd_in,
+ STDIN_FILENO) == -1)
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+ "dup2 failed in child: %s", strerror (errno));
+ _exit (4);
+ }
+ }
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == -1)
+ {
+ if (dup2 (fdnul, STDERR_FILENO) == -1)
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx,
+ "dup2(dev/null, 2) failed: %s", strerror (errno));
+ _exit (4);
+ }
+ }
+ close (fdnul);
+
+ /* Close all files which will not be duped and are not in the
+ fd_child_list. */
+ n = sysconf (_SC_OPEN_MAX);
+ if (n < 0)
+ n = MAX_OPEN_FDS;
+ for (i = 0; i < n; i++)
+ {
+ if (i == STDIN_FILENO || i == STDOUT_FILENO || i == STDERR_FILENO)
+ continue;
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ while (*fdp != -1 && *fdp != i)
+ fdp++;
+ }
+
+ if (!(fdp && *fdp != -1))
+ close (i);
+ }
+ gpg_err_set_errno (0);
+
+ if (! name)
+ {
+ /* No name and no args given, thus we don't do an exec
+ but continue the forked process. */
+ *argv = "server";
+
+ /* FIXME: Cleanup. */
+ return 0;
+ }
+
+ execv (name, (char *const *) argv);
+
+ /* oops - use the pipe to tell the parent about it */
+ snprintf (errbuf, sizeof(errbuf)-1,
+ "ERR %d can't exec `%s': %.50s\n",
+ _assuan_error (ctx, GPG_ERR_ASS_SERVER_START),
+ name, strerror (errno));
+ errbuf[sizeof(errbuf)-1] = 0;
+ writen (1, errbuf, strlen (errbuf));
+ _exit (4);
+ }
+
+ if (! name)
+ *argv = "client";
+
+ *r_pid = pid;
+
+ return 0;
+}
+
+
+
+/* FIXME: Add some sort of waitpid function that covers GPGME and
+ gpg-agent's use of assuan. */
+static pid_t
+__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
+ int *status, int options)
+{
+ /* We can't just release the PID, a waitpid is mandatory. But
+ NOWAIT in POSIX systems just means the caller already did the
+ waitpid for this child. */
+ if (! nowait)
+ return waitpid (pid, NULL, 0);
+ return 0;
+}
+
+
+
+int
+__assuan_socketpair (assuan_context_t ctx, int namespace, int style,
+ int protocol, assuan_fd_t filedes[2])
+{
+ return socketpair (namespace, style, protocol, filedes);
+}
+
+
+
+/* The default system hooks for assuan contexts. */
+struct assuan_system_hooks _assuan_system_hooks =
+ {
+ ASSUAN_SYSTEM_HOOKS_VERSION,
+ __assuan_usleep,
+ __assuan_pipe,
+ __assuan_close,
+ __assuan_read,
+ __assuan_write,
+ __assuan_recvmsg,
+ __assuan_sendmsg,
+ __assuan_spawn,
+ __assuan_waitpid,
+ __assuan_socketpair
+ };
diff --git a/src/system-w32.c b/src/system-w32.c
new file mode 100644
index 0000000..31da194
--- /dev/null
+++ b/src/system-w32.c
@@ -0,0 +1,466 @@
+/* system-w32.c - System support functions for Windows.
+ Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of Assuan.
+
+ Assuan 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.
+
+ Assuan 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 <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <fcntl.h>
+#include <windows.h>
+
+#include "assuan-defs.h"
+#include "debug.h"
+
+
+
+assuan_fd_t
+assuan_fdopen (int fd)
+{
+ assuan_fd_t ifd = (assuan_fd_t) _get_osfhandle (fd);
+ assuan_fd_t ofd;
+
+ if (! DuplicateHandle(GetCurrentProcess(), ifd,
+ GetCurrentProcess(), &ofd, 0,
+ TRUE, DUPLICATE_SAME_ACCESS))
+ {
+ gpg_err_set_errno (EIO);
+ return ASSUAN_INVALID_FD;
+ }
+ return ofd;
+}
+
+
+
+/* Sleep for the given number of microseconds. Default
+ implementation. */
+void
+__assuan_usleep (assuan_context_t ctx, unsigned int usec)
+{
+ if (!usec)
+ return;
+
+ Sleep (usec / 1000);
+}
+
+
+
+/* Create a pipe with one inheritable end. Default implementation. */
+int
+__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
+{
+ HANDLE rh;
+ HANDLE wh;
+ HANDLE th;
+ SECURITY_ATTRIBUTES sec_attr;
+
+ memset (&sec_attr, 0, sizeof (sec_attr));
+ sec_attr.nLength = sizeof (sec_attr);
+ sec_attr.bInheritHandle = FALSE;
+
+ if (!CreatePipe (&rh, &wh, &sec_attr, 0))
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
+ "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ if (! DuplicateHandle (GetCurrentProcess(), (inherit_idx == 0) ? rh : wh,
+ GetCurrentProcess(), &th, 0,
+ TRUE, DUPLICATE_SAME_ACCESS ))
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
+ "DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1));
+ CloseHandle (rh);
+ CloseHandle (wh);
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+ if (inherit_idx == 0)
+ {
+ CloseHandle (rh);
+ rh = th;
+ }
+ else
+ {
+ CloseHandle (wh);
+ wh = th;
+ }
+
+ fd[0] = rh;
+ fd[1] = wh;
+
+ return 0;
+}
+
+
+
+/* Close the given file descriptor, created with _assuan_pipe or one
+ of the socket functions. Default implementation. */
+int
+__assuan_close (assuan_context_t ctx, assuan_fd_t fd)
+{
+ int rc = closesocket (HANDLE2SOCKET(fd));
+ if (rc)
+ gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()) );
+ if (rc && WSAGetLastError () == WSAENOTSOCK)
+ {
+ rc = CloseHandle (fd);
+ if (rc)
+ /* FIXME. */
+ gpg_err_set_errno (EIO);
+ }
+ return rc;
+}
+
+
+
+static ssize_t
+__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
+{
+ /* Due to the peculiarities of the W32 API we can't use read for a
+ network socket and thus we try to use recv first and fallback to
+ read if recv detects that it is not a network socket. */
+ int res;
+
+ res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
+ if (res == -1)
+ {
+ switch (WSAGetLastError ())
+ {
+ case WSAENOTSOCK:
+ {
+ DWORD nread = 0;
+
+ res = ReadFile (fd, buffer, size, &nread, NULL);
+ if (! res)
+ {
+ switch (GetLastError ())
+ {
+ case ERROR_BROKEN_PIPE:
+ gpg_err_set_errno (EPIPE);
+ break;
+
+ default:
+ gpg_err_set_errno (EIO);
+ }
+ res = -1;
+ }
+ else
+ res = (int) nread;
+ }
+ break;
+
+ case WSAEWOULDBLOCK:
+ gpg_err_set_errno (EAGAIN);
+ break;
+
+ case ERROR_BROKEN_PIPE:
+ gpg_err_set_errno (EPIPE);
+ break;
+
+ default:
+ gpg_err_set_errno (EIO);
+ break;
+ }
+ }
+ return res;
+}
+
+
+
+static ssize_t
+__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
+ size_t size)
+{
+ /* Due to the peculiarities of the W32 API we can't use write for a
+ network socket and thus we try to use send first and fallback to
+ write if send detects that it is not a network socket. */
+ int res;
+
+ res = send (HANDLE2SOCKET (fd), buffer, size, 0);
+ if (res == -1 && WSAGetLastError () == WSAENOTSOCK)
+ {
+ DWORD nwrite;
+
+ res = WriteFile (fd, buffer, size, &nwrite, NULL);
+ if (! res)
+ {
+ switch (GetLastError ())
+ {
+ case ERROR_BROKEN_PIPE:
+ case ERROR_NO_DATA:
+ gpg_err_set_errno (EPIPE);
+ break;
+
+ default:
+ gpg_err_set_errno (EIO);
+ break;
+ }
+ res = -1;
+ }
+ else
+ res = (int) nwrite;
+ }
+ return res;
+}
+
+
+
+static int
+__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+ int flags)
+{
+ gpg_err_set_errno (ENOSYS);
+ return -1;
+}
+
+
+
+
+static int
+__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+ int flags)
+{
+ gpg_err_set_errno (ENOSYS);
+ return -1;
+}
+
+
+
+
+/* Build a command line for use with W32's CreateProcess. On success
+ CMDLINE gets the address of a newly allocated string. */
+static int
+build_w32_commandline (assuan_context_t ctx, const char * const *argv,
+ char **cmdline)
+{
+ int i, n;
+ const char *s;
+ char *buf, *p;
+
+ *cmdline = NULL;
+ n = 0;
+ for (i=0; (s = argv[i]); i++)
+ {
+ n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
+ for (; *s; s++)
+ if (*s == '\"')
+ n++; /* Need to double inner quotes. */
+ }
+ n++;
+
+ buf = p = _assuan_malloc (ctx, n);
+ if (! buf)
+ return -1;
+
+ for (i = 0; argv[i]; i++)
+ {
+ if (i)
+ p = stpcpy (p, " ");
+ if (! *argv[i]) /* Empty string. */
+ p = stpcpy (p, "\"\"");
+ else if (strpbrk (argv[i], " \t\n\v\f\""))
+ {
+ p = stpcpy (p, "\"");
+ for (s = argv[i]; *s; s++)
+ {
+ *p++ = *s;
+ if (*s == '\"')
+ *p++ = *s;
+ }
+ *p++ = '\"';
+ *p = 0;
+ }
+ else
+ p = stpcpy (p, argv[i]);
+ }
+
+ *cmdline= buf;
+ return 0;
+}
+
+
+int
+__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
+ const char **argv,
+ assuan_fd_t fd_in, assuan_fd_t fd_out,
+ assuan_fd_t *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue, 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;
+ assuan_fd_t fd;
+ assuan_fd_t *fdp;
+ char *cmdline;
+ HANDLE nullfd = INVALID_HANDLE_VALUE;
+
+ /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
+ variable. However this requires us to write a full environment
+ handler, because the strings are expected in sorted order. The
+ suggestion given in the MS Reference Library, to save the old
+ value, changeit, create proces and restore it, is not thread
+ safe. */
+
+ /* Build the command line. */
+ if (build_w32_commandline (ctx, argv, &cmdline))
+ return -1;
+
+ /* Start the process. */
+ memset (&sec_attr, 0, sizeof sec_attr);
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ memset (&si, 0, sizeof si);
+ si.cb = sizeof (si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ /* FIXME: Dup to nul if ASSUAN_INVALID_FD. */
+ si.hStdInput = fd_in;
+ si.hStdOutput = fd_out;
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fd = assuan_fd_from_posix_fd (fileno (stderr));
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != ASSUAN_INVALID_FD && *fdp != fd; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == ASSUAN_INVALID_FD)
+ {
+ nullfd = CreateFileW (L"nul", GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (nullfd == INVALID_HANDLE_VALUE)
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+ "can't open `nul': %s", _assuan_w32_strerror (ctx, -1));
+ _assuan_free (ctx, cmdline);
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+ si.hStdError = nullfd;
+ }
+ else
+ si.hStdError = fd;
+
+ /* Note: We inherit all handles flagged as inheritable. This seems
+ to be a security flaw but there seems to be no way of selecting
+ handles to inherit. */
+ /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */
+ /* name, cmdline); */
+ if (!CreateProcess (name, /* Program to start. */
+ cmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ TRUE, /* Inherit handles. */
+ (CREATE_DEFAULT_ERROR_MODE
+ | ((flags & 128)? DETACHED_PROCESS : 0)
+ | GetPriorityClass (GetCurrentProcess ())
+ | CREATE_SUSPENDED), /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ &si, /* Startup information. */
+ &pi /* Returns process information. */
+ ))
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx,
+ "CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1));
+ _assuan_free (ctx, cmdline);
+ if (nullfd != INVALID_HANDLE_VALUE)
+ CloseHandle (nullfd);
+
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ _assuan_free (ctx, cmdline);
+ if (nullfd != INVALID_HANDLE_VALUE)
+ CloseHandle (nullfd);
+
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+
+ /* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */
+ /* " dwProcessID=%d dwThreadId=%d\n", */
+ /* pi.hProcess, pi.hThread, */
+ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+
+ *r_pid = (pid_t) pi.hProcess;
+
+ /* No need to modify peer process, as we don't change the handle
+ names. However this also means we are not safe, as we inherit
+ too many handles. Should use approach similar to gpgme and glib
+ using a helper process. */
+
+ return 0;
+}
+
+
+
+
+/* FIXME: Add some sort of waitpid function that covers GPGME and
+ gpg-agent's use of assuan. */
+static pid_t
+__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
+ int *status, int options)
+{
+ CloseHandle ((HANDLE) pid);
+ return 0;
+}
+
+
+
+int
+__assuan_socketpair (assuan_context_t ctx, int namespace, int style,
+ int protocol, assuan_fd_t filedes[2])
+{
+ gpg_err_set_errno (ENOSYS);
+ return -1;
+}
+
+
+/* The default system hooks for assuan contexts. */
+struct assuan_system_hooks _assuan_system_hooks =
+ {
+ ASSUAN_SYSTEM_HOOKS_VERSION,
+ __assuan_usleep,
+ __assuan_pipe,
+ __assuan_close,
+ __assuan_read,
+ __assuan_write,
+ __assuan_recvmsg,
+ __assuan_sendmsg,
+ __assuan_spawn,
+ __assuan_waitpid,
+ __assuan_socketpair
+ };
diff --git a/src/system-w32ce.c b/src/system-w32ce.c
new file mode 100644
index 0000000..ce0796c
--- /dev/null
+++ b/src/system-w32ce.c
@@ -0,0 +1,464 @@
+/* system-w32ce.c - System support functions for WindowsCE.
+ Copyright (C) 2010 Free Software Foundation, Inc.
+
+ This file is part of Assuan.
+
+ Assuan 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.
+
+ Assuan 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 <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <fcntl.h>
+#include <windows.h>
+
+#include "assuan-defs.h"
+#include "debug.h"
+
+
+
+assuan_fd_t
+assuan_fdopen (int fd)
+{
+ assuan_fd_t ifd = (assuan_fd_t)fd;
+ assuan_fd_t ofd;
+
+ if (! DuplicateHandle(GetCurrentProcess(), ifd,
+ GetCurrentProcess(), &ofd, 0,
+ TRUE, DUPLICATE_SAME_ACCESS))
+ {
+ gpg_err_set_errno (EIO);
+ return ASSUAN_INVALID_FD;
+ }
+ return ofd;
+}
+
+
+
+/* Sleep for the given number of microseconds. Default
+ implementation. */
+void
+__assuan_usleep (assuan_context_t ctx, unsigned int usec)
+{
+ if (!usec)
+ return;
+
+ Sleep (usec / 1000);
+}
+
+
+
+/* Create a pipe with one inheritable end. Default implementation. */
+int
+__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
+{
+ HANDLE rh;
+ HANDLE wh;
+ HANDLE th;
+ SECURITY_ATTRIBUTES sec_attr;
+
+ memset (&sec_attr, 0, sizeof (sec_attr));
+ sec_attr.nLength = sizeof (sec_attr);
+ sec_attr.bInheritHandle = FALSE;
+
+ if (!CreatePipe (&rh, &wh, &sec_attr, 0))
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
+ "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ if (! DuplicateHandle (GetCurrentProcess(), (inherit_idx == 0) ? rh : wh,
+ GetCurrentProcess(), &th, 0,
+ TRUE, DUPLICATE_SAME_ACCESS ))
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
+ "DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1));
+ CloseHandle (rh);
+ CloseHandle (wh);
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+ if (inherit_idx == 0)
+ {
+ CloseHandle (rh);
+ rh = th;
+ }
+ else
+ {
+ CloseHandle (wh);
+ wh = th;
+ }
+
+ fd[0] = rh;
+ fd[1] = wh;
+
+ return 0;
+}
+
+
+
+/* Close the given file descriptor, created with _assuan_pipe or one
+ of the socket functions. Default implementation. */
+int
+__assuan_close (assuan_context_t ctx, assuan_fd_t fd)
+{
+ int rc = closesocket (HANDLE2SOCKET(fd));
+ if (rc)
+ gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()) );
+ if (rc && WSAGetLastError () == WSAENOTSOCK)
+ {
+ rc = CloseHandle (fd);
+ if (rc)
+ /* FIXME. */
+ gpg_err_set_errno (EIO);
+ }
+ return rc;
+}
+
+
+
+static ssize_t
+__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
+{
+ /* Due to the peculiarities of the W32 API we can't use read for a
+ network socket and thus we try to use recv first and fallback to
+ read if recv detects that it is not a network socket. */
+ int res;
+
+ res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
+ if (res == -1)
+ {
+ switch (WSAGetLastError ())
+ {
+ case WSAENOTSOCK:
+ {
+ DWORD nread = 0;
+
+ res = ReadFile (fd, buffer, size, &nread, NULL);
+ if (! res)
+ {
+ switch (GetLastError ())
+ {
+ case ERROR_BROKEN_PIPE:
+ gpg_err_set_errno (EPIPE);
+ break;
+
+ default:
+ gpg_err_set_errno (EIO);
+ }
+ res = -1;
+ }
+ else
+ res = (int) nread;
+ }
+ break;
+
+ case WSAEWOULDBLOCK:
+ gpg_err_set_errno (EAGAIN);
+ break;
+
+ case ERROR_BROKEN_PIPE:
+ gpg_err_set_errno (EPIPE);
+ break;
+
+ default:
+ gpg_err_set_errno (EIO);
+ break;
+ }
+ }
+ return res;
+}
+
+
+
+static ssize_t
+__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
+ size_t size)
+{
+ /* Due to the peculiarities of the W32 API we can't use write for a
+ network socket and thus we try to use send first and fallback to
+ write if send detects that it is not a network socket. */
+ int res;
+
+ res = send (HANDLE2SOCKET (fd), buffer, size, 0);
+ if (res == -1 && WSAGetLastError () == WSAENOTSOCK)
+ {
+ DWORD nwrite;
+
+ res = WriteFile (fd, buffer, size, &nwrite, NULL);
+ if (! res)
+ {
+ switch (GetLastError ())
+ {
+ case ERROR_BROKEN_PIPE:
+ case ERROR_NO_DATA:
+ gpg_err_set_errno (EPIPE);
+ break;
+
+ default:
+ gpg_err_set_errno (EIO);
+ break;
+ }
+ res = -1;
+ }
+ else
+ res = (int) nwrite;
+ }
+ return res;
+}
+
+
+
+static int
+__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+ int flags)
+{
+ gpg_err_set_errno (ENOSYS);
+ return -1;
+}
+
+
+
+
+static int
+__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
+ int flags)
+{
+ gpg_err_set_errno (ENOSYS);
+ return -1;
+}
+
+
+
+
+/* Build a command line for use with W32's CreateProcess. On success
+ CMDLINE gets the address of a newly allocated string. */
+static int
+build_w32_commandline (assuan_context_t ctx, const char * const *argv,
+ char **cmdline)
+{
+ int i, n;
+ const char *s;
+ char *buf, *p;
+
+ *cmdline = NULL;
+ n = 0;
+ for (i=0; (s = argv[i]); i++)
+ {
+ n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
+ for (; *s; s++)
+ if (*s == '\"')
+ n++; /* Need to double inner quotes. */
+ }
+ n++;
+
+ buf = p = _assuan_malloc (ctx, n);
+ if (! buf)
+ return -1;
+
+ for (i = 0; argv[i]; i++)
+ {
+ if (i)
+ p = stpcpy (p, " ");
+ if (! *argv[i]) /* Empty string. */
+ p = stpcpy (p, "\"\"");
+ else if (strpbrk (argv[i], " \t\n\v\f\""))
+ {
+ p = stpcpy (p, "\"");
+ for (s = argv[i]; *s; s++)
+ {
+ *p++ = *s;
+ if (*s == '\"')
+ *p++ = *s;
+ }
+ *p++ = '\"';
+ *p = 0;
+ }
+ else
+ p = stpcpy (p, argv[i]);
+ }
+
+ *cmdline= buf;
+ return 0;
+}
+
+
+int
+__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
+ const char **argv,
+ assuan_fd_t fd_in, assuan_fd_t fd_out,
+ assuan_fd_t *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue, 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;
+ assuan_fd_t fd;
+ assuan_fd_t *fdp;
+ char *cmdline;
+ HANDLE nullfd = INVALID_HANDLE_VALUE;
+
+ /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
+ variable. However this requires us to write a full environment
+ handler, because the strings are expected in sorted order. The
+ suggestion given in the MS Reference Library, to save the old
+ value, changeit, create proces and restore it, is not thread
+ safe. */
+
+ /* Build the command line. */
+ if (build_w32_commandline (ctx, argv, &cmdline))
+ return -1;
+
+ /* Start the process. */
+ memset (&sec_attr, 0, sizeof sec_attr);
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ memset (&si, 0, sizeof si);
+ si.cb = sizeof (si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ /* FIXME: Dup to nul if ASSUAN_INVALID_FD. */
+ si.hStdInput = fd_in;
+ si.hStdOutput = fd_out;
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fd = assuan_fd_from_posix_fd (fileno (stderr));
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != ASSUAN_INVALID_FD && *fdp != fd; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == ASSUAN_INVALID_FD)
+ {
+ nullfd = CreateFileW (L"nul", GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (nullfd == INVALID_HANDLE_VALUE)
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
+ "can't open `nul': %s", _assuan_w32_strerror (ctx, -1));
+ _assuan_free (ctx, cmdline);
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+ si.hStdError = nullfd;
+ }
+ else
+ si.hStdError = fd;
+
+ /* Note: We inherit all handles flagged as inheritable. This seems
+ to be a security flaw but there seems to be no way of selecting
+ handles to inherit. */
+ /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */
+ /* name, cmdline); */
+ if (!CreateProcess (name, /* Program to start. */
+ cmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ TRUE, /* Inherit handles. */
+ (CREATE_DEFAULT_ERROR_MODE
+ | CREATE_SUSPENDED), /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ &si, /* Startup information. */
+ &pi /* Returns process information. */
+ ))
+ {
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx,
+ "CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1));
+ _assuan_free (ctx, cmdline);
+ if (nullfd != INVALID_HANDLE_VALUE)
+ CloseHandle (nullfd);
+
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ _assuan_free (ctx, cmdline);
+ if (nullfd != INVALID_HANDLE_VALUE)
+ CloseHandle (nullfd);
+
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+
+ /* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */
+ /* " dwProcessID=%d dwThreadId=%d\n", */
+ /* pi.hProcess, pi.hThread, */
+ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+
+ *r_pid = (pid_t) pi.hProcess;
+
+ /* No need to modify peer process, as we don't change the handle
+ names. However this also means we are not safe, as we inherit
+ too many handles. Should use approach similar to gpgme and glib
+ using a helper process. */
+
+ return 0;
+}
+
+
+
+
+/* FIXME: Add some sort of waitpid function that covers GPGME and
+ gpg-agent's use of assuan. */
+static pid_t
+__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
+ int *status, int options)
+{
+ CloseHandle ((HANDLE) pid);
+ return 0;
+}
+
+
+
+int
+__assuan_socketpair (assuan_context_t ctx, int namespace, int style,
+ int protocol, assuan_fd_t filedes[2])
+{
+ gpg_err_set_errno (ENOSYS);
+ return -1;
+}
+
+
+/* The default system hooks for assuan contexts. */
+struct assuan_system_hooks _assuan_system_hooks =
+ {
+ ASSUAN_SYSTEM_HOOKS_VERSION,
+ __assuan_usleep,
+ __assuan_pipe,
+ __assuan_close,
+ __assuan_read,
+ __assuan_write,
+ __assuan_recvmsg,
+ __assuan_sendmsg,
+ __assuan_spawn,
+ __assuan_waitpid,
+ __assuan_socketpair
+ };
diff --git a/src/system.c b/src/system.c
index fa942f7..22d7a0b 100644
--- a/src/system.c
+++ b/src/system.c
@@ -28,11 +28,6 @@
#include <sys/types.h>
#include <time.h>
#include <fcntl.h>
-#ifdef HAVE_W32_SYSTEM
-# include <windows.h>
-#else
-# include <sys/wait.h>
-#endif
#include "assuan-defs.h"
#include "debug.h"
@@ -45,30 +40,7 @@
#define DEBUG_SYSIO 0
-
-assuan_fd_t
-assuan_fdopen (int fd)
-{
-#ifdef HAVE_W32_SYSTEM
-#ifdef HAVE_W32CE_SYSTEM
- assuan_fd_t ifd = (assuan_fd_t)fd;
-#else
- assuan_fd_t ifd = (assuan_fd_t) _get_osfhandle (fd);
-#endif
- assuan_fd_t ofd;
- if (! DuplicateHandle(GetCurrentProcess(), ifd,
- GetCurrentProcess(), &ofd, 0,
- TRUE, DUPLICATE_SAME_ACCESS))
- {
- gpg_err_set_errno (EIO);
- return ASSUAN_INVALID_FD;
- }
- return ofd;
-#else
- return dup (fd);
-#endif
-}
/* Manage memory specific to a context. */
@@ -154,40 +126,8 @@ _assuan_system_hooks_copy (assuan_system_hooks_t dst,
;
}
-
-/* Sleep for the given number of microseconds. Default
- implementation. */
-void
-__assuan_usleep (assuan_context_t ctx, unsigned int usec)
-{
- if (! usec)
- return;
-
-#ifdef HAVE_NANOSLEEP
- {
- struct timespec req;
- struct timespec rem;
-
- req.tv_sec = 0;
- req.tv_nsec = usec * 1000;
-
- while (nanosleep (&req, &rem) < 0 && errno == EINTR)
- req = rem;
- }
-#elif defined(HAVE_W32_SYSTEM)
- Sleep (usec / 1000);
-#else
- {
- struct timeval tv;
-
- tv.tv_sec = usec / 1000000;
- tv.tv_usec = usec % 1000000;
- select (0, NULL, NULL, NULL, &tv);
- }
-#endif
-}
-
+
/* Sleep for the given number of microseconds. */
void
_assuan_usleep (assuan_context_t ctx, unsigned int usec)
@@ -198,61 +138,8 @@ _assuan_usleep (assuan_context_t ctx, unsigned int usec)
(ctx->system.usleep) (ctx, usec);
}
-
-/* Create a pipe with one inheritable end. Default implementation. */
-int
-__assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
-{
-#ifdef HAVE_W32_SYSTEM
- HANDLE rh;
- HANDLE wh;
- HANDLE th;
- SECURITY_ATTRIBUTES sec_attr;
-
- memset (&sec_attr, 0, sizeof (sec_attr));
- sec_attr.nLength = sizeof (sec_attr);
- sec_attr.bInheritHandle = FALSE;
-
- if (!CreatePipe (&rh, &wh, &sec_attr, 0))
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
- "CreatePipe failed: %s", _assuan_w32_strerror (ctx, -1));
- gpg_err_set_errno (EIO);
- return -1;
- }
-
- if (! DuplicateHandle (GetCurrentProcess(), (inherit_idx == 0) ? rh : wh,
- GetCurrentProcess(), &th, 0,
- TRUE, DUPLICATE_SAME_ACCESS ))
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_pipe", ctx,
- "DuplicateHandle failed: %s", _assuan_w32_strerror (ctx, -1));
- CloseHandle (rh);
- CloseHandle (wh);
- gpg_err_set_errno (EIO);
- return -1;
- }
- if (inherit_idx == 0)
- {
- CloseHandle (rh);
- rh = th;
- }
- else
- {
- CloseHandle (wh);
- wh = th;
- }
-
- fd[0] = rh;
- fd[1] = wh;
-
- return 0;
-#else
- return pipe (fd);
-#endif
-}
-
+
/* Create a pipe with one inheritable end. */
int
_assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
@@ -269,30 +156,8 @@ _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
return TRACE_SUC2 ("read=0x%x, write=0x%x", fd[0], fd[1]);
}
-
-/* Close the given file descriptor, created with _assuan_pipe or one
- of the socket functions. Default implementation. */
-int
-__assuan_close (assuan_context_t ctx, assuan_fd_t fd)
-{
-#ifdef HAVE_W32_SYSTEM
- int rc = closesocket (HANDLE2SOCKET(fd));
- if (rc)
- gpg_err_set_errno ( _assuan_sock_wsa2errno (WSAGetLastError ()) );
- if (rc && WSAGetLastError () == WSAENOTSOCK)
- {
- rc = CloseHandle (fd);
- if (rc)
- /* FIXME. */
- gpg_err_set_errno (EIO);
- }
- return rc;
-#else
- return close (fd);
-#endif
-}
-
+
/* Close the given file descriptor, created with _assuan_pipe or one
of the socket functions. */
int
@@ -304,64 +169,8 @@ _assuan_close (assuan_context_t ctx, assuan_fd_t fd)
return (ctx->system.close) (ctx, fd);
}
-
-static ssize_t
-__assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
-{
-#ifdef HAVE_W32_SYSTEM
- /* Due to the peculiarities of the W32 API we can't use read for a
- network socket and thus we try to use recv first and fallback to
- read if recv detects that it is not a network socket. */
- int res;
-
- res = recv (HANDLE2SOCKET (fd), buffer, size, 0);
- if (res == -1)
- {
- switch (WSAGetLastError ())
- {
- case WSAENOTSOCK:
- {
- DWORD nread = 0;
-
- res = ReadFile (fd, buffer, size, &nread, NULL);
- if (! res)
- {
- switch (GetLastError ())
- {
- case ERROR_BROKEN_PIPE:
- gpg_err_set_errno (EPIPE);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- }
- res = -1;
- }
- else
- res = (int) nread;
- }
- break;
-
- case WSAEWOULDBLOCK:
- gpg_err_set_errno (EAGAIN);
- break;
-
- case ERROR_BROKEN_PIPE:
- gpg_err_set_errno (EPIPE);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- break;
- }
- }
- return res;
-#else /*!HAVE_W32_SYSTEM*/
- return read (fd, buffer, size);
-#endif /*!HAVE_W32_SYSTEM*/
-}
-
+
ssize_t
_assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
{
@@ -376,48 +185,8 @@ _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
#endif
}
-
-static ssize_t
-__assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
- size_t size)
-{
-#ifdef HAVE_W32_SYSTEM
- /* Due to the peculiarities of the W32 API we can't use write for a
- network socket and thus we try to use send first and fallback to
- write if send detects that it is not a network socket. */
- int res;
-
- res = send (HANDLE2SOCKET (fd), buffer, size, 0);
- if (res == -1 && WSAGetLastError () == WSAENOTSOCK)
- {
- DWORD nwrite;
-
- res = WriteFile (fd, buffer, size, &nwrite, NULL);
- if (! res)
- {
- switch (GetLastError ())
- {
- case ERROR_BROKEN_PIPE:
- case ERROR_NO_DATA:
- gpg_err_set_errno (EPIPE);
- break;
-
- default:
- gpg_err_set_errno (EIO);
- break;
- }
- res = -1;
- }
- else
- res = (int) nwrite;
- }
- return res;
-#else /*!HAVE_W32_SYSTEM*/
- return write (fd, buffer, size);
-#endif /*!HAVE_W32_SYSTEM*/
-}
-
+
ssize_t
_assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
size_t size)
@@ -433,25 +202,8 @@ _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
#endif
}
-
-static int
-__assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
- int flags)
-{
-#ifdef HAVE_W32_SYSTEM
- gpg_err_set_errno (ENOSYS);
- return -1;
-#else
- int ret;
- do
- ret = recvmsg (fd, msg, flags);
- while (ret == -1 && errno == EINTR);
-
- return ret;
-#endif
-}
-
+
int
_assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
@@ -485,25 +237,8 @@ _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
#endif
}
-
-static int
-__assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
- int flags)
-{
-#ifdef HAVE_W32_SYSTEM
- gpg_err_set_errno (ENOSYS);
- return -1;
-#else
- int ret;
- do
- ret = sendmsg (fd, msg, flags);
- while (ret == -1 && errno == EINTR);
-
- return ret;
-#endif
-}
-
+
int
_assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
int flags)
@@ -536,340 +271,8 @@ _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
#endif
}
-
-#ifdef HAVE_W32_SYSTEM
-/* Build a command line for use with W32's CreateProcess. On success
- CMDLINE gets the address of a newly allocated string. */
-static int
-build_w32_commandline (assuan_context_t ctx, const char * const *argv,
- char **cmdline)
-{
- int i, n;
- const char *s;
- char *buf, *p;
-
- *cmdline = NULL;
- n = 0;
- for (i=0; (s = argv[i]); i++)
- {
- n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
- for (; *s; s++)
- if (*s == '\"')
- n++; /* Need to double inner quotes. */
- }
- n++;
-
- buf = p = _assuan_malloc (ctx, n);
- if (! buf)
- return -1;
-
- for (i = 0; argv[i]; i++)
- {
- if (i)
- p = stpcpy (p, " ");
- if (! *argv[i]) /* Empty string. */
- p = stpcpy (p, "\"\"");
- else if (strpbrk (argv[i], " \t\n\v\f\""))
- {
- p = stpcpy (p, "\"");
- for (s = argv[i]; *s; s++)
- {
- *p++ = *s;
- if (*s == '\"')
- *p++ = *s;
- }
- *p++ = '\"';
- *p = 0;
- }
- else
- p = stpcpy (p, argv[i]);
- }
-
- *cmdline= buf;
- return 0;
-}
-
-
-int
-__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
- const char **argv,
- assuan_fd_t fd_in, assuan_fd_t fd_out,
- assuan_fd_t *fd_child_list,
- void (*atfork) (void *opaque, int reserved),
- void *atforkvalue, 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;
- assuan_fd_t fd;
- assuan_fd_t *fdp;
- char *cmdline;
- HANDLE nullfd = INVALID_HANDLE_VALUE;
-
- /* fixme: Actually we should set the "_assuan_pipe_connect_pid" env
- variable. However this requires us to write a full environment
- handler, because the strings are expected in sorted order. The
- suggestion given in the MS Reference Library, to save the old
- value, changeit, create proces and restore it, is not thread
- safe. */
-
- /* Build the command line. */
- if (build_w32_commandline (ctx, argv, &cmdline))
- return -1;
-
- /* Start the process. */
- memset (&sec_attr, 0, sizeof sec_attr);
- sec_attr.nLength = sizeof sec_attr;
- sec_attr.bInheritHandle = FALSE;
-
- memset (&si, 0, sizeof si);
- si.cb = sizeof (si);
- si.dwFlags = STARTF_USESTDHANDLES;
- /* FIXME: Dup to nul if ASSUAN_INVALID_FD. */
- si.hStdInput = fd_in;
- si.hStdOutput = fd_out;
-
- /* Dup stderr to /dev/null unless it is in the list of FDs to be
- passed to the child. */
- fd = assuan_fd_from_posix_fd (fileno (stderr));
- fdp = fd_child_list;
- if (fdp)
- {
- for (; *fdp != ASSUAN_INVALID_FD && *fdp != fd; fdp++)
- ;
- }
- if (!fdp || *fdp == ASSUAN_INVALID_FD)
- {
- nullfd = CreateFileW (L"nul", GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, 0, NULL);
- if (nullfd == INVALID_HANDLE_VALUE)
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
- "can't open `nul': %s", _assuan_w32_strerror (ctx, -1));
- _assuan_free (ctx, cmdline);
- gpg_err_set_errno (EIO);
- return -1;
- }
- si.hStdError = nullfd;
- }
- else
- si.hStdError = fd;
-
-#ifdef HAVE_W32CE_SYSTEM
-# define DETACHED_PROCESS (0)
-#endif
- /* Note: We inherit all handles flagged as inheritable. This seems
- to be a security flaw but there seems to be no way of selecting
- handles to inherit. */
- /* _assuan_log_printf ("CreateProcess, path=`%s' cmdline=`%s'\n", */
- /* name, cmdline); */
- if (!CreateProcess (name, /* Program to start. */
- cmdline, /* Command line arguments. */
- &sec_attr, /* Process security attributes. */
- &sec_attr, /* Thread security attributes. */
- TRUE, /* Inherit handles. */
- (CREATE_DEFAULT_ERROR_MODE
- | ((flags & 128)? DETACHED_PROCESS : 0)
-#ifndef HAVE_W32CE_SYSTEM
- | GetPriorityClass (GetCurrentProcess ())
-#endif
- | CREATE_SUSPENDED), /* Creation flags. */
- NULL, /* Environment. */
- NULL, /* Use current drive/directory. */
- &si, /* Startup information. */
- &pi /* Returns process information. */
- ))
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_w32", ctx,
- "CreateProcess failed: %s", _assuan_w32_strerror (ctx, -1));
- _assuan_free (ctx, cmdline);
- if (nullfd != INVALID_HANDLE_VALUE)
- CloseHandle (nullfd);
-
- gpg_err_set_errno (EIO);
- return -1;
- }
-
- _assuan_free (ctx, cmdline);
- if (nullfd != INVALID_HANDLE_VALUE)
- CloseHandle (nullfd);
-
- ResumeThread (pi.hThread);
- CloseHandle (pi.hThread);
-
- /* _assuan_log_printf ("CreateProcess ready: hProcess=%p hThread=%p" */
- /* " dwProcessID=%d dwThreadId=%d\n", */
- /* pi.hProcess, pi.hThread, */
- /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
-
- *r_pid = (pid_t) pi.hProcess;
-
- /* No need to modify peer process, as we don't change the handle
- names. However this also means we are not safe, as we inherit
- too many handles. Should use approach similar to gpgme and glib
- using a helper process. */
-
- return 0;
-}
-
-#else
-
-static int
-writen (int fd, const char *buffer, size_t length)
-{
- while (length)
- {
- int nwritten = write (fd, buffer, length);
-
- if (nwritten < 0)
- {
- if (errno == EINTR)
- continue;
- return -1; /* write error */
- }
- length -= nwritten;
- buffer += nwritten;
- }
- return 0; /* okay */
-}
-
-
-int
-__assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
- const char **argv,
- assuan_fd_t fd_in, assuan_fd_t fd_out,
- assuan_fd_t *fd_child_list,
- void (*atfork) (void *opaque, int reserved),
- void *atforkvalue, unsigned int flags)
-{
- int pid;
-
- pid = fork ();
- if (pid < 0)
- return -1;
-
- if (pid == 0)
- {
- /* Child process (server side). */
- int i;
- int n;
- char errbuf[512];
- int *fdp;
- int fdnul;
-
- if (atfork)
- atfork (atforkvalue, 0);
-
- fdnul = open ("/dev/null", O_WRONLY);
- if (fdnul == -1)
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
- "can't open `/dev/null': %s", strerror (errno));
- _exit (4);
- }
-
- /* Dup handles to stdin/stdout. */
- if (fd_out != STDOUT_FILENO)
- {
- if (dup2 (fd_out == ASSUAN_INVALID_FD ? fdnul : fd_out,
- STDOUT_FILENO) == -1)
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
- "dup2 failed in child: %s", strerror (errno));
- _exit (4);
- }
- }
-
- if (fd_in != STDIN_FILENO)
- {
- if (dup2 (fd_in == ASSUAN_INVALID_FD ? fdnul : fd_in,
- STDIN_FILENO) == -1)
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_spawn", ctx,
- "dup2 failed in child: %s", strerror (errno));
- _exit (4);
- }
- }
-
- /* Dup stderr to /dev/null unless it is in the list of FDs to be
- passed to the child. */
- fdp = fd_child_list;
- if (fdp)
- {
- for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
- ;
- }
- if (!fdp || *fdp == -1)
- {
- if (dup2 (fdnul, STDERR_FILENO) == -1)
- {
- TRACE1 (ctx, ASSUAN_LOG_SYSIO, "pipe_connect_unix", ctx,
- "dup2(dev/null, 2) failed: %s", strerror (errno));
- _exit (4);
- }
- }
- close (fdnul);
-
- /* Close all files which will not be duped and are not in the
- fd_child_list. */
- n = sysconf (_SC_OPEN_MAX);
- if (n < 0)
- n = MAX_OPEN_FDS;
- for (i = 0; i < n; i++)
- {
- if (i == STDIN_FILENO || i == STDOUT_FILENO || i == STDERR_FILENO)
- continue;
- fdp = fd_child_list;
- if (fdp)
- {
- while (*fdp != -1 && *fdp != i)
- fdp++;
- }
-
- if (!(fdp && *fdp != -1))
- close (i);
- }
- gpg_err_set_errno (0);
-
- if (! name)
- {
- /* No name and no args given, thus we don't do an exec
- but continue the forked process. */
- *argv = "server";
-
- /* FIXME: Cleanup. */
- return 0;
- }
-
- execv (name, (char *const *) argv);
-
- /* oops - use the pipe to tell the parent about it */
- snprintf (errbuf, sizeof(errbuf)-1,
- "ERR %d can't exec `%s': %.50s\n",
- _assuan_error (ctx, GPG_ERR_ASS_SERVER_START),
- name, strerror (errno));
- errbuf[sizeof(errbuf)-1] = 0;
- writen (1, errbuf, strlen (errbuf));
- _exit (4);
- }
-
- if (! name)
- *argv = "client";
-
- *r_pid = pid;
-
- return 0;
-}
-#endif /* ! HAVE_W32_SYSTEM */
-
+
/* Create a new process from NAME and ARGV. Provide FD_IN and FD_OUT
as stdin and stdout. Inherit the ASSUAN_INVALID_FD-terminated
FD_CHILD_LIST as given (no remapping), which must be inheritable.
@@ -924,26 +327,10 @@ _assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
return TRACE_SYSERR (res);
}
+
/* FIXME: Add some sort of waitpid function that covers GPGME and
gpg-agent's use of assuan. */
-static pid_t
-__assuan_waitpid (assuan_context_t ctx, pid_t pid, int nowait,
- int *status, int options)
-{
-#ifndef HAVE_W32_SYSTEM
- /* We can't just release the PID, a waitpid is mandatory. But
- NOWAIT in POSIX systems just means the caller already did the
- waitpid for this child. */
- if (! nowait)
- return waitpid (pid, NULL, 0);
-#else /* ! HAVE_W32_SYSTEM */
- CloseHandle ((HANDLE) pid);
-#endif /* HAVE_W32_SYSTEM */
- return 0;
-}
-
-
pid_t
_assuan_waitpid (assuan_context_t ctx, pid_t pid, int action,
int *status, int options)
@@ -960,19 +347,8 @@ _assuan_waitpid (assuan_context_t ctx, pid_t pid, int action,
#endif
}
-
-int
-__assuan_socketpair (assuan_context_t ctx, int namespace, int style,
- int protocol, assuan_fd_t filedes[2])
-{
-#if HAVE_W32_SYSTEM
- gpg_err_set_errno (ENOSYS);
- return -1;
-#else
- return socketpair (namespace, style, protocol, filedes);
-#endif
-}
+
int
_assuan_socketpair (assuan_context_t ctx, int namespace, int style,
int protocol, assuan_fd_t filedes[2])
@@ -989,19 +365,3 @@ _assuan_socketpair (assuan_context_t ctx, int namespace, int style,
return TRACE_SYSERR (res);
}
-
-/* The default system hooks for assuan contexts. */
-struct assuan_system_hooks _assuan_system_hooks =
- {
- ASSUAN_SYSTEM_HOOKS_VERSION,
- __assuan_usleep,
- __assuan_pipe,
- __assuan_close,
- __assuan_read,
- __assuan_write,
- __assuan_recvmsg,
- __assuan_sendmsg,
- __assuan_spawn,
- __assuan_waitpid,
- __assuan_socketpair
- };