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

Reply via email to