/** * Helper method which allows to execute a callable as the super user the server got started by. * * @param callable $callable The callable to run * @param array $arguments Arguments to pass to the callable * * @return mixed The callables result */ public static function sudo(callable $callable, array $arguments = array()) { // don't do anything under Windows if (FileSystem::getOsIdentifier() === FileSystem::OS_IDENTIFIER_WIN) { return call_user_func_array($callable, $arguments); } // get the current user user pair (super user and effective user) $currentUserId = (int) posix_geteuid(); $superUserId = (int) posix_getuid(); // temporarily switch to the super user posix_seteuid($superUserId); // execute the callable $result = call_user_func_array($callable, $arguments); // switch back to the effective user posix_seteuid($currentUserId); return $result; }
/** * Handle an event. * * @param \League\Event\EventInterface $event The triggering event * * @return void * @see \League\Event\ListenerInterface::handle() */ public function handle(EventInterface $event) { try { // load the application server instance /** @var \AppserverIo\Appserver\Core\Interfaces\ApplicationServerInterface $applicationServer */ $applicationServer = $this->getApplicationServer(); // write a log message that the event has been invoked $applicationServer->getSystemLogger()->info($event->getName()); // don't do anything under Windows if (FileSystem::getOsIdentifier() === 'WIN') { $applicationServer->getSystemLogger()->info('Don\'t switch UID to \'%s\' because OS is Windows'); return; } // initialize the variable for user/group $uid = 0; $gid = 0; // throw an exception if the POSIX extension is not available if (extension_loaded('posix') === false) { throw new \Exception('Can\'t switch user, because POSIX extension is not available'); } // print a message with the old UID/EUID $applicationServer->getSystemLogger()->info("Running as " . posix_getuid() . "/" . posix_geteuid()); // extract the user and group name as variables extract(posix_getgrnam($applicationServer->getSystemConfiguration()->getGroup())); extract(posix_getpwnam($applicationServer->getSystemConfiguration()->getUser())); // switch the effective GID to the passed group if (posix_setegid($gid) === false) { $applicationServer->getSystemLogger()->error(sprintf('Can\'t switch GID to \'%s\'', $gid)); } // print a message with the new GID/EGID $applicationServer->getSystemLogger()->info("Running as group" . posix_getgid() . "/" . posix_getegid()); // switch the effective UID to the passed user if (posix_seteuid($uid) === false) { $applicationServer->getSystemLogger()->error(sprintf('Can\'t switch UID to \'%s\'', $uid)); } // print a message with the new UID/EUID $applicationServer->getSystemLogger()->info("Running as user " . posix_getuid() . "/" . posix_geteuid()); } catch (\Exception $e) { $applicationServer->getSystemLogger()->error($e->__toString()); } }
/** * Switches the setup mode to the passed value. * * @param string $newMode The mode to switch to * @param string $configurationFilename The path of the configuration filename * @param string $user The name of the user who started the application server * * @return void * @throws \Exception Is thrown for an invalid setup mode passed */ public function switchSetupMode($newMode, $configurationFilename, $user) { // log a message that we switch setup mode now $this->getInitialContext()->getSystemLogger()->info(sprintf('Now switch mode to %s!!!', $newMode)); // init setup context Setup::prepareContext($this->getBaseDirectory()); // init variable for the group $group = null; // pattern to replace the user in the etc/appserver/appserver.xml file $configurationUserReplacePattern = '/(<appserver[^>]+>[^<]+<params>.*<param name="user[^>]+>)([^<]+)/s'; // check setup modes switch ($newMode) { // prepares everything for developer mode case ContainerService::SETUP_MODE_DEV: // get defined group from configuration $group = Setup::getValue(SetupKeys::GROUP); // replace user in configuration file file_put_contents($configurationFilename, preg_replace($configurationUserReplacePattern, '${1}' . $user, file_get_contents($configurationFilename))); // add everyone write access to configuration files for dev mode FileSystem::recursiveChmod($this->getEtcDir(), 0777, 0777); break; // prepares everything for production mode // prepares everything for production mode case ContainerService::SETUP_MODE_PROD: // get defined user and group from configuration $user = Setup::getValue(SetupKeys::USER); $group = Setup::getValue(SetupKeys::GROUP); // replace user to be same as user in configuration file file_put_contents($configurationFilename, preg_replace($configurationUserReplacePattern, '${1}' . $user, file_get_contents($configurationFilename))); // set correct file permissions for configurations FileSystem::recursiveChmod($this->getEtcDir()); break; // prepares everything for first installation which is default mode // prepares everything for first installation which is default mode case ContainerService::SETUP_MODE_INSTALL: // load the flag marked the server as installed $isInstalledFlag = $this->getIsInstalledFlag(); // first check if it is a fresh installation if ($isInstalledFlag->isReadable() === false) { // set example app dodeploy flag to be deployed for a fresh installation touch($this->getDeployDir('example.phar.dodeploy')); } // create is installed flag for prevent further setup install mode calls touch($isInstalledFlag); // get defined user and group from configuration $user = Setup::getValue(SetupKeys::USER); $group = Setup::getValue(SetupKeys::GROUP); // set correct file permissions for configurations FileSystem::recursiveChmod($this->getEtcDir()); break; default: throw new \Exception(sprintf('Invalid setup mode %s given', $newMode)); } // check if user and group is set if (!is_null($user) && !is_null($group)) { // get needed files as accessable for all root files remove "." and ".." from the list $rootFiles = scandir($this->getBaseDirectory()); // iterate all files foreach ($rootFiles as $rootFile) { // we want just files on root dir if (is_file($rootFile) && !in_array($rootFile, array('.', '..'))) { FileSystem::chmod($rootFile, 0644); FileSystem::chown($rootFile, $user, $group); } } // ... and change own and mod of following directories FileSystem::chown($this->getBaseDirectory(), $user, $group); FileSystem::chown($this->getWebappsDir(), $user, $group); FileSystem::recursiveChown($this->getTmpDir(), $user, $group); FileSystem::recursiveChmod($this->getTmpDir()); FileSystem::recursiveChown($this->getDeployDir(), $user, $group); FileSystem::recursiveChmod($this->getDeployDir()); FileSystem::recursiveChown($this->getBaseDirectory('resources'), $user, $group); FileSystem::recursiveChmod($this->getBaseDirectory('resources')); FileSystem::recursiveChown($this->getBaseDirectory('src'), $user, $group); FileSystem::recursiveChmod($this->getBaseDirectory('src')); FileSystem::recursiveChown($this->getBaseDirectory('var'), $user, $group); FileSystem::recursiveChmod($this->getBaseDirectory('var')); FileSystem::recursiveChown($this->getBaseDirectory('tests'), $user, $group); FileSystem::recursiveChmod($this->getBaseDirectory('tests')); FileSystem::recursiveChown($this->getBaseDirectory('vendor'), $user, $group); FileSystem::recursiveChmod($this->getBaseDirectory('vendor')); // make server.php executable FileSystem::chmod($this->getBaseDirectory('server.php'), 0755); // log a message that we successfully switched to the new setup mode $this->getInitialContext()->getSystemLogger()->info(sprintf("Setup for mode '%s' done successfully!", $newMode)); } else { throw new \Exception('No user or group given'); } }
/** * (non-PHPdoc) * * @param \AppserverIo\Appserver\Core\Api\Node\ContainerNodeInterface $containerNode The container the archive belongs to * @param \SplFileInfo $archive The archive file to be deployed * * @return void * @see \AppserverIo\Appserver\Core\AbstractExtractor::deployArchive() */ public function deployArchive(ContainerNodeInterface $containerNode, \SplFileInfo $archive) { try { // create folder names based on the archive's basename $tmpFolderName = new \SplFileInfo($this->getTmpDir($containerNode) . DIRECTORY_SEPARATOR . $archive->getFilename()); $webappFolderName = new \SplFileInfo($this->getWebappsDir($containerNode) . DIRECTORY_SEPARATOR . basename($archive->getFilename(), $this->getExtensionSuffix())); // check if archive has not been deployed yet or failed sometime if ($this->isDeployable($archive)) { // flag webapp as deploying $this->flagArchive($archive, ExtractorInterface::FLAG_DEPLOYING); // backup actual webapp folder, if available if ($webappFolderName->isDir()) { // backup files that are NOT part of the archive $this->backupArchive($containerNode, $archive); // delete directories previously backed up $this->removeDir($webappFolderName); } // remove old temporary directory $this->removeDir($tmpFolderName); // initialize a \Phar instance $p = new \Phar($archive); // create a recursive directory iterator $iterator = new \RecursiveIteratorIterator($p); // unify the archive filename, because Windows uses a \ instead of / $archiveFilename = sprintf('phar://%s', str_replace(DIRECTORY_SEPARATOR, '/', $archive->getPathname())); // iterate over all files foreach ($iterator as $file) { // prepare the temporary filename $target = $tmpFolderName . str_replace($archiveFilename, '', $file->getPathname()); // create the directory if necessary if (file_exists($directory = dirname($target)) === false) { if (mkdir($directory, 0755, true) === false) { throw new \Exception(sprintf('Can\'t create directory %s', $directory)); } } // finally copy the file if (copy($file, $target) === false) { throw new \Exception(sprintf('Can\'t copy %s file to %s', $file, $target)); } } // move extracted content to webapps folder and remove temporary directory FileSystem::copyDir($tmpFolderName->getPathname(), $webappFolderName->getPathname()); FileSystem::removeDir($tmpFolderName->getPathname()); // we need to set the user/rights for the extracted folder $this->setUserRights($webappFolderName); // restore backup if available $this->restoreBackup($containerNode, $archive); // flag webapp as deployed $this->flagArchive($archive, ExtractorInterface::FLAG_DEPLOYED); // log a message that the application has successfully been deployed $this->getInitialContext()->getSystemLogger()->info(sprintf('Application archive %s has succussfully been deployed', $archive->getBasename($this->getExtensionSuffix()))); } } catch (\Exception $e) { // log error $this->getInitialContext()->getSystemLogger()->error($e->__toString()); // flag webapp as failed $this->flagArchive($archive, ExtractorInterface::FLAG_FAILED); } }
/** * Parses and returns the directories and files that matches * the passed glob pattern in a recursive way (if wanted). * * @param string $pattern The glob pattern used to parse the directories * @param integer $flags The flags passed to the glob function * @param boolean $recursive Whether or not to parse directories recursively * * @return array The directories matches the passed glob pattern * @link http://php.net/glob */ protected static function globDir($pattern, $flags = 0, $recursive = true) { return FileSystem::globDir($pattern, $flags, $recursive); }
/** * Recursively parses and returns the directories that matches the passed * glob pattern. * * @param string $pattern The glob pattern used to parse the directories * @param integer $flags The flags passed to the glob function * * @return array The directories matches the passed glob pattern * @link http://php.net/glob */ public function globDir($pattern, $flags = 0) { return FileSystem::globDir($pattern, $flags); }
/** * Copies a directory recursively. * * @param string $src The source directory to copy * @param string $dst The target directory * * @return void */ public function copyDir($src, $dst) { FileSystem::copyDir($src, $dst); }