From: Todd C. Miller Date: Wed, 11 Dec 2013 20:43:10 +0000 (-0700) Subject: The OpenBSD strtonum() uses very short error strings that can't X-Git-Tag: SUDO_1_8_9^2~42 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cbf41b8b96241aafbbd7e1d5a65c227aad694555;p=sudo The OpenBSD strtonum() uses very short error strings that can't be translated usefully. Convert them to longer strings on error. Also use the longer strings for atomode() and atoid(). --- diff --git a/common/atoid.c b/common/atoid.c index 29397f6e0..5e1528cde 100644 --- a/common/atoid.c +++ b/common/atoid.c @@ -75,20 +75,20 @@ atoid(const char *p, const char *sep, char **endp, const char **errstr) } if (!valid) { if (errstr != NULL) - *errstr = N_("invalid"); + *errstr = N_("invalid value"); errno = EINVAL; goto done; } if ((errno == ERANGE && lval == LONG_MAX) || lval > INT_MAX) { errno = ERANGE; if (errstr != NULL) - *errstr = N_("too large"); + *errstr = N_("value too large"); goto done; } if ((errno == ERANGE && lval == LONG_MIN) || lval < INT_MIN) { errno = ERANGE; if (errstr != NULL) - *errstr = N_("too small"); + *errstr = N_("value too small"); goto done; } rval = (id_t)lval; @@ -103,14 +103,14 @@ atoid(const char *p, const char *sep, char **endp, const char **errstr) } if (!valid) { if (errstr != NULL) - *errstr = N_("invalid"); + *errstr = N_("invalid value"); errno = EINVAL; goto done; } if ((errno == ERANGE && ulval == ULONG_MAX) || ulval > UINT_MAX) { errno = ERANGE; if (errstr != NULL) - *errstr = N_("too large"); + *errstr = N_("value too large"); goto done; } rval = (id_t)ulval; diff --git a/common/atomode.c b/common/atomode.c index 9c4d299ce..beb8215ef 100644 --- a/common/atomode.c +++ b/common/atomode.c @@ -51,13 +51,13 @@ atomode(const char *cp, const char **errstr) lval = strtol(cp, &ep, 8); if (ep == cp || *ep != '\0') { if (errstr != NULL) - *errstr = N_("invalid"); + *errstr = N_("invalid value"); errno = EINVAL; debug_return_int(0); } if (lval < 0 || lval > 0777) { if (errstr != NULL) - *errstr = lval < 0 ? N_("too small") : N_("too large"); + *errstr = lval < 0 ? N_("value too small") : N_("value too large"); errno = ERANGE; debug_return_int(0); } diff --git a/compat/strtonum.c b/compat/strtonum.c index 7db673e28..35d4d41f4 100644 --- a/compat/strtonum.c +++ b/compat/strtonum.c @@ -22,15 +22,59 @@ #include #include #include -#ifdef HAVE_STDLIB_H +#ifdef STDC_HEADERS # include -#endif +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ #include "missing.h" #define DEFAULT_TEXT_DOMAIN "sudo" #include "gettext.h" +#ifdef HAVE_STRTONUM + +/* + * The OpenBSD strtonum error string too short to be translated sensibly. + * This wrapper just changes errstr as follows: + * invalid -> invalid value + * too large -> value too large + * too small -> value too small + */ +long long +rpl_strtonum(const char *str, long long minval, long long maxval, + const char **errstrp) +{ + long long retval; + const char *errstr; + +# undef strtonum + retval = strtonum(str, minval, maxval, &errstr); + if (errstr != NULL) { + if (errno == EINVAL) { + errstr = N_("invalid value"); + } else if (errno == ERANGE) { + errstr = strcmp(errstr, "too large") == 0 ? + N_("value too large") : N_("value too small"); + } + } + if (errstrp != NULL) + *errstrp = errstr; + return retval; +} + +#else + enum strtonum_err { STN_VALID, STN_INVALID, @@ -42,7 +86,7 @@ enum strtonum_err { * Convert a string to a number in the range [minval, maxval] */ long long -strtonum(const char *str, long long minval, long long maxval, +rpl_strtonum(const char *str, long long minval, long long maxval, const char **errstrp) { const unsigned char *ustr = (const unsigned char *)str; @@ -136,20 +180,21 @@ done: result = 0; errno = EINVAL; if (errstrp != NULL) - *errstrp = N_("invalid"); + *errstrp = N_("invalid value"); break; case STN_TOOSMALL: result = 0; errno = ERANGE; if (errstrp != NULL) - *errstrp = N_("too small"); + *errstrp = N_("value too small"); break; case STN_TOOBIG: result = 0; errno = ERANGE; if (errstrp != NULL) - *errstrp = N_("too large"); + *errstrp = N_("value too large"); break; } return result; } +#endif /* HAVE_STRTONUM */ diff --git a/configure b/configure index 35d91eb54..92a80df4b 100755 --- a/configure +++ b/configure @@ -18014,6 +18014,24 @@ esac fi fi +# We wrap OpenBSD's strtonum() to get translatable error strings. +for ac_func in strtonum +do : + ac_fn_c_check_func "$LINENO" "strtonum" "ac_cv_func_strtonum" +if test "x$ac_cv_func_strtonum" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRTONUM 1 +_ACEOF + +fi +done + +case " $LIBOBJS " in + *" strtonum.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strtonum.$ac_objext" + ;; +esac + if test X"$ac_cv_type_struct_timespec" != X"no"; then ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_mtim" = xyes; then : diff --git a/configure.ac b/configure.ac index 5f11b943b..086cb61a3 100644 --- a/configure.ac +++ b/configure.ac @@ -2415,6 +2415,9 @@ if test X"$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf" = X"yesyes" AC_LIBOBJ(snprintf) fi fi +# We wrap OpenBSD's strtonum() to get translatable error strings. +AC_CHECK_FUNCS(strtonum) +AC_LIBOBJ(strtonum) if test X"$ac_cv_type_struct_timespec" != X"no"; then AC_CHECK_MEMBER([struct stat.st_mtim], [AC_DEFINE(HAVE_ST_MTIM)] [AC_CHECK_MEMBER([struct stat.st_mtim.st__tim], AC_DEFINE(HAVE_ST__TIM))], diff --git a/include/missing.h b/include/missing.h index 6dfceead1..1fc4aa579 100644 --- a/include/missing.h +++ b/include/missing.h @@ -475,7 +475,9 @@ char *strsignal(int); int sig2str(int, char *); #endif #ifndef HAVE_STRTONUM -long long strtonum(const char *, long long, long long, const char **); +long long rpl_strtonum(const char *, long long, long long, const char **); +# undef strtonum +# define strtonum rpl_strtonum #endif void initprogname(const char *); diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index 9459c50f6..e68daa462 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -610,7 +610,7 @@ store_int(char *val, struct sudo_defs_types *def, int op) i = strtonum(val, INT_MIN, INT_MAX, &errstr); if (errstr != NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "%s is %s", val, errstr); + "%s: %s", val, errstr); debug_return_bool(false); } def->sd_un.ival = i; @@ -633,7 +633,7 @@ store_uint(char *val, struct sudo_defs_types *def, int op) u = strtonum(val, 0, UINT_MAX, &errstr); if (errstr != NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "%s is %s", val, errstr); + "%s: %s", val, errstr); debug_return_bool(false); } /* XXX - should have uival */ diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c index 0b4ea23bb..52adea176 100644 --- a/plugins/sudoers/iolog.c +++ b/plugins/sudoers/iolog.c @@ -144,7 +144,7 @@ io_set_max_sessid(const char *maxval) if (errstr != NULL) { if (errno != ERANGE) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "bad maxseq: %s is %s", maxval, errstr); + "bad maxseq: %s: %s", maxval, errstr); debug_return_bool(false); } /* Out of range, clamp to SESSID_MAX as documented. */ diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c index 82ad6c3e9..626c770b1 100644 --- a/plugins/sudoers/ldap.c +++ b/plugins/sudoers/ldap.c @@ -1421,8 +1421,8 @@ sudo_ldap_parse_keyword(const char *keyword, const char *value, case CONF_INT: *(int *)(cur->valp) = strtonum(value, INT_MIN, INT_MAX, &errstr); if (errstr != NULL) { - warningx(U_("%s: %s: value %s out of range)"), - path_ldap_conf, keyword, value); + warningx(U_("%s: %s: %s: %s"), + path_ldap_conf, keyword, value, U_(errstr)); } break; case CONF_STR: diff --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c index c3537cfd1..055b3e331 100644 --- a/plugins/sudoers/sudoreplay.c +++ b/plugins/sudoers/sudoreplay.c @@ -846,7 +846,7 @@ parse_logfile(char *logfile) li->tstamp = strtonum(cp, LLONG_MIN, LLONG_MAX, &errstr); if (errstr != NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "%s: timestamp %s is %s", logfile, cp, errstr); + "%s: timestamp %s: %s", logfile, cp, errstr); goto bad; } @@ -885,14 +885,14 @@ parse_logfile(char *logfile) li->rows = strtonum(cp, 1, INT_MAX, &errstr); if (errstr != NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "%s: tty rows %s is %s", logfile, cp, errstr); + "%s: tty rows %s: %s", logfile, cp, errstr); } if (ep != NULL) { cp = ep + 1; li->cols = strtonum(cp, 1, INT_MAX, &errstr); if (errstr != NULL) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "%s: tty cols %s is %s", logfile, cp, errstr); + "%s: tty cols %s: %s", logfile, cp, errstr); } } } diff --git a/src/parse_args.c b/src/parse_args.c index 99fb249f2..d4b6305b4 100644 --- a/src/parse_args.c +++ b/src/parse_args.c @@ -178,7 +178,7 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp, char *cp, **env_add, **settings; const char *runas_user = NULL; const char *runas_group = NULL; - const char *debug_flags, *errstr; + const char *debug_flags; int nenv = 0; int env_size = 32; debug_decl(parse_args, SUDO_DEBUG_ARGS) @@ -242,9 +242,8 @@ parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp, SET(flags, MODE_BACKGROUND); break; case 'C': - strtonum(optarg, 4, INT_MAX, &errstr); - if (errstr != NULL) { - warningx(U_("the argument to -C was %s"), U_(errstr)); + if (strtonum(optarg, 3, INT_MAX, NULL) == 0) { + warningx(_("the argument to -C must be a number greater than or equal to 3")); usage(1); } sudo_settings[ARG_CLOSEFROM].value = optarg; diff --git a/src/ttyname.c b/src/ttyname.c index b9532e15d..4a95b625d 100644 --- a/src/ttyname.c +++ b/src/ttyname.c @@ -449,7 +449,7 @@ get_process_ttyname(void) dev_t tdev = strtonum(cp, INT_MIN, INT_MAX, &errstr); if (errstr) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "%s: tty device number %s", path, errstr); + "%s: tty device %s: %s", path, cp, errstr); } if (tdev > 0) tty = sudo_ttyname_dev(tdev);