From 60eef27e6dd953a376c7f63b0979d271df3d9497 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Wed, 9 Aug 2023 10:16:10 -0600 Subject: [PATCH] Add verbose version of "sudo -l command" by using an extra -l. The output of "sudo -ll command" consists of the matching sudoers rule (in long form) with the addition of a "Matched" entry that shows the fully-qualfied path along with any arguments. --- plugins/sudoers/display.c | 28 +++++++++++++++++----- plugins/sudoers/lookup.c | 25 +++++++++---------- plugins/sudoers/parse.h | 11 +++++++-- plugins/sudoers/regress/fuzz/fuzz_policy.c | 2 +- plugins/sudoers/sudoers.c | 14 ++++------- plugins/sudoers/testsudoers.c | 8 +++---- 6 files changed, 53 insertions(+), 35 deletions(-) diff --git a/plugins/sudoers/display.c b/plugins/sudoers/display.c index b913c7983..6e4a6fc28 100644 --- a/plugins/sudoers/display.c +++ b/plugins/sudoers/display.c @@ -537,7 +537,7 @@ bad: static int display_cmnd_check(struct sudoers_parse_tree *parse_tree, struct passwd *pw, - time_t now) + time_t now, struct sudoers_match_info *match_info) { int host_match, runas_match, cmnd_match = UNSPEC; char *saved_user_cmnd, *saved_user_base; @@ -576,8 +576,13 @@ display_cmnd_check(struct sudoers_parse_tree *parse_tree, struct passwd *pw, if (runas_match == ALLOW) { cmnd_match = cmnd_matches(parse_tree, cs->cmnd, cs->runchroot, NULL); - if (cmnd_match != UNSPEC) + if (cmnd_match != UNSPEC) { + match_info->parse_tree = parse_tree; + match_info->us = us; + match_info->priv = priv; + match_info->cs = cs; goto done; + } } } } @@ -594,8 +599,10 @@ done: * Returns true if the command is allowed, false if not or -1 on error. */ int -display_cmnd(struct sudo_nss_list *snl, struct passwd *pw) +display_cmnd(struct sudo_nss_list *snl, struct passwd *pw, bool verbose) { + struct sudoers_match_info match_info = { NULL }; + struct sudo_lbuf lbuf; struct sudo_nss *nss; int m, match = UNSPEC; int ret = false; @@ -604,13 +611,14 @@ display_cmnd(struct sudo_nss_list *snl, struct passwd *pw) /* Iterate over each source, checking for the command. */ time(&now); + sudo_lbuf_init(&lbuf, output, 0, NULL, 0); TAILQ_FOREACH(nss, snl, entries) { if (nss->query(nss, pw) == -1) { /* The query function should have printed an error message. */ debug_return_int(-1); } - m = display_cmnd_check(nss->parse_tree, pw, now); + m = display_cmnd_check(nss->parse_tree, pw, now, &match_info); if (m != UNSPEC) match = m; @@ -618,9 +626,17 @@ display_cmnd(struct sudo_nss_list *snl, struct passwd *pw) break; } if (match == ALLOW) { - const int len = sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n", + if (verbose) { + /* Append matching sudoers rule (long form). */ + display_cmndspec_long(match_info.parse_tree, pw, match_info.us, + match_info.priv, match_info.cs, NULL, &lbuf); + sudo_lbuf_append(&lbuf, " Matched: "); + } + sudo_lbuf_append(&lbuf, "%s%s%s\n", list_cmnd, user_args ? " " : "", user_args ? user_args : ""); - ret = len < 0 ? -1 : true; + sudo_lbuf_print(&lbuf); + ret = sudo_lbuf_error(&lbuf) ? -1 : true; + sudo_lbuf_destroy(&lbuf); } debug_return_int(ret); } diff --git a/plugins/sudoers/lookup.c b/plugins/sudoers/lookup.c index 25c7f4f4d..895d4ed47 100644 --- a/plugins/sudoers/lookup.c +++ b/plugins/sudoers/lookup.c @@ -99,8 +99,8 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, time_t now, int user_match = userlist_matches(nss->parse_tree, pw, &us->users); if (user_match != ALLOW) { if (callback != NULL && user_match != UNSPEC) { - callback(us, user_match, NULL, UNSPEC, NULL, UNSPEC, - UNSPEC, UNSPEC, cb_data); + callback(nss->parse_tree, us, user_match, NULL, UNSPEC, + NULL, UNSPEC, UNSPEC, UNSPEC, cb_data); } continue; } @@ -110,8 +110,8 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, time_t now, &priv->hostlist); if (host_match != ALLOW) { if (callback != NULL) { - callback(us, user_match, priv, host_match, NULL, UNSPEC, - UNSPEC, UNSPEC, cb_data); + callback(nss->parse_tree, us, user_match, priv, + host_match, NULL, UNSPEC, UNSPEC, UNSPEC, cb_data); } continue; } @@ -183,8 +183,9 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, time_t now, } } if (callback != NULL) { - callback(us, user_match, priv, host_match, cs, - date_match, runas_match, cmnd_match, cb_data); + callback(nss->parse_tree, us, user_match, priv, + host_match, cs, date_match, runas_match, + cmnd_match, cb_data); } if (cmnd_match != UNSPEC) { /* @@ -243,8 +244,8 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw, int user_match = userlist_matches(nss->parse_tree, pw, &us->users); if (user_match != ALLOW) { if (callback != NULL && user_match != UNSPEC) { - callback(us, user_match, NULL, UNSPEC, NULL, UNSPEC, - UNSPEC, UNSPEC, cb_data); + callback(nss->parse_tree, us, user_match, NULL, UNSPEC, NULL, + UNSPEC, UNSPEC, UNSPEC, cb_data); } continue; } @@ -256,8 +257,8 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw, CLR(*validated, FLAG_NO_HOST); } else { if (callback != NULL) { - callback(us, user_match, priv, host_match, NULL, UNSPEC, - UNSPEC, UNSPEC, cb_data); + callback(nss->parse_tree, us, user_match, priv, host_match, + NULL, UNSPEC, UNSPEC, UNSPEC, cb_data); } continue; } @@ -283,8 +284,8 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw, } } if (callback != NULL) { - callback(us, user_match, priv, host_match, cs, date_match, - runas_match, cmnd_match, cb_data); + callback(nss->parse_tree, us, user_match, priv, host_match, + cs, date_match, runas_match, cmnd_match, cb_data); } if (cmnd_match != UNSPEC) { diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h index a6bc8c02e..952f20b43 100644 --- a/plugins/sudoers/parse.h +++ b/plugins/sudoers/parse.h @@ -298,6 +298,13 @@ struct defaults { int column; /* column number of Defaults entry */ }; +struct sudoers_match_info { + struct sudoers_parse_tree *parse_tree; + struct userspec *us; /* matching userspec */ + struct privilege *priv; /* matching privilege */ + struct cmndspec *cs; /* matching cmndspec */ +}; + /* * Parsed sudoers policy. */ @@ -324,7 +331,7 @@ struct cmnd_info { /* * Optional callback for sudoers_lookup(). */ -typedef void (*sudoers_lookup_callback_fn_t)(struct userspec *us, int user_match, struct privilege *priv, int host_match, struct cmndspec *cs, int date_match, int runas_match, int cmnd_match, void *closure); +typedef void (*sudoers_lookup_callback_fn_t)(struct sudoers_parse_tree *parse_tree, struct userspec *us, int user_match, struct privilege *priv, int host_match, struct cmndspec *cs, int date_match, int runas_match, int cmnd_match, void *closure); /* * Parse configuration settings, passed to init_parser(). @@ -481,7 +488,7 @@ unsigned int sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, time_t /* display.c */ int display_privs(struct sudo_nss_list *snl, struct passwd *pw, bool verbose); -int display_cmnd(struct sudo_nss_list *snl, struct passwd *pw); +int display_cmnd(struct sudo_nss_list *snl, struct passwd *pw, bool verbose); /* parse_ldif.c */ bool sudoers_parse_ldif(struct sudoers_parse_tree *parse_tree, FILE *fp, const char *sudoers_base, bool store_options); diff --git a/plugins/sudoers/regress/fuzz/fuzz_policy.c b/plugins/sudoers/regress/fuzz/fuzz_policy.c index bc8e7c769..392a609ea 100644 --- a/plugins/sudoers/regress/fuzz/fuzz_policy.c +++ b/plugins/sudoers/regress/fuzz/fuzz_policy.c @@ -815,7 +815,7 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, time_t now, /* STUB */ int -display_cmnd(struct sudo_nss_list *snl, struct passwd *pw) +display_cmnd(struct sudo_nss_list *snl, struct passwd *pw, bool verbose) { return true; } diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index f9351a923..e0152d7d5 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -325,16 +325,10 @@ done: debug_return_str(iolog_path); } -struct sudoers_match_info { - struct privilege *priv; /* matching privilege */ - struct userspec *us; /* matching userspec */ - struct cmndspec *cs; /* matching cmndspec */ -}; - static void -cb_lookup(struct userspec *us, int user_match, struct privilege *priv, - int host_match, struct cmndspec *cs, int date_match, int runas_match, - int cmnd_match, void *closure) +cb_lookup(struct sudoers_parse_tree *parse_tree, struct userspec *us, + int user_match, struct privilege *priv, int host_match, struct cmndspec *cs, + int date_match, int runas_match, int cmnd_match, void *closure) { struct sudoers_match_info *info = closure; @@ -950,7 +944,7 @@ sudoers_list(int argc, char * const argv[], const char *list_user, bool verbose) goto done; if (ISSET(sudo_mode, MODE_CHECK)) - ret = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw); + ret = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw, verbose); else ret = display_privs(snl, list_pw ? list_pw : sudo_user.pw, verbose); diff --git a/plugins/sudoers/testsudoers.c b/plugins/sudoers/testsudoers.c index f71e960dc..c9143d870 100644 --- a/plugins/sudoers/testsudoers.c +++ b/plugins/sudoers/testsudoers.c @@ -74,7 +74,7 @@ static bool cb_runas_default(const char *file, int line, int column, const union static int testsudoers_error(const char * restrict buf); static int testsudoers_output(const char * restrict buf); sudo_noreturn static void usage(void); -static void cb_lookup(struct userspec *us, int user_match, struct privilege *priv, int host_match, struct cmndspec *cs, int date_match, int runas_match, int cmnd_match, void *closure); +static void cb_lookup(struct sudoers_parse_tree *parse_tree, struct userspec *us, int user_match, struct privilege *priv, int host_match, struct cmndspec *cs, int date_match, int runas_match, int cmnd_match, void *closure); static int testsudoers_query(const struct sudo_nss *nss, struct passwd *pw); /* @@ -626,9 +626,9 @@ set_cmnd_path(const char *runchroot) } static void -cb_lookup(struct userspec *us, int user_match, struct privilege *priv, - int host_match, struct cmndspec *cs, int date_match, int runas_match, - int cmnd_match, void *closure) +cb_lookup(struct sudoers_parse_tree *parse_tree, struct userspec *us, + int user_match, struct privilege *priv, int host_match, struct cmndspec *cs, + int date_match, int runas_match, int cmnd_match, void *closure) { static struct privilege *prev_priv; struct sudo_lbuf lbuf;