diff --git a/MANIFEST b/MANIFEST index 17df54c24..31b6efaed 100644 --- a/MANIFEST +++ b/MANIFEST @@ -499,6 +499,7 @@ plugins/sudoers/bsm_audit.c plugins/sudoers/bsm_audit.h plugins/sudoers/check.c plugins/sudoers/check.h +plugins/sudoers/check_aliases.c plugins/sudoers/cvtsudoers.c plugins/sudoers/cvtsudoers.h plugins/sudoers/cvtsudoers_json.c diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index 1c2768a2b..2655ffc70 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -186,8 +186,8 @@ SUDOERS_OBJS = $(AUTH_OBJS) audit.lo boottime.lo check.lo editor.lo env.lo \ SUDOERS_IOBJS = $(SUDOERS_OBJS:.lo=.i) -VISUDO_OBJS = editor.lo find_path.lo goodpath.lo locale.lo stubs.o \ - sudo_printf.o visudo.o +VISUDO_OBJS = check_aliases.o editor.lo find_path.lo goodpath.lo locale.lo \ + stubs.o sudo_printf.o visudo.o 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) $< 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 $@ +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 \ $(incdir)/compat/stdbool.h $(incdir)/sudo_compat.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_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 + $(srcdir)/defaults.h $(srcdir)/interfaces.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)/regress/fuzz/fuzz_sudoers.c fuzz_sudoers.i: $(srcdir)/regress/fuzz/fuzz_sudoers.c $(devdir)/def_data.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_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 + $(srcdir)/defaults.h $(srcdir)/interfaces.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) $< 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 $@ diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h index 2eb97c5e9..4dc36d45a 100644 --- a/plugins/sudoers/parse.h +++ b/plugins/sudoers/parse.h @@ -343,6 +343,9 @@ void alias_apply(struct sudoers_parse_tree *parse_tree, int (*func)(struct sudoe void alias_free(void *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 */ extern struct sudoers_parse_tree parsed_policy; bool init_parser(const char *path, bool quiet, bool strict); diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c index 653697289..071322960 100644 --- a/plugins/sudoers/visudo.c +++ b/plugins/sudoers/visudo.c @@ -85,7 +85,6 @@ TAILQ_HEAD(sudoersfile_list, sudoersfile); */ static void quit(int); static int whatnow(void); -static int check_aliases(bool strict, bool quiet); static char *get_editor(int *editor_argc, char ***editor_argv); static bool check_syntax(const char *, bool, bool, bool); 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; } - if (check_aliases(strict, quiet) != 0) { + if (check_aliases(&parsed_policy, strict, quiet, print_unused) != 0) { parse_error = true; } debug_return; @@ -1058,128 +1057,17 @@ open_sudoers(const char *path, bool doedit, bool *keepopen) debug_return_ptr(fp); } -static int -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); -} - +/* Display unused aliases from check_aliases(). */ static int print_unused(struct sudoers_parse_tree *parse_tree, struct alias *a, void *v) { - 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); + const bool quiet = *((bool *)v); + + 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; }