1 | /* Check if effective user id can access file |
2 | Copyright (C) 1990-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | /* Written by David MacKenzie and Torbjorn Granlund. |
20 | Adapted for GNU C library by Roland McGrath. */ |
21 | |
22 | #ifdef HAVE_CONFIG_H |
23 | # include <config.h> |
24 | #endif |
25 | |
26 | #include <sys/types.h> |
27 | #include <sys/stat.h> |
28 | |
29 | #ifdef S_IEXEC |
30 | # ifndef S_IXUSR |
31 | # define S_IXUSR S_IEXEC |
32 | # endif |
33 | # ifndef S_IXGRP |
34 | # define S_IXGRP (S_IEXEC >> 3) |
35 | # endif |
36 | # ifndef S_IXOTH |
37 | # define S_IXOTH (S_IEXEC >> 6) |
38 | # endif |
39 | #endif /* S_IEXEC */ |
40 | |
41 | #if defined HAVE_UNISTD_H || defined _LIBC |
42 | # include <unistd.h> |
43 | #endif |
44 | |
45 | #ifndef _POSIX_VERSION |
46 | uid_t getuid (); |
47 | gid_t getgid (); |
48 | uid_t geteuid (); |
49 | gid_t getegid (); |
50 | #endif /* not POSIX_VERSION */ |
51 | |
52 | #include <errno.h> |
53 | #ifndef errno |
54 | extern int errno; |
55 | #endif |
56 | #ifndef __set_errno |
57 | # define __set_errno(val) errno = (val) |
58 | #endif |
59 | |
60 | #if defined EACCES && !defined EACCESS |
61 | # define EACCESS EACCES |
62 | #endif |
63 | |
64 | #ifndef F_OK |
65 | # define F_OK 0 |
66 | # define X_OK 1 |
67 | # define W_OK 2 |
68 | # define R_OK 4 |
69 | #endif |
70 | |
71 | #if !defined S_IROTH && defined R_OK |
72 | # define S_IROTH R_OK |
73 | #endif |
74 | #if !defined S_IWOTH && defined W_OK |
75 | # define S_IWOTH W_OK |
76 | #endif |
77 | #if !defined S_IXOTH && defined X_OK |
78 | # define S_IXOTH X_OK |
79 | #endif |
80 | |
81 | |
82 | #ifdef _LIBC |
83 | |
84 | # define group_member __group_member |
85 | # define euidaccess __euidaccess |
86 | |
87 | #else |
88 | |
89 | /* The user's real user id. */ |
90 | static uid_t uid; |
91 | |
92 | /* The user's real group id. */ |
93 | static gid_t gid; |
94 | |
95 | /* The user's effective user id. */ |
96 | static uid_t euid; |
97 | |
98 | /* The user's effective group id. */ |
99 | static gid_t egid; |
100 | |
101 | /* Nonzero if UID, GID, EUID, and EGID have valid values. */ |
102 | static int have_ids; |
103 | |
104 | # ifdef HAVE_GETGROUPS |
105 | int group_member (); |
106 | # else |
107 | # define group_member(gid) 0 |
108 | # endif |
109 | |
110 | #endif |
111 | |
112 | |
113 | /* Return 0 if the user has permission of type MODE on file PATH; |
114 | otherwise, return -1 and set `errno' to EACCESS. |
115 | Like access, except that it uses the effective user and group |
116 | id's instead of the real ones, and it does not check for read-only |
117 | filesystem, text busy, etc. */ |
118 | |
119 | int |
120 | euidaccess (const char *path, int mode) |
121 | { |
122 | struct __stat64_t64 stats; |
123 | int granted; |
124 | |
125 | #ifdef _LIBC |
126 | uid_t euid; |
127 | gid_t egid; |
128 | #else |
129 | if (have_ids == 0) |
130 | { |
131 | have_ids = 1; |
132 | uid = getuid (); |
133 | gid = getgid (); |
134 | euid = geteuid (); |
135 | egid = getegid (); |
136 | } |
137 | |
138 | if (uid == euid && gid == egid) |
139 | /* If we are not set-uid or set-gid, access does the same. */ |
140 | return access (path, mode); |
141 | #endif |
142 | |
143 | if (__stat64_time64 (path, &stats)) |
144 | return -1; |
145 | |
146 | mode &= (X_OK | W_OK | R_OK); /* Clear any bogus bits. */ |
147 | #if R_OK != S_IROTH || W_OK != S_IWOTH || X_OK != S_IXOTH |
148 | ?error Oops, portability assumptions incorrect. |
149 | #endif |
150 | |
151 | if (mode == F_OK) |
152 | return 0; /* The file exists. */ |
153 | |
154 | #ifdef _LIBC |
155 | /* Now we need the IDs. */ |
156 | euid = __geteuid (); |
157 | egid = __getegid (); |
158 | |
159 | if (__getuid () == euid && __getgid () == egid) |
160 | /* If we are not set-uid or set-gid, access does the same. */ |
161 | return __access (path, mode); |
162 | #endif |
163 | |
164 | /* The super-user can read and write any file, and execute any file |
165 | that anyone can execute. */ |
166 | if (euid == 0 && ((mode & X_OK) == 0 |
167 | || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))) |
168 | return 0; |
169 | |
170 | if (euid == stats.st_uid) |
171 | granted = (unsigned int) (stats.st_mode & (mode << 6)) >> 6; |
172 | else if (egid == stats.st_gid || group_member (stats.st_gid)) |
173 | granted = (unsigned int) (stats.st_mode & (mode << 3)) >> 3; |
174 | else |
175 | granted = (stats.st_mode & mode); |
176 | /* XXX Add support for ACLs. */ |
177 | if (granted == mode) |
178 | return 0; |
179 | __set_errno (EACCESS); |
180 | return -1; |
181 | } |
182 | #undef euidaccess |
183 | #undef eaccess |
184 | #ifdef weak_alias |
185 | weak_alias (__euidaccess, euidaccess) |
186 | weak_alias (__euidaccess, eaccess) |
187 | #endif |
188 | |
189 | #ifdef TEST |
190 | # include <stdio.h> |
191 | # include <errno.h> |
192 | # include "error.h" |
193 | |
194 | char *program_name; |
195 | |
196 | int |
197 | main (int argc, char **argv) |
198 | { |
199 | char *file; |
200 | int mode; |
201 | int err; |
202 | |
203 | program_name = argv[0]; |
204 | if (argc < 3) |
205 | abort (); |
206 | file = argv[1]; |
207 | mode = atoi (argv[2]); |
208 | |
209 | err = euidaccess (file, mode); |
210 | printf ("%d\n" , err); |
211 | if (err != 0) |
212 | error (0, errno, "%s" , file); |
213 | exit (0); |
214 | } |
215 | #endif |
216 | |