FNAME = '/tmp/lshttpd/.admin'; $this->FSTATUS = '/tmp/lshttpd/.status'; $this->FPID = '/tmp/lshttpd/lshttpd.pid'; } public function init() { clearstatcache(); $this->serverLastModTime = filemtime($this->FSTATUS); $this->readStatus(); } public function refreshConf($data) { $listeners = $data['listener']; foreach ($listeners as $lname => $addr) { if (!isset($this->listeners[$lname])) { $this->listeners[$lname] = []; $this->listeners[$lname]['addr'] = $addr; $this->listeners[$lname]['status'] = 'Error'; } } $vhnames = $data['vhost']; // first char 0|1 (active|inactive), 2nd char A:in conf only, M: in both, S: in status only foreach ($vhnames as $vhname) { if (!isset($this->vhosts[$vhname])) { $this->vhosts[$vhname] = '0A'; } else { $this->vhosts[$vhname] = substr($this->vhosts[$vhname], 0, 1) . 'M'; } } $this->serv['name'] = $data['serv']; if (array_key_exists('awstats', $data)) { $this->awstats = $data['awstats']; } else { $this->awstats = null; } $fd = fopen($this->FPID, 'r'); if ($fd) { $this->serv['pid'] = trim(fgets($fd)); fclose($fd); } $this->serverLog = $data['servLog']; } public function process($act, $actId) { $this->act = $act; $this->actId = $actId; if ($act == 'RESET_ALL_PHP_PROCESSES') { $this->resetphp(); return true; } if ($this->isPending()) { return false; } $this->checkLastMod(); if (( $act == 'upgrade' ) || ( $act == 'switchTo' ) || ( $act == 'validatelicense' ) || ( $act == 'remove' )) { $this->vermgr(); } elseif ($actId) { $this->vhostControl(); } elseif ($act == 'restart') { $this->restartServer(); } elseif ($act == 'toggledbg') { $this->cmd = ['toggledbg']; $this->issueCmd(); sleep(2); $this->readStatus(); } return true; } private function resetphp() { $touchfile = $_SERVER['LS_SERVER_ROOT'] . "admin/tmp/.lsphp_restart.txt"; //fixed location if (touch($touchfile)) { $this->messages[] = ['success', 'Successfully notified LiteSpeed server to restart all detached PHP processes.']; } else { $this->messages[] = ['error', 'Failed to notify LiteSpeed server to restart all detached PHP processes.']; } } public function waitForChange() { for ($count = 0; $count < 5; ++$count) { if ($this->checkLastMod()) { return true; } sleep(1); } return false; } private function readStatus() { $this->listeners = []; $this->adminL = []; $this->vhosts = []; $this->license = []; $fd = fopen($this->FSTATUS, 'r'); if (!$fd) { return false; } while (!feof($fd)) { $buffer = fgets($fd, 512); if (strncmp($buffer, 'LISTENER0', 9) == 0) { $this->readListener($this->listeners, $buffer, $fd); } elseif (strncmp($buffer, 'LISTENER1', 9) == 0) { $this->readListener($this->adminL, $buffer, $fd); } elseif (strncmp($buffer, 'VHOST', 5) == 0) { $this->readVh($buffer, $fd); } elseif (strncmp($buffer, 'DEBUG_LOG: ', 11) == 0) { $this->debugOn = (substr($buffer, 11, 1) === '1') ? true : false; } elseif (strncmp($buffer, 'LICENSE', 7) == 0 || strncmp($buffer, 'FEATURES', 8) == 0) { $this->readLicenseInfo($buffer, $d); } elseif (strncmp($buffer, 'EOF', 3) == 0) { break; } } fclose($fd); return true; } private function readListener(&$l, $buffer, &$fd) { $m = []; if (preg_match("/\[(.+)\] (.+)$/", $buffer, $m)) { $lname = $m[1]; $l[$lname]['addr'] = $m[2]; $l[$lname]['status'] = 'Running'; $tmp = fgets($fd, 512); while (strncmp($tmp, 'ENDL', 4) != 0) { if (strncmp($tmp, 'LVMAP', 5) == 0) { $tm = []; if (preg_match("/\[(.+)\] (.+)$/", $tmp, $tm)) { $l[$lname]['map'][$tm[1]][] = $tm[2]; } } $tmp = fgets($fd, 512); } } } private function readVh($buffer, &$fd) { $m = []; if (preg_match("/\[(.+)\] ([01])/", $buffer, $m)) { $vname = $m[1]; if ($vname != '_AdminVHost') { $this->vhosts[$m[1]] = $m[2] . 'S'; } } } private function readLicenseInfo($buffer, &$fd) { // LICENSE_EXPIRES: 0, UPDATE_EXPIRES: 1597636800, SERIAL: , TYPE: 9:2 $m = []; if (preg_match("/^LICENSE_EXPIRES: (\d+), UPDATE_EXPIRES: (\d+), SERIAL: (.+), TYPE: (.+)$/", $buffer, $m)) { $this->license['expires'] = $m[1]; $this->license['updateExpires'] = $m[2]; $this->license['serial'] = $m[3]; $proc = trim($m[4]); if ($this->license['expires'] == 0) { $this->license['expires_date'] = 'Never'; } else { $this->license['expires_date'] = date('M d, Y', $this->license['expires']); } $this->license['updateExpires_date'] = date('M d, Y', $this->license['updateExpires']); // translate proc to type $this->license['proc'] = $proc; $this->license['type'] = $this->translateLicProc($proc); } else if (preg_match("/FEATURES: (\d+)$/", $buffer, $m)) { $feature = $m[1]; $this->license['feature'] = $feature; if (($feature & 1) == 0 && $this->license['proc'] == 1) { // no cache, old 1-CPU license $this->license['type'] = '1-CPU License (1-Worker)'; } } } private function translateLicProc($proc) { if (strncmp($proc, '9:', 2) == 0) { return 'Web Host Elite (X-Worker = ' . substr($proc, 2) . ')'; } switch ($proc) { // old type, to be retired case 'V': return 'VPS License (1-Worker with 2GB Memory Limit)'; case 'U': case 'VU': case 'U1': return 'UltraVPS License (1-Worker with 8GB Memory Limit)'; case '8': return '8-CPU License (8-Worker)'; // current ones case 'F': return 'Free Starter (1-Domain & 1-Worker with 2GB Memory Limit)'; case 'S': // SiteOwner return 'Site Owner Plus (5-Domain & 1-Worker)'; case 'SM': // SiteOwner with memeory limit return 'Site Owner (5-Domain 1-Worker with 8GB Memory Limit)'; case 'D': // domain limit return 'Domain Limited (limited-Domain 1-Worker)'; case 'DM': // domain and memory limit return 'Domain Limited (limited-Domain 1-Worker with 8GB Memory Limit)'; case '1M': // 1cpu with memory limit return 'Web Host Lite (1-Worker with 8GB Memory Limit)'; case '1': return 'Web Host Essential (1-Worker)'; case '2': return 'Web Host Professional (2-Worker)'; case '3': return 'Dedicated (3-Worker)'; case '4': return 'Web Host Enterprise (4-Worker)'; case 'X': case '9': // failsafe, should not happen return 'Web Host Elite (X-Worker)'; default : return '1-Worker'; // do not error out to be safe } } public function checkLastMod() { clearstatcache(); $mt = filemtime($this->FSTATUS); if ($this->serverLastModTime != $mt) { $this->serverLastModTime = $mt; return true; } return false; } public function restartServer() { $this->cmd = ['restart']; CLIENT::singleton()->setChanged(false); $this->issueCmd(); } public function vermgr() { if ($this->act == 'switchTo') { $this->cmd = array("mgrver:$this->actId"); } elseif ($this->act == 'remove') { $this->cmd = array("mgrver:-d $this->actId"); } elseif ($this->act == 'upgrade') { $product = PRODUCT::GetInstance(); $edition = 'std'; if ($product->edition == 'ENTERPRISE') { $edition = 'ent'; } $this->cmd = array("{$this->act}:{$this->actId}-$edition"); } elseif ($this->act == 'validatelicense') { $this->cmd = ['ValidateLicense']; } else { unset($this->cmd); return; //illegal action } $this->issueCmd(); $this->waitForChange(); $this->readStatus(); } public function vhostControl() { $this->cmd = array("$this->act:vhost:$this->actId"); $this->issueCmd(); $this->waitForChange(); $this->readStatus(); } public function install($app) { $this->cmd = array('install:' . $app); $this->issueCmd(); } public static function getCommandSocket($cmd) { if (strncmp($_SERVER['LSWS_ADMIN_SOCK'], 'uds://', 6) == 0) { $sock = socket_create(AF_UNIX, SOCK_STREAM, 0); $chrootOffset = 0; if (isset($_SERVER['LS_CHROOT'])) { $chrootOffset = strlen($_SERVER['LS_CHROOT']); } $addr = substr($_SERVER['LSWS_ADMIN_SOCK'], 5 + $chrootOffset); if (socket_connect($sock, $addr) == false) { error_log("failed to connect to server addr ($addr)! socket_connect() failed: " . socket_strerror(socket_last_error()) . "\n"); return false; } } else { $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); $addr = explode(':', $_SERVER['LSWS_ADMIN_SOCK']); if (socket_connect($sock, $addr[0], intval($addr[1])) == false) { error_log('failed to connect to server (' . $_SERVER['LSWS_ADMIN_SOCK'] . ')! socket_connect() failed: ' . socket_strerror(socket_last_error()) . "\n"); return false; } } $clientid = CLIENT::singleton()->getIdData(); $uid = PMA_blowfish_decrypt($clientid['id'], $clientid['sec0']); $password = PMA_blowfish_decrypt($clientid['pass'], $clientid['sec1']); $outBuf = "auth:" . $uid . ':' . $password . "\n"; $outBuf .= $cmd . "\n" . 'end of actions'; socket_write($sock, $outBuf); socket_shutdown($sock, 1); return $sock; } private function issueCmd() { CLIENT::singleton()->reauthenticate(); $commandline = ''; foreach ($this->cmd as $line) { $commandline .= $line . "\n"; } $sock = Service::getCommandSocket($commandline); if ($sock != false) { $res = socket_recv($sock, $buffer, 1024, 0); socket_close($sock); return (( $res > 0 ) && (strncasecmp($buffer, 'OK', 2) == 0 )); } return false; } public static function retrieveCommandData($cmd) { $sock = Service::getCommandSocket($cmd); $buffer = ''; if ($sock != false) { $read = [$sock]; $write = null; $except = null; $num_changed_sockets = socket_select($read, $write, $except, 3); //wait for max 3 seconds if ($num_changed_sockets === false) { error_log("socket_select failed: " . socket_strerror(socket_last_error())); } elseif ($num_changed_sockets > 0) { while (socket_recv($sock, $data, 8192, 0)) { $buffer .= $data; } } socket_close($sock); } return $buffer; } public function isPending() { if (file_exists($this->FNAME)) { $this->cmdStatus = 'IS_PENDING'; return true; } return false; } public function getLogData() { $data = []; $data['filename'] = $this->getServerLog(); $level = DUtil::getGoodVal(DUtil::grab_input('request', 'sel_level')); if ($level == null) { $level = 'I'; } if (!in_array($level, ['E', 'W', 'N', 'I', 'D'])) { return null; } $data['level'] = $level; $fd = fopen($data['filename'], 'r'); if (!$fd) { return null; } fseek($fd, 0, SEEK_END); $endpos = ftell($fd); fclose($fd); $data['logSize'] = number_format($endpos / 1024, 2); $searchSize = (int) DUtil::getGoodVal(DUtil::grab_input('request', 'searchSize')); if ($searchSize <= 0) { $searchSize = 20; } elseif ($searchSize > 512) { $searchSize = 512; } $data['searchSize'] = $searchSize; $searchFrom = (int) DUtil::getGoodVal(DUtil::grab_input('request', 'searchFrom')); if (isset($_REQUEST['end'])) { $searchFrom = $endpos; } else { if (isset($_REQUEST['prev'])) { $searchFrom -= $searchSize; } elseif (isset($_REQUEST['next'])) { $searchFrom += $searchSize; } elseif (isset($_REQUEST['begin'])) { $searchFrom = 0; } if ($searchFrom < 0) { $searchFrom = 0; } $data['searchFrom'] = $searchFrom; $searchFrom *= 1024; } $searchSize *= 1024; if ($searchFrom >= $endpos) { $searchFrom = $endpos - $searchSize; if ($searchFrom < 0) { $searchFrom = 0; } $data['searchFrom'] = number_format($searchFrom / 1024, 2, '.', ''); } if ($searchFrom + $searchSize < $endpos) { $endpos = $searchFrom + $searchSize; } $data['fromPos'] = (int) $searchFrom; $data['endPos'] = (int) $endpos; return $data; } public function showErrLog(&$buf, $len = 20480) { $buf = []; $data = []; $data['filename'] = $this->getServerLog(); $data['level'] = 'W'; $fd = fopen($data['filename'], 'r'); if (!$fd) { $buf[] = 'Failed read server log file from ' . $data['filename']; return 0; } fseek($fd, 0, SEEK_END); $data['endPos'] = ftell($fd); if ($data['endPos'] > $len) { $data['fromPos'] = $data['endPos'] - $len; } else { $data['fromPos'] = 0; } fclose($fd); $res = $this->getLog($data); if ($res[0] == 0) { return 0; } if ($res[0] > 10) { $r = explode("\n", $res[2]); $i = count($r) - 11; for ($j = 0; $j < 10; ++$j) { $buf[] = $r[$i + $j]; } $res[0] = 'last 10'; } else { $buf[] = $res[2]; } return $res[0]; } public function getLog($data) { $newlineTag = '[ERR[WAR[NOT[INF[DEB'; $levels = array('E' => 1, 'W' => 2, 'N' => 3, 'I' => 4, 'D' => 5); $level = $levels[substr($data['level'], 0, 1)]; $fd = fopen($data['filename'], 'r'); if (!$fd) { echo '