I wrote: > On this platform, faccessat is emulated through access() and euidaccess(): > > $ nm gllib/faccessat.o > U ___error > U _access > U _euidaccess > 00000000 T _faccessat > U _fchdir > U _free_cwd > U _openat_proc_name > U _openat_restore_fail > U _openat_save_fail > U _restore_cwd > U _rpl_free > U _save_cwd >
The next change is to make euidaccess() reject trailing slashes on symlinks to non-directories as well. This is not specified by POSIX (since euidaccess is not a POSIX function), but is useful because: - This is how the glibc euidaccess() function behaves. - It is consistent with the access() function. - This is what we need to get faccessat() work right w.r.t. to POSIX. 2023-10-03 Bruno Haible <br...@clisp.org> euidaccess: Reject trailing slashes on symlinks to non-directories. * modules/euidaccess (Depends-on): Add access. euidaccess: Add tests. * tests/test-access.h: New file, extracted from tests/test-access.c. * tests/test-access.c: Moved most code to tests/test-access.h. Include test-access.h. (main): Invoke test_access. * tests/test-euidaccess.c: New file, based on tests/test-access.c. * modules/access-tests (Files): Add tests/test-access.h. * modules/euidaccess-tests: New file, based on modules/access-tests.
>From 7631c4a3a5897fcafe182eae589e5dc04faa4680 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Tue, 3 Oct 2023 16:42:59 +0200 Subject: [PATCH 1/2] euidaccess: Add tests. * tests/test-access.h: New file, extracted from tests/test-access.c. * tests/test-access.c: Moved most code to tests/test-access.h. Include test-access.h. (main): Invoke test_access. * tests/test-euidaccess.c: New file, based on tests/test-access.c. * modules/access-tests (Files): Add tests/test-access.h. * modules/euidaccess-tests: New file, based on modules/access-tests. --- ChangeLog | 11 +++++ modules/access-tests | 1 + modules/euidaccess-tests | 17 +++++++ tests/test-access.c | 85 ++------------------------------ tests/test-access.h | 102 +++++++++++++++++++++++++++++++++++++++ tests/test-euidaccess.c | 40 +++++++++++++++ 6 files changed, 174 insertions(+), 82 deletions(-) create mode 100644 modules/euidaccess-tests create mode 100644 tests/test-access.h create mode 100644 tests/test-euidaccess.c diff --git a/ChangeLog b/ChangeLog index 9b4317264e..7a70e6ab9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2023-10-03 Bruno Haible <br...@clisp.org> + + euidaccess: Add tests. + * tests/test-access.h: New file, extracted from tests/test-access.c. + * tests/test-access.c: Moved most code to tests/test-access.h. + Include test-access.h. + (main): Invoke test_access. + * tests/test-euidaccess.c: New file, based on tests/test-access.c. + * modules/access-tests (Files): Add tests/test-access.h. + * modules/euidaccess-tests: New file, based on modules/access-tests. + 2023-10-03 Bruno Haible <br...@clisp.org> access: Make last change work also when module 'stat' is in use. diff --git a/modules/access-tests b/modules/access-tests index 78344887cd..0c9179f70c 100644 --- a/modules/access-tests +++ b/modules/access-tests @@ -1,5 +1,6 @@ Files: tests/test-access.c +tests/test-access.h tests/signature.h tests/macros.h diff --git a/modules/euidaccess-tests b/modules/euidaccess-tests new file mode 100644 index 0000000000..7465470ba7 --- /dev/null +++ b/modules/euidaccess-tests @@ -0,0 +1,17 @@ +Files: +tests/test-euidaccess.c +tests/test-access.h +tests/signature.h +tests/macros.h + +Depends-on: +creat +root-uid +symlink + +configure.ac: +AC_CHECK_FUNCS_ONCE([geteuid]) + +Makefile.am: +TESTS += test-euidaccess +check_PROGRAMS += test-euidaccess diff --git a/tests/test-access.c b/tests/test-access.c index 771678f0f7..3d0b6d1ba5 100644 --- a/tests/test-access.c +++ b/tests/test-access.c @@ -27,93 +27,14 @@ SIGNATURE_CHECK (access, int, (const char *, int)); #include "root-uid.h" #include "macros.h" -/* mingw and MSVC 9 lack geteuid, so setup a dummy value. */ -#if !HAVE_GETEUID -# define geteuid() ROOT_UID -#endif - #define BASE "test-access.t" +#include "test-access.h" + int main () { - /* Remove anything from prior partial run. */ - unlink (BASE "f"); - unlink (BASE "f1"); - chmod (BASE "f2", 0600); - unlink (BASE "f2"); - unlink (BASE "sl"); - - { - errno = 0; - ASSERT (access (BASE "f", R_OK) == -1); - ASSERT (errno == ENOENT); - - errno = 0; - ASSERT (access (BASE "f", W_OK) == -1); - ASSERT (errno == ENOENT); - - errno = 0; - ASSERT (access (BASE "f", X_OK) == -1); - ASSERT (errno == ENOENT); - } - { - ASSERT (close (creat (BASE "f1", 0700)) == 0); - - ASSERT (access (BASE "f1", F_OK) == 0); - ASSERT (access (BASE "f1", R_OK) == 0); - ASSERT (access (BASE "f1", W_OK) == 0); - ASSERT (access (BASE "f1", X_OK) == 0); - - ASSERT (access (BASE "f1/", F_OK) == -1); - ASSERT (errno == ENOTDIR); - ASSERT (access (BASE "f1/", R_OK) == -1); - ASSERT (errno == ENOTDIR); - ASSERT (access (BASE "f1/", W_OK) == -1); - ASSERT (errno == ENOTDIR); - ASSERT (access (BASE "f1/", X_OK) == -1); - ASSERT (errno == ENOTDIR); - - if (symlink (BASE "f1", BASE "sl") == 0) - { - ASSERT (access (BASE "sl/", F_OK) == -1); - ASSERT (errno == ENOTDIR); - ASSERT (access (BASE "sl/", R_OK) == -1); - ASSERT (errno == ENOTDIR); - ASSERT (access (BASE "sl/", W_OK) == -1); - ASSERT (errno == ENOTDIR); - ASSERT (access (BASE "sl/", X_OK) == -1); - ASSERT (errno == ENOTDIR); - } - } - { - ASSERT (close (creat (BASE "f2", 0600)) == 0); - ASSERT (chmod (BASE "f2", 0400) == 0); - - ASSERT (access (BASE "f2", R_OK) == 0); - - if (geteuid () != ROOT_UID) - { - errno = 0; - ASSERT (access (BASE "f2", W_OK) == -1); - ASSERT (errno == EACCES); - } - -#if defined _WIN32 && !defined __CYGWIN__ - /* X_OK works like R_OK. */ - ASSERT (access (BASE "f2", X_OK) == 0); -#else - errno = 0; - ASSERT (access (BASE "f2", X_OK) == -1); - ASSERT (errno == EACCES); -#endif - } - - /* Cleanup. */ - ASSERT (unlink (BASE "f1") == 0); - ASSERT (chmod (BASE "f2", 0600) == 0); - ASSERT (unlink (BASE "f2") == 0); - unlink (BASE "sl"); + test_access (access); return 0; } diff --git a/tests/test-access.h b/tests/test-access.h new file mode 100644 index 0000000000..f6958decfc --- /dev/null +++ b/tests/test-access.h @@ -0,0 +1,102 @@ +/* Tests of access and euidaccess. + Copyright (C) 2019-2023 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* mingw and MSVC 9 lack geteuid, so setup a dummy value. */ +#if !HAVE_GETEUID +# define geteuid() ROOT_UID +#endif + +static void +test_access (int (*func) (const char * /*file*/, int /*mode*/)) +{ + /* Remove anything from prior partial run. */ + unlink (BASE "f"); + unlink (BASE "f1"); + chmod (BASE "f2", 0600); + unlink (BASE "f2"); + unlink (BASE "sl"); + + { + errno = 0; + ASSERT (func (BASE "f", R_OK) == -1); + ASSERT (errno == ENOENT); + + errno = 0; + ASSERT (func (BASE "f", W_OK) == -1); + ASSERT (errno == ENOENT); + + errno = 0; + ASSERT (func (BASE "f", X_OK) == -1); + ASSERT (errno == ENOENT); + } + { + ASSERT (close (creat (BASE "f1", 0700)) == 0); + + ASSERT (func (BASE "f1", F_OK) == 0); + ASSERT (func (BASE "f1", R_OK) == 0); + ASSERT (func (BASE "f1", W_OK) == 0); + ASSERT (func (BASE "f1", X_OK) == 0); + + ASSERT (func (BASE "f1/", F_OK) == -1); + ASSERT (errno == ENOTDIR); + ASSERT (func (BASE "f1/", R_OK) == -1); + ASSERT (errno == ENOTDIR); + ASSERT (func (BASE "f1/", W_OK) == -1); + ASSERT (errno == ENOTDIR); + ASSERT (func (BASE "f1/", X_OK) == -1); + ASSERT (errno == ENOTDIR); + + if (symlink (BASE "f1", BASE "sl") == 0) + { + ASSERT (func (BASE "sl/", F_OK) == -1); + ASSERT (errno == ENOTDIR); + ASSERT (func (BASE "sl/", R_OK) == -1); + ASSERT (errno == ENOTDIR); + ASSERT (func (BASE "sl/", W_OK) == -1); + ASSERT (errno == ENOTDIR); + ASSERT (func (BASE "sl/", X_OK) == -1); + ASSERT (errno == ENOTDIR); + } + } + { + ASSERT (close (creat (BASE "f2", 0600)) == 0); + ASSERT (chmod (BASE "f2", 0400) == 0); + + ASSERT (func (BASE "f2", R_OK) == 0); + + if (geteuid () != ROOT_UID) + { + errno = 0; + ASSERT (func (BASE "f2", W_OK) == -1); + ASSERT (errno == EACCES); + } + +#if defined _WIN32 && !defined __CYGWIN__ + /* X_OK works like R_OK. */ + ASSERT (func (BASE "f2", X_OK) == 0); +#else + errno = 0; + ASSERT (func (BASE "f2", X_OK) == -1); + ASSERT (errno == EACCES); +#endif + } + + /* Cleanup. */ + ASSERT (unlink (BASE "f1") == 0); + ASSERT (chmod (BASE "f2", 0600) == 0); + ASSERT (unlink (BASE "f2") == 0); + unlink (BASE "sl"); +} diff --git a/tests/test-euidaccess.c b/tests/test-euidaccess.c new file mode 100644 index 0000000000..510ba6e46b --- /dev/null +++ b/tests/test-euidaccess.c @@ -0,0 +1,40 @@ +/* Tests of euidaccess. + Copyright (C) 2019-2023 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <unistd.h> + +#include "signature.h" +SIGNATURE_CHECK (euidaccess, int, (const char *, int)); + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include "root-uid.h" +#include "macros.h" + +#define BASE "test-euidaccess.t" + +#include "test-access.h" + +int +main () +{ + test_access (euidaccess); + + return 0; +} -- 2.34.1
>From 4451579fdc486cb862632d960ef29303a342ce6d Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Tue, 3 Oct 2023 18:13:54 +0200 Subject: [PATCH 2/2] euidaccess: Reject trailing slashes on symlinks to non-directories. * modules/euidaccess (Depends-on): Add access. --- ChangeLog | 3 +++ modules/euidaccess | 1 + 2 files changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index 7a70e6ab9a..95c08b304e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2023-10-03 Bruno Haible <br...@clisp.org> + euidaccess: Reject trailing slashes on symlinks to non-directories. + * modules/euidaccess (Depends-on): Add access. + euidaccess: Add tests. * tests/test-access.h: New file, extracted from tests/test-access.c. * tests/test-access.c: Moved most code to tests/test-access.h. diff --git a/modules/euidaccess b/modules/euidaccess index b45cf358d1..627f2de96d 100644 --- a/modules/euidaccess +++ b/modules/euidaccess @@ -10,6 +10,7 @@ unistd extensions root-uid fcntl-h +access [test $HAVE_EUIDACCESS = 0] group-member [test $HAVE_EUIDACCESS = 0] stat [test $HAVE_EUIDACCESS = 0] sys_stat [test $HAVE_EUIDACCESS = 0] -- 2.34.1