[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
- [Acl-devel] [PATCH] acl_{set,get}_file nofollow variants,
Aaron S. Knister <=