From 27acee6a04dbc6d2b153387bc89d2f711ded9726 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 4 Nov 2022 17:00:37 +0900 Subject: client: Only call _assuan_waitpid when it's not socket. * src/client.c (_assuan_client_finish): Check if it's socket. -- GnuPG-bug-id: 6236 Signed-off-by: NIIBE Yutaka --- src/client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client.c b/src/client.c index e0759f6..dcb2a1a 100644 --- a/src/client.c +++ b/src/client.c @@ -50,7 +50,8 @@ _assuan_client_finish (assuan_context_t ctx) } if (ctx->pid != ASSUAN_INVALID_PID && ctx->pid) { - _assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0); + if (!ctx->flags.is_socket) + _assuan_waitpid (ctx, ctx->pid, ctx->flags.no_waitpid, NULL, 0); ctx->pid = ASSUAN_INVALID_PID; } -- cgit v1.2.3 From ce794a0a88a8dca11810ac79e6be6bf6b4e5326c Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 4 Nov 2022 17:55:34 +0900 Subject: w32: Add SENDFD internal command. * src/assuan-handler.c (w32_handler_sendfd): New. (std_cmd_table): Add the "SENDFD" command. -- GnuPG-bug-id: 6236 Signed-off-by: NIIBE Yutaka --- src/assuan-handler.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/assuan-handler.c b/src/assuan-handler.c index 126eccb..37f84b6 100644 --- a/src/assuan-handler.c +++ b/src/assuan-handler.c @@ -27,6 +27,9 @@ #include #include #include +#if HAVE_W32_SYSTEM || HAVE_W64_SYSTEM +#include +#endif #include "assuan-defs.h" #include "debug.h" @@ -356,6 +359,48 @@ std_handler_output (assuan_context_t ctx, char *line) } +#if HAVE_W32_SYSTEM || HAVE_W64_SYSTEM +/* + * The command used by a client to send FD. That is, from the viewpoint + * of handling this command, it is to _receive_ a file handle. + */ +static const char w32_help_sendfd[] = + "SENDFD \n" + "\n" + "Used by a client to pass a file HANDLE to the server.\n" + "The server opens as a local file HANDLE."; +static gpg_error_t +w32_handler_sendfd (assuan_context_t ctx, char *line) +{ + gpg_error_t err = 0; + char *endp; + intptr_t file_handle; + int fd; + +#if HAVE_W64_SYSTEM + file_handle = strtoull (line, &endp, 16); +#elif HAVE_W32_SYSTEM + file_handle = strtoul (line, &endp, 16); +#endif + + if (*endp) + { + err = set_error (ctx, GPG_ERR_ASS_SYNTAX, "hex number required"); + return PROCESS_DONE (ctx, err); + } + + fd = _open_osfhandle ((intptr_t)file_handle, _O_RDWR); + if (fd < 0) + { + CloseHandle ((HANDLE)file_handle); + err = GPG_ERR_ASSUAN; + } + + ctx->uds.pendingfds[ctx->uds.pendingfdscount++] = (assuan_fd_t)fd; + return PROCESS_DONE (ctx, err); +} +#endif + /* This is a table with the standard commands and handler for them. The table is used to initialize a new context and associate strings with default handlers */ @@ -376,6 +421,9 @@ static struct { { "INPUT", std_handler_input, std_help_input, 0 }, { "OUTPUT", std_handler_output, std_help_output, 0 }, +#if HAVE_W32_SYSTEM + { "SENDFD", w32_handler_sendfd, w32_help_sendfd, 1 }, +#endif { } }; -- cgit v1.2.3 From 870fdcf92e5991c0bb2e349a951aa8dd93b0e22f Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 4 Nov 2022 19:04:39 +0900 Subject: w32: Support sendfd/recvfd through pipe connection. * src/assuan-defs.h (w32_fdpass_send, w32_fdpass_recv): New. * src/assuan-pipe-connect.c [HAVE_W32_SYSTEM] (pipe_connect): Set w32_fdpass_send. [!HAVE_W32_SYSTEM] (assuan_pipe_connect): Use socketpair_connect. * src/assuan-pipe-server.c [HAVE_W32_SYSTEM] (assuan_init_pipe_server): Set w32_fdpass_recv. * src/system-w32.c (get_file_handle): New. (w32_fdpass_send): New, using "SENDFD" internal command. (w32_fdpass_recv): New, using the result of "SENDFD" internal command. -- GnuPG-bug-id: 6236 Signed-off-by: NIIBE Yutaka --- src/assuan-defs.h | 2 ++ src/assuan-pipe-connect.c | 16 +++++----- src/assuan-pipe-server.c | 4 +++ src/system-w32.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 8 deletions(-) diff --git a/src/assuan-defs.h b/src/assuan-defs.h index 47ff4ef..68bd983 100644 --- a/src/assuan-defs.h +++ b/src/assuan-defs.h @@ -327,6 +327,8 @@ int _assuan_error_is_eagain (assuan_context_t ctx, gpg_error_t err); #ifdef HAVE_W32_SYSTEM char *_assuan_w32_strerror (assuan_context_t ctx, int ec); +gpg_error_t w32_fdpass_send (assuan_context_t ctx, assuan_fd_t fd); +gpg_error_t w32_fdpass_recv (assuan_context_t ctx, assuan_fd_t *fd); #endif /*HAVE_W32_SYSTEM*/ diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c index 1589d79..13ea3de 100644 --- a/src/assuan-pipe-connect.c +++ b/src/assuan-pipe-connect.c @@ -209,7 +209,11 @@ pipe_connect (assuan_context_t ctx, ctx->engine.release = _assuan_client_release; ctx->engine.readfnc = _assuan_simple_read; ctx->engine.writefnc = _assuan_simple_write; +#ifdef HAVE_W32_SYSTEM + ctx->engine.sendfd = w32_fdpass_send; +#else ctx->engine.sendfd = NULL; +#endif ctx->engine.receivefd = NULL; ctx->finish_handler = _assuan_client_finish; ctx->max_accepts = 1; @@ -413,16 +417,12 @@ assuan_pipe_connect (assuan_context_t ctx, TRACE2 (ctx, ASSUAN_LOG_CTX, "assuan_pipe_connect", ctx, "name=%s, flags=0x%x", name ? name : "(null)", flags); +#ifndef HAVE_W32_SYSTEM if (flags & ASSUAN_PIPE_CONNECT_FDPASSING) - { -#ifdef HAVE_W32_SYSTEM - return _assuan_error (ctx, GPG_ERR_NOT_IMPLEMENTED); -#else - return socketpair_connect (ctx, name, argv, fd_child_list, - atfork, atforkvalue); -#endif - } + return socketpair_connect (ctx, name, argv, fd_child_list, + atfork, atforkvalue); else +#endif return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue, flags); } diff --git a/src/assuan-pipe-server.c b/src/assuan-pipe-server.c index db66978..8da54ad 100644 --- a/src/assuan-pipe-server.c +++ b/src/assuan-pipe-server.c @@ -115,7 +115,11 @@ assuan_init_pipe_server (assuan_context_t ctx, assuan_fd_t filedes[2]) ctx->engine.readfnc = _assuan_simple_read; ctx->engine.writefnc = _assuan_simple_write; ctx->engine.sendfd = NULL; +#ifdef HAVE_W32_SYSTEM + ctx->engine.receivefd = w32_fdpass_recv; +#else ctx->engine.receivefd = NULL; +#endif ctx->max_accepts = 1; s = getenv ("_assuan_pipe_connect_pid"); diff --git a/src/system-w32.c b/src/system-w32.c index cfc1d61..76ff2a0 100644 --- a/src/system-w32.c +++ b/src/system-w32.c @@ -167,6 +167,83 @@ __assuan_close (assuan_context_t ctx, assuan_fd_t fd) +/* Get a file HANDLE to send, from POSIX fd. */ +static gpg_error_t +get_file_handle (int fd, int server_pid, HANDLE *r_handle) +{ + HANDLE prochandle, handle, newhandle; + + handle = (void *)_get_osfhandle (fd); + + prochandle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, server_pid); + if (!prochandle) + return gpg_error (GPG_ERR_ASS_PARAMETER);/*FIXME: error*/ + + if (!DuplicateHandle (GetCurrentProcess (), handle, prochandle, &newhandle, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + CloseHandle (prochandle); + return gpg_error (GPG_ERR_ASS_PARAMETER);/*FIXME: error*/ + } + CloseHandle (prochandle); + *r_handle = newhandle; + return 0; +} + + +/* Send a FD (which means POSIX fd) to the peer. */ +gpg_error_t +w32_fdpass_send (assuan_context_t ctx, assuan_fd_t fd) +{ + char fdpass_msg[256]; + int res; + int fd0; /* POSIX fd */ + intptr_t fd_converted_to_integer; + HANDLE file_handle; + gpg_error_t err; + + fd_converted_to_integer = (intptr_t)fd; + fd0 = (int)fd_converted_to_integer; /* Bit pattern is possibly truncated. */ + + err = get_file_handle (fd0, ctx->pid, &file_handle); + if (err) + return err; + + res = snprintf (fdpass_msg, sizeof (fdpass_msg), "SENDFD %p", file_handle); + if (res < 0) + { + CloseHandle (file_handle); + return gpg_error (GPG_ERR_ASS_PARAMETER);/*FIXME: error*/ + } + + err = assuan_transact (ctx, fdpass_msg, NULL, NULL, NULL, NULL, NULL, NULL); + return err; +} + + +/* Receive a HANDLE from the peer and turn it into a FD (POSIX fd). */ +gpg_error_t +w32_fdpass_recv (assuan_context_t ctx, assuan_fd_t *fd) +{ + int i; + + if (!ctx->uds.pendingfdscount) + { + TRACE0 (ctx, ASSUAN_LOG_SYSIO, "w32_receivefd", ctx, + "no pending file descriptors"); + return _assuan_error (ctx, GPG_ERR_ASS_GENERAL); + } + + *fd = ctx->uds.pendingfds[0]; + for (i=1; i < ctx->uds.pendingfdscount; i++) + ctx->uds.pendingfds[i-1] = ctx->uds.pendingfds[i]; + ctx->uds.pendingfdscount--; + + TRACE1 (ctx, ASSUAN_LOG_SYSIO, "w32_fdpass_recv", ctx, + "received fd: %p", ctx->uds.pendingfds[0]); + return 0; +} + ssize_t __assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size) { -- cgit v1.2.3