blob: 50a5769c3d6358fef4af8f67e9ee7cc8aeddc2b0 [file] [log] [blame]
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05301/****************************************************************************
micky3879b9f5e72025-07-08 18:04:53 -04002 * Copyright 2019-2021,2023 Thomas E. Dickey *
3 * Copyright 1998-2011,2012 Free Software Foundation, Inc. *
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +05304 * *
5 * Permission is hereby granted, free of charge, to any person obtaining a *
6 * copy of this software and associated documentation files (the *
7 * "Software"), to deal in the Software without restriction, including *
8 * without limitation the rights to use, copy, modify, merge, publish, *
9 * distribute, distribute with modifications, sublicense, and/or sell *
10 * copies of the Software, and to permit persons to whom the Software is *
11 * furnished to do so, subject to the following conditions: *
12 * *
13 * The above copyright notice and this permission notice shall be included *
14 * in all copies or substantial portions of the Software. *
15 * *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * *
24 * Except as contained in this notice, the name(s) of the above copyright *
25 * holders shall not be used in advertising or otherwise to promote the *
26 * sale, use or other dealings in this Software without prior written *
27 * authorization. *
28 ****************************************************************************/
29
30/****************************************************************************
31 * Author: Thomas E. Dickey *
32 ****************************************************************************/
33
34#include <curses.priv.h>
35
36#include <ctype.h>
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053037
micky3879b9f5e72025-07-08 18:04:53 -040038#ifndef USE_ROOT_ACCESS
39#if HAVE_SETFSUID
40#include <sys/fsuid.h>
41#else
42#include <sys/stat.h>
43#endif
44#endif
45
46#if HAVE_GETAUXVAL && HAVE_SYS_AUXV_H && defined(__GLIBC__) && (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 19)
47#include <sys/auxv.h>
48#define USE_GETAUXVAL 1
49#else
50#define USE_GETAUXVAL 0
51#endif
52
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053053#include <tic.h>
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053054
micky3879b9f5e72025-07-08 18:04:53 -040055MODULE_ID("$Id: access.c,v 1.37 2023/06/24 21:55:09 tom Exp $")
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053056
57#define LOWERCASE(c) ((isalpha(UChar(c)) && isupper(UChar(c))) ? tolower(UChar(c)) : (c))
58
micky3879b9f5e72025-07-08 18:04:53 -040059#ifdef _NC_MSC
60# define ACCESS(FN, MODE) access((FN), (MODE)&(R_OK|W_OK))
61#else
62# define ACCESS access
63#endif
64
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053065NCURSES_EXPORT(char *)
66_nc_rootname(char *path)
67{
68 char *result = _nc_basename(path);
69#if !MIXEDCASE_FILENAMES || defined(PROG_EXT)
70 static char *temp;
71 char *s;
72
micky3879b9f5e72025-07-08 18:04:53 -040073 if ((temp = strdup(result)) != 0)
74 result = temp;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053075#if !MIXEDCASE_FILENAMES
76 for (s = result; *s != '\0'; ++s) {
Steve Kondikae271bc2015-11-15 02:50:53 +010077 *s = (char) LOWERCASE(*s);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +053078 }
79#endif
80#if defined(PROG_EXT)
81 if ((s = strrchr(result, '.')) != 0) {
82 if (!strcmp(s, PROG_EXT))
83 *s = '\0';
84 }
85#endif
86#endif
87 return result;
88}
89
90/*
91 * Check if a string appears to be an absolute pathname.
92 */
93NCURSES_EXPORT(bool)
94_nc_is_abs_path(const char *path)
95{
96#if defined(__EMX__) || defined(__DJGPP__)
97#define is_pathname(s) ((((s) != 0) && ((s)[0] == '/')) \
98 || (((s)[0] != 0) && ((s)[1] == ':')))
99#else
100#define is_pathname(s) ((s) != 0 && (s)[0] == '/')
101#endif
102 return is_pathname(path);
103}
104
105/*
106 * Return index of the basename
107 */
108NCURSES_EXPORT(unsigned)
109_nc_pathlast(const char *path)
110{
111 const char *test = strrchr(path, '/');
112#ifdef __EMX__
113 if (test == 0)
114 test = strrchr(path, '\\');
115#endif
116 if (test == 0)
117 test = path;
118 else
119 test++;
Steve Kondikae271bc2015-11-15 02:50:53 +0100120 return (unsigned) (test - path);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530121}
122
123NCURSES_EXPORT(char *)
124_nc_basename(char *path)
125{
126 return path + _nc_pathlast(path);
127}
128
129NCURSES_EXPORT(int)
130_nc_access(const char *path, int mode)
131{
Steve Kondikae271bc2015-11-15 02:50:53 +0100132 int result;
133
134 if (path == 0) {
135 result = -1;
micky3879b9f5e72025-07-08 18:04:53 -0400136 } else if (ACCESS(path, mode) < 0) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530137 if ((mode & W_OK) != 0
138 && errno == ENOENT
139 && strlen(path) < PATH_MAX) {
140 char head[PATH_MAX];
Steve Kondikae271bc2015-11-15 02:50:53 +0100141 char *leaf;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530142
Steve Kondikae271bc2015-11-15 02:50:53 +0100143 _nc_STRCPY(head, path, sizeof(head));
144 leaf = _nc_basename(head);
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530145 if (leaf == 0)
146 leaf = head;
147 *leaf = '\0';
148 if (head == leaf)
Steve Kondikae271bc2015-11-15 02:50:53 +0100149 _nc_STRCPY(head, ".", sizeof(head));
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530150
micky3879b9f5e72025-07-08 18:04:53 -0400151 result = ACCESS(head, R_OK | W_OK | X_OK);
Steve Kondikae271bc2015-11-15 02:50:53 +0100152 } else {
153 result = -1;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530154 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100155 } else {
156 result = 0;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530157 }
Steve Kondikae271bc2015-11-15 02:50:53 +0100158 return result;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530159}
160
161NCURSES_EXPORT(bool)
162_nc_is_dir_path(const char *path)
163{
164 bool result = FALSE;
165 struct stat sb;
166
167 if (stat(path, &sb) == 0
Steve Kondikae271bc2015-11-15 02:50:53 +0100168 && S_ISDIR(sb.st_mode)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530169 result = TRUE;
170 }
171 return result;
172}
173
174NCURSES_EXPORT(bool)
175_nc_is_file_path(const char *path)
176{
177 bool result = FALSE;
178 struct stat sb;
179
180 if (stat(path, &sb) == 0
Steve Kondikae271bc2015-11-15 02:50:53 +0100181 && S_ISREG(sb.st_mode)) {
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530182 result = TRUE;
183 }
184 return result;
185}
186
micky3879b9f5e72025-07-08 18:04:53 -0400187#if HAVE_GETEUID && HAVE_GETEGID
188#define is_posix_elevated() \
189 (getuid() != geteuid() \
190 || getgid() != getegid())
191#else
192#define is_posix_elevated() FALSE
193#endif
194
195#if HAVE_ISSETUGID
196#define is_elevated() issetugid()
197#elif USE_GETAUXVAL && defined(AT_SECURE)
198#define is_elevated() \
199 (getauxval(AT_SECURE) \
200 ? TRUE \
201 : (errno != ENOENT \
202 ? FALSE \
203 : is_posix_elevated()))
204#else
205#define is_elevated() is_posix_elevated()
206#endif
207
208#if HAVE_SETFSUID
209#define lower_privileges() \
210 int save_err = errno; \
211 setfsuid(getuid()); \
212 setfsgid(getgid()); \
213 errno = save_err
214#define resume_elevation() \
215 save_err = errno; \
216 setfsuid(geteuid()); \
217 setfsgid(getegid()); \
218 errno = save_err
219#else
220#define lower_privileges() /* nothing */
221#define resume_elevation() /* nothing */
222#endif
223
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530224/*
micky3879b9f5e72025-07-08 18:04:53 -0400225 * Returns true if not running as root or setuid. We use this check to allow
226 * applications to use environment variables that are used for searching lists
227 * of directories, etc.
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530228 */
229NCURSES_EXPORT(int)
230_nc_env_access(void)
231{
micky3879b9f5e72025-07-08 18:04:53 -0400232 int result = TRUE;
233
234#if HAVE_GETUID && HAVE_GETEUID
235#if !defined(USE_SETUID_ENVIRON)
236 if (is_elevated()) {
237 result = FALSE;
238 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530239#endif
micky3879b9f5e72025-07-08 18:04:53 -0400240#if !defined(USE_ROOT_ENVIRON)
241 if ((getuid() == ROOT_UID) || (geteuid() == ROOT_UID)) {
242 result = FALSE;
243 }
244#endif
245#endif /* HAVE_GETUID && HAVE_GETEUID */
246 return result;
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530247}
micky3879b9f5e72025-07-08 18:04:53 -0400248
249#ifndef USE_ROOT_ACCESS
250/*
251 * Limit privileges if possible; otherwise disallow access for updating files.
252 */
253NCURSES_EXPORT(FILE *)
254_nc_safe_fopen(const char *path, const char *mode)
255{
256 FILE *result = NULL;
257#if HAVE_SETFSUID
258 lower_privileges();
259 result = fopen(path, mode);
260 resume_elevation();
261#else
262 if (!is_elevated() || *mode == 'r') {
263 result = fopen(path, mode);
264 }
Amit Daniel Kachhape6a01f52011-07-20 11:45:59 +0530265#endif
micky3879b9f5e72025-07-08 18:04:53 -0400266 return result;
267}
268
269NCURSES_EXPORT(int)
270_nc_safe_open3(const char *path, int flags, mode_t mode)
271{
272 int result = -1;
273#if HAVE_SETFSUID
274 lower_privileges();
275 result = open(path, flags, mode);
276 resume_elevation();
277#else
278 if (!is_elevated() || (flags & O_RDONLY)) {
279 result = open(path, flags, mode);
280 }
281#endif
282 return result;
283}
284#endif /* USE_ROOT_ACCESS */