summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/assuan-listen.c2
-rw-r--r--src/assuan-pipe-connect.c26
-rw-r--r--src/assuan-pipe-server.c7
-rw-r--r--src/assuan-socket-connect.c26
-rw-r--r--src/assuan-socket-server.c4
-rw-r--r--src/client.c2
-rw-r--r--src/system-w32.c76
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/fdpassing-socket.c359
-rw-r--r--tests/fdpassing.c24
10 files changed, 510 insertions, 20 deletions
diff --git a/src/assuan-listen.c b/src/assuan-listen.c
index 6755d59..93560ff 100644
--- a/src/assuan-listen.c
+++ b/src/assuan-listen.c
@@ -117,7 +117,7 @@ assuan_accept (assuan_context_t ctx)
else
{
static char const okstr[] = "OK Pleased to meet you";
- pid_t apid = assuan_get_pid (ctx);
+ pid_t apid = getpid ();
if (apid != ASSUAN_INVALID_PID)
{
char tmpbuf[50];
diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c
index 13ea3de..fc56334 100644
--- a/src/assuan-pipe-connect.c
+++ b/src/assuan-pipe-connect.c
@@ -104,7 +104,31 @@ initial_handshake (assuan_context_t ctx)
if (err)
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx,
"can't connect server: %s", gpg_strerror (err));
- else if (response != ASSUAN_RESPONSE_OK)
+ else if (response == ASSUAN_RESPONSE_OK)
+ {
+#ifdef HAVE_W32_SYSTEM
+ const char *line = ctx->inbound.line + off;
+ int pid = ASSUAN_INVALID_PID;
+
+ /* Parse the message: OK ..., process %i */
+ line = strchr (line, ',');
+ if (line)
+ {
+ line = strchr (line + 1, ' ');
+ if (line)
+ {
+ line = strchr (line + 1, ' ');
+ if (line)
+ pid = atoi (line + 1);
+ }
+ }
+ if (pid != ASSUAN_INVALID_PID)
+ ctx->pid = pid;
+#else
+ ;
+#endif
+ }
+ else
{
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx,
"can't connect server: `%s'", ctx->inbound.line);
diff --git a/src/assuan-pipe-server.c b/src/assuan-pipe-server.c
index 8da54ad..7977b83 100644
--- a/src/assuan-pipe-server.c
+++ b/src/assuan-pipe-server.c
@@ -82,8 +82,11 @@ assuan_init_pipe_server (assuan_context_t ctx, assuan_fd_t filedes[2])
return TRACE_ERR (rc);
#ifdef HAVE_W32_SYSTEM
- infd = filedes[0];
- outfd = filedes[1];
+ if (filedes)
+ {
+ infd = filedes[0];
+ outfd = filedes[1];
+ }
#else
s = getenv ("_assuan_connection_fd");
if (s && *s && is_valid_socket (s))
diff --git a/src/assuan-socket-connect.c b/src/assuan-socket-connect.c
index 019a41c..457edfe 100644
--- a/src/assuan-socket-connect.c
+++ b/src/assuan-socket-connect.c
@@ -115,8 +115,12 @@ _assuan_connect_finalize (assuan_context_t ctx, assuan_fd_t fd,
ctx->max_accepts = -1;
ctx->flags.is_socket = 1;
+#ifdef HAVE_W32_SYSTEM
+ ctx->engine.sendfd = w32_fdpass_send;
+#else
if (flags & ASSUAN_SOCKET_CONNECT_FDPASSING)
_assuan_init_uds_io (ctx);
+#endif
/* initial handshake */
{
@@ -127,7 +131,27 @@ _assuan_connect_finalize (assuan_context_t ctx, assuan_fd_t fd,
if (err)
TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect", ctx,
"can't connect to server: %s\n", gpg_strerror (err));
- else if (response != ASSUAN_RESPONSE_OK)
+ else if (response == ASSUAN_RESPONSE_OK)
+ {
+ const char *line = ctx->inbound.line + off;
+ int pid = ASSUAN_INVALID_PID;
+
+ /* Parse the message: OK ..., process %i */
+ line = strchr (line, ',');
+ if (line)
+ {
+ line = strchr (line + 1, ' ');
+ if (line)
+ {
+ line = strchr (line + 1, ' ');
+ if (line)
+ pid = atoi (line + 1);
+ }
+ }
+ if (pid != ASSUAN_INVALID_PID)
+ ctx->pid = pid;
+ }
+ else
{
char *sname = _assuan_encode_c_string (ctx, ctx->inbound.line);
if (sname)
diff --git a/src/assuan-socket-server.c b/src/assuan-socket-server.c
index a8330a8..f5fe038 100644
--- a/src/assuan-socket-server.c
+++ b/src/assuan-socket-server.c
@@ -238,8 +238,12 @@ assuan_init_socket_server (assuan_context_t ctx, assuan_fd_t fd,
: accept_connection);
ctx->finish_handler = _assuan_server_finish;
+#ifdef HAVE_W32_SYSTEM
+ ctx->engine.receivefd = w32_fdpass_recv;
+#else
if (flags & ASSUAN_SOCKET_SERVER_FDPASSING)
_assuan_init_uds_io (ctx);
+#endif
rc = _assuan_register_std_commands (ctx);
if (rc)
diff --git a/src/client.c b/src/client.c
index dcb2a1a..1746788 100644
--- a/src/client.c
+++ b/src/client.c
@@ -51,7 +51,7 @@ _assuan_client_finish (assuan_context_t ctx)
if (ctx->pid != ASSUAN_INVALID_PID && ctx->pid)
{
if (!ctx->flags.is_socket)
- _assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0);
+ _assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0);
ctx->pid = ASSUAN_INVALID_PID;
}
diff --git a/src/system-w32.c b/src/system-w32.c
index 76ff2a0..1392a1e 100644
--- a/src/system-w32.c
+++ b/src/system-w32.c
@@ -167,6 +167,10 @@ __assuan_close (assuan_context_t ctx, assuan_fd_t fd)
+/* To encode/decode file HANDLE, we use FDPASS_FORMAT */
+#define FDPASS_FORMAT "%p"
+#define FDPASS_MSG_SIZE (sizeof (uintptr_t)*2 + 1)
+
/* Get a file HANDLE to send, from POSIX fd. */
static gpg_error_t
get_file_handle (int fd, int server_pid, HANDLE *r_handle)
@@ -220,6 +224,30 @@ w32_fdpass_send (assuan_context_t ctx, assuan_fd_t fd)
return err;
}
+static int
+process_fdpass_msg (const char *fdpass_msg, size_t msglen, int *r_fd)
+{
+ void *file_handle;
+ int res;
+ int fd;
+
+ *r_fd = -1;
+
+ res = sscanf (fdpass_msg, FDPASS_FORMAT, &file_handle);
+ if (res != 1)
+ return -1;
+
+ fd = _open_osfhandle ((intptr_t)file_handle, _O_RDWR);
+ if (fd < 0)
+ {
+ CloseHandle (file_handle);
+ return -1;
+ }
+
+ *r_fd = fd;
+ return 0;
+}
+
/* Receive a HANDLE from the peer and turn it into a FD (POSIX fd). */
gpg_error_t
@@ -252,7 +280,53 @@ __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
if (ctx->flags.is_socket)
{
+ fd_set fds;
int tries = 3;
+ fd_set efds;
+
+ FD_ZERO (&fds);
+ FD_SET (HANDLE2SOCKET (fd), &fds);
+ FD_ZERO (&efds);
+ FD_SET (HANDLE2SOCKET (fd), &efds);
+ res = select (0, &fds, NULL, &efds, NULL);
+ if (res < 0)
+ {
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+ else if (FD_ISSET (HANDLE2SOCKET (fd), &efds))
+ {
+ int fd_recv;
+ char fdpass_msg[FDPASS_MSG_SIZE];
+
+ /* the message of ! */
+ res = recv (HANDLE2SOCKET (fd), fdpass_msg, sizeof (fdpass_msg), MSG_OOB);
+ if (res < 0)
+ {
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ /* the body of message */
+ res = recv (HANDLE2SOCKET (fd), fdpass_msg, sizeof (fdpass_msg), 0);
+ if (res < 0)
+ {
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ res = process_fdpass_msg (fdpass_msg, res, &fd_recv);
+ if (res < 0)
+ {
+ gpg_err_set_errno (EIO);
+ return -1;
+ }
+
+ ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = (assuan_fd_t)fd_recv;
+ TRACE1 (ctx, ASSUAN_LOG_SYSIO, "__assuan_read", ctx,
+ "received fd: %d", fd_recv);
+ /* Fall through */
+ }
again:
ec = 0;
@@ -266,8 +340,6 @@ __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
layer then needs to take care of EAGAIN. No need to
specify a timeout - the socket is not expected to be in
blocking mode. */
- fd_set fds;
-
FD_ZERO (&fds);
FD_SET (HANDLE2SOCKET (fd), &fds);
select (0, &fds, NULL, NULL, NULL);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f43c712..f61cec5 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -29,6 +29,7 @@ TESTS = version
if HAVE_W32_SYSTEM
testtools =
+TESTS += fdpassing
else
TESTS += pipeconnect
testtools = socks5
@@ -43,5 +44,4 @@ AM_LDFLAGS = -no-install
noinst_HEADERS = common.h
noinst_PROGRAMS = $(TESTS) $(w32cetools) $(testtools)
-LDADD = ../src/libassuan.la $(GPG_ERROR_LIBS) \
- @LDADD_FOR_TESTS_KLUDGE@
+LDADD = ../src/libassuan.la $(GPG_ERROR_LIBS) @LDADD_FOR_TESTS_KLUDGE@
diff --git a/tests/fdpassing-socket.c b/tests/fdpassing-socket.c
new file mode 100644
index 0000000..bbf4b97
--- /dev/null
+++ b/tests/fdpassing-socket.c
@@ -0,0 +1,359 @@
+/* fdpassing - Check the file descriptor passing.
+ Copyright (C) 2006, 2009 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 3 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/stat.h>
+#if HAVE_W32_SYSTEM
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <wincrypt.h>
+# include <io.h>
+#else
+# include <sys/socket.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+
+#include "../src/assuan.h"
+#include "common.h"
+
+
+/*
+
+ S E R V E R
+
+*/
+
+static gpg_error_t
+cmd_echo (assuan_context_t ctx, char *line)
+{
+ assuan_fd_t fd;
+ int c;
+ estream_t fp;
+ int nbytes;
+
+ log_info ("got ECHO command (%s)\n", line);
+
+ fd = assuan_get_input_fd (ctx);
+ if (fd == ASSUAN_INVALID_FD)
+ return gpg_error (GPG_ERR_ASS_NO_INPUT);
+ fp = gpgrt_fdopen ((int)fd, "r");
+ if (!fp)
+ {
+ log_error ("fdopen failed on input fd: %s\n", strerror (errno));
+ return gpg_error (GPG_ERR_ASS_GENERAL);
+ }
+ nbytes = 0;
+ while ( (c = gpgrt_fgetc (fp)) != -1)
+ {
+ putc (c, stdout);
+ nbytes++;
+ }
+ fflush (stdout);
+ log_info ("done printing %d bytes to stdout\n", nbytes);
+
+ gpgrt_fclose (fp);
+ return 0;
+}
+
+static gpg_error_t
+register_commands (assuan_context_t ctx)
+{
+ static struct
+ {
+ const char *name;
+ gpg_error_t (*handler) (assuan_context_t, char *line);
+ } table[] =
+ {
+ { "ECHO", cmd_echo },
+ { "INPUT", NULL },
+ { "OUTPUT", NULL },
+ { NULL, NULL }
+ };
+ int i;
+ gpg_error_t rc;
+
+ for (i=0; table[i].name; i++)
+ {
+ rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL);
+ if (rc)
+ return rc;
+ }
+ return 0;
+}
+
+
+#define SUN_LEN(ptr) ((size_t) (( \
+ + strlen ((ptr)->sun_path))
+
+static assuan_sock_nonce_t socket_nonce;
+
+static void
+server (const char *socketname)
+{
+ int rc;
+ assuan_context_t ctx;
+ assuan_fd_t fd;
+ struct sockaddr_un unaddr_struct;
+ struct sockaddr *addr;
+ socklen_t len;
+
+ log_info ("server started\n");
+
+ fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
+ if (fd == ASSUAN_INVALID_FD)
+ log_fatal ("assuan_sock_new failed\n");
+
+ addr = (struct sockaddr *)&unaddr_struct;
+ rc = assuan_sock_set_sockaddr_un (socketname, addr, NULL);
+ if (rc)
+ {
+ assuan_sock_close (fd);
+ log_fatal ("assuan_sock_set_sockaddr_un failed: %s\n", gpg_strerror (rc));
+ }
+
+ len = offsetof (struct sockaddr_un, sun_path)
+ + strlen (unaddr_struct.sun_path);
+ rc = assuan_sock_bind (fd, addr, len);
+ if (rc)
+ {
+ assuan_sock_close (fd);
+ log_fatal ("assuan_sock_bind failed: %s\n", gpg_strerror (rc));
+ }
+
+ rc = assuan_sock_get_nonce (addr, len, &socket_nonce);
+ if (rc)
+ {
+ assuan_sock_close (fd);
+ log_fatal ("assuan_sock_get_nonce failed: %s\n", gpg_strerror (rc));
+ }
+
+ rc = listen (HANDLE2SOCKET (fd), 5);
+ if (rc < 0)
+ {
+ assuan_sock_close (fd);
+ log_fatal ("listen failed: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+ }
+
+ rc = assuan_new (&ctx);
+ if (rc)
+ log_fatal ("assuan_new failed: %s\n", gpg_strerror (rc));
+
+ rc = assuan_init_socket_server (ctx, fd, 0);
+ if (rc)
+ log_fatal ("assuan_init_socket_server failed: %s\n", gpg_strerror (rc));
+
+ assuan_set_sock_nonce (ctx, &socket_nonce);
+
+ rc = register_commands (ctx);
+ if (rc)
+ log_fatal ("register_commands failed: %s\n", gpg_strerror(rc));
+
+ assuan_set_log_stream (ctx, stderr);
+
+ for (;;)
+ {
+ rc = assuan_accept (ctx);
+ if (rc)
+ {
+ if (rc != -1)
+ log_error ("assuan_accept failed: %s\n", gpg_strerror (rc));
+ break;
+ }
+
+ log_info ("client connected. Client's pid is %ld\n",
+ (long)assuan_get_pid (ctx));
+
+ rc = assuan_process (ctx);
+ if (rc)
+ log_error ("assuan_process failed: %s\n", gpg_strerror (rc));
+ }
+
+ assuan_release (ctx);
+}
+
+
+
+
+/*
+
+ C L I E N T
+
+*/
+
+
+/* Client main. If true is returned, a disconnect has not been done. */
+static int
+client (assuan_context_t ctx, const char *fname)
+{
+ int rc;
+ estream_t fp;
+ int i;
+
+ log_info ("client started. Servers's pid is %ld\n",
+ (long)assuan_get_pid (ctx));
+
+ for (i=0; i < 6; i++)
+ {
+ fp = gpgrt_fopen (fname, "r");
+ if (!fp)
+ {
+ log_error ("failed to open `%s': %s\n", fname,
+ strerror (errno));
+ return -1;
+ }
+
+ rc = assuan_sendfd (ctx, (assuan_fd_t)gpgrt_fileno (fp));
+ if (rc)
+ {
+ gpgrt_fclose (fp);
+ log_error ("assuan_sendfd failed: %s\n", gpg_strerror (rc));
+ return -1;
+ }
+ gpgrt_fclose (fp);
+
+ rc = assuan_transact (ctx, "INPUT FD", NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ if (rc)
+ {
+ log_error ("sending INPUT FD failed: %s\n", gpg_strerror (rc));
+ return -1;
+ }
+
+ rc = assuan_transact (ctx, "ECHO", NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc)
+ {
+ log_error ("sending ECHO failed: %s\n", gpg_strerror (rc));
+ return -1;
+ }
+ }
+
+ /* Give us some time to check with lsof that all descriptors are closed. */
+/* sleep (10); */
+
+ assuan_release (ctx);
+ return 0;
+}
+
+
+
+
+/*
+
+ M A I N
+
+*/
+int
+main (int argc, char **argv)
+{
+ int last_argc = -1;
+ assuan_context_t ctx;
+ gpg_error_t err;
+ int is_server = 0;
+ char *fname = prepend_srcdir ("motd");
+ const char *socketname = NULL;
+
+ if (argc)
+ {
+ log_set_prefix (*argv);
+ argc--; argv++;
+ }
+ while (argc && last_argc != argc )
+ {
+ last_argc = argc;
+ if (!strcmp (*argv, "--help"))
+ {
+ puts (
+"usage: ./fdpassing [options]\n"
+"\n"
+"Options:\n"
+" --verbose Show what is going on\n"
+" --socketname Specify the socket path.\n"
+);
+ exit (0);
+ }
+ if (!strcmp (*argv, "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--debug"))
+ {
+ verbose = debug = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--server"))
+ {
+ is_server = 1;
+ argc--; argv++;
+ }
+ else if (!strcmp (*argv, "--socketname"))
+ {
+ argc--; argv++;
+ if (argc)
+ {
+ socketname = *argv++;
+ argc--;
+ }
+ }
+ }
+
+
+ assuan_sock_init ();
+ assuan_set_assuan_log_prefix (log_prefix);
+
+ if (is_server)
+ {
+ server (socketname);
+ log_info ("server finished\n");
+ }
+ else
+ {
+ err = assuan_new (&ctx);
+ if (err)
+ log_fatal ("assuan_new failed: %s\n", gpg_strerror (err));
+
+ err = assuan_socket_connect (ctx, socketname, 0, 0);
+ if (err)
+ {
+ log_error ("assuan_socket_connect failed: %s\n", gpg_strerror (err));
+ assuan_release (ctx);
+ errorcount++;
+ }
+ else
+ {
+ if (client (ctx, fname))
+ {
+ log_info ("waiting for server to terminate...\n");
+ assuan_release (ctx);
+ }
+ log_info ("client finished\n");
+ }
+ }
+
+ xfree (fname);
+ return errorcount ? 1 : 0;
+}
diff --git a/tests/fdpassing.c b/tests/fdpassing.c
index 0e23ffc..6323a41 100644
--- a/tests/fdpassing.c
+++ b/tests/fdpassing.c
@@ -25,10 +25,8 @@
#include <string.h>
#include <assert.h>
#include <sys/stat.h>
-#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
-#include <sys/wait.h> /* Used by main driver. */
#include "../src/assuan.h"
#include "common.h"
@@ -62,11 +60,11 @@ cmd_echo (assuan_context_t ctx, char *line)
nbytes = 0;
while ( (c=getc (fp)) != -1)
{
- putc (c, stdout);
+ putc (c, stderr);
nbytes++;
}
- fflush (stdout);
- log_info ("done printing %d bytes to stdout\n", nbytes);
+ fflush (stderr);
+ log_info ("done printing %d bytes to stderr\n", nbytes);
fclose (fp);
return 0;
@@ -104,14 +102,18 @@ server (void)
{
int rc;
assuan_context_t ctx;
+ assuan_fd_t filedes[2];
log_info ("server started\n");
+ filedes[0] = _get_osfhandle (0);
+ filedes[1] = _get_osfhandle (1);
+
rc = assuan_new (&ctx);
if (rc)
log_fatal ("assuan_new failed: %s\n", gpg_strerror (rc));
- rc = assuan_init_pipe_server (ctx, NULL);
+ rc = assuan_init_pipe_server (ctx, filedes);
if (rc)
log_fatal ("assuan_init_pipe_server failed: %s\n", gpg_strerror (rc));
@@ -119,7 +121,7 @@ server (void)
if (rc)
log_fatal ("register_commands failed: %s\n", gpg_strerror(rc));
- assuan_set_log_stream (ctx, stderr);
+ // assuan_set_log_stream (ctx, stderr);
for (;;)
{
@@ -278,11 +280,11 @@ main (int argc, char **argv)
{
const char *loc;
- no_close_fds[0] = 2;
+ no_close_fds[0] = _get_osfhandle (fileno (stderr));
no_close_fds[1] = -1;
if (with_exec)
{
- arglist[0] = "fdpassing";
+ arglist[0] = "fdpassing.exe";
arglist[1] = "--server";
arglist[2] = verbose? "--verbose":NULL;
arglist[3] = NULL;
@@ -292,7 +294,9 @@ main (int argc, char **argv)
if (err)
log_fatal ("assuan_new failed: %s\n", gpg_strerror (err));
- err = assuan_pipe_connect (ctx, with_exec? "./fdpassing":NULL,
+ assuan_set_log_stream (ctx, stderr);
+
+ err = assuan_pipe_connect (ctx, with_exec? "./fdpassing.exe":NULL,
with_exec ? arglist : &loc,
no_close_fds, NULL, NULL, 1);
if (err)