1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00
gnupg/common/exechelp-w32.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

359 lines
8.9 KiB
C
Raw Normal View History

2010-03-22 15:00:54 +00:00
/* exechelp-w32.c - Fork and exec helpers for W32.
* Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc.
* Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH
*
* This file is part of GnuPG.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either
*
* - 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.
*
* or
*
* - the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* or both in parallel, as here.
*
* This file 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+)
*/
#include <config.h>
#if !defined(HAVE_W32_SYSTEM)
2010-03-22 15:00:54 +00:00
#error This code is only used on W32.
common,agent,gpg,dirmngr,g13,scd,tests,tools: New spawn function. * common/exechelp-posix.c (do_exec, gnupg_spawn_process): Remove. (check_syscall_func, pre_syscall, post_syscall) : New. (do_create_socketpair, posix_open_null, call_spawn_cb): New. (my_exec, spawn_detached, gnupg_spawn_helper): New. (gnupg_process_spawn, process_kill, gnupg_process_terminate): New. (gnupg_process_get_fds, gnupg_process_get_streams): New. (process_vctl, gnupg_process_ctl): New. (gnupg_process_wait, gnupg_process_release): New. (gnupg_process_wait_list): New. * common/exechelp-w32.c: Add definition of _WIN32_WINNT as 0x600. (check_syscall_func, pre_syscall, post_syscall): New. (gnupg_spawn_process): Remove. (check_windows_version): New. (spawn_detached, gnupg_spawn_helper, gnupg_process_spawn): New. (gnupg_process_get_fds, gnupg_process_get_streams): New. (process_kill, process_vctl, gnupg_process_ctl): New. (gnupg_process_wait, gnupg_process_terminate): New. (gnupg_process_release, gnupg_process_wait_list): New. * common/exechelp.h: Re-write for new API. * common/exectool.c (gnupg_exec_tool_stream): Follow the change. * common/asshelp.c (start_new_service): Likewise. * agent/genkey.c (do_check_passphrase_pattern): Likewise. * dirmngr/ldap-wrapper.c (struct wrapper_context_s): Use PROC. (destroy_wrapper): Follow the change of API. (read_log_data): Follow the change of API, use printable_pid. (ldap_reaper_thread, ldap_wrapper_release_context): Likewise. (ldap_wrapper_connection_cleanup, ldap_wrapper): Likewise. * g10/photoid.c (run_with_pipe): Follow the change of API. (show_photo): Likewise. * g13/be-encfs.c (run_umount_helper): Likewise. (run_encfs_tool): Likewise. * g13/g13.c: Add including ./common/exechelp.h. * g13/mount.c: Likewise. * g13/runner.c: Follow the change of API. * g13/runner.h: Follow the change of API. * scd/app.c (setup_env): New. (report_change): Follow the change of API. * tests/gpgscm/ffi.c (proc_object_finalize): New. (proc_object_to_string): New. (proc_wrap, proc_unwrap): New. (do_spawn_process): Remove. (do_process_spawn): New. (setup_std_fds): New. (do_spawn_process_fd): Remove. (do_process_spawn_fd): New. (do_wait_process): Remove. (do_process_wait): New. (do_wait_processes): Remove. * tests/gpgscm/t-child.scm: Follow the change of API. * tests/gpgscm/tests.scm: Likewise. * tests/openpgp/defs.scm: Likewise. * tests/tpm2dtests/defs.scm: Likewise. * tools/gpg-card.c: Likewise. * tools/gpgconf-comp.c: Likewise. * tools/gpgconf.c: Likewise. * tools/gpgtar-create.c: Likewise. * tools/gpgtar-extract.c: Likewise. * tools/gpgtar-list.c: Likewise. -- GnuPG-bug-id: 6275 Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-11 19:18:21 +09:00
#else
#define _WIN32_WINNT 0x600
2010-03-22 15:00:54 +00:00
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
2010-03-10 12:24:58 +00:00
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
#include <unistd.h>
#include <fcntl.h>
2006-10-17 14:34:42 +00:00
#ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
#undef HAVE_NPTH
#undef USE_NPTH
2006-10-17 14:34:42 +00:00
#endif
#ifdef HAVE_NPTH
#include <npth.h>
#endif
#ifdef HAVE_STAT
# include <sys/stat.h>
#endif
#include "util.h"
#include "i18n.h"
#include "sysutils.h"
#include "exechelp.h"
#include <windows.h>
common,agent,gpg,dirmngr,g13,scd,tests,tools: New spawn function. * common/exechelp-posix.c (do_exec, gnupg_spawn_process): Remove. (check_syscall_func, pre_syscall, post_syscall) : New. (do_create_socketpair, posix_open_null, call_spawn_cb): New. (my_exec, spawn_detached, gnupg_spawn_helper): New. (gnupg_process_spawn, process_kill, gnupg_process_terminate): New. (gnupg_process_get_fds, gnupg_process_get_streams): New. (process_vctl, gnupg_process_ctl): New. (gnupg_process_wait, gnupg_process_release): New. (gnupg_process_wait_list): New. * common/exechelp-w32.c: Add definition of _WIN32_WINNT as 0x600. (check_syscall_func, pre_syscall, post_syscall): New. (gnupg_spawn_process): Remove. (check_windows_version): New. (spawn_detached, gnupg_spawn_helper, gnupg_process_spawn): New. (gnupg_process_get_fds, gnupg_process_get_streams): New. (process_kill, process_vctl, gnupg_process_ctl): New. (gnupg_process_wait, gnupg_process_terminate): New. (gnupg_process_release, gnupg_process_wait_list): New. * common/exechelp.h: Re-write for new API. * common/exectool.c (gnupg_exec_tool_stream): Follow the change. * common/asshelp.c (start_new_service): Likewise. * agent/genkey.c (do_check_passphrase_pattern): Likewise. * dirmngr/ldap-wrapper.c (struct wrapper_context_s): Use PROC. (destroy_wrapper): Follow the change of API. (read_log_data): Follow the change of API, use printable_pid. (ldap_reaper_thread, ldap_wrapper_release_context): Likewise. (ldap_wrapper_connection_cleanup, ldap_wrapper): Likewise. * g10/photoid.c (run_with_pipe): Follow the change of API. (show_photo): Likewise. * g13/be-encfs.c (run_umount_helper): Likewise. (run_encfs_tool): Likewise. * g13/g13.c: Add including ./common/exechelp.h. * g13/mount.c: Likewise. * g13/runner.c: Follow the change of API. * g13/runner.h: Follow the change of API. * scd/app.c (setup_env): New. (report_change): Follow the change of API. * tests/gpgscm/ffi.c (proc_object_finalize): New. (proc_object_to_string): New. (proc_wrap, proc_unwrap): New. (do_spawn_process): Remove. (do_process_spawn): New. (setup_std_fds): New. (do_spawn_process_fd): Remove. (do_process_spawn_fd): New. (do_wait_process): Remove. (do_process_wait): New. (do_wait_processes): Remove. * tests/gpgscm/t-child.scm: Follow the change of API. * tests/gpgscm/tests.scm: Likewise. * tests/openpgp/defs.scm: Likewise. * tests/tpm2dtests/defs.scm: Likewise. * tools/gpg-card.c: Likewise. * tools/gpgconf-comp.c: Likewise. * tools/gpgconf.c: Likewise. * tools/gpgtar-create.c: Likewise. * tools/gpgtar-extract.c: Likewise. * tools/gpgtar-list.c: Likewise. -- GnuPG-bug-id: 6275 Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-11 19:18:21 +09:00
#include <processthreadsapi.h>
/* Define to 1 do enable debugging. */
#define DEBUG_W32_SPAWN 0
/* It seems Vista doesn't grok X_OK and so fails access() tests.
Previous versions interpreted X_OK as F_OK anyway, so we'll just
use F_OK directly. */
#undef X_OK
#define X_OK F_OK
2010-03-10 12:24:58 +00:00
/* We assume that a HANDLE can be represented by an intptr_t which
should be true for all systems (HANDLE is defined as void *).
Further we assume that -1 denotes an invalid handle. */
# define fd_to_handle(a) ((HANDLE)(a))
# define handle_to_fd(a) ((intptr_t)(a))
# define pid_to_handle(a) ((HANDLE)(a))
# define handle_to_pid(a) ((int)(a))
/* Helper */
static inline gpg_error_t
my_error_from_syserror (void)
{
return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
}
static inline gpg_error_t
my_error (int errcode)
{
return gpg_err_make (default_errsource, errcode);
}
/* Return the maximum number of currently allowed open file
descriptors. Only useful on POSIX systems but returns a value on
other systems too. */
int
get_max_fds (void)
{
int max_fds = -1;
#ifdef OPEN_MAX
if (max_fds == -1)
max_fds = OPEN_MAX;
#endif
if (max_fds == -1)
max_fds = 256; /* Arbitrary limit. */
return max_fds;
}
2010-08-23 19:26:05 +00:00
/* Under Windows this is a dummy function. */
void
spawn: Remove spawn callback, introduce gnupg_spawn_actions. * common/exechelp-posix.c (call_spawn_cb): Remove. (gnupg_spawn_actions_new, gnupg_spawn_actions_release) (gnupg_spawn_actions_set_environ, gnupg_spawn_actions_set_atfork) (gnupg_spawn_actions_set_redirect) (gnupg_spawn_actions_set_inherit_fds): New. (my_exec, spawn_detached): Use spawn actions. (gnupg_spawn_helper): Remove. (gnupg_process_spawn): Remove callback, introduce gnupg_spawn_actions. * common/exechelp-w32.c: Ditto. * common/exechelp.h: Ditto. * agent/genkey.c (do_check_passphrase_pattern): Follow the change of gnupg_process_spawn API. * common/asshelp.c (start_new_service): Likewise. * common/exectool.c (gnupg_exec_tool_stream): Likewise. * common/t-exechelp.c (test_pipe_stream): Likewise. * dirmngr/ldap-wrapper.c (ldap_wrapper): Likewise. * g10/photoid.c (run_with_pipe): Likewise. * scd/app.c (report_change): Likewise. * tests/gpgscm/ffi.c (do_process_spawn_io, do_process_spawn_fd): Likewise. * tools/gpg-card.c (cmd_gpg): Likewise. * tools/gpgconf-comp.c (gpg_agent_runtime_change): Likewise. (scdaemon_runtime_change, tpm2daemon_runtime_change) (dirmngr_runtime_change, keyboxd_runtime_change) (gc_component_launch, gc_component_check_options) (retrieve_options_from_program): Likewise. * tools/gpgconf.c (show_versions_via_dirmngr): Likewise. * tools/gpgtar-create.c (gpgtar_create): Likewise. * tools/gpgtar-extract.c (gpgtar_extract): Likewise. * tools/gpgtar-list.c (gpgtar_list): Likewise. -- Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-05-31 15:36:39 +09:00
close_all_fds (int first, const int *except)
{
2010-08-23 19:26:05 +00:00
(void)first;
(void)except;
}
/* Returns an array with all currently open file descriptors. The end
* of the array is marked by -1. The caller needs to release this
* array using the *standard free* and not with xfree. This allow the
* use of this function right at startup even before libgcrypt has
* been initialized. Returns NULL on error and sets ERRNO
* accordingly. Note that fstat prints a warning to DebugView for all
* invalid fds which is a bit annoying. We actually do not need this
* function in real code (close_all_fds is a dummy anyway) but we keep
* it for use by t-exechelp.c. */
int *
get_all_open_fds (void)
{
int *array;
size_t narray;
int fd, max_fd, idx;
#ifndef HAVE_STAT
array = calloc (1, sizeof *array);
if (array)
array[0] = -1;
#else /*HAVE_STAT*/
struct stat statbuf;
max_fd = get_max_fds ();
narray = 32; /* If you change this change also t-exechelp.c. */
array = calloc (narray, sizeof *array);
if (!array)
return NULL;
/* Note: The list we return is ordered. */
for (idx=0, fd=0; fd < max_fd; fd++)
if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
{
if (idx+1 >= narray)
{
int *tmp;
narray += (narray < 256)? 32:256;
tmp = realloc (array, narray * sizeof *array);
if (!tmp)
{
free (array);
return NULL;
}
array = tmp;
}
array[idx++] = fd;
}
array[idx] = -1;
#endif /*HAVE_STAT*/
return array;
}
#define INHERIT_READ 1
#define INHERIT_WRITE 2
#define INHERIT_BOTH (INHERIT_READ|INHERIT_WRITE)
/* Create pipe. FLAGS indicates which ends are inheritable. */
static int
create_inheritable_pipe (HANDLE filedes[2], int flags)
{
HANDLE r, w;
SECURITY_ATTRIBUTES sec_attr;
memset (&sec_attr, 0, sizeof sec_attr );
sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = TRUE;
if (!CreatePipe (&r, &w, &sec_attr, 0))
return -1;
if ((flags & INHERIT_READ) == 0)
if (! SetHandleInformation (r, HANDLE_FLAG_INHERIT, 0))
goto fail;
if ((flags & INHERIT_WRITE) == 0)
if (! SetHandleInformation (w, HANDLE_FLAG_INHERIT, 0))
goto fail;
2009-09-30 15:28:38 +00:00
filedes[0] = r;
filedes[1] = w;
2009-09-30 15:28:38 +00:00
return 0;
fail:
log_error ("SetHandleInformation failed: %s\n", w32_strerror (-1));
CloseHandle (r);
CloseHandle (w);
return -1;
2009-09-30 15:28:38 +00:00
}
2010-03-22 14:22:41 +00:00
static gpg_error_t
create_pipe_and_estream (gnupg_fd_t *r_fd, int flags,
estream_t *r_fp, int outbound, int nonblock)
{
gpg_error_t err = 0;
es_syshd_t syshd;
gnupg_fd_t fds[2];
int inherit_flags = 0;
if (flags == GNUPG_PIPE_OUTBOUND)
inherit_flags = INHERIT_READ;
else if (flags == GNUPG_PIPE_INBOUND)
inherit_flags = INHERIT_WRITE;
else
inherit_flags = INHERIT_BOTH;
if (create_inheritable_pipe (fds, inherit_flags) < 0)
2009-09-30 15:28:38 +00:00
{
err = my_error_from_syserror ();
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
*r_fd = GNUPG_INVALID_FD;
*r_fp = NULL;
return err;
2009-09-30 15:28:38 +00:00
}
syshd.type = ES_SYSHD_HANDLE;
if (!outbound)
{
syshd.u.handle = fds[0];
*r_fd = fds[1];
*r_fp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
}
else
{
syshd.u.handle = fds[1];
*r_fd = fds[0];
*r_fp = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
}
if (!*r_fp)
{
err = my_error_from_syserror ();
log_error (_("error creating a stream for a pipe: %s\n"),
gpg_strerror (err));
CloseHandle (fds[0]);
CloseHandle (fds[1]);
*r_fd = GNUPG_INVALID_FD;
return err;
}
return 0;
2009-09-30 15:28:38 +00:00
}
2010-03-22 14:22:41 +00:00
/* Portable function to create a pipe. Under Windows the write end is
inheritable. Pipe is created and the read end is stored at R_FD.
An estream is created for the write end and stored at R_FP. */
2010-03-22 14:22:41 +00:00
gpg_error_t
gnupg_create_inbound_pipe (gnupg_fd_t *r_fd, estream_t *r_fp, int nonblock)
2010-03-22 14:22:41 +00:00
{
if (!r_fd || !r_fp)
gpg_error (GPG_ERR_INV_ARG);
return create_pipe_and_estream (r_fd, GNUPG_PIPE_INBOUND, r_fp, 0, nonblock);
2010-03-22 14:22:41 +00:00
}
2009-09-30 15:28:38 +00:00
/* Portable function to create a pipe. Under Windows the read end is
inheritable. Pipe is created and the write end is stored at R_FD.
An estream is created for the write end and stored at R_FP. */
2009-09-30 15:28:38 +00:00
gpg_error_t
gnupg_create_outbound_pipe (gnupg_fd_t *r_fd, estream_t *r_fp, int nonblock)
2009-09-30 15:28:38 +00:00
{
if (!r_fd || !r_fp)
gpg_error (GPG_ERR_INV_ARG);
return create_pipe_and_estream (r_fd, GNUPG_PIPE_OUTBOUND, r_fp, 1, nonblock);
}
/* Portable function to create a pipe. FLAGS=GNUPG_PIPE_INBOUND for
ihneritable write-end for Windows, GNUPG_PIPE_OUTBOUND for
inheritable read-end for Windows, GNUPG_PIPE_BOTH to specify
both ends may be inheritable. */
gpg_error_t
gnupg_create_pipe (int filedes[2], int flags)
{
gnupg_fd_t fds[2];
gpg_error_t err = 0;
int inherit_flags = 0;
if (flags == GNUPG_PIPE_OUTBOUND)
inherit_flags = INHERIT_READ;
else if (flags == GNUPG_PIPE_INBOUND)
inherit_flags = INHERIT_WRITE;
else
inherit_flags = INHERIT_BOTH;
if (create_inheritable_pipe (fds, inherit_flags) < 0)
return my_error_from_syserror ();
filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), O_RDONLY);
if (filedes[0] == -1)
{
log_error ("failed to translate osfhandle %p\n", fds[0]);
CloseHandle (fds[0]);
CloseHandle (fds[1]);
filedes[1] = -1;
err = my_error (GPG_ERR_GENERAL);
}
else
{
filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), O_APPEND);
if (filedes[1] == -1)
{
log_error ("failed to translate osfhandle %p\n", fds[1]);
close (filedes[0]);
filedes[0] = -1;
CloseHandle (fds[1]);
err = my_error (GPG_ERR_GENERAL);
}
else
err = 0;
}
return err;
}
/* Close the end of a pipe. */
void
gnupg_close_pipe (int fd)
{
if (fd != -1)
close (fd);
}