| xf.li | bdd93d5 | 2023-05-12 07:10:14 -0700 | [diff] [blame] | 1 | /* Check if effective user id can access file | 
 | 2 |    Copyright (C) 1990-2016 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 |    <http://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 |