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
The order is now:

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

Prior to this change there was no check for the dotless version of the
filename.

Fixes curl#12129
Closes #xxxx
  • Loading branch information
jay committed Oct 29, 2023
1 parent 904ae12 commit 407444a
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 39 deletions.
20 changes: 15 additions & 5 deletions docs/cmdline-opts/config.d
Expand Up @@ -58,7 +58,11 @@ config file is checked for in the following places in this order:

1) **"$CURL_HOME/.curlrc"**

2) **"$XDG_CONFIG_HOME/curlrc"** (Added in 7.73.0)
2a) **"$XDG_CONFIG_HOME/curlrc"** (Added in 7.73.0) (see notes)

2b) **"$CURL_HOME/.config/curlrc"** (Only if XDG_CONFIG_HOME is not set)

2c) **"$HOME/.config/curlrc"** (Only if XDG_CONFIG_HOME is not set)

3) **"$HOME/.curlrc"**

Expand All @@ -70,8 +74,14 @@ config file is checked for in the following places in this order:

7) Non-Windows: use getpwuid to find the home directory

8) On Windows, if it finds no *.curlrc* file in the sequence described above, it
checks for one in the same dir the curl executable is placed.
8) On Windows, if it finds no *.curlrc* file in the sequence described above,
it checks for one in the same dir the curl executable is placed.

For those entries above where curlrc does not have the leading dot, if *curlrc*
is not found then the location is also checked for *.curlrc*.

Additionally, on Windows if *.curlrc* is not found then the location is also
checked for *_curlrc*. Older versions on Windows checked for *_curlrc* only.

On Windows two filenames are checked per location: *.curlrc* and *_curlrc*,
preferring the former. Older versions on Windows checked for *_curlrc* only.
Prior to curl 8.5.0, location #2 (XDG home and its fallbacks) did not check for
*curlrc*, instead the first check was for *.curlrc* with the leading dot.
75 changes: 51 additions & 24 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 Down Expand Up @@ -90,32 +92,54 @@ static char *checkhome(const char *home, const char *fname, bool dotscore)
}

/*
* 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
*
* On Windows if 'fname' is .curlrc then each location is checked for .curlrc
* and _curlrc for legacy reasons.
*
* 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 (only if 'fname' is .curlrc on Windows)
*/
char *findfile(const char *fname, int dotscore)
char *findfile(const char *fname)
{
int i;
bool xdg = FALSE;
bool dotscore;
bool fname_is_relative_path;
bool xdg_main_found = FALSE;
DEBUGASSERT(fname && fname[0]);
DEBUGASSERT((dotscore != 1) || (fname[0] == '.'));

if(!fname[0])
return NULL;

#ifdef WIN32
/* dotscore means also check for fname with a leading underscore: _curlrc */
dotscore = !strcmp(".curlrc", fname);
#else
dotscore = false;
#endif

fname_is_relative_path = !!strpbrk(fname, "\\/");

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);

if(home) {
char *path;
const char *filename = fname;
if(i == 1 /* XDG_CONFIG_HOME */)
xdg = TRUE;
if(i == 1 /* XDG_CONFIG_HOME is set */)
xdg_main_found = TRUE;
if(!home[0]) {
curl_free(home);
continue;
Expand All @@ -127,17 +151,20 @@ 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) {
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;
Expand Down
8 changes: 1 addition & 7 deletions src/tool_findfile.h
Expand Up @@ -25,12 +25,6 @@
***************************************************************************/
#include "tool_setup.h"

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

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

#endif /* HEADER_CURL_TOOL_HOMEDIR_H */
2 changes: 1 addition & 1 deletion src/tool_operate.c
Expand Up @@ -2007,7 +2007,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");
if(known) {
/* new in curl 7.19.6 */
result = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, known);
Expand Down
5 changes: 3 additions & 2 deletions src/tool_parsecfg.c
Expand Up @@ -88,8 +88,9 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
char *pathalloc = NULL;

if(!filename) {
/* NULL means load .curlrc from homedir! */
char *curlrc = findfile(".curlrc", CURLRC_DOTSCORE);
/* NULL means load .curlrc from homedir.
On Windows a findfile check for .curlrc also checks for _curlrc */
char *curlrc = findfile(".curlrc");
if(curlrc) {
file = fopen(curlrc, FOPEN_READTEXT);
if(!file) {
Expand Down

0 comments on commit 407444a

Please sign in to comment.