aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2024-10-11 07:17:53 +0000
committerNIIBE Yutaka <[email protected]>2024-10-11 07:29:02 +0000
commit1860f6407f834b681c21f67db7236eaad161524c (patch)
tree81e1fee4007e1b70fad278f9716fd65fcc28a7e4 /src
parentw32: Fix releasing memory for UTF-8 text. (diff)
downloadlibgpg-error-1860f6407f834b681c21f67db7236eaad161524c.tar.gz
libgpg-error-1860f6407f834b681c21f67db7236eaad161524c.zip
spawn: Add new function to modify environment.
* src/gpg-error.def.in (gpgrt_spawn_actions_set_envchange): New. * src/gpg-error.vers (gpgrt_spawn_actions_set_envchange): New. * src/gpg-error.h.in (gpgrt_spawn_actions_set_envchange): New. * src/gpgrt-int.h (_gpgrt_spawn_actions_set_envchange): New. * src/spawn-posix.c (struct gpgrt_spawn_actions): New field ENVCHANGE. (prepare_environ): New. (my_exec): Take care of ENVCHANGE. (_gpgrt_spawn_actions_set_envchange): New. * src/spawn-w32.c (struct gpgrt_spawn_actions): New field ENVCHANGE. (prepare_env_block): New. (_gpgrt_spawn_actions_set_envchange): New. (spawn_detached, _gpgrt_process_spawn): Take care of ENVCHANGE. * src/visibility.c (gpgrt_spawn_actions_set_envchange): New. * src/visibility.h (gpgrt_spawn_actions_set_envchange): New. * tests/Makefile.am (TESTS): Add t-spawn. * tests/t-spawn.c: New. -- GnuPG-bug-id: 7307 Signed-off-by: NIIBE Yutaka <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/gpg-error.def.in1
-rw-r--r--src/gpg-error.h.in2
-rw-r--r--src/gpg-error.vers1
-rw-r--r--src/gpgrt-int.h2
-rw-r--r--src/spawn-posix.c47
-rw-r--r--src/spawn-w32.c210
-rw-r--r--src/visibility.c7
-rw-r--r--src/visibility.h2
8 files changed, 264 insertions, 8 deletions
diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in
index 31a28ef..3b9f462 100644
--- a/src/gpg-error.def.in
+++ b/src/gpg-error.def.in
@@ -254,5 +254,6 @@ EXPORTS
gpgrt_spawn_actions_set_envvars @194
gpgrt_spawn_actions_set_redirect @195
gpgrt_spawn_actions_set_inherit_handles @196
+ gpgrt_spawn_actions_set_envchange @197
;; end of file with public symbols for Windows.
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index 68a9347..44566ae 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -1120,6 +1120,8 @@ typedef struct gpgrt_process *gpgrt_process_t;
typedef struct gpgrt_spawn_actions *gpgrt_spawn_actions_t;
gpg_err_code_t gpgrt_spawn_actions_new (gpgrt_spawn_actions_t *r_act);
void gpgrt_spawn_actions_release (gpgrt_spawn_actions_t act);
+void gpgrt_spawn_actions_set_envchange (gpgrt_spawn_actions_t,
+ const char *const*);
@define:spawn_actions_functions@
enum gpgrt_process_requests
diff --git a/src/gpg-error.vers b/src/gpg-error.vers
index c4704df..2868f3c 100644
--- a/src/gpg-error.vers
+++ b/src/gpg-error.vers
@@ -221,6 +221,7 @@ GPG_ERROR_1.0 {
gpgrt_spawn_actions_set_redirect;
gpgrt_spawn_actions_set_inherit_fds;
gpgrt_spawn_actions_set_atfork;
+ gpgrt_spawn_actions_set_envchange;
local:
*;
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index 4a37686..55933a1 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -637,6 +637,8 @@ gpg_err_code_t _gpgrt_make_pipe (int filedes[2], estream_t *r_fp,
/* Actions (at spawning a child process), which is OS-specific. */
gpg_err_code_t _gpgrt_spawn_actions_new (gpgrt_spawn_actions_t *r_act);
void _gpgrt_spawn_actions_release (gpgrt_spawn_actions_t act);
+void _gpgrt_spawn_actions_set_envchange (gpgrt_spawn_actions_t,
+ const char *const*);
#ifdef HAVE_W32_SYSTEM
void _gpgrt_spawn_actions_set_envvars (gpgrt_spawn_actions_t, char *);
void _gpgrt_spawn_actions_set_redirect (gpgrt_spawn_actions_t,
diff --git a/src/spawn-posix.c b/src/spawn-posix.c
index 9787ec1..4bb90ca 100644
--- a/src/spawn-posix.c
+++ b/src/spawn-posix.c
@@ -57,9 +57,6 @@
#include "gpgrt-int.h"
-/* (Only glibc's unistd.h declares this iff _GNU_SOURCE is used.) */
-extern char **environ;
-
/* Definition for the gpgrt_spawn_actions_t. Note that there is a
* different one for Windows. */
@@ -67,6 +64,7 @@ struct gpgrt_spawn_actions {
int fd[3];
const int *except_fds;
char **environ;
+ const char *const *envchange;
void (*atfork) (void *);
void *atfork_arg;
};
@@ -318,6 +316,31 @@ posix_open_null (int for_write)
}
+static gpg_err_code_t
+prepare_environ (const char *const *envchange)
+{
+ const char *const *envp;
+ const char *e;
+
+ for (envp = envchange; (e = *envp); envp++)
+ {
+ char *name = xtrystrdup (e);
+ char *p;
+
+ if (!name)
+ return _gpg_err_code_from_syserror ();
+
+ p = strchr (name, '=');
+ if (p)
+ *p++ = 0;
+
+ _gpgrt_setenv (name, p, 1);
+ xfree (name);
+ }
+
+ return 0;
+}
+
static int
my_exec (const char *pgmname, const char *argv[], gpgrt_spawn_actions_t act)
{
@@ -345,8 +368,8 @@ my_exec (const char *pgmname, const char *argv[], gpgrt_spawn_actions_t act)
/* Close all other files. */
_gpgrt_close_all_fds (3, act->except_fds);
- if (act->environ)
- environ = act->environ;
+ if (act->envchange && prepare_environ (act->envchange))
+ goto leave;
if (act->atfork)
act->atfork (act->atfork_arg);
@@ -355,8 +378,13 @@ my_exec (const char *pgmname, const char *argv[], gpgrt_spawn_actions_t act)
if (pgmname == NULL)
return 0;
- execv (pgmname, (char *const *)argv);
+ if (act->environ)
+ execve (pgmname, (char *const *)argv, act->environ);
+ else
+ execv (pgmname, (char *const *)argv);
+
/* No way to print anything, as we have may have closed all streams. */
+ leave:
_exit (127);
return -1;
}
@@ -456,6 +484,13 @@ _gpgrt_spawn_actions_set_environ (gpgrt_spawn_actions_t act,
}
void
+_gpgrt_spawn_actions_set_envchange (gpgrt_spawn_actions_t act,
+ const char *const *envchange)
+{
+ act->envchange = envchange;
+}
+
+void
_gpgrt_spawn_actions_set_atfork (gpgrt_spawn_actions_t act,
void (*atfork)(void *), void *arg)
{
diff --git a/src/spawn-w32.c b/src/spawn-w32.c
index 909929c..c21ac4b 100644
--- a/src/spawn-w32.c
+++ b/src/spawn-w32.c
@@ -73,6 +73,7 @@ struct gpgrt_spawn_actions {
void *hd[3];
void **inherit_hds;
char *env;
+ const char *const *envchange;
};
@@ -328,6 +329,147 @@ check_windows_version (void)
return is_vista_or_later;
}
+static gpg_err_code_t
+prepare_env_block (char **r_env, const char *const *envchange)
+{
+ gpg_err_code_t ec;
+ wchar_t *orig_env_block;
+ wchar_t *wp;
+ int i;
+ size_t envlen[256];
+ wchar_t *env_block;
+ size_t env_block_len;
+
+ const char *const *envp;
+ const char *e;
+ int env_num;
+
+ wp = orig_env_block = GetEnvironmentStringsW ();
+ for (i = 0; *wp != L'\0'; i++)
+ if (i >= DIM (envlen))
+ {
+ FreeEnvironmentStringsW (orig_env_block);
+ return GPG_ERR_TOO_LARGE;
+ }
+ else
+ wp += ((envlen[i] = wcslen (wp)) + 1);
+ wp++;
+ env_num = i;
+
+ env_block_len = (char *)wp - (char *)orig_env_block;
+ env_block = xtrymalloc (env_block_len);
+ if (!env_block)
+ {
+ FreeEnvironmentStringsW (orig_env_block);
+ return _gpg_err_code_from_syserror ();
+ }
+ memcpy (env_block, orig_env_block, env_block_len);
+ FreeEnvironmentStringsW (orig_env_block);
+
+ for (envp = envchange; (e = *envp); envp++)
+ {
+ wchar_t *we;
+ int off = 0;
+
+ we = _gpgrt_utf8_to_wchar (e);
+ if (!we)
+ {
+ ec = _gpg_err_code_from_syserror ();
+ goto leave;
+ }
+
+ wp = wcschr (we, L'=');
+ if (!wp)
+ {
+ /* Remove WE entry in the environment block. */
+ for (i = 0; i < env_num; i++)
+ if (!wcsncmp (&env_block[off], we, wcslen (we))
+ && env_block[off+wcslen (we)] == L'=')
+ break;
+ else
+ off += envlen[i] + 1;
+
+ if (i == env_num)
+ /* not found */;
+ else
+ {
+ env_block_len -= (envlen[i] + 1) * sizeof (wchar_t);
+ env_num--;
+ for (; i < env_num; i++)
+ {
+ int off0 = off;
+
+ off += envlen[i] + 1;
+ memmove (&env_block[off0], &env_block[off],
+ ((envlen[i] = envlen[i+1]) + 1) * sizeof (wchar_t));
+ }
+ env_block[(env_block_len / sizeof (wchar_t)) - 1] = L'\0';
+ }
+ }
+ else
+ {
+ size_t old_env_block_len;
+
+ for (i = 0; i < env_num; i++)
+ if (!wcsncmp (&env_block[off], we, wp - we + 1))
+ break;
+ else
+ off += envlen[i] + 1;
+
+ if (i < env_num)
+ {
+ int off0 = off;
+
+ off += envlen[i] + 1;
+ /* If an existing entry, remove it. */
+ env_block_len -= (envlen[i] + 1) * sizeof (wchar_t);
+ env_num--;
+ for (; i < env_num; i++)
+ {
+ size_t len = (envlen[i] = envlen[i+1]) + 1;
+
+ memmove (&env_block[off0], &env_block[off],
+ len * sizeof (wchar_t));
+ off0 += len;
+ off += len;
+ }
+ env_block[(env_block_len / sizeof (wchar_t)) - 1] = L'\0';
+ }
+
+ if (i >= DIM (envlen) - 1)
+ {
+ ec = GPG_ERR_TOO_LARGE;
+ _gpgrt_free_wchar (we);
+ goto leave;
+ }
+
+ old_env_block_len = env_block_len;
+ env_block_len += ((envlen[i++] = wcslen (we)) + 1) * sizeof (wchar_t);
+ env_num = i;
+ env_block = xtryrealloc (env_block, env_block_len);
+ if (!env_block)
+ {
+ ec = _gpg_err_code_from_syserror ();
+ _gpgrt_free_wchar (we);
+ goto leave;
+ }
+ memmove ((char *)env_block + old_env_block_len - sizeof (wchar_t),
+ we, (envlen[env_num - 1] + 1) * sizeof (wchar_t));
+ env_block[(env_block_len / sizeof (wchar_t)) - 1] = L'\0';
+ }
+
+ _gpgrt_free_wchar (we);
+ }
+ ec = 0;
+
+ leave:
+ if (ec)
+ xfree (env_block);
+ else
+ *r_env = (char *)env_block;
+
+ return ec;
+}
static gpg_err_code_t
spawn_detached (const char *pgmname, char *cmdline, gpgrt_spawn_actions_t act)
@@ -342,6 +484,7 @@ spawn_detached (const char *pgmname, char *cmdline, gpgrt_spawn_actions_t act)
int ret;
BOOL ask_inherit = FALSE;
int i;
+ char *env = NULL;
ec = _gpgrt_access (pgmname, X_OK);
if (ec)
@@ -425,6 +568,29 @@ spawn_detached (const char *pgmname, char *cmdline, gpgrt_spawn_actions_t act)
| CREATE_NEW_PROCESS_GROUP
| DETACHED_PROCESS);
+ if (act->env)
+ {
+ /* Either ENV or ENVCHANGE can be specified, not both. */
+ if (act->envchange)
+ {
+ xfree (cmdline);
+ return GPG_ERR_INV_ARG;
+ }
+
+ env = act->env;
+ }
+ else if (act->envchange)
+ {
+ ec = prepare_env_block (&env, act->envchange);
+ if (ec)
+ {
+ xfree (cmdline);
+ return ec;
+ }
+
+ cr_flags |= CREATE_UNICODE_ENVIRONMENT;
+ }
+
/* Take care: CreateProcessW may modify wpgmname */
if (!(wpgmname = _gpgrt_utf8_to_wchar (pgmname)))
ret = 0;
@@ -437,11 +603,14 @@ spawn_detached (const char *pgmname, char *cmdline, gpgrt_spawn_actions_t act)
&sec_attr, /* Thread security attributes. */
ask_inherit, /* Inherit handles. */
cr_flags, /* Creation flags. */
- act->env, /* Environment. */
+ env, /* Environment. */
NULL, /* Use current drive/directory. */
(STARTUPINFOW *)&si, /* Startup information. */
&pi /* Returns process information. */
);
+ if (act->envchange)
+ xfree (env);
+ env = NULL;
if (!ret)
{
if (!wpgmname || !wcmdline)
@@ -505,6 +674,13 @@ _gpgrt_spawn_actions_release (gpgrt_spawn_actions_t act)
xfree (act);
}
+void
+_gpgrt_spawn_actions_set_envchange (gpgrt_spawn_actions_t act,
+ const char *const *envchange)
+{
+ act->envchange = envchange;
+}
+
/* Set the environment block for child process.
* ENV is an ASCII encoded string, terminated by two zero bytes.
*/
@@ -552,6 +728,7 @@ _gpgrt_process_spawn (const char *pgmname, const char *argv[],
int i;
BOOL ask_inherit = FALSE;
struct gpgrt_spawn_actions act_default;
+ char *env = NULL;
if (!act)
{
@@ -783,6 +960,32 @@ _gpgrt_process_spawn (const char *pgmname, const char *argv[],
| ((flags & GPGRT_PROCESS_NO_CONSOLE) ? DETACHED_PROCESS : 0)
| GetPriorityClass (GetCurrentProcess ())
| CREATE_SUSPENDED);
+
+ if (act->env)
+ {
+ /* Either ENV or ENVCHANGE can be specified, not both. */
+ if (act->envchange)
+ {
+ xfree (process);
+ xfree (cmdline);
+ return GPG_ERR_INV_ARG;
+ }
+
+ env = act->env;
+ }
+ else if (act->envchange)
+ {
+ ec = prepare_env_block (&env, act->envchange);
+ if (ec)
+ {
+ xfree (process);
+ xfree (cmdline);
+ return ec;
+ }
+
+ cr_flags |= CREATE_UNICODE_ENVIRONMENT;
+ }
+
if (!(wpgmname = _gpgrt_utf8_to_wchar (pgmname)))
ret = 0;
else if (!(wcmdline = _gpgrt_utf8_to_wchar (cmdline)))
@@ -794,11 +997,14 @@ _gpgrt_process_spawn (const char *pgmname, const char *argv[],
&sec_attr, /* Thread security attributes. */
ask_inherit, /* Inherit handles. */
cr_flags, /* Creation flags. */
- act->env, /* Environment. */
+ env, /* Environment. */
NULL, /* Use current drive/directory. */
(STARTUPINFOW *)&si, /* Startup information. */
&pi /* Returns process information. */
);
+ if (act->envchange)
+ xfree (env);
+ env = NULL;
if (!ret)
{
if (!wpgmname || !wcmdline)
diff --git a/src/visibility.c b/src/visibility.c
index 0e8121e..15b38b4 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1145,6 +1145,13 @@ gpgrt_spawn_actions_release (gpgrt_spawn_actions_t act)
_gpgrt_spawn_actions_release (act);
}
+void
+gpgrt_spawn_actions_set_envchange (gpgrt_spawn_actions_t act,
+ const char *const *env)
+{
+ _gpgrt_spawn_actions_set_envchange (act, env);
+}
+
#ifdef HAVE_W32_SYSTEM
void
gpgrt_spawn_actions_set_envvars (gpgrt_spawn_actions_t act,
diff --git a/src/visibility.h b/src/visibility.h
index 29ebaee..748a42a 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -231,6 +231,7 @@ MARK_VISIBLE (gpgrt_absfnameconcat)
MARK_VISIBLE (gpgrt_spawn_actions_new)
MARK_VISIBLE (gpgrt_spawn_actions_release)
+MARK_VISIBLE (gpgrt_spawn_actions_set_envchange)
#ifdef HAVE_W32_SYSTEM
MARK_VISIBLE (gpgrt_spawn_actions_set_envvars)
MARK_VISIBLE (gpgrt_spawn_actions_set_redirect)
@@ -423,6 +424,7 @@ MARK_VISIBLE (gpgrt_spawn_actions_set_atfork)
#define gpgrt_spawn_actions_new _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_spawn_actions_release _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_spawn_actions_set_envchange _gpgrt_USE_UNDERSCORED_FUNCTION
#ifdef HAVE_W32_SYSTEM
#define gpgrt_spawn_actions_set_envvars _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_spawn_actions_set_redirect _gpgrt_USE_UNDERSCORED_FUNCTION