]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tool_homedir: Change GetEnv() to use libcurl's curl_getenv()
authorJay Satiro <raysatiro@yahoo.com>
Wed, 29 Jan 2020 08:23:55 +0000 (03:23 -0500)
committerJay Satiro <raysatiro@yahoo.com>
Wed, 12 Feb 2020 23:37:31 +0000 (18:37 -0500)
- Deduplicate GetEnv() code.

- On Windows change ultimate call to use Windows API
  GetEnvironmentVariable() instead of C runtime getenv().

Prior to this change both libcurl and the tool had their own GetEnv
which over time diverged. Now the tool's GetEnv is a wrapper around
curl_getenv (libcurl API function which is itself a wrapper around
libcurl's GetEnv).

Furthermore this change fixes a bug in that Windows API
GetEnvironmentVariable() is called instead of C runtime getenv() to get
the environment variable since some changes aren't always visible to the
latter.

Reported-by: Christoph M. Becker
Fixes https://github.com/curl/curl/issues/4774
Closes https://github.com/curl/curl/pull/4863

lib/getenv.c
src/tool_homedir.c

index e444a6a3adc742d849c6c13097a5cf210ac74c27..a50226e73800d685bcbf1829f0b0130d6a7fcf09 100644 (file)
 
 #include "memdebug.h"
 
-static
-char *GetEnv(const char *variable)
+static char *GetEnv(const char *variable)
 {
 #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
   (void)variable;
   return NULL;
-#else
-#ifdef WIN32
-  char env[4096];
-  char *temp = getenv(variable);
-  env[0] = '\0';
-  if(temp != NULL)
-    ExpandEnvironmentStringsA(temp, env, sizeof(env));
-  return (env[0] != '\0')?strdup(env):NULL;
+#elif defined(WIN32)
+  /* This uses Windows API instead of C runtime getenv() to get the environment
+     variable since some changes aren't always visible to the latter. #4774 */
+  char *buf = NULL;
+  char *tmp;
+  DWORD bufsize;
+  DWORD rc = 1;
+  const DWORD max = 32768; /* max env var size from MSCRT source */
+
+  for(;;) {
+    tmp = realloc(buf, rc);
+    if(!tmp) {
+      free(buf);
+      return NULL;
+    }
+
+    buf = tmp;
+    bufsize = rc;
+
+    /* It's possible for rc to be 0 if the variable was found but empty.
+       Since getenv doesn't make that distinction we ignore it as well. */
+    rc = GetEnvironmentVariableA(variable, buf, bufsize);
+    if(!rc || rc == bufsize || rc > max) {
+      free(buf);
+      return NULL;
+    }
+
+    /* if rc < bufsize then rc is bytes written not including null */
+    if(rc < bufsize)
+      return buf;
+
+    /* else rc is bytes needed, try again */
+  }
 #else
   char *env = getenv(variable);
   return (env && env[0])?strdup(env):NULL;
 #endif
-#endif
 }
 
 char *curl_getenv(const char *v)
index 6bc69551e5eef6202ea24bf38eb85dcd2f17e116..e4ea97d384396eb091b60cefdedd905347c779fa 100644 (file)
 #  include <pwd.h>
 #endif
 
+#include <curl/mprintf.h>
+
 #include "tool_homedir.h"
 
 #include "memdebug.h" /* keep this as LAST include */
 
-static char *GetEnv(const char *variable, char do_expand)
+static char *GetEnv(const char *variable)
 {
-  char *env = NULL;
-#ifdef WIN32
-  char  buf1[1024], buf2[1024];
-  DWORD rc;
+  char *dupe, *env;
 
-  /* Don't use getenv(); it doesn't find variable added after program was
-   * started. Don't accept truncated results (i.e. rc >= sizeof(buf1)).  */
+  env = curl_getenv(variable);
+  if(!env)
+    return NULL;
 
-  rc = GetEnvironmentVariableA(variable, buf1, sizeof(buf1));
-  if(rc > 0 && rc < sizeof(buf1)) {
-    env = buf1;
-    variable = buf1;
-  }
-  if(do_expand && strchr(variable, '%')) {
-    /* buf2 == variable if not expanded */
-    rc = ExpandEnvironmentStringsA(variable, buf2, sizeof(buf2));
-    if(rc > 0 && rc < sizeof(buf2) &&
-       !strchr(buf2, '%'))    /* no vars still unexpanded */
-      env = buf2;
-  }
-#else
-  (void)do_expand;
-  /* no length control */
-  env = getenv(variable);
-#endif
-  return (env && env[0]) ? strdup(env) : NULL;
+  dupe = strdup(env);
+  curl_free(env);
+  return dupe;
 }
 
 /* return the home directory of the current user as an allocated string */
@@ -64,11 +49,11 @@ char *homedir(void)
 {
   char *home;
 
-  home = GetEnv("CURL_HOME", FALSE);
+  home = GetEnv("CURL_HOME");
   if(home)
     return home;
 
-  home = GetEnv("HOME", FALSE);
+  home = GetEnv("HOME");
   if(home)
     return home;
 
@@ -86,10 +71,18 @@ char *homedir(void)
  }
 #endif /* PWD-stuff */
 #ifdef WIN32
-  home = GetEnv("APPDATA", TRUE);
-  if(!home)
-    home = GetEnv("%USERPROFILE%\\Application Data", TRUE); /* Normally only
-                                                               on Win-2K/XP */
+  home = GetEnv("APPDATA");
+  if(!home) {
+    char *env = GetEnv("USERPROFILE");
+    if(env) {
+      char *path = curl_maprintf("%s\\Application Data", env);
+      if(path) {
+        home = strdup(path);
+        curl_free(path);
+      }
+      free(env);
+    }
+  }
 #endif /* WIN32 */
   return home;
 }