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