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