summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--COPYING2
-rw-r--r--Makefile18
-rw-r--r--color.c1
-rw-r--r--eval.c1
-rw-r--r--posix1e.c192
-rw-r--r--posix1e.h33
-rwxr-xr-xtests.sh6
-rw-r--r--util.c168
-rw-r--r--util.h12
9 files changed, 248 insertions, 185 deletions
diff --git a/COPYING b/COPYING
index 670e870..ac9a6a7 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (C) 2015-2018 Tavian Barnes <tavianator@tavianator.com>
+Copyright (C) 2015-2019 Tavian Barnes <tavianator@tavianator.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
diff --git a/Makefile b/Makefile
index c631c35..319680c 100644
--- a/Makefile
+++ b/Makefile
@@ -63,7 +63,23 @@ ALL_LDLIBS = $(LOCAL_LDLIBS) $(LDLIBS)
all: bfs
-bfs: bftw.o color.o diag.o dstring.o eval.o exec.o main.o mtab.o opt.o parse.o printf.o spawn.o stat.o typo.o util.o
+bfs: \
+ bftw.o \
+ color.o \
+ diag.o \
+ dstring.o \
+ eval.o \
+ exec.o \
+ main.o \
+ mtab.o \
+ opt.o \
+ parse.o \
+ posix1e.o \
+ printf.o \
+ spawn.o \
+ stat.o \
+ typo.o \
+ util.o
$(CC) $(ALL_LDFLAGS) $^ $(ALL_LDLIBS) -o $@
sanitized: CFLAGS := -g $(WFLAGS) -fsanitize=address -fsanitize=undefined
diff --git a/color.c b/color.c
index a877ff7..82076cf 100644
--- a/color.c
+++ b/color.c
@@ -16,6 +16,7 @@
#include "color.h"
#include "bftw.h"
+#include "posix1e.h"
#include "stat.h"
#include "util.h"
#include <assert.h>
diff --git a/eval.c b/eval.c
index 5b55b8d..37f8bf5 100644
--- a/eval.c
+++ b/eval.c
@@ -22,6 +22,7 @@
#include "dstring.h"
#include "exec.h"
#include "mtab.h"
+#include "posix1e.h"
#include "printf.h"
#include "stat.h"
#include "util.h"
diff --git a/posix1e.c b/posix1e.c
new file mode 100644
index 0000000..00bff10
--- /dev/null
+++ b/posix1e.c
@@ -0,0 +1,192 @@
+/****************************************************************************
+ * bfs *
+ * Copyright (C) 2019 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#include "posix1e.h"
+#include "bftw.h"
+#include "util.h"
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if BFS_HAS_SYS_ACL
+# include <sys/acl.h>
+#endif
+
+#if BFS_HAS_POSIX1E_CAPABILITIES
+# include <sys/capability.h>
+#endif
+
+#if BFS_HAS_SYS_ACL || BFS_HAS_POSIX1E_CAPABILITIES
+
+static const char *open_path(const struct BFTW *ftwbuf, int *fd) {
+#ifdef O_PATH
+ // The POSIX.1e APIS predate the *at() family of functions. We'd still
+ // like to do something to avoid path re-traversals and limit races
+ // though. Ideally we could just do openat(..., O_PATH) (since we may
+ // not have read access) and pass that fd to something like cap_get_fd()
+ // but that will fail since fgetxattr() needs read access to the file.
+ // The workaround is to use O_PATH to open an fd and then pass
+ // /proc/self/fd/<fd> to cap_get_path(). Inspired by
+ // https://android.googlesource.com/platform/bionic/+/2825f10b7f61558c264231a536cf3affc0d84204
+ int flags = O_PATH;
+ if (ftwbuf->at_flags & AT_SYMLINK_NOFOLLOW) {
+ flags |= O_NOFOLLOW;
+ }
+
+ *fd = openat(ftwbuf->at_fd, ftwbuf->at_path, flags);
+ if (*fd < 0) {
+ return NULL;
+ }
+
+ size_t size = strlen("/proc/self/fd/") + CHAR_BIT*sizeof(int) + 1;
+ char *path = malloc(size);
+ if (!path) {
+ close(*fd);
+ *fd = -1;
+ return NULL;
+ }
+
+ snprintf(path, size, "/proc/self/fd/%d", *fd);
+ return path;
+#else
+ *fd = -1;
+ return ftwbuf->path;
+#endif
+}
+
+static void close_path(const struct BFTW *ftwbuf, const char *path, int fd) {
+ if (path && path != ftwbuf->path) {
+ free((void *)path);
+ }
+ if (fd >= 0) {
+ close(fd);
+ }
+}
+
+#endif // BFS_HAS_SYS_ACL || BFS_HAS_POSIX1E_CAPABILITIES
+
+#if BFS_HAS_SYS_ACL
+
+/** Check if any ACLs of the given type are non-trivial. */
+static bool bfs_check_acl_type(const char *path, acl_type_t type) {
+ acl_t acl = acl_get_file(path, type);
+ if (!acl) {
+ return false;
+ }
+
+ bool ret = false;
+ acl_entry_t entry;
+ for (int status = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+ status > 0;
+ status = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) {
+#if defined(ACL_USER_OBJ) && defined(ACL_GROUP_OBJ) && defined(ACL_OTHER)
+ acl_tag_t tag;
+ if (acl_get_tag_type(entry, &tag) != 0) {
+ continue;
+ }
+ if (tag != ACL_USER_OBJ && tag != ACL_GROUP_OBJ && tag != ACL_OTHER) {
+ ret = true;
+ break;
+ }
+#else
+ ret = true;
+ break;
+#endif
+ }
+
+ acl_free(acl);
+ return ret;
+}
+
+bool bfs_check_acl(const struct BFTW *ftwbuf) {
+ if (ftwbuf->typeflag == BFTW_LNK) {
+ return false;
+ }
+
+ int fd;
+ const char *path = open_path(ftwbuf, &fd);
+ if (!path) {
+ return false;
+ }
+
+ bool ret = false;
+ if (bfs_check_acl_type(path, ACL_TYPE_ACCESS)) {
+ ret = true;
+ } else if (bfs_check_acl_type(path, ACL_TYPE_DEFAULT)) {
+ ret = true;
+#ifdef ACL_TYPE_EXTENDED
+ } else if (bfs_check_acl_type(path, ACL_TYPE_EXTENDED)) {
+ ret = true;
+#endif
+ }
+
+ close_path(ftwbuf, path, fd);
+ return ret;
+}
+
+#else // !BFS_HAS_SYS_ACL
+
+bool bfs_check_acl(const struct BFTW *ftwbuf) {
+ return false;
+}
+
+#endif
+
+#if BFS_HAS_POSIX1E_CAPABILITIES
+
+bool bfs_check_capabilities(const struct BFTW *ftwbuf) {
+ bool ret = false;
+
+ if (ftwbuf->typeflag == BFTW_LNK) {
+ goto out;
+ }
+
+ int fd;
+ const char *path = open_path(ftwbuf, &fd);
+ if (!path) {
+ goto out;
+ }
+
+ cap_t caps = cap_get_file(path);
+ if (!caps) {
+ goto out_close;
+ }
+
+ // TODO: Any better way to check for a non-empty capability set?
+ char *text = cap_to_text(caps, NULL);
+ if (!text) {
+ goto out_free_caps;
+ }
+ ret = text[0];
+
+ cap_free(text);
+out_free_caps:
+ cap_free(caps);
+out_close:
+ close_path(ftwbuf, path, fd);
+out:
+ return ret;
+}
+
+#else // !BFS_HAS_POSIX1E_CAPABILITIES
+
+bool bfs_check_capabilities(const struct BFTW *ftwbuf) {
+ return false;
+}
+
+#endif
diff --git a/posix1e.h b/posix1e.h
new file mode 100644
index 0000000..da7c2b4
--- /dev/null
+++ b/posix1e.h
@@ -0,0 +1,33 @@
+/****************************************************************************
+ * bfs *
+ * Copyright (C) 2019 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#ifndef BFS_POSIX1E_H
+#define BFS_POSIX1E_H
+
+#include "bftw.h"
+#include "util.h"
+
+/**
+ * Check if a file has a non-trvial Access Control List.
+ */
+bool bfs_check_acl(const struct BFTW *ftwbuf);
+
+/**
+ * Check if a file has a non-trvial capability set.
+ */
+bool bfs_check_capabilities(const struct BFTW *ftwbuf);
+
+#endif // BFS_POSIX1E_H
diff --git a/tests.sh b/tests.sh
index 0b2678d..5905d38 100755
--- a/tests.sh
+++ b/tests.sh
@@ -174,10 +174,10 @@ function make_rainbow() {
touchp "$1/mh1"
ln "$1/mh1" "$1/mh2"
mkfifo "$1/pipe"
- # XXX: block
- # XXX: chardev
+ # TODO: block
+ # TODO: chardev
ln -s nowhere "$1/broken"
- # XXX: socket
+ # TODO: socket
touchp "$1"/s{u,g,ug}id
chmod u+s "$1"/su{,g}id
chmod g+s "$1"/s{u,}gid
diff --git a/util.c b/util.c
index ba7b75e..b708527 100644
--- a/util.c
+++ b/util.c
@@ -30,14 +30,6 @@
#include <sys/types.h>
#include <unistd.h>
-#if BFS_HAS_SYS_ACL
-# include <sys/acl.h>
-#endif
-
-#if BFS_HAS_POSIX1E_CAPABILITIES
-# include <sys/capability.h>
-#endif
-
#if BFS_HAS_SYS_PARAM
# include <sys/param.h>
#endif
@@ -385,163 +377,3 @@ int bfs_minor(dev_t dev) {
return dev & 0xFF;
#endif
}
-
-#if BFS_HAS_SYS_ACL || BFS_HAS_POSIX1E_CAPABILITIES
-
-static const char *open_path(const struct BFTW *ftwbuf, int *fd) {
-#ifdef O_PATH
- // The POSIX.1e APIS predate the *at() family of functions. We'd still
- // like to do something to avoid path re-traversals and limit races
- // though. Ideally we could just do openat(..., O_PATH) (since we may
- // not have read access) and pass that fd to something like cap_get_fd()
- // but that will fail since fgetxattr() needs read access to the file.
- // The workaround is to use O_PATH to open an fd and then pass
- // /proc/self/fd/<fd> to cap_get_path(). Inspired by
- // https://android.googlesource.com/platform/bionic/+/2825f10b7f61558c264231a536cf3affc0d84204
- int flags = O_PATH;
- if (ftwbuf->at_flags & AT_SYMLINK_NOFOLLOW) {
- flags |= O_NOFOLLOW;
- }
-
- *fd = openat(ftwbuf->at_fd, ftwbuf->at_path, flags);
- if (*fd < 0) {
- return NULL;
- }
-
- size_t size = strlen("/proc/self/fd/") + CHAR_BIT*sizeof(int) + 1;
- char *path = malloc(size);
- if (!path) {
- close(*fd);
- *fd = -1;
- return NULL;
- }
-
- snprintf(path, size, "/proc/self/fd/%d", *fd);
- return path;
-#else
- *fd = -1;
- return ftwbuf->path;
-#endif
-}
-
-static void close_path(const struct BFTW *ftwbuf, const char *path, int fd) {
- if (path && path != ftwbuf->path) {
- free((void *)path);
- }
- if (fd >= 0) {
- close(fd);
- }
-}
-
-#endif // BFS_HAS_SYS_ACL || BFS_HAS_POSIX1E_CAPABILITIES
-
-#if BFS_HAS_SYS_ACL
-
-/** Check if any ACLs of the given type are non-trivial. */
-static bool bfs_check_acl_type(const char *path, acl_type_t type) {
- acl_t acl = acl_get_file(path, type);
- if (!acl) {
- return false;
- }
-
- bool ret = false;
- acl_entry_t entry;
- for (int status = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
- status > 0;
- status = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) {
-#if defined(ACL_USER_OBJ) && defined(ACL_GROUP_OBJ) && defined(ACL_OTHER)
- acl_tag_t tag;
- if (acl_get_tag_type(entry, &tag) != 0) {
- continue;
- }
- if (tag != ACL_USER_OBJ && tag != ACL_GROUP_OBJ && tag != ACL_OTHER) {
- ret = true;
- break;
- }
-#else
- ret = true;
- break;
-#endif
- }
-
- acl_free(acl);
- return ret;
-}
-
-bool bfs_check_acl(const struct BFTW *ftwbuf) {
- if (ftwbuf->typeflag == BFTW_LNK) {
- return false;
- }
-
- int fd;
- const char *path = open_path(ftwbuf, &fd);
- if (!path) {
- return false;
- }
-
- bool ret = false;
- if (bfs_check_acl_type(path, ACL_TYPE_ACCESS)) {
- ret = true;
- } else if (bfs_check_acl_type(path, ACL_TYPE_DEFAULT)) {
- ret = true;
-#ifdef ACL_TYPE_EXTENDED
- } else if (bfs_check_acl_type(path, ACL_TYPE_EXTENDED)) {
- ret = true;
-#endif
- }
-
- close_path(ftwbuf, path, fd);
- return ret;
-}
-
-#else // !BFS_HAS_SYS_ACL
-
-bool bfs_check_acl(const struct BFTW *ftwbuf) {
- return false;
-}
-
-#endif
-
-#if BFS_HAS_POSIX1E_CAPABILITIES
-
-bool bfs_check_capabilities(const struct BFTW *ftwbuf) {
- bool ret = false;
-
- if (ftwbuf->typeflag == BFTW_LNK) {
- goto out;
- }
-
- int fd;
- const char *path = open_path(ftwbuf, &fd);
- if (!path) {
- goto out;
- }
-
- cap_t caps = cap_get_file(path);
- if (!caps) {
- goto out_close;
- }
-
- // TODO: Any better way to check for a non-empty capability set?
- char *text = cap_to_text(caps, NULL);
- if (!text) {
- goto out_free_caps;
- }
- ret = text[0];
-
- cap_free(text);
-out_free_caps:
- cap_free(caps);
-out_close:
- close_path(ftwbuf, path, fd);
-out:
- return ret;
-}
-
-#else // !BFS_HAS_POSIX1E_CAPABILITIES
-
-bool bfs_check_capabilities(const struct BFTW *ftwbuf) {
- return false;
-}
-
-#endif
diff --git a/util.h b/util.h
index 4a9947c..2031c02 100644
--- a/util.h
+++ b/util.h
@@ -205,16 +205,4 @@ int bfs_major(dev_t dev);
*/
int bfs_minor(dev_t dev);
-struct BFTW;
-
-/**
- * Check if a file has a non-trvial Access Control List.
- */
-bool bfs_check_acl(const struct BFTW *ftwbuf);
-
-/**
- * Check if a file has a non-trvial capability set.
- */
-bool bfs_check_capabilities(const struct BFTW *ftwbuf);
-
#endif // BFS_UTIL_H