From fa924d09bc9e3c8c2bb2fefa8ac76c939374a098 Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Wed, 20 Feb 2013 15:09:21 -0500 Subject: [PATCH] Make sudoers file long list output better match the format used by ldap sudoers. Tags are now converted to options and there is a single command per line. --- plugins/sudoers/parse.c | 129 ++++++++++++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 32 deletions(-) diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c index d0ab7a2c8..40479c58d 100644 --- a/plugins/sudoers/parse.c +++ b/plugins/sudoers/parse.c @@ -47,7 +47,7 @@ #include /* Characters that must be quoted in sudoers */ -#define SUDOERS_QUOTED ":\\,=#\"" +#define SUDOERS_QUOTED ":\\,=#\"" /* sudoers nsswitch routines */ struct sudo_nss sudo_nss_file = { @@ -75,8 +75,10 @@ extern bool parse_error; /* * Local prototypes. */ -static void print_member(struct lbuf *, char *, int, int, int); -static int display_bound_defaults(int, struct lbuf *); +static int display_bound_defaults(int dtype, struct lbuf *lbuf); +static void print_member(struct lbuf *lbuf, struct member *m, int alias_type); +static void print_member2(struct lbuf *lbuf, struct member *m, + const char *separator, int alias_type); int sudo_file_open(struct sudo_nss *nss) @@ -289,14 +291,16 @@ sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag) debug_return_int(validated); } +#define TAG_SET(tt) \ + ((tt) != UNSPEC && (tt) != IMPLIED) + #define TAG_CHANGED(t) \ - (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t) + (TAG_SET(cs->tags.t) && cs->tags.t != tags->t) static void sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags, struct lbuf *lbuf) { - struct member *m; debug_decl(sudo_file_append_cmnd, SUDO_DEBUG_NSS) #ifdef HAVE_PRIV_SET @@ -331,9 +335,7 @@ sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags, lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " : "NOLOG_OUTPUT: "); tags->log_output = cs->tags.log_output; } - m = cs->cmnd; - print_member(lbuf, m->name, m->type, m->negated, - CMNDALIAS); + print_member(lbuf, cs->cmnd, CMNDALIAS); debug_return; } @@ -368,8 +370,7 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us, tq_foreach_fwd(&cs->runasuserlist, m) { if (m != tq_first(&cs->runasuserlist)) lbuf_append(lbuf, ", "); - print_member(lbuf, m->name, m->type, m->negated, - RUNASALIAS); + print_member(lbuf, m, RUNASALIAS); } } else if (tq_empty(&cs->runasgrouplist)) { lbuf_append(lbuf, "%s", def_runas_default); @@ -381,8 +382,7 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us, tq_foreach_fwd(&cs->runasgrouplist, m) { if (m != tq_first(&cs->runasgrouplist)) lbuf_append(lbuf, ", "); - print_member(lbuf, m->name, m->type, m->negated, - RUNASALIAS); + print_member(lbuf, m, RUNASALIAS); } } lbuf_append(lbuf, ") "); @@ -403,6 +403,40 @@ sudo_file_display_priv_short(struct passwd *pw, struct userspec *us, debug_return_int(nfound); } +#define TAGS_CHANGED(ot, nt) \ + ((TAG_SET((nt).setenv) && (nt).setenv != (ot).setenv) || \ + (TAG_SET((nt).noexec) && (nt).noexec != (ot).noexec) || \ + (TAG_SET((nt).nopasswd) && (nt).nopasswd != (ot).nopasswd) || \ + (TAG_SET((nt).log_input) && (nt).log_input != (ot).log_input) || \ + (TAG_SET((nt).log_output) && (nt).log_output != (ot).log_output)) + +/* + * Compare the current cmndspec with the previous one to determine + * whether we need to start a new long entry for "sudo -ll". + * Returns true if we should start a new long entry, else false. + */ +static bool +new_long_entry(struct cmndspec *cs, struct cmndspec *prev_cs) +{ + if (prev_cs == NULL) + return true; + if (RUNAS_CHANGED(cs, prev_cs) || TAGS_CHANGED(cs->tags, prev_cs->tags)) + return true; +#ifdef HAVE_PRIV_SET + if (cs->privs && (!prev_cs->privs || strcmp(cs->privs, prev_cs->privs) != 0) + return true; + if (cs->limitprivs && (!prev_cs->limitprivs || strcmp(cs->limitprivs, prev_cs->limitprivs) != 0) + return true; +#endif /* HAVE_PRIV_SET */ +#ifdef HAVE_SELINUX + if (cs->role && (!prev_cs->role || strcmp(cs->role, prev_cs->role) != 0) + return true; + if (cs->type && (!prev_cs->type || strcmp(cs->type, prev_cs->type) != 0) + return true; +#endif /* HAVE_SELINUX */ + return false; +} + static int sudo_file_display_priv_long(struct passwd *pw, struct userspec *us, struct lbuf *lbuf) @@ -410,23 +444,22 @@ sudo_file_display_priv_long(struct passwd *pw, struct userspec *us, struct cmndspec *cs, *prev_cs; struct member *m; struct privilege *priv; - struct cmndtag tags; - int nfound = 0; + int nfound = 0, olen; debug_decl(sudo_file_display_priv_long, SUDO_DEBUG_NSS) tq_foreach_fwd(&us->privileges, priv) { if (hostlist_matches(&priv->hostlist) != ALLOW) continue; - lbuf_append(lbuf, _("\nSudoers entry:\n")); + prev_cs = NULL; tq_foreach_fwd(&priv->cmndlist, cs) { - if (RUNAS_CHANGED(cs, prev_cs)) { + if (new_long_entry(cs, prev_cs)) { + lbuf_append(lbuf, _("\nSudoers entry:\n")); lbuf_append(lbuf, _(" RunAsUsers: ")); if (!tq_empty(&cs->runasuserlist)) { tq_foreach_fwd(&cs->runasuserlist, m) { if (m != tq_first(&cs->runasuserlist)) lbuf_append(lbuf, ", "); - print_member(lbuf, m->name, m->type, m->negated, - RUNASALIAS); + print_member(lbuf, m, RUNASALIAS); } } else if (tq_empty(&cs->runasgrouplist)) { lbuf_append(lbuf, "%s", def_runas_default); @@ -439,20 +472,44 @@ sudo_file_display_priv_long(struct passwd *pw, struct userspec *us, tq_foreach_fwd(&cs->runasgrouplist, m) { if (m != tq_first(&cs->runasgrouplist)) lbuf_append(lbuf, ", "); - print_member(lbuf, m->name, m->type, m->negated, - RUNASALIAS); + print_member(lbuf, m, RUNASALIAS); } lbuf_append(lbuf, "\n"); } + olen = lbuf->len; + lbuf_append(lbuf, _(" Options: ")); + if (TAG_SET(cs->tags.setenv)) + lbuf_append(lbuf, "%ssetenv, ", cs->tags.setenv ? "" : "!"); + if (TAG_SET(cs->tags.noexec)) + lbuf_append(lbuf, "%snoexec, ", cs->tags.noexec ? "" : "!"); + if (TAG_SET(cs->tags.nopasswd)) + lbuf_append(lbuf, "%sauthenticate, ", cs->tags.nopasswd ? "!" : ""); + if (TAG_SET(cs->tags.log_input)) + lbuf_append(lbuf, "%slog_input, ", cs->tags.log_input ? "" : "!"); + if (TAG_SET(cs->tags.log_output)) + lbuf_append(lbuf, "%slog_output, ", cs->tags.log_output ? "" : "!"); + if (lbuf->buf[lbuf->len - 2] == ',') { + lbuf->len -= 2; /* remove trailing ", " */ + lbuf_append(lbuf, "\n"); + } else { + lbuf->len = olen; /* no options */ + } +#ifdef HAVE_PRIV_SET + if (cs->privs) + lbuf_append(lbuf, " Privs: %s\n", cs->privs); + if (cs->limitprivs) + lbuf_append(lbuf, " Limitprivs: %s\n", cs->limitprivs); +#endif /* HAVE_PRIV_SET */ +#ifdef HAVE_SELINUX + if (cs->role) + lbuf_append(lbuf, " Role: %s\n", cs->role); + if (cs->type) + lbuf_append(lbuf, " Type: %s\n", cs->type); +#endif /* HAVE_SELINUX */ lbuf_append(lbuf, _(" Commands:\n")); - tags.noexec = UNSPEC; - tags.setenv = UNSPEC; - tags.nopasswd = UNSPEC; - tags.log_input = UNSPEC; - tags.log_output = UNSPEC; } lbuf_append(lbuf, "\t"); - sudo_file_append_cmnd(cs, &tags, lbuf); + print_member2(lbuf, cs->cmnd, "\n\t", CMNDALIAS); lbuf_append(lbuf, "\n"); prev_cs = cs; nfound++; @@ -600,7 +657,7 @@ display_bound_defaults(int dtype, struct lbuf *lbuf) for (m = binding; m != NULL; m = m->next) { if (m != binding) lbuf_append(lbuf, ","); - print_member(lbuf, m->name, m->type, m->negated, atype); + print_member(lbuf, m, atype); lbuf_append(lbuf, " "); } } else @@ -666,7 +723,7 @@ done: */ static void _print_member(struct lbuf *lbuf, char *name, int type, int negated, - int alias_type) + const char *separator, int alias_type) { struct alias *a; struct member *m; @@ -694,9 +751,10 @@ _print_member(struct lbuf *lbuf, char *name, int type, int negated, if ((a = alias_find(name, alias_type)) != NULL) { tq_foreach_fwd(&a->members, m) { if (m != tq_first(&a->members)) - lbuf_append(lbuf, ", "); + lbuf_append(lbuf, separator); _print_member(lbuf, m->name, m->type, - negated ? !m->negated : m->negated, alias_type); + negated ? !m->negated : m->negated, separator, + alias_type); } break; } @@ -709,9 +767,16 @@ _print_member(struct lbuf *lbuf, char *name, int type, int negated, } static void -print_member(struct lbuf *lbuf, char *name, int type, int negated, +print_member(struct lbuf *lbuf, struct member *m, int alias_type) +{ + alias_seqno++; + _print_member(lbuf, m->name, m->type, m->negated, ", ", alias_type); +} + +static void +print_member2(struct lbuf *lbuf, struct member *m, const char *separator, int alias_type) { alias_seqno++; - _print_member(lbuf, name, type, negated, alias_type); + _print_member(lbuf, m->name, m->type, m->negated, separator, alias_type); } -- 2.40.0