aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Makefile.am8
-rw-r--r--common/asshelp.c43
-rw-r--r--common/asshelp.h11
-rw-r--r--common/audit.c4
-rw-r--r--common/b64dec.c299
-rw-r--r--common/b64enc.c423
-rw-r--r--common/dynload.h11
-rw-r--r--common/exechelp-posix.c993
-rw-r--r--common/exechelp-w32.c1209
-rw-r--r--common/exechelp.h231
-rw-r--r--common/exectool.c40
-rw-r--r--common/get-passphrase.c3
-rw-r--r--common/init.c1
-rw-r--r--common/iobuf.c72
-rw-r--r--common/iobuf.h6
-rw-r--r--common/miscellaneous.c50
-rw-r--r--common/openpgpdefs.h9
-rw-r--r--common/ssh-utils.c24
-rw-r--r--common/sysutils.c182
-rw-r--r--common/sysutils.h13
-rw-r--r--common/t-b64.c283
-rw-r--r--common/t-exechelp.c152
-rw-r--r--common/t-iobuf.c56
-rw-r--r--common/util.h34
24 files changed, 1906 insertions, 2251 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
index 91718f99e..d27603f96 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -65,7 +65,7 @@ common_sources = \
homedir.c \
gettime.c gettime.h \
yesno.c \
- b64enc.c b64dec.c zb32.c zb32.h \
+ zb32.c zb32.h \
convert.c \
percent.c \
mbox-util.c mbox-util.h \
@@ -161,11 +161,12 @@ module_tests = t-stringhelp t-timestuff \
t-convert t-percent t-gettime t-sysutils t-sexputil \
t-session-env t-openpgp-oid t-ssh-utils \
t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
- t-name-value t-ccparray t-recsel t-w32-cmdline t-b64
+ t-name-value t-ccparray t-recsel t-w32-cmdline t-exechelp
+
if HAVE_W32_SYSTEM
module_tests += t-w32-reg
else
-module_tests += t-exechelp t-exectool
+module_tests += t-exectool
endif
if MAINTAINER_MODE
@@ -196,7 +197,6 @@ t_gettime_LDADD = $(t_common_ldadd)
t_sysutils_LDADD = $(t_common_ldadd)
t_helpfile_LDADD = $(t_common_ldadd)
t_sexputil_LDADD = $(t_common_ldadd)
-t_b64_LDADD = $(t_common_ldadd)
t_exechelp_LDADD = $(t_common_ldadd)
t_exectool_LDADD = $(t_common_ldadd)
t_session_env_LDADD = $(t_common_ldadd)
diff --git a/common/asshelp.c b/common/asshelp.c
index eb3e41bf5..5a40e0380 100644
--- a/common/asshelp.c
+++ b/common/asshelp.c
@@ -386,7 +386,8 @@ start_new_service (assuan_context_t *r_ctx,
const char *opt_lc_ctype,
const char *opt_lc_messages,
session_env_t session_env,
- int autostart, int verbose, int debug,
+ unsigned int flags,
+ int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
@@ -445,7 +446,7 @@ start_new_service (assuan_context_t *r_ctx,
}
err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
- if (err && autostart)
+ if (err && (flags & ASSHELP_FLAG_AUTOSTART))
{
char *abs_homedir;
lock_spawn_t lock;
@@ -523,16 +524,12 @@ start_new_service (assuan_context_t *r_ctx,
&& assuan_socket_connect (ctx, sockname, 0, connect_flags))
{
#ifdef HAVE_W32_SYSTEM
- err = gnupg_spawn_process_detached (program? program : program_name,
- argv, NULL);
+ err = gnupg_process_spawn (program? program : program_name, argv,
+ GNUPG_PROCESS_DETACHED,
+ NULL, NULL, NULL);
#else /*!W32*/
- pid_t pid;
-
- err = gnupg_spawn_process_fd (program? program : program_name,
- argv, -1, -1, -1, &pid);
- if (!err)
- err = gnupg_wait_process (program? program : program_name,
- pid, 1, NULL);
+ err = gnupg_process_spawn (program? program : program_name, argv,
+ 0, NULL, NULL, NULL);
#endif /*!W32*/
if (err)
log_error ("failed to start %s '%s': %s\n",
@@ -551,7 +548,8 @@ start_new_service (assuan_context_t *r_ctx,
xfree (sockname);
if (err)
{
- if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
+ if ((flags & ASSHELP_FLAG_AUTOSTART)
+ || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
log_error ("can't connect to the %s: %s\n",
printed_name, gpg_strerror (err));
assuan_release (ctx);
@@ -603,55 +601,58 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
const char *opt_lc_ctype,
const char *opt_lc_messages,
session_env_t session_env,
- int autostart, int verbose, int debug,
+ unsigned int flags,
+ int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
return start_new_service (r_ctx, GNUPG_MODULE_NAME_AGENT,
errsource, agent_program,
opt_lc_ctype, opt_lc_messages, session_env,
- autostart, verbose, debug,
+ flags, verbose, debug,
status_cb, status_cb_arg);
}
/* Try to connect to the dirmngr via a socket. On platforms
- supporting it, start it up if needed and if AUTOSTART is true.
+ supporting it, start it up if needed and if ASSHELP_FLAG_AUTOSTART is set.
Returns a new assuan context at R_CTX or an error code. */
gpg_error_t
start_new_keyboxd (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *keyboxd_program,
- int autostart, int verbose, int debug,
+ unsigned int flags,
+ int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
return start_new_service (r_ctx, GNUPG_MODULE_NAME_KEYBOXD,
errsource, keyboxd_program,
NULL, NULL, NULL,
- autostart, verbose, debug,
+ flags, verbose, debug,
status_cb, status_cb_arg);
}
/* Try to connect to the dirmngr via a socket. On platforms
- supporting it, start it up if needed and if AUTOSTART is true.
+ supporting it, start it up if needed and if ASSHELP_FLAG_AUTOSTART is set.
Returns a new assuan context at R_CTX or an error code. */
gpg_error_t
start_new_dirmngr (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *dirmngr_program,
- int autostart, int verbose, int debug,
+ unsigned int flags,
+ int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
#ifndef USE_DIRMNGR_AUTO_START
- autostart = 0;
+ flags &= ~ASSHELP_FLAG_AUTOSTART; /* Clear flag. */
#endif
return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR,
errsource, dirmngr_program,
NULL, NULL, NULL,
- autostart, verbose, debug,
+ flags, verbose, debug,
status_cb, status_cb_arg);
}
diff --git a/common/asshelp.h b/common/asshelp.h
index e7e43bd1b..bca50759d 100644
--- a/common/asshelp.h
+++ b/common/asshelp.h
@@ -37,6 +37,8 @@
#include "util.h"
/*-- asshelp.c --*/
+#define ASSHELP_FLAG_AUTOSTART 1 /* Autostart the new service. */
+
void setup_libassuan_logging (unsigned int *debug_var_address,
int (*log_monitor)(assuan_context_t ctx,
@@ -61,7 +63,8 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
const char *opt_lc_ctype,
const char *opt_lc_messages,
session_env_t session_env,
- int autostart, int verbose, int debug,
+ unsigned int flags,
+ int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg);
@@ -71,7 +74,8 @@ gpg_error_t
start_new_keyboxd (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *keyboxd_program,
- int autostart, int verbose, int debug,
+ unsigned int flags,
+ int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg);
@@ -81,7 +85,8 @@ gpg_error_t
start_new_dirmngr (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *dirmngr_program,
- int autostart, int verbose, int debug,
+ unsigned int flags,
+ int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg);
diff --git a/common/audit.c b/common/audit.c
index ae0d45216..42a2cf6d6 100644
--- a/common/audit.c
+++ b/common/audit.c
@@ -45,8 +45,8 @@ struct log_item_s
int intvalue; /* A logged integer value. */
char *string; /* A malloced string or NULL. */
ksba_cert_t cert; /* A certifciate or NULL. */
- int have_err:1;
- int have_intvalue:1;
+ unsigned int have_err:1;
+ unsigned int have_intvalue:1;
};
typedef struct log_item_s *log_item_t;
diff --git a/common/b64dec.c b/common/b64dec.c
deleted file mode 100644
index 2904b0471..000000000
--- a/common/b64dec.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/* b64dec.c - Simple Base64 decoder.
- * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
- * Copyright (C) 2008, 2011, 2016 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 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.
- *
- * 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 Lesser General Public License
- * along with this program; if not, see <https://www.gnu.org/licenses/>.
- * SPDX-License-Identifier: LGPL-2.1-or-later
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-#include "i18n.h"
-#include "util.h"
-
-
-/* The reverse base-64 list used for base-64 decoding. */
-static unsigned char const asctobin[128] =
- {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
- 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
- 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
- 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
- 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
- };
-
-enum decoder_states
- {
- s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
- s_b64_0, s_b64_1, s_b64_2, s_b64_3,
- s_waitendtitle, s_waitend
- };
-
-
-
-/* Initialize the context for the base64 decoder. If TITLE is NULL a
- plain base64 decoding is done. If it is the empty string the
- decoder will skip everything until a "-----BEGIN " line has been
- seen, decoding ends at a "----END " line. */
-gpg_error_t
-b64dec_start (struct b64state *state, const char *title)
-{
- memset (state, 0, sizeof *state);
- if (title)
- {
- state->title = xtrystrdup (title);
- if (!state->title)
- state->lasterr = gpg_error_from_syserror ();
- else
- state->idx = s_init;
- }
- else
- state->idx = s_b64_0;
- return state->lasterr;
-}
-
-
-/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
- new length of the buffer at R_NBYTES. */
-gpg_error_t
-b64dec_proc (struct b64state *state, void *buffer, size_t length,
- size_t *r_nbytes)
-{
- enum decoder_states ds = state->idx;
- unsigned char val = state->radbuf[0];
- int pos = state->quad_count;
- char *d, *s;
-
- if (state->lasterr)
- return state->lasterr;
-
- if (state->stop_seen)
- {
- *r_nbytes = 0;
- state->lasterr = gpg_error (GPG_ERR_EOF);
- xfree (state->title);
- state->title = NULL;
- return state->lasterr;
- }
-
- for (s=d=buffer; length && !state->stop_seen; length--, s++)
- {
- again:
- switch (ds)
- {
- case s_idle:
- if (*s == '\n')
- {
- ds = s_lfseen;
- pos = 0;
- }
- break;
- case s_init:
- ds = s_lfseen;
- /* fall through */
- case s_lfseen:
- if (*s != "-----BEGIN "[pos])
- {
- ds = s_idle;
- goto again;
- }
- else if (pos == 10)
- {
- pos = 0;
- ds = s_beginseen;
- }
- else
- pos++;
- break;
- case s_beginseen:
- if (*s != "PGP "[pos])
- ds = s_begin; /* Not a PGP armor. */
- else if (pos == 3)
- ds = s_waitheader;
- else
- pos++;
- break;
- case s_waitheader:
- if (*s == '\n')
- ds = s_waitblank;
- break;
- case s_waitblank:
- if (*s == '\n')
- ds = s_b64_0; /* blank line found. */
- else if (*s == ' ' || *s == '\r' || *s == '\t')
- ; /* Ignore spaces. */
- else
- {
- /* Armor header line. Note that we don't care that our
- * FSM accepts a header prefixed with spaces. */
- ds = s_waitheader; /* Wait for next header. */
- }
- break;
- case s_begin:
- if (*s == '\n')
- ds = s_b64_0;
- break;
- case s_b64_0:
- case s_b64_1:
- case s_b64_2:
- case s_b64_3:
- {
- int c;
-
- if (*s == '-' && state->title)
- {
- /* Not a valid Base64 character: assume end
- header. */
- ds = s_waitend;
- }
- else if (*s == '=')
- {
- /* Pad character: stop */
- if (ds == s_b64_1)
- *d++ = val;
- ds = state->title? s_waitendtitle : s_waitend;
- }
- else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
- ; /* Skip white spaces. */
- else if ( (*s & 0x80)
- || (c = asctobin[*(unsigned char *)s]) == 255)
- {
- /* Skip invalid encodings. */
- state->invalid_encoding = 1;
- }
- else if (ds == s_b64_0)
- {
- val = c << 2;
- ds = s_b64_1;
- }
- else if (ds == s_b64_1)
- {
- val |= (c>>4)&3;
- *d++ = val;
- val = (c<<4)&0xf0;
- ds = s_b64_2;
- }
- else if (ds == s_b64_2)
- {
- val |= (c>>2)&15;
- *d++ = val;
- val = (c<<6)&0xc0;
- ds = s_b64_3;
- }
- else
- {
- val |= c&0x3f;
- *d++ = val;
- ds = s_b64_0;
- }
- }
- break;
- case s_waitendtitle:
- if (*s == '-')
- ds = s_waitend;
- break;
- case s_waitend:
- if ( *s == '\n')
- state->stop_seen = 1;
- break;
- default:
- BUG();
- }
- }
-
-
- state->idx = ds;
- state->radbuf[0] = val;
- state->quad_count = pos;
- *r_nbytes = (d -(char*) buffer);
- return 0;
-}
-
-
-/* This function needs to be called before releasing the decoder
- state. It may return an error code in case an encoding error has
- been found during decoding. */
-gpg_error_t
-b64dec_finish (struct b64state *state)
-{
- xfree (state->title);
- state->title = NULL;
-
- if (state->lasterr)
- return state->lasterr;
-
- return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
-}
-
-
-/* Convert STRING consisting of base64 characters into its binary
- * representation and store the result in a newly allocated buffer at
- * R_BUFFER with its length at R_BUFLEN. If TITLE is NULL a plain
- * base64 decoding is done. If it is the empty string the decoder
- * will skip everything until a "-----BEGIN " line has been seen,
- * decoding then ends at a "----END " line. On failure the function
- * returns an error code and sets R_BUFFER to NULL. If the decoded
- * data has a length of 0 a dummy buffer will still be allocated and
- * the length is set to 0. */
-gpg_error_t
-b64decode (const char *string, const char *title,
- void **r_buffer, size_t *r_buflen)
-{
- gpg_error_t err;
- struct b64state state;
- size_t nbytes;
- char *buffer;
-
- *r_buffer = NULL;
- *r_buflen = 0;
-
- buffer = xtrystrdup (string);
- if (!buffer)
- return gpg_error_from_syserror();
-
- err = b64dec_start (&state, title);
- if (err)
- {
- xfree (buffer);
- return err;
- }
- b64dec_proc (&state, buffer, strlen (buffer), &nbytes);
- err = b64dec_finish (&state);
- if (err)
- xfree (buffer);
- else
- {
- *r_buffer = buffer;
- *r_buflen = nbytes;
- }
- return err;
-}
diff --git a/common/b64enc.c b/common/b64enc.c
deleted file mode 100644
index 7846dcb3e..000000000
--- a/common/b64enc.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/* b64enc.c - Simple Base64 encoder.
- * Copyright (C) 2001, 2003, 2004, 2008, 2010,
- * 2011 Free Software Foundation, Inc.
- * Copyright (C) 2001, 2003, 2004, 2008, 2010,
- * 2011 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 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.
- *
- * 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 Lesser General Public License
- * along with this program; if not, see <https://www.gnu.org/licenses/>.
- * SPDX-License-Identifier: LGPL-2.1-or-later
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-#include "i18n.h"
-#include "util.h"
-
-#define B64ENC_DID_HEADER 1
-#define B64ENC_DID_TRAILER 2
-#define B64ENC_NO_LINEFEEDS 16
-#define B64ENC_USE_PGPCRC 32
-
-/* The base-64 character list */
-static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
-
-/* Stuff required to create the OpenPGP CRC. This crc_table has been
- created using this code:
-
- #include <stdio.h>
- #include <stdint.h>
-
- #define CRCPOLY 0x864CFB
-
- int
- main (void)
- {
- int i, j;
- uint32_t t;
- uint32_t crc_table[256];
-
- crc_table[0] = 0;
- for (i=j=0; j < 128; j++ )
- {
- t = crc_table[j];
- if ( (t & 0x00800000) )
- {
- t <<= 1;
- crc_table[i++] = t ^ CRCPOLY;
- crc_table[i++] = t;
- }
- else
- {
- t <<= 1;
- crc_table[i++] = t;
- crc_table[i++] = t ^ CRCPOLY;
- }
- }
-
- puts ("static const u32 crc_table[256] = {");
- for (i=j=0; i < 256; i++)
- {
- printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
- if (i != 255)
- {
- putchar (',');
- if ( ++j > 5)
- {
- j = 0;
- putchar ('\n');
- }
- }
- }
- puts ("\n};");
- return 0;
- }
-*/
-#define CRCINIT 0xB704CE
-static const u32 crc_table[256] = {
- 0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a,
- 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf,
- 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
- 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e,
- 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa,
- 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
- 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b,
- 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7,
- 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
- 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af,
- 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29,
- 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
- 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1,
- 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad,
- 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099,
- 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375,
- 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821,
- 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4,
- 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049,
- 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5,
- 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791,
- 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52,
- 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66,
- 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a,
- 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337,
- 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2,
- 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6,
- 0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a,
- 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e,
- 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132,
- 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506,
- 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea,
- 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c,
- 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9,
- 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604,
- 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8,
- 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc,
- 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69,
- 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d,
- 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1,
- 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
- 0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9,
- 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538
-};
-
-
-static gpg_error_t
-enc_start (struct b64state *state, FILE *fp, estream_t stream,
- const char *title)
-{
- memset (state, 0, sizeof *state);
- state->fp = fp;
- state->stream = stream;
- state->lasterr = 0;
- if (title && !*title)
- state->flags |= B64ENC_NO_LINEFEEDS;
- else if (title)
- {
- if (!strncmp (title, "PGP ", 4))
- {
- state->flags |= B64ENC_USE_PGPCRC;
- state->crc = CRCINIT;
- }
- state->title = xtrystrdup (title);
- if (!state->title)
- state->lasterr = gpg_error_from_syserror ();
- }
- return state->lasterr;
-}
-
-
-/* Prepare for base-64 writing to the stream FP. If TITLE is not NULL
- and not an empty string, this string will be used as the title for
- the armor lines, with TITLE being an empty string, we don't write
- the header lines and furthermore even don't write any linefeeds.
- If TITLE starts with "PGP " the OpenPGP CRC checksum will be
- written as well. With TITLE being NULL, we merely don't write
- header but make sure that lines are not too long. Note, that we
- don't write any output unless at least one byte get written using
- b64enc_write. */
-gpg_error_t
-b64enc_start (struct b64state *state, FILE *fp, const char *title)
-{
- return enc_start (state, fp, NULL, title);
-}
-
-/* Same as b64enc_start but takes an estream. */
-gpg_error_t
-b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
-{
- return enc_start (state, NULL, fp, title);
-}
-
-
-static int
-my_fputs (const char *string, struct b64state *state)
-{
- if (state->stream)
- return es_fputs (string, state->stream);
- else
- return fputs (string, state->fp);
-}
-
-
-/* Write NBYTES from BUFFER to the Base 64 stream identified by
- STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
- stream. */
-gpg_error_t
-b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
-{
- unsigned char radbuf[4];
- int idx, quad_count;
- const unsigned char *p;
-
- if (state->lasterr)
- return state->lasterr;
-
- if (!nbytes)
- {
- if (buffer)
- if (state->stream? es_fflush (state->stream) : fflush (state->fp))
- goto write_error;
- return 0;
- }
-
- if (!(state->flags & B64ENC_DID_HEADER))
- {
- if (state->title)
- {
- if ( my_fputs ("-----BEGIN ", state) == EOF
- || my_fputs (state->title, state) == EOF
- || my_fputs ("-----\n", state) == EOF)
- goto write_error;
- if ( (state->flags & B64ENC_USE_PGPCRC)
- && my_fputs ("\n", state) == EOF)
- goto write_error;
- }
-
- state->flags |= B64ENC_DID_HEADER;
- }
-
- idx = state->idx;
- quad_count = state->quad_count;
- assert (idx < 4);
- memcpy (radbuf, state->radbuf, idx);
-
- if ( (state->flags & B64ENC_USE_PGPCRC) )
- {
- size_t n;
- u32 crc = state->crc;
-
- for (p=buffer, n=nbytes; n; p++, n-- )
- crc = ((u32)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
- state->crc = (crc & 0x00ffffff);
- }
-
- for (p=buffer; nbytes; p++, nbytes--)
- {
- radbuf[idx++] = *p;
- if (idx > 2)
- {
- char tmp[4];
-
- tmp[0] = bintoasc[(*radbuf >> 2) & 077];
- tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
- tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
- tmp[3] = bintoasc[radbuf[2]&077];
- if (state->stream)
- {
- for (idx=0; idx < 4; idx++)
- es_putc (tmp[idx], state->stream);
- idx = 0;
- if (es_ferror (state->stream))
- goto write_error;
- }
- else
- {
- for (idx=0; idx < 4; idx++)
- putc (tmp[idx], state->fp);
- idx = 0;
- if (ferror (state->fp))
- goto write_error;
- }
- if (++quad_count >= (64/4))
- {
- quad_count = 0;
- if (!(state->flags & B64ENC_NO_LINEFEEDS)
- && my_fputs ("\n", state) == EOF)
- goto write_error;
- }
- }
- }
- memcpy (state->radbuf, radbuf, idx);
- state->idx = idx;
- state->quad_count = quad_count;
- return 0;
-
- write_error:
- state->lasterr = gpg_error_from_syserror ();
- if (state->title)
- {
- xfree (state->title);
- state->title = NULL;
- }
- return state->lasterr;
-}
-
-
-gpg_error_t
-b64enc_finish (struct b64state *state)
-{
- gpg_error_t err = 0;
- unsigned char radbuf[4];
- int idx, quad_count;
- char tmp[4];
-
- if (state->lasterr)
- return state->lasterr;
-
- if (!(state->flags & B64ENC_DID_HEADER))
- goto cleanup;
-
- /* Flush the base64 encoding */
- idx = state->idx;
- quad_count = state->quad_count;
- assert (idx < 4);
- memcpy (radbuf, state->radbuf, idx);
-
- if (idx)
- {
- tmp[0] = bintoasc[(*radbuf>>2)&077];
- if (idx == 1)
- {
- tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
- tmp[2] = '=';
- tmp[3] = '=';
- }
- else
- {
- tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
- tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
- tmp[3] = '=';
- }
- if (state->stream)
- {
- for (idx=0; idx < 4; idx++)
- es_putc (tmp[idx], state->stream);
- if (es_ferror (state->stream))
- goto write_error;
- }
- else
- {
- for (idx=0; idx < 4; idx++)
- putc (tmp[idx], state->fp);
- if (ferror (state->fp))
- goto write_error;
- }
-
- if (++quad_count >= (64/4))
- {
- quad_count = 0;
- if (!(state->flags & B64ENC_NO_LINEFEEDS)
- && my_fputs ("\n", state) == EOF)
- goto write_error;
- }
- }
-
- /* Finish the last line and write the trailer. */
- if (quad_count
- && !(state->flags & B64ENC_NO_LINEFEEDS)
- && my_fputs ("\n", state) == EOF)
- goto write_error;
-
- if ( (state->flags & B64ENC_USE_PGPCRC) )
- {
- /* Write the CRC. */
- my_fputs ("=", state);
- radbuf[0] = state->crc >>16;
- radbuf[1] = state->crc >> 8;
- radbuf[2] = state->crc;
- tmp[0] = bintoasc[(*radbuf>>2)&077];
- tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
- tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
- tmp[3] = bintoasc[radbuf[2]&077];
- if (state->stream)
- {
- for (idx=0; idx < 4; idx++)
- es_putc (tmp[idx], state->stream);
- if (es_ferror (state->stream))
- goto write_error;
- }
- else
- {
- for (idx=0; idx < 4; idx++)
- putc (tmp[idx], state->fp);
- if (ferror (state->fp))
- goto write_error;
- }
- if (!(state->flags & B64ENC_NO_LINEFEEDS)
- && my_fputs ("\n", state) == EOF)
- goto write_error;
- }
-
- if (state->title)
- {
- if ( my_fputs ("-----END ", state) == EOF
- || my_fputs (state->title, state) == EOF
- || my_fputs ("-----\n", state) == EOF)
- goto write_error;
- }
-
- goto cleanup;
-
- write_error:
- err = gpg_error_from_syserror ();
-
- cleanup:
- if (state->title)
- {
- xfree (state->title);
- state->title = NULL;
- }
- state->fp = NULL;
- state->stream = NULL;
- state->lasterr = err;
- return err;
-}
diff --git a/common/dynload.h b/common/dynload.h
index 6ac7b4e17..af3906c81 100644
--- a/common/dynload.h
+++ b/common/dynload.h
@@ -34,12 +34,15 @@
#ifndef __MINGW32__
# include <dlfcn.h>
#else
-# include <errhandlingapi.h>
-# include <handleapi.h>
-# include <libloaderapi.h>
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# endif
+# include <windows.h>
# include "utf8conv.h"
# include "mischelp.h"
-# define RTLD_LAZY 0
+# ifndef RTLD_LAZY
+# define RTLD_LAZY 0
+# endif
static inline void *
dlopen (const char *name, int flag)
diff --git a/common/exechelp-posix.c b/common/exechelp-posix.c
index fa613449d..7b20a3796 100644
--- a/common/exechelp-posix.c
+++ b/common/exechelp-posix.c
@@ -273,73 +273,6 @@ get_all_open_fds (void)
}
-/* The exec core used right after the fork. This will never return. */
-static void
-do_exec (const char *pgmname, const char *argv[],
- int fd_in, int fd_out, int fd_err,
- int *except, unsigned int flags)
-{
- char **arg_list;
- int i, j;
- int fds[3];
- int nodevnull[3];
-
- fds[0] = fd_in;
- fds[1] = fd_out;
- fds[2] = fd_err;
-
- nodevnull[0] = !!(flags & GNUPG_SPAWN_KEEP_STDIN);
- nodevnull[1] = !!(flags & GNUPG_SPAWN_KEEP_STDOUT);
- nodevnull[2] = !!(flags & GNUPG_SPAWN_KEEP_STDERR);
-
- /* Create the command line argument array. */
- i = 0;
- if (argv)
- while (argv[i])
- i++;
- arg_list = xcalloc (i+2, sizeof *arg_list);
- arg_list[0] = strrchr (pgmname, '/');
- if (arg_list[0])
- arg_list[0]++;
- else
- arg_list[0] = xstrdup (pgmname);
- if (argv)
- for (i=0,j=1; argv[i]; i++, j++)
- arg_list[j] = (char*)argv[i];
-
- /* Assign /dev/null to unused FDs. */
- for (i=0; i <= 2; i++)
- {
- if (nodevnull[i])
- continue;
- if (fds[i] == -1)
- {
- fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
- if (fds[i] == -1)
- log_fatal ("failed to open '%s': %s\n",
- "/dev/null", strerror (errno));
- }
- }
-
- /* Connect the standard files. */
- for (i=0; i <= 2; i++)
- {
- if (nodevnull[i])
- continue;
- if (fds[i] != i && dup2 (fds[i], i) == -1)
- log_fatal ("dup2 std%s failed: %s\n",
- i==0?"in":i==1?"out":"err", strerror (errno));
- }
-
- /* Close all other files. */
- close_all_fds (3, except);
-
- execv (pgmname, arg_list);
- /* No way to print anything, as we have closed all streams. */
- _exit (127);
-}
-
-
static gpg_error_t
do_create_pipe (int filedes[2])
{
@@ -431,487 +364,669 @@ gnupg_close_pipe (int fd)
close (fd);
}
+#include <sys/socket.h>
-/* Fork and exec the PGMNAME, see exechelp.h for details. */
-gpg_error_t
-gnupg_spawn_process (const char *pgmname, const char *argv[],
- int *except, unsigned int flags,
- estream_t *r_infp,
- estream_t *r_outfp,
- estream_t *r_errfp,
- pid_t *pid)
-{
- gpg_error_t err;
- int inpipe[2] = {-1, -1};
- int outpipe[2] = {-1, -1};
- int errpipe[2] = {-1, -1};
- estream_t infp = NULL;
- estream_t outfp = NULL;
- estream_t errfp = NULL;
- int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
+struct gnupg_process {
+ const char *pgmname;
+ unsigned int terminated :1; /* or detached */
+ unsigned int flags;
+ pid_t pid;
+ int fd_in;
+ int fd_out;
+ int fd_err;
+ int wstatus;
+};
- if (r_infp)
- *r_infp = NULL;
- if (r_outfp)
- *r_outfp = NULL;
- if (r_errfp)
- *r_errfp = NULL;
- *pid = (pid_t)(-1); /* Always required. */
+static int gnupg_process_syscall_func_initialized;
- if (r_infp)
- {
- err = create_pipe_and_estream (inpipe, &infp, 1, nonblock);
- if (err)
- return err;
- }
+/* Functions called before and after blocking syscalls. */
+static void (*pre_syscall_func) (void);
+static void (*post_syscall_func) (void);
- if (r_outfp)
+static void
+check_syscall_func (void)
+{
+ if (!gnupg_process_syscall_func_initialized)
{
- err = create_pipe_and_estream (outpipe, &outfp, 0, nonblock);
- if (err)
- {
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != -1)
- close (inpipe[1]);
- if (inpipe[0] != -1)
- close (inpipe[0]);
-
- return err;
- }
+ gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
+ gnupg_process_syscall_func_initialized = 1;
}
+}
- if (r_errfp)
- {
- err = create_pipe_and_estream (errpipe, &errfp, 0, nonblock);
- if (err)
- {
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != -1)
- close (inpipe[1]);
- if (inpipe[0] != -1)
- close (inpipe[0]);
-
- if (outfp)
- es_fclose (outfp);
- else if (outpipe[0] != -1)
- close (outpipe[0]);
- if (outpipe[1] != -1)
- close (outpipe[1]);
-
- return err;
- }
- }
+static void
+pre_syscall (void)
+{
+ if (pre_syscall_func)
+ pre_syscall_func ();
+}
+
+static void
+post_syscall (void)
+{
+ if (post_syscall_func)
+ post_syscall_func ();
+}
- *pid = fork ();
- if (*pid == (pid_t)(-1))
- {
- err = my_error_from_syserror ();
- log_error (_("error forking process: %s\n"), gpg_strerror (err));
-
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != -1)
- close (inpipe[1]);
- if (inpipe[0] != -1)
- close (inpipe[0]);
-
- if (outfp)
- es_fclose (outfp);
- else if (outpipe[0] != -1)
- close (outpipe[0]);
- if (outpipe[1] != -1)
- close (outpipe[1]);
-
- if (errfp)
- es_fclose (errfp);
- else if (errpipe[0] != -1)
- close (errpipe[0]);
- if (errpipe[1] != -1)
- close (errpipe[1]);
- return err;
- }
+static gpg_err_code_t
+do_create_socketpair (int filedes[2])
+{
+ gpg_error_t err = 0;
- if (!*pid)
+ pre_syscall ();
+ if (socketpair (AF_LOCAL, SOCK_STREAM, 0, filedes) == -1)
{
- /* This is the child. */
- gcry_control (GCRYCTL_TERM_SECMEM);
- es_fclose (infp);
- es_fclose (outfp);
- es_fclose (errfp);
- do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1],
- except, flags);
- /*NOTREACHED*/
+ err = gpg_err_code_from_syserror ();
+ filedes[0] = filedes[1] = -1;
}
+ post_syscall ();
- /* This is the parent. */
- if (inpipe[0] != -1)
- close (inpipe[0]);
- if (outpipe[1] != -1)
- close (outpipe[1]);
- if (errpipe[1] != -1)
- close (errpipe[1]);
+ return err;
+}
- if (r_infp)
- *r_infp = infp;
- if (r_outfp)
- *r_outfp = outfp;
- if (r_errfp)
- *r_errfp = errfp;
+static int
+posix_open_null (int for_write)
+{
+ int fd;
- return 0;
+ fd = open ("/dev/null", for_write? O_WRONLY : O_RDONLY);
+ if (fd == -1)
+ log_fatal ("failed to open '/dev/null': %s\n", strerror (errno));
+ return fd;
}
+static void
+call_spawn_cb (struct spawn_cb_arg *sca,
+ int fd_in, int fd_out, int fd_err,
+ void (*spawn_cb) (struct spawn_cb_arg *), void *spawn_cb_arg)
+{
+ sca->fds[0] = fd_in;
+ sca->fds[1] = fd_out;
+ sca->fds[2] = fd_err;
+ sca->except_fds = NULL;
+ sca->arg = spawn_cb_arg;
+ if (spawn_cb)
+ (*spawn_cb) (sca);
+}
+static void
+my_exec (const char *pgmname, const char *argv[], struct spawn_cb_arg *sca)
+{
+ int i;
-/* Simplified version of gnupg_spawn_process. This function forks and
- then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
- and ERRFD to stderr (any of them may be -1 to connect them to
- /dev/null). The arguments for the process are expected in the NULL
- terminated array ARGV. The program name itself should not be
- included there. Calling gnupg_wait_process is required.
+ /* Assign /dev/null to unused FDs. */
+ for (i = 0; i <= 2; i++)
+ if (sca->fds[i] == -1)
+ sca->fds[i] = posix_open_null (i);
- Returns 0 on success or an error code. */
-gpg_error_t
-gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
- int infd, int outfd, int errfd, pid_t *pid)
+ /* Connect the standard files. */
+ for (i = 0; i <= 2; i++)
+ if (sca->fds[i] != i)
+ {
+ if (dup2 (sca->fds[i], i) == -1)
+ log_fatal ("dup2 std%s failed: %s\n",
+ i==0?"in":i==1?"out":"err", strerror (errno));
+ /*
+ * We don't close sca.fds[i] here, but close them by
+ * close_all_fds. Note that there may be same one in three of
+ * sca->fds[i].
+ */
+ }
+
+ /* Close all other files. */
+ close_all_fds (3, sca->except_fds);
+
+ execv (pgmname, (char *const *)argv);
+ /* No way to print anything, as we have may have closed all streams. */
+ _exit (127);
+}
+
+static gpg_err_code_t
+spawn_detached (const char *pgmname, const char *argv[],
+ void (*spawn_cb) (struct spawn_cb_arg *), void *spawn_cb_arg)
{
- gpg_error_t err;
+ gpg_err_code_t ec;
+ pid_t pid;
- *pid = fork ();
- if (*pid == (pid_t)(-1))
+ /* FIXME: Is this GnuPG specific or should we keep it. */
+ if (getuid() != geteuid())
{
- err = my_error_from_syserror ();
- log_error (_("error forking process: %s\n"), strerror (errno));
- return err;
+ xfree (argv);
+ return GPG_ERR_BUG;
}
- if (!*pid)
+ if (access (pgmname, X_OK))
{
- gcry_control (GCRYCTL_TERM_SECMEM);
- /* Run child. */
- do_exec (pgmname, argv, infd, outfd, errfd, NULL, 0);
- /*NOTREACHED*/
+ ec = gpg_err_code_from_syserror ();
+ xfree (argv);
+ return ec;
}
- return 0;
-}
-
-
-
+ pre_syscall ();
+ pid = fork ();
+ post_syscall ();
+ if (pid == (pid_t)(-1))
+ {
+ ec = gpg_err_code_from_syserror ();
+ log_error (_("error forking process: %s\n"), gpg_strerror (ec));
+ xfree (argv);
+ return ec;
+ }
-/* Waiting for child processes.
+ if (!pid)
+ {
+ pid_t pid2;
+ struct spawn_cb_arg sca;
- waitpid(2) may return information about terminated children that we
- did not yet request, and there is no portable way to wait for a
- specific set of children.
+ if (setsid() == -1 || chdir ("/"))
+ _exit (1);
- As a workaround, we store the results of children for later use.
+ pid2 = fork (); /* Double fork to let init take over the new child. */
+ if (pid2 == (pid_t)(-1))
+ _exit (1);
+ if (pid2)
+ _exit (0); /* Let the parent exit immediately. */
- XXX: This assumes that PIDs are not reused too quickly. */
+ call_spawn_cb (&sca, -1, -1, -1, spawn_cb, spawn_cb_arg);
-struct terminated_child
-{
- pid_t pid;
- int exitcode;
- struct terminated_child *next;
-};
+ my_exec (pgmname, argv, &sca);
+ /*NOTREACHED*/
+ }
-struct terminated_child *terminated_children;
+ pre_syscall ();
+ if (waitpid (pid, NULL, 0) == -1)
+ {
+ post_syscall ();
+ ec = gpg_err_code_from_syserror ();
+ log_error ("waitpid failed in gpgrt_spawn_process_detached: %s",
+ gpg_strerror (ec));
+ return ec;
+ }
+ else
+ post_syscall ();
+ return 0;
+}
-static gpg_error_t
-store_result (pid_t pid, int exitcode)
+void
+gnupg_spawn_helper (struct spawn_cb_arg *sca)
{
- struct terminated_child *c;
+ int *user_except = sca->arg;
+ sca->except_fds = user_except;
+}
- c = xtrymalloc (sizeof *c);
- if (c == NULL)
- return gpg_err_code_from_syserror ();
+gpg_err_code_t
+gnupg_process_spawn (const char *pgmname, const char *argv1[],
+ unsigned int flags,
+ void (*spawn_cb) (struct spawn_cb_arg *),
+ void *spawn_cb_arg,
+ gnupg_process_t *r_process)
+{
+ gpg_err_code_t ec;
+ gnupg_process_t process;
+ int fd_in[2];
+ int fd_out[2];
+ int fd_err[2];
+ pid_t pid;
+ const char **argv;
+ int i, j;
- c->pid = pid;
- c->exitcode = exitcode;
- c->next = terminated_children;
- terminated_children = c;
+ check_syscall_func ();
- return 0;
-}
+ if (r_process)
+ *r_process = NULL;
+ /* Create the command line argument array. */
+ i = 0;
+ if (argv1)
+ while (argv1[i])
+ i++;
+ argv = xtrycalloc (i+2, sizeof *argv);
+ if (!argv)
+ return gpg_err_code_from_syserror ();
+ argv[0] = strrchr (pgmname, '/');
+ if (argv[0])
+ argv[0]++;
+ else
+ argv[0] = pgmname;
-static int
-get_result (pid_t pid, int *r_exitcode)
-{
- struct terminated_child *c, **prevp;
+ if (argv1)
+ for (i=0, j=1; argv1[i]; i++, j++)
+ argv[j] = argv1[i];
- for (prevp = &terminated_children, c = terminated_children;
- c;
- prevp = &c->next, c = c->next)
- if (c->pid == pid)
- {
- *prevp = c->next;
- *r_exitcode = c->exitcode;
- xfree (c);
- return 1;
- }
+ if ((flags & GNUPG_PROCESS_DETACHED))
+ {
+ if ((flags & GNUPG_PROCESS_STDFDS_SETTING))
+ {
+ xfree (argv);
+ return GPG_ERR_INV_FLAG;
+ }
- return 0;
-}
+ /* In detached case, it must be no R_PROCESS. */
+ if (r_process)
+ {
+ xfree (argv);
+ return GPG_ERR_INV_ARG;
+ }
+ return spawn_detached (pgmname, argv, spawn_cb, spawn_cb_arg);
+ }
-/* See exechelp.h for a description. */
-gpg_error_t
-gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
-{
- gpg_err_code_t ec;
- int i, status;
+ process = xtrycalloc (1, sizeof (struct gnupg_process));
+ if (process == NULL)
+ {
+ xfree (argv);
+ return gpg_err_code_from_syserror ();
+ }
- if (r_exitcode)
- *r_exitcode = -1;
+ process->pgmname = pgmname;
+ process->flags = flags;
- if (pid == (pid_t)(-1))
- return gpg_error (GPG_ERR_INV_VALUE);
+ if ((flags & GNUPG_PROCESS_STDINOUT_SOCKETPAIR))
+ {
+ ec = do_create_socketpair (fd_in);
+ if (ec)
+ {
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+ fd_out[0] = dup (fd_in[0]);
+ fd_out[1] = dup (fd_in[1]);
+ }
+ else
+ {
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE))
+ {
+ ec = do_create_pipe (fd_in);
+ if (ec)
+ {
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDIN_KEEP))
+ {
+ fd_in[0] = 0;
+ fd_in[1] = -1;
+ }
+ else
+ {
+ fd_in[0] = -1;
+ fd_in[1] = -1;
+ }
-#ifdef USE_NPTH
- i = npth_waitpid (pid, &status, hang? 0:WNOHANG);
-#else
- while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1)
- && errno == EINTR);
-#endif
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE))
+ {
+ ec = do_create_pipe (fd_out);
+ if (ec)
+ {
+ if (fd_in[0] >= 0 && fd_in[0] != 0)
+ close (fd_in[0]);
+ if (fd_in[1] >= 0)
+ close (fd_in[1]);
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDOUT_KEEP))
+ {
+ fd_out[0] = -1;
+ fd_out[1] = 1;
+ }
+ else
+ {
+ fd_out[0] = -1;
+ fd_out[1] = -1;
+ }
+ }
- if (i == (pid_t)(-1))
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
{
- ec = gpg_err_code_from_errno (errno);
- log_error (_("waiting for process %d to terminate failed: %s\n"),
- (int)pid, strerror (errno));
+ ec = do_create_pipe (fd_err);
+ if (ec)
+ {
+ if (fd_in[0] >= 0 && fd_in[0] != 0)
+ close (fd_in[0]);
+ if (fd_in[1] >= 0)
+ close (fd_in[1]);
+ if (fd_out[0] >= 0)
+ close (fd_out[0]);
+ if (fd_out[1] >= 0 && fd_out[1] != 1)
+ close (fd_out[1]);
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
}
- else if (!i)
+ else if ((flags & GNUPG_PROCESS_STDERR_KEEP))
{
- ec = GPG_ERR_TIMEOUT; /* Still running. */
+ fd_err[0] = -1;
+ fd_err[1] = 2;
}
- else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
+ else
{
- log_error (_("error running '%s': probably not installed\n"), pgmname);
- ec = GPG_ERR_CONFIGURATION;
+ fd_err[0] = -1;
+ fd_err[1] = -1;
}
- else if (WIFEXITED (status) && WEXITSTATUS (status))
+
+ pre_syscall ();
+ pid = fork ();
+ post_syscall ();
+ if (pid == (pid_t)(-1))
{
- if (!r_exitcode)
- log_error (_("error running '%s': exit status %d\n"), pgmname,
- WEXITSTATUS (status));
- else
- *r_exitcode = WEXITSTATUS (status);
- ec = GPG_ERR_GENERAL;
+ ec = gpg_err_code_from_syserror ();
+ log_error (_("error forking process: %s\n"), gpg_strerror (ec));
+ if (fd_in[0] >= 0 && fd_in[0] != 0)
+ close (fd_in[0]);
+ if (fd_in[1] >= 0)
+ close (fd_in[1]);
+ if (fd_out[0] >= 0)
+ close (fd_out[0]);
+ if (fd_out[1] >= 0 && fd_out[1] != 1)
+ close (fd_out[1]);
+ if (fd_err[0] >= 0)
+ close (fd_err[0]);
+ if (fd_err[1] >= 0 && fd_err[1] != 2)
+ close (fd_err[1]);
+ xfree (process);
+ xfree (argv);
+ return ec;
}
- else if (!WIFEXITED (status))
+
+ if (!pid)
{
- log_error (_("error running '%s': terminated\n"), pgmname);
- ec = GPG_ERR_GENERAL;
+ struct spawn_cb_arg sca;
+
+ if (fd_in[1] >= 0)
+ close (fd_in[1]);
+ if (fd_out[0] >= 0)
+ close (fd_out[0]);
+ if (fd_err[0] >= 0)
+ close (fd_err[0]);
+
+ call_spawn_cb (&sca, fd_in[0], fd_out[1], fd_err[1],
+ spawn_cb, spawn_cb_arg);
+
+ /* Run child. */
+ my_exec (pgmname, argv, &sca);
+ /*NOTREACHED*/
}
- else
+
+ xfree (argv);
+ process->pid = pid;
+
+ if (fd_in[0] >= 0 && fd_in[0] != 0)
+ close (fd_in[0]);
+ if (fd_out[1] >= 0 && fd_out[1] != 1)
+ close (fd_out[1]);
+ if (fd_err[1] >= 0 && fd_err[1] != 2)
+ close (fd_err[1]);
+ process->fd_in = fd_in[1];
+ process->fd_out = fd_out[0];
+ process->fd_err = fd_err[0];
+ process->wstatus = -1;
+ process->terminated = 0;
+
+ if (r_process == NULL)
{
- if (r_exitcode)
- *r_exitcode = 0;
- ec = 0;
+ ec = gnupg_process_wait (process, 1);
+ gnupg_process_release (process);
+ return ec;
}
- return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+ *r_process = process;
+ return 0;
}
-/* See exechelp.h for a description. */
-gpg_error_t
-gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
- int hang, int *r_exitcodes)
+static gpg_err_code_t
+process_kill (gnupg_process_t process, int sig)
{
gpg_err_code_t ec = 0;
- size_t i, left;
- int *dummy = NULL;
+ pid_t pid = process->pid;
- if (r_exitcodes == NULL)
+ pre_syscall ();
+ if (kill (pid, sig) < 0)
+ ec = gpg_err_code_from_syserror ();
+ post_syscall ();
+ return ec;
+}
+
+gpg_err_code_t
+gnupg_process_terminate (gnupg_process_t process)
+{
+ return process_kill (process, SIGTERM);
+}
+
+gpg_err_code_t
+gnupg_process_get_fds (gnupg_process_t process, unsigned int flags,
+ int *r_fd_in, int *r_fd_out, int *r_fd_err)
+{
+ (void)flags;
+ if (r_fd_in)
{
- dummy = r_exitcodes = xtrymalloc (sizeof *r_exitcodes * count);
- if (dummy == NULL)
- return gpg_err_code_from_syserror ();
+ *r_fd_in = process->fd_in;
+ process->fd_in = -1;
}
-
- for (i = 0, left = count; i < count; i++)
+ if (r_fd_out)
{
- int status = -1;
+ *r_fd_out = process->fd_out;
+ process->fd_out = -1;
+ }
+ if (r_fd_err)
+ {
+ *r_fd_err = process->fd_err;
+ process->fd_err = -1;
+ }
- /* Skip invalid PID. */
- if (pids[i] == (pid_t)(-1))
- {
- r_exitcodes[i] = -1;
- left -= 1;
- continue;
- }
+ return 0;
+}
- /* See if there was a previously stored result for this pid. */
- if (get_result (pids[i], &status))
- left -= 1;
+gpg_err_code_t
+gnupg_process_get_streams (gnupg_process_t process, unsigned int flags,
+ gpgrt_stream_t *r_fp_in, gpgrt_stream_t *r_fp_out,
+ gpgrt_stream_t *r_fp_err)
+{
+ int nonblock = (flags & GNUPG_PROCESS_STREAM_NONBLOCK)? 1: 0;
- r_exitcodes[i] = status;
+ if (r_fp_in)
+ {
+ *r_fp_in = es_fdopen (process->fd_in, nonblock? "w,nonblock" : "w");
+ process->fd_in = -1;
+ }
+ if (r_fp_out)
+ {
+ *r_fp_out = es_fdopen (process->fd_out, nonblock? "r,nonblock" : "r");
+ process->fd_out = -1;
+ }
+ if (r_fp_err)
+ {
+ *r_fp_err = es_fdopen (process->fd_err, nonblock? "r,nonblock" : "r");
+ process->fd_err = -1;
}
+ return 0;
+}
- while (left > 0)
+static gpg_err_code_t
+process_vctl (gnupg_process_t process, unsigned int request, va_list arg_ptr)
+{
+ switch (request)
{
- pid_t pid;
- int status;
+ case GNUPG_PROCESS_NOP:
+ return 0;
-#ifdef USE_NPTH
- pid = npth_waitpid (-1, &status, hang ? 0 : WNOHANG);
-#else
- while ((pid = waitpid (-1, &status, hang ? 0 : WNOHANG)) == (pid_t)(-1)
- && errno == EINTR);
-#endif
+ case GNUPG_PROCESS_GET_PROC_ID:
+ {
+ int *r_id = va_arg (arg_ptr, int *);
- if (pid == (pid_t)(-1))
- {
- ec = gpg_err_code_from_errno (errno);
- log_error (_("waiting for processes to terminate failed: %s\n"),
- strerror (errno));
- break;
- }
- else if (!pid)
- {
- ec = GPG_ERR_TIMEOUT; /* Still running. */
- break;
- }
- else
- {
- for (i = 0; i < count; i++)
- if (pid == pids[i])
- break;
+ if (r_id == NULL)
+ return GPG_ERR_INV_VALUE;
- if (i == count)
- {
- /* No match, store this result. */
- ec = store_result (pid, status);
- if (ec)
- break;
- continue;
- }
+ *r_id = (int)process->pid;
+ return 0;
+ }
- /* Process PIDS[i] died. */
- if (r_exitcodes[i] != (pid_t) -1)
- {
- log_error ("PID %d was reused", pid);
- ec = GPG_ERR_GENERAL;
- break;
- }
+ case GNUPG_PROCESS_GET_EXIT_ID:
+ {
+ int status = process->wstatus;
+ int *r_exit_status = va_arg (arg_ptr, int *);
- left -= 1;
- r_exitcodes[i] = status;
- }
- }
+ if (!process->terminated)
+ return GPG_ERR_UNFINISHED;
- for (i = 0; i < count; i++)
- {
- if (r_exitcodes[i] == -1)
- continue;
+ if (WIFEXITED (status))
+ {
+ if (r_exit_status)
+ *r_exit_status = WEXITSTATUS (status);
+ }
+ else
+ *r_exit_status = -1;
- if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127)
- {
- log_error (_("error running '%s': probably not installed\n"),
- pgmnames[i]);
- ec = GPG_ERR_CONFIGURATION;
- }
- else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]))
- {
- if (dummy)
- log_error (_("error running '%s': exit status %d\n"),
- pgmnames[i], WEXITSTATUS (r_exitcodes[i]));
- else
- r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]);
- ec = GPG_ERR_GENERAL;
- }
- else if (!WIFEXITED (r_exitcodes[i]))
- {
- log_error (_("error running '%s': terminated\n"), pgmnames[i]);
- ec = GPG_ERR_GENERAL;
- }
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_PID:
+ {
+ pid_t *r_pid = va_arg (arg_ptr, pid_t *);
+
+ if (r_pid == NULL)
+ return GPG_ERR_INV_VALUE;
+
+ *r_pid = process->pid;
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_WSTATUS:
+ {
+ int status = process->wstatus;
+ int *r_if_exited = va_arg (arg_ptr, int *);
+ int *r_if_signaled = va_arg (arg_ptr, int *);
+ int *r_exit_status = va_arg (arg_ptr, int *);
+ int *r_termsig = va_arg (arg_ptr, int *);
+
+ if (!process->terminated)
+ return GPG_ERR_UNFINISHED;
+
+ if (WIFEXITED (status))
+ {
+ if (r_if_exited)
+ *r_if_exited = 1;
+ if (r_if_signaled)
+ *r_if_signaled = 0;
+ if (r_exit_status)
+ *r_exit_status = WEXITSTATUS (status);
+ if (r_termsig)
+ *r_termsig = 0;
+ }
+ else if (WIFSIGNALED (status))
+ {
+ if (r_if_exited)
+ *r_if_exited = 0;
+ if (r_if_signaled)
+ *r_if_signaled = 1;
+ if (r_exit_status)
+ *r_exit_status = 0;
+ if (r_termsig)
+ *r_termsig = WTERMSIG (status);
+ }
+
+ return 0;
+ }
+
+ case GNUPG_PROCESS_KILL:
+ {
+ int sig = va_arg (arg_ptr, int);
+
+ return process_kill (process, sig);
+ }
+
+ default:
+ break;
}
- xfree (dummy);
- return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+ return GPG_ERR_UNKNOWN_COMMAND;
}
-
-
-void
-gnupg_release_process (pid_t pid)
+gpg_err_code_t
+gnupg_process_ctl (gnupg_process_t process, unsigned int request, ...)
{
- (void)pid;
-}
+ va_list arg_ptr;
+ gpg_err_code_t ec;
+ va_start (arg_ptr, request);
+ ec = process_vctl (process, request, arg_ptr);
+ va_end (arg_ptr);
+ return ec;
+}
-/* Spawn a new process and immediately detach from it. The name of
- the program to exec is PGMNAME and its arguments are in ARGV (the
- programname is automatically passed as first argument).
- Environment strings in ENVP are set. An error is returned if
- pgmname is not executable; to make this work it is necessary to
- provide an absolute file name. All standard file descriptors are
- connected to /dev/null. */
-gpg_error_t
-gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
- const char *envp[] )
+gpg_err_code_t
+gnupg_process_wait (gnupg_process_t process, int hang)
{
gpg_err_code_t ec;
+ int status;
pid_t pid;
- int i;
- if (getuid() != geteuid())
- return my_error (GPG_ERR_BUG);
+ if (process->terminated)
+ /* Already terminated. */
+ return 0;
- if ((ec = gnupg_access (pgmname, X_OK)))
- return gpg_err_make (default_errsource, ec);
+ pre_syscall ();
+ while ((pid = waitpid (process->pid, &status, hang? 0: WNOHANG))
+ == (pid_t)(-1) && errno == EINTR);
+ post_syscall ();
- pid = fork ();
if (pid == (pid_t)(-1))
{
- log_error (_("error forking process: %s\n"), strerror (errno));
- return my_error_from_syserror ();
+ ec = gpg_err_code_from_syserror ();
+ log_error (_("waiting for process %d to terminate failed: %s\n"),
+ (int)pid, gpg_strerror (ec));
}
- if (!pid)
+ else if (!pid)
{
- pid_t pid2;
-
- gcry_control (GCRYCTL_TERM_SECMEM);
- if (setsid() == -1 || chdir ("/"))
- _exit (1);
-
- pid2 = fork (); /* Double fork to let init take over the new child. */
- if (pid2 == (pid_t)(-1))
- _exit (1);
- if (pid2)
- _exit (0); /* Let the parent exit immediately. */
+ ec = GPG_ERR_TIMEOUT; /* Still running. */
+ }
+ else
+ {
+ process->terminated = 1;
+ process->wstatus = status;
+ ec = 0;
+ }
- if (envp)
- for (i=0; envp[i]; i++)
- putenv (xstrdup (envp[i]));
+ return ec;
+}
- do_exec (pgmname, argv, -1, -1, -1, NULL, 0);
+void
+gnupg_process_release (gnupg_process_t process)
+{
+ if (!process)
+ return;
- /*NOTREACHED*/
+ if (process->terminated)
+ {
+ gnupg_process_terminate (process);
+ gnupg_process_wait (process, 1);
}
- if (waitpid (pid, NULL, 0) == -1)
- log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
- strerror (errno));
-
- return 0;
+ xfree (process);
}
-
-/* Kill a process; that is send an appropriate signal to the process.
- gnupg_wait_process must be called to actually remove the process
- from the system. An invalid PID is ignored. */
-void
-gnupg_kill_process (pid_t pid)
+gpg_err_code_t
+gnupg_process_wait_list (gnupg_process_t *process_list, int count, int hang)
{
- if (pid != (pid_t)(-1))
+ gpg_err_code_t ec = 0;
+ int i;
+
+ for (i = 0; i < count; i++)
{
- kill (pid, SIGTERM);
+ if (process_list[i]->terminated)
+ continue;
+
+ ec = gnupg_process_wait (process_list[i], hang);
+ if (ec)
+ break;
}
+
+ return ec;
}
diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c
index 2093f0d8b..08290e442 100644
--- a/common/exechelp-w32.c
+++ b/common/exechelp-w32.c
@@ -33,6 +33,8 @@
#if !defined(HAVE_W32_SYSTEM)
#error This code is only used on W32.
+#else
+#define _WIN32_WINNT 0x600
#endif
#include <stdio.h>
@@ -63,9 +65,11 @@
#include "util.h"
#include "i18n.h"
#include "sysutils.h"
+#define NEED_STRUCT_SPAWN_CB_ARG
#include "exechelp.h"
#include <windows.h>
+#include <processthreadsapi.h>
/* Define to 1 do enable debugging. */
#define DEBUG_W32_SPAWN 0
@@ -405,143 +409,147 @@ gnupg_close_pipe (int fd)
if (fd != -1)
close (fd);
}
+
+struct gnupg_process {
+ const char *pgmname;
+ unsigned int terminated :1; /* or detached */
+ unsigned int flags;
+ HANDLE hProcess;
+ HANDLE hd_in;
+ HANDLE hd_out;
+ HANDLE hd_err;
+ int exitcode;
+};
+
+static int gnupg_process_syscall_func_initialized;
+
+/* Functions called before and after blocking syscalls. */
+static void (*pre_syscall_func) (void);
+static void (*post_syscall_func) (void);
+
+static void
+check_syscall_func (void)
+{
+ if (!gnupg_process_syscall_func_initialized)
+ {
+ gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
+ gnupg_process_syscall_func_initialized = 1;
+ }
+}
-/* Fork and exec the PGMNAME, see exechelp.h for details. */
-gpg_error_t
-gnupg_spawn_process (const char *pgmname, const char *argv[],
- int *except, unsigned int flags,
- estream_t *r_infp,
- estream_t *r_outfp,
- estream_t *r_errfp,
- pid_t *pid)
+static void
+pre_syscall (void)
{
- gpg_error_t err;
- SECURITY_ATTRIBUTES sec_attr;
- PROCESS_INFORMATION pi =
- {
- NULL, /* Returns process handle. */
- 0, /* Returns primary thread handle. */
- 0, /* Returns pid. */
- 0 /* Returns tid. */
- };
- STARTUPINFOW si;
- int cr_flags;
- char *cmdline;
- wchar_t *wcmdline = NULL;
- wchar_t *wpgmname = NULL;
- HANDLE inpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
- HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
- HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
- estream_t infp = NULL;
- estream_t outfp = NULL;
- estream_t errfp = NULL;
- HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
- INVALID_HANDLE_VALUE,
- INVALID_HANDLE_VALUE};
- int i, rc;
- es_syshd_t syshd;
- gpg_err_source_t errsource = default_errsource;
- int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
+ if (pre_syscall_func)
+ pre_syscall_func ();
+}
+
- (void)except; /* Not yet used. */
+static void
+post_syscall (void)
+{
+ if (post_syscall_func)
+ post_syscall_func ();
+}
- if (r_infp)
- *r_infp = NULL;
- if (r_outfp)
- *r_outfp = NULL;
- if (r_errfp)
- *r_errfp = NULL;
- *pid = (pid_t)(-1); /* Always required. */
- if (r_infp)
+/*
+ * Check if STARTUPINFOEXW supports PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
+ */
+static int
+check_windows_version (void)
+{
+ static int is_vista_or_later = -1;
+
+ OSVERSIONINFO osvi;
+
+ if (is_vista_or_later == -1)
{
- if (create_inheritable_pipe (inpipe, INHERIT_READ))
- {
- err = gpg_err_make (errsource, GPG_ERR_GENERAL);
- log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
- return err;
- }
+ memset (&osvi,0,sizeof(osvi));
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ GetVersionEx (&osvi);
- syshd.type = ES_SYSHD_HANDLE;
- syshd.u.handle = inpipe[1];
- infp = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
- if (!infp)
- {
- err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
- log_error (_("error creating a stream for a pipe: %s\n"),
- gpg_strerror (err));
- CloseHandle (inpipe[0]);
- CloseHandle (inpipe[1]);
- inpipe[0] = inpipe[1] = INVALID_HANDLE_VALUE;
- return err;
- }
+ /* The feature is available on Vista or later. */
+ is_vista_or_later = (osvi.dwMajorVersion >= 6);
}
- if (r_outfp)
- {
- if (create_inheritable_pipe (outpipe, INHERIT_WRITE))
- {
- err = gpg_err_make (errsource, GPG_ERR_GENERAL);
- log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
- return err;
- }
+ return is_vista_or_later;
+}
- syshd.type = ES_SYSHD_HANDLE;
- syshd.u.handle = outpipe[0];
- outfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
- if (!outfp)
- {
- err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
- log_error (_("error creating a stream for a pipe: %s\n"),
- gpg_strerror (err));
- CloseHandle (outpipe[0]);
- CloseHandle (outpipe[1]);
- outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[1]);
- if (inpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[0]);
- return err;
- }
+
+static gpg_err_code_t
+spawn_detached (const char *pgmname, char *cmdline,
+ void (*spawn_cb) (struct spawn_cb_arg *), void *spawn_cb_arg)
+{
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
+ STARTUPINFOEXW si;
+ int cr_flags;
+ wchar_t *wcmdline = NULL;
+ wchar_t *wpgmname = NULL;
+ gpg_err_code_t ec;
+ int ret;
+ struct spawn_cb_arg sca;
+ BOOL ask_inherit = FALSE;
+
+ ec = gnupg_access (pgmname, X_OK);
+ if (ec)
+ {
+ xfree (cmdline);
+ return ec;
}
- if (r_errfp)
+ memset (&si, 0, sizeof si);
+
+ sca.allow_foreground_window = FALSE;
+ sca.hd[0] = INVALID_HANDLE_VALUE;
+ sca.hd[1] = INVALID_HANDLE_VALUE;
+ sca.hd[2] = INVALID_HANDLE_VALUE;
+ sca.inherit_hds = NULL;
+ sca.arg = spawn_cb_arg;
+ if (spawn_cb)
+ (*spawn_cb) (&sca);
+
+ if (sca.inherit_hds)
{
- if (create_inheritable_pipe (errpipe, INHERIT_WRITE))
- {
- err = gpg_err_make (errsource, GPG_ERR_GENERAL);
- log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
- return err;
- }
+ SIZE_T attr_list_size = 0;
+ HANDLE hd[16];
+ HANDLE *hd_p = sca.inherit_hds;
+ int j = 0;
- syshd.type = ES_SYSHD_HANDLE;
- syshd.u.handle = errpipe[0];
- errfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
- if (!errfp)
+ if (hd_p)
{
- err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
- log_error (_("error creating a stream for a pipe: %s\n"),
- gpg_strerror (err));
- CloseHandle (errpipe[0]);
- CloseHandle (errpipe[1]);
- errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
- if (outfp)
- es_fclose (outfp);
- else if (outpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[0]);
- if (outpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[1]);
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[1]);
- if (inpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[0]);
- return err;
+ while (*hd_p != INVALID_HANDLE_VALUE)
+ if (j < DIM (hd))
+ hd[j++] = *hd_p++;
+ else
+ {
+ log_error ("Too much handles\n");
+ break;
+ }
}
+
+ if (j)
+ {
+ if (check_windows_version ())
+ {
+ InitializeProcThreadAttributeList (NULL, 1, 0, &attr_list_size);
+ si.lpAttributeList = xtrymalloc (attr_list_size);
+ if (si.lpAttributeList == NULL)
+ {
+ xfree (cmdline);
+ return gpg_err_code_from_syserror ();
+ }
+ InitializeProcThreadAttributeList (si.lpAttributeList, 1, 0,
+ &attr_list_size);
+ UpdateProcThreadAttribute (si.lpAttributeList, 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ hd, sizeof (HANDLE) * j, NULL, NULL);
+ }
+
+ ask_inherit = TRUE;
+ }
}
/* Prepare security attributes. */
@@ -549,502 +557,683 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = FALSE;
- /* Build the command line. */
- err = build_w32_commandline (pgmname, argv, &cmdline);
- if (err)
- return err;
-
- if (inpipe[0] == INVALID_HANDLE_VALUE)
- nullhd[0] = ((flags & GNUPG_SPAWN_KEEP_STDIN)?
- GetStdHandle (STD_INPUT_HANDLE) : w32_open_null (0));
- if (outpipe[1] == INVALID_HANDLE_VALUE)
- nullhd[1] = ((flags & GNUPG_SPAWN_KEEP_STDOUT)?
- GetStdHandle (STD_OUTPUT_HANDLE) : w32_open_null (1));
- if (errpipe[1] == INVALID_HANDLE_VALUE)
- nullhd[2] = ((flags & GNUPG_SPAWN_KEEP_STDERR)?
- GetStdHandle (STD_ERROR_HANDLE) : w32_open_null (1));
-
- memset (&si, 0, sizeof si);
- si.cb = sizeof (si);
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_HIDE;
- si.hStdInput = inpipe[0] == INVALID_HANDLE_VALUE? nullhd[0] : inpipe[0];
- si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
- si.hStdError = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
+ /* Start the process. */
+ si.StartupInfo.cb = sizeof (si);
+ si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
+ si.StartupInfo.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
cr_flags = (CREATE_DEFAULT_ERROR_MODE
- | ((flags & GNUPG_SPAWN_DETACHED)? DETACHED_PROCESS : 0)
| GetPriorityClass (GetCurrentProcess ())
- | CREATE_SUSPENDED);
- /* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", */
- /* pgmname, cmdline); */
+ | CREATE_NEW_PROCESS_GROUP
+ | DETACHED_PROCESS);
+
/* Take care: CreateProcessW may modify wpgmname */
if (!(wpgmname = utf8_to_wchar (pgmname)))
- rc = 0;
+ ret = 0;
else if (!(wcmdline = utf8_to_wchar (cmdline)))
- rc = 0;
+ ret = 0;
else
- rc = CreateProcessW (wpgmname, /* Program to start. */
- wcmdline, /* Command line arguments. */
- &sec_attr, /* Process security attributes. */
- &sec_attr, /* Thread security attributes. */
- TRUE, /* Inherit handles. */
- cr_flags, /* Creation flags. */
- NULL, /* Environment. */
- NULL, /* Use current drive/directory. */
- &si, /* Startup information. */
- &pi /* Returns process information. */
- );
- if (!rc)
+ ret = CreateProcessW (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ ask_inherit, /* Inherit handles. */
+ cr_flags, /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ (STARTUPINFOW *)&si, /* Startup information. */
+ &pi /* Returns process information. */
+ );
+ if (!ret)
{
if (!wpgmname || !wcmdline)
log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
strerror (errno));
else
- log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
+ log_error ("CreateProcess(detached) failed: %d\n",
+ (int)GetLastError ());
xfree (wpgmname);
xfree (wcmdline);
xfree (cmdline);
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[1]);
- if (inpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[0]);
- if (outfp)
- es_fclose (outfp);
- else if (outpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[0]);
- if (outpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[1]);
- if (errfp)
- es_fclose (errfp);
- else if (errpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (errpipe[0]);
- if (errpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (errpipe[1]);
- return gpg_err_make (errsource, GPG_ERR_GENERAL);
+ return GPG_ERR_GENERAL;
}
+ if (si.lpAttributeList)
+ DeleteProcThreadAttributeList (si.lpAttributeList);
xfree (wpgmname);
xfree (wcmdline);
xfree (cmdline);
- cmdline = NULL;
- /* Close the inherited handles to /dev/null. */
- for (i=0; i < DIM (nullhd); i++)
- if (nullhd[i] != INVALID_HANDLE_VALUE)
- CloseHandle (nullhd[i]);
+ /* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
+ /* " dwProcessID=%d dwThreadId=%d\n", */
+ /* pi.hProcess, pi.hThread, */
+ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
- /* Close the inherited ends of the pipes. */
- if (inpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[0]);
- if (outpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[1]);
- if (errpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (errpipe[1]);
-
- /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
- /* " dwProcessID=%d dwThreadId=%d\n", */
- /* pi.hProcess, pi.hThread, */
- /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
- /* log_debug (" outfp=%p errfp=%p\n", outfp, errfp); */
+ /* Note: AllowSetForegroundWindow doesn't make sense for background
+ process. */
- /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
- invalid argument error if we pass it the correct processID. As a
- workaround we use -1 (ASFW_ANY). */
- if ((flags & GNUPG_SPAWN_RUN_ASFW))
- gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
-
- /* Process has been created suspended; resume it now. */
- ResumeThread (pi.hThread);
CloseHandle (pi.hThread);
-
- if (r_infp)
- *r_infp = infp;
- if (r_outfp)
- *r_outfp = outfp;
- if (r_errfp)
- *r_errfp = errfp;
-
- *pid = handle_to_pid (pi.hProcess);
+ CloseHandle (pi.hProcess);
return 0;
-
}
+void
+gnupg_spawn_helper (struct spawn_cb_arg *sca)
+{
+ HANDLE *user_except = sca->arg;
+ sca->inherit_hds = user_except;
+}
-/* Simplified version of gnupg_spawn_process. This function forks and
- then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
- and ERRFD to stderr (any of them may be -1 to connect them to
- /dev/null). The arguments for the process are expected in the NULL
- terminated array ARGV. The program name itself should not be
- included there. Calling gnupg_wait_process is required.
-
- Returns 0 on success or an error code. */
-gpg_error_t
-gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
- int infd, int outfd, int errfd, pid_t *pid)
+gpg_err_code_t
+gnupg_process_spawn (const char *pgmname, const char *argv[],
+ unsigned int flags,
+ void (*spawn_cb) (struct spawn_cb_arg *),
+ void *spawn_cb_arg,
+ gnupg_process_t *r_process)
{
- gpg_error_t err;
+ gpg_err_code_t ec;
+ gnupg_process_t process;
SECURITY_ATTRIBUTES sec_attr;
PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
- STARTUPINFOW si;
+ STARTUPINFOEXW si;
+ int cr_flags;
char *cmdline;
wchar_t *wcmdline = NULL;
wchar_t *wpgmname = NULL;
- int i, rc;
- HANDLE stdhd[3];
+ int ret;
+ HANDLE hd_in[2];
+ HANDLE hd_out[2];
+ HANDLE hd_err[2];
+ struct spawn_cb_arg sca;
+ int i;
+ BOOL ask_inherit = FALSE;
+
+ check_syscall_func ();
+
+ /* Build the command line. */
+ ec = build_w32_commandline (pgmname, argv, &cmdline);
+ if (ec)
+ return ec;
+
+ if ((flags & GNUPG_PROCESS_DETACHED))
+ {
+ if ((flags & GNUPG_PROCESS_STDFDS_SETTING))
+ {
+ xfree (cmdline);
+ return GPG_ERR_INV_FLAG;
+ }
- /* Setup return values. */
- *pid = (pid_t)(-1);
+ /* In detached case, it must be no R_PROCESS. */
+ if (r_process)
+ {
+ xfree (cmdline);
+ return GPG_ERR_INV_ARG;
+ }
+
+ return spawn_detached (pgmname, cmdline, spawn_cb, spawn_cb_arg);
+ }
+
+ if (r_process)
+ *r_process = NULL;
+
+ process = xtrymalloc (sizeof (struct gnupg_process));
+ if (process == NULL)
+ {
+ xfree (cmdline);
+ return gpg_err_code_from_syserror ();
+ }
+
+ process->pgmname = pgmname;
+ process->flags = flags;
+
+ if ((flags & GNUPG_PROCESS_STDINOUT_SOCKETPAIR))
+ {
+ xfree (process);
+ xfree (cmdline);
+ return GPG_ERR_NOT_SUPPORTED;
+ }
+
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE))
+ {
+ ec = create_inheritable_pipe (hd_in, INHERIT_READ);
+ if (ec)
+ {
+ xfree (process);
+ xfree (cmdline);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDIN_KEEP))
+ {
+ hd_in[0] = GetStdHandle (STD_INPUT_HANDLE);
+ hd_in[1] = INVALID_HANDLE_VALUE;
+ }
+ else
+ {
+ hd_in[0] = w32_open_null (0);
+ hd_in[1] = INVALID_HANDLE_VALUE;
+ }
+
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE))
+ {
+ ec = create_inheritable_pipe (hd_out, INHERIT_WRITE);
+ if (ec)
+ {
+ if (hd_in[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_in[0]);
+ if (hd_in[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_in[1]);
+ xfree (process);
+ xfree (cmdline);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDOUT_KEEP))
+ {
+ hd_out[0] = INVALID_HANDLE_VALUE;
+ hd_out[1] = GetStdHandle (STD_OUTPUT_HANDLE);
+ }
+ else
+ {
+ hd_out[0] = INVALID_HANDLE_VALUE;
+ hd_out[1] = w32_open_null (1);
+ }
+
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
+ {
+ ec = create_inheritable_pipe (hd_err, INHERIT_WRITE);
+ if (ec)
+ {
+ if (hd_in[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_in[0]);
+ if (hd_in[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_in[1]);
+ if (hd_out[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_out[0]);
+ if (hd_out[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_out[1]);
+ xfree (process);
+ xfree (cmdline);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDERR_KEEP))
+ {
+ hd_err[0] = INVALID_HANDLE_VALUE;
+ hd_err[1] = GetStdHandle (STD_ERROR_HANDLE);
+ }
+ else
+ {
+ hd_err[0] = INVALID_HANDLE_VALUE;
+ hd_err[1] = w32_open_null (1);
+ }
+
+ memset (&si, 0, sizeof si);
+
+ sca.allow_foreground_window = FALSE;
+ sca.hd[0] = hd_in[0];
+ sca.hd[1] = hd_out[1];
+ sca.hd[2] = hd_err[1];
+ sca.inherit_hds = NULL;
+ sca.arg = spawn_cb_arg;
+ if (spawn_cb)
+ (*spawn_cb) (&sca);
+
+ i = 0;
+ if (sca.hd[0] != INVALID_HANDLE_VALUE)
+ i++;
+ if (sca.hd[1] != INVALID_HANDLE_VALUE)
+ i++;
+ if (sca.hd[2] != INVALID_HANDLE_VALUE)
+ i++;
+
+ if (i != 0 || sca.inherit_hds)
+ {
+ SIZE_T attr_list_size = 0;
+ HANDLE hd[16];
+ HANDLE *hd_p = sca.inherit_hds;
+ int j = 0;
+
+ if (sca.hd[0] != INVALID_HANDLE_VALUE)
+ hd[j++] = sca.hd[0];
+ if (sca.hd[1] != INVALID_HANDLE_VALUE)
+ hd[j++] = sca.hd[1];
+ if (sca.hd[1] != INVALID_HANDLE_VALUE)
+ hd[j++] = sca.hd[2];
+ if (hd_p)
+ {
+ while (*hd_p != INVALID_HANDLE_VALUE)
+ if (j < DIM (hd))
+ hd[j++] = *hd_p++;
+ else
+ {
+ log_error ("Too much handles\n");
+ break;
+ }
+ }
+
+ if (j)
+ {
+ if (check_windows_version ())
+ {
+ InitializeProcThreadAttributeList (NULL, 1, 0, &attr_list_size);
+ si.lpAttributeList = xtrymalloc (attr_list_size);
+ if (si.lpAttributeList == NULL)
+ {
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE)
+ || !(flags & GNUPG_PROCESS_STDIN_KEEP))
+ CloseHandle (hd_in[0]);
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE))
+ CloseHandle (hd_in[1]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE))
+ CloseHandle (hd_out[0]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE)
+ || !(flags & GNUPG_PROCESS_STDOUT_KEEP))
+ CloseHandle (hd_out[1]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
+ CloseHandle (hd_err[0]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE)
+ || !(flags & GNUPG_PROCESS_STDERR_KEEP))
+ CloseHandle (hd_err[1]);
+ xfree (process);
+ xfree (cmdline);
+ return gpg_err_code_from_syserror ();
+ }
+ InitializeProcThreadAttributeList (si.lpAttributeList, 1, 0,
+ &attr_list_size);
+ UpdateProcThreadAttribute (si.lpAttributeList, 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ hd, sizeof (HANDLE) * j, NULL, NULL);
+ }
+ ask_inherit = TRUE;
+ }
+ }
/* Prepare security attributes. */
memset (&sec_attr, 0, sizeof sec_attr );
sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = FALSE;
- /* Build the command line. */
- err = build_w32_commandline (pgmname, argv, &cmdline);
- if (err)
- return err;
-
- memset (&si, 0, sizeof si);
- si.cb = sizeof (si);
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
- stdhd[0] = infd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
- stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
- stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
- si.hStdInput = infd == -1? stdhd[0] : (void*)_get_osfhandle (infd);
- si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
- si.hStdError = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
-
-/* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
- /* Take care: CreateProcessW may modify wpgmname */
+ /* Start the process. */
+ si.StartupInfo.cb = sizeof (si);
+ si.StartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ si.StartupInfo.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_HIDE;
+ si.StartupInfo.hStdInput = sca.hd[0];
+ si.StartupInfo.hStdOutput = sca.hd[1];
+ si.StartupInfo.hStdError = sca.hd[2];
+
+ /* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
+ cr_flags = (CREATE_DEFAULT_ERROR_MODE
+ | GetPriorityClass (GetCurrentProcess ())
+ | CREATE_SUSPENDED);
if (!(wpgmname = utf8_to_wchar (pgmname)))
- rc = 0;
+ ret = 0;
else if (!(wcmdline = utf8_to_wchar (cmdline)))
- rc = 0;
+ ret = 0;
else
- rc = CreateProcessW (wpgmname, /* Program to start. */
- wcmdline, /* Command line arguments. */
- &sec_attr, /* Process security attributes. */
- &sec_attr, /* Thread security attributes. */
- TRUE, /* Inherit handles. */
- (CREATE_DEFAULT_ERROR_MODE
- | GetPriorityClass (GetCurrentProcess ())
- | CREATE_SUSPENDED | DETACHED_PROCESS),
- NULL, /* Environment. */
- NULL, /* Use current drive/directory. */
- &si, /* Startup information. */
- &pi /* Returns process information. */
- );
- if (!rc)
+ ret = CreateProcessW (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ ask_inherit, /* Inherit handles. */
+ cr_flags, /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ (STARTUPINFOW *)&si, /* Startup information. */
+ &pi /* Returns process information. */
+ );
+ if (!ret)
{
if (!wpgmname || !wcmdline)
log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
- strerror (errno));
+ strerror (errno));
else
- log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
- err = my_error (GPG_ERR_GENERAL);
+ log_error ("CreateProcess failed: ec=%d\n",
+ (int)GetLastError ());
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE)
+ || !(flags & GNUPG_PROCESS_STDIN_KEEP))
+ CloseHandle (hd_in[0]);
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE))
+ CloseHandle (hd_in[1]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE))
+ CloseHandle (hd_out[0]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE)
+ || !(flags & GNUPG_PROCESS_STDOUT_KEEP))
+ CloseHandle (hd_out[1]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
+ CloseHandle (hd_err[0]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE)
+ || !(flags & GNUPG_PROCESS_STDERR_KEEP))
+ CloseHandle (hd_err[1]);
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (process);
+ xfree (cmdline);
+ return GPG_ERR_GENERAL;
}
- else
- err = 0;
+
+ if (si.lpAttributeList)
+ DeleteProcThreadAttributeList (si.lpAttributeList);
xfree (wpgmname);
xfree (wcmdline);
xfree (cmdline);
- for (i=0; i < 3; i++)
- if (stdhd[i] != INVALID_HANDLE_VALUE)
- CloseHandle (stdhd[i]);
- if (err)
- return err;
-/* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
-/* " dwProcessID=%d dwThreadId=%d\n", */
-/* pi.hProcess, pi.hThread, */
-/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE)
+ || !(flags & GNUPG_PROCESS_STDIN_KEEP))
+ CloseHandle (hd_in[0]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE)
+ || !(flags & GNUPG_PROCESS_STDOUT_KEEP))
+ CloseHandle (hd_out[1]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE)
+ || !(flags & GNUPG_PROCESS_STDERR_KEEP))
+ CloseHandle (hd_err[1]);
+
+ /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
+ /* " dwProcessID=%d dwThreadId=%d\n", */
+ /* pi.hProcess, pi.hThread, */
+ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+
+ if (sca.allow_foreground_window)
+ {
+ /* Fixme: For unknown reasons AllowSetForegroundWindow returns
+ * an invalid argument error if we pass it the correct
+ * processID. As a workaround we use -1 (ASFW_ANY). */
+ if (!AllowSetForegroundWindow (ASFW_ANY /*pi.dwProcessId*/))
+ log_info ("AllowSetForegroundWindow() failed: ec=%d\n",
+ (int)GetLastError ());
+ }
/* Process has been created suspended; resume it now. */
+ pre_syscall ();
ResumeThread (pi.hThread);
CloseHandle (pi.hThread);
+ post_syscall ();
- *pid = handle_to_pid (pi.hProcess);
- return 0;
+ process->hProcess = pi.hProcess;
+ process->hd_in = hd_in[1];
+ process->hd_out = hd_out[0];
+ process->hd_err = hd_err[0];
+ process->exitcode = -1;
+ process->terminated = 0;
+ if (r_process == NULL)
+ {
+ ec = gnupg_process_wait (process, 1);
+ gnupg_process_release (process);
+ return ec;
+ }
+
+ *r_process = process;
+ return 0;
}
+gpg_err_code_t
+gnupg_process_get_fds (gnupg_process_t process, unsigned int flags,
+ int *r_fd_in, int *r_fd_out, int *r_fd_err)
+{
+ (void)flags;
+ if (r_fd_in)
+ {
+ *r_fd_in = _open_osfhandle ((intptr_t)process->hd_in, O_APPEND);
+ process->hd_in = INVALID_HANDLE_VALUE;
+ }
+ if (r_fd_out)
+ {
+ *r_fd_out = _open_osfhandle ((intptr_t)process->hd_out, O_RDONLY);
+ process->hd_out = INVALID_HANDLE_VALUE;
+ }
+ if (r_fd_err)
+ {
+ *r_fd_err = _open_osfhandle ((intptr_t)process->hd_err, O_RDONLY);
+ process->hd_err = INVALID_HANDLE_VALUE;
+ }
+
+ return 0;
+}
-/* See exechelp.h for a description. */
-gpg_error_t
-gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
+gpg_err_code_t
+gnupg_process_get_streams (gnupg_process_t process, unsigned int flags,
+ estream_t *r_fp_in, estream_t *r_fp_out,
+ estream_t *r_fp_err)
{
- return gnupg_wait_processes (&pgmname, &pid, 1, hang, r_exitcode);
+ int nonblock = (flags & GNUPG_PROCESS_STREAM_NONBLOCK)? 1: 0;
+ es_syshd_t syshd;
+
+ syshd.type = ES_SYSHD_HANDLE;
+ if (r_fp_in)
+ {
+ syshd.u.handle = process->hd_in;
+ *r_fp_in = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
+ process->hd_in = INVALID_HANDLE_VALUE;
+ }
+ if (r_fp_out)
+ {
+ syshd.u.handle = process->hd_out;
+ *r_fp_out = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
+ process->hd_out = INVALID_HANDLE_VALUE;
+ }
+ if (r_fp_err)
+ {
+ syshd.u.handle = process->hd_err;
+ *r_fp_err = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
+ process->hd_err = INVALID_HANDLE_VALUE;
+ }
+ return 0;
}
-/* See exechelp.h for a description. */
-gpg_error_t
-gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
- int hang, int *r_exitcodes)
+static gpg_err_code_t
+process_kill (gnupg_process_t process, unsigned int exitcode)
{
gpg_err_code_t ec = 0;
- size_t i;
- HANDLE *procs;
- int code;
- procs = xtrycalloc (count, sizeof *procs);
- if (procs == NULL)
- return my_error_from_syserror ();
+ pre_syscall ();
+ if (TerminateProcess (process->hProcess, exitcode))
+ ec = gpg_err_code_from_syserror ();
+ post_syscall ();
+ return ec;
+}
- for (i = 0; i < count; i++)
+static gpg_err_code_t
+process_vctl (gnupg_process_t process, unsigned int request, va_list arg_ptr)
+{
+ switch (request)
{
- if (r_exitcodes)
- r_exitcodes[i] = -1;
+ case GNUPG_PROCESS_NOP:
+ return 0;
- if (pids[i] == (pid_t)(-1))
- return my_error (GPG_ERR_INV_VALUE);
+ case GNUPG_PROCESS_GET_PROC_ID:
+ {
+ int *r_id = va_arg (arg_ptr, int *);
- procs[i] = pid_to_handle (pids[i]);
- }
+ if (r_id == NULL)
+ return GPG_ERR_INV_VALUE;
- /* FIXME: We should do a pth_waitpid here. However this has not yet
- been implemented. A special W32 pth system call would even be
- better. */
- code = WaitForMultipleObjects (count, procs, TRUE, hang? INFINITE : 0);
- switch (code)
- {
- case WAIT_TIMEOUT:
- ec = GPG_ERR_TIMEOUT;
- goto leave;
+ *r_id = (int)GetProcessId (process->hProcess);
+ return 0;
+ }
- case WAIT_FAILED:
- log_error (_("waiting for processes to terminate failed: %s\n"),
- w32_strerror (-1));
- ec = GPG_ERR_GENERAL;
- goto leave;
+ case GNUPG_PROCESS_GET_EXIT_ID:
+ {
+ int *r_exit_status = va_arg (arg_ptr, int *);
+ unsigned long exit_code;
- case WAIT_OBJECT_0:
- for (i = 0; i < count; i++)
- {
- DWORD exc;
+ *r_exit_status = -1;
- if (! GetExitCodeProcess (procs[i], &exc))
- {
- log_error (_("error getting exit code of process %d: %s\n"),
- (int) pids[i], w32_strerror (-1) );
- ec = GPG_ERR_GENERAL;
- }
- else if (exc)
- {
- if (!r_exitcodes)
- log_error (_("error running '%s': exit status %d\n"),
- pgmnames[i], (int)exc);
- else
- r_exitcodes[i] = (int)exc;
- ec = GPG_ERR_GENERAL;
- }
- else
- {
- if (r_exitcodes)
- r_exitcodes[i] = 0;
- }
- }
- break;
+ if (!process->terminated)
+ return GPG_ERR_UNFINISHED;
+
+ if (process->hProcess == INVALID_HANDLE_VALUE)
+ return 0;
+
+ if (GetExitCodeProcess (process->hProcess, &exit_code) == 0)
+ return gpg_err_code_from_syserror ();
+
+ *r_exit_status = (int)exit_code;
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_P_HANDLE:
+ {
+ HANDLE *r_hProcess = va_arg (arg_ptr, HANDLE *);
+
+ if (r_hProcess == NULL)
+ return GPG_ERR_INV_VALUE;
+
+ *r_hProcess = process->hProcess;
+ process->hProcess = INVALID_HANDLE_VALUE;
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_HANDLES:
+ {
+ HANDLE *r_hd_in = va_arg (arg_ptr, HANDLE *);
+ HANDLE *r_hd_out = va_arg (arg_ptr, HANDLE *);
+ HANDLE *r_hd_err = va_arg (arg_ptr, HANDLE *);
+
+ if (r_hd_in)
+ {
+ *r_hd_in = process->hd_in;
+ process->hd_in = INVALID_HANDLE_VALUE;
+ }
+ if (r_hd_out)
+ {
+ *r_hd_out = process->hd_out;
+ process->hd_out = INVALID_HANDLE_VALUE;
+ }
+ if (r_hd_err)
+ {
+ *r_hd_err = process->hd_err;
+ process->hd_err = INVALID_HANDLE_VALUE;
+ }
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_EXIT_CODE:
+ {
+ unsigned long *r_exitcode = va_arg (arg_ptr, unsigned long *);
+
+ if (!process->terminated)
+ return GPG_ERR_UNFINISHED;
+
+ if (process->hProcess == INVALID_HANDLE_VALUE)
+ {
+ *r_exitcode = (unsigned long)-1;
+ return 0;
+ }
+
+ if (GetExitCodeProcess (process->hProcess, r_exitcode) == 0)
+ return gpg_err_code_from_syserror ();
+ return 0;
+ }
+
+ case GNUPG_PROCESS_KILL_WITH_EC:
+ {
+ unsigned int exitcode = va_arg (arg_ptr, unsigned int);
+
+ if (process->terminated)
+ return 0;
+
+ if (process->hProcess == INVALID_HANDLE_VALUE)
+ return 0;
+
+ return process_kill (process, exitcode);
+ }
default:
- log_error ("WaitForMultipleObjects returned unexpected "
- "code %d\n", code);
- ec = GPG_ERR_GENERAL;
break;
}
- leave:
- return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+ return GPG_ERR_UNKNOWN_COMMAND;
}
-
-
-void
-gnupg_release_process (pid_t pid)
+gpg_err_code_t
+gnupg_process_ctl (gnupg_process_t process, unsigned int request, ...)
{
- if (pid != (pid_t)INVALID_HANDLE_VALUE)
- {
- HANDLE process = (HANDLE)pid;
+ va_list arg_ptr;
+ gpg_err_code_t ec;
- CloseHandle (process);
- }
+ va_start (arg_ptr, request);
+ ec = process_vctl (process, request, arg_ptr);
+ va_end (arg_ptr);
+ return ec;
}
-
-/* Spawn a new process and immediately detach from it. The name of
- the program to exec is PGMNAME and its arguments are in ARGV (the
- programname is automatically passed as first argument).
- Environment strings in ENVP are set. An error is returned if
- pgmname is not executable; to make this work it is necessary to
- provide an absolute file name. All standard file descriptors are
- connected to /dev/null. */
-gpg_error_t
-gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
- const char *envp[] )
+gpg_err_code_t
+gnupg_process_wait (gnupg_process_t process, int hang)
{
- gpg_error_t err;
- SECURITY_ATTRIBUTES sec_attr;
- PROCESS_INFORMATION pi =
- {
- NULL, /* Returns process handle. */
- 0, /* Returns primary thread handle. */
- 0, /* Returns pid. */
- 0 /* Returns tid. */
- };
- STARTUPINFOW si;
- int cr_flags;
- char *cmdline;
- wchar_t *wcmdline = NULL;
- wchar_t *wpgmname = NULL;
- BOOL in_job = FALSE;
gpg_err_code_t ec;
- int rc;
- int jobdebug;
+ int code;
- /* We don't use ENVP. */
- (void)envp;
+ if (process->hProcess == INVALID_HANDLE_VALUE)
+ return 0;
- cmdline = getenv ("GNUPG_EXEC_DEBUG_FLAGS");
- jobdebug = (cmdline && (atoi (cmdline) & 1));
+ pre_syscall ();
+ code = WaitForSingleObject (process->hProcess, hang? INFINITE : 0);
+ post_syscall ();
- if ((ec = gnupg_access (pgmname, X_OK)))
- return gpg_err_make (default_errsource, ec);
+ switch (code)
+ {
+ case WAIT_TIMEOUT:
+ ec = GPG_ERR_TIMEOUT; /* Still running. */
+ break;
- /* Prepare security attributes. */
- memset (&sec_attr, 0, sizeof sec_attr );
- sec_attr.nLength = sizeof sec_attr;
- sec_attr.bInheritHandle = FALSE;
+ case WAIT_FAILED:
+ log_error (_("waiting for process to terminate failed: ec=%d\n"),
+ (int)GetLastError ());
+ ec = GPG_ERR_GENERAL;
+ break;
- /* Build the command line. */
- err = build_w32_commandline (pgmname, argv, &cmdline);
- if (err)
- return err;
+ case WAIT_OBJECT_0:
+ process->terminated = 1;
+ ec = 0;
+ break;
- /* Start the process. */
- memset (&si, 0, sizeof si);
- si.cb = sizeof (si);
- si.dwFlags = STARTF_USESHOWWINDOW;
- si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
+ default:
+ log_debug ("WaitForSingleObject returned unexpected code %d\n", code);
+ ec = GPG_ERR_GENERAL;
+ break;
+ }
- cr_flags = (CREATE_DEFAULT_ERROR_MODE
- | GetPriorityClass (GetCurrentProcess ())
- | CREATE_NEW_PROCESS_GROUP
- | DETACHED_PROCESS);
+ return ec;
+}
- /* Check if we were spawned as part of a Job.
- * In a job we need to add CREATE_BREAKAWAY_FROM_JOB
- * to the cr_flags, otherwise our child processes
- * are killed when we terminate. */
- if (!IsProcessInJob (GetCurrentProcess(), NULL, &in_job))
- {
- log_error ("IsProcessInJob() failed: %s\n", w32_strerror (-1));
- in_job = FALSE;
- }
+gpg_err_code_t
+gnupg_process_terminate (gnupg_process_t process)
+{
+ return process_kill (process, 1);
+}
- if (in_job)
- {
- /* Only try to break away from job if it is allowed, otherwise
- * CreateProcess() would fail with an "Access is denied" error. */
- JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
- if (!QueryInformationJobObject (NULL, JobObjectExtendedLimitInformation,
- &info, sizeof info, NULL))
- {
- log_error ("QueryInformationJobObject() failed: %s\n",
- w32_strerror (-1));
- }
- else if ((info.BasicLimitInformation.LimitFlags &
- JOB_OBJECT_LIMIT_BREAKAWAY_OK))
- {
- if (jobdebug)
- log_debug ("Using CREATE_BREAKAWAY_FROM_JOB flag\n");
- cr_flags |= CREATE_BREAKAWAY_FROM_JOB;
- }
- else if ((info.BasicLimitInformation.LimitFlags &
- JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))
- {
- /* The child process should automatically detach from the job. */
- if (jobdebug)
- log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag; "
- "JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK is set\n");
- }
- else
- {
- /* It seems that the child process must remain in the job.
- * This is not necessarily an error, although it can cause premature
- * termination of the child process when the job is closed. */
- if (jobdebug)
- log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag\n");
- }
- }
- else
- {
- if (jobdebug)
- log_debug ("Process is not in a Job\n");
- }
+void
+gnupg_process_release (gnupg_process_t process)
+{
+ if (!process)
+ return;
- /* log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */
- /* pgmname, cmdline); */
- /* Take care: CreateProcessW may modify wpgmname */
- if (!(wpgmname = utf8_to_wchar (pgmname)))
- rc = 0;
- else if (!(wcmdline = utf8_to_wchar (cmdline)))
- rc = 0;
- else
- rc = CreateProcessW (wpgmname, /* Program to start. */
- wcmdline, /* Command line arguments. */
- &sec_attr, /* Process security attributes. */
- &sec_attr, /* Thread security attributes. */
- FALSE, /* Inherit handles. */
- cr_flags, /* Creation flags. */
- NULL, /* Environment. */
- NULL, /* Use current drive/directory. */
- &si, /* Startup information. */
- &pi /* Returns process information. */
- );
- if (!rc)
+ if (process->terminated)
{
- if (!wpgmname || !wcmdline)
- log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
- strerror (errno));
- else
- log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
- xfree (wpgmname);
- xfree (wcmdline);
- xfree (cmdline);
- return my_error (GPG_ERR_GENERAL);
+ gnupg_process_terminate (process);
+ gnupg_process_wait (process, 1);
}
- xfree (wpgmname);
- xfree (wcmdline);
- xfree (cmdline);
- cmdline = NULL;
-
-/* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
-/* " dwProcessID=%d dwThreadId=%d\n", */
-/* pi.hProcess, pi.hThread, */
-/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
- CloseHandle (pi.hThread);
- CloseHandle (pi.hProcess);
-
- return 0;
+ CloseHandle (process->hProcess);
+ xfree (process);
}
-
-/* Kill a process; that is send an appropriate signal to the process.
- gnupg_wait_process must be called to actually remove the process
- from the system. An invalid PID is ignored. */
-void
-gnupg_kill_process (pid_t pid)
+gpg_err_code_t
+gnupg_process_wait_list (gnupg_process_t *process_list, int count, int hang)
{
- if (pid != (pid_t) INVALID_HANDLE_VALUE)
+ gpg_err_code_t ec = 0;
+ int i;
+
+ for (i = 0; i < count; i++)
{
- HANDLE process = (HANDLE) pid;
+ if (process_list[i]->terminated)
+ continue;
- /* Arbitrary error code. */
- TerminateProcess (process, 1);
+ ec = gnupg_process_wait (process_list[i], hang);
+ if (ec)
+ break;
}
+
+ return ec;
}
diff --git a/common/exechelp.h b/common/exechelp.h
index 3343fe598..0370b23a4 100644
--- a/common/exechelp.h
+++ b/common/exechelp.h
@@ -73,140 +73,103 @@ gpg_error_t gnupg_create_pipe (int filedes[2]);
void gnupg_close_pipe (int fd);
-#define GNUPG_SPAWN_NONBLOCK 16
-#define GNUPG_SPAWN_RUN_ASFW 64
-#define GNUPG_SPAWN_DETACHED 128
-#define GNUPG_SPAWN_KEEP_STDIN 256
-#define GNUPG_SPAWN_KEEP_STDOUT 512
-#define GNUPG_SPAWN_KEEP_STDERR 1024
-
-/* Fork and exec the program PGMNAME.
-
- If R_INFP is NULL connect stdin of the new process to /dev/null; if
- it is not NULL store the address of a pointer to a new estream
- there. If R_OUTFP is NULL connect stdout of the new process to
- /dev/null; if it is not NULL store the address of a pointer to a
- new estream there. If R_ERRFP is NULL connect stderr of the new
- process to /dev/null; if it is not NULL store the address of a
- pointer to a new estream there. On success the pid of the new
- process is stored at PID. On error -1 is stored at PID and if
- R_OUTFP or R_ERRFP are not NULL, NULL is stored there.
-
- The arguments for the process are expected in the NULL terminated
- array ARGV. The program name itself should not be included there.
- If PREEXEC is not NULL, the given function will be called right
- before the exec.
-
- IF EXCEPT is not NULL, it is expected to be an ordered list of file
- descriptors, terminated by an entry with the value (-1). These
- file descriptors won't be closed before spawning a new program.
-
- Returns 0 on success or an error code. Calling gnupg_wait_process
- and gnupg_release_process is required if the function succeeded.
-
- FLAGS is a bit vector:
-
- GNUPG_SPAWN_NONBLOCK
- If set the two output streams are created in non-blocking
- mode and the input stream is switched to non-blocking mode.
- This is merely a convenience feature because the caller
- could do the same with gpgrt_set_nonblock. Does not yet
- work for Windows.
-
- GNUPG_SPAWN_DETACHED
- If set the process will be started as a background process.
- This flag is only useful under W32 (but not W32CE) systems,
- so that no new console is created and pops up a console
- window when starting the server. Does not work on W32CE.
-
- GNUPG_SPAWN_RUN_ASFW
- On W32 (but not on W32CE) run AllowSetForegroundWindow for
- the child. Note that due to unknown problems this actually
- allows SetForegroundWindow for all children of this process.
-
- GNUPG_SPAWN_KEEP_STDIN
- GNUPG_SPAWN_KEEP_STDOUT
- GNUPG_SPAWN_KEEP_STDERR
- Do not assign /dev/null to a non-required standard file
- descriptor.
-
- */
-gpg_error_t
-gnupg_spawn_process (const char *pgmname, const char *argv[],
- int *execpt, unsigned int flags,
- estream_t *r_infp,
- estream_t *r_outfp,
- estream_t *r_errfp,
- pid_t *pid);
-
-
-/* Simplified version of gnupg_spawn_process. This function forks and
- then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
- and ERRFD to stderr (any of them may be -1 to connect them to
- /dev/null). The arguments for the process are expected in the NULL
- terminated array ARGV. The program name itself should not be
- included there. Calling gnupg_wait_process and
- gnupg_release_process is required. Returns 0 on success or an
- error code. */
-gpg_error_t gnupg_spawn_process_fd (const char *pgmname,
- const char *argv[],
- int infd, int outfd, int errfd,
- pid_t *pid);
-
-
-/* If HANG is true, waits for the process identified by PID to exit;
- if HANG is false, checks whether the process has terminated.
- PGMNAME should be the same as supplied to the spawn function and is
- only used for diagnostics. Return values:
-
- 0
- The process exited successful. 0 is stored at R_EXITCODE.
-
- GPG_ERR_GENERAL
- The process exited without success. The exit code of process
- is then stored at R_EXITCODE. An exit code of -1 indicates
- that the process terminated abnormally (e.g. due to a signal).
-
- GPG_ERR_TIMEOUT
- The process is still running (returned only if HANG is false).
-
- GPG_ERR_INV_VALUE
- An invalid PID has been specified.
-
- Other error codes may be returned as well. Unless otherwise noted,
- -1 will be stored at R_EXITCODE. R_EXITCODE may be passed as NULL
- if the exit code is not required (in that case an error message will
- be printed). Note that under Windows PID is not the process id but
- the handle of the process. */
-gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int hang,
- int *r_exitcode);
-
-/* Like gnupg_wait_process, but for COUNT processes. */
-gpg_error_t gnupg_wait_processes (const char **pgmnames, pid_t *pids,
- size_t count, int hang, int *r_exitcodes);
-
-
-/* Kill a process; that is send an appropriate signal to the process.
- gnupg_wait_process must be called to actually remove the process
- from the system. An invalid PID is ignored. */
-void gnupg_kill_process (pid_t pid);
-
-/* Release the process identified by PID. This function is actually
- only required for Windows but it does not harm to always call it.
- It is a nop if PID is invalid. */
-void gnupg_release_process (pid_t pid);
-
-
-/* Spawn a new process and immediately detach from it. The name of
- the program to exec is PGMNAME and its arguments are in ARGV (the
- programname is automatically passed as first argument).
- Environment strings in ENVP are set. An error is returned if
- pgmname is not executable; to make this work it is necessary to
- provide an absolute file name. */
-gpg_error_t gnupg_spawn_process_detached (const char *pgmname,
- const char *argv[],
- const char *envp[] );
-
+/* The opaque type for a subprocess. */
+typedef struct gnupg_process *gnupg_process_t;
+#ifdef HAVE_W32_SYSTEM
+struct spawn_cb_arg;
+#ifdef NEED_STRUCT_SPAWN_CB_ARG
+struct spawn_cb_arg {
+ HANDLE hd[3];
+ HANDLE *inherit_hds;
+ BOOL allow_foreground_window;
+ void *arg;
+};
+#endif
+#else
+struct spawn_cb_arg {
+ int fds[3];
+ int *except_fds;
+ void *arg;
+};
+#endif
+
+#define GNUPG_PROCESS_DETACHED (1 << 1)
+
+/* Specify how to keep/connect standard fds. */
+#define GNUPG_PROCESS_STDIN_PIPE (1 << 8)
+#define GNUPG_PROCESS_STDOUT_PIPE (1 << 9)
+#define GNUPG_PROCESS_STDERR_PIPE (1 << 10)
+#define GNUPG_PROCESS_STDINOUT_SOCKETPAIR (1 << 11)
+#define GNUPG_PROCESS_STDIN_KEEP (1 << 12)
+#define GNUPG_PROCESS_STDOUT_KEEP (1 << 13)
+#define GNUPG_PROCESS_STDERR_KEEP (1 << 14)
+#define GNUPG_PROCESS_STDFDS_SETTING ( GNUPG_PROCESS_STDIN_PIPE \
+ | GNUPG_PROCESS_STDOUT_PIPE | GNUPG_PROCESS_STDERR_PIPE \
+ | GNUPG_PROCESS_STDINOUT_SOCKETPAIR | GNUPG_PROCESS_STDIN_KEEP \
+ | GNUPG_PROCESS_STDOUT_KEEP | GNUPG_PROCESS_STDERR_KEEP)
+
+#define GNUPG_PROCESS_STREAM_NONBLOCK (1 << 16)
+
+/* Spawn helper. */
+void gnupg_spawn_helper (struct spawn_cb_arg *sca);
+
+/* Spawn PGMNAME. */
+gpg_err_code_t gnupg_process_spawn (const char *pgmname, const char *argv[],
+ unsigned int flags,
+ void (*spawn_cb) (struct spawn_cb_arg *),
+ void *spawn_cb_arg,
+ gnupg_process_t *r_process);
+
+/* Get FDs for subprocess I/O. It is the caller which should care
+ FDs (closing FDs). */
+gpg_err_code_t gnupg_process_get_fds (gnupg_process_t process,
+ unsigned int flags,
+ int *r_fd_in, int *r_fd_out,
+ int *r_fd_err);
+
+/* Get STREAMs for subprocess I/O. It is the caller which should care
+ STREAMs (closing STREAMs). */
+gpg_err_code_t gnupg_process_get_streams (gnupg_process_t process,
+ unsigned int flags,
+ gpgrt_stream_t *r_fp_in,
+ gpgrt_stream_t *r_fp_out,
+ gpgrt_stream_t *r_fp_err);
+
+enum gnupg_process_requests
+ {
+ /* Portable requests */
+ GNUPG_PROCESS_NOP = 0,
+ GNUPG_PROCESS_GET_PROC_ID = 1,
+ GNUPG_PROCESS_GET_EXIT_ID = 2,
+
+ /* POSIX only */
+ GNUPG_PROCESS_GET_PID = 16,
+ GNUPG_PROCESS_GET_WSTATUS = 17,
+ GNUPG_PROCESS_KILL = 18,
+
+ /* Windows only */
+ GNUPG_PROCESS_GET_P_HANDLE = 32,
+ GNUPG_PROCESS_GET_HANDLES = 33,
+ GNUPG_PROCESS_GET_EXIT_CODE = 34,
+ GNUPG_PROCESS_KILL_WITH_EC = 35
+ };
+
+/* Control of a process. */
+gpg_err_code_t gnupg_process_ctl (gnupg_process_t process,
+ unsigned int request, ...);
+
+/* Wait for a single PROCESS. */
+gpg_err_code_t gnupg_process_wait (gnupg_process_t process, int hang);
+
+/* Terminate a PROCESS. */
+gpg_err_code_t gnupg_process_terminate (gnupg_process_t process);
+
+/* Release PROCESS resources. */
+void gnupg_process_release (gnupg_process_t process);
+
+/* Wait for a multiple processes. */
+gpg_err_code_t gnupg_process_wait_list (gnupg_process_t *process_list,
+ int count, int hang);
#endif /*GNUPG_COMMON_EXECHELP_H*/
diff --git a/common/exectool.c b/common/exectool.c
index aaf5898d0..3505c25f1 100644
--- a/common/exectool.c
+++ b/common/exectool.c
@@ -38,10 +38,14 @@
#include <gpg-error.h>
#include <assuan.h>
+
#include "i18n.h"
#include "logging.h"
#include "membuf.h"
#include "mischelp.h"
+#ifdef HAVE_W32_SYSTEM
+#define NEED_STRUCT_SPAWN_CB_ARG 1
+#endif
#include "exechelp.h"
#include "sysutils.h"
#include "util.h"
@@ -301,7 +305,6 @@ copy_buffer_flush (struct copy_buffer *c, estream_t sink)
}
-
/* Run the program PGMNAME with the command line arguments given in
* the NULL terminates array ARGV. If INPUT is not NULL it will be
* fed to stdin of the process. stderr is logged using log_info and
@@ -321,7 +324,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
void *status_cb_value)
{
gpg_error_t err;
- pid_t pid = (pid_t) -1;
+ gnupg_process_t proc = NULL;
estream_t infp = NULL;
estream_t extrafp = NULL;
estream_t outfp = NULL, errfp = NULL;
@@ -335,7 +338,6 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
read_and_log_buffer_t fderrstate;
struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
int quiet = 0;
- int dummy_exitcode;
memset (fds, 0, sizeof fds);
memset (&fderrstate, 0, sizeof fderrstate);
@@ -411,10 +413,15 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
else
exceptclose[0] = -1;
- err = gnupg_spawn_process (pgmname, argv,
- exceptclose, GNUPG_SPAWN_NONBLOCK,
- input? &infp : NULL,
- &outfp, &errfp, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ ((input
+ ? GNUPG_PROCESS_STDIN_PIPE
+ : 0)
+ | GNUPG_PROCESS_STDOUT_PIPE
+ | GNUPG_PROCESS_STDERR_PIPE),
+ gnupg_spawn_helper, exceptclose, &proc);
+ gnupg_process_get_streams (proc, GNUPG_PROCESS_STREAM_NONBLOCK,
+ input? &infp : NULL, &outfp, &errfp);
if (extrapipe[0] != -1)
close (extrapipe[0]);
if (argsave)
@@ -546,20 +553,25 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
es_fclose (outfp); outfp = NULL;
es_fclose (errfp); errfp = NULL;
- err = gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
- pid = (pid_t)(-1);
+ err = gnupg_process_wait (proc, 1);
+ if (!err)
+ { /* To be compatible to old wait_process. */
+ int status;
+
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &status);
+ if (status)
+ err = gpg_error (GPG_ERR_GENERAL);
+ }
leave:
- if (err && pid != (pid_t) -1)
- gnupg_kill_process (pid);
+ if (err && proc)
+ gnupg_process_terminate (proc);
es_fclose (infp);
es_fclose (extrafp);
es_fclose (outfp);
es_fclose (errfp);
- if (pid != (pid_t)(-1))
- gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
copy_buffer_shred (cpbuf_in);
xfree (cpbuf_in);
diff --git a/common/get-passphrase.c b/common/get-passphrase.c
index c24b40e88..8ea822710 100644
--- a/common/get-passphrase.c
+++ b/common/get-passphrase.c
@@ -94,7 +94,8 @@ start_agent (void)
agentargs.lc_ctype,
agentargs.lc_messages,
agentargs.session_env,
- 1, agentargs.verbosity, 0, NULL, NULL);
+ ASSHELP_FLAG_AUTOSTART,
+ agentargs.verbosity, 0, NULL, NULL);
if (!err)
{
/* Tell the agent that we support Pinentry notifications. No
diff --git a/common/init.c b/common/init.c
index 62a48f8c7..8ea51c8b0 100644
--- a/common/init.c
+++ b/common/init.c
@@ -37,6 +37,7 @@
# include <winsock2.h>
# endif
# include <windows.h>
+# include <wctype.h>
#endif
#include <gcrypt.h>
diff --git a/common/iobuf.c b/common/iobuf.c
index 748e6935d..e46eeac95 100644
--- a/common/iobuf.c
+++ b/common/iobuf.c
@@ -166,7 +166,8 @@ block_filter_ctx_t;
/* Local prototypes. */
static int underflow (iobuf_t a, int clear_pending_eof);
static int underflow_target (iobuf_t a, int clear_pending_eof, size_t target);
-static int translate_file_handle (int fd, int for_write);
+static iobuf_t do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open);
+
/* Sends any pending data to the filter's FILTER function. Note: this
works on the filter and not on the whole pipeline. That is,
@@ -389,7 +390,7 @@ fd_cache_close (const char *fname, gnupg_fd_t fp)
close (fp);
#endif
if (DBG_IOBUF)
- log_debug ("fd_cache_close (%d) real\n", (int)fp);
+ log_debug ("fd_cache_close (%d) real\n", FD_DBG (fp));
return;
}
/* try to reuse a slot */
@@ -696,7 +697,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
if (f != FD_FOR_STDIN && f != FD_FOR_STDOUT)
{
if (DBG_IOBUF)
- log_debug ("%s: close fd/handle %d\n", a->fname, FD2INT (f));
+ log_debug ("%s: close fd/handle %d\n", a->fname, FD_DBG (f));
if (!a->keep_open)
fd_cache_close (a->no_cache ? NULL : a->fname, f);
}
@@ -1410,7 +1411,7 @@ iobuf_is_pipe_filename (const char *fname)
{
if (!fname || (*fname=='-' && !fname[1]) )
return 1;
- return check_special_filename (fname, 0, 1) != -1;
+ return gnupg_check_special_filename (fname) != GNUPG_INVALID_FD;
}
@@ -1423,7 +1424,7 @@ do_open (const char *fname, int special_filenames,
file_filter_ctx_t *fcx;
size_t len = 0;
int print_only = 0;
- int fd;
+ gnupg_fd_t fd;
byte desc[MAX_IOBUF_DESC];
log_assert (use == IOBUF_INPUT || use == IOBUF_OUTPUT);
@@ -1447,9 +1448,8 @@ do_open (const char *fname, int special_filenames,
else if (!fname)
return NULL;
else if (special_filenames
- && (fd = check_special_filename (fname, 0, 1)) != -1)
- return iobuf_fdopen (translate_file_handle (fd, use == IOBUF_INPUT ? 0 : 1),
- opentype);
+ && (fd = gnupg_check_special_filename (fname)) != GNUPG_INVALID_FD)
+ return do_iobuf_fdopen (fd, opentype, 0);
else
{
if (use == IOBUF_INPUT)
@@ -1472,7 +1472,8 @@ do_open (const char *fname, int special_filenames,
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
if (DBG_IOBUF)
log_debug ("iobuf-%d.%d: open '%s' desc=%s fd=%d\n",
- a->no, a->subno, fname, iobuf_desc (a, desc), FD2INT (fcx->fp));
+ a->no, a->subno, fname, iobuf_desc (a, desc),
+ FD_DBG (fcx->fp));
return a;
}
@@ -1497,22 +1498,19 @@ iobuf_openrw (const char *fname)
static iobuf_t
-do_iobuf_fdopen (int fd, const char *mode, int keep_open)
+do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open)
{
iobuf_t a;
- gnupg_fd_t fp;
file_filter_ctx_t *fcx;
size_t len = 0;
- fp = INT2FD (fd);
-
a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
iobuf_buffer_size);
fcx = xmalloc (sizeof *fcx + 20);
fcx->fp = fp;
fcx->print_only_name = 1;
fcx->keep_open = keep_open;
- sprintf (fcx->fname, "[fd %d]", fd);
+ sprintf (fcx->fname, "[fd %d]", FD_DBG (fp));
a->filter = file_filter;
a->filter_ov = fcx;
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
@@ -1525,15 +1523,15 @@ do_iobuf_fdopen (int fd, const char *mode, int keep_open)
iobuf_t
-iobuf_fdopen (int fd, const char *mode)
+iobuf_fdopen (gnupg_fd_t fp, const char *mode)
{
- return do_iobuf_fdopen (fd, mode, 0);
+ return do_iobuf_fdopen (fp, mode, 0);
}
iobuf_t
-iobuf_fdopen_nc (int fd, const char *mode)
+iobuf_fdopen_nc (gnupg_fd_t fp, const char *mode)
{
- return do_iobuf_fdopen (fd, mode, 1);
+ return do_iobuf_fdopen (fp, mode, 1);
}
@@ -1585,7 +1583,7 @@ iobuf_sockopen (int fd, const char *mode)
log_debug ("iobuf-%d.%d: sockopen '%s'\n", a->no, a->subno, scx->fname);
iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
#else
- a = iobuf_fdopen (fd, mode);
+ a = do_iobuf_fdopen (fd, mode, 0);
#endif
return a;
}
@@ -2644,20 +2642,20 @@ iobuf_get_filelength (iobuf_t a)
}
-int
+gnupg_fd_t
iobuf_get_fd (iobuf_t a)
{
for (; a->chain; a = a->chain)
;
if (a->filter != file_filter)
- return -1;
+ return GNUPG_INVALID_FD;
{
file_filter_ctx_t *b = a->filter_ov;
gnupg_fd_t fp = b->fp;
- return FD2INT (fp);
+ return fp;
}
}
@@ -2948,36 +2946,6 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
return nbytes;
}
-static int
-translate_file_handle (int fd, int for_write)
-{
-#if defined(HAVE_W32_SYSTEM)
- {
- int x;
-
- (void)for_write;
-
- if (fd == 0)
- x = (int) GetStdHandle (STD_INPUT_HANDLE);
- else if (fd == 1)
- x = (int) GetStdHandle (STD_OUTPUT_HANDLE);
- else if (fd == 2)
- x = (int) GetStdHandle (STD_ERROR_HANDLE);
- else
- x = fd;
-
- if (x == -1)
- log_debug ("GetStdHandle(%d) failed: ec=%d\n",
- fd, (int) GetLastError ());
-
- fd = x;
- }
-#else
- (void)for_write;
-#endif
- return fd;
-}
-
void
iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
diff --git a/common/iobuf.h b/common/iobuf.h
index 04e6b4421..4354c718d 100644
--- a/common/iobuf.h
+++ b/common/iobuf.h
@@ -333,11 +333,11 @@ iobuf_t iobuf_openrw (const char *fname);
creates an input filter. Note: MODE must reflect the file
descriptors actual mode! When the filter is destroyed, the file
descriptor is closed. */
-iobuf_t iobuf_fdopen (int fd, const char *mode);
+iobuf_t iobuf_fdopen (gnupg_fd_t fd, const char *mode);
/* Like iobuf_fdopen, but doesn't close the file descriptor when the
filter is destroyed. */
-iobuf_t iobuf_fdopen_nc (int fd, const char *mode);
+iobuf_t iobuf_fdopen_nc (gnupg_fd_t fd, const char *mode);
/* Create a filter using an existing estream. If MODE contains the
letter 'w', creates an output filter. Otherwise, creates an input
@@ -590,7 +590,7 @@ uint64_t iobuf_get_filelength (iobuf_t a);
/* Return the file descriptor designating the underlying file. This
only works with file_filter based pipelines. */
-int iobuf_get_fd (iobuf_t a);
+gnupg_fd_t iobuf_get_fd (iobuf_t a);
/* Return the real filename, if available. This only supports
pipelines that end in file filters. Returns NULL if not
diff --git a/common/miscellaneous.c b/common/miscellaneous.c
index 1a090b1f5..28d3e7a2e 100644
--- a/common/miscellaneous.c
+++ b/common/miscellaneous.c
@@ -687,3 +687,53 @@ parse_compatibility_flags (const char *string, unsigned int *flagvar,
*flagvar |= result;
return 0;
}
+
+
+/* Convert STRING consisting of base64 characters into its binary
+ * representation and store the result in a newly allocated buffer at
+ * R_BUFFER with its length at R_BUFLEN. If TITLE is NULL a plain
+ * base64 decoding is done. If it is the empty string the decoder
+ * will skip everything until a "-----BEGIN " line has been seen,
+ * decoding then ends at a "----END " line. On failure the function
+ * returns an error code and sets R_BUFFER to NULL. If the decoded
+ * data has a length of 0 a dummy buffer will still be allocated and
+ * the length is set to 0. */
+gpg_error_t
+b64decode (const char *string, const char *title,
+ void **r_buffer, size_t *r_buflen)
+{
+ gpg_error_t err;
+ gpgrt_b64state_t state;
+ size_t nbytes;
+ char *buffer;
+
+ *r_buffer = NULL;
+ *r_buflen = 0;
+
+ buffer = xtrystrdup (string);
+ if (!buffer)
+ return gpg_error_from_syserror();
+
+ state = gpgrt_b64dec_start (title);
+ if (!state)
+ {
+ err = gpg_error_from_syserror ();
+ xfree (buffer);
+ return err;
+ }
+ err = gpgrt_b64dec_proc (state, buffer, strlen (buffer), &nbytes);
+ if (!err)
+ {
+ err = gpgrt_b64dec_finish (state);
+ state = NULL;
+ }
+ if (err)
+ xfree (buffer);
+ else
+ {
+ *r_buffer = buffer;
+ *r_buflen = nbytes;
+ }
+ gpgrt_b64dec_finish (state); /* Make sure it is released. */
+ return err;
+}
diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h
index 180680bcc..d8672ac47 100644
--- a/common/openpgpdefs.h
+++ b/common/openpgpdefs.h
@@ -171,7 +171,12 @@ typedef enum
PUBKEY_ALGO_ECDSA = 19, /* RFC-6637 */
PUBKEY_ALGO_ELGAMAL = 20, /* Elgamal encrypt+sign (legacy). */
/* 21 reserved by OpenPGP. */
- PUBKEY_ALGO_EDDSA = 22, /* EdDSA (not yet assigned). */
+ PUBKEY_ALGO_EDDSA = 22, /* EdDSA. */
+ PUBKEY_ALGO_KY768_25519 = 29, /* Kyber768 + X25519 (aka ML-KEM-768) */
+ PUBKEY_ALGO_KY1024_448 = 30, /* Kyber1024 + X448 (aka ML-KEM-1024) */
+ PUBKEY_ALGO_DIL3_25519 = 35, /* Dilithium3 + Ed25519 (aka ML-DSA-65) */
+ PUBKEY_ALGO_DIL5_448 = 36, /* Dilithium5 + Ed448 (aka ML-DSA-87) */
+ PUBKEY_ALGO_SPHINX_SHA2 = 41, /* SPHINX+-simple-SHA2 (aka SLH-DSA-SHA2) */
PUBKEY_ALGO_PRIVATE10 = 110
}
pubkey_algo_t;
@@ -206,7 +211,7 @@ compress_algo_t;
#define OPENPGP_MAX_NPKEY 5 /* Maximum number of public key parameters. */
#define OPENPGP_MAX_NSKEY 7 /* Maximum number of secret key parameters. */
#define OPENPGP_MAX_NSIG 2 /* Maximum number of signature parameters. */
-#define OPENPGP_MAX_NENC 2 /* Maximum number of encryption parameters. */
+#define OPENPGP_MAX_NENC 4 /* Maximum number of encryption parameters. */
/* Decode an rfc4880 encoded S2K count. */
diff --git a/common/ssh-utils.c b/common/ssh-utils.c
index ab29558cf..d27e2e200 100644
--- a/common/ssh-utils.c
+++ b/common/ssh-utils.c
@@ -259,7 +259,7 @@ get_fingerprint (gcry_sexp_t key, int algo,
}
else
{
- struct b64state b64s;
+ gpgrt_b64state_t b64s;
estream_t stream;
char *p;
long int len;
@@ -273,15 +273,15 @@ get_fingerprint (gcry_sexp_t key, int algo,
goto leave;
}
- err = b64enc_start_es (&b64s, stream, "");
- if (err)
+ b64s = gpgrt_b64enc_start (stream, "");
+ if (!b64s)
{
es_fclose (stream);
goto leave;
}
- err = b64enc_write (&b64s,
- gcry_md_read (md, algo), gcry_md_get_algo_dlen (algo));
+ err = gpgrt_b64enc_write (b64s, gcry_md_read (md, algo),
+ gcry_md_get_algo_dlen (algo));
if (err)
{
es_fclose (stream);
@@ -289,7 +289,7 @@ get_fingerprint (gcry_sexp_t key, int algo,
}
/* Finish, get the length, and close the stream. */
- err = b64enc_finish (&b64s);
+ err = gpgrt_b64enc_finish (b64s);
len = es_ftell (stream);
es_fclose (stream);
if (err)
@@ -566,7 +566,7 @@ ssh_public_key_in_base64 (gcry_sexp_t key, estream_t stream,
const char *identifier = NULL;
void *blob = NULL;
size_t bloblen;
- struct b64state b64_state;
+ gpgrt_b64state_t b64_state;
algo = get_pk_algo_from_key (key);
if (algo == 0)
@@ -624,15 +624,15 @@ ssh_public_key_in_base64 (gcry_sexp_t key, estream_t stream,
es_fprintf (stream, "%s ", identifier);
- err = b64enc_start_es (&b64_state, stream, "");
- if (err)
+ b64_state = gpgrt_b64enc_start (stream, "");
+ if (!b64_state)
{
es_free (blob);
- return err;
+ return gpg_error_from_syserror ();
}
- err = b64enc_write (&b64_state, blob, bloblen);
- b64enc_finish (&b64_state);
+ err = gpgrt_b64enc_write (b64_state, blob, bloblen);
+ gpgrt_b64enc_finish (b64_state);
es_free (blob);
if (err)
return err;
diff --git a/common/sysutils.c b/common/sysutils.c
index 90627b7c8..6c7d616b9 100644
--- a/common/sysutils.c
+++ b/common/sysutils.c
@@ -559,17 +559,15 @@ translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
}
/* This is the same as translate_sys2libc_fd but takes an integer
- which is assumed to be such an system handle. On WindowsCE the
- passed FD is a rendezvous ID and the function finishes the pipe
- creation. */
+ which is assumed to be such an system handle. */
int
translate_sys2libc_fd_int (int fd, int for_write)
{
#ifdef HAVE_W32_SYSTEM
if (fd <= 2)
- return fd; /* Do not do this for error, stdin, stdout, stderr. */
+ return fd; /* Do not do this for stdin, stdout, and stderr. */
- return translate_sys2libc_fd ((void*)fd, for_write);
+ return translate_sys2libc_fd ((void*)(intptr_t)fd, for_write);
#else
(void)for_write;
return fd;
@@ -577,6 +575,70 @@ translate_sys2libc_fd_int (int fd, int for_write)
}
+/*
+ * Parse the string representation of a file reference (file handle on
+ * Windows or file descriptor on POSIX) in FDSTR. The string
+ * representation may be either of folllowing:
+
+ * (1) 0, 1, or 2 which means stdin, stdout, and stderr, respectively.
+ * (2) Integer representation (by %d of printf).
+ * (3) Hex representation which starts as "0x".
+ *
+ * Then, fill R_SYSHD, according to the value of a file reference.
+ *
+ */
+gpg_error_t
+gnupg_parse_fdstr (const char *fdstr, es_syshd_t *r_syshd)
+{
+ int fd = -1;
+#ifdef HAVE_W32_SYSTEM
+ gnupg_fd_t hd;
+ char *endptr;
+ int base;
+
+ if (!strcmp (fdstr, "0"))
+ fd = 0;
+ else if (!strcmp (fdstr, "1"))
+ fd = 1;
+ else if (!strcmp (fdstr, "2"))
+ fd = 2;
+
+ if (fd >= 0)
+ {
+ r_syshd->type = ES_SYSHD_FD;
+ r_syshd->u.fd = fd;
+ return 0;
+ }
+
+ if (!strncmp (fdstr, "0x", 2))
+ {
+ base = 16;
+ fdstr += 2;
+ }
+ else
+ base = 10;
+
+ gpg_err_set_errno (0);
+#ifdef _WIN64
+ hd = (gnupg_fd_t)strtoll (fdstr, &endptr, base);
+#else
+ hd = (gnupg_fd_t)strtol (fdstr, &endptr, base);
+#endif
+ if (errno != 0 || endptr == fdstr || *endptr != '\0')
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ r_syshd->type = ES_SYSHD_HANDLE;
+ r_syshd->u.handle = hd;
+ return 0;
+#else
+ fd = atoi (fdstr);
+ r_syshd->type = ES_SYSHD_FD;
+ r_syshd->u.fd = fd;
+ return 0;
+#endif
+}
+
+
/* Check whether FNAME has the form "-&nnnn", where N is a non-zero
* number. Returns this number or -1 if it is not the case. If the
* caller wants to use the file descriptor for writing FOR_WRITE shall
@@ -594,13 +656,74 @@ check_special_filename (const char *fname, int for_write, int notranslate)
for (i=0; digitp (fname+i); i++ )
;
if (!fname[i])
- return notranslate? atoi (fname)
- /**/ : translate_sys2libc_fd_int (atoi (fname), for_write);
+ {
+ if (notranslate)
+ return atoi (fname);
+ else
+ {
+ es_syshd_t syshd;
+
+ if (gnupg_parse_fdstr (fname, &syshd))
+ return -1;
+
+#ifdef HAVE_W32_SYSTEM
+ if (syshd.type == ES_SYSHD_FD)
+ return syshd.u.fd;
+ else
+ return translate_sys2libc_fd ((gnupg_fd_t)syshd.u.handle, for_write);
+#else
+ (void)for_write;
+ return syshd.u.fd;
+#endif
+ }
+ }
}
return -1;
}
+/* Check whether FNAME has the form "-&nnnn", where N is a number
+ * representing a file. Returns GNUPG_INVALID_FD if it is not the
+ * case. Returns a file descriptor on POSIX, a system handle on
+ * Windows. */
+gnupg_fd_t
+gnupg_check_special_filename (const char *fname)
+{
+ if (allow_special_filenames
+ && fname && *fname == '-' && fname[1] == '&')
+ {
+ int i;
+
+ fname += 2;
+ for (i=0; digitp (fname+i); i++ )
+ ;
+ if (!fname[i])
+ {
+ es_syshd_t syshd;
+
+ if (gnupg_parse_fdstr (fname, &syshd))
+ return GNUPG_INVALID_FD;
+
+#ifdef HAVE_W32_SYSTEM
+ if (syshd.type == ES_SYSHD_FD)
+ {
+ if (syshd.u.fd == 0)
+ return GetStdHandle (STD_INPUT_HANDLE);
+ else if (syshd.u.fd == 1)
+ return GetStdHandle (STD_OUTPUT_HANDLE);
+ else if (syshd.u.fd == 2)
+ return GetStdHandle (STD_ERROR_HANDLE);
+ }
+ else
+ return syshd.u.handle;
+#else
+ return syshd.u.fd;
+#endif
+ }
+ }
+ return GNUPG_INVALID_FD;
+}
+
/* Replacement for tmpfile(). This is required because the tmpfile
function of Windows' runtime library is broken, insecure, ignores
TMPDIR and so on. In addition we create a file with an inheritable
@@ -1158,6 +1281,19 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
return setenv (name, value, overwrite);
#else /*!HAVE_SETENV*/
if (! getenv (name) || overwrite)
+#if defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+ {
+ int e = _putenv_s (name, value);
+
+ if (e)
+ {
+ gpg_err_set_errno (e);
+ return -1;
+ }
+ else
+ return 0;
+ }
+#else
{
char *buf;
@@ -1175,6 +1311,7 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
# endif
return putenv (buf);
}
+#endif /*!HAVE_W32_SYSTEM*/
return 0;
#endif /*!HAVE_SETENV*/
}
@@ -1199,6 +1336,18 @@ gnupg_unsetenv (const char *name)
#ifdef HAVE_UNSETENV
return unsetenv (name);
+#elif defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+ {
+ int e = _putenv_s (name, "");
+
+ if (e)
+ {
+ gpg_err_set_errno (e);
+ return -1;
+ }
+ else
+ return 0;
+ }
#else /*!HAVE_UNSETENV*/
{
char *buf;
@@ -1829,3 +1978,22 @@ gnupg_fd_valid (int fd)
close (d);
return 1;
}
+
+
+/* Open a stream from FD (a file descriptor on POSIX, a system
+ handle on Windows), non-closed. */
+estream_t
+open_stream_nc (gnupg_fd_t fd, const char *mode)
+{
+ es_syshd_t syshd;
+
+#ifdef HAVE_W32_SYSTEM
+ syshd.type = ES_SYSHD_HANDLE;
+ syshd.u.handle = fd;
+#else
+ syshd.type = ES_SYSHD_FD;
+ syshd.u.fd = fd;
+#endif
+
+ return es_sysopen_nc (&syshd, mode);
+}
diff --git a/common/sysutils.h b/common/sysutils.h
index a78a81c64..dac2d9244 100644
--- a/common/sysutils.h
+++ b/common/sysutils.h
@@ -38,12 +38,20 @@
typedef void *gnupg_fd_t;
#define GNUPG_INVALID_FD ((void*)(-1))
#define INT2FD(s) ((void *)(s))
-#define FD2INT(h) ((unsigned int)(h))
+# ifdef _WIN64
+# define FD2INT(h) ((intptr_t)(h))
+# else
+# define FD2INT(h) ((unsigned int)(h))
+# endif
+#define FD_DBG(h) ((int)(intptr_t)(h))
+#define FD2NUM(h) ((int)(intptr_t)(h))
#else
typedef int gnupg_fd_t;
#define GNUPG_INVALID_FD (-1)
#define INT2FD(s) (s)
#define FD2INT(h) (h)
+#define FD_DBG(h) (h)
+#define FD2NUM(h) (h)
#endif
#ifdef HAVE_STAT
@@ -74,7 +82,9 @@ void gnupg_sleep (unsigned int seconds);
void gnupg_usleep (unsigned int usecs);
int translate_sys2libc_fd (gnupg_fd_t fd, int for_write);
int translate_sys2libc_fd_int (int fd, int for_write);
+gpg_error_t gnupg_parse_fdstr (const char *fdstr, es_syshd_t *r_syshd);
int check_special_filename (const char *fname, int for_write, int notranslate);
+gnupg_fd_t gnupg_check_special_filename (const char *fname);
FILE *gnupg_tmpfile (void);
void gnupg_reopen_std (const char *pgmname);
void gnupg_inhibit_set_foregound_window (int yes);
@@ -108,6 +118,7 @@ gpg_error_t gnupg_inotify_watch_delete_self (int *r_fd, const char *fname);
gpg_error_t gnupg_inotify_watch_socket (int *r_fd, const char *socket_name);
int gnupg_inotify_has_name (int fd, const char *name);
+estream_t open_stream_nc (gnupg_fd_t fd, const char *mode);
#ifdef HAVE_W32_SYSTEM
int gnupg_w32_set_errno (int ec);
diff --git a/common/t-b64.c b/common/t-b64.c
deleted file mode 100644
index 16c079d1d..000000000
--- a/common/t-b64.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/* t-b64.c - Module tests for b64enc.c and b64dec.c
- * Copyright (C) 2008 Free Software Foundation, Inc.
- * Copyright (C) 2008, 2023 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 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.
- *
- * 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 Lesser General Public License
- * along with this program; if not, see <https://www.gnu.org/licenses/>.
- * SPDX-License-Identifier: LGPL-2.1-or-later
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "util.h"
-
-#define pass() do { ; } while(0)
-#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
- __FILE__,__LINE__, (a)); \
- errcount++; \
- } while(0)
-#define oops() do { fprintf (stderr, "%s:%d: ooops\n", \
- __FILE__,__LINE__); \
- exit (2); \
- } while(0)
-
-static int verbose;
-static int errcount;
-
-
-/* Convert STRING consisting of hex characters into its binary
- * representation and return it as an allocated buffer. The valid
- * length of the buffer is returned at R_LENGTH. The string is
- * delimited by end of string. The function returns NULL on
- * error. */
-static void *
-hex2buffer (const char *string, size_t *r_length)
-{
- const char *s;
- unsigned char *buffer;
- size_t length;
-
- buffer = xmalloc (strlen(string)/2+1);
- length = 0;
- for (s=string; *s; s +=2 )
- {
- if (!hexdigitp (s) || !hexdigitp (s+1))
- return NULL; /* Invalid hex digits. */
- ((unsigned char*)buffer)[length++] = xtoi_2 (s);
- }
- *r_length = length;
- return buffer;
-}
-
-
-static void
-test_b64decode (void)
-{
- static struct {
- const char *string; /* String to test. */
- const char *title; /* title parameter. */
- gpg_error_t err; /* expected error. */
- const char *datastr; /* Expected data (hex encoded) */
- } tests[] = {
- { "YQ==", NULL, 0,
- "61" },
- { "YWE==", NULL, 0,
- "6161" },
- { "YWFh", NULL, 0,
- "616161" },
- { "YWFhYQ==", NULL, 0,
- "61616161" },
- { "YWJjZA==", NULL, 0,
- "61626364" },
- { "AA=", NULL, 0,
- "00" },
- { "AAEA=", NULL, 0,
- "000100" },
- { "/w==", NULL, 0,
- "ff" },
- { "oRQwEqADCgEDoQsGCSqGSIL3EgECAg==", NULL, 0,
- "a1143012a0030a0103a10b06092a864882f712010202" },
- { "oRQwEqADCgEDoQsGCSqGSIL3EgECA-==", NULL, GPG_ERR_BAD_DATA,
- "a1143012a0030a0103a10b06092a864882f712010202" },
- { "oRQwEqADCgEDoQsGCSqGSIL3EgECAg==", "", 0,
- "" },
- { "-----BEGIN PGP\n\n"
- "oRQwEqADCgEDoQsGCSqGSIL3EgECAg==\n"
- "-----END PGP\n", "", 0,
- "a1143012a0030a0103a10b06092a864882f712010202" },
-
- { "", NULL, 0,
- "" }
- };
- int tidx;
- gpg_error_t err;
- void *data = NULL;
- size_t datalen;
- char *wantdata = NULL;
- size_t wantdatalen;
-
- for (tidx = 0; tidx < DIM(tests); tidx++)
- {
- xfree (wantdata);
- if (!(wantdata = hex2buffer (tests[tidx].datastr, &wantdatalen)))
- oops ();
- xfree (data);
- err = b64decode (tests[tidx].string, tests[tidx].title, &data, &datalen);
- if (verbose)
- fprintf (stderr, "%s:%d: test %d, err=%d, datalen=%zu\n",
- __FILE__, __LINE__, tidx, err, datalen);
- if (gpg_err_code (err) != tests[tidx].err)
- fail (tidx);
- else if (err)
- pass ();
- else if (wantdatalen != datalen)
- fail (tidx);
- else if (memcmp (wantdata, data, datalen))
- fail (tidx);
- else
- pass ();
- }
- xfree (wantdata);
- xfree (data);
-}
-
-
-static void
-test_b64enc_pgp (const char *string)
-{
- gpg_error_t err;
- struct b64state state;
-
- if (!string)
- string = "a";
-
- err = b64enc_start (&state, stdout, "PGP MESSAGE");
- if (err)
- fail (1);
-
- err = b64enc_write (&state, string, strlen (string));
- if (err)
- fail (2);
-
- err = b64enc_finish (&state);
- if (err)
- fail (3);
-
- pass ();
-}
-
-
-static void
-test_b64enc_file (const char *fname)
-{
- gpg_error_t err;
- struct b64state state;
- FILE *fp;
- char buffer[50];
- size_t nread;
-
- fp = fname ? fopen (fname, "r") : stdin;
- if (!fp)
- {
- fprintf (stderr, "%s:%d: can't open '%s': %s\n",
- __FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
- fail (0);
- }
-
- err = b64enc_start (&state, stdout, "DATA");
- if (err)
- fail (1);
-
- while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
- {
- err = b64enc_write (&state, buffer, nread);
- if (err)
- fail (2);
- }
-
- err = b64enc_finish (&state);
- if (err)
- fail (3);
-
- fclose (fp);
- pass ();
-}
-
-
-static void
-test_b64dec_file (const char *fname)
-{
- gpg_error_t err;
- struct b64state state;
- FILE *fp;
- char buffer[50];
- size_t nread, nbytes;
-
- fp = fname ? fopen (fname, "r") : stdin;
- if (!fp)
- {
- fprintf (stderr, "%s:%d: can't open '%s': %s\n",
- __FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
- fail (0);
- }
-
- err = b64dec_start (&state, "");
- if (err)
- fail (1);
-
- while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
- {
- err = b64dec_proc (&state, buffer, nread, &nbytes);
- if (err)
- {
- if (gpg_err_code (err) == GPG_ERR_EOF)
- break;
- fail (2);
- }
- else if (nbytes)
- fwrite (buffer, 1, nbytes, stdout);
- }
-
- err = b64dec_finish (&state);
- if (err)
- fail (3);
-
- fclose (fp);
- pass ();
-}
-
-
-
-int
-main (int argc, char **argv)
-{
- int do_encode = 0;
- int do_decode = 0;
- int do_pgpdecode = 0;
-
- if (argc)
- { argc--; argv++; }
- if (argc && !strcmp (argv[0], "--verbose"))
- {
- verbose = 1;
- argc--; argv++;
- }
-
- if (argc && !strcmp (argv[0], "--encode"))
- {
- do_encode = 1;
- argc--; argv++;
- }
- else if (argc && !strcmp (argv[0], "--decode"))
- {
- do_decode = 1;
- argc--; argv++;
- }
- else if (argc)
- do_pgpdecode = 1;
-
- if (do_encode)
- test_b64enc_file (argc? *argv: NULL);
- else if (do_decode)
- test_b64dec_file (argc? *argv: NULL);
- else if (do_pgpdecode)
- test_b64enc_pgp (argc? *argv: NULL);
- else
- test_b64decode ();
-
- return !!errcount;
-}
diff --git a/common/t-exechelp.c b/common/t-exechelp.c
index 3bf082bbb..2179ef2a0 100644
--- a/common/t-exechelp.c
+++ b/common/t-exechelp.c
@@ -29,7 +29,7 @@
static int verbose;
-
+#ifndef HAVE_W32_SYSTEM
static void
print_open_fds (int *array)
{
@@ -169,20 +169,168 @@ test_close_all_fds (void)
}
}
+#endif
+
+static char buff12k[1024*12];
+static char buff4k[1024*4];
+
+static void
+run_server (void)
+{
+ estream_t fp;
+ int i;
+ char *p;
+ unsigned int len;
+ int ret;
+ es_syshd_t syshd;
+ size_t n;
+ off_t o;
+
+#ifdef HAVE_W32_SYSTEM
+ syshd.type = ES_SYSHD_HANDLE;
+ syshd.u.handle = (HANDLE)_get_osfhandle (1);
+#else
+ syshd.type = ES_SYSHD_FD;
+ syshd.u.fd = 1;
+#endif
+
+ fp = es_sysopen_nc (&syshd, "w");
+ if (fp == NULL)
+ {
+ fprintf (stderr, "es_fdopen failed\n");
+ exit (1);
+ }
+
+ /* Fill the buffer by ASCII chars. */
+ p = buff12k;
+ for (i = 0; i < sizeof (buff12k); i++)
+ if ((i % 64) == 63)
+ *p++ = '\n';
+ else
+ *p++ = (i % 64) + '@';
+
+ len = sizeof (buff12k);
+
+ ret = es_write (fp, (void *)&len, sizeof (len), NULL);
+ if (ret)
+ {
+ fprintf (stderr, "es_write (1) failed\n");
+ exit (1);
+ }
+
+ es_fflush (fp);
+
+ o = 0;
+ n = len;
+
+ while (1)
+ {
+ size_t n0, n1;
+
+ n0 = n > 4096 ? 4096 : n;
+ memcpy (buff4k, buff12k + o, n0);
+
+ ret = es_write (fp, buff4k, n0, &n1);
+ if (ret || n0 != n1)
+ {
+ fprintf (stderr, "es_write (2) failed\n");
+ exit (1);
+ }
+
+ o += n0;
+ n -= n0;
+ if (n == 0)
+ break;
+ }
+
+ es_fclose (fp);
+ exit (0);
+}
+
+
+static void
+test_pipe_stream (const char *pgmname)
+{
+ gpg_error_t err;
+ gnupg_process_t proc;
+ estream_t outfp;
+ const char *argv[2];
+ unsigned int len;
+ size_t n;
+ off_t o;
+ int ret;
+
+ argv[0] = "--server";
+ argv[1] = NULL;
+
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDOUT_PIPE
+ |GNUPG_PROCESS_STDERR_KEEP),
+ NULL, NULL, &proc);
+ if (err)
+ {
+ fprintf (stderr, "gnupg_process_spawn failed\n");
+ exit (1);
+ }
+
+ gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
+
+ ret = es_read (outfp, (void *)&len, sizeof (len), NULL);
+ if (ret)
+ {
+ fprintf (stderr, "es_read (1) failed\n");
+ exit (1);
+ }
+
+ o = 0;
+ while (1)
+ {
+ if (es_feof (outfp))
+ break;
+
+ ret = es_read (outfp, buff4k, sizeof (buff4k), &n);
+ if (ret)
+ {
+ fprintf (stderr, "es_read (2) failed\n");
+ exit (1);
+ }
+
+ memcpy (buff12k + o, buff4k, n);
+ o += n;
+ }
+
+ if (o != sizeof (buff12k))
+ {
+ fprintf (stderr, "received data with wrong length %d\n", (int)o);
+ exit (1);
+ }
+ es_fclose (outfp);
+ gnupg_process_release (proc);
+}
int
main (int argc, char **argv)
{
+ const char *myname = "no-pgm";
+
if (argc)
- { argc--; argv++; }
+ {
+ myname = argv[0];
+ argc--; argv++;
+ }
if (argc && !strcmp (argv[0], "--verbose"))
{
verbose = 1;
argc--; argv++;
}
+ if (argc && !strcmp (argv[0], "--server"))
+ run_server ();
+#ifndef HAVE_W32_SYSTEM
test_close_all_fds ();
+#endif
+ test_pipe_stream (myname);
return 0;
}
diff --git a/common/t-iobuf.c b/common/t-iobuf.c
index bdeab99a4..aacf27a8b 100644
--- a/common/t-iobuf.c
+++ b/common/t-iobuf.c
@@ -1,3 +1,36 @@
+/* t-iobuf.c - Simple module test for iobuf.c
+ * Copyright (C) 2015 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-later OR GPL-2.0-or-later)
+ */
+
+/* The whole code here does not very fill into our general test frame
+ * work patter. But let's keep it as it is. */
+
#include <config.h>
#include <stdio.h>
#include <string.h>
@@ -7,6 +40,20 @@
#include "iobuf.h"
#include "stringhelp.h"
+
+static void *
+xmalloc (size_t n)
+{
+ void *p = malloc (n);
+ if (!p)
+ {
+ fprintf (stderr, "t-iobuf: out of core\n");
+ abort ();
+ }
+ return p;
+}
+
+
/* Return every other byte. In particular, reads two bytes, returns
the second one. */
static int
@@ -86,7 +133,7 @@ static struct content_filter_state *
content_filter_new (const char *buffer)
{
struct content_filter_state *state
- = malloc (sizeof (struct content_filter_state));
+ = xmalloc (sizeof (struct content_filter_state));
state->pos = 0;
state->len = strlen (buffer);
@@ -215,8 +262,7 @@ main (int argc, char *argv[])
allocate a buffer that is 5 bytes long, then no reallocation
should be required. */
size = 5;
- buffer = malloc (size);
- assert (buffer);
+ buffer = xmalloc (size);
max_len = 100;
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
assert (n == 4);
@@ -229,7 +275,7 @@ main (int argc, char *argv[])
requires 6 bytes of storage. We pass a buffer that is 5 bytes
large and we allow the buffer to be grown. */
size = 5;
- buffer = malloc (size);
+ buffer = xmalloc (size);
max_len = 100;
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
assert (n == 5);
@@ -243,7 +289,7 @@ main (int argc, char *argv[])
requires 7 bytes of storage. We pass a buffer that is 5 bytes
large and we don't allow the buffer to be grown. */
size = 5;
- buffer = malloc (size);
+ buffer = xmalloc (size);
max_len = 5;
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
assert (n == 4);
diff --git a/common/util.h b/common/util.h
index 803ab3d5c..e2d95b1af 100644
--- a/common/util.h
+++ b/common/util.h
@@ -149,36 +149,6 @@ ssize_t read_line (FILE *fp,
size_t *max_length);
-/*-- b64enc.c and b64dec.c --*/
-struct b64state
-{
- unsigned int flags;
- int idx;
- int quad_count;
- FILE *fp;
- estream_t stream;
- char *title;
- unsigned char radbuf[4];
- u32 crc;
- int stop_seen:1;
- int invalid_encoding:1;
- gpg_error_t lasterr;
-};
-
-gpg_error_t b64enc_start (struct b64state *state, FILE *fp, const char *title);
-gpg_error_t b64enc_start_es (struct b64state *state, estream_t fp,
- const char *title);
-gpg_error_t b64enc_write (struct b64state *state,
- const void *buffer, size_t nbytes);
-gpg_error_t b64enc_finish (struct b64state *state);
-
-gpg_error_t b64dec_start (struct b64state *state, const char *title);
-gpg_error_t b64dec_proc (struct b64state *state, void *buffer, size_t length,
- size_t *r_nbytes);
-gpg_error_t b64dec_finish (struct b64state *state);
-gpg_error_t b64decode (const char *string, const char *title,
- void **r_buffer, size_t *r_buflen);
-
/*-- sexputil.c */
char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
void log_printcanon (const char *text,
@@ -388,6 +358,10 @@ struct compatibility_flags_s
int parse_compatibility_flags (const char *string, unsigned int *flagvar,
const struct compatibility_flags_s *flags);
+gpg_error_t b64decode (const char *string, const char *title,
+ void **r_buffer, size_t *r_buflen);
+
+
/*-- Simple replacement functions. */