Write "Mac OS X" instead of "MacOS X".
[gnulib.git] / lib / euidaccess.c
1 /* euidaccess -- check if effective user id can access file
2
3    Copyright (C) 1990-1991, 1995, 1998, 2000, 2003-2006, 2008-2012 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 #endif
67
68 /* Return 0 if the user has permission of type MODE on FILE;
69    otherwise, return -1 and set 'errno'.
70    Like access, except that it uses the effective user and group
71    id's instead of the real ones, and it does not always check for read-only
72    file system, text busy, etc.  */
73
74 int
75 euidaccess (const char *file, int mode)
76 {
77 #if HAVE_FACCESSAT                   /* glibc, AIX 7, Solaris 11, Cygwin 1.7 */
78   return faccessat (AT_FDCWD, file, mode, AT_EACCESS);
79 #elif defined EFF_ONLY_OK               /* IRIX, OSF/1, Interix */
80   return access (file, mode | EFF_ONLY_OK);
81 #elif defined ACC_SELF                  /* AIX */
82   return accessx (file, mode, ACC_SELF);
83 #elif HAVE_EACCESS                      /* FreeBSD */
84   return eaccess (file, mode);
85 #else       /* Mac OS X, NetBSD, OpenBSD, HP-UX, Solaris, Cygwin, mingw, BeOS */
86
87   uid_t uid = getuid ();
88   gid_t gid = getgid ();
89   uid_t euid = geteuid ();
90   gid_t egid = getegid ();
91   struct stat stats;
92
93 # if HAVE_DECL_SETREGID && PREFER_NONREENTRANT_EUIDACCESS
94
95   /* Define PREFER_NONREENTRANT_EUIDACCESS if you prefer euidaccess to
96      return the correct result even if this would make it
97      nonreentrant.  Define this only if your entire application is
98      safe even if the uid or gid might temporarily change.  If your
99      application uses signal handlers or threads it is probably not
100      safe.  */
101
102   if (mode == F_OK)
103     return stat (file, &stats);
104   else
105     {
106       int result;
107       int saved_errno;
108
109       if (uid != euid)
110         setreuid (euid, uid);
111       if (gid != egid)
112         setregid (egid, gid);
113
114       result = access (file, mode);
115       saved_errno = errno;
116
117       /* Restore them.  */
118       if (uid != euid)
119         setreuid (uid, euid);
120       if (gid != egid)
121         setregid (gid, egid);
122
123       errno = saved_errno;
124       return result;
125     }
126
127 # else
128
129   /* The following code assumes the traditional Unix model, and is not
130      correct on systems that have ACLs or the like.  However, it's
131      better than nothing, and it is reentrant.  */
132
133   unsigned int granted;
134   if (uid == euid && gid == egid)
135     /* If we are not set-uid or set-gid, access does the same.  */
136     return access (file, mode);
137
138   if (stat (file, &stats) != 0)
139     return -1;
140
141   /* The super-user can read and write any file, and execute any file
142      that anyone can execute.  */
143   if (euid == 0 && ((mode & X_OK) == 0
144                     || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
145     return 0;
146
147   /* Convert the mode to traditional form, clearing any bogus bits.  */
148   if (R_OK == 4 && W_OK == 2 && X_OK == 1 && F_OK == 0)
149     mode &= 7;
150   else
151     mode = ((mode & R_OK ? 4 : 0)
152             + (mode & W_OK ? 2 : 0)
153             + (mode & X_OK ? 1 : 0));
154
155   if (mode == 0)
156     return 0;                   /* The file exists.  */
157
158   /* Convert the file's permission bits to traditional form.  */
159   if (S_IRUSR == (4 << 6) && S_IWUSR == (2 << 6) && S_IXUSR == (1 << 6)
160       && S_IRGRP == (4 << 3) && S_IWGRP == (2 << 3) && S_IXGRP == (1 << 3)
161       && S_IROTH == (4 << 0) && S_IWOTH == (2 << 0) && S_IXOTH == (1 << 0))
162     granted = stats.st_mode;
163   else
164     granted = ((stats.st_mode & S_IRUSR ? 4 << 6 : 0)
165                + (stats.st_mode & S_IWUSR ? 2 << 6 : 0)
166                + (stats.st_mode & S_IXUSR ? 1 << 6 : 0)
167                + (stats.st_mode & S_IRGRP ? 4 << 3 : 0)
168                + (stats.st_mode & S_IWGRP ? 2 << 3 : 0)
169                + (stats.st_mode & S_IXGRP ? 1 << 3 : 0)
170                + (stats.st_mode & S_IROTH ? 4 << 0 : 0)
171                + (stats.st_mode & S_IWOTH ? 2 << 0 : 0)
172                + (stats.st_mode & S_IXOTH ? 1 << 0 : 0));
173
174   if (euid == stats.st_uid)
175     granted >>= 6;
176   else if (egid == stats.st_gid || group_member (stats.st_gid))
177     granted >>= 3;
178
179   if ((mode & ~granted) == 0)
180     return 0;
181   __set_errno (EACCESS);
182   return -1;
183
184 # endif
185 #endif
186 }
187 #undef euidaccess
188 #ifdef weak_alias
189 weak_alias (__euidaccess, euidaccess)
190 #endif
191 \f
192 #ifdef TEST
193 # include <error.h>
194 # include <stdio.h>
195 # include <stdlib.h>
196
197 char *program_name;
198
199 int
200 main (int argc, char **argv)
201 {
202   char *file;
203   int mode;
204   int err;
205
206   program_name = argv[0];
207   if (argc < 3)
208     abort ();
209   file = argv[1];
210   mode = atoi (argv[2]);
211
212   err = euidaccess (file, mode);
213   printf ("%d\n", err);
214   if (err != 0)
215     error (0, errno, "%s", file);
216   exit (0);
217 }
218 #endif