1 /* eaccess.c - eaccess replacement for the shell, plus other access functions. */
3 /* Copyright (C) 2006 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
21 #if defined (HAVE_CONFIG_H)
27 #include "bashtypes.h"
29 #if defined (HAVE_UNISTD_H)
40 #if !defined (_POSIX_VERSION) && defined (HAVE_SYS_FILE_H)
41 # include <sys/file.h>
42 #endif /* !_POSIX_VERSION */
43 #include "posixstat.h"
55 static int path_is_devfd __P((const char *));
56 static int sh_stataccess __P((char *, int));
57 #if HAVE_DECL_SETREGID
58 static int sh_euidaccess __P((char *, int));
65 if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
67 else if (STREQN (path, "/dev/std", 8))
69 if (STREQ (path+8, "in") || STREQ (path+8, "out") || STREQ (path+8, "err"))
78 /* A wrapper for stat () which disallows pathnames that are empty strings
79 and handles /dev/fd emulation on systems that don't have it. */
90 if (path[0] == '/' && path[1] == 'd' && strncmp (path, "/dev/fd/", 8) == 0)
92 #if !defined (HAVE_DEV_FD)
96 if (legal_number (path + 8, &fd) && fd == (int)fd)
98 r = fstat ((int)fd, finfo);
99 if (r == 0 || errno != EBADF)
105 /* If HAVE_DEV_FD is defined, DEV_FD_PREFIX is defined also, and has a
106 trailing slash. Make sure /dev/fd/xx really uses DEV_FD_PREFIX/xx.
107 On most systems, with the notable exception of linux, this is
108 effectively a no-op. */
110 strcpy (pbuf, DEV_FD_PREFIX);
111 strcat (pbuf, path + 8);
112 return (stat (pbuf, finfo));
113 #endif /* !HAVE_DEV_FD */
115 #if !defined (HAVE_DEV_STDIN)
116 else if (STREQN (path, "/dev/std", 8))
118 if (STREQ (path+8, "in"))
119 return (fstat (0, finfo));
120 else if (STREQ (path+8, "out"))
121 return (fstat (1, finfo));
122 else if (STREQ (path+8, "err"))
123 return (fstat (2, finfo));
125 return (stat (path, finfo));
127 #endif /* !HAVE_DEV_STDIN */
128 return (stat (path, finfo));
131 /* Do the same thing access(2) does, but use the effective uid and gid,
132 and don't make the mistake of telling root that any file is
133 executable. This version uses stat(2). */
135 sh_stataccess (path, mode)
141 if (sh_stat (path, &st) < 0)
144 if (current_user.euid == 0)
146 /* Root can read or write any file. */
147 if ((mode & X_OK) == 0)
150 /* Root can execute any file that has any one of the execute
152 if (st.st_mode & S_IXUGO)
156 if (st.st_uid == current_user.euid) /* owner */
158 else if (group_member (st.st_gid))
161 if (st.st_mode & mode)
168 #if HAVE_DECL_SETREGID
169 /* Version to call when uid != euid or gid != egid. We temporarily swap
170 the effective and real uid and gid as appropriate. */
172 sh_euidaccess (path, mode)
178 if (current_user.uid != current_user.euid)
179 setreuid (current_user.euid, current_user.uid);
180 if (current_user.gid != current_user.egid)
181 setregid (current_user.egid, current_user.gid);
183 r = access (path, mode);
186 if (current_user.uid != current_user.euid)
187 setreuid (current_user.uid, current_user.euid);
188 if (current_user.gid != current_user.egid)
189 setregid (current_user.gid, current_user.egid);
197 sh_eaccess (path, mode)
201 if (path_is_devfd (path))
202 return (sh_stataccess (path, mode));
204 #if defined (HAVE_EACCESS) /* FreeBSD */
205 return (eaccess (path, mode));
206 #elif defined (EFF_ONLY_OK) /* SVR4(?), SVR4.2 */
207 return access (path, mode|EFF_ONLY_OK);
210 return (sh_stataccess (path, mode));
212 # if HAVE_DECL_SETREGID
213 if (current_user.uid != current_user.euid || current_user.gid != current_user.egid)
214 return (sh_euidaccess (path, mode));
217 if (current_user.uid == current_user.euid && current_user.gid == current_user.egid)
218 return (access (path, mode));
220 return (sh_stataccess (path, mode));