Copy environment block rather than setting extra variables.
authorIain Patterson <me@iain.cx>
Thu, 9 Jan 2014 18:27:00 +0000 (18:27 +0000)
committerIain Patterson <me@iain.cx>
Thu, 9 Jan 2014 18:27:00 +0000 (18:27 +0000)
If AppEnvironmentExtra is configured we were calling
SetEnvironmentVariable() to append each one to the existing environment.
That's arguably wrong as it could mess up NSSM's own environment.

Instead we now call GetEnvironmentStrings() and take a copy of the
current environment ebfore appending the extra environment as we were
doing before.

registry.cpp

index caa0fb1..443d2e5 100644 (file)
@@ -500,38 +500,63 @@ int get_parameters(nssm_service_t *service, STARTUPINFO *si) {
 \r
   if (si) {\r
     if (service->env_extra) {\r
-      /* Append these to any other environment variables set. */\r
+      TCHAR *env;\r
+      unsigned long envlen;\r
+\r
+      /* Copy our environment for the application. */\r
+      if (! service->env) {\r
+        TCHAR *rawenv = GetEnvironmentStrings();\r
+        env = rawenv;\r
+        if (env) {\r
+          /*\r
+            The environment block starts with variables of the form\r
+            =C:=C:\Windows\System32 which we ignore.\r
+          */\r
+          while (*env == _T('=')) {\r
+            for ( ; *env; env++);\r
+            env++;\r
+          }\r
+          envlen = 0;\r
+          if (*env) {\r
+            while (true) {\r
+              for ( ; env[envlen]; envlen++);\r
+              if (! env[++envlen]) break;\r
+            }\r
+            envlen++;\r
+\r
+            service->envlen = envlen * sizeof(TCHAR);\r
+            service->env = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, service->envlen);\r
+            memmove(service->env, env, service->envlen);\r
+            FreeEnvironmentStrings(rawenv);\r
+          }\r
+        }\r
+      }\r
+\r
+      /* Append extra variables to configured variables. */\r
       if (service->env) {\r
-        /* Append extra variables to configured variables. */\r
-        unsigned long envlen = service->envlen + service->env_extralen - 1;\r
-        TCHAR *env = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, envlen);\r
+        envlen = service->envlen + service->env_extralen - sizeof(TCHAR)/*?*/;\r
+        env = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, envlen);\r
         if (env) {\r
           memmove(env, service->env, service->envlen - sizeof(TCHAR));\r
-          /* envlen is in bytes. */\r
+          /* envlen is in bytes but env[i] is in characters. */\r
           memmove(env + (service->envlen / sizeof(TCHAR)) - 1, service->env_extra, service->env_extralen);\r
 \r
           HeapFree(GetProcessHeap(), 0, service->env);\r
+          HeapFree(GetProcessHeap(), 0, service->env_extra);\r
           service->env = env;\r
           service->envlen = envlen;\r
         }\r
         else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, _T("environment"), _T("get_parameters()"), 0);\r
       }\r
       else {\r
-        /* Append extra variables to our environment. */\r
-        TCHAR *env, *s;\r
-        size_t envlen, len;\r
-\r
-        env = service->env_extra;\r
-        len = 0;\r
-        while (*env) {\r
-          envlen = _tcslen(env) + 1;\r
-          for (s = env; *s && *s != _T('='); s++);\r
-          if (*s == _T('=')) *s++ = _T('\0');\r
-          if (! SetEnvironmentVariable(env, s)) log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_SETENVIRONMENTVARIABLE_FAILED, env, s, error_string(GetLastError()), 0);\r
-          env += envlen;\r
-        }\r
+        /* Huh?  No environment at all? */\r
+        service->env = service->env_extra;\r
+        service->envlen = service->env_extralen;\r
       }\r
     }\r
+\r
+    service->env_extra = 0;\r
+    service->env_extralen = 0;\r
   }\r
 \r
   /* Try to get priority - may fail. */\r