| 1 | /* Check if effective user id can access file | 
|---|
| 2 | Copyright (C) 1990-2020 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 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 (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 |  | 
|---|