X-Git-Url: http://git.home-dn.net/?p=manu%2Fsuphp.git;a=blobdiff_plain;f=src%2FApplication.cpp;h=bedba59b5edc5da01d2fafc07feb9e3919346c4b;hp=bb7ce50f7d6d63ef5a52ea3a563ab95ca7ae97ee;hb=849f4a7977b5780eacae8fad7a078d05f4a615ee;hpb=b0eaa3f1fbf491fdc8a3044cf20754f14254338a diff --git a/src/Application.cpp b/src/Application.cpp index bb7ce50..bedba59 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -1,5 +1,5 @@ /* - suPHP - (c)2002-2005 Sebastian Marsching + suPHP - (c)2002-2008 Sebastian Marsching This file is part of suPHP. @@ -33,6 +33,7 @@ #include "UserInfo.hpp" #include "GroupInfo.hpp" #include "Util.hpp" +#include "PathMatcher.hpp" #include "Application.hpp" @@ -48,7 +49,7 @@ int suPHP::Application::run(CommandLine& cmdline, Environment& env) { Configuration config; API& api = API_Helper::getSystemAPI(); Logger& logger = api.getSystemLogger(); - + #ifdef OPT_CONFIGFILE File cfgFile = File(OPT_CONFIGFILE); #else @@ -62,219 +63,271 @@ int suPHP::Application::run(CommandLine& cmdline, Environment& env) { // Begin try block - soft exception cannot really be handled before // initialization try { - std::string scriptFilename; - - // If caller is super-user, print info message and exit - if (api.getRealProcessUser().isSuperUser()) { - this->printAboutMessage(); - return 0; - } - config.readFromFile(cfgFile); - - // Check permissions (real uid, effective uid) - this->checkProcessPermissions(config); - - // Initialize logger - // not done before, because we need super-user privileges for - // logging anyway - logger.init(config); - - try { - scriptFilename = env.getVar("SCRIPT_FILENAME"); - } catch (KeyNotFoundException& e) { - logger.logError("Environment variable SCRIPT_FILENAME not set"); - this->printAboutMessage(); - return 1; - } - - this->checkScriptFile(scriptFilename, config, env); - - // Root privileges are needed for chroot() - // so do this before changing process permissions - if (config.getChrootPath().length() > 0) { - api.chroot(config.getChrootPath()); - } - - this->changeProcessPermissions(scriptFilename, config, env); - - interpreter = this->getInterpreter(env, config); - targetMode = this->getTargetMode(interpreter); - - // Prepare environment for new process - newEnv = this->prepareEnvironment(env, config, targetMode); - - // Set PATH_TRANSLATED to SCRIPT_FILENAME, otherwise - // the PHP interpreter will not be able to find the script - if (targetMode == TARGETMODE_PHP && newEnv.hasVar("PATH_TRANSLATED")) { - newEnv.setVar("PATH_TRANSLATED", scriptFilename); - } - - // Log attempt to execute script - logger.logInfo("Executing \"" + scriptFilename + "\" as UID " - + Util::intToStr(api.getEffectiveProcessUser().getUid()) - + ", GID " - + Util::intToStr( - api.getEffectiveProcessGroup().getGid())); - - this->executeScript(scriptFilename, interpreter, targetMode, newEnv, - config); - - // Function should never return - // So, if we get here, return with error code - return 1; + std::string scriptFilename; + UserInfo targetUser; + GroupInfo targetGroup; + + // If caller is super-user, print info message and exit + if (api.getRealProcessUser().isSuperUser()) { + this->printAboutMessage(); + return 0; + } + config.readFromFile(cfgFile); + + // Check permissions (real uid, effective uid) + this->checkProcessPermissions(config); + + // Initialize logger + // not done before, because we need super-user privileges for + // logging anyway + logger.init(config); + + try { + scriptFilename = env.getVar("SCRIPT_FILENAME"); + } catch (KeyNotFoundException& e) { + logger.logError("Environment variable SCRIPT_FILENAME not set"); + this->printAboutMessage(); + return 1; + } + + + // Do checks that do not need target user info + this->checkScriptFileStage1(scriptFilename, config, env); + + // Find out target user + this->checkProcessPermissions(scriptFilename, config, env, targetUser, targetGroup); + + // Now do checks that might require user info + this->checkScriptFileStage2(scriptFilename, config, env, targetUser, targetGroup); + + // Root privileges are needed for chroot() + // so do this before changing process permissions + if (config.getChrootPath().length() > 0) { + PathMatcher pathMatcher = PathMatcher(targetUser, targetGroup); + std::string chrootPath = pathMatcher.resolveVariables(config.getChrootPath()); + api.chroot(chrootPath); + } + + this->changeProcessPermissions(config, targetUser, targetGroup); + + interpreter = this->getInterpreter(env, config); + targetMode = this->getTargetMode(interpreter); + + // Prepare environment for new process + newEnv = this->prepareEnvironment(env, config, targetMode); + + // Set PATH_TRANSLATED to SCRIPT_FILENAME, otherwise + // the PHP interpreter will not be able to find the script + if (targetMode == TARGETMODE_PHP && newEnv.hasVar("PATH_TRANSLATED")) { + newEnv.setVar("PATH_TRANSLATED", scriptFilename); + } + + // Log attempt to execute script + logger.logInfo("Executing \"" + scriptFilename + "\" as UID " + + Util::intToStr(api.getEffectiveProcessUser().getUid()) + + ", GID " + + Util::intToStr( + api.getEffectiveProcessGroup().getGid())); + + this->executeScript(scriptFilename, interpreter, targetMode, newEnv, + config); + + // Function should never return + // So, if we get here, return with error code + return 1; } catch (SoftException& e) { - if (!config.getErrorsToBrowser()) { - std::cerr << e; - return 2; - } - std::cout << "Content-Type: text/html\n" - << "Status: 500\n" - << "\n" - << "\n" - << " \n" - << " 500 Internal Server Error\n" - << " \n" - << " \n" - << "

Internal Server Error

\n" - << "

" << e.getMessage() << "

\n" - << "
" - << "
suPHP " << PACKAGE_VERSION << "
\n" - << " \n" - << "\n"; + if (!config.getErrorsToBrowser()) { + std::cerr << e; + return 2; + } + std::cout << "Content-Type: text/html\n" + << "Status: 500\n" + << "\n" + << "\n" + << " \n" + << " 500 Internal Server Error\n" + << " \n" + << " \n" + << "

Internal Server Error

\n" + << "

" << e.getMessage() << "

\n" + << "
" + << "
suPHP " << PACKAGE_VERSION << "
\n" + << " \n" + << "\n"; } } void suPHP::Application::printAboutMessage() { std::cerr << "suPHP version " << PACKAGE_VERSION << "\n"; - std::cerr << "(c) 2002-2005 Sebastian Marsching\n"; + std::cerr << "(c) 2002-2007 Sebastian Marsching\n"; std::cerr << std::endl; std::cerr << "suPHP has to be called by mod_suphp to work." << std::endl; } -void suPHP::Application::checkProcessPermissions(Configuration& config) +void suPHP::Application::checkProcessPermissions(Configuration& config) throw (SecurityException, LookupException) { API& api = API_Helper::getSystemAPI(); if (api.getRealProcessUser() != - api.getUserInfo(config.getWebserverUser())) { - throw SecurityException("Calling user is not webserver user!", - __FILE__, __LINE__); + api.getUserInfo(config.getWebserverUser())) { + throw SecurityException("Calling user is not webserver user!", + __FILE__, __LINE__); } - + if (!api.getEffectiveProcessUser().isSuperUser()) { - throw SecurityException( - "Do not have root privileges. Executable not set-uid root?", - __FILE__, __LINE__); + throw SecurityException( + "Do not have root privileges. Executable not set-uid root?", + __FILE__, __LINE__); } } -void suPHP::Application::checkScriptFile( - const std::string& scriptFilename, +void suPHP::Application::checkScriptFileStage1( + const std::string& scriptFilename, const Configuration& config, const Environment& environment) const throw (SystemException, SoftException) { Logger& logger = API_Helper::getSystemAPI().getSystemLogger(); File scriptFile = File(scriptFilename); + File realScriptFile = File(scriptFile.getRealPath()); // Check wheter file exists if (!scriptFile.exists()) { - std::string error = "File " + scriptFile.getPath() + " does not exist"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + std::string error = "File " + scriptFile.getPath() + " does not exist"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } - - // Get full path to script file - - File realScriptFile = File(scriptFile.getRealPath()); - File directory = realScriptFile.getParentDirectory(); - - // Check wheter script is in docroot - if (realScriptFile.getPath().find(config.getDocroot()) != 0) { - std::string error = "Script \"" + scriptFile.getPath() - + "\" resolving to \"" + realScriptFile.getPath() - + "\" not within configured docroot"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + if (!realScriptFile.exists()) { + std::string error = "File " + realScriptFile.getPath() + + " referenced by symlink " +scriptFile.getPath() + + " does not exist"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } // If enabled, check whether script is in the vhost's docroot if (!environment.hasVar("DOCUMENT_ROOT")) - throw SoftException("Environment variable DOCUMENT_ROOT not set", - __FILE__, __LINE__); + throw SoftException("Environment variable DOCUMENT_ROOT not set", + __FILE__, __LINE__); if (config.getCheckVHostDocroot() - && realScriptFile.getPath().find(environment.getVar("DOCUMENT_ROOT")) - != 0) { - - std::string error = "File \"" + realScriptFile.getPath() - + "\" is not in document root of Vhost \"" - + environment.getVar("DOCUMENT_ROOT") + "\""; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + && realScriptFile.getPath().find(environment.getVar("DOCUMENT_ROOT")) + != 0) { + + std::string error = "File \"" + realScriptFile.getPath() + + "\" is not in document root of Vhost \"" + + environment.getVar("DOCUMENT_ROOT") + "\""; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); + } + if (config.getCheckVHostDocroot() + && scriptFile.getPath().find(environment.getVar("DOCUMENT_ROOT")) + != 0) { + + std::string error = "File \"" + scriptFile.getPath() + + "\" is not in document root of Vhost \"" + + environment.getVar("DOCUMENT_ROOT") + "\""; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } - // Check script and directory permissions + // Check script permissions + // Directories will be checked later if (!realScriptFile.hasUserReadBit()) { - std::string error = "File \"" + realScriptFile.getPath() - + "\" not readable"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); - + std::string error = "File \"" + realScriptFile.getPath() + + "\" not readable"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); + } if (!config.getAllowFileGroupWriteable() - && realScriptFile.hasGroupWriteBit()) { - std::string error = "File \"" + realScriptFile.getPath() - + "\" is writeable by group"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); - } - - if (!config.getAllowDirectoryGroupWriteable() - && directory.hasGroupWriteBit()) { - std::string error = "Directory \"" + directory.getPath() - + "\" is writeable by group"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + && realScriptFile.hasGroupWriteBit()) { + std::string error = "File \"" + realScriptFile.getPath() + + "\" is writeable by group"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } if (!config.getAllowFileOthersWriteable() - && realScriptFile.hasOthersWriteBit()) { - std::string error = "File \"" + realScriptFile.getPath() - + "\" is writeable by others"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); - } - - if (!config.getAllowDirectoryOthersWriteable() - && directory.hasOthersWriteBit()) { - std::string error = "Directory \"" + directory.getPath() - + "\" is writeable by others"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + && realScriptFile.hasOthersWriteBit()) { + std::string error = "File \"" + realScriptFile.getPath() + + "\" is writeable by others"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } // Check UID/GID of symlink is matching target if (scriptFile.getUser() != realScriptFile.getUser() - || scriptFile.getGroup() != realScriptFile.getGroup()) { - std::string error = "UID or GID of symlink \"" + scriptFile.getPath() - + "\" is not matching its target"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + || scriptFile.getGroup() != realScriptFile.getGroup()) { + std::string error = "UID or GID of symlink \"" + scriptFile.getPath() + + "\" is not matching its target"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } } +void suPHP::Application::checkScriptFileStage2( + const std::string& scriptFilename, + const Configuration& config, + const Environment& environment, + const UserInfo& targetUser, + const GroupInfo& targetGroup) const + throw (SystemException, SoftException) { + Logger& logger = API_Helper::getSystemAPI().getSystemLogger(); + File scriptFile = File(scriptFilename); + PathMatcher pathMatcher = PathMatcher(targetUser, targetGroup); + + // Get full path to script file + File realScriptFile = File(scriptFile.getRealPath()); + + // Check wheter script is in one of the defined docroots + bool file_in_docroot = false; + const std::vector docroots = config.getDocroots(); + for (std::vector::const_iterator i = docroots.begin(); i != docroots.end(); i++) { + std::string docroot = *i; + if (pathMatcher.matches(docroot, realScriptFile.getPath())) { + file_in_docroot = true; + break; + } + } + if (!file_in_docroot) { + std::string error = "Script \"" + scriptFile.getPath() + + "\" resolving to \"" + realScriptFile.getPath() + + "\" not within configured docroot"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); + } + file_in_docroot = false; + for (std::vector::const_iterator i = docroots.begin(); i != docroots.end(); i++) { + std::string docroot = *i; + if (pathMatcher.matches(docroot, scriptFile.getPath())) { + file_in_docroot = true; + break; + } + } + if (!file_in_docroot) { + std::string error = "Script \"" + scriptFile.getPath() + + "\" not within configured docroot"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); + } -void suPHP::Application::changeProcessPermissions( - const std::string& scriptFilename, + // Check directory ownership and permissions + checkParentDirectories(realScriptFile, targetUser, config); + checkParentDirectories(scriptFile, targetUser, config); +} + +void suPHP::Application::checkProcessPermissions( + const std::string& scriptFilename, const Configuration& config, - const Environment& environment) const + const Environment& environment, + UserInfo& targetUser, + GroupInfo& targetGroup) const throw (SystemException, SoftException, SecurityException) { - UserInfo targetUser; - GroupInfo targetGroup; - File scriptFile = File(File(scriptFilename).getRealPath()); + File scriptFile = File(scriptFilename); + File realScriptFile = File(scriptFile.getRealPath()); API& api = API_Helper::getSystemAPI(); Logger& logger = api.getSystemLogger(); @@ -291,44 +344,44 @@ void suPHP::Application::changeProcessPermissions( // Check UID/GID of script if (scriptFile.getUser().getUid() < config.getMinUid()) { - std::string error = "UID of script \"" + scriptFilename - + "\" is smaller than min_uid"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + std::string error = "UID of script \"" + scriptFilename + + "\" is smaller than min_uid"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } if (scriptFile.getGroup().getGid() < config.getMinGid()) { - std::string error = "GID of script \"" + scriptFilename - + "\" is smaller than min_gid"; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + std::string error = "GID of script \"" + scriptFilename + + "\" is smaller than min_gid"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } - + // Paranoid and force mode #if (defined(OPT_USERGROUP_PARANOID) || defined(OPT_USERGROUP_FORCE)) std::string targetUsername, targetGroupname; try { - targetUsername = environment.getVar("SUPHP_USER"); - targetGroupname = environment.getVar("SUPHP_GROUP"); + targetUsername = environment.getVar("SUPHP_USER"); + targetGroupname = environment.getVar("SUPHP_GROUP"); } catch (KeyNotFoundException& e) { - throw SecurityException( - "Environment variable SUPHP_USER or SUPHP_GROUP not set", - __FILE__, __LINE__); + throw SecurityException( + "Environment variable SUPHP_USER or SUPHP_GROUP not set", + __FILE__, __LINE__); } - + if (targetUsername[0] == '#' && targetUsername.find_first_not_of( - "0123456789", 1) == std::string::npos) { - targetUser = api.getUserInfo(Util::strToInt(targetUsername.substr(1))); + "0123456789", 1) == std::string::npos) { + targetUser = api.getUserInfo(Util::strToInt(targetUsername.substr(1))); } else { - targetUser = api.getUserInfo(targetUsername); + targetUser = api.getUserInfo(targetUsername); } if (targetGroupname[0] == '#' && targetGroupname.find_first_not_of( - "0123456789", 1) == std::string::npos) { - targetGroup = api.getGroupInfo( - Util::strToInt(targetGroupname.substr(1))); + "0123456789", 1) == std::string::npos) { + targetGroup = api.getGroupInfo( + Util::strToInt(targetGroupname.substr(1))); } else { - targetGroup = api.getGroupInfo(targetGroupname); + targetGroup = api.getGroupInfo(targetGroupname); } #endif // OPT_USERGROUP_PARANOID || OPT_USERGROUP_FORCE @@ -338,35 +391,41 @@ void suPHP::Application::changeProcessPermissions( targetUser = scriptFile.getUser(); targetGroup = scriptFile.getGroup(); #endif // OPT_USERGROUP_OWNER - + // Paranoid mode only #ifdef OPT_USERGROUP_PARANOID if (targetUser != scriptFile.getUser()) { - std::string error ="Mismatch between target UID (" - + Util::intToStr(targetUser.getUid()) + ") and UID (" - + Util::intToStr(scriptFile.getUser().getUid()) + ") of file \"" - + scriptFile.getPath() + "\""; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + std::string error ="Mismatch between target UID (" + + Util::intToStr(targetUser.getUid()) + ") and UID (" + + Util::intToStr(scriptFile.getUser().getUid()) + ") of file \"" + + scriptFile.getPath() + "\""; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } if (targetGroup != scriptFile.getGroup()) { - std::string error ="Mismatch between target GID (" - + Util::intToStr(targetGroup.getGid()) + ") and GID (" - + Util::intToStr(scriptFile.getGroup().getGid()) + ") of file \"" - + scriptFile.getPath() + "\""; - logger.logWarning(error); - throw SoftException(error, __FILE__, __LINE__); + std::string error ="Mismatch between target GID (" + + Util::intToStr(targetGroup.getGid()) + ") and GID (" + + Util::intToStr(scriptFile.getGroup().getGid()) + ") of file \"" + + scriptFile.getPath() + "\""; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); } -#endif // OPT_USERGROUP_PARANOID +#endif // OPT_USERGROUP_PARANOID +} - // Common code used for all modes +void suPHP::Application::changeProcessPermissions( + const Configuration& config, + const UserInfo& targetUser, + const GroupInfo& targetGroup) const + throw (SystemException, SoftException, SecurityException) { + API& api = API_Helper::getSystemAPI(); // Set new group first, because we still need super-user privileges // for this api.setProcessGroup(targetGroup); - + // Then set new user api.setProcessUser(targetUser); @@ -379,44 +438,44 @@ Environment suPHP::Application::prepareEnvironment( throw (KeyNotFoundException) { // Create environment for new process from old environment Environment env = sourceEnv; - + // Delete unwanted environment variables if (env.hasVar("LD_PRELOAD")) - env.deleteVar("LD_PRELOAD"); + env.deleteVar("LD_PRELOAD"); if (env.hasVar("LD_LIBRARY_PATH")) - env.deleteVar("LD_LIBRARY_PATH"); + env.deleteVar("LD_LIBRARY_PATH"); if (env.hasVar("SUPHP_USER")) - env.deleteVar("SUPHP_USER"); + env.deleteVar("SUPHP_USER"); if (env.hasVar("SUPHP_GROUP")) - env.deleteVar("SUPHP_GROUP"); + env.deleteVar("SUPHP_GROUP"); if (env.hasVar("SUPHP_HANDLER")) - env.deleteVar("SUPHP_HANDLER"); + env.deleteVar("SUPHP_HANDLER"); if (env.hasVar("SUPHP_AUTH_USER")) - env.deleteVar("SUPHP_AUTH_USER"); + env.deleteVar("SUPHP_AUTH_USER"); if (env.hasVar("SUPHP_AUTH_PW")) - env.deleteVar("SUPHP_AUTH_PW"); + env.deleteVar("SUPHP_AUTH_PW"); if (env.hasVar("SUPHP_PHP_CONFIG")) - env.deleteVar("SUPHP_PHP_CONFIG"); - + env.deleteVar("SUPHP_PHP_CONFIG"); + // Reset PATH env.putVar("PATH", config.getEnvPath()); // If we are in PHP mode, set PHP specific variables if (mode == TARGETMODE_PHP) { - if (sourceEnv.hasVar("SUPHP_PHP_CONFIG")) - env.putVar("PHPRC", sourceEnv.getVar("SUPHP_PHP_CONFIG")); - if (sourceEnv.hasVar("SUPHP_AUTH_USER") - && sourceEnv.hasVar("SUPHP_AUTH_PW")) { - env.putVar("PHP_AUTH_USER", sourceEnv.getVar("SUPHP_AUTH_USER")); - env.putVar("PHP_AUTH_PW", sourceEnv.getVar("SUPHP_AUTH_PW")); - } - - // PHP may need this, when compiled with security features - if (!env.hasVar("REDIRECT_STATUS")) { - env.putVar("REDIRECT_STATUS", "200"); - } + if (sourceEnv.hasVar("SUPHP_PHP_CONFIG")) + env.putVar("PHPRC", sourceEnv.getVar("SUPHP_PHP_CONFIG")); + if (sourceEnv.hasVar("SUPHP_AUTH_USER") + && sourceEnv.hasVar("SUPHP_AUTH_PW")) { + env.putVar("PHP_AUTH_USER", sourceEnv.getVar("SUPHP_AUTH_USER")); + env.putVar("PHP_AUTH_PW", sourceEnv.getVar("SUPHP_AUTH_PW")); + } + + // PHP may need this, when compiled with security features + if (!env.hasVar("REDIRECT_STATUS")) { + env.putVar("REDIRECT_STATUS", "200"); + } } - + return env; } @@ -425,18 +484,18 @@ std::string suPHP::Application::getInterpreter( const Environment& env, const Configuration& config) throw (SecurityException) { if (!env.hasVar("SUPHP_HANDLER")) - throw SecurityException("Environment variable SUPHP_HANDLER not set", - __FILE__, __LINE__); + throw SecurityException("Environment variable SUPHP_HANDLER not set", + __FILE__, __LINE__); std::string handler = env.getVar("SUPHP_HANDLER"); - + std::string interpreter = ""; try { - interpreter = config.getInterpreter(handler); + interpreter = config.getInterpreter(handler); } catch (KeyNotFoundException& e) { - throw SecurityException ("Handler not found in configuration", e, - __FILE__, __LINE__); + throw SecurityException ("Handler not found in configuration", e, + __FILE__, __LINE__); } - + return interpreter; } @@ -444,55 +503,92 @@ std::string suPHP::Application::getInterpreter( TargetMode suPHP::Application::getTargetMode(const std::string& interpreter) throw (SecurityException) { if (interpreter.substr(0, 4) == "php:") - return TARGETMODE_PHP; + return TARGETMODE_PHP; else if (interpreter == "execute:!self") - return TARGETMODE_SELFEXECUTE; + return TARGETMODE_SELFEXECUTE; else - throw SecurityException("Unknown Interpreter: " + interpreter, - __FILE__, __LINE__); + throw SecurityException("Unknown Interpreter: " + interpreter, + __FILE__, __LINE__); } void suPHP::Application::executeScript(const std::string& scriptFilename, - const std::string& interpreter, - TargetMode mode, - const Environment& env, - const Configuration& config) const + const std::string& interpreter, + TargetMode mode, + const Environment& env, + const Configuration& config) const throw (SoftException) { try { - // Change working directory to script path - API_Helper::getSystemAPI().setCwd( - File(scriptFilename).getParentDirectory().getPath()); - if (mode == TARGETMODE_PHP) { - std::string interpreterPath = interpreter.substr(4); - CommandLine cline; - cline.putArgument(interpreterPath); - API_Helper::getSystemAPI().execute(interpreterPath, cline, env); - } else if (mode == TARGETMODE_SELFEXECUTE) { - CommandLine cline; - cline.putArgument(scriptFilename); - API_Helper::getSystemAPI().execute(scriptFilename, cline, env); - } + // Change working directory to script path + API_Helper::getSystemAPI().setCwd( + File(scriptFilename).getParentDirectory().getPath()); + if (mode == TARGETMODE_PHP) { + std::string interpreterPath = interpreter.substr(4); + CommandLine cline; + cline.putArgument(interpreterPath); + API_Helper::getSystemAPI().execute(interpreterPath, cline, env); + } else if (mode == TARGETMODE_SELFEXECUTE) { + CommandLine cline; + cline.putArgument(scriptFilename); + API_Helper::getSystemAPI().execute(scriptFilename, cline, env); + } } catch (SystemException& e) { - throw SoftException("Could not execute script \"" + scriptFilename - + "\"", e, __FILE__, __LINE__); + throw SoftException("Could not execute script \"" + scriptFilename + + "\"", e, __FILE__, __LINE__); } } +void suPHP::Application::checkParentDirectories(const File& file, + const UserInfo& owner, + const Configuration& config) const throw (SoftException) { + File directory = file; + Logger& logger = API_Helper::getSystemAPI().getSystemLogger(); + do { + directory = directory.getParentDirectory(); + + UserInfo directoryOwner = directory.getUser(); + if (directoryOwner != owner && !directoryOwner.isSuperUser()) { + std::string error = "Directory " + directory.getPath() + + " is not owned by " + owner.getUsername(); + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); + } + + if (!directory.isSymlink() + && !config.getAllowDirectoryGroupWriteable() + && directory.hasGroupWriteBit()) { + std::string error = "Directory \"" + directory.getPath() + + "\" is writeable by group"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); + } + + if (!directory.isSymlink() + && !config.getAllowDirectoryOthersWriteable() + && directory.hasOthersWriteBit()) { + std::string error = "Directory \"" + directory.getPath() + + "\" is writeable by others"; + logger.logWarning(error); + throw SoftException(error, __FILE__, __LINE__); + } + } while (directory.getPath() != "/"); +} + + int main(int argc, char **argv) { try { - API& api = API_Helper::getSystemAPI(); - CommandLine cmdline; - Environment env; - Application app; - for (int i=0; i