Skip to content

Commit

Permalink
tool_findfile: detect files in XDG home without leading dot
Browse files Browse the repository at this point in the history
WIP

The order is now:

- $XDG_CONFIG_HOME/curlrc
- $XDG_CONFIG_HOME/.curlrc
- $XDG_CONFIG_HOME/_curlrc (if dotscore is true)

Fixes curl#12129
Closes #xxxx

Prior to this change there was no check for the dotless version of the
filename.
  • Loading branch information
jay committed Oct 16, 2023
1 parent b1b7552 commit 43d8988
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 33 deletions.
97 changes: 69 additions & 28 deletions src/tool_findfile.c
Expand Up @@ -35,6 +35,8 @@
#include <fcntl.h>
#endif

#include <string.h>

#include <curl/mprintf.h>

#include "tool_findfile.h"
Expand All @@ -44,24 +46,24 @@
struct finder {
const char *env;
const char *append;
bool withoutdot;
bool xdg;
};

/* The order of the variables below is important, as the index number is used
in the findfile() function */
static const struct finder conf_list[] = {
{ "CURL_HOME", NULL, FALSE },
{ "XDG_CONFIG_HOME", NULL, FALSE }, /* index == 1, used in the code */
{ "XDG_CONFIG_HOME", NULL, TRUE }, /* index == 1, used in the code */
/* XDG Base Directory spec says if XDG_CONFIG_HOME is not set (the findfile
function keeps track of this) then treat as if set to homedir/.config */
{ "CURL_HOME", "/.config", TRUE }, /* XDG fallback */
{ "HOME", "/.config", TRUE }, /* XDG fallback */
{ "HOME", NULL, FALSE },
#ifdef WIN32
{ "USERPROFILE", NULL, FALSE },
{ "APPDATA", NULL, FALSE },
{ "USERPROFILE", "\\Application Data", FALSE},
#endif
/* these are for .curlrc if XDG_CONFIG_HOME is not defined */
{ "CURL_HOME", "/.config", TRUE },
{ "HOME", "/.config", TRUE },

{ NULL, NULL, FALSE }
};

Expand All @@ -75,47 +77,77 @@ static char *checkhome(const char *home, const char *fname, bool dotscore)
c = curl_maprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]);
else
c = curl_maprintf("%s" DIR_CHAR "%s", home, fname);
fprintf(tool_stderr, "checkhome: checking path: %s\n", c);
if(c) {
int fd = open(c, O_RDONLY);
if(fd >= 0) {
char *path = strdup(c);
close(fd);
curl_free(c);
fprintf(tool_stderr, "checkhome: found path: %s\n", path);
return path;
}
fprintf(tool_stderr, "checkhome: did NOT find path\n");
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.
* findfile() - return the full path name of the configuration file 'fname'.
*
* 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
*
* When XDG locations are searched, if 'fname' has a leading dot and is just a
* filename and not a relative path, then the filename is first searched for
* with the dot stripped. For example, if 'fname' is .curlrc and the
* $XDG_CONFIG_HOME location is being searched, it happens in this order:
*
* $XDG_CONFIG_HOME/curlrc
* $XDG_CONFIG_HOME/.curlrc
* $XDG_CONFIG_HOME/_curlrc (if dotscore is true)
*
* The behavior of 'dotscore' is controlled by the macros below.
*
* CURL_DOTSCORE_ON: if 'fname' has a leading dot and is just a filename and
* not a relative path, and is not found in a location then try again with an
* underscore prefix. For example, if filename .curlrc is not found in a
* location then check for _curlrc in the same location before trying the next
* location for .curlrc.
*
* CURL_DOTSCORE_OFF: do not try an alternate underscore filename.
*
* CURL_DOTSCORE_DEFAULT: OS dependent, either ON or OFF.
*/
char *findfile(const char *fname, int dotscore)
char *findfile(const char *fname, bool dotscore)
{
int i;
bool xdg = FALSE;
bool fname_is_relative_path;
bool xdg_main_found = FALSE;
DEBUGASSERT(fname && fname[0]);
DEBUGASSERT((dotscore != 1) || (fname[0] == '.'));
DEBUGASSERT(!dotscore || (fname[0] == '.'));

if(!fname[0])
if(!fname[0] || (dotscore && fname[0] != '.'))
return NULL;
dotscore = true;
fname_is_relative_path = !!strpbrk(fname, "\\/");

/* assume an fname like .ssh/foo with underscore checking is a mistake */
DEBUGASSERT(!dotscore || !fname_is_relative_path);

for(i = 0; conf_list[i].env; i++) {
char *home = curl_getenv(conf_list[i].env);
char *home;
home = curl_getenv(conf_list[i].env);
fprintf(tool_stderr, "\nfindfile: checking env: %s\n", conf_list[i].env);
if(home) {
char *path;
const char *filename = fname;
if(i == 1 /* XDG_CONFIG_HOME */)
xdg = TRUE;
fprintf(tool_stderr, "findfile: found env: %s: %s\n",
conf_list[i].env, home);
if(i == 1 /* XDG_CONFIG_HOME is set */)
xdg_main_found = TRUE;
if(!home[0]) {
curl_free(home);
continue;
Expand All @@ -127,29 +159,38 @@ char *findfile(const char *fname, int dotscore)
return NULL;
home = c;
}
if(conf_list[i].withoutdot) {
if(!dotscore || xdg) {
/* this is not looking for .curlrc, or the XDG_CONFIG_HOME was
defined so we skip the extended check */
if(conf_list[i].xdg && fname[0] == '.' && !fname_is_relative_path) {
/* skip fallbacks for XDG home if XDG_CONFIG_HOME was set */
if(i != 1 && xdg_main_found) {
fprintf(tool_stderr, "skipping\n");
curl_free(home);
continue;
}
filename++; /* move past the leading dot */
dotscore = 0; /* disable it for this check */
/* check for filename without the dot */
path = checkhome(home, fname + 1, false);
if(path) {
curl_free(home);
return path;
}
}
path = checkhome(home, filename, dotscore ? dotscore - 1 : 0);
path = checkhome(home, fname, fname_is_relative_path ? false : dotscore);
curl_free(home);
if(path)
return path;
/* if(path)
return path;*/
}
else {
fprintf(tool_stderr, "findfile: not found env: %s\n", conf_list[i].env);
}
}
#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
{
struct passwd *pw = getpwuid(geteuid());
if(pw) {
char *home = pw->pw_dir;
if(home && home[0])
if(home && home[0]) {
fprintf(tool_stderr, "\nfindfile: pw_dir: %s\n", home);
return checkhome(home, fname, FALSE);
}
}
}
#endif /* PWD-stuff */
Expand Down
12 changes: 9 additions & 3 deletions src/tool_findfile.h
Expand Up @@ -25,12 +25,18 @@
***************************************************************************/
#include "tool_setup.h"

/* These macros are for findfile() parameter 'dotscore' and documented above
* the function definition.
*/
#define CURL_DOTSCORE_ON TRUE /* look for underscore-prefixed name too */
#define CURL_DOTSCORE_OFF FALSE

#ifdef WIN32
#define CURLRC_DOTSCORE 2 /* look for underscore-prefixed name too */
#define CURL_DOTSCORE_DEFAULT CURL_DOTSCORE_ON
#else
#define CURLRC_DOTSCORE 1 /* regular .curlrc check */
#define CURL_DOTSCORE_DEFAULT CURL_DOTSCORE_OFF
#endif

char *findfile(const char *fname, int dotscore);
char *findfile(const char *fname, bool dotscore);

#endif /* HEADER_CURL_TOOL_HOMEDIR_H */
2 changes: 1 addition & 1 deletion src/tool_operate.c
Expand Up @@ -2006,7 +2006,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,

if((use_proto == proto_scp || use_proto == proto_sftp) &&
!config->insecure_ok) {
char *known = findfile(".ssh/known_hosts", FALSE);
char *known = findfile(".ssh/known_hosts", CURL_DOTSCORE_OFF);
if(known) {
/* new in curl 7.19.6 */
result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, known);
Expand Down
2 changes: 1 addition & 1 deletion src/tool_parsecfg.c
Expand Up @@ -89,7 +89,7 @@ int parseconfig(const char *filename, struct GlobalConfig *global)

if(!filename) {
/* NULL means load .curlrc from homedir! */
char *curlrc = findfile(".curlrc", CURLRC_DOTSCORE);
char *curlrc = findfile(".curlrc", CURL_DOTSCORE_DEFAULT);
if(curlrc) {
file = fopen(curlrc, FOPEN_READTEXT);
if(!file) {
Expand Down

0 comments on commit 43d8988

Please sign in to comment.