diff --git a/MANIFEST b/MANIFEST index d4c27925d..631048349 100644 --- a/MANIFEST +++ b/MANIFEST @@ -34,6 +34,7 @@ compat/mksiglist.c compat/mksiglist.h compat/mkstemp.c compat/nanosleep.c +compat/setenv.c compat/siglist.in compat/snprintf.c compat/strcasecmp.c @@ -42,6 +43,7 @@ compat/strlcat.c compat/strlcpy.c compat/strsignal.c compat/timespec.h +compat/unsetenv.c compat/utime.h compat/utimes.c config.guess diff --git a/aclocal.m4 b/aclocal.m4 index f42923a31..7a4bdca93 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -272,22 +272,6 @@ AC_DEFUN([SUDO_FUNC_UNSETENV_VOID], fi ]) -dnl -dnl check putenv() argument for const -dnl -AC_DEFUN([SUDO_FUNC_PUTENV_CONST], -[AC_CACHE_CHECK([whether putenv has a const argument], -sudo_cv_func_putenv_const, -[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT -int putenv(const char *string) {return 0;}], [])], - [sudo_cv_func_putenv_const=yes], - [sudo_cv_func_putenv_const=no]) - ]) - if test $sudo_cv_func_putenv_const = yes; then - AC_DEFINE(PUTENV_CONST, 1, [Define to 1 if the `putenv' has a const argument.]) - fi -]) - dnl dnl check for sa_len field in struct sockaddr dnl diff --git a/compat/setenv.c b/compat/setenv.c new file mode 100644 index 000000000..a5c06e0fd --- /dev/null +++ b/compat/setenv.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010 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 */ +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ +#include + +#include + +int +setenv(const char *var, const char *val, int overwrite) +{ + char *envstr, *dst; + const char *src; + size_t esize; + + if (!var || *var == '\0') { + errno = EINVAL; + return -1; + } + + /* + * POSIX says a var name with '=' is an error but BSD + * just ignores the '=' and anything after it. + */ + for (src = var; *src != '\0' && *src != '='; src++) + ; + esize = (size_t)(src - var) + 2; + if (val) { + esize += strlen(val); /* glibc treats a NULL val as "" */ + } + + /* Allocate and fill in envstr. */ + if ((envstr = malloc(esize)) == NULL) + return -1; + for (src = var, dst = envstr; *src != '\0' && *src != '=';) + *dst++ = *src++; + *dst++ = '='; + if (val) { + for (src = val; *src != '\0';) + *dst++ = *src++; + } + *dst = '\0'; + + if (!overwrite && getenv(var) != NULL) { + free(envstr); + return 0; + } + return putenv(envstr); +} diff --git a/compat/unsetenv.c b/compat/unsetenv.c new file mode 100644 index 000000000..df4082922 --- /dev/null +++ b/compat/unsetenv.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010 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 */ +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#include + +#include + +extern char **environ; /* global environment */ + +#ifdef UNSETENV_VOID +void +#else +int +#endif +unsetenv(const char *var) +{ + char **ep = environ; + size_t len; + + if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) { + errno = EINVAL; +#ifdef UNSETENV_VOID + return; +#else + return -1; +#endif + } + + len = strlen(var); + while (*ep != NULL) { + if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') { + /* Found it; shift remainder + NULL over by one. */ + char **cur = ep; + while ((*cur = *(cur + 1)) != NULL) + cur++; + /* Keep going, could be multiple instances of the var. */ + } else { + ep++; + } + } +#ifndef UNSETENV_VOID + return 0; +#endif +} diff --git a/configure b/configure index 2a6f4dd6f..de1845f95 100755 --- a/configure +++ b/configure @@ -14764,7 +14764,7 @@ LIBS=$ac_save_LIBS for ac_func in strchr strrchr memchr memcpy memset sysconf tzset \ strftime setrlimit initgroups fstat gettimeofday \ - regcomp setlocale getaddrinfo setenv vhangup \ + regcomp setlocale getaddrinfo vhangup \ mbr_check_membership setrlimit64 do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` @@ -15011,42 +15011,16 @@ $as_echo "#define UNSETENV_VOID 1" >>confdefs.h fi +else + case " $LIBOBJS " in + *" unsetenv.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS unsetenv.$ac_objext" + ;; +esac + fi done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether putenv has a const argument" >&5 -$as_echo_n "checking whether putenv has a const argument... " >&6; } -if test "${sudo_cv_func_putenv_const+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_includes_default -int putenv(const char *string) {return 0;} -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - sudo_cv_func_putenv_const=yes -else - sudo_cv_func_putenv_const=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_func_putenv_const" >&5 -$as_echo "$sudo_cv_func_putenv_const" >&6; } - if test $sudo_cv_func_putenv_const = yes; then - -$as_echo "#define PUTENV_CONST 1" >>confdefs.h - - fi - if test -z "$SKIP_SETRESUID"; then for ac_func in setresuid do : @@ -15375,7 +15349,7 @@ esac fi -for ac_func in memrchr strerror strcasecmp strlcpy strlcat +for ac_func in memrchr strerror strcasecmp strlcpy strlcat setenv do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index fa5d65d3f..b818b7c8b 100644 --- a/configure.in +++ b/configure.in @@ -1916,7 +1916,7 @@ dnl AC_FUNC_GETGROUPS AC_CHECK_FUNCS(strchr strrchr memchr memcpy memset sysconf tzset \ strftime setrlimit initgroups fstat gettimeofday \ - regcomp setlocale getaddrinfo setenv vhangup \ + regcomp setlocale getaddrinfo vhangup \ mbr_check_membership setrlimit64) AC_CHECK_FUNCS(getline, [], [ AC_LIBOBJ(getline) @@ -1939,8 +1939,7 @@ AC_CHECK_FUNCS(openpty, [AC_CHECK_HEADERS(util.h pty.h, [break])], [ ]) ]) ]) -AC_CHECK_FUNCS(unsetenv, SUDO_FUNC_UNSETENV_VOID) -SUDO_FUNC_PUTENV_CONST +AC_CHECK_FUNCS(unsetenv, [SUDO_FUNC_UNSETENV_VOID], [AC_LIBOBJ(unsetenv)]) if test -z "$SKIP_SETRESUID"; then AC_CHECK_FUNCS(setresuid, [ SKIP_SETREUID=yes @@ -1970,7 +1969,7 @@ AC_CHECK_FUNCS(utimes, [AC_CHECK_FUNCS(futimes futimesat, [break])], [AC_CHECK_F AC_CHECK_FUNCS(killpg, [], [AC_LIBOBJ(killpg)]) SUDO_FUNC_FNMATCH([AC_DEFINE(HAVE_FNMATCH)], [AC_LIBOBJ(fnmatch)]) SUDO_FUNC_ISBLANK -AC_REPLACE_FUNCS(memrchr strerror strcasecmp strlcpy strlcat) +AC_REPLACE_FUNCS(memrchr strerror strcasecmp strlcpy strlcat setenv) AC_CHECK_FUNCS(nanosleep, [], [ # On Solaris, nanosleep is in librt AC_CHECK_LIB(rt, nanosleep, [REPLAY_LIBS="${REPLAY_LIBS} -lrt"], [AC_LIBOBJ(nanosleep)]) diff --git a/plugins/sudoers/env.c b/plugins/sudoers/env.c index b956eeb32..637b854d3 100644 --- a/plugins/sudoers/env.c +++ b/plugins/sudoers/env.c @@ -255,134 +255,6 @@ sudo_setenv(const char *var, const char *val, int dupcheck) sudo_putenv(estring, dupcheck, TRUE); } -/* - * Version of getenv(3) that uses our own environ pointer. - */ -char * -getenv(const char *var) -{ - char *cp, **ev; - size_t vlen = strlen(var); - - for (ev = env.envp; (cp = *ev) != NULL; ev++) { - if (strncmp(var, cp, vlen) == 0 && cp[vlen] == '=') - return cp + vlen + 1; - } - return NULL; -} - -/* - * Version of setenv(3) that uses our own environ pointer. - */ -int -setenv(const char *var, const char *val, int overwrite) -{ - char *estring, *ep; - const char *cp; - size_t esize; - - if (!var || *var == '\0') { - errno = EINVAL; - return -1; - } - - /* - * POSIX says a var name with '=' is an error but BSD - * just ignores the '=' and anything after it. - */ - for (cp = var; *cp && *cp != '='; cp++) - ; - esize = (size_t)(cp - var) + 2; - if (val) { - esize += strlen(val); /* glibc treats a NULL val as "" */ - } - - /* Allocate and fill in estring. */ - estring = ep = emalloc(esize); - for (cp = var; *cp && *cp != '='; cp++) - *ep++ = *cp; - *ep++ = '='; - if (val) { - for (cp = val; *cp; cp++) - *ep++ = *cp; - } - *ep = '\0'; - -#ifdef ENV_DEBUG - if (env.envp[env.env_len] != NULL) - errorx(1, "setenv: corrupted envp, len mismatch"); -#endif - sudo_putenv(estring, TRUE, overwrite); - return 0; -} - -/* - * Version of unsetenv(3) that uses our own environ pointer. - */ -#ifdef UNSETENV_VOID -void -#else -int -#endif -unsetenv(const char *var) -{ - char **ep = env.envp; - size_t len; - - if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) { - errno = EINVAL; -#ifdef UNSETENV_VOID - return; -#else - return -1; -#endif - } - -#ifdef ENV_DEBUG - if (env.envp[env.env_len] != NULL) - errorx(1, "unsetenv: corrupted envp, len mismatch"); -#endif - - len = strlen(var); - while (*ep != NULL) { - if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') { - /* Found it; shift remainder + NULL over by one. */ - char **cur = ep; - while ((*cur = *(cur + 1)) != NULL) - cur++; - /* Keep going, could be multiple instances of the var. */ - } else { - ep++; - } - } - env.env_len = ep - env.envp; -#ifndef UNSETENV_VOID - return 0; -#endif -} - -/* - * Version of putenv(3) that uses our own environ pointer. - */ -int -#ifdef PUTENV_CONST -putenv(const char *string) -#else -putenv(char *string) -#endif -{ - if (strchr(string, '=') == NULL) { - errno = EINVAL; - return -1; - } -#ifdef ENV_DEBUG - if (env.envp[env.env_len] != NULL) - errorx(1, "putenv: corrupted envp, len mismatch"); -#endif - sudo_putenv((char *)string, TRUE, TRUE); - return 0; -} - /* * Similar to putenv(3) but operates on sudo's private copy of the * environment (not environ) and it always overwrites. The dupcheck param