pluginName = $pluginName; $budleMapping = Array( 'lvemanager' => 'main', 'resource-usage' => 'resource_usage', 'resource_usage' => 'resource_usage', 'nodejs_selector' => 'nodejs_selector', 'python_selector' => 'python_selector', 'php_selector' => 'php_selector', 'xray' => 'xray', 'wpos' => 'wpos', ); if (!isset($budleMapping[$pluginName])) { $this->_haltWith(400); return; } $this->bundleName = $budleMapping[$pluginName]; $this->loadConfig(); $this->loadUserData(); } /** * Halt request with HTTP status code. Production override of * ``http_response_code(...) + exit()``; tests subclass to record * the exit instead of terminating the test process. * * Status MUST be set before any output: when ``processRequest`` has * already called ``ob_end_clean()``, an ``echo`` from the caller would * flush headers with the default 200 and a later ``http_response_code()`` * silently no-ops. Accepting the body here keeps the order correct in * every call site. */ protected function _haltWith($code, $body = null) { http_response_code($code); if ($body !== null) { echo $body; } exit(); } function loadConfig() { $iniData = file_get_contents(self::CONFIG_INI_FILE); $this->config = parse_ini_string($iniData, true)['lvemanager_config']; if (!$this->config) { $this->config = Array(); } } function loadUserData() { $userInfoCli = $this->config['ui_user_info']; $token = $this->defineAndGetSessionToken(); $this->userData = json_decode(shell_exec($userInfoCli.' '.escapeshellarg($token))); } function validateUserData($data) { if ( !is_object($data) || !property_exists($data, 'userName') || !is_string($data->userName) || !property_exists($data, 'userType') || !in_array($data->userType, ['admin', 'reseller', 'user']) ) { $this->sendErrorResponse('INVALID USER DATA', false, true); } } /** * Update and return session token if it was provided by vendor. * @return string */ public function defineAndGetSessionToken() { if (@$_GET['token']) { setcookie('CLSIDTOKEN', @$_GET['token']); return @$_GET['token']; } if (isset($_COOKIE['CLSIDTOKEN'])) { return $_COOKIE['CLSIDTOKEN']; } $this->sendErrorResponse('INVALID SESSION TOKEN', false, true); } /** * Get base URL of site. * @return string */ public function getBaseUrl() { return $this->userData->baseUri; } /** * Get plugin version * @return string */ public static function getPluginVersion() { return trim(exec('cat /usr/share/l.v.e-manager/version')); } /** * Get name of current authorized user in system. * @return string */ public function getLogin() { return $this->userData->userName; } /** * Get name of current authorized user in system. * @return string */ public function getUserId() { return $this->userData->userId; } /** * Get URL to vendor resources, * which were defined in integration config file * @return string */ public function getVendorSrcUrl() { return $this->getBaseUrl().'/vendor_src/'; } /** * Get current user type: admin|reseller|user * @return string */ public function getUserType() { return $this->userData->userType; } public function getRequestHandler() { $pluginMapping = Array( 'lvemanager' => 'send-request.php', 'nodejs_selector' => 'send-request-nodejs.php', 'python_selector' => 'send-request-python.php', 'php_selector' => 'send-request-php-selector.php', 'xray' => 'send-request-xray.php', 'resource_usage' => 'send-request-resource-usage.php', 'wpos' => 'send-request-awp.php', ); return $pluginMapping[$this->pluginName] ? $pluginMapping[$this->pluginName] : $pluginMapping['lvemanager']; } /** * Check reseller have not access to admin * and user have not acces to reseller and admin. * * @param $owner * @return down privileges value */ public function checkOwner($owner) { switch ($this->userData->userType) { case $this::OWNER_RESELLER: $newOwner = in_array($owner, array($this::OWNER_RESELLER, $this::OWNER_USER)) ? $owner : $this::OWNER_RESELLER; break; case $this::OWNER_USER: $newOwner = $this::OWNER_USER; break; default: $newOwner = $owner; } return $newOwner; } /** * Processes of incoming post request. * * @param $owner * @throws pm_Exception */ public function processRequest($owner, $plugin_name = '') { $this->_checkVulnerabilities(); $this->validateUserData($this->userData); $this->owner = $this->checkOwner($owner); if (!isset($_POST['command'])) { $this->sendErrorResponse('COMMAND NOT SPECIFIED'); } $data['owner'] = $this->owner; $data['command'] = $_POST['command']; if (isset($_POST['method'])) { $data['method'] = $_POST['method']; } if (isset($_POST['params'])) { $data['params'] = $_POST['params']; } if (in_array($this->owner, array(self::OWNER_USER, self::OWNER_RESELLER))) { $this->userInfo = array( 'username' => $this->getLogin(), 'lve-id' => $this->getUserId(), ); $data['user_info'] = $this->userInfo; } if (isset($_POST['mockJson'])) { $data['mockJson'] = $_POST['mockJson']; } if (isset($_POST['lang'])) { $data['lang'] = $_POST['lang']; } if ($plugin_name !== '') { $data['plugin_name'] = $plugin_name; } $fullCommandStr = sprintf( "%s --data=%s 2>&1", $this->CLOUDLINUX_CLI, base64_encode(json_encode($data)) ); putenv('LC_ALL=en_US.UTF-8'); ob_start(); passthru($fullCommandStr); $responseInJson = ob_get_contents(); ob_end_clean(); $response = json_decode($responseInJson, true); if (is_null($response) && !empty($responseInJson)) { $this->sendErrorResponse( 'ERROR.wrong_received_data', false, false, 503, $responseInJson ); } if (isset($response['result']) && $response['result'] === 'file') { $this->serveFile($response['filepath'], $response['filesize'], $data); } else if (isset($response['result']) && $response['result'] !== 'success' && $response['result'] !== 'rollback') { $this->sendErrorResponse($responseInJson, true); } else if (empty($responseInJson)) { $this->sendErrorResponse('RESPONSE OF COMMAND IS EMPTY'); } echo $responseInJson; } /** * Returns response to SPA with error code, message and break execution of * script with status code. * * @param $message * @param $isJSON * @param $logoutSignal * @param int $statusCode * @param string $details */ public function sendErrorResponse( $message, $isJSON = false, $logoutSignal = false, $statusCode = 503, $details = '' ) { if ($isJSON) { $body = $message; } else { $body = json_encode(array( 'result' => $message, 'logoutSignal' => $logoutSignal, 'details' => $details, )); } $this->_haltWith($statusCode, $body); } /** * Returns response to SPA with file * * @param $filepath */ public function serveFile($fileName, $fileSize, $requestData) { header("Content-Type: application/x-download"); header("Content-Length: $fileSize"); $requestData['method'] = 'log_data'; $fullCommandStr = sprintf( "%s --data=%s 2>&1", $this->CLOUDLINUX_CLI, base64_encode(json_encode($requestData)) ); $descriptorspec = array( 0 => array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("pipe", "w") // stderr is a pipe that the child will write to ); $pipes = array(); $process = proc_open($fullCommandStr, $descriptorspec, $pipes); if (is_resource($process)) { while ($s = fgets($pipes[1])) { print $s; flush(); } } exit(); } /** * Checking of vulnerabilities: CSRF and HTTP_REFERER */ private function _checkVulnerabilities() { $this->_checkCSRFToken(); $this->_checkReferer(); } /* * Check CSRF token. */ private function _checkCSRFToken() { if (!isset($_COOKIE['csrftoken']) || $_COOKIE['csrftoken'] !== $_SERVER['HTTP_X_CSRFTOKEN'] ) { $this->sendErrorResponse('BAD FORGERY PROTECTION TOKEN', false, true); } } /** * Check HTTP_REFERER. */ private function _checkReferer() { if (!preg_match( sprintf( '/^%s:\/\/%s/', (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? 'https' : 'http', preg_quote($_SERVER['HTTP_HOST'], '/') ), $_SERVER['HTTP_REFERER']) ) { $this->sendErrorResponse('BAD REFERER', false, true); } } public function setCSRFToken() { if (!isset($_COOKIE['csrftoken'])) { setcookie("csrftoken", md5(uniqid(rand(), true))); } } public function getAppMode() { $modeFile = '/usr/share/l.v.e-manager/spa/app_mode.status'; if (file_exists($modeFile)) { return trim(file_get_contents($modeFile)); } return self::APP_MODE; } /** * Instert static files */ public function insertPanel() { $pluginVersion = $this->getPluginVersion(); $requestHandler = $this->getRequestHandler(); if ($this->pluginName == 'wpos') { return <<