Move alias checking code out of visudo.c and into check_aliases.c.

This commit is contained in:
Todd C. Miller
2021-02-23 18:42:37 -07:00
parent c71a397368
commit 5a85543c16
4 changed files with 47 additions and 131 deletions

View File

@@ -499,6 +499,7 @@ plugins/sudoers/bsm_audit.c
plugins/sudoers/bsm_audit.h plugins/sudoers/bsm_audit.h
plugins/sudoers/check.c plugins/sudoers/check.c
plugins/sudoers/check.h plugins/sudoers/check.h
plugins/sudoers/check_aliases.c
plugins/sudoers/cvtsudoers.c plugins/sudoers/cvtsudoers.c
plugins/sudoers/cvtsudoers.h plugins/sudoers/cvtsudoers.h
plugins/sudoers/cvtsudoers_json.c plugins/sudoers/cvtsudoers_json.c

View File

@@ -186,8 +186,8 @@ SUDOERS_OBJS = $(AUTH_OBJS) audit.lo boottime.lo check.lo editor.lo env.lo \
SUDOERS_IOBJS = $(SUDOERS_OBJS:.lo=.i) SUDOERS_IOBJS = $(SUDOERS_OBJS:.lo=.i)
VISUDO_OBJS = editor.lo find_path.lo goodpath.lo locale.lo stubs.o \ VISUDO_OBJS = check_aliases.o editor.lo find_path.lo goodpath.lo locale.lo \
sudo_printf.o visudo.o stubs.o sudo_printf.o visudo.o
VISUDO_IOBJS = sudo_printf.i visudo.i VISUDO_IOBJS = sudo_printf.i visudo.i
@@ -973,6 +973,30 @@ check_addr.i: $(srcdir)/regress/parser/check_addr.c $(devdir)/def_data.h \
$(CC) -E -o $@ $(CPPFLAGS) $< $(CC) -E -o $@ $(CPPFLAGS) $<
check_addr.plog: check_addr.i check_addr.plog: check_addr.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/parser/check_addr.c --i-file $< --output-file $@ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/parser/check_addr.c --i-file $< --output-file $@
check_aliases.o: $(srcdir)/check_aliases.c $(devdir)/def_data.h \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_eventlog.h $(incdir)/sudo_fatal.h \
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
$(top_builddir)/pathnames.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/check_aliases.c
check_aliases.i: $(srcdir)/check_aliases.c $(devdir)/def_data.h \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_eventlog.h $(incdir)/sudo_fatal.h \
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \
$(top_builddir)/pathnames.h
$(CC) -E -o $@ $(CPPFLAGS) $<
check_aliases.plog: check_aliases.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/check_aliases.c --i-file $< --output-file $@
check_base64.o: $(srcdir)/regress/parser/check_base64.c \ check_base64.o: $(srcdir)/regress/parser/check_base64.c \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_util.h $(top_builddir)/config.h $(incdir)/sudo_util.h $(top_builddir)/config.h
@@ -1551,10 +1575,10 @@ fuzz_sudoers.o: $(srcdir)/regress/fuzz/fuzz_sudoers.c $(devdir)/def_data.h \
$(incdir)/sudo_eventlog.h $(incdir)/sudo_fatal.h \ $(incdir)/sudo_eventlog.h $(incdir)/sudo_fatal.h \
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \ $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \ $(srcdir)/defaults.h $(srcdir)/interfaces.h \
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \ $(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
$(top_builddir)/pathnames.h $(top_builddir)/config.h $(top_builddir)/pathnames.h
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/fuzz/fuzz_sudoers.c $(CC) -c $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/fuzz/fuzz_sudoers.c
fuzz_sudoers.i: $(srcdir)/regress/fuzz/fuzz_sudoers.c $(devdir)/def_data.h \ fuzz_sudoers.i: $(srcdir)/regress/fuzz/fuzz_sudoers.c $(devdir)/def_data.h \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
@@ -1562,10 +1586,10 @@ fuzz_sudoers.i: $(srcdir)/regress/fuzz/fuzz_sudoers.c $(devdir)/def_data.h \
$(incdir)/sudo_eventlog.h $(incdir)/sudo_fatal.h \ $(incdir)/sudo_eventlog.h $(incdir)/sudo_fatal.h \
$(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \ $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \ $(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(srcdir)/defaults.h $(srcdir)/logging.h $(srcdir)/parse.h \ $(srcdir)/defaults.h $(srcdir)/interfaces.h \
$(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \ $(srcdir)/logging.h $(srcdir)/parse.h $(srcdir)/sudo_nss.h \
$(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \
$(top_builddir)/pathnames.h $(top_builddir)/config.h $(top_builddir)/pathnames.h
$(CC) -E -o $@ $(CPPFLAGS) $< $(CC) -E -o $@ $(CPPFLAGS) $<
fuzz_sudoers.plog: fuzz_sudoers.i fuzz_sudoers.plog: fuzz_sudoers.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/fuzz/fuzz_sudoers.c --i-file $< --output-file $@ rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/fuzz/fuzz_sudoers.c --i-file $< --output-file $@

View File

@@ -343,6 +343,9 @@ void alias_apply(struct sudoers_parse_tree *parse_tree, int (*func)(struct sudoe
void alias_free(void *a); void alias_free(void *a);
void alias_put(struct alias *a); void alias_put(struct alias *a);
/* check_aliases.c */
int check_aliases(struct sudoers_parse_tree *parse_tree, bool strict, bool quiet, int (*cb_unused)(struct sudoers_parse_tree *, struct alias *, void *));
/* gram.c */ /* gram.c */
extern struct sudoers_parse_tree parsed_policy; extern struct sudoers_parse_tree parsed_policy;
bool init_parser(const char *path, bool quiet, bool strict); bool init_parser(const char *path, bool quiet, bool strict);

View File

@@ -85,7 +85,6 @@ TAILQ_HEAD(sudoersfile_list, sudoersfile);
*/ */
static void quit(int); static void quit(int);
static int whatnow(void); static int whatnow(void);
static int check_aliases(bool strict, bool quiet);
static char *get_editor(int *editor_argc, char ***editor_argv); static char *get_editor(int *editor_argc, char ***editor_argv);
static bool check_syntax(const char *, bool, bool, bool); static bool check_syntax(const char *, bool, bool, bool);
static bool edit_sudoers(struct sudoersfile *, char *, int, char **, int); static bool edit_sudoers(struct sudoersfile *, char *, int, char **, int);
@@ -565,7 +564,7 @@ check_defaults_and_aliases(bool strict, bool quiet)
} }
parse_error = true; parse_error = true;
} }
if (check_aliases(strict, quiet) != 0) { if (check_aliases(&parsed_policy, strict, quiet, print_unused) != 0) {
parse_error = true; parse_error = true;
} }
debug_return; debug_return;
@@ -1058,128 +1057,17 @@ open_sudoers(const char *path, bool doedit, bool *keepopen)
debug_return_ptr(fp); debug_return_ptr(fp);
} }
static int /* Display unused aliases from check_aliases(). */
check_alias(char *name, int type, char *file, int line, int column,
bool strict, bool quiet)
{
struct member *m;
struct alias *a;
int errors = 0;
debug_decl(check_alias, SUDOERS_DEBUG_ALIAS);
if ((a = alias_get(&parsed_policy, name, type)) != NULL) {
/* check alias contents */
TAILQ_FOREACH(m, &a->members, entries) {
if (m->type != ALIAS)
continue;
errors += check_alias(m->name, type, a->file, a->line, a->column,
strict, quiet);
}
alias_put(a);
} else {
if (!quiet) {
if (errno == ELOOP) {
fprintf(stderr, strict ?
U_("Error: %s:%d:%d: cycle in %s \"%s\"") :
U_("Warning: %s:%d:%d: cycle in %s \"%s\""),
file, line, column, alias_type_to_string(type), name);
} else {
fprintf(stderr, strict ?
U_("Error: %s:%d:%d: %s \"%s\" referenced but not defined") :
U_("Warning: %s:%d:%d: %s \"%s\" referenced but not defined"),
file, line, column, alias_type_to_string(type), name);
}
fputc('\n', stderr);
if (strict && errorfile == NULL) {
errorfile = rcstr_addref(file);
errorlineno = line;
}
}
errors++;
}
debug_return_int(errors);
}
/*
* Iterate through the sudoers datastructures looking for undefined
* aliases or unused aliases.
*/
static int
check_aliases(bool strict, bool quiet)
{
struct rbtree *used_aliases;
struct cmndspec *cs;
struct member *m;
struct privilege *priv;
struct userspec *us;
int errors = 0;
debug_decl(check_aliases, SUDOERS_DEBUG_ALIAS);
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, &parsed_policy.userspecs, entries) {
TAILQ_FOREACH(m, &us->users, entries) {
if (m->type == ALIAS) {
errors += check_alias(m->name, USERALIAS,
us->file, us->line, us->column, strict, quiet);
}
}
TAILQ_FOREACH(priv, &us->privileges, entries) {
TAILQ_FOREACH(m, &priv->hostlist, entries) {
if (m->type == ALIAS) {
errors += check_alias(m->name, HOSTALIAS,
us->file, us->line, us->column, strict, quiet);
}
}
TAILQ_FOREACH(cs, &priv->cmndlist, entries) {
if (cs->runasuserlist != NULL) {
TAILQ_FOREACH(m, cs->runasuserlist, entries) {
if (m->type == ALIAS) {
errors += check_alias(m->name, RUNASALIAS,
us->file, us->line, us->column, strict, quiet);
}
}
}
if (cs->runasgrouplist != NULL) {
TAILQ_FOREACH(m, cs->runasgrouplist, entries) {
if (m->type == ALIAS) {
errors += check_alias(m->name, RUNASALIAS,
us->file, us->line, us->column, strict, quiet);
}
}
}
if ((m = cs->cmnd)->type == ALIAS) {
errors += check_alias(m->name, CMNDALIAS,
us->file, us->line, us->column, strict, quiet);
}
}
}
}
/* Reverse check (destructive) */
if (!alias_find_used(&parsed_policy, used_aliases))
errors++;
free_aliases(used_aliases);
/* If all aliases were referenced we will have an empty tree. */
if (!no_aliases(&parsed_policy) && !quiet)
alias_apply(&parsed_policy, print_unused, NULL);
debug_return_int(strict ? errors : 0);
}
static int static int
print_unused(struct sudoers_parse_tree *parse_tree, struct alias *a, void *v) print_unused(struct sudoers_parse_tree *parse_tree, struct alias *a, void *v)
{ {
fprintf(stderr, U_("Warning: %s:%d:%d: unused %s \"%s\""), const bool quiet = *((bool *)v);
a->file, a->line, a->column, alias_type_to_string(a->type), a->name);
fputc('\n', stderr); if (!quiet) {
fprintf(stderr, U_("Warning: %s:%d:%d: unused %s \"%s\""), a->file,
a->line, a->column, alias_type_to_string(a->type), a->name);
fputc('\n', stderr);
}
return 0; return 0;
} }