summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--bfs.15
-rw-r--r--eval.c7
-rw-r--r--eval.h1
-rw-r--r--parse.c19
-rw-r--r--util.c72
-rw-r--r--util.h6
7 files changed, 110 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index f304ab1..ad997b1 100644
--- a/Makefile
+++ b/Makefile
@@ -53,7 +53,7 @@ LOCAL_LDLIBS :=
ifeq ($(OS),Linux)
LOCAL_LDFLAGS += -Wl,--as-needed
-LOCAL_LDLIBS += -lcap -lrt
+LOCAL_LDLIBS += -lacl -lcap -lrt
endif
ALL_CPPFLAGS = $(LOCAL_CPPFLAGS) $(CPPFLAGS)
diff --git a/bfs.1 b/bfs.1
index 2140a6b..9c7f14c 100644
--- a/bfs.1
+++ b/bfs.1
@@ -516,6 +516,11 @@ Treat
as a path to search (useful if it begins with a dash).
.LP
Tests:
+.TP
+.B \-acl
+Find files with non-trivial
+.BR acl (5)
+(Access Control Lists).
.PP
\fB\-Bmin\fR [\fI\-+\fR]\fIN\fR
.br
diff --git a/eval.c b/eval.c
index 44e4a6d..ce72579 100644
--- a/eval.c
+++ b/eval.c
@@ -197,6 +197,13 @@ bool eval_access(const struct expr *expr, struct eval_state *state) {
}
/**
+ * -acl test.
+ */
+bool eval_acl(const struct expr *expr, struct eval_state *state) {
+ return bfs_check_acl(state->ftwbuf);
+}
+
+/**
* -capable test.
*/
bool eval_capable(const struct expr *expr, struct eval_state *state) {
diff --git a/eval.h b/eval.h
index 52bda54..89bf421 100644
--- a/eval.h
+++ b/eval.h
@@ -24,6 +24,7 @@ bool eval_true(const struct expr *expr, struct eval_state *state);
bool eval_false(const struct expr *expr, struct eval_state *state);
bool eval_access(const struct expr *expr, struct eval_state *state);
+bool eval_acl(const struct expr *expr, struct eval_state *state);
bool eval_capable(const struct expr *expr, struct eval_state *state);
bool eval_perm(const struct expr *expr, struct eval_state *state);
diff --git a/parse.c b/parse.c
index a1b60e3..554d56b 100644
--- a/parse.c
+++ b/parse.c
@@ -923,6 +923,22 @@ static struct expr *parse_access(struct parser_state *state, int flag, int arg2)
}
/**
+ * Parse -acl.
+ */
+static struct expr *parse_acl(struct parser_state *state, int flag, int arg2) {
+#if BFS_HAS_SYS_ACL
+ struct expr *expr = parse_nullary_test(state, eval_acl);
+ if (expr) {
+ expr->cost = 2*STAT_COST;
+ }
+ return expr;
+#else
+ cfprintf(state->cmdline->cerr, "%{er}error: %s is missing platform support.%{rs}\n", state->argv[0]);
+ return NULL;
+#endif
+}
+
+/**
* Parse -[aBcm]?newer.
*/
static struct expr *parse_newer(struct parser_state *state, int field, int arg2) {
@@ -2438,6 +2454,8 @@ static struct expr *parse_help(struct parser_state *state, int arg1, int arg2) {
cfprintf(cout, " %{cyn}-f%{rs} %{mag}PATH%{rs}\n");
cfprintf(cout, " Treat %{mag}PATH%{rs} as a path to search (useful if begins with a dash)\n\n");
+ cfprintf(cout, " %{blu}-acl%{rs}\n");
+ cfprintf(cout, " Find files with non-trivial Access Control Lists\n");
cfprintf(cout, " %{blu}-Bmin%{rs} %{bld}[-+]N%{rs}\n");
cfprintf(cout, " %{blu}-Btime%{rs} %{bld}[-+]N%{rs}\n");
cfprintf(cout, " Find files Birthed %{bld}N%{rs} minutes/days ago\n");
@@ -2538,6 +2556,7 @@ static const struct table_entry parse_table[] = {
{"-L", false, parse_follow, BFTW_LOGICAL | BFTW_DETECT_CYCLES, false},
{"-X", false, parse_xargs_safe},
{"-a"},
+ {"-acl", false, parse_acl},
{"-amin", false, parse_time, BFS_STAT_ATIME, MINUTES},
{"-and"},
{"-anewer", false, parse_newer, BFS_STAT_ATIME},
diff --git a/util.c b/util.c
index 0ec6dba..359a5cd 100644
--- a/util.c
+++ b/util.c
@@ -30,6 +30,10 @@
#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
@@ -382,7 +386,7 @@ int bfs_minor(dev_t dev) {
#endif
}
-#if BFS_HAS_POSIX1E_CAPABILITIES
+#if BFS_HAS_SYS_ACL || BFS_HAS_POSIX1E_CAPABILITIES
static const char *open_path(const struct BFTW *ftwbuf, int *fd) {
#ifdef O_PATH
@@ -429,6 +433,72 @@ static void close_path(const struct BFTW *ftwbuf, const char *path, int 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)) {
+ 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;
+ }
+ }
+
+ 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;
diff --git a/util.h b/util.h
index 7506924..836db37 100644
--- a/util.h
+++ b/util.h
@@ -34,6 +34,7 @@
#endif
#define BFS_HAS_MNTENT BFS_HAS_INCLUDE(<mntent.h>, __GLIBC__)
+#define BFS_HAS_SYS_ACL BFS_HAS_INCLUDE(<sys/acl.h>, true)
#define BFS_HAS_SYS_CAPABILITY BFS_HAS_INCLUDE(<sys/capability.h>, __linux__)
#define BFS_HAS_SYS_MKDEV BFS_HAS_INCLUDE(<sys/mkdev.h>, false)
#define BFS_HAS_SYS_PARAM BFS_HAS_INCLUDE(<sys/param.h>, true)
@@ -198,6 +199,11 @@ 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);