1
/*********************************************************
2
* Copyright (C) 2010 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
*********************************************************/
20
* vixToolsEnvVars.c --
22
* Routines that encapsulate the complexity of dealing with
23
* environment variables when the process may be impersonating
29
#include <crt_externs.h>
37
#include "vixToolsInt.h"
41
extern char **environ;
44
struct VixToolsEnvIterator {
47
VIX_TOOLS_ENV_TYPE_ENV_BLOCK = 1,
48
VIX_TOOLS_ENV_TYPE_ENVIRON,
51
/* Used when envType is VIX_TOOLS_ENV_TYPE_ENV_BLOCK. */
53
wchar_t *envBlock; // Keep the original around to free.
56
/* Used when envType is VIX_TOOLS_ENV_TYPE_ENVIRON. */
65
struct VixToolsUserEnvironment {
68
wchar_t *envBlock; // Only used when impersonated == TRUE.
70
// The POSIX versions don't need any state currently.
77
*-----------------------------------------------------------------------------
79
* VixToolsNewEnvIterator --
81
* Create a new environment variable iterator for the user
82
* represented by 'userToken'.
83
* The resulting VixToolsEnvIterator must be freed using
84
* VixToolsDestroyEnvIterator.
92
*-----------------------------------------------------------------------------
96
VixToolsNewEnvIterator(void *userToken, // IN
97
VixToolsEnvIterator **envItr) // OUT
99
VixError err = VIX_OK;
100
VixToolsEnvIterator *it = Util_SafeMalloc(sizeof *it);
102
if (NULL == envItr) {
110
if (PROCESS_CREATOR_USER_TOKEN != userToken) {
112
* The process is impersonating a user, so retrieve the user's
113
* environment block instead of using the process's environment.
115
it->envType = VIX_TOOLS_ENV_TYPE_ENV_BLOCK;
116
err = VixToolsGetEnvBlock(userToken, &it->data.eb.envBlock);
117
if (VIX_FAILED(err)) {
120
it->data.eb.currEnvVar = it->data.eb.envBlock;
123
* The action is being performed as the user running the process
124
* so the process's environment is fine.
125
* TODO: Is this totally equivilent to the behavior when impersonated?
126
* Would fetching the environment block include changes to the user's
127
* or system's environment made after the process is running?
129
it->envType = VIX_TOOLS_ENV_TYPE_ENVIRON;
130
it->data.environ = _wenviron;
132
#elif defined(__APPLE__)
133
it->environ = *_NSGetEnviron();
134
#elif defined(__FreeBSD__)
136
* Looking at /build/toolchain/bsd32/freebsd-6.3/usr/include/stand.h,
137
* environ is a pointer to a doubly linked list of structs. I guess they
138
* just want to be different. Anyway, this is something that needs
139
* work if we want to support FreeBSD.
141
err = VIX_E_NOT_SUPPORTED;
144
it->environ = environ;
148
if (VIX_FAILED(err)) {
157
*-----------------------------------------------------------------------------
159
* VixToolsGetNextEnvVar --
161
* Get the next envariable variable pair in the form NAME=VALUE.
164
* A heap-allocated UTF-8 string, or NULL when the iterator has
168
* Advances the iterator.
170
*-----------------------------------------------------------------------------
174
VixToolsGetNextEnvVar(VixToolsEnvIterator *envItr) // IN
178
if (NULL == envItr) {
183
if (VIX_TOOLS_ENV_TYPE_ENV_BLOCK == envItr->envType) {
184
if (L'\0' == envItr->data.eb.currEnvVar[0]) {
187
envVar = Unicode_AllocWithUTF16(envItr->data.eb.currEnvVar);
188
while(*envItr->data.eb.currEnvVar++);
190
} else if (VIX_TOOLS_ENV_TYPE_ENVIRON == envItr->envType) {
191
if (NULL == *envItr->data.environ) {
194
envVar = Unicode_AllocWithUTF16(*envItr->data.environ);
195
envItr->data.environ++;
198
/* Is someone using uninitialized memory? */
202
if (NULL == *envItr->environ) {
205
envVar = Unicode_Alloc(*envItr->environ, STRING_ENCODING_DEFAULT);
214
*-----------------------------------------------------------------------------
216
* VixToolsDestroyEnvIterator --
218
* Free()s any memory associated with the VixToolsEnvIterator.
226
*-----------------------------------------------------------------------------
230
VixToolsDestroyEnvIterator(VixToolsEnvIterator *envItr) // IN
232
if (NULL != envItr) {
234
if (VIX_TOOLS_ENV_TYPE_ENV_BLOCK == envItr->envType) {
235
if (NULL != envItr->data.eb.envBlock) {
236
VixToolsDestroyEnvironmentBlock(envItr->data.eb.envBlock);
246
*-----------------------------------------------------------------------------
248
* VixToolsNewUserEnvironment --
250
* Create a new UserEnvironment that can be used to query for
251
* environment variables.
259
*-----------------------------------------------------------------------------
263
VixToolsNewUserEnvironment(void *userToken, // IN
264
VixToolsUserEnvironment **env) // OUT
266
VixError err = VIX_OK;
267
VixToolsUserEnvironment *myEnv = Util_SafeMalloc(sizeof *myEnv);
277
if (PROCESS_CREATOR_USER_TOKEN != userToken) {
278
myEnv->impersonated = TRUE;
279
err = VixToolsGetEnvBlock(userToken, &myEnv->envBlock);
280
if (VIX_FAILED(err)) {
284
myEnv->impersonated = FALSE;
285
/* We will just read from the process's environment. */
292
if (VIX_FAILED(err)) {
301
*-----------------------------------------------------------------------------
303
* VixToolsGetEnvFromUserEnvironment --
305
* Looks up the environment variable given by 'name' in the provided
309
* A heap-allocated UTF-8 string, or NULL if the environment variable
315
*-----------------------------------------------------------------------------
319
VixToolsGetEnvFromUserEnvironment(const VixToolsUserEnvironment *env, // IN
320
const char *name) // IN
329
if (env->impersonated) {
330
envVar = VixToolsGetEnvVarFromEnvBlock(env->envBlock, name);
332
envVar = Util_SafeStrdup(Posix_Getenv(name));
335
envVar = Util_SafeStrdup(Posix_Getenv(name));
343
*-----------------------------------------------------------------------------
345
* VixToolsDestroyUserEnvironment --
347
* Releases any resources used by the VixToolsUserEnvironment.
348
* The VixToolsUserEnvironment must not be used after calling
357
*-----------------------------------------------------------------------------
361
VixToolsDestroyUserEnvironment(VixToolsUserEnvironment *env) // IN
365
if (NULL != env->envBlock) {
366
if (env->impersonated) {
367
VixToolsDestroyEnvironmentBlock(env->envBlock);
378
*-----------------------------------------------------------------------------
380
* VixToolsEnvironToEnvBlock --
382
* Converts a NULL terminated array of UTF-8 environment variables in
383
* the form NAME=VALUE to an Win32 environment block, which is a single
384
* contiguous array containing UTF-16 environment variables in the same
385
* form, each separated by a UTF-16 null character, followed by two
386
* training null characters.
394
*-----------------------------------------------------------------------------
398
VixToolsEnvironToEnvBlock(char const * const *environ, // IN: UTF-8
399
wchar_t **envBlock) // OUT
404
static const wchar_t nullTerm[] = { L'\0', L'\0' };
408
if ((NULL == environ) || (NULL == envBlock)) {
415
while (NULL != *environ) {
416
wchar_t *envVar = Unicode_GetAllocUTF16(*environ);
418
res = DynBuf_Append(&buf, envVar,
419
(wcslen(envVar) + 1) * sizeof(*envVar));
422
err = VIX_E_OUT_OF_MEMORY;
429
* Append two null characters at the end. This adds an extra (third) null
430
* if there was at least one environment variable (since there already
431
* is one after the last string) but we need both if there were no
432
* environment variables in the input array. I'll waste two bytes to
433
* keep the code a little simpler.
435
res = DynBuf_Append(&buf, nullTerm, sizeof nullTerm);
437
err = VIX_E_OUT_OF_MEMORY;
441
*envBlock = DynBuf_Detach(&buf);
445
DynBuf_Destroy(&buf);
453
*-----------------------------------------------------------------------------
455
* VixToolsValidateEnviron --
457
* Ensures that the NULL terminated array of strings contains
458
* properly formated environment variables.
466
*-----------------------------------------------------------------------------
470
VixToolsValidateEnviron(char const * const *environ) // IN
472
if (NULL == environ) {
476
while (NULL != *environ) {
478
* Each string should contain at least one '=', to delineate between
479
* the name and the value.
481
if (NULL == Str_Strchr(*environ, '=')) {
482
return VIX_E_INVALID_ARG;
494
*-----------------------------------------------------------------------------
496
* TestVixToolsEnvironToEnvBlockEmptyEnviron --
498
* Tests VixToolsEnvironToEnvBlock() with an empty environment: an
499
* char ** pointing to a single NULL pointer.
507
*-----------------------------------------------------------------------------
511
TestVixToolsEnvironToEnvBlockEmptyEnviron(void)
513
const char *environ1[] = { NULL };
517
err = VixToolsEnvironToEnvBlock(environ1, &envBlock);
518
ASSERT(VIX_OK == err);
520
ASSERT((L'\0' == envBlock[0]) && (L'\0' == envBlock[1]));
526
*-----------------------------------------------------------------------------
528
* TestVixToolsEnvironToEnvBlockTwoGood --
530
* Tests VixToolsEnvironToEnvBlock() with an environment containing
539
*-----------------------------------------------------------------------------
543
TestVixToolsEnvironToEnvBlockTwoGood(void)
545
const char *environ1[] = { "foo=bar", "env=block", NULL };
546
wchar_t *envBlock, *currPos;
549
err = VixToolsEnvironToEnvBlock(environ1, &envBlock);
550
ASSERT(VIX_OK == err);
553
ASSERT(wcscmp(currPos, L"foo=bar") == 0);
554
currPos += wcslen(L"foo=bar") + 1;
555
ASSERT(wcscmp(currPos, L"env=block") == 0);
561
*-----------------------------------------------------------------------------
563
* TestVixToolsEnvironToEnvBlock --
565
* Runs unit tests for VixToolsEnvironToEnvBlock().
573
*-----------------------------------------------------------------------------
577
TestVixToolsEnvironToEnvBlock(void)
579
TestVixToolsEnvironToEnvBlockEmptyEnviron();
580
TestVixToolsEnvironToEnvBlockTwoGood();
582
#endif // #ifdef _WIN32
586
*-----------------------------------------------------------------------------
588
* TestVixToolsValidateEnvironEmptyEnviron --
590
* Tests VixToolsEnvironToEnvBlock() with an empty environment.
598
*-----------------------------------------------------------------------------
602
TestVixToolsValidateEnvironEmptyEnviron(void)
604
const char *environ1[] = { NULL };
607
err = VixToolsValidateEnviron(environ1);
608
ASSERT(VIX_OK == err);
613
*-----------------------------------------------------------------------------
615
* TestVixToolsValidateEnvironTwoGoodVars --
617
* Tests VixToolsEnvironToEnvBlock() with an environment containing
618
* two valid environment variables.
626
*-----------------------------------------------------------------------------
630
TestVixToolsValidateEnvironTwoGoodVars(void)
632
const char *environ1[] = { "foo=bar", "vix=api", NULL };
635
err = VixToolsValidateEnviron(environ1);
636
ASSERT(VIX_OK == err);
641
*-----------------------------------------------------------------------------
643
* TestVixToolsValidateEnvironOneBad --
645
* Tests VixToolsEnvironToEnvBlock() with an environment containing
646
* one invalid environment variable.
654
*-----------------------------------------------------------------------------
658
TestVixToolsValidateEnvironOneBad(void)
660
const char *environ1[] = { "noequals", NULL };
663
err = VixToolsValidateEnviron(environ1);
664
ASSERT(VIX_E_INVALID_ARG == err);
669
*-----------------------------------------------------------------------------
671
* TestVixToolsValidateEnvironSecondBad --
673
* Tests VixToolsEnvironToEnvBlock() with an environment containing
674
* one valid environment variable followed by one invalid environment
683
*-----------------------------------------------------------------------------
687
TestVixToolsValidateEnvironSecondBad(void)
689
const char *environ1[] = { "foo=bar", "noequals", NULL };
692
err = VixToolsValidateEnviron(environ1);
693
ASSERT(VIX_E_INVALID_ARG == err);
698
*-----------------------------------------------------------------------------
700
* TestVixToolsValidateEnviron --
702
* Run unit tests for VixToolsValidateEnviron().
710
*-----------------------------------------------------------------------------
714
TestVixToolsValidateEnviron(void)
716
TestVixToolsValidateEnvironEmptyEnviron();
717
TestVixToolsValidateEnvironTwoGoodVars();
718
TestVixToolsValidateEnvironOneBad();
719
TestVixToolsValidateEnvironSecondBad();
724
*-----------------------------------------------------------------------------
726
* TextVixToolsEnvVars --
728
* Run unit tests for functions in this file.
736
*-----------------------------------------------------------------------------
740
TestVixToolsEnvVars(void)
743
TestVixToolsEnvironToEnvBlock();
745
TestVixToolsValidateEnviron();
747
#endif // #ifdef VMX86_DEVEL