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.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -35,16 +35,11 @@
|
||||
#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;
|
||||
@@ -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)
|
||||
|
||||
if (parse_tree->aliases != NULL) {
|
||||
key.name = name;
|
||||
key.type = type;
|
||||
if ((node = rbfind(aliases, &key)) == NULL) {
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
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(init_aliases, SUDOERS_DEBUG_ALIAS)
|
||||
debug_decl(alloc_aliases, SUDOERS_DEBUG_ALIAS)
|
||||
|
||||
debug_return_ptr(rbcreate(alias_compare));
|
||||
}
|
||||
|
||||
void
|
||||
free_aliases(struct rbtree *aliases)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -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];
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -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[];
|
||||
|
||||
|
@@ -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_ptr(&handle->parse_tree);
|
||||
}
|
||||
|
||||
/*
|
||||
* No need for explicit sudoers queries, the parse function handled it.
|
||||
*/
|
||||
static int
|
||||
sudo_file_query(struct sudo_nss *nss, struct passwd *pw)
|
||||
{
|
||||
debug_decl(sudo_file_query, SUDOERS_DEBUG_NSS)
|
||||
debug_return_int(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We return all cached userspecs, the parse functions will
|
||||
* perform matching against pw for us.
|
||||
* No need to get defaults for sudoers file, the parse function handled it.
|
||||
*/
|
||||
static struct userspec_list *
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return cached defaults entries.
|
||||
*/
|
||||
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 */
|
||||
|
@@ -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, " ");
|
||||
|
@@ -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 <Todd.Miller@sudo.ws>
|
||||
*
|
||||
* 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"
|
||||
{
|
||||
;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
#line 198 "gram.y"
|
||||
{
|
||||
;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
case 9:
|
||||
#line 201 "gram.y"
|
||||
{
|
||||
;
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
case 10:
|
||||
#line 204 "gram.y"
|
||||
{
|
||||
;
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
case 11:
|
||||
#line 207 "gram.y"
|
||||
{
|
||||
;
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
#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;
|
||||
|
@@ -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 <Todd.Miller@sudo.ws>
|
||||
*
|
||||
* 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) {
|
||||
|
@@ -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_int(-1);
|
||||
}
|
||||
|
||||
/* Use cached result if it matches pw. */
|
||||
if (handle->pw != NULL) {
|
||||
if (pw == handle->pw) {
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
sudo_pw_delref(handle->pw);
|
||||
handle->pw = NULL;
|
||||
}
|
||||
|
||||
/* Free old userspecs, if any. */
|
||||
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)
|
||||
goto done;
|
||||
|
||||
/* Convert to sudoers parse tree. */
|
||||
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 = 0;
|
||||
|
||||
done:
|
||||
/* Cleanup. */
|
||||
sudo_ldap_result_free(lres);
|
||||
if (ret == -1)
|
||||
free_userspecs(&handle->parse_tree.userspecs);
|
||||
debug_return_int(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_ldap_parse(struct sudo_nss *nss)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* Use cached result if it matches pw. */
|
||||
if (handle->pw != NULL) {
|
||||
if (pw == handle->pw)
|
||||
goto done;
|
||||
sudo_pw_delref(handle->pw);
|
||||
handle->pw = NULL;
|
||||
}
|
||||
|
||||
/* Free old userspecs, if any. */
|
||||
free_userspecs(&handle->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;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Convert to sudoers parse tree. */
|
||||
if (!ldap_to_sudoers(handle->ld, lres, &handle->userspecs)) {
|
||||
ret = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Stash a ref to the passwd struct in the handle. */
|
||||
sudo_pw_addref(pw);
|
||||
handle->pw = pw;
|
||||
|
||||
ret = &handle->userspecs;
|
||||
|
||||
done:
|
||||
/* Cleanup. */
|
||||
sudo_ldap_result_free(lres);
|
||||
if (ret == NULL) {
|
||||
free_userspecs(&handle->userspecs);
|
||||
debug_return_ptr(NULL);
|
||||
}
|
||||
debug_return_ptr(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* STUB
|
||||
*/
|
||||
static int
|
||||
sudo_ldap_parse(struct sudo_nss *nss)
|
||||
{
|
||||
return 0;
|
||||
debug_return_ptr(&handle->parse_tree);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
@@ -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);
|
||||
|
@@ -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,14 +710,11 @@ 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);
|
||||
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");
|
||||
} else {
|
||||
@@ -724,14 +728,11 @@ 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);
|
||||
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");
|
||||
} else {
|
||||
@@ -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;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -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 */
|
||||
|
@@ -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;
|
||||
/* 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);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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 int
|
||||
sudo_sss_parse(struct sudo_nss *nss)
|
||||
{
|
||||
debug_decl(sudo_sss_parse, SUDOERS_DEBUG_SSSD);
|
||||
debug_return_int(0);
|
||||
}
|
||||
|
||||
static struct defaults_list *
|
||||
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 */
|
||||
|
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -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;
|
||||
};
|
||||
|
@@ -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);
|
||||
if (nss->open(nss) == -1 || (nss->parse_tree = nss->parse(nss)) == NULL) {
|
||||
TAILQ_REMOVE(snl, nss, entries);
|
||||
continue;
|
||||
}
|
||||
|
||||
sources++;
|
||||
if (defs == NULL || !update_defaults(defs,
|
||||
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"));
|
||||
}
|
||||
} else {
|
||||
TAILQ_REMOVE(snl, nss, entries);
|
||||
}
|
||||
}
|
||||
if (sources == 0) {
|
||||
sudo_warnx(U_("no valid sudoers sources found, quitting"));
|
||||
@@ -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"));
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user