/* * 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 */ #if defined(HAVE_STDINT_H) # include #elif defined(HAVE_INTTYPES_H) # include #endif #ifdef HAVE_STDBOOL_H # include #else # include "compat/stdbool.h" #endif #include #include #define DEFAULT_TEXT_DOMAIN "sudo" #include "gettext.h" /* must be included before missing.h */ #include "missing.h" #include "sudo_debug.h" #include "sudo_util.h" /* * Parse a uid/gid in string form. * If sep is non-NULL, it contains valid separator characters (e.g. comma, space) * If endp is non-NULL it is set to the next char after the ID. * On success, returns the parsed ID and clears errstr. * On error, returns 0 and sets errstr. */ id_t atoid(const char *p, const char *sep, char **endp, const char **errstr) { char *ep; id_t rval = 0; bool valid = false; debug_decl(atoid, SUDO_DEBUG_UTIL) if (sep == NULL) sep = ""; errno = 0; if (*p == '-') { long lval = strtol(p, &ep, 10); if (ep != p) { /* check for valid separator (including '\0') */ do { if (*ep == *sep) valid = true; } while (*sep++ != '\0'); } if (!valid) { if (errstr != NULL) *errstr = N_("invalid value"); errno = EINVAL; goto done; } if ((errno == ERANGE && lval == LONG_MAX) || lval > INT_MAX) { errno = ERANGE; if (errstr != NULL) *errstr = N_("value too large"); goto done; } if ((errno == ERANGE && lval == LONG_MIN) || lval < INT_MIN) { errno = ERANGE; if (errstr != NULL) *errstr = N_("value too small"); goto done; } rval = (id_t)lval; } else { unsigned long ulval = strtoul(p, &ep, 10); if (ep != p) { /* check for valid separator (including '\0') */ do { if (*ep == *sep) valid = true; } while (*sep++ != '\0'); } if (!valid) { if (errstr != NULL) *errstr = N_("invalid value"); errno = EINVAL; goto done; } if ((errno == ERANGE && ulval == ULONG_MAX) || ulval > UINT_MAX) { errno = ERANGE; if (errstr != NULL) *errstr = N_("value too large"); goto done; } rval = (id_t)ulval; } if (errstr != NULL) *errstr = NULL; if (endp != NULL) *endp = ep; done: debug_return_int(rval); }