summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2014-12-02 10:16:03 +0000
committerCorinna Vinschen <corinna@vinschen.de>2014-12-02 10:16:03 +0000
commit9119d13db870473f40d7678a980009e12a0d2379 (patch)
treeb5227028ccff6e9566a25bd251d74b51e40a4ce0 /winsup/cygwin
parent0c326d84b59308341b3c88394373c7dd8b4918dc (diff)
downloadcygnal-9119d13db870473f40d7678a980009e12a0d2379.tar.gz
cygnal-9119d13db870473f40d7678a980009e12a0d2379.tar.bz2
cygnal-9119d13db870473f40d7678a980009e12a0d2379.zip
* autoload.cc (CreateEnvironmentBlock): Import.
(DestroyEnvironmentBlock): Import. * environ.cc (env_compare): New static bsearch comparison function. (build_env): Add parameter taking a user token. If token is non-NULL, fetch user's default Windows environment and merge it into the resulting environment. Explain what we do in preceeding comment. * environ,h (build_env): Align prototype to above change. * external.cc (create_winenv): Call build_env with NULL token. * spawn.cc (child_info_spawn::worker): When spawning new process under another user account, call build_env with new token to allow merging user's default Windows environment. * winlean.h (_USERENV_): Define to override dllimport.
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/ChangeLog15
-rw-r--r--winsup/cygwin/autoload.cc3
-rw-r--r--winsup/cygwin/environ.cc113
-rw-r--r--winsup/cygwin/environ.h4
-rw-r--r--winsup/cygwin/external.cc3
-rw-r--r--winsup/cygwin/spawn.cc8
-rw-r--r--winsup/cygwin/winlean.h1
7 files changed, 137 insertions, 10 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 7251509cd..8e7bebad4 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,20 @@
2014-12-02 Corinna Vinschen <corinna@vinschen.de>
+ * autoload.cc (CreateEnvironmentBlock): Import.
+ (DestroyEnvironmentBlock): Import.
+ * environ.cc (env_compare): New static bsearch comparison function.
+ (build_env): Add parameter taking a user token. If token is non-NULL,
+ fetch user's default Windows environment and merge it into the resulting
+ environment. Explain what we do in preceeding comment.
+ * environ,h (build_env): Align prototype to above change.
+ * external.cc (create_winenv): Call build_env with NULL token.
+ * spawn.cc (child_info_spawn::worker): When spawning new process under
+ another user account, call build_env with new token to allow merging
+ user's default Windows environment.
+ * winlean.h (_USERENV_): Define to override dllimport.
+
+2014-12-02 Corinna Vinschen <corinna@vinschen.de>
+
* spawn.cc (child_info_spawn::worker): Fix formatting.
2014-12-02 Corinna Vinschen <corinna@vinschen.de>
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 6340e8080..7859725ff 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -675,6 +675,9 @@ LoadDLLfunc (SetParent, 8, user32)
LoadDLLfunc (SetProcessWindowStation, 4, user32)
LoadDLLfunc (SetThreadDesktop, 4, user32)
+LoadDLLfunc (CreateEnvironmentBlock, 12, userenv)
+LoadDLLfunc (DestroyEnvironmentBlock, 4, userenv)
+
LoadDLLfuncEx3 (waveInAddBuffer, 12, winmm, 1, 0, 1)
LoadDLLfuncEx3 (waveInClose, 4, winmm, 1, 0, 1)
LoadDLLfuncEx3 (waveInGetNumDevs, 0, winmm, 1, 0, 1)
diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc
index 9b9be4a00..e33256fe3 100644
--- a/winsup/cygwin/environ.cc
+++ b/winsup/cygwin/environ.cc
@@ -9,12 +9,14 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
#include "winsup.h"
+#include <userenv.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include <ctype.h>
#include <locale.h>
#include <assert.h>
+#include <sys/param.h>
#include <cygwin/version.h>
#include "pinfo.h"
#include "perprocess.h"
@@ -1047,14 +1049,39 @@ raise_envblock (int new_tl, PWCHAR &envblock, PWCHAR &s)
#define SPENVS_SIZE (sizeof (spenvs) / sizeof (spenvs[0]))
+int
+env_compare (const void *key, const void *memb)
+{
+ const char *k = *(const char **) key;
+ const char *m = *(const char **) memb;
+
+ char *ke = strchr (k, '=');
+ char *me = strchr (m, '=');
+ if (ke == NULL || me == NULL)
+ return strcasecmp (k, m);
+ int ret = strncasecmp (k, m, MIN (ke - k, me - m));
+ if (!ret)
+ ret = (ke - k) - (me - m);
+ return ret;
+}
+
/* Create a Windows-style environment block, i.e. a typical character buffer
filled with null terminated strings, terminated by double null characters.
Converts environment variables noted in conv_envvars into win32 form
- prior to placing them in the string. */
+ prior to placing them in the string.
+
+ If new_token is set, we're going to switch the user account in
+ child_info_spawn::worker. If so, we're also fetching the Windows default
+ environment for the new user, and merge it into the environment we propage
+ to the child. */
char ** __reg3
build_env (const char * const *envp, PWCHAR &envblock, int &envc,
- bool no_envblock)
+ bool no_envblock, HANDLE new_token)
{
+ PWCHAR cwinenv = NULL;
+ size_t winnum = 0;
+ char **winenv = NULL;
+
int len, n;
const char * const *srcp;
char **dstp;
@@ -1066,13 +1093,57 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc,
for (n = 0; envp[n]; n++)
continue;
+ /* Fetch windows env and convert to POSIX-style env. */
+ if (new_token
+ && CreateEnvironmentBlock ((LPVOID *) &cwinenv, new_token, FALSE))
+ {
+ PWCHAR var = cwinenv;
+ while (*var)
+ {
+ ++winnum;
+ var = wcschr (var, L'\0') + 1;
+ }
+ winenv = (char **) calloc (winnum + 1, sizeof (char *));
+ if (winenv)
+ {
+ for (winnum = 0, var = cwinenv;
+ *var;
+ ++winnum, var = wcschr (var, L'\0') + 1)
+ sys_wcstombs_alloc (&winenv[winnum], HEAP_NOTHEAP, var);
+ }
+ DestroyEnvironmentBlock (cwinenv);
+ /* Eliminate variables which are already available in envp. The windows
+ env is sorted, so we can use bsearch. We're doing this first step,
+ so the following code doesn't allocate too much memory. */
+ if (winenv)
+ {
+ for (srcp = envp; *srcp; srcp++)
+ {
+ char **elem = (char **) bsearch (srcp, winenv, winnum,
+ sizeof *winenv, env_compare);
+ if (elem)
+ {
+ system_printf ("remove: %s", *elem);
+ free (*elem);
+ /* Use memmove to keep array sorted.
+ winnum - (elem - winenv) copies all elements following
+ elem, including the trailing NULL pointer. */
+ memmove (elem, elem + 1,
+ (winnum - (elem - winenv)) * sizeof *elem);
+ --winnum;
+ }
+ }
+ }
+ }
+
/* Allocate a new "argv-style" environ list with room for extra stuff. */
char **newenv = (char **) cmalloc_abort (HEAP_1_ARGV, sizeof (char *) *
- (n + SPENVS_SIZE + 1));
+ (n + winnum + SPENVS_SIZE + 1));
int tl = 0;
char **pass_dstp;
- char **pass_env = (char **) alloca (sizeof (char *) * (n + SPENVS_SIZE + 1));
+ char **pass_env = (char **) alloca (sizeof (char *)
+ * (n + winnum + SPENVS_SIZE + 1));
/* Iterate over input list, generating a new environment list and refreshing
"special" entries, if necessary. */
for (srcp = envp, dstp = newenv, pass_dstp = pass_env; *srcp; srcp++)
@@ -1107,19 +1178,49 @@ build_env (const char * const *envp, PWCHAR &envblock, int &envc,
assert ((srcp - envp) == n);
/* Fill in any required-but-missing environment variables. */
for (unsigned i = 0; i < SPENVS_SIZE; i++)
- if (!saw_spenv[i] && (spenvs[i].force_into_environment || cygheap->user.issetuid ()))
+ if (!saw_spenv[i] && (spenvs[i].force_into_environment
+ || cygheap->user.issetuid ()))
{
*dstp = spenvs[i].retrieve (false);
if (*dstp && *dstp != env_dontadd)
{
*pass_dstp++ = *dstp;
tl += strlen (*dstp) + 1;
+ /* Eliminate from winenv. */
+ if (winenv)
+ {
+ char **elem = (char **) bsearch (dstp, winenv, winnum,
+ sizeof *winenv, env_compare);
+ if (elem)
+ {
+ system_printf ("remove: %s", *elem);
+ free (*elem);
+ memmove (elem, elem + 1,
+ (winnum - (elem - winenv)) * sizeof *elem);
+ --winnum;
+ }
+ }
dstp++;
}
}
+ /* Fill in any Windows environment vars still missing. */
+ if (winenv)
+ {
+ char **elem;
+ for (elem = winenv; *elem; ++elem)
+ {
+ *dstp = cstrdup1 (*elem);
+ free (*elem);
+ *pass_dstp++ = *dstp;
+ tl += strlen (*dstp) + 1;
+ ++dstp;
+ }
+ free (winenv);
+ }
+
envc = dstp - newenv; /* Number of entries in newenv */
- assert ((size_t) envc <= (n + SPENVS_SIZE));
+ assert ((size_t) envc <= (n + winnum + SPENVS_SIZE));
*dstp = NULL; /* Terminate */
size_t pass_envc = pass_dstp - pass_env;
diff --git a/winsup/cygwin/environ.h b/winsup/cygwin/environ.h
index b2d65c8bd..5048fcd2f 100644
--- a/winsup/cygwin/environ.h
+++ b/winsup/cygwin/environ.h
@@ -1,6 +1,6 @@
/* environ.h: Declarations for environ manipulation
- Copyright 2000, 2001, 2002, 2003, 2005, 2006, 2008, 2013 Red Hat, Inc.
+ Copyright 2000, 2001, 2002, 2003, 2005, 2006, 2008, 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -45,6 +45,6 @@ extern "C" char **__cygwin_environ, ***main_environ;
extern "C" char __stdcall **cur_environ ();
#endif
char ** __reg3 build_env (const char * const *envp, PWCHAR &envblock,
- int &envc, bool need_envblock);
+ int &envc, bool need_envblock, HANDLE new_token);
#define ENV_CVT -1
diff --git a/winsup/cygwin/external.cc b/winsup/cygwin/external.cc
index b42c284e1..5fac4bb66 100644
--- a/winsup/cygwin/external.cc
+++ b/winsup/cygwin/external.cc
@@ -138,7 +138,8 @@ create_winenv (const char * const *env)
{
int unused_envc;
PWCHAR envblock = NULL;
- char **envp = build_env (env ?: cur_environ (), envblock, unused_envc, false);
+ char **envp = build_env (env ?: cur_environ (), envblock, unused_envc, false,
+ NULL);
PWCHAR p = envblock;
if (envp)
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index e29ba6a8c..a0686c5d8 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -531,8 +531,14 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
if (!real_path.iscygexec())
::cygheap->fdtab.set_file_pointers_for_exec ();
+ /* If we switch the user, merge the user's Windows environment. */
+ bool switch_user = ::cygheap->user.issetuid ()
+ && (::cygheap->user.saved_uid
+ != ::cygheap->user.real_uid);
moreinfo->envp = build_env (envp, envblock, moreinfo->envc,
- real_path.iscygexec ());
+ real_path.iscygexec (),
+ switch_user ? ::cygheap->user.primary_token ()
+ : NULL);
if (!moreinfo->envp || !envblock)
{
set_errno (E2BIG);
diff --git a/winsup/cygwin/winlean.h b/winsup/cygwin/winlean.h
index 63cebdb96..329199a28 100644
--- a/winsup/cygwin/winlean.h
+++ b/winsup/cygwin/winlean.h
@@ -28,6 +28,7 @@ details. */
#define _SHELL32_
#define _SPOOL32_
#define _USER32_
+#define _USERENV_
#define _WINMM_
#define WINIMPM
#define WINSOCK_API_LINKAGE