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.
This commit is contained in:
Todd C. Miller
2023-08-09 10:16:10 -06:00
parent f6291bf83e
commit 60eef27e6d
6 changed files with 53 additions and 35 deletions

View File

@@ -537,7 +537,7 @@ bad:
static int static int
display_cmnd_check(struct sudoers_parse_tree *parse_tree, struct passwd *pw, 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; int host_match, runas_match, cmnd_match = UNSPEC;
char *saved_user_cmnd, *saved_user_base; 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) { if (runas_match == ALLOW) {
cmnd_match = cmnd_matches(parse_tree, cs->cmnd, cmnd_match = cmnd_matches(parse_tree, cs->cmnd,
cs->runchroot, NULL); 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; goto done;
}
} }
} }
} }
@@ -594,8 +599,10 @@ done:
* Returns true if the command is allowed, false if not or -1 on error. * Returns true if the command is allowed, false if not or -1 on error.
*/ */
int 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; struct sudo_nss *nss;
int m, match = UNSPEC; int m, match = UNSPEC;
int ret = false; 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. */ /* Iterate over each source, checking for the command. */
time(&now); time(&now);
sudo_lbuf_init(&lbuf, output, 0, NULL, 0);
TAILQ_FOREACH(nss, snl, entries) { TAILQ_FOREACH(nss, snl, entries) {
if (nss->query(nss, pw) == -1) { if (nss->query(nss, pw) == -1) {
/* The query function should have printed an error message. */ /* The query function should have printed an error message. */
debug_return_int(-1); 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) if (m != UNSPEC)
match = m; match = m;
@@ -618,9 +626,17 @@ display_cmnd(struct sudo_nss_list *snl, struct passwd *pw)
break; break;
} }
if (match == ALLOW) { 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 : ""); 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); debug_return_int(ret);
} }

View File

@@ -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); int user_match = userlist_matches(nss->parse_tree, pw, &us->users);
if (user_match != ALLOW) { if (user_match != ALLOW) {
if (callback != NULL && user_match != UNSPEC) { if (callback != NULL && user_match != UNSPEC) {
callback(us, user_match, NULL, UNSPEC, NULL, UNSPEC, callback(nss->parse_tree, us, user_match, NULL, UNSPEC,
UNSPEC, UNSPEC, cb_data); NULL, UNSPEC, UNSPEC, UNSPEC, cb_data);
} }
continue; continue;
} }
@@ -110,8 +110,8 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, time_t now,
&priv->hostlist); &priv->hostlist);
if (host_match != ALLOW) { if (host_match != ALLOW) {
if (callback != NULL) { if (callback != NULL) {
callback(us, user_match, priv, host_match, NULL, UNSPEC, callback(nss->parse_tree, us, user_match, priv,
UNSPEC, UNSPEC, cb_data); host_match, NULL, UNSPEC, UNSPEC, UNSPEC, cb_data);
} }
continue; continue;
} }
@@ -183,8 +183,9 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, time_t now,
} }
} }
if (callback != NULL) { if (callback != NULL) {
callback(us, user_match, priv, host_match, cs, callback(nss->parse_tree, us, user_match, priv,
date_match, runas_match, cmnd_match, cb_data); host_match, cs, date_match, runas_match,
cmnd_match, cb_data);
} }
if (cmnd_match != UNSPEC) { 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); int user_match = userlist_matches(nss->parse_tree, pw, &us->users);
if (user_match != ALLOW) { if (user_match != ALLOW) {
if (callback != NULL && user_match != UNSPEC) { if (callback != NULL && user_match != UNSPEC) {
callback(us, user_match, NULL, UNSPEC, NULL, UNSPEC, callback(nss->parse_tree, us, user_match, NULL, UNSPEC, NULL,
UNSPEC, UNSPEC, cb_data); UNSPEC, UNSPEC, UNSPEC, cb_data);
} }
continue; continue;
} }
@@ -256,8 +257,8 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw,
CLR(*validated, FLAG_NO_HOST); CLR(*validated, FLAG_NO_HOST);
} else { } else {
if (callback != NULL) { if (callback != NULL) {
callback(us, user_match, priv, host_match, NULL, UNSPEC, callback(nss->parse_tree, us, user_match, priv, host_match,
UNSPEC, UNSPEC, cb_data); NULL, UNSPEC, UNSPEC, UNSPEC, cb_data);
} }
continue; continue;
} }
@@ -283,8 +284,8 @@ sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw,
} }
} }
if (callback != NULL) { if (callback != NULL) {
callback(us, user_match, priv, host_match, cs, date_match, callback(nss->parse_tree, us, user_match, priv, host_match,
runas_match, cmnd_match, cb_data); cs, date_match, runas_match, cmnd_match, cb_data);
} }
if (cmnd_match != UNSPEC) { if (cmnd_match != UNSPEC) {

View File

@@ -298,6 +298,13 @@ struct defaults {
int column; /* column number of Defaults entry */ 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. * Parsed sudoers policy.
*/ */
@@ -324,7 +331,7 @@ struct cmnd_info {
/* /*
* Optional callback for sudoers_lookup(). * 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(). * 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 */ /* display.c */
int display_privs(struct sudo_nss_list *snl, struct passwd *pw, bool verbose); 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 */ /* parse_ldif.c */
bool sudoers_parse_ldif(struct sudoers_parse_tree *parse_tree, FILE *fp, const char *sudoers_base, bool store_options); bool sudoers_parse_ldif(struct sudoers_parse_tree *parse_tree, FILE *fp, const char *sudoers_base, bool store_options);

View File

@@ -815,7 +815,7 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, time_t now,
/* STUB */ /* STUB */
int 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; return true;
} }

View File

@@ -325,16 +325,10 @@ done:
debug_return_str(iolog_path); 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 static void
cb_lookup(struct userspec *us, int user_match, struct privilege *priv, cb_lookup(struct sudoers_parse_tree *parse_tree, struct userspec *us,
int host_match, struct cmndspec *cs, int date_match, int runas_match, int user_match, struct privilege *priv, int host_match, struct cmndspec *cs,
int cmnd_match, void *closure) int date_match, int runas_match, int cmnd_match, void *closure)
{ {
struct sudoers_match_info *info = 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; goto done;
if (ISSET(sudo_mode, MODE_CHECK)) 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 else
ret = display_privs(snl, list_pw ? list_pw : sudo_user.pw, verbose); ret = display_privs(snl, list_pw ? list_pw : sudo_user.pw, verbose);

View File

@@ -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_error(const char * restrict buf);
static int testsudoers_output(const char * restrict buf); static int testsudoers_output(const char * restrict buf);
sudo_noreturn static void usage(void); 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); static int testsudoers_query(const struct sudo_nss *nss, struct passwd *pw);
/* /*
@@ -626,9 +626,9 @@ set_cmnd_path(const char *runchroot)
} }
static void static void
cb_lookup(struct userspec *us, int user_match, struct privilege *priv, cb_lookup(struct sudoers_parse_tree *parse_tree, struct userspec *us,
int host_match, struct cmndspec *cs, int date_match, int runas_match, int user_match, struct privilege *priv, int host_match, struct cmndspec *cs,
int cmnd_match, void *closure) int date_match, int runas_match, int cmnd_match, void *closure)
{ {
static struct privilege *prev_priv; static struct privilege *prev_priv;
struct sudo_lbuf lbuf; struct sudo_lbuf lbuf;