]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Revert "acl-util: drop now unused fd_acl_make_writable()"
authorMike Yuan <me@yhndnzj.com>
Tue, 16 Dec 2025 00:47:10 +0000 (01:47 +0100)
committerMike Yuan <me@yhndnzj.com>
Tue, 16 Dec 2025 19:16:57 +0000 (20:16 +0100)
This reverts commit 4175cd4f400c2e89028878dc265ccd67ca838edd.

It turned out that we still need this. Preparation for later commits.

src/shared/acl-util.c
src/shared/acl-util.h
src/test/test-acl-util.c

index bcac9a9bb805bdd090c7aa4386e855a7a75c99a1..21bbb01278b47140576904554cd7871f765e4ddf 100644 (file)
@@ -738,6 +738,68 @@ maybe_fallback:
         /* No ACLs? Then just update the regular mode_t */
         return fd_acl_make_read_only_fallback(fd);
 }
+
+int fd_acl_make_writable(int fd) {
+        _cleanup_(acl_freep) acl_t acl = NULL;
+        acl_entry_t i;
+        int r;
+
+        /* Safely adds the writable bit to the owner's ACL entry of this inode. (And only the owner's! – This
+         * not the obvious inverse of fd_acl_make_read_only() hence!) */
+
+        r = dlopen_libacl();
+        if (r < 0)
+                return r;
+
+        acl = sym_acl_get_fd(fd);
+        if (!acl) {
+                if (!ERRNO_IS_NOT_SUPPORTED(errno))
+                        return -errno;
+
+                /* No ACLs? Then just update the regular mode_t */
+                return fd_acl_make_writable_fallback(fd);
+        }
+
+        for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+             r > 0;
+             r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
+                acl_permset_t permset;
+                acl_tag_t tag;
+                int b;
+
+                if (sym_acl_get_tag_type(i, &tag) < 0)
+                        return -errno;
+
+                if (tag != ACL_USER_OBJ)
+                        continue;
+
+                if (sym_acl_get_permset(i, &permset) < 0)
+                        return -errno;
+
+                b = sym_acl_get_perm(permset, ACL_WRITE);
+                if (b < 0)
+                        return -errno;
+
+                if (b)
+                        return 0; /* Already set? Then there's nothing to do. */
+
+                if (sym_acl_add_perm(permset, ACL_WRITE) < 0)
+                        return -errno;
+
+                break;
+        }
+        if (r < 0)
+                return -errno;
+
+        if (sym_acl_set_fd(fd, acl) < 0) {
+                if (!ERRNO_IS_NOT_SUPPORTED(errno))
+                        return -errno;
+
+                return fd_acl_make_writable_fallback(fd);
+        }
+
+        return 1;
+}
 #endif
 
 int fd_acl_make_read_only_fallback(int fd) {
@@ -757,6 +819,23 @@ int fd_acl_make_read_only_fallback(int fd) {
         return 1;
 }
 
+int fd_acl_make_writable_fallback(int fd) {
+        struct stat st;
+
+        assert(fd >= 0);
+
+        if (fstat(fd, &st) < 0)
+                return -errno;
+
+        if ((st.st_mode & 0200) != 0) /* already set */
+                return 0;
+
+        if (fchmod(fd, (st.st_mode & 07777) | 0200) < 0)
+                return -errno;
+
+        return 1;
+}
+
 int inode_type_can_acl(mode_t mode) {
         return IN_SET(mode & S_IFMT, S_IFSOCK, S_IFREG, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO);
 }
index d65fe0299fd616f2287443a9ad152b4e7d2c7ce8..33a19f30b4130dd9bf71c5e9fecd6e383f061170 100644 (file)
@@ -4,6 +4,7 @@
 #include "shared-forward.h"
 
 int fd_acl_make_read_only_fallback(int fd);
+int fd_acl_make_writable_fallback(int fd);
 
 #if HAVE_ACL
 #include <acl/libacl.h> /* IWYU pragma: export */
@@ -55,6 +56,7 @@ int acls_for_file(const char *path, acl_type_t type, acl_t acl, acl_t *ret);
 int fd_add_uid_acl_permission(int fd, uid_t uid, unsigned mask);
 
 int fd_acl_make_read_only(int fd);
+int fd_acl_make_writable(int fd);
 
 /* acl_free() takes multiple argument types. Multiple cleanup functions are necessary. */
 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(acl_t, sym_acl_free, acl_freep, NULL);
@@ -104,6 +106,10 @@ static inline int fd_add_uid_acl_permission(int fd, uid_t uid, unsigned mask) {
 static inline int fd_acl_make_read_only(int fd) {
         return fd_acl_make_read_only_fallback(fd);
 }
+
+static inline int fd_acl_make_writable(int fd) {
+        return fd_acl_make_writable_fallback(fd);
+}
 #endif
 
 int inode_type_can_acl(mode_t mode);
index bf65d38b37fc8e7889328972131acca4e1e9c53a..5967c4b40616094c39cd191a026d4d7c1b7e2528 100644 (file)
@@ -112,6 +112,30 @@ TEST_RET(fd_acl_make_read_only) {
         cmd = strjoina("stat ", fn);
         ASSERT_OK_ZERO_ERRNO(system(cmd));
 
+        log_info("writable");
+        ASSERT_OK_POSITIVE(fd_acl_make_writable(fd));
+
+        ASSERT_OK_ERRNO(fstat(fd, &st));
+        ASSERT_EQ(st.st_mode & 0222, 0200u);
+
+        cmd = strjoina("getfacl -p ", fn);
+        ASSERT_OK_ZERO_ERRNO(system(cmd));
+
+        cmd = strjoina("stat ", fn);
+        ASSERT_OK_ZERO_ERRNO(system(cmd));
+
+        log_info("read-only");
+        ASSERT_OK_POSITIVE(fd_acl_make_read_only(fd));
+
+        ASSERT_OK_ERRNO(fstat(fd, &st));
+        ASSERT_EQ(st.st_mode & 0222, 0000u);
+
+        cmd = strjoina("getfacl -p ", fn);
+        ASSERT_OK_ZERO_ERRNO(system(cmd));
+
+        cmd = strjoina("stat ", fn);
+        ASSERT_OK_ZERO_ERRNO(system(cmd));
+
         return 0;
 }