From bb6d003e4ff6e0d4bc92a56e0247eca490eac3ae Mon Sep 17 00:00:00 2001 From: Allan Odgaard Date: Wed, 6 Feb 2013 23:43:13 +0100 Subject: [PATCH] Read environment variable whitelist from user defaults MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is read using the ‘environmentWhitelist’ key and the value should be a colon-separated list of variables that should be inherited from TextMate’s parent process. If the variable includes an asterisk then it is matched as a glob. Example: defaults write com.macromates.TextMate.preview environmentWhitelist '$default:MANPATH:*EDITOR' Here ‘$default’ will expand to TextMate’s default whitelist. Normally TextMate will setup HOME, PATH, TMPDIR, LOGNAME, and USER. If you whitelist any of these, then the variable (if set) will instead be inherited from the parent process. Closes #718. --- Frameworks/io/src/environment.cc | 61 +++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/Frameworks/io/src/environment.cc b/Frameworks/io/src/environment.cc index 2b059774..80195ed0 100644 --- a/Frameworks/io/src/environment.cc +++ b/Frameworks/io/src/environment.cc @@ -1,18 +1,47 @@ #include "environment.h" #include "path.h" +#include +#include +#include +#include #include #include namespace oak { - static bool include_variable (std::string const& variable) - { - static std::set const WhiteListedVariables = { "COMMAND_MODE", "SHELL", "SHLVL", "SSH_AUTH_SOCK", "__CF_USER_TEXT_ENCODING" }; - return variable.find("Apple") == 0 || WhiteListedVariables.find(variable) != WhiteListedVariables.end(); - } - std::map setup_basic_environment () { + std::string whitelistStr = "Apple_*:COMMAND_MODE:SHELL:SHLVL:SSH_AUTH_SOCK:__CF_USER_TEXT_ENCODING"; + if(CFStringRef userWhitelist = (CFStringRef)CFPreferencesCopyAppValue(CFSTR("environmentWhitelist"), kCFPreferencesCurrentApplication)) + { + if(CFGetTypeID(userWhitelist) == CFStringGetTypeID()) + whitelistStr = format_string::expand(cf::to_s(userWhitelist), std::map{ { "default", whitelistStr } }); + CFRelease(userWhitelist); + } + + std::set whitelistSet; + std::vector whitelistGlobs; + for(auto str : text::split(whitelistStr, ":")) + { + if(str.find("*") != std::string::npos) + whitelistGlobs.push_back(str); + else whitelistSet.insert(str); + } + + std::map res; + + char*** envPtr = _NSGetEnviron(); + for(char** pair = *envPtr; pair && *pair; ++pair) + { + char* value = strchr(*pair, '='); + if(value && *value == '=') + { + std::string const key = std::string(*pair, value); + if(whitelistSet.find(key) != whitelistSet.end() || std::any_of(whitelistGlobs.begin(), whitelistGlobs.end(), [&key](path::glob_t const& glob){ return glob.does_match(key); })) + res[key] = value + 1; + } + } + passwd* entry = path::passwd_entry(); int mib[2] = { CTL_USER, USER_CS_PATH }; @@ -21,21 +50,11 @@ namespace oak char* path = new char[len]; sysctl(mib, 2, path, &len, NULL, 0); - std::map res; - - char*** envPtr = _NSGetEnviron(); - for(char** pair = *envPtr; pair && *pair; ++pair) - { - char* value = strchr(*pair, '='); - if(value && *value == '=' && include_variable(std::string(*pair, value))) - res[std::string(*pair, value)] = value + 1; - } - - res["HOME"] = entry->pw_dir; - res["PATH"] = path; - res["TMPDIR"] = path::temp(); - res["LOGNAME"] = entry->pw_name; - res["USER"] = entry->pw_name; + res.insert(std::make_pair("HOME", entry->pw_dir)); + res.insert(std::make_pair("PATH", path)); + res.insert(std::make_pair("TMPDIR", path::temp())); + res.insert(std::make_pair("LOGNAME", entry->pw_name)); + res.insert(std::make_pair("USER", entry->pw_name)); return res; }