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.1