acl-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Acl-devel] [PATCH] acl_{set,get}_file nofollow variants


From: Aaron S. Knister
Subject: [Acl-devel] [PATCH] acl_{set,get}_file nofollow variants
Date: Tue, 6 Mar 2018 17:00:07 -0500

Add act_set_file and acl_get_file nofollow variants to allow one to
relatively safely operate on paths without inadvertently following a
symbolic link.
---
 exports                        |  7 ++++
 include/libacl.h               |  2 +
 libacl/Makemodule.am           | 10 ++++-
 libacl/__acl_get_file.c        | 91 ++++++++++++++++++++++++++++++++++++++++++
 libacl/__acl_get_file.h        |  4 ++
 libacl/__acl_set_file.c        | 67 +++++++++++++++++++++++++++++++
 libacl/__acl_set_file.h        |  3 ++
 libacl/acl_get_file.c          | 59 ++-------------------------
 libacl/acl_get_file_nofollow.c | 34 ++++++++++++++++
 libacl/acl_set_file.c          | 36 ++---------------
 libacl/acl_set_file_nofollow.c | 31 ++++++++++++++
 test/.gitignore                |  2 +
 test/Makemodule.am             |  7 ++++
 test/get_nofollow.c            | 40 +++++++++++++++++++
 test/misc.test                 | 37 +++++++++++++++++
 test/set_nofollow.c            | 43 ++++++++++++++++++++
 16 files changed, 382 insertions(+), 91 deletions(-)
 create mode 100644 libacl/__acl_get_file.c
 create mode 100644 libacl/__acl_get_file.h
 create mode 100644 libacl/__acl_set_file.c
 create mode 100644 libacl/__acl_set_file.h
 create mode 100644 libacl/acl_get_file_nofollow.c
 create mode 100644 libacl/acl_set_file_nofollow.c
 create mode 100644 test/get_nofollow.c
 create mode 100644 test/set_nofollow.c

diff --git a/exports b/exports
index 830a2b9..e14527f 100644
--- a/exports
+++ b/exports
@@ -75,3 +75,10 @@ ACL_1.2 {
        # Linux specific extensions
        acl_extended_file_nofollow;
 } ACL_1.1;
+
+ACL_1.3 {
+    global:
+       # Linux specific extensions
+       acl_get_file_nofollow;
+       acl_set_file_nofollow;
+} ACL_1.2;
diff --git a/include/libacl.h b/include/libacl.h
index 63ddcf6..3472eba 100644
--- a/include/libacl.h
+++ b/include/libacl.h
@@ -63,7 +63,9 @@ EXPORT int acl_extended_file_nofollow(const char *path_p);
 EXPORT int acl_extended_fd(int fd);
 EXPORT int acl_entries(acl_t acl);
 EXPORT const char *acl_error(int code);
+EXPORT acl_t acl_get_file_nofollow(const char *path_p, acl_type_t type);
 EXPORT int acl_get_perm(acl_permset_t permset_d, acl_perm_t perm);
+EXPORT int acl_set_file_nofollow(const char *path_p, acl_type_t type, acl_t 
acl);
 
 /* Copying permissions between files */
 struct error_context;
diff --git a/libacl/Makemodule.am b/libacl/Makemodule.am
index c35214c..cfaec6e 100644
--- a/libacl/Makemodule.am
+++ b/libacl/Makemodule.am
@@ -18,7 +18,9 @@ HFILES = \
        libacl/__acl_from_xattr.h \
        libacl/__acl_to_xattr.h \
        libacl/perm_copy.h \
-       libacl/__acl_extended_file.h
+       libacl/__acl_extended_file.h \
+       libacl/__acl_get_file.h \
+       libacl/__acl_set_file.h
 
 POSIX_CFILES = \
        libacl/acl_add_perm.c \
@@ -61,8 +63,12 @@ LIBACL_CFILES = \
        libacl/acl_extended_file.c \
        libacl/acl_extended_file_nofollow.c \
        libacl/acl_from_mode.c \
+       libacl/acl_get_file_nofollow.c \
+       libacl/acl_set_file_nofollow.c \
        libacl/acl_to_any_text.c \
-       libacl/__acl_extended_file.c
+       libacl/__acl_extended_file.c \
+       libacl/__acl_get_file.c \
+       libacl/__acl_set_file.c 
 
 INTERNAL_CFILES = \
        libacl/__acl_from_xattr.c \
diff --git a/libacl/__acl_get_file.c b/libacl/__acl_get_file.c
new file mode 100644
index 0000000..826d566
--- /dev/null
+++ b/libacl/__acl_get_file.c
@@ -0,0 +1,91 @@
+/*
+  File: acl_get_file.c
+
+  Copyright (C) 1999, 2000
+  Andreas Gruenbacher, <address@hidden>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/xattr.h>
+#include "libacl.h"
+#include "__acl_from_xattr.h"
+
+#include "byteorder.h"
+#include "acl_ea.h"
+
+/* 23.4.16 */
+acl_t
+__acl_get_file(const char *path_p, acl_type_t type,
+            ssize_t (*getxattr_fun)(const char *, const char *,
+                                  void *, size_t),
+            ssize_t (*stat_fun)(const char *, struct stat *))
+{
+       const size_t size_guess = acl_ea_size(16);
+       char *ext_acl_p = alloca(size_guess);
+       const char *name;
+       int retval;
+
+       switch(type) {
+               case ACL_TYPE_ACCESS:
+                       name = ACL_EA_ACCESS;
+                       break;
+               case ACL_TYPE_DEFAULT:
+                       name = ACL_EA_DEFAULT;
+                       break;
+               default:
+                       errno = EINVAL;
+                       return NULL;
+       }
+
+       if (!ext_acl_p)
+               return NULL;
+       retval = getxattr_fun(path_p, name, ext_acl_p, size_guess);
+       if (retval == -1 && errno == ERANGE) {
+               retval = getxattr_fun(path_p, name, NULL, 0);
+               if (retval > 0) {
+                       ext_acl_p = alloca(retval);
+                       if (!ext_acl_p)
+                               return NULL;
+                       retval = getxattr_fun(path_p, name, ext_acl_p, retval);
+               }
+       }
+       if (retval > 0) {
+               acl_t acl = __acl_from_xattr(ext_acl_p, retval);
+               return acl;
+       } else if (retval == 0 || errno == ENOATTR || errno == ENODATA) {
+               struct stat st;
+
+               if (stat_fun(path_p, &st) != 0)
+                       return NULL;
+
+               if (type == ACL_TYPE_DEFAULT) {
+                       if (S_ISDIR(st.st_mode))
+                               return acl_init(0);
+                       else {
+                               errno = EACCES;
+                               return NULL;
+                       }
+               } else
+                       return acl_from_mode(st.st_mode);
+       } else
+               return NULL;
+}
+
diff --git a/libacl/__acl_get_file.h b/libacl/__acl_get_file.h
new file mode 100644
index 0000000..2975403
--- /dev/null
+++ b/libacl/__acl_get_file.h
@@ -0,0 +1,4 @@
+acl_t __acl_get_file(const char *, acl_type_t ,
+                    ssize_t (*)(const char *, const char *,
+                                  void *, size_t),
+                    int (*)(const char*, struct stat*));
diff --git a/libacl/__acl_set_file.c b/libacl/__acl_set_file.c
new file mode 100644
index 0000000..4345014
--- /dev/null
+++ b/libacl/__acl_set_file.c
@@ -0,0 +1,67 @@
+/*
+  File: acl_set_file.c
+
+  Copyright (C) 1999, 2000
+  Andreas Gruenbacher, <address@hidden>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/xattr.h>
+#include "libacl.h"
+#include "__acl_to_xattr.h"
+
+#include "byteorder.h"
+#include "acl_ea.h"
+
+
+/* 23.4.22 */
+int
+__acl_set_file(const char *path_p, acl_type_t type, acl_t acl,
+              ssize_t (*setxattr_fun)(const char *, const char *,
+                                  void *, size_t, int))
+{
+       acl_obj *acl_obj_p = ext2int(acl, acl);
+       char *ext_acl_p;
+       const char *name;
+       size_t size;
+       int error;
+
+       if (!acl_obj_p)
+               return -1;
+       switch (type) {
+               case ACL_TYPE_ACCESS:
+                       name = ACL_EA_ACCESS;
+                       break;
+               case ACL_TYPE_DEFAULT:
+                       name = ACL_EA_DEFAULT;
+                       break;
+               default:
+                       errno = EINVAL;
+                       return -1;
+       }
+
+       ext_acl_p = __acl_to_xattr(acl_obj_p, &size);
+       if (!ext_acl_p)
+               return -1;
+       error = setxattr_fun(path_p, name, (char *)ext_acl_p, size, 0);
+       free(ext_acl_p);
+       return error;
+}
+
diff --git a/libacl/__acl_set_file.h b/libacl/__acl_set_file.h
new file mode 100644
index 0000000..91257cc
--- /dev/null
+++ b/libacl/__acl_set_file.h
@@ -0,0 +1,3 @@
+int __acl_set_file(const char *, acl_type_t, acl_t,
+                  int (*)(const char *, const char *,
+                                  const void *, size_t, int));
diff --git a/libacl/acl_get_file.c b/libacl/acl_get_file.c
index 8e4b07d..12beb6e 100644
--- a/libacl/acl_get_file.c
+++ b/libacl/acl_get_file.c
@@ -20,69 +20,16 @@
 */
 
 #include "config.h"
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
-#include <stdio.h>
+#include <sys/stat.h>
 #include <sys/xattr.h>
 #include "libacl.h"
-#include "__acl_from_xattr.h"
 
-#include "byteorder.h"
-#include "acl_ea.h"
+#include "__acl_get_file.h"
 
 /* 23.4.16 */
 acl_t
 acl_get_file(const char *path_p, acl_type_t type)
 {
-       const size_t size_guess = acl_ea_size(16);
-       char *ext_acl_p = alloca(size_guess);
-       const char *name;
-       int retval;
-
-       switch(type) {
-               case ACL_TYPE_ACCESS:
-                       name = ACL_EA_ACCESS;
-                       break;
-               case ACL_TYPE_DEFAULT:
-                       name = ACL_EA_DEFAULT;
-                       break;
-               default:
-                       errno = EINVAL;
-                       return NULL;
-       }
-
-       if (!ext_acl_p)
-               return NULL;
-       retval = getxattr(path_p, name, ext_acl_p, size_guess);
-       if (retval == -1 && errno == ERANGE) {
-               retval = getxattr(path_p, name, NULL, 0);
-               if (retval > 0) {
-                       ext_acl_p = alloca(retval);
-                       if (!ext_acl_p)
-                               return NULL;
-                       retval = getxattr(path_p, name, ext_acl_p, retval);
-               }
-       }
-       if (retval > 0) {
-               acl_t acl = __acl_from_xattr(ext_acl_p, retval);
-               return acl;
-       } else if (retval == 0 || errno == ENOATTR || errno == ENODATA) {
-               struct stat st;
-
-               if (stat(path_p, &st) != 0)
-                       return NULL;
-
-               if (type == ACL_TYPE_DEFAULT) {
-                       if (S_ISDIR(st.st_mode))
-                               return acl_init(0);
-                       else {
-                               errno = EACCES;
-                               return NULL;
-                       }
-               } else
-                       return acl_from_mode(st.st_mode);
-       } else
-               return NULL;
+       return __acl_get_file(path_p, type, getxattr, stat);
 }
-
diff --git a/libacl/acl_get_file_nofollow.c b/libacl/acl_get_file_nofollow.c
new file mode 100644
index 0000000..4d291d8
--- /dev/null
+++ b/libacl/acl_get_file_nofollow.c
@@ -0,0 +1,34 @@
+/*
+  File: acl_get_file_nofollow.c
+
+  Copyright (C) 1999, 2000
+  Andreas Gruenbacher, <address@hidden>
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "config.h"
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include "libacl.h"
+
+#include "__acl_get_file.h"
+
+acl_t
+acl_get_file_nofollow(const char *path_p, acl_type_t type)
+{
+       return __acl_get_file(path_p, type, lgetxattr, lstat);
+}
diff --git a/libacl/acl_set_file.c b/libacl/acl_set_file.c
index 70fbb3d..fe6f676 100644
--- a/libacl/acl_set_file.c
+++ b/libacl/acl_set_file.c
@@ -20,46 +20,16 @@
 */
 
 #include "config.h"
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
+#include <sys/stat.h>
 #include <sys/xattr.h>
 #include "libacl.h"
-#include "__acl_to_xattr.h"
-
-#include "byteorder.h"
-#include "acl_ea.h"
 
+#include "__acl_set_file.h"
 
 /* 23.4.22 */
 int
 acl_set_file(const char *path_p, acl_type_t type, acl_t acl)
 {
-       acl_obj *acl_obj_p = ext2int(acl, acl);
-       char *ext_acl_p;
-       const char *name;
-       size_t size;
-       int error;
-
-       if (!acl_obj_p)
-               return -1;
-       switch (type) {
-               case ACL_TYPE_ACCESS:
-                       name = ACL_EA_ACCESS;
-                       break;
-               case ACL_TYPE_DEFAULT:
-                       name = ACL_EA_DEFAULT;
-                       break;
-               default:
-                       errno = EINVAL;
-                       return -1;
-       }
-
-       ext_acl_p = __acl_to_xattr(acl_obj_p, &size);
-       if (!ext_acl_p)
-               return -1;
-       error = setxattr(path_p, name, (char *)ext_acl_p, size, 0);
-       free(ext_acl_p);
-       return error;
+       return __acl_set_file(path_p, type, acl, setxattr);
 }
-
diff --git a/libacl/acl_set_file_nofollow.c b/libacl/acl_set_file_nofollow.c
new file mode 100644
index 0000000..d859dff
--- /dev/null
+++ b/libacl/acl_set_file_nofollow.c
@@ -0,0 +1,31 @@
+/*
+  File: acl_set_file_nofollow.c
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "config.h"
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include "libacl.h"
+
+#include "__acl_set_file.h"
+
+int
+acl_set_file_nofollow(const char *path_p, acl_type_t type, acl_t acl)
+{
+       return __acl_set_file(path_p, type, acl, lsetxattr);
+}
diff --git a/test/.gitignore b/test/.gitignore
index e6e5019..375d328 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1 +1,3 @@
 *.dir/
+set_nofollow
+get_nofollow
diff --git a/test/Makemodule.am b/test/Makemodule.am
index 17d4927..90aee9e 100644
--- a/test/Makemodule.am
+++ b/test/Makemodule.am
@@ -28,6 +28,13 @@ EXTRA_DIST += \
        $(TESTS)
 
 check_LTLIBRARIES = libtestlookup.la
+check_PROGRAMS = test/get_nofollow test/set_nofollow
+
+prog_ldadd = $(LDADD) libacl.la libmisc.la
+test_get_nofollow_SOURCES = test/get_nofollow.c
+test_get_nofollow_LDADD = $(prog_ldadd)
+test_set_nofollow_SOURCES = test/set_nofollow.c
+test_set_nofollow_LDADD = $(prog_ldadd)
 
 libtestlookup_la_SOURCES = test/test_passwd.c test/test_group.c
 libtestlookup_la_CFLAGS = -DBASEDIR=\"$(abs_srcdir)\"
diff --git a/test/get_nofollow.c b/test/get_nofollow.c
new file mode 100644
index 0000000..7d7a38f
--- /dev/null
+++ b/test/get_nofollow.c
@@ -0,0 +1,40 @@
+#include "config.h"
+#include <sys/acl.h>
+#include <sys/types.h>
+#include <acl/libacl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+
+       char *file_path;
+       char *aclText=NULL;
+       acl_t acl=NULL;
+       acl_entry_t entry=NULL;
+       acl_permset_t permset;
+       uid_t qualifier=1;
+
+       file_path = argv[1];
+       
+        /* Get ACL for file */
+        acl=acl_get_file_nofollow(file_path, ACL_TYPE_ACCESS);
+        if ( acl == (acl_t)NULL ) {
+                fprintf(stderr, "Failed to get ACL from file `%s': %s\n", 
file_path, strerror(errno));
+                goto fail;
+        }
+
+        /* Grab string of original state of ACL */
+        aclText=acl_to_any_text(acl, NULL, ',', TEXT_ABBREVIATE);
+        if ( aclText == NULL ) {
+                fprintf(stderr, "Failed to convert ACL to text: %s\n", 
strerror(errno));
+                goto fail;
+        }
+       printf("%s\n", aclText);
+
+       return 0;
+
+       fail:
+               return 1;
+
+}
diff --git a/test/misc.test b/test/misc.test
index 3d39b42..f8ef56e 100644
--- a/test/misc.test
+++ b/test/misc.test
@@ -499,3 +499,40 @@ Malformed restore file
        $ echo "# owner: root" > f
        $ setfacl --restore=f 2>&1
        >setfacl: f: No filename found in line 0, aborting
+
+Don't follow symlinks when using acl_{get,set}_file_nofollow
+
+       $ touch a
+       $ setfacl -m u:bin:r-x a
+       $ getfacl a
+       > # file: a
+       > # owner: %TUSER
+       > # group: %TGROUP
+       > user::rw-
+       > user:bin:r-x
+       > group::rw-
+       > mask::rwx
+       > other::r--
+       > 
+
+       $ ln -s a b
+       $ readlink b
+       > a
+
+       $ get_nofollow b
+       > u::rwx,g::rwx,o::rwx
+       $ set_nofollow b u::rwx,u:daemon:rwx,g::rwx,o::rwx
+       > access ACL 'u::rwx,u:daemon:rwx,g::rwx,o::rwx': Missing or wrong 
entry at entry 3
+       $ set_nofollow b u::rwx,u:daemon:rwx,g::rwx,m::rwx,o::rwx
+       $ get_nofollow b
+       > u::rwx,u:daemon:rwx,g::rwx,m::rwx,o::rwx
+       $ get_nofollow a
+       > u::rw-,u:bin:r-x,g::rw-,m::rwx,o::r--
+
+Confirm that acl_{get,set}_file_nofollow work on normal files
+
+       $ set_nofollow a u::rw-,u:daemon:r-x,g::rw-,m::rwx,o::r--
+       $ get_nofollow a
+       > u::rw-,u:daemon:r-x,g::rw-,m::rwx,o::r--
+
+       $ rm a b
diff --git a/test/set_nofollow.c b/test/set_nofollow.c
new file mode 100644
index 0000000..89a5c27
--- /dev/null
+++ b/test/set_nofollow.c
@@ -0,0 +1,43 @@
+#include "config.h"
+#include <sys/acl.h>
+#include <sys/types.h>
+#include <acl/libacl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+
+       char *filePath;
+       char *aclText;
+       int rc, entryIdx;
+       acl_t acl=NULL;
+       acl_entry_t entry=NULL;
+       acl_permset_t permset;
+       uid_t qualifier=1;
+
+       filePath = argv[1];
+       aclText = argv[2];
+       
+       acl = acl_from_text(argv[2]);
+       rc = acl_check(acl, &entryIdx);
+       if (rc < 0) {
+               fprintf(stderr, "%s - %s\n", aclText, strerror(errno));
+                       goto fail;
+       } else if (rc > 0) {
+               fprintf(stderr, "access ACL '%s': %s at entry %d\n", aclText, 
acl_error(rc), entryIdx);
+               goto fail;
+       }
+
+       rc=acl_set_file_nofollow(filePath, ACL_TYPE_ACCESS, acl);
+       if (rc != 0) {
+               fprintf(stderr, "Failed to set acl on file `%s': %s\n", 
filePath, strerror(rc == -1 ? errno: rc));
+               goto fail;
+       }
+
+       return 0;       
+
+       fail:
+               return 1;
+
+}
-- 
1.7.12.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]