1/* euidaccess -- check if effective user id can access file 2 3 Copyright (C) 1990-1991, 1995, 1998, 2000, 2003-2006, 2008-2010 Free 4 Software Foundation, Inc. 5 6 This file is part of the GNU C Library. 7 8 This program is free software: you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 20 21/* Written by David MacKenzie and Torbjorn Granlund. 22 Adapted for GNU C library by Roland McGrath. */ 23 24#ifndef _LIBC 25# include <config.h> 26#endif 27 28#include <fcntl.h> 29#include <sys/types.h> 30#include <sys/stat.h> 31#include <unistd.h> 32 33#if HAVE_LIBGEN_H 34# include <libgen.h> 35#endif 36 37#include <errno.h> 38#ifndef __set_errno 39# define __set_errno(val) errno = (val) 40#endif 41 42#if defined EACCES && !defined EACCESS 43# define EACCESS EACCES 44#endif 45 46#ifndef F_OK 47# define F_OK 0 48# define X_OK 1 49# define W_OK 2 50# define R_OK 4 51#endif 52 53 54#ifdef _LIBC 55 56# define access __access 57# define getuid __getuid 58# define getgid __getgid 59# define geteuid __geteuid 60# define getegid __getegid 61# define group_member __group_member 62# define euidaccess __euidaccess 63# undef stat 64# define stat stat64 65 66#else 67 68# include "group-member.h" 69 70#endif 71 72/* Return 0 if the user has permission of type MODE on FILE; 73 otherwise, return -1 and set `errno'. 74 Like access, except that it uses the effective user and group 75 id's instead of the real ones, and it does not always check for read-only 76 file system, text busy, etc. */ 77 78int 79euidaccess (const char *file, int mode) 80{ 81#if HAVE_FACCESSAT 82 return faccessat (AT_FDCWD, file, mode, AT_EACCESS); 83#elif defined EFF_ONLY_OK 84 return access (file, mode | EFF_ONLY_OK); 85#elif defined ACC_SELF 86 return accessx (file, mode, ACC_SELF); 87#elif HAVE_EACCESS 88 return eaccess (file, mode); 89#else 90 91 uid_t uid = getuid (); 92 gid_t gid = getgid (); 93 uid_t euid = geteuid (); 94 gid_t egid = getegid (); 95 struct stat stats; 96 97# if HAVE_DECL_SETREGID && PREFER_NONREENTRANT_EUIDACCESS 98 99 /* Define PREFER_NONREENTRANT_EUIDACCESS if you prefer euidaccess to 100 return the correct result even if this would make it 101 nonreentrant. Define this only if your entire application is 102 safe even if the uid or gid might temporarily change. If your 103 application uses signal handlers or threads it is probably not 104 safe. */ 105 106 if (mode == F_OK) 107 return stat (file, &stats); 108 else 109 { 110 int result; 111 int saved_errno; 112 113 if (uid != euid) 114 setreuid (euid, uid); 115 if (gid != egid) 116 setregid (egid, gid); 117 118 result = access (file, mode); 119 saved_errno = errno; 120 121 /* Restore them. */ 122 if (uid != euid) 123 setreuid (uid, euid); 124 if (gid != egid) 125 setregid (gid, egid); 126 127 errno = saved_errno; 128 return result; 129 } 130 131# else 132 133 /* The following code assumes the traditional Unix model, and is not 134 correct on systems that have ACLs or the like. However, it's 135 better than nothing, and it is reentrant. */ 136 137 unsigned int granted; 138 if (uid == euid && gid == egid) 139 /* If we are not set-uid or set-gid, access does the same. */ 140 return access (file, mode); 141 142 if (stat (file, &stats) != 0) 143 return -1; 144 145 /* The super-user can read and write any file, and execute any file 146 that anyone can execute. */ 147 if (euid == 0 && ((mode & X_OK) == 0 148 || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))) 149 return 0; 150 151 /* Convert the mode to traditional form, clearing any bogus bits. */ 152 if (R_OK == 4 && W_OK == 2 && X_OK == 1 && F_OK == 0) 153 mode &= 7; 154 else 155 mode = ((mode & R_OK ? 4 : 0) 156 + (mode & W_OK ? 2 : 0) 157 + (mode & X_OK ? 1 : 0)); 158 159 if (mode == 0) 160 return 0; /* The file exists. */ 161 162 /* Convert the file's permission bits to traditional form. */ 163 if (S_IRUSR == (4 << 6) && S_IWUSR == (2 << 6) && S_IXUSR == (1 << 6) 164 && S_IRGRP == (4 << 3) && S_IWGRP == (2 << 3) && S_IXGRP == (1 << 3) 165 && S_IROTH == (4 << 0) && S_IWOTH == (2 << 0) && S_IXOTH == (1 << 0)) 166 granted = stats.st_mode; 167 else 168 granted = ((stats.st_mode & S_IRUSR ? 4 << 6 : 0) 169 + (stats.st_mode & S_IWUSR ? 2 << 6 : 0) 170 + (stats.st_mode & S_IXUSR ? 1 << 6 : 0) 171 + (stats.st_mode & S_IRGRP ? 4 << 3 : 0) 172 + (stats.st_mode & S_IWGRP ? 2 << 3 : 0) 173 + (stats.st_mode & S_IXGRP ? 1 << 3 : 0) 174 + (stats.st_mode & S_IROTH ? 4 << 0 : 0) 175 + (stats.st_mode & S_IWOTH ? 2 << 0 : 0) 176 + (stats.st_mode & S_IXOTH ? 1 << 0 : 0)); 177 178 if (euid == stats.st_uid) 179 granted >>= 6; 180 else if (egid == stats.st_gid || group_member (stats.st_gid)) 181 granted >>= 3; 182 183 if ((mode & ~granted) == 0) 184 return 0; 185 __set_errno (EACCESS); 186 return -1; 187 188# endif 189#endif 190} 191#undef euidaccess 192#ifdef weak_alias 193weak_alias (__euidaccess, euidaccess) 194#endif 195 196#ifdef TEST 197# include <error.h> 198# include <stdio.h> 199# include <stdlib.h> 200 201char *program_name; 202 203int 204main (int argc, char **argv) 205{ 206 char *file; 207 int mode; 208 int err; 209 210 program_name = argv[0]; 211 if (argc < 3) 212 abort (); 213 file = argv[1]; 214 mode = atoi (argv[2]); 215 216 err = euidaccess (file, mode); 217 printf ("%d\n", err); 218 if (err != 0) 219 error (0, errno, "%s", file); 220 exit (0); 221} 222#endif 223