]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Fix handling of symbolic link ACLs
authorMartin Matuska <martin@matuska.org>
Sat, 21 Aug 2021 18:51:07 +0000 (20:51 +0200)
committerMartin Matuska <martin@matuska.org>
Sun, 22 Aug 2021 01:50:30 +0000 (03:50 +0200)
On Linux ACLs on symbolic links are not supported.
We must avoid calling acl_set_file() on symbolic links as their
targets are modified instead.

While here, do not try to set default ACLs on non-directories.

Fixes #1565

libarchive/archive_disk_acl_freebsd.c
libarchive/archive_disk_acl_linux.c
libarchive/archive_disk_acl_sunos.c

index aba41e5dabb581fc75987b4d5d6211b3996c01db..ed4e7a7896a9e22a201db4d03dd9defaf61f691c 100644 (file)
@@ -319,7 +319,7 @@ translate_acl(struct archive_read_disk *a,
 
 static int
 set_acl(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl,
+    struct archive_acl *abstract_acl, __LA_MODE_T mode,
     int ae_requested_type, const char *tname)
 {
        int              acl_type = 0;
@@ -364,6 +364,13 @@ set_acl(struct archive *a, int fd, const char *name,
                return (ARCHIVE_FAILED);
        }
 
+       if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {
+               errno = EINVAL;
+               archive_set_error(a, errno,
+                   "Cannot set default ACL on non-directory");
+               return (ARCHIVE_WARN);
+       }
+
        acl = acl_init(entries);
        if (acl == (acl_t)NULL) {
                archive_set_error(a, errno,
@@ -542,7 +549,10 @@ set_acl(struct archive *a, int fd, const char *name,
        else if (acl_set_link_np(name, acl_type, acl) != 0)
 #else
        /* FreeBSD older than 8.0 */
-       else if (acl_set_file(name, acl_type, acl) != 0)
+       else if (S_ISLNK(mode)) {
+           /* acl_set_file() follows symbolic links, skip */
+           ret = ARCHIVE_OK;
+       } else if (acl_set_file(name, acl_type, acl) != 0)
 #endif
        {
                if (errno == EOPNOTSUPP) {
@@ -677,14 +687,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
            & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
                if ((archive_acl_types(abstract_acl)
                    & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
-                       ret = set_acl(a, fd, name, abstract_acl,
+                       ret = set_acl(a, fd, name, abstract_acl, mode,
                            ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
                        if (ret != ARCHIVE_OK)
                                return (ret);
                }
                if ((archive_acl_types(abstract_acl)
                    & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
-                       ret = set_acl(a, fd, name, abstract_acl,
+                       ret = set_acl(a, fd, name, abstract_acl, mode,
                            ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
 
                /* Simultaneous POSIX.1e and NFSv4 is not supported */
@@ -693,7 +703,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
 #if ARCHIVE_ACL_FREEBSD_NFS4
        else if ((archive_acl_types(abstract_acl) &
            ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
-               ret = set_acl(a, fd, name, abstract_acl,
+               ret = set_acl(a, fd, name, abstract_acl, mode,
                    ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
        }
 #endif
index 3928f3d6fafdd6cecdd98bc9911d3ece1edb32fe..31d270535cf73dabf6aa26a175e90f48b10c14ce 100644 (file)
@@ -343,6 +343,11 @@ set_richacl(struct archive *a, int fd, const char *name,
                return (ARCHIVE_FAILED);
        }
 
+       if (S_ISLNK(mode)) {
+               /* Linux does not support RichACLs on symbolic links */
+               return (ARCHIVE_OK);
+       }
+
        richacl = richacl_alloc(entries);
        if (richacl == NULL) {
                archive_set_error(a, errno,
@@ -455,7 +460,7 @@ exit_free:
 #if ARCHIVE_ACL_LIBACL
 static int
 set_acl(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl,
+    struct archive_acl *abstract_acl, __LA_MODE_T mode,
     int ae_requested_type, const char *tname)
 {
        int              acl_type = 0;
@@ -488,6 +493,18 @@ set_acl(struct archive *a, int fd, const char *name,
                return (ARCHIVE_FAILED);
        }
 
+       if (S_ISLNK(mode)) {
+               /* Linux does not support ACLs on symbolic links */
+               return (ARCHIVE_OK);
+       }
+
+       if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {
+               errno = EINVAL;
+               archive_set_error(a, errno,
+                   "Cannot set default ACL on non-directory");
+               return (ARCHIVE_WARN);
+       }
+
        acl = acl_init(entries);
        if (acl == (acl_t)NULL) {
                archive_set_error(a, errno,
@@ -727,14 +744,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
            & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
                if ((archive_acl_types(abstract_acl)
                    & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
-                       ret = set_acl(a, fd, name, abstract_acl,
+                       ret = set_acl(a, fd, name, abstract_acl, mode,
                            ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
                        if (ret != ARCHIVE_OK)
                                return (ret);
                }
                if ((archive_acl_types(abstract_acl)
                    & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
-                       ret = set_acl(a, fd, name, abstract_acl,
+                       ret = set_acl(a, fd, name, abstract_acl, mode,
                            ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
        }
 #endif /* ARCHIVE_ACL_LIBACL */
index b0f5dfad9b1380391d8ec1bca937781d10822362..0ef3ad52eeb91b710eba77dfa0d89ca6444cdb76 100644 (file)
@@ -443,7 +443,7 @@ translate_acl(struct archive_read_disk *a,
 
 static int
 set_acl(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl,
+    struct archive_acl *abstract_acl, __LA_MODE_T mode,
     int ae_requested_type, const char *tname)
 {
        aclent_t         *aclent;
@@ -467,7 +467,6 @@ set_acl(struct archive *a, int fd, const char *name,
        if (entries == 0)
                return (ARCHIVE_OK);
 
-
        switch (ae_requested_type) {
        case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
                cmd = SETACL;
@@ -492,6 +491,12 @@ set_acl(struct archive *a, int fd, const char *name,
                return (ARCHIVE_FAILED);
        }
 
+        if (S_ISLNK(mode)) {
+                /* Skip ACLs on symbolic links */
+               ret = ARCHIVE_OK;
+               goto exit_free;
+        }
+
        e = 0;
 
        while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
@@ -801,7 +806,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
        if ((archive_acl_types(abstract_acl)
            & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
                /* Solaris writes POSIX.1e access and default ACLs together */
-               ret = set_acl(a, fd, name, abstract_acl,
+               ret = set_acl(a, fd, name, abstract_acl, mode,
                    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
 
                /* Simultaneous POSIX.1e and NFSv4 is not supported */
@@ -810,7 +815,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
 #if ARCHIVE_ACL_SUNOS_NFS4
        else if ((archive_acl_types(abstract_acl) &
            ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
-               ret = set_acl(a, fd, name, abstract_acl,
+               ret = set_acl(a, fd, name, abstract_acl, mode,
                    ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
        }
 #endif