From 6fe70075fe7ebc5d0e457831bc65fd1d8538610d Mon Sep 17 00:00:00 2001 From: Morgan Weetman Date: Wed, 7 Jan 2015 15:31:55 +1100 Subject: [PATCH 5/8] find: added capability predicate * find/defs.h (typedef PREDICATEFUNCTION): added pred_cap * find/parser.c: added parse_cap function added parse_icap function added insert_cap function added an entry to parse_table * find/pred.c (pred_cap): added function, added an entry to pred_table[] * find/tree.c (costlookup[]): added pred_cap entry * find/find.1: added -cap and -icap entries --- find/defs.h | 1 + find/find.1 | 12 ++++++++++++ find/parser.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ find/pred.c | 29 +++++++++++++++++++++++++++++ find/tree.c | 1 + 5 files changed, 95 insertions(+) diff --git a/find/defs.h b/find/defs.h index 4ab1bb1..cd57544 100644 --- a/find/defs.h +++ b/find/defs.h @@ -405,6 +405,7 @@ PREDICATEFUNCTION pred_and; PREDICATEFUNCTION pred_anewer; PREDICATEFUNCTION pred_atime; PREDICATEFUNCTION pred_closeparen; +PREDICATEFUNCTION pred_cap; PREDICATEFUNCTION pred_cmin; PREDICATEFUNCTION pred_cnewer; PREDICATEFUNCTION pred_comma; diff --git a/find/find.1 b/find/find.1 index 096a3ed..6d03d85 100644 --- a/find/find.1 +++ b/find/find.1 @@ -521,6 +521,13 @@ a file has to have been accessed at least .I two days ago. +.IP "\-cap \fIpattern\fR" +Match file capabilities against the regular expression +\fIpattern\fR. For example to search for files that have +CAP_SETUID you could use '.*setuid.*'. This option +also takes advantage of +.B \-regextype + .IP "\-cmin \fIn\fR" File's status was last changed \fIn\fR minutes ago. @@ -577,6 +584,11 @@ File's numeric group ID is \fIn\fR. .IP "\-group \fIgname\fR" File belongs to group \fIgname\fR (numeric group ID allowed). +.IP "\-icap \fIpattern\fR" +Like +.BR \-cap , +but the match is case insensitive. + .IP "\-ilname \fIpattern\fR" Like .BR \-lname , diff --git a/find/parser.c b/find/parser.c index 16163f5..d5b5731 100644 --- a/find/parser.c +++ b/find/parser.c @@ -85,6 +85,7 @@ static bool parse_accesscheck (const struct parser_table*, char *argv[], int * static bool parse_amin (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_and (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_anewer (const struct parser_table*, char *argv[], int *arg_ptr); +static bool parse_cap (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_cmin (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_cnewer (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_comma (const struct parser_table*, char *argv[], int *arg_ptr); @@ -105,6 +106,7 @@ static bool parse_fstype (const struct parser_table*, char *argv[], int * static bool parse_gid (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_group (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_help (const struct parser_table*, char *argv[], int *arg_ptr); +static bool parse_icap (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_ilname (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_iname (const struct parser_table*, char *argv[], int *arg_ptr); static bool parse_inum (const struct parser_table*, char *argv[], int *arg_ptr); @@ -169,6 +171,9 @@ static bool insert_regex (char *argv[], int *arg_ptr, static bool insert_xattr (char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options); +static bool insert_cap (char *argv[], int *arg_ptr, + const struct parser_table *entry, + int regex_options); static bool insert_exec_ok (const char *action, const struct parser_table *entry, char *argv[], @@ -238,6 +243,7 @@ static struct parser_table const parse_table[] = PARSE_PUNCTUATION("and", and), /* GNU */ PARSE_TEST ("anewer", anewer), /* GNU */ {ARG_TEST, "atime", parse_time, pred_atime}, /* POSIX */ + PARSE_TEST ("cap", cap), /* GNU */ PARSE_TEST ("cmin", cmin), /* GNU */ PARSE_TEST ("cnewer", cnewer), /* GNU */ {ARG_TEST, "ctime", parse_time, pred_ctime}, /* POSIX */ @@ -258,6 +264,7 @@ static struct parser_table const parse_table[] = PARSE_TEST ("fstype", fstype), /* GNU, Unix */ PARSE_TEST ("gid", gid), /* GNU */ PARSE_TEST ("group", group), /* POSIX */ + PARSE_TEST_NP ("icap", icap), /* GNU */ PARSE_OPTION ("ignore_readdir_race", ignore_race), /* GNU */ PARSE_TEST ("ilname", ilname), /* GNU */ PARSE_TEST ("iname", iname), /* GNU */ @@ -797,6 +804,12 @@ parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr) return false; } +static bool +parse_cap (const struct parser_table* entry, char **argv, int *arg_ptr) +{ + return insert_cap (argv, arg_ptr, entry, options.regex_options); +} + bool parse_closeparen (const struct parser_table* entry, char **argv, int *arg_ptr) { @@ -1277,6 +1290,12 @@ estimate_pattern_match_rate (const char *pattern, int is_regex) } static bool +parse_icap (const struct parser_table* entry, char **argv, int *arg_ptr) +{ + return insert_cap (argv, arg_ptr, entry, RE_ICASE|options.regex_options); +} + +static bool parse_ilname (const struct parser_table* entry, char **argv, int *arg_ptr) { const char *name; @@ -2924,6 +2943,39 @@ insert_type (char **argv, int *arg_ptr, return false; } +static bool +insert_cap (char **argv, + int *arg_ptr, + const struct parser_table *entry, + int regex_options) +{ + const char *rx; + if (collect_arg (argv, arg_ptr, &rx)) + { + struct re_pattern_buffer *re; + const char *error_message; + struct predicate *our_pred = insert_primary_withpred (entry, pred_cap, rx); + our_pred->need_stat = true; + our_pred->need_type = false; + re = xmalloc (sizeof (struct re_pattern_buffer)); + our_pred->args.regex = re; + re->allocated = 100; + re->buffer = xmalloc (re->allocated); + re->fastmap = NULL; + + re_set_syntax (regex_options); + re->syntax = regex_options; + re->translate = NULL; + + error_message = re_compile_pattern (rx, strlen (rx), re); + if (error_message) + error (EXIT_FAILURE, 0, "%s", error_message); + our_pred->est_success_rate = estimate_pattern_match_rate (rx, 1); + return true; + } + return false; +} + /* Return true if the file accessed via FP is a terminal. */ diff --git a/find/pred.c b/find/pred.c index ddf9917..83c8286 100644 --- a/find/pred.c +++ b/find/pred.c @@ -36,6 +36,7 @@ #include #include #include /* for unlinkat() */ +#include /* for pred_cap() */ /* gnulib headers. */ #include "areadlink.h" @@ -90,6 +91,7 @@ struct pred_assoc pred_table[] = {pred_and, "and "}, {pred_anewer, "anewer "}, {pred_atime, "atime "}, + {pred_cap, "cap "}, {pred_closeparen, ") "}, {pred_cmin, "cmin "}, {pred_cnewer, "cnewer "}, @@ -261,6 +263,33 @@ pred_atime (const char *pathname, struct stat *stat_buf, struct predicate *pred_ } bool +pred_cap (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +{ + (void) pathname; + char *cap_str; + cap_t caps; + bool ret = false; + + // get capabilities + caps = cap_get_file(pathname); + cap_str = cap_to_text(caps, NULL); + if ( cap_str == NULL ) { + cap_free(caps); + return(ret); + } + + // perform regex match + if (regexec(pred_ptr->args.regex, cap_str, (size_t) 0, NULL, 0) == 0) + ret = true; + + // clean up + cap_free(caps); + cap_free(cap_str); + return(ret); + +} + +bool pred_closeparen (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { (void) &pathname; diff --git a/find/tree.c b/find/tree.c index 2dba99d..d91b080 100644 --- a/find/tree.c +++ b/find/tree.c @@ -947,6 +947,7 @@ static struct pred_cost_lookup costlookup[] = { pred_and , NeedsNothing, }, { pred_anewer , NeedsStatInfo, }, { pred_atime , NeedsStatInfo, }, + { pred_cap , NeedsNothing, }, { pred_closeparen, NeedsNothing }, { pred_cmin , NeedsStatInfo, }, { pred_cnewer , NeedsStatInfo, }, -- 1.9.3