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.
/*
- * Copyright (c) 2004-2005, 2007-2016
+ * Copyright (c) 2004-2005, 2007-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
#include "redblack.h"
#include <gram.h>
-/*
- * 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;
* 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,
* 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));
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:
* 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));
}
/*
* 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 *
* 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;
}
}
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;
}
}
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) {
if (pw == NULL)
continue;
- if (user_matches(pw, m) == true)
+ if (user_matches(&parsed_policy, pw, m) == true)
matched = true;
sudo_pw_delref(pw);
/* 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;
}
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));
}
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");
{
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));
}
* 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;
}
}
}
if (TAILQ_EMPTY(&us->privileges)) {
- TAILQ_REMOVE(&userspecs, us, entries);
+ TAILQ_REMOVE(&parsed_policy.userspecs, us, entries);
free_userspec(us);
continue;
}
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;
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. */
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) {
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);
}
}
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);
}
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;
}
{
debug_decl(alias_prune, SUDOERS_DEBUG_ALIAS)
- alias_apply(alias_prune_helper, conf);
+ alias_apply(&parsed_policy, alias_prune_helper, conf);
debug_return;
}
/* 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;
}
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,
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);
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);
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;
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);
}
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));
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);
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);
}
U_("unable to allocate memory"));
}
}
- TAILQ_INSERT_TAIL(&defaults, d, entries);
+ TAILQ_INSERT_TAIL(&parsed_policy.defaults, d, entries);
}
debug_return;
}
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) {
/* 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;
}
/*
- * Copyright (c) 1999-2005, 2007-2017
+ * Copyright (c) 1999-2005, 2007-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* 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)
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;
}
* 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;
/*
* 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. */
/*
* 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) */
* 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];
/*
- * Copyright (c) 1999-2005, 2008-2016
+ * Copyright (c) 1999-2005, 2008-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
/*
* 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[];
struct sudo_file_handle {
FILE *fp;
- struct defaults_list defaults;
- struct userspec_list userspecs;
+ struct sudoers_parse_tree parse_tree;
};
static int
fclose(handle->fp);
sudoersin = NULL;
- free_userspecs(&handle->userspecs);
- free_defaults(&handle->defaults);
-
+ free_parse_tree(&handle->parse_tree);
free(handle);
nss->handle = NULL;
}
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;
}
/*
- * 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)
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;
} 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 */
* 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;
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;
}
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) \
* 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)
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));
}
* 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;
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);
}
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);
}
}
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);
}
}
} 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;
}
* 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;
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);
}
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");
* 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);
}
* 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;
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, " ");
#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 <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
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
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 {
int tok;
} YYSTYPE;
#endif /* YYSTYPE_DEFINED */
-#line 130 "gram.c"
+#line 133 "gram.c"
#define COMMAND 257
#define ALIAS 258
#define DEFVAR 259
YYSTYPE *yyvs;
unsigned int yystacksize;
int yyparse(void);
-#line 899 "gram.y"
+#line 906 "gram.y"
void
sudoerserror(const char *s)
{
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);
}
}
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);
}
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.
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) {
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)
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"));
}
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) {
}
break;
case 20:
-#line 243 "gram.y"
+#line 246 "gram.y"
{
yyval.defaults = new_default(yyvsp[0].string, NULL, false);
if (yyval.defaults == NULL) {
}
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) {
}
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) {
}
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) {
}
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) {
}
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) {
}
break;
case 30:
-#line 311 "gram.y"
+#line 314 "gram.y"
{
yyval.member = new_member(NULL, ALL);
if (yyval.member == NULL) {
}
break;
case 31:
-#line 318 "gram.y"
+#line 321 "gram.y"
{
yyval.member = new_member(yyvsp[0].string, NETGROUP);
if (yyval.member == NULL) {
}
break;
case 32:
-#line 325 "gram.y"
+#line 328 "gram.y"
{
yyval.member = new_member(yyvsp[0].string, NTWKADDR);
if (yyval.member == NULL) {
}
break;
case 33:
-#line 332 "gram.y"
+#line 335 "gram.y"
{
yyval.member = new_member(yyvsp[0].string, WORD);
if (yyval.member == NULL) {
}
break;
case 35:
-#line 342 "gram.y"
+#line 345 "gram.y"
{
struct cmndspec *prev;
prev = HLTQ_LAST(yyvsp[-2].cmndspec, cmndspec, entries);
}
break;
case 36:
-#line 395 "gram.y"
+#line 398 "gram.y"
{
struct cmndspec *cs = calloc(1, sizeof(*cs));
if (cs == NULL) {
}
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) {
}
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) {
}
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) {
}
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) {
}
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"));
}
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) {
}
break;
case 55:
-#line 556 "gram.y"
+#line 559 "gram.y"
{
yyval.runas = calloc(1, sizeof(struct runascontainer));
if (yyval.runas == NULL) {
}
break;
case 56:
-#line 565 "gram.y"
+#line 568 "gram.y"
{
yyval.runas = calloc(1, sizeof(struct runascontainer));
if (yyval.runas == NULL) {
}
break;
case 57:
-#line 574 "gram.y"
+#line 577 "gram.y"
{
yyval.runas = calloc(1, sizeof(struct runascontainer));
if (yyval.runas == NULL) {
}
break;
case 58:
-#line 583 "gram.y"
+#line 586 "gram.y"
{
yyval.runas = calloc(1, sizeof(struct runascontainer));
if (yyval.runas != NULL) {
}
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);
}
break;
case 61:
-#line 611 "gram.y"
+#line 614 "gram.y"
{
yyval.options.notafter = parse_gentime(yyvsp[0].string);
free(yyvsp[0].string);
}
break;
case 62:
-#line 619 "gram.y"
+#line 622 "gram.y"
{
yyval.options.timeout = parse_timeout(yyvsp[0].string);
free(yyvsp[0].string);
}
break;
case 63:
-#line 630 "gram.y"
+#line 633 "gram.y"
{
#ifdef HAVE_SELINUX
free(yyval.options.role);
}
break;
case 64:
-#line 636 "gram.y"
+#line 639 "gram.y"
{
#ifdef HAVE_SELINUX
free(yyval.options.type);
}
break;
case 65:
-#line 642 "gram.y"
+#line 645 "gram.y"
{
#ifdef HAVE_PRIV_SET
free(yyval.options.privs);
}
break;
case 66:
-#line 648 "gram.y"
+#line 651 "gram.y"
{
#ifdef HAVE_PRIV_SET
free(yyval.options.limitprivs);
}
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) {
}
break;
case 83:
-#line 710 "gram.y"
+#line 713 "gram.y"
{
yyval.member = new_member(yyvsp[0].string, ALIAS);
if (yyval.member == NULL) {
}
break;
case 84:
-#line 717 "gram.y"
+#line 720 "gram.y"
{
struct sudo_command *c = calloc(1, sizeof(*c));
if (c == NULL) {
}
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;
}
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;
}
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;
}
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;
}
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) {
}
break;
case 106:
-#line 828 "gram.y"
+#line 835 "gram.y"
{
yyval.member = new_member(NULL, ALL);
if (yyval.member == NULL) {
}
break;
case 107:
-#line 835 "gram.y"
+#line 842 "gram.y"
{
yyval.member = new_member(yyvsp[0].string, NETGROUP);
if (yyval.member == NULL) {
}
break;
case 108:
-#line 842 "gram.y"
+#line 849 "gram.y"
{
yyval.member = new_member(yyvsp[0].string, USERGROUP);
if (yyval.member == NULL) {
}
break;
case 109:
-#line 849 "gram.y"
+#line 856 "gram.y"
{
yyval.member = new_member(yyvsp[0].string, WORD);
if (yyval.member == NULL) {
}
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) {
}
break;
case 115:
-#line 882 "gram.y"
+#line 889 "gram.y"
{
yyval.member = new_member(NULL, ALL);
if (yyval.member == NULL) {
}
break;
case 116:
-#line 889 "gram.y"
+#line 896 "gram.y"
{
yyval.member = new_member(yyvsp[0].string, WORD);
if (yyval.member == NULL) {
}
}
break;
-#line 2139 "gram.c"
+#line 2175 "gram.c"
}
yyssp -= yym;
yystate = *yyssp;
%{
/*
- * Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2017
+ * Copyright (c) 1996, 1998-2005, 2007-2013, 2014-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
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
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;
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;
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;
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;
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);
}
}
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);
}
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.
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) {
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
/* 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;
}
}
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);
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);
}
/*
* 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
* 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;
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);
* 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);
* 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;
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);
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);
* 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;
}
* 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);
}
/*
* 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;
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);
* 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;
}
* 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;
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);
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)
/* 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;
}
}
}
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)
{
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
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,
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;
/* 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)
}
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;
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) {
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);
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++;
}
}
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;
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) {
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);
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");
}
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++;
}
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);
* 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;
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:
* 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;
default:
debug_return_int(-1);
}
- TAILQ_FOREACH(d, defs, entries) {
+ TAILQ_FOREACH(d, &parse_tree->defaults, entries) {
if (d->type != deftype)
continue;
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
* 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);
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");
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");
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;
}
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;
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) {
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);
}
/* 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;
/*
- * Copyright (c) 1996, 1998-2000, 2004, 2007-2016
+ * Copyright (c) 1996, 1998-2000, 2004, 2007-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
};
/*
- * 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);
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);
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 */
/* 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 */
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;
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;
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)
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);
}
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;
}
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);
/*
* 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. */
}
/* 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);
"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;
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");
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) {
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;
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 */
/*
- * Copyright (c) 2007-2011, 2013-2015 Todd C. Miller <Todd.Miller@sudo.ws>
+ * Copyright (c) 2007-2011, 2013-2015, 2017-2018
+ * Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
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;
};
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"));
/* 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)
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"));
}
(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(".");
/* 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" :
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));
}
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");
{
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));
}
}
/* 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);
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);
{
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);
}
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);
}
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);
}
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)
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,
}
/* 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);
}