]>
git.ipfire.org Git - thirdparty/bash.git/blob - lib/sh/eaccess.c
d9bca8c40b448596af15b9180f655f54784637a5
1 /* eaccess.c - eaccess replacement for the shell, plus other access functions. */
3 /* Copyright (C) 2006-2010 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
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
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
)
203 if (path_is_devfd (path
))
204 return (sh_stataccess (path
, mode
));
206 #if defined (HAVE_FACCESSAT) && defined (AT_EACCESS)
207 return (faccessat (AT_FDCWD
, path
, mode
, AT_EACCESS
));
208 #elif defined (HAVE_EACCESS) /* FreeBSD */
209 ret
= eaccess (path
, mode
); /* XXX -- not always correct for X_OK */
210 # if defined (__FreeBSD__)
211 if (ret
== 0 && current_user
.euid
== 0 && mode
== X_OK
)
212 return (sh_stataccess (path
, mode
));
215 #elif defined (EFF_ONLY_OK) /* SVR4(?), SVR4.2 */
216 return access (path
, mode
|EFF_ONLY_OK
);
219 return (sh_stataccess (path
, mode
));
221 # if HAVE_DECL_SETREGID
222 if (current_user
.uid
!= current_user
.euid
|| current_user
.gid
!= current_user
.egid
)
223 return (sh_euidaccess (path
, mode
));
226 if (current_user
.uid
== current_user
.euid
&& current_user
.gid
== current_user
.egid
)
228 ret
= access (path
, mode
);
229 #if defined (__FreeBSD__) || defined (SOLARIS)
230 if (ret
== 0 && current_user
.euid
== 0 && mode
== X_OK
)
231 return (sh_stataccess (path
, mode
));
237 return (sh_stataccess (path
, mode
));