|
|
6f67c1 |
From 5a6af47c3db45b6303bac4dcd6da186fd5cd178c Mon Sep 17 00:00:00 2001
|
|
|
6f67c1 |
From: Ondrej Valousek <ondrej.valousek.xm@renesas.com>
|
|
|
6f67c1 |
Date: Fri, 2 Dec 2022 13:40:19 +0100
|
|
|
6f67c1 |
Subject: [PATCH 1/3] file-has-acl: Basic support for checking NFSv4 ACLs in
|
|
|
6f67c1 |
Linux.
|
|
|
6f67c1 |
|
|
|
6f67c1 |
* lib/acl-internal.h (acl_nfs4_nontrivial): New declaration.
|
|
|
6f67c1 |
* lib/acl-internal.c (acl_nfs4_nontrivial): New function.
|
|
|
6f67c1 |
* lib/file-has-acl.c: Include <arpa/inet.h>.
|
|
|
6f67c1 |
(XATTR_NAME_NFSV4_ACL, TRIVIAL_NFS4_ACL_MAX_LENGTH): New macros.
|
|
|
6f67c1 |
(file_has_acl): Test for NFSv4 ACLs.
|
|
|
6f67c1 |
* doc/acl-nfsv4.txt: New file.
|
|
|
6f67c1 |
|
|
|
6f67c1 |
Upstream-commit: b0604a8e134dbcc307c0ffdd5ebd3693e9de7081
|
|
|
6f67c1 |
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
|
6f67c1 |
---
|
|
|
6f67c1 |
doc/acl-nfsv4.txt | 17 ++++++++
|
|
|
6f67c1 |
lib/acl-internal.c | 100 +++++++++++++++++++++++++++++++++++++++++++++
|
|
|
6f67c1 |
lib/acl-internal.h | 3 ++
|
|
|
6f67c1 |
lib/file-has-acl.c | 21 ++++++++++
|
|
|
6f67c1 |
4 files changed, 141 insertions(+)
|
|
|
6f67c1 |
create mode 100644 doc/acl-nfsv4.txt
|
|
|
6f67c1 |
|
|
|
6f67c1 |
diff --git a/doc/acl-nfsv4.txt b/doc/acl-nfsv4.txt
|
|
|
6f67c1 |
new file mode 100644
|
|
|
6f67c1 |
index 0000000..71352f5
|
|
|
6f67c1 |
--- /dev/null
|
|
|
6f67c1 |
+++ b/doc/acl-nfsv4.txt
|
|
|
6f67c1 |
@@ -0,0 +1,17 @@
|
|
|
6f67c1 |
+General introduction:
|
|
|
6f67c1 |
+ https://linux.die.net/man/5/nfs4_acl
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+The NFSv4 acls are defined in RFC7530 and as such, every NFSv4 server supporting ACLs
|
|
|
6f67c1 |
+will support this kind of ACLs (note the difference from POSIX draft ACLs)
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+The ACLs can be obtained via the nfsv4-acl-tools, i.e.
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+$ nfs4_getfacl <file>
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+# file: <file>
|
|
|
6f67c1 |
+A::OWNER@:rwaDxtTnNcCy
|
|
|
6f67c1 |
+A::GROUP@:rwaDxtTnNcy
|
|
|
6f67c1 |
+A::EVERYONE@:rwaDxtTnNcy
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+Gnulib is aiming to only provide a basic support of these, i.e. recognize trivial
|
|
|
6f67c1 |
+and non-trivial ACLs
|
|
|
6f67c1 |
diff --git a/lib/acl-internal.c b/lib/acl-internal.c
|
|
|
6f67c1 |
index be244c6..4c65dff 100644
|
|
|
6f67c1 |
--- a/lib/acl-internal.c
|
|
|
6f67c1 |
+++ b/lib/acl-internal.c
|
|
|
6f67c1 |
@@ -25,6 +25,9 @@
|
|
|
6f67c1 |
|
|
|
6f67c1 |
#if USE_ACL && HAVE_ACL_GET_FILE
|
|
|
6f67c1 |
|
|
|
6f67c1 |
+# include <string.h>
|
|
|
6f67c1 |
+# include <arpa/inet.h>
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
|
|
6f67c1 |
|
|
|
6f67c1 |
/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
|
|
|
6f67c1 |
@@ -122,6 +125,103 @@ acl_default_nontrivial (acl_t acl)
|
|
|
6f67c1 |
return (acl_entries (acl) > 0);
|
|
|
6f67c1 |
}
|
|
|
6f67c1 |
|
|
|
6f67c1 |
+# define ACE4_WHO_OWNER "OWNER@"
|
|
|
6f67c1 |
+# define ACE4_WHO_GROUP "GROUP@"
|
|
|
6f67c1 |
+# define ACE4_WHO_EVERYONE "EVERYONE@"
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+# define ACE4_ACCESS_ALLOWED_ACE_TYPE 0
|
|
|
6f67c1 |
+# define ACE4_ACCESS_DENIED_ACE_TYPE 1
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+/* ACE flag values */
|
|
|
6f67c1 |
+# define ACE4_IDENTIFIER_GROUP 0x00000040
|
|
|
6f67c1 |
+# define ROUNDUP(x, y) (((x) + (y) - 1) & - (y))
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+int
|
|
|
6f67c1 |
+acl_nfs4_nontrivial (char *xattr, int len)
|
|
|
6f67c1 |
+{
|
|
|
6f67c1 |
+ int bufs = len;
|
|
|
6f67c1 |
+ uint32_t num_aces = ntohl (*((uint32_t*)(xattr))), /* Grab the number of aces in the acl */
|
|
|
6f67c1 |
+ num_a_aces = 0,
|
|
|
6f67c1 |
+ num_d_aces = 0;
|
|
|
6f67c1 |
+ char *bufp = xattr;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ bufp += 4; /* sizeof(uint32_t); */
|
|
|
6f67c1 |
+ bufs -= 4;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ for (uint32_t ace_n = 0; num_aces > ace_n ; ace_n++)
|
|
|
6f67c1 |
+ {
|
|
|
6f67c1 |
+ int d_ptr;
|
|
|
6f67c1 |
+ uint32_t flag,
|
|
|
6f67c1 |
+ wholen,
|
|
|
6f67c1 |
+ type;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* Get the acl type */
|
|
|
6f67c1 |
+ if (bufs <= 0)
|
|
|
6f67c1 |
+ return -1;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ type = ntohl (*((uint32_t*)bufp));
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ bufp += 4;
|
|
|
6f67c1 |
+ bufs -= 4;
|
|
|
6f67c1 |
+ if (bufs <= 0)
|
|
|
6f67c1 |
+ return -1;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ flag = ntohl (*((uint32_t*)bufp));
|
|
|
6f67c1 |
+ /* As per RFC 7530, the flag should be 0, but we are just generous to Netapp
|
|
|
6f67c1 |
+ * and also accept the Group flag
|
|
|
6f67c1 |
+ */
|
|
|
6f67c1 |
+ if (flag & ~ACE4_IDENTIFIER_GROUP)
|
|
|
6f67c1 |
+ return 1;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* we skip mask -
|
|
|
6f67c1 |
+ * it's too risky to test it and it does not seem to be actually needed */
|
|
|
6f67c1 |
+ bufp += 2*4;
|
|
|
6f67c1 |
+ bufs -= 2*4;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ if (bufs <= 0)
|
|
|
6f67c1 |
+ return -1;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ wholen = ntohl (*((uint32_t*)bufp));
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ bufp += 4;
|
|
|
6f67c1 |
+ bufs -= 4;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* Get the who string */
|
|
|
6f67c1 |
+ if (bufs <= 0)
|
|
|
6f67c1 |
+ return -1;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* for trivial ACL, we expect max 5 (typically 3) ACES, 3 Allow, 2 deny */
|
|
|
6f67c1 |
+ if (((strncmp (bufp, ACE4_WHO_OWNER, wholen) == 0)
|
|
|
6f67c1 |
+ || (strncmp (bufp, ACE4_WHO_GROUP, wholen) == 0))
|
|
|
6f67c1 |
+ && wholen == 6)
|
|
|
6f67c1 |
+ {
|
|
|
6f67c1 |
+ if (type == ACE4_ACCESS_ALLOWED_ACE_TYPE)
|
|
|
6f67c1 |
+ num_a_aces++;
|
|
|
6f67c1 |
+ if (type == ACE4_ACCESS_DENIED_ACE_TYPE)
|
|
|
6f67c1 |
+ num_d_aces++;
|
|
|
6f67c1 |
+ }
|
|
|
6f67c1 |
+ else
|
|
|
6f67c1 |
+ if ((strncmp (bufp, ACE4_WHO_EVERYONE, wholen) == 0)
|
|
|
6f67c1 |
+ && (type == ACE4_ACCESS_ALLOWED_ACE_TYPE)
|
|
|
6f67c1 |
+ && (wholen == 9))
|
|
|
6f67c1 |
+ num_a_aces++;
|
|
|
6f67c1 |
+ else
|
|
|
6f67c1 |
+ return 1;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ d_ptr = ROUNDUP (wholen, 4);
|
|
|
6f67c1 |
+ bufp += d_ptr;
|
|
|
6f67c1 |
+ bufs -= d_ptr;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* Make sure we aren't outside our domain */
|
|
|
6f67c1 |
+ if (bufs < 0)
|
|
|
6f67c1 |
+ return -1;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ }
|
|
|
6f67c1 |
+ return !((num_a_aces <= 3) && (num_d_aces <= 2)
|
|
|
6f67c1 |
+ && (num_a_aces + num_d_aces == num_aces));
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+}
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
# endif
|
|
|
6f67c1 |
|
|
|
6f67c1 |
#elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
|
|
|
6f67c1 |
diff --git a/lib/acl-internal.h b/lib/acl-internal.h
|
|
|
6f67c1 |
index 9353376..2a249ff 100644
|
|
|
6f67c1 |
--- a/lib/acl-internal.h
|
|
|
6f67c1 |
+++ b/lib/acl-internal.h
|
|
|
6f67c1 |
@@ -143,6 +143,9 @@ rpl_acl_set_fd (int fd, acl_t acl)
|
|
|
6f67c1 |
# define acl_entries rpl_acl_entries
|
|
|
6f67c1 |
extern int acl_entries (acl_t);
|
|
|
6f67c1 |
# endif
|
|
|
6f67c1 |
+/* Return 1 if given ACL in XDR format is non-trivial
|
|
|
6f67c1 |
+ * Return 0 if it is trivial */
|
|
|
6f67c1 |
+extern int acl_nfs4_nontrivial (char *, int);
|
|
|
6f67c1 |
|
|
|
6f67c1 |
# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
|
|
6f67c1 |
/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
|
|
|
6f67c1 |
diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
|
|
|
6f67c1 |
index e02f062..1710234 100644
|
|
|
6f67c1 |
--- a/lib/file-has-acl.c
|
|
|
6f67c1 |
+++ b/lib/file-has-acl.c
|
|
|
6f67c1 |
@@ -32,6 +32,11 @@
|
|
|
6f67c1 |
#if GETXATTR_WITH_POSIX_ACLS
|
|
|
6f67c1 |
# include <sys/xattr.h>
|
|
|
6f67c1 |
# include <linux/xattr.h>
|
|
|
6f67c1 |
+# include <arpa/inet.h>
|
|
|
6f67c1 |
+# ifndef XATTR_NAME_NFSV4_ACL
|
|
|
6f67c1 |
+# define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
|
|
|
6f67c1 |
+# endif
|
|
|
6f67c1 |
+# define TRIVIAL_NFS4_ACL_MAX_LENGTH 128
|
|
|
6f67c1 |
#endif
|
|
|
6f67c1 |
|
|
|
6f67c1 |
/* Return 1 if NAME has a nontrivial access control list,
|
|
|
6f67c1 |
@@ -67,6 +72,22 @@ file_has_acl (char const *name, struct stat const *sb)
|
|
|
6f67c1 |
return 1;
|
|
|
6f67c1 |
}
|
|
|
6f67c1 |
|
|
|
6f67c1 |
+ if (ret < 0)
|
|
|
6f67c1 |
+ { /* we might be on NFS, so try to check NFSv4 ACLs too */
|
|
|
6f67c1 |
+ char xattr[TRIVIAL_NFS4_ACL_MAX_LENGTH];
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ errno = 0; /* we need to reset errno set by the previous getxattr() */
|
|
|
6f67c1 |
+ ret = getxattr (name, XATTR_NAME_NFSV4_ACL, xattr, TRIVIAL_NFS4_ACL_MAX_LENGTH);
|
|
|
6f67c1 |
+ if (ret < 0 && errno == ENODATA)
|
|
|
6f67c1 |
+ ret = 0;
|
|
|
6f67c1 |
+ else
|
|
|
6f67c1 |
+ if (ret < 0 && errno == ERANGE)
|
|
|
6f67c1 |
+ return 1; /* we won't fit into the buffer, so non-trivial ACL is presented */
|
|
|
6f67c1 |
+ else
|
|
|
6f67c1 |
+ if (ret > 0)
|
|
|
6f67c1 |
+ /* looks like trivial ACL, but we need to investigate further */
|
|
|
6f67c1 |
+ return acl_nfs4_nontrivial (xattr, ret);
|
|
|
6f67c1 |
+ }
|
|
|
6f67c1 |
if (ret < 0)
|
|
|
6f67c1 |
return - acl_errno_valid (errno);
|
|
|
6f67c1 |
return ret;
|
|
|
6f67c1 |
--
|
|
|
6f67c1 |
2.38.1
|
|
|
6f67c1 |
|
|
|
6f67c1 |
|
|
|
6f67c1 |
From c5266d204a446bea619fa18da8520dceb0a54192 Mon Sep 17 00:00:00 2001
|
|
|
6f67c1 |
From: Paul Eggert <eggert@cs.ucla.edu>
|
|
|
6f67c1 |
Date: Fri, 23 Dec 2022 15:18:29 -0800
|
|
|
6f67c1 |
Subject: [PATCH 2/3] file-has-acl: improve recent NFSv4 support
|
|
|
6f67c1 |
MIME-Version: 1.0
|
|
|
6f67c1 |
Content-Type: text/plain; charset=UTF-8
|
|
|
6f67c1 |
Content-Transfer-Encoding: 8bit
|
|
|
6f67c1 |
|
|
|
6f67c1 |
This fixes a link failure with emacsclient on GNU/Linux. This
|
|
|
6f67c1 |
program wants file_has_acl but none of the other ACL primitives,
|
|
|
6f67c1 |
so it doesn’t link acl-internal.o; this way it doesn’t need to
|
|
|
6f67c1 |
link with -lacl. While I was at it I reviewed the recent changes,
|
|
|
6f67c1 |
fixed some unlikely overflow bugs, and adjusted to GNU style.
|
|
|
6f67c1 |
* doc/acl-nfsv4.txt: Remove. Its contents are now in a
|
|
|
6f67c1 |
comment in lib/file-has-acl.c.
|
|
|
6f67c1 |
* lib/acl-internal.c, lib/acl-internal.h: Move recent changes
|
|
|
6f67c1 |
relating to acl_nfs4_nontrivial to lib/file-has-acl.c, so that
|
|
|
6f67c1 |
there is no trouble linking programs that need only file_has_acl.
|
|
|
6f67c1 |
* lib/file-has-acl.c (acl_nfs4_nontrivial): Move here from
|
|
|
6f67c1 |
lib/acl-internal.c, so that we needn't link -lacl in
|
|
|
6f67c1 |
programs that want only file_has_acl, such as emacsclient.
|
|
|
6f67c1 |
Do not assume a char buffer is aligned for uint32_t.
|
|
|
6f67c1 |
Check more carefully for buffer read overrun.
|
|
|
6f67c1 |
Allow up to 6 ACEs, since other code does; but check
|
|
|
6f67c1 |
that they’re distinct. Avoid integer overflow.
|
|
|
6f67c1 |
Use memcmp rather than strncmp to compare memory blocks.
|
|
|
6f67c1 |
(file_has_acl): Preserve initial errno instead of setting to 0.
|
|
|
6f67c1 |
Allocate a bit more room for trivial ACL buffer.
|
|
|
6f67c1 |
Use EINVAL for botchedk NFSv4 ACLs (which shouldn’t happen).
|
|
|
6f67c1 |
|
|
|
6f67c1 |
Upstream-commit: 35bd46f0c816948dc1a0430c8ba8b10a01167320
|
|
|
6f67c1 |
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
|
6f67c1 |
---
|
|
|
6f67c1 |
doc/acl-nfsv4.txt | 17 ------
|
|
|
6f67c1 |
lib/acl-internal.c | 100 -----------------------------------
|
|
|
6f67c1 |
lib/acl-internal.h | 3 --
|
|
|
6f67c1 |
lib/file-has-acl.c | 129 +++++++++++++++++++++++++++++++++++++++------
|
|
|
6f67c1 |
4 files changed, 113 insertions(+), 136 deletions(-)
|
|
|
6f67c1 |
delete mode 100644 doc/acl-nfsv4.txt
|
|
|
6f67c1 |
|
|
|
6f67c1 |
diff --git a/doc/acl-nfsv4.txt b/doc/acl-nfsv4.txt
|
|
|
6f67c1 |
deleted file mode 100644
|
|
|
6f67c1 |
index 71352f5..0000000
|
|
|
6f67c1 |
--- a/doc/acl-nfsv4.txt
|
|
|
6f67c1 |
+++ /dev/null
|
|
|
6f67c1 |
@@ -1,17 +0,0 @@
|
|
|
6f67c1 |
-General introduction:
|
|
|
6f67c1 |
- https://linux.die.net/man/5/nfs4_acl
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
-The NFSv4 acls are defined in RFC7530 and as such, every NFSv4 server supporting ACLs
|
|
|
6f67c1 |
-will support this kind of ACLs (note the difference from POSIX draft ACLs)
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
-The ACLs can be obtained via the nfsv4-acl-tools, i.e.
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
-$ nfs4_getfacl <file>
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
-# file: <file>
|
|
|
6f67c1 |
-A::OWNER@:rwaDxtTnNcCy
|
|
|
6f67c1 |
-A::GROUP@:rwaDxtTnNcy
|
|
|
6f67c1 |
-A::EVERYONE@:rwaDxtTnNcy
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
-Gnulib is aiming to only provide a basic support of these, i.e. recognize trivial
|
|
|
6f67c1 |
-and non-trivial ACLs
|
|
|
6f67c1 |
diff --git a/lib/acl-internal.c b/lib/acl-internal.c
|
|
|
6f67c1 |
index 4c65dff..be244c6 100644
|
|
|
6f67c1 |
--- a/lib/acl-internal.c
|
|
|
6f67c1 |
+++ b/lib/acl-internal.c
|
|
|
6f67c1 |
@@ -25,9 +25,6 @@
|
|
|
6f67c1 |
|
|
|
6f67c1 |
#if USE_ACL && HAVE_ACL_GET_FILE
|
|
|
6f67c1 |
|
|
|
6f67c1 |
-# include <string.h>
|
|
|
6f67c1 |
-# include <arpa/inet.h>
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
|
|
6f67c1 |
|
|
|
6f67c1 |
/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
|
|
|
6f67c1 |
@@ -125,103 +122,6 @@ acl_default_nontrivial (acl_t acl)
|
|
|
6f67c1 |
return (acl_entries (acl) > 0);
|
|
|
6f67c1 |
}
|
|
|
6f67c1 |
|
|
|
6f67c1 |
-# define ACE4_WHO_OWNER "OWNER@"
|
|
|
6f67c1 |
-# define ACE4_WHO_GROUP "GROUP@"
|
|
|
6f67c1 |
-# define ACE4_WHO_EVERYONE "EVERYONE@"
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
-# define ACE4_ACCESS_ALLOWED_ACE_TYPE 0
|
|
|
6f67c1 |
-# define ACE4_ACCESS_DENIED_ACE_TYPE 1
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
-/* ACE flag values */
|
|
|
6f67c1 |
-# define ACE4_IDENTIFIER_GROUP 0x00000040
|
|
|
6f67c1 |
-# define ROUNDUP(x, y) (((x) + (y) - 1) & - (y))
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
-int
|
|
|
6f67c1 |
-acl_nfs4_nontrivial (char *xattr, int len)
|
|
|
6f67c1 |
-{
|
|
|
6f67c1 |
- int bufs = len;
|
|
|
6f67c1 |
- uint32_t num_aces = ntohl (*((uint32_t*)(xattr))), /* Grab the number of aces in the acl */
|
|
|
6f67c1 |
- num_a_aces = 0,
|
|
|
6f67c1 |
- num_d_aces = 0;
|
|
|
6f67c1 |
- char *bufp = xattr;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- bufp += 4; /* sizeof(uint32_t); */
|
|
|
6f67c1 |
- bufs -= 4;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- for (uint32_t ace_n = 0; num_aces > ace_n ; ace_n++)
|
|
|
6f67c1 |
- {
|
|
|
6f67c1 |
- int d_ptr;
|
|
|
6f67c1 |
- uint32_t flag,
|
|
|
6f67c1 |
- wholen,
|
|
|
6f67c1 |
- type;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- /* Get the acl type */
|
|
|
6f67c1 |
- if (bufs <= 0)
|
|
|
6f67c1 |
- return -1;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- type = ntohl (*((uint32_t*)bufp));
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- bufp += 4;
|
|
|
6f67c1 |
- bufs -= 4;
|
|
|
6f67c1 |
- if (bufs <= 0)
|
|
|
6f67c1 |
- return -1;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- flag = ntohl (*((uint32_t*)bufp));
|
|
|
6f67c1 |
- /* As per RFC 7530, the flag should be 0, but we are just generous to Netapp
|
|
|
6f67c1 |
- * and also accept the Group flag
|
|
|
6f67c1 |
- */
|
|
|
6f67c1 |
- if (flag & ~ACE4_IDENTIFIER_GROUP)
|
|
|
6f67c1 |
- return 1;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- /* we skip mask -
|
|
|
6f67c1 |
- * it's too risky to test it and it does not seem to be actually needed */
|
|
|
6f67c1 |
- bufp += 2*4;
|
|
|
6f67c1 |
- bufs -= 2*4;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- if (bufs <= 0)
|
|
|
6f67c1 |
- return -1;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- wholen = ntohl (*((uint32_t*)bufp));
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- bufp += 4;
|
|
|
6f67c1 |
- bufs -= 4;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- /* Get the who string */
|
|
|
6f67c1 |
- if (bufs <= 0)
|
|
|
6f67c1 |
- return -1;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- /* for trivial ACL, we expect max 5 (typically 3) ACES, 3 Allow, 2 deny */
|
|
|
6f67c1 |
- if (((strncmp (bufp, ACE4_WHO_OWNER, wholen) == 0)
|
|
|
6f67c1 |
- || (strncmp (bufp, ACE4_WHO_GROUP, wholen) == 0))
|
|
|
6f67c1 |
- && wholen == 6)
|
|
|
6f67c1 |
- {
|
|
|
6f67c1 |
- if (type == ACE4_ACCESS_ALLOWED_ACE_TYPE)
|
|
|
6f67c1 |
- num_a_aces++;
|
|
|
6f67c1 |
- if (type == ACE4_ACCESS_DENIED_ACE_TYPE)
|
|
|
6f67c1 |
- num_d_aces++;
|
|
|
6f67c1 |
- }
|
|
|
6f67c1 |
- else
|
|
|
6f67c1 |
- if ((strncmp (bufp, ACE4_WHO_EVERYONE, wholen) == 0)
|
|
|
6f67c1 |
- && (type == ACE4_ACCESS_ALLOWED_ACE_TYPE)
|
|
|
6f67c1 |
- && (wholen == 9))
|
|
|
6f67c1 |
- num_a_aces++;
|
|
|
6f67c1 |
- else
|
|
|
6f67c1 |
- return 1;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- d_ptr = ROUNDUP (wholen, 4);
|
|
|
6f67c1 |
- bufp += d_ptr;
|
|
|
6f67c1 |
- bufs -= d_ptr;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- /* Make sure we aren't outside our domain */
|
|
|
6f67c1 |
- if (bufs < 0)
|
|
|
6f67c1 |
- return -1;
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- }
|
|
|
6f67c1 |
- return !((num_a_aces <= 3) && (num_d_aces <= 2)
|
|
|
6f67c1 |
- && (num_a_aces + num_d_aces == num_aces));
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
-}
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
# endif
|
|
|
6f67c1 |
|
|
|
6f67c1 |
#elif USE_ACL && HAVE_FACL && defined GETACL /* Solaris, Cygwin, not HP-UX */
|
|
|
6f67c1 |
diff --git a/lib/acl-internal.h b/lib/acl-internal.h
|
|
|
6f67c1 |
index 2a249ff..9353376 100644
|
|
|
6f67c1 |
--- a/lib/acl-internal.h
|
|
|
6f67c1 |
+++ b/lib/acl-internal.h
|
|
|
6f67c1 |
@@ -143,9 +143,6 @@ rpl_acl_set_fd (int fd, acl_t acl)
|
|
|
6f67c1 |
# define acl_entries rpl_acl_entries
|
|
|
6f67c1 |
extern int acl_entries (acl_t);
|
|
|
6f67c1 |
# endif
|
|
|
6f67c1 |
-/* Return 1 if given ACL in XDR format is non-trivial
|
|
|
6f67c1 |
- * Return 0 if it is trivial */
|
|
|
6f67c1 |
-extern int acl_nfs4_nontrivial (char *, int);
|
|
|
6f67c1 |
|
|
|
6f67c1 |
# if HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
|
|
|
6f67c1 |
/* ACL is an ACL, from a file, stored as type ACL_TYPE_EXTENDED.
|
|
|
6f67c1 |
diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
|
|
|
6f67c1 |
index 1710234..676523b 100644
|
|
|
6f67c1 |
--- a/lib/file-has-acl.c
|
|
|
6f67c1 |
+++ b/lib/file-has-acl.c
|
|
|
6f67c1 |
@@ -29,14 +29,97 @@
|
|
|
6f67c1 |
|
|
|
6f67c1 |
#include "acl-internal.h"
|
|
|
6f67c1 |
|
|
|
6f67c1 |
-#if GETXATTR_WITH_POSIX_ACLS
|
|
|
6f67c1 |
+#if USE_ACL && GETXATTR_WITH_POSIX_ACLS
|
|
|
6f67c1 |
+# include <string.h>
|
|
|
6f67c1 |
+# include <arpa/inet.h>
|
|
|
6f67c1 |
# include <sys/xattr.h>
|
|
|
6f67c1 |
# include <linux/xattr.h>
|
|
|
6f67c1 |
-# include <arpa/inet.h>
|
|
|
6f67c1 |
# ifndef XATTR_NAME_NFSV4_ACL
|
|
|
6f67c1 |
# define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
|
|
|
6f67c1 |
# endif
|
|
|
6f67c1 |
-# define TRIVIAL_NFS4_ACL_MAX_LENGTH 128
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+enum {
|
|
|
6f67c1 |
+ /* ACE4_ACCESS_ALLOWED_ACE_TYPE = 0x00000000, */
|
|
|
6f67c1 |
+ ACE4_ACCESS_DENIED_ACE_TYPE = 0x00000001,
|
|
|
6f67c1 |
+ ACE4_IDENTIFIER_GROUP = 0x00000040
|
|
|
6f67c1 |
+};
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+/* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial.
|
|
|
6f67c1 |
+ -1 upon failure to determine it. Possibly change errno. Assume that
|
|
|
6f67c1 |
+ the ACL is valid, except avoid undefined behavior even if invalid.
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ See <https://linux.die.net/man/5/nfs4_acl>. The NFSv4 acls are
|
|
|
6f67c1 |
+ defined in Internet RFC 7530 and as such, every NFSv4 server
|
|
|
6f67c1 |
+ supporting ACLs should support NFSv4 ACLs (they differ from from
|
|
|
6f67c1 |
+ POSIX draft ACLs). The ACLs can be obtained via the
|
|
|
6f67c1 |
+ nfsv4-acl-tools, e.g., the nfs4_getfacl command. Gnulib provides
|
|
|
6f67c1 |
+ only basic support of NFSv4 ACLs, i.e., recognize trivial vs
|
|
|
6f67c1 |
+ nontrivial ACLs. */
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+static int
|
|
|
6f67c1 |
+acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes)
|
|
|
6f67c1 |
+{
|
|
|
6f67c1 |
+ enum { BYTES_PER_NETWORK_UINT = 4};
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* Grab the number of aces in the acl. */
|
|
|
6f67c1 |
+ nbytes -= BYTES_PER_NETWORK_UINT;
|
|
|
6f67c1 |
+ if (nbytes < 0)
|
|
|
6f67c1 |
+ return -1;
|
|
|
6f67c1 |
+ uint32_t num_aces = ntohl (*xattr++);
|
|
|
6f67c1 |
+ if (6 < num_aces)
|
|
|
6f67c1 |
+ return 1;
|
|
|
6f67c1 |
+ int ace_found = 0;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ for (int ace_n = 0; ace_n < num_aces; ace_n++)
|
|
|
6f67c1 |
+ {
|
|
|
6f67c1 |
+ /* Get the acl type and flag. Skip the mask; it's too risky to
|
|
|
6f67c1 |
+ test it and it does not seem to be needed. Get the wholen. */
|
|
|
6f67c1 |
+ nbytes -= 4 * BYTES_PER_NETWORK_UINT;
|
|
|
6f67c1 |
+ if (nbytes < 0)
|
|
|
6f67c1 |
+ return -1;
|
|
|
6f67c1 |
+ uint32_t type = ntohl (xattr[0]);
|
|
|
6f67c1 |
+ uint32_t flag = ntohl (xattr[1]);
|
|
|
6f67c1 |
+ uint32_t wholen = ntohl (xattr[3]);
|
|
|
6f67c1 |
+ xattr += 4;
|
|
|
6f67c1 |
+ int64_t wholen4 = wholen;
|
|
|
6f67c1 |
+ wholen4 = ((wholen4 + (BYTES_PER_NETWORK_UINT))
|
|
|
6f67c1 |
+ & ~ (BYTES_PER_NETWORK_UINT - 1));
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* Trivial ACLs have only ACE4_ACCESS_ALLOWED_ACE_TYPE or
|
|
|
6f67c1 |
+ ACE4_ACCESS_DENIED_ACE_TYPE. */
|
|
|
6f67c1 |
+ if (ACE4_ACCESS_DENIED_ACE_TYPE < type)
|
|
|
6f67c1 |
+ return 1;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* RFC 7530 says FLAG should be 0, but be generous to NetApp and
|
|
|
6f67c1 |
+ also accept the group flag. */
|
|
|
6f67c1 |
+ if (flag & ~ACE4_IDENTIFIER_GROUP)
|
|
|
6f67c1 |
+ return 1;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* Get the who string. Check NBYTES - WHOLEN4 before storing
|
|
|
6f67c1 |
+ into NBYTES, to avoid truncation on conversion. */
|
|
|
6f67c1 |
+ if (nbytes - wholen4 < 0)
|
|
|
6f67c1 |
+ return -1;
|
|
|
6f67c1 |
+ nbytes -= wholen4;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ /* For a trivial ACL, max 6 (typically 3) ACEs, 3 allow, 3 deny.
|
|
|
6f67c1 |
+ Check that there is at most one ACE of each TYPE and WHO. */
|
|
|
6f67c1 |
+ int who2
|
|
|
6f67c1 |
+ = (wholen == 6 && memcmp (xattr, "OWNER@", 6) == 0 ? 0
|
|
|
6f67c1 |
+ : wholen == 6 && memcmp (xattr, "GROUP@", 6) == 0 ? 2
|
|
|
6f67c1 |
+ : wholen == 9 && memcmp (xattr, "EVERYONE@", 9) == 0 ? 4
|
|
|
6f67c1 |
+ : -1);
|
|
|
6f67c1 |
+ if (who2 < 0)
|
|
|
6f67c1 |
+ return 1;
|
|
|
6f67c1 |
+ int ace_found_bit = 1 << (who2 | type);
|
|
|
6f67c1 |
+ if (ace_found & ace_found_bit)
|
|
|
6f67c1 |
+ return 1;
|
|
|
6f67c1 |
+ ace_found |= ace_found_bit;
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ xattr = (uint32_t *) ((char *) xattr + wholen4);
|
|
|
6f67c1 |
+ }
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ return 0;
|
|
|
6f67c1 |
+}
|
|
|
6f67c1 |
#endif
|
|
|
6f67c1 |
|
|
|
6f67c1 |
/* Return 1 if NAME has a nontrivial access control list,
|
|
|
6f67c1 |
@@ -56,6 +139,7 @@ file_has_acl (char const *name, struct stat const *sb)
|
|
|
6f67c1 |
# if GETXATTR_WITH_POSIX_ACLS
|
|
|
6f67c1 |
|
|
|
6f67c1 |
ssize_t ret;
|
|
|
6f67c1 |
+ int initial_errno = errno;
|
|
|
6f67c1 |
|
|
|
6f67c1 |
ret = getxattr (name, XATTR_NAME_POSIX_ACL_ACCESS, NULL, 0);
|
|
|
6f67c1 |
if (ret < 0 && errno == ENODATA)
|
|
|
6f67c1 |
@@ -73,20 +157,33 @@ file_has_acl (char const *name, struct stat const *sb)
|
|
|
6f67c1 |
}
|
|
|
6f67c1 |
|
|
|
6f67c1 |
if (ret < 0)
|
|
|
6f67c1 |
- { /* we might be on NFS, so try to check NFSv4 ACLs too */
|
|
|
6f67c1 |
- char xattr[TRIVIAL_NFS4_ACL_MAX_LENGTH];
|
|
|
6f67c1 |
-
|
|
|
6f67c1 |
- errno = 0; /* we need to reset errno set by the previous getxattr() */
|
|
|
6f67c1 |
- ret = getxattr (name, XATTR_NAME_NFSV4_ACL, xattr, TRIVIAL_NFS4_ACL_MAX_LENGTH);
|
|
|
6f67c1 |
- if (ret < 0 && errno == ENODATA)
|
|
|
6f67c1 |
- ret = 0;
|
|
|
6f67c1 |
+ {
|
|
|
6f67c1 |
+ /* Check for NFSv4 ACLs. The max length of a trivial
|
|
|
6f67c1 |
+ ACL is 6 words for owner, 6 for group, 7 for everyone,
|
|
|
6f67c1 |
+ all times 2 because there are both allow and deny ACEs.
|
|
|
6f67c1 |
+ There are 6 words for owner because of type, flag, mask,
|
|
|
6f67c1 |
+ wholen, "OWNER@"+pad and similarly for group; everyone is
|
|
|
6f67c1 |
+ another word to hold "EVERYONE@". */
|
|
|
6f67c1 |
+ uint32_t xattr[2 * (6 + 6 + 7)];
|
|
|
6f67c1 |
+
|
|
|
6f67c1 |
+ ret = getxattr (name, XATTR_NAME_NFSV4_ACL, xattr, sizeof xattr);
|
|
|
6f67c1 |
+ if (ret < 0)
|
|
|
6f67c1 |
+ switch (errno)
|
|
|
6f67c1 |
+ {
|
|
|
6f67c1 |
+ case ENODATA: return 0;
|
|
|
6f67c1 |
+ case ERANGE : return 1; /* ACL must be nontrivial. */
|
|
|
6f67c1 |
+ }
|
|
|
6f67c1 |
else
|
|
|
6f67c1 |
- if (ret < 0 && errno == ERANGE)
|
|
|
6f67c1 |
- return 1; /* we won't fit into the buffer, so non-trivial ACL is presented */
|
|
|
6f67c1 |
- else
|
|
|
6f67c1 |
- if (ret > 0)
|
|
|
6f67c1 |
- /* looks like trivial ACL, but we need to investigate further */
|
|
|
6f67c1 |
- return acl_nfs4_nontrivial (xattr, ret);
|
|
|
6f67c1 |
+ {
|
|
|
6f67c1 |
+ /* It looks like a trivial ACL, but investigate further. */
|
|
|
6f67c1 |
+ ret = acl_nfs4_nontrivial (xattr, ret);
|
|
|
6f67c1 |
+ if (ret < 0)
|
|
|
6f67c1 |
+ {
|
|
|
6f67c1 |
+ errno = EINVAL;
|
|
|
6f67c1 |
+ return ret;
|
|
|
6f67c1 |
+ }
|
|
|
6f67c1 |
+ errno = initial_errno;
|
|
|
6f67c1 |
+ }
|
|
|
6f67c1 |
}
|
|
|
6f67c1 |
if (ret < 0)
|
|
|
6f67c1 |
return - acl_errno_valid (errno);
|
|
|
6f67c1 |
--
|
|
|
6f67c1 |
2.38.1
|
|
|
6f67c1 |
|
|
|
6f67c1 |
|
|
|
6f67c1 |
From faf965110372c82cd99e9f44f0c64f03cdabb2c1 Mon Sep 17 00:00:00 2001
|
|
|
6f67c1 |
From: Paul Eggert <eggert@cs.ucla.edu>
|
|
|
6f67c1 |
Date: Tue, 27 Dec 2022 20:00:58 -0800
|
|
|
6f67c1 |
Subject: [PATCH 3/3] file-has-acl: fix recently-introduced NFSv4 bug
|
|
|
6f67c1 |
|
|
|
6f67c1 |
* lib/file-has-acl.c (acl_nfs4_nontrivial): Fix off-by-one
|
|
|
6f67c1 |
error when rounding WHOLEN up to next multiple of 4.
|
|
|
6f67c1 |
Pacify GCC 12.2.1 -Wcast-align.
|
|
|
6f67c1 |
|
|
|
6f67c1 |
Upstream-commit: d65e5a8ba77595a598c9ddb8dfa09c4aea732659
|
|
|
6f67c1 |
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
|
|
6f67c1 |
---
|
|
|
6f67c1 |
lib/file-has-acl.c | 9 +++++----
|
|
|
6f67c1 |
1 file changed, 5 insertions(+), 4 deletions(-)
|
|
|
6f67c1 |
|
|
|
6f67c1 |
diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
|
|
|
6f67c1 |
index 676523b..7876edc 100644
|
|
|
6f67c1 |
--- a/lib/file-has-acl.c
|
|
|
6f67c1 |
+++ b/lib/file-has-acl.c
|
|
|
6f67c1 |
@@ -81,9 +81,10 @@ acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes)
|
|
|
6f67c1 |
uint32_t flag = ntohl (xattr[1]);
|
|
|
6f67c1 |
uint32_t wholen = ntohl (xattr[3]);
|
|
|
6f67c1 |
xattr += 4;
|
|
|
6f67c1 |
- int64_t wholen4 = wholen;
|
|
|
6f67c1 |
- wholen4 = ((wholen4 + (BYTES_PER_NETWORK_UINT))
|
|
|
6f67c1 |
- & ~ (BYTES_PER_NETWORK_UINT - 1));
|
|
|
6f67c1 |
+ int whowords = (wholen / BYTES_PER_NETWORK_UINT
|
|
|
6f67c1 |
+ + (wholen % BYTES_PER_NETWORK_UINT != 0));
|
|
|
6f67c1 |
+ int64_t wholen4 = whowords;
|
|
|
6f67c1 |
+ wholen4 *= BYTES_PER_NETWORK_UINT;
|
|
|
6f67c1 |
|
|
|
6f67c1 |
/* Trivial ACLs have only ACE4_ACCESS_ALLOWED_ACE_TYPE or
|
|
|
6f67c1 |
ACE4_ACCESS_DENIED_ACE_TYPE. */
|
|
|
6f67c1 |
@@ -115,7 +116,7 @@ acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes)
|
|
|
6f67c1 |
return 1;
|
|
|
6f67c1 |
ace_found |= ace_found_bit;
|
|
|
6f67c1 |
|
|
|
6f67c1 |
- xattr = (uint32_t *) ((char *) xattr + wholen4);
|
|
|
6f67c1 |
+ xattr += whowords;
|
|
|
6f67c1 |
}
|
|
|
6f67c1 |
|
|
|
6f67c1 |
return 0;
|
|
|
6f67c1 |
--
|
|
|
6f67c1 |
2.38.1
|
|
|
6f67c1 |
|