* * This file is part of Easy-WI. * * Easy-WI is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Easy-WI is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Easy-WI. If not, see . * * Diese Datei ist Teil von Easy-WI. * * Easy-WI ist Freie Software: Sie koennen es unter den Bedingungen * der GNU General Public License, wie von der Free Software Foundation, * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder spaeteren * veroeffentlichten Version, weiterverbreiten und/oder modifizieren. * * Easy-WI wird in der Hoffnung, dass es nuetzlich sein wird, aber * OHNE JEDE GEWAEHELEISTUNG, bereitgestellt; sogar ohne die implizite * Gewaehrleistung der MARKTFAEHIGKEIT oder EIGNUNG FUER EINEN BESTIMMTEN ZWECK. * Siehe die GNU General Public License fuer weitere Details. * * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem * Programm erhalten haben. Wenn nicht, siehe . */ // Include PHPSeclib if not already included if (!class_exists('SSH2')) { include(EASYWIDIR . '/third_party/phpseclib/autoloader.php'); } // Include EasyWi FTP if not already included if (!class_exists('EasyWiFTP')) { include(EASYWIDIR . '/stuff/methods/class_ftp.php'); } if (!class_exists('Yaml')) { include(EASYWIDIR . '/third_party/Symfony/autoloader_yaml.php'); } use Symfony\Component\Yaml\Yaml; class AppServer { private $uniqueHex, $winCmds = array(), $shellScriptHeader, $shellScripts = array('user' => '', 'server' => array()), $commandReturns = array(), $undefinedRequiredVars = array(); public $appMasterServerDetails = array(), $appServerDetails = false; // The constructor gathers the root data function __construct($id) { global $sql, $aeskey; $this->uniqueHex = dechex(mt_rand()); $query = $sql->prepare("SELECT *,AES_DECRYPT(`port`,:aeskey) AS `decryptedport`,AES_DECRYPT(`user`,:aeskey) AS `decrypteduser`,AES_DECRYPT(`pass`,:aeskey) AS `decryptedpass`,AES_DECRYPT(`steamAccount`,:aeskey) AS `decryptedsteamAccount`,AES_DECRYPT(`steamPassword`,:aeskey) AS `decryptedsteamPassword` FROM `rserverdata` WHERE `id`=:serverID LIMIT 1"); $query->execute(array(':serverID' => $id, ':aeskey' => $aeskey)); while ($row = $query->fetch(PDO::FETCH_ASSOC)) { $this->appMasterServerDetails['id'] = (int) $id; $this->appMasterServerDetails['notified'] = (int) $row['notified']; $this->appMasterServerDetails['ssh2IP'] = (string) $row['ip']; $this->appMasterServerDetails['ssh2Port'] = (int) $row['decryptedport']; $this->appMasterServerDetails['ssh2User'] = (string) $row['decrypteduser']; $this->appMasterServerDetails['ssh2Publickey'] = (string) $row['publickey']; $this->appMasterServerDetails['ssh2DecryptedPass'] = (string) $row['decryptedpass']; $this->appMasterServerDetails['ssh2KeyName'] = (string) $row['keyname']; $this->appMasterServerDetails['ftpPort'] = (string) $row['ftpport']; $this->appMasterServerDetails['os'] = (string) $row['os']; $this->appMasterServerDetails['iniVars'] = @parse_ini_string($row['install_paths'], true); # https://github.com/easy-wi/developer/issues/70 $this->appMasterServerDetails['privateKey'] = EASYWIDIR . '/keys/' . removePub($this->appMasterServerDetails['ssh2KeyName']); $this->appMasterServerDetails['quotaActive'] = $row['quota_active']; $this->appMasterServerDetails['quotaCmd'] = $row['quota_cmd']; $this->appMasterServerDetails['repquotaCmd'] = $row['repquota_cmd']; $this->appMasterServerDetails['blocksize'] = $row['blocksize']; $this->appMasterServerDetails['inodeBlockRatio'] = $row['inode_block_ratio']; $this->appMasterServerDetails['configBadFiles'] = preg_split('/,/', $row['config_bad_files'], -1, PREG_SPLIT_NO_EMPTY); $this->appMasterServerDetails['configBadTime'] = (int) $row['config_bad_time']; $this->appMasterServerDetails['configBinaries'] = preg_split('/,/', $row['config_binaries'], -1, PREG_SPLIT_NO_EMPTY); $this->appMasterServerDetails['configDemoTime'] = (int) $row['config_demo_time']; $this->appMasterServerDetails['configFiles'] = preg_split('/,/', $row['config_files'], -1, PREG_SPLIT_NO_EMPTY); $this->appMasterServerDetails['configIonice'] = (string) $row['config_ionice']; $this->appMasterServerDetails['configLogTime'] = (int) $row['config_log_time']; $this->appMasterServerDetails['configUserID'] = ($row['config_user_id'] > 0) ? (int) $row['config_user_id'] : 1000; $this->appMasterServerDetails['configZtmpTime'] = (int) $row['config_ztmp_time']; if ($this->appMasterServerDetails['os'] == 'L') { $this->shellScriptHeader = "#!/bin/bash\n"; $this->shellScriptHeader .= "if ionice -c3 true 2>/dev/null; then IONICE='ionice -n 7 '; fi\n"; $this->shellScripts['user'] = $this->shellScriptHeader . 'rm -f /home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/userCud-' . $this->uniqueHex . '.sh' . "\n"; } } return ($query->rowCount() > 0) ? true : false; } // Function that gathers the details of the currently active app public function getAppServerDetails($id) { // Those three variables are always defined, when this class is used global $sql, $aeskey, $resellerLockupID; $query = $sql->prepare("SELECT g.*,AES_DECRYPT(g.`ppassword`,:aeskey) AS `decryptedppass`,AES_DECRYPT(g.`ftppassword`,:aeskey) AS `decryptedftppass`,u.`cname` FROM `gsswitch` AS g INNER JOIN `userdata` AS u ON u.`id`=g.`userid` WHERE g.`id`=:id AND g.`resellerid`=:resellerID LIMIT 1"); $query->execute(array(':id' => $id, ':aeskey' => $aeskey, ':resellerID' => $resellerLockupID)); while ($row = $query->fetch(PDO::FETCH_ASSOC)) { // If app details can not be found return false if (!$this->getAppDetails($row['serverid'], $id)) { $query2 = $sql->prepare("SELECT `id` FROM `serverlist` WHERE `switchID`=? LIMIT 1"); $query2->execute(array($id)); $row['serverid'] = $query2->fetchColumn(); if ($row['serverid'] > 0) { $query2 = $sql->prepare("UPDATE `gsswitch` SET `serverid`=? WHERE `id`=? LIMIT 1"); $query2->execute(array($row['serverid'], $id)); } if (!$this->getAppDetails($row['serverid'], $id)) { $this->appServerDetails = false; return false; } } $this->appServerDetails['app']['id'] = $row['serverid']; $this->appServerDetails['id'] = (int) $row['id']; $this->appServerDetails['userid'] = (int) $row['userid']; $this->appServerDetails['type'] = (string) $row['type']; $this->appServerDetails['lendServer'] = (string) $row['lendserver']; $this->appServerDetails['protectionModeAllowed'] = ($this->appServerDetails['template']['protectedApp'] == 'Y') ? (string) $row['pallowed'] : 'N'; $this->appServerDetails['protectionModeStarted'] = ($this->appServerDetails['protectionModeAllowed'] == 'Y') ? (string) $row['protected'] : 'N'; $this->appServerDetails['eacAllowed'] = (string) $row['eacallowed']; $this->appServerDetails['tvAllowed'] = (string) $row['tvenable']; $this->appServerDetails['serverIP'] = (string) $row['serverip']; $this->appServerDetails['port'] = (int) $row['port']; $this->appServerDetails['port2'] = (int) $row['port2']; $this->appServerDetails['port3'] = (int) $row['port3']; $this->appServerDetails['port4'] = (int) $row['port4']; $this->appServerDetails['port5'] = (int) $row['port5']; $this->appServerDetails['minram'] = ($row['minram'] > 0) ? (int) $row['minram'] : 512; $this->appServerDetails['maxram'] = ($row['maxram'] > 0) ? (int) $row['maxram'] : 1024; $this->appServerDetails['slots'] = (int) $row['slots']; $this->appServerDetails['userMasterFastDownload'] = (string) $row['masterfdl']; $this->appServerDetails['specificFastDownLoadData'] = (string) $row['mfdldata']; $this->appServerDetails['useTaskSet'] = (string) $row['taskset']; $this->appServerDetails['cores'] = (string) $row['cores']; $this->appServerDetails['maxCores'] = count(preg_split("/\,/", $this->appServerDetails['cores'], -1, PREG_SPLIT_NO_EMPTY)); $this->appServerDetails['maxCores'] = ($this->appServerDetails['maxCores'] == 0) ? 1 : $this->appServerDetails['maxCores']; $this->appServerDetails['userName'] = ($row['newlayout'] == 'Y') ? (string) $row['cname'] . '-' . $id : (string) $row['cname']; $this->appServerDetails['userNameExecute'] = ($this->appServerDetails['protectionModeStarted'] == 'Y') ? (string) $this->appServerDetails['userName'] . '-p' : (string) $this->appServerDetails['userName']; $this->appServerDetails['hdd'] = (int) $row['hdd']; $this->appServerDetails['homeLabel'] = (string) $row['homeLabel']; // Password value is only used for setting. In case a server is inactive we need to generate a random one, so the customer can no longer log in. $this->appServerDetails['ftpPassword'] = ($row['active'] == 'Y') ? (string) $row['decryptedftppass'] : passwordgenerate(10); $this->appServerDetails['ftpPasswordProtected'] = ($row['active'] == 'Y') ? (string) $row['decryptedppass'] : passwordgenerate(10); // This password will be used, when a FTP connection needs to be setup $this->appServerDetails['ftpPasswordExecute'] = ($this->appServerDetails['protectionModeStarted'] == 'Y') ? (string) $row['decryptedppass'] : (string) $row['decryptedftppass']; // As the data loading is sequential, required parameters for the ternary operator will not be available within getAppDetails() function $this->appServerDetails['app']['templateChoosen'] = ($this->appServerDetails['app']['servertemplate'] == 1 or $this->appServerDetails['protectionModeStarted'] == 'Y') ? $this->appServerDetails['template']['shorten'] : $this->appServerDetails['template']['shorten'] . '-' . $this->appServerDetails['app']['servertemplate']; $this->appServerDetails['app']['uploadDir'] = ($this->appServerDetails['tvAllowed'] == 'Y') ? $this->appServerDetails['app']['uploadDir'] : false; $this->appServerDetails['homeDir'] = ($this->appMasterServerDetails['iniVars'] and isset($this->appMasterServerDetails['iniVars'][$row['homeLabel']]['path'])) ? (string) $this->appMasterServerDetails['iniVars'][$row['homeLabel']]['path'] : '/home'; $serverTemplateDir = $this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName']; $serverTemplateDir .= ($this->appServerDetails['protectionModeStarted'] == 'Y') ? '/pserver/' : '/server/'; $this->appServerDetails['absolutePath'] = $this->removeSlashes($serverTemplateDir . '/' . $this->appServerDetails['app']['templateChoosen'] . '/'); $this->appServerDetails['absoluteTemplatePath'] = $this->removeSlashes($serverTemplateDir); // For protected users the pserver/ directory is the home folder // We deliberately let admins that failed to setup a chrooted FTP environment run into errors $absoluteFTPPath = ($this->appServerDetails['protectionModeStarted'] == 'Y') ? '/' : '/server/'; $absoluteFTPPath .= $this->appServerDetails['app']['templateChoosen']; if ($this->getGameType() == 'hl2') { $absoluteFTPPath .= '/' . $this->appServerDetails['template']['binarydir']; } $absoluteFTPPath .= '/' . $this->appServerDetails['template']['modfolder'] . '/'; $this->appServerDetails['absoluteFTPPath'] = $this->removeSlashes($absoluteFTPPath); $this->appServerDetails['absoluteFTPPathNoChroot'] = $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName'] . $this->appServerDetails['absoluteFTPPath']); } return ($query->rowCount() > 0) ? true : false; } // Function that gathers the details of the currently active app private function getAppDetails($id, $appServerID) { global $sql, $aeskey; $query = $sql->prepare("SELECT t.`id` AS `template_id`,t.`steamgame`,t.`gameq`,t.`shorten`,t.`protected`,t.`protectedSaveCFGs`,t.`gamebinary`,t.`gamebinaryWin`,t.`binarydir`,t.`modfolder`,t.`copyStartBinary`,t.`cmd` AS `template_cmd`,t.`modcmds` AS `template_modcmds`,t.`steamGameserverToken`,`configedit`,s.*,AES_DECRYPT(s.`uploaddir`,:aeskey) AS `d_uploaddir`,AES_DECRYPT(s.`webapiAuthkey`,:aeskey) AS `d_webapiauthkey`,AES_DECRYPT(s.`steamServerToken`,:aeskey) AS `d_steamServerToken` FROM `serverlist` AS s INNER JOIN `servertypes` AS t ON t.`id`=s.`servertype` WHERE s.`id`=:id AND s.`switchID`=:appServerID LIMIT 1"); $query->execute(array(':aeskey' => $aeskey, ':id' => $id, ':appServerID' => $appServerID)); while ($row = $query->fetch(PDO::FETCH_ASSOC)) { // First block will be global app template settings $this->appServerDetails['template']['id'] = (string) $row['template_id']; $this->appServerDetails['template']['gameq'] = (string) $row['gameq']; $this->appServerDetails['template']['shorten'] = (string) $row['shorten']; $this->appServerDetails['template']['protectedApp'] = (string) $row['protected']; $this->appServerDetails['template']['protectedSaveCFGs'] = $row['protectedSaveCFGs']; $this->appServerDetails['template']['gameBinary'] = ($this->appMasterServerDetails['os'] == 'L') ? (string) $row['gamebinary'] : (string) $row['gamebinaryWin']; $this->appServerDetails['template']['binarydir'] = (string) $row['binarydir']; $this->appServerDetails['template']['modfolder'] = (string) $row['modfolder']; $this->appServerDetails['template']['modcmds'] = (string) $row['template_modcmds']; $this->appServerDetails['template']['steamgame'] = (string) $row['steamgame']; $this->appServerDetails['template']['steamGameserverToken'] = (string) $row['steamGameserverToken']; $this->appServerDetails['template']['configedit'] = $row['configedit']; $this->appServerDetails['template']['copyStartBinary'] = $row['copyStartBinary']; // second block will be specific app settings $this->appServerDetails['app']['anticheat'] = (int) $row['anticheat']; $this->appServerDetails['app']['fps'] = (int) $row['fps']; $this->appServerDetails['app']['tic'] = (int) $row['tic']; $this->appServerDetails['app']['servertemplate'] = (int) $row['servertemplate']; $this->appServerDetails['app']['map'] = (string) $row['map']; $this->appServerDetails['app']['workShop'] = (string) $row['workShop']; $this->appServerDetails['app']['mapGroup'] = (string) $row['mapGroup']; $this->appServerDetails['app']['steamServerToken'] = (string) $row['d_steamServerToken']; $this->appServerDetails['app']['workshopCollection'] = (int) $row['workshopCollection']; $this->appServerDetails['app']['webApiAuthKey'] = (string) $row['d_webapiauthkey']; $this->appServerDetails['app']['upload'] = (int) $row['upload']; $this->appServerDetails['app']['uploadDir'] = (strlen($row['d_uploaddir']) > 0) ? (string) $row['d_uploaddir'] : false; $this->appServerDetails['app']['modcmd'] = (string) $row['modcmd']; $this->appServerDetails['app']['gamemod'] = (string) $row['gamemod']; $this->appServerDetails['app']['gamemod2'] = (string) $row['gamemod2']; // Third will be app settings which might get overwritten by global settings $this->appServerDetails['app']['cmd'] = ($row['owncmd'] == 'Y') ? (string) $row['cmd'] : (string) $row['template_cmd']; } return ($query->rowCount() > 0) ? true : false; } private function getReplacements() { if ($this->appServerDetails['lendServer'] == 'Y') { $lendDetails = $this->getLendDetails(); } if (!isset($lendDetails) or !is_array($lendDetails)) { $lendDetails = array('rcon' => '', 'password' => '', 'slots' => $this->appServerDetails['slots']); } $placeholder = array('%binary%', '%tickrate%', '%tic%', '%ip%', '%port%', '%tvport%', '%port2%', '%port3%', '%port4%', '%port5%', '%slots%', '%map%', '%mapgroup%', '%fps%', '%minram%', '%maxram%', '%maxcores%', '%folder%', '%user%', '%absolutepath%'); $replacePlaceholderWith = array( $this->appServerDetails['template']['gameBinary'], $this->appServerDetails['app']['tic'], $this->appServerDetails['app']['tic'], $this->appServerDetails['serverIP'], $this->appServerDetails['port'], $this->appServerDetails['port2'], $this->appServerDetails['port2'], $this->appServerDetails['port3'], $this->appServerDetails['port4'], $this->appServerDetails['port5'], ($this->appServerDetails['lendServer'] == 'Y') ? $lendDetails['slots'] : $this->appServerDetails['slots'], $this->appServerDetails['app']['map'], $this->appServerDetails['app']['mapGroup'], $this->appServerDetails['app']['fps'], $this->appServerDetails['minram'], $this->appServerDetails['maxram'], $this->appServerDetails['maxCores'], $this->appServerDetails['app']['templateChoosen'], $this->appServerDetails['userName'], $this->appServerDetails['absolutePath'] ); return array('placeholder' => $placeholder, 'replacePlaceholderWith' => $replacePlaceholderWith); } // function that gathers the details for all installed addons public function getAddonDetails () { global $sql; $this->appServerDetails['extensions']['addons'] = array(); $this->appServerDetails['extensions']['addonSettings'] = array(); $this->appServerDetails['extensions']['maps'] = array(); $this->appServerDetails['extensions']['cmds'] = array(); $this->appServerDetails['extensions']['rmcmd'] = array(); $query = $sql->prepare("SELECT a.`id`,a.`cmd`,a.`rmcmd`,a.`addon`,a.`type`,a.`paddon`,a.`depending`,a.`folder` FROM `addons_installed` AS i INNER JOIN `addons` AS a ON a.`id`=i.`addonid` WHERE i.`serverid`=? AND i.`paddon`=? AND i.`servertemplate`=?"); $query->execute(array($this->appServerDetails['app']['id'], $this->appServerDetails['protectionModeStarted'], $this->appServerDetails['app']['servertemplate'])); while ($row = $query->fetch(PDO::FETCH_ASSOC)) { if ($row['type'] == 'tool') { $this->appServerDetails['extensions']['addons'][$row['id']] = $row['addon']; } else { $this->appServerDetails['extensions']['maps'][$row['id']] = $row['addon']; } $this->appServerDetails['extensions']['addonSettings'][$row['id']] = array('protectedAllowed' => $row['paddon'], 'folder' => $row['folder']); // Maps are allowed with protection mode in any case. Addons can be limited. We need to filter addons which should not be running when protection mode is active if ($row['type'] == 'map' or $this->appServerDetails['protectionModeStarted'] == 'N' or ($this->appServerDetails['protectionModeStarted'] == 'Y' and $row['paddon'] == 'Y')) { if (strlen($row['cmd']) > 0) { $this->appServerDetails['extensions']['cmds'][] = (substr($row['cmd'], 0, 12) == '[no_padding]') ? trim(substr($row['cmd'], 12)) : ' ' . $row['cmd']; } if (strlen($row['rmcmd']) > 0) { foreach (preg_split("/\r\n/", $row['rmcmd'], -1, PREG_SPLIT_NO_EMPTY) as $removeCommand) { if (strlen($removeCommand) > 0) { $this->appServerDetails['extensions']['removeCmds'][] = $removeCommand; } } } } } } // Function that checks if the game server is landed and if yes with which details private function getLendDetails () { global $sql, $aeskey; $cmd = ''; $query = $sql->prepare("SELECT `rcon`,`password`,`slots`,AES_DECRYPT(`ftpuploadpath`,?) AS `decyptedftpuploadpath` FROM `lendedserver` WHERE `serverid`=? LIMIT 1"); $query->execute(array($aeskey, $this->appServerDetails['app']['id'])); while ($row = $query->fetch(PDO::FETCH_ASSOC)) { $this->appServerDetails['slots'] = (int) $row['slots']; if (strlen($row['decyptedftpuploadpath']) > 0 and $row['decyptedftpuploadpath'] != 'ftp://username:password@1.1.1.1/demos') { $this->appServerDetails['app']['uploadDir'] = $row['decyptedftpuploadpath']; } $gameType = $this->getGameType(); if ($gameType == 'hl2') { $cmd .= ' +rcon_password ' .$row['rcon'] . ' +sv_password ' . $row['password']. ' +tv_enable 1 +tv_autorecord 1'; } else if ($gameType == 'hl1') { $cmd .= ' +rcon_password ' . $row['rcon'] . ' +sv_password ' . $row['password']; } else if ($gameType == 'cod') { $cmd .= ' +set rcon_password ' . $row['rcon'] . ' +set g_password ' . $row['password']; } else { $cmd = array('rcon' => $row['rcon'], 'password' => $row['password'], 'slots' => $row['slots']); } } return $cmd; } /* * Abstract helper functions */ private function addLogline ($logName, $logLine) { $this->shellScripts['user'] .= 'echo "`date`: ' . $logLine . '" >> "/home/' . $this->appMasterServerDetails['ssh2User'] . '/logs/' . $logName . '"' . "\n"; } private function removeSlashes ($string) { while (strpos($string, '//') !== false) { $string = str_replace('//', '/', $string); } return $string; } // Often we need to proceed depending on game engine type private function getGameType () { // First do a check against the binary if (in_array($this->appServerDetails['template']['gameBinary'], array('srcds_run', 'srcds.exe'))) { return 'hl2'; } if (in_array($this->appServerDetails['template']['gameBinary'], array('hlds_run', 'hlds.exe'))) { return 'hl1'; } if (in_array($this->appServerDetails['template']['gameBinary'], array('cod4_lnxded', 'codwaw_lnxded', 'iw3mp.exe', 'CoDWaWmp.exe'))) { return 'cod'; } // The admin might have configured a shell script instead of the native binary or script // We also need to check against the gameQ setting to be on the safe side if (in_array($this->appServerDetails['template']['gameq'], array('minecraft', 'minequery'))) { return 'mc'; } if (in_array($this->appServerDetails['template']['gameq'], array('aoc', 'csgo', 'css', 'dods', 'hl2dm', 'l4d', 'l4d2', 'ns2', 'tf2', 'zps'))) { return 'hl2'; } if (in_array($this->appServerDetails['template']['gameq'], array('cs16', 'cscz', 'dod', 'insurgency', 'ns', 'tfc'))) { return 'hl1'; } if (substr($this->appServerDetails['template']['gameq'], 0, 3) == 'cod') { return 'cod'; } return $this->appServerDetails['template']['gameq']; } /* * Following code contains the user management related funtions */ private function linuxAddModUserGenerate ($userName, $password, $protected = false, $deactivate = false) { $password = ($deactivate == false) ? $password : passwordgenerate(10); $userNameHome = ($protected == false) ? $this->appServerDetails['userName'] : $this->appServerDetails['userName'] . '/pserver'; // Check if the user can be found. If not, add it, if yes, edit $this->shellScripts['user'] .= 'if [ "`id ' . $userName . ' 2>/dev/null`" == "" ]; then' . "\n"; $this->shellScripts['user'] .= 'CONFIGUSERID=' . $this->appMasterServerDetails['configUserID'] . "\n"; $this->shellScripts['user'] .= 'USER=`ls -la /var/run/screen | grep S-' . $userName . ' | head -n 1 | awk \'{print $3}\'`' . "\n"; $this->shellScripts['user'] .= 'if [ "$USER" != "" -a $USER -eq $USER 2> /dev/null ]; then CONFIGUSERID=$USER; fi' . "\n"; $this->shellScripts['user'] .= 'USERID=`getent passwd | cut -f3 -d: | sort -un | awk \'BEGIN { id=\'${CONFIGUSERID}\' } $1 == id { id++ } $1 > id { print id; exit }\'`' . "\n"; $this->shellScripts['user'] .= 'if [ "`ls -la /var/run/screen | awk \'{print $3}\' | grep $USERID`" == "" -a "`grep \"x:$USERID:\" /etc/passwd`" == "" ]; then' . "\n"; $this->shellScripts['user'] .= 'sudo /usr/sbin/useradd -m -p `perl -e \'print crypt("\'' . $password . '\'","Sa")\'` -d ' . $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $userNameHome) . ' -g ' . $this->appMasterServerDetails['ssh2User'] . ' -s /bin/false -u $USERID ' . $userName . ' 2>/dev/null' . "\n"; $this->shellScripts['user'] .= 'else' . "\n"; $this->shellScripts['user'] .= 'while [ "`ls -la /var/run/screen | awk \'{print $3}\' | grep $USERID`" != "" -o "`grep \"x:$USERID:\" /etc/passwd`" != "" ]; do' . "\n"; $this->shellScripts['user'] .= 'USERID=$[USERID+1]' . "\n"; $this->shellScripts['user'] .= 'if [ "`ls -la /var/run/screen | awk \'{print $3}\' | grep $USERID`" == "" -a "`grep \"x:$USERID:\" /etc/passwd`" == "" ]; then' . "\n"; $this->shellScripts['user'] .= 'sudo /usr/sbin/useradd -m -p `perl -e \'print crypt("\'' . $password . '\'","Sa")\'` -m -d ' . $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $userNameHome) . ' -g ' . $this->appMasterServerDetails['ssh2User'] . ' -s /bin/false -u $USERID ' . $userName . ' 2>/dev/null' . "\n"; $this->shellScripts['user'] .= 'fi' . "\n"; $this->shellScripts['user'] .= 'done' . "\n"; $this->shellScripts['user'] .= 'fi' . "\n"; $this->addLogline('user.log', 'User ' . $userName . ' added'); $this->shellScripts['user'] .= 'else' . "\n"; $this->shellScripts['user'] .= 'sudo /usr/sbin/usermod -p `perl -e \'print crypt("\'' . $password . '\'","Sa")\'` -m -d ' . $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $userNameHome) . ' ' . $userName . "\n"; $this->addLogline('user.log', 'User ' . $userName . ' edited'); $this->shellScripts['user'] .= 'fi' . "\n"; } private function linuxAddModUser ($deactivate) { $this->linuxAddModUserGenerate ($this->appServerDetails['userName'], $this->appServerDetails['ftpPassword'], false, $deactivate); if ($this->appServerDetails['protectionModeAllowed']) { $this->linuxAddModUserGenerate ($this->appServerDetails['userName'] . '-p', $this->appServerDetails['ftpPasswordProtected'], true, $deactivate); } } private function windowsAddModUser () { } private function linuxDeleteUserGenerate ($userName) { $this->shellScripts['user'] .= 'if [ "`id ' . $userName . ' 2>/dev/null`" != "" ]; then' . "\n"; $this->shellScripts['user'] .= '${IONICE}nice -n +19 sudo /usr/sbin/userdel -fr ' . $userName . ' > /dev/null 2>&1 ' . "\n"; $this->addLogline('user.log', 'User ' . $userName . ' deleted'); $this->shellScripts['user'] .= 'fi' . "\n"; } private function linuxDelUser ($type) { $this->linuxDeleteUserGenerate($this->appServerDetails['userName'] . '-p'); if ($type == 'both') { $this->linuxDeleteUserGenerate($this->appServerDetails['userName']); } } private function windowsDeluser ($type) { } public function userCud ($action, $type = false, $deactivate = false) { if ($this->appServerDetails and isset($this->appMasterServerDetails['os'])) { if ($action == 'del') { if ($this->appMasterServerDetails['os'] == 'L') { $this->linuxDelUser($type); } else { $this->windowsDeluser($type); } } else { if ($this->appMasterServerDetails['os'] == 'L') { $this->linuxAddModUser($deactivate); } else { $this->windowsAddModUser($deactivate); } } return true; } return false; } // Quotas are a Linux technique to define the diskspace a user is allowed to use. public function setQuota () { if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'L' and $this->appMasterServerDetails['quotaActive'] == 'Y' and strlen($this->appMasterServerDetails['quotaCmd']) > 0 and $this->appServerDetails['hdd'] > 0) { // setquota works with KibiByte and Inodes; Stored is Megabyte $sizeInKibiByte = $this->appServerDetails['hdd'] * 1024; $sizeInByte = $this->appServerDetails['hdd'] * 1048576; $blockAmount = round(($sizeInByte /$this->appMasterServerDetails['blocksize'])); $inodeAmount = round($blockAmount / $this->appMasterServerDetails['inodeBlockRatio']); $mountPoint = (isset($this->appMasterServerDetails['iniVars'][$this->appServerDetails['homeLabel']]['mountpoint'])) ? $this->appMasterServerDetails['iniVars'][$this->appServerDetails['homeLabel']]['mountpoint'] : $this->appServerDetails['homeDir']; $this->shellScripts['user'] .= str_replace('%cmd%', ' -u ' . $this->appServerDetails['userName'] . ' ' . $sizeInKibiByte . ' ' . $sizeInKibiByte . ' ' . $inodeAmount . ' ' . $inodeAmount . ' ' . $mountPoint, $this->appMasterServerDetails['quotaCmd']) . "\n"; $this->addLogline('user.log', 'Userquota set for ' . $this->appServerDetails['userName']); } } /* * The next section contains private and public functions. * When the root is Linux, they will generate the self deleting temporary shell scripts in ram, write them to the root and execute. * When the root is Windows, they will generate the to be executed commands in ram and start them all at once at the end. */ // Generic function that add a userĀ“s script to the to be generated and executed list // The execution of scripts as a user will be sequential and blocking // That way we can ensure that a server is installed before it gets started private function addLinuxScript ($scriptName, $script, $userName = false, $doNotexecute = false) { $userName = ($userName == false) ? $this->appServerDetails['userNameExecute'] : $userName; if ($doNotexecute == false) { $this->shellScripts['user'] .= 'chmod 770 ' . $scriptName . "\n"; $this->shellScripts['user'] .= 'sudo -u ' . $userName . ' ' . $scriptName . "\n"; } $this->shellScripts['server']["{$scriptName}"] = $script; } private function copyStartFile($sourcePath, $targetPath) { $targetPath = $this->removeSlashes($targetPath . $this->appServerDetails['template']['binarydir']); $sourceFile = $this->removeSlashes($sourcePath . $this->appServerDetails['template']['binarydir'] . '/' . $this->appServerDetails['template']['gameBinary']); $targetFile = $this->removeSlashes($targetPath . '/' . $this->appServerDetails['template']['gameBinary']); $script = 'if [ -f "' . $sourceFile . '" ]; then' . "\n"; $script .= 'if [ ! -d "' . $targetPath . '" ]; then mkdir -p "' . $targetPath . '"; fi' . "\n"; $script .= 'if [ -f "' . $targetFile . '" ]; then' . "\n"; $script .= 'chmod 700 "' . $targetFile . '"' . "\n"; $script .= 'rm -f "' . $targetFile . '"' . "\n"; $script .= 'fi' . "\n"; $script .= 'cp -f "' . $sourceFile . '" "' . $targetFile . '"'. "\n"; $script .= 'chmod 700 "' . $targetFile . '"' . "\n"; $script .= 'fi' . "\n"; return $script; } // Function that generated the script for adding an app private function linuxAddApp ($templates, $standalone = true) { if ($standalone) { $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/add-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '-apps.sh'); } $serverDir = ($this->appServerDetails['protectionModeStarted'] == 'Y') ? 'pserver/' : 'server/'; $absolutePath = $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName'] . '/' . $serverDir); $copyFileExtensions = array('xml', 'vdf', 'cfg', 'con', 'conf', 'config', 'ini', 'gam', 'txt', 'log', 'smx', 'sp', 'db', 'lang', 'lua', 'props', 'properties', 'json', 'example', 'html', 'yml', 'yaml', 'csv'); if ($standalone and isset($scriptName)) { $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; } else { $script = ''; } $script .= "PATTERN='(/valve|/overviews/|/scripts/|/media/|/particles/|/sound/|/hl2/|/overviews/|/resource/|/sprites/|gameinfo.txt|steam.inf|steam_appid.txt)'" . "\n"; // Migrate old folder structure with ip_port as sub folder to structure without $script .= 'if [ -d ' . $absolutePath . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' ]; then' . "\n"; $script .= 'mv ' . $absolutePath . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '/* ' . $absolutePath . "\n"; $script .= '${IONICE}nice -n +19 rm -rf ' . $absolutePath . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . "\n"; $script .= 'fi' . "\n"; foreach ($templates as $template) { $absoluteTargetTemplatePath = $this->removeSlashes($absolutePath . $template . '/'); $sourceTemplate = (substr($template, -2) == '-2' or substr($template, -2) == '-3') ? substr($template, 0, (strlen($template) -2)) : $template; $absoluteSourceTemplatePath = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/masterserver/' . $sourceTemplate . '/'); $script .= 'if [ ! -d "' . $absoluteTargetTemplatePath . '" ]; then mkdir -p "' . $absoluteTargetTemplatePath . '"; fi' . "\n"; $script .= 'cd ' . $absoluteSourceTemplatePath . "\n"; if ($this->appServerDetails['template']['copyStartBinary'] == 'Y') { $script .= $this->copyStartFile($absoluteSourceTemplatePath, $absoluteTargetTemplatePath); } $script .= 'FILEFOUND=(`find -mindepth 1 -type f \( -iname "*.' . implode('" -or -iname "*.', $copyFileExtensions) . '" \) | grep -v -E "$PATTERN"`)' . "\n"; $script .= 'for FILTEREDFILES in ${FILEFOUND[@]}; do' . "\n"; $script .= 'FOLDERNAME=`dirname "$FILTEREDFILES"`' . "\n"; $script .= 'if ([[ `find "$FOLDERNAME" -maxdepth 0 -type d` ]] && [[ ! -d "' . $absoluteTargetTemplatePath . '$FOLDERNAME" ]]); then mkdir -p "' . $absoluteTargetTemplatePath . '$FOLDERNAME"; fi' . "\n"; $script .= 'if [ -f "' . $absoluteTargetTemplatePath . '$FILTEREDFILES" ]; then find "' . $absoluteTargetTemplatePath . '$FILTEREDFILES" -maxdepth 1 -type l -delete; fi' . "\n"; $script .= 'if [ ! -f "' . $absoluteTargetTemplatePath . '$FILTEREDFILES" ]; then ${IONICE}cp "' . $absoluteSourceTemplatePath . '$FILTEREDFILES" "' . $absoluteTargetTemplatePath . '$FILTEREDFILES"; fi' . "\n"; $script .= 'done' . "\n"; $script .= 'cp -sr ' . $absoluteSourceTemplatePath . '* ' . $absoluteTargetTemplatePath . ' > /dev/null 2>&1' . "\n"; $this->addLogline('app_server.log', 'Server template ' . $absoluteTargetTemplatePath . ' owned by user ' . $this->appServerDetails['userNameExecute'] . ' added/synced'); } $dirChmod = 700; $fileChmod = 600; if ($this->appServerDetails['protectionModeStarted'] == 'Y') { $dirChmod = 750; $fileChmod = 640; } $script .= '${IONICE}nice -n +19 find ' . $absolutePath . ' -type d -print0 | xargs -0 chmod ' . $dirChmod . "\n"; if ($this->appServerDetails['template']['copyStartBinary'] == 'Y' and strlen($this->appServerDetails['template']['gameBinary']) > 0) { $script .= '${IONICE}nice -n +19 find ' . $absolutePath . ' -type f ! -name "' . $this->appServerDetails['template']['gameBinary'] . '" -print0 | xargs -0 chmod ' . $fileChmod . "\n"; } else { $script .= '${IONICE}nice -n +19 find ' . $absolutePath . ' -type f -print0 | xargs -0 chmod ' . $fileChmod . "\n"; } $script .= '${IONICE}nice -n +19 find -L ' . $absolutePath . ' -type l -delete' . "\n"; if ($standalone and isset($scriptName)) { $this->addLinuxScript($scriptName, $script); } return $script; } private function getAllAllowedGames($names = false) { global $sql; $returnArray = array(); if ($this->appServerDetails) { if ($names) { $query = $sql->prepare("SELECT DISTINCT(t.`shorten`) AS `name` FROM `serverlist` AS s INNER JOIN `servertypes` AS t ON t.`id`=s.`servertype` WHERE s.`switchID`=?"); } else { $query = $sql->prepare("SELECT DISTINCT(t.`description `) AS `name` FROM `serverlist` AS s INNER JOIN `servertypes` AS t ON t.`id`=s.`servertype` WHERE s.`switchID`=?"); } $query->execute(array($this->appServerDetails['id'])); while ($row = $query->fetch(PDO::FETCH_ASSOC)) { $returnArray[] = $row['name']; } } return $returnArray; } public function addApp ($templates = array(), $sendMail = false) { if (count($templates) == 0) { $templates = array($this->appServerDetails['app']['templateChoosen']); } if ($sendMail === true) { $mailConnectInfo = array( 'ip' => $this->appServerDetails['serverIP'], 'port' => $this->appServerDetails['port'] ); for ($i = 2; $i < 6; $i++) { if ($this->appServerDetails["port{$i}"] > 0) { $mailConnectInfo["port{$i}"] = $this->appServerDetails["port{$i}"]; } } sendmail('emailserverinstall', $this->appServerDetails['userid'], $this->appServerDetails['serverIP'] . ':' . $this->appServerDetails['port'], implode(', ', $this->getAllAllowedGames(true)), $mailConnectInfo); } if ($this->appServerDetails) { if ($this->appMasterServerDetails['os'] == 'L') { $this->linuxAddApp($templates); } else if ($this->appMasterServerDetails['os'] == 'W') { } } } private function backUpSpareFiles($template, $spareFiles) { if (count($spareFiles) == 0) { return ''; } $script = 'cd ' . $template . "\n"; foreach ($spareFiles as $spareFile) { $script .= 'TARGET_FOLDER="`dirname ' . $spareFile . '`"' . "\n"; $script .= 'if [ ! -d "../sparefiles/${TARGET_FOLDER}" ]; then mkdir -p "../sparefiles/${TARGET_FOLDER}"' . "\n"; $script .= 'cp "' . $spareFile . '" "../sparefiles/' . $spareFile . '"' . "\n"; } $script .= 'cd ..' . "\n"; return $script; } private function restoreSpareFiles($template) { $script = 'if [ -d "sparefiles" ]; then' . "\n"; $script .= 'if [ !-d "' . $template . '" ]; then mkdir -p "' . $template . '"' . "\n"; $script .= 'mv "sparefiles/*" "' . $template . '/"' . "\n"; $script .= 'rm -rf "sparefiles"' . "\n"; $script .= 'fi' . "\n"; return $script; } private function linuxRemoveApp($templates, $spareFiles) { $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/del-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '-templates.sh'); $serverDir = ($this->appServerDetails['protectionModeStarted'] == 'Y') ? 'pserver/' : 'server/'; $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; $script .= 'cd ' . $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName'] . '/' . $serverDir) . "\n"; foreach ($templates as $template) { $script .= $this->backUpSpareFiles($template, $spareFiles); $script .= 'if [ -d "' . $template . '" ]; then ${IONICE}rm -rf "' . $template . '"; fi' . "\n"; $this->addLogline('app_server.log', 'Server template ' . $serverDir . $template . ' owned by user ' . $this->appServerDetails['userNameExecute'] . ' deleted'); $script .= $this->restoreSpareFiles($template); } $this->addLinuxScript($scriptName, $script); } public function removeApp($templates, $spareFiles = array()) { if ($this->appServerDetails) { $this->easyAntiCheatSettings('stop'); if (count($templates) > 0) { if ($this->appMasterServerDetails['os'] == 'L') { $this->linuxRemoveApp($templates, $spareFiles); } else if ($this->appMasterServerDetails['os'] == 'W') { } } } } private function linuxMcWorldSave($standalone = true) { $screenName = $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port']; $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/worldsave-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); if ($standalone === true) { $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; } else { $script = ''; } $script .= 'if [ "`screen -ls | grep ' . $screenName . ' | awk \'{print $1}\'`" != "" ]; then' . "\n"; $script .= 'screen -p 0 -S ' . $screenName . ' -X stuff $\'\n\'' . "\n"; $script .= 'screen -p 0 -S ' . $screenName . ' -X stuff "say SERVER WILL SAVE THE WORLD NOW"' . "\n"; $script .= 'screen -p 0 -S ' . $screenName . ' -X stuff $\'\n\'' . "\n"; $script .= 'screen -p 0 -S ' . $screenName . ' -X stuff $\'\n\'' . "\n"; $script .= 'screen -p 0 -S ' . $screenName . ' -X stuff "save-all"' . "\n"; $script .= 'screen -p 0 -S ' . $screenName . ' -X stuff $\'\n\'' . "\n"; $script .= 'sleep 10' . "\n"; $script .= 'fi' . "\n"; if ($standalone === true) { $this->addLinuxScript($scriptName, $script); $this->addLogline('app_server.log', 'Minecraft worldsave ' . $screenName . ' owned by user ' . $this->appServerDetails['userNameExecute']); } return $script; } public function mcWorldSave () { if ($this->appServerDetails and $this->getGameType() == 'mc') { if ($this->appMasterServerDetails['os'] == 'L') { } else if ($this->appMasterServerDetails['os'] == 'W') { } } } private function linuxStopApp ($standalone = true, $scriptName = '') { $screenName = $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port']; if ($standalone === true or $scriptName == '') { $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/stop-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; } else { $script = ''; } $script .= 'screen -wipe > /dev/null 2>&1' . "\n"; $script .= 'if [[ `screen -ls | grep ' . $screenName . '` ]]; then' . "\n"; if ($this->appServerDetails['template']['gameq'] == 'minecraft') { $script .= $this->linuxMcWorldSave(false); } $gameType = $this->getGameType(); if ($gameType == 'hl2' and $this->appServerDetails['tvAllowed'] == 'Y') { $script .= 'screen -p 0 -S ' . $screenName . ' -X stuff $\'\n\'' . "\n"; $script .= 'screen -p 0 -S ' . $screenName . ' -X stuff "tv_stoprecord"' . "\n"; $script .= 'screen -p 0 -S ' . $screenName . ' -X stuff $\'\n\'' . "\n"; } $script .= 'if [ "`screen -ls | grep ' . $screenName . ' | wc -l`" == "1" ]; then screen -r ' . $screenName . ' -X quit; fi' . "\n"; $script .= 'fi' . "\n"; $script .= 'ps x | grep ' . $screenName . ' | grep -v ' . $scriptName . ' | grep -v grep | awk \'{print $1}\' | while read PID; do' . "\n"; $script .= 'kill $PID > /dev/null 2>&1' . "\n"; $script .= 'kill -9 $PID > /dev/null 2>&1' . "\n"; $script .= 'done' . "\n"; $script .= 'ps x | grep -v ' . $scriptName . ' | grep Ssl | grep java | grep -v grep | awk \'{print $1}\' | while read PID; do' . "\n"; $script .= 'kill $PID > /dev/null 2>&1' . "\n"; $script .= 'kill -9 $PID > /dev/null 2>&1' . "\n"; $script .= 'done' . "\n"; $script .= 'ps x | grep -v ' . $scriptName . ' | grep Ssl+ | grep java | grep -v grep | awk \'{print $1}\' | while read PID; do' . "\n"; $script .= 'kill $PID > /dev/null 2>&1' . "\n"; $script .= 'kill -9 $PID > /dev/null 2>&1' . "\n"; $script .= 'done' . "\n"; if ($gameType == 'hl2' and $this->appServerDetails['tvAllowed'] == 'Y' and in_array($this->appServerDetails['app']['upload'], array(2, 3)) and $this->appServerDetails['app']['uploadDir']) { $script .= $this->linuxDemoUpload(false); } $script .= $this->arkCheckSleep(); if ($standalone === true) { $this->addLinuxScript($scriptName, $script); $this->addLogline('app_server.log', 'App ' . $screenName . ' owned by user ' . $this->appServerDetails['userNameExecute'] . ' stopped'); } return $script; } public function stopApp () { global $sql; if ($this->appServerDetails) { $this->easyAntiCheatSettings('stop'); if ($this->appMasterServerDetails['os'] == 'L') { $this->linuxStopApp(); } else if ($this->appMasterServerDetails['os'] == 'W') { } $query = $sql->prepare("UPDATE `gsswitch` SET `stopped`='Y' WHERE `id`=? LIMIT 1"); $query->execute(array($this->appServerDetails['id'])); } } private function linuxHardStop ($userName) { $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/hardstop-' . $userName . '.sh'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; $script .= 'crontab -r' . "\n"; $script .= 'screen -wipe > /dev/null 2>&1' . "\n"; $script .= 'pkill -u `whoami`' . "\n"; $this->addLinuxScript($scriptName, $script, $userName); $this->addLogline('app_server.log', 'Hard stop for user ' . $userName); } public function stopAppHard () { if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'L') { $this->linuxHardStop($this->appServerDetails['userName']); if ($this->appServerDetails['protectionModeAllowed'] == 'Y') { $this->linuxHardStop($this->appServerDetails['userNameExecute']); } } else if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'W') { } } private function replaceValue($customColumns, $replaceSettings, $value) { if (is_string($value) and strpos($value, '%') !== false) { $value = str_replace($replaceSettings['placeholder'], $replaceSettings['replacePlaceholderWith'], $value); } foreach ($customColumns as $customColumn) { $value = str_replace('%' . $customColumn['name'] . '%', $customColumn['value'], $value); } // Check if it is a numeric value but a string and convert if (is_numeric($value) and gettype($value) == "string") { $value = (int) $value; } return $value; } private function protectedYaml($replaceSettings, $parsedConfig) { $customColumns = customColumns('G', $this->appServerDetails['id']); foreach ($parsedConfig as $key => $value) { if (is_array($value) or is_object($value)) { $parsedConfig[$key] = $this->protectedYaml($replaceSettings, $value); } else { $parsedConfig[$key] = $this->replaceValue($customColumns, $replaceSettings, $value); } } return $parsedConfig; } private function protectedXML($replaceSettings, $parsedConfig) { $customColumns = customColumns('G', $this->appServerDetails['id']); foreach ($parsedConfig as $key => $value) { if (is_object($value)) { foreach ($value->attributes() as $k => $v) { $value->attributes()->$k = $this->replaceValue($customColumns, $replaceSettings, (string) $v); } } else if (is_array($value)) { $parsedConfig[$key] = $this->protectedXML($replaceSettings, $value); } else { $parsedConfig[$key] = $this->replaceValue($customColumns, $replaceSettings, $value); } } return $parsedConfig; } private function xmlStringToObject($xml) { try { if (strpos($xml, '' . $xml . ''; } return new SimpleXMLElement($xml); } catch (Exception $e) { return new stdClass; } } private function parseYML($string) { try { return Yaml::parse($string); } catch (Exception $e) { return new stdClass; } } private function protectedSettingsToArray() { $protectedString = ''; $cvarProtectArray = array(); $lendServerReplaceMents = array(); $debugger = array(); $replaceSettings = $this->getReplacements(); @parse_ini_string($this->appServerDetails['template']['configedit'], true, INI_SCANNER_RAW); foreach (explode("\n", $this->appServerDetails['template']['configedit']) as $line) { $line = str_replace(array("\r"), '', $line); if (preg_match('/^(\[[\w\/\.\-\_]{1,}\]|\[[\w\/\.\-\_]{1,}\] (xml|ini|cfg|lua|json|ddot|yml|Yaml|yaml))$/', $line)) { if (strlen($protectedString) > 0 and isset($configPathAndFile) and !isset($cvarProtectArray[$configPathAndFile]['cvars'])) { if (in_array($cvarProtectArray[$configPathAndFile]['type'], array('yml', 'yaml', 'Yaml'))) { $cvarProtectArray[$configPathAndFile]['cvars'] = $this->protectedYaml($replaceSettings, $this->parseYML($protectedString)); } else if ($cvarProtectArray[$configPathAndFile]['type'] == 'xml') { $cvarProtectArray[$configPathAndFile]['cvars'] = $this->protectedXML($replaceSettings, $this->xmlStringToObject($protectedString)); } } $exploded = preg_split("/\s+/", $line, -1, PREG_SPLIT_NO_EMPTY); $cvarType = (isset($exploded[1])) ? $exploded[1] : 'cfg'; $configPathAndFile = substr($exploded[0], 1, strlen($exploded[0]) - 2); $cvarProtectArray[$configPathAndFile]['type'] = $cvarType; $protectedString = ''; } else if (isset($configPathAndFile) and isset($cvarProtectArray[$configPathAndFile]['type'])) { unset($splitLine); if ($cvarProtectArray[$configPathAndFile]['type'] == 'cfg') { $splitLine = preg_split("/\s+/", $line, -1, PREG_SPLIT_NO_EMPTY); //TODO } else if (in_array($cvarProtectArray[$configPathAndFile]['type'], array('yml','yaml','Yaml'/*,'xml'*/))) { $protectedString .= $line . "\r\n"; } else if (in_array($cvarProtectArray[$configPathAndFile]['type'], array('ini','lua'))) { $splitLine = preg_split("/\=/", $line, -1, PREG_SPLIT_NO_EMPTY); } else if (in_array($cvarProtectArray[$configPathAndFile]['type'], array('json','ddot'))) { $splitLine = preg_split("/:/", $line, -1, PREG_SPLIT_NO_EMPTY); //TODO // In case of XML configs the splitting is more complicated } else if ($cvarProtectArray[$configPathAndFile]['type'] == 'xml') { $exploded = explode('>', $line); if (isset($exploded[1])) { $key = str_replace('<', '', $exploded[0]); @list($value) = explode('<', $exploded[1]); $splitLine = array($key, $value); } } else { $debugger[] = 'Type not known yet: '. $line; } if (isset($splitLine[1])) { $replacedLine = str_replace($replaceSettings['placeholder'], $replaceSettings['replacePlaceholderWith'], $splitLine[1]); foreach (customColumns('G', $this->appServerDetails['id']) as $customColumn) { $replacedLine = str_replace('%' . $customColumn['name'] . '%', $customColumn['value'], $replacedLine); } $cvarProtectArray[$configPathAndFile]['cvars'][$splitLine[0]] = $replacedLine; } else if (isset($splitLine[0])) { $debugger[] = 'no second part for ' . $splitLine[0]; } else { $debugger[] = '$splitLine not defined'; } } else { $debugger[] = 'The sorry rest: ' . $line; } } if (strlen($protectedString) > 0 and isset($configPathAndFile) and !isset($cvarProtectArray[$configPathAndFile]['cvars'])) { if (in_array($cvarProtectArray[$configPathAndFile]['type'], array('yml', 'yaml', 'Yaml'))) { $cvarProtectArray[$configPathAndFile]['cvars'] = $this->protectedYaml($replaceSettings, $this->parseYML($protectedString)); //TODO }/* else if ($cvarProtectArray[$configPathAndFile]['type'] == 'xml') { $cvarProtectArray[$configPathAndFile]['cvars'] = $this->protectedXML($replaceSettings, $this->xmlStringToObject($protectedString)); }*/ } if ($this->appServerDetails['lendServer'] == 'Y') { if ($this->appServerDetails['lendServer'] == 'Y') { $lendDetails = $this->getLendDetails(); } if (!isset($lendDetails) or !is_array($lendDetails)) { $lendDetails = array('rcon' => '', 'password' => '', 'slots' => $this->appServerDetails['slots']); } $gameType = $this->getGameType(); if ($gameType == 'mc') { $lendServerReplaceMents = array('enable-rcon' => 'true', 'rcon.password' => $lendDetails['rcon']); } else if ($gameType == 'hl2' or $gameType == 'hl1') { $lendServerReplaceMents = array('sv_password' => $lendDetails['password'], 'rcon' => $lendDetails['rcon']); } else if ($gameType == 'cod') { $lendServerReplaceMents = array('g_password' => $lendDetails['password'], 'rcon_password' => $lendDetails['rcon']); } else if ($gameType == 'teeworlds') { $lendServerReplaceMents = array('sv_password' => $lendDetails['password'], 'sv_rcon_password' => $lendDetails['rcon']); } else if ($gameType == 'samp') { $lendServerReplaceMents = array('password' => $lendDetails['password'], 'rcon' => 1, 'rcon_password' => $lendDetails['rcon']); } } // Remove configs that do not contain any overwrite settings // Removing will prevent unnecessary FTP connections foreach ($cvarProtectArray as $config => $values) { if ($this->appServerDetails['lendServer'] == 'Y') { foreach ($lendServerReplaceMents as $cvar => $value) { $cvarProtectArray[$config]['cvars'][$cvar] = $value; } } if (!isset($values['cvars']) or count($values['cvars']) == 0) { unset($cvarProtectArray[$config]); } } return $cvarProtectArray; } private function getFileAndPathName($fileWithPath) { $splitConfigPath = preg_split('/\//', $this->removeSlashes($fileWithPath), -1, PREG_SPLIT_NO_EMPTY); $folderFileCount = count($splitConfigPath) - 1; $i = 0; $path = ''; while ($i < $folderFileCount) { $path .= '/' . $splitConfigPath[$i]; $i++; } return array('path' => $path, 'file' => $splitConfigPath[$i]); } private function isAssociative($array) { return array_keys($array) !== range(0, count($array) - 1); } private function replaceArrayValues($givenArray, $replacements) { foreach(array_keys($givenArray) as $key) { if (is_array($givenArray[$key])) { $givenArray[$key] = $this->replaceArrayValues($givenArray[$key], ((is_array($replacements) or is_object($replacements)) and isset($replacements[$key])) ? $replacements[$key] : $replacements); } else { if (isset($this->undefinedRequiredVars[$key])) { unset($this->undefinedRequiredVars[$key]); } if (isset($replacements[$key])) { $givenArray[$key] = $replacements[$key]; } // Check if it is a numeric value but a string and convert if (is_numeric($givenArray[$key]) and gettype($givenArray[$key]) == "string") { $givenArray[$key] = (int) $givenArray[$key]; } } } return $givenArray; } private function booleanOrValue($value) { if (is_bool($value)) { return ($value) ? "true" : "false"; } return $value; } private function generateIniString($array) { $iniString = ''; foreach($array as $key => $value) { if (is_array($value)) { foreach($value as $arrayValue) { $iniString .= $key . '=' . $this->booleanOrValue($arrayValue) . PHP_EOL; } } else { $iniString .= $key . '=' . $this->booleanOrValue($value) . PHP_EOL; } } return $iniString; } private function replaceIni($stored, $replacements) { if (!$stored) { $stored = array(); } $iniString = ""; $arrayKeys = array_keys($stored); if (count($arrayKeys) !== 0) { if (is_array($stored[$arrayKeys[0]]) and $this->isAssociative($stored[$arrayKeys[0]])) { foreach($stored as $iniGroup => $values) { $iniString .= '[' . $iniGroup . ']' . PHP_EOL; $iniString .= $this->generateIniString($this->replaceArrayValues($values, $replacements)); } } else { $iniString = $this->generateIniString($this->replaceArrayValues($stored, $replacements)); } } $iniString .= $this->generateIniString($this->undefinedRequiredVars); return $iniString; } private function addNotFoundVars($replacedArray, $key, $value) { if (!isset($replacedArray[$key]) or (!is_array($replacedArray[$key]) and !is_object($replacedArray[$key]))) { $replacedArray[$key] = $value; } else { foreach ($replacedArray[$key] as $k => $v) { $replacedArray[$key] = $this->addNotFoundVars($replacedArray[$key], $k, $v); } } return $replacedArray; } private function replaceArray($stored, $replacements) { if (!$stored) { $stored = array(); } $replacedArray = $this->replaceArrayValues($stored, $replacements); foreach ($this->undefinedRequiredVars as $key => $value) { $replacedArray = $this->addNotFoundVars($replacedArray, $key, $value); } return $replacedArray; } private function replaceYaml($stored, $replacements) { return Yaml::dump($this->replaceArray($stored, $replacements), 2, 4); } //TODO: Replace XML objects private function replaceXML($stored, $replacements) { if (!$stored) { $stored = new SimpleXMLElement(''); } return $stored->asXML(); } private function replaceJSON($stored, $replacements) { return json_encode($this->replaceArray($stored, $replacements), JSON_PRETTY_PRINT); } private function replaceLua($stored, $replacements) { return Lua::arrayToLua($this->replaceArray($stored, $replacements)); } private function correctProtectedFiles () { $protectedConfigs = $this->protectedSettingsToArray(); if (count($protectedConfigs) > 0) { $ftpObect = new EasyWiFTP($this->appMasterServerDetails['ssh2IP'], $this->appMasterServerDetails['ftpPort'], $this->appServerDetails['userNameExecute'], $this->appServerDetails['ftpPasswordExecute']); if ($ftpObect->loggedIn === true) { foreach ($protectedConfigs as $config => $values) { $fileWithPath = $this->appServerDetails['absoluteFTPPath'] . '/' . $config; $fileAndPath = $this->getFileAndPathName($fileWithPath); if (!$ftpObect->downloadToTemp($fileWithPath)) { $noChrootfileWithPath = $this->appServerDetails['absoluteFTPPathNoChroot'] . '/' . $config; $noChrootfileAndPath = $this->getFileAndPathName($noChrootfileWithPath); if ($ftpObect->downloadToTemp($noChrootfileAndPath)) { $fileAndPath = $noChrootfileAndPath; } } $path = $fileAndPath['path']; $fileName = $fileAndPath['file']; $configFileContent = $ftpObect->getTempFileContent(); // We have one temp handle for all files to reduce the amount of needed ram $ftpObect->tempHandle = null; $this->undefinedRequiredVars = $values['cvars']; //TODO handle each type of file with specific parser if ($values['type'] === 'ini') { $ftpObect->writeContentToTemp($this->replaceIni(@parse_ini_string($configFileContent, false, INI_SCANNER_RAW), $values['cvars'])); } else if ($values['type'] === 'yml' or $values['type'] === 'Yaml' or $values['type'] === 'yaml') { $ftpObect->writeContentToTemp($this->replaceYaml($this->parseYML($configFileContent), $values['cvars'])); //TODO /* } else if ($values['type'] === 'xml') { $ftpObect->writeContentToTemp($this->replaceXML(new SimpleXMLElement($configFileContent), $values['cvars'])); */ } else if ($values['type'] == 'json') { $ftpObect->writeContentToTemp($this->replaceJSON(@parse_ini_string(@json_decode($configFileContent), false, INI_SCANNER_RAW), $values['cvars'])); } else if ($values['type'] == 'lua') { if (!class_exists('Lua')) { include(EASYWIDIR . '/stuff/methods/class_lua.php'); } $ftpObect->writeContentToTemp($this->replaceLua(Lua::luaToArray($configFileContent), $values['cvars'])); } else { $cvarsNotFound = $values['cvars']; // Depending how the file was uploaded and written, there might be lots of not needed characters in the file // A clean up will make the file handling lot easier $configFileContent = str_replace(array("\0","\b","\r","\Z"),"", $configFileContent); $lines = explode("\n", $configFileContent); $lineCount = count($lines) - 1; $i = 0; // iterate over all lines foreach ($lines as $singeLine) { // Set to false on each iteration to be able to detect config overwrites $edited = false; // For easier comparison make a string to lower $loweredSingleLine = strtolower($singeLine); foreach ($values['cvars'] as $cvar => $value) { if ($values['type'] == 'cfg' and preg_match('/^[\s\/]{0,}' . strtolower($cvar) . '\s+(.*)$/', $loweredSingleLine)) { $edited = true; unset($cvarsNotFound[$cvar]); $splitLine = preg_split('/' . $cvar . '/', $singeLine, -1, PREG_SPLIT_NO_EMPTY); $ftpObect->writeContentToTemp((isset($splitLine[1])) ? $splitLine[0] . $cvar . ' ' . $value : $cvar . ' ' . $value); } else if ($values['type'] == 'ddot' and preg_match('/^[\s\/]{0,}' . strtolower($cvar) . '[\s+]{0,}\:[\s+]{0,}(.*)$/', $loweredSingleLine)) { $edited = true; unset($cvarsNotFound[$cvar]); $ftpObect->writeContentToTemp($cvar . ':' . $value); } else if ($values['type'] == 'xml' and @preg_match("/^(.*)\<" . strtolower($cvar) . "\>(.*)\<\/" . strtolower($cvar) . "\>(.*)$/", $loweredSingleLine)) { $edited = true; unset($cvarsNotFound[$cvar]); $splitLine = preg_split('/\<' . $cvar . '/', $singeLine, -1, PREG_SPLIT_NO_EMPTY); $ftpObect->writeContentToTemp((isset($splitLine[1])) ? $splitLine[0] . '<' .$cvar . '>' . $value . '' : '<' . $cvar . '> ' . $value . ''); } } // Write untouched content if ($edited == false) { $ftpObect->writeContentToTemp($singeLine); } // If we do not count, we would add a newline at the end every time, a file is edited if ($i < $lineCount) { $ftpObect->writeContentToTemp("\r\n"); } $i++; } $debug = array(); // In case of ini or CFG files we can add entries, which are missing from the file and should be protected foreach ($cvarsNotFound as $cvar => $value) { if ($values['type'] == 'cfg') { $ftpObect->writeContentToTemp($cvar . ' ' . $value . "\r\n"); } else if ($values['type'] == 'ddot') { $ftpObect->writeContentToTemp($cvar . ':' . $value . "\r\n"); } else { $debug[] = 'Type is: ' . $values['type'] . ' and key value: ' . $cvar . '=>' . $value; } } } $ftpObect->uploadFileFromTemp($path, $fileName, false); } } $ftpObect->logOut(); } } // If EAC is available and active the server.cfg needs to be retrieved and EAC setup private function easyAntiCheatSettings ($action = 'start') { global $resellerLockupID; if ($this->appServerDetails['eacAllowed'] == 'Y') { $gameType = $this->getGameType(); // On app start we only run commands for supported games if ($action == 'start' and in_array($this->appServerDetails['app']['anticheat'], array(3, 4, 5, 6)) and ($gameType == 'hl1' or $gameType == 'hl2')) { if ($gameType == 'hl2') { $config = 'cfg/server.cfg'; } else if ($gameType == 'hl1') { $config = 'server.cfg'; } else { $config = 'main/server.cfg'; } $ftpObect = new EasyWiFTP($this->appMasterServerDetails['ssh2IP'], $this->appMasterServerDetails['ftpPort'], $this->appServerDetails['userNameExecute'], $this->appServerDetails['ftpPasswordExecute']); if ($ftpObect->loggedIn === true) { if (!$ftpObect->downloadToTemp($this->appServerDetails['absoluteFTPPath'] . $config)) { $ftpObect->downloadToTemp($this->appServerDetails['absoluteFTPPathNoChroot'] . $config); } $configFile = $ftpObect->getTempFileContent(); $configFile = str_replace(array("\0","\b","\r","\Z"), '', $configFile); $configFile = preg_replace('/\s+/', ' ', $configFile); $lines = explode("\n", $configFile); foreach ($lines as $singeLine) { // Do a rough check if the line is a comment if (preg_match("/\w/", substr($singeLine, 0, 1))) { if (preg_match("/\"/", $singeLine)) { $exploded = explode('"', $singeLine); $cvar = str_replace(' ', '', $exploded[0]); } else { $exploded = explode(' ', $singeLine); $cvar = $exploded[0]; } if ($cvar == 'rcon_password' and isset($exploded[1])) { $rconPassword = $exploded[1]; } } } if (isset($rconPassword)) { eacchange('change', $this->appServerDetails['template']['id'], $rconPassword, $resellerLockupID); } } // On app stop we run commands in any case to ensure we remove left overs } else if ($action == 'stop') { eacchange('remove', $this->appServerDetails['template']['id'], '', $resellerLockupID); } } } private function generateStartCommand () { $gameType = $this->getGameType(); // https://github.com/easy-wi/developer/issues/205 // In case Workshop is on we need to remove mapgroup $startCommand = ($this->appServerDetails['app']['workShop'] == 'Y') ? str_replace(array('%mapgroup%', ' +mapgroup'), '', $this->appServerDetails['app']['cmd']) : $this->appServerDetails['app']['cmd']; // In case of hl2 based servers and no TV allowed, turn off the source tv capabilities if ($gameType == 'hl2' and $this->appServerDetails['tvAllowed'] == 'N') { $startCommand .= ' -nohltv -tvdisable'; } // If the user decided to use EAC instead of VAC, or turned VAC off on porpuse if (($gameType == 'hl1' or $gameType == 'hl2') and ($this->appServerDetails['app']['anticheat'] == 2 or ($this->appServerDetails['app']['anticheat'] > 2 and $this->appServerDetails['eacAllowed'] == 'Y'))) { $startCommand .= ' -insecure'; } // Mod commands are typically used at CS:GO, COD and so and load build in modifications like arms race $modCommand = $this->appServerDetails['app']['modcmd']; foreach (explode("\r\n", $this->appServerDetails['template']['modcmds']) as $line) { if (preg_match('/^(\[[\w\/\.\-\_\= ]{1,}\])$/', $line)) { $exploded = preg_split("/\=/", trim($line,'[]'), -1, PREG_SPLIT_NO_EMPTY); $name = trim($exploded[0]); // This construction appears redundant, but is required as a fallback in case there was an issue in the DB and at least one mod command is required if (isset($exploded[1]) and trim($exploded[1]) == 'default' and ($modCommand === null or $modCommand == '')) { $modCommand = trim($exploded[0]); } if (!isset($modsCmds[$name])) { $modsCmds[$name] = array(); } } else if (isset($name) and isset ($modsCmds[$name]) and $line != '') { $modsCmds[$name][] = $line; } } if (isset($modsCmds[$modCommand]) and is_array($modsCmds[$modCommand])) { foreach ($modsCmds[$modCommand] as $singleModADD) { $startCommand .= ' ' . $singleModADD; } } // Steam Workshop support if ($this->appServerDetails['app']['workShop'] == 'Y' and strlen($this->appServerDetails['app']['webApiAuthKey']) > 0 and strlen($this->appServerDetails['app']['workshopCollection']) > 0) { if (in_array($this->appServerDetails['template']['shorten'], array('gmod', 'garrysmod'))) { $startCommand .= ' -nodefaultmap +host_workshop_collection ' . $this->appServerDetails['app']['workshopCollection'] . ' -authkey ' . $this->appServerDetails['app']['webApiAuthKey']; } else { $startCommand .= ' -nodefaultmap +host_workshop_collection ' . $this->appServerDetails['app']['workshopCollection'] . ' +workshop_start_map ' . $this->appServerDetails['app']['map'] . ' -authkey ' . $this->appServerDetails['app']['webApiAuthKey']; $startCommand = preg_replace('/[\s\s+]{1,}\+map[\s\s+]{1,}[\w-_!%]{1,}/', '', $startCommand); } } // Steam Server Token Support if ($this->appServerDetails['template']['steamGameserverToken'] == 'Y' and strlen($this->appServerDetails['app']['steamServerToken']) > 0) { $startCommand .= ' +sv_setsteamaccount ' . $this->appServerDetails['app']['steamServerToken']; } if ($this->appServerDetails['lendServer'] == 'Y') { $lendDetails = $this->getLendDetails(); if (!is_array($lendDetails)) { $startCommand .= $this->getLendDetails(); } } // Add addon commands if (isset($this->appServerDetails['extensions']['cmds']) and count($this->appServerDetails['extensions']['cmds']) > 0) { $startCommand .= implode('', $this->appServerDetails['extensions']['cmds']); } // Remove what needs to be removed according to installed addons if (isset($this->appServerDetails['extensions']['removeCmds']) and count($this->appServerDetails['extensions']['removeCmds']) > 0) { foreach ($this->appServerDetails['extensions']['removeCmds'] as $removeCommand) { $startCommand = str_replace($removeCommand, '', $startCommand); } } $replaceSettings = $this->getReplacements(); $startCommand = str_replace($replaceSettings['placeholder'], $replaceSettings['replacePlaceholderWith'], $startCommand); foreach (customColumns('G', $this->appServerDetails['id']) as $customColumn) { $startCommand = str_replace("%${customColumn['name']}%", $customColumn['value'], $startCommand); } //If a template is set up for both OS, we might need to alter the start of the command if ($this->appMasterServerDetails['os'] == 'W') { if (substr($startCommand, 0, 2) == './') { $startCommand = substr($startCommand, 3); } if (substr($startCommand, 0, 1) == '.') { $startCommand = substr($startCommand, 2); } $shellCommand = ''; } else { $shellCommand = 'if [ "`screen -v | awk \'{split($3, a, "."); print a[2]}\'`" == "05" ]; then' . "\n"; $shellCommand .= 'SCREENLOG="screenlog.0"' . "\n"; $shellCommand .= 'fi' . "\n"; $shellCommand .= ($this->appServerDetails['useTaskSet'] == 'Y' and strlen($this->appServerDetails['cores']) > 0) ? 'taskset -c ' . $this->appServerDetails['cores'] . ' ' : ''; $shellCommand .= 'screen -A -m -d -L $SCREENLOG -S ' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' ' . $startCommand . "\n"; } return $shellCommand; } private function arkCheckSleep () { // Loop used for ARK only. Ensures enough time has elapsed for worl save if ($this->appServerDetails['template']['gameBinary'] == 'ShooterGameServer') { // For 30 seconds check every half second if the world save is done and a restart can be performed $script = 'I=0' . "\n"; $script .= 'while [ "`ps fx | grep \'./ShooterGameServer\' | grep -v grep | head -n 1`" != "" -a $I -lt 60 ]; do' . "\n"; $script .= 'sleep 0.5' . "\n"; $script .= 'let I=I+1' . "\n"; $script .= 'done' . "\n"; // If a process is still running, kill it hard $script .= 'ps fx | grep \'./ShooterGameServer\' | grep -v grep | awk \'{print $1}\' | while read PID; do' . "\n"; $script .= 'kill $PID' . "\n"; $script .= 'done' . "\n"; return $script; } return ''; } private function linuxStartApp () { $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/start-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $serverDir = $this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName']; $serverDir .= ($this->appServerDetails['protectionModeStarted'] == 'Y') ? '/pserver/' : '/server/'; $serverDir = $this->removeSlashes($serverDir); $serverTemplateDir = $this->removeSlashes($serverDir . '/'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; $script .= $this->linuxStopApp(false, $scriptName); $script .= '${IONICE}find -L ' . $serverDir . ' -type l -delete' . "\n"; if ($this->appServerDetails['protectionModeStarted'] == 'Y') { $script .= '${IONICE}nice -n +19 find ' . $serverDir . ' -type d -print0 | xargs -0 chmod 750' . "\n"; if ($this->appServerDetails['template']['copyStartBinary'] == 'Y' and strlen($this->appServerDetails['template']['gameBinary']) > 0) { $script .= '${IONICE}nice -n +19 find ' . $serverDir . ' -type f ! -name "' . $this->appServerDetails['template']['gameBinary'] . '" -print0 | xargs -0 chmod 750' . "\n"; } else { $script .= '${IONICE}nice -n +19 find ' . $serverDir . ' -type f ! -name "ShooterGameServer" -print0 | xargs -0 chmod 640' . "\n"; } } else { $script .= '${IONICE}nice -n +19 find ' . $serverDir . ' -type d -print0 | xargs -0 chmod 700' . "\n"; if ($this->appServerDetails['template']['copyStartBinary'] == 'Y' and strlen($this->appServerDetails['template']['gameBinary']) > 0) { $script .= '${IONICE}nice -n +19 find ' . $serverDir . ' -type f ! -name "' . $this->appServerDetails['template']['gameBinary'] . '" -print0 | xargs -0 chmod 700' . "\n"; } else { $script .= '${IONICE}nice -n +19 find ' . $serverDir . ' -type f ! -name "ShooterGameServer" -print0 | xargs -0 chmod 600' . "\n"; } // Remove files where they do not belong $script .= '${IONICE}nice -n +19 find ' . $serverDir . ' -mindepth 1 -maxdepth 1 \( -type f -or -type l \) -delete' . "\n"; $script .= '${IONICE}nice -n +19 find ' . $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName']) . ' -mindepth 1 -maxdepth 1 \( -type f -or -type l \)'; $script .= ' ! -name ".profile" ! -name ".bashrc" ! -name ".bash_logout" -delete' . "\n"; // Remove folders where they do not belong $script .= '${IONICE}nice -n +19 find ' . $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName']) . ' -mindepth 1 -maxdepth 1 -type d'; $script .= ' ! -name ".steam" ! -name "pserver" ! -name "backup" ! -name "fdl_data" ! -name "server" -print0 | xargs -0 rm -rf' . "\n"; $script .= '${IONICE}nice -n +19 find /home/' . $this->appMasterServerDetails['ssh2User'] . '/fdl_data -type f -user `whoami` ! -name "*.bz2" -delete' . "\n"; } if ($this->appServerDetails['template']['steamgame'] == 'S') { $script .= 'if [ ! -f "' . $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName'] . '/.steam/sdk32/steamclient.so') . '" ]; then' . "\n"; $script .= ' mkdir -p "' . $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName'] . '/.steam/sdk32/') . '"' . "\n"; $script .= ' ln -s "' . $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/masterserver//steamCMD/linux32/steamclient.so') . '" "'; $script .= $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName'] . '/.steam/sdk32/steamclient.so') . '"' . "\n"; $script .= 'fi' . "\n"; } if (count($this->appMasterServerDetails['configBinaries']) > 0 or count($this->appMasterServerDetails['configFiles']) > 0 ) { $script .= 'FILESFOUND=(`find ' . $serverDir . ' -type f '; if (count($this->appMasterServerDetails['configBinaries']) > 0) { $script .= '\( -iname "*.' . implode('" -or -iname "*.', $this->appMasterServerDetails['configBinaries']) . '" \)'; } if (count($this->appMasterServerDetails['configFiles']) > 0) { $script .= ' -wholename "' . implode('" -o -wholename "', $this->appMasterServerDetails['configFiles']) . '"'; } $script .= '`)' . "\n"; $script .= 'for BADFILE in ${FILESFOUND[@]}; do' . "\n"; $script .= 'chmod 666 $BADFILE > /dev/null 2>&1' . "\n"; $script .= 'rm -f $BADFILE > /dev/null 2>&1' . "\n"; $script .= 'if [ -f $BADFILE ]; then exit 0; fi' . "\n"; $script .= 'done' . "\n"; } if ($this->appMasterServerDetails['configBadTime'] > 0 and count($this->appMasterServerDetails['configBadFiles']) > 0) { $script .= '${IONICE}find ' . $serverDir . ' -type f \( -iname "*.' . implode('" -or -iname "*.', $this->appMasterServerDetails['configBadFiles']) . '" \) -mtime +' . $this->appMasterServerDetails['configBadTime'] . ' -delete' . "\n"; } if ($this->appMasterServerDetails['configDemoTime'] > 0) { $script .= '${IONICE}find ' . $serverTemplateDir . ' -type f -name "*.dem" -mtime +' . $this->appMasterServerDetails['configDemoTime'] . ' -delete' . "\n"; } if ($this->appMasterServerDetails['configLogTime'] > 0) { $script .= '${IONICE}find ' . $serverTemplateDir . ' -type f -name "*.log" -mtime +' . $this->appMasterServerDetails['configLogTime'] . ' -delete' . "\n"; } if ($this->appMasterServerDetails['configZtmpTime'] > 0) { $script .= '${IONICE}find ' . $serverTemplateDir . ' -type f -name "*.ztmp" -mtime +' . $this->appMasterServerDetails['configZtmpTime'] . ' -delete' . "\n"; } $script .= 'cd ' . $this->appServerDetails['absolutePath'] . "\n"; if (strlen($this->appServerDetails['template']['binarydir']) > 0) { $script .= 'BINARY_DIR=`find "' . $this->appServerDetails['template']['binarydir'] . '" -type d | head -n 1`' . "\n"; $script .= 'if [ "$BINARY_DIR" != "" ]; then cd "$BINARY_DIR"; fi' . "\n"; } // Loop used for ARK only. Ensures enough time has elapsed for world save if ($this->appServerDetails['template']['gameBinary'] == 'ShooterGameServer') { // For 30 seconds check every half second if the world save is done and a restart can be performed $script .= 'I=0' . "\n"; $script .= 'while [ "`ps fx | grep \'./ShooterGameServer\' | grep -v grep | head -n 1 | awk \'{print $5}\' | sed \'s/.\///g\'`" != "ShooterGameServer" -a $I -lt 60 ]; do' . "\n"; $script .= 'sleep 0.5' . "\n"; $script .= 'let I=I+1' . "\n"; $script .= 'done' . "\n"; // If a process is still running, kill it hard $script .= 'ps fx | grep \'./ShooterGameServer\' | grep -v grep | awk \'{print $1}\' | while read PID; do' . "\n"; $script .= 'kill $PID' . "\n"; $script .= 'done' . "\n"; // } $script .= $this->arkCheckSleep(); $script .= 'if [ -f screenlog.0 ]; then rm -f screenlog.0; fi' . "\n"; $script .= $this->generateStartCommand() . "\n"; if ($this->getGameType() == 'hl2' and $this->appServerDetails['tvAllowed'] == 'Y' and in_array($this->appServerDetails['app']['upload'], array(4, 5)) and $this->appServerDetails['app']['uploadDir']) { $script .= $this->linuxDemoUpload(false); } $this->addLinuxScript($scriptName, $script); $this->addLogline('app_server.log', 'App ' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' owned by user ' . $this->appServerDetails['userNameExecute'] . ' started'); } public function startApp () { global $sql; if ($this->appServerDetails) { $this->getAddonDetails(); $this->correctProtectedFiles(); $this->easyAntiCheatSettings(); if ($this->appMasterServerDetails['os'] == 'L') { if ($this->appServerDetails['protectionModeStarted'] == 'Y') { $this->linuxHardStop($this->appServerDetails['userName']); } else if ($this->appServerDetails['protectionModeAllowed'] == 'Y' and $this->appServerDetails['protectionModeStarted'] == 'N') { $this->linuxHardStop($this->appServerDetails['userName'] . '-p'); } $this->linuxAddApp(array($this->appServerDetails['app']['templateChoosen'])); $this->linuxAddAddons(); $this->linuxStartApp(); } else if ($this->appMasterServerDetails['os'] == 'W') { } $query = $sql->prepare("UPDATE `gsswitch` SET `stopped`='N' WHERE `id`=? LIMIT 1"); $query->execute(array($this->appServerDetails['id'])); } } private function linuxDemoUpload ($standalone = true) { $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/demo-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); if ($standalone == true) { $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; } else { $script = ''; } if (in_array($this->appServerDetails['app']['upload'], array(3, 5))) { $script .= 'KEEP="-k"' . "\n"; } // This if cases have to be run on the root as the PHP script does not know what is installed there $script .= 'LSOF=`which lsof`' . "\n"; $script .= 'if [ "$LSOF" == "" ]; then KEEP="-k"; fi' . "\n"; $script .= 'cd ' . $this->appServerDetails['absolutePath'] . "\n"; $uploadScript = 'if [[ `which zip` ]]; then' . "\n"; $uploadScript .= 'if [ "$KEEP" == "" ]; then KEEP="-m"; fi' . "\n"; $uploadScript .= '${IONICE}nice -n +19 zip -q $KEEP $DEMOPATH/$DEMO.zip $DEMOPATH/$DEMO' . "\n"; $uploadScript .= 'ZIP="zip"' . "\n"; $uploadScript .= 'elif [[ `which bzip2` ]]; then' . "\n"; $uploadScript .= '${IONICE}nice -n +19 bzip2 -s -q -9 $KEEP $DEMOPATH/$DEMO' . "\n"; $uploadScript .= 'ZIP="bz2"' . "\n"; $uploadScript .= 'fi' . "\n"; $uploadScript .= 'DEMOANDPATH="$DEMOPATH/$DEMO.$ZIP"' . "\n"; $uploadScript .= 'wput -q --limit-rate=1024K --remove-source-files --tries 3 --basename="${DEMOPATH/\/\///}" "${DEMOANDPATH/\/\///}" "' . $this->appServerDetails['app']['uploadDir'] . '"' . "\n"; // 2 and 3 are one time run (manuel mode) if (in_array($this->appServerDetails['app']['upload'], array(2, 3))) { $script .= 'cd `find -mindepth 1 -maxdepth 3 -type d -name "' . $this->appServerDetails['template']['modfolder'] . '" | head -n1`' . "\n"; $script .= 'find . -maxdepth 2 -type f -name "*.dem" | while read LINE; do' . "\n"; $script .= 'DEMOPATH="`dirname $LINE`/"' . "\n"; $script .= 'DEMO="`basename $LINE`"' . "\n"; $script .= 'if [ "$LSOF" != "" ]; then ' . "\n"; $script .= 'if [[ ! `lsof $LINE` ]]; then' . "\n"; $script .= $uploadScript; $script .= 'fi' . "\n"; $script .= 'else' . "\n"; $script .= $uploadScript; $script .= 'fi' . "\n"; $script .= 'done' . "\n"; // 4 and 5 is continuous run with a tail of the screenlog } else if (in_array($this->appServerDetails['app']['upload'], array(4, 5))) { $script .= 'DEMOPATH=`find -mindepth 1 -maxdepth 3 -type d -name "' . $this->appServerDetails['template']['modfolder'] . '" | head -n1`' . "\n"; $script .= 'SCREENLOG="`find ' . $this->appServerDetails['absolutePath'] . ' -name "screenlog.0" | head -n1`"' . "\n"; $script .= 'if [ "$SCREENLOG" != "" ]; then' . "\n"; $script .= 'cd `dirname $SCREENLOG`' . "\n"; $script .= 'tail -f screenlog.0 | while read LINE; do' . "\n"; $script .= 'if [[ `echo $LINE | grep -E "Completed (SourceTV|GOTV)"` ]]; then' . "\n"; $script .= 'DEMO=`echo -n "$LINE" | awk \'{print $4}\' | tr -d \'"\' | tr -d \',\'`' . "\n"; $script .= 'if [ "$LSOF" != "" ]; then ' . "\n"; $script .= 'if [[ ! `lsof $DEMOPATH/$DEMO` ]]; then' . "\n"; $script .= $uploadScript; $script .= 'fi' . "\n"; $script .= 'else' . "\n"; $script .= $uploadScript; $script .= 'fi' . "\n"; $script .= 'fi' . "\n"; $script .= 'done' . "\n"; $script .= 'fi' . "\n"; } if (in_array($this->appServerDetails['app']['upload'], array(2, 3, 4, 5))) { // The demo listener needs to be started in a separate screen if (in_array($this->appServerDetails['app']['upload'], array(4, 5))) { $this->addLinuxScript($scriptName, $script, $this->appServerDetails['userNameExecute'], true); $screenScriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/demo-start-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $screenScriptName . "\n"; // Kill any screen that is running with the same name $script .= 'ps fx | grep \'SCREEN\' | grep \'demo_' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '\' | grep -v grep | awk \'{print $1}\' | while read PID; do' . "\n"; $script .= 'kill $PID > /dev/null 2>&1' . "\n"; $script .= 'kill -9 $PID > /dev/null 2>&1' . "\n"; $script .= 'done' . "\n"; $script .= 'screen -d -m -S demo_' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' ' . $scriptName . "\n"; // Rename for the function return $scriptName = $screenScriptName; } $this->addLogline('app_server.log', 'Demo upload started for ' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' owned by user ' . $this->appServerDetails['userNameExecute']); if ($standalone == true) { $this->addLinuxScript($scriptName, $script); } return $script; } return ''; } public function demoUpload () { if ($this->appServerDetails and $this->appServerDetails['app']['uploadDir'] and $this->appMasterServerDetails['os'] == 'L') { $this->linuxDemoUpload(); } else if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'W') { } } private function linuxAddonShellGeneric ($type, $name, $action, $folders = '') { $masterAddonFolder = '/home/' . $this->appMasterServerDetails['ssh2User'] . '/'; $masterAddonFolder .= ($type == 'addon') ? 'masteraddons/' : 'mastermaps/'; $masterAddonFolder .= $name . '/'; if (strlen($this->appServerDetails['template']['modfolder']) == 0) { $script = 'GAMEDIR="' . $this->appServerDetails['absolutePath'] . '"' . "\n"; } else { $script = 'if [ "`find ' . $this->appServerDetails['absolutePath'] . ' -mindepth 1 -maxdepth 3 -type d -name ' . $this->appServerDetails['template']['modfolder'] . ' | wc -l`" == "1" ]; then' . "\n"; $script .= 'GAMEDIR=`find ' . $this->appServerDetails['absolutePath'] . ' -mindepth 1 -maxdepth 3 -type d -name "' . $this->appServerDetails['template']['modfolder'] . '" | head -n 1`' . "\n"; $script .= 'else' . "\n"; $script .= 'GAMEDIR=`find ' . $this->appServerDetails['absolutePath'] . ' -mindepth 1 -maxdepth 1 -type d -name "' . $this->appServerDetails['template']['modfolder'] . '" | head -n 1`' . "\n"; $script .= 'fi' . "\n"; } $script .= 'if [ -d "' . $masterAddonFolder . '" -a "$GAMEDIR" != "" ]; then' . "\n"; $script .= 'cd ' . $masterAddonFolder . "\n"; if ($action == 'add') { $script .= $this->linuxAddAddonShellCommands($type, $masterAddonFolder); } else { $script .= $this->linuxRemoveAddonShellCommands($folders); } $script .= 'fi' . "\n"; return $script; } private function linuxAddAddonShellCommands ($type, $masterAddonFolder) { $script = ''; $script .= 'cp -sr ' . $masterAddonFolder . '* $GAMEDIR/ > /dev/null 2>&1' . "\n"; if ($type == 'addon') { $script .= 'find -type f | grep -i -E -w \'(xml|cfg|con|conf|config|gam|ini|txt|vdf|smx|sp|ext|sma|amxx|lang|lua|json|yml)$\' | sed \'s/\.\///g\' | while read FILE; do' . "\n"; $script .= 'FOLDER=`dirname $FILE`' . "\n"; $script .= 'FILENAME=`basename $FILE`' . "\n"; $script .= 'if [ ! -d $GAMEDIR/$FOLDER ]; then mkdir -p $GAMEDIR/$FOLDER/; fi' . "\n"; $script .= 'find $GAMEDIR/$FILE -type l -delete > /dev/null 2>&1' . "\n"; $script .= 'if [ "$FILENAME" == "liblist.gam" ]; then' . "\n"; $script .= 'mv $GAMEDIR/$FILE $GAMEDIR/$FILE.old' . "\n"; $script .= 'cp ' . $masterAddonFolder . '$FILE $GAMEDIR/$FILE' . "\n"; $script .= 'elif [ "$FILENAME" == "plugins.ini" ]; then' . "\n"; $script .= 'if [ -f $GAMEDIR/$FILE ]; then' . "\n"; $script .= 'cat ' . $masterAddonFolder . '$FILE | while read $LINE; do' . "\n"; $script .= 'if [ `grep "$LINE" $GAMEDIR/$FILE` == "" ]; then echo $LINE >> $GAMEDIR/$FILE; fi' . "\n"; $script .= 'done' . "\n"; $script .= 'else' . "\n"; $script .= 'cp ' . $masterAddonFolder . '$FILE $GAMEDIR/$FILE' . "\n"; $script .= 'fi' . "\n"; $script .= 'elif [ "$FILENAME" == "gametypes.txt" ]; then' . "\n"; $script .= 'if [ "$FOLDER" != "cfg/mani_admin_plugin" ]; then cp ' . $masterAddonFolder . '$FILE $GAMEDIR/$FILE; fi' . "\n"; $script .= 'elif [ ! -f $GAMEDIR/$FILE -a ! -f "$GAMEDIR/$FOLDER/disabled/$FILENAME" ]; then' . "\n"; $script .= 'cp ' . $masterAddonFolder . '$FILE $GAMEDIR/$FILE' . "\n"; $script .= 'fi' . "\n"; $script .= 'done' . "\n"; } return $script; } private function linuxAddAddons ($id = false) { $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/addons-add-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; if ($id === false) { $logLine = ''; if (isset($this->appServerDetails['extensions']['addons']) and count($this->appServerDetails['extensions']['addons']) > 0) { foreach ($this->appServerDetails['extensions']['addons'] as $id => $addon) { // A possible scenario is that the addon has been installed while unprotected and the mode switched later on // In such a case we need to ensure that the addon is not installed on restart if ($this->appServerDetails['protectionModeStarted'] == 'N' or ($this->appServerDetails['protectionModeStarted'] == 'Y' and $this->appServerDetails['extensions']['addonSettings'][$id]['protectedAllowed'] == 'Y')) { $script .= $this->linuxAddonShellGeneric('addon', $addon, 'add'); } } $logLine .= 'added addon(s) ' . implode(',', $this->appServerDetails['extensions']['addons']); } if (isset($this->appServerDetails['extensions']['maps']) and count($this->appServerDetails['extensions']['maps']) > 0) { foreach ($this->appServerDetails['extensions']['maps'] as $addon) { $script .= $this->linuxAddonShellGeneric('map', $addon, 'add'); } $logLine .= ' added map(s) ' . implode(',', $this->appServerDetails['extensions']['maps']); } } else if (isset($this->appServerDetails['extensions']['addons'][$id])) { $script .= $this->linuxAddonShellGeneric('addon', $this->appServerDetails['extensions']['addons'][$id], 'add'); $logLine = 'Added addon ' . $this->appServerDetails['extensions']['addons'][$id]; } else if (isset($this->appServerDetails['extensions']['maps'][$id])) { $script .= $this->linuxAddonShellGeneric('map', $this->appServerDetails['extensions']['maps'][$id], 'add'); $logLine = 'Added map ' . $this->appServerDetails['extensions']['maps'][$id]; } if (isset($logLine) and strlen($logLine) > 0) { $this->addLinuxScript($scriptName, $script); $this->addLogline('app_server.log', $logLine . ' to app ' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' owned by user ' . $this->appServerDetails['userNameExecute']); } } public function addAddon ($id = false) { if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'L') { $this->linuxAddAddons($id); } else if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'W') { } } private function getDependentAddonsQuery($id) { global $sql; $array = array(); $query = $sql->prepare("SELECT a.`id`,a.`addon` FROM `addons` AS a INNER JOIN `addons_installed` AS i ON i.`addonid`=a.`id` AND i.`serverid`=? AND i.`servertemplate`=? WHERE a.`depending`=?"); $query->execute(array($this->appServerDetails['app']['id'], $this->appServerDetails['app']['servertemplate'], $id)); while ($row = $query->fetch(PDO::FETCH_ASSOC)) { $array[] = $row['id']; } return $array; } private function getDependentAddons ($id) { $addonIDs = $this->getDependentAddonsQuery($id); if (count($addonIDs) > 0) { foreach ($addonIDs as $addonID) { foreach($this->getDependentAddons($addonID) as $dependentAddonID) { $addonIDs[] = $dependentAddonID; } } } return $addonIDs; } private function linuxRemoveAddonShellCommands ($folders) { $script = 'find -mindepth 1 -type f | sed \'s/\.\///g\' | while read FILES; do' . "\n"; $script .= 'if [ "`basename $FILES`" == "liblist.gam" ]; then' . "\n"; $script .= 'mv $GAMEDIR/$FILES.old $GAMEDIR/$FILES' . "\n"; $script .= 'elif [ "`basename $FILES`" == "plugins.ini" ]; then' . "\n"; $script .= 'if [ -f /home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/$USER.pluginlist.temp ]; then rm -f /home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/$USER.pluginlist.temp; fi' . "\n"; $script .= 'cat $GAMEDIR/$FILES | while read LINE; do' . "\n"; $script .= 'if [[ `grep "$LINE" $FILES` == "" ]]; then echo "$LINE" >> /home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/$USER.pluginlist.temp; fi' . "\n"; $script .= 'done' . "\n"; $script .= 'cp /home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/$USER.pluginlist.temp $GAMEDIR/$FILES' . "\n"; $script .= 'rm -f /home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/$USER.pluginlist.temp' . "\n"; $script .= 'else' . "\n"; $script .= 'rm -rf "$GAMEDIR/$FILES" > /dev/null 2>&1' . "\n"; $script .= 'if [ "$FILES" == "liblist.gam" ]; then mv $GAMEDIR/$FILES.old $GAMEDIR/$FILES > /dev/null 2>&1; fi' . "\n"; $script .= 'fi' . "\n"; $script .= 'done' . "\n"; $script .= 'cd $GAMEDIR' . "\n"; $script .= 'find -mindepth 1 -type d -empty -delete' . "\n"; // Check for to be removed folders if (count($folders) > 0) { $script .= 'find -mindepth 1 \( -iname "' . implode('" -or -iname "', $folders) . '"\) -print0 | xargs -0 rm -rf' . "\n"; } return $script; } private function linuxRemoveAddons ($ids) { $names = array(); $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/addons-del-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; $script .= 'USER=`id -un`' . "\n"; foreach ($ids as $id) { $folders = (isset($this->appServerDetails['extensions']['addonSettings'][$id]['folder'])) ? preg_split('/(\s+|,)/', $this->appServerDetails['extensions']['addonSettings'][$id]['folder'], -1, PREG_SPLIT_NO_EMPTY) : array(); if (isset($this->appServerDetails['extensions']['addons'][$id])) { $names[] = $this->appServerDetails['extensions']['addons'][$id]; $script .= $this->linuxAddonShellGeneric('addon', $this->appServerDetails['extensions']['addons'][$id], 'del', $folders); } else if (isset($this->appServerDetails['extensions']['maps'][$id])) { $names[] = $this->appServerDetails['extensions']['maps'][$id]; $script .= $this->linuxAddonShellGeneric('map', $this->appServerDetails['extensions']['maps'][$id], 'del', $folders); } } if (count($names) > 0) { $this->addLinuxScript($scriptName, $script); $this->addLogline('app_server.log', 'Removed addon(s)/map(s) ' . implode(',', $names) . ' from app ' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' owned by user ' . $this->appServerDetails['userNameExecute']); } } public function removeAddon ($id) { global $sql; if ($this->appServerDetails) { $toBeRemovedAddonIDs = array($id); foreach ($this->getDependentAddons($id) as $addonID) { $toBeRemovedAddonIDs[] = $addonID; } if ($this->appMasterServerDetails['os'] == 'L') { $this->linuxRemoveAddons($toBeRemovedAddonIDs); } else if ($this->appMasterServerDetails['os'] == 'W') { } $query = $sql->prepare("DELETE FROM `addons_installed` WHERE `addonid`=? AND `serverid`=? AND `servertemplate`=? LIMIT 1"); foreach ($toBeRemovedAddonIDs as $addonID) { $query->execute(array($addonID, $this->appServerDetails['app']['id'], $this->appServerDetails['app']['servertemplate'])); } } } private function linuxMigrateServer ($sourceFTP, $targetTemplate, $modFolder) { $serverDir = $this->removeSlashes($this->appServerDetails['homeDir'] . '/' . $this->appServerDetails['userName'] . '/server/' . '/' . $targetTemplate . '/'); $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/migrate-' . $this->appServerDetails['userName'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; $script .= 'if [ -d "' . $serverDir . '" ]; then ${IONICE}rm -rf "' . $serverDir . '"; fi' . "\n"; $script .= $this->linuxAddApp(array($targetTemplate), false); $script .= 'if [ ! -d "' . $serverDir . '" ]; then mkdir -p "' . $serverDir . '"; fi' . "\n"; $script .= 'cd ' . $serverDir . "\n"; if (strlen($modFolder) > 0) { $script .= 'MODFOLDER=`find -mindepth 1 -maxdepth 3 -type d -name "' . $modFolder . '" | head -n 1`' . "\n"; $script .= 'if [ "$MODFOLDER" != "" ]; then cd $MODFOLDER; fi' . "\n"; } $cutDirs = count(preg_split('/\//', $sourceFTP['path'], -1, PREG_SPLIT_NO_EMPTY)); if ($cutDirs < 0) { $cutDirs = 0; } $script .= 'find -type f -print0 | xargs -0 rm -f' . "\n"; $script .= 'wget -q -r -l inf -nc -nH --limit-rate=4096K --retr-symlinks --no-check-certificate --ftp-user=' . $sourceFTP['user'] . ' --ftp-password=' . $sourceFTP['password'] . ' --cut-dirs=' . $cutDirs . ' ' . $sourceFTP['connectString'] . "\n"; $script .= $this->linuxAddApp(array($targetTemplate), false); $this->addLinuxScript($scriptName, $script); $this->addLogline('app_server.log', 'Migrated server to ' . $targetTemplate . ' belonging to app ' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' owned by user ' . $this->appServerDetails['userName']); } public function migrateToEasyWi ($sourceFTP, $targetTemplate, $modFolder) { if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'L') { $this->linuxMigrateServer($sourceFTP, $targetTemplate, $modFolder); } else if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'W') { } } private function linuxFastDLSync ($fdlConnectString) { $gameType = $this->getGameType(); if (in_array($gameType, array('hl1', 'hl2', 'cod'))) { $fdlFileList = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/conf/fdl-' . $this->appServerDetails['template']['shorten'] . '.list'); $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/fdl-sync-' . $this->appServerDetails['userName'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; $script .= 'USERNAME=`id -un`' . "\n"; $script .= 'if [ -f "' . $fdlFileList . '" ]; then' . "\n"; $script .= 'cd ' . $this->appServerDetails['absolutePath'] . "\n"; $excludePattern = '\.log\|\.txt\|\.cfg\|\.vdf\|\.db\|\.dat\|\.ztmp\|\.blib\|log\/\|logs\/\|downloads\/\|DownloadLists\/\|metamod\/\|amxmodx\/\|hl\/\|hl2\/\|cfg\/\|addons\/\|bin\/\|classes/'; if ($gameType == 'hl2') { $fdlMasterFolder = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/fdl_data/hl2/' . $this->appServerDetails['template']['shorten'] . '/'); $script .= 'if [ ! -d "' . $fdlMasterFolder . '" ]; then mkdir -p "' . $fdlMasterFolder . '"; fi' . "\n"; $script .= 'find "' . $fdlMasterFolder . '" -maxdepth 1 -type d -user `whoami` -exec chmod 770 {} \;' . "\n"; $logFile = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/logs/fdl-hl2.log'); if (strlen($this->appServerDetails['template']['binarydir']) > 0) { $script .= 'cd ' . $this->appServerDetails['template']['binarydir'] . "\n"; } if ($this->appServerDetails['template']['gameq'] == 'l4d2') { $script .= 'cd left4dead2/left4dead2/' . "\n"; } else if (strlen($this->appServerDetails['template']['modfolder']) > 0) { $script .= 'cd ' . $this->appServerDetails['template']['modfolder'] . '/' . "\n"; } $script .= 'ABSOLUTEGAMEPATH=`readlink -f .`' . "\n"; $script .= 'find particles/ maps/ materials/ resource/ models/ sound/ -type l -or -type f 2> /dev/null | grep -v "' . $excludePattern . '" | while read FOUNDFILE; do' . "\n"; } else if ($gameType == 'hl1') { $logFile = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/logs/fdl-hl1.log'); $script .= 'cd ' . $this->appServerDetails['template']['modfolder'] . '/' . "\n"; $script .= 'find . -type l -or -type f 2> /dev/null | grep -v "' . $excludePattern . '" | while read FOUNDFILE; do' . "\n"; } else { $logFile = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/logs/fdl-cod.log'); $script .= 'find usermaps/ mods/ -type l -or -type f \( -iname "*.ff" -or -iname "*.iwd" \) 2> /dev/null | grep -v "' . $excludePattern . '" | while read FOUNDFILE; do' . "\n"; } $script .= 'FILTEREDFILE=${FOUNDFILE//\.\//}' . "\n"; $script .= 'if [[ ! `grep "$FILTEREDFILE" "' . $fdlFileList . '"` ]]; then' . "\n"; $script .= 'FILENAME=`basename $FILTEREDFILE`' . "\n"; if ($gameType == 'hl2' and isset($fdlMasterFolder)) { $script .= 'cd ' . $fdlMasterFolder . "\n"; $script .= 'ABSOLUTEFILTEREDFILE="$ABSOLUTEGAMEPATH/$FILTEREDFILE"' . "\n"; $script .= 'FDLDATADIR=' . $fdlMasterFolder . '`dirname "$FILTEREDFILE"`' . "\n"; $script .= 'if [ ! -d $FDLDATADIR ]; then mkdir -p $FDLDATADIR; chmod 770 $FDLDATADIR; fi' . "\n"; $script .= 'FDLDATAFILENAME="$FDLDATADIR/$FILENAME"' . "\n"; $script .= 'CHECKSUMNEW=`${IONICE}nice -n +19 md5sum "$ABSOLUTEFILTEREDFILE" | awk \'{print $1}\'`' . "\n"; $script .= 'if [ -f "$FDLDATAFILENAME.stat" -a -f "$FDLDATAFILENAME.bz2" ]; then' . "\n"; $script .= 'CHECKSUMOLD=`head -n 1 "$FDLDATAFILENAME.stat" 2> /dev/null`' . "\n"; $script .= 'else' . "\n"; $script .= 'CHECKSUMOLD=""' . "\n"; $script .= 'fi' . "\n"; $script .= 'if [ "$CHECKSUMOLD" != "$CHECKSUMNEW" ]; then' . "\n"; $script .= '${IONICE}nice -n +19 bzip2 -k -s -q -9 -f -c "$ABSOLUTEFILTEREDFILE" > "$FDLDATAFILENAME.bz2"' . "\n"; $script .= 'echo $CHECKSUMNEW > "$FDLDATAFILENAME.stat"' . "\n"; $script .= 'chmod 660 "$FDLDATAFILENAME.stat" "$FDLDATAFILENAME.bz2"' . "\n"; $script .= 'fi' . "\n"; $script .= 'if [ "$CHECKSUMOLD" != "$CHECKSUMNEW" -a "$CHECKSUMOLD" != "" ]; then' . "\n"; $script .= 'wput -q --reupload --limit-rate=1024K "$FILTEREDFILE.bz2" ' . $fdlConnectString . "\n"; $script .= 'echo "`date`: $USERNAME: ' . $this->appServerDetails['app']['templateChoosen'] . ' file $FILENAME compressed and uploaded" >> ' . $logFile . "\n"; $script .= 'else' . "\n"; $script .= 'wput -q --dont-continue --limit-rate=1024K "$FILTEREDFILE.bz2" ' . $fdlConnectString . "\n"; $script .= 'echo "`date`: $USERNAME: ' . $this->appServerDetails['app']['templateChoosen'] . ' file $FILENAME uploaded" >> ' . $logFile . "\n"; $script .= 'fi' . "\n"; } else { $script .= 'if [ "`wput -q -nv --limit-rate=1024K "$FILTEREDFILE" ' . $fdlConnectString . ' | grep \"Skipping file\"`" != "" ]; then' . "\n"; $script .= 'wput -qN --limit-rate=1024K "$FILTEREDFILE" ' . $fdlConnectString . "\n"; $script .= 'echo "`date`: $USERNAME: ' . $this->appServerDetails['app']['templateChoosen'] . ' file $FILENAME checked" >> ' . $logFile . "\n"; $script .= 'else' . "\n"; $script .= 'echo "`date`: $USERNAME: ' . $this->appServerDetails['app']['templateChoosen'] . ' file $FILENAME uploaded" >> ' . $logFile . "\n"; $script .= 'fi' . "\n"; } $script .= 'fi' . "\n"; $script .= 'done' . "\n"; if ($gameType == 'hl2' and isset($fdlMasterFolder)) { $script .= 'find "' . $fdlMasterFolder . '" -type d -user $USERNAME -exec chmod 770 {} \;' . "\n"; $script .= 'find "' . $fdlMasterFolder . '" -type f -user $USERNAME -exec chmod 660 {} \;' . "\n"; } $script .= 'fi' . "\n"; $this->addLinuxScript($scriptName, $script); $this->addLogline('fdl.log', 'FDL sync started for app on server ' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' owned by user ' . $this->appServerDetails['userName']); } } public function fastDLSync ($fdlConnectString) { if (strlen($fdlConnectString) > 0) { if (substr($fdlConnectString, -1, 1) != '/') { $fdlConnectString .= '/'; } $fdlConnectString .= $this->appServerDetails['template']['shorten'] . '/'; if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'L') { $this->linuxFastDLSync($fdlConnectString); } else if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'W') { } } } private function linuxBackupCreate ($ftpUploadString) { global $resellerLockupID; $backupDir = $this->removeSlashes($this->appServerDetails['homeDir'] .'/' . $this->appServerDetails['userName'] . '/backup/'); $backUpFile = $this->removeSlashes($backupDir . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-$GAMETEMPLATE.tar.bz2'); $serverDir = $this->removeSlashes($this->appServerDetails['homeDir'] .'/' . $this->appServerDetails['userName'] . '/server/'); $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/backup-create-' . $this->appServerDetails['userName'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; $script .= 'if [ ! -d "' . $backupDir . '" ]; then mkdir -p "' . $backupDir . '"; fi' . "\n"; $script .= 'find "' . $serverDir . '" -mindepth 1 -maxdepth 1 -type d | while read FOLDER; do' . "\n"; $script .= 'GAMETEMPLATE=`basename $FOLDER`' . "\n"; $script .= 'if [[ `lsof -f -- "' . $backUpFile . '" 2>/dev/null` ]]; then continue; fi' . "\n"; $script .= 'if [ -f "' . $backUpFile . '" ]; then rm -f "' . $backUpFile . '"; fi' . "\n"; $script .= 'cd "' . $serverDir . '/$GAMETEMPLATE"' . "\n"; $script .= '${IONICE}nice -n +19 tar cfj "' . $backUpFile . '" .' . "\n"; if (strlen($ftpUploadString) > 0) { $script .= 'wput -q --limit-rate=4098 --basename="' . $backupDir . '" "' . $backUpFile . '" "' . $ftpUploadString . '"' . "\n"; } $script .= 'done' . "\n"; $script .= 'wget -q --timeout=60 --no-check-certificate -O - ' . webhostdomain($resellerLockupID) . '/get_password.php?w=bu\\&shorten=`id -un`\\id=' . $this->appServerDetails['port'] . '\\&ip=' . $this->appServerDetails['serverIP'] . "\n"; $this->addLinuxScript($scriptName, $script); $this->addLogline('app_server.log', 'Created backup for apps on server ' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' owned by user ' . $this->appServerDetails['userName']); } public function backupCreate ($ftpUploadString) { if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'L') { $this->linuxBackupCreate($ftpUploadString); } else if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'W') { } } private function linuxBackupDeploy ($template, $ftpDownloadString) { global $resellerLockupID; $backupDir = $this->removeSlashes($this->appServerDetails['homeDir'] . $this->appServerDetails['userName'] . '/backup/'); $serverDir = $this->removeSlashes($this->appServerDetails['homeDir'] . $this->appServerDetails['userName'] . '/server/'); $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/backup-deploy-' . $this->appServerDetails['userName'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; if (strlen($ftpDownloadString) > 0) { $script .= 'if [ ! -d "' . $backupDir . '" ]; then mkdir -p "' . $backupDir . '"; fi' . "\n"; $script .= 'cd ' . $backupDir . "\n"; $script .= 'mv "' . $this->removeSlashes($backupDir . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-' . $template . '.tar.bz2') . '" "' . $this->removeSlashes($backupDir . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-' . $template . '_old.tar.bz2"') . "\n"; $script .= 'wget -q --timeout=10 --no-check-certificate ' . $ftpDownloadString . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-' . $template . '.tar.bz2' . "\n"; $script .= 'if [ -f "' . $this->removeSlashes($backupDir . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-' . $template . '.tar.bz2') . '" ]; then' . "\n"; $script .= 'rm -f "' . $this->removeSlashes($backupDir . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-' . $template . '_old.tar.bz2"') . "\n"; $script .= 'else' . "\n"; $script .= 'mv "' . $this->removeSlashes($backupDir . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-' . $template . '_old.tar.bz2') . '" "' . $this->removeSlashes($backupDir . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-' . $template . '.tar.bz2"') . "\n"; $script .= 'fi' . "\n"; } $script .= 'if [ -f "' . $this->removeSlashes($backupDir . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-' . $template . '.tar.bz2') . '" ]; then' . "\n"; $script .= 'rm -rf ' . $this->removeSlashes($serverDir . '/' . $template . '/*') . "\n"; $script .= 'fi' . "\n"; $script .= 'if [ ! -d "' . $this->removeSlashes($serverDir . '/' . $template) . '" ]; then mkdir -p "' . $this->removeSlashes($serverDir . '/' . $template) . '"; fi' . "\n"; $script .= '${IONICE}nice -n +19 tar -C "' . $this->removeSlashes($serverDir . '/' . $template) . '" -xjf "' . $this->removeSlashes($backupDir . '/' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . '-' . $template . '.tar.bz2"') . "\n"; $script .= 'wget -q --no-check-certificate -O - ' . webhostdomain($resellerLockupID) . '/get_password.php?w=rb\\&shorten=`id -un`\\id=' . $this->appServerDetails['port'] . '\\&ip=' . $this->appServerDetails['serverIP'] . "\n"; $this->addLinuxScript($scriptName, $script); $this->addLogline('app_server.log', 'Deployed backup for app template ' . $template . ' on server ' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' owned by user ' . $this->appServerDetails['userName']); } public function backupDeploy ($template, $ftpDownloadString) { if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'L') { $this->linuxBackupDeploy($template, $ftpDownloadString); } else if ($this->appServerDetails and $this->appMasterServerDetails['os'] == 'W') { } } private function shellCommandLinux($command) { $scriptName = $this->removeSlashes('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/execute-cmd-' . $this->appServerDetails['userNameExecute'] . '-' . $this->appServerDetails['serverIP'] . '-' . $this->appServerDetails['port'] . '.sh'); $screenName = $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port']; $script = $this->shellScriptHeader; $script .= 'rm -f ' . $scriptName . "\n"; $script .= 'screen -S ' . $screenName . ' -X stuff $\'' . $command . '\n\''; $this->addLinuxScript($scriptName, $script); $this->addLogline('app_server.log', 'App console command' . $this->appServerDetails['serverIP'] . '_' . $this->appServerDetails['port'] . ' owned by user ' . $this->appServerDetails['userNameExecute'] . ' executed'); return true; } public function shellCommand($command) { // Linux and Windows deamon are reached via SSH2. if ($this->appMasterServerDetails['os'] == 'L') { return $this->shellCommandLinux($command); } return false; } private function getKeyAndOrPassword () { if ($this->appMasterServerDetails['ssh2Publickey'] != 'N' and file_exists($this->appMasterServerDetails['privateKey'])) { $ssh2Pass = new phpseclib\Crypt\RSA(); if ($this->appMasterServerDetails['ssh2Publickey'] == 'B') { $ssh2Pass->setPassword($this->appMasterServerDetails['ssh2DecryptedPass']); } $ssh2Pass->loadKey(file_get_contents($this->appMasterServerDetails['privateKey'])); } else { $ssh2Pass = $this->appMasterServerDetails['ssh2DecryptedPass']; } return $ssh2Pass; } private function handleFailedConnectAttemps () { global $sql, $resellerLockupID, $rSA; $query = $sql->prepare("UPDATE `rserverdata` SET `notified`=`notified`+1 WHERE `id`=? LIMIT 1"); $query->execute(array($this->appMasterServerDetails['id'])); // While we keep on counting up, the mail is send only once to prevent spam if (($this->appMasterServerDetails['notified'] + 1) == $rSA['down_checks']) { $query = ($resellerLockupID == 0) ? $sql->prepare("SELECT `id`,`mail_serverdown` FROM `userdata` WHERE `resellerid`=0 AND `accounttype`='a'") : $sql->prepare("SELECT `id`,`mail_serverdown` FROM `userdata` WHERE (`id`=${$resellerLockupID} AND `id`=`resellerid`) OR `resellerid`=0 AND `accounttype`='a'"); $query->execute(); while ($row = $query->fetch(PDO::FETCH_ASSOC)) { if ($row['mail_serverdown'] == 'Y') { sendmail('emaildown', $row['id'], $this->appMasterServerDetails['ssh2IP'], ''); } } } } private function executeLinux () { if (strlen($this->shellScripts['user']) > 0 or count($this->shellScripts['server']) > 0) { $sftpObject = new phpseclib\Net\SFTP($this->appMasterServerDetails['ssh2IP'], $this->appMasterServerDetails['ssh2Port']); $ssh2Pass = $this->getKeyAndOrPassword(); $loginReturn = $sftpObject->login($this->appMasterServerDetails['ssh2User'], $ssh2Pass); if ($loginReturn) { $this->commandReturns[] = $sftpObject->put('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/userCud-' . $this->uniqueHex . '.sh', $this->shellScripts['user']); $this->commandReturns[] = $sftpObject->chmod(0700, '/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/userCud-' . $this->uniqueHex . '.sh'); foreach($this->shellScripts['server'] as $fileName => $scriptContent) { $this->commandReturns[] = 'script added: ' . $fileName; $this->commandReturns[] = $sftpObject->put($fileName, $scriptContent); } // Files have been created, now login with SSH2 and execute the gobal script $sshObject = new phpseclib\Net\SSH2($this->appMasterServerDetails['ssh2IP'], $this->appMasterServerDetails['ssh2Port']); if ($sshObject->login($this->appMasterServerDetails['ssh2User'], $ssh2Pass)) { $this->commandReturns[] = $sshObject->exec('/home/' . $this->appMasterServerDetails['ssh2User'] . '/temp/userCud-' . $this->uniqueHex . '.sh & '); } return true; } $this->handleFailedConnectAttemps(); } return false; } public function execute () { // Linux and Windows deamon are reached via SSH2. if ($this->appMasterServerDetails['os'] == 'L') { return $this->executeLinux(); // create the script in server array // run the user script which than will execute the other scripts } return false; } public function debug() { if ($this->appMasterServerDetails['os'] == 'L') { return array($this->shellScripts['user'], implode("\r\n", $this->shellScripts['server']), implode("\r\n", $this->commandReturns)); } if ($this->appMasterServerDetails['os'] == 'W') { return array(implode("\r\n", $this->winCmds), implode("\r\n", $this->commandReturns)); } return array(); } function __destruct() { } }