From 70d519c8ad4123e131de7e48e135dcec1e35c5da Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Thu, 26 Jul 2018 15:12:33 -0600 Subject: [PATCH] o Move userspecs, defaults and aliases into a new struct sudoers_parse_tree. o The parse tree is now passed to the alias, match and defaults functions. o The nss API has been changed so that the nss parse() function returns a pointer to a struct sudoers_parse_tree which will be filled in by the getdefs() and query() functions. --- plugins/sudoers/alias.c | 184 ++++++++++---------- plugins/sudoers/cvtsudoers.c | 58 ++++--- plugins/sudoers/cvtsudoers_json.c | 12 +- plugins/sudoers/cvtsudoers_ldif.c | 16 +- plugins/sudoers/defaults.c | 27 +-- plugins/sudoers/defaults.h | 8 +- plugins/sudoers/file.c | 52 ++---- plugins/sudoers/fmtsudoers.c | 61 ++++--- plugins/sudoers/gram.c | 274 +++++++++++++++++------------- plugins/sudoers/gram.y | 68 ++++++-- plugins/sudoers/ldap.c | 79 ++++----- plugins/sudoers/match.c | 66 ++++--- plugins/sudoers/parse.c | 148 ++++++++-------- plugins/sudoers/parse.h | 58 ++++--- plugins/sudoers/sssd.c | 86 +++++----- plugins/sudoers/sudo_nss.h | 11 +- plugins/sudoers/sudoers.c | 29 ++-- plugins/sudoers/testsudoers.c | 27 +-- plugins/sudoers/visudo.c | 26 +-- 19 files changed, 693 insertions(+), 597 deletions(-) diff --git a/plugins/sudoers/alias.c b/plugins/sudoers/alias.c index b15150d72..c66241159 100644 --- a/plugins/sudoers/alias.c +++ b/plugins/sudoers/alias.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005, 2007-2016 + * Copyright (c) 2004-2005, 2007-2018 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -35,16 +35,11 @@ #include "redblack.h" #include -/* - * Globals - */ -static struct rbtree *aliases; - /* * Comparison function for the red-black tree. * Aliases are sorted by name with the type used as a tie-breaker. */ -int +static int alias_compare(const void *v1, const void *v2) { const struct alias *a1 = (const struct alias *)v1; @@ -68,16 +63,19 @@ alias_compare(const void *v1, const void *v2) * alias to mark it as unused. */ struct alias * -alias_get(const char *name, int type) +alias_get(struct sudoers_parse_tree *parse_tree, const char *name, int type) { struct alias key; struct rbnode *node; struct alias *a = NULL; debug_decl(alias_get, SUDOERS_DEBUG_ALIAS) + if (parse_tree->aliases == NULL) + debug_return_ptr(NULL); + key.name = (char *)name; key.type = type; - if ((node = rbfind(aliases, &key)) != NULL) { + if ((node = rbfind(parse_tree->aliases, &key)) != NULL) { /* * Check whether this alias is already in use. * If so, we've detected a loop. If not, set the flag, @@ -112,12 +110,20 @@ alias_put(struct alias *a) * Returns NULL on success and an error string on failure. */ const char * -alias_add(char *name, int type, char *file, int lineno, struct member *members) +alias_add(struct sudoers_parse_tree *parse_tree, char *name, int type, + char *file, int lineno, struct member *members) { static char errbuf[512]; struct alias *a; debug_decl(alias_add, SUDOERS_DEBUG_ALIAS) + if (parse_tree->aliases == NULL) { + if ((parse_tree->aliases = alloc_aliases()) == NULL) { + strlcpy(errbuf, N_("unable to allocate memory"), sizeof(errbuf)); + debug_return_str(errbuf); + } + } + a = calloc(1, sizeof(*a)); if (a == NULL) { strlcpy(errbuf, N_("unable to allocate memory"), sizeof(errbuf)); @@ -129,9 +135,10 @@ alias_add(char *name, int type, char *file, int lineno, struct member *members) a->file = rcstr_addref(file); a->lineno = lineno; HLTQ_TO_TAILQ(&a->members, members, entries); - switch (rbinsert(aliases, a, NULL)) { + switch (rbinsert(parse_tree->aliases, a, NULL)) { case 1: - snprintf(errbuf, sizeof(errbuf), N_("Alias \"%s\" already defined"), name); + snprintf(errbuf, sizeof(errbuf), N_("Alias \"%s\" already defined"), + name); alias_free(a); debug_return_str(errbuf); case -1: @@ -146,37 +153,26 @@ alias_add(char *name, int type, char *file, int lineno, struct member *members) * Apply a function to each alias entry and pass in a cookie. */ void -alias_apply(int (*func)(void *, void *), void *cookie) +alias_apply(struct sudoers_parse_tree *parse_tree, int (*func)(void *, void *), + void *cookie) { debug_decl(alias_apply, SUDOERS_DEBUG_ALIAS) - rbapply(aliases, func, cookie, inorder); + if (parse_tree->aliases != NULL) + rbapply(parse_tree->aliases, func, cookie, inorder); debug_return; } /* - * Returns true if there are no aliases, else false. + * Returns true if there are no aliases in the parse_tree, else false. */ bool -no_aliases(void) +no_aliases(struct sudoers_parse_tree *parse_tree) { debug_decl(no_aliases, SUDOERS_DEBUG_ALIAS) - debug_return_bool(rbisempty(aliases)); -} - -/* - * Replace the aliases tree with a new one, returns the old. - */ -struct rbtree * -replace_aliases(struct rbtree *new_aliases) -{ - struct rbtree *old_aliases = aliases; - debug_decl(replace_aliases, SUDOERS_DEBUG_ALIAS) - - aliases = new_aliases; - - debug_return_ptr(old_aliases); + debug_return_bool(parse_tree->aliases == NULL || + rbisempty(parse_tree->aliases)); } /* @@ -202,31 +198,37 @@ alias_free(void *v) * Find the named alias, remove it from the tree and return it. */ struct alias * -alias_remove(char *name, int type) +alias_remove(struct sudoers_parse_tree *parse_tree, char *name, int type) { struct rbnode *node; struct alias key; debug_decl(alias_remove, SUDOERS_DEBUG_ALIAS) - key.name = name; - key.type = type; - if ((node = rbfind(aliases, &key)) == NULL) { - errno = ENOENT; - return NULL; + if (parse_tree->aliases != NULL) { + key.name = name; + key.type = type; + if ((node = rbfind(parse_tree->aliases, &key)) != NULL) + debug_return_ptr(rbdelete(parse_tree->aliases, node)); } - debug_return_ptr(rbdelete(aliases, node)); + errno = ENOENT; + debug_return_ptr(NULL); } -bool -init_aliases(void) +struct rbtree * +alloc_aliases(void) +{ + debug_decl(alloc_aliases, SUDOERS_DEBUG_ALIAS) + + debug_return_ptr(rbcreate(alias_compare)); +} + +void +free_aliases(struct rbtree *aliases) { - debug_decl(init_aliases, SUDOERS_DEBUG_ALIAS) + debug_decl(free_aliases, SUDOERS_DEBUG_ALIAS) if (aliases != NULL) rbdestroy(aliases, alias_free); - aliases = rbcreate(alias_compare); - - debug_return_bool(aliases != NULL); } const char * @@ -244,17 +246,18 @@ alias_type_to_string(int alias_type) * referenced by that alias. Stores removed aliases in a freelist. */ static bool -alias_remove_recursive(char *name, int type, struct rbtree *freelist) +alias_remove_recursive(struct sudoers_parse_tree *parse_tree, char *name, + int type, struct rbtree *freelist) { struct member *m; struct alias *a; bool ret = true; debug_decl(alias_remove_recursive, SUDOERS_DEBUG_ALIAS) - if ((a = alias_remove(name, type)) != NULL) { + if ((a = alias_remove(parse_tree, name, type)) != NULL) { TAILQ_FOREACH(m, &a->members, entries) { if (m->type == ALIAS) { - if (!alias_remove_recursive(m->name, type, freelist)) + if (!alias_remove_recursive(parse_tree, m->name, type, freelist)) ret = false; } } @@ -264,81 +267,80 @@ alias_remove_recursive(char *name, int type, struct rbtree *freelist) debug_return_bool(ret); } +static int +alias_find_used_members(struct sudoers_parse_tree *parse_tree, + struct member_list *members, int atype, struct rbtree *used_aliases) +{ + struct member *m; + int errors = 0; + debug_decl(alias_find_used_members, SUDOERS_DEBUG_ALIAS) + + if (members != NULL) { + TAILQ_FOREACH(m, members, entries) { + if (m->type != ALIAS) + continue; + if (!alias_remove_recursive(parse_tree, m->name, atype, used_aliases)) + errors++; + } + } + + debug_return_int(errors); +} + /* * Move all aliases referenced by userspecs to used_aliases. */ bool -alias_find_used(struct rbtree *used_aliases) +alias_find_used(struct sudoers_parse_tree *parse_tree, struct rbtree *used_aliases) { struct privilege *priv; struct userspec *us; struct cmndspec *cs; struct defaults *d; struct member *m; - int atype, errors = 0; + int errors = 0; debug_decl(alias_find_used, SUDOERS_DEBUG_ALIAS) /* Move referenced aliases to used_aliases. */ - TAILQ_FOREACH(us, &userspecs, entries) { - TAILQ_FOREACH(m, &us->users, entries) { - if (m->type == ALIAS) { - if (!alias_remove_recursive(m->name, USERALIAS, used_aliases)) - errors++; - } - } + TAILQ_FOREACH(us, &parse_tree->userspecs, entries) { + errors += alias_find_used_members(parse_tree, &us->users, + USERALIAS, used_aliases); TAILQ_FOREACH(priv, &us->privileges, entries) { - TAILQ_FOREACH(m, &priv->hostlist, entries) { - if (m->type == ALIAS) { - if (!alias_remove_recursive(m->name, HOSTALIAS, used_aliases)) - errors++; - } - } + errors += alias_find_used_members(parse_tree, &priv->hostlist, + HOSTALIAS, used_aliases); TAILQ_FOREACH(cs, &priv->cmndlist, entries) { - if (cs->runasuserlist != NULL) { - TAILQ_FOREACH(m, cs->runasuserlist, entries) { - if (m->type == ALIAS) { - if (!alias_remove_recursive(m->name, RUNASALIAS, used_aliases)) - errors++; - } - } - } - if (cs->runasgrouplist != NULL) { - TAILQ_FOREACH(m, cs->runasgrouplist, entries) { - if (m->type == ALIAS) { - if (!alias_remove_recursive(m->name, RUNASALIAS, used_aliases)) - errors++; - } - } - } + errors += alias_find_used_members(parse_tree, cs->runasuserlist, + RUNASALIAS, used_aliases); + errors += alias_find_used_members(parse_tree, cs->runasgrouplist, + RUNASALIAS, used_aliases); if ((m = cs->cmnd)->type == ALIAS) { - if (!alias_remove_recursive(m->name, CMNDALIAS, used_aliases)) + if (!alias_remove_recursive(parse_tree, m->name, CMNDALIAS, + used_aliases)) errors++; } } } } - TAILQ_FOREACH(d, &defaults, entries) { + TAILQ_FOREACH(d, &parse_tree->defaults, entries) { switch (d->type) { case DEFAULTS_HOST: - atype = HOSTALIAS; + errors += alias_find_used_members(parse_tree, d->binding, + HOSTALIAS, used_aliases); break; case DEFAULTS_USER: - atype = USERALIAS; + errors += alias_find_used_members(parse_tree, d->binding, + USERALIAS, used_aliases); break; case DEFAULTS_RUNAS: - atype = RUNASALIAS; + errors += alias_find_used_members(parse_tree, d->binding, + RUNASALIAS, used_aliases); break; case DEFAULTS_CMND: - atype = CMNDALIAS; + errors += alias_find_used_members(parse_tree, d->binding, + CMNDALIAS, used_aliases); break; default: - continue; /* not an alias */ - } - TAILQ_FOREACH(m, d->binding, entries) { - if (m->type == ALIAS) { - if (!alias_remove_recursive(m->name, atype, used_aliases)) - errors++; - } + break; } } diff --git a/plugins/sudoers/cvtsudoers.c b/plugins/sudoers/cvtsudoers.c index f84e4a2aa..e086d7deb 100644 --- a/plugins/sudoers/cvtsudoers.c +++ b/plugins/sudoers/cvtsudoers.c @@ -703,7 +703,7 @@ userlist_matches_filter(struct member_list *users, struct cvtsudoers_config *con pw.pw_uid = (uid_t)-1; pw.pw_gid = (gid_t)-1; - if (user_matches(&pw, m) == true) + if (user_matches(&parsed_policy, &pw, m) == true) matched = true; } else { STAILQ_FOREACH(s, &filters->users, entries) { @@ -729,7 +729,7 @@ userlist_matches_filter(struct member_list *users, struct cvtsudoers_config *con if (pw == NULL) continue; - if (user_matches(pw, m) == true) + if (user_matches(&parsed_policy, pw, m) == true) matched = true; sudo_pw_delref(pw); @@ -804,7 +804,7 @@ hostlist_matches_filter(struct member_list *hostlist, struct cvtsudoers_config * /* Only need one host in the filter to match. */ /* XXX - can't use netgroup_tuple with NULL pw */ - if (host_matches(NULL, lhost, shost, m) == true) { + if (host_matches(&parsed_policy, NULL, lhost, shost, m) == true) { matched = true; break; } @@ -840,8 +840,10 @@ print_defaults_sudoers(struct sudo_lbuf *lbuf, bool expand_aliases) struct defaults *def, *next; debug_decl(print_defaults_sudoers, SUDOERS_DEBUG_UTIL) - TAILQ_FOREACH_SAFE(def, &defaults, entries, next) - sudoers_format_default_line(lbuf, def, &next, expand_aliases); + TAILQ_FOREACH_SAFE(def, &parsed_policy.defaults, entries, next) { + sudoers_format_default_line(lbuf, &parsed_policy, def, &next, + expand_aliases); + } debug_return_bool(!sudo_lbuf_error(lbuf)); } @@ -859,7 +861,7 @@ print_alias_sudoers(void *v1, void *v2) TAILQ_FOREACH(m, &a->members, entries) { if (m != TAILQ_FIRST(&a->members)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, NULL, UNSPEC); + sudoers_format_member(lbuf, &parsed_policy, m, NULL, UNSPEC); } sudo_lbuf_append(lbuf, "\n"); @@ -874,7 +876,7 @@ print_aliases_sudoers(struct sudo_lbuf *lbuf) { debug_decl(print_aliases_sudoers, SUDOERS_DEBUG_UTIL) - alias_apply(print_alias_sudoers, lbuf); + alias_apply(&parsed_policy, print_alias_sudoers, lbuf); debug_return_bool(!sudo_lbuf_error(lbuf)); } @@ -905,9 +907,9 @@ filter_userspecs(struct cvtsudoers_config *conf) * host lists. It acts more like a grep than a true filter. * In the future, we may want to add a prune option. */ - TAILQ_FOREACH_SAFE(us, &userspecs, entries, next_us) { + TAILQ_FOREACH_SAFE(us, &parsed_policy.userspecs, entries, next_us) { if (!userlist_matches_filter(&us->users, conf)) { - TAILQ_REMOVE(&userspecs, us, entries); + TAILQ_REMOVE(&parsed_policy.userspecs, us, entries); free_userspec(us); continue; } @@ -918,7 +920,7 @@ filter_userspecs(struct cvtsudoers_config *conf) } } if (TAILQ_EMPTY(&us->privileges)) { - TAILQ_REMOVE(&userspecs, us, entries); + TAILQ_REMOVE(&parsed_policy.userspecs, us, entries); free_userspec(us); continue; } @@ -942,7 +944,8 @@ alias_matches(const char *name, const char *alias_name, int alias_type) if (strcmp(name, alias_name) == 0) debug_return_bool(true); - if ((a = alias_get(alias_name, alias_type)) != NULL) { + a = alias_get(&parsed_policy, alias_name, alias_type); + if (a != NULL) { TAILQ_FOREACH(m, &a->members, entries) { if (m->type != ALIAS) continue; @@ -975,7 +978,7 @@ alias_used_by_userspecs(struct member_list *user_aliases, debug_decl(alias_used_by_userspecs, SUDOERS_DEBUG_ALIAS) /* Iterate over the policy, checking for aliases. */ - TAILQ_FOREACH_SAFE(us, &userspecs, entries, us_next) { + TAILQ_FOREACH_SAFE(us, &parsed_policy.userspecs, entries, us_next) { TAILQ_FOREACH_SAFE(m, &us->users, entries, m_next) { if (m->type == ALIAS) { /* If alias is used, remove from user_aliases and free. */ @@ -1055,13 +1058,14 @@ filter_defaults(struct cvtsudoers_config *conf) struct member_list *prev_binding = NULL; struct defaults *def, *def_next; struct member *m, *m_next; + struct alias *a; int alias_type; debug_decl(filter_defaults, SUDOERS_DEBUG_DEFAULTS) if (filters == NULL && conf->defaults == CVT_DEFAULTS_ALL) debug_return; - TAILQ_FOREACH_SAFE(def, &defaults, entries, def_next) { + TAILQ_FOREACH_SAFE(def, &parsed_policy.defaults, entries, def_next) { bool keep = true; switch (def->type) { @@ -1118,20 +1122,21 @@ filter_defaults(struct cvtsudoers_config *conf) TAILQ_INSERT_TAIL(&cmnd_aliases, m, entries); break; default: - sudo_fatalx_nodebug("unexpected alias type %d", alias_type); + sudo_fatalx_nodebug("unexpected alias type %d", + alias_type); break; } } } } - TAILQ_REMOVE(&defaults, def, entries); + TAILQ_REMOVE(&parsed_policy.defaults, def, entries); free_default(def, &prev_binding); if (prev_binding != NULL) { /* Remove and free Defaults that share the same binding. */ while (def_next != NULL && def_next->binding == prev_binding) { def = def_next; def_next = TAILQ_NEXT(def, entries); - TAILQ_REMOVE(&defaults, def, entries); + TAILQ_REMOVE(&parsed_policy.defaults, def, entries); free_default(def, &prev_binding); } } @@ -1144,22 +1149,22 @@ filter_defaults(struct cvtsudoers_config *conf) alias_used_by_userspecs(&user_aliases, &runas_aliases, &host_aliases, &cmnd_aliases); TAILQ_FOREACH_SAFE(m, &user_aliases, entries, m_next) { - struct alias *a = alias_remove(m->name, USERALIAS); + a = alias_remove(&parsed_policy, m->name, USERALIAS); alias_free(a); free_member(m); } TAILQ_FOREACH_SAFE(m, &runas_aliases, entries, m_next) { - struct alias *a = alias_remove(m->name, RUNASALIAS); + a = alias_remove(&parsed_policy, m->name, RUNASALIAS); alias_free(a); free_member(m); } TAILQ_FOREACH_SAFE(m, &host_aliases, entries, m_next) { - struct alias *a = alias_remove(m->name, HOSTALIAS); + a = alias_remove(&parsed_policy, m->name, HOSTALIAS); alias_free(a); free_member(m); } TAILQ_FOREACH_SAFE(m, &cmnd_aliases, entries, m_next) { - struct alias *a = alias_remove(m->name, CMNDALIAS); + a = alias_remove(&parsed_policy, m->name, CMNDALIAS); alias_free(a); free_member(m); } @@ -1174,20 +1179,19 @@ static void alias_remove_unused(void) { struct rbtree *used_aliases; - struct rbtree *unused_aliases; debug_decl(alias_remove_unused, SUDOERS_DEBUG_ALIAS) - used_aliases = rbcreate(alias_compare); + used_aliases = alloc_aliases(); if (used_aliases == NULL) sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); /* Move all referenced aliases to used_aliases. */ - if (!alias_find_used(used_aliases)) + if (!alias_find_used(&parsed_policy, used_aliases)) sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); /* Only unreferenced aliases are left, swap and free the unused ones. */ - unused_aliases = replace_aliases(used_aliases); - rbdestroy(unused_aliases, alias_free); + free_aliases(parsed_policy.aliases); + parsed_policy.aliases = used_aliases; debug_return; } @@ -1224,7 +1228,7 @@ alias_prune(struct cvtsudoers_config *conf) { debug_decl(alias_prune, SUDOERS_DEBUG_ALIAS) - alias_apply(alias_prune_helper, conf); + alias_apply(&parsed_policy, alias_prune_helper, conf); debug_return; } @@ -1271,7 +1275,7 @@ convert_sudoers_sudoers(const char *output_file, struct cvtsudoers_config *conf) /* Print User_Specs, separated by blank lines. */ if (!ISSET(conf->suppress, SUPPRESS_PRIVS)) { - if (!sudoers_format_userspecs(&lbuf, &userspecs, "\n", + if (!sudoers_format_userspecs(&lbuf, &parsed_policy, "\n", conf->expand_aliases, true)) { goto done; } diff --git a/plugins/sudoers/cvtsudoers_json.c b/plugins/sudoers/cvtsudoers_json.c index 556160e90..7ca59850e 100644 --- a/plugins/sudoers/cvtsudoers_json.c +++ b/plugins/sudoers/cvtsudoers_json.c @@ -475,7 +475,7 @@ print_member_json_int(FILE *fp, char *name, int type, bool negated, struct alias *a; struct member *m; - if ((a = alias_get(value.u.string, alias_type)) != NULL) { + if ((a = alias_get(&parsed_policy, value.u.string, alias_type)) != NULL) { TAILQ_FOREACH(m, &a->members, entries) { print_member_json_int(fp, m->name, m->type, negated ? !m->negated : m->negated, @@ -661,13 +661,13 @@ print_defaults_json(FILE *fp, int indent, bool expand_aliases, bool need_comma) int type; debug_decl(print_defaults_json, SUDOERS_DEBUG_UTIL) - if (TAILQ_EMPTY(&defaults)) + if (TAILQ_EMPTY(&parsed_policy.defaults)) debug_return_bool(need_comma); fprintf(fp, "%s\n%*s\"Defaults\": [\n", need_comma ? "," : "", indent, ""); indent += 4; - TAILQ_FOREACH_SAFE(def, &defaults, entries, next) { + TAILQ_FOREACH_SAFE(def, &parsed_policy.defaults, entries, next) { type = get_defaults_type(def); if (type == -1) { sudo_warnx(U_("unknown defaults entry \"%s\""), def->var); @@ -745,7 +745,7 @@ print_aliases_by_type_json(FILE *fp, int alias_type, const char *title, closure.alias_type = alias_type; closure.title = title; closure.need_comma = need_comma; - alias_apply(print_alias_json, &closure); + alias_apply(&parsed_policy, print_alias_json, &closure); if (closure.count != 0) { print_indent(fp, closure.indent); fputs("]\n", fp); @@ -1083,12 +1083,12 @@ print_userspecs_json(FILE *fp, int indent, bool expand_aliases, bool need_comma) struct userspec *us; debug_decl(print_userspecs_json, SUDOERS_DEBUG_UTIL) - if (TAILQ_EMPTY(&userspecs)) + if (TAILQ_EMPTY(&parsed_policy.userspecs)) debug_return_bool(need_comma); fprintf(fp, "%s\n%*s\"User_Specs\": [\n", need_comma ? "," : "", indent, ""); indent += 4; - TAILQ_FOREACH(us, &userspecs, entries) { + TAILQ_FOREACH(us, &parsed_policy.userspecs, entries) { print_userspec_json(fp, us, indent, expand_aliases); } indent -= 4; diff --git a/plugins/sudoers/cvtsudoers_ldif.c b/plugins/sudoers/cvtsudoers_ldif.c index 1fbda1f55..4e4473dad 100644 --- a/plugins/sudoers/cvtsudoers_ldif.c +++ b/plugins/sudoers/cvtsudoers_ldif.c @@ -167,14 +167,14 @@ print_global_defaults_ldif(FILE *fp, const char *base) sudo_lbuf_init(&lbuf, NULL, 0, NULL, 80); - TAILQ_FOREACH(opt, &defaults, entries) { + TAILQ_FOREACH(opt, &parsed_policy.defaults, entries) { /* Skip bound Defaults (unsupported). */ if (opt->type == DEFAULTS) { count++; } else { lbuf.len = 0; sudo_lbuf_append(&lbuf, "# "); - sudoers_format_default_line(&lbuf, opt, false, true); + sudoers_format_default_line(&lbuf, &parsed_policy, opt, false, true); fprintf(fp, "# Unable to translate %s:%d\n%s\n", opt->file, opt->lineno, lbuf.buf); } @@ -195,7 +195,7 @@ print_global_defaults_ldif(FILE *fp, const char *base) print_attribute_ldif(fp, "cn", "defaults"); print_attribute_ldif(fp, "description", "Default sudoOption's go here"); - print_options_ldif(fp, &defaults); + print_options_ldif(fp, &parsed_policy.defaults); putc('\n', fp); debug_return_bool(!ferror(fp)); @@ -239,7 +239,7 @@ print_member_ldif(FILE *fp, char *name, int type, bool negated, free(attr_val); break; case ALIAS: - if ((a = alias_get(name, alias_type)) != NULL) { + if ((a = alias_get(&parsed_policy, name, alias_type)) != NULL) { TAILQ_FOREACH(m, &a->members, entries) { print_member_ldif(fp, m->name, m->type, negated ? !m->negated : m->negated, alias_type, attr_name); @@ -601,7 +601,7 @@ print_userspecs_ldif(FILE *fp, struct cvtsudoers_config *conf) struct userspec *us; debug_decl(print_userspecs_ldif, SUDOERS_DEBUG_UTIL) - TAILQ_FOREACH(us, &userspecs, entries) { + TAILQ_FOREACH(us, &parsed_policy.userspecs, entries) { if (!print_userspec_ldif(fp, us, conf)) debug_return_bool(false); } @@ -860,7 +860,7 @@ ldif_store_options(struct cvtsudoers_str_list *options) U_("unable to allocate memory")); } } - TAILQ_INSERT_TAIL(&defaults, d, entries); + TAILQ_INSERT_TAIL(&parsed_policy.defaults, d, entries); } debug_return; } @@ -928,7 +928,7 @@ role_to_sudoers(struct sudo_role *role, bool store_options, if (reuse_userspec) { /* Re-use the previous userspec */ - us = TAILQ_LAST(&userspecs, userspec_list); + us = TAILQ_LAST(&parsed_policy.userspecs, userspec_list); } else { /* Allocate a new userspec and fill in the user list. */ if ((us = calloc(1, sizeof(*us))) == NULL) { @@ -1039,7 +1039,7 @@ role_to_sudoers(struct sudo_role *role, bool store_options, /* Add finished userspec to the list if new. */ if (!reuse_userspec) - TAILQ_INSERT_TAIL(&userspecs, us, entries); + TAILQ_INSERT_TAIL(&parsed_policy.userspecs, us, entries); debug_return; } diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index d4715f72f..8611d5906 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2005, 2007-2017 + * Copyright (c) 1999-2005, 2007-2018 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -696,7 +696,8 @@ default_type_matches(struct defaults *d, int what) * Returns true if it matches, else false. */ static bool -default_binding_matches(struct defaults *d, int what) +default_binding_matches(struct sudoers_parse_tree *parse_tree, + struct defaults *d, int what) { debug_decl(default_binding_matches, SUDOERS_DEBUG_DEFAULTS) @@ -705,19 +706,19 @@ default_binding_matches(struct defaults *d, int what) debug_return_bool(true); break; case DEFAULTS_USER: - if (userlist_matches(sudo_user.pw, d->binding) == ALLOW) + if (userlist_matches(parse_tree, sudo_user.pw, d->binding) == ALLOW) debug_return_bool(true); break; case DEFAULTS_RUNAS: - if (runaslist_matches(d->binding, NULL, NULL, NULL) == ALLOW) + if (runaslist_matches(parse_tree, d->binding, NULL, NULL, NULL) == ALLOW) debug_return_bool(true); break; case DEFAULTS_HOST: - if (hostlist_matches(sudo_user.pw, d->binding) == ALLOW) + if (hostlist_matches(parse_tree, sudo_user.pw, d->binding) == ALLOW) debug_return_bool(true); break; case DEFAULTS_CMND: - if (cmndlist_matches(d->binding) == ALLOW) + if (cmndlist_matches(parse_tree, d->binding) == ALLOW) debug_return_bool(true); break; } @@ -729,7 +730,7 @@ default_binding_matches(struct defaults *d, int what) * Pass in an OR'd list of which default types to update. */ bool -update_defaults(struct defaults_list *defs, int what, bool quiet) +update_defaults(struct sudoers_parse_tree *parse_tree, int what, bool quiet) { struct defaults *d; bool ret = true; @@ -741,14 +742,14 @@ update_defaults(struct defaults_list *defs, int what, bool quiet) /* * First apply Defaults values marked as early. */ - TAILQ_FOREACH(d, defs, entries) { + TAILQ_FOREACH(d, &parse_tree->defaults, entries) { struct early_default *early = is_early_default(d->var); if (early == NULL) continue; /* Defaults type and binding must match. */ if (!default_type_matches(d, what) || - !default_binding_matches(d, what)) + !default_binding_matches(parse_tree, d, what)) continue; /* Copy the value to sudo_defs_table and mark as early. */ @@ -763,14 +764,14 @@ update_defaults(struct defaults_list *defs, int what, bool quiet) /* * Then set the rest of the defaults. */ - TAILQ_FOREACH(d, defs, entries) { + TAILQ_FOREACH(d, &parse_tree->defaults, entries) { /* Skip Defaults marked as early, we already did them. */ if (is_early_default(d->var)) continue; /* Defaults type and binding must match. */ if (!default_type_matches(d, what) || - !default_binding_matches(d, what)) + !default_binding_matches(parse_tree, d, what)) continue; /* Copy the value to sudo_defs_table and run callback (if any) */ @@ -784,14 +785,14 @@ update_defaults(struct defaults_list *defs, int what, bool quiet) * Check all defaults entries without actually setting them. */ bool -check_defaults(bool quiet) +check_defaults(struct sudoers_parse_tree *parse_tree, bool quiet) { struct defaults *d; bool ret = true; int idx; debug_decl(check_defaults, SUDOERS_DEBUG_DEFAULTS) - TAILQ_FOREACH(d, &defaults, entries) { + TAILQ_FOREACH(d, &parse_tree->defaults, entries) { idx = find_default(d->var, d->file, d->lineno, quiet); if (idx != -1) { struct sudo_defs_types *def = &sudo_defs_table[idx]; diff --git a/plugins/sudoers/defaults.h b/plugins/sudoers/defaults.h index 41582acce..3d360b8e0 100644 --- a/plugins/sudoers/defaults.h +++ b/plugins/sudoers/defaults.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2005, 2008-2016 + * Copyright (c) 1999-2005, 2008-2018 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -122,15 +122,15 @@ struct early_default { /* * Prototypes */ -struct defaults_list; +struct sudoers_parse_tree; void dump_default(void); bool init_defaults(void); struct early_default *is_early_default(const char *name); bool run_early_defaults(void); bool set_early_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet, struct early_default *early); bool set_default(const char *var, const char *val, int op, const char *file, int lineno, bool quiet); -bool update_defaults(struct defaults_list *defs, int what, bool quiet); -bool check_defaults(bool quiet); +bool update_defaults(struct sudoers_parse_tree *parse_tree, int what, bool quiet); +bool check_defaults(struct sudoers_parse_tree *parse_tree, bool quiet); extern struct sudo_defs_types sudo_defs_table[]; diff --git a/plugins/sudoers/file.c b/plugins/sudoers/file.c index dc6713f1c..62a6eade7 100644 --- a/plugins/sudoers/file.c +++ b/plugins/sudoers/file.c @@ -40,8 +40,7 @@ struct sudo_file_handle { FILE *fp; - struct defaults_list defaults; - struct userspec_list userspecs; + struct sudoers_parse_tree parse_tree; }; static int @@ -54,9 +53,7 @@ sudo_file_close(struct sudo_nss *nss) fclose(handle->fp); sudoersin = NULL; - free_userspecs(&handle->userspecs); - free_defaults(&handle->defaults); - + free_parse_tree(&handle->parse_tree); free(handle); nss->handle = NULL; } @@ -83,8 +80,7 @@ sudo_file_open(struct sudo_nss *nss) if (handle != NULL) { handle->fp = open_sudoers(sudoers_file, false, NULL); if (handle->fp != NULL) { - TAILQ_INIT(&handle->userspecs); - TAILQ_INIT(&handle->defaults); + init_parse_tree(&handle->parse_tree); } else { free(handle); handle = NULL; @@ -95,9 +91,9 @@ sudo_file_open(struct sudo_nss *nss) } /* - * Parse the specified sudoers file. + * Parse and return the specified sudoers file. */ -static int +static struct sudoers_parse_tree * sudo_file_parse(struct sudo_nss *nss) { debug_decl(sudo_file_close, SUDOERS_DEBUG_NSS) @@ -106,7 +102,7 @@ sudo_file_parse(struct sudo_nss *nss) if (handle == NULL || handle->fp == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: called with NULL %s", __func__, handle ? "file pointer" : "handle"); - debug_return_int(-1); + debug_return_ptr(NULL); } sudoersin = handle->fp; @@ -117,49 +113,33 @@ sudo_file_parse(struct sudo_nss *nss) } else { log_warningx(SLOG_SEND_MAIL, N_("parse error in %s"), errorfile); } - debug_return_int(-1); + debug_return_ptr(NULL); } - /* Move parsed userspecs and defaults to nss structure. */ - TAILQ_CONCAT(&handle->userspecs, &userspecs, entries); - TAILQ_CONCAT(&handle->defaults, &defaults, entries); + /* Move parsed sudoers policy to nss handle. */ + reparent_parse_tree(&handle->parse_tree); - debug_return_int(0); + debug_return_ptr(&handle->parse_tree); } /* - * We return all cached userspecs, the parse functions will - * perform matching against pw for us. + * No need for explicit sudoers queries, the parse function handled it. */ -static struct userspec_list * +static int sudo_file_query(struct sudo_nss *nss, struct passwd *pw) { - struct sudo_file_handle *handle = nss->handle; debug_decl(sudo_file_query, SUDOERS_DEBUG_NSS) - - if (handle == NULL) { - sudo_debug_printf(SUDO_DEBUG_ERROR, - "%s: called with NULL handle", __func__); - debug_return_ptr(NULL); - } - debug_return_ptr(&handle->userspecs); + debug_return_int(0); } /* - * Return cached defaults entries. + * No need to get defaults for sudoers file, the parse function handled it. */ -static struct defaults_list * +static int sudo_file_getdefs(struct sudo_nss *nss) { debug_decl(sudo_file_getdefs, SUDOERS_DEBUG_NSS) - struct sudo_file_handle *handle = nss->handle; - - if (handle == NULL) { - sudo_debug_printf(SUDO_DEBUG_ERROR, - "%s: called with NULL handle", __func__); - debug_return_ptr(NULL); - } - debug_return_ptr(&handle->defaults); + debug_return_int(0); } /* sudo_nss implementation */ diff --git a/plugins/sudoers/fmtsudoers.c b/plugins/sudoers/fmtsudoers.c index bd1a930fa..69e3019ad 100644 --- a/plugins/sudoers/fmtsudoers.c +++ b/plugins/sudoers/fmtsudoers.c @@ -37,8 +37,9 @@ * the specified separator (which must not be NULL in the UNSPEC case). */ static bool -sudoers_format_member_int(struct sudo_lbuf *lbuf, char *name, int type, - bool negated, const char *separator, int alias_type) +sudoers_format_member_int(struct sudo_lbuf *lbuf, + struct sudoers_parse_tree *parse_tree, char *name, int type, bool negated, + const char *separator, int alias_type) { struct alias *a; struct member *m; @@ -81,13 +82,13 @@ sudoers_format_member_int(struct sudo_lbuf *lbuf, char *name, int type, goto print_word; case ALIAS: if (alias_type != UNSPEC) { - if ((a = alias_get(name, alias_type)) != NULL) { + if ((a = alias_get(parse_tree, name, alias_type)) != NULL) { TAILQ_FOREACH(m, &a->members, entries) { if (m != TAILQ_FIRST(&a->members)) sudo_lbuf_append(lbuf, "%s", separator); - sudoers_format_member_int(lbuf, m->name, m->type, - negated ? !m->negated : m->negated, separator, - alias_type); + sudoers_format_member_int(lbuf, parse_tree, m->name, + m->type, negated ? !m->negated : m->negated, + separator, alias_type); } alias_put(a); break; @@ -116,11 +117,12 @@ sudoers_format_member_int(struct sudo_lbuf *lbuf, char *name, int type, } bool -sudoers_format_member(struct sudo_lbuf *lbuf, struct member *m, +sudoers_format_member(struct sudo_lbuf *lbuf, + struct sudoers_parse_tree *parse_tree, struct member *m, const char *separator, int alias_type) { - return sudoers_format_member_int(lbuf, m->name, m->type, m->negated, - separator, alias_type); + return sudoers_format_member_int(lbuf, parse_tree, m->name, m->type, + m->negated, separator, alias_type); } #define FIELD_CHANGED(ocs, ncs, fld) \ @@ -133,7 +135,8 @@ sudoers_format_member(struct sudo_lbuf *lbuf, struct member *m, * Write a cmndspec to lbuf in sudoers format. */ bool -sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct cmndspec *cs, +sudoers_format_cmndspec(struct sudo_lbuf *lbuf, + struct sudoers_parse_tree *parse_tree, struct cmndspec *cs, struct cmndspec *prev_cs, bool expand_aliases) { debug_decl(sudoers_format_cmndspec, SUDOERS_DEBUG_UTIL) @@ -185,7 +188,7 @@ sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct cmndspec *cs, 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: "); - sudoers_format_member(lbuf, cs->cmnd, ", ", + sudoers_format_member(lbuf, parse_tree, cs->cmnd, ", ", expand_aliases ? CMNDALIAS : UNSPEC); debug_return_bool(!sudo_lbuf_error(lbuf)); } @@ -194,7 +197,8 @@ sudoers_format_cmndspec(struct sudo_lbuf *lbuf, struct cmndspec *cs, * Write a privilege to lbuf in sudoers format. */ bool -sudoers_format_privilege(struct sudo_lbuf *lbuf, struct privilege *priv, +sudoers_format_privilege(struct sudo_lbuf *lbuf, + struct sudoers_parse_tree *parse_tree, struct privilege *priv, bool expand_aliases) { struct cmndspec *cs, *prev_cs; @@ -205,7 +209,7 @@ sudoers_format_privilege(struct sudo_lbuf *lbuf, struct privilege *priv, TAILQ_FOREACH(m, &priv->hostlist, entries) { if (m != TAILQ_FIRST(&priv->hostlist)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, ", ", + sudoers_format_member(lbuf, parse_tree, m, ", ", expand_aliases ? HOSTALIAS : UNSPEC); } @@ -222,7 +226,7 @@ sudoers_format_privilege(struct sudo_lbuf *lbuf, struct privilege *priv, TAILQ_FOREACH(m, cs->runasuserlist, entries) { if (m != TAILQ_FIRST(cs->runasuserlist)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, ", ", + sudoers_format_member(lbuf, parse_tree, m, ", ", expand_aliases ? RUNASALIAS : UNSPEC); } } @@ -231,7 +235,7 @@ sudoers_format_privilege(struct sudo_lbuf *lbuf, struct privilege *priv, TAILQ_FOREACH(m, cs->runasgrouplist, entries) { if (m != TAILQ_FIRST(cs->runasgrouplist)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, ", ", + sudoers_format_member(lbuf, parse_tree, m, ", ", expand_aliases ? RUNASALIAS : UNSPEC); } } @@ -240,7 +244,7 @@ sudoers_format_privilege(struct sudo_lbuf *lbuf, struct privilege *priv, } else if (cs != TAILQ_FIRST(&priv->cmndlist)) { sudo_lbuf_append(lbuf, ", "); } - sudoers_format_cmndspec(lbuf, cs, prev_cs, expand_aliases); + sudoers_format_cmndspec(lbuf, parse_tree, cs, prev_cs, expand_aliases); prev_cs = cs; } @@ -251,8 +255,9 @@ sudoers_format_privilege(struct sudo_lbuf *lbuf, struct privilege *priv, * Write a userspec to lbuf in sudoers format. */ bool -sudoers_format_userspec(struct sudo_lbuf *lbuf, struct userspec *us, - bool expand_aliases) +sudoers_format_userspec(struct sudo_lbuf *lbuf, + struct sudoers_parse_tree *parse_tree, + struct userspec *us, bool expand_aliases) { struct privilege *priv; struct sudoers_comment *comment; @@ -268,7 +273,7 @@ sudoers_format_userspec(struct sudo_lbuf *lbuf, struct userspec *us, TAILQ_FOREACH(m, &us->users, entries) { if (m != TAILQ_FIRST(&us->users)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, ", ", + sudoers_format_member(lbuf, parse_tree, m, ", ", expand_aliases ? USERALIAS : UNSPEC); } @@ -277,7 +282,7 @@ sudoers_format_userspec(struct sudo_lbuf *lbuf, struct userspec *us, sudo_lbuf_append(lbuf, " : "); else sudo_lbuf_append(lbuf, " "); - if (!sudoers_format_privilege(lbuf, priv, expand_aliases)) + if (!sudoers_format_privilege(lbuf, parse_tree, priv, expand_aliases)) break; } sudo_lbuf_append(lbuf, "\n"); @@ -289,16 +294,17 @@ sudoers_format_userspec(struct sudo_lbuf *lbuf, struct userspec *us, * Write a userspec_list to lbuf in sudoers format. */ bool -sudoers_format_userspecs(struct sudo_lbuf *lbuf, struct userspec_list *usl, - const char *separator, bool expand_aliases, bool flush) +sudoers_format_userspecs(struct sudo_lbuf *lbuf, + struct sudoers_parse_tree *parse_tree, const char *separator, + bool expand_aliases, bool flush) { struct userspec *us; debug_decl(sudoers_format_userspecs, SUDOERS_DEBUG_UTIL) - TAILQ_FOREACH(us, usl, entries) { - if (separator != NULL && us != TAILQ_FIRST(usl)) + TAILQ_FOREACH(us, &parse_tree->userspecs, entries) { + if (separator != NULL && us != TAILQ_FIRST(&parse_tree->userspecs)) sudo_lbuf_append(lbuf, "%s", separator); - if (!sudoers_format_userspec(lbuf, us, expand_aliases)) + if (!sudoers_format_userspec(lbuf, parse_tree, us, expand_aliases)) break; sudo_lbuf_print(lbuf); } @@ -336,7 +342,8 @@ sudoers_format_default(struct sudo_lbuf *lbuf, struct defaults *d) * entries with the same binding on a single line. */ bool -sudoers_format_default_line(struct sudo_lbuf *lbuf, struct defaults *d, +sudoers_format_default_line( struct sudo_lbuf *lbuf, + struct sudoers_parse_tree *parse_tree, struct defaults *d, struct defaults **next, bool expand_aliases) { struct member *m; @@ -369,7 +376,7 @@ sudoers_format_default_line(struct sudo_lbuf *lbuf, struct defaults *d, TAILQ_FOREACH(m, d->binding, entries) { if (m != TAILQ_FIRST(d->binding)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, ", ", alias_type); + sudoers_format_member(lbuf, parse_tree, m, ", ", alias_type); } sudo_lbuf_append(lbuf, " "); diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c index 52df29a75..85a8b8a1d 100644 --- a/plugins/sudoers/gram.c +++ b/plugins/sudoers/gram.c @@ -38,7 +38,7 @@ #define YYPREFIX "sudoers" #line 2 "gram.y" /* - * Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2017 + * Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2018 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -98,8 +98,11 @@ bool parse_error = false; int errorlineno = -1; char *errorfile = NULL; -struct defaults_list defaults = TAILQ_HEAD_INITIALIZER(defaults); -struct userspec_list userspecs = TAILQ_HEAD_INITIALIZER(userspecs); +struct sudoers_parse_tree parsed_policy = { + TAILQ_HEAD_INITIALIZER(parsed_policy.userspecs), + TAILQ_HEAD_INITIALIZER(parsed_policy.defaults), + NULL /* aliases */ +}; /* * Local protoypes @@ -110,7 +113,7 @@ static bool add_userspec(struct member *, struct privilege *); static struct defaults *new_default(char *, char *, short); static struct member *new_member(char *, int); static struct command_digest *new_digest(int, char *); -#line 77 "gram.y" +#line 80 "gram.y" #ifndef YYSTYPE_DEFINED #define YYSTYPE_DEFINED typedef union { @@ -127,7 +130,7 @@ typedef union { int tok; } YYSTYPE; #endif /* YYSTYPE_DEFINED */ -#line 130 "gram.c" +#line 133 "gram.c" #define COMMAND 257 #define ALIAS 258 #define DEFVAR 259 @@ -667,7 +670,7 @@ short *yysslim; YYSTYPE *yyvs; unsigned int yystacksize; int yyparse(void); -#line 899 "gram.y" +#line 906 "gram.y" void sudoerserror(const char *s) { @@ -799,7 +802,7 @@ add_defaults(int type, struct member *bmem, struct defaults *defs) HLTQ_FOREACH_SAFE(d, defs, entries, next) { d->type = type; d->binding = binding; - TAILQ_INSERT_TAIL(&defaults, d, entries); + TAILQ_INSERT_TAIL(&parsed_policy.defaults, d, entries); } } @@ -826,7 +829,7 @@ add_userspec(struct member *members, struct privilege *privs) HLTQ_TO_TAILQ(&u->users, members, entries); HLTQ_TO_TAILQ(&u->privileges, privs, entries); STAILQ_INIT(&u->comments); - TAILQ_INSERT_TAIL(&userspecs, u, entries); + TAILQ_INSERT_TAIL(&parsed_policy.userspecs, u, entries); debug_return_bool(true); } @@ -1007,6 +1010,41 @@ free_userspec(struct userspec *us) debug_return; } +/* + * Initialized a sudoers parse tree. + */ +void +init_parse_tree(struct sudoers_parse_tree *parse_tree) +{ + TAILQ_INIT(&parse_tree->userspecs); + TAILQ_INIT(&parse_tree->defaults); + parse_tree->aliases = NULL; +} + +/* + * Move the contents of parsed_policy to new_tree. + */ +void +reparent_parse_tree(struct sudoers_parse_tree *new_tree) +{ + TAILQ_CONCAT(&new_tree->userspecs, &parsed_policy.userspecs, entries); + TAILQ_CONCAT(&new_tree->defaults, &parsed_policy.defaults, entries); + new_tree->aliases = parsed_policy.aliases; + parsed_policy.aliases = NULL; +} + +/* + * Free the contents of a sudoers parse tree and initialize it. + */ +void +free_parse_tree(struct sudoers_parse_tree *parse_tree) +{ + free_userspecs(&parse_tree->userspecs); + free_defaults(&parse_tree->defaults); + free_aliases(parse_tree->aliases); + parse_tree->aliases = NULL; +} + /* * Free up space used by data structures from a previous parser run and sets * the current sudoers file to path. @@ -1017,15 +1055,9 @@ init_parser(const char *path, bool quiet) bool ret = true; debug_decl(init_parser, SUDOERS_DEBUG_PARSER) - free_userspecs(&userspecs); - free_defaults(&defaults); + free_parse_tree(&parsed_policy); init_lexer(); - if (!init_aliases()) { - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - ret = false; - } - rcstr_delref(sudoers); if (path != NULL) { if ((sudoers = rcstr_dup(path)) == NULL) { @@ -1063,7 +1095,7 @@ init_options(struct command_options *opts) opts->limitprivs = NULL; #endif } -#line 1014 "gram.c" +#line 1046 "gram.c" /* allocate initial stack or double stack size, up to YYMAXDEPTH */ #if defined(__cplusplus) || defined(__STDC__) static int yygrowstack(void) @@ -1272,23 +1304,23 @@ yyreduce: switch (yyn) { case 1: -#line 175 "gram.y" +#line 178 "gram.y" { ; } break; case 5: -#line 183 "gram.y" +#line 186 "gram.y" { ; } break; case 6: -#line 186 "gram.y" +#line 189 "gram.y" { yyerrok; } break; case 7: -#line 189 "gram.y" +#line 192 "gram.y" { if (!add_userspec(yyvsp[-1].member, yyvsp[0].privilege)) { sudoerserror(N_("unable to allocate memory")); @@ -1297,73 +1329,73 @@ case 7: } break; case 8: -#line 195 "gram.y" +#line 198 "gram.y" { ; } break; case 9: -#line 198 "gram.y" +#line 201 "gram.y" { ; } break; case 10: -#line 201 "gram.y" +#line 204 "gram.y" { ; } break; case 11: -#line 204 "gram.y" +#line 207 "gram.y" { ; } break; case 12: -#line 207 "gram.y" +#line 210 "gram.y" { if (!add_defaults(DEFAULTS, NULL, yyvsp[0].defaults)) YYERROR; } break; case 13: -#line 211 "gram.y" +#line 214 "gram.y" { if (!add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 14: -#line 215 "gram.y" +#line 218 "gram.y" { if (!add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 15: -#line 219 "gram.y" +#line 222 "gram.y" { if (!add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 16: -#line 223 "gram.y" +#line 226 "gram.y" { if (!add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults)) YYERROR; } break; case 18: -#line 230 "gram.y" +#line 233 "gram.y" { HLTQ_CONCAT(yyvsp[-2].defaults, yyvsp[0].defaults, entries); yyval.defaults = yyvsp[-2].defaults; } break; case 19: -#line 236 "gram.y" +#line 239 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, true); if (yyval.defaults == NULL) { @@ -1373,7 +1405,7 @@ case 19: } break; case 20: -#line 243 "gram.y" +#line 246 "gram.y" { yyval.defaults = new_default(yyvsp[0].string, NULL, false); if (yyval.defaults == NULL) { @@ -1383,7 +1415,7 @@ case 20: } break; case 21: -#line 250 "gram.y" +#line 253 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, true); if (yyval.defaults == NULL) { @@ -1393,7 +1425,7 @@ case 21: } break; case 22: -#line 257 "gram.y" +#line 260 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+'); if (yyval.defaults == NULL) { @@ -1403,7 +1435,7 @@ case 22: } break; case 23: -#line 264 "gram.y" +#line 267 "gram.y" { yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-'); if (yyval.defaults == NULL) { @@ -1413,14 +1445,14 @@ case 23: } break; case 25: -#line 274 "gram.y" +#line 277 "gram.y" { HLTQ_CONCAT(yyvsp[-2].privilege, yyvsp[0].privilege, entries); yyval.privilege = yyvsp[-2].privilege; } break; case 26: -#line 280 "gram.y" +#line 283 "gram.y" { struct privilege *p = calloc(1, sizeof(*p)); if (p == NULL) { @@ -1435,21 +1467,21 @@ case 26: } break; case 27: -#line 294 "gram.y" +#line 297 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 28: -#line 298 "gram.y" +#line 301 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 29: -#line 304 "gram.y" +#line 307 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -1459,7 +1491,7 @@ case 29: } break; case 30: -#line 311 "gram.y" +#line 314 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -1469,7 +1501,7 @@ case 30: } break; case 31: -#line 318 "gram.y" +#line 321 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); if (yyval.member == NULL) { @@ -1479,7 +1511,7 @@ case 31: } break; case 32: -#line 325 "gram.y" +#line 328 "gram.y" { yyval.member = new_member(yyvsp[0].string, NTWKADDR); if (yyval.member == NULL) { @@ -1489,7 +1521,7 @@ case 32: } break; case 33: -#line 332 "gram.y" +#line 335 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -1499,7 +1531,7 @@ case 33: } break; case 35: -#line 342 "gram.y" +#line 345 "gram.y" { struct cmndspec *prev; prev = HLTQ_LAST(yyvsp[-2].cmndspec, cmndspec, entries); @@ -1553,7 +1585,7 @@ case 35: } break; case 36: -#line 395 "gram.y" +#line 398 "gram.y" { struct cmndspec *cs = calloc(1, sizeof(*cs)); if (cs == NULL) { @@ -1605,7 +1637,7 @@ case 36: } break; case 37: -#line 446 "gram.y" +#line 449 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA224, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1615,7 +1647,7 @@ case 37: } break; case 38: -#line 453 "gram.y" +#line 456 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA256, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1625,7 +1657,7 @@ case 38: } break; case 39: -#line 460 "gram.y" +#line 463 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA384, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1635,7 +1667,7 @@ case 39: } break; case 40: -#line 467 "gram.y" +#line 470 "gram.y" { yyval.digest = new_digest(SUDO_DIGEST_SHA512, yyvsp[0].string); if (yyval.digest == NULL) { @@ -1645,13 +1677,13 @@ case 40: } break; case 41: -#line 476 "gram.y" +#line 479 "gram.y" { yyval.member = yyvsp[0].member; } break; case 42: -#line 479 "gram.y" +#line 482 "gram.y" { if (yyvsp[0].member->type != COMMAND) { sudoerserror(N_("a digest requires a path name")); @@ -1663,75 +1695,75 @@ case 42: } break; case 43: -#line 490 "gram.y" +#line 493 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 44: -#line 494 "gram.y" +#line 497 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 45: -#line 500 "gram.y" +#line 503 "gram.y" { yyval.string = yyvsp[0].string; } break; case 46: -#line 505 "gram.y" +#line 508 "gram.y" { yyval.string = yyvsp[0].string; } break; case 47: -#line 509 "gram.y" +#line 512 "gram.y" { yyval.string = yyvsp[0].string; } break; case 48: -#line 514 "gram.y" +#line 517 "gram.y" { yyval.string = yyvsp[0].string; } break; case 49: -#line 519 "gram.y" +#line 522 "gram.y" { yyval.string = yyvsp[0].string; } break; case 50: -#line 524 "gram.y" +#line 527 "gram.y" { yyval.string = yyvsp[0].string; } break; case 51: -#line 528 "gram.y" +#line 531 "gram.y" { yyval.string = yyvsp[0].string; } break; case 52: -#line 533 "gram.y" +#line 536 "gram.y" { yyval.runas = NULL; } break; case 53: -#line 536 "gram.y" +#line 539 "gram.y" { yyval.runas = yyvsp[-1].runas; } break; case 54: -#line 541 "gram.y" +#line 544 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas != NULL) { @@ -1749,7 +1781,7 @@ case 54: } break; case 55: -#line 556 "gram.y" +#line 559 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1761,7 +1793,7 @@ case 55: } break; case 56: -#line 565 "gram.y" +#line 568 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1773,7 +1805,7 @@ case 56: } break; case 57: -#line 574 "gram.y" +#line 577 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas == NULL) { @@ -1785,7 +1817,7 @@ case 57: } break; case 58: -#line 583 "gram.y" +#line 586 "gram.y" { yyval.runas = calloc(1, sizeof(struct runascontainer)); if (yyval.runas != NULL) { @@ -1803,13 +1835,13 @@ case 58: } break; case 59: -#line 600 "gram.y" +#line 603 "gram.y" { init_options(&yyval.options); } break; case 60: -#line 603 "gram.y" +#line 606 "gram.y" { yyval.options.notbefore = parse_gentime(yyvsp[0].string); free(yyvsp[0].string); @@ -1820,7 +1852,7 @@ case 60: } break; case 61: -#line 611 "gram.y" +#line 614 "gram.y" { yyval.options.notafter = parse_gentime(yyvsp[0].string); free(yyvsp[0].string); @@ -1831,7 +1863,7 @@ case 61: } break; case 62: -#line 619 "gram.y" +#line 622 "gram.y" { yyval.options.timeout = parse_timeout(yyvsp[0].string); free(yyvsp[0].string); @@ -1845,7 +1877,7 @@ case 62: } break; case 63: -#line 630 "gram.y" +#line 633 "gram.y" { #ifdef HAVE_SELINUX free(yyval.options.role); @@ -1854,7 +1886,7 @@ case 63: } break; case 64: -#line 636 "gram.y" +#line 639 "gram.y" { #ifdef HAVE_SELINUX free(yyval.options.type); @@ -1863,7 +1895,7 @@ case 64: } break; case 65: -#line 642 "gram.y" +#line 645 "gram.y" { #ifdef HAVE_PRIV_SET free(yyval.options.privs); @@ -1872,7 +1904,7 @@ case 65: } break; case 66: -#line 648 "gram.y" +#line 651 "gram.y" { #ifdef HAVE_PRIV_SET free(yyval.options.limitprivs); @@ -1881,97 +1913,97 @@ case 66: } break; case 67: -#line 656 "gram.y" +#line 659 "gram.y" { TAGS_INIT(yyval.tag); } break; case 68: -#line 659 "gram.y" +#line 662 "gram.y" { yyval.tag.nopasswd = true; } break; case 69: -#line 662 "gram.y" +#line 665 "gram.y" { yyval.tag.nopasswd = false; } break; case 70: -#line 665 "gram.y" +#line 668 "gram.y" { yyval.tag.noexec = true; } break; case 71: -#line 668 "gram.y" +#line 671 "gram.y" { yyval.tag.noexec = false; } break; case 72: -#line 671 "gram.y" +#line 674 "gram.y" { yyval.tag.setenv = true; } break; case 73: -#line 674 "gram.y" +#line 677 "gram.y" { yyval.tag.setenv = false; } break; case 74: -#line 677 "gram.y" +#line 680 "gram.y" { yyval.tag.log_input = true; } break; case 75: -#line 680 "gram.y" +#line 683 "gram.y" { yyval.tag.log_input = false; } break; case 76: -#line 683 "gram.y" +#line 686 "gram.y" { yyval.tag.log_output = true; } break; case 77: -#line 686 "gram.y" +#line 689 "gram.y" { yyval.tag.log_output = false; } break; case 78: -#line 689 "gram.y" +#line 692 "gram.y" { yyval.tag.follow = true; } break; case 79: -#line 692 "gram.y" +#line 695 "gram.y" { yyval.tag.follow = false; } break; case 80: -#line 695 "gram.y" +#line 698 "gram.y" { yyval.tag.send_mail = true; } break; case 81: -#line 698 "gram.y" +#line 701 "gram.y" { yyval.tag.send_mail = false; } break; case 82: -#line 703 "gram.y" +#line 706 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -1981,7 +2013,7 @@ case 82: } break; case 83: -#line 710 "gram.y" +#line 713 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -1991,7 +2023,7 @@ case 83: } break; case 84: -#line 717 "gram.y" +#line 720 "gram.y" { struct sudo_command *c = calloc(1, sizeof(*c)); if (c == NULL) { @@ -2009,10 +2041,11 @@ case 84: } break; case 87: -#line 738 "gram.y" +#line 741 "gram.y" { const char *s; - s = alias_add(yyvsp[-2].string, HOSTALIAS, sudoers, this_lineno, yyvsp[0].member); + s = alias_add(&parsed_policy, yyvsp[-2].string, HOSTALIAS, + sudoers, this_lineno, yyvsp[0].member); if (s != NULL) { sudoerserror(s); YYERROR; @@ -2020,17 +2053,18 @@ case 87: } break; case 89: -#line 749 "gram.y" +#line 753 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 92: -#line 759 "gram.y" +#line 763 "gram.y" { const char *s; - s = alias_add(yyvsp[-2].string, CMNDALIAS, sudoers, this_lineno, yyvsp[0].member); + s = alias_add(&parsed_policy, yyvsp[-2].string, CMNDALIAS, + sudoers, this_lineno, yyvsp[0].member); if (s != NULL) { sudoerserror(s); YYERROR; @@ -2038,17 +2072,18 @@ case 92: } break; case 94: -#line 770 "gram.y" +#line 775 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 97: -#line 780 "gram.y" +#line 785 "gram.y" { const char *s; - s = alias_add(yyvsp[-2].string, RUNASALIAS, sudoers, this_lineno, yyvsp[0].member); + s = alias_add(&parsed_policy, yyvsp[-2].string, RUNASALIAS, + sudoers, this_lineno, yyvsp[0].member); if (s != NULL) { sudoerserror(s); YYERROR; @@ -2056,10 +2091,11 @@ case 97: } break; case 100: -#line 794 "gram.y" +#line 800 "gram.y" { const char *s; - s = alias_add(yyvsp[-2].string, USERALIAS, sudoers, this_lineno, yyvsp[0].member); + s = alias_add(&parsed_policy, yyvsp[-2].string, USERALIAS, + sudoers, this_lineno, yyvsp[0].member); if (s != NULL) { sudoerserror(s); YYERROR; @@ -2067,28 +2103,28 @@ case 100: } break; case 102: -#line 805 "gram.y" +#line 812 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 103: -#line 811 "gram.y" +#line 818 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 104: -#line 815 "gram.y" +#line 822 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 105: -#line 821 "gram.y" +#line 828 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2098,7 +2134,7 @@ case 105: } break; case 106: -#line 828 "gram.y" +#line 835 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2108,7 +2144,7 @@ case 106: } break; case 107: -#line 835 "gram.y" +#line 842 "gram.y" { yyval.member = new_member(yyvsp[0].string, NETGROUP); if (yyval.member == NULL) { @@ -2118,7 +2154,7 @@ case 107: } break; case 108: -#line 842 "gram.y" +#line 849 "gram.y" { yyval.member = new_member(yyvsp[0].string, USERGROUP); if (yyval.member == NULL) { @@ -2128,7 +2164,7 @@ case 108: } break; case 109: -#line 849 "gram.y" +#line 856 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -2138,28 +2174,28 @@ case 109: } break; case 111: -#line 859 "gram.y" +#line 866 "gram.y" { HLTQ_CONCAT(yyvsp[-2].member, yyvsp[0].member, entries); yyval.member = yyvsp[-2].member; } break; case 112: -#line 865 "gram.y" +#line 872 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = false; } break; case 113: -#line 869 "gram.y" +#line 876 "gram.y" { yyval.member = yyvsp[0].member; yyval.member->negated = true; } break; case 114: -#line 875 "gram.y" +#line 882 "gram.y" { yyval.member = new_member(yyvsp[0].string, ALIAS); if (yyval.member == NULL) { @@ -2169,7 +2205,7 @@ case 114: } break; case 115: -#line 882 "gram.y" +#line 889 "gram.y" { yyval.member = new_member(NULL, ALL); if (yyval.member == NULL) { @@ -2179,7 +2215,7 @@ case 115: } break; case 116: -#line 889 "gram.y" +#line 896 "gram.y" { yyval.member = new_member(yyvsp[0].string, WORD); if (yyval.member == NULL) { @@ -2188,7 +2224,7 @@ case 116: } } break; -#line 2139 "gram.c" +#line 2175 "gram.c" } yyssp -= yym; yystate = *yyssp; diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y index 7e3a1ef2a..b8b583305 100644 --- a/plugins/sudoers/gram.y +++ b/plugins/sudoers/gram.y @@ -1,6 +1,6 @@ %{ /* - * Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2017 + * Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2018 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -60,8 +60,11 @@ bool parse_error = false; int errorlineno = -1; char *errorfile = NULL; -struct defaults_list defaults = TAILQ_HEAD_INITIALIZER(defaults); -struct userspec_list userspecs = TAILQ_HEAD_INITIALIZER(userspecs); +struct sudoers_parse_tree parsed_policy = { + TAILQ_HEAD_INITIALIZER(parsed_policy.userspecs), + TAILQ_HEAD_INITIALIZER(parsed_policy.defaults), + NULL /* aliases */ +}; /* * Local protoypes @@ -737,7 +740,8 @@ hostaliases : hostalias hostalias : ALIAS '=' hostlist { const char *s; - s = alias_add($1, HOSTALIAS, sudoers, this_lineno, $3); + s = alias_add(&parsed_policy, $1, HOSTALIAS, + sudoers, this_lineno, $3); if (s != NULL) { sudoerserror(s); YYERROR; @@ -758,7 +762,8 @@ cmndaliases : cmndalias cmndalias : ALIAS '=' cmndlist { const char *s; - s = alias_add($1, CMNDALIAS, sudoers, this_lineno, $3); + s = alias_add(&parsed_policy, $1, CMNDALIAS, + sudoers, this_lineno, $3); if (s != NULL) { sudoerserror(s); YYERROR; @@ -779,7 +784,8 @@ runasaliases : runasalias runasalias : ALIAS '=' userlist { const char *s; - s = alias_add($1, RUNASALIAS, sudoers, this_lineno, $3); + s = alias_add(&parsed_policy, $1, RUNASALIAS, + sudoers, this_lineno, $3); if (s != NULL) { sudoerserror(s); YYERROR; @@ -793,7 +799,8 @@ useraliases : useralias useralias : ALIAS '=' userlist { const char *s; - s = alias_add($1, USERALIAS, sudoers, this_lineno, $3); + s = alias_add(&parsed_policy, $1, USERALIAS, + sudoers, this_lineno, $3); if (s != NULL) { sudoerserror(s); YYERROR; @@ -1027,7 +1034,7 @@ add_defaults(int type, struct member *bmem, struct defaults *defs) HLTQ_FOREACH_SAFE(d, defs, entries, next) { d->type = type; d->binding = binding; - TAILQ_INSERT_TAIL(&defaults, d, entries); + TAILQ_INSERT_TAIL(&parsed_policy.defaults, d, entries); } } @@ -1054,7 +1061,7 @@ add_userspec(struct member *members, struct privilege *privs) HLTQ_TO_TAILQ(&u->users, members, entries); HLTQ_TO_TAILQ(&u->privileges, privs, entries); STAILQ_INIT(&u->comments); - TAILQ_INSERT_TAIL(&userspecs, u, entries); + TAILQ_INSERT_TAIL(&parsed_policy.userspecs, u, entries); debug_return_bool(true); } @@ -1235,6 +1242,41 @@ free_userspec(struct userspec *us) debug_return; } +/* + * Initialized a sudoers parse tree. + */ +void +init_parse_tree(struct sudoers_parse_tree *parse_tree) +{ + TAILQ_INIT(&parse_tree->userspecs); + TAILQ_INIT(&parse_tree->defaults); + parse_tree->aliases = NULL; +} + +/* + * Move the contents of parsed_policy to new_tree. + */ +void +reparent_parse_tree(struct sudoers_parse_tree *new_tree) +{ + TAILQ_CONCAT(&new_tree->userspecs, &parsed_policy.userspecs, entries); + TAILQ_CONCAT(&new_tree->defaults, &parsed_policy.defaults, entries); + new_tree->aliases = parsed_policy.aliases; + parsed_policy.aliases = NULL; +} + +/* + * Free the contents of a sudoers parse tree and initialize it. + */ +void +free_parse_tree(struct sudoers_parse_tree *parse_tree) +{ + free_userspecs(&parse_tree->userspecs); + free_defaults(&parse_tree->defaults); + free_aliases(parse_tree->aliases); + parse_tree->aliases = NULL; +} + /* * Free up space used by data structures from a previous parser run and sets * the current sudoers file to path. @@ -1245,15 +1287,9 @@ init_parser(const char *path, bool quiet) bool ret = true; debug_decl(init_parser, SUDOERS_DEBUG_PARSER) - free_userspecs(&userspecs); - free_defaults(&defaults); + free_parse_tree(&parsed_policy); init_lexer(); - if (!init_aliases()) { - sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - ret = false; - } - rcstr_delref(sudoers); if (path != NULL) { if ((sudoers = rcstr_dup(path)) == NULL) { diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index 0c5047d42..59512b9a1 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -152,9 +152,7 @@ STAILQ_HEAD(ldap_netgroup_list, ldap_netgroup); struct sudo_ldap_handle { LDAP *ld; struct passwd *pw; - struct userspec_list userspecs; - struct defaults_list defaults; - bool cached_defaults; + struct sudoers_parse_tree parse_tree; }; #ifdef HAVE_LDAP_INITIALIZE @@ -1553,8 +1551,7 @@ sudo_ldap_close(struct sudo_nss *nss) /* Free the handle container. */ if (handle->pw != NULL) sudo_pw_delref(handle->pw); - free_userspecs(&handle->userspecs); - free_defaults(&handle->defaults); + free_parse_tree(&handle->parse_tree); free(handle); nss->handle = NULL; } @@ -1660,40 +1657,39 @@ sudo_ldap_open(struct sudo_nss *nss) } handle->ld = ld; /* handle->pw = NULL; */ - TAILQ_INIT(&handle->userspecs); - TAILQ_INIT(&handle->defaults); + init_parse_tree(&handle->parse_tree); nss->handle = handle; done: debug_return_int(rc == LDAP_SUCCESS ? 0 : -1); } -static struct defaults_list * +static int sudo_ldap_getdefs(struct sudo_nss *nss) { struct sudo_ldap_handle *handle = nss->handle; - struct defaults_list *ret = &handle->defaults; struct timeval tv, *tvp = NULL; struct ldap_config_str *base; LDAPMessage *entry, *result = NULL; char *filt = NULL; - int rc; + int rc, ret = -1; + static bool cached; debug_decl(sudo_ldap_getdefs, SUDOERS_DEBUG_LDAP) if (handle == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: called with NULL handle", __func__); - debug_return_ptr(NULL); + debug_return_int(-1); } /* Use cached result if present. */ - if (handle->cached_defaults) - goto done; + if (cached) + debug_return_int(0); filt = sudo_ldap_build_default_filter(); if (filt == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - debug_return_ptr(NULL); + debug_return_int(-1); } DPRINTF1("Looking for cn=defaults: %s", filt); @@ -1711,21 +1707,20 @@ sudo_ldap_getdefs(struct sudo_nss *nss) filt, NULL, 0, NULL, NULL, tvp, 0, &result); if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { DPRINTF1("found:%s", ldap_get_dn(ld, entry)); - if (!sudo_ldap_parse_options(ld, entry, &handle->defaults)) { - ret = NULL; + if (!sudo_ldap_parse_options(ld, entry, &handle->parse_tree.defaults)) goto done; - } } else { DPRINTF1("no default options found in %s", base->val); } } - handle->cached_defaults = true; + cached = true; + ret = 0; done: ldap_msgfree(result); free(filt); - debug_return_ptr(ret); + debug_return_int(ret); } /* @@ -1918,67 +1913,73 @@ oom: * Perform LDAP query for user and host and convert to sudoers * parse tree. */ -static struct userspec_list * +static int sudo_ldap_query(struct sudo_nss *nss, struct passwd *pw) { struct sudo_ldap_handle *handle = nss->handle; struct ldap_result *lres = NULL; - struct userspec_list *ret = &handle->userspecs; + int ret = -1; debug_decl(sudo_ldap_query, SUDOERS_DEBUG_LDAP) if (handle == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: called with NULL handle", __func__); - debug_return_ptr(NULL); + debug_return_int(-1); } /* Use cached result if it matches pw. */ if (handle->pw != NULL) { - if (pw == handle->pw) + if (pw == handle->pw) { + ret = 0; goto done; + } sudo_pw_delref(handle->pw); handle->pw = NULL; } /* Free old userspecs, if any. */ - free_userspecs(&handle->userspecs); + free_userspecs(&handle->parse_tree.userspecs); DPRINTF1("%s: ldap search user %s, host %s", __func__, pw->pw_name, user_runhost); - if ((lres = sudo_ldap_result_get(nss, pw)) == NULL) { - ret = NULL; + if ((lres = sudo_ldap_result_get(nss, pw)) == NULL) goto done; - } /* Convert to sudoers parse tree. */ - if (!ldap_to_sudoers(handle->ld, lres, &handle->userspecs)) { - ret = NULL; + if (!ldap_to_sudoers(handle->ld, lres, &handle->parse_tree.userspecs)) goto done; - } /* Stash a ref to the passwd struct in the handle. */ sudo_pw_addref(pw); handle->pw = pw; - ret = &handle->userspecs; + ret = 0; done: /* Cleanup. */ sudo_ldap_result_free(lres); - if (ret == NULL) { - free_userspecs(&handle->userspecs); - debug_return_ptr(NULL); - } - debug_return_ptr(ret); + if (ret == -1) + free_userspecs(&handle->parse_tree.userspecs); + debug_return_int(ret); } /* - * STUB + * Return the initialized (but empty) sudoers parse tree. + * The contents will be populated by the getdefs() and query() functions. */ -static int +static struct sudoers_parse_tree * sudo_ldap_parse(struct sudo_nss *nss) { - return 0; + struct sudo_ldap_handle *handle = nss->handle; + debug_decl(sudo_ldap_parse, SUDOERS_DEBUG_LDAP) + + if (handle == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR, + "%s: called with NULL handle", __func__); + debug_return_ptr(NULL); + } + + debug_return_ptr(&handle->parse_tree); } #if 0 diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c index f0a8e9c40..71d67fdc9 100644 --- a/plugins/sudoers/match.c +++ b/plugins/sudoers/match.c @@ -93,7 +93,8 @@ static bool digest_matches(int fd, const char *file, const struct command_digest * Returns ALLOW, DENY or UNSPEC. */ int -user_matches(const struct passwd *pw, const struct member *m) +user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + const struct member *m) { struct alias *a; int matched = UNSPEC; @@ -114,9 +115,9 @@ user_matches(const struct passwd *pw, const struct member *m) matched = !m->negated; break; case ALIAS: - if ((a = alias_get(m->name, USERALIAS)) != NULL) { + if ((a = alias_get(parse_tree, m->name, USERALIAS)) != NULL) { /* XXX */ - int rc = userlist_matches(pw, &a->members); + int rc = userlist_matches(parse_tree, pw, &a->members); if (rc != UNSPEC) matched = m->negated ? !rc : rc; alias_put(a); @@ -136,14 +137,15 @@ user_matches(const struct passwd *pw, const struct member *m) * Returns ALLOW, DENY or UNSPEC. */ int -userlist_matches(const struct passwd *pw, const struct member_list *list) +userlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + const struct member_list *list) { struct member *m; int matched = UNSPEC; debug_decl(userlist_matches, SUDOERS_DEBUG_MATCH) TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { - if ((matched = user_matches(pw, m)) != UNSPEC) + if ((matched = user_matches(parse_tree, pw, m)) != UNSPEC) break; } debug_return_int(matched); @@ -155,9 +157,9 @@ userlist_matches(const struct passwd *pw, const struct member_list *list) * Returns ALLOW, DENY or UNSPEC. */ int -runaslist_matches(const struct member_list *user_list, - const struct member_list *group_list, struct member **matching_user, - struct member **matching_group) +runaslist_matches(struct sudoers_parse_tree *parse_tree, + const struct member_list *user_list, const struct member_list *group_list, + struct member **matching_user, struct member **matching_group) { struct member *m; struct alias *a; @@ -191,9 +193,10 @@ runaslist_matches(const struct member_list *user_list, user_matched = !m->negated; break; case ALIAS: - if ((a = alias_get(m->name, RUNASALIAS)) != NULL) { - rc = runaslist_matches(&a->members, &empty, - matching_user, NULL); + a = alias_get(parse_tree, m->name, RUNASALIAS); + if (a != NULL) { + rc = runaslist_matches(parse_tree, &a->members, + &empty, matching_user, NULL); if (rc != UNSPEC) user_matched = m->negated ? !rc : rc; alias_put(a); @@ -234,9 +237,10 @@ runaslist_matches(const struct member_list *user_list, group_matched = !m->negated; break; case ALIAS: - if ((a = alias_get(m->name, RUNASALIAS)) != NULL) { - rc = runaslist_matches(&empty, &a->members, - NULL, matching_group); + a = alias_get(parse_tree, m->name, RUNASALIAS); + if (a != NULL) { + rc = runaslist_matches(parse_tree, &empty, + &a->members, NULL, matching_group); if (rc != UNSPEC) group_matched = m->negated ? !rc : rc; alias_put(a); @@ -273,15 +277,16 @@ runaslist_matches(const struct member_list *user_list, * Returns ALLOW, DENY or UNSPEC. */ static int -hostlist_matches_int(const struct passwd *pw, const char *lhost, - const char *shost, const struct member_list *list) +hostlist_matches_int(struct sudoers_parse_tree *parse_tree, + const struct passwd *pw, const char *lhost, const char *shost, + const struct member_list *list) { struct member *m; int matched = UNSPEC; debug_decl(hostlist_matches, SUDOERS_DEBUG_MATCH) TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { - matched = host_matches(pw, lhost, shost, m); + matched = host_matches(parse_tree, pw, lhost, shost, m); if (matched != UNSPEC) break; } @@ -293,9 +298,10 @@ hostlist_matches_int(const struct passwd *pw, const char *lhost, * Returns ALLOW, DENY or UNSPEC. */ int -hostlist_matches(const struct passwd *pw, const struct member_list *list) +hostlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + const struct member_list *list) { - return hostlist_matches_int(pw, user_runhost, user_srunhost, list); + return hostlist_matches_int(parse_tree, pw, user_runhost, user_srunhost, list); } /* @@ -303,8 +309,8 @@ hostlist_matches(const struct passwd *pw, const struct member_list *list) * Returns ALLOW, DENY or UNSPEC. */ int -host_matches(const struct passwd *pw, const char *lhost, const char *shost, - const struct member *m) +host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, + const char *lhost, const char *shost, const struct member *m) { struct alias *a; int matched = UNSPEC; @@ -324,9 +330,11 @@ host_matches(const struct passwd *pw, const char *lhost, const char *shost, matched = !m->negated; break; case ALIAS: - if ((a = alias_get(m->name, HOSTALIAS)) != NULL) { + a = alias_get(parse_tree, m->name, HOSTALIAS); + if (a != NULL) { /* XXX */ - int rc = hostlist_matches_int(pw, lhost, shost, &a->members); + int rc = hostlist_matches_int(parse_tree, pw, lhost, shost, + &a->members); if (rc != UNSPEC) matched = m->negated ? !rc : rc; alias_put(a); @@ -346,14 +354,15 @@ host_matches(const struct passwd *pw, const char *lhost, const char *shost, * Returns ALLOW, DENY or UNSPEC. */ int -cmndlist_matches(const struct member_list *list) +cmndlist_matches(struct sudoers_parse_tree *parse_tree, + const struct member_list *list) { struct member *m; int matched = UNSPEC; debug_decl(cmndlist_matches, SUDOERS_DEBUG_MATCH) TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { - matched = cmnd_matches(m); + matched = cmnd_matches(parse_tree, m); if (matched != UNSPEC) break; } @@ -365,7 +374,7 @@ cmndlist_matches(const struct member_list *list) * Returns ALLOW, DENY or UNSPEC. */ int -cmnd_matches(const struct member *m) +cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m) { struct alias *a; struct sudo_command *c; @@ -377,8 +386,9 @@ cmnd_matches(const struct member *m) matched = !m->negated; break; case ALIAS: - if ((a = alias_get(m->name, CMNDALIAS)) != NULL) { - rc = cmndlist_matches(&a->members); + a = alias_get(parse_tree, m->name, CMNDALIAS); + if (a != NULL) { + rc = cmndlist_matches(parse_tree, &a->members); if (rc != UNSPEC) matched = m->negated ? !rc : rc; alias_put(a); diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c index d7f3e7e21..f61518636 100644 --- a/plugins/sudoers/parse.c +++ b/plugins/sudoers/parse.c @@ -65,19 +65,18 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, CLR(validated, FLAG_NO_HOST); match = DENY; TAILQ_FOREACH(nss, snl, entries) { - struct userspec_list *usl = nss->query(nss, pw); - if (usl == NULL) { + if (nss->query(nss, pw) == -1) { /* The query function should have printed an error message. */ SET(validated, VALIDATE_ERROR); break; } - TAILQ_FOREACH(us, usl, entries) { - if (userlist_matches(pw, &us->users) != ALLOW) + TAILQ_FOREACH(us, &nss->parse_tree->userspecs, entries) { + if (userlist_matches(nss->parse_tree, pw, &us->users) != ALLOW) continue; TAILQ_FOREACH(priv, &us->privileges, entries) { int priv_nopass = UNSPEC; - if (hostlist_matches(pw, &priv->hostlist) != ALLOW) + if (hostlist_matches(nss->parse_tree, pw, &priv->hostlist) != ALLOW) continue; TAILQ_FOREACH(def, &priv->defaults, entries) { if (strcmp(def->var, "authenticate") == 0) @@ -96,7 +95,7 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, /* Only check the command when listing another user. */ if (user_uid == 0 || list_pw == NULL || user_uid == list_pw->pw_uid || - cmnd_matches(cs->cmnd) == ALLOW) + cmnd_matches(nss->parse_tree, cs->cmnd) == ALLOW) match = ALLOW; } } @@ -115,7 +114,7 @@ sudoers_lookup_pseudo(struct sudo_nss_list *snl, struct passwd *pw, } static int -sudoers_lookup_check(struct userspec_list *usl, struct passwd *pw, +sudoers_lookup_check(struct sudo_nss *nss, struct passwd *pw, int *validated, struct cmndspec **matching_cs, struct defaults_list **defs, time_t now) { @@ -126,12 +125,12 @@ sudoers_lookup_check(struct userspec_list *usl, struct passwd *pw, struct member *matching_user; debug_decl(sudoers_lookup_check, SUDOERS_DEBUG_PARSER) - TAILQ_FOREACH_REVERSE(us, usl, userspec_list, entries) { - if (userlist_matches(pw, &us->users) != ALLOW) + TAILQ_FOREACH_REVERSE(us, &nss->parse_tree->userspecs, userspec_list, entries) { + if (userlist_matches(nss->parse_tree, pw, &us->users) != ALLOW) continue; CLR(*validated, FLAG_NO_USER); TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) { - host_match = hostlist_matches(pw, &priv->hostlist); + host_match = hostlist_matches(nss->parse_tree, pw, &priv->hostlist); if (host_match == ALLOW) CLR(*validated, FLAG_NO_HOST); else @@ -146,10 +145,11 @@ sudoers_lookup_check(struct userspec_list *usl, struct passwd *pw, continue; } matching_user = NULL; - runas_match = runaslist_matches(cs->runasuserlist, - cs->runasgrouplist, &matching_user, NULL); + runas_match = runaslist_matches(nss->parse_tree, + cs->runasuserlist, cs->runasgrouplist, &matching_user, + NULL); if (runas_match == ALLOW) { - cmnd_match = cmnd_matches(cs->cmnd); + cmnd_match = cmnd_matches(nss->parse_tree, cs->cmnd); if (cmnd_match != UNSPEC) { /* * If user is running command as himself, @@ -273,6 +273,7 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated, int pwflag) { struct defaults_list *defs = NULL; + struct sudoers_parse_tree *parse_tree = NULL; struct cmndspec *cs = NULL; struct sudo_nss *nss; int m, match = UNSPEC; @@ -292,23 +293,24 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated, /* Query each sudoers source and check the user. */ time(&now); TAILQ_FOREACH(nss, snl, entries) { - struct userspec_list *usl = nss->query(nss, pw); - if (usl == NULL) { + if (nss->query(nss, pw) == -1) { /* The query function should have printed an error message. */ SET(validated, VALIDATE_ERROR); break; } - m = sudoers_lookup_check(usl, pw, &validated, &cs, &defs, now); - if (m != UNSPEC) + m = sudoers_lookup_check(nss, pw, &validated, &cs, &defs, now); + if (m != UNSPEC) { match = m; + parse_tree = nss->parse_tree; + } if (!sudo_nss_can_continue(nss, m)) break; } - if (defs != NULL) - update_defaults(defs, SETDEF_GENERIC, false); if (match != UNSPEC) { + if (defs != NULL) + update_defaults(parse_tree, SETDEF_GENERIC, false); if (!apply_cmndspec(cs)) SET(validated, VALIDATE_ERROR); else if (match == ALLOW) @@ -322,8 +324,8 @@ sudoers_lookup(struct sudo_nss_list *snl, struct passwd *pw, int validated, } static int -display_priv_short(struct passwd *pw, struct userspec *us, - struct sudo_lbuf *lbuf) +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; @@ -332,7 +334,7 @@ display_priv_short(struct passwd *pw, struct userspec *us, debug_decl(display_priv_short, SUDOERS_DEBUG_PARSER) TAILQ_FOREACH(priv, &us->privileges, entries) { - if (hostlist_matches(pw, &priv->hostlist) != ALLOW) + if (hostlist_matches(parse_tree, pw, &priv->hostlist) != ALLOW) continue; prev_cs = NULL; TAILQ_FOREACH(cs, &priv->cmndlist, entries) { @@ -345,7 +347,8 @@ display_priv_short(struct passwd *pw, struct userspec *us, TAILQ_FOREACH(m, cs->runasuserlist, entries) { if (m != TAILQ_FIRST(cs->runasuserlist)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, ", ", RUNASALIAS); + sudoers_format_member(lbuf, parse_tree, m, ", ", + RUNASALIAS); } } else if (cs->runasgrouplist == NULL) { sudo_lbuf_append(lbuf, "%s", def_runas_default); @@ -357,14 +360,15 @@ display_priv_short(struct passwd *pw, struct userspec *us, TAILQ_FOREACH(m, cs->runasgrouplist, entries) { if (m != TAILQ_FIRST(cs->runasgrouplist)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, ", ", RUNASALIAS); + sudoers_format_member(lbuf, parse_tree, m, ", ", + RUNASALIAS); } } sudo_lbuf_append(lbuf, ") "); } else if (cs != TAILQ_FIRST(&priv->cmndlist)) { sudo_lbuf_append(lbuf, ", "); } - sudoers_format_cmndspec(lbuf, cs, prev_cs, true); + sudoers_format_cmndspec(lbuf, parse_tree, cs, prev_cs, true); prev_cs = cs; nfound++; } @@ -409,8 +413,8 @@ new_long_entry(struct cmndspec *cs, struct cmndspec *prev_cs) } static int -display_priv_long(struct passwd *pw, struct userspec *us, - struct sudo_lbuf *lbuf) +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; @@ -418,7 +422,7 @@ display_priv_long(struct passwd *pw, struct userspec *us, debug_decl(display_priv_long, SUDOERS_DEBUG_PARSER) TAILQ_FOREACH(priv, &us->privileges, entries) { - if (hostlist_matches(pw, &priv->hostlist) != ALLOW) + if (hostlist_matches(parse_tree, pw, &priv->hostlist) != ALLOW) continue; prev_cs = NULL; TAILQ_FOREACH(cs, &priv->cmndlist, entries) { @@ -437,7 +441,8 @@ display_priv_long(struct passwd *pw, struct userspec *us, TAILQ_FOREACH(m, cs->runasuserlist, entries) { if (m != TAILQ_FIRST(cs->runasuserlist)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, ", ", RUNASALIAS); + sudoers_format_member(lbuf, parse_tree, m, ", ", + RUNASALIAS); } } else if (cs->runasgrouplist == NULL) { sudo_lbuf_append(lbuf, "%s", def_runas_default); @@ -450,7 +455,8 @@ display_priv_long(struct passwd *pw, struct userspec *us, TAILQ_FOREACH(m, cs->runasgrouplist, entries) { if (m != TAILQ_FIRST(cs->runasgrouplist)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, ", ", RUNASALIAS); + sudoers_format_member(lbuf, parse_tree, m, ", ", + RUNASALIAS); } sudo_lbuf_append(lbuf, "\n"); } @@ -512,7 +518,8 @@ display_priv_long(struct passwd *pw, struct userspec *us, sudo_lbuf_append(lbuf, _(" Commands:\n")); } sudo_lbuf_append(lbuf, "\t"); - sudoers_format_member(lbuf, cs->cmnd, "\n\t", CMNDALIAS); + sudoers_format_member(lbuf, parse_tree, cs->cmnd, "\n\t", + CMNDALIAS); sudo_lbuf_append(lbuf, "\n"); prev_cs = cs; nfound++; @@ -522,21 +529,21 @@ display_priv_long(struct passwd *pw, struct userspec *us, } static int -sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw, +sudo_display_userspecs(struct sudoers_parse_tree *parse_tree, struct passwd *pw, struct sudo_lbuf *lbuf) { struct userspec *us; int nfound = 0; debug_decl(sudo_display_userspecs, SUDOERS_DEBUG_PARSER) - TAILQ_FOREACH(us, usl, entries) { - if (userlist_matches(pw, &us->users) != ALLOW) + TAILQ_FOREACH(us, &parse_tree->userspecs, entries) { + if (userlist_matches(parse_tree, pw, &us->users) != ALLOW) continue; if (long_list) - nfound += display_priv_long(pw, us, lbuf); + nfound += display_priv_long(parse_tree, pw, us, lbuf); else - nfound += display_priv_short(pw, us, lbuf); + nfound += display_priv_short(parse_tree, pw, us, lbuf); } if (sudo_lbuf_error(lbuf)) debug_return_int(-1); @@ -547,7 +554,7 @@ sudo_display_userspecs(struct userspec_list *usl, struct passwd *pw, * Display matching Defaults entries for the given user on this host. */ static int -display_defaults(struct defaults_list *defs, struct passwd *pw, +display_defaults(struct sudoers_parse_tree *parse_tree, struct passwd *pw, struct sudo_lbuf *lbuf) { struct defaults *d; @@ -560,14 +567,14 @@ display_defaults(struct defaults_list *defs, struct passwd *pw, else prefix = ", "; - TAILQ_FOREACH(d, defs, entries) { + TAILQ_FOREACH(d, &parse_tree->defaults, entries) { switch (d->type) { case DEFAULTS_HOST: - if (hostlist_matches(pw, d->binding) != ALLOW) + if (hostlist_matches(parse_tree, pw, d->binding) != ALLOW) continue; break; case DEFAULTS_USER: - if (userlist_matches(pw, d->binding) != ALLOW) + if (userlist_matches(parse_tree, pw, d->binding) != ALLOW) continue; break; case DEFAULTS_RUNAS: @@ -588,8 +595,8 @@ display_defaults(struct defaults_list *defs, struct passwd *pw, * Display Defaults entries of the given type. */ static int -display_bound_defaults_by_type(struct defaults_list *defs, int deftype, - struct sudo_lbuf *lbuf) +display_bound_defaults_by_type(struct sudoers_parse_tree *parse_tree, + int deftype, struct sudo_lbuf *lbuf) { struct defaults *d; struct member_list *binding = NULL; @@ -618,7 +625,7 @@ display_bound_defaults_by_type(struct defaults_list *defs, int deftype, default: debug_return_int(-1); } - TAILQ_FOREACH(d, defs, entries) { + TAILQ_FOREACH(d, &parse_tree->defaults, entries) { if (d->type != deftype) continue; @@ -631,7 +638,7 @@ display_bound_defaults_by_type(struct defaults_list *defs, int deftype, TAILQ_FOREACH(m, binding, entries) { if (m != TAILQ_FIRST(binding)) sudo_lbuf_append(lbuf, ","); - sudoers_format_member(lbuf, m, ", ", atype); + sudoers_format_member(lbuf, parse_tree, m, ", ", atype); sudo_lbuf_append(lbuf, " "); } } else @@ -648,15 +655,15 @@ display_bound_defaults_by_type(struct defaults_list *defs, int deftype, * Display Defaults entries that are per-runas or per-command */ static int -display_bound_defaults(struct defaults_list *defs, struct passwd *pw, - struct sudo_lbuf *lbuf) +display_bound_defaults(struct sudoers_parse_tree *parse_tree, + struct passwd *pw, struct sudo_lbuf *lbuf) { int nfound = 0; debug_decl(display_bound_defaults, SUDOERS_DEBUG_PARSER) /* XXX - should only print ones that match what the user can do. */ - nfound += display_bound_defaults_by_type(defs, DEFAULTS_RUNAS, lbuf); - nfound += display_bound_defaults_by_type(defs, DEFAULTS_CMND, lbuf); + nfound += display_bound_defaults_by_type(parse_tree, DEFAULTS_RUNAS, lbuf); + nfound += display_bound_defaults_by_type(parse_tree, DEFAULTS_CMND, lbuf); if (sudo_lbuf_error(lbuf)) debug_return_int(-1); @@ -703,13 +710,10 @@ display_privs(struct sudo_nss_list *snl, struct passwd *pw) pw->pw_name, user_srunhost); count = 0; TAILQ_FOREACH(nss, snl, entries) { - struct defaults_list *defs = nss->getdefs(nss); - if (defs != NULL) { - n = display_defaults(defs, pw, &def_buf); - if (n == -1) - goto bad; - count += n; - } + n = display_defaults(nss->parse_tree, pw, &def_buf); + if (n == -1) + goto bad; + count += n; } if (count != 0) { sudo_lbuf_append(&def_buf, "\n\n"); @@ -724,13 +728,10 @@ display_privs(struct sudo_nss_list *snl, struct passwd *pw) pw->pw_name); count = 0; TAILQ_FOREACH(nss, snl, entries) { - struct defaults_list *defs = nss->getdefs(nss); - if (defs != NULL) { - n = display_bound_defaults(defs, pw, &def_buf); - if (n == -1) - goto bad; - count += n; - } + n = display_bound_defaults(nss->parse_tree, pw, &def_buf); + if (n == -1) + goto bad; + count += n; } if (count != 0) { sudo_lbuf_append(&def_buf, "\n\n"); @@ -745,9 +746,8 @@ display_privs(struct sudo_nss_list *snl, struct passwd *pw) pw->pw_name, user_srunhost); count = 0; TAILQ_FOREACH(nss, snl, entries) { - struct userspec_list *usl = nss->query(nss, pw); - if (usl != NULL) { - n = sudo_display_userspecs(usl, pw, &priv_buf); + if (nss->query(nss, pw) != -1) { + n = sudo_display_userspecs(nss->parse_tree, pw, &priv_buf); if (n == -1) goto bad; count += n; @@ -778,7 +778,8 @@ bad: } static int -display_cmnd_check(struct userspec_list *usl, struct passwd *pw, time_t now) +display_cmnd_check(struct sudoers_parse_tree *parse_tree, struct passwd *pw, + time_t now) { int host_match, runas_match, cmnd_match; struct cmndspec *cs; @@ -786,11 +787,11 @@ display_cmnd_check(struct userspec_list *usl, struct passwd *pw, time_t now) struct userspec *us; debug_decl(display_cmnd_check, SUDOERS_DEBUG_PARSER) - TAILQ_FOREACH_REVERSE(us, usl, userspec_list, entries) { - if (userlist_matches(pw, &us->users) != ALLOW) + TAILQ_FOREACH_REVERSE(us, &parse_tree->userspecs, userspec_list, entries) { + if (userlist_matches(parse_tree, pw, &us->users) != ALLOW) continue; TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) { - host_match = hostlist_matches(pw, &priv->hostlist); + host_match = hostlist_matches(parse_tree, pw, &priv->hostlist); if (host_match != ALLOW) continue; TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) { @@ -802,10 +803,10 @@ display_cmnd_check(struct userspec_list *usl, struct passwd *pw, time_t now) if (now > cs->notafter) continue; } - runas_match = runaslist_matches(cs->runasuserlist, + runas_match = runaslist_matches(parse_tree, cs->runasuserlist, cs->runasgrouplist, NULL, NULL); if (runas_match == ALLOW) { - cmnd_match = cmnd_matches(cs->cmnd); + cmnd_match = cmnd_matches(parse_tree, cs->cmnd); if (cmnd_match != UNSPEC) debug_return_int(cmnd_match); } @@ -832,13 +833,12 @@ display_cmnd(struct sudo_nss_list *snl, struct passwd *pw) /* Iterate over each source, checking for the command. */ time(&now); TAILQ_FOREACH(nss, snl, entries) { - struct userspec_list *usl = nss->query(nss, pw); - if (usl == NULL) { + if (nss->query(nss, pw) == -1) { /* The query function should have printed an error message. */ debug_return_int(-1); } - m = display_cmnd_check(usl, pw, now); + m = display_cmnd_check(nss->parse_tree, pw, now); if (m != UNSPEC) match = m; diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h index 1216f2823..4d93069e7 100644 --- a/plugins/sudoers/parse.h +++ b/plugins/sudoers/parse.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 1998-2000, 2004, 2007-2016 + * Copyright (c) 1996, 1998-2000, 2004, 2007-2018 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -239,26 +239,29 @@ struct defaults { }; /* - * Parsed sudoers info. + * Parsed sudoers policy. */ -extern struct userspec_list userspecs; -extern struct defaults_list defaults; +struct sudoers_parse_tree { + struct userspec_list userspecs; + struct defaults_list defaults; + struct rbtree *aliases; +}; /* alias.c */ -bool no_aliases(void); -struct rbtree *replace_aliases(struct rbtree *new_aliases); -const char *alias_add(char *name, int type, char *file, int lineno, struct member *members); +struct rbtree *alloc_aliases(void); +void free_aliases(struct rbtree *aliases); +bool no_aliases(struct sudoers_parse_tree *parse_tree); +const char *alias_add(struct sudoers_parse_tree *parse_tree, char *name, int type, char *file, int lineno, struct member *members); const char *alias_type_to_string(int alias_type); -int alias_compare(const void *a1, const void *a2); -struct alias *alias_get(const char *name, int type); -struct alias *alias_remove(char *name, int type); -bool alias_find_used(struct rbtree *used_aliases); -void alias_apply(int (*func)(void *, void *), void *cookie); +struct alias *alias_get(struct sudoers_parse_tree *parse_tree, const char *name, int type); +struct alias *alias_remove(struct sudoers_parse_tree *parse_tree, char *name, int type); +bool alias_find_used(struct sudoers_parse_tree *parse_tree, struct rbtree *used_aliases); +void alias_apply(struct sudoers_parse_tree *parse_tree, int (*func)(void *, void *), void *cookie); void alias_free(void *a); void alias_put(struct alias *a); -bool init_aliases(void); /* gram.c */ +extern struct sudoers_parse_tree parsed_policy; bool init_parser(const char *path, bool quiet); void free_member(struct member *m); void free_members(struct member_list *members); @@ -267,6 +270,9 @@ void free_userspec(struct userspec *us); void free_userspecs(struct userspec_list *usl); void free_default(struct defaults *def, struct member_list **binding); void free_defaults(struct defaults_list *defs); +void init_parse_tree(struct sudoers_parse_tree *parse_tree); +void free_parse_tree(struct sudoers_parse_tree *parse_tree); +void reparent_parse_tree(struct sudoers_parse_tree *new_tree); /* match_addr.c */ bool addr_matches(char *n); @@ -280,13 +286,13 @@ bool hostname_matches(const char *shost, const char *lhost, const char *pattern) bool netgr_matches(const char *netgr, const char *lhost, const char *shost, const char *user); bool usergr_matches(const char *group, const char *user, const struct passwd *pw); bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw); -int cmnd_matches(const struct member *m); -int cmndlist_matches(const struct member_list *list); -int host_matches(const struct passwd *pw, const char *host, const char *shost, const struct member *m); -int hostlist_matches(const struct passwd *pw, const struct member_list *list); -int runaslist_matches(const struct member_list *user_list, const struct member_list *group_list, struct member **matching_user, struct member **matching_group); -int user_matches(const struct passwd *pw, const struct member *m); -int userlist_matches(const struct passwd *pw, const struct member_list *list); +int cmnd_matches(struct sudoers_parse_tree *parse_tree, const struct member *m); +int cmndlist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *list); +int host_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const char *host, const char *shost, const struct member *m); +int hostlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const struct member_list *list); +int runaslist_matches(struct sudoers_parse_tree *parse_tree, const struct member_list *user_list, const struct member_list *group_list, struct member **matching_user, struct member **matching_group); +int user_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const struct member *m); +int userlist_matches(struct sudoers_parse_tree *parse_tree, const struct passwd *pw, const struct member_list *list); const char *sudo_getdomainname(void); /* toke.c */ @@ -322,12 +328,12 @@ 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 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, bool expand_aliases); bool sudoers_format_default(struct sudo_lbuf *lbuf, struct defaults *d); -bool sudoers_format_default_line(struct sudo_lbuf *lbuf, struct defaults *d, struct defaults **next, bool expand_aliases); -bool sudoers_format_member(struct sudo_lbuf *lbuf, struct member *m, const char *separator, int alias_type); -bool sudoers_format_privilege(struct sudo_lbuf *lbuf, struct privilege *priv, bool expand_aliases); -bool sudoers_format_userspec(struct sudo_lbuf *lbuf, struct userspec *us, bool expand_aliases); -bool sudoers_format_userspecs(struct sudo_lbuf *lbuf, struct userspec_list *usl, const char *separator, bool expand_aliases, bool flush); +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); #endif /* SUDOERS_PARSE_H */ diff --git a/plugins/sudoers/sssd.c b/plugins/sudoers/sssd.c index 1b5df7fe6..0c66a4b1a 100644 --- a/plugins/sudoers/sssd.c +++ b/plugins/sudoers/sssd.c @@ -83,9 +83,7 @@ struct sudo_sss_handle { char *ipa_shost; struct passwd *pw; void *ssslib; - struct userspec_list userspecs; - struct defaults_list defaults; - bool cached_defaults; + struct sudoers_parse_tree parse_tree; sss_sudo_send_recv_t fn_send_recv; sss_sudo_send_recv_defaults_t fn_send_recv_defaults; sss_sudo_free_result_t fn_free_result; @@ -237,7 +235,7 @@ val_array_iter(void **vp) static bool sss_to_sudoers(struct sudo_sss_handle *handle, - struct sss_sudo_result *sss_result, struct userspec_list *sss_userspecs) + struct sss_sudo_result *sss_result) { struct userspec *us; struct member *m; @@ -250,7 +248,7 @@ sss_to_sudoers(struct sudo_sss_handle *handle, TAILQ_INIT(&us->users); TAILQ_INIT(&us->privileges); STAILQ_INIT(&us->comments); - TAILQ_INSERT_TAIL(sss_userspecs, us, entries); + TAILQ_INSERT_TAIL(&handle->parse_tree.userspecs, us, entries); /* We only include rules where the user matches. */ if ((m = calloc(1, sizeof(*m))) == NULL) @@ -387,7 +385,7 @@ sss_to_sudoers(struct sudo_sss_handle *handle, oom: sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); - free_userspecs(sss_userspecs); + free_userspecs(&handle->parse_tree.userspecs); debug_return_bool(false); } @@ -517,8 +515,7 @@ sudo_sss_close(struct sudo_nss *nss) free(handle->ipa_host); if (handle->ipa_host != handle->ipa_shost) free(handle->ipa_shost); - free_userspecs(&handle->userspecs); - free_defaults(&handle->defaults); + free_parse_tree(&handle->parse_tree); free(handle); nss->handle = NULL; } @@ -544,9 +541,7 @@ sudo_sss_open(struct sudo_nss *nss) sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); debug_return_int(ENOMEM); } - - TAILQ_INIT(&handle->userspecs); - TAILQ_INIT(&handle->defaults); + init_parse_tree(&handle->parse_tree); /* Load symbols */ handle->ssslib = sudo_dso_load(path, SUDO_DSO_LAZY); @@ -625,18 +620,18 @@ sudo_sss_open(struct sudo_nss *nss) /* * Perform query for user and host and convert to sudoers parse tree. */ -static struct userspec_list * +static int sudo_sss_query(struct sudo_nss *nss, struct passwd *pw) { struct sudo_sss_handle *handle = nss->handle; struct sss_sudo_result *sss_result = NULL; - struct userspec_list *ret = &handle->userspecs; + int ret = 0; debug_decl(sudo_sss_query, SUDOERS_DEBUG_SSSD); if (handle == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: called with NULL handle", __func__); - debug_return_ptr(NULL); + debug_return_int(-1); } /* Use cached result if it matches pw. */ @@ -648,7 +643,7 @@ sudo_sss_query(struct sudo_nss *nss, struct passwd *pw) } /* Free old userspecs, if any. */ - free_userspecs(&handle->userspecs); + free_userspecs(&handle->parse_tree.userspecs); /* Fetch list of sudoRole entries that match user and host. */ sss_result = sudo_sss_result_get(nss, pw); @@ -657,45 +652,59 @@ sudo_sss_query(struct sudo_nss *nss, struct passwd *pw) "searching SSSD/LDAP for sudoers entries for user %s, host %s", pw->pw_name, user_runhost); - if (sss_result == NULL) - goto done; - /* Stash a ref to the passwd struct in the handle. */ sudo_pw_addref(pw); handle->pw = pw; - /* Convert to sudoers parse tree. */ - if (!sss_to_sudoers(handle, sss_result, &handle->userspecs)) { - ret = NULL; - goto done; + /* Convert to sudoers parse tree if the user was found. */ + if (sss_result != NULL) { + if (!sss_to_sudoers(handle, sss_result)) { + ret = -1; + goto done; + } } done: /* Cleanup */ handle->fn_free_result(sss_result); - if (ret == NULL) { - free_userspecs(&handle->userspecs); - sudo_pw_delref(handle->pw); - handle->pw = NULL; + if (ret == -1) { + free_userspecs(&handle->parse_tree.userspecs); + if (handle->pw != NULL) { + sudo_pw_delref(handle->pw); + handle->pw = NULL; + } } sudo_debug_printf(SUDO_DEBUG_DIAG, "Done with LDAP searches"); - debug_return_ptr(ret); + debug_return_int(ret); } -static int +/* + * Return the initialized (but empty) sudoers parse tree. + * The contents will be populated by the getdefs() and query() functions. + */ +static struct sudoers_parse_tree * sudo_sss_parse(struct sudo_nss *nss) { + struct sudo_sss_handle *handle = nss->handle; debug_decl(sudo_sss_parse, SUDOERS_DEBUG_SSSD); - debug_return_int(0); + + if (handle == NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR, + "%s: called with NULL handle", __func__); + debug_return_ptr(NULL); + } + + debug_return_ptr(&handle->parse_tree); } -static struct defaults_list * +static int sudo_sss_getdefs(struct sudo_nss *nss) { struct sudo_sss_handle *handle = nss->handle; struct sss_sudo_result *sss_result = NULL; + static bool cached; uint32_t sss_error; unsigned int i; int rc; @@ -704,12 +713,12 @@ sudo_sss_getdefs(struct sudo_nss *nss) if (handle == NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: called with NULL handle", __func__); - debug_return_ptr(NULL); + debug_return_int(-1); } /* Use cached result if present. */ - if (handle->cached_defaults) - debug_return_ptr(&handle->defaults); + if (cached) + debug_return_int(0); sudo_debug_printf(SUDO_DEBUG_DIAG, "Looking for cn=defaults"); @@ -725,7 +734,7 @@ sudo_sss_getdefs(struct sudo_nss *nss) default: sudo_debug_printf(SUDO_DEBUG_ERROR, "handle->fn_send_recv_defaults: rc=%d, sss_error=%u", rc, sss_error); - debug_return_ptr(NULL); + debug_return_int(-1); } switch (sss_error) { @@ -735,7 +744,8 @@ sudo_sss_getdefs(struct sudo_nss *nss) struct sss_sudo_rule *sss_rule = sss_result->rules + i; sudo_debug_printf(SUDO_DEBUG_DIAG, "Parsing cn=defaults, %d/%d", i, sss_result->num_rules); - if (!sudo_sss_parse_options(handle, sss_rule, &handle->defaults)) + if (!sudo_sss_parse_options(handle, sss_rule, + &handle->parse_tree.defaults)) goto bad; } break; @@ -747,13 +757,13 @@ sudo_sss_getdefs(struct sudo_nss *nss) sudo_debug_printf(SUDO_DEBUG_ERROR, "sss_error=%u\n", sss_error); goto bad; } - handle->cached_defaults = true; handle->fn_free_result(sss_result); - debug_return_ptr(&handle->defaults); + cached = true; + debug_return_int(0); bad: handle->fn_free_result(sss_result); - debug_return_ptr(NULL); + debug_return_int(-1); } /* sudo_nss implementation */ diff --git a/plugins/sudoers/sudo_nss.h b/plugins/sudoers/sudo_nss.h index d6d3aa3c0..e4566f8ff 100644 --- a/plugins/sudoers/sudo_nss.h +++ b/plugins/sudoers/sudo_nss.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2007-2011, 2013-2015 Todd C. Miller + * Copyright (c) 2007-2011, 2013-2015, 2017-2018 + * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,14 +22,16 @@ struct passwd; struct userspec_list; struct defaults_list; +/* XXX - parse_tree, ret_if_found and ret_if_notfound should be private */ struct sudo_nss { TAILQ_ENTRY(sudo_nss) entries; int (*open)(struct sudo_nss *nss); int (*close)(struct sudo_nss *nss); - int (*parse)(struct sudo_nss *nss); - struct userspec_list *(*query)(struct sudo_nss *nss, struct passwd *pw); - struct defaults_list *(*getdefs)(struct sudo_nss *nss); + struct sudoers_parse_tree *(*parse)(struct sudo_nss *nss); + int (*query)(struct sudo_nss *nss, struct passwd *pw); + int (*getdefs)(struct sudo_nss *nss); void *handle; + struct sudoers_parse_tree *parse_tree; bool ret_if_found; bool ret_if_notfound; }; diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c index 47fea3400..28c6ada56 100644 --- a/plugins/sudoers/sudoers.c +++ b/plugins/sudoers/sudoers.c @@ -192,17 +192,17 @@ sudoers_policy_init(void *info, char * const envp[]) sudo_warn_set_locale_func(sudoers_warn_setlocale); init_parser(sudoers_file, false); TAILQ_FOREACH_SAFE(nss, snl, entries, nss_next) { - if (nss->open(nss) == 0 && nss->parse(nss) == 0) { - struct defaults_list *defs = nss->getdefs(nss); - sources++; - if (defs == NULL || !update_defaults(defs, - SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false)) { - log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR, - N_("problem with defaults entries")); - } - } else { + if (nss->open(nss) == -1 || (nss->parse_tree = nss->parse(nss)) == NULL) { TAILQ_REMOVE(snl, nss, entries); - } + continue; + } + + sources++; + if (nss->getdefs(nss) == -1 || !update_defaults(nss->parse_tree, + SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS, false)) { + log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR, + N_("problem with defaults entries")); + } } if (sources == 0) { sudo_warnx(U_("no valid sudoers sources found, quitting")); @@ -243,12 +243,12 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], /* Is root even allowed to run sudo? */ if (user_uid == 0 && !def_root_sudo) { /* Not an audit event. */ - sudo_warnx(U_("sudoers specifies that root is not allowed to sudo")); - goto bad; + sudo_warnx(U_("sudoers specifies that root is not allowed to sudo")); + goto bad; } if (!set_perms(PERM_INITIAL)) - goto bad; + goto bad; /* Environment variables specified on the command line. */ if (env_add != NULL && env_add[0] != NULL) @@ -854,8 +854,7 @@ set_cmnd(void) user_base = user_cmnd; TAILQ_FOREACH(nss, snl, entries) { - struct defaults_list *defs = nss->getdefs(nss); - if (defs == NULL || !update_defaults(defs, SETDEF_CMND, false)) { + if (!update_defaults(nss->parse_tree, SETDEF_CMND, false)) { log_warningx(SLOG_SEND_MAIL|SLOG_NO_STDERR, N_("problem with defaults entries")); } diff --git a/plugins/sudoers/testsudoers.c b/plugins/sudoers/testsudoers.c index 556f4ae69..fde8b743e 100644 --- a/plugins/sudoers/testsudoers.c +++ b/plugins/sudoers/testsudoers.c @@ -285,7 +285,7 @@ main(int argc, char *argv[]) (void) fputs("Parses OK", stdout); } - if (!update_defaults(&defaults, SETDEF_ALL, false)) + if (!update_defaults(&parsed_policy, SETDEF_ALL, false)) (void) fputs(" (problem with defaults entries)", stdout); puts("."); @@ -301,22 +301,23 @@ main(int argc, char *argv[]) /* This loop must match the one in sudo_file_lookup() */ printf("\nEntries for user %s:\n", user_name); match = UNSPEC; - TAILQ_FOREACH_REVERSE(us, &userspecs, userspec_list, entries) { - if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) + TAILQ_FOREACH_REVERSE(us, &parsed_policy.userspecs, userspec_list, entries) { + if (userlist_matches(&parsed_policy, sudo_user.pw, &us->users) != ALLOW) continue; TAILQ_FOREACH_REVERSE(priv, &us->privileges, privilege_list, entries) { sudo_lbuf_append(&lbuf, "\n"); - sudoers_format_privilege(&lbuf, priv, false); + sudoers_format_privilege(&lbuf, &parsed_policy, priv, false); sudo_lbuf_print(&lbuf); - host_match = hostlist_matches(sudo_user.pw, &priv->hostlist); + host_match = hostlist_matches(&parsed_policy, sudo_user.pw, + &priv->hostlist); if (host_match == ALLOW) { puts("\thost matched"); TAILQ_FOREACH_REVERSE(cs, &priv->cmndlist, cmndspec_list, entries) { - runas_match = runaslist_matches(cs->runasuserlist, - cs->runasgrouplist, NULL, NULL); + runas_match = runaslist_matches(&parsed_policy, + cs->runasuserlist, cs->runasgrouplist, NULL, NULL); if (runas_match == ALLOW) { puts("\trunas matched"); - cmnd_match = cmnd_matches(cs->cmnd); + cmnd_match = cmnd_matches(&parsed_policy, cs->cmnd); if (cmnd_match != UNSPEC) match = cmnd_match; printf("\tcmnd %s\n", match == ALLOW ? "allowed" : @@ -483,8 +484,8 @@ print_defaults(struct sudo_lbuf *lbuf) struct defaults *def, *next; debug_decl(print_defaults, SUDOERS_DEBUG_UTIL) - TAILQ_FOREACH_SAFE(def, &defaults, entries, next) - sudoers_format_default_line(lbuf, def, &next, false); + TAILQ_FOREACH_SAFE(def, &parsed_policy.defaults, entries, next) + sudoers_format_default_line(lbuf, &parsed_policy, def, &next, false); debug_return_bool(!sudo_lbuf_error(lbuf)); } @@ -502,7 +503,7 @@ print_alias(void *v1, void *v2) TAILQ_FOREACH(m, &a->members, entries) { if (m != TAILQ_FIRST(&a->members)) sudo_lbuf_append(lbuf, ", "); - sudoers_format_member(lbuf, m, NULL, UNSPEC); + sudoers_format_member(lbuf, &parsed_policy, m, NULL, UNSPEC); } sudo_lbuf_append(lbuf, "\n"); @@ -514,7 +515,7 @@ print_aliases(struct sudo_lbuf *lbuf) { debug_decl(print_aliases, SUDOERS_DEBUG_UTIL) - alias_apply(print_alias, lbuf); + alias_apply(&parsed_policy, print_alias, lbuf); debug_return_bool(!sudo_lbuf_error(lbuf)); } @@ -541,7 +542,7 @@ dump_sudoers(struct sudo_lbuf *lbuf) } /* Print User_Specs */ - if (!sudoers_format_userspecs(lbuf, &userspecs, NULL, false, true)) + if (!sudoers_format_userspecs(lbuf, &parsed_policy, NULL, false, true)) goto done; if (lbuf->len > 1) { sudo_lbuf_print(lbuf); diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c index dd9c03d67..340dbb5c5 100644 --- a/plugins/sudoers/visudo.c +++ b/plugins/sudoers/visudo.c @@ -246,8 +246,8 @@ main(int argc, char *argv[]) init_parser(sudoers_file, quiet); sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); (void) sudoersparse(); - (void) update_defaults(&defaults, SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, - quiet); + (void) update_defaults(&parsed_policy, + SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, quiet); sudoers_setlocale(oldlocale, NULL); editor = get_editor(&editor_argc, &editor_argv); @@ -538,13 +538,13 @@ check_defaults_and_aliases(bool strict, bool quiet) { debug_decl(check_defaults_and_aliases, SUDOERS_DEBUG_UTIL) - if (!check_defaults(quiet)) { + if (!check_defaults(&parsed_policy, quiet)) { struct defaults *d; rcstr_delref(errorfile); errorfile = NULL; errorlineno = -1; /* XXX - should edit all files with errors */ - TAILQ_FOREACH(d, &defaults, entries) { + TAILQ_FOREACH(d, &parsed_policy.defaults, entries) { if (d->error) { /* Defaults parse error, set errorfile/errorlineno. */ errorfile = rcstr_addref(d->file); @@ -602,7 +602,7 @@ reparse_sudoers(char *editor, int editor_argc, char **editor_argv, } fclose(sudoersin); if (!parse_error) { - (void) update_defaults(&defaults, + (void) update_defaults(&parsed_policy, SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true); check_defaults_and_aliases(strict, quiet); } @@ -920,7 +920,7 @@ check_syntax(const char *sudoers_file, bool quiet, bool strict, bool oldperms) sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); } if (!parse_error) { - (void) update_defaults(&defaults, + (void) update_defaults(&parsed_policy, SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER, true); check_defaults_and_aliases(strict, quiet); } @@ -1023,7 +1023,7 @@ check_alias(char *name, int type, char *file, int lineno, bool strict, bool quie int errors = 0; debug_decl(check_alias, SUDOERS_DEBUG_ALIAS) - if ((a = alias_get(name, type)) != NULL) { + if ((a = alias_get(&parsed_policy, name, type)) != NULL) { /* check alias contents */ TAILQ_FOREACH(m, &a->members, entries) { if (m->type != ALIAS) @@ -1071,14 +1071,14 @@ check_aliases(bool strict, bool quiet) int errors = 0; debug_decl(check_aliases, SUDOERS_DEBUG_ALIAS) - used_aliases = rbcreate(alias_compare); + used_aliases = alloc_aliases(); if (used_aliases == NULL) { sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); debug_return_int(-1); } /* Forward check. */ - TAILQ_FOREACH(us, &userspecs, entries) { + TAILQ_FOREACH(us, &parsed_policy.userspecs, entries) { TAILQ_FOREACH(m, &us->users, entries) { if (m->type == ALIAS) { errors += check_alias(m->name, USERALIAS, @@ -1118,13 +1118,13 @@ check_aliases(bool strict, bool quiet) } /* Reverse check (destructive) */ - if (!alias_find_used(used_aliases)) + if (!alias_find_used(&parsed_policy, used_aliases)) errors++; - rbdestroy(used_aliases, alias_free); + free_aliases(used_aliases); /* If all aliases were referenced we will have an empty tree. */ - if (!no_aliases() && !quiet) - alias_apply(print_unused, NULL); + if (!no_aliases(&parsed_policy) && !quiet) + alias_apply(&parsed_policy, print_unused, NULL); debug_return_int(strict ? errors : 0); } -- 2.40.0