diff --git a/MANIFEST b/MANIFEST index bc93d7c0e..8271d14ad 100644 --- a/MANIFEST +++ b/MANIFEST @@ -13,6 +13,7 @@ common/aix.c common/alloc.c common/atobool.c common/atoid.c +common/atomode.c common/event.c common/event_poll.c common/event_select.c diff --git a/common/Makefile.in b/common/Makefile.in index 3314fd1eb..929fdc789 100644 --- a/common/Makefile.in +++ b/common/Makefile.in @@ -66,7 +66,7 @@ DEFS = @OSDEFS@ -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\" SHELL = @SHELL@ -LTOBJS = alloc.lo atobool.lo atoid.lo event.lo fatal.lo fileops.lo \ +LTOBJS = alloc.lo atobool.lo atoid.lo atomode.lo event.lo fatal.lo fileops.lo \ fmt_string.lo gidlist.lo lbuf.lo progname.lo secure_path.lo \ setgroups.lo sudo_conf.lo sudo_debug.lo sudo_dso.lo sudo_printf.lo \ term.lo ttysize.lo @COMMON_OBJS@ @@ -179,6 +179,9 @@ atoid.lo: $(srcdir)/atoid.c $(incdir)/gettext.h $(incdir)/missing.h \ $(incdir)/sudo_debug.h $(top_builddir)/config.h \ $(top_srcdir)/compat/stdbool.h $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/atoid.c +atomode.lo: $(srcdir)/atomode.c $(incdir)/gettext.h $(incdir)/missing.h \ + $(incdir)/sudo_debug.h $(top_builddir)/config.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/atomode.c conf_test.lo: $(srcdir)/regress/sudo_conf/conf_test.c $(incdir)/missing.h \ $(incdir)/queue.h $(incdir)/sudo_conf.h $(top_builddir)/config.h \ $(top_srcdir)/compat/stdbool.h diff --git a/common/atoid.c b/common/atoid.c index 1d7d87c28..29397f6e0 100644 --- a/common/atoid.c +++ b/common/atoid.c @@ -74,18 +74,24 @@ atoid(const char *p, const char *sep, char **endp, const char **errstr) } while (*sep++ != '\0'); } if (!valid) { - *errstr = N_("invalid value"); + if (errstr != NULL) + *errstr = N_("invalid"); errno = EINVAL; goto done; } - if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || - (lval > INT_MAX || lval < INT_MIN)) { + if ((errno == ERANGE && lval == LONG_MAX) || lval > INT_MAX) { errno = ERANGE; - *errstr = N_("value out of range"); + if (errstr != NULL) + *errstr = N_("too large"); + goto done; + } + if ((errno == ERANGE && lval == LONG_MIN) || lval < INT_MIN) { + errno = ERANGE; + if (errstr != NULL) + *errstr = N_("too small"); goto done; } rval = (id_t)lval; - *errstr = NULL; } else { unsigned long ulval = strtoul(p, &ep, 10); if (ep != p) { @@ -96,18 +102,21 @@ atoid(const char *p, const char *sep, char **endp, const char **errstr) } while (*sep++ != '\0'); } if (!valid) { - *errstr = N_("invalid value"); + if (errstr != NULL) + *errstr = N_("invalid"); errno = EINVAL; goto done; } if ((errno == ERANGE && ulval == ULONG_MAX) || ulval > UINT_MAX) { errno = ERANGE; - *errstr = N_("value too large"); + if (errstr != NULL) + *errstr = N_("too large"); goto done; } rval = (id_t)ulval; - *errstr = NULL; } + if (errstr != NULL) + *errstr = NULL; if (endp != NULL) *endp = ep; done: diff --git a/common/atomode.c b/common/atomode.c new file mode 100644 index 000000000..9c4d299ce --- /dev/null +++ b/common/atomode.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#include + +#define DEFAULT_TEXT_DOMAIN "sudo" +#include "gettext.h" + +#include "missing.h" +#include "sudo_debug.h" + +/* + * Parse an octal file mode in the range [0, 0777]. + * On success, returns the parsed mode and clears errstr. + * On error, returns 0 and sets errstr. + */ +int +atomode(const char *cp, const char **errstr) +{ + char *ep; + long lval; + debug_decl(atomode, SUDO_DEBUG_UTIL) + + errno = 0; + lval = strtol(cp, &ep, 8); + if (ep == cp || *ep != '\0') { + if (errstr != NULL) + *errstr = N_("invalid"); + errno = EINVAL; + debug_return_int(0); + } + if (lval < 0 || lval > 0777) { + if (errstr != NULL) + *errstr = lval < 0 ? N_("too small") : N_("too large"); + errno = ERANGE; + debug_return_int(0); + } + debug_return_int((int)lval); +} diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c index b6f7622c5..9459c50f6 100644 --- a/plugins/sudoers/defaults.c +++ b/plugins/sudoers/defaults.c @@ -811,17 +811,20 @@ logpri2str(int n) static bool store_mode(char *val, struct sudo_defs_types *def, int op) { - char *endp; - long l; + mode_t mode; + const char *errstr; debug_decl(store_mode, SUDO_DEBUG_DEFAULTS) if (op == false) { - def->sd_un.mode = (mode_t)0777; + def->sd_un.mode = 0777; } else { - l = strtol(val, &endp, 8); - if (endp == val || *endp != '\0' || l < 0 || l > 0777) + mode = atomode(val, &errstr); + if (errstr != NULL) { + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "%s is %s", val, errstr); debug_return_bool(false); - def->sd_un.mode = (mode_t)l; + } + def->sd_un.mode = mode; } if (def->callback) debug_return_bool(def->callback(val)); diff --git a/plugins/sudoers/policy.c b/plugins/sudoers/policy.c index 0824abac7..9d08ed47e 100644 --- a/plugins/sudoers/policy.c +++ b/plugins/sudoers/policy.c @@ -91,7 +91,6 @@ sudoers_policy_deserialize_info(void *v, char **runas_user, char **runas_group) const char *debug_flags = NULL; const char *remhost = NULL; int flags = 0; - char *ep; debug_decl(sudoers_policy_deserialize_info, SUDO_DEBUG_PLUGIN) #define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0) @@ -118,17 +117,10 @@ sudoers_policy_deserialize_info(void *v, char **runas_user, char **runas_group) continue; } if (MATCHES(*cur, "sudoers_mode=")) { - long lval; - errno = 0; p = *cur + sizeof("sudoers_mode=") - 1; - lval = strtol(p, &ep, 8); - if (ep == p || *ep != '\0') - fatalx(U_("%s: %s"), *cur, U_("invalid")); - if (lval < 0) - fatalx(U_("%s: %s"), *cur, U_("too small")); - if (lval > 0777) - fatalx(U_("%s: %s"), *cur, U_("too large")); - sudoers_mode = (mode_t) lval; + sudoers_mode = atomode(p, &errstr); + if (errstr != NULL) + fatalx(U_("%s: %s"), *cur, U_(errstr)); continue; } if (MATCHES(*cur, "ldap_conf=")) { diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 1ee6265a6..56d9dae9c 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -321,6 +321,9 @@ int atobool(const char *str); /* atoid.c */ int atoid(const char *str, const char *sep, char **endp, const char **errstr); +/* atomode.c */ +int atomode(const char *cp, const char **errstr); + /* boottime.c */ int get_boottime(struct timeval *); diff --git a/src/sudo.c b/src/sudo.c index f8c3fab53..b6d233155 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -555,7 +555,7 @@ command_info_to_details(char * const info[], struct command_details *details) cp = info[i] + sizeof("closefrom=") - 1; details->closefrom = strtonum(cp, 0, INT_MAX, &errstr); if (errstr != NULL) - fatalx(U_("%s: %s"), cp, U_(errstr)); + fatalx(U_("%s: %s"), info[i], U_(errstr)); break; } break; @@ -574,7 +574,7 @@ command_info_to_details(char * const info[], struct command_details *details) cp = info[i] + sizeof("nice=") - 1; details->priority = strtonum(cp, INT_MIN, INT_MAX, &errstr); if (errstr != NULL) - fatalx(U_("%s: %s"), cp, U_(errstr)); + fatalx(U_("%s: %s"), info[i], U_(errstr)); SET(details->flags, CD_SET_PRIORITY); break; } @@ -676,25 +676,17 @@ command_info_to_details(char * const info[], struct command_details *details) cp = info[i] + sizeof("timeout=") - 1; details->timeout = strtonum(cp, 0, INT_MAX, &errstr); if (errstr != NULL) - fatalx(U_("%s: %s"), cp, U_(errstr)); + fatalx(U_("%s: %s"), info[i], U_(errstr)); SET(details->flags, CD_SET_TIMEOUT); break; } break; case 'u': if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) { - long lval; - char *ep; - errno = 0; cp = info[i] + sizeof("umask=") - 1; - lval = strtol(cp, &ep, 8); - if (ep == cp || *ep != '\0') - fatalx(U_("%s: %s"), info[i], U_("invalid")); - if (lval < 0) - fatalx(U_("%s: %s"), info[i], U_("too small")); - if (lval > 0777) - fatalx(U_("%s: %s"), info[i], U_("too large")); - details->umask = (mode_t)lval; + details->umask = atomode(cp, &errstr); + if (errstr != NULL) + fatalx(U_("%s: %s"), info[i], U_(errstr)); SET(details->flags, CD_SET_UMASK); break; } diff --git a/src/sudo.h b/src/sudo.h index a8af1e4e3..6fced6d2b 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -189,6 +189,9 @@ bool atobool(const char *str); /* atoid.c */ id_t atoid(const char *str, const char *sep, char **endp, const char **errstr); +/* atomode.c */ +int atomode(const char *cp, const char **errstr); + /* parse_args.c */ int parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp, char ***env_addp);