Split set_default_entry() out of set_default() so we can call it

from check_defaults() to validate the defaults value.  In visudo,
suppress warnings from update_defaults() and rely on check_defaults()
to provide warnings.
This commit is contained in:
Todd C. Miller
2016-07-23 09:10:48 -06:00
parent 29d842dbaf
commit 2c21663b22
2 changed files with 190 additions and 175 deletions

View File

@@ -197,6 +197,182 @@ dump_defaults(void)
debug_return;
}
static bool
set_default_entry(struct sudo_defs_types *def, const char *val, int op, bool quiet)
{
debug_decl(set_default_entry, SUDOERS_DEBUG_DEFAULTS)
switch (def->type & T_MASK) {
case T_LOGFAC:
if (!store_syslogfac(val, def, op)) {
if (!quiet) {
if (val)
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, def->name);
else
sudo_warnx(U_("no value specified for `%s'"), def->name);
}
debug_return_bool(false);
}
break;
case T_LOGPRI:
if (!store_syslogpri(val, def, op)) {
if (!quiet) {
if (val)
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, def->name);
else
sudo_warnx(U_("no value specified for `%s'"), def->name);
}
debug_return_bool(false);
}
break;
case T_STR:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(def->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), def->name);
debug_return_bool(false);
}
}
if (ISSET(def->type, T_PATH) && val && *val != '/') {
if (!quiet) {
sudo_warnx(U_("values for `%s' must start with a '/'"),
def->name);
}
debug_return_bool(false);
}
switch (store_str(val, def, op)) {
case true:
/* OK */
break;
case false:
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, def->name);
}
/* FALLTHROUGH */
default:
debug_return_bool(false);
}
break;
case T_INT:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(def->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), def->name);
debug_return_bool(false);
}
}
if (!store_int(val, def, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, def->name);
}
debug_return_bool(false);
}
break;
case T_UINT:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(def->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), def->name);
debug_return_bool(false);
}
}
if (!store_uint(val, def, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, def->name);
}
debug_return_bool(false);
}
break;
case T_FLOAT:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(def->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), def->name);
debug_return_bool(false);
}
}
if (!store_float(val, def, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, def->name);
}
debug_return_bool(false);
}
break;
case T_MODE:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(def->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), def->name);
debug_return_bool(false);
}
}
if (!store_mode(val, def, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, def->name);
}
debug_return_bool(false);
}
break;
case T_FLAG:
if (val) {
if (!quiet) {
sudo_warnx(U_("option `%s' does not take a value"),
def->name);
}
debug_return_bool(false);
}
def->sd_un.flag = op;
if (def->callback)
debug_return_bool(def->callback(&def->sd_un));
break;
case T_LIST:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(def->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), def->name);
debug_return_bool(false);
}
}
if (!store_list(val, def, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, def->name);
}
debug_return_bool(false);
}
break;
case T_TUPLE:
if (!val && !ISSET(def->type, T_BOOL)) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), def->name);
debug_return_bool(false);
}
if (!store_tuple(val, def, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, def->name);
}
debug_return_bool(false);
}
break;
}
debug_return_bool(true);
}
/*
* Sets/clears an entry in the defaults structure
* If a variable that takes a value is used in a boolean
@@ -221,171 +397,7 @@ set_default(const char *var, const char *val, int op, bool quiet)
debug_return_bool(false);
}
switch (cur->type & T_MASK) {
case T_LOGFAC:
if (!store_syslogfac(val, cur, op)) {
if (!quiet) {
if (val)
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, var);
else
sudo_warnx(U_("no value specified for `%s'"), var);
}
debug_return_bool(false);
}
break;
case T_LOGPRI:
if (!store_syslogpri(val, cur, op)) {
if (!quiet) {
if (val)
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, var);
else
sudo_warnx(U_("no value specified for `%s'"), var);
}
debug_return_bool(false);
}
break;
case T_STR:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(cur->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), var);
debug_return_bool(false);
}
}
if (ISSET(cur->type, T_PATH) && val && *val != '/') {
if (!quiet)
sudo_warnx(U_("values for `%s' must start with a '/'"), var);
debug_return_bool(false);
}
switch (store_str(val, cur, op)) {
case true:
/* OK */
break;
case false:
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, var);
}
/* FALLTHROUGH */
default:
debug_return_bool(false);
}
break;
case T_INT:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(cur->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), var);
debug_return_bool(false);
}
}
if (!store_int(val, cur, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, var);
}
debug_return_bool(false);
}
break;
case T_UINT:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(cur->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), var);
debug_return_bool(false);
}
}
if (!store_uint(val, cur, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, var);
}
debug_return_bool(false);
}
break;
case T_FLOAT:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(cur->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), var);
debug_return_bool(false);
}
}
if (!store_float(val, cur, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, var);
}
debug_return_bool(false);
}
break;
case T_MODE:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(cur->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), var);
debug_return_bool(false);
}
}
if (!store_mode(val, cur, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, var);
}
debug_return_bool(false);
}
break;
case T_FLAG:
if (val) {
if (!quiet)
sudo_warnx(U_("option `%s' does not take a value"), var);
debug_return_bool(false);
}
cur->sd_un.flag = op;
if (cur->callback)
debug_return_bool(cur->callback(&cur->sd_un));
break;
case T_LIST:
if (!val) {
/* Check for bogus boolean usage or lack of a value. */
if (!ISSET(cur->type, T_BOOL) || op != false) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), var);
debug_return_bool(false);
}
}
if (!store_list(val, cur, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, var);
}
debug_return_bool(false);
}
break;
case T_TUPLE:
if (!val && !ISSET(cur->type, T_BOOL)) {
if (!quiet)
sudo_warnx(U_("no value specified for `%s'"), var);
debug_return_bool(false);
}
if (!store_tuple(val, cur, op)) {
if (!quiet) {
sudo_warnx(U_("value `%s' is invalid for option `%s'"),
val, var);
}
debug_return_bool(false);
}
break;
}
debug_return_bool(true);
debug_return_bool(set_default_entry(cur, val, op, quiet));
}
/*
@@ -712,7 +724,7 @@ update_defaults(int what, bool quiet)
bool
check_defaults(int what, bool quiet)
{
struct sudo_defs_types *cur;
struct sudo_defs_types *cur, tmp;
struct defaults *def;
bool rc = true;
debug_decl(check_defaults, SUDOERS_DEBUG_DEFAULTS)
@@ -729,6 +741,11 @@ check_defaults(int what, bool quiet)
sudo_warnx(U_("unknown defaults entry `%s'"), def->var);
rc = false;
}
/* Don't actually set the defaults value, just checking. */
tmp = *cur;
tmp.callback = NULL;
if (!set_default_entry(&tmp, def->val, def->op, quiet))
rc = false;
}
debug_return_bool(rc);
}

View File

@@ -554,7 +554,6 @@ reparse_sudoers(char *editor, int editor_argc, char **editor_argv,
struct sudoersfile *sp, *last;
FILE *fp;
int ch, oldlocale;
bool ok;
debug_decl(reparse_sudoers, SUDOERS_DEBUG_UTIL)
/*
@@ -581,17 +580,16 @@ reparse_sudoers(char *editor, int editor_argc, char **editor_argv,
parse_error = true;
errorfile = sp->path;
}
ok = update_defaults(SETDEF_GENERIC|SETDEF_HOST, quiet);
if (!check_defaults(SETDEF_ALL & ~(SETDEF_GENERIC|SETDEF_HOST), quiet))
ok = false;
sudoers_setlocale(oldlocale, NULL);
fclose(sudoersin);
if (!parse_error) {
if (!ok || check_aliases(strict, quiet) != 0) {
(void) update_defaults(SETDEF_GENERIC|SETDEF_HOST, true);
if (!check_defaults(SETDEF_ALL, quiet) ||
check_aliases(strict, quiet) != 0) {
parse_error = true;
errorfile = NULL;
}
}
sudoers_setlocale(oldlocale, NULL);
/*
* Got an error, prompt the user for what to do now.
@@ -923,9 +921,9 @@ check_syntax(const char *sudoers_file, bool quiet, bool strict, bool oldperms)
errorfile = sudoers_file;
}
if (!parse_error) {
if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST, quiet) ||
!check_defaults(SETDEF_ALL & ~(SETDEF_GENERIC|SETDEF_HOST), quiet)
|| check_aliases(strict, quiet) != 0) {
(void) update_defaults(SETDEF_GENERIC|SETDEF_HOST, true);
if (!check_defaults(SETDEF_ALL, quiet) ||
check_aliases(strict, quiet) != 0) {
parse_error = true;
errorfile = NULL;
}