1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24 #include "tool_setup.h"
25
26 #ifdef HAVE_PWD_H
27 #undef __NO_NET_API /* required for AmigaOS to declare getpwuid() */
28 #include <pwd.h>
29 #define __NO_NET_API
30 #endif
31
32 #ifdef HAVE_SYS_STAT_H
33 #include <sys/stat.h>
34 #endif
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38
39 #include <curlx.h>
40
41 #include "tool_findfile.h"
42
43 #include "memdebug.h" /* keep this as LAST include */
44
45 struct finder {
46 const char *env;
47 const char *append;
48 bool withoutdot;
49 };
50
51 /* The order of the variables below is important, as the index number is used
52 in the findfile() function */
53 static const struct finder conf_list[] = {
54 { "CURL_HOME", NULL, FALSE },
55 { "XDG_CONFIG_HOME", NULL, TRUE },
56 { "HOME", NULL, FALSE },
57 #ifdef _WIN32
58 { "USERPROFILE", NULL, FALSE },
59 { "APPDATA", NULL, FALSE },
60 { "USERPROFILE", "\\Application Data", FALSE},
61 #endif
62 /* these are for .curlrc if XDG_CONFIG_HOME is not defined */
63 { "CURL_HOME", "/.config", TRUE },
64 { "HOME", "/.config", TRUE },
65
66 { NULL, NULL, FALSE }
67 };
68
checkhome(const char * home,const char * fname,bool dotscore)69 static char *checkhome(const char *home, const char *fname, bool dotscore)
70 {
71 const char pref[2] = { '.', '_' };
72 int i;
73 for(i = 0; i < (dotscore ? 2 : 1); i++) {
74 char *c;
75 if(dotscore)
76 c = aprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]);
77 else
78 c = aprintf("%s" DIR_CHAR "%s", home, fname);
79 if(c) {
80 int fd = open(c, O_RDONLY);
81 if(fd >= 0) {
82 char *path = strdup(c);
83 close(fd);
84 curl_free(c);
85 return path;
86 }
87 curl_free(c);
88 }
89 }
90 return NULL;
91 }
92
93 /*
94 * findfile() - return the full path name of the file.
95 *
96 * If 'dotscore' is TRUE, then check for the file first with a leading dot
97 * and then with a leading underscore.
98 *
99 * 1. Iterate over the environment variables in order, and if set, check for
100 * the given file to be accessed there, then it is a match.
101 * 2. Non-Windows: try getpwuid
102 */
findfile(const char * fname,int dotscore)103 char *findfile(const char *fname, int dotscore)
104 {
105 int i;
106 DEBUGASSERT(fname && fname[0]);
107 DEBUGASSERT((dotscore != 1) || (fname[0] == '.'));
108
109 if(!fname[0])
110 return NULL;
111
112 for(i = 0; conf_list[i].env; i++) {
113 char *home = curl_getenv(conf_list[i].env);
114 if(home) {
115 char *path;
116 const char *filename = fname;
117 if(!home[0]) {
118 curl_free(home);
119 continue;
120 }
121 if(conf_list[i].append) {
122 char *c = aprintf("%s%s", home, conf_list[i].append);
123 curl_free(home);
124 if(!c)
125 return NULL;
126 home = c;
127 }
128 if(conf_list[i].withoutdot) {
129 if(!dotscore) {
130 /* this is not looking for .curlrc, or the XDG_CONFIG_HOME was
131 defined so we skip the extended check */
132 curl_free(home);
133 continue;
134 }
135 filename++; /* move past the leading dot */
136 dotscore = 0; /* disable it for this check */
137 }
138 path = checkhome(home, filename, dotscore ? dotscore - 1 : 0);
139 curl_free(home);
140 if(path)
141 return path;
142 }
143 }
144 #if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
145 {
146 struct passwd *pw = getpwuid(geteuid());
147 if(pw) {
148 char *home = pw->pw_dir;
149 if(home && home[0])
150 return checkhome(home, fname, FALSE);
151 }
152 }
153 #endif /* PWD-stuff */
154 return NULL;
155 }
156