From 1e5af355642ee3b4940778b8055556273cf94d64 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Sun, 5 Aug 2018 07:17:34 -0600 Subject: [PATCH] Refactor code to convert defaults to tags and do conversion on output for "sudo -l". Remove the short_list (was long_list) global in favor of a verbose argument. --- plugins/sudoers/fmtsudoers.c | 110 +++++++++++++++++++++++++++++------ plugins/sudoers/ldap.c | 3 +- plugins/sudoers/ldap_util.c | 41 ++++--------- plugins/sudoers/parse.c | 31 ++++++---- plugins/sudoers/parse.h | 26 ++++++++- plugins/sudoers/policy.c | 8 +-- plugins/sudoers/sssd.c | 2 +- plugins/sudoers/sudoers.c | 5 +- plugins/sudoers/sudoers.h | 3 +- 9 files changed, 153 insertions(+), 76 deletions(-) diff --git a/plugins/sudoers/fmtsudoers.c b/plugins/sudoers/fmtsudoers.c index 30d19b2a6..c297f622b 100644 --- a/plugins/sudoers/fmtsudoers.c +++ b/plugins/sudoers/fmtsudoers.c @@ -125,11 +125,77 @@ sudoers_format_member(struct sudo_lbuf *lbuf, m->negated, separator, alias_type); } +/* + * Store a defaults entry as a command tag. + */ +bool +sudoers_defaults_to_tags(const char *var, const char *val, int op, + struct cmndtag *tags) +{ + bool ret = true; + debug_decl(sudoers_defaults_to_tags, SUDOERS_DEBUG_UTIL) + + if (op == true || op == false) { + if (strcmp(var, "authenticate") == 0) { + tags->nopasswd = op == false; + } else if (strcmp(var, "sudoedit_follow") == 0) { + tags->follow = op == true; + } else if (strcmp(var, "log_input") == 0) { + tags->log_input = op == true; + } else if (strcmp(var, "log_output") == 0) { + tags->log_output = op == true; + } else if (strcmp(var, "noexec") == 0) { + tags->noexec = op == true; + } else if (strcmp(var, "setenv") == 0) { + tags->setenv = op == true; + } else if (strcmp(var, "mail_all_cmnds") == 0 || + strcmp(var, "mail_always") == 0 || + strcmp(var, "mail_no_perms") == 0) { + tags->send_mail = op == true; + } else { + ret = false; + } + } else { + ret = false; + } + debug_return_bool(ret); +} + +/* + * Convert a defaults list to command tags. + */ +bool +sudoers_defaults_list_to_tags(struct defaults_list *defs, struct cmndtag *tags) +{ + bool ret = true; + struct defaults *d; + debug_decl(sudoers_defaults_list_to_tags, SUDOERS_DEBUG_UTIL) + + TAGS_INIT(*tags); + if (defs != NULL) { + TAILQ_FOREACH(d, defs, entries) { + if (!sudoers_defaults_to_tags(d->var, d->val, d->op, tags)) { + if (d->val != NULL) { + sudo_debug_printf(SUDO_DEBUG_WARN, + "unable to convert defaults to tag: %s%s%s", d->var, + d->op == '+' ? "+=" : d->op == '-' ? "-=" : "=", d->val); + } else { + sudo_debug_printf(SUDO_DEBUG_WARN, + "unable to convert defaults to tag: %s%s%s", + d->op == false ? "!" : "", d->var, ""); + } + ret = false; + } + } + } + debug_return_bool(ret); +} + #define FIELD_CHANGED(ocs, ncs, fld) \ ((ocs) == NULL || (ncs)->fld != (ocs)->fld) -#define TAG_CHANGED(ocs, ncs, tt) \ - (TAG_SET((ncs)->tags.tt) && FIELD_CHANGED(ocs, ncs, tags.tt)) +#define TAG_CHANGED(ocs, ncs, t, tt) \ + (TAG_SET((t).tt) && FIELD_CHANGED(ocs, ncs, tags.tt)) /* * Write a cmndspec to lbuf in sudoers format. @@ -137,10 +203,13 @@ sudoers_format_member(struct sudo_lbuf *lbuf, bool sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct sudoers_parse_tree *parse_tree, struct cmndspec *cs, - struct cmndspec *prev_cs, bool expand_aliases) + struct cmndspec *prev_cs, struct cmndtag tags, bool expand_aliases) { debug_decl(sudoers_format_cmndspec, SUDOERS_DEBUG_UTIL) + /* Merge privilege-level tags with cmndspec tags. */ + TAGS_MERGE(tags, cs->tags); + #ifdef HAVE_PRIV_SET if (cs->privs != NULL && FIELD_CHANGED(prev_cs, cs, privs)) sudo_lbuf_append(lbuf, "PRIVS=\"%s\" ", cs->privs); @@ -174,20 +243,20 @@ sudoers_format_cmndspec(struct sudo_lbuf *lbuf, tm->tm_hour, tm->tm_min, tm->tm_sec); sudo_lbuf_append(lbuf, "NOTAFTER=%s ", buf); } - if (TAG_CHANGED(prev_cs, cs, setenv)) - sudo_lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " : "NOSETENV: "); - if (TAG_CHANGED(prev_cs, cs, noexec)) - sudo_lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " : "EXEC: "); - if (TAG_CHANGED(prev_cs, cs, nopasswd)) - sudo_lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " : "PASSWD: "); - if (TAG_CHANGED(prev_cs, cs, log_input)) - sudo_lbuf_append(lbuf, cs->tags.log_input ? "LOG_INPUT: " : "NOLOG_INPUT: "); - if (TAG_CHANGED(prev_cs, cs, log_output)) - sudo_lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " : "NOLOG_OUTPUT: "); - if (TAG_CHANGED(prev_cs, cs, send_mail)) - sudo_lbuf_append(lbuf, cs->tags.send_mail ? "MAIL: " : "NOMAIL: "); - if (TAG_CHANGED(prev_cs, cs, follow)) - sudo_lbuf_append(lbuf, cs->tags.follow ? "FOLLOW: " : "NOFOLLOW: "); + if (TAG_CHANGED(prev_cs, cs, tags, setenv)) + sudo_lbuf_append(lbuf, tags.setenv ? "SETENV: " : "NOSETENV: "); + if (TAG_CHANGED(prev_cs, cs, tags, noexec)) + sudo_lbuf_append(lbuf, tags.noexec ? "NOEXEC: " : "EXEC: "); + if (TAG_CHANGED(prev_cs, cs, tags, nopasswd)) + sudo_lbuf_append(lbuf, tags.nopasswd ? "NOPASSWD: " : "PASSWD: "); + if (TAG_CHANGED(prev_cs, cs, tags, log_input)) + sudo_lbuf_append(lbuf, tags.log_input ? "LOG_INPUT: " : "NOLOG_INPUT: "); + if (TAG_CHANGED(prev_cs, cs, tags, log_output)) + sudo_lbuf_append(lbuf, tags.log_output ? "LOG_OUTPUT: " : "NOLOG_OUTPUT: "); + if (TAG_CHANGED(prev_cs, cs, tags, send_mail)) + sudo_lbuf_append(lbuf, tags.send_mail ? "MAIL: " : "NOMAIL: "); + if (TAG_CHANGED(prev_cs, cs, tags, follow)) + sudo_lbuf_append(lbuf, tags.follow ? "FOLLOW: " : "NOFOLLOW: "); sudoers_format_member(lbuf, parse_tree, cs->cmnd, ", ", expand_aliases ? CMNDALIAS : UNSPEC); debug_return_bool(!sudo_lbuf_error(lbuf)); @@ -202,9 +271,13 @@ sudoers_format_privilege(struct sudo_lbuf *lbuf, bool expand_aliases) { struct cmndspec *cs, *prev_cs; + struct cmndtag tags; struct member *m; debug_decl(sudoers_format_privilege, SUDOERS_DEBUG_UTIL) + /* Convert per-privilege defaults to tags. */ + sudoers_defaults_list_to_tags(&priv->defaults, &tags); + /* Print hosts list. */ TAILQ_FOREACH(m, &priv->hostlist, entries) { if (m != TAILQ_FIRST(&priv->hostlist)) @@ -244,7 +317,8 @@ sudoers_format_privilege(struct sudo_lbuf *lbuf, } else if (cs != TAILQ_FIRST(&priv->cmndlist)) { sudo_lbuf_append(lbuf, ", "); } - sudoers_format_cmndspec(lbuf, parse_tree, cs, prev_cs, expand_aliases); + sudoers_format_cmndspec(lbuf, parse_tree, cs, prev_cs, tags, + expand_aliases); prev_cs = cs; } diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index fe45b8f5e..8d2b778b0 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -1196,8 +1196,7 @@ ldap_to_sudoers(LDAP *ld, struct ldap_result *lres, priv = sudo_ldap_role_to_priv(cn, hosts, runasusers, runasgroups, cmnds, opts, notbefore ? notbefore[0]->bv_val : NULL, - notafter ? notafter[0]->bv_val : NULL, false, !short_list, - berval_iter); + notafter ? notafter[0]->bv_val : NULL, false, true, berval_iter); cleanup: if (cn != NULL) diff --git a/plugins/sudoers/ldap_util.c b/plugins/sudoers/ldap_util.c index b2a1d2107..1e411f694 100644 --- a/plugins/sudoers/ldap_util.c +++ b/plugins/sudoers/ldap_util.c @@ -439,37 +439,16 @@ sudo_ldap_role_to_priv(const char *cn, void *hosts, void *runasusers, } } else { /* Convert to tags. */ - bool handled = true; - - if (op == true || op == false) { - if (strcmp(var, "authenticate") == 0) { - cmndspec->tags.nopasswd = op == false; - } else if (strcmp(var, "sudoedit_follow") == 0) { - cmndspec->tags.follow = op == true; - } else if (strcmp(var, "log_input") == 0) { - cmndspec->tags.log_input = op == true; - } else if (strcmp(var, "log_output") == 0) { - cmndspec->tags.log_output = op == true; - } else if (strcmp(var, "noexec") == 0) { - cmndspec->tags.noexec = op == true; - } else if (strcmp(var, "setenv") == 0) { - cmndspec->tags.setenv = op == true; - } else if (strcmp(var, "mail_all_cmnds") == 0 || - strcmp(var, "mail_always") == 0 || - strcmp(var, "mail_no_perms") == 0) { - cmndspec->tags.send_mail = op == true; - } else { - handled = false; - } - } else { - handled = false; - } - if (!handled && warnings) { - /* XXX - callback to process unsupported options. */ - if (val != NULL) { - sudo_warnx(U_("unable to convert sudoOption: %s%s%s"), var, op == '+' ? "+=" : op == '-' ? "-=" : "=", val); - } else { - sudo_warnx(U_("unable to convert sudoOption: %s%s%s"), op == false ? "!" : "", var, ""); + bool converted = sudoers_defaults_to_tags(var, val, op, + &cmndspec->tags); + if (!converted) { + if (warnings) { + /* XXX - callback to process unsupported options. */ + if (val != NULL) { + sudo_warnx(U_("unable to convert sudoOption: %s%s%s"), var, op == '+' ? "+=" : op == '-' ? "-=" : "=", val); + } else { + sudo_warnx(U_("unable to convert sudoOption: %s%s%s"), op == false ? "!" : "", var, ""); + } } continue; } diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c index 537b1f60a..438449a93 100644 --- a/plugins/sudoers/parse.c +++ b/plugins/sudoers/parse.c @@ -327,19 +327,23 @@ static int display_priv_short(struct sudoers_parse_tree *parse_tree, struct passwd *pw, struct userspec *us, struct sudo_lbuf *lbuf) { - struct cmndspec *cs, *prev_cs; - struct member *m; struct privilege *priv; int nfound = 0; debug_decl(display_priv_short, SUDOERS_DEBUG_PARSER) TAILQ_FOREACH(priv, &us->privileges, entries) { + struct cmndspec *cs, *prev_cs = NULL; + struct cmndtag tags; + if (hostlist_matches(parse_tree, pw, &priv->hostlist) != ALLOW) continue; - prev_cs = NULL; + + sudoers_defaults_list_to_tags(&priv->defaults, &tags); TAILQ_FOREACH(cs, &priv->cmndlist, entries) { /* Start a new line if RunAs changes. */ if (prev_cs == NULL || RUNAS_CHANGED(cs, prev_cs)) { + struct member *m; + if (cs != TAILQ_FIRST(&priv->cmndlist)) sudo_lbuf_append(lbuf, "\n"); sudo_lbuf_append(lbuf, " ("); @@ -368,7 +372,7 @@ display_priv_short(struct sudoers_parse_tree *parse_tree, struct passwd *pw, } else if (cs != TAILQ_FIRST(&priv->cmndlist)) { sudo_lbuf_append(lbuf, ", "); } - sudoers_format_cmndspec(lbuf, parse_tree, cs, prev_cs, true); + sudoers_format_cmndspec(lbuf, parse_tree, cs, prev_cs, tags, true); prev_cs = cs; nfound++; } @@ -416,12 +420,13 @@ static int display_priv_long(struct sudoers_parse_tree *parse_tree, struct passwd *pw, struct userspec *us, struct sudo_lbuf *lbuf) { - struct cmndspec *cs, *prev_cs; struct privilege *priv; - int nfound = 0, olen; + int nfound = 0; debug_decl(display_priv_long, SUDOERS_DEBUG_PARSER) TAILQ_FOREACH(priv, &us->privileges, entries) { + struct cmndspec *cs, *prev_cs; + if (hostlist_matches(parse_tree, pw, &priv->hostlist) != ALLOW) continue; prev_cs = NULL; @@ -430,6 +435,8 @@ display_priv_long(struct sudoers_parse_tree *parse_tree, struct passwd *pw, struct member *m; if (new_long_entry(cs, prev_cs)) { + int olen; + if (priv->ldap_role != NULL) { sudo_lbuf_append(lbuf, _("\nLDAP Role: %s\n"), priv->ldap_role); @@ -530,7 +537,7 @@ display_priv_long(struct sudoers_parse_tree *parse_tree, struct passwd *pw, static int sudo_display_userspecs(struct sudoers_parse_tree *parse_tree, struct passwd *pw, - struct sudo_lbuf *lbuf) + struct sudo_lbuf *lbuf, bool verbose) { struct userspec *us; int nfound = 0; @@ -540,10 +547,10 @@ sudo_display_userspecs(struct sudoers_parse_tree *parse_tree, struct passwd *pw, if (userlist_matches(parse_tree, pw, &us->users) != ALLOW) continue; - if (short_list) - nfound += display_priv_short(parse_tree, pw, us, lbuf); - else + if (verbose) nfound += display_priv_long(parse_tree, pw, us, lbuf); + else + nfound += display_priv_short(parse_tree, pw, us, lbuf); } if (sudo_lbuf_error(lbuf)) debug_return_int(-1); @@ -692,7 +699,7 @@ output(const char *buf) * Returns true on success or -1 on error. */ int -display_privs(struct sudo_nss_list *snl, struct passwd *pw) +display_privs(struct sudo_nss_list *snl, struct passwd *pw, bool verbose) { struct sudo_nss *nss; struct sudo_lbuf def_buf, priv_buf; @@ -747,7 +754,7 @@ display_privs(struct sudo_nss_list *snl, struct passwd *pw) count = 0; TAILQ_FOREACH(nss, snl, entries) { if (nss->query(nss, pw) != -1) { - n = sudo_display_userspecs(nss->parse_tree, pw, &priv_buf); + n = sudo_display_userspecs(nss->parse_tree, pw, &priv_buf, verbose); if (n == -1) goto bad; count += n; diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h index 4d93069e7..519677edb 100644 --- a/plugins/sudoers/parse.h +++ b/plugins/sudoers/parse.h @@ -43,6 +43,26 @@ (t).setenv = UNSPEC; \ } while (0) +/* + * Copy any tags set in t2 into t, overriding the value in t. + */ +#define TAGS_MERGE(t, t2) do { \ + if ((t2).follow != UNSPEC) \ + (t).follow = (t2).follow; \ + if ((t2).log_input != UNSPEC) \ + (t).log_input = (t2).log_input; \ + if ((t2).log_output != UNSPEC) \ + (t).log_output = (t2).log_output; \ + if ((t2).noexec != UNSPEC) \ + (t).noexec = (t2).noexec; \ + if ((t2).nopasswd != UNSPEC) \ + (t).nopasswd = (t2).nopasswd; \ + if ((t2).send_mail != UNSPEC) \ + (t).send_mail = (t2).send_mail; \ + if ((t2).setenv != UNSPEC) \ + (t).setenv = (t2).setenv; \ +} while (0) + /* * Returns true if any tag are not UNSPEC, else false. */ @@ -323,17 +343,19 @@ const char *digest_type_to_name(int digest_type); /* parse.c */ struct sudo_nss_list; int sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated, int pwflag); -int display_privs(struct sudo_nss_list *snl, struct passwd *pw); +int display_privs(struct sudo_nss_list *snl, struct passwd *pw, bool verbose); int display_cmnd(struct sudo_nss_list *snl, struct passwd *pw); /* fmtsudoers.c */ struct sudo_lbuf; -bool sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct sudoers_parse_tree *parse_tree, struct cmndspec *cs, struct cmndspec *prev_cs, bool expand_aliases); +bool sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct sudoers_parse_tree *parse_tree, struct cmndspec *cs, struct cmndspec *prev_cs, struct cmndtag tags, bool expand_aliases); bool sudoers_format_default(struct sudo_lbuf *lbuf, struct defaults *d); bool sudoers_format_default_line(struct sudo_lbuf *lbuf, struct sudoers_parse_tree *parse_tree, struct defaults *d, struct defaults **next, bool expand_aliases); bool sudoers_format_member(struct sudo_lbuf *lbuf, struct sudoers_parse_tree *parse_tree, struct member *m, const char *separator, int alias_type); bool sudoers_format_privilege(struct sudo_lbuf *lbuf, struct sudoers_parse_tree *parse_tree, struct privilege *priv, bool expand_aliases); bool sudoers_format_userspec(struct sudo_lbuf *lbuf, struct sudoers_parse_tree *parse_tree, struct userspec *us, bool expand_aliases); bool sudoers_format_userspecs(struct sudo_lbuf *lbuf, struct sudoers_parse_tree *parse_tree, const char *separator, bool expand_aliases, bool flush); +bool sudoers_defaults_to_tags(const char *var, const char *val, int op, struct cmndtag *tags); +bool sudoers_defaults_list_to_tags(struct defaults_list *defs, struct cmndtag *tags); #endif /* SUDOERS_PARSE_H */ diff --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c index ca8e1c8bd..afadd0e59 100644 --- a/plugins/sudoers/policy.c +++ b/plugins/sudoers/policy.c @@ -858,7 +858,7 @@ sudoers_policy_check(int argc, char * const argv[], char *env_add[], exec_args.envp = user_env_out; exec_args.info = command_infop; - ret = sudoers_policy_main(argc, argv, 0, env_add, &exec_args); + ret = sudoers_policy_main(argc, argv, 0, env_add, false, &exec_args); if (ret == true && sudo_version >= SUDO_API_MKVERSION(1, 3)) { /* Unset close function if we don't need it to avoid extra process. */ if (!def_log_input && !def_log_output && !def_use_pty && @@ -876,7 +876,7 @@ sudoers_policy_validate(void) user_cmnd = "validate"; SET(sudo_mode, MODE_VALIDATE); - debug_return_int(sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL)); + debug_return_int(sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, false, NULL)); } static void @@ -904,8 +904,6 @@ sudoers_policy_list(int argc, char * const argv[], int verbose, SET(sudo_mode, MODE_CHECK); else SET(sudo_mode, MODE_LIST); - if (!verbose) - short_list = true; if (list_user) { list_pw = sudo_getpwnam(list_user); if (list_pw == NULL) { @@ -913,7 +911,7 @@ sudoers_policy_list(int argc, char * const argv[], int verbose, debug_return_int(-1); } } - ret = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL); + ret = sudoers_policy_main(argc, argv, I_LISTPW, NULL, verbose, NULL); if (list_user) { sudo_pw_delref(list_pw); list_pw = NULL; diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c index 1ca8b6848..5b2fbb78f 100644 --- a/plugins/sudoers/sssd.c +++ b/plugins/sudoers/sssd.c @@ -356,7 +356,7 @@ sss_to_sudoers(struct sudo_sss_handle *handle, priv = sudo_ldap_role_to_priv(cn, hosts, runasusers, runasgroups, cmnds, opts, notbefore ? notbefore[0] : NULL, - notafter ? notafter[0] : NULL, false, !short_list, val_array_iter); + notafter ? notafter[0] : NULL, false, true, val_array_iter); cleanup: if (cn_array != NULL) diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 8d39140d6..e57ee31c6 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -85,7 +85,6 @@ static bool tty_present(void); */ struct sudo_user sudo_user; struct passwd *list_pw; -bool short_list; uid_t timestamp_uid; gid_t timestamp_gid; #ifdef HAVE_BSD_AUTH_H @@ -226,7 +225,7 @@ cleanup: int sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], - void *closure) + bool verbose, void *closure) { char **edit_argv = NULL; char *iolog_path = NULL; @@ -485,7 +484,7 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], ret = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw); break; case MODE_LIST: - ret = display_privs(snl, list_pw ? list_pw : sudo_user.pw); + ret = display_privs(snl, list_pw ? list_pw : sudo_user.pw, verbose); break; case MODE_VALIDATE: /* Nothing to do. */ diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index a169f2954..81b8594c9 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -373,11 +373,10 @@ bool matches_env_pattern(const char *pattern, const char *var, bool *full_match) /* sudoers.c */ FILE *open_sudoers(const char *, bool, bool *); int sudoers_policy_init(void *info, char * const envp[]); -int sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], void *closure); +int sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], bool verbose, void *closure); void sudoers_cleanup(void); extern struct sudo_user sudo_user; extern struct passwd *list_pw; -extern bool short_list; extern int sudo_mode; extern uid_t timestamp_uid; extern gid_t timestamp_gid; -- 2.40.0