diff options
Diffstat (limited to '')
-rw-r--r-- | lib/env.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/lib/env.c b/lib/env.c new file mode 100644 index 0000000..91c935c --- /dev/null +++ b/lib/env.c @@ -0,0 +1,140 @@ +/* + * environ[] array cleanup code and getenv() wappers + * + * No copyright is claimed. This code is in the public domain; do with + * it what you wish. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include <sys/syscall.h> +#endif +#include <unistd.h> +#include <sys/types.h> + +#include "env.h" + +#ifndef HAVE_ENVIRON_DECL +extern char **environ; +#endif + +static char * const forbid[] = { + "BASH_ENV=", /* GNU creeping featurism strikes again... */ + "ENV=", + "HOME=", + "IFS=", + "KRB_CONF=", + "LD_", /* anything with the LD_ prefix */ + "LIBPATH=", + "MAIL=", + "NLSPATH=", + "PATH=", + "SHELL=", + "SHLIB_PATH=", + (char *) 0 +}; + +/* these are allowed, but with no slashes inside + (to work around security problems in GNU gettext) */ +static char * const noslash[] = { + "LANG=", + "LANGUAGE=", + "LC_", /* anything with the LC_ prefix */ + (char *) 0 +}; + +void +sanitize_env(void) +{ + char **envp = environ; + char * const *bad; + char **cur; + int last = 0; + + for (cur = envp; *cur; cur++) + last++; + + for (cur = envp; *cur; cur++) { + for (bad = forbid; *bad; bad++) { + if (strncmp(*cur, *bad, strlen(*bad)) == 0) { + last = remote_entry(envp, cur - envp, last); + cur--; + break; + } + } + } + + for (cur = envp; *cur; cur++) { + for (bad = noslash; *bad; bad++) { + if (strncmp(*cur, *bad, strlen(*bad)) != 0) + continue; + if (!strchr(*cur, '/')) + continue; /* OK */ + last = remote_entry(envp, cur - envp, last); + cur--; + break; + } + } +} + + +char *safe_getenv(const char *arg) +{ + uid_t ruid = getuid(); + + if (ruid != 0 || (ruid != geteuid()) || (getgid() != getegid())) + return NULL; +#ifdef HAVE_PRCTL + if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#else +#if (defined(linux) && defined(SYS_prctl)) + if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0) + return NULL; +#endif +#endif +#ifdef HAVE_SECURE_GETENV +return secure_getenv(arg); +#elif HAVE___SECURE_GETENV + return __secure_getenv(arg); +#else + return getenv(arg); +#endif +} + +#ifdef TEST_PROGRAM +int main(void) +{ + char *const *bad; + char copy[32]; + char *p; + int retval = EXIT_SUCCESS; + + for (bad = forbid; *bad; bad++) { + strcpy(copy, *bad); + p = strchr(copy, '='); + if (p) + *p = '\0'; + setenv(copy, copy, 1); + } + sanitize_env(); + for (bad = forbid; *bad; bad++) { + strcpy(copy, *bad); + p = strchr(copy, '='); + if (p) + *p = '\0'; + p = getenv(copy); + if (p) { + warnx("%s was not removed", copy); + retval = EXIT_FAILURE; + } + } + return retval; +} +#endif |