]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tool_findfile: search for a file in the homedir
authorDaniel Stenberg <daniel@haxx.se>
Fri, 19 Nov 2021 15:11:29 +0000 (16:11 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 28 Nov 2021 23:57:22 +0000 (00:57 +0100)
The homedir() function is now renamed into findfile() and iterates over
all the environment variables trying to access the file in question
until it finds it. Last resort is then getpwuid() if
available. Previously it would first try to find a home directory and if
that was set, insist on checking only that directory for the file. This
now returns the full file name it finds.

The Windows specific checks are now done differently too and in this
order:

1 - %USERPROFILE%
2 - %APPDATA%
3 - %USERPROFILE%\\Application Data

The windows order is modified to match how the Windows 10 ssh tool works
when it searches for .ssh/known_hosts.

Reported-by: jeffrson on github
Co-authored-by: Jay Satiro
Fixes #8033
Closes #8035

src/Makefile.inc
src/tool_findfile.c [new file with mode: 0644]
src/tool_findfile.h [moved from src/tool_homedir.h with 90% similarity]
src/tool_homedir.c [deleted file]
src/tool_operate.c
src/tool_paramhlp.c
src/tool_parsecfg.c

index 9fb9946d633510bc8145ea10b6c2371e8c4e577a..44cfe0f816121b50c3410efdbe89494f50f8ccde 100644 (file)
@@ -65,12 +65,12 @@ CURL_CFILES = \
   tool_doswin.c \
   tool_easysrc.c \
   tool_filetime.c \
+  tool_findfile.c \
   tool_formparse.c \
   tool_getparam.c \
   tool_getpass.c \
   tool_help.c \
   tool_helpers.c \
-  tool_homedir.c \
   tool_hugehelp.c \
   tool_libinfo.c \
   tool_listhelp.c \
@@ -108,12 +108,12 @@ CURL_HFILES = \
   tool_doswin.h \
   tool_easysrc.h \
   tool_filetime.h \
+  tool_findfile.h \
   tool_formparse.h \
   tool_getparam.h \
   tool_getpass.h \
   tool_help.h \
   tool_helpers.h \
-  tool_homedir.h \
   tool_hugehelp.h \
   tool_libinfo.h \
   tool_main.h \
diff --git a/src/tool_findfile.c b/src/tool_findfile.c
new file mode 100644 (file)
index 0000000..cda8c8e
--- /dev/null
@@ -0,0 +1,134 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "tool_setup.h"
+
+#ifdef HAVE_PWD_H
+#  undef __NO_NET_API /* required for building for AmigaOS */
+#  include <pwd.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include <curl/mprintf.h>
+
+#include "tool_findfile.h"
+
+#include "memdebug.h" /* keep this as LAST include */
+
+struct finder {
+  const char *env;
+  const char *append;
+};
+
+static const struct finder list[] = {
+  { "CURL_HOME", NULL },
+  { "XDG_CONFIG_HOME", NULL },
+  { "HOME", NULL },
+#ifdef WIN32
+  { "USERPROFILE", NULL },
+  { "APPDATA", NULL },
+  { "USERPROFILE", "\\Application Data"},
+#endif
+  { NULL, NULL }
+};
+
+static char *checkhome(const char *home, const char *fname, bool dotscore)
+{
+  const char pref[2] = { '.', '_' };
+  int i;
+  for(i = 0; i < (dotscore ? 2 : 1); i++) {
+    char *c;
+    if(dotscore)
+      c = curl_maprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]);
+    else
+      c = curl_maprintf("%s" DIR_CHAR "%s", home, fname);
+    if(c) {
+      int fd = open(c, O_RDONLY);
+      if(fd >= 0) {
+        char *path = strdup(c);
+        close(fd);
+        curl_free(c);
+        return path;
+      }
+      curl_free(c);
+    }
+  }
+  return NULL;
+}
+
+/*
+ * findfile() - return the full path name of the file.
+ *
+ * If 'dotscore' is TRUE, then check for the file first with a leading dot
+ * and then with a leading underscore.
+ *
+ * 1. Iterate over the environment variables in order, and if set, check for
+ *    the given file to be accessed there, then it is a match.
+ * 2. Non-windows: try getpwuid
+ */
+char *findfile(const char *fname, bool dotscore)
+{
+  int i;
+  DEBUGASSERT(fname && fname[0]);
+  DEBUGASSERT(!dotscore || (fname[0] == '.'));
+
+  if(!fname[0])
+    return NULL;
+
+  for(i = 0; list[i].env; i++) {
+    char *home = curl_getenv(list[i].env);
+    if(home) {
+      char *path;
+      if(!home[0]) {
+        curl_free(home);
+        continue;
+      }
+      if(list[i].append) {
+        char *c = curl_maprintf("%s%s", home, list[i].append);
+        curl_free(home);
+        if(!c)
+          return NULL;
+        home = c;
+      }
+      path = checkhome(home, fname, dotscore);
+      curl_free(home);
+      if(path)
+        return path;
+    }
+  }
+#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
+  {
+    struct passwd *pw = getpwuid(geteuid());
+    if(pw) {
+      char *home = pw->pw_dir;
+      if(home && home[0])
+        return checkhome(home, fname, FALSE);
+    }
+  }
+#endif /* PWD-stuff */
+  return NULL;
+}
similarity index 90%
rename from src/tool_homedir.h
rename to src/tool_findfile.h
index 31e38e96a33952e10a82694190b71fd601ee249f..0f6a8eb55b52f9f4847d86f28b2e6d85f3d89cb6 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -23,6 +23,6 @@
  ***************************************************************************/
 #include "tool_setup.h"
 
-char *homedir(const char *fname);
+char *findfile(const char *fname, bool dotscore);
 
 #endif /* HEADER_CURL_TOOL_HOMEDIR_H */
diff --git a/src/tool_homedir.c b/src/tool_homedir.c
deleted file mode 100644 (file)
index 632bdcc..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "tool_setup.h"
-
-#ifdef HAVE_PWD_H
-#  undef __NO_NET_API /* required for building for AmigaOS */
-#  include <pwd.h>
-#endif
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.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 *dupe, *env;
-
-  env = curl_getenv(variable);
-  if(!env)
-    return NULL;
-
-  dupe = strdup(env);
-  curl_free(env);
-  return dupe;
-}
-
-/* return the home directory of the current user as an allocated string */
-
-/*
- * The original logic found a home dir to use (by checking a range of
- * environment variables and last using getpwuid) and returned that for the
- * parent to use.
- *
- * With the XDG_CONFIG_HOME support (added much later than the other), this
- * variable is treated differently in order to not ruin existing installations
- * even if this environment variable is set. If this variable is set, and a
- * file name is set to check, then only if that file name exists in that
- * directory will it be returned as a "home directory".
- *
- * 1. use CURL_HOME if set
- * 2. use XDG_CONFIG_HOME if set and fname is present
- * 3. use HOME if set
- * 4. Non-windows: use getpwuid
- * 5. Windows: use APPDATA if set
- * 6. Windows: use "USERPROFILE\Application Data" is set
- */
-
-char *homedir(const char *fname)
-{
-  char *home;
-
-  home = GetEnv("CURL_HOME");
-  if(home)
-    return home;
-
-  if(fname) {
-    home = GetEnv("XDG_CONFIG_HOME");
-    if(home) {
-      char *c = curl_maprintf("%s" DIR_CHAR "%s", home, fname);
-      if(c) {
-        int fd = open(c, O_RDONLY);
-        curl_free(c);
-        if(fd >= 0) {
-          close(fd);
-          return home;
-        }
-      }
-      free(home);
-    }
-  }
-
-  home = GetEnv("HOME");
-  if(home)
-    return home;
-
-#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
- {
-   struct passwd *pw = getpwuid(geteuid());
-
-   if(pw) {
-     home = pw->pw_dir;
-     if(home && home[0])
-       home = strdup(home);
-     else
-       home = NULL;
-   }
- }
-#endif /* PWD-stuff */
-#ifdef WIN32
-  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;
-}
index b9183c22a4184fa7ba40aec5c8615fe3f83291a0..d648dc054c706c4dd4b9cfadbe0c97d8b72e61d7 100644 (file)
@@ -63,7 +63,7 @@
 #include "tool_filetime.h"
 #include "tool_getparam.h"
 #include "tool_helpers.h"
-#include "tool_homedir.h"
+#include "tool_findfile.h"
 #include "tool_libinfo.h"
 #include "tool_main.h"
 #include "tool_msgs.h"
@@ -1716,23 +1716,19 @@ static CURLcode single_transfer(struct GlobalConfig *global,
 
         if((use_proto & (CURLPROTO_SCP|CURLPROTO_SFTP)) &&
            !config->insecure_ok) {
-          char *home = homedir(NULL);
-          if(home) {
-            char *file = aprintf("%s/.ssh/known_hosts", home);
-            if(file) {
-              /* new in curl 7.19.6 */
-              result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
-              curl_free(file);
-              if(result == CURLE_UNKNOWN_OPTION)
-                /* libssh2 version older than 1.1.1 */
-                result = CURLE_OK;
-            }
-            Curl_safefree(home);
+          char *known = findfile(".ssh/known_hosts", FALSE);
+          if(known) {
+            /* new in curl 7.19.6 */
+            result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, known);
+            curl_free(known);
+            if(result == CURLE_UNKNOWN_OPTION)
+              /* libssh2 version older than 1.1.1 */
+              result = CURLE_OK;
             if(result)
               break;
           }
           else
-            warnf(global, "No home dir, couldn't find known_hosts file!");
+            warnf(global, "Couldn't find a known_hosts file!");
         }
 
         if(config->no_body || config->remote_time) {
index 28a8754f1e0779d4ce3bdc65e8acdb8d696f3275..8ac6cf53e04cdca55a9e931648810fa2218658d2 100644 (file)
@@ -30,7 +30,6 @@
 #include "tool_cfgable.h"
 #include "tool_getparam.h"
 #include "tool_getpass.h"
-#include "tool_homedir.h"
 #include "tool_msgs.h"
 #include "tool_paramhlp.h"
 #include "tool_version.h"
index d26774faf8276bdc62970be8442436f1a66abcf8..ba8ac60e24ab5bd8d8e87ba7e1e205ed424f0261 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -28,7 +28,7 @@
 #include "tool_cfgable.h"
 #include "tool_getparam.h"
 #include "tool_helpers.h"
-#include "tool_homedir.h"
+#include "tool_findfile.h"
 #include "tool_msgs.h"
 #include "tool_parsecfg.h"
 #include "dynbuf.h"
@@ -45,9 +45,9 @@ static const char *unslashquote(const char *line, char *param);
 static bool my_get_line(FILE *fp, struct curlx_dynbuf *, bool *error);
 
 #ifdef WIN32
-static FILE *execpath(const char *filename)
+static FILE *execpath(const char *filename, char **pathp)
 {
-  char filebuffer[512];
+  static char filebuffer[512];
   /* Get the filename of our executable. GetModuleFileName is already declared
    * via inclusions done in setup header file.  We assume that we are using
    * the ASCII version here.
@@ -62,8 +62,11 @@ static FILE *execpath(const char *filename)
       /* If we have enough space, build the RC filename */
       remaining = sizeof(filebuffer) - strlen(filebuffer);
       if(strlen(filename) < remaining - 1) {
+        FILE *f;
         msnprintf(lastdirchar, remaining, "%s%s", DIR_CHAR, filename);
-        return fopen(filebuffer, FOPEN_READTEXT);
+        *pathp = filebuffer;
+        f = fopen(filebuffer, FOPEN_READTEXT);
+        return f;
       }
     }
   }
@@ -81,55 +84,37 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
   int rc = 0;
   struct OperationConfig *operation = global->last;
   char *pathalloc = NULL;
+#ifdef WIN32
+#define DOTSCORE TRUE /* look for underscore-prefixed name too */
+#else
+#define DOTSCORE FALSE
+#endif
 
-  if(!filename || !*filename) {
-    /* NULL or no file name attempts to load .curlrc from the homedir! */
-
-    char *home = homedir(".curlrc");
-#ifndef WIN32
-    if(home) {
-      pathalloc = curl_maprintf("%s%s.curlrc", home, DIR_CHAR);
-      if(!pathalloc) {
-        free(home);
-        return 1; /* out of memory */
+  if(!filename) {
+    /* NULL means load .curlrc from homedir! */
+    char *curlrc = findfile(".curlrc", DOTSCORE);
+    if(curlrc) {
+      file = fopen(curlrc, FOPEN_READTEXT);
+      if(!file) {
+        curl_free(curlrc);
+        return 1;
       }
-      filename = pathalloc;
-    }
-#else /* Windows */
-    if(home) {
-      int i = 0;
-      char prefix = '.';
-      do {
-        /* if it was allocated in a previous attempt */
-        curl_free(pathalloc);
-        /* check for .curlrc then _curlrc in the home dir */
-        pathalloc = curl_maprintf("%s%s%ccurlrc", home, DIR_CHAR, prefix);
-        if(!pathalloc) {
-          free(home);
-          return 1; /* out of memory */
-        }
-
-        /* Check if the file exists - if not, try _curlrc */
-        file = fopen(pathalloc, FOPEN_READTEXT);
-        if(file) {
-          filename = pathalloc;
-          break;
-        }
-        prefix = '_';
-      } while(++i < 2);
+      filename = pathalloc = curlrc;
     }
-    if(!filename) {
+#ifdef WIN32 /* Windows */
+    else {
+      char *fullp;
       /* check for .curlrc then _curlrc in the dir of the executable */
-      file = execpath(".curlrc");
+      file = execpath(".curlrc", &fullp);
       if(!file)
-        file = execpath("_curlrc");
+        file = execpath("_curlrc", &fullp);
+      if(file)
+        /* this is the filename we read from */
+        filename = fullp;
     }
 #endif
-
-    Curl_safefree(home); /* we've used it, now free it */
   }
-
-  if(!file && filename) { /* no need to fopen() again */
+  else {
     if(strcmp(filename, "-"))
       file = fopen(filename, FOPEN_READTEXT);
     else
@@ -145,6 +130,7 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
     struct curlx_dynbuf buf;
     bool fileerror;
     curlx_dyn_init(&buf, MAX_CONFIG_LINE_LENGTH);
+    DEBUGASSERT(filename);
 
     while(my_get_line(file, &buf, &fileerror)) {
       int res;