From c52635fce35aa7d2e4414a44bac9fe06dfb56885 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 17 Dec 2018 22:05:49 -0500 Subject: Implement -acl test --- Makefile | 2 +- bfs.1 | 5 +++++ eval.c | 7 +++++++ eval.h | 1 + parse.c | 19 +++++++++++++++++ util.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- util.h | 6 ++++++ 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 @@ -196,6 +196,13 @@ bool eval_access(const struct expr *expr, struct eval_state *state) { return xfaccessat(ftwbuf->at_fd, ftwbuf->at_path, expr->idata) == 0; } +/** + * -acl test. + */ +bool eval_acl(const struct expr *expr, struct eval_state *state) { + return bfs_check_acl(state->ftwbuf); +} + /** * -capable test. */ 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 @@ -922,6 +922,22 @@ static struct expr *parse_access(struct parser_state *state, int flag, int arg2) return expr; } +/** + * 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. */ @@ -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 #include +#if BFS_HAS_SYS_ACL +# include +#endif + #if BFS_HAS_POSIX1E_CAPABILITIES # include #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(, __GLIBC__) +#define BFS_HAS_SYS_ACL BFS_HAS_INCLUDE(, true) #define BFS_HAS_SYS_CAPABILITY BFS_HAS_INCLUDE(, __linux__) #define BFS_HAS_SYS_MKDEV BFS_HAS_INCLUDE(, false) #define BFS_HAS_SYS_PARAM BFS_HAS_INCLUDE(, true) @@ -197,6 +198,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. */ -- cgit v1.2.3