/*
- * Copyright (c) 2000-2005, 2007-2011
+ * Copyright (c) 2000-2005, 2007-2013
* Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
#include <config.h>
#include <sys/types.h>
-#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef STDC_HEADERS
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
#ifdef HAVE_LOGIN_CAP_H
# include <login_cap.h>
# ifndef LOGIN_SETENV
#endif /* HAVE_LOGIN_CAP_H */
#include <ctype.h>
#include <errno.h>
+#include <limits.h>
#include <pwd.h>
#include "sudoers.h"
+/*
+ * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t
+ * could be signed (as it is on SunOS 4.x). This just means that
+ * emalloc2() and erealloc3() cannot allocate huge amounts on such a
+ * platform but that is OK since sudo doesn't need to do so anyway.
+ */
+#ifndef SIZE_MAX
+# ifdef SIZE_T_MAX
+# define SIZE_MAX SIZE_T_MAX
+# else
+# define SIZE_MAX INT_MAX
+# endif /* SIZE_T_MAX */
+#endif /* SIZE_MAX */
+
/*
* Flags used in rebuild_env()
*/
memset(env.envp, 0, env.env_size * sizeof(char *));
#endif
memcpy(env.envp, envp, len * sizeof(char *));
- env.envp[len] = '\0';
+ env.envp[len] = NULL;
/* Free the old envp we allocated, if any. */
if (env.old_envp != NULL)
bool found = false;
/* Make sure there is room for the new entry plus a NULL. */
- if (env.env_len + 2 > env.env_size) {
+ if (env.env_size > 2 && env.env_len > env.env_size - 2) {
char **nenvp;
- size_t nsize = env.env_size + 128;
- nenvp = env.envp ? realloc(env.envp, nsize * sizeof(char *)) :
- malloc(nsize * sizeof(char *));
+ size_t nsize;
+
+ if (env.env_size > SIZE_MAX - 128) {
+ fatalx_nodebug(_("internal error, %s overflow"),
+ "sudo_putenv_nodebug()");
+ }
+ nsize = env.env_size + 128;
+ if (nsize > SIZE_MAX / sizeof(char *)) {
+ fatalx_nodebug(_("internal error, %s overflow"),
+ "sudo_putenv_nodebug()");
+ }
+ nenvp = realloc(env.envp, nsize * sizeof(char *));
if (nenvp == NULL) {
errno = ENOMEM;
return -1;
if (dupcheck) {
len = (strchr(str, '=') - str) + 1;
- for (ep = env.envp; !found && *ep != NULL; ep++) {
+ for (ep = env.envp; *ep != NULL; ep++) {
if (strncmp(str, *ep, len) == 0) {
if (overwrite)
*ep = str;
found = true;
+ break;
}
}
- /* Prune out duplicate variables. */
+ /* Prune out extra instances of the variable we just overwrote. */
if (found && overwrite) {
- while (*ep != NULL) {
+ while (*++ep != NULL) {
if (strncmp(str, *ep, len) == 0) {
char **cur = ep;
while ((*cur = *(cur + 1)) != NULL)
cur++;
- } else {
- ep++;
+ ep--;
}
}
env.env_len = ep - env.envp;
int rval;
debug_decl(sudo_putenv, SUDO_DEBUG_ENV)
+ sudo_debug_printf(SUDO_DEBUG_INFO, "sudo_putenv: %s", str);
+
rval = sudo_putenv_nodebug(str, dupcheck, overwrite);
if (rval == -1) {
#ifdef ENV_DEBUG
if (env.envp[env.env_len] != NULL)
- errorx(1, _("sudo_putenv: corrupted envp, length mismatch"));
+ fatalx(_("sudo_putenv: corrupted envp, length mismatch"));
#endif
- errorx(1, _("unable to allocate memory"));
+ fatalx(NULL);
}
debug_return_int(rval);
}
{
char *estring;
size_t esize;
+ int rval;
debug_decl(sudo_setenv2, SUDO_DEBUG_ENV)
esize = strlen(var) + 1 + strlen(val) + 1;
strlcat(estring, "=", esize) >= esize ||
strlcat(estring, val, esize) >= esize) {
- errorx(1, _("internal error, sudo_setenv2() overflow"));
+ fatalx(_("internal error, %s overflow"), "sudo_setenv2()");
}
- debug_return_int(sudo_putenv(estring, dupcheck, overwrite));
+ rval = sudo_putenv(estring, dupcheck, overwrite);
+ if (rval == -1)
+ efree(estring);
+ debug_return_int(rval);
+}
+
+/*
+ * Similar to setenv(3) but operates on a private copy of the environment.
+ */
+int
+sudo_setenv(const char *var, const char *val, int overwrite)
+{
+ return sudo_setenv2(var, val, true, (bool)overwrite);
}
/*
static int
sudo_setenv_nodebug(const char *var, const char *val, int overwrite)
{
- char *estring;
+ char *ep, *estring = NULL;
+ const char *cp;
size_t esize;
+ int rval = -1;
- esize = strlen(var) + 1 + strlen(val) + 1;
- if ((estring = malloc(esize)) == NULL) {
- errno = ENOMEM;
- return -1;
- }
-
- /* Build environment string and insert it. */
- if (strlcpy(estring, var, esize) >= esize ||
- strlcat(estring, "=", esize) >= esize ||
- strlcat(estring, val, esize) >= esize) {
-
+ if (var == NULL || *var == '\0') {
errno = EINVAL;
- return -1;
+ goto done;
}
- return sudo_putenv_nodebug(estring, true, overwrite);
-}
-/*
- * Similar to setenv(3) but operates on a private copy of the environment.
- */
-int
-sudo_setenv(const char *var, const char *val, int overwrite)
-{
- int rval;
- debug_decl(sudo_setenv, SUDO_DEBUG_ENV)
+ /*
+ * 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 "" */
+ }
- rval = sudo_setenv_nodebug(var, val, overwrite);
- if (rval == -1) {
- if (errno == EINVAL)
- errorx(1, _("internal error, sudo_setenv() overflow"));
- errorx(1, _("unable to allocate memory"));
+ /* Allocate and fill in estring. */
+ if ((estring = ep = malloc(esize)) == NULL) {
+ errno = ENOMEM;
+ goto done;
}
- debug_return_int(rval);
+ for (cp = var; *cp && *cp != '='; cp++)
+ *ep++ = *cp;
+ *ep++ = '=';
+ if (val) {
+ for (cp = val; *cp; cp++)
+ *ep++ = *cp;
+ }
+ *ep = '\0';
+
+ rval = sudo_putenv_nodebug(estring, true, overwrite);
+done:
+ if (rval == -1)
+ free(estring);
+ return rval;
}
/*
int rval;
debug_decl(sudo_unsetenv, SUDO_DEBUG_ENV)
+ sudo_debug_printf(SUDO_DEBUG_INFO, "sudo_unsetenv: %s", name);
+
rval = sudo_unsetenv_nodebug(name);
debug_return_int(rval);
char *val;
debug_decl(sudo_getenv, SUDO_DEBUG_ENV)
+ sudo_debug_printf(SUDO_DEBUG_INFO, "sudo_getenv: %s", name);
+
val = sudo_getenv_nodebug(name);
debug_return_str(val);
delete_it = matches_env_delete(var);
if (!delete_it)
delete_it = matches_env_check(var) == false;
+
+ sudo_debug_printf(SUDO_DEBUG_INFO, "delete %s: %s",
+ var, delete_it ? "YES" : "NO");
debug_return_bool(delete_it);
}
if (keepit == -1)
keepit = matches_env_keep(var);
+ sudo_debug_printf(SUDO_DEBUG_INFO, "keep %s: %s",
+ var, keepit ? "YES" : "NO");
debug_return_bool(keepit == true);
}
rebuild_env(void)
{
char **old_envp, **ep, *cp, *ps1;
- char idbuf[MAX_UID_T_LEN];
+ char idbuf[MAX_UID_T_LEN + 1];
unsigned int didvar;
bool reset_home = false;
} else {
if (!ISSET(didvar, DID_SHELL))
sudo_setenv2("SHELL", sudo_user.pw->pw_shell, false, true);
- if (!ISSET(didvar, DID_LOGNAME))
- sudo_setenv2("LOGNAME", user_name, false, true);
- if (!ISSET(didvar, DID_USER))
- sudo_setenv2("USER", user_name, false, true);
- if (!ISSET(didvar, DID_USERNAME))
- sudo_setenv2("USERNAME", user_name, false, true);
+ /* We will set LOGNAME later in the !def_set_logname case. */
+ if (!def_set_logname) {
+ if (!ISSET(didvar, DID_LOGNAME))
+ sudo_setenv2("LOGNAME", user_name, false, true);
+ if (!ISSET(didvar, DID_USER))
+ sudo_setenv2("USER", user_name, false, true);
+ if (!ISSET(didvar, DID_USERNAME))
+ sudo_setenv2("USERNAME", user_name, false, true);
+ }
}
/* If we didn't keep HOME, reset it based on target user. */
/*
* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is not
* disabled. We skip this if we are running a login shell (because
- * they have already been set them) or sudoedit (because we want the
- * editor to find the user's startup files).
+ * they have already been set) or sudoedit (because we want the editor
+ * to find the invoking user's startup files).
*/
if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) {
if (!ISSET(didvar, KEPT_LOGNAME))
if (bad != NULL) {
bad[blen - 2] = '\0'; /* remove trailing ", " */
log_fatal(NO_MAIL,
- _("sorry, you are not allowed to set the following environment variables: %s"), bad);
+ N_("sorry, you are not allowed to set the following environment variables: %s"), bad);
/* NOTREACHED */
efree(bad);
}
read_env_file(const char *path, int overwrite)
{
FILE *fp;
- char *cp, *var, *val;
- size_t var_len, val_len;
+ char *cp, *var, *val, *line = NULL;
+ size_t var_len, val_len, linesize = 0;
if ((fp = fopen(path, "r")) == NULL)
return;
- while ((var = sudo_parseln(fp)) != NULL) {
+ while (sudo_parseln(&line, &linesize, NULL, fp) != -1) {
/* Skip blank or comment lines */
- if (*var == '\0')
+ if (*(var = line) == '\0')
continue;
/* Skip optional "export " */
sudo_putenv(cp, true, overwrite);
}
+ free(line);
fclose(fp);
}
return SUDO_HOOK_RET_NEXT;
in_progress = true;
+
+ /* Hack to make GNU gettext() find the sudoers locale when needed. */
+ if (*name == 'L' && sudoers_getlocale() == SUDOERS_LOCALE_SUDOERS) {
+ if (strcmp(name, "LANGUAGE") == 0 || strcmp(name, "LANG") == 0) {
+ *value = NULL;
+ goto done;
+ }
+ if (strcmp(name, "LC_ALL") == 0 || strcmp(name, "LC_MESSAGES") == 0) {
+ *value = def_sudoers_locale;
+ goto done;
+ }
+ }
+
*value = sudo_getenv_nodebug(name);
+done:
in_progress = false;
return SUDO_HOOK_RET_STOP;
}