]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
VMTools: services/apps use config env settings to override unhandled system env
authorKruti Pendharkar <kp025370@broadcom.com>
Wed, 10 Dec 2025 05:31:19 +0000 (21:31 -0800)
committerKruti Pendharkar <kp025370@broadcom.com>
Wed, 10 Dec 2025 05:31:19 +0000 (21:31 -0800)
settings

Previously, only the VMToolsd service and user process would use the
config file set or unset environment settings, and only when the process name
was known (vmsvc, vmusr).

The code to process the config environment variables has moved from tools core to
vmtools library.

17 files changed:
open-vm-tools/lib/include/vmware/tools/utils.h
open-vm-tools/libvmtools/Makefile.am
open-vm-tools/libvmtools/i18n.c
open-vm-tools/libvmtools/vmtoolsMisc.c [new file with mode: 0644]
open-vm-tools/services/vmtoolsd/cmdLine.c
open-vm-tools/services/vmtoolsd/mainLoop.c
open-vm-tools/services/vmtoolsd/mainPosix.c
open-vm-tools/toolbox/toolbox-cmd.c
open-vm-tools/vgauth/cli/Makefile.am
open-vm-tools/vgauth/cli/main.c
open-vm-tools/vgauth/common/i18n.c
open-vm-tools/vgauth/common/prefs.c
open-vm-tools/vgauth/common/prefs.h
open-vm-tools/vgauth/lib/common.c
open-vm-tools/vgauth/service/Makefile.am
open-vm-tools/vgauth/service/main.c
open-vm-tools/vgauthImport/vgauthImport.c

index d31a03eba39b7b1f8f71fd1700c8eef2099ecc48..8fec8af3f3120149796a47eb2c3016ca73ad0f75 100644 (file)
@@ -177,6 +177,11 @@ VMTools_GetLibdir(void);
 
 #endif
 
+void
+VMTools_SetupEnv(const gchar *appName,
+                 GKeyFile *config,
+                 gboolean globalVars);
+
 GSource *
 VMTools_CreateTimer(gint timeout);
 
index 3e0ea0f32f5b9b32704338f0640325747689824c..12f4d96438493b8a13f62c4bebe55cfb7b9e9cdf 100644 (file)
@@ -1,5 +1,7 @@
 ################################################################################
-### Copyright (c) 2008-2021,2023 VMware, Inc.  All rights reserved.
+### Copyright (c) 2008-2025 Broadcom. All Rights Reserved.
+### Broadcom Confidential. The term "Broadcom" refers to Broadcom Inc.
+### and/or its subsidiaries.
 ###
 ### This program is free software; you can redistribute it and/or modify
 ### it under the terms of version 2 of the GNU General Public License as
@@ -73,6 +75,7 @@ libvmtools_la_SOURCES += signalSource.c
 libvmtools_la_SOURCES += vmtools.c
 libvmtools_la_SOURCES += vmtoolsConfig.c
 libvmtools_la_SOURCES += vmtoolsLog.c
+libvmtools_la_SOURCES += vmtoolsMisc.c
 libvmtools_la_SOURCES += vmxLogger.c
 
 # Recompile the stub for Log_* functions, but not Log() itself (see -DNO_LOG_STUB).
@@ -80,7 +83,7 @@ libvmtools_la_SOURCES += $(top_srcdir)/lib/stubs/stub-log.c
 
 libvmtools_la_CPPFLAGS =
 libvmtools_la_CPPFLAGS += -DVMTOOLS_USE_GLIB
-libvmtools_la_CPPFLAGS += -DNO_LOG_STUB
+libvmtools_la_CPPFLAGS += -DNO_LOG_STUB -DG_LOG_DOMAIN=\"vmtoolslib\"
 libvmtools_la_CPPFLAGS += -DVMTOOLS_DATA_DIR=\"$(datadir)/open-vm-tools\"
 libvmtools_la_CPPFLAGS += @GLIB2_CPPFLAGS@
 
index bbed57ed40b2736cce7e65f9324c594478873fb4..4caeb16e7d2764d218dc3e392530a5125b7511cb 100644 (file)
@@ -482,8 +482,9 @@ MsgLoadCatalog(const char *path)
    stream = g_io_channel_new_file(localPath, "r", &err);
    VMTOOLS_RELEASE_FILENAME_LOCAL(localPath);
 
-   if (err != NULL) {
-      g_debug("Unable to open '%s': %s\n", path, err->message);
+   if (stream == NULL) {
+      g_debug("Unable to open '%s': %s\n", path,
+              err != NULL ? err->message : "No GError");
       g_clear_error(&err);
       return NULL;
    }
@@ -495,21 +496,22 @@ MsgLoadCatalog(const char *path)
       gboolean eof = FALSE;
       char *name = NULL;
       char *value = NULL;
-      gchar *line;
 
       /* Read the next key / value pair. */
       for (;;) {
          gsize i;
          gsize len;
          gsize term;
+         gchar *line = NULL;
          char *unused = NULL;
          gboolean cont = FALSE;
+         GIOStatus status;
 
-         g_io_channel_read_line(stream, &line, &len, &term, &err);
+         status = g_io_channel_read_line(stream, &line, &len, &term, &err);
 
-         if (err != NULL) {
+         if (status == G_IO_STATUS_ERROR) {
             g_warning("Unable to read a line from '%s': %s\n",
-                      path, err->message);
+                      path, err != NULL ? err->message : "No GError");
             g_clear_error(&err);
             error = TRUE;
             g_free(line);
diff --git a/open-vm-tools/libvmtools/vmtoolsMisc.c b/open-vm-tools/libvmtools/vmtoolsMisc.c
new file mode 100644 (file)
index 0000000..a9d6020
--- /dev/null
@@ -0,0 +1,657 @@
+/*********************************************************
+ * Copyright (c) 2012-2025 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
+ *
+ * This program 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 version 2.1 and no later version.
+ *
+ * This program 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 Lesser 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file vmtoolsMisc.c
+ *
+ *    Convenience functions for retrieving the information about the
+ *    Tools Insallation (Eg: library files location).
+ */
+#if defined(_WIN32)
+#include "windowsu.h"
+#else
+#include "posix.h"
+#endif
+#include "vmware/tools/utils.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <glib/gstdio.h>
+#ifdef _WIN32
+#include <wincrypt.h>
+#include "w32Messages.h"
+#endif
+#include "conf.h"
+#include "err.h"
+#include "util.h"
+#include "dictll.h"
+#include "guestApp.h"
+
+#ifndef _WIN32
+
+/**
+ * Reads the /etc/vmware-tools/config file and returns the vlaue of
+ * 'libdir' property.
+ *
+ * @return The value of 'libdir' property. NULL if the 'libdir' property is
+ * not found in the config file.
+ */
+
+gchar *
+VMTools_GetLibdir(void)
+{
+   gchar *confDirPath = NULL;
+   gchar *confFilePath = NULL;
+   gchar *localPath = NULL;
+   FILE *stream = NULL;
+   char *libdirValue = NULL;
+   char *line = NULL;
+   char *name = NULL;
+   char *value = NULL;
+
+   confDirPath = GuestApp_GetConfPath();
+
+   if (confDirPath == NULL) {
+      Panic("%s: Could not get path to the configuration file.\n", __FUNCTION__);
+   }
+
+   confFilePath = g_strdup_printf("%s%sconfig", confDirPath, DIRSEPS);
+   localPath = VMTOOLS_GET_FILENAME_LOCAL(confFilePath, NULL);
+   if (localPath == NULL) {
+      g_warning("Error converting path to local encoding.");
+      goto exit;
+   }
+
+   stream = g_fopen(localPath, "r");
+   if (stream == NULL) {
+      g_debug("%s: Failed to open file \"%s\": %s\n",
+              __FUNCTION__, confFilePath, Err_ErrString());
+      goto exit;
+   }
+
+   while (DictLL_ReadLine(stream, &line, &name, &value)
+          == DictLL_ReadLineSuccess) {
+      if (strcmp(name, "libdir") == 0) {
+         libdirValue = Util_SafeStrdup(value);
+         break;
+      }
+
+      free(line);
+      line = NULL;
+      free(name);
+      name = NULL;
+      free(value);
+      value = NULL;
+   }
+
+exit:
+
+   free(line);
+   line = NULL;
+   free(name);
+   name = NULL;
+   free(value);
+   value = NULL;
+
+   if (stream != NULL && fclose(stream)) {
+      g_warning("%s: Unable to close \"%s\": %s\n",
+                __FUNCTION__, confFilePath, Err_ErrString());
+   }
+
+   VMTOOLS_RELEASE_FILENAME_LOCAL(localPath);
+   g_free(confFilePath);
+   g_free(confDirPath);
+
+   return libdirValue;
+}
+#else  // _WIN32
+#define POWERSHELL_GPO_REG_KEY \
+        "Software\\Policies\\Microsoft\\Windows\\PowerShell"
+#define POWERSHELL_GPO_EXEC_POLICY "ExecutionPolicy"
+#define VMW_CERT_ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
+
+
+/*
+ ******************************************************************************
+ * VMTools_IsGPOExecPolicyAllSigned --
+ *
+ * Check the powershell GPO machine execution policy
+ *
+ * @return TRUE if powershell GPO MachinePolicy is set to AllSigned.
+ *         FALSE in case of error or if MachinePolicy is not AllSigned.
+ *
+ * Side effects:
+ *      None.
+ *
+ ******************************************************************************
+ */
+
+gboolean
+VMTools_IsGPOExecPolicyAllSigned(void)
+{
+   LONG ret;
+   HKEY hKey;
+   DWORD regSz;
+   gchar buf[32];
+   /* Set len to one less than sizeof(buf) to null terminate buf */
+   DWORD len = sizeof(buf) - 1;
+
+   ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+                       POWERSHELL_GPO_REG_KEY,
+                       0,
+                       KEY_READ,
+                       &hKey);
+   if (ret != ERROR_SUCCESS) {
+      g_debug("%s: Registry open failed.\n", __FUNCTION__);
+      return FALSE;
+   }
+
+   ret = RegQueryValueExA(hKey,
+                          POWERSHELL_GPO_EXEC_POLICY,
+                          NULL,
+                          &regSz,
+                          (LPBYTE)buf,
+                          &len);
+
+   RegCloseKey(hKey);
+
+   if (ret != ERROR_SUCCESS || regSz != REG_SZ || len == 0) {
+      g_debug("%s: Failed to get powershell GPO policy. ret: %d\n",
+              __FUNCTION__,
+              ret);
+      return FALSE;
+   }
+
+   buf[len] = '\0';
+   g_debug("%s: Powershell GPO execution policy: \"%s\"\n", __FUNCTION__, buf);
+
+   return (g_strcmp0(buf, "AllSigned") == 0);
+}
+
+
+/*
+ ******************************************************************************
+ * VMTools_IsCertPresent --
+ *
+ * Checks if our certificate is present in TrustedPublisher cert store.
+ *
+ * @return
+ *      TRUE if certificate is found.
+ *      FALSE otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ ******************************************************************************
+ */
+
+gboolean
+VMTools_IsCertPresent()
+{
+   HCERTSTORE trustedPublisher;
+   static const wchar_t *certStoreW = L"TrustedPublisher";
+   static const wchar_t *certSubjectW = L"Broadcom Inc";
+   PCCERT_CONTEXT certContext;
+
+   trustedPublisher = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
+                                    0,
+                                    (HCRYPTPROV)NULL,
+                                    CERT_SYSTEM_STORE_LOCAL_MACHINE |
+                                    CERT_STORE_OPEN_EXISTING_FLAG,
+                                    certStoreW);
+
+   if (trustedPublisher == NULL) {
+      g_debug("%s Failed to open TrustedPublisher store.\n", __FUNCTION__);
+      return FALSE;
+   }
+
+   certContext = CertFindCertificateInStore(trustedPublisher,
+                                            VMW_CERT_ENCODING,
+                                            0,
+                                            CERT_FIND_SUBJECT_STR,
+                                            certSubjectW,
+                                            NULL);
+
+   if (certContext == NULL) {
+      g_debug("%s: No certificate found.\n", __FUNCTION__);
+      CertCloseStore(trustedPublisher, 0);
+      return FALSE;
+   }
+
+   CertFreeCertificateContext(certContext);
+   CertCloseStore(trustedPublisher, 0);
+
+   g_debug("%s: A valid certificate found.\n", __FUNCTION__);
+   return TRUE;
+}
+
+
+/*
+ ******************************************************************************
+ * VMTools_LogWinEvent --
+ *
+ * Logs a windows event for message.
+ *
+ * @param[in] msg message to be logged in windows event.
+ *
+ * @return
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ ******************************************************************************
+ */
+
+void
+VMTools_LogWinEvent(const gchar *msg)
+{
+   HANDLE h;
+   wchar_t *msgBufW;
+
+   h = RegisterEventSourceW(NULL, L"VMware Tools");
+   if (h == NULL) {
+      g_debug("%s: Register windows event failed.\n", __FUNCTION__);
+      return;
+   }
+
+   msgBufW = (wchar_t *)g_utf8_to_utf16(msg, -1, NULL, NULL, NULL);
+   if (msgBufW == NULL) {
+      g_warning("%s: Error converting \"%s\".\n", __FUNCTION__, msg);
+      goto done;
+   }
+
+   ReportEventW(h,
+                EVENTLOG_INFORMATION_TYPE,
+                0,                        // category
+                VMTOOLS_EVENT_LOG_MESSAGE,// Event ID
+                NULL,                     // user
+                1,                        // numStrings
+                0,                        // data size
+                &msgBufW,                 // string array
+                NULL);                    // any binary data
+
+   g_free(msgBufW);
+
+done:
+   DeregisterEventSource(h);
+}
+
+
+/**
+ * Gets error message for the last error.
+ *
+ * @param[in]  error    Error code to be converted to string message.
+ *
+ * @return The error message, or NULL in case of failure.
+ */
+
+static char *
+VMToolsGetLastErrorMsg(DWORD error)
+{
+   char *msg = Win32U_FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+                                    FORMAT_MESSAGE_IGNORE_INSERTS,
+                                    NULL,
+                                    error,
+                                    0,       // Default language
+                                    NULL);
+   if (msg == NULL) {
+      g_warning("Failed to get error message for %d, error=%d.\n",
+                error, GetLastError());
+      return NULL;
+   }
+
+   return msg;
+}
+
+#endif // _WIN32
+
+
+/**
+ * Gets an environment variable for the current process.
+ *
+ * @param[in]  name       Name of the env variable.
+ *
+ * @return The value of env variable, or NULL in case of error.
+ *         The caller is expected to free the returned value.
+ */
+
+static gchar *
+VMToolsEnvGetVar(const char *name)      // IN
+{
+   gchar *value;
+
+#if defined(_WIN32)
+   DWORD valueSize;
+   /*
+    * Win32U_GetEnvironmentVariable requires buffer to be accurate size.
+    * So, we need to get the value size first.
+    *
+    * Windows bug: GetEnvironmentVariable() does not clear stale
+    * error when the return value is 0 because of env variable
+    * holding empty string value (just NUL-char). So, we need to
+    * clear it before we call the Win32 API.
+    */
+   SetLastError(ERROR_SUCCESS);
+   valueSize = Win32U_GetEnvironmentVariable(name, NULL, 0);
+   if (valueSize == 0) {
+      goto error;
+   }
+
+   value = g_malloc(valueSize);
+   SetLastError(ERROR_SUCCESS);
+   if (Win32U_GetEnvironmentVariable(name, value, valueSize) == 0) {
+      g_free(value);
+      goto error;
+   }
+
+   return value;
+
+error:
+{
+   DWORD error = GetLastError();
+   if (error == ERROR_SUCCESS) {
+      g_message("Env variable %s is empty.\n", name);
+   } else if (error == ERROR_ENVVAR_NOT_FOUND) {
+      g_message("Env variable %s not found.\n", name);
+   } else {
+      char *errorMsg = VMToolsGetLastErrorMsg(error);
+      if (errorMsg != NULL) {
+         g_warning("Failed to get env variable size %s, error=%s.\n",
+                   name, errorMsg);
+         free(errorMsg);
+      } else {
+         g_warning("Failed to get env variable size %s, error=%d.\n",
+                   name, error);
+      }
+   }
+   return NULL;
+}
+#else
+   value = Posix_Getenv(name);
+   return value == NULL ? value : g_strdup(value);
+#endif
+}
+
+
+/**
+ * Sets an environment variable for the current process.
+ *
+ * @param[in]  name       Name of the env variable.
+ * @param[in]  value      Value for the env variable.
+ *
+ * @return gboolean, TRUE on success or FALSE in case of error.
+ */
+
+static gboolean
+VMToolsEnvSetVar(const char *name,      // IN
+                 const char *value)     // IN
+{
+#if defined(_WIN32)
+   if (!Win32U_SetEnvironmentVariable(name, value)) {
+      char *errorMsg;
+      DWORD error = GetLastError();
+
+      errorMsg = VMToolsGetLastErrorMsg(error);
+      if (errorMsg != NULL) {
+         g_warning("Failed to set env variable %s=%s, error=%s.\n",
+                   name, value, errorMsg);
+         free(errorMsg);
+      } else {
+         g_warning("Failed to set env variable %s=%s, error=%d.\n",
+                   name, value, error);
+      }
+      return FALSE;
+   }
+#else
+   if (Posix_Setenv(name, value, TRUE) != 0) {
+      g_warning("Failed to set env variable %s=%s, error=%s.\n",
+                name, value, strerror(errno));
+      return FALSE;
+   }
+#endif
+   return TRUE;
+}
+
+/**
+ * Unsets an environment variable for the current process.
+ *
+ * @param[in]  name       Name of the env variable.
+ *
+ * @return gboolean, TRUE on success or FALSE in case of error.
+ */
+
+static gboolean
+VMToolsEnvUnsetVar(const char *name)    // IN
+{
+#if defined(_WIN32)
+   if (!Win32U_SetEnvironmentVariable(name, NULL)) {
+      char *errorMsg;
+      DWORD error = GetLastError();
+
+      errorMsg = VMToolsGetLastErrorMsg(error);
+      if (errorMsg != NULL) {
+         g_warning("Failed to unset env variable %s, error=%s.\n",
+                   name, errorMsg);
+         free(errorMsg);
+      } else {
+         g_warning("Failed to unset env variable %s, error=%d.\n",
+                   name, error);
+      }
+      return FALSE;
+   }
+#else
+   if (Posix_Unsetenv(name) != 0) {
+      g_warning("Failed to unset env variable %s, error=%s.\n",
+                name, strerror(errno));
+      return FALSE;
+   }
+#endif
+   return TRUE;
+}
+
+
+/**
+ * Setup environment variables for the current process from
+ * a given config group.
+ *
+ * @param[in]  appName    app name.
+ * @param[in]  config     config dictionary.
+ * @param[in]  globalVars global variables.
+ * @param[in]  group      Configuration group to be read.
+ * @param[in]  doUnset    Whether to unset the environment vars.
+ */
+
+static void
+VMToolsInitEnvGroup(const gchar *appName,// IN
+                    GKeyFile *config,    // IN
+                    gboolean globalVars, // IN
+                    const gchar *group,  // IN
+                    gboolean doUnset)    // IN
+{
+   gsize i;
+   gsize length;
+   GError *err = NULL;
+   gchar **keys = g_key_file_get_keys(config, group, &length, &err);
+   if (keys == NULL) {
+      if (err != NULL) {
+         if (err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
+            g_warning("Failed to get keys for config group %s (err=%d).\n",
+                      group, err->code);
+         }
+         g_clear_error(&err);
+      } else {
+         g_warning("Failed to get keys for config group %s (err=unknown).\n",
+                   group);
+      }
+      g_info("Skipping environment initialization for %s from %s config.\n",
+             appName, group);
+      return;
+   }
+
+   g_info("Found %"FMTSZ"d environment variable(s) in %s config.\n",
+          length, group);
+
+   /*
+    * Following 2 formats are supported:
+    * 1. <variableName> = <value>
+    * 2. <serviceName>.<variableName> = <value>
+    *
+    * Variables specified in format #1 are applied to all services and
+    * variables specified in format #2 are applied to specified service only.
+    *
+    * When the globalVars is TRUE, only format #1 settings will be applied.
+    * All service-specific, format #2, settings will be skipped.
+    * When the globalVars is FALSE, only format #2 settings will be applied.
+    * All global, format #1, settings will be skipped.
+    *
+    * Services and applications requiring both formats to be applied must
+    * call the VMTools_SetupEnv twice with globalVars TRUE, then FALSE.
+    * These are processed separately to allow the global variables to be
+    * set very early on in the process start, to fix GLib, when the service
+    * name is unknown.
+    */
+   for (i = 0; i < length; i++) {
+      const gchar *name = NULL;
+      const gchar *key = keys[i];
+      const gchar *delim;
+
+      /*
+       * Pick the keys that have service name prefix or no prefix.
+       */
+      delim = strchr(key, '.');
+      if (globalVars) {
+         if (delim == NULL) {
+            name = key;
+         }
+      } else if (delim != NULL) {
+         if (strncmp(key, appName, delim - key) == 0) {
+            name = delim + 1;
+         }
+      }
+
+      /*
+       * Ignore entries with empty env variable names.
+       */
+      if (name != NULL && *name != '\0') {
+         gchar *oldValue = VMToolsEnvGetVar(name);
+         if (doUnset) {
+            /*
+             * We can't avoid duplicate removals, but removing a non-existing
+             * environment variable is a no-op anyway.
+             */
+            if (VMToolsEnvUnsetVar(name)) {
+               g_message("Removed env var %s=[%s]\n",
+                         name, oldValue == NULL ? "(null)" : oldValue);
+            }
+         } else {
+            gchar *value = VMTools_ConfigGetString(config, group,
+                                                   key, NULL);
+            if (value != NULL) {
+               /*
+                * Get rid of trailing space.
+                */
+               g_strchomp(value);
+
+               /*
+                * Avoid updating environment var if it is already set to
+                * the same value.
+                *
+                * Also, g_key_file_get_keys() does not filter out duplicates
+                * but, VMTools_ConfigGetString returns only last entry
+                * for the key. So, by comparing old value, we avoid setting
+                * the environment multiple times when there are duplicates.
+                *
+                * NOTE: Need to use g_strcmp0 because oldValue can be NULL.
+                * As value can't be NULL but oldValue can be NULL, we might
+                * still do an unnecessary update in cases like setting a
+                * variable to empty/no value twice. However, it does not harm
+                * and is not worth avoiding it.
+                */
+               if (g_strcmp0(oldValue, value) == 0) {
+                  g_info("Env var %s already set to [%s], skipping.\n",
+                         name, oldValue);
+                  g_free(oldValue);
+                  g_free(value);
+                  continue;
+               }
+               g_debug("Changing env var %s from [%s] -> [%s]\n",
+                       name, oldValue == NULL ? "(null)" : oldValue, value);
+               if (VMToolsEnvSetVar(name, value)) {
+                  g_message("Updated env var %s from [%s] -> [%s]\n",
+                            name, oldValue == NULL ? "(null)" : oldValue,
+                            value);
+               }
+               g_free(value);
+            }
+         }
+         g_free(oldValue);
+      }
+   }
+
+   g_info("Initialized environment for %s from %s config.\n",
+          appName, group);
+   g_strfreev(keys);
+}
+
+
+/**
+ * Setup environment variables for the current process.
+ *
+ * @param[in]  appName    app name.
+ * @param[in]  config     config dictionary.
+ * @param[in]  globalVars global variables.
+ */
+
+static void
+VMToolsInitEnv(const gchar *appName,
+               GKeyFile *config,
+               gboolean globalVars)
+{
+   /*
+    * First apply unset environment configuration to start clean.
+    */
+   VMToolsInitEnvGroup(appName,
+                       config,
+                       globalVars,
+                       CONFGROUPNAME_UNSET_ENVIRONMENT,
+                       TRUE);
+   VMToolsInitEnvGroup(appName,
+                       config,
+                       globalVars,
+                       CONFGROUPNAME_SET_ENVIRONMENT,
+                       FALSE);
+}
+
+
+/**
+ * Setup environment variables for the current process.
+ *
+ * @param[in]  appName    app name.
+ * @param[in]  config     config dictionary.
+ * @param[in]  globalVars global variables.
+ */
+
+void
+VMTools_SetupEnv(const gchar *appName,
+                 GKeyFile *config,
+                 gboolean globalVars)
+{
+   /* Initialize the environment from config. */
+   VMToolsInitEnv(appName, config, globalVars);
+}
index a6a2a802806538a94450829acaa61a6d101500cb..55dab01a1ac4dd642b336ff1f15f4e527b9977ff 100644 (file)
@@ -367,7 +367,8 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state,
                                  ToolsCoreCmdLineError);
 
    if (!g_option_context_parse(context, &argc, &argv, &error)) {
-      g_printerr("%s: %s\n", N_("Command line parsing failed"), error->message);
+      g_printerr("%s: %s\n", N_("Command line parsing failed"),
+                 error != NULL ? error->message : "No GError");
       goto exit;
    }
 
index b37607f90ee884a4eb0a8893cf11f685aea91b57..61050c19d40295d04754372714178201d75371dd 100644 (file)
@@ -785,33 +785,6 @@ ToolsCore_ReloadConfig(ToolsServiceState *state,
 
 #if defined(_WIN32)
 
-/**
- * Gets error message for the last error.
- *
- * @param[in]  error    Error code to be converted to string message.
- *
- * @return The error message, or NULL in case of failure.
- */
-
-static char *
-ToolCoreGetLastErrorMsg(DWORD error)
-{
-   char *msg = Win32U_FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
-                                     FORMAT_MESSAGE_IGNORE_INSERTS,
-                                     NULL,
-                                     error,
-                                     0,       // Default language
-                                     NULL);
-   if (msg == NULL) {
-      g_warning("Failed to get error message for %d, error=%d.\n",
-                error, GetLastError());
-      return NULL;
-   }
-
-   return msg;
-}
-
-
 /**
  * Check the version for a file using GetFileVersionInfo method
  *
@@ -906,287 +879,6 @@ exit:
 #endif
 
 
-/**
- * Gets an environment variable for the current process.
- *
- * @param[in]  name       Name of the env variable.
- *
- * @return The value of env variable, or NULL in case of error.
- */
-
-static gchar *
-ToolsCoreEnvGetVar(const char *name)      // IN
-{
-   gchar *value;
-
-#if defined(_WIN32)
-   DWORD valueSize;
-   /*
-    * Win32U_GetEnvironmentVariable requires buffer to be accurate size.
-    * So, we need to get the value size first.
-    *
-    * Windows bug: GetEnvironmentVariable() does not clear stale
-    * error when the return value is 0 because of env variable
-    * holding empty string value (just NUL-char). So, we need to
-    * clear it before we call the Win32 API.
-    */
-   SetLastError(ERROR_SUCCESS);
-   valueSize = Win32U_GetEnvironmentVariable(name, NULL, 0);
-   if (valueSize == 0) {
-      goto error;
-   }
-
-   value = g_malloc(valueSize);
-   SetLastError(ERROR_SUCCESS);
-   if (Win32U_GetEnvironmentVariable(name, value, valueSize) == 0) {
-      g_free(value);
-      goto error;
-   }
-
-   return value;
-
-error:
-{
-   DWORD error = GetLastError();
-   if (error == ERROR_SUCCESS) {
-      g_message("Env variable %s is empty.\n", name);
-   } else if (error == ERROR_ENVVAR_NOT_FOUND) {
-      g_message("Env variable %s not found.\n", name);
-   } else {
-      char *errorMsg = ToolCoreGetLastErrorMsg(error);
-      if (errorMsg != NULL) {
-         g_warning("Failed to get env variable size %s, error=%s.\n",
-                   name, errorMsg);
-         free(errorMsg);
-      } else {
-         g_warning("Failed to get env variable size %s, error=%d.\n",
-                   name, error);
-      }
-   }
-   return NULL;
-}
-#else
-   value = Posix_Getenv(name);
-   return value == NULL ? value : g_strdup(value);
-#endif
-}
-
-
-/**
- * Sets an environment variable for the current process.
- *
- * @param[in]  name       Name of the env variable.
- * @param[in]  value      Value for the env variable.
- *
- * @return gboolean, TRUE on success or FALSE in case of error.
- */
-
-static gboolean
-ToolsCoreEnvSetVar(const char *name,      // IN
-                   const char *value)     // IN
-{
-#if defined(_WIN32)
-   if (!Win32U_SetEnvironmentVariable(name, value)) {
-      char *errorMsg;
-      DWORD error = GetLastError();
-
-      errorMsg = ToolCoreGetLastErrorMsg(error);
-      if (errorMsg != NULL) {
-         g_warning("Failed to set env variable %s=%s, error=%s.\n",
-                   name, value, errorMsg);
-         free(errorMsg);
-      } else {
-         g_warning("Failed to set env variable %s=%s, error=%d.\n",
-                   name, value, error);
-      }
-      return FALSE;
-   }
-#else
-   if (Posix_Setenv(name, value, TRUE) != 0) {
-      g_warning("Failed to set env variable %s=%s, error=%s.\n",
-                name, value, strerror(errno));
-      return FALSE;
-   }
-#endif
-   return TRUE;
-}
-
-
-/**
- * Unsets an environment variable for the current process.
- *
- * @param[in]  name       Name of the env variable.
- *
- * @return gboolean, TRUE on success or FALSE in case of error.
- */
-
-static gboolean
-ToolsCoreEnvUnsetVar(const char *name)    // IN
-{
-#if defined(_WIN32)
-   if (!Win32U_SetEnvironmentVariable(name, NULL)) {
-      char *errorMsg;
-      DWORD error = GetLastError();
-
-      errorMsg = ToolCoreGetLastErrorMsg(error);
-      if (errorMsg != NULL) {
-         g_warning("Failed to unset env variable %s, error=%s.\n",
-                   name, errorMsg);
-         free(errorMsg);
-      } else {
-         g_warning("Failed to unset env variable %s, error=%d.\n",
-                   name, error);
-      }
-      return FALSE;
-   }
-#else
-   if (Posix_Unsetenv(name) != 0) {
-      g_warning("Failed to unset env variable %s, error=%s.\n",
-                name, strerror(errno));
-      return FALSE;
-   }
-#endif
-   return TRUE;
-}
-
-
-/**
- * Setup environment variables for the current process from
- * a given config group.
- *
- * @param[in]  ctx       Application context.
- * @param[in]  group     Configuration group to be read.
- * @param[in]  doUnset   Whether to unset the environment vars.
- */
-
-static void
-ToolsCoreInitEnvGroup(ToolsAppCtx *ctx,   // IN
-                      const gchar *group, // IN
-                      gboolean doUnset)   // IN
-{
-   gsize i;
-   gsize length;
-   GError *err = NULL;
-   gchar **keys = g_key_file_get_keys(ctx->config, group, &length, &err);
-   if (err != NULL) {
-      if (err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
-         g_warning("Failed to get keys for config group %s (err=%d).\n",
-                   group, err->code);
-      }
-      g_clear_error(&err);
-      g_info("Skipping environment initialization for %s from %s config.\n",
-             ctx->name, group);
-      return;
-   }
-
-   g_info("Found %"FMTSZ"d environment variable(s) in %s config.\n",
-          length, group);
-
-   /*
-    * Following 2 formats are supported:
-    * 1. <variableName> = <value>
-    * 2. <serviceName>.<variableName> = <value>
-    *
-    * Variables specified in format #1 are applied to all services and
-    * variables specified in format #2 are applied to specified service only.
-    */
-   for (i = 0; i < length; i++) {
-      const gchar *name = NULL;
-      const gchar *key = keys[i];
-      const gchar *delim;
-
-      /*
-       * Pick the keys that have service name prefix or no prefix.
-       */
-      delim = strchr(key, '.');
-      if (delim == NULL) {
-         name = key;
-      } else if (strncmp(key, ctx->name, delim - key) == 0) {
-         name = delim + 1;
-      }
-
-      /*
-       * Ignore entries with empty env variable names.
-       */
-      if (name != NULL && *name != '\0') {
-         gchar *oldValue = ToolsCoreEnvGetVar(name);
-         if (doUnset) {
-            /*
-             * We can't avoid duplicate removals, but removing a non-existing
-             * environment variable is a no-op anyway.
-             */
-            if (ToolsCoreEnvUnsetVar(name)) {
-               g_message("Removed env var %s=[%s]\n",
-                         name, oldValue == NULL ? "(null)" : oldValue);
-            }
-         } else {
-            gchar *value = VMTools_ConfigGetString(ctx->config, group,
-                                                   key, NULL);
-            if (value != NULL) {
-               /*
-                * Get rid of trailing space.
-                */
-               g_strchomp(value);
-
-               /*
-                * Avoid updating environment var if it is already set to
-                * the same value.
-                *
-                * Also, g_key_file_get_keys() does not filter out duplicates
-                * but, VMTools_ConfigGetString returns only last entry
-                * for the key. So, by comparing old value, we avoid setting
-                * the environment multiple times when there are duplicates.
-                *
-                * NOTE: Need to use g_strcmp0 because oldValue can be NULL.
-                * As value can't be NULL but oldValue can be NULL, we might
-                * still do an unnecessary update in cases like setting a
-                * variable to empty/no value twice. However, it does not harm
-                * and is not worth avoiding it.
-                */
-               if (g_strcmp0(oldValue, value) == 0) {
-                  g_info("Env var %s already set to [%s], skipping.\n",
-                         name, oldValue);
-                  g_free(oldValue);
-                  g_free(value);
-                  continue;
-               }
-               g_debug("Changing env var %s from [%s] -> [%s]\n",
-                       name, oldValue == NULL ? "(null)" : oldValue, value);
-               if (ToolsCoreEnvSetVar(name, value)) {
-                  g_message("Updated env var %s from [%s] -> [%s]\n",
-                            name, oldValue == NULL ? "(null)" : oldValue,
-                            value);
-               }
-               g_free(value);
-            }
-         }
-         g_free(oldValue);
-      }
-   }
-
-   g_info("Initialized environment for %s from %s config.\n",
-          ctx->name, group);
-   g_strfreev(keys);
-}
-
-
-/**
- * Setup environment variables for the current process.
- *
- * @param[in]  ctx       Application context.
- */
-
-static void
-ToolsCoreInitEnv(ToolsAppCtx *ctx)
-{
-   /*
-    * First apply unset environment configuration to start clean.
-    */
-   ToolsCoreInitEnvGroup(ctx, CONFGROUPNAME_UNSET_ENVIRONMENT, TRUE);
-   ToolsCoreInitEnvGroup(ctx, CONFGROUPNAME_SET_ENVIRONMENT, FALSE);
-}
-
-
 /**
  * Performs any initial setup steps for the service's main loop.
  *
@@ -1230,7 +922,7 @@ ToolsCore_Setup(ToolsServiceState *state)
    g_object_set(state->ctx.serviceObj, TOOLS_CORE_PROP_CTX, &state->ctx, NULL);
 
    /* Initialize the environment from config. */
-   ToolsCoreInitEnv(&state->ctx);
+   VMTools_SetupEnv(state->ctx.name, state->ctx.config, FALSE);
    ToolsCorePool_Init(&state->ctx);
 
    /* Initializes the debug library if needed. */
index be31206c342cf9cd64b5db7fe3709fad08bae11a..72790ffe8066edf93125a6cd9c3c0b31d0415d60 100644 (file)
@@ -1,5 +1,6 @@
 /*********************************************************
- * Copyright (c) 2008-2020,2022-2023 VMware, Inc. All rights reserved.
+ * Copyright (c) 2008-2025 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -253,8 +254,16 @@ main(int argc,
    i = atexit(VMTools_TeardownVmxGuestLog);
    ASSERT(i == 0);
    VMTools_UseVmxGuestLog(VMTOOLS_APP_NAME);
-   VMTools_ConfigLogging(G_LOG_DOMAIN, NULL, TRUE, FALSE);
-   VMTools_SetupVmxGuestLog(FALSE, NULL, NULL);
+
+   /*
+    * ConfigLogging will be reset due to the config file being loaded.
+    * Set to vmtoolsd, temporarily, then clear.
+    * This is performed early to update env settings from the config file.
+    */
+   gState.name = G_LOG_DOMAIN;
+   ToolsCore_ReloadConfig(&gState, TRUE);
+   VMTools_SetupEnv(gState.name, gState.ctx.config, TRUE);
+   gState.name = NULL;
 
    VMTools_BindTextDomain(VMW_TEXT_DOMAIN, NULL, NULL);
 
index 57ff78dd9f93f967da5576f168f8f224bcc32c3a..e251f6fff83678542cf61026c0205f927d5f6462 100644 (file)
@@ -479,6 +479,8 @@ main(int argc,    // IN: length of command line arguments
    TOOLBOXCMD_LOAD_GLOBALCONFIG(conf)
 
    VMTools_ConfigLogging("toolboxcmd", conf, FALSE, FALSE);
+   /* Initialize any global environment variables that might be required. */
+   VMTools_SetupEnv("toolboxcmd", conf, TRUE);
    VMTools_BindTextDomain(VMW_TEXT_DOMAIN, NULL, NULL);
 
    if (!VmCheck_IsVirtualWorld()) {
index 69bb10047da0b97eb1ef1021773477e678c9f788..09d2481d86bb036158e81491e538b4a7b2947db2 100644 (file)
@@ -1,5 +1,7 @@
 ################################################################################
-### Copyright (C) 2014-2016, 2020 VMware, Inc.  All rights reserved.
+### Copyright (c) 2014-2025 Broadcom. All Rights Reserved.
+### Broadcom Confidential. The term "Broadcom" refers to Broadcom Inc.
+### and/or its subsidiaries.
 ###
 ### This program is free software; you can redistribute it and/or modify
 ### it under the terms of version 2 of the GNU General Public License as
@@ -32,6 +34,7 @@ vmware_vgauth_cmd_LDADD += @VMTOOLS_LIBS@
 vmware_vgauth_cmd_LDADD += @GLIB2_LIBS@
 vmware_vgauth_cmd_LDADD += @GTHREAD_LIBS@
 vmware_vgauth_cmd_LDADD += @SSL_LIBS@
+vmware_vgauth_cmd_LDADD += @VMTOOLS_LIBS@
 vmware_vgauth_cmd_LDADD += ../lib/libvgauth.la
 vmware_vgauth_cmd_LDADD += -lssl
 vmware_vgauth_cmd_LDADD += -lcrypto
index e2b7ef06190f491f0521cb9faf50f48c143b608f..411ffc9b84079fe12fa7a4089232cebc154719d1 100644 (file)
@@ -1,5 +1,6 @@
 /*********************************************************
- * Copyright (c) 2011-2020, 2023 VMware, Inc. All rights reserved.
+ * Copyright (c) 2011-2025 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -749,6 +750,13 @@ mainRun(int argc,
     * Set up the option parser
     */
    g_set_prgname(appName);
+
+   err = VGAuth_Init(appName, 0, NULL, &ctx);
+   if (VGAUTH_E_OK != err) {
+      g_printerr("%s\n", SU_(vgauth.init.failed, "Failed to init VGAuth"));
+      exit(-1);
+   }
+
    noteMsg = g_strdup_printf(lNote, "removeAll");
    context = g_option_context_new(paramStr);
    summaryMsg = g_strdup_printf(
@@ -872,6 +880,8 @@ next:
                  SU_(cmdline.parse, "Command line parsing failed"),
                  gErr->message);
       g_error_free(gErr);
+      VGAuth_Shutdown(ctx);
+      g_free(appName);
       exit(-1);
    }
 #endif
@@ -883,12 +893,6 @@ next:
       Usage(context, paramStr, cmdOptions);
    }
 
-   err = VGAuth_Init(appName, 0, NULL, &ctx);
-   if (VGAUTH_E_OK != err) {
-      g_printerr("%s\n", SU_(vgauth.init.failed, "Failed to init VGAuth"));
-      exit(-1);
-   }
-
    /*
     * XXX
     * If username is unset, should it use the current user?
index 59ee3858cbe8832a95f0ae25de4ffc8b21b346be..4f742e481805abf68f5908b669894f0c5a56019b 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (c) 2010-2025 Broadcom. All Rights Reserved.
+ * Copyright (c) 2011-2025 Broadcom. All Rights Reserved.
  * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -571,8 +571,9 @@ MsgLoadCatalog(const char *path)
    g_debug("%s: loading message catalog '%s'\n", __FUNCTION__, localPath);
    RELEASE_FILENAME_LOCAL(localPath);
 
-   if (err != NULL) {
-      g_debug("Unable to open '%s': %s\n", path, err->message);
+   if (stream == NULL) {
+      g_debug("Unable to open '%s': %s\n", path,
+              err != NULL ? err->message : "No GError");
       g_clear_error(&err);
       return NULL;
    }
@@ -584,18 +585,19 @@ MsgLoadCatalog(const char *path)
    for (;;) {
       char *name = NULL;
       char *value = NULL;
-      gchar *line;
+      gchar *line = NULL;
       gsize len;
       gsize term;
       char *unused = NULL;
+      GIOStatus status;
 
       /* Read the next key / value pair. */
 
-      g_io_channel_read_line(stream, &line, &len, &term, &err);
+      status = g_io_channel_read_line(stream, &line, &len, &term, &err);
 
-      if (err != NULL) {
+      if (status == G_IO_STATUS_ERROR) {
          g_warning("Unable to read a line from '%s': %s\n",
-                   path, err->message);
+                   path, err != NULL ? err->message : "No GError");
          g_clear_error(&err);
          error = TRUE;
          g_free(line);
@@ -627,13 +629,13 @@ MsgLoadCatalog(const char *path)
       }
       g_free(unused);
       g_free(line);
+      line = NULL;
 
       if (error) {
          /*
           * If the local DictLL_UnmarshalLine() returns NULL, name and value
           * will remain NULL pointers.  No malloc'ed memory to free here.
           */
-         /* coverity[leaked_storage] */
          break;
       }
 
index 686aace3bc92d13a247e6bed9d9a5afcf3f93f96..4fa1012f0ee38632ebbb0175da530457102bf200 100644 (file)
@@ -1,5 +1,6 @@
 /*********************************************************
- * Copyright (C) 2011-2016,2020 VMware, Inc. All rights reserved.
+ * Copyright (c) 2011-2025 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -28,7 +29,7 @@
 #ifdef _WIN32
 #include "winUtil.h"
 #endif
-
+#include "vmware/tools/utils.h"
 
 /*
  ******************************************************************************
@@ -234,13 +235,35 @@ Pref_GetBool(PrefHandle ph,
 }
 
 
+/*
+ ******************************************************************************
+ * Pref_InitEnv --                                                       */ /**
+ *
+ * Intializes the environment variables from any preferences.
+ *
+ * @param[in] ph         The handle to the preferences.
+ * @param[in] appfName   The app name.
+ * @param[in] globalVars Update global environment variables.
+ *
+ ******************************************************************************
+ */
+
+void
+Pref_InitEnv(PrefHandle ph,
+             const gchar *appName,
+             gboolean globalVars)
+{
+   GKeyFile *keyFile = ph->keyFile;
+   VMTools_SetupEnv(appName, keyFile, globalVars);
+}
+
 /*
  ******************************************************************************
  * Pref_LogAllEntries --                                                 */ /**
  *
  * Logs the full contents of the prefs.  Useful for debugging.
  *
- * @param[in] ph  The PrefHandle to dunp.
+ * @param[in] ph  The PrefHandle to dump.
  *
  ******************************************************************************
  */
index 71805325747b53fc5f8ab816929911cb893a8aae..3ca8a2268205b9984b6a354d9103323e41621cfb 100644 (file)
@@ -51,6 +51,9 @@ gboolean Pref_GetBool(PrefHandle ph,
                       const gchar *prefName,
                       const gchar *groupName,
                       gboolean defaultVal);
+void Pref_InitEnv(PrefHandle ph,
+                  const gchar *appfName,
+                  gboolean globalVars);
 
 void Pref_LogAllEntries(const PrefHandle ph);
 
index 1db3a4f706d7ddd8b71ea9116c075b2725cc5fc1..f76a8a1b7da9d9e9081a64dce9e5d3349add52c8 100644 (file)
@@ -308,6 +308,7 @@ VGAuth_Init(const char *applicationName,
       gchar *msgCatalog;
 
       gPrefs = Pref_Init(VGAUTH_PREF_CONFIG_FILENAME);
+      Pref_InitEnv(gPrefs, applicationName, TRUE);
       logSuccessAudits = Pref_GetBool(gPrefs,
                                       VGAUTH_PREF_AUDIT_SUCCESS,
                                       VGAUTH_PREF_GROUP_NAME_AUDIT,
index 9f46a9a9349cf4c8651820a9b8649ffe29d75d16..7e8949fb01ca05dcd273842c5fa904a1126929ff 100644 (file)
@@ -1,5 +1,7 @@
 ################################################################################
-### Copyright (C) 2014-2020, 2022, 2023 VMware, Inc.  All rights reserved.
+### Copyright (c) 2014-2025 Broadcom. All Rights Reserved.
+### Broadcom Confidential. The term "Broadcom" refers to Broadcom Inc.
+### and/or its subsidiaries.
 ###
 ### This program is free software; you can redistribute it and/or modify
 ### it under the terms of version 2 of the GNU General Public License as
@@ -71,6 +73,7 @@ VGAuthService_LDADD += @GLIB2_LIBS@
 VGAuthService_LDADD += @GTHREAD_LIBS@
 VGAuthService_LDADD += @XMLSEC1_LIBS@
 VGAuthService_LDADD += @SSL_LIBS@
+VGAuthService_LDADD += @VMTOOLS_LIBS@
 VGAuthService_LDADD += -lssl
 VGAuthService_LDADD += -lcrypto
 
index f157cf40ce82d62d9a825c86265ce86ae5aff33a..adc247239bdddef552adf6ab03ff97cbf75be783 100644 (file)
@@ -1,5 +1,6 @@
 /*********************************************************
- * Copyright (c) 2011-2021, 2023 VMware, Inc. All rights reserved.
+ * Copyright (c) 2011-2025 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -538,6 +539,7 @@ main(int argc,
 #endif
 
    gPrefs = Pref_Init(VGAUTH_PREF_CONFIG_FILENAME);
+   Pref_InitEnv(gPrefs, VGAUTH_SERVICE_NAME, TRUE);
 
    /*
     * Determine where the service is running from, so resources can
index 3b2d1462941d140229ddeae823022c2256cfec91..41aaff57d654f37093d5a2df20b49dc9d97c1a11 100644 (file)
@@ -1,5 +1,6 @@
 /*********************************************************
- * Copyright (c) 2012,2018-2021, 2023 VMware, Inc. All rights reserved.
+ * Copyright (c) 2012-2025 Broadcom. All Rights Reserved.
+ * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -45,7 +46,8 @@
 
 #define NOT_VMWARE_ERROR "Failed sending message to VMware.\n"
 
-static Bool ProcessNamespace(char *namespace);
+static Bool ProcessNamespace(char *namespace,
+                             VGAuthContext *ctx);
 
 #define NSDB_PRIV_GET_VALUES_CMD "namespace-priv-get-values"
 #define NSDB_PRIV_SET_KEYS_CMD "namespace-priv-set-keys"
@@ -154,8 +156,9 @@ vgauthLog(const char *logDomain,
  * Parses the data coming back from the namespace-get-values call, and
  * updates the VGAuth alias store with the information.
  *
+ * @param[in]  ctx       The VGAuthContext.
  * @param[in]  result    The raw data.  UTF-8 bytestream with embedded NULs.
- * @param[in]  ersultLen The length of the data.
+ * @param[in]  resultLen The length of the data.
  *
  * @return TRUE if successful, FALSE otherwise.
  *
@@ -163,7 +166,8 @@ vgauthLog(const char *logDomain,
  */
 
 static Bool
-ProcessQueryReply(char *result,
+ProcessQueryReply(VGAuthContext *ctx,
+                  char *result,
                   size_t resultLen)
 {
    char *p = result;
@@ -173,7 +177,6 @@ ProcessQueryReply(char *result,
    Bool addMapped = FALSE;
    Bool status = TRUE;
    VGAuthError vgErr;
-   VGAuthContext *ctx = NULL;
    int i;
    int numMapped = 0;
    VGAuthMappedAlias *maList = NULL;
@@ -231,17 +234,6 @@ ProcessQueryReply(char *result,
     */
    g_strstrip(pemCert);
 
-   /*
-    * Now tell VGAuth.
-    */
-   VGAuth_SetLogHandler(vgauthLog, NULL, 0, NULL);
-   vgErr = VGAuth_Init(VGAUTHIMPORT_APP_NAME, 0, NULL, &ctx);
-   if (VGAUTH_FAILED(vgErr)) {
-      fprintf(stderr, "Failed to init VGAuth context\n");
-      status = FALSE;
-      goto done;
-   }
-
    /*
     * Make sure we don't already have the entry.
     *
@@ -303,9 +295,6 @@ ProcessQueryReply(char *result,
    }
 
 done:
-   if (NULL != ctx) {
-      VGAuth_Shutdown(ctx);
-   }
    for (i = 0; i < ARRAYSIZE(nameVals); i++) {
       free(nameVals[i].val);
    }
@@ -452,6 +441,7 @@ done:
  * with a timestamp noting when the data was processed.
  *
  * @param[in]  namespace   The namespace name.
+ * @param[in]  ctx         The VGAuthContext.
  *
  * @return TRUE if successful, FALSE otherwise.
  *
@@ -459,7 +449,8 @@ done:
  */
 
 static Bool
-ProcessNamespace(char *namespace)
+ProcessNamespace(char *namespace,
+                 VGAuthContext *ctx)
 {
    char *result = NULL;
    size_t resultLen = 0;
@@ -479,7 +470,7 @@ ProcessNamespace(char *namespace)
       if (resultLen == 0) {
          fprintf(stderr, "Error: No keys found in namespace '%s'\n", namespace);
       } else {
-         status = ProcessQueryReply(result, resultLen);
+         status = ProcessQueryReply(ctx, result, resultLen);
 
          if (status ) {
             status = SetImportTime(namespace);
@@ -522,6 +513,8 @@ main(int argc, char *argv[])
       { NULL },
    };
    GOptionContext *optCtx;
+   VGAuthContext *ctx = NULL;
+   VGAuthError vgErr;
 
 /*
  * Using WinUtil_EnableSafePathSearching() and WinUtil_VerifyExePathW() from
@@ -545,6 +538,17 @@ main(int argc, char *argv[])
    gAppName = g_path_get_basename(argv[0]);
 
    g_set_prgname(gAppName);
+
+   /*
+    * Initialize VGAuth and set up the environment.
+    */
+   VGAuth_SetLogHandler(vgauthLog, NULL, 0, NULL);
+   vgErr = VGAuth_Init(VGAUTHIMPORT_APP_NAME, 0, NULL, &ctx);
+   if (VGAUTH_FAILED(vgErr)) {
+      fprintf(stderr, "Failed to init VGAuth context\n");
+      goto out;
+   }
+
    optCtx = g_option_context_new(usageMsg);
    g_option_context_set_summary(optCtx, summaryMsg);
    g_option_context_add_main_entries(optCtx, options, NULL);
@@ -569,9 +573,12 @@ main(int argc, char *argv[])
       goto out;
    }
 
-   success = ProcessNamespace(argv[1]) ? 0 : 1;
+   success = ProcessNamespace(argv[1], ctx) ? 0 : 1;
 
 out:
+   if (NULL != ctx) {
+      VGAuth_Shutdown(ctx);
+   }
    g_option_context_free(optCtx);
    g_free(gAppName);