chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / sysdeps / posix / euidaccess.c
1 /* Check if effective user id can access file
2    Copyright (C) 1990,1991,1995-2001,2005,2007 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 /* Written by David MacKenzie and Torbjorn Granlund.
21    Adapted for GNU C library by Roland McGrath.  */
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #ifdef S_IEXEC
31 # ifndef S_IXUSR
32 #  define S_IXUSR S_IEXEC
33 # endif
34 # ifndef S_IXGRP
35 #  define S_IXGRP (S_IEXEC >> 3)
36 # endif
37 # ifndef S_IXOTH
38 #  define S_IXOTH (S_IEXEC >> 6)
39 # endif
40 #endif /* S_IEXEC */
41
42 #if defined HAVE_UNISTD_H || defined _LIBC
43 # include <unistd.h>
44 #endif
45
46 #ifndef _POSIX_VERSION
47 uid_t getuid ();
48 gid_t getgid ();
49 uid_t geteuid ();
50 gid_t getegid ();
51 #endif /* not POSIX_VERSION */
52
53 #include <errno.h>
54 #ifndef errno
55 extern int errno;
56 #endif
57 #ifndef __set_errno
58 # define __set_errno(val) errno = (val)
59 #endif
60
61 #if defined EACCES && !defined EACCESS
62 # define EACCESS EACCES
63 #endif
64
65 #ifndef F_OK
66 # define F_OK 0
67 # define X_OK 1
68 # define W_OK 2
69 # define R_OK 4
70 #endif
71
72 #if !defined S_IROTH && defined R_OK
73 # define S_IROTH R_OK
74 #endif
75 #if !defined S_IWOTH && defined W_OK
76 # define S_IWOTH W_OK
77 #endif
78 #if !defined S_IXOTH && defined X_OK
79 # define S_IXOTH X_OK
80 #endif
81
82
83 #ifdef _LIBC
84
85 # define group_member __group_member
86 # define euidaccess __euidaccess
87
88 #else
89
90 /* The user's real user id. */
91 static uid_t uid;
92
93 /* The user's real group id. */
94 static gid_t gid;
95
96 /* The user's effective user id. */
97 static uid_t euid;
98
99 /* The user's effective group id. */
100 static gid_t egid;
101
102 /* Nonzero if UID, GID, EUID, and EGID have valid values. */
103 static int have_ids;
104
105 # ifdef HAVE_GETGROUPS
106 int group_member ();
107 # else
108 #  define group_member(gid)     0
109 # endif
110
111 #endif
112
113
114 /* Return 0 if the user has permission of type MODE on file PATH;
115    otherwise, return -1 and set `errno' to EACCESS.
116    Like access, except that it uses the effective user and group
117    id's instead of the real ones, and it does not check for read-only
118    filesystem, text busy, etc. */
119
120 int
121 euidaccess (path, mode)
122      const char *path;
123      int mode;
124 {
125   struct stat64 stats;
126   int granted;
127
128 #ifdef  _LIBC
129   uid_t euid;
130   gid_t egid;
131 #else
132   if (have_ids == 0)
133     {
134       have_ids = 1;
135       uid = getuid ();
136       gid = getgid ();
137       euid = geteuid ();
138       egid = getegid ();
139     }
140
141   if (uid == euid && gid == egid)
142     /* If we are not set-uid or set-gid, access does the same.  */
143     return access (path, mode);
144 #endif
145
146   if (stat64 (path, &stats))
147     return -1;
148
149   mode &= (X_OK | W_OK | R_OK); /* Clear any bogus bits. */
150 #if R_OK != S_IROTH || W_OK != S_IWOTH || X_OK != S_IXOTH
151   ?error Oops, portability assumptions incorrect.
152 #endif
153
154   if (mode == F_OK)
155     return 0;                   /* The file exists. */
156
157 #ifdef  _LIBC
158   /* Now we need the IDs.  */
159   euid = __geteuid ();
160   egid = __getegid ();
161
162   if (__getuid () == euid && __getgid () == egid)
163     /* If we are not set-uid or set-gid, access does the same.  */
164     return __access (path, mode);
165 #endif
166
167   /* The super-user can read and write any file, and execute any file
168      that anyone can execute. */
169   if (euid == 0 && ((mode & X_OK) == 0
170                     || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
171     return 0;
172
173   if (euid == stats.st_uid)
174     granted = (unsigned int) (stats.st_mode & (mode << 6)) >> 6;
175   else if (egid == stats.st_gid || group_member (stats.st_gid))
176     granted = (unsigned int) (stats.st_mode & (mode << 3)) >> 3;
177   else
178     granted = (stats.st_mode & mode);
179   /* XXX Add support for ACLs.  */
180   if (granted == mode)
181     return 0;
182   __set_errno (EACCESS);
183   return -1;
184 }
185 #undef euidaccess
186 #undef eaccess
187 #ifdef weak_alias
188 weak_alias (__euidaccess, euidaccess)
189 weak_alias (__euidaccess, eaccess)
190 #endif
191 \f
192 #ifdef TEST
193 # include <stdio.h>
194 # include <errno.h>
195 # include "error.h"
196
197 char *program_name;
198
199 int
200 main (argc, argv)
201      int argc;
202      char **argv;
203 {
204   char *file;
205   int mode;
206   int err;
207
208   program_name = argv[0];
209   if (argc < 3)
210     abort ();
211   file = argv[1];
212   mode = atoi (argv[2]);
213
214   err = euidaccess (file, mode);
215   printf ("%d\n", err);
216   if (err != 0)
217     error (0, errno, "%s", file);
218   exit (0);
219 }
220 #endif