diff --git a/.deployed-at b/.deployed-at deleted file mode 100644 index 74848ff4..00000000 --- a/.deployed-at +++ /dev/null @@ -1 +0,0 @@ -2025-08-29 15:39:12 UTC diff --git a/.gitignore b/.gitignore deleted file mode 100644 index d47b65cd..00000000 --- a/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -*.log -*.tmp -cache/ -tmp/ -sessions/ -*.tar -*.tar.gz -*.zip -*.bak -node_modules/ -vendor/*/cache/ -.env -.env.* -config.local.php -!_agent-linux/** -!_agent-windows/** diff --git a/.google.html.swp b/.google.html.swp deleted file mode 100644 index 26188999..00000000 Binary files a/.google.html.swp and /dev/null differ diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index 182cbf55..00000000 --- a/IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,117 +0,0 @@ -# OGP Agent Resource Stats Integration - Implementation Complete - -## Summary - -Successfully integrated the standalone Python collector.py functionality directly into the OGP agents, removing external dependencies and simplifying deployment. - -## What Was Implemented - -### 1. Database Configuration -- Added database connection parameters to both Linux and Windows agent config files -- Configurable collection frequency (default: 5 minutes) -- Uses same database schema as original collector.py - -### 2. Resource Collection System -- **Machine-wide metrics:** CPU, memory, disk, network, load averages -- **Process-specific metrics:** Per-game-server process monitoring -- **Platform-specific implementations:** Linux (proc filesystem) and Windows (wmic) - -### 3. Automatic Scheduling -- Integrated into existing agent scheduler system -- No external cron jobs required -- Starts/stops with agent automatically - -### 4. Process Detection -- Scans agent directory for server subdirectories -- Associates running processes with server directories -- Collects detailed process metrics (memory, I/O, ports, etc.) - -## Benefits Achieved - -✅ **Removed Python Dependencies** -- No more psutil requirement -- No more mysql-connector-python requirement -- Pure Perl implementation using native system tools - -✅ **Simplified Deployment** -- No separate cron job setup needed -- Configuration through existing agent config files -- Automatic startup with agent - -✅ **Maintained Compatibility** -- Uses identical database schema -- Produces same data format as collector.py -- Existing dashboards continue to work unchanged - -✅ **Cross-Platform Support** -- Linux implementation using /proc filesystem -- Windows implementation using wmic and native commands -- Platform-specific optimizations - -## Files Modified - -### Linux Agent -- `_agent-linux/Cfg/Config.pm` - Added database configuration -- `_agent-linux/ogp_agent.pl` - Added resource collection system - -### Windows Agent -- `_agent-windows/Cfg/Config.pm` - Added database configuration -- `_agent-windows/ogp_agent.pl` - Added resource collection system - -## Database Tables Used -- `gsp_machines` - Machine catalog -- `gsp_machine_samples` - System-wide metrics -- `gsp_process_samples` - Per-process metrics - -## Configuration Required - -### 1. Install Perl Database Modules -```bash -# Ubuntu/Debian -sudo apt-get install libdbi-perl libdbd-mysql-perl - -# CentOS/RHEL -sudo yum install perl-DBI perl-DBD-MySQL -``` - -### 2. Update Agent Configuration -Add to both `_agent-linux/Cfg/Config.pm` and `_agent-windows/Cfg/Config.pm`: - -```perl -# Resource stats database configuration -stats_db_host => 'your_mysql_host', -stats_db_user => 'your_db_user', -stats_db_pass => 'your_db_password', -stats_db_name => 'your_panel_database', -stats_table_prefix => 'gsp_', -stats_frequency_minutes => '5', -``` - -### 3. Create Database Tables -Run the SQL schema from `modules/resource_stats/mysql_query.sql` - -### 4. Restart OGP Agents -The resource collection will start automatically with the agents. - -## Migration Steps - -1. **Stop existing collector.py cron jobs** -2. **Install required Perl modules** on agent machines -3. **Update agent configurations** with database details -4. **Restart OGP agents** -5. **Verify data collection** in database -6. **Remove collector.py and Python dependencies** - -## Validation - -The implementation has been tested and verified: -- ✅ Both Linux and Windows agents compile without errors -- ✅ Database connectivity works correctly -- ✅ Data insertion functions properly -- ✅ System resource collection functions work -- ✅ Process detection logic functions -- ✅ Scheduler integration is successful - -## Result - -The OGP agents now include fully integrated resource monitoring that replaces the standalone Python collector.py script while maintaining complete compatibility with existing systems and dashboards. \ No newline at end of file diff --git a/MYSQL_AUTO_CREATE_README.md b/MYSQL_AUTO_CREATE_README.md deleted file mode 100644 index 908b0d49..00000000 --- a/MYSQL_AUTO_CREATE_README.md +++ /dev/null @@ -1,56 +0,0 @@ -# MySQL Auto-Create Feature - -This feature automatically creates MySQL databases for each new game server created through the billing system. - -## Required Settings - -Add the following settings to your OGP settings table to enable MySQL auto-creation: - -### Required Settings: -- `mysql_auto_create` - Set to '1' to enable, '0' to disable -- `mysql_root_user` - MySQL root username for creating databases (e.g., 'remoteuser') -- `mysql_root_password` - MySQL root password -- `mysql_host` - MySQL server hostname (e.g., 'mysql.iaregamer.com') - -### Optional Settings: -- `mysql_port` - MySQL server port (defaults to '3306' if not set) -- `mysql_special_user` - Additional user to grant access (like 'dayzhivemind' in original script) -- `mysql_special_password` - Password for the special user -- `mysql_init_sql_file` - Path to SQL file to import into new databases (e.g., '1.9.0_fresh.sql') -- `mysql_default_server_id` - MySQL server ID from mysql_servers table to track databases in OGP - -## How it works: - -1. When a new server is created, the system generates: - - Database name: `server_` (e.g., `server_1745`) - - Database user: Same as database name (e.g., `server_1745`) - - Random 12-character password - -2. The system creates the database and grants privileges: - - Full privileges to the database user from localhost and any host (%) - - If mysql_special_user is set, grants full privileges to that user too - - Flushes privileges - -3. If mysql_init_sql_file is specified, imports that SQL file into the new database - -4. If mysql_default_server_id is set, adds the database to OGP's mysql_databases table for tracking - -## Example Settings SQL: - -```sql -INSERT INTO ogp_settings (setting, value) VALUES ('mysql_auto_create', '1'); -INSERT INTO ogp_settings (setting, value) VALUES ('mysql_root_user', 'remoteuser'); -INSERT INTO ogp_settings (setting, value) VALUES ('mysql_root_password', 'Pkloyn7yvpht!'); -INSERT INTO ogp_settings (setting, value) VALUES ('mysql_host', 'mysql.iaregamer.com'); -INSERT INTO ogp_settings (setting, value) VALUES ('mysql_port', '3306'); -INSERT INTO ogp_settings (setting, value) VALUES ('mysql_special_user', 'dayzhivemind'); -INSERT INTO ogp_settings (setting, value) VALUES ('mysql_special_password', 'Pkloyn7yvpht!'); -INSERT INTO ogp_settings (setting, value) VALUES ('mysql_init_sql_file', '/path/to/1.9.0_fresh.sql'); -INSERT INTO ogp_settings (setting, value) VALUES ('mysql_default_server_id', '1'); -``` - -## Logging - -The system logs MySQL database creation events: -- Success: "MYSQL DB CREATED - Database server_ created for server " -- Failure: "MYSQL DB CREATION FAILED - " \ No newline at end of file diff --git a/README.md b/README.md index fa941461..20f1000f 100644 --- a/README.md +++ b/README.md @@ -1,212 +1,22 @@ -# GameServerPanel (GSP) - Unstable Branch +# OGP-AdminLTE +AdminLTE Theme adapted for OpenGamePanel -This is the **GameServerPanel (GSP)** project, a cross-platform game server management panel and agent system. +### Features +- [x] Installs a Theme Database for User specific Theme Settings +- [x] Responsive +- [x] Dark and Light Mode Switcher +- [x] Custom Dashboard with additional Rows (all Boxes are movable!) +- [x] Custom Server Overview (with Chart & Cronjob) +- [x] Custom FTP Style +- [x] Custom Shop Style +- [x] User specific Avatars (will also load other User Avatars if needed) +- [x] Maintenance Notification on Login Screen +- [x] Custom Logo Upload -This README covers installation and setup for: -- **The Web Panel** -- **The Linux Agent** -- **The Windows Agent** - ---- - -## Table of Contents - -- [Prerequisites](#prerequisites) -- [Panel Installation (Linux)](#panel-installation-linux) -- [Agent Installation (Linux)](#agent-installation-linux) -- [Agent Installation (Windows)](#agent-installation-windows) -- [Example Installation Scripts](#example-installation-scripts) -- [Troubleshooting](#troubleshooting) -- [Contributing](#contributing) - ---- - -## Prerequisites - -### General - -- **Git** -- **curl/wget** -- **Sudo/root privileges** - -### Panel (Linux) - -- **Ubuntu 22.04+** (other distros may work) -- **Apache2** or **nginx** -- **PHP 8.1+** -- **MariaDB** or **MySQL** -- **Required PHP extensions**: - `php-mysqli php-json php-curl php-xml php-zip php-gd php-mbstring php-bcmath php-intl php-pdo php-cli` -- **Composer** (for PHP dependency management) - -### Linux Agent - -- **Ubuntu 22.04+** (other distros may work) -- **Perl 5** -- **Perl modules**: - `Proc::ProcessTable`, `IO::Socket`, `DBI`, `Sys::Hostname`, `LWP::UserAgent`, `JSON`, `File::Path` -- **Screen** (for game server management) - -### Windows Agent - -- **Windows 10/11/Server** -- **Strawberry Perl** (or ActivePerl) -- **Perl modules**: - Same as Linux agent (`Proc::ProcessTable`, etc.) -- **Run agent as Administrator** for full functionality - ---- - -## Panel Installation (Linux) - -1. **Install prerequisites:** - - ```bash - sudo apt update - sudo apt install apache2 mariadb-server php php-mysqli php-json php-curl php-xml php-zip php-gd php-mbstring php-bcmath php-intl php-pdo php-cli composer git unzip - ``` - -2. **Clone the repository:** - - ```bash - git clone -b unstable https://github.com/GameServerPanel/GSP.git - cd GSP/ControlPanel - ``` - -3. **Install PHP dependencies:** - - ```bash - composer install - ``` - -4. **Set permissions:** - - ```bash - sudo chown -R www-data:www-data . - sudo chmod -R 755 . - ``` - -5. **Configure Apache/nginx:** - - Point your DocumentRoot to `GSP/ControlPanel/public` - - Restart your webserver. - -6. **Configure the Panel:** - - Open the panel in your browser - - Follow setup wizard (enter database details, admin account, etc.) - ---- - -## Agent Installation (Linux) - -1. **Install prerequisites:** - - ```bash - sudo apt update - sudo apt install perl build-essential screen libproc-processtable-perl libio-socket-perl libdbi-perl libsys-hostname-perl libwww-perl libjson-perl libfile-path-perl - ``` - -2. **Clone the agent:** - - ```bash - git clone -b unstable https://github.com/GameServerPanel/GSP.git - cd GSP/Agent - ``` - -3. **Run the agent:** - - ```bash - perl ogp_agent.pl - ``` - -> If `libproc-process-table-perl` is not available on your distro, install via CPAN: -> -> ```bash -> sudo apt install cpanminus -> sudo cpanm Proc::ProcessTable -> ``` - ---- - -## Agent Installation (Windows) - -1. **Install [Strawberry Perl](https://strawberryperl.com/)** -2. **Open Command Prompt as Administrator** - -3. **Install required Perl modules:** - - ```shell - cpan install Proc::ProcessTable IO::Socket DBI Sys::Hostname LWP::UserAgent JSON File::Path - ``` - -4. **Clone the repository or download the Agent folder** -5. **Run the agent:** - - ```shell - perl ogp_agent.pl - ``` - ---- - -## Example Installation Scripts - -### Linux Agent Quick Install - -```bash -#!/bin/bash -sudo apt update -sudo apt install -y perl build-essential screen git \ - libproc-processtable-perl libio-socket-perl libdbi-perl \ - libsys-hostname-perl libwww-perl libjson-perl libfile-path-perl -git clone -b unstable https://github.com/GameServerPanel/GSP.git -cd GSP/Agent -perl ogp_agent.pl -``` - -### Panel Quick Install - -```bash -#!/bin/bash -sudo apt update -sudo apt install -y apache2 mariadb-server php php-mysqli php-json php-curl php-xml php-zip php-gd php-mbstring php-bcmath php-intl php-pdo php-cli composer git unzip -git clone -b unstable https://github.com/GameServerPanel/GSP.git -cd GSP/ControlPanel -composer install -sudo chown -R www-data:www-data . -sudo chmod -R 755 . -# Configure your web server to point to GSP/ControlPanel/public -``` - ---- - -## Troubleshooting - -- **Missing Perl modules:** - Use `cpanm` or `cpan` to install missing modules. - -- **libproc-process-table-perl not found:** - Install via CPAN (`cpanm Proc::ProcessTable`) - -- **Web panel not loading:** - Check Apache/nginx logs, file permissions, and PHP modules. - -- **Agent cannot communicate with panel:** - Check firewall settings and agent config. - ---- - -## Contributing - -- Fork the repository -- Create a feature branch -- Make your changes -- Submit a pull request - ---- - -## License - -See `LICENSE` file in the repository. - ---- - -**For detailed help or bug reports, open an issue on [GitHub](https://github.com/GameServerPanel/GSP/issues).** \ No newline at end of file +### Images +![This is an image](../main/adminlte_dark.png) +![This is an image](../main/adminlte_light.png) +![This is an image](../main/adminlte_online-servers.png) +![This is an image](../main/adminlte_shop.png) +![This is an image](../main/adminlte_maintenance.png) +![This is an image](../main/adminlte_support_chat.png) diff --git a/README.txt b/README.txt new file mode 100644 index 00000000..f71174a8 --- /dev/null +++ b/README.txt @@ -0,0 +1,25 @@ +Hi guys! + +EXIM as smarthost is only needed for hosts with dynamically assigned IP because it avoids to be blocked by some mail servers like hotmail. + +Upload all files. + +Login with ssh and change to the user 'www-data'(in ubuntu) or 'apache'(in centos) or any other user that manages the apache server with, for example: + +sudo su - www-data + +Now edit the cron tab for this user + +crontab -e + +and copy this line at the end of the file and save it (WARNING:modify it with the correct path): + +*/1 * * * * php /var/www/html/ogp/modules/billing/cron-shop.php + +Now this script searches for expired game homes every minute, and wil stop and remove them if they are expired. +If you would like to do this at midnight every day instead of every minute you should use + +0 0 * * * php /var/www/html/ogp/modules/billing/cron-shop.php + +TIP: Searching in google, for example, "cron every month" you will find the correct code to search expired homes and remove them every month. + diff --git a/RESOURCE_STATS_README.md b/RESOURCE_STATS_README.md deleted file mode 100644 index 65db1061..00000000 --- a/RESOURCE_STATS_README.md +++ /dev/null @@ -1,201 +0,0 @@ -# OGP Agent Resource Stats Collection - -This document describes the integrated resource statistics collection system in the OGP agents that replaces the standalone Python collector.py script. - -## Overview - -The OGP agents now include built-in resource monitoring that collects: -- **Machine-wide statistics:** CPU usage, memory, disk space, network activity, load averages -- **Per-server process statistics:** Memory usage, CPU usage, I/O statistics, listening ports, folder sizes - -Data is automatically inserted into the same MySQL database tables used by the web panel for display. - -## Configuration - -### Database Configuration - -Update the agent configuration files with your database connection details: - -**Linux Agent:** `_agent-linux/Cfg/Config.pm` -**Windows Agent:** `_agent-windows/Cfg/Config.pm` - -```perl -# Resource stats database configuration -stats_db_host => '127.0.0.1', # Database server hostname/IP -stats_db_user => 'panel_user', # Database username -stats_db_pass => 'your_password_here', # Database password -stats_db_name => 'panel_database', # Database name (same as your web panel) -stats_table_prefix => 'gsp_', # Table prefix (must match collector.py) -stats_frequency_minutes => '5', # Collection frequency in minutes -``` - -### Database Tables - -The system uses the same database tables as the original collector.py: - -```sql --- Machine catalog -gsp_machines - --- Machine-wide samples (CPU, memory, disk, network) -gsp_machine_samples - --- Per-process/per-server samples -gsp_process_samples -``` - -Run the SQL schema from `modules/resource_stats/mysql_query.sql` to create these tables if they don't exist. - -### Required Perl Modules - -The agents require these Perl modules for database connectivity: - -```bash -# Ubuntu/Debian -sudo apt-get install libdbi-perl libdbd-mysql-perl - -# CentOS/RHEL -sudo yum install perl-DBI perl-DBD-MySQL - -# Or via CPAN -cpan DBI DBD::mysql -``` - -## Features - -### Automatic Integration -- Runs automatically as part of the agent scheduler -- No separate cron jobs required -- Starts when the agent starts -- Stops when the agent stops - -### Platform Support - -**Linux Agent:** -- Uses `/proc` filesystem for system stats -- Native command-line tools (`df`, `netstat`, etc.) -- Full CPU, memory, disk, and network monitoring -- Process association via working directory and command line analysis - -**Windows Agent:** -- Uses `wmic` for system information -- Native Windows commands (`dir`, `netstat`) -- CPU, memory, disk monitoring (no load averages on Windows) -- Process association via executable path and command line analysis - -### Process Detection - -The system automatically detects game server processes by: -1. Scanning for subdirectories in the agent directory -2. Finding processes whose working directory, executable path, or command line references these directories -3. Collecting detailed metrics for each associated process - -### Data Collection - -**Machine-wide metrics:** -- Load averages (Linux only) -- CPU percentage -- Memory usage (used/total/percentage) -- Swap usage -- Disk usage for agent directory -- Network interface statistics -- Network throughput - -**Process-specific metrics:** -- Process ID and name -- Command line -- CPU percentage -- Memory usage (RSS/VMS) -- I/O statistics (read/write bytes) -- Open file descriptors -- Listening network ports -- Server directory size - -## Monitoring and Troubleshooting - -### Log Messages - -The agent logs resource collection activity: - -``` -Starting resource stats collection -Resource stats collection completed -``` - -### Error Handling - -If database modules are not available: -``` -DBD::mysql not available - resource stats collection disabled -``` - -If database connection fails: -``` -Failed to connect to stats database: [error details] -``` - -### Verification - -To verify the system is working: - -1. Check agent logs for collection messages -2. Query the database tables: - ```sql - SELECT COUNT(*) FROM gsp_machine_samples WHERE ts >= NOW() - INTERVAL 1 HOUR; - SELECT COUNT(*) FROM gsp_process_samples WHERE ts >= NOW() - INTERVAL 1 HOUR; - ``` - -### Performance Impact - -- Collection runs every 5 minutes by default (configurable) -- Minimal performance overhead during collection -- Uses native system tools for maximum efficiency -- Database operations are optimized with prepared statements - -## Migration from collector.py - -To migrate from the standalone Python collector: - -1. **Stop the cron job** running collector.py -2. **Install Perl database modules** on agent machines -3. **Update agent configuration** with database details -4. **Restart OGP agents** to enable collection -5. **Verify data collection** is working -6. **Remove collector.py and Python dependencies** - -The new system produces identical data to collector.py and uses the same database schema, so existing dashboards and reports will continue to work without changes. - -## Frequency Configuration - -The collection frequency can be adjusted by changing `stats_frequency_minutes` in the config: - -- `stats_frequency_minutes => '1'` - Every minute (high frequency) -- `stats_frequency_minutes => '5'` - Every 5 minutes (default) -- `stats_frequency_minutes => '15'` - Every 15 minutes (low frequency) - -Note: Very high frequencies (every minute) may impact performance on busy servers. - -## Security Considerations - -- Database credentials are stored in agent configuration files -- Use dedicated database user with minimal privileges -- Consider firewall rules if database is on separate server -- Monitor database connections and prevent connection leaks - -## Troubleshooting Common Issues - -**Collection not working:** -1. Check if DBD::mysql is installed -2. Verify database connection details -3. Check database user permissions -4. Review agent logs for error messages - -**Missing process data:** -1. Verify game servers are running from subdirectories -2. Check process detection logic matches your server layout -3. Review process association in agent logs - -**Performance issues:** -1. Reduce collection frequency -2. Check database performance -3. Monitor agent resource usage during collection \ No newline at end of file diff --git a/_agent-linux/ogp_agent.pl b/_agent-linux/ogp_agent.pl deleted file mode 100644 index eedcc03f..00000000 --- a/_agent-linux/ogp_agent.pl +++ /dev/null @@ -1,5181 +0,0 @@ -#!/usr/bin/perl -# -# OGP - Open Game Panel -# Copyright (C) 2008 - 2018 The OGP Development Team -# -# http://www.opengamepanel.org/ -# -# This program 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 2 -# of the License, or any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# - -use warnings; -use strict; - -use Cwd; # Fast way to get the current directory -use lib getcwd(); -use Frontier::Daemon::OGP::Forking; # Forking XML-RPC server -use File::Copy; # Simple file copy functions -use File::Copy::Recursive - qw(fcopy rcopy dircopy fmove rmove dirmove pathempty pathrmdir) - ; # Used to copy whole directories -use File::Basename; # Used to get the file name or the directory name from a given path -use Crypt::XXTEA; # Encryption between webpages and agent. -use Cfg::Config; # Config file -use Cfg::Preferences; # Preferences file -use Fcntl ':flock'; # Import LOCK_* constants for file locking -use LWP::UserAgent; # Used for fetching URLs -use MIME::Base64; # Used to ensure data travelling right through the network. -use Getopt::Long; # Used for command line params. -use Path::Class::File; # Used to handle files and directories. -use File::Path qw(mkpath); -use Archive::Extract; # Used to handle archived files. -use File::Find; -use Schedule::Cron; # Used for scheduling tasks - -# Compression tools -use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error); # Used to compress files to bz2. -use Compress::Zlib; # Used to compress file download buffers to zlib. -use Archive::Tar; # Used to create tar, tgz or tbz archives. -use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); # Used to create zip archives. - -# Database modules for resource stats -use DBI; # Database interface -eval "use DBD::mysql"; # MySQL driver (optional, will skip stats if not available) - -# Current location of the agent. -use constant AGENT_RUN_DIR => getcwd(); - -# Load our config file values -use constant AGENT_KEY => $Cfg::Config{key}; -use constant AGENT_IP => $Cfg::Config{listen_ip}; -use constant AGENT_LOG_FILE => $Cfg::Config{logfile}; -use constant AGENT_PORT => $Cfg::Config{listen_port}; -use constant AGENT_VERSION => $Cfg::Config{version}; -use constant WEB_ADMIN_API_KEY => $Cfg::Config{web_admin_api_key}; -use constant WEB_API_URL => $Cfg::Config{web_api_url}; -use constant STEAM_DL_LIMIT => $Cfg::Config{steam_dl_limit}; -use constant SCREEN_LOG_LOCAL => $Cfg::Preferences{screen_log_local}; -use constant DELETE_LOGS_AFTER => $Cfg::Preferences{delete_logs_after}; -use constant LINUX_USER_PER_GAME_SERVER => $Cfg::Preferences{linux_user_per_game_server}; -use constant AGENT_PID_FILE => - Path::Class::File->new(AGENT_RUN_DIR, 'ogp_agent.pid'); -use constant AGENT_RSYNC_GENERIC_LOG => - Path::Class::File->new(AGENT_RUN_DIR, 'rsync_update_generic.log'); -use constant STEAM_LICENSE_OK => "Accept"; -use constant STEAM_LICENSE => $Cfg::Config{steam_license}; -use constant MANUAL_TMP_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'tmp'); -use constant SHARED_GAME_TMP_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'shared'); -use constant STEAMCMD_CLIENT_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'steamcmd'); -use constant STEAMCMD_CLIENT_BIN => - Path::Class::File->new(STEAMCMD_CLIENT_DIR, 'steamcmd.sh'); -use constant SCREEN_LOGS_DIR => - Path::Class::Dir->new(AGENT_RUN_DIR, 'screenlogs'); -use constant GAME_STARTUP_DIR => - Path::Class::Dir->new(AGENT_RUN_DIR, 'startups'); -use constant SCREENRC_FILE => - Path::Class::File->new(AGENT_RUN_DIR, 'ogp_screenrc'); -use constant SCREENRC_FILE_BK => - Path::Class::File->new(AGENT_RUN_DIR, 'ogp_screenrc_bk'); -use constant SCREENRC_TMP_FILE => - Path::Class::File->new(AGENT_RUN_DIR, 'ogp_screenrc.tmp'); -use constant SCREEN_TYPE_HOME => "HOME"; -use constant SCREEN_TYPE_UPDATE => "UPDATE"; -use constant SERVER_RUNNER_USER => "ogp_server_runner"; -use constant FD_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'FastDownload'); -use constant FD_ALIASES_DIR => Path::Class::Dir->new(FD_DIR, 'aliases'); -use constant FD_PID_FILE => Path::Class::File->new(FD_DIR, 'fd.pid'); -use constant SCHED_PID => Path::Class::File->new(AGENT_RUN_DIR, 'scheduler.pid'); -use constant SCHED_TASKS => Path::Class::File->new(AGENT_RUN_DIR, 'scheduler.tasks'); -use constant SCHED_LOG_FILE => Path::Class::File->new(AGENT_RUN_DIR, 'scheduler.log'); - -# Resource stats database constants -use constant STATS_DB_HOST => $Cfg::Config{stats_db_host}; -use constant STATS_DB_USER => $Cfg::Config{stats_db_user}; -use constant STATS_DB_PASS => $Cfg::Config{stats_db_pass}; -use constant STATS_DB_NAME => $Cfg::Config{stats_db_name}; -use constant STATS_TABLE_PREFIX => $Cfg::Config{stats_table_prefix}; -use constant STATS_FREQUENCY_MINUTES => $Cfg::Config{stats_frequency_minutes}; - -$Cfg::Config{sudo_password} =~ s/('+)/'\"$1\"'/g; -our $SUDOPASSWD = $Cfg::Config{sudo_password}; -my $no_startups = 0; -my $clear_startups = 0; -our $log_std_out = 0; - -GetOptions( - 'no-startups' => \$no_startups, - 'clear-startups' => \$clear_startups, - 'log-stdout' => \$log_std_out - ); - -# Starting the agent as root user is not supported anymore. -if ($< == 0) -{ - print "ERROR: You are trying to start the agent as root user."; - print "This is not currently supported. If you wish to start the"; - print "you need to create a normal user account for it."; - exit 1; -} - -### Logger function. -### @param line the line that is put to the log file. -sub logger -{ - my $logcmd = $_[0]; - my $also_print = 0; - - if (@_ == 2) - { - ($also_print) = $_[1]; - } - - $logcmd = localtime() . " $logcmd\n"; - - if ($log_std_out == 1) - { - print "$logcmd"; - return; - } - if ($also_print == 1) - { - print "$logcmd"; - } - - open(LOGFILE, '>>', AGENT_LOG_FILE) - or die("Can't open " . AGENT_LOG_FILE . " - $!"); - flock(LOGFILE, LOCK_EX) or die("Failed to lock log file."); - seek(LOGFILE, 0, 2) or die("Failed to seek to end of file."); - print LOGFILE "$logcmd" or die("Failed to write to log file."); - flock(LOGFILE, LOCK_UN) or die("Failed to unlock log file."); - close(LOGFILE) or die("Failed to close log file."); -} - -# Rotate the log file -if (-e AGENT_LOG_FILE) -{ - if (-e AGENT_LOG_FILE . ".bak") - { - unlink(AGENT_LOG_FILE . ".bak"); - } - logger "Rotating log file"; - move(AGENT_LOG_FILE, AGENT_LOG_FILE . ".bak"); - logger "New log file created"; -} - -# If for some reason the screenrc file doesn't exist, restore it from the backup copy -# I've seen this happen a few times -if (! -e SCREENRC_FILE) -{ - copy(SCREENRC_FILE_BK,SCREENRC_FILE); -} - -open INPUTFILE, "<", SCREENRC_FILE or die $!; -open OUTPUTFILE, ">", SCREENRC_TMP_FILE or die $!; -my $dest = SCREEN_LOGS_DIR . "/screenlog.%t"; -while () -{ - $_ =~ s/logfile.*/logfile $dest/g; - print OUTPUTFILE $_; -} -close INPUTFILE; -close OUTPUTFILE; -unlink SCREENRC_FILE; -move(SCREENRC_TMP_FILE,SCREENRC_FILE); - -# Check the screen logs folder -if (!-d SCREEN_LOGS_DIR && !mkdir SCREEN_LOGS_DIR) -{ - logger "Could not create " . SCREEN_LOGS_DIR . " directory $!.", 1; - exit -1; -} - -if ( ! chmod 0777, SCREEN_LOGS_DIR ){ - logger "Could not chmod 777 " . SCREEN_LOGS_DIR . " directory $!.", 1; - exit -1; -} - -my $groupCommandScreenLogs = "chmod -Rf g-s '" . SCREEN_LOGS_DIR . "'"; -sudo_exec_without_decrypt($groupCommandScreenLogs); - -$groupCommandScreenLogs = "find '" . SCREEN_LOGS_DIR . "' -type d | xargs chmod g+s"; -sudo_exec_without_decrypt($groupCommandScreenLogs); - -$groupCommandScreenLogs = "find '" . SCREEN_LOGS_DIR . "' -type d | xargs setfacl -d -m u::rwX,g::rwX,o::-"; -sudo_exec_without_decrypt($groupCommandScreenLogs); - -# Check the global shared games folder -if (!-d SHARED_GAME_TMP_DIR && !mkdir SHARED_GAME_TMP_DIR) -{ - logger "Could not create " . SHARED_GAME_TMP_DIR . " directory $!.", 1; - exit -1; -} - -if (check_steam_cmd_client() == -1) -{ - print "ERROR: You must download and uncompress the new steamcmd package."; - print "BE SURE TO INSTALL IT IN " . AGENT_RUN_DIR . "/steamcmd directory,"; - print "so it can be managed by the agent to install servers."; - exit 1; -} - -# create the directory for startup flags -if (!-e GAME_STARTUP_DIR) -{ - logger "Creating the startups directory " . GAME_STARTUP_DIR . ""; - if (!mkdir GAME_STARTUP_DIR) - { - my $message = - "Failed to create the " - . GAME_STARTUP_DIR - . " directory - check permissions. Errno: $!"; - logger $message, 1; - exit 1; - } -} -elsif ($clear_startups) -{ - opendir(STARTUPDIR, GAME_STARTUP_DIR); - while (my $startup_file = readdir(STARTUPDIR)) - { - - # Skip . and .. - next if $startup_file =~ /^\./; - $startup_file = Path::Class::File->new(GAME_STARTUP_DIR, $startup_file); - logger "Removing " . $startup_file . "."; - unlink($startup_file); - } - closedir(STARTUPDIR); -} -# If the directory already existed check if we need to start some games. -elsif ($no_startups != 1) -{ - - # Loop through all the startup flags, and call universal startup - opendir(STARTUPDIR, GAME_STARTUP_DIR); - logger "Reading startup flags from " . GAME_STARTUP_DIR . ""; - while (my $dirlist = readdir(STARTUPDIR)) - { - - # Skip . and .. - next if $dirlist =~ /^\./; - logger "Found $dirlist"; - open(STARTFILE, '<', Path::Class::Dir->new(GAME_STARTUP_DIR, $dirlist)) - || logger "Error opening start flag $!"; - while () - { - my ( - $home_id, $home_path, $server_exe, - $run_dir, $startup_cmd, $server_port, - $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log - ) = split(',', $_); - - if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == - 1) - { - logger - "This server ($server_exe on $server_ip : $server_port) is already running (ID: $home_id)."; - next; - } - - logger "Starting server_exe $server_exe from home $home_path."; - universal_start_without_decrypt( - $home_id, $home_path, $server_exe, - $run_dir, $startup_cmd, $server_port, - $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log - ); - } - close(STARTFILE); - } - closedir(STARTUPDIR); -} - -# Create the pid file -open(PID, '>', AGENT_PID_FILE) - or die("Can't write to pid file - " . AGENT_PID_FILE . "\n"); -print PID "$$\n"; -close(PID); - -logger "Open Game Panel - Agent started - " - . AGENT_VERSION - . " - port " - . AGENT_PORT - . " - PID $$", 1; - -# Stop previous scheduler process if exists -scheduler_stop(); -# Create new object with default dispatcher for scheduled tasks -my $cron = new Schedule::Cron( \&scheduler_dispatcher, { - nofork => 1, - loglevel => 0, - log => sub { print $_[1], "\n"; } - } ); - -$cron->add_entry( "* * * * * *", \&scheduler_read_tasks ); - -# Add resource stats collection task -my $stats_frequency = STATS_FREQUENCY_MINUTES || 5; -my $stats_cron_pattern = "*/$stats_frequency * * * *"; # Every N minutes -$cron->add_entry( $stats_cron_pattern, \&collect_resource_stats ); - -# Run scheduler -$cron->run( {detach=>1, pid_file=>SCHED_PID} ); - -if(-e Path::Class::File->new(FD_DIR, 'Settings.pm')) -{ - require "FastDownload/Settings.pm"; # Settings for Fast Download Daemon. - if(defined($FastDownload::Settings{autostart_on_agent_startup}) && $FastDownload::Settings{autostart_on_agent_startup} eq "1") - { - start_fastdl(); - } -} - -my $d = Frontier::Daemon::OGP::Forking->new( - methods => { - is_screen_running => \&is_screen_running, - universal_start => \&universal_start, - renice_process => \&renice_process, - cpu_count => \&cpu_count, - rfile_exists => \&rfile_exists, - quick_chk => \&quick_chk, - steam_cmd => \&steam_cmd, - fetch_steam_version => \&fetch_steam_version, - installed_steam_version => \&installed_steam_version, - automatic_steam_update => \&automatic_steam_update, - get_log => \&get_log, - stop_server => \&stop_server, - send_rcon_command => \&send_rcon_command, - dirlist => \&dirlist, - dirlistfm => \&dirlistfm, - readfile => \&readfile, - writefile => \&writefile, - rebootnow => \&rebootnow, - what_os => \&what_os, - start_file_download => \&start_file_download, - lock_additional_files => \&lock_additional_files, - is_file_download_in_progress => \&is_file_download_in_progress, - uncompress_file => \&uncompress_file, - discover_ips => \&discover_ips, - mon_stats => \&mon_stats, - exec => \&exec, - clone_home => \&clone_home, - remove_home => \&remove_home, - start_rsync_install => \&start_rsync_install, - rsync_progress => \&rsync_progress, - restart_server => \&restart_server, - sudo_exec => \&sudo_exec, - master_server_update => \&master_server_update, - secure_path => \&secure_path, - get_chattr => \&get_chattr, - ftp_mgr => \&ftp_mgr, - compress_files => \&compress_files, - stop_fastdl => \&stop_fastdl, - restart_fastdl => \&restart_fastdl, - fastdl_status => \&fastdl_status, - fastdl_get_aliases => \&fastdl_get_aliases, - fastdl_add_alias => \&fastdl_add_alias, - fastdl_del_alias => \&fastdl_del_alias, - fastdl_get_info => \&fastdl_get_info, - fastdl_create_config => \&fastdl_create_config, - agent_restart => \&agent_restart, - scheduler_add_task => \&scheduler_add_task, - scheduler_del_task => \&scheduler_del_task, - scheduler_list_tasks => \&scheduler_list_tasks, - scheduler_edit_task => \&scheduler_edit_task, - get_file_part => \&get_file_part, - stop_update => \&stop_update, - shell_action => \&shell_action, - remote_query => \&remote_query, - send_steam_guard_code => \&send_steam_guard_code, - steam_workshop => \&steam_workshop, - get_workshop_mods_info => \&get_workshop_mods_info - }, - debug => 4, - LocalPort => AGENT_PORT, - LocalAddr => AGENT_IP, - ReuseAddr => '1' -) or die "Couldn't start OGP Agent: $!"; - -sub backup_home_log -{ - my ($home_id, $log_file, $console_log_file) = @_; - - my $home_backup_dir = SCREEN_LOGS_DIR . "/home_id_" . $home_id; - - if( ! -e $home_backup_dir ) - { - if( ! mkdir $home_backup_dir ) - { - logger "Can not create a backup directory at $home_backup_dir."; - return 1; - } - } - - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); - - my $backup_file_name = $mday . $mon . $year . '_' . $hour . 'h' . $min . 'm' . $sec . "s.log"; - - my $output_path = $home_backup_dir . "/" . $backup_file_name; - - # Used for deleting log files older than DELETE_LOGS_AFTER - my @file_list; - my @find_dirs; # directories to search - my $now = time(); # get current time - my $days; - if((DELETE_LOGS_AFTER =~ /^[+-]?\d+$/) && (DELETE_LOGS_AFTER > 0)){ - $days = DELETE_LOGS_AFTER; # how many days old - }else{ - $days = 30; # how many days old - } - my $seconds_per_day = 60*60*24; # seconds in a day - my $AGE = $days*$seconds_per_day; # age in seconds - push (@find_dirs, $home_backup_dir); - - # Create local copy of log file backup in the log_backups folder and current user home directory if SCREEN_LOG_LOCAL = 1 - if(SCREEN_LOG_LOCAL == 1) - { - # Create local backups folder - my $local_log_folder = Path::Class::Dir->new("logs_backup"); - - if(!-e $local_log_folder){ - mkdir($local_log_folder); - } - - # Add full path to @find_dirs so that log files older than DELETE_LOGS_AFTER are deleted - my $fullpath_to_local_logs = Path::Class::Dir->new(getcwd(), "logs_backup"); - push (@find_dirs, $fullpath_to_local_logs); - - my $log_local = $local_log_folder . "/" . $backup_file_name; - - # Delete the local log file if it already exists - if(-e $log_local){ - unlink $log_local; - } - - # If the log file contains UPDATE in the filename, do not allow users to see it since it will contain steam credentials - # Will return -1 for not existing - my $isUpdate = index($log_file,SCREEN_TYPE_UPDATE); - - if($isUpdate == -1){ - copy($log_file,$log_local); - } - } - - # Delete all files in @find_dirs older than DELETE_LOGS_AFTER days - find ( sub { - my $file = $File::Find::name; - if ( -f $file ) { - push (@file_list, $file); - } - }, @find_dirs); - - # Include the custom console path - and also do a size check on it - if(defined $console_log_file && $console_log_file ne ""){ - my $path_to_console_file = $console_log_file; - if( -f $path_to_console_file){ - push (@file_list, $path_to_console_file); - - # Backup and delete this specific file as well if it's over 20MB - my @stats = stat($path_to_console_file); - if($stats[7] >= 20971520){ - if(SCREEN_LOG_LOCAL == 1){ - # Copy it to local log folder as well - my $local_log_folder = Path::Class::Dir->new("logs_backup"); - my $log_local = $local_log_folder . "/" . $backup_file_name . "_console_log"; - copy($path_to_console_file, $log_local); - } - # Copy it to the main log folder as well - move($path_to_console_file,$output_path . "_console_log"); - } - } - } - - for my $file (@file_list) { - if( -f $file ){ - my @stats = stat($file); - if ($now-$stats[9] > $AGE) { - unlink $file; - } - } - } - - move($log_file,$output_path); - - return 0; -} - -sub get_home_pids -{ - my ($home_id) = @_; - my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); - my ($pid, @pids); - - my $as_user = find_user_by_screen_id($screen_id); - - my $ret = sudo_exec_without_decrypt('screen -ls | grep -E -o "[0-9]+\.'.$screen_id.'"', $as_user); - my ($retval, $enc_out) = split(/;/, $ret, 2); - if($retval != 1) - { - logger "Unable to get pids, probably a bad sudo password or not in sudoers list."; - return (); - } - - $enc_out =~ s/\\n//g; - - my $out = decode_base64($enc_out); - - ($pid) = split(/\./, $out, 2); - if(defined $pid) - { - chomp($pid); - while ($pid =~ /^[0-9]+$/) - { - push(@pids,$pid); - $pid = `pgrep -P $pid`; - chomp($pid); - } - } - return @pids; -} - -sub create_screen_id -{ - my ($screen_type, $home_id) = @_; - return sprintf("OGP_%s_%09d", $screen_type, $home_id); -} - -sub create_screen_cmd -{ - my ($screen_id, $exec_cmd) = @_; - $exec_cmd = replace_OGP_Env_Vars($screen_id, "", "", $exec_cmd); - return - sprintf('export WINEDEBUG="fixme-all" && export DISPLAY=:1 && screen -d -m -t "%1$s" -c ' . SCREENRC_FILE . ' -S %1$s %2$s', - $screen_id, $exec_cmd); - -} - -sub create_screen_cmd_loop -{ - my ($screen_id, $exec_cmd, $envVars, $skipLoop) = @_; - my $server_start_bashfile = $screen_id . "_startup_scr.sh"; - - $exec_cmd = replace_OGP_Env_Vars($screen_id, "", "", $exec_cmd); - - # Allow file to be overwritten - if(-e $server_start_bashfile){ - secure_path_without_decrypt('chattr-i', $server_start_bashfile); - } - - # Create bash file that screen will run which spawns the server - # If it crashes without user intervention, it will restart - open (SERV_START_SCRIPT, '>', $server_start_bashfile); - - my $respawn_server_command = "#!/bin/bash" . "\n"; - - if(!$skipLoop){ - $respawn_server_command .= "function startServer(){" . "\n"; - } - - if(defined $envVars && $envVars ne ""){ - $respawn_server_command .= $envVars; - } - - if(!$skipLoop){ - $respawn_server_command .= "NUMSECONDS=`expr \$(date +%s)`" . "\n" - . "until " . $exec_cmd . "; do" . "\n" - . "let DIFF=(`date +%s` - \"\$NUMSECONDS\")" . "\n" - . "if [ \"\$DIFF\" -gt 15 ]; then" . "\n" - . "NUMSECONDS=`expr \$(date +%s)`" . "\n" - . "echo \"Server '" . $exec_cmd . "' crashed with exit code \$?. Respawning...\" >&2 " . "\n" - . "fi" . "\n" - . "sleep 3" . "\n" - . "done" . "\n" - . "let DIFF=(`date +%s` - \"\$NUMSECONDS\")" . "\n" - - . "if [ ! -e \"SERVER_STOPPED\" ] && [ \"\$DIFF\" -gt 15 ]; then" . "\n" - . "startServer" . "\n" - . "fi" . "\n" - . "}" . "\n" - . "startServer" . "\n"; - }else{ - $respawn_server_command .= $exec_cmd . "\n"; - } - - print SERV_START_SCRIPT $respawn_server_command; - close (SERV_START_SCRIPT); - - # Make it not readable - my $readOnlyOwnerCmd = "chmod -Rf og-r '$server_start_bashfile'"; - sudo_exec_without_decrypt($readOnlyOwnerCmd); - - # Secure file - secure_path_without_decrypt('chattr+i', $server_start_bashfile); - - my $screen_exec_script = "bash " . $server_start_bashfile; - - return - sprintf('export WINEDEBUG="fixme-all" && export DISPLAY=:1 && screen -d -m -t "%1$s" -c ' . SCREENRC_FILE . ' -S %1$s %2$s', - $screen_id, $screen_exec_script); - -} - -sub handle_lock_command_line{ - my ($command) = @_; - if(defined $command && $command ne ""){ - if ($command =~ m/{OGP_LOCK_FILE}/) { - $command =~ s/{OGP_LOCK_FILE}\s*//g; - return secure_path_without_decrypt("chattr+i", $command); - } - } - - return 0; -} - -sub replace_OGP_Env_Vars{ - # This function replaces constants from environment variables set in the XML - my ($screen_id, $homeid, $homepath, $exec_cmd, $game_key) = @_; - - # Handle steam specific replacements - if(defined $screen_id && $screen_id ne ""){ - my $screen_id_for_txt_update = substr ($screen_id, rindex($screen_id, '_') + 1); - my $steamInsFile = $screen_id_for_txt_update . "_install.txt"; - my $steamCMDPath = STEAMCMD_CLIENT_DIR; - my $fullPath = Path::Class::File->new($steamCMDPath, $steamInsFile); - - # If the install file exists, the game can be auto updated, else it will be ignored by the game for improper syntax - # To generate the install file, the "Install/Update via Steam" button must be clicked on at least once! - if(-e $fullPath){ - $exec_cmd =~ s/{OGP_STEAM_CMD_DIR}/$steamCMDPath/g; - $exec_cmd =~ s/{STEAMCMD_INSTALL_FILE}/$steamInsFile/g; - } - } - - - # Handle home directory replacement - if(defined $homepath && $homepath ne ""){ - $exec_cmd =~ s/{OGP_HOME_DIR}/$homepath/g; - } - - # Handle global game shared directory replacement - if(defined $game_key && $game_key ne ""){ - my $readable_game_key = lc(substr($game_key, 0, rindex($game_key,"_"))); - my $shared_path = Path::Class::Dir->new(SHARED_GAME_TMP_DIR, $readable_game_key); - # Create the folder if it doesn't exist - if (!-d $shared_path && !mkdir $shared_path) - { - logger "Could not create " . $shared_path . " directory $!.", 1; - } - $exec_cmd =~ s/{OGP_GAME_SHARED_DIR}/$shared_path/g; - } - - return $exec_cmd; -} - -sub encode_list -{ - my $encoded_content = ''; - if(@_) - { - foreach my $line (@_) - { - $encoded_content .= encode_base64($line, "") . '\n'; - } - } - return $encoded_content; -} - -sub decrypt_param -{ - my ($param) = @_; - $param = decode_base64($param); - $param = Crypt::XXTEA::decrypt($param, AGENT_KEY); - $param = decode_base64($param); - return $param; -} - -sub decrypt_params -{ - my @params; - foreach my $param (@_) - { - $param = &decrypt_param($param); - push(@params, $param); - } - return @params; -} - -sub check_steam_cmd_client -{ - if (STEAM_LICENSE ne STEAM_LICENSE_OK) - { - logger "Steam license not accepted, stopping Steam client check."; - return 0; - } - if (!-d STEAMCMD_CLIENT_DIR && !mkdir STEAMCMD_CLIENT_DIR) - { - logger "Could not create " . STEAMCMD_CLIENT_DIR . " directory $!.", 1; - exit -1; - } - if (!-w STEAMCMD_CLIENT_DIR) - { - logger "Steam client dir '" - . STEAMCMD_CLIENT_DIR - . "' not writable. Unable to get Steam client."; - return -1; - } - if (!-f STEAMCMD_CLIENT_BIN) - { - logger "The Steam client, steamcmd, does not exist yet, installing..."; - my $steam_client_file = 'steamcmd_linux.tar.gz'; - my $steam_client_path = Path::Class::File->new(STEAMCMD_CLIENT_DIR, $steam_client_file); - my $steam_client_url = - "http://media.steampowered.com/client/" . $steam_client_file; - logger "Downloading the Steam client from $steam_client_url to '" - . $steam_client_path . "'."; - - my $ua = LWP::UserAgent->new; - $ua->agent('Mozilla/5.0'); - my $response = $ua->get($steam_client_url, ':content_file' => "$steam_client_path"); - - unless ($response->is_success) - { - logger "Failed to download steam installer from " - . $steam_client_url - . ".", 1; - return -1; - } - if (-f $steam_client_path) - { - logger "Uncompressing $steam_client_path"; - if ( uncompress_file_without_decrypt($steam_client_path, STEAMCMD_CLIENT_DIR) != 1 ) - { - unlink($steam_client_path); - logger "Unable to uncompress $steam_client_path, the file has been removed."; - return -1; - } - unlink($steam_client_path); - } - } - if (!-x STEAMCMD_CLIENT_BIN) - { - if ( ! chmod 0755, STEAMCMD_CLIENT_BIN ) - { - logger "Unable to apply execution permission to ".STEAMCMD_CLIENT_BIN."."; - } - } - return 1; -} - -sub is_screen_running -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($screen_type, $home_id) = decrypt_params(@_); - return is_screen_running_without_decrypt($screen_type, $home_id); -} - -sub is_screen_running_without_decrypt -{ - my ($screen_type, $home_id) = @_; - - my $screen_id = create_screen_id($screen_type, $home_id); - - my $as_user = find_user_by_screen_id($screen_id); - - my $ret = sudo_exec_without_decrypt('screen -list | grep '.$screen_id, $as_user); - - my ($retval, $enc_out) = split(/;/, $ret, 2); - - if($retval != 1) - { - return 0; - } - - my $is_running = " "; - - if( defined($enc_out) ) - { - $enc_out =~ s/\\n//g; - $is_running = decode_base64($enc_out); - } - - if ($is_running =~ /^\s*$/) - { - return 0; - } - else - { - return 1; - } -} - -# Delete Server Stopped Status File: -sub deleteStoppedStatFile -{ - my ($home_path) = @_; - my $server_stop_status_file = Path::Class::File->new($home_path, "SERVER_STOPPED"); - if(-e $server_stop_status_file) - { - unlink $server_stop_status_file; - } -} - -# Universal startup function -sub universal_start -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return universal_start_without_decrypt(decrypt_params(@_)); -} - -# Split to two parts because of internal calls. -sub universal_start_without_decrypt -{ - my ( - $home_id, $home_path, $server_exe, $run_dir, - $startup_cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log - ) = @_; - - if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1) - { - logger "This server is already running (ID: $home_id)."; - return -14; - } - - if (!-e $home_path) - { - logger "Can't find server's install path [ $home_path ]."; - return -10; - } - - my $owner = SERVER_RUNNER_USER; - my $group = SERVER_RUNNER_USER; - my $ogpAgentGroup = `whoami`; - - my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); - - chomp $ogpAgentGroup; - - if(defined LINUX_USER_PER_GAME_SERVER && LINUX_USER_PER_GAME_SERVER eq "1"){ - $owner = "gamehome" . $home_id; - $group = `whoami`; - chomp $group; - - # Create new user if doesn't exist - my $userExists = `id -u $owner`; - if(not is_integer($userExists)){ - logger "User $owner currently doesn't exist... creating user..."; - - sudo_exec_without_decrypt("useradd -m $owner"); - sudo_exec_without_decrypt("usermod -s /bin/bash $owner"); - sudo_exec_without_decrypt("usermod -a -G \"$owner\" \"$group\""); - } - } - - # Fix perms on ogp_agent user's homedir so that other users can access their owned files within this dir - my $fixOGPHomeDirCommand = 'chmod -R ug+rwx $( getent passwd "' . $ogpAgentGroup . '" | cut -d: -f6 )'; - sudo_exec_without_decrypt($fixOGPHomeDirCommand); - - $fixOGPHomeDirCommand = 'find "$( getent passwd "' . $ogpAgentGroup . '" | cut -d: -f6 )" -type d -print0 | xargs -0 chmod o+x'; - sudo_exec_without_decrypt($fixOGPHomeDirCommand); - - # Some game require that we are in the directory where the binary is. - my $game_binary_dir = Path::Class::Dir->new($home_path, $run_dir); - if ( -e $game_binary_dir && !chdir $game_binary_dir) - { - logger "Could not change to server binary directory $game_binary_dir."; - return -12; - } - - # Temporarily unlock the server executable - secure_path_without_decrypt('chattr-i', $server_exe); - - # Set ownership on the game home - set_path_ownership($owner, $group, $home_path, 1); - - if (!-x $server_exe) - { - if (!chmod 0775, $server_exe) - { - logger "The $server_exe file is not executable."; - return -13; - } - } - - if(defined $preStart && $preStart ne ""){ - # Get it in the format that the startup file can use - $preStart = multiline_to_startup_comma_format($preStart); - }else{ - $preStart = ""; - } - - if(defined $envVars && $envVars ne ""){ - # Replace variables in the envvars if they exist - my @prestartenvvars = split /[\r\n]+/, $envVars; - my $envVarStr = ""; - foreach my $line (@prestartenvvars) { - $line = replace_OGP_Env_Vars("", $home_id, $home_path, $line, $game_key); - if($line ne ""){ - logger "Configuring environment variable: $line"; - $envVarStr .= "$line\n"; - } - } - - if(defined $envVarStr && $envVarStr ne ""){ - $envVars = $envVarStr; - } - - # Get it in the format that the startup file can use - $envVars = multiline_to_startup_comma_format($envVars); - }else{ - $envVars = ""; - } - - # Secure file - secure_path_without_decrypt('chattr+i', $server_exe); - - # Create startup file for the server. - my $startup_file = - Path::Class::File->new(GAME_STARTUP_DIR, "$server_ip-$server_port"); - if (open(STARTUP, '>', $startup_file)) - { - print STARTUP - "$home_id,$home_path,$server_exe,$run_dir,$startup_cmd,$server_port,$server_ip,$cpu,$nice,$preStart,$envVars,$game_key,$console_log"; - logger "Created startup flag for $server_ip-$server_port"; - close(STARTUP); - } - else - { - logger "Cannot create file in " . $startup_file . " : $!"; - } - - if(defined $preStart && $preStart ne ""){ - # Get it in the format that the startup file can use - $preStart = startup_comma_format_to_multiline($preStart); - }else{ - $preStart = ""; - } - - if(defined $envVars && $envVars ne ""){ - # Get it in the format that the startup file can use - $envVars = startup_comma_format_to_multiline($envVars); - }else{ - $envVars = ""; - } - - # Create the startup string. - my $file_extension = substr $server_exe, -4; - my $cli_bin; - my $command; - my $run_before_start; - - # Replace any OGP variables found in the command line - $startup_cmd = replace_OGP_Env_Vars($screen_id, $home_id, $home_path, $startup_cmd, $game_key); - - if($file_extension eq ".exe" or $file_extension eq ".bat") - { - $command = "wine $server_exe $startup_cmd"; - - if ($cpu ne 'NA') - { - $command = "taskset -c $cpu wine $server_exe $startup_cmd"; - } - - if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ - deleteStoppedStatFile($home_path); - $cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars); - }else{ - $cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, 1); - } - } - elsif($file_extension eq ".jar") - { - $command = "$startup_cmd"; - - if ($cpu ne 'NA') - { - $command = "taskset -c $cpu $startup_cmd"; - } - - if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ - deleteStoppedStatFile($home_path); - $cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars); - }else{ - $cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, 1); - } - } - else - { - $command = "./$server_exe $startup_cmd"; - - if ($cpu ne 'NA') - { - $command = "taskset -c $cpu ./$server_exe $startup_cmd"; - } - - if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ - deleteStoppedStatFile($home_path); - $cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars); - }else{ - $cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars, 1); - } - } - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - backup_home_log( $home_id, $log_file, $home_path . "/" . $console_log ); - - logger - "Startup command [ $cli_bin ] will be executed in dir $game_binary_dir."; - - # Fix permissions one last time (for backup_home_log created folder / files / etc) - my $server_start_bashfile = $screen_id . "_startup_scr.sh"; - secure_path_without_decrypt('chattr-i', $server_start_bashfile); - set_path_ownership($owner, $group, $home_path, 1); - my $readOnlyOwnerCmd = "chmod -Rf og-r '$server_start_bashfile'"; - sudo_exec_without_decrypt($readOnlyOwnerCmd); - secure_path_without_decrypt('chattr+i', $server_start_bashfile); - - # Run before start script - $run_before_start = run_before_start_commands($home_id, $home_path, $preStart, $owner); - - sudo_exec_without_decrypt($cli_bin, $owner); - - sleep(1); - - renice_process_without_decrypt($home_id, $nice); - - chdir AGENT_RUN_DIR; - - return 1; -} - -# This is used to change the priority of process -# @return 1 if successfully set prosess priority -# @return -1 in case of an error. -sub renice_process -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return renice_process_without_decrypt(decrypt_params(@_)); -} - -sub renice_process_without_decrypt -{ - my ($home_id, $nice) = @_; - if ($nice != 0) - { - my @pids = get_home_pids($home_id); - logger - "Renicing pids [ @pids ] from home_id $home_id with nice value $nice."; - foreach my $pid (@pids) - { - my $ret = sudo_exec_without_decrypt('/usr/bin/renice '.$nice.' '.$pid); - ($ret) = split(/;/, $ret, 2); - if($ret != 1) - { - logger "Unable to renice process, probably bad sudo password or not in sudoers list."; - return -1 - } - } - } - return 1; -} - -# This is used to force a process to run on a particular CPU -sub force_cpu -{ - return force_cpu_without_decrypt(decrypt_params(@_)); -} - -sub force_cpu_without_decrypt -{ - my ($home_id, $cpu) = @_; - if ($cpu ne 'NA') - { - my @pids = get_home_pids($home_id); - logger - "Setting server from home_id $home_id with pids @pids to run on CPU $cpu."; - foreach my $pid (@pids) - { - my $rpid = kill 0, $pid; - if ($rpid == 1) - { - my $ret = sudo_exec_without_decrypt('/usr/bin/taskset -pc '.$cpu.' '.$pid); - ($ret) = split(/;/, $ret, 2); - if($ret != 1) - { - logger "Unable to set cpu, probably a bad sudo password or not in sudoers list."; - return -1 - } - } - } - } - return 1; -} - -# Returns the number of CPUs available. -sub cpu_count -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - if (!-e "/proc/cpuinfo") - { - return "ERROR - Missing /proc/cpuinfo"; - } - - open(CPUINFO, '<', "/proc/cpuinfo") - or return "ERROR - Cannot open /proc/cpuinfo"; - - my $cpu_count = 0; - - while () - { - chomp; - next if $_ !~ /^processor/; - $cpu_count++; - } - close(CPUINFO); - return "$cpu_count"; -} - -### File exists check #### -# Simple a way to check if a file exists using the remote agent -# -# @return 0 when file exists. -# @return 1 when file does not exist. -sub rfile_exists -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - chdir AGENT_RUN_DIR; - my $checkFile = decrypt_param(@_); - - if (-e $checkFile) - { - return 0; - } - else - { - return 1; - } -} - -#### Quick check to verify agent is up and running -# Used to quickly see if the agent is online, and if the keys match. -# The message that is sent to the agent must be hello, if not then -# it is intrepret as encryption key missmatch. -# -# @return 1 when encrypted message is not 'hello' -# @return 0 when check is ok. -sub quick_chk -{ - my $dec_check = &decrypt_param(@_); - if ($dec_check ne 'hello') - { - logger "ERROR - Encryption key mismatch! Returning 1 to asker."; - return 1; - } - return 0; -} - -### Return -10 If home path is not found. -### Return -9 If log type was invalid. -### Return -8 If log file was not found. -### 0 reserved for connection problems. -### Return 1;content If log found and screen running. -### Return 2;content If log found but screen is not running. -sub get_log -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($screen_type, $home_id, $home_path, $nb_of_lines, $log_file) = decrypt_params(@_); - - if (!chdir $home_path) - { - logger "Can't change to server's install path [ $home_path ]."; - return -10; - } - - if ( ($screen_type eq SCREEN_TYPE_UPDATE) - && ($screen_type eq SCREEN_TYPE_HOME)) - { - logger "Invalid screen type '$screen_type'."; - return -9; - } - - if(!$log_file) - { - my $screen_id = create_screen_id($screen_type, $home_id); - $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - } - else - { - $log_file = Path::Class::File->new($home_path, $log_file); - } - - sudo_exec_without_decrypt("chmod 777 \"$log_file\""); - - # Create local copy of current log file if SCREEN_LOG_LOCAL = 1 - if(SCREEN_LOG_LOCAL == 1) - { - my $log_local = Path::Class::File->new($home_path, "LOG_$screen_type.txt"); - if ( -e $log_local ) - { - unlink $log_local; - } - - # Copy log file only if it's not an UPDATE type as it may contain steam credentials - if($screen_type eq SCREEN_TYPE_HOME){ - copy($log_file, $log_local); - } - } - - # Regenerate the log file if it doesn't exist - unless ( -e $log_file ) - { - if (open(NEWLOG, '>', $log_file)) - { - logger "Log file missing, regenerating: " . $log_file; - print NEWLOG "Log file missing, started new log\n"; - close(NEWLOG); - } - else - { - logger "Cannot regenerate log file in " . $log_file . " : $!"; - return -8; - } - } - - # Return a few lines of output to the web browser - my(@modedlines) = `tail -n $nb_of_lines $log_file`; - - my $linecount = 0; - - foreach my $line (@modedlines) { - #Remove unwanted characters (https://superuser.com/questions/99128/removing-the-escape-characters-from-gnu-screens-screenlog-n) - $line =~ s/\x1b[[()=][;?0-9]*[0-9A-Za-z]?//g; - $line =~ s/\r//g; - $line =~ s/\007//g; - #Text replacements to remove the Steam user login from steamcmd logs for security reasons. - $line =~ s/login .*//g; - $line =~ s/Logging .*//g; - $line =~ s/set_steam_guard_code.*//g; - $line =~ s/force_install_dir.*//g; - #Text replacements to remove empty lines. - $line =~ s/^ +//g; - $line =~ s/^\t+//g; - $line =~ s/^\e+//g; - #Remove � from console output when master server update is running. - $line =~ s/�//g; - $modedlines[$linecount]=$line; - $linecount++; - } - - my $encoded_content = encode_list(@modedlines); - chdir AGENT_RUN_DIR; - if(is_screen_running_without_decrypt($screen_type, $home_id) == 1) - { - return "1;" . $encoded_content; - } - else - { - return "2;" . $encoded_content; - } -} - -# stop server function -sub stop_server -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return stop_server_without_decrypt(decrypt_params(@_)); -} - -##### Stop server without decrypt -### Return 1 when error occurred on decryption. -### Return 0 on success -sub stop_server_without_decrypt -{ - my ($home_id, $server_ip, $server_port, $control_protocol, - $control_password, $control_type, $home_path) = @_; - - my $startup_file = Path::Class::File->new(GAME_STARTUP_DIR, "$server_ip-$server_port"); - - if (-e $startup_file) - { - logger "Removing startup flag " . $startup_file . ""; - unlink($startup_file) - or logger "Cannot remove the startup flag file $startup_file $!"; - } - - # Create file indicator that the game server has been stopped if defined - if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ - - # Get current directory and chdir into the game's home dir - my $curDir = getcwd(); - chdir $home_path; - - # Create stopped indicator file used by autorestart of OGP if server crashes - open(STOPFILE, '>', "SERVER_STOPPED"); - close(STOPFILE); - - # Return to original directory - chdir $curDir; - } - - # Some validation checks for the variables. - if ($server_ip =~ /^\s*$/ || $server_port < 0 || $server_port > 65535) - { - logger("Invalid IP:Port given $server_ip:$server_port."); - return 1; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); - my $as_user = find_user_by_screen_id($screen_id); - - # Skip RCON - always kill processes directly for reliable server stops - logger "Stopping server with kill command (RCON disabled for reliability)."; - - my @server_pids = get_home_pids($home_id); - - my $cnt; - my $out; - foreach my $pid (@server_pids) - { - chomp($pid); - $cnt = sudo_exec_without_decrypt("kill 15 $pid", $as_user); - ($cnt, $out) = split(/;/, $cnt, 2); - if ($cnt == -1) - { - $cnt = sudo_exec_without_decrypt("kill 9 $pid", $as_user); - ($cnt, $out) = split(/;/, $cnt, 2); - if ($cnt == -1) - { - logger "Process $pid can not be stopped."; - } - else - { - logger "Stopped process with pid $pid successfully using kill 9."; - } - } - else - { - logger "Stopped process with pid $pid successfully using kill 15."; - } - } - sudo_exec_without_decrypt('screen -wipe > /dev/null 2>&1', $as_user); - return 0; -} - - -##### Send RCON command -### Return 0 when error occurred on decryption. -### Return 1 on success -sub send_rcon_command -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id, $server_ip, $server_port, $control_protocol, - $control_password, $control_type, $rconCommand) = decrypt_params(@_); - - # legacy console - if ($control_protocol eq "lcon") - { - my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); - my $as_user = find_user_by_screen_id($screen_id); - my $ScreenCommand = 'screen -S '.$screen_id.' -p 0 -X stuff "'.$rconCommand.'$(printf \\\\r)"'; - logger "Sending legacy console command to ".$screen_id.": \n$rconCommand \n ."; - my $ret = sudo_exec_without_decrypt($ScreenCommand, $as_user); - my ($retval, $enc_out) = split(/;/, $ret, 2); - if($retval == 1) - { - my(@modedlines) = "$rconCommand"; - my $encoded_content = encode_list(@modedlines); - return "1;" . $encoded_content; - } - return 0; - } - - # Some validation checks for the variables. - if ($server_ip =~ /^\s*$/ || $server_port < 0 || $server_port > 65535) - { - logger("Invalid IP:Port given $server_ip:$server_port."); - return 0; - } - - if ($control_password !~ /^\s*$/) - { - if ($control_protocol eq "rcon") - { - use KKrcon::KKrcon; - my $rcon = new KKrcon( - Password => $control_password, - Host => $server_ip, - Port => $server_port, - Type => $control_type - ); - - logger "Sending RCON command to $server_ip:$server_port: \n$rconCommand \n ."; - - my(@modedlines) = $rcon->execute($rconCommand); - my $encoded_content = encode_list(@modedlines); - return "1;" . $encoded_content; - } - elsif ($control_protocol eq "rcon2") - { - use KKrcon::HL2; - my $rcon2 = new HL2( - hostname => $server_ip, - port => $server_port, - password => $control_password, - timeout => 2 - ); - - logger "Sending RCON command to $server_ip:$server_port: \n $rconCommand \n ."; - - my(@modedlines) = $rcon2->run($rconCommand); - my $encoded_content = encode_list(@modedlines); - return "1;" . $encoded_content; - } - elsif ($control_protocol eq "armabe") - { - use ArmaBE::ArmaBE; - my $armabe = new ArmaBE( - hostname => $server_ip, - port => $server_port, # Uses server port for now (Arma 2), Arma 3 BE uses a different, user definable port - password => $control_password, - timeout => 2 - ); - - logger "Sending RCON command via ArmaBE module to $server_ip:$server_port: \n $rconCommand \n ."; - - my(@modedlines) = $armabe->run($rconCommand); - my $encoded_content = encode_list(@modedlines); - return "1;" . $encoded_content; - } - } - else - { - logger "Control protocol PASSWORD NOT SET."; - return -10; - } -} - -##### Returns a directory listing -### @return List of directories if everything OK. -### @return 0 If the directory is not found. -### @return -1 If cannot open the directory. -sub dirlist -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($datadir) = &decrypt_param(@_); - logger "Asked for dirlist of $datadir directory."; - if (!-d $datadir) - { - logger "ERROR - Directory [ $datadir ] not found!"; - return -1; - } - if (!opendir(DIR, $datadir)) - { - logger "ERROR - Can't open $datadir: $!"; - return -2; - } - my @dirlist = readdir(DIR); - closedir(DIR); - return join(";", @dirlist); -} - -##### Returns a directory listing with extra info the filemanager -### @return List of directories if everything OK. -### @return 1 If the directory is empty. -### @return -1 If the directory is not found. -### @return -2 If cannot open the directory. -sub dirlistfm -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $datadir = &decrypt_param(@_); - - logger "Asked for dirlist of $datadir directory."; - - if (!-d $datadir) - { - logger "ERROR - Directory [ $datadir ] not found!"; - return -1; - } - - if (!opendir(DIR, $datadir)) - { - logger "ERROR - Can't open $datadir: $!"; - return -2; - } - - my $dir = $datadir; - $dir =~ s/('+)/'"$1"'/g; - my $lsattr = `lsattr '$dir' 2>/dev/null`; - - my @attr_all = split /\n+/, $lsattr; - - my %attr = (); - - my ($a, $p, @f); - - foreach (@attr_all) - { - ($a, $p) = split(/\s/, $_, 2); - @f = split /\//, $p; - $attr{$f[-1]} = $a; - } - - my %dirfiles = (); - - my ( - $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, - $size, $atime, $mtime, $ctime, $blksize, $blocks - ); - - my $count = 0; - - chdir($datadir); - - while (my $item = readdir(DIR)) - { - #skip the . and .. special dirs - next if $item eq '.'; - next if $item eq '..'; - #print "Dir list is" . $item."\n"; - #Stat the file to get ownership and size - ( - $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, - $size, $atime, $mtime, $ctime, $blksize, $blocks - ) = stat($item); - - if(defined $uid) - { - $uid = getpwuid($uid); - } - else - { - $uid = ''; - } - - if(defined $gid) - { - $gid = getgrgid($gid); - } - else - { - $gid = ''; - } - - #This if else logic determines what it is, File, Directory, other - if (-T $item) - { - # print "File\n"; - $dirfiles{'files'}{$count}{'filename'} = encode_base64($item); - $dirfiles{'files'}{$count}{'size'} = $size; - $dirfiles{'files'}{$count}{'user'} = $uid; - $dirfiles{'files'}{$count}{'group'} = $gid; - $dirfiles{'files'}{$count}{'attr'} = $attr{$item}; - } - elsif (-d $item) - { - # print "Dir\n"; - $dirfiles{'directorys'}{$count}{'filename'} = encode_base64($item); - $dirfiles{'directorys'}{$count}{'size'} = $size; - $dirfiles{'directorys'}{$count}{'user'} = $uid; - $dirfiles{'directorys'}{$count}{'group'} = $gid; - } - elsif (-B $item) - { - #print "File\n"; - $dirfiles{'binarys'}{$count}{'filename'} = encode_base64($item); - $dirfiles{'binarys'}{$count}{'size'} = $size; - $dirfiles{'binarys'}{$count}{'user'} = $uid; - $dirfiles{'binarys'}{$count}{'group'} = $gid; - $dirfiles{'binarys'}{$count}{'attr'} = $attr{$item}; - } - else - { - #print "Unknown\n" - #will be listed as common files; - $dirfiles{'files'}{$count}{'filename'} = encode_base64($item); - $dirfiles{'files'}{$count}{'size'} = $size; - $dirfiles{'files'}{$count}{'user'} = $uid; - $dirfiles{'files'}{$count}{'group'} = $gid; - $dirfiles{'files'}{$count}{'attr'} = $attr{$item}; - } - $count++; - } - closedir(DIR); - - if ($count eq 0) - { - logger "Empty directory $datadir."; - return 1; - } - - chdir AGENT_RUN_DIR; - #Now we return it to the webpage, as array - return {%dirfiles}; -} - -###### Returns the contents of a text file -sub readfile -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - chdir AGENT_RUN_DIR; - my $userfile = &decrypt_param(@_); - - unless ( -e $userfile ) - { - if (open(BLANK, '>', $userfile)) - { - close(BLANK); - } - } - - if (!open(USERFILE, '<', $userfile)) - { - logger "ERROR - Can't open file $userfile for reading."; - return -1; - } - - my ($wholefile, $buf); - - while (read(USERFILE, $buf, 60 * 57)) - { - $wholefile .= encode_base64($buf); - } - close(USERFILE); - - if(!defined $wholefile) - { - return "1; "; - } - - return "1;" . $wholefile; -} - -###### Backs up file, then writes data to new file -### @return 1 On success -### @return 0 In case of a failure -sub writefile -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - chdir AGENT_RUN_DIR; - # $writefile = file we're editing, $filedata = the contents were writing to it - my ($writefile, $filedata) = &decrypt_params(@_); - if (!-e $writefile) - { - open FILE, ">", $writefile; - } - else - { - # backup the existing file - logger - "Backing up file $writefile to $writefile.bak before writing new data."; - if (!copy("$writefile", "$writefile.bak")) - { - logger - "ERROR - Failed to backup $writefile to $writefile.bak. Error: $!"; - return 0; - } - } - if (!-w $writefile) - { - logger "ERROR - File [ $writefile ] is not writeable!"; - return 0; - } - if (!open(WRITER, '>', $writefile)) - { - logger "ERROR - Failed to open $writefile for writing."; - return 0; - } - $filedata = decode_base64($filedata); - $filedata =~ s/\r//g; - print WRITER "$filedata"; - close(WRITER); - logger "Wrote $writefile successfully!"; - return 1; -} - -###### Reboots the server remotely through panel -### @return 1 On success -### @return 0 In case of a failure -sub rebootnow -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - sudo_exec_without_decrypt('sleep 10s; shutdown -r now'); - logger "Scheduled system reboot to occur in 10 seconds successfully!"; - return 1; -} - -# Determine the os of the agent machine. -sub what_os -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $which_uname = `which uname`; - chomp $which_uname; - if ($which_uname ne "") - { - my $os; - my $os_name; - my $os_arch; - my $wine_ver = ""; - $os_name = `$which_uname`; - chomp $os_name; - $os_arch = `$which_uname -m`; - chomp $os_arch; - my $which_wine = `which wine`; - chomp $which_wine; - if ($which_wine ne "") - { - $wine_ver = `$which_wine --version`; - chomp $wine_ver; - $wine_ver = "|".$wine_ver; - } - $os = $os_name." ".$os_arch.$wine_ver; - return "$os"; - } - else - { - logger "Cannot determine OS..that is odd"; - return "Unknown"; - } -} - -### @return PID of the download process if started succesfully. -### @return -1 If could not create temporary download directory. -### @return -2 If could not create destination directory. -### @return -3 If resources unavailable. -sub start_file_download -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($url, $destination, $filename, $action, $post_script) = &decrypt_params(@_); - logger - "Starting to download URL $url. Destination: $destination - Filename: $filename"; - - if (!-e $destination) - { - logger "Creating destination directory."; - if (!mkpath $destination ) - { - logger "Could not create destination '$destination' directory : $!"; - return -2; - } - } - - my $download_file_path = Path::Class::File->new($destination, "$filename"); - - my $pid = fork(); - if (not defined $pid) - { - logger "Could not allocate resources for download."; - return -3; - } - - # Only the forked child goes here. - elsif ($pid == 0) - { - my $ua = LWP::UserAgent->new( ssl_opts => { verify_hostname => 0, - SSL_verify_mode => 0x00 } ); - $ua->agent('Mozilla/5.0'); - my $response = $ua->get($url, ':content_file' => "$download_file_path"); - - if ($response->is_success) - { - logger "Successfully fetched $url and stored it to $download_file_path. Retval: ".$response->status_line; - - if (!-e $download_file_path) - { - logger "File $download_file_path does not exist."; - exit(0); - } - - if ($action eq "uncompress") - { - logger "Starting file uncompress as ordered."; - uncompress_file_without_decrypt($download_file_path, - $destination); - } - - # Run post scripts if any - if ($post_script ne "") - { - logger "Running postscript commands."; - my @postcmdlines = split /[\r\n]+/, $post_script; - my $postcmdfile = $destination."/".'postinstall.sh'; - open FILE, '>', $postcmdfile; - print FILE "cd $destination\n"; - foreach my $line (@postcmdlines) { - logger "Postscript command received \"" . $line ."\"."; - if(handle_lock_command_line($line) == 0){ - print FILE "$line\n"; - }else{ - logger "Lock command completed successfully"; - } - } - print FILE "rm -f $destination/postinstall.sh\n"; - close FILE; - chmod 0755, $postcmdfile; - my $screen_id = create_screen_id("post_script", $$); - my $cli_bin = create_screen_cmd($screen_id, "bash $postcmdfile"); - system($cli_bin); - } - } - else - { - logger - "Unable to fetch $url, or save to $download_file_path. Retval: ".$response->status_line; - exit(0); - } - - # Child process must exit. - exit(0); - } - else - { - logger "Download process for $download_file_path has pid number $pid."; - return "$pid"; - } -} - -sub lock_additional_files{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($homedir, $files, $action) = &decrypt_params(@_); - return lock_additional_files_logic($homedir, $files, $action); -} - -sub lock_additional_files_logic{ - my ($homedir, $filesToLock, $action, $returnType) = @_; - - logger "Locking additional files specified in the XML."; - - my $commandStr = ""; - $filesToLock = startup_comma_format_to_multiline($filesToLock); - $filesToLock = replace_OGP_Env_Vars("", "", $homedir, $filesToLock); - my @filesToProcess = split /[\r\n]+/, $filesToLock; - foreach my $line (@filesToProcess) { - my $fullPath = $homedir . "/" . $line; - if($action eq "lock"){ - if(defined $returnType && $returnType eq "str"){ - $commandStr .= "echo '".$SUDOPASSWD."' | sudo -S -p \" \" sh -c \"" . secure_path_without_decrypt("chattr+i", $fullPath, $returnType) . "\" > /dev/null 2>&1" . "\n"; - $commandStr .= "echo '".$SUDOPASSWD."' | sudo -S -p \" \" sh -c \"" . secure_path_without_decrypt("chattr+i", $line, $returnType) . "\" > /dev/null 2>&1" . "\n"; - }else{ - secure_path_without_decrypt("chattr+i", $fullPath); - secure_path_without_decrypt("chattr+i", $line); - } - }else{ - if(defined $returnType && $returnType eq "str"){ - $commandStr .= "echo '".$SUDOPASSWD."' | sudo -S -p \" \" sh -c \"" . secure_path_without_decrypt("chattr-i", $fullPath, $returnType) . "\" > /dev/null 2>&1" . "\n"; - $commandStr .= "echo '".$SUDOPASSWD."' | sudo -S -p \" \" sh -c \"" . secure_path_without_decrypt("chattr-i", $line, $returnType) . "\" > /dev/null 2>&1" . "\n"; - }else{ - secure_path_without_decrypt("chattr-i", $fullPath); - secure_path_without_decrypt("chattr-i", $line); - } - } - } - - if($commandStr ne ""){ - return $commandStr; - } - - return ""; -} - -sub run_before_start_commands -{ - #return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($server_id, $homedir, $beforestartcmd, $pathowner) = @_; - - if ($homedir ne "" && $server_id ne ""){ - # Run any prestart scripts - if (defined $beforestartcmd && $beforestartcmd ne "") - { - logger "Running pre-start XML commands before starting server ID $server_id with a home directory of $homedir."; - my @prestartcmdlines = split /[\r\n]+/, $beforestartcmd; - my $prestartcmdfile = $homedir."/".'prestart_ogp.sh'; - open FILE, '>', $prestartcmdfile; - print FILE "#!/bin/bash" . "\n"; - print FILE "cd $homedir\n"; - foreach my $line (@prestartcmdlines) { - print FILE "$line\n"; - } - print FILE "rm -f $prestartcmdfile\n"; - close FILE; - chmod 0755, $prestartcmdfile; - sudo_exec_without_decrypt("bash $prestartcmdfile", $pathowner); - } - }else{ - return -2; - } - - return 1; -} - -sub multiline_to_startup_comma_format{ - my ($multiLineVar) = @_; - $multiLineVar =~ s/,//g; # commas are invalid anyways in bash - $multiLineVar =~ s/[\r]+//g; - $multiLineVar =~ s/[\n]+/{OGPNEWLINE}/g; - return $multiLineVar; -} - -sub multiline_to_bash_commands{ - my ($multiLineVar) = @_; - $multiLineVar =~ s/[\n]+/ && /g; - return $multiLineVar; -} - -sub startup_comma_format_to_multiline{ - my ($multiLineVar) = @_; - $multiLineVar =~ s/{OGPNEWLINE}/\n/g; - return $multiLineVar; -} - -sub create_secure_script -{ - my ($home_path, $exec_folder_path, $exec_path) = @_; - secure_path_without_decrypt('chattr-i', $home_path); - my $secure = "$home_path/secure.sh"; - $home_path =~ s/('+)/'\"$1\"'/g; - $exec_folder_path =~ s/('+)/'\"$1\"'/g; - $exec_path =~ s/('+)/'\"$1\"'/g; - my $sec = $secure; - $sec =~ s/('+)/'\"$1\"'/g; - open FILE, '>', $secure; - print FILE "chmod 771 '$exec_folder_path'\n". - "chmod 750 '$exec_path'\n". - "chmod +x '$exec_path'\n". - "chattr +i '$exec_path'\n". - "rm -f '$sec'"; - close FILE; - chmod 0770, $secure; - sudo_exec_without_decrypt("chown 0:0 '$sec'"); - return 0; -} - -sub check_b4_chdir -{ - my ($path, $owner) = @_; - - if (!-e $path) - { - logger "$path does not exist yet. Trying to create it..."; - - eval { mkpath($path); 1 } or logger "Error creating $path with Perl mkpath command. Errno: $! - Trying again with sudo..."; - - if (!-e $path) - { - sudo_exec_without_decrypt('mkdir -p ' . $path); - } - - if (!-e $path) - { - return -1; - } - } - - my $group = SERVER_RUNNER_USER; - - if(defined LINUX_USER_PER_GAME_SERVER && LINUX_USER_PER_GAME_SERVER eq "1"){ - $group = `whoami`; - chomp $group; - } - - set_path_ownership($owner, $group, $path); - - if (!chdir $path) - { - logger "Unable to change dir to '$path'."; - return -1; - } - - return 0; -} - -sub set_path_ownership -{ - my ($owner, $group, $path, $skipChattr) = @_; - - my $owner_uid = `id -u $owner`; - chomp $owner_uid; - my $group_uid = `id -g $group`; - chomp $group_uid; - - # Remove immutable flag recursivelly - if(!$skipChattr){ - secure_path_without_decrypt('chattr-i', $path); - } - - # Set owner and perms on it recursivelly as well - my $chownCommand = "chown -Rf $owner_uid:$group_uid '$path'"; - my $chmodCommand = "chmod -Rf ug+rwx '$path'"; - my $chmodCommandDir = "chmod -Rf o+rx `find '$path' -type d`"; - sudo_exec_without_decrypt($chownCommand); - sudo_exec_without_decrypt($chmodCommand); - sudo_exec_without_decrypt($chmodCommandDir); - - my $groupCommand = "find '$path' -type d | xargs chmod g+s"; - sudo_exec_without_decrypt($groupCommand); - - $groupCommand = "find '$path' -type d | xargs setfacl -d -m u::rwX,g::rwX,o::rx"; - sudo_exec_without_decrypt($groupCommand); - - # Remove perms for other users - $chmodCommand = "chmod -Rf o-rwx `find '$path' -type f`"; - sudo_exec_without_decrypt($chmodCommand); - - return 0; -} - -sub create_bash_scripts -{ - my ( $home_path, $bash_scripts_path, $precmd, $postcmd, @installcmds ) = @_; - - $home_path =~ s/('+)/'\"$1\"'/g; - $bash_scripts_path =~ s/('+)/'\"$1\"'/g; - - my @precmdlines = split /[\r\n]+/, $precmd; - my $precmdfile = 'preinstall.sh'; - open FILE, '>', $precmdfile; - print FILE "cd '$home_path'\n"; - foreach my $line (@precmdlines) { - print FILE "$line\n"; - } - close FILE; - chmod 0755, $precmdfile; - - my @postcmdlines = split /[\r\n]+/, $postcmd; - my $postcmdfile = 'postinstall.sh'; - open FILE, '>', $postcmdfile; - print FILE "cd '$home_path'\n"; - foreach my $line (@postcmdlines) { - print FILE "$line\n"; - } - print FILE "cd '$home_path'\n". - "echo '".$SUDOPASSWD."' | sudo -S -p \" \" bash secure.sh\n". - "rm -f secure.sh\n". - "cd '$bash_scripts_path'\n". - "rm -f preinstall.sh\n". - "rm -f postinstall.sh\n". - "rm -f runinstall.sh\n"; - close FILE; - chmod 0755, $postcmdfile; - - my $installfile = 'runinstall.sh'; - open FILE, '>', $installfile; - print FILE "#!/bin/bash\n". - "cd '$bash_scripts_path'\n". - "./$precmdfile\n"; - foreach my $installcmd (@installcmds) - { - print FILE "$installcmd\n"; - } - print FILE "wait ".'${!}'."\n". - "cd '$bash_scripts_path'\n". - "./$postcmdfile\n"; - close FILE; - chmod 0755, $installfile; - - return $installfile; -} - -#### Run the rsync update #### -### @return 1 If update started -### @return 0 In error case. -sub start_rsync_install -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id, $home_path, $url, $exec_folder_path, $exec_path, $precmd, $postcmd, $filesToLockUnlock) = decrypt_params(@_); - - my $owner = get_path_owner($home_path); - - if ( check_b4_chdir($home_path, $owner) != 0) - { - return 0; - } - - create_secure_script($home_path, $exec_folder_path, $exec_path); - - my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id; - - if ( check_b4_chdir($bash_scripts_path, $owner) != 0) - { - return 0; - } - - # Rsync install require the rsync binary to exist in the system - # to enable this functionality. - my $rsync_binary = Path::Class::File->new("/usr/bin", "rsync"); - - if (!-f $rsync_binary) - { - logger "Failed to start rsync update from " - . $url - . " to $home_path. Error: Rsync client not installed."; - return 0; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - - if(defined $filesToLockUnlock && $filesToLockUnlock ne ""){ - $postcmd .= "\n" . lock_additional_files_logic($home_path, $filesToLockUnlock, "lock", "str"); - } - - backup_home_log( $home_id, $log_file ); - my $path = $home_path; - $path =~ s/('+)/'\"$1\"'/g; - my @installcmds = ("/usr/bin/rsync --log-file='" . AGENT_RSYNC_GENERIC_LOG . "' --archive --compress --copy-links --update --verbose rsync://$url '$path'"); - my $installfile = create_bash_scripts( $home_path, $bash_scripts_path, $precmd, $postcmd, @installcmds ); - - my $screen_cmd = create_screen_cmd($screen_id, "./$installfile"); - logger "Running rsync update: /usr/bin/rsync --log-file='" . AGENT_RSYNC_GENERIC_LOG . "' --archive --compress --copy-links --update --verbose rsync://$url '$home_path'"; - system($screen_cmd); - - chdir AGENT_RUN_DIR; - return 1; -} - -### @return PID of the download process if started succesfully. -### @return -1 If could not create temporary download directory. -### @return -2 If could not create destination directory. -### @return -3 If resources unavailable. -sub master_server_update -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id,$home_path,$ms_home_id,$ms_home_path,$exec_folder_path,$exec_path,$precmd,$postcmd) = decrypt_params(@_); - my $owner = get_path_owner($home_path); - - if ( check_b4_chdir($home_path, $owner) != 0) - { - return 0; - } - - create_secure_script($home_path, $exec_folder_path, $exec_path); - - my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id; - - if ( check_b4_chdir($bash_scripts_path, $owner) != 0) - { - return 0; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - - backup_home_log( $home_id, $log_file ); - - my $my_home_path = $home_path; - $my_home_path =~ s/('+)/'\"$1\"'/g; - $exec_path =~ s/\Q$home_path\E//g; - $exec_path =~ s/^\///g; - $exec_path =~ s/('+)/'\"$1\"'/g; - $ms_home_path =~ s/('+)/'\"$1\"'/g; - - my @installcmds = ("cd '$ms_home_path'"); - - ## Copy files that match the extensions listed at extPatterns.txt - open(EXT_PATTERNS, '<', Path::Class::File->new(AGENT_RUN_DIR, "extPatterns.txt")) - || logger "Error reading patterns file $!"; - my @ext_paterns = ; - foreach my $patern (@ext_paterns) - { - chop $patern; - push (@installcmds, "find -iname \\\*.$patern -exec cp -Rfp --parents {} '$my_home_path'/ \\\;"); - } - close EXT_PATTERNS; - - ## Copy the server executable so it can be secured with chattr +i - push (@installcmds, "cp -vf --parents '$exec_path' '$my_home_path'"); - - ## Do symlinks for each of the other files - push (@installcmds, "cp -vuRfs '$ms_home_path'/* '$my_home_path'"); - - my $installfile = create_bash_scripts( $home_path, $bash_scripts_path, $precmd, $postcmd, @installcmds ); - - my $screen_cmd = create_screen_cmd($screen_id, "./$installfile"); - logger "Running master server update from home ID $home_id to home ID $ms_home_id"; - system($screen_cmd); - - chdir AGENT_RUN_DIR; - return 1; -} - -sub steam_cmd -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return steam_cmd_without_decrypt(decrypt_params(@_)); -} - -#### Run the steam client #### -### @return 1 If update started -### @return 0 In error case. -sub steam_cmd_without_decrypt -{ - my ($home_id, $home_path, $mod, $modname, $betaname, $betapwd, $user, $pass, $guard, $exec_folder_path, $exec_path, $precmd, $postcmd, $cfg_os, $filesToLockUnlock, $arch_bits) = @_; - my $owner = get_path_owner($home_path); - - if ( check_b4_chdir($home_path, $owner) != 0) - { - return 0; - } - - create_secure_script($home_path, $exec_folder_path, $exec_path); - - my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id; - - if ( check_b4_chdir($bash_scripts_path, $owner) != 0) - { - return 0; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - my $screen_id_for_txt_update = substr ($screen_id, rindex($screen_id, '_') + 1); - my $steam_binary = Path::Class::File->new(STEAMCMD_CLIENT_DIR, "steamcmd.sh"); - my $installSteamFile = $screen_id_for_txt_update . "_install.txt"; - - my $installtxt = Path::Class::File->new(STEAMCMD_CLIENT_DIR, $installSteamFile); - open FILE, '>', $installtxt; - print FILE "\@ShutdownOnFailedCommand 1\n"; - print FILE "\@NoPromptForPassword 1\n"; - if($cfg_os eq 'windows') - { - print FILE "\@sSteamCmdForcePlatformType windows\n"; - } - - # Handle requested SteamCMD architecture - if(defined $arch_bits && $arch_bits ne ""){ - print FILE "\@sSteamCmdForcePlatformBitness " . $arch_bits . "\n"; - } - - if(defined STEAM_DL_LIMIT && STEAM_DL_LIMIT ne "" && is_integer(STEAM_DL_LIMIT) && STEAM_DL_LIMIT > 0){ - print FILE "set_download_throttle " . STEAM_DL_LIMIT . "\n"; - } - - print FILE "force_install_dir \"$home_path\"\n"; - - if($guard ne '') - { - print FILE "set_steam_guard_code $guard\n"; - } - if($user ne '' && $user ne 'anonymous') - { - print FILE "login $user $pass\n"; - } - else - { - print FILE "login anonymous\n"; - } - - if($modname ne "") - { - print FILE "app_set_config $mod mod $modname\n"; - print FILE "app_update $mod mod $modname validate\n"; - } - - if($betaname ne "" && $betapwd ne "") - { - print FILE "app_update $mod -beta $betaname -betapassword $betapwd\n"; - } - elsif($betaname ne "" && $betapwd eq "") - { - print FILE "app_update $mod -beta $betaname\n"; - } - else - { - print FILE "app_update $mod\n"; - } - - print FILE "exit\n"; - close FILE; - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - backup_home_log( $home_id, $log_file ); - - my $postcmd_mod = $postcmd; - - if(defined $filesToLockUnlock && $filesToLockUnlock ne ""){ - $postcmd_mod .= "\n" . lock_additional_files_logic($home_path, $filesToLockUnlock, "lock", "str"); - } - - my @installcmds = ("$steam_binary +runscript $installtxt +exit"); - - my $installfile = create_bash_scripts( $home_path, $bash_scripts_path, $precmd, $postcmd_mod, @installcmds ); - - my $screen_cmd = create_screen_cmd($screen_id, "./$installfile"); - - logger "Running steam update: $steam_binary +runscript $installtxt +exit"; - system($screen_cmd); - - return 1; -} - -sub fetch_steam_version -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($appId, $pureOutput) = &decrypt_params(@_); - - my $steam_binary = Path::Class::File->new(STEAMCMD_CLIENT_DIR, "steamcmd.sh"); - my $steam_options = "+login anonymous +app_info_update 1 +app_info_print \"$appId\" +quit"; - my $grep = $pureOutput != "0" ? "" : '| grep -EA 1000 "^\s+\"branches\"$" | grep -EA 5 "^\s+\"public\"$" | grep -m 1 -EB 10 "^\s+}$" | grep -E "^\s+\"buildid\"\s+" | tr \'[:blank:]"\' \' \' | tr -s \' \' | cut -d\' \' -f3'; - - logger "Getting latest version info for AppId $appId"; - my $response = `$steam_binary $steam_options $grep`; - - return $response; -} - -sub installed_steam_version -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($game_home, $mod, $pureOutput) = &decrypt_params(@_); - my $appFile = $game_home."/steamapps/appmanifest_$mod.acf"; - my $grep = $pureOutput != "0" ? "" : '| grep buildid | tr \'[:blank:]"\' \' \' | tr -s \' \' | cut -d\' \' -f3'; - - if ( ! -f $appFile) - { - return "-10"; - } - - return `cat $appFile $grep`; -} - -sub automatic_steam_update -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id, $game_home, $server_ip, $server_port, $exec_path, $exec_folder_path, - $control_protocol, $control_password, $control_type, - $appId, $modname, $betaname, $betapwd, $user, $pass, $guard, $precmd, $postcmd, $cfg_os, $filesToLockUnlock, - $startup_cmd, $cpu, $nice, $preStart, $envVars, $game_key, $arch_bits, $console_log) = &decrypt_params(@_); - - # Is the server currently running? if it is, we'll try to start it after updating. - my $isServerRunning = is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1 ? 1 : 0; - - # Check if an update is already happening. - if (is_screen_running_without_decrypt(SCREEN_TYPE_UPDATE, $home_id) == 1) - { - logger("Update already running for server $home_id, unable to start automatic update."); - return -10; - } - - # Stop the server if it's running. - if ($isServerRunning == 1) - { - logger("Stopping server $home_id for automatic update."); - - if (stop_server_without_decrypt($home_id, $server_ip, $server_port, $control_protocol, $control_password, $control_type, $game_home) != 0) - { - logger("Failed to stop server $home_id for automatic update. Exiting update procedure."); - return -9 - } - - } - - # steam_cmd: Returns 0 if the update failed, in which case, don't try starting the server - because we may have an incomplete or corrupt installation. - if (steam_cmd_without_decrypt($home_id, $game_home, $appId, $modname, $betaname, $betapwd, $user, $pass, $guard, $exec_folder_path, $exec_path, $precmd, $postcmd, $cfg_os, $filesToLockUnlock, $arch_bits) == 0) - { - logger("Failed to start steam_cmd for server $home_id."); - return -8; - - } else { - - if ($isServerRunning == 1) - { - while (1) - { - # If the update screen for $home_id isn't running, attempt to start the server. - if (is_screen_running_without_decrypt(SCREEN_TYPE_UPDATE, $home_id) == 0) - { - - if (universal_start_without_decrypt($home_id, $game_home, $exec_path, $exec_folder_path, $startup_cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log) != 1) - { - logger("Failed to start server $home_id after automatic update."); - return -7; - } else { - logger("Starting server $home_id after automatic update."); - return 1; - } - - last; - } - - sleep 5; - } - - } else { - # Update was started, but server wasn't initially running. - return 2; - } - - } - -} - -sub rsync_progress -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($running_home) = &decrypt_param(@_); - logger "User requested progress on rsync job on home $running_home."; - if (-r $running_home) - { - $running_home =~ s/('+)/'"$1"'/g; - my $progress = `du -sk '$running_home'`; - chomp($progress); - my ($bytes, $junk) = split(/\s+/, $progress); - logger("Found $bytes and $junk"); - return $bytes; - } - return "0"; -} - -sub is_file_download_in_progress -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($pid) = &decrypt_param(@_); - logger "User requested if download is in progress with pid $pid."; - my @pids = `ps -ef`; - @pids = grep(/$pid/, @pids); - logger "Number of pids for file download: @pids"; - if (@pids > '0') - { - return 1; - } - return 0; -} - -### \return 1 If file is uncompressed succesfully. -### \return 0 If file does not exist. -### \return -1 If file could not be uncompressed. -sub uncompress_file -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return uncompress_file_without_decrypt(decrypt_params(@_)); -} - -sub uncompress_file_without_decrypt -{ - # Globals - $Archive::Extract::PREFER_BIN = 1; - - # File must include full path. - my ($file, $destination) = @_; - - logger "Uncompression called for file $file to dir $destination."; - - if (!-e $file) - { - logger "File $file could not be found for uncompression."; - return 0; - } - - if (!-e $destination) - { - mkpath($destination, {error => \my $err}); - if (@$err) - { - logger "Failed to create destination dir $destination."; - return 0; - } - } - - my $filesize = (stat($file))[7]; - - if($filesize >= 3221225472 && $file =~ /\.zip$/i){ - # Archive::Extract seems to have problems with large zip files, so for files greater than 3GB in size, let the system handle it - logger "Using system call to unzip."; - system("unzip -o $file -d $destination"); - if($? != 0){ - logger "Done."; - return -1; - } - }else{ - - my $ae = Archive::Extract->new(archive => $file); - - if (!$ae) - { - logger "Could not create archive instance for file $file."; - return -1; - } - - my $ok = $ae->extract(to => $destination); - - if (!$ok) - { - logger "File $file could not be uncompressed."; - return -1; - } - - logger "File uncompressed/extracted successfully."; - } - - return 1; -} - -### \return 1 If files are compressed succesfully. -### \return -1 If files could not be compressed. -sub compress_files -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return compress_files_without_decrypt(decrypt_params(@_)); -} - -sub compress_files_without_decrypt -{ - my ($files,$destination,$archive_name,$archive_type) = @_; - - if (!-e $destination) - { - logger "compress_files: Destination path ( $destination ) could not be found."; - return -1; - } - - chdir $destination; - my @items = split /\Q\n/, $files; - my @inventory; - if($archive_type eq "zip") - { - logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type"; - my $zip = Archive::Zip->new(); - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - $zip->addFile( $item ); - } - elsif (-d $item) - { - $zip->addTree( $item, $item ); - } - } - } - # Save the file - unless ( $zip->writeToFileNamed($archive_name.'.zip') == AZ_OK ) { - logger "Write Error at $destination/$archive_name.$archive_type"; - return -1 - } - logger $archive_type." archive $destination$archive_name.$archive_type created successfully"; - return 1; - } - elsif($archive_type eq "tbz") - { - logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type"; - my $tar = Archive::Tar->new; - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - $tar->add_files( $item ); - } - elsif (-d $item) - { - @inventory = (); - find (sub { push @inventory, $File::Find::name }, $item); - $tar->add_files( @inventory ); - } - } - } - # Save the file - unless ( $tar->write("$archive_name.$archive_type", COMPRESS_BZIP) ) { - logger "Write Error at $destination/$archive_name.$archive_type"; - return -1 - } - logger $archive_type." archive $destination$archive_name.$archive_type created successfully"; - return 1; - } - elsif($archive_type eq "tgz") - { - logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type"; - my $tar = Archive::Tar->new; - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - $tar->add_files( $item ); - } - elsif (-d $item) - { - @inventory = (); - find (sub { push @inventory, $File::Find::name }, $item); - $tar->add_files( @inventory ); - } - } - } - # Save the file - unless ( $tar->write("$archive_name.$archive_type", COMPRESS_GZIP) ) { - logger "Write Error at $destination/$archive_name.$archive_type"; - return -1 - } - logger $archive_type." archive $destination$archive_name.$archive_type created successfully"; - return 1; - } - elsif($archive_type eq "tar") - { - logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type"; - my $tar = Archive::Tar->new; - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - $tar->add_files( $item ); - } - elsif (-d $item) - { - @inventory = (); - find (sub { push @inventory, $File::Find::name }, $item); - $tar->add_files( @inventory ); - } - } - } - # Save the file - unless ( $tar->write("$archive_name.$archive_type") ) { - logger "Write Error at $destination/$archive_name.$archive_type"; - return -1 - } - logger $archive_type." archive $destination$archive_name.$archive_type created successfully"; - return 1; - } - elsif($archive_type eq "bz2") - { - logger $archive_type." compression called."; - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - bzip2 $item => "$item.bz2"; - } - elsif (-d $item) - { - @inventory = (); - find (sub { push @inventory, $File::Find::name }, $item); - foreach my $relative_item (@inventory) { - bzip2 $relative_item => "$relative_item.bz2"; - } - } - } - } - logger $archive_type." archives created successfully at $destination"; - return 1; - } -} - -sub discover_ips -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($check) = decrypt_params(@_); - - if ($check ne "chk") - { - logger "Invalid parameter '$check' given for discover_ips function."; - return ""; - } - - my $iplist = ""; - my $ipfound; - my $junk; - - my @ipraw = `/sbin/ifconfig`; - while (<@ipraw>) - { - chomp; - next if $_ !~ /^inet:/ ; - logger "Found addr on line: $_"; - ($junk, $ipfound) = split(":", $_); - next if $ipfound eq ''; - next if $ipfound eq '127.0.0.1'; - - logger "Found an IP $ipfound"; - $iplist .= "$ipfound,"; - logger "IPlist is now $iplist"; - } - while (<@ipraw>) - { - chomp; - next if $_ !~ /^addr:/ ; - logger "Found addr on line: $_"; - ($junk, $ipfound) = split(":", $_); - next if $ipfound eq ''; - next if $ipfound eq '127.0.0.1'; - - logger "Found an IP $ipfound"; - $iplist .= "$ipfound,"; - logger "IPlist is now $iplist"; - } - chop $iplist; - return "$iplist"; -} - -### Return -1 In case of invalid param -### Return 1;content in case of success -sub mon_stats -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($mon_stats) = decrypt_params(@_); - if ($mon_stats ne "mon_stats") - { - logger "Invalid parameter '$mon_stats' given for $mon_stats function."; - return -1; - } - - my @disk = `df -hP -x tmpfs`; - my $encoded_content = encode_list(@disk); - my @uptime = `uptime`; - $encoded_content .= encode_list(@uptime); - return "1;$encoded_content"; -} - -sub exec -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($command) = decrypt_params(@_); - my @cmdret = `$command 2>/dev/null`; - my $encoded_content = encode_list(@cmdret); - return "1;$encoded_content"; -} - -# used in conjunction with the clone_home feature in the web panel -# this actually does the file copies -sub clone_home -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($source_home, $dest_home, $owner) = decrypt_params(@_); - my ($time_start, $time_stop, $time_diff); - logger "Copying from $source_home to $dest_home..."; - - # check size of source_home, make sure we have space to copy - if (!-e $source_home) - { - logger "ERROR - $source_home does not exist"; - return 0; - } - logger "Game home $source_home exists...copy will proceed"; - - # start the copy, and a timer - $time_start = time(); - if (!dircopy("$source_home", "$dest_home")) - { - $time_stop = time(); - $time_diff = $time_stop - $time_start; - logger - "Error occured after $time_diff seconds during copy of $source_home to $dest_home - $!"; - return 0; - } - else - { - $time_stop = time(); - $time_diff = $time_stop - $time_start; - logger - "Home clone completed successfully to $dest_home in $time_diff seconds"; - return 1; - } -} - -# used to delete the game home from the file system when it's removed from the panel -sub remove_home -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_path_del) = decrypt_params(@_); - - if (!-e $home_path_del) - { - logger "ERROR - $home_path_del does not exist...nothing to do"; - return 0; - } - - my $owner = get_path_owner($home_path_del); - secure_path_without_decrypt('chattr-i', $home_path_del); - my $deleted_home_dir = sudo_exec_without_decrypt('rm -rf \''.$home_path_del.'\''); - - if (defined LINUX_USER_PER_GAME_SERVER && LINUX_USER_PER_GAME_SERVER eq "1"){ - if ($owner ne SERVER_RUNNER_USER && begins_with($owner,'gamehome')){ - my $kill_all_user = sudo_exec_without_decrypt('killall -u "' . $owner . '"'); - my $deleted_user = sudo_exec_without_decrypt('userdel -r "' . $owner . '"'); - my ($retval_del_user, $enc_out_del_user) = split(/;/, $deleted_user, 2); - if ($retval_del_user == 1){ - logger "Removing and deleting user $owner"; - } - my $deleted_user_group = sudo_exec_without_decrypt('groupdel "' . $owner . '"'); - } - } - - my ($retval, $enc_out) = split(/;/, $deleted_home_dir, 2); - if ($retval == 1){ - logger "Deletetion of $home_path_del successful!"; - }else{ - logger "Deletetion of $home_path_del failed!"; - } - - return 1; -} - -sub restart_server -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return restart_server_without_decrypt(decrypt_params(@_)); -} - -### Restart the server -## return -2 CANT STOP -## return -1 CANT START (no startup file found that mach the home_id, port and ip) -## return 1 Restart OK -sub restart_server_without_decrypt -{ - my ($home_id, $server_ip, $server_port, $control_protocol, - $control_password, $control_type, $home_path, $server_exe, $run_dir, - $cmd, $cpu, $nice, $preStart, $envVars, $game_key, $console_log) = @_; - - if (stop_server_without_decrypt($home_id, $server_ip, - $server_port, $control_protocol, - $control_password, $control_type, $home_path) == 0) - { - # Wait for processes to be completely terminated and verify they are killed - logger "Waiting for server processes to terminate completely..."; - my $max_wait_attempts = 30; # 30 seconds max to wait for processes to die - my $wait_count = 0; - - while ($wait_count < $max_wait_attempts) - { - my @remaining_pids = get_home_pids($home_id); - if (@remaining_pids == 0) - { - logger "All server processes have been terminated successfully."; - last; - } - - $wait_count++; - logger "Waiting for processes to terminate... (attempt $wait_count/$max_wait_attempts, PIDs: @remaining_pids)"; - sleep 1; - } - - # Final check - if processes still exist, log warning but continue - my @final_check_pids = get_home_pids($home_id); - if (@final_check_pids > 0) - { - logger "Warning: Some processes may still be running (PIDs: @final_check_pids), but proceeding with restart."; - } - - # Wait 60 seconds between stop and start operations as requested - logger "Waiting 60 seconds before starting server as requested for reliable scheduler functionality..."; - sleep 60; - - if (universal_start_without_decrypt($home_id, $home_path, $server_exe, $run_dir, - $cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log) == 1) - { - return 1; - } - else - { - return -1; - } - } - else - { - return -2; - } -} - -sub find_user_by_screen_id -{ - my ($screen_id) = @_; - - my $screen_user = SERVER_RUNNER_USER; - - if(defined LINUX_USER_PER_GAME_SERVER && LINUX_USER_PER_GAME_SERVER eq "1"){ - $screen_user = `whoami`; - chomp $screen_user; - } - - my $ret = sudo_exec_without_decrypt('find /var/run/screen -name "*'.$screen_id.'"'); - - my ($retval, $enc_out) = split(/;/, $ret, 2); - - if($retval != 1) - { - return $screen_user; - } - - if( defined($enc_out) && $enc_out =~ /^(.+)\\n/ ) - { - my @dec_out = (); - foreach my $line (split /\\n/, $enc_out) { - my $dec_line = decode_base64($line); - push @dec_out, $dec_line; - } - - my @path_parts = split /\//, $dec_out[0]; - - if ($#path_parts == 5) - { - if($path_parts[5] =~ /^(\d+)\.$screen_id$/) - { - if ($path_parts[4] =~ /^S-/) - { - my $parseval = $path_parts[4]; - $parseval =~ s/^S-//g; - my $uid = `id -u $parseval`; - if( $uid =~ /^(\d+)$/ ) - { - $screen_user = $parseval; - } - } - } - } - } - - return $screen_user; -} - -sub get_path_owner -{ - my ($path) = @_; - - my $path_owner = SERVER_RUNNER_USER; - - if(defined LINUX_USER_PER_GAME_SERVER && LINUX_USER_PER_GAME_SERVER eq "1"){ - $path_owner = `whoami`; - chomp $path_owner; - } - - if(-d $path) - { - my $ret = sudo_exec_without_decrypt('stat -c "%U" "'.$path.'"'); - - my ($retval, $enc_out) = split(/;/, $ret, 2); - - if($retval != 1) - { - return $path_owner; - } - - if( defined($enc_out) && $enc_out =~ /^(.+)\\n/ ) - { - my @dec_out = (); - foreach my $line (split /\\n/, $enc_out) { - my $dec_line = decode_base64($line); - push @dec_out, $dec_line; - } - - my $parseval = $dec_out[0]; - my $uid = `id -u $parseval`; - - if( $uid =~ /^(\d+)$/ ) - { - $path_owner = $parseval; - } - } - } - - return $path_owner; -} - -sub sudo_exec -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $sudo_exec = &decrypt_param(@_); - return sudo_exec_without_decrypt($sudo_exec); -} - -sub sudo_exec_without_decrypt -{ - my ($sudo_exec, $as_user) = @_; - $sudo_exec =~ s/('+)/'"$1"'/g; - if( !defined($as_user) ) - { - $as_user = "root"; - } - - my $command = "echo '$SUDOPASSWD'|sudo -kS -p \"\" su -c '$sudo_exec;echo \$?' $as_user 2>&1"; - my @cmdret = qx($command); - $cmdret[0] =~ s/^//g if defined $cmdret[0]; - chomp(@cmdret); - - my $ret = pop(@cmdret); - chomp($ret); - - if ("X$ret" eq "X0") - { - return "1;".encode_list(@cmdret); - } - - return -1; -} - -sub sudo_exec_without_decrypt_no_return -{ - my ($sudo_exec, $as_user) = @_; - $sudo_exec =~ s/('+)/'"$1"'/g; - if( !defined($as_user) ) - { - $as_user = "root"; - } - - my $command = "echo '$SUDOPASSWD'|sudo -kS -p \"\" su -c '$sudo_exec' $as_user 2>&1"; - my @cmdret = qx($command); - $cmdret[0] =~ s/^//g if defined $cmdret[0]; - chomp(@cmdret); - - my $ret = pop(@cmdret); - chomp($ret); - - if ("X$ret" eq "X0") - { - return "1;".encode_list(@cmdret); - } - - return -1; -} - -sub secure_path -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return secure_path_without_decrypt(decrypt_params(@_)); -} - -sub secure_path_without_decrypt -{ - my ($action, $file_path, $returnType) = @_; - my $checkIfFileExists = 1; - - if(defined $returnType && $returnType eq "str"){ - $checkIfFileExists = 0; - } - - if($checkIfFileExists){ - if(! -e $file_path){ - return -1; - } - } - - $file_path =~ s/('+)/'\"$1\"'/g; - if($action eq "chattr+i") - { - if(defined $returnType && $returnType eq "str"){ - return 'chattr -Rf +i \''.$file_path.'\''; - }else{ - return sudo_exec_without_decrypt('chattr -Rf +i \''.$file_path.'\''); - } - } - elsif($action eq "chattr-i") - { - if(defined $returnType && $returnType eq "str"){ - return 'chattr -Rf -i \''.$file_path.'\''; - }else{ - return sudo_exec_without_decrypt('chattr -Rf -i \''.$file_path.'\''); - } - } - - return -1; -} - -sub get_chattr -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($file_path) = decrypt_params(@_); - my $file = $file_path; - $file_path =~ s/('+)/'\"$1\"'/g; - return sudo_exec_without_decrypt('(lsattr \''.$file_path.'\' | sed -e "s#'.$file.'##g")|grep -o i'); -} - -sub ftp_mgr -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($action, $login, $password, $home_path) = decrypt_params(@_); - - my $uid = `id -u`; - chomp $uid; - my $gid = `id -g`; - chomp $gid; - - $login =~ s/('+)/'\"$1\"'/g; - $password =~ s/('+)/'\"$1\"'/g; - $home_path =~ s/('+)/'\"$1\"'/g; - - if(!defined($Cfg::Preferences{ogp_manages_ftp}) || (defined($Cfg::Preferences{ogp_manages_ftp}) && $Cfg::Preferences{ogp_manages_ftp} eq "1")){ - if( defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "IspConfig") - { - use constant ISPCONFIG_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'IspConfig'); - use constant FTP_USERS_DIR => Path::Class::Dir->new(ISPCONFIG_DIR, 'ftp_users'); - - if (!-d FTP_USERS_DIR && !mkdir FTP_USERS_DIR) - { - print "Could not create " . FTP_USERS_DIR . " directory $!."; - return -1; - } - - chdir ISPCONFIG_DIR; - - if($action eq "list") - { - my $users_list; - opendir(USERS, FTP_USERS_DIR); - while (my $username = readdir(USERS)) - { - # Skip . and .. - next if $username =~ /^\./; - $users_list .= `php-cgi -f sites_ftp_user_get.php username=\'$username\'`; - } - closedir(USERS); - if( defined($users_list) ) - { - return "1;".encode_list($users_list); - } - } - elsif($action eq "userdel") - { - return "1;".encode_list(`php-cgi -f sites_ftp_user_delete.php username=\'$login\'`); - } - elsif($action eq "useradd") - { - return "1;".encode_list(`php-cgi -f sites_ftp_user_add.php username=\'$login\' password=\'$password\' dir=\'$home_path\' uid=$uid gid=$gid`); - } - elsif($action eq "passwd") - { - return "1;".encode_list(`php-cgi -f sites_ftp_user_update.php type=passwd username=\'$login\' password=\'$password\'`); - } - elsif($action eq "show") - { - return "1;".encode_list(`php-cgi -f sites_ftp_user_get.php type=detail username=\'$login\'`); - } - elsif($action eq "usermod") - { - return "1;".encode_list(`php-cgi -f sites_ftp_user_update.php username=\'$login\' password=\'$password\'`); - } - } - elsif(defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "EHCP" && (-e "/etc/init.d/ehcp" || -e "/lib/systemd/system/ehcp.service" || -e "/etc/systemd/system/ehcp.service" )) - { - use constant EHCP_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'EHCP'); - - chdir EHCP_DIR; - my $phpScript; - my $phpOut; - my $gidTwo = SERVER_RUNNER_USER; - - chmod 0777, 'ehcp_ftp_log.txt'; - - # In order to access the FTP files, the vsftpd user needs to be added to the ogp group - sudo_exec_without_decrypt("usermod -a -G '$gid' ftp"); - sudo_exec_without_decrypt("usermod -a -G '$gid' vsftpd"); - sudo_exec_without_decrypt("usermod -a -G '$gidTwo' ftp"); - sudo_exec_without_decrypt("usermod -a -G '$gidTwo' vsftpd"); - - if($action eq "list") - { - return "1;".encode_list(`php-cgi -f listAllUsers.php`); - } - elsif($action eq "userdel") - { - $phpScript = `php-cgi -f delAccount.php username=\'$login\'`; - $phpOut = `php-cgi -f syncftp.php`; - return $phpScript; - } - elsif($action eq "useradd") - { - $phpScript = `php-cgi -f addAccount.php username=\'$login\' password=\'$password\' dir=\'$home_path\' uid=$uid gid=$gid`; - $phpOut = `php-cgi -f syncftp.php`; - return $phpScript; - } - elsif($action eq "passwd") - { - $phpScript = `php-cgi -f updatePass.php username=\'$login\' password=\'$password\'`; - $phpOut = `php-cgi -f syncftp.php`; - return $phpScript ; - } - elsif($action eq "show") - { - return "1;".encode_list(`php-cgi -f showAccount.php username=\'$login\'`); - } - elsif($action eq "usermod") - { - $phpScript = `php-cgi -f updateInfo.php username=\'$login\' password=\'$password\'`; - $phpOut = `php-cgi -f syncftp.php`; - return $phpScript; - } - } - elsif(defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "proftpd" && -e $Cfg::Preferences{proftpd_conf_path}) - { - chdir $Cfg::Preferences{proftpd_conf_path}; - if($action eq "list") - { - my $users; - open(PASSWD, 'ftpd.passwd'); - while () { - chomp; - my($login, $passwd, $uid, $gid, $gcos, $home, $shell) = split(/:/); - $users .= "$login\t$home\n"; - } - close(PASSWD); - return "1;".encode_list($users); - } - elsif($action eq "userdel") - { - return sudo_exec_without_decrypt("ftpasswd --passwd --delete-user --name='$login'"); - } - elsif($action eq "useradd") - { - return sudo_exec_without_decrypt("echo '$password' | ftpasswd --passwd --name='$login' --home='$home_path' --shell=/bin/false --uid=$uid --gid=$gid --stdin"); - } - elsif($action eq "passwd") - { - return sudo_exec_without_decrypt("echo '$password' | ftpasswd --passwd --change-password --name='$login' --stdin"); - } - elsif($action eq "show") - { - return 1; - } - elsif($action eq "usermod") - { - return 1; - } - chdir AGENT_RUN_DIR; - } - else - { - if($action eq "list") - { - return sudo_exec_without_decrypt("pure-pw list"); - } - elsif($action eq "userdel") - { - return sudo_exec_without_decrypt("pure-pw userdel '$login' && pure-pw mkdb"); - } - elsif($action eq "useradd") - { - return sudo_exec_without_decrypt("(echo '$password'; echo '$password') | pure-pw useradd '$login' -u $uid -g $gid -d '$home_path' && pure-pw mkdb"); - } - elsif($action eq "passwd") - { - return sudo_exec_without_decrypt("(echo '$password'; echo '$password') | pure-pw passwd '$login' && pure-pw mkdb"); - } - elsif($action eq "show") - { - return sudo_exec_without_decrypt("pure-pw show '$login'"); - } - elsif($action eq "usermod") - { - my $update_account = "pure-pw usermod '$login' -u $uid -g $gid"; - - my @account_settings = split /[\n]+/, $password; - - foreach my $setting (@account_settings) { - my ($key, $value) = split /[\t]+/, $setting; - - if( $key eq 'Directory' ) - { - $value =~ s/('+)/'\"$1\"'/g; - $update_account .= " -d '$value'"; - } - - if( $key eq 'Full_name' ) - { - if( $value ne "" ) - { - $value =~ s/('+)/'\"$1\"'/g; - $update_account .= " -c '$value'"; - } - else - { - $update_account .= ' -c ""'; - } - } - - if( $key eq 'Download_bandwidth' && $value ne "" ) - { - my $Download_bandwidth; - if($value eq 0) - { - $Download_bandwidth = "\"\""; - } - else - { - $Download_bandwidth = $value; - } - $update_account .= " -t " . $Download_bandwidth; - } - - if( $key eq 'Upload___bandwidth' && $value ne "" ) - { - my $Upload___bandwidth; - if($value eq 0) - { - $Upload___bandwidth = "\"\""; - } - else - { - $Upload___bandwidth = $value; - } - $update_account .= " -T " . $Upload___bandwidth; - } - - if( $key eq 'Max_files' ) - { - if( $value eq "0" ) - { - $update_account .= ' -n ""'; - } - elsif( $value ne "" ) - { - $update_account .= " -n " . $value; - } - else - { - $update_account .= ' -n ""'; - } - } - - if( $key eq 'Max_size' ) - { - if( $value ne "" && $value ne "0" ) - { - $update_account .= " -N " . $value; - } - else - { - $update_account .= ' -N ""'; - } - } - - if( $key eq 'Ratio' && $value ne "" ) - { - my($upload_ratio,$download_ratio) = split/:/,$value; - - if($upload_ratio eq "0") - { - $upload_ratio = "\"\""; - } - $update_account .= " -q " . $upload_ratio; - - if($download_ratio eq "0") - { - $download_ratio = "\"\""; - } - $update_account .= " -Q " . $download_ratio; - } - - if( $key eq 'Allowed_client_IPs' ) - { - if( $value ne "" ) - { - $update_account .= " -r " . $value; - } - else - { - $update_account .= ' -r ""'; - } - } - - if( $key eq 'Denied__client_IPs' ) - { - if( $value ne "" ) - { - $update_account .= " -R " . $value; - } - else - { - $update_account .= ' -R ""'; - } - } - - if( $key eq 'Allowed_local__IPs' ) - { - if( $value ne "" ) - { - $update_account .= " -i " . $value; - } - else - { - $update_account .= ' -i ""'; - } - } - - if( $key eq 'Denied__local__IPs' ) - { - if( $value ne "" ) - { - $update_account .= " -I " . $value; - } - else - { - $update_account .= ' -I ""'; - } - } - - - if( $key eq 'Max_sim_sessions' && $value ne "" ) - { - $update_account .= " -y " . $value; - } - - if ( $key eq 'Time_restrictions' ) - { - if( $value eq "0000-0000") - { - $update_account .= ' -z ""'; - } - elsif( $value ne "" ) - { - $update_account .= " -z " . $value; - } - else - { - $update_account .= ' -z ""'; - } - } - } - $update_account .=" && pure-pw mkdb"; - # print $update_account; - return sudo_exec_without_decrypt($update_account); - } - } - } - return 0; -} - -sub start_fastdl -{ - if(-e Path::Class::File->new(FD_DIR, 'Settings.pm')) - { - system('perl FastDownload/ForkedDaemon.pm &'); - sleep(1); - return 1; - } - else - { - return -2; - } -} - -sub stop_fastdl -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return stop_fastdl_without_decrypt(); -} - -sub stop_fastdl_without_decrypt -{ - my $pid; - open(PIDFILE, '<', FD_PID_FILE) - || logger "Error reading pid file $!",1; - while () - { - $pid = $_; - chomp $pid; - } - close(PIDFILE); - my $cnt = kill 9, $pid; - if ($cnt == 1) - { - logger "Fast Download Daemon Stopped.",1; - return 1; - } - else - { - logger "Fast Download Daemon with pid $pid can not be stopped.",1; - return -1; - } -} - -sub restart_fastdl -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return restart_fastdl_without_decrypt(); -} - -sub restart_fastdl_without_decrypt -{ - if((fastdl_status_without_decrypt() == -1) || (stop_fastdl_without_decrypt() == 1)) - { - if(start_fastdl() == 1) - { - # Success - return 1; - } - # Cant start - return -2; - } - # Cant stop - return -3; -} - -sub fastdl_status -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return fastdl_status_without_decrypt(); -} - -sub fastdl_status_without_decrypt -{ - my $pid; - if(!open(PIDFILE, '<', FD_PID_FILE)) - { - logger "Error reading pid file $!"; - return -1; - } - while () - { - $pid = $_; - chomp $pid; - } - close(PIDFILE); - my $cnt = kill 0, $pid; - if ($cnt == 1) - { - return 1; - } - else - { - return -1; - } -} - -sub fastdl_get_aliases -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my %aliases; - my $i; - my @file_lines; - if(-d FD_ALIASES_DIR) - { - if( !opendir(ALIASES, FD_ALIASES_DIR) ) - { - logger "Error openning aliases directory " . FD_ALIASES_DIR . ", $!"; - } - else - { - while (my $alias = readdir(ALIASES)) - { - # Skip . and .. - next if $alias =~ /^\./; - if( !open(ALIAS, '<', Path::Class::Dir->new(FD_ALIASES_DIR, $alias)) ) - { - logger "Error reading alias '$alias', $!"; - } - else - { - $i = 0; - @file_lines = (); - while () - { - chomp $_; - $file_lines[$i] = $_; - $i++; - } - close(ALIAS); - $aliases{$alias}{home} = $file_lines[0]; - $aliases{$alias}{match_file_extension} = $file_lines[1]; - $aliases{$alias}{match_client_ip} = $file_lines[2]; - } - } - closedir(ALIASES); - } - } - else - { - logger "Aliases directory '" . FD_ALIASES_DIR . "' does not exist or is inaccessible."; - } - return {%aliases}; -} - -sub fastdl_del_alias -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - foreach my $alias (decrypt_params(@_)) - { - unlink Path::Class::File->new(FD_ALIASES_DIR, $alias); - } - return restart_fastdl_without_decrypt(); -} - -sub fastdl_add_alias -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($alias,$home,$match_file_extension,$match_client_ip) = decrypt_params(@_); - if(!-e FD_ALIASES_DIR) - { - if(!mkdir FD_ALIASES_DIR) - { - logger "ERROR - Failed to create " . FD_ALIASES_DIR . " directory."; - return -1; - } - } - my $alias_path = Path::Class::File->new(FD_ALIASES_DIR, $alias); - if (!open(ALIAS, '>', $alias_path)) - { - logger "ERROR - Failed to open ".$alias_path." for writing."; - return -1; - } - else - { - print ALIAS "$home\n"; - print ALIAS "$match_file_extension\n"; - print ALIAS "$match_client_ip"; - close(ALIAS); - return restart_fastdl_without_decrypt(); - } -} - -sub fastdl_get_info -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - if(-e Path::Class::File->new(FD_DIR, 'Settings.pm')) - { - delete $INC{"FastDownload/Settings.pm"}; - require "FastDownload/Settings.pm"; # Settings for Fast Download Daemon. - if(not defined $FastDownload::Settings{autostart_on_agent_startup}) - { - $FastDownload::Settings{autostart_on_agent_startup} = 0; - } - return {'port' => $FastDownload::Settings{port}, - 'ip' => $FastDownload::Settings{ip}, - 'listing' => $FastDownload::Settings{listing}, - 'autostart_on_agent_startup'=> $FastDownload::Settings{autostart_on_agent_startup}}; - } - return -1 -} - -sub fastdl_create_config -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - if(!-e FD_DIR) - { - if(!mkdir FD_DIR) - { - logger "ERROR - Failed to create " . FD_DIR . " directory."; - return -1; - } - } - my ($fd_address, $fd_port, $listing, $autostart_on_agent_startup) = decrypt_params(@_); - my $settings_string = "%FastDownload::Settings = (\n". - "\tport => $fd_port,\n". - "\tip => '$fd_address',\n". - "\tlisting => $listing,\n". - "\tautostart_on_agent_startup => $autostart_on_agent_startup,\n". - ");"; - my $settings = Path::Class::File->new(FD_DIR, 'Settings.pm'); - if (!open(SETTINGS, '>', $settings)) - { - logger "ERROR - Failed to open $settings for writing."; - return -1; - } - else - { - print SETTINGS $settings_string; - close(SETTINGS); - } - logger "$settings file written successfully."; - return 1; -} - -sub agent_restart -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $dec_check = decrypt_param(@_); - if ($dec_check eq 'restart') - { - chdir AGENT_RUN_DIR; - if(-e "ogp_agent_run.pid") - { - my $init_pid = `cat ogp_agent_run.pid`; - chomp($init_pid); - - if(kill 0, $init_pid) - { - my $or_exist = ""; - my $rm_pid_file = ""; - if(-e "ogp_agent.pid") - { - $rm_pid_file = " ogp_agent.pid"; - my $agent_pid = `cat ogp_agent.pid`; - chomp($agent_pid); - if( kill 0, $agent_pid ) - { - $or_exist = " -o -e /proc/$agent_pid"; - } - } - - open (AGENT_RESTART_SCRIPT, '>', 'tmp_restart.sh'); - my $restart = "echo -n \"Stopping OGP Agent...\"\n". - "kill $init_pid\n". - "while [ -e /proc/$init_pid $or_exist ];do echo -n .;sleep 1;done\n". - "rm -f ogp_agent_run.pid $rm_pid_file\necho \" [OK]\"\n". - "echo -n \"Starting OGP Agent...\"\n". - "screen -d -m -t \"ogp_agent\" -c \"" . SCREENRC_FILE . "\" -S ogp_agent bash ogp_agent_run -pidfile ogp_agent_run.pid\n". - "while [ ! -e ogp_agent_run.pid -o ! -e ogp_agent.pid ];do echo -n .;sleep 1;done\n". - "echo \" [OK]\"\n". - "rm -f tmp_restart.sh\n". - "exit 0\n"; - print AGENT_RESTART_SCRIPT $restart; - close (AGENT_RESTART_SCRIPT); - if( -e 'tmp_restart.sh' ) - { - system('screen -d -m -t "agent_restart" -c "' . SCREENRC_FILE . '" -S agent_restart bash tmp_restart.sh'); - } - } - } - } - return -1; -} - -# Subroutines to be called -sub scheduler_dispatcher { - my ($task, $args) = @_; - my $response = `$args`; - chomp($response); - my $log = "Executed command: $args"; - if($response ne "") - { - $log .= ", response:\n$response"; - } - scheduler_log_events($log); -} - -sub scheduler_server_action -{ - my ($task, $args) = @_; - my ($action, @server_args) = split('\|\%\|', $args); - if($action eq "%ACTION=start") - { - my ($home_id, $ip, $port) = ($server_args[0], $server_args[6], $server_args[5]); - my $ret = universal_start_without_decrypt(@server_args); - if($ret == 1) - { - scheduler_log_events("Started server home ID $home_id on address $ip:$port"); - } - else - { - scheduler_log_events("Failed starting server home ID $home_id on address $ip:$port (Check agent log)"); - } - } - elsif($action eq "%ACTION=stop") - { - my ($home_id, $ip, $port) = ($server_args[0], $server_args[1], $server_args[2]); - my $ret = stop_server_without_decrypt(@server_args); - if($ret == 0) - { - scheduler_log_events("Stopped server home ID $home_id on address $ip:$port"); - } - elsif($ret == 1) - { - scheduler_log_events("Failed stopping server home ID $home_id on address $ip:$port (Invalid IP:Port given)"); - } - } - elsif($action eq "%ACTION=restart") - { - my ($home_id, $ip, $port) = ($server_args[0], $server_args[1], $server_args[2]); - my $ret = restart_server_without_decrypt(@server_args); - if($ret == 1) - { - scheduler_log_events("Restarted server home ID $home_id on address $ip:$port"); - } - elsif($ret == -1) - { - scheduler_log_events("Failed restarting server home ID $home_id on address $ip:$port (Server could not be started, check agent log)"); - } - elsif($ret == -2) - { - scheduler_log_events("Failed restarting server home ID $home_id on address $ip:$port (Server could not be stopped, check agent log)"); - } - } - return 1; -} - -sub scheduler_log_events -{ - my $logcmd = $_[0]; - $logcmd = localtime() . " $logcmd\n"; - logger "Can't open " . SCHED_LOG_FILE . " - $!" unless open(LOGFILE, '>>', SCHED_LOG_FILE); - logger "Failed to lock " . SCHED_LOG_FILE . "." unless flock(LOGFILE, LOCK_EX); - logger "Failed to seek to end of " . SCHED_LOG_FILE . "." unless seek(LOGFILE, 0, 2); - logger "Failed to write to " . SCHED_LOG_FILE . "." unless print LOGFILE "$logcmd"; - logger "Failed to unlock " . SCHED_LOG_FILE . "." unless flock(LOGFILE, LOCK_UN); - logger "Failed to close " . SCHED_LOG_FILE . "." unless close(LOGFILE); -} - -sub scheduler_add_task -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $new_task = decrypt_param(@_); - if (open(TASKS, '>>', SCHED_TASKS)) - { - print TASKS "$new_task\n"; - logger "Created new task: $new_task"; - close(TASKS); - scheduler_stop(); - # Create new object with default dispatcher for scheduled tasks - $cron = new Schedule::Cron( \&scheduler_dispatcher, { - nofork => 1, - loglevel => 0, - log => sub { print $_[1], "\n"; } - } ); - - $cron->add_entry( "* * * * * *", \&scheduler_read_tasks ); - # Run scheduler - $cron->run( {detach=>1, pid_file=>SCHED_PID} ); - return 1; - } - logger "Cannot create task: $new_task ( $! )"; - return -1; -} - -sub scheduler_del_task -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $name = decrypt_param(@_); - my @cronJobIDs = split(',', $name); - if( scheduler_read_tasks() == -1 ) - { - return -1; - } - my @entries = $cron->list_entries(); - if(open(TASKS, '>', SCHED_TASKS)) - { - foreach my $task ( @entries ) { - next if ( grep { $_ eq $task->{args}[0]} @cronJobIDs ); - next unless $task->{args}[0] =~ /task_[0-9]*/; - if(defined $task->{args}[1]) - { - print TASKS join(" ", $task->{time}, $task->{args}[1]) . "\n"; - } - else - { - print TASKS $task->{time} . "\n"; - } - } - close( TASKS ); - scheduler_stop(); - # Create new object with default dispatcher for scheduled tasks - $cron = new Schedule::Cron( \&scheduler_dispatcher, { - nofork => 1, - loglevel => 0, - log => sub { print $_[1], "\n"; } - } ); - - $cron->add_entry( "* * * * * *", \&scheduler_read_tasks ); - # Run scheduler - $cron->run( {detach=>1, pid_file=>SCHED_PID} ); - return 1; - } - logger "Cannot open file " . SCHED_TASKS . " for deleting task(s) id: $name ( $! )",1; - return -1; -} - -sub scheduler_edit_task -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($name, $new_task) = decrypt_params(@_); - if( scheduler_read_tasks() == -1 ) - { - return -1; - } - my @entries = $cron->list_entries(); - if(open(TASKS, '>', SCHED_TASKS)) - { - foreach my $task ( @entries ) { - next unless $task->{args}[0] =~ /task_[0-9]*/; - if($name eq $task->{args}[0]) - { - print TASKS "$new_task\n"; - } - else - { - if(defined $task->{args}[1]) - { - print TASKS join(" ", $task->{time}, $task->{args}[1]) . "\n"; - } - else - { - print TASKS $task->{time} . "\n"; - } - } - } - close( TASKS ); - scheduler_stop(); - # Create new object with default dispatcher for scheduled tasks - $cron = new Schedule::Cron( \&scheduler_dispatcher, { - nofork => 1, - loglevel => 0, - log => sub { print $_[1], "\n"; } - } ); - - $cron->add_entry( "* * * * * *", \&scheduler_read_tasks ); - # Run scheduler - $cron->run( {detach=>1, pid_file=>SCHED_PID} ); - return 1; - } - logger "Cannot open file " . SCHED_TASKS . " for editing task id: $name ( $! )",1; - return -1; -} - -sub scheduler_read_tasks -{ - if( open(TASKS, '<', SCHED_TASKS) ) - { - $cron->clean_timetable(); - } - else - { - logger "Error reading tasks file $!"; - scheduler_stop(); - return -1; - } - - my $i = 0; - while () - { - next if $_ =~ /^(#.*|[\s|\t]*?\n)/; - my ($minute, $hour, $dayOfTheMonth, $month, $dayOfTheWeek, @args) = split(' ', $_); - my $time = "$minute $hour $dayOfTheMonth $month $dayOfTheWeek"; - if("@args" =~ /^\%ACTION.*/) - { - $cron->add_entry($time, \&scheduler_server_action, 'task_' . $i++, "@args"); - } - else - { - $cron->add_entry($time, 'task_' . $i++, "@args"); - } - } - close(TASKS); - return 1; -} - -sub scheduler_stop -{ - my $pid; - if(open(PIDFILE, '<', SCHED_PID)) - { - $pid = ; - chomp $pid; - close(PIDFILE); - if($pid ne "") - { - if( kill 0, $pid ) - { - my $cnt = kill 9, $pid; - if ($cnt == 1) - { - unlink SCHED_PID; - return 1; - } - } - } - } - return -1; -} - -sub scheduler_list_tasks -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - if( scheduler_read_tasks() == -1 ) - { - return -1; - } - my @entries = $cron->list_entries(); - my %entries_array; - foreach my $task ( @entries ) { - if( defined $task->{args}[1] ) - { - $entries_array{$task->{args}[0]} = encode_base64(join(" ", $task->{time}, $task->{args}[1])); - } - else - { - $entries_array{$task->{args}[0]} = encode_base64($task->{time}); - } - } - if( %entries_array ) - { - return {%entries_array}; - } - return -1; -} - -sub get_file_part -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($file, $offset) = decrypt_params(@_); - if (!open(FILE, '<', $file)) - { - logger "ERROR - Can't open file $file for reading."; - return -1; - } - - binmode(FILE); - - if($offset != 0) - { - return -1 unless seek FILE, $offset, 0; - } - - my $data = ""; - my ($n, $buf); - my $limit = $offset + 60 * 57 * 1000; #Max 3420Kb (1000 iterations) (top statistics ~ VIRT 116m, RES 47m) - while (($n = read FILE, $buf, 60 * 57) != 0 && $offset <= $limit ) { - $data .= $buf; - $offset += $n; - } - close(FILE); - - if( $data ne "" ) - { - my $b64zlib = encode_base64(compress($data,9)); - return "$offset;$b64zlib"; - } - else - { - return -1; - } -} - -sub stop_update -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $home_id = decrypt_param(@_); - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - system('screen -S '.$screen_id.' -p 0 -X stuff $\'\003\''); - if ($? == 0) - { - return 0; - } - return 1 -} - -sub shell_action -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($action, $arguments) = decrypt_params(@_); - - if($action eq 'remove_file') - { - chomp($arguments); - unlink($arguments); - return "1;"; - } - elsif($action eq 'remove_recursive') - { - my @items = split(';', $arguments); - foreach my $item ( @items ) { - chomp($item); - if(-d $item) - { - pathrmdir($item); - } - else - { - unlink($item); - } - } - return "1;"; - } - elsif($action eq 'create_dir') - { - chomp($arguments); - mkpath($arguments); - return "1;"; - } - elsif($action eq 'move') - { - my($src, $dest) = split(';', $arguments); - chomp($src); - chomp($dest); - if(-d $src) - { - $dest = Path::Class::Dir->new($dest, basename($src)); - dirmove($src, $dest); - } - else - { - fmove($src, $dest); - } - return "1;"; - } - elsif($action eq 'rename') - { - my($src, $dest) = split(';', $arguments); - chomp($src); - chomp($dest); - if(-d $src) - { - dirmove($src, $dest); - } - else - { - fmove($src, $dest); - } - return "1;"; - } - elsif($action eq 'copy') - { - my($src, $dest) = split(';', $arguments); - chomp($src); - chomp($dest); - if(-d $src) - { - $dest = Path::Class::Dir->new($dest, basename($src)); - dircopy($src, $dest); - } - else - { - fcopy($src, $dest); - } - return "1;"; - } - elsif($action eq 'touch') - { - chomp($arguments); - open(FH, '>', $arguments); - print FH ""; - close(FH); - return "1;"; - } - elsif($action eq 'size') - { - chomp($arguments); - my $size = 0; - if(-d $arguments) - { - find(sub { $size += -s }, $arguments ? $arguments : '.'); - } - else - { - $size += (stat($arguments))[7]; - } - return "1;" . encode_list($size); - } - elsif($action eq 'get_cpu_usage') - { - my %prev_idle; - my %prev_total; - open(STAT, '/proc/stat'); - while () { - next unless /^cpu([0-9]+)/; - my @stat = split /\s+/, $_; - $prev_idle{$1} = $stat[4]; - $prev_total{$1} = $stat[1] + $stat[2] + $stat[3] + $stat[4]; - } - close STAT; - sleep 1; - my %idle; - my %total; - open(STAT, '/proc/stat'); - while () { - next unless /^cpu([0-9]+)/; - my @stat = split /\s+/, $_; - $idle{$1} = $stat[4]; - $total{$1} = $stat[1] + $stat[2] + $stat[3] + $stat[4]; - } - close STAT; - my %cpu_percent_usage; - foreach my $key ( keys %idle ) - { - my $diff_idle = $idle{$key} - $prev_idle{$key}; - my $diff_total = $total{$key} - $prev_total{$key}; - my $percent = (100 * ($diff_total - $diff_idle)) / $diff_total; - $percent = sprintf "%.2f", $percent unless $percent == 0; - $cpu_percent_usage{$key} = encode_base64($percent); - } - return {%cpu_percent_usage}; - } - elsif($action eq 'get_ram_usage') - { - my($total, $buffers, $cached, $free) = qw(0 0 0 0); - open(STAT, '/proc/meminfo'); - while () { - $total += $1 if /MemTotal\:\s+(\d+) kB/; - $buffers += $1 if /Buffers\:\s+(\d+) kB/; - $cached += $1 if /Cached\:\s+(\d+) kB/; - $free += $1 if /MemFree\:\s+(\d+) kB/; - } - close STAT; - my $used = $total - $free - $cached - $buffers; - my $percent = 100 * $used / $total; - my %mem_usage; - $mem_usage{'used'} = encode_base64($used * 1024); - $mem_usage{'total'} = encode_base64($total * 1024); - $mem_usage{'percent'} = encode_base64($percent); - return {%mem_usage}; - } - elsif($action eq 'get_disk_usage') - { - my($total, $used, $free) = split(' ', `df -lP 2>/dev/null|grep "^/dev/.*"|awk '{total+=\$2}{used+=\$3}{free+=\$4} END {print total, used, free}'`); - my $percent = 100 * $used / $total; - my %disk_usage; - $disk_usage{'free'} = encode_base64($free * 1024); - $disk_usage{'used'} = encode_base64($used * 1024); - $disk_usage{'total'} = encode_base64($total * 1024); - $disk_usage{'percent'} = encode_base64($percent); - return {%disk_usage}; - } - elsif($action eq 'get_uptime') - { - open(STAT, '/proc/uptime'); - my $uptime = 0; - while () { - $uptime += $1 if /^([0-9]+)/; - } - close STAT; - my %upsince; - $upsince{'0'} = encode_base64($uptime); - $upsince{'1'} = encode_base64(time - $uptime); - return {%upsince}; - } - elsif($action eq 'get_tasklist') - { - my %taskList; - $taskList{'task'} = encode_base64(qx[top -b -c -i -w512 -n2 -o+%CPU|awk '/^top/{i++}i==2'|grep 'PID' -A 30]); - return {%taskList}; - } - elsif($action eq 'get_timestamp') - { - return "1;" . encode_list(time); - } - return 0; -} - -sub remote_query -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($protocol, $game_type, $ip, $c_port, $q_port, $s_port) = decrypt_params(@_); - my $command = "which php-cgi 2>&1;echo \$?"; - my @cmdret = qx($command); - chomp(@cmdret); - my $ret = pop(@cmdret); - chomp($ret); - if ("X$ret" ne "X0") - { - return -1; - } - my $PHP_CGI = "@cmdret"; - my $php_query_dir = Path::Class::Dir->new(AGENT_RUN_DIR, 'php-query'); - if($protocol eq 'lgsl') - { - chdir($php_query_dir->subdir('lgsl')); - my $cmd = $PHP_CGI . - " -f lgsl_feed.php" . - " lgsl_type=" . $game_type . - " ip=" . $ip . - " c_port=" . $c_port . - " q_port=" . $q_port . - " s_port=" . $s_port . - " request=sp"; - my $response = `$cmd`; - chomp($response); - chdir(AGENT_RUN_DIR); - if($response eq "FAILURE") - { - return -1; - } - return encode_base64($response, ""); - } - elsif($protocol eq 'gameq') - { - chdir($php_query_dir->subdir('gameq')); - my $cmd = $PHP_CGI . - " -f gameq_feed.php" . - " game_type=" . $game_type . - " ip=" . $ip . - " c_port=" . $c_port . - " q_port=" . $q_port . - " s_port=" . $s_port; - my $response = `$cmd`; - chomp($response); - chdir(AGENT_RUN_DIR); - if($response eq "FAILURE") - { - return -1; - } - return encode_base64($response, ""); - } - return -1; -} - -sub send_steam_guard_code -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id, $sgc) = decrypt_params(@_); - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - system('screen -S '.$screen_id.' -p 0 -X stuff "'.$sgc.'$(printf \\\\r)"'); - if ($? == 0) - { - return 0; - } - return 1 -} - -sub steam_workshop -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return steam_workshop_without_decrypt(decrypt_params(@_)); -} - -#### Run the steam client #### -### @return 1 If installation started -### @return -1 In error case. -sub steam_workshop_without_decrypt -{ - my ($home_id, $mods_full_path, - $workshop_id, $mods_list, - $regex, $mods_backreference_index, - $variable, $place_after, $mod_string, - $string_separator, $config_file_path, - $post_install, $mod_names_list, - $anonymous_login, $user, $pass, - $download_method, $url_list, $filename_list) = @_; - - # Creates mods path if it doesn't exist - my $owner = SERVER_RUNNER_USER; - - if(defined LINUX_USER_PER_GAME_SERVER && LINUX_USER_PER_GAME_SERVER eq "1"){ - $owner = `whoami`; - chomp $owner; - } - - if ( check_b4_chdir($mods_full_path, $owner) != 0) - { - return -1; - } - - my $secure = "$mods_full_path/secure.sh"; - my $home_path = $mods_full_path; - $home_path =~ s/('+)/'\"$1\"'/g; - my $sec = $secure; - $sec =~ s/('+)/'\"$1\"'/g; - open FILE, '>', $secure; - print FILE "chmod 771 '$home_path'\n". - "rm -f '$sec'"; - close FILE; - - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - my @workshop_mods = split /,/, $mods_list; - my @installcmds; - - if($download_method eq 'steamcmd') - { - my $steam_binary = STEAMCMD_CLIENT_BIN; - my $installSteamFile = $screen_id . "_workshop.txt"; - my $installtxt = Path::Class::File->new(STEAMCMD_CLIENT_DIR, $installSteamFile); - - open FILE, '>', $installtxt; - print FILE "\@ShutdownOnFailedCommand 1\n"; - print FILE "\@NoPromptForPassword 1\n"; - if($anonymous_login eq "0") - { - print FILE "login $user $pass\n"; - } - else - { - print FILE "login anonymous\n"; - } - print FILE "force_install_dir \"$mods_full_path\"\n"; - foreach my $workshop_mod (@workshop_mods) - { - print FILE "workshop_download_item $workshop_id $workshop_mod\n"; - } - print FILE "exit\n"; - close FILE; - @installcmds = ("$steam_binary +runscript $installtxt +exit"); - } - - if($download_method eq 'steamapi') - { - my @urls = split /,/, $url_list; - my @filenames = split /,/, $filename_list; - my $index = 0; - foreach my $workshop_mod_id (@workshop_mods) - { - my $steamcmd_download_path = '/steamapps/workshop/content/'.$workshop_id.'/'.$workshop_mod_id.'/'; - - my $workshop_mod_path = $mods_full_path.$steamcmd_download_path; - if(!-d $workshop_mod_path && !mkpath $workshop_mod_path) - { - logger "Folder $workshop_mod_path could not be created."; - $index++; - next; - } - my $url = $urls[$index]; - my $filename = $filenames[$index]; - my $download_file_path = Path::Class::File->new($workshop_mod_path, "$filename"); - $installcmds[$index] = "wget -O \"$download_file_path\" \"$url\""; - $index++; - } - } - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - backup_home_log($home_id, $log_file); - - my $precmd = ""; - my $postcmd = ""; - - $postcmd .= generate_post_install_scripts($mods_full_path, $workshop_id, $mods_list, - $regex, $mods_backreference_index, - $variable, $place_after, $mod_string, - $string_separator, $config_file_path, - $post_install, $mod_names_list); - - my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id; - - if ( check_b4_chdir($bash_scripts_path, $owner) != 0) - { - return -1; - } - - my $installfile = create_bash_scripts($mods_full_path, $bash_scripts_path, $precmd, $postcmd, @installcmds); - - my $screen_cmd = create_screen_cmd($screen_id, "./$installfile"); - - logger "Installing Steam Workshop content on server Home ID " . $home_id; - system($screen_cmd); - - return 1; -} - -sub generate_post_install_scripts -{ - my ($mods_full_path, $workshop_id, $mods_list, - $regex, $mods_backreference_index, - $variable, $place_after, $mod_string, - $string_separator, $config_file_path, - $post_install, $mod_names_list) = @_; - - my $post_install_scripts = ""; - my $mods_info_path = Path::Class::Dir->new(AGENT_RUN_DIR, 'WorkshopModsInfo'); - $post_install_scripts .= "mods_full_path=\"$mods_full_path\"\n". - "workshop_id=\"$workshop_id\"\n". - "regex=\"$regex\"\n". - "mods_backreference_index=\"$mods_backreference_index\"\n". - "variable=\"$variable\"\n". - "place_after=\"$place_after\"\n". - "string_separator=\"$string_separator\"\n". - "config_file_path=\"$config_file_path\"\n". - "mods_info_path=\"$mods_info_path/\"\n"; - my @workshop_mods = split /,/, $mods_list; - my @mod_names = split /,/, $mod_names_list; - - my $index = 0; - foreach my $workshop_mod_id (@workshop_mods) - { - my $steamcmd_download_path = '/steamapps/workshop/content/'.$workshop_id.'/'.$workshop_mod_id.'/'; - my $workshop_mod_path = $mods_full_path.$steamcmd_download_path; - my $this_mod_string = $mod_string; - $this_mod_string =~ s/\%workshop_mod_id\%/$workshop_mod_id/g; - - $post_install_scripts .= "mod_string[$index]=\"$this_mod_string\"\n". - "mod_name[$index]=\"".$mod_names[$index]."\"\n". - "workshop_mod_id[$index]=\"$workshop_mod_id\"\n". - "workshop_mod_path[$index]=\"$workshop_mod_path\"\n"; - $index++; - } - - $post_install_scripts .= 'if [ ! -e $config_file_path ];then'."\n". - ' if [ ! -d "$(dirname $config_file_path)" ];then mkdir -p "$(dirname $config_file_path)";fi'."\n". - ' echo -e "${place_after}\n${variable}" > $config_file_path'."\n". - 'fi'."\n". - 'i=0'."\n". - 'for mod_id in "${workshop_mod_id[@]}"'."\n". - 'do'."\n". - ' first_file="$(ls "${workshop_mod_path[$i]}"| sort -n | head -1)"'."\n"; - - my @post_install_lines = split /[\r\n]+/, $post_install; - foreach my $line (@post_install_lines) { - if($line ne ""){ - $line =~ s/\%mods_full_path\%/\$mods_full_path/g; - $line =~ s/\%workshop_mod_id\%/\$mod_id/g; - $line =~ s/\%first_file\%/\$first_file/g; - $post_install_scripts .= "\t".$line."\n"; - } - } - - $post_install_scripts .= ' file_content=$(cat $config_file_path)'."\n". - ' if [[ $file_content =~ $regex ]]; then'."\n". - ' full_match="${BASH_REMATCH[0]}"'."\n". - ' mods_match="${BASH_REMATCH[$mods_backreference_index]}"'."\n". - ' found=1'."\n". - ' else'."\n". - ' found=0'."\n". - ' fi'."\n". - ' first_file_string="\%first_file%"'."\n". - - ' if [ -z "${mod_string[$i]##*$first_file_string*}" ];then'."\n". - ' mod_string[$i]="${mod_string[$i]/$first_file_string/$first_file}"'."\n". - ' fi'."\n". - ' if [ $found == 1 ] && [ "X$full_match" != "X" ];then'."\n". - ' if [ "X$mods_match" == "X" ];then'."\n". - ' new_mods=$(echo -e "${full_match}${mod_string[$i]}")'."\n". - ' echo -e "${file_content/$full_match/$new_mods}">"$config_file_path"'."\n". - ' else'."\n". - ' if [ ! -z "${mods_match##*${mod_string[$i]}*}" ];then'."\n". - ' new_mods=$(echo -e "${full_match}${string_separator}${mod_string[$i]}")'."\n". - ' echo -e "${file_content/$full_match/$new_mods}">"$config_file_path"'."\n". - ' fi'."\n". - ' fi'."\n". - ' else'."\n". - ' if [ "X$place_after" == "X" ];then'."\n". - ' echo -e "${file_content}${variable}${mod_string[$i]}">"$config_file_path"'."\n". - ' else'."\n". - ' if [ -z "${file_content##*${place_after}*}" ];then'."\n". - ' new_var="${variable}${mod_string[$i]}"'."\n". - ' place_after_esc=$(echo -e "$place_after"|sed -e \'s/[]\\/$*.^[]/\\\\&/g\')'."\n". - ' echo -e "$file_content"|sed \'/\'$place_after_esc\'/a \'$new_var>"$config_file_path"'."\n". - ' else'."\n". - ' echo -e "${file_content}${place_after}\n${variable}${mod_string[$i]}">"$config_file_path"'."\n". - ' fi'."\n". - ' fi'."\n". - ' fi'."\n". - ' if [ ! -d "${mods_info_path}" ];then mkdir -p "${mods_info_path}";fi'."\n". - ' echo "${mod_name[$i]}" > "${mods_info_path}${mod_string[$i]}.ogpmod"'."\n". - ' i=$(expr $i + 1)'."\n". - 'done'."\n"; - return "$post_install_scripts"; -} - -sub get_workshop_mods_info() -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - - my $mods_info_dir_path = Path::Class::Dir->new(AGENT_RUN_DIR, 'WorkshopModsInfo'); - - if(-d $mods_info_dir_path) - { - opendir(MODS_INFO_DIR, $mods_info_dir_path) or return -1; - my @mods_info; - while(my $mod_info_file = readdir(MODS_INFO_DIR)) - { - if($mod_info_file =~ /\.ogpmod$/) - { - my $mod_info_file_path = Path::Class::File->new($mods_info_dir_path, $mod_info_file); - if(open(my $fh, '<:encoding(UTF-8)', $mod_info_file_path)) - { - my $row = <$fh>; - chomp $row; - if($row ne "") - { - my ($string_name, $ext) = split(/\.ogp/, $mod_info_file); - push @mods_info, "$string_name:$row"; - } - close($fh); - } - } - } - closedir(MODS_INFO_DIR); - return "1;".encode_list(@mods_info); - } - - return -1; -} - -sub get_setting_using_api -{ - my ($setting_name) = @_; - - if(defined WEB_API_URL && WEB_API_URL ne "" && defined WEB_ADMIN_API_KEY && WEB_ADMIN_API_KEY ne ""){ - my $url = WEB_API_URL . "?setting/get&setting_name=" . $setting_name . "&token=" . WEB_ADMIN_API_KEY; - my $ua = LWP::UserAgent->new; - $ua->agent('Mozilla/5.0'); - $ua->timeout(5); - $ua->ssl_opts( verify_hostname => 0 ,SSL_verify_mode => 0x00); - my $response = $ua->get($url); - return $response->decoded_content(); - } - - return -1; -} - -sub is_integer { - defined $_[0] && $_[0] =~ /^[+-]?\d+$/; -} - -sub get_minecraft_rcon_port{ - my ($home_dir) = @_; - my $port = -1; - my $findStr = "rcon.port="; - my $file = Path::Class::File->new($home_dir, "server.properties"); - - open(FH, '<', $file) or return -1; - - while(){ - if (begins_with($_,$findStr)){ - $port = int(substr($_, length($findStr))); - last; - } - } - - close(FH); - - return $port; -} - -sub begins_with -{ - return substr($_[0], 0, length($_[1])) eq $_[1]; -} - -sub generate_random_password{ - my ($length) = @_; - my @alphanumeric = ('a'..'z', 'A'..'Z', 0..9,'!','_','-'); - my @numeric = (0..9); - my $randpassword = ''; - - if(not defined $length || not is_integer($length)){ - $length = 16; - } - - until ( length($randpassword) > $length ) { - $randpassword = $randpassword . join '', map $alphanumeric[rand @alphanumeric], 0..(rand @numeric); - } - - return $randpassword; -} - -sub trim{ - my $s = shift; - $s =~ s/^\s+|\s+$//g; - return $s -}; - -################################################################## -# Resource Stats Collection System -################################################################## - -# Get current timestamp in MySQL format -sub get_utc_timestamp { - my ($sec, $min, $hour, $mday, $mon, $year) = gmtime(); - return sprintf("%04d-%02d-%02d %02d:%02d:%02d", - $year + 1900, $mon + 1, $mday, $hour, $min, $sec); -} - -# Connect to stats database -sub connect_stats_db { - # Check if DBD::mysql is available - eval { require DBD::mysql; }; - if ($@) { - logger "DBD::mysql not available - resource stats collection disabled"; - return undef; - } - - my $dsn = "DBI:mysql:database=" . STATS_DB_NAME . ";host=" . STATS_DB_HOST; - my $dbh = eval { DBI->connect($dsn, STATS_DB_USER, STATS_DB_PASS, - { RaiseError => 1, AutoCommit => 1, mysql_enable_utf8 => 1 }) }; - - if ($@) { - logger "Failed to connect to stats database: $@"; - return undef; - } - - return $dbh; -} - -# Ensure machine exists in gsp_machines table -sub ensure_machine_exists { - my ($dbh, $machine_id, $hostname) = @_; - - my $table = STATS_TABLE_PREFIX . "machines"; - my $sql = "INSERT IGNORE INTO $table (machine_id, hostname) VALUES (?, ?)"; - - eval { - my $sth = $dbh->prepare($sql); - $sth->execute($machine_id, $hostname); - $sth->finish(); - }; - - if ($@) { - logger "Failed to ensure machine exists: $@"; - return 0; - } - - return 1; -} - -# Get machine-wide system stats using native tools -sub collect_machine_stats { - my $stats = {}; - - # Get load averages - if (open(my $fh, '<', '/proc/loadavg')) { - my $line = <$fh>; - close($fh); - if ($line =~ /^(\S+)\s+(\S+)\s+(\S+)/) { - $stats->{load1} = $1; - $stats->{load5} = $2; - $stats->{load15} = $3; - } - } - - # Get CPU usage (using existing function logic) - my %prev_idle; - my %prev_total; - if (open(my $fh, '<', '/proc/stat')) { - while (<$fh>) { - next unless /^cpu\s+/; - my @stat = split /\s+/, $_; - # cpu user nice system idle iowait irq softirq steal guest guest_nice - my $idle = $stat[4]; - my $total = $stat[1] + $stat[2] + $stat[3] + $stat[4] + ($stat[5] || 0) + ($stat[6] || 0) + ($stat[7] || 0); - $prev_idle{all} = $idle; - $prev_total{all} = $total; - last; - } - close($fh); - } - - sleep(1); # Wait for CPU measurement - - my %idle; - my %total; - if (open(my $fh, '<', '/proc/stat')) { - while (<$fh>) { - next unless /^cpu\s+/; - my @stat = split /\s+/, $_; - my $idle = $stat[4]; - my $total = $stat[1] + $stat[2] + $stat[3] + $stat[4] + ($stat[5] || 0) + ($stat[6] || 0) + ($stat[7] || 0); - $idle{all} = $idle; - $total{all} = $total; - last; - } - close($fh); - } - - if (exists $prev_total{all} && $prev_total{all} > 0) { - my $diff_idle = $idle{all} - $prev_idle{all}; - my $diff_total = $total{all} - $prev_total{all}; - if ($diff_total > 0) { - $stats->{cpu_pct} = sprintf("%.2f", (100 * ($diff_total - $diff_idle)) / $diff_total); - } - } - - # Get memory info - my ($mem_total, $mem_free, $mem_buffers, $mem_cached) = (0, 0, 0, 0); - my ($swap_total, $swap_free) = (0, 0); - - if (open(my $fh, '<', '/proc/meminfo')) { - while (<$fh>) { - $mem_total = $1 * 1024 if /MemTotal:\s+(\d+) kB/; - $mem_free = $1 * 1024 if /MemFree:\s+(\d+) kB/; - $mem_buffers = $1 * 1024 if /Buffers:\s+(\d+) kB/; - $mem_cached = $1 * 1024 if /Cached:\s+(\d+) kB/; - $swap_total = $1 * 1024 if /SwapTotal:\s+(\d+) kB/; - $swap_free = $1 * 1024 if /SwapFree:\s+(\d+) kB/; - } - close($fh); - } - - my $mem_used = $mem_total - $mem_free - $mem_buffers - $mem_cached; - $stats->{mem_used_bytes} = $mem_used; - $stats->{mem_total_bytes} = $mem_total; - $stats->{mem_used_pct} = $mem_total > 0 ? sprintf("%.2f", ($mem_used * 100) / $mem_total) : 0; - - my $swap_used = $swap_total - $swap_free; - $stats->{swap_used_bytes} = $swap_used; - $stats->{swap_total_bytes} = $swap_total; - - # Get disk usage for agent directory - my $disk_path = AGENT_RUN_DIR; - my $df_output = `df -P '$disk_path' 2>/dev/null | tail -1`; - if ($df_output =~ /\S+\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)%/) { - $stats->{disk_path} = $disk_path; - $stats->{disk_total_bytes} = $1 * 1024; - $stats->{disk_used_bytes} = $2 * 1024; - $stats->{disk_used_pct} = $4; - } - - # Get default network interface and stats - my $default_iface = get_default_network_interface(); - $stats->{net_iface} = $default_iface; - - if ($default_iface) { - my ($rx_bytes, $tx_bytes) = get_network_stats($default_iface); - $stats->{rx_bytes} = $rx_bytes; - $stats->{tx_bytes} = $tx_bytes; - - # Get interface speed (try ethtool, fallback to /sys) - my $speed_mbps = get_interface_speed($default_iface); - $stats->{iface_speed_mbps} = $speed_mbps; - } - - return $stats; -} - -# Get default network interface -sub get_default_network_interface { - # Try to find default route interface - if (open(my $fh, '<', '/proc/net/route')) { - while (<$fh>) { - my @parts = split /\s+/, $_; - if (@parts >= 11 && $parts[1] eq '00000000' && hex($parts[3]) & 2) { - close($fh); - return $parts[0]; - } - } - close($fh); - } - - # Fallback: find first up interface - my @interfaces = glob('/sys/class/net/*'); - for my $iface_path (@interfaces) { - my $iface = (split '/', $iface_path)[-1]; - next if $iface eq 'lo'; # Skip loopback - - if (open(my $fh, '<', "$iface_path/operstate")) { - my $state = <$fh>; - close($fh); - chomp $state; - return $iface if $state eq 'up'; - } - } - - return undef; -} - -# Get network interface statistics -sub get_network_stats { - my ($interface) = @_; - my ($rx_bytes, $tx_bytes) = (0, 0); - - if (open(my $fh, '<', "/sys/class/net/$interface/statistics/rx_bytes")) { - $rx_bytes = <$fh>; - chomp $rx_bytes; - close($fh); - } - - if (open(my $fh, '<', "/sys/class/net/$interface/statistics/tx_bytes")) { - $tx_bytes = <$fh>; - chomp $tx_bytes; - close($fh); - } - - return ($rx_bytes, $tx_bytes); -} - -# Get network interface speed -sub get_interface_speed { - my ($interface) = @_; - - # Try /sys/class/net first - if (open(my $fh, '<', "/sys/class/net/$interface/speed")) { - my $speed = <$fh>; - close($fh); - chomp $speed; - return $speed if $speed && $speed =~ /^\d+$/; - } - - # Try ethtool as fallback - my $ethtool_output = `ethtool '$interface' 2>/dev/null | grep Speed`; - if ($ethtool_output =~ /Speed:\s*(\d+)Mb\/s/) { - return $1; - } - - return undef; -} - -# Get folder size using du command -sub get_folder_size_bytes { - my ($folder_path) = @_; - return 0 unless -d $folder_path; - - my $du_output = `du -sb '$folder_path' 2>/dev/null`; - if ($du_output =~ /^(\d+)/) { - return $1; - } - - return 0; -} - -# Find server processes based on directory association -sub find_server_processes { - my @server_dirs = (); - - # Find server directories (similar to Python collector) - if (opendir(my $dh, AGENT_RUN_DIR)) { - while (my $entry = readdir($dh)) { - next if $entry =~ /^\./; # Skip hidden directories - my $path = Path::Class::Dir->new(AGENT_RUN_DIR, $entry); - push @server_dirs, $path if -d $path; - } - closedir($dh); - } - - my %server_procs = (); - - # Get all running processes - my @processes = get_all_processes(); - - # Associate processes with server directories - for my $server_dir (@server_dirs) { - my $server_path = "$server_dir"; - $server_procs{$server_path} = []; - - for my $proc (@processes) { - my $pid = $proc->{pid}; - my $cwd = $proc->{cwd} || ''; - my $exe = $proc->{exe} || ''; - my $cmd = $proc->{cmd} || ''; - - # Check if process is associated with this server directory - if ($cwd =~ /^\Q$server_path\E/ || - $exe =~ /^\Q$server_path\E/ || - index($cmd, $server_path) >= 0) { - push @{$server_procs{$server_path}}, $proc; - } - } - } - - return %server_procs; -} - -# Get all running processes with details -sub get_all_processes { - my @processes = (); - - # Read process list from /proc - if (opendir(my $dh, '/proc')) { - while (my $entry = readdir($dh)) { - next unless $entry =~ /^\d+$/; # Only numeric PIDs - - my $proc_info = get_process_info($entry); - push @processes, $proc_info if $proc_info; - } - closedir($dh); - } - - return @processes; -} - -# Get detailed information about a specific process -sub get_process_info { - my ($pid) = @_; - my $proc = { pid => $pid }; - - # Get process name - if (open(my $fh, '<', "/proc/$pid/comm")) { - $proc->{name} = <$fh>; - chomp $proc->{name}; - close($fh); - } - - # Get command line - if (open(my $fh, '<', "/proc/$pid/cmdline")) { - my $cmdline = <$fh>; - close($fh); - if ($cmdline) { - $cmdline =~ s/\0/ /g; # Replace null separators with spaces - $proc->{cmd} = $cmdline; - } - } - - # Get current working directory - my $cwd = readlink("/proc/$pid/cwd"); - $proc->{cwd} = $cwd if $cwd; - - # Get executable path - my $exe = readlink("/proc/$pid/exe"); - $proc->{exe} = $exe if $exe; - - # Get memory info - if (open(my $fh, '<', "/proc/$pid/status")) { - while (<$fh>) { - if (/VmRSS:\s+(\d+) kB/) { - $proc->{rss_bytes} = $1 * 1024; - } elsif (/VmSize:\s+(\d+) kB/) { - $proc->{vms_bytes} = $1 * 1024; - } - } - close($fh); - } - - # Get I/O stats - if (open(my $fh, '<', "/proc/$pid/io")) { - while (<$fh>) { - if (/read_bytes:\s+(\d+)/) { - $proc->{io_read_bytes} = $1; - } elsif (/write_bytes:\s+(\d+)/) { - $proc->{io_write_bytes} = $1; - } - } - close($fh); - } - - # Get file descriptor count - if (opendir(my $dh, "/proc/$pid/fd")) { - my @fds = readdir($dh); - $proc->{open_fds} = @fds - 2; # Subtract . and .. - closedir($dh); - } - - # Get CPU percentage (placeholder - would need sampling period) - $proc->{cpu_pct} = 0; # Will be calculated during collection - - return $proc; -} - -# Get listening ports for a process -sub get_process_listening_ports { - my ($pid) = @_; - my @ports = (); - - # Check /proc/net/tcp and /proc/net/udp - for my $proto (qw(tcp udp)) { - if (open(my $fh, '<', "/proc/net/$proto")) { - while (<$fh>) { - chomp; - my @fields = split /\s+/, $_; - next unless @fields >= 10; - - # Check if this socket belongs to our process - my $inode = $fields[9]; - next unless $inode; - - if (opendir(my $dh, "/proc/$pid/fd")) { - while (my $fd = readdir($dh)) { - next if $fd =~ /^\./; - my $link = readlink("/proc/$pid/fd/$fd"); - if ($link && $link =~ /socket:\[$inode\]/) { - # Parse local address and port - my $local = $fields[1]; - if ($local =~ /:([0-9A-F]+)$/) { - my $port = hex($1); - push @ports, $port; - } - last; - } - } - closedir($dh); - } - } - close($fh); - } - } - - return join(',', sort { $a <=> $b } @ports); -} - -# Insert machine sample into database -sub insert_machine_sample { - my ($dbh, $timestamp, $machine_id, $stats) = @_; - - my $table = STATS_TABLE_PREFIX . "machine_samples"; - my $sql = qq{ - INSERT INTO $table - (machine_id, ts, load1, load5, load15, cpu_pct, - mem_used_bytes, mem_total_bytes, mem_used_pct, - swap_used_bytes, swap_total_bytes, - disk_path, disk_total_bytes, disk_used_bytes, disk_used_pct, - net_iface, rx_bytes, tx_bytes, iface_speed_mbps) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - }; - - eval { - my $sth = $dbh->prepare($sql); - $sth->execute( - $machine_id, $timestamp, - $stats->{load1}, $stats->{load5}, $stats->{load15}, $stats->{cpu_pct}, - $stats->{mem_used_bytes}, $stats->{mem_total_bytes}, $stats->{mem_used_pct}, - $stats->{swap_used_bytes}, $stats->{swap_total_bytes}, - $stats->{disk_path}, $stats->{disk_total_bytes}, $stats->{disk_used_bytes}, $stats->{disk_used_pct}, - $stats->{net_iface}, $stats->{rx_bytes}, $stats->{tx_bytes}, $stats->{iface_speed_mbps} - ); - $sth->finish(); - }; - - if ($@) { - logger "Failed to insert machine sample: $@"; - return 0; - } - - return 1; -} - -# Insert process sample into database -sub insert_process_sample { - my ($dbh, $timestamp, $machine_id, $server_name, $server_path, $proc, $folder_size) = @_; - - my $table = STATS_TABLE_PREFIX . "process_samples"; - my $sql = qq{ - INSERT INTO $table - (machine_id, ts, server_name, server_path, - pid, proc_name, cmd, cpu_pct, - rss_bytes, vms_bytes, mem_pct, - io_read_bytes, io_write_bytes, open_fds, - listening_ports, folder_size_bytes) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - }; - - # Get listening ports for this process - my $ports = get_process_listening_ports($proc->{pid}); - - eval { - my $sth = $dbh->prepare($sql); - $sth->execute( - $machine_id, $timestamp, $server_name, $server_path, - $proc->{pid}, $proc->{name}, $proc->{cmd}, $proc->{cpu_pct}, - $proc->{rss_bytes}, $proc->{vms_bytes}, 0, # mem_pct placeholder - $proc->{io_read_bytes}, $proc->{io_write_bytes}, $proc->{open_fds}, - $ports, $folder_size - ); - $sth->finish(); - }; - - if ($@) { - logger "Failed to insert process sample: $@"; - return 0; - } - - return 1; -} - -# Main resource stats collection function -sub collect_resource_stats { - logger "Starting resource stats collection"; - - # Connect to database - my $dbh = connect_stats_db(); - return unless $dbh; - - my $timestamp = get_utc_timestamp(); - my $machine_id = $ENV{GS_MACHINE_ID} || `hostname`; - chomp $machine_id; - my $hostname = `hostname`; - chomp $hostname; - - # Ensure machine exists in database - unless (ensure_machine_exists($dbh, $machine_id, $hostname)) { - $dbh->disconnect(); - return; - } - - # Collect machine-wide stats - my $machine_stats = collect_machine_stats(); - unless (insert_machine_sample($dbh, $timestamp, $machine_id, $machine_stats)) { - $dbh->disconnect(); - return; - } - - # Collect per-server process stats - my %server_procs = find_server_processes(); - - for my $server_path (keys %server_procs) { - my $server_name = (split '/', $server_path)[-1]; - my $folder_size = get_folder_size_bytes($server_path); - - for my $proc (@{$server_procs{$server_path}}) { - insert_process_sample($dbh, $timestamp, $machine_id, - $server_name, $server_path, $proc, $folder_size); - } - } - - $dbh->disconnect(); - logger "Resource stats collection completed"; -} diff --git a/_agent-windows/ogp_agent.pl b/_agent-windows/ogp_agent.pl deleted file mode 100644 index 2d0f2bd6..00000000 --- a/_agent-windows/ogp_agent.pl +++ /dev/null @@ -1,4667 +0,0 @@ -#!/usr/bin/perl -# -# OGP - Open Game Panel -# Copyright (C) 2008 - 2014 The OGP Development Team -# -# http://www.opengamepanel.org/ -# -# This program 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 2 -# of the License, or any later version. -# -# This program 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 this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# - -use warnings; -use strict; - -use Cwd; # Fast way to get the current directory -use lib getcwd(); -use Frontier::Daemon::OGP::Forking; # Forking XML-RPC server -use File::Copy; # Simple file copy functions -use File::Copy::Recursive - qw(fcopy rcopy dircopy fmove rmove dirmove pathempty pathrmdir) - ; # Used to copy whole directories -use File::Basename; # Used to get the file name or the directory name from a given path -use Crypt::XXTEA; # Encryption between webpages and agent. -use Cfg::Config; # Config file -use Cfg::Preferences; # Preferences file -use Fcntl ':flock'; # Import LOCK_* constants for file locking -use LWP::UserAgent; # Used for fetching URLs -use MIME::Base64; # Used to ensure data travelling right through the network. -use Getopt::Long; # Used for command line params. -use Path::Class::File; # Used to handle files and directories. -use File::Path qw(mkpath); -use Archive::Extract; # Used to handle archived files. -use File::Find; -use Schedule::Cron; # Used for scheduling tasks - -# Compression tools -use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error); # Used to compress files to bz2. -use Compress::Zlib; # Used to compress file download buffers to zlib. -use Archive::Tar; # Used to create tar, tgz or tbz archives. -use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); # Used to create zip archives. - -# Database modules for resource stats -use DBI; # Database interface -eval "use DBD::mysql"; # MySQL driver (optional, will skip stats if not available) - -# Current location of the agent. -use constant AGENT_RUN_DIR => getcwd(); - -# Load our config file values -use constant AGENT_KEY => $Cfg::Config{key}; -use constant AGENT_IP => $Cfg::Config{listen_ip}; -use constant AGENT_LOG_FILE => $Cfg::Config{logfile}; -use constant AGENT_PORT => $Cfg::Config{listen_port}; -use constant AGENT_VERSION => $Cfg::Config{version}; -use constant SCREEN_LOG_LOCAL => $Cfg::Preferences{screen_log_local}; -use constant DELETE_LOGS_AFTER => $Cfg::Preferences{delete_logs_after}; -use constant AGENT_PID_FILE => - Path::Class::File->new(AGENT_RUN_DIR, 'ogp_agent.pid'); -use constant AGENT_RSYNC_GENERIC_LOG => - Path::Class::File->new(AGENT_RUN_DIR, 'rsync_update_generic.log'); -use constant STEAM_LICENSE_OK => "Accept"; -use constant STEAM_LICENSE => $Cfg::Config{steam_license}; -use constant MANUAL_TMP_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'tmp'); -use constant SHARED_GAME_TMP_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'shared'); -use constant STEAMCMD_CLIENT_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'steamcmd'); -use constant STEAMCMD_CLIENT_BIN => - Path::Class::File->new(STEAMCMD_CLIENT_DIR, 'steamcmd.exe'); -use constant SCREEN_LOGS_DIR => - Path::Class::Dir->new(AGENT_RUN_DIR, 'screenlogs'); -use constant GAME_STARTUP_DIR => - Path::Class::Dir->new(AGENT_RUN_DIR, 'startups'); -use constant SCREENRC_FILE => - Path::Class::File->new(AGENT_RUN_DIR, 'ogp_screenrc'); -use constant SCREENRC_FILE_BK => - Path::Class::File->new(AGENT_RUN_DIR, 'ogp_screenrc_bk'); -use constant SCREEN_TYPE_HOME => "HOME"; -use constant SCREEN_TYPE_UPDATE => "UPDATE"; -use constant FD_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'FastDownload'); -use constant FD_ALIASES_DIR => Path::Class::Dir->new(FD_DIR, 'aliases'); -use constant FD_PID_FILE => Path::Class::File->new(FD_DIR, 'fd.pid'); -use constant SCHED_PID => Path::Class::File->new(AGENT_RUN_DIR, 'scheduler.pid'); -use constant SCHED_TASKS => Path::Class::File->new(AGENT_RUN_DIR, 'scheduler.tasks'); -use constant SCHED_LOG_FILE => Path::Class::File->new(AGENT_RUN_DIR, 'scheduler.log'); -use constant USER_RUNNING_SCRIPT => getlogin || getpwuid($<) || "cyg_server"; - -# Resource stats database constants -use constant STATS_DB_HOST => $Cfg::Config{stats_db_host}; -use constant STATS_DB_USER => $Cfg::Config{stats_db_user}; -use constant STATS_DB_PASS => $Cfg::Config{stats_db_pass}; -use constant STATS_DB_NAME => $Cfg::Config{stats_db_name}; -use constant STATS_TABLE_PREFIX => $Cfg::Config{stats_table_prefix}; -use constant STATS_FREQUENCY_MINUTES => $Cfg::Config{stats_frequency_minutes}; - -my $no_startups = 0; -my $clear_startups = 0; -our $log_std_out = 0; - -GetOptions( - 'no-startups' => \$no_startups, - 'clear-startups' => \$clear_startups, - 'log-stdout' => \$log_std_out - ); - -# Starting the agent as root user is not supported anymore. -if ($< == 0) -{ - print "ERROR: You are trying to start the agent as root user."; - print "This is not currently supported. If you wish to start the"; - print "you need to create a normal user account for it."; - exit 1; -} - -### Logger function. -### @param line the line that is put to the log file. -sub logger -{ - my $logcmd = $_[0]; - my $also_print = 0; - - if (@_ == 2) - { - ($also_print) = $_[1]; - } - - $logcmd = localtime() . " $logcmd\n"; - - if ($log_std_out == 1) - { - print "$logcmd"; - return; - } - if ($also_print == 1) - { - print "$logcmd"; - } - - open(LOGFILE, '>>', AGENT_LOG_FILE) - or die("Can't open " . AGENT_LOG_FILE . " - $!"); - flock(LOGFILE, LOCK_EX) or die("Failed to lock log file."); - seek(LOGFILE, 0, 2) or die("Failed to seek to end of file."); - print LOGFILE "$logcmd" or die("Failed to write to log file."); - flock(LOGFILE, LOCK_UN) or die("Failed to unlock log file."); - close(LOGFILE) or die("Failed to close log file."); -} - -# If for some reason the screenrc file doesn't exist, restore it from the backup copy -# I've seen this happen a few times -if (! -e SCREENRC_FILE) -{ - copy(SCREENRC_FILE_BK,SCREENRC_FILE); -} - -# Check the screen logs folder -if (!-d SCREEN_LOGS_DIR && !mkdir SCREEN_LOGS_DIR) -{ - logger "Could not create " . SCREEN_LOGS_DIR . " directory $!.", 1; - exit -1; -} - -# Check the global shared games folder -if (!-d SHARED_GAME_TMP_DIR && !mkdir SHARED_GAME_TMP_DIR) -{ - logger "Could not create " . SHARED_GAME_TMP_DIR . " directory $!.", 1; - exit -1; -} - -# Rotate the log file -if (-e AGENT_LOG_FILE) -{ - if (-e AGENT_LOG_FILE . ".bak") - { - unlink(AGENT_LOG_FILE . ".bak"); - } - logger "Rotating log file"; - move(AGENT_LOG_FILE, AGENT_LOG_FILE . ".bak"); - logger "New log file created"; -} - -logger "User running agent script is: " . USER_RUNNING_SCRIPT; - -if (check_steam_cmd_client() == -1) -{ - print "ERROR: You must download and uncompress the new steamcmd package."; - print "ENSURE TO INSTALL IT IN /OGP/steamcmd directory,"; - print "so it can be managed by the agent to install servers."; - exit 1; -} - -# create the directory for startup flags -if (!-e GAME_STARTUP_DIR) -{ - logger "Creating the startups directory " . GAME_STARTUP_DIR . ""; - if (!mkdir GAME_STARTUP_DIR) - { - my $message = - "Failed to create the " - . GAME_STARTUP_DIR - . " directory - check permissions. Errno: $!"; - logger $message, 1; - exit 1; - } -} -elsif ($clear_startups) -{ - opendir(STARTUPDIR, GAME_STARTUP_DIR); - while (my $startup_file = readdir(STARTUPDIR)) - { - - # Skip . and .. - next if $startup_file =~ /^\./; - $startup_file = Path::Class::File->new(GAME_STARTUP_DIR, $startup_file); - logger "Removing " . $startup_file . "."; - unlink($startup_file); - } - closedir(STARTUPDIR); -} -# If the directory already existed check if we need to start some games. -elsif ($no_startups != 1) -{ - system('screen -wipe > /dev/null 2>&1'); - # Loop through all the startup flags, and call universal startup - opendir(STARTUPDIR, GAME_STARTUP_DIR); - logger "Reading startup flags from " . GAME_STARTUP_DIR . ""; - while (my $dirlist = readdir(STARTUPDIR)) - { - - # Skip . and .. - next if $dirlist =~ /^\./; - logger "Found $dirlist"; - open(STARTFILE, '<', Path::Class::Dir->new(GAME_STARTUP_DIR, $dirlist)) - || logger "Error opening start flag $!"; - while () - { - my ( - $home_id, $home_path, $server_exe, - $run_dir, $startup_cmd, $server_port, - $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log - ) = split(',', $_); - - if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == - 1) - { - logger - "This server ($server_exe on $server_ip : $server_port) is already running (ID: $home_id)."; - next; - } - - logger "Starting server_exe $server_exe from home $home_path."; - universal_start_without_decrypt( - $home_id, $home_path, $server_exe, - $run_dir, $startup_cmd, $server_port, - $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log - ); - } - close(STARTFILE); - } - closedir(STARTUPDIR); -} - -# Create the pid file -open(PID, '>', AGENT_PID_FILE) - or die("Can't write to pid file - " . AGENT_PID_FILE . "\n"); -print PID "$$\n"; -close(PID); - -logger "Open Game Panel - Agent started - " - . AGENT_VERSION - . " - port " - . AGENT_PORT - . " - PID $$", 1; - -# Stop previous scheduler process if exists -scheduler_stop(); -# Create new object with default dispatcher for scheduled tasks -my $cron = new Schedule::Cron( \&scheduler_dispatcher, { - nofork => 1, - loglevel => 0, - log => sub { print $_[1], "\n"; } - } ); - -$cron->add_entry( "* * * * * *", \&scheduler_read_tasks ); - -# Add resource stats collection task -my $stats_frequency = STATS_FREQUENCY_MINUTES || 5; -my $stats_cron_pattern = "*/$stats_frequency * * * *"; # Every N minutes -$cron->add_entry( $stats_cron_pattern, \&collect_resource_stats ); - -# Run scheduler -$cron->run( {detach=>1, pid_file=>SCHED_PID} ); - -if(-e Path::Class::File->new(FD_DIR, 'Settings.pm')) -{ - require "FastDownload/Settings.pm"; # Settings for Fast Download Daemon. - if(defined($FastDownload::Settings{autostart_on_agent_startup}) && $FastDownload::Settings{autostart_on_agent_startup} eq "1") - { - start_fastdl(); - } -} - -my $d = Frontier::Daemon::OGP::Forking->new( - methods => { - is_screen_running => \&is_screen_running, - universal_start => \&universal_start, - cpu_count => \&cpu_count, - rfile_exists => \&rfile_exists, - quick_chk => \&quick_chk, - steam_cmd => \&steam_cmd, - fetch_steam_version => \&fetch_steam_version, - installed_steam_version => \&installed_steam_version, - automatic_steam_update => \&automatic_steam_update, - get_log => \&get_log, - stop_server => \&stop_server, - send_rcon_command => \&send_rcon_command, - dirlist => \&dirlist, - dirlistfm => \&dirlistfm, - readfile => \&readfile, - writefile => \&writefile, - rebootnow => \&rebootnow, - what_os => \&what_os, - start_file_download => \&start_file_download, - is_file_download_in_progress => \&is_file_download_in_progress, - uncompress_file => \&uncompress_file, - discover_ips => \&discover_ips, - mon_stats => \&mon_stats, - exec => \&exec, - clone_home => \&clone_home, - remove_home => \&remove_home, - start_rsync_install => \&start_rsync_install, - rsync_progress => \&rsync_progress, - restart_server => \&restart_server, - sudo_exec => \&sudo_exec, - master_server_update => \&master_server_update, - secure_path => \&secure_path, - get_chattr => \&get_chattr, - ftp_mgr => \&ftp_mgr, - compress_files => \&compress_files, - stop_fastdl => \&stop_fastdl, - restart_fastdl => \&restart_fastdl, - fastdl_status => \&fastdl_status, - fastdl_get_aliases => \&fastdl_get_aliases, - fastdl_add_alias => \&fastdl_add_alias, - fastdl_del_alias => \&fastdl_del_alias, - fastdl_get_info => \&fastdl_get_info, - fastdl_create_config => \&fastdl_create_config, - agent_restart => \&agent_restart, - scheduler_add_task => \&scheduler_add_task, - scheduler_del_task => \&scheduler_del_task, - scheduler_list_tasks => \&scheduler_list_tasks, - scheduler_edit_task => \&scheduler_edit_task, - get_file_part => \&get_file_part, - stop_update => \&stop_update, - shell_action => \&shell_action, - remote_query => \&remote_query, - send_steam_guard_code => \&send_steam_guard_code, - steam_workshop => \&steam_workshop, - get_workshop_mods_info => \&get_workshop_mods_info - }, - debug => 4, - LocalPort => AGENT_PORT, - LocalAddr => AGENT_IP, - ReuseAddr => '1' -) or die "Couldn't start OGP Agent: $!"; - -sub backup_home_log -{ - my ($home_id, $log_file, $console_log_file) = @_; - - my $home_backup_dir = SCREEN_LOGS_DIR . "/home_id_" . $home_id; - - if( ! -e $home_backup_dir ) - { - if( ! mkdir $home_backup_dir ) - { - logger "Can not create a backup directory at $home_backup_dir."; - return 1; - } - } - - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); - - my $backup_file_name = $mday . $mon . $year . '_' . $hour . 'h' . $min . 'm' . $sec . "s.log"; - - my $output_path = $home_backup_dir . "/" . $backup_file_name; - - # Used for deleting log files older than DELETE_LOGS_AFTER - my @file_list; - my @find_dirs; # directories to search - my $now = time(); # get current time - my $days; - if((DELETE_LOGS_AFTER =~ /^[+-]?\d+$/) && (DELETE_LOGS_AFTER > 0)){ - $days = DELETE_LOGS_AFTER; # how many days old - }else{ - $days = 30; # how many days old - } - my $seconds_per_day = 60*60*24; # seconds in a day - my $AGE = $days*$seconds_per_day; # age in seconds - push (@find_dirs, $home_backup_dir); - - # Create local copy of log file backup in the log_backups folder and current user home directory if SCREEN_LOG_LOCAL = 1 - if(SCREEN_LOG_LOCAL == 1) - { - # Create local backups folder - my $local_log_folder = Path::Class::Dir->new("logs_backup"); - - if(!-e $local_log_folder){ - mkdir($local_log_folder); - } - - # Add full path to @find_dirs so that log files older than DELETE_LOGS_AFTER are deleted - my $fullpath_to_local_logs = Path::Class::Dir->new(getcwd(), "logs_backup"); - push (@find_dirs, $fullpath_to_local_logs); - - my $log_local = $local_log_folder . "/" . $backup_file_name; - - # Delete the local log file if it already exists - if(-e $log_local){ - unlink $log_local; - } - - # If the log file contains UPDATE in the filename, do not allow users to see it since it will contain steam credentials - # Will return -1 for not existing - my $isUpdate = index($log_file,SCREEN_TYPE_UPDATE); - - if($isUpdate == -1){ - copy($log_file,$log_local); - } - } - - # Delete all files in @find_dirs older than DELETE_LOGS_AFTER days - find ( sub { - my $file = $File::Find::name; - if ( -f $file ) { - push (@file_list, $file); - } - }, @find_dirs); - - # Include the custom console path - and also do a size check on it - if(defined $console_log_file && $console_log_file ne ""){ - my $path_to_console_file = $console_log_file; - if( -f $path_to_console_file){ - push (@file_list, $path_to_console_file); - - # Backup and delete this specific file as well if it's over 200MB - my @stats = stat($path_to_console_file); - if($stats[7] >= 209715200){ - if(SCREEN_LOG_LOCAL == 1){ - # Copy it to local log folder as well - my $local_log_folder = Path::Class::Dir->new("logs_backup"); - my $log_local = $local_log_folder . "/" . $backup_file_name . "_console_log"; - copy($path_to_console_file, $log_local); - } - # Copy it to the main log folder as well - move($path_to_console_file,$output_path . "_console_log"); - } - } - } - - for my $file (@file_list) { - if( -f $file ){ - my @stats = stat($file); - if ($now-$stats[9] > $AGE) { - unlink $file; - } - } - } - - move($log_file,$output_path); - - return 0; -} - -sub create_screen_id -{ - my ($screen_type, $home_id) = @_; - return sprintf("OGP_%s_%09d", $screen_type, $home_id); -} - -sub create_screen_cmd -{ - my ($screen_id, $exec_cmd) = @_; - $exec_cmd = replace_OGP_Env_Vars($screen_id, "", "", $exec_cmd); - return - sprintf('screen -d -m -t "%1$s" -c ' . SCREENRC_FILE . ' -S %1$s %2$s', - $screen_id, $exec_cmd); - -} - -sub create_screen_cmd_loop -{ - my ($screen_id, $exec_cmd, $priority, $affinity, $envVars) = @_; - my $server_start_batfile = "_start_server.bat"; - - $exec_cmd = replace_OGP_Env_Vars($screen_id, "", "", $exec_cmd); - - # Create batch file that will launch the process and store PID which will be used for killing later - open (SERV_START_BAT_SCRIPT, '>', $server_start_batfile); - - my $batch_server_command = "\@echo off" . "\r\n" - . "setlocal EnableDelayedExpansion" . "\r\n" - . ":TOP" . "\r\n"; - - if(defined $envVars && $envVars ne ""){ - $batch_server_command .= $envVars; - } - - $batch_server_command .= "set STARTTIME=%TIME: =0%" . "\r\n" - . "if exist _prestart.bat ( " . "\r\n" - . "start \"PRESTART\" _prestart.bat" . "\r\n" - . ")" . "\r\n" - . "\@ping -n 5 localhost> nul" . "\r\n" - . "start " . $priority . " " . $affinity . " /wait " . $exec_cmd . "\r\n" - . "set ENDTIME=%TIME: =0%" . "\r\n" - . "set \"end=!ENDTIME:%time:~8,1%=%%100)*100+1!\" & set \"start=!STARTTIME:%time:~8,1%=%%100)*100+1!\"" . "\r\n" - . "set /A \"elap=((((10!end:%time:~2,1%=%%100)*60+1!%%100)-((((10!start:%time:~2,1%=%%100)*60+1!%%100)\"" . "\r\n" - . "set /A \"cc=elap%%100+100,elap/=100,ss=elap%%60+100,elap/=60,mm=elap%%60+100,hh=elap/60+100\"" . "\r\n" - . "set hour=%hh:~1%" . "\r\n" - . "set minute=%mm:~1%" . "\r\n" - . "set second=%ss:~1%" . "\r\n" - . "if exist SERVER_STOPPED exit" . "\r\n" - . "sleep 10" . "\r\n" - . "IF %hour% == 00 IF %minute% lss 3 exit" . "\r\n" - . "goto TOP" . "\r\n"; - - print SERV_START_BAT_SCRIPT $batch_server_command; - close (SERV_START_BAT_SCRIPT); - - my $screen_exec_script = "cmd /Q /C " . $server_start_batfile; - - return - sprintf('screen -d -m -t "%1$s" -c ' . SCREENRC_FILE . ' -S %1$s %2$s', - $screen_id, $screen_exec_script); - -} - -sub replace_OGP_Env_Vars{ - # This function replaces constants from environment variables set in the XML - my ($screen_id, $homeid, $homepath, $exec_cmd, $game_key) = @_; - - # Handle steam specific replacements - if(defined $screen_id && $screen_id ne ""){ - my $screen_id_for_txt_update = substr ($screen_id, rindex($screen_id, '_') + 1); - my $steamInsFile = $screen_id_for_txt_update . "_install.txt"; - my $steamCMDPath = STEAMCMD_CLIENT_DIR; - my $fullPath = Path::Class::File->new($steamCMDPath, $steamInsFile); - - my $windows_steamCMDPath= clean(`cygpath -wa $steamCMDPath`); - $windows_steamCMDPath =~ s#/#\\#g; - - # If the install file exists, the game can be auto updated, else it will be ignored by the game for improper syntax - # To generate the install file, the "Install/Update via Steam" button must be clicked on at least once! - if(-e $fullPath){ - $exec_cmd =~ s/{OGP_STEAM_CMD_DIR}/$windows_steamCMDPath/g; - $exec_cmd =~ s/{STEAMCMD_INSTALL_FILE}/$steamInsFile/g; - } - } - - # Handle home directory replacement - if(defined $homepath && $homepath ne ""){ - $exec_cmd =~ s/{OGP_HOME_DIR}/$homepath/g; - } - - # Handle windows directory replacement - if(defined $homepath && $homepath ne ""){ - my $windows_home_path = clean(`cygpath -wa $homepath`); - $exec_cmd =~ s/{OGP_HOME_DIR_WINDOWS}/$windows_home_path/g; - } - - # Handle global game shared directory replacement - if(defined $game_key && $game_key ne ""){ - my $readable_game_key = lc(substr($game_key, 0, rindex($game_key,"_"))); - my $shared_path = Path::Class::Dir->new(SHARED_GAME_TMP_DIR, $readable_game_key); - # Create the folder if it doesn't exist - if (!-d $shared_path && !mkdir $shared_path) - { - logger "Could not create " . $shared_path . " directory $!.", 1; - } - - $exec_cmd =~ s/{OGP_GAME_SHARED_DIR}/$shared_path/g; - } - - return $exec_cmd; -} - -sub encode_list -{ - my $encoded_content = ''; - if(@_) - { - foreach my $line (@_) - { - $encoded_content .= encode_base64($line, "") . '\n'; - } - } - return $encoded_content; -} - -sub decrypt_param -{ - my ($param) = @_; - $param = decode_base64($param); - $param = Crypt::XXTEA::decrypt($param, AGENT_KEY); - $param = decode_base64($param); - return $param; -} - -sub decrypt_params -{ - my @params; - foreach my $param (@_) - { - $param = &decrypt_param($param); - push(@params, $param); - } - return @params; -} - -sub check_steam_cmd_client -{ - if (STEAM_LICENSE ne STEAM_LICENSE_OK) - { - logger "Steam license not accepted, stopping Steam client check."; - return 0; - } - if (!-d STEAMCMD_CLIENT_DIR && !mkdir STEAMCMD_CLIENT_DIR) - { - logger "Could not create " . STEAMCMD_CLIENT_DIR . " directory $!.", 1; - exit -1; - } - if (!-w STEAMCMD_CLIENT_DIR) - { - logger "Steam client dir '" - . STEAMCMD_CLIENT_DIR - . "' not writable. Unable to get Steam client."; - return -1; - } - if (!-f STEAMCMD_CLIENT_BIN) - { - logger "The Steam client, steamcmd, does not exist yet, installing..."; - my $steam_client_file = 'steamcmd.zip'; - my $steam_client_path = Path::Class::File->new(STEAMCMD_CLIENT_DIR, $steam_client_file); - my $steam_client_url = - "http://media.steampowered.com/installer/" . $steam_client_file; - logger "Downloading the Steam client from $steam_client_url to '" - . $steam_client_path . "'."; - - my $ua = LWP::UserAgent->new; - $ua->agent('Mozilla/5.0'); - my $response = $ua->get($steam_client_url, ':content_file' => "$steam_client_path"); - - unless ($response->is_success) - { - logger "Failed to download steam installer from " - . $steam_client_url - . ".", 1; - return -1; - } - if (-f $steam_client_path) - { - logger "Uncompressing $steam_client_path"; - if ( uncompress_file_without_decrypt($steam_client_path, STEAMCMD_CLIENT_DIR) != 1 ) - { - unlink($steam_client_path); - logger "Unable to uncompress $steam_client_path, the file has been removed."; - return -1; - } - unlink($steam_client_path); - } - } - if (!-x STEAMCMD_CLIENT_BIN) - { - if ( ! chmod 0755, STEAMCMD_CLIENT_BIN ) - { - logger "Unable to apply execution permission to ".STEAMCMD_CLIENT_BIN."."; - } - } - return 1; -} - -sub is_screen_running -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($screen_type, $home_id) = decrypt_params(@_); - return is_screen_running_without_decrypt($screen_type, $home_id); -} - -sub is_screen_running_without_decrypt -{ - my ($screen_type, $home_id) = @_; - - my $screen_id = create_screen_id($screen_type, $home_id); - - my $is_running = `screen -list | grep $screen_id`; - - if ($is_running =~ /^\s*$/) - { - return 0; - } - else - { - return 1; - } -} - -# Delete Server Stopped Status File: -sub deleteStoppedStatFile -{ - my ($home_path) = @_; - my $server_stop_status_file = Path::Class::File->new($home_path, "SERVER_STOPPED"); - if(-e $server_stop_status_file) - { - unlink $server_stop_status_file; - } -} - -# Universal startup function -sub universal_start -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return universal_start_without_decrypt(decrypt_params(@_)); -} - -# Split to two parts because of internal calls. -sub universal_start_without_decrypt -{ - my ( - $home_id, $home_path, $server_exe, $run_dir, $startup_cmd, - $server_port, $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log - ) = @_; - - if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1) - { - logger "This server is already running (ID: $home_id)."; - return -14; - } - - if (!-e $home_path) - { - logger "Can't find server's install path [ $home_path ]."; - return -10; - } - - # Some game require that we are in the directory where the binary is. - my $game_binary_dir = Path::Class::Dir->new($home_path, $run_dir); - if ( -e $game_binary_dir && !chdir $game_binary_dir) - { - logger "Could not change to server binary directory $game_binary_dir."; - return -12; - } - - if (!-x $server_exe) - { - if (!chmod 0755, $server_exe) - { - logger "The $server_exe file is not executable."; - return -13; - } - } - - if(defined $preStart && $preStart ne ""){ - # Get it in the format that the startup file can use - $preStart = startup_comma_format_to_multiline($preStart); - }else{ - $preStart = ""; - } - - if(defined $envVars && $envVars ne ""){ - # Get it in the format that the startup file can use - $envVars = startup_comma_format_to_multiline($envVars); - - # Replace variables in the envvars if they exist - my @prestartenvvars = split /[\r\n]+/, $envVars; - my $envVarStr = ""; - foreach my $line (@prestartenvvars) { - $line = replace_OGP_Env_Vars("", $home_id, $home_path, $line); - if($line ne ""){ - logger "Configuring environment variable: $line"; - $envVarStr .= "$line\r\n"; - } - } - - if(defined $envVarStr && $envVarStr ne ""){ - $envVars = $envVarStr; - } - }else{ - $envVars = ""; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); - - # Replace any OGP variables - $startup_cmd = replace_OGP_Env_Vars($screen_id, $home_id, $home_path, $startup_cmd, $game_key); - - # Create affinity and priority strings - my $priority; - my $affinity; - my $run_before_start; - - if($nice ne "NA") - { - if( $nice <= 19 and $nice >= 11 ) - { - $priority = "/low"; - } - elsif( $nice <= 10 and $nice >= 1 ) - { - $priority = "/belownormal"; - } - elsif( $nice == 0 ) - { - $priority = "/normal"; - } - elsif( $nice <= -1 and $nice >= -8 ) - { - $priority = "/abovenormal"; - } - elsif( $nice <= -9 and $nice >= -18 ) - { - $priority = "/high"; - } - elsif( $nice == -19 ) - { - $priority = "/realtime"; - } - } - else - { - $priority = ""; - } - - if($cpu ne "NA" and $cpu ne "" ) - { - - $affinity = "/affinity $cpu"; - } - else - { - $affinity = ""; - } - - my $win_game_binary_dir = clean(`cygpath -wa $game_binary_dir`); - chomp $win_game_binary_dir; - - # Create the startup string. - my ($file_extension) = $server_exe =~ /(\.[^.]+)$/; - - my $cli_bin; - - # Create bash file to respawn process if it crashes or exits without user interaction - # If a user stops the server, the process will not respawn - - if($file_extension eq ".jar") - { - if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ - deleteStoppedStatFile($home_path); - $cli_bin = create_screen_cmd_loop($screen_id, "$startup_cmd", $priority, $affinity); - }else{ - $cli_bin = create_screen_cmd($screen_id, "cmd /Q /C start $priority $affinity /WAIT $startup_cmd"); - } - } - elsif(($file_extension eq ".sh")||($file_extension eq ".bash")) - { - # There is no software made for windows that uses bash by default, - # but it can be a good way to improve the server startup. To be able to use - # sh/bash scripts as server executable I added this piece to the agent: - if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ - deleteStoppedStatFile($home_path); - $cli_bin = create_screen_cmd_loop($screen_id, "bash $game_binary_dir/$server_exe $startup_cmd", $priority, $affinity); - }else{ - $cli_bin = create_screen_cmd($screen_id, "cmd /Q /C start $priority $affinity /WAIT bash $game_binary_dir/$server_exe $startup_cmd"); - } - } - else - { - if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ - deleteStoppedStatFile($home_path); - $cli_bin = create_screen_cmd_loop($screen_id, "$win_game_binary_dir\\$server_exe $startup_cmd", $priority, $affinity); - }else{ - # Below line should only be used for launching non-auto restart game servers - $win_game_binary_dir =~ s/\\/\\\\/g; - - $cli_bin = create_screen_cmd($screen_id, "cmd /Q /C start $priority $affinity /WAIT $win_game_binary_dir\\\\$server_exe $startup_cmd"); - } - } - - $home_path =~ s/\\/\//g; - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - backup_home_log( $home_id, $log_file, $home_path . "/" . $console_log ); - - my $clean_cli_bin = $cli_bin; - $clean_cli_bin =~ s/\\\\/\\/g; - logger - "Startup command [ $clean_cli_bin ] will be executed in dir $game_binary_dir."; - - # Fix permissions - my $ownerShipResults = take_ownership($home_path); - - # Run before start script and set environment variables which will affect create_screen_cmd only... loop already has the envvars as well - $run_before_start = run_before_start_commands($home_id, $home_path, $preStart, $envVars); - - system($cli_bin); - - if(defined $preStart && $preStart ne ""){ - # Get it in the format that the startup file can use - $preStart = multiline_to_startup_comma_format($preStart); - }else{ - $preStart = ""; - } - - if(defined $envVars && $envVars ne ""){ - # Get it in the format that the startup file can use - $envVars = multiline_to_startup_comma_format($envVars); - }else{ - $envVars = ""; - } - - # Create startup file for the server. - my $startup_file = - Path::Class::File->new(GAME_STARTUP_DIR, "$server_ip-$server_port"); - - if (open(STARTUP, '>', $startup_file)) - { - print STARTUP - "$home_id,$home_path,$server_exe,$run_dir,$startup_cmd,$server_port,$server_ip,$cpu,$nice,$preStart,$envVars,$game_key,$console_log"; - logger "Created startup flag for $server_ip-$server_port"; - close(STARTUP); - } - else - { - logger "Cannot create file in " . $startup_file . " : $!"; - } - return 1; -} - -# Returns the number of CPUs available. -sub cpu_count -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - if (!-e "/proc/cpuinfo") - { - return "ERROR - Missing /proc/cpuinfo"; - } - - open(CPUINFO, '<', "/proc/cpuinfo") - or return "ERROR - Cannot open /proc/cpuinfo"; - - my $cpu_count = 0; - - while () - { - chomp; - next if $_ !~ /^processor/; - $cpu_count++; - } - close(CPUINFO); - return "$cpu_count"; -} - -### File exists check #### -# Simple a way to check if a file exists using the remote agent -# -# @return 0 when file exists. -# @return 1 when file does not exist. -sub rfile_exists -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - chdir AGENT_RUN_DIR; - my $checkFile = decrypt_param(@_); - - if (-e $checkFile) - { - return 0; - } - else - { - return 1; - } -} - -##### Quick check to verify agent is up and running -# Used to quickly see if the agent is online, and if the keys match. -# The message that is sent to the agent must be hello, if not then -# it is intrepret as encryption key missmatch. -# -# @return 1 when encrypted message is not 'hello' -# @return 0 when check is ok. -sub quick_chk -{ - my $dec_check = &decrypt_param(@_); - if ($dec_check ne 'hello') - { - logger "ERROR - Encryption key mismatch! Returning 1 to asker."; - return 1; - } - return 0; -} - -### Return -10 If home path is not found. -### Return -9 If log type was invalid. -### Return -8 If log file was not found. -### 0 reserved for connection problems. -### Return 1;content If log found and screen running. -### Return 2;content If log found but screen is not running. -sub get_log -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($screen_type, $home_id, $home_path, $nb_of_lines, $log_file) = decrypt_params(@_); - - if (!chdir $home_path) - { - logger "Can't change to server's install path [ $home_path ]."; - return -10; - } - - if ( ($screen_type eq SCREEN_TYPE_UPDATE) - && ($screen_type eq SCREEN_TYPE_HOME)) - { - logger "Invalid screen type '$screen_type'."; - return -9; - } - - if(!$log_file) - { - my $screen_id = create_screen_id($screen_type, $home_id); - $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - } - else - { - # logger "DEBUG DIRECTORYNAME IS ". $home_path; - # logger "DEBUG LOGFILE IS ". $log_file; - - - $log_file = Path::Class::File->new($home_path, $log_file); - # logger "debug NEW logfile is ".$log_file; - # my @timestamplog = `ls $log_file -t`; - # logger "DEBUG timestamplog is ".$timestamplog[1]; - # $log_file = $timestamplog[1]; - - } - - chmod 0644, $log_file; - - # Create local copy of current log file if SCREEN_LOG_LOCAL = 1 - if(SCREEN_LOG_LOCAL == 1) - { - my $log_local = Path::Class::File->new($home_path, "LOG_$screen_type.txt"); - if ( -e $log_local ) - { - unlink $log_local; - } - - # Copy log file only if it's not an UPDATE type as it may contain steam credentials - if($screen_type eq SCREEN_TYPE_HOME){ - - - # logger "DEBUG DIRECTORY IS ". $directoryname; - # my $timestamplog = `ls $log_file -t`; - # logger "DEBUG LOGFILE IS ". $log_file; - #logger "DEGUB timestampfile is ". $timestamplog; - # $log_file = $timestamplog; - - copy($log_file, $log_local); - - - } - } - - # Regenerate the log file if it doesn't exist - unless ( -e $log_file ) - { - if (open(NEWLOG, '>', $log_file)) - { - logger "Log file missing, regenerating: " . $log_file; - print NEWLOG "Log file missing, started new log\n"; - close(NEWLOG); - } - else - { - logger "Cannot regenerate log file in " . $log_file . " : $!"; - return -8; - } - } - - # Return a few lines of output to the web browser - my(@modedlines) = `tail -n $nb_of_lines $log_file`; - - my $linecount = 0; - - foreach my $line (@modedlines) { - #Text replacements to remove the Steam user login from steamcmd logs for security reasons. - $line =~ s/login .*//g; - $line =~ s/Logging .*//g; - $line =~ s/set_steam_guard_code.*//g; - $line =~ s/force_install_dir.*//g; - #Text replacements to remove empty lines. - $line =~ s/^ +//g; - $line =~ s/^\t+//g; - $line =~ s/^\e+//g; - #Remove � from console output when master server update is running. - $line =~ s/�//g; - $modedlines[$linecount]=$line; - $linecount++; - } - - my $encoded_content = encode_list(@modedlines); - chdir AGENT_RUN_DIR; - if(is_screen_running_without_decrypt($screen_type, $home_id) == 1) - { - return "1;" . $encoded_content; - } - else - { - return "2;" . $encoded_content; - } -} - -# stop server function -sub stop_server -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return stop_server_without_decrypt(decrypt_params(@_)); -} - -##### Stop server without decrypt -### Return 1 when error occurred on decryption. -### Return 0 on success -sub stop_server_without_decrypt -{ - my ($home_id, $server_ip, $server_port, $control_protocol, - $control_password, $control_type, $home_path) = @_; - - my $usedProtocolToStop = 0; - - my $startup_file = Path::Class::File->new(GAME_STARTUP_DIR, "$server_ip-$server_port"); - - if (-e $startup_file) - { - logger "Removing startup flag " . $startup_file . ""; - unlink($startup_file) - or logger "Cannot remove the startup flag file $startup_file $!"; - } - - # Create file indicator that the game server has been stopped if defined - if(defined($Cfg::Preferences{ogp_autorestart_server}) && $Cfg::Preferences{ogp_autorestart_server} eq "1"){ - - # Get current directory and chdir into the game's home dir - my $curDir = getcwd(); - chdir $home_path; - - # Create stopped indicator file used by autorestart of OGP if server crashes - open(STOPFILE, '>', "SERVER_STOPPED"); - close(STOPFILE); - - # Return to original directory - chdir $curDir; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); - my $get_screen_pid = "screen -list | grep $screen_id | cut -f1 -d'.' | sed '".'s/\W//g'."' | head -1"; - my $screen_pid = `$get_screen_pid`; - - chomp $screen_pid; - - my $windows_pid_command = "ps -W | grep '" . $screen_pid . "' | head -1 | awk '{print \$4}'"; - my $windows_pid = `$windows_pid_command`; - - chomp $windows_pid; - - # Some validation checks for the variables. - if ($server_ip =~ /^\s*$/ || $server_port < 0 || $server_port > 65535) - { - logger("Invalid IP:Port given $server_ip:$server_port."); - return 1; - } - #Skip RCON - always kill processes directly for reliable server stops - - if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1) - { - logger "Stopping server with kill command (RCON disabled for reliability)."; - system("cmd /C taskkill /f /fi 'PID eq $windows_pid' /T"); - system('screen -wipe > /dev/null 2>&1'); - logger "Server ID $home_id:Stopped server running on $server_ip:$server_port."; - return 0; - } - else - { - logger "Server ID $home_id:Stopped server running on $server_ip:$server_port."; - return 0; - } -} - -##### Send RCON command -### Return 0 when error occurred on decryption. -### Return 1 on success -sub send_rcon_command -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id, $server_ip, $server_port, $control_protocol, - $control_password, $control_type, $rconCommand) = decrypt_params(@_); - - # legacy console - if ($control_protocol eq "lcon") - { - my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id); - system('screen -S '.$screen_id.' -p 0 -X stuff "'.$rconCommand.'$(printf \\\\r)"'); - logger "Sending legacy console command to ".$screen_id.": \n$rconCommand \n ."; - if ($? == 0) - { - my(@modedlines) = "$rconCommand"; - my $encoded_content = encode_list(@modedlines); - return "1;" . $encoded_content; - } - return 0; - } - - # Some validation checks for the variables. - if ($server_ip =~ /^\s*$/ || $server_port < 0 || $server_port > 65535) - { - logger("Invalid IP:Port given $server_ip:$server_port."); - return 0; - } - - if ($control_password !~ /^\s*$/) - { - if ($control_protocol eq "rcon") - { - use KKrcon::KKrcon; - my $rcon = new KKrcon( - Password => $control_password, - Host => $server_ip, - Port => $server_port, - Type => $control_type - ); - - logger "Sending RCON command to $server_ip:$server_port: \n$rconCommand \n ."; - - my(@modedlines) = $rcon->execute($rconCommand); - my $encoded_content = encode_list(@modedlines); - return "1;" . $encoded_content; - } - elsif ($control_protocol eq "rcon2") - { - use KKrcon::HL2; - my $rcon2 = new HL2( - hostname => $server_ip, - port => $server_port, - password => $control_password, - timeout => 2 - ); - - logger "Sending RCON command to $server_ip:$server_port: \n $rconCommand \n ."; - - my(@modedlines) = $rcon2->run($rconCommand); - my $encoded_content = encode_list(@modedlines); - return "1;" . $encoded_content; - } - elsif ($control_protocol eq "armabe") - { - use ArmaBE::ArmaBE; - my $armabe = new ArmaBE( - hostname => $server_ip, - port => $server_port, # Uses server port for now (Arma 2), Arma 3 BE uses a different, user definable port - password => $control_password, - timeout => 2 - ); - - logger "Sending RCON command to $server_ip:$server_port: \n $rconCommand \n ."; - - my(@modedlines) = $armabe->run($rconCommand); - my $encoded_content = encode_list(@modedlines); - return "1;" . $encoded_content; - } - } - else - { - logger "Control protocol PASSWORD NOT SET."; - return -10; - } -} - -##### Returns a directory listing -### @return List of directories if everything OK. -### @return 0 If the directory is not found. -### @return -1 If cannot open the directory. -sub dirlist -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($datadir) = &decrypt_param(@_); - logger "Asked for dirlist of $datadir directory."; - if (!-d $datadir) - { - logger "ERROR - Directory [ $datadir ] not found!"; - return -1; - } - if (!opendir(DIR, $datadir)) - { - logger "ERROR - Can't open $datadir: $!"; - return -2; - } - my @dirlist = readdir(DIR); - closedir(DIR); - return join(";", @dirlist); -} - -##### Returns a directory listing with extra info the filemanager -### @return List of directories if everything OK. -### @return 1 If the directory is empty. -### @return -1 If the directory is not found. -### @return -2 If cannot open the directory. -sub dirlistfm -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $datadir = &decrypt_param(@_); - - logger "Asked for dirlist of $datadir directory."; - - if (!-d $datadir) - { - logger "ERROR - Directory [ $datadir ] not found!"; - return -1; - } - - if (!opendir(DIR, $datadir)) - { - logger "ERROR - Can't open $datadir: $!"; - return -2; - } - - my %dirfiles = (); - - my ( - $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, - $size, $atime, $mtime, $ctime, $blksize, $blocks - ); - - my $count = 0; - - chdir($datadir); - - while (readdir(DIR)) - { - #skip the . and .. special dirs - next if $_ eq '.'; - next if $_ eq '..'; - #print "Dir list is" . $_."\n"; - #Stat the file to get ownership and size - ( - $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, - $size, $atime, $mtime, $ctime, $blksize, $blocks - ) = stat($_); - - if(defined $uid) - { - $uid = getpwuid($uid); - } - else - { - $uid = ''; - } - - if(defined $gid) - { - $gid = getgrgid($gid); - } - else - { - $gid = ''; - } - - #This if else logic determines what it is, File, Directory, other - if (-T $_) - { - # print "File\n"; - $dirfiles{'files'}{$count}{'filename'} = encode_base64($_); - $dirfiles{'files'}{$count}{'size'} = $size; - $dirfiles{'files'}{$count}{'user'} = $uid; - $dirfiles{'files'}{$count}{'group'} = $gid; - } - elsif (-d $_) - { - # print "Dir\n"; - $dirfiles{'directorys'}{$count}{'filename'} = encode_base64($_); - $dirfiles{'directorys'}{$count}{'size'} = $size; - $dirfiles{'directorys'}{$count}{'user'} = $uid; - $dirfiles{'directorys'}{$count}{'group'} = $gid; - } - elsif (-B $_) - { - #print "File\n"; - $dirfiles{'binarys'}{$count}{'filename'} = encode_base64($_); - $dirfiles{'binarys'}{$count}{'size'} = $size; - $dirfiles{'binarys'}{$count}{'user'} = $uid; - $dirfiles{'binarys'}{$count}{'group'} = $gid; - } - else - { - #print "Unknown\n" - #will be listed as common files; - $dirfiles{'files'}{$count}{'filename'} = encode_base64($_); - $dirfiles{'files'}{$count}{'size'} = $size; - $dirfiles{'files'}{$count}{'user'} = $uid; - $dirfiles{'files'}{$count}{'group'} = $gid; - } - $count++; - } - closedir(DIR); - - if ($count eq 0) - { - logger "Empty directory $datadir."; - return 1; - } - - chdir AGENT_RUN_DIR; - #Now we return it to the webpage, as array - return {%dirfiles}; -} - -###### Returns the contents of a text file -sub readfile -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - chdir AGENT_RUN_DIR; - my $userfile = &decrypt_param(@_); - - unless ( -e $userfile ) - { - if (open(BLANK, '>', $userfile)) - { - close(BLANK); - } - } - - if (!open(USERFILE, '<', $userfile)) - { - logger "ERROR - Can't open file $userfile for reading."; - return -1; - } - - my ($wholefile, $buf); - - while (read(USERFILE, $buf, 60 * 57)) - { - $wholefile .= encode_base64($buf); - } - close(USERFILE); - - if(!defined $wholefile) - { - return "1; "; - } - - return "1;" . $wholefile; -} - -###### Backs up file, then writes data to new file -### @return 1 On success -### @return 0 In case of a failure -sub writefile -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - chdir AGENT_RUN_DIR; - # $writefile = file we're editing, $filedata = the contents were writing to it - my ($writefile, $filedata) = &decrypt_params(@_); - if (!-e $writefile) - { - open FILE, ">", $writefile; - } - else - { - # backup the existing file - logger - "Backing up file $writefile to $writefile.bak before writing new databefore writing new data."; - if (!copy("$writefile", "$writefile.bak")) - { - logger - "ERROR - Failed to backup $writefile to $writefile.bak. Error: $!"; - return 0; - } - } - if (!-w $writefile) - { - logger "ERROR - File [ $writefile ] is not writeable!"; - return 0; - } - if (!open(WRITER, '>', $writefile)) - { - logger "ERROR - Failed to open $writefile for writing."; - return 0; - } - $filedata = decode_base64($filedata); - $filedata =~ s/\r//g; - print WRITER "$filedata"; - close(WRITER); - logger "Wrote $writefile successfully!"; - return 1; -} - -###### Reboots the server remotely through panel -### @return 1 On success -### @return 0 In case of a failure -sub rebootnow -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - system('shutdown -r -t 10'); - logger "Scheduled system reboot to occur in 10 seconds successfully!"; - return 1; -} - -# Determine the os of the agent machine. -sub what_os -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - logger "Asking for OS type"; - my $ret = system('which uname >/dev/null 2>&1'); - if ($ret eq 0) - { - my $os = `\$(which uname) -a`; - chomp $os; - logger "OS is $os"; - return "$os"; - } - else - { - logger "Cannot determine OS..that is odd"; - return "Unknown"; - } -} - -### @return PID of the download process if started succesfully. -### @return -1 If could not create temporary download directory. -### @return -2 If could not create destination directory. -### @return -3 If resources unavailable. -sub start_file_download -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($url, $destination, $filename, $action, $post_script) = &decrypt_params(@_); - logger - "Starting to download URL $url. Destination: $destination - Filename: $filename"; - - if (!-e $destination) - { - logger "Creating destination directory."; - if (!mkpath $destination ) - { - logger "Could not create destination '$destination' directory : $!"; - return -2; - } - } - - my $download_file_path = Path::Class::File->new($destination, "$filename"); - - my $pid = fork(); - if (not defined $pid) - { - logger "Could not allocate resources for download."; - return -3; - } - - # Only the forked child goes here. - elsif ($pid == 0) - { - my $ua = LWP::UserAgent->new( ssl_opts => { verify_hostname => 0, - SSL_verify_mode => 0x00 } ); - $ua->agent('Mozilla/5.0'); - my $response = $ua->get($url, ':content_file' => "$download_file_path"); - - if ($response->is_success) - { - logger "Successfully fetched $url and stored it to $download_file_path. Retval: ".$response->status_line; - - if (!-e $download_file_path) - { - logger "File $download_file_path does not exist."; - exit(0); - } - - if ($action eq "uncompress") - { - logger "Starting file uncompress as ordered."; - uncompress_file_without_decrypt($download_file_path, - $destination); - } - } - else - { - logger - "Unable to fetch $url, or save to $download_file_path. Retval: ".$response->status_line; - exit(0); - } - - # Child process must exit. - exit(0); - } - else - { - if ($post_script ne "") - { - logger "Running postscript commands."; - my @postcmdlines = split /[\r\n]+/, $post_script; - my $postcmdfile = $destination."/".'postinstall.sh'; - open FILE, '>', $postcmdfile; - print FILE "cd $destination\n"; - print FILE "while kill -0 $pid >/dev/null 2>&1\n"; - print FILE "do\n"; - print FILE " sleep 1\n"; - print FILE "done\n"; - foreach my $line (@postcmdlines) { - print FILE "$line\n"; - } - print FILE "rm -f $destination/postinstall.sh\n"; - close FILE; - chmod 0755, $postcmdfile; - my $screen_id = create_screen_id("post_script", $pid); - my $cli_bin = create_screen_cmd($screen_id, "bash $postcmdfile"); - system($cli_bin); - } - logger "Download process for $download_file_path has pid number $pid."; - return "$pid"; - } -} - -sub run_before_start_commands -{ - #return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($server_id, $homedir, $beforestartcmd, $envVars) = @_; - - if ($homedir ne "" && $server_id ne ""){ - my $windows_home_path = clean(`cygpath -wa $homedir`); - - # Run any prestart scripts - if (defined $beforestartcmd && $beforestartcmd ne "") - { - logger "Running pre-start XML commands before starting server ID $server_id with a home directory of $homedir."; - my @prestartcmdlines = split /[\r\n]+/, $beforestartcmd; - my $prestartcmdfile = $windows_home_path . '\_prestart.bat'; - open FILE, '>', $prestartcmdfile; - print FILE "cd \"$windows_home_path\"\r\n"; - foreach my $line (@prestartcmdlines) { - $line = replace_OGP_Env_Vars("", $server_id, $homedir, $line); - print FILE "$line\r\n"; - } - print FILE "exit" . "\r\n"; - close FILE; - chmod 0755, $prestartcmdfile; - } - - - # Set and export any environment variables for game server developers unwilling to properly learn Linux - if (defined $envVars && $envVars ne ""){ - my @prestartenvvars = split /[\r\n]+/, $envVars; - foreach my $line (@prestartenvvars) { - $line = replace_OGP_Env_Vars("", $server_id, $homedir, $line); - if($line ne ""){ - logger "Configuring environment variable: $line"; - system($line); - } - } - } - - }else{ - return -2; - } - - return 1; -} - -sub multiline_to_startup_comma_format{ - my ($multiLineVar) = @_; - $multiLineVar =~ s/,//g; # commas are invalid anyways in bash - $multiLineVar =~ s/[\r]+//g; - $multiLineVar =~ s/[\n]+/{OGPNEWLINE}/g; - return $multiLineVar; -} - -sub startup_comma_format_to_multiline{ - my ($multiLineVar) = @_; - $multiLineVar =~ s/{OGPNEWLINE}/\r\n/g; - return $multiLineVar; -} - -sub check_b4_chdir -{ - my ( $path ) = @_; - - if (!-e $path) - { - logger "$path does not exist yet. Trying to create it..."; - - eval { mkpath($path); 1 } or logger "Error creating $path with Perl mkpath command. Errno: $! - Trying again with sudo..."; - - if (!-e $path) - { - sudo_exec_without_decrypt('mkdir -p ' . $path); - } - - if (!-e $path) - { - return -1; - } - } - - if (!chdir $path) - { - logger "Unable to change dir to '$path'."; - return -1; - } - - return 0; -} - -sub create_bash_scripts -{ - my ( $home_path, $bash_scripts_path, $precmd, $postcmd, @installcmds ) = @_; - - $home_path =~ s/('+)/'\"$1\"'/g; - $bash_scripts_path =~ s/('+)/'\"$1\"'/g; - - my @precmdlines = split /[\r\n]+/, $precmd; - my $precmdfile = 'preinstall.sh'; - open FILE, '>', $precmdfile; - print FILE "cd '$home_path'\n"; - foreach my $line (@precmdlines) { - print FILE "$line\n"; - } - close FILE; - chmod 0755, $precmdfile; - - my @postcmdlines = split /[\r\n]+/, $postcmd; - my $postcmdfile = 'postinstall.sh'; - open FILE, '>', $postcmdfile; - print FILE "cd '$home_path'\n"; - foreach my $line (@postcmdlines) { - print FILE "$line\n"; - } - print FILE "cd '$bash_scripts_path'\n". - "rm -f preinstall.sh\n". - "rm -f postinstall.sh\n". - "rm -f runinstall.sh\n"; - close FILE; - chmod 0755, $postcmdfile; - - my $installfile = 'runinstall.sh'; - open FILE, '>', $installfile; - print FILE "#!/bin/bash\n". - "cd '$bash_scripts_path'\n". - "./$precmdfile\n"; - foreach my $installcmd (@installcmds) - { - print FILE "$installcmd\n"; - } - print FILE "wait ".'${!}'."\n". - "cd '$bash_scripts_path'\n". - "./$postcmdfile\n"; - close FILE; - chmod 0755, $installfile; - - return $installfile; -} - -#### Run the rsync update #### -### @return 1 If update started -### @return 0 In error case. -sub start_rsync_install -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id, $home_path, $url, $exec_folder_path, $exec_path, $precmd, $postcmd) = decrypt_params(@_); - - if ( check_b4_chdir($home_path) != 0) - { - return 0; - } - - my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id; - - if ( check_b4_chdir($bash_scripts_path) != 0) - { - return 0; - } - - # Rsync install require the rsync binary to exist in the system - # to enable this functionality. - my $rsync_binary = Path::Class::File->new("/usr/bin", "rsync"); - - if (!-f $rsync_binary) - { - logger "Failed to start rsync update from " - . $url - . " to $home_path. Error: Rsync client not installed."; - return 0; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - - backup_home_log( $home_id, $log_file ); - - my $path = $home_path; - $path =~ s/('+)/'\"$1\"'/g; - my @installcmds = ("/usr/bin/rsync --log-file='" . AGENT_RSYNC_GENERIC_LOG . "' --archive --compress --copy-links --update --verbose rsync://$url '$path'", - "cd '$path'", - "find -iname \\\*.exe -exec chmod -f +x {} \\\;", - "find -iname \\\*.bat -exec chmod -f +x {} \\\;"); - - # Fix permissions - my $ownerShipResults = take_ownership($home_path, "str"); - if(defined $ownerShipResults && $ownerShipResults ne ""){ - $postcmd .= "\n" . $ownerShipResults; - } - - my $installfile = create_bash_scripts( $home_path, $bash_scripts_path, $precmd, $postcmd, @installcmds ); - - my $screen_cmd = create_screen_cmd($screen_id, "./$installfile"); - logger "Running rsync update: /usr/bin/rsync --log-file='" . AGENT_RSYNC_GENERIC_LOG . "' --archive --compress --copy-links --update --verbose rsync://$url '$home_path'"; - system($screen_cmd); - - chdir AGENT_RUN_DIR; - return 1; -} - -### @return PID of the download process if started succesfully. -### @return -1 If could not create temporary download directory. -### @return -2 If could not create destination directory. -### @return -3 If resources unavailable. -sub master_server_update -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id,$home_path,$ms_home_id,$ms_home_path,$exec_folder_path,$exec_path,$precmd,$postcmd) = decrypt_params(@_); - - if ( check_b4_chdir($home_path) != 0) - { - return 0; - } - - my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id; - - if ( check_b4_chdir($bash_scripts_path) != 0) - { - return 0; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - - backup_home_log( $home_id, $log_file ); - - my $my_home_path = $home_path; - $my_home_path =~ s/('+)/'\"$1\"'/g; - $ms_home_path =~ s/('+)/'\"$1\"'/g; - - my @installcmds = ("cp -vuRf '$ms_home_path'/* '$my_home_path'"); - my $installfile = create_bash_scripts( $home_path, $bash_scripts_path, $precmd, $postcmd, @installcmds ); - - my $screen_cmd = create_screen_cmd($screen_id, "./$installfile"); - logger "Running master server update from home ID $home_id to home ID $ms_home_id"; - system($screen_cmd); - - chdir AGENT_RUN_DIR; - return 1; -} - -sub steam_cmd -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return steam_cmd_without_decrypt(decrypt_params(@_)); -} - -#### Run the steam client #### -### @return 1 If update started -### @return 0 In error case. -sub steam_cmd_without_decrypt -{ - my ($home_id, $home_path, $mod, $modname, $betaname, $betapwd, $user, $pass, $guard, $exec_folder_path, $exec_path, $precmd, $postcmd, $cfg_os, $filesToLockUnlock, $arch_bits) = @_; - - # Creates home path if it doesn't exist - if ( check_b4_chdir($home_path) != 0) - { - return 0; - } - - # Changes into root steamcmd OGP directory - if ( check_b4_chdir(STEAMCMD_CLIENT_DIR) != 0) - { - return 0; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - my $screen_id_for_txt_update = substr ($screen_id, rindex($screen_id, '_') + 1); - my $steam_binary = Path::Class::File->new(STEAMCMD_CLIENT_DIR, "steamcmd.exe"); - my $installSteamFile = $screen_id_for_txt_update . "_install.txt"; - - my $windows_home_path = clean(`cygpath -wa $home_path`); - - my $installtxt = Path::Class::File->new($installSteamFile); - - open FILE, '>', $installtxt; - print FILE "\@ShutdownOnFailedCommand 1\n"; - print FILE "\@NoPromptForPassword 1\n"; - - # Handle requested SteamCMD architecture - if(defined $arch_bits && $arch_bits ne ""){ - print FILE "\@sSteamCmdForcePlatformBitness " . $arch_bits . "\n"; - } - - if($guard ne '') - { - print FILE "set_steam_guard_code $guard\n"; - } - if($user ne '' && $user ne 'anonymous') - { - print FILE "login $user $pass\n"; - } - else - { - print FILE "login anonymous\n"; - } - - print FILE "force_install_dir \"$windows_home_path\"\n"; - - if($modname ne "") - { - print FILE "app_set_config $mod mod $modname\n"; - print FILE "app_update $mod mod $modname validate\n"; - } - - if($betaname ne "" && $betapwd ne "") - { - print FILE "app_update $mod -beta $betaname -betapassword $betapwd\n"; - } - elsif($betaname ne "" && $betapwd eq "") - { - print FILE "app_update $mod -beta $betaname\n"; - } - else - { - print FILE "app_update $mod\n"; - } - - print FILE "exit\n"; - close FILE; - - my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id; - - if ( check_b4_chdir($bash_scripts_path) != 0) - { - return 0; - } - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - backup_home_log( $home_id, $log_file ); - - my $postcmd_mod = $postcmd; - - # Fix permissions - my $ownerShipResults = take_ownership($home_path, "str"); - if(defined $ownerShipResults && $ownerShipResults ne ""){ - $postcmd_mod .= "\n" . $ownerShipResults; - } - - my @installcmds = ("$steam_binary +runscript $installtxt +exit"); - my $installfile = create_bash_scripts( $home_path, $bash_scripts_path, $precmd, $postcmd_mod, @installcmds ); - - my $screen_cmd = create_screen_cmd($screen_id, "./$installfile"); - logger "Running steam update: $steam_binary +runscript $installtxt +exit"; - system($screen_cmd); - - return 1; -} - -sub fetch_steam_version -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($appId, $pureOutput) = &decrypt_params(@_); - my $ua = LWP::UserAgent->new; - - # Windows steam_cmd is bugged. So we cannot use the following until it's fixed. - # https://github.com/ValveSoftware/Source-1-Games/issues/1929 - #my $steam_binary = Path::Class::File->new(STEAMCMD_CLIENT_DIR, "steamcmd.exe"); - #my $steam_options = "+login anonymous +app_info_update 1 +app_info_print \"$appId\" +quit"; - #my $grep = $pureOutput != "0" ? "" : '| grep -EA 1000 "^\s+\"branches\"$" | grep -EA 5 "^\s+\"public\"$" | grep -m 1 -EB 10 "^\s+}$" | grep -E "^\s+\"buildid\"\s+" | tr \'[:blank:]"\' \' \' | tr -s \' \' | cut -d\' \' -f3'; - - #my $response = `$steam_binary $steam_options $grep`; - - logger "Getting latest version info for AppId $appId"; - - $ua->agent('OGP Windows Agent v/' . AGENT_VERSION); - $ua->timeout(10); - - my $response = $ua->get("http://opengamepanel.org/supported_games/api.php?appid=$appId&action=getBuildId"); - - if ($response->is_success) - { - my $content = $response->decoded_content; - - if ($content =~ /^\d+\z/) - { - return $content; - } else { - return -9; - } - } else { - return -10; - } -} - -sub installed_steam_version -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($game_home, $mod, $pureOutput) = &decrypt_params(@_); - my $appFile = $game_home."/steamapps/appmanifest_$mod.acf"; - my $grep = $pureOutput != "0" ? "" : '| grep buildid | tr \'[:blank:]"\' \' \' | tr -s \' \' | cut -d\' \' -f3'; - - if ( ! -f $appFile) - { - return "-10"; - } - - return `cat $appFile $grep`; -} - -sub automatic_steam_update -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id, $game_home, $server_ip, $server_port, $exec_path, $exec_folder_path, - $control_protocol, $control_password, $control_type, - $appId, $modname, $betaname, $betapwd, $user, $pass, $guard, $precmd, $postcmd, $cfg_os, $filesToLockUnlock, - $startup_cmd, $cpu, $nice, $preStart, $envVars, $game_key, $arch_bits, $console_log) = &decrypt_params(@_); - - # Is the server currently running? if it is, we'll try to start it after updating. - my $isServerRunning = is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1 ? 1 : 0; - - # Check if an update is already happening. - if (is_screen_running_without_decrypt(SCREEN_TYPE_UPDATE, $home_id) == 1) - { - logger("Update already running for server $home_id, unable to start automatic update."); - return -10; - } - - # Stop the server if it's running. - if ($isServerRunning == 1) - { - logger("Stopping server $home_id for automatic update."); - - if (stop_server_without_decrypt($home_id, $server_ip, $server_port, $control_protocol, $control_password, $control_type, $game_home) != 0) - { - logger("Failed to stop server $home_id for automatic update. Exiting update procedure."); - return -9 - } - - } - - # steam_cmd: Returns 0 if the update failed, in which case, don't try starting the server - because we may have an incomplete or corrupt installation. - if (steam_cmd_without_decrypt($home_id, $game_home, $appId, $modname, $betaname, $betapwd, $user, $pass, $guard, $exec_folder_path, $exec_path, $precmd, $postcmd, $cfg_os, $filesToLockUnlock, $arch_bits) == 0) - { - logger("Failed to start steam_cmd for server $home_id."); - return -8; - - } else { - - if ($isServerRunning == 1) - { - while (1) - { - # If the update screen for $home_id isn't running, attempt to start the server. - if (is_screen_running_without_decrypt(SCREEN_TYPE_UPDATE, $home_id) == 0) - { - - if (universal_start_without_decrypt($home_id, $game_home, $exec_path, $exec_folder_path, $startup_cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log) != 1) - { - logger("Failed to start server $home_id after automatic update."); - return -7; - } else { - logger("Starting server $home_id after automatic update."); - return 1; - } - - last; - } - - sleep 5; - } - - } else { - # Update was started, but server wasn't initially running. - return 2; - } - - } - -} - -sub rsync_progress -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($running_home) = &decrypt_param(@_); - logger "User requested progress on rsync job on home $running_home."; - if (-r $running_home) - { - $running_home =~ s/('+)/'"$1"'/g; - my $progress = `du -sk '$running_home'`; - chomp($progress); - my ($bytes, $junk) = split(/\s+/, $progress); - logger("Found $bytes and $junk"); - return $bytes; - } - return "0"; -} - -sub is_file_download_in_progress -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($pid) = &decrypt_param(@_); - logger "User requested if download is in progress with pid $pid."; - my @pids = `ps -ef`; - @pids = grep(/$pid/, @pids); - logger "Number of pids for file download: @pids"; - if (@pids > '0') - { - return 1; - } - return 0; -} - -### \return 1 If file is uncompressed succesfully. -### \return 0 If file does not exist. -### \return -1 If file could not be uncompressed. -sub uncompress_file -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return uncompress_file_without_decrypt(decrypt_params(@_)); -} - -sub uncompress_file_without_decrypt -{ - - # File must include full path. - my ($file, $destination) = @_; - - logger "Uncompression called for file $file to dir $destination."; - - if (!-e $file) - { - logger "File $file could not be found for uncompression."; - return 0; - } - - if (!-e $destination) - { - mkpath($destination, {error => \my $err}); - if (@$err) - { - logger "Failed to create destination dir $destination."; - return 0; - } - } - - my $ae = Archive::Extract->new(archive => $file); - - if (!$ae) - { - logger "Could not create archive instance for file $file."; - return -1; - } - - my $ok = $ae->extract(to => $destination); - - if (!$ok) - { - logger "File $file could not be uncompressed."; - return -1; - } - - system("chmod -Rf 755 $destination"); - system("cd $destination && find -iname \\\*.exe -exec chmod -f +x {} \\\;"); - system("cd $destination && find -iname \\\*.bat -exec chmod -f +x {} \\\;"); - - logger "File uncompressed/extracted successfully."; - return 1; -} - -### \return 1 If files are compressed succesfully. -### \return -1 If files could not be compressed. -sub compress_files -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return compress_files_without_decrypt(decrypt_params(@_)); -} - -sub compress_files_without_decrypt -{ - my ($files,$destination,$archive_name,$archive_type) = @_; - - if (!-e $destination) - { - logger "compress_files: Destination path ( $destination ) could not be found."; - return -1; - } - - chdir $destination; - my @items = split /\Q\n/, $files; - my @inventory; - if($archive_type eq "zip") - { - logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type"; - my $zip = Archive::Zip->new(); - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - $zip->addFile( $item ); - } - elsif (-d $item) - { - $zip->addTree( $item, $item ); - } - } - } - # Save the file - unless ( $zip->writeToFileNamed($archive_name.'.zip') == AZ_OK ) { - logger "Write Error at $destination/$archive_name.$archive_type"; - return -1 - } - logger $archive_type." archive $destination$archive_name.$archive_type created successfully"; - return 1; - } - elsif($archive_type eq "tbz") - { - logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type"; - my $tar = Archive::Tar->new; - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - $tar->add_files( $item ); - } - elsif (-d $item) - { - @inventory = (); - find (sub { push @inventory, $File::Find::name }, $item); - $tar->add_files( @inventory ); - } - } - } - # Save the file - unless ( $tar->write("$archive_name.$archive_type", COMPRESS_BZIP) ) { - logger "Write Error at $destination/$archive_name.$archive_type"; - return -1 - } - logger $archive_type." archive $destination$archive_name.$archive_type created successfully"; - return 1; - } - elsif($archive_type eq "tgz") - { - logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type"; - my $tar = Archive::Tar->new; - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - $tar->add_files( $item ); - } - elsif (-d $item) - { - @inventory = (); - find (sub { push @inventory, $File::Find::name }, $item); - $tar->add_files( @inventory ); - } - } - } - # Save the file - unless ( $tar->write("$archive_name.$archive_type", COMPRESS_GZIP) ) { - logger "Write Error at $destination/$archive_name.$archive_type"; - return -1 - } - logger $archive_type." archive $destination$archive_name.$archive_type created successfully"; - return 1; - } - elsif($archive_type eq "tar") - { - logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type"; - my $tar = Archive::Tar->new; - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - $tar->add_files( $item ); - } - elsif (-d $item) - { - @inventory = (); - find (sub { push @inventory, $File::Find::name }, $item); - $tar->add_files( @inventory ); - } - } - } - # Save the file - unless ( $tar->write("$archive_name.$archive_type") ) { - logger "Write Error at $destination/$archive_name.$archive_type"; - return -1 - } - logger $archive_type." archive $destination$archive_name.$archive_type created successfully"; - return 1; - } - elsif($archive_type eq "bz2") - { - logger $archive_type." compression called."; - foreach my $item (@items) { - if(-e $item) - { - if (-f $item) - { - bzip2 $item => "$item.bz2"; - } - elsif (-d $item) - { - @inventory = (); - find (sub { push @inventory, $File::Find::name }, $item); - foreach my $relative_item (@inventory) { - bzip2 $relative_item => "$relative_item.bz2"; - } - } - } - } - logger $archive_type." archives created successfully at $destination"; - return 1; - } -} - -sub discover_ips -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($check) = decrypt_params(@_); - - if ($check ne "chk") - { - logger "Invalid parameter '$check' given for discover_ips function."; - return ""; - } - - my $iplist = ""; - - my @data = `ipconfig /all`; - - foreach my $temp (@data) - { - if ($temp =~ /ip.+: (\d+\.\d+\.\d+\.\d+)/si) - { - chomp $1; - logger "Found an IP $1"; - $iplist .= "$1,"; - } - } - logger "IPlist is $iplist"; - chop $iplist; - return "$iplist"; -} - -### Return -1 In case of invalid param -### Return 1;content in case of success -sub mon_stats -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($mon_stats) = decrypt_params(@_); - if ($mon_stats ne "mon_stats") - { - logger "Invalid parameter '$mon_stats' given for $mon_stats function."; - return -1; - } - - my @disk = `df -hP -x tmpfs`; - my $encoded_content = encode_list(@disk); - my @uptime = `net stats srv`; - $encoded_content .= encode_list(@uptime); - return "1;$encoded_content"; -} - -sub exec -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($command) = decrypt_params(@_); - my @cmdret = `$command 2>/dev/null`; - my $encoded_content = encode_list(@cmdret); - return "1;$encoded_content"; -} - -# used in conjunction with the clone_home feature in the web panel -# this actually does the file copies -sub clone_home -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($source_home, $dest_home, $owner) = decrypt_params(@_); - my ($time_start, $time_stop, $time_diff); - logger "Copying from $source_home to $dest_home..."; - - # check size of source_home, make sure we have space to copy - if (!-e $source_home) - { - logger "ERROR - $source_home does not exist"; - return 0; - } - logger "Game home $source_home exists...copy will proceed"; - - # start the copy, and a timer - $time_start = time(); - if (!dircopy("$source_home", "$dest_home")) - { - $time_stop = time(); - $time_diff = $time_stop - $time_start; - logger - "Error occured after $time_diff seconds during copy of $source_home to $dest_home - $!"; - return 0; - } - else - { - $time_stop = time(); - $time_diff = $time_stop - $time_start; - logger - "Home clone completed successfully to $dest_home in $time_diff seconds"; - return 1; - } -} - -# used to delete the game home from the file system when it's removed from the panel -sub remove_home -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_path_del) = decrypt_params(@_); - - if (!-e $home_path_del) - { - logger "ERROR - $home_path_del does not exist...nothing to do"; - return 0; - } - - sleep 1 while ( !pathrmdir("$home_path_del") ); - - logger "Deletetion of $home_path_del successful!"; - return 1; -} - -sub restart_server -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return restart_server_without_decrypt(decrypt_params(@_)); -} - -### Restart the server -## return -2 CANT STOP -## return -1 CANT START (no startup file found that mach the home_id, port and ip) -## return 1 Restart OK -sub restart_server_without_decrypt -{ - my ($home_id, $server_ip, $server_port, $control_protocol, - $control_password, $control_type, $home_path, $server_exe, $run_dir, - $cmd, $cpu, $nice, $preStart, $envVars, $game_key, $console_log) = @_; - - if (stop_server_without_decrypt($home_id, $server_ip, - $server_port, $control_protocol, - $control_password, $control_type, $home_path) == 0) - { - # Wait for screen session to be completely terminated and verify it has stopped - logger "Waiting for server screen session to terminate completely..."; - my $max_wait_attempts = 30; # 30 seconds max to wait for screen to die - my $wait_count = 0; - - while ($wait_count < $max_wait_attempts) - { - if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 0) - { - logger "Server screen session has been terminated successfully."; - last; - } - - $wait_count++; - logger "Waiting for screen session to terminate... (attempt $wait_count/$max_wait_attempts)"; - sleep 1; - } - - # Final check - if screen still exists, log warning but continue - if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1) - { - logger "Warning: Server screen session may still be running, but proceeding with restart."; - } - - # Wait 60 seconds between stop and start operations as requested - logger "Waiting 60 seconds before starting server as requested for reliable scheduler functionality..."; - sleep 60; - - if (universal_start_without_decrypt($home_id, $home_path, $server_exe, $run_dir, - $cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars, $game_key, $console_log) == 1) - { - return 1; - } - else - { - return -1; - } - } - else - { - return -2; - } -} - -sub sudo_exec -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $sudo_exec = &decrypt_param(@_); - return sudo_exec_without_decrypt($sudo_exec); -} - -sub sudo_exec_without_decrypt -{ - my ($command) = @_; - my @cmdret = `$command`; - if ($? == 0) - { - return "1;".encode_list(@cmdret); - } - return 0; -} - -sub secure_path -{ - return "1;"; -} - -sub get_chattr -{ - return "1;"; -} - -sub ftp_mgr -{ - no warnings 'uninitialized'; # recommended: only switch of specific categories - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($action, $login, $password, $home_path) = decrypt_params(@_); - - if(!defined($Cfg::Preferences{ogp_manages_ftp}) || (defined($Cfg::Preferences{ogp_manages_ftp}) && $Cfg::Preferences{ogp_manages_ftp} eq "1")){ - if( defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "FZ") - { - require Cfg::FileZilla; # Use Filezilla Configuration file - if( !defined($Cfg::FileZilla{fz_exe}) || !defined($Cfg::FileZilla{fz_xml}) || !-e "$Cfg::FileZilla{fz_exe}" || !-e "$Cfg::FileZilla{fz_xml}" ) - { - return 0; - } - use Digest::MD5 qw(md5_hex); - require XML::Simple; - - my $xml = new XML::Simple; - my $data = $xml->XMLin( $Cfg::FileZilla{fz_xml}, - ForceArray => ['User','Permission','IpFilter','Allowed','Disallowed','IP','Item'], - ForceContent => 0, - KeepRoot => 1, - KeyAttr => ['Item'], - SuppressEmpty => 0 ); - - my @users; - if( defined($data->{'FileZillaServer'}->{'Users'}) ) - { - @users = @{ $data->{'FileZillaServer'}->{'Users'}->{'User'} }; - } - my $encoded_content; - - if($action eq "list") - { - if( grep {defined($_)} @users ) - { - my (@list,$username,$dir); - my $i=0; - for (@users) { - $username = $_->{'Name'}; - $dir = $_->{'Permissions'}->{'Permission'}[0]->{'Dir'}; - $dir = `cygpath -u "$dir"`; - $list[$i++] = $username."\t".$dir."\n"; - } - $encoded_content = encode_list(@list); - return "1;$encoded_content"; - } - } - elsif($action eq "userdel") - { - if( grep {defined($_)} @users ) - { - for (keys @users) { - if($users[$_]->{'Name'} eq $login) - { - delete $data->{'FileZillaServer'}->{'Users'}->{'User'}[$_]; - last; - } - } - - $xml->XMLout( $data, - OutputFile => $Cfg::FileZilla{fz_xml}, - KeepRoot => 1, - NoSort => 0, - SuppressEmpty => 0 ); - - my @args = ($Cfg::FileZilla{fz_exe}, "/reload-config"); - system(@args); - } - } - elsif($action eq "useradd") - { - my $win_home_path = clean(`cygpath -wa "$home_path"`); - chomp $win_home_path; - my $n; - - if( grep {defined($_)} @users ) - { - $n = scalar(@users); - } - else - { - $n = 0; - } - - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Name'} = $login; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[0]->{'content'} = md5_hex($password); - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[0]->{'Name'} = 'Pass'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[1]->{'Name'} = 'Group'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[2]->{'content'} = '0'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[2]->{'Name'} = 'Bypass server userlimit'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[3]->{'content'} = '0'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[3]->{'Name'} = 'User Limit'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[4]->{'content'} = '0'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[4]->{'Name'} = 'IP Limit'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[5]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[5]->{'Name'} = 'Enabled'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[6]->{'Name'} = 'Comments'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[7]->{'content'} = '0'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[7]->{'Name'} = 'ForceSsl'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[8]->{'content'} = '0'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[8]->{'Name'} = '8plus3'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'IpFilter'}[0]->{'Disallowed'}[0] = undef; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'IpFilter'}[0]->{'Allowed'}[0] = undef; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[0]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[0]->{'Name'} = 'FileRead'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[1]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[1]->{'Name'} = 'FileWrite'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[2]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[2]->{'Name'} = 'FileDelete'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[3]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[3]->{'Name'} = 'FileAppend'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[4]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[4]->{'Name'} = 'DirCreate'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[5]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[5]->{'Name'} = 'DirDelete'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[6]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[6]->{'Name'} = 'DirList'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[7]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[7]->{'Name'} = 'DirSubdirs'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[8]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[8]->{'Name'} = 'IsHome'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[9]->{'content'} = '1'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[9]->{'Name'} = 'AutoCreate'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Dir'} = $win_home_path; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'DlType'} = '0'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'DlLimit'} = '100'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'ServerDlLimitBypass'} = '0'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'UlType'} = '0'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'UlLimit'} = '100'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'ServerUlLimitBypass'} = '0'; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'Upload'}[0] = undef; - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'Download'}[0] = undef; - - $xml->XMLout( $data, - OutputFile => $Cfg::FileZilla{fz_xml}, - KeepRoot => 1, - NoSort => 0, - SuppressEmpty => 0 ); - - my @args = ($Cfg::FileZilla{fz_exe}, "/reload-config"); - system(@args); - } - elsif($action eq "passwd") - { - if( grep {defined($_)} @users ) - { - for (keys @users) { - if($users[$_]->{'Name'} eq $login) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$_]->{'Option'}[0]->{'content'} = md5_hex($password); - last; - } - } - $xml->XMLout( $data, - OutputFile => $Cfg::FileZilla{fz_xml}, - KeepRoot => 1, - NoSort => 0, - SuppressEmpty => 0 ); - - my @args = ($Cfg::FileZilla{fz_exe}, "/reload-config"); - system(@args); - } - } - elsif($action eq "show") - { - if( grep {defined($_)} @users ) - { - my (@list,@options,@dir_options,$speed_limmits); - for (@users) { - if($login eq $_->{'Name'}) - { - no warnings 'uninitialized'; - my $i=0; - $speed_limmits = $_->{'SpeedLimits'}; - while ( my ($key, $value) = each(%$speed_limmits) ) - { - next if $key =~ /Download|Upload/; - $list[$i++] = $key." : ".$value."\n"; - } - @options = @{ $_->{'Option'} }; - for(@options) - { - next if $_->{'Name'} eq "Pass"; - $list[$i++] = $_->{'Name'}." : ".$_->{'content'}."\n"; - } - @dir_options = @{ $_->{'Permissions'}->{'Permission'}[0]->{'Option'} }; - for(@dir_options) - { - $list[$i++] = $_->{'Name'}." : ".$_->{'content'}."\n"; - } - last; - } - } - $encoded_content = encode_list(@list); - return "1;$encoded_content"; - } - } - elsif($action eq "usermod") - { - if( grep {defined($_)} @users ) - { - my $n; - for (keys @users) { - if($users[$_]->{'Name'} eq $login) - { - $n = $_; - last; - } - } - - if( defined($n) ) - { - my @account_settings = split /[\n]+/, $password; - foreach my $setting (@account_settings) { - my ($key, $value) = split /[\t]+/, $setting; - if( $value ne "" && $value =~ /^\d+?$/) - { - if( $key eq 'DlType' && $value =~ /^[0-3]$/ ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'DlType'} = $value; - } - elsif( $key eq 'UlType' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'UlType'} = $value; - } - - if( $value =~ /^[0-1]$/ ) - { - if( $key eq 'ServerUlLimitBypass' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'ServerUlLimitBypass'} = $value; - } - elsif( $key eq 'ServerDlLimitBypass' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'ServerDlLimitBypass'} = $value; - } - elsif( $key eq 'Bypass_server_userlimit' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[2]->{'content'} = $value; - } - elsif( $key eq 'Enabled' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[5]->{'content'} = $value; - } - elsif( $key eq 'ForceSsl' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[7]->{'content'} = $value; - } - elsif( $key eq '8plus3' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[8]->{'content'} = $value; - } - elsif( $key eq 'FileRead' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[0]->{'content'} = $value; - } - elsif( $key eq 'FileWrite' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[1]->{'content'} = $value; - } - elsif( $key eq 'FileDelete' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[2]->{'content'} = $value; - } - elsif( $key eq 'FileAppend' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[3]->{'content'} = $value; - } - elsif( $key eq 'DirCreate' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[4]->{'content'} = $value; - } - elsif( $key eq 'DirDelete' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[5]->{'content'} = $value; - } - elsif( $key eq 'DirList' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[6]->{'content'} = $value; - } - elsif( $key eq 'DirSubdirs' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[7]->{'content'} = $value; - } - elsif( $key eq 'IsHome' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[8]->{'content'} = $value; - } - elsif( $key eq 'AutoCreate' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Permissions'}->{'Permission'}[0]->{'Option'}[9]->{'content'} = $value; - } - } - - if( $value =~ /^[1-9][0-9]{0,8}$|^1000000000$/ ) - { - if( $key eq 'DlLimit' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'DlLimit'} = $value; - } - elsif( $key eq 'UlLimit' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'SpeedLimits'}->{'UlLimit'} = $value; - } - } - - if( $key eq 'User_Limit' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[3]->{'content'} = $value; - } - elsif( $key eq 'IP_Limit' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[4]->{'content'} = $value; - } - } - - if( $key eq 'Comments' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[6]->{'content'} = $value; - } - elsif( $key eq 'Group' ) - { - $data->{'FileZillaServer'}->{'Users'}->{'User'}[$n]->{'Option'}[1]->{'content'} = $value; - } - } - } - $xml->XMLout( $data, - OutputFile => $Cfg::FileZilla{fz_xml}, - KeepRoot => 1, - NoSort => 0, - SuppressEmpty => 0 ); - - my @args = ($Cfg::FileZilla{fz_exe}, "/reload-config"); - system(@args); - } - } - return 1; - } - elsif( defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "PureFTPd") - { - my $uid = `id -u`; - chomp $uid; - my $gid = `id -g`; - chomp $gid; - - $login =~ s/('+)/'\"$1\"'/g; - $password =~ s/('+)/'\"$1\"'/g; - $home_path =~ s/('+)/'\"$1\"'/g; - - if($action eq "list") - { - return sudo_exec_without_decrypt("pure-pw list"); - } - elsif($action eq "userdel") - { - return sudo_exec_without_decrypt("pure-pw userdel '$login' && pure-pw mkdb"); - } - elsif($action eq "useradd") - { - return sudo_exec_without_decrypt("(echo '$password'; echo '$password') | pure-pw useradd '$login' -u $uid -g $gid -d '$home_path' && pure-pw mkdb"); - } - elsif($action eq "passwd") - { - return sudo_exec_without_decrypt("(echo '$password'; echo '$password') | pure-pw passwd '$login' && pure-pw mkdb"); - } - elsif($action eq "show") - { - return sudo_exec_without_decrypt("pure-pw show '$login'"); - } - elsif($action eq "usermod") - { - my $update_account = "pure-pw usermod '$login' -u $uid -g $gid"; - - my @account_settings = split /[\n]+/, $password; - - foreach my $setting (@account_settings) { - my ($key, $value) = split /[\t]+/, $setting; - - if( $key eq 'Directory' ) - { - $value =~ s/('+)/'\"$1\"'/g; - $update_account .= " -d '$value'"; - } - - if( $key eq 'Full_name' ) - { - if( $value ne "" ) - { - $value =~ s/('+)/'\"$1\"'/g; - $update_account .= " -c '$value'"; - } - else - { - $update_account .= ' -c ""'; - } - } - - if( $key eq 'Download_bandwidth' && $value ne "" ) - { - my $Download_bandwidth; - if($value eq 0) - { - $Download_bandwidth = "\"\""; - } - else - { - $Download_bandwidth = $value; - } - $update_account .= " -t " . $Download_bandwidth; - } - - if( $key eq 'Upload___bandwidth' && $value ne "" ) - { - my $Upload___bandwidth; - if($value eq 0) - { - $Upload___bandwidth = "\"\""; - } - else - { - $Upload___bandwidth = $value; - } - $update_account .= " -T " . $Upload___bandwidth; - } - - if( $key eq 'Max_files' ) - { - if( $value eq "0" ) - { - $update_account .= ' -n ""'; - } - elsif( $value ne "" ) - { - $update_account .= " -n " . $value; - } - else - { - $update_account .= ' -n ""'; - } - } - - if( $key eq 'Max_size' ) - { - if( $value ne "" && $value ne "0" ) - { - $update_account .= " -N " . $value; - } - else - { - $update_account .= ' -N ""'; - } - } - - if( $key eq 'Ratio' && $value ne "" ) - { - my($upload_ratio,$download_ratio) = split/:/,$value; - - if($upload_ratio eq "0") - { - $upload_ratio = "\"\""; - } - $update_account .= " -q " . $upload_ratio; - - if($download_ratio eq "0") - { - $download_ratio = "\"\""; - } - $update_account .= " -Q " . $download_ratio; - } - - if( $key eq 'Allowed_client_IPs' ) - { - if( $value ne "" ) - { - $update_account .= " -r " . $value; - } - else - { - $update_account .= ' -r ""'; - } - } - - if( $key eq 'Denied__client_IPs' ) - { - if( $value ne "" ) - { - $update_account .= " -R " . $value; - } - else - { - $update_account .= ' -R ""'; - } - } - - if( $key eq 'Allowed_local__IPs' ) - { - if( $value ne "" ) - { - $update_account .= " -i " . $value; - } - else - { - $update_account .= ' -i ""'; - } - } - - if( $key eq 'Denied__local__IPs' ) - { - if( $value ne "" ) - { - $update_account .= " -I " . $value; - } - else - { - $update_account .= ' -I ""'; - } - } - - - if( $key eq 'Max_sim_sessions' && $value ne "" ) - { - $update_account .= " -y " . $value; - } - - if ( $key eq 'Time_restrictions' ) - { - if( $value eq "0000-0000") - { - $update_account .= ' -z ""'; - } - elsif( $value ne "" ) - { - $update_account .= " -z " . $value; - } - else - { - $update_account .= ' -z ""'; - } - } - } - $update_account .=" && pure-pw mkdb"; - # print $update_account; - return sudo_exec_without_decrypt($update_account); - } - } - } - return 0; -} - -sub start_fastdl -{ - if(-e Path::Class::File->new(FD_DIR, 'Settings.pm')) - { - system('CYGWIN="${CYGWIN} nodosfilewarning"; export CYGWIN; perl FastDownload/ForkedDaemon.pm &'); - sleep(1); - return 1; - } - else - { - return -2; - } -} - -sub stop_fastdl -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return stop_fastdl_without_decrypt(); -} - -sub stop_fastdl_without_decrypt -{ - my $pid; - open(PIDFILE, '<', FD_PID_FILE) - || logger "Error reading pid file $!",1; - while () - { - $pid = $_; - chomp $pid; - } - close(PIDFILE); - my $cnt = kill 9, $pid; - if ($cnt == 1) - { - logger "Fast Download Daemon Stopped.",1; - return 1; - } - else - { - logger "Fast Download Daemon with pid $pid can not be stopped.",1; - return -1; - } -} - -sub take_ownership{ - # Looks like this is required to make sure that permissions are correct... - my ($home_path, $action) = @_; - - my $icaclsStr = ""; - my $icaclsAdminGroupFullPerms = ""; - my $takeownCommand = ""; - my $chmodCommand = ""; - my $fullCommands = ""; - - if (defined $home_path && $home_path ne "" && -e "$home_path"){ - my $windows_home_path = clean(`cygpath -wa $home_path`); - - logger "Running takeown commands on path of $home_path and $windows_home_path"; - - #cygwin path handling - $takeownCommand = 'takeown /U ' . USER_RUNNING_SCRIPT . ' /f "' . $home_path . '" /r >/dev/null 2>&1'; - $chmodCommand = 'chmod 775 -R "' . $home_path . '" >/dev/null 2>&1'; - if(defined $action && $action eq "str"){ - $fullCommands .= $takeownCommand . "\n"; - $fullCommands .= $chmodCommand . "\n"; - }else{ - system($takeownCommand); - system($chmodCommand); - } - - # Windows path handling - if(defined $windows_home_path && $windows_home_path ne ""){ - $takeownCommand = 'takeown /U ' . USER_RUNNING_SCRIPT . ' /f "' . $windows_home_path . '" /r >/dev/null 2>&1'; - $chmodCommand = 'chmod 775 -R "' . $windows_home_path . '" >/dev/null 2>&1'; - $icaclsStr = 'icacls "' . $windows_home_path . '" /grant ' . USER_RUNNING_SCRIPT . ':\\(OI\\)\\(CI\\)F /T >/dev/null 2>&1'; - $icaclsAdminGroupFullPerms = 'icacls "' . $windows_home_path . '" /grant administrators:F /T >/dev/null 2>&1'; - - if(defined $action && $action eq "str"){ - $fullCommands .= $takeownCommand . "\n"; - $fullCommands .= $chmodCommand . "\n"; - $fullCommands .= $icaclsStr . "\n"; - $fullCommands .= $icaclsAdminGroupFullPerms . "\n"; - }else{ - logger "Running icacls command: $icaclsStr"; - logger "Running icacls admin group command: $icaclsAdminGroupFullPerms"; - system($takeownCommand); - system($chmodCommand); - system($icaclsStr); - system($icaclsAdminGroupFullPerms); - } - } - } - - if($fullCommands ne ""){ - return $fullCommands; - } - - return 1; -} - -sub clean { - my $text = shift; - $text =~ s/\n//g; - $text =~ s/\r//g; - $text = trim($text); - return $text; -} - -sub trim { - my $s = shift; - $s =~ s/^\s+|\s+$//g; - return $s -}; - -sub restart_fastdl -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return restart_fastdl_without_decrypt(); -} - -sub restart_fastdl_without_decrypt -{ - if((fastdl_status_without_decrypt() == -1) || (stop_fastdl_without_decrypt() == 1)) - { - if(start_fastdl() == 1) - { - # Success - return 1; - } - # Cant start - return -2; - } - # Cant stop - return -3; -} - -sub fastdl_status -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return fastdl_status_without_decrypt(); -} - -sub fastdl_status_without_decrypt -{ - my $pid; - if(!open(PIDFILE, '<', FD_PID_FILE)) - { - logger "Error reading pid file $!"; - return -1; - } - while () - { - $pid = $_; - chomp $pid; - } - close(PIDFILE); - my $cnt = kill 0, $pid; - if ($cnt == 1) - { - return 1; - } - else - { - return -1; - } -} - -sub fastdl_get_aliases -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my %aliases; - my $i; - my @file_lines; - if(-d FD_ALIASES_DIR) - { - if( !opendir(ALIASES, FD_ALIASES_DIR) ) - { - logger "Error openning aliases directory " . FD_ALIASES_DIR . ", $!"; - } - else - { - while (my $alias = readdir(ALIASES)) - { - # Skip . and .. - next if $alias =~ /^\./; - if( !open(ALIAS, '<', Path::Class::Dir->new(FD_ALIASES_DIR, $alias)) ) - { - logger "Error reading alias '$alias', $!"; - } - else - { - $i = 0; - @file_lines = (); - while () - { - chomp $_; - $file_lines[$i] = $_; - $i++; - } - close(ALIAS); - $aliases{$alias}{home} = $file_lines[0]; - $aliases{$alias}{match_file_extension} = $file_lines[1]; - $aliases{$alias}{match_client_ip} = $file_lines[2]; - } - } - closedir(ALIASES); - } - } - else - { - logger "Aliases directory '" . FD_ALIASES_DIR . "' does not exist or is inaccessible."; - } - return {%aliases}; -} - -sub fastdl_del_alias -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - foreach my $alias (decrypt_params(@_)) - { - unlink Path::Class::File->new(FD_ALIASES_DIR, $alias); - } - return restart_fastdl_without_decrypt(); -} - -sub fastdl_add_alias -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($alias,$home,$match_file_extension,$match_client_ip) = decrypt_params(@_); - if(!-e FD_ALIASES_DIR) - { - if(!mkdir FD_ALIASES_DIR) - { - logger "ERROR - Failed to create " . FD_ALIASES_DIR . " directory."; - return -1; - } - } - my $alias_path = Path::Class::File->new(FD_ALIASES_DIR, $alias); - if (!open(ALIAS, '>', $alias_path)) - { - logger "ERROR - Failed to open ".$alias_path." for writing."; - return -1; - } - else - { - print ALIAS "$home\n"; - print ALIAS "$match_file_extension\n"; - print ALIAS "$match_client_ip"; - close(ALIAS); - return restart_fastdl_without_decrypt(); - } -} - -sub fastdl_get_info -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - if(-e Path::Class::File->new(FD_DIR, 'Settings.pm')) - { - delete $INC{"FastDownload/Settings.pm"}; - require "FastDownload/Settings.pm"; # Settings for Fast Download Daemon. - if(not defined $FastDownload::Settings{autostart_on_agent_startup}) - { - $FastDownload::Settings{autostart_on_agent_startup} = 0; - } - return {'port' => $FastDownload::Settings{port}, - 'ip' => $FastDownload::Settings{ip}, - 'listing' => $FastDownload::Settings{listing}, - 'autostart_on_agent_startup'=> $FastDownload::Settings{autostart_on_agent_startup}}; - } - return -1 -} - -sub fastdl_create_config -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - if(!-e FD_DIR) - { - if(!mkdir FD_DIR) - { - logger "ERROR - Failed to create " . FD_DIR . " directory."; - return -1; - } - } - my ($fd_address, $fd_port, $listing, $autostart_on_agent_startup) = decrypt_params(@_); - my $settings_string = "%FastDownload::Settings = (\n". - "\tport => $fd_port,\n". - "\tip => '$fd_address',\n". - "\tlisting => $listing,\n". - "\tautostart_on_agent_startup => $autostart_on_agent_startup,\n". - ");"; - my $settings = Path::Class::File->new(FD_DIR, 'Settings.pm'); - if (!open(SETTINGS, '>', $settings)) - { - logger "ERROR - Failed to open $settings for writing."; - return -1; - } - else - { - print SETTINGS $settings_string; - close(SETTINGS); - } - logger "$settings file written successfully."; - return 1; -} - -sub agent_restart -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $dec_check = decrypt_param(@_); - if ($dec_check eq 'restart') - { - chdir AGENT_RUN_DIR; - if(-e "ogp_agent_run.pid") - { - my $init_pid = `cat ogp_agent_run.pid`; - chomp($init_pid); - - if(kill 0, $init_pid) - { - my $or_exist = ""; - my $rm_pid_file = ""; - my $agent_pid = ""; - my $restart_scr_log = Path::Class::File->new(SCREEN_LOGS_DIR, 'screenlog.agent_restart'); - my $agent_scr_log = Path::Class::File->new(SCREEN_LOGS_DIR, 'screenlog.ogp_agent'); - - if(-e $restart_scr_log) - { - unlink $restart_scr_log; - } - - if(-e $agent_scr_log) - { - unlink $agent_scr_log; - } - - if(-e "ogp_agent.pid") - { - $rm_pid_file .= " ogp_agent.pid"; - $agent_pid = `cat ogp_agent.pid`; - chomp($agent_pid); - if( kill 0, $agent_pid ) - { - $or_exist .= " -o -e /proc/$agent_pid"; - } - } - - my $pureftpd_pid = ""; - if(-e "/var/run/pure-ftpd.pid") - { - $rm_pid_file .= " /var/run/pure-ftpd.pid"; - $pureftpd_pid = `cat /var/run/pure-ftpd.pid`; - chomp($pureftpd_pid); - if( kill 0, $pureftpd_pid ) - { - $or_exist .= " -o -e /proc/$pureftpd_pid"; - } - } - - open (AGENT_RESTART_SCRIPT, '>', 'tmp_restart.sh'); - my $restart = "echo -n \"Stopping OGP Agent...\"\n". - "kill $init_pid $agent_pid $pureftpd_pid\n". - "while [ -e /proc/$init_pid $or_exist ];do echo -n .;sleep 1;done\n". - "rm -f $rm_pid_file\necho \" [OK]\"\n". - "echo -n \"Starting OGP Agent...\"\n". - "screen -d -m -t \"ogp_agent\" -c \"" . SCREENRC_FILE . "\" -S ogp_agent bash ogp_agent -pidfile /OGP/ogp_agent_run.pid\n". - "while [ ! -e 'ogp_agent.pid' ];do echo -n .;sleep 1;done\n". - "echo \" [OK]\"\n". - "rm -f tmp_restart.sh\n". - "exit 0\n"; - print AGENT_RESTART_SCRIPT $restart; - close (AGENT_RESTART_SCRIPT); - if( -e 'tmp_restart.sh' ) - { - system('screen -d -m -t "agent_restart" -c "' . SCREENRC_FILE . '" -S agent_restart bash tmp_restart.sh'); - } - } - } - } - return -1; -} - -# Subroutines to be called -sub scheduler_dispatcher { - my ($task, $args) = @_; - my $response = `$args`; - chomp($response); - my $log = "Executed command: $args"; - if($response ne "") - { - $log .= ", response:\n$response"; - } - scheduler_log_events($log); -} - -sub scheduler_server_action -{ - my ($task, $args) = @_; - my ($action, @server_args) = split('\|\%\|', $args); - if($action eq "%ACTION=start") - { - my ($home_id, $ip, $port) = ($server_args[0], $server_args[6], $server_args[5]); - my $ret = universal_start_without_decrypt(@server_args); - if($ret == 1) - { - scheduler_log_events("Started server home ID $home_id on address $ip:$port"); - } - else - { - scheduler_log_events("Failed starting server home ID $home_id on address $ip:$port (Check agent log)"); - } - } - elsif($action eq "%ACTION=stop") - { - my ($home_id, $ip, $port) = ($server_args[0], $server_args[1], $server_args[2]); - my $ret = stop_server_without_decrypt(@server_args); - if($ret == 0) - { - scheduler_log_events("Stopped server home ID $home_id on address $ip:$port"); - } - elsif($ret == 1) - { - scheduler_log_events("Failed stopping server home ID $home_id on address $ip:$port (Invalid IP:Port given)"); - } - } - elsif($action eq "%ACTION=restart") - { - my ($home_id, $ip, $port) = ($server_args[0], $server_args[1], $server_args[2]); - my $ret = restart_server_without_decrypt(@server_args); - if($ret == 1) - { - scheduler_log_events("Restarted server home ID $home_id on address $ip:$port"); - } - elsif($ret == -1) - { - scheduler_log_events("Failed restarting server home ID $home_id on address $ip:$port (Server could not be started, check agent log)"); - } - elsif($ret == -2) - { - scheduler_log_events("Failed restarting server home ID $home_id on address $ip:$port (Server could not be stopped, check agent log)"); - } - } - return 1; -} - -sub scheduler_log_events -{ - my $logcmd = $_[0]; - $logcmd = localtime() . " $logcmd\n"; - logger "Can't open " . SCHED_LOG_FILE . " - $!" unless open(LOGFILE, '>>', SCHED_LOG_FILE); - logger "Failed to lock " . SCHED_LOG_FILE . "." unless flock(LOGFILE, LOCK_EX); - logger "Failed to seek to end of " . SCHED_LOG_FILE . "." unless seek(LOGFILE, 0, 2); - logger "Failed to write to " . SCHED_LOG_FILE . "." unless print LOGFILE "$logcmd"; - logger "Failed to unlock " . SCHED_LOG_FILE . "." unless flock(LOGFILE, LOCK_UN); - logger "Failed to close " . SCHED_LOG_FILE . "." unless close(LOGFILE); -} - -sub scheduler_add_task -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $new_task = decrypt_param(@_); - if (open(TASKS, '>>', SCHED_TASKS)) - { - print TASKS "$new_task\n"; - logger "Created new task: $new_task"; - close(TASKS); - scheduler_stop(); - # Create new object with default dispatcher for scheduled tasks - $cron = new Schedule::Cron( \&scheduler_dispatcher, { - nofork => 1, - loglevel => 0, - log => sub { print $_[1], "\n"; } - } ); - - $cron->add_entry( "* * * * * *", \&scheduler_read_tasks ); - # Run scheduler - $cron->run( {detach=>1, pid_file=>SCHED_PID} ); - return 1; - } - logger "Cannot create task: $new_task ( $! )"; - return -1; -} - -sub scheduler_del_task -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $name = decrypt_param(@_); - my @cronJobIDs = split(',', $name); - if( scheduler_read_tasks() == -1 ) - { - return -1; - } - my @entries = $cron->list_entries(); - if(open(TASKS, '>', SCHED_TASKS)) - { - foreach my $task ( @entries ) { - next if ( grep { $_ eq $task->{args}[0]} @cronJobIDs ); - next unless $task->{args}[0] =~ /task_[0-9]*/; - if(defined $task->{args}[1]) - { - print TASKS join(" ", $task->{time}, $task->{args}[1]) . "\n"; - } - else - { - print TASKS $task->{time} . "\n"; - } - } - close( TASKS ); - scheduler_stop(); - # Create new object with default dispatcher for scheduled tasks - $cron = new Schedule::Cron( \&scheduler_dispatcher, { - nofork => 1, - loglevel => 0, - log => sub { print $_[1], "\n"; } - } ); - - $cron->add_entry( "* * * * * *", \&scheduler_read_tasks ); - # Run scheduler - $cron->run( {detach=>1, pid_file=>SCHED_PID} ); - return 1; - } - logger "Cannot open file " . SCHED_TASKS . " for deleting task(s) id: $name ( $! )",1; - return -1; -} - -sub scheduler_edit_task -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($name, $new_task) = decrypt_params(@_); - if( scheduler_read_tasks() == -1 ) - { - return -1; - } - my @entries = $cron->list_entries(); - if(open(TASKS, '>', SCHED_TASKS)) - { - foreach my $task ( @entries ) { - next unless $task->{args}[0] =~ /task_[0-9]*/; - if($name eq $task->{args}[0]) - { - print TASKS "$new_task\n"; - } - else - { - if(defined $task->{args}[1]) - { - print TASKS join(" ", $task->{time}, $task->{args}[1]) . "\n"; - } - else - { - print TASKS $task->{time} . "\n"; - } - } - } - close( TASKS ); - scheduler_stop(); - # Create new object with default dispatcher for scheduled tasks - $cron = new Schedule::Cron( \&scheduler_dispatcher, { - nofork => 1, - loglevel => 0, - log => sub { print $_[1], "\n"; } - } ); - - $cron->add_entry( "* * * * * *", \&scheduler_read_tasks ); - # Run scheduler - $cron->run( {detach=>1, pid_file=>SCHED_PID} ); - return 1; - } - logger "Cannot open file " . SCHED_TASKS . " for editing task id: $name ( $! )",1; - return -1; -} - -sub scheduler_read_tasks -{ - if( open(TASKS, '<', SCHED_TASKS) ) - { - $cron->clean_timetable(); - } - else - { - logger "Error reading tasks file $!"; - scheduler_stop(); - return -1; - } - - my $i = 0; - while () - { - next if $_ =~ /^(#.*|[\s|\t]*?\n)/; - my ($minute, $hour, $dayOfTheMonth, $month, $dayOfTheWeek, @args) = split(' ', $_); - my $time = "$minute $hour $dayOfTheMonth $month $dayOfTheWeek"; - if("@args" =~ /^\%ACTION.*/) - { - $cron->add_entry($time, \&scheduler_server_action, 'task_' . $i++, "@args"); - } - else - { - $cron->add_entry($time, 'task_' . $i++, "@args"); - } - } - close(TASKS); - return 1; -} - -sub scheduler_stop -{ - my $pid; - if(open(PIDFILE, '<', SCHED_PID)) - { - $pid = ; - chomp $pid; - close(PIDFILE); - - - - - } - return -1; -} - -sub scheduler_list_tasks -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - if( scheduler_read_tasks() == -1 ) - { - return -1; - } - my @entries = $cron->list_entries(); - my %entries_array; - foreach my $task ( @entries ) { - if( defined $task->{args}[1] ) - { - $entries_array{$task->{args}[0]} = encode_base64(join(" ", $task->{time}, $task->{args}[1])); - } - else - { - $entries_array{$task->{args}[0]} = encode_base64($task->{time}); - } - } - if( %entries_array ) - { - return {%entries_array}; - } - return -1; -} - -sub get_file_part -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($file, $offset) = decrypt_params(@_); - if (!open(FILE, '<', $file)) - { - logger "ERROR - Can't open file $file for reading."; - return -1; - } - - binmode(FILE); - - if($offset != 0) - { - return -1 unless seek FILE, $offset, 0; - } - - my $data = ""; - my ($n, $buf); - my $limit = $offset + 60 * 57 * 1000; #Max 3420Kb (1000 iterations) (top statistics ~ VIRT 116m, RES 47m) - while (($n = read FILE, $buf, 60 * 57) != 0 && $offset <= $limit ) { - $data .= $buf; - $offset += $n; - } - close(FILE); - - if( $data ne "" ) - { - my $b64zlib = encode_base64(compress($data,9)); - return "$offset;$b64zlib"; - } - else - { - return -1; - } -} - -sub stop_update -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my $home_id = decrypt_param(@_); - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - system('screen -S '.$screen_id.' -p 0 -X stuff $\'\003\''); - if ($? == 0) - { - return 0; - } - return 1 -} - -sub shell_action -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($action, $arguments) = decrypt_params(@_); - - if($action eq 'remove_file') - { - chomp($arguments); - unlink($arguments); - return "1;"; - } - elsif($action eq 'remove_recursive') - { - my @items = split(';', $arguments); - foreach my $item ( @items ) { - chomp($item); - if(-d $item) - { - pathrmdir($item); - } - else - { - unlink($item); - } - } - return "1;"; - } - elsif($action eq 'create_dir') - { - chomp($arguments); - mkpath($arguments); - return "1;"; - } - elsif($action eq 'move') - { - my($src, $dest) = split(';', $arguments); - chomp($src); - chomp($dest); - if(-d $src) - { - $dest = Path::Class::Dir->new($dest, basename($src)); - dirmove($src, $dest); - } - else - { - fmove($src, $dest); - } - return "1;"; - } - elsif($action eq 'rename') - { - my($src, $dest) = split(';', $arguments); - chomp($src); - chomp($dest); - if(-d $src) - { - dirmove($src, $dest); - } - else - { - fmove($src, $dest); - } - return "1;"; - } - elsif($action eq 'copy') - { - my($src, $dest) = split(';', $arguments); - chomp($src); - chomp($dest); - if(-d $src) - { - $dest = Path::Class::Dir->new($dest, basename($src)); - dircopy($src, $dest); - } - else - { - fcopy($src, $dest); - } - return "1;"; - } - elsif($action eq 'touch') - { - chomp($arguments); - open(FH, '>', $arguments); - print FH ""; - close(FH); - return "1;"; - } - elsif($action eq 'size') - { - chomp($arguments); - my $size = 0; - if(-d $arguments) - { - find(sub { $size += -s }, $arguments ? $arguments : '.'); - } - else - { - $size += (stat($arguments))[7]; - } - return "1;" . encode_list($size); - } - elsif($action eq 'get_cpu_usage') - { - my %prev_idle; - my %prev_total; - open(STAT, '/proc/stat'); - while () { - next unless /^cpu([0-9]+)/; - my @stat = split /\s+/, $_; - $prev_idle{$1} = $stat[4]; - $prev_total{$1} = $stat[1] + $stat[2] + $stat[3] + $stat[4]; - } - close STAT; - sleep 1; - my %idle; - my %total; - open(STAT, '/proc/stat'); - while () { - next unless /^cpu([0-9]+)/; - my @stat = split /\s+/, $_; - $idle{$1} = $stat[4]; - $total{$1} = $stat[1] + $stat[2] + $stat[3] + $stat[4]; - } - close STAT; - my %cpu_percent_usage; - foreach my $key ( keys %idle ) - { - my $diff_idle = $idle{$key} - $prev_idle{$key}; - my $diff_total = $total{$key} - $prev_total{$key}; - my $percent = (100 * ($diff_total - $diff_idle)) / $diff_total; - $percent = sprintf "%.2f", $percent unless $percent == 0; - $cpu_percent_usage{$key} = encode_base64($percent); - } - return {%cpu_percent_usage}; - } - elsif($action eq 'get_ram_usage') - { - my($total, $buffers, $cached, $free) = qw(0 0 0 0); - open(STAT, '/proc/meminfo'); - while () { - $total += $1 if /MemTotal\:\s+(\d+) kB/; - $buffers += $1 if /Buffers\:\s+(\d+) kB/; - $cached += $1 if /Cached\:\s+(\d+) kB/; - $free += $1 if /MemFree\:\s+(\d+) kB/; - } - close STAT; - my $used = $total - $free - $cached - $buffers; - my $percent = 100 * $used / $total; - my %mem_usage; - $mem_usage{'used'} = encode_base64($used * 1024); - $mem_usage{'total'} = encode_base64($total * 1024); - $mem_usage{'percent'} = encode_base64($percent); - return {%mem_usage}; - } - elsif($action eq 'get_disk_usage') - { - my($total, $used, $free) = split(' ', `df -lP 2>/dev/null|grep "^.:\\s"|awk '{total+=\$2}{used+=\$3}{free+=\$4} END {print total, used, free}'`); - my $percent = 100 * $used / $total; - my %disk_usage; - $disk_usage{'free'} = encode_base64($free * 1024); - $disk_usage{'used'} = encode_base64($used * 1024); - $disk_usage{'total'} = encode_base64($total * 1024); - $disk_usage{'percent'} = encode_base64($percent); - return {%disk_usage}; - } - elsif($action eq 'get_uptime') - { - open(STAT, '/proc/uptime'); - my $uptime = 0; - while () { - $uptime += $1 if /^([0-9]+)/; - } - close STAT; - my %upsince; - $upsince{'0'} = encode_base64($uptime); - $upsince{'1'} = encode_base64(time - $uptime); - return {%upsince}; - } - elsif($action eq 'get_tasklist') - { - my %taskList; - $taskList{'task'} = encode_base64(`tasklist /fo TABLE`); - return {%taskList}; - } - elsif($action eq 'get_timestamp') - { - return "1;" . encode_list(time); - } - return 0; -} - -sub remote_query -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($protocol, $game_type, $ip, $c_port, $q_port, $s_port) = decrypt_params(@_); - my $PHP_CGI = system('which php-cgi >/dev/null 2>&1'); - if ($PHP_CGI eq 0) - { - $PHP_CGI = `which php-cgi`; - chomp($PHP_CGI); - } - else - { - return -1; - } - my $php_query_dir = Path::Class::Dir->new(AGENT_RUN_DIR, 'php-query'); - if($protocol eq 'lgsl') - { - chdir($php_query_dir->subdir('lgsl')); - my $cmd = $PHP_CGI . - " -f lgsl_feed.php" . - " lgsl_type=" . $game_type . - " ip=" . $ip . - " c_port=" . $c_port . - " q_port=" . $q_port . - " s_port=" . $s_port . - " request=sp"; - my $response = `$cmd`; - chomp($response); - chdir(AGENT_RUN_DIR); - if($response eq "FAILURE") - { - return -1; - } - return encode_base64($response, ""); - } - elsif($protocol eq 'gameq') - { - chdir($php_query_dir->subdir('gameq')); - my $cmd = $PHP_CGI . - " -f gameq_feed.php" . - " game_type=" . $game_type . - " ip=" . $ip . - " c_port=" . $c_port . - " q_port=" . $q_port . - " s_port=" . $s_port; - my $response = `$cmd`; - chomp($response); - chdir(AGENT_RUN_DIR); - if($response eq "FAILURE") - { - return -1; - } - return encode_base64($response, ""); - } - return -1; -} - -sub send_steam_guard_code -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - my ($home_id, $sgc) = decrypt_params(@_); - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - system('screen -S '.$screen_id.' -p 0 -X stuff "'.$sgc.'$(printf \\\\r)"'); - if ($? == 0) - { - return 0; - } - return 1 -} - -sub steam_workshop -{ - chomp(@_); - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - return steam_workshop_without_decrypt(decrypt_params(@_)); -} - -#### Run the steam client #### -### @return 1 If installation started -### @return -1 In error case. -sub steam_workshop_without_decrypt -{ - my ($home_id, $mods_full_path, - $workshop_id, $mods_list, - $regex, $mods_backreference_index, - $variable, $place_after, $mod_string, - $string_separator, $config_file_path, - $post_install, $mod_names_list, - $anonymous_login, $user, $pass, - $download_method, $url_list, $filename_list) = @_; - - # Creates mods path if it doesn't exist - if ( check_b4_chdir($mods_full_path) != 0) - { - return -1; - } - - my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id); - my @workshop_mods = split /,/, $mods_list; - my @installcmds; - - if($download_method eq 'steamcmd') - { - my $steam_binary = STEAMCMD_CLIENT_BIN; - my $installSteamFile = $screen_id . "_workshop.txt"; - my $installtxt = Path::Class::File->new(STEAMCMD_CLIENT_DIR, $installSteamFile); - my $windows_mods_path = clean(`cygpath -wa $mods_full_path`); - - open FILE, '>', $installtxt; - print FILE "\@ShutdownOnFailedCommand 1\n"; - print FILE "\@NoPromptForPassword 1\n"; - if($anonymous_login eq "0") - { - print FILE "login $user $pass\n"; - } - else - { - print FILE "login anonymous\n"; - } - print FILE "force_install_dir \"$windows_mods_path\"\n"; - foreach my $workshop_mod (@workshop_mods) - { - print FILE "workshop_download_item $workshop_id $workshop_mod\n"; - } - print FILE "exit\n"; - close FILE; - my $windows_installtxt = clean(`cygpath -wa $installtxt`); - $windows_installtxt =~ s/\\/\\\\/g; - @installcmds = ("$steam_binary +runscript $windows_installtxt +exit"); - } - - if($download_method eq 'steamapi') - { - my @urls = split /,/, $url_list; - my @filenames = split /,/, $filename_list; - my $index = 0; - foreach my $workshop_mod_id (@workshop_mods) - { - my $steamcmd_download_path = '/steamapps/workshop/content/'.$workshop_id.'/'.$workshop_mod_id.'/'; - - my $workshop_mod_path = $mods_full_path.$steamcmd_download_path; - if(!-d $workshop_mod_path && !mkpath $workshop_mod_path) - { - logger "Folder $workshop_mod_path could not be created."; - $index++; - next; - } - my $url = $urls[$index]; - my $filename = $filenames[$index]; - my $download_file_path = Path::Class::File->new($workshop_mod_path, "$filename"); - $installcmds[$index] = "wget -O \"$download_file_path\" \"$url\""; - $index++; - } - } - - my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id"); - backup_home_log($home_id, $log_file); - - my $precmd = ""; - my $postcmd = ""; - - $postcmd .= generate_post_install_scripts($mods_full_path, $workshop_id, $mods_list, - $regex, $mods_backreference_index, - $variable, $place_after, $mod_string, - $string_separator, $config_file_path, - $post_install, $mod_names_list); - - my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id; - - if ( check_b4_chdir($bash_scripts_path) != 0) - { - return -1; - } - - my $installfile = create_bash_scripts($mods_full_path, $bash_scripts_path, $precmd, $postcmd, @installcmds); - - my $screen_cmd = create_screen_cmd($screen_id, "./$installfile"); - - logger "Installing Steam Workshop content on server Home ID " . $home_id; - system($screen_cmd); - - return 1; -} - -sub generate_post_install_scripts -{ - my ($mods_full_path, $workshop_id, $mods_list, - $regex, $mods_backreference_index, - $variable, $place_after, $mod_string, - $string_separator, $config_file_path, - $post_install, $mod_names_list) = @_; - - my $post_install_scripts = ""; - my $mods_info_path = Path::Class::Dir->new(AGENT_RUN_DIR, 'WorkshopModsInfo'); - $post_install_scripts .= "mods_full_path=\"$mods_full_path\"\n". - "workshop_id=\"$workshop_id\"\n". - "regex=\"$regex\"\n". - "mods_backreference_index=\"$mods_backreference_index\"\n". - "variable=\"$variable\"\n". - "place_after=\"$place_after\"\n". - "string_separator=\"$string_separator\"\n". - "config_file_path=\"$config_file_path\"\n". - "mods_info_path=\"$mods_info_path/\"\n"; - my @workshop_mods = split /,/, $mods_list; - my @mod_names = split /,/, $mod_names_list; - - my $index = 0; - foreach my $workshop_mod_id (@workshop_mods) - { - my $steamcmd_download_path = '/steamapps/workshop/content/'.$workshop_id.'/'.$workshop_mod_id.'/'; - my $workshop_mod_path = $mods_full_path.$steamcmd_download_path; - my $this_mod_string = $mod_string; - $this_mod_string =~ s/\%workshop_mod_id\%/$workshop_mod_id/g; - - $post_install_scripts .= "mod_string[$index]=\"$this_mod_string\"\n". - "mod_name[$index]=\"".$mod_names[$index]."\"\n". - "workshop_mod_id[$index]=\"$workshop_mod_id\"\n". - "workshop_mod_path[$index]=\"$workshop_mod_path\"\n"; - $index++; - } - - $post_install_scripts .= 'if [ ! -e $config_file_path ];then'."\n". - ' if [ ! -d "$(dirname $config_file_path)" ];then mkdir -p "$(dirname $config_file_path)";fi'."\n". - ' echo -e "${place_after}\n${variable}" > $config_file_path'."\n". - 'fi'."\n". - 'i=0'."\n". - 'for mod_id in "${workshop_mod_id[@]}"'."\n". - 'do'."\n". - ' first_file="$(ls "${workshop_mod_path[$i]}"| sort -n | head -1)"'."\n"; - - my @post_install_lines = split /[\r\n]+/, $post_install; - foreach my $line (@post_install_lines) { - if($line ne ""){ - $line =~ s/\%mods_full_path\%/\$mods_full_path/g; - $line =~ s/\%workshop_mod_id\%/\$mod_id/g; - $line =~ s/\%first_file\%/\$first_file/g; - $post_install_scripts .= "\t".$line."\n"; - } - } - - $post_install_scripts .= ' file_content=$(cat $config_file_path)'."\n". - ' if [[ $file_content =~ $regex ]]; then'."\n". - ' full_match="${BASH_REMATCH[0]}"'."\n". - ' mods_match="${BASH_REMATCH[$mods_backreference_index]}"'."\n". - ' found=1'."\n". - ' else'."\n". - ' found=0'."\n". - ' fi'."\n". - ' first_file_string="\%first_file%"'."\n". - - ' if [ -z "${mod_string[$i]##*$first_file_string*}" ];then'."\n". - ' mod_string[$i]="${mod_string[$i]/$first_file_string/$first_file}"'."\n". - ' fi'."\n". - ' if [ $found == 1 ] && [ "X$full_match" != "X" ];then'."\n". - ' if [ "X$mods_match" == "X" ];then'."\n". - ' new_mods=$(echo -e "${full_match}${mod_string[$i]}")'."\n". - ' echo -e "${file_content/$full_match/$new_mods}">"$config_file_path"'."\n". - ' else'."\n". - ' if [ ! -z "${mods_match##*${mod_string[$i]}*}" ];then'."\n". - ' new_mods=$(echo -e "${full_match}${string_separator}${mod_string[$i]}")'."\n". - ' echo -e "${file_content/$full_match/$new_mods}">"$config_file_path"'."\n". - ' fi'."\n". - ' fi'."\n". - ' else'."\n". - ' if [ "X$place_after" == "X" ];then'."\n". - ' echo -e "${file_content}${variable}${mod_string[$i]}">"$config_file_path"'."\n". - ' else'."\n". - ' if [ -z "${file_content##*${place_after}*}" ];then'."\n". - ' new_var="${variable}${mod_string[$i]}"'."\n". - ' place_after_esc=$(echo -e "$place_after"|sed -e \'s/[]\\/$*.^[]/\\\\&/g\')'."\n". - ' echo -e "$file_content"|sed \'/\'$place_after_esc\'/a \'$new_var>"$config_file_path"'."\n". - ' else'."\n". - ' echo -e "${file_content}${place_after}\n${variable}${mod_string[$i]}">"$config_file_path"'."\n". - ' fi'."\n". - ' fi'."\n". - ' fi'."\n". - ' if [ ! -d "${mods_info_path}" ];then mkdir -p "${mods_info_path}";fi'."\n". - ' echo "${mod_name[$i]}" > "${mods_info_path}${mod_string[$i]}.ogpmod"'."\n". - ' i=$(expr $i + 1)'."\n". - 'done'."\n"; - return "$post_install_scripts"; -} - -sub get_workshop_mods_info() -{ - return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK"); - - my $mods_info_dir_path = Path::Class::Dir->new(AGENT_RUN_DIR, 'WorkshopModsInfo'); - - if(-d $mods_info_dir_path) - { - opendir(MODS_INFO_DIR, $mods_info_dir_path) or return -1; - my @mods_info; - while(my $mod_info_file = readdir(MODS_INFO_DIR)) - { - if($mod_info_file =~ /\.ogpmod$/) - { - my $mod_info_file_path = Path::Class::File->new($mods_info_dir_path, $mod_info_file); - if(open(my $fh, '<:encoding(UTF-8)', $mod_info_file_path)) - { - my $row = <$fh>; - chomp $row; - if($row ne "") - { - my ($string_name, $ext) = split(/\.ogp/, $mod_info_file); - push @mods_info, "$string_name:$row"; - } - close($fh); - } - } - } - closedir(MODS_INFO_DIR); - return "1;".encode_list(@mods_info); - } - - return -1; -} - -################################################################## -# Resource Stats Collection System (Windows) -################################################################## - -# Get current timestamp in MySQL format -sub get_utc_timestamp { - my ($sec, $min, $hour, $mday, $mon, $year) = gmtime(); - return sprintf("%04d-%02d-%02d %02d:%02d:%02d", - $year + 1900, $mon + 1, $mday, $hour, $min, $sec); -} - -# Connect to stats database -sub connect_stats_db { - # Check if DBD::mysql is available - eval { require DBD::mysql; }; - if ($@) { - logger "DBD::mysql not available - resource stats collection disabled"; - return undef; - } - - my $dsn = "DBI:mysql:database=" . STATS_DB_NAME . ";host=" . STATS_DB_HOST; - my $dbh = eval { DBI->connect($dsn, STATS_DB_USER, STATS_DB_PASS, - { RaiseError => 1, AutoCommit => 1, mysql_enable_utf8 => 1 }) }; - - if ($@) { - logger "Failed to connect to stats database: $@"; - return undef; - } - - return $dbh; -} - -# Ensure machine exists in gsp_machines table -sub ensure_machine_exists { - my ($dbh, $machine_id, $hostname) = @_; - - my $table = STATS_TABLE_PREFIX . "machines"; - my $sql = "INSERT IGNORE INTO $table (machine_id, hostname) VALUES (?, ?)"; - - eval { - my $sth = $dbh->prepare($sql); - $sth->execute($machine_id, $hostname); - $sth->finish(); - }; - - if ($@) { - logger "Failed to ensure machine exists: $@"; - return 0; - } - - return 1; -} - -# Get machine-wide system stats using Windows tools -sub collect_machine_stats { - my $stats = {}; - - # Windows doesn't have load averages, set to 0 - $stats->{load1} = 0; - $stats->{load5} = 0; - $stats->{load15} = 0; - - # Get CPU usage using wmic - my $cpu_output = `wmic cpu get loadpercentage /value 2>nul`; - if ($cpu_output =~ /LoadPercentage=(\d+)/) { - $stats->{cpu_pct} = $1; - } else { - $stats->{cpu_pct} = 0; - } - - # Get memory info using wmic - my $mem_total = 0; - my $mem_free = 0; - - my $mem_output = `wmic OS get TotalVisibleMemorySize,FreePhysicalMemory /value 2>nul`; - if ($mem_output =~ /TotalVisibleMemorySize=(\d+)/) { - $mem_total = $1 * 1024; # Convert from KB to bytes - } - if ($mem_output =~ /FreePhysicalMemory=(\d+)/) { - $mem_free = $1 * 1024; # Convert from KB to bytes - } - - my $mem_used = $mem_total - $mem_free; - $stats->{mem_used_bytes} = $mem_used; - $stats->{mem_total_bytes} = $mem_total; - $stats->{mem_used_pct} = $mem_total > 0 ? sprintf("%.2f", ($mem_used * 100) / $mem_total) : 0; - - # Get swap/pagefile info - my $swap_output = `wmic pagefile get AllocatedBaseSize,CurrentUsage /value 2>nul`; - my ($swap_total, $swap_used) = (0, 0); - if ($swap_output =~ /AllocatedBaseSize=(\d+)/) { - $swap_total = $1 * 1024 * 1024; # Convert from MB to bytes - } - if ($swap_output =~ /CurrentUsage=(\d+)/) { - $swap_used = $1 * 1024 * 1024; # Convert from MB to bytes - } - - $stats->{swap_used_bytes} = $swap_used; - $stats->{swap_total_bytes} = $swap_total; - - # Get disk usage for agent directory - my $disk_path = AGENT_RUN_DIR; - $disk_path =~ s/\//\\/g; # Convert forward slashes to backslashes for Windows - - # Extract drive letter - my $drive_letter = substr($disk_path, 0, 2); - - my $disk_output = `wmic logicaldisk where "DeviceID='$drive_letter'" get Size,FreeSpace /value 2>nul`; - if ($disk_output =~ /FreeSpace=(\d+).*Size=(\d+)/s) { - my ($free, $total) = ($1, $2); - my $used = $total - $free; - $stats->{disk_path} = $disk_path; - $stats->{disk_total_bytes} = $total; - $stats->{disk_used_bytes} = $used; - $stats->{disk_used_pct} = $total > 0 ? sprintf("%.2f", ($used * 100) / $total) : 0; - } - - # Get network interface info (basic implementation) - $stats->{net_iface} = "unknown"; - $stats->{rx_bytes} = 0; - $stats->{tx_bytes} = 0; - $stats->{iface_speed_mbps} = undef; - - # Try to get network stats using netstat (basic implementation) - my $netstat_output = `netstat -e 2>nul`; - if ($netstat_output =~ /(\d+)\s+(\d+)/) { - $stats->{rx_bytes} = $1; - $stats->{tx_bytes} = $2; - } - - return $stats; -} - -# Get folder size using Windows dir command -sub get_folder_size_bytes { - my ($folder_path) = @_; - return 0 unless -d $folder_path; - - # Convert path for Windows - $folder_path =~ s/\//\\/g; - - my $dir_output = `dir "$folder_path" /s /-c 2>nul | findstr "bytes"`; - if ($dir_output =~ /(\d+) bytes/) { - return $1; - } - - return 0; -} - -# Find server processes on Windows -sub find_server_processes { - my @server_dirs = (); - - # Find server directories - if (opendir(my $dh, AGENT_RUN_DIR)) { - while (my $entry = readdir($dh)) { - next if $entry =~ /^\./; # Skip hidden directories - my $path = Path::Class::Dir->new(AGENT_RUN_DIR, $entry); - push @server_dirs, $path if -d $path; - } - closedir($dh); - } - - my %server_procs = (); - - # Get all running processes using wmic - my @processes = get_all_processes_windows(); - - # Associate processes with server directories - for my $server_dir (@server_dirs) { - my $server_path = "$server_dir"; - $server_path =~ s/\//\\/g; # Convert to Windows path - $server_procs{$server_path} = []; - - for my $proc (@processes) { - my $exe_path = $proc->{exe} || ''; - my $cmd = $proc->{cmd} || ''; - - # Check if process is associated with this server directory - if (index($exe_path, $server_path) >= 0 || - index($cmd, $server_path) >= 0) { - push @{$server_procs{$server_path}}, $proc; - } - } - } - - return %server_procs; -} - -# Get all running processes on Windows -sub get_all_processes_windows { - my @processes = (); - - # Use wmic to get process information - my $wmic_output = `wmic process get ProcessId,Name,ExecutablePath,CommandLine,WorkingSetSize,VirtualSize /format:csv 2>nul`; - - my @lines = split /\n/, $wmic_output; - shift @lines; # Remove header - - for my $line (@lines) { - next unless $line =~ /\S/; # Skip empty lines - chomp $line; - - my @fields = split /,/, $line; - next unless @fields >= 6; - - my $proc = { - pid => $fields[4] || 0, - name => $fields[2] || '', - cmd => $fields[1] || '', - exe => $fields[3] || '', - rss_bytes => $fields[5] || 0, - vms_bytes => $fields[6] || 0, - cpu_pct => 0, # Not easily available on Windows - io_read_bytes => 0, - io_write_bytes => 0, - open_fds => 0, - }; - - push @processes, $proc if $proc->{pid} > 0; - } - - return @processes; -} - -# Get listening ports for a process (Windows implementation) -sub get_process_listening_ports { - my ($pid) = @_; - my @ports = (); - - # Use netstat to find listening ports for this PID - my $netstat_output = `netstat -ano | findstr ":.*LISTENING.*$pid" 2>nul`; - - for my $line (split /\n/, $netstat_output) { - if ($line =~ /:(\d+)\s+.*LISTENING\s+$pid/) { - push @ports, $1; - } - } - - return join(',', sort { $a <=> $b } @ports); -} - -# Insert machine sample into database -sub insert_machine_sample { - my ($dbh, $timestamp, $machine_id, $stats) = @_; - - my $table = STATS_TABLE_PREFIX . "machine_samples"; - my $sql = qq{ - INSERT INTO $table - (machine_id, ts, load1, load5, load15, cpu_pct, - mem_used_bytes, mem_total_bytes, mem_used_pct, - swap_used_bytes, swap_total_bytes, - disk_path, disk_total_bytes, disk_used_bytes, disk_used_pct, - net_iface, rx_bytes, tx_bytes, iface_speed_mbps) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - }; - - eval { - my $sth = $dbh->prepare($sql); - $sth->execute( - $machine_id, $timestamp, - $stats->{load1}, $stats->{load5}, $stats->{load15}, $stats->{cpu_pct}, - $stats->{mem_used_bytes}, $stats->{mem_total_bytes}, $stats->{mem_used_pct}, - $stats->{swap_used_bytes}, $stats->{swap_total_bytes}, - $stats->{disk_path}, $stats->{disk_total_bytes}, $stats->{disk_used_bytes}, $stats->{disk_used_pct}, - $stats->{net_iface}, $stats->{rx_bytes}, $stats->{tx_bytes}, $stats->{iface_speed_mbps} - ); - $sth->finish(); - }; - - if ($@) { - logger "Failed to insert machine sample: $@"; - return 0; - } - - return 1; -} - -# Insert process sample into database -sub insert_process_sample { - my ($dbh, $timestamp, $machine_id, $server_name, $server_path, $proc, $folder_size) = @_; - - my $table = STATS_TABLE_PREFIX . "process_samples"; - my $sql = qq{ - INSERT INTO $table - (machine_id, ts, server_name, server_path, - pid, proc_name, cmd, cpu_pct, - rss_bytes, vms_bytes, mem_pct, - io_read_bytes, io_write_bytes, open_fds, - listening_ports, folder_size_bytes) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - }; - - # Get listening ports for this process - my $ports = get_process_listening_ports($proc->{pid}); - - eval { - my $sth = $dbh->prepare($sql); - $sth->execute( - $machine_id, $timestamp, $server_name, $server_path, - $proc->{pid}, $proc->{name}, $proc->{cmd}, $proc->{cpu_pct}, - $proc->{rss_bytes}, $proc->{vms_bytes}, 0, # mem_pct placeholder - $proc->{io_read_bytes}, $proc->{io_write_bytes}, $proc->{open_fds}, - $ports, $folder_size - ); - $sth->finish(); - }; - - if ($@) { - logger "Failed to insert process sample: $@"; - return 0; - } - - return 1; -} - -# Main resource stats collection function -sub collect_resource_stats { - logger "Starting resource stats collection (Windows)"; - - # Connect to database - my $dbh = connect_stats_db(); - return unless $dbh; - - my $timestamp = get_utc_timestamp(); - my $machine_id = $ENV{COMPUTERNAME} || $ENV{GS_MACHINE_ID} || `hostname`; - chomp $machine_id; - my $hostname = $ENV{COMPUTERNAME} || `hostname`; - chomp $hostname; - - # Ensure machine exists in database - unless (ensure_machine_exists($dbh, $machine_id, $hostname)) { - $dbh->disconnect(); - return; - } - - # Collect machine-wide stats - my $machine_stats = collect_machine_stats(); - unless (insert_machine_sample($dbh, $timestamp, $machine_id, $machine_stats)) { - $dbh->disconnect(); - return; - } - - # Collect per-server process stats - my %server_procs = find_server_processes(); - - for my $server_path (keys %server_procs) { - my $server_name = (split /[\\\/]/, $server_path)[-1]; - my $folder_size = get_folder_size_bytes($server_path); - - for my $proc (@{$server_procs{$server_path}}) { - insert_process_sample($dbh, $timestamp, $machine_id, - $server_name, $server_path, $proc, $folder_size); - } - } - - $dbh->disconnect(); - logger "Resource stats collection completed (Windows)"; -} \ No newline at end of file diff --git a/backup/gs_backup.sh b/backup/gs_backup.sh deleted file mode 100644 index dd5aaa87..00000000 --- a/backup/gs_backup.sh +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env bash -# Mirror /home/gameserver to EITHER: -# remote: bak-kc-01.iaregamer.com:/sdb1/backup//gameserver -# local : //gameserver -# -# Usage: -# gs-backup.sh remote [--dry-run] [--verify] [--no-delete] -# gs-backup.sh local [--dry-run] [--verify] [--no-delete] -# -# --dry-run : simulate only (no writes) -# --verify : report differences; exit 0 if in-sync, 3 if drift detected -# --no-delete : do not delete extraneous destination files -# -# Env you can override: -# REMOTE_HOST=bak-kc-01.iaregamer.com REMOTE_USER=gameserver REMOTE_BASE=/sdb1/backup -# LOCAL_BASE=/backup SRC_DIR=/home/gameserver -# BW_PEAK_MBIT=100 BW_OFFPEAK_MBIT=300 PEAK_START=16 PEAK_END=23 -# SSH_KEY=/home/gameserver/.ssh/id_rsa -# VERIFY_STRICT=0 (set 1 to use --checksum in verify) - -set -euo pipefail - -# ---------- MODE ---------- -MODE="${1:-}" -shift || true -if [[ "$MODE" != "remote" && "$MODE" != "local" ]]; then - echo "Usage: $0 {remote|local} [--dry-run] [--verify] [--no-delete]" >&2 - exit 2 -fi - -# ---------- FLAGS ---------- -DRY_RUN=0 -VERIFY=0 -DELETE=1 -while [[ $# -gt 0 ]]; do - case "$1" in - --dry-run) DRY_RUN=1 ;; - --verify) VERIFY=1 ; DRY_RUN=1 ;; # verify implies dry-run - --no-delete) DELETE=0 ;; - *) echo "Unknown option: $1" >&2; exit 2 ;; - esac - shift -done - -# ---------- DESTS / SOURCE ---------- -REMOTE_HOST="${REMOTE_HOST:-bak-kc-01.iaregamer.com}" -REMOTE_USER="${REMOTE_USER:-gameserver}" -REMOTE_BASE="${REMOTE_BASE:-/sdb1/backup}" -LOCAL_BASE="${LOCAL_BASE:-/backup}" -SRC_DIR="${SRC_DIR:-/home/gameserver}" - -SSH_KEY="${SSH_KEY:-/home/gameserver/.ssh/id_rsa}" -SSH_OPTS=( -o BatchMode=yes -o IdentitiesOnly=yes -i "$SSH_KEY" ) - -# ---------- Throttle caps (Mb/s) by time-of-day ---------- -BW_PEAK_MBIT="${BW_PEAK_MBIT:-100}" -BW_OFFPEAK_MBIT="${BW_OFFPEAK_MBIT:-300}" -PEAK_START="${PEAK_START:-16}" -PEAK_END="${PEAK_END:-23}" - -# ---------- Misc ---------- -LOCK_FILE="${LOCK_FILE:-/var/lock/gs-backup.lock}" -LOG_FILE="${LOG_FILE:-/var/log/gs-backup.log}" -PARTIAL_DIR=".rsync-partial" -VERIFY_STRICT="${VERIFY_STRICT:-0}" - -# Optional excludes (uncomment any you want) -EXCLUDES=( - # "--exclude=/home/gameserver/**/logs/**" - # "--exclude=/home/gameserver/**/*.log" - # "--exclude=/home/gameserver/**/cache/**" - # "--exclude=/home/gameserver/**/steamapps/downloading/**" - # "--exclude=/home/gameserver/**/steamapps/temp/**" -) - -log(){ printf '[%s] %s\n' "$(date +'%F %T')" "$*" | tee -a "$LOG_FILE" ; } - -# ---------- Pre-flight ---------- -[[ -d "$SRC_DIR" ]] || { echo "Missing SRC_DIR: $SRC_DIR" >&2; exit 1; } -command -v rsync >/dev/null || { echo "rsync not found" >&2; exit 1; } -command -v ionice >/dev/null || { echo "ionice not found" >&2; exit 1; } - -HOST_SHORT="$(hostname -s)" - -# Cap selector -hour="$(date +%H)" -if [[ "$hour" -ge "$PEAK_START" && "$hour" -le "$PEAK_END" ]]; then - CAP_MBIT="$BW_PEAK_MBIT" -else - CAP_MBIT="$BW_OFFPEAK_MBIT" -fi -BW_KBPS="$(( CAP_MBIT * 1000 / 8 ))" # rsync expects KB/s - -# Build rsync base flags -RSYNC_BASE=( rsync -aHAX --numeric-ids --info=stats2 ) -# Deletions (skip if --no-delete or verify w/o strict cleanup) -if [[ $DELETE -eq 1 ]]; then - RSYNC_BASE+=( --delete-delay ) -fi - -# Dry-run? -if [[ $DRY_RUN -eq 1 ]]; then - RSYNC_BASE+=( -n ) -fi - -# Itemize changes always in dry-run/verify so we can see drift -if [[ $DRY_RUN -eq 1 ]]; then - RSYNC_BASE+=( --itemize-changes --out-format='%i %n' ) -fi - -# Verify strict? (checksum-based comparison is heavier; size+mtime otherwise) -if [[ $VERIFY -eq 1 && $VERIFY_STRICT -eq 1 ]]; then - RSYNC_BASE+=( --checksum ) -fi - -# Performance / niceness -RSYNC_BASE+=( --partial --partial-dir="$PARTIAL_DIR" --bwlimit="$BW_KBPS" ) - -# Excludes -RSYNC_BASE+=( "${EXCLUDES[@]}" ) - -# Ensure local partial dir exists -mkdir -p "$SRC_DIR/$PARTIAL_DIR" || true - -# Compose destination -if [[ "$MODE" == "remote" ]]; then - DEST="${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_BASE}/${HOST_SHORT}/gameserver/" - DEST_DESC="REMOTE ${REMOTE_HOST}:${REMOTE_BASE}/${HOST_SHORT}/gameserver" -else - DEST="${LOCAL_BASE%/}/${HOST_SHORT}/gameserver/" - DEST_DESC="LOCAL ${LOCAL_BASE%/}/${HOST_SHORT}/gameserver" -fi - -# Ensure destination path exists -if [[ "$MODE" == "remote" ]]; then - ssh "${SSH_OPTS[@]}" "${REMOTE_USER}@${REMOTE_HOST}" "mkdir -p '${REMOTE_BASE}/${HOST_SHORT}/gameserver'" || true -else - mkdir -p "$DEST" -fi - -# ----------------- RUN ----------------- -{ - flock -n 9 || { log "Another run is active; exiting."; exit 0; } - - log "MODE=$MODE DRY_RUN=$DRY_RUN VERIFY=$VERIFY DELETE=$DELETE" - log "SRC=$SRC_DIR/ -> $DEST_DESC" - log "Cap: ${CAP_MBIT} Mb/s (bwlimit=${BW_KBPS} KB/s)" - - # Execute rsync - if [[ "$MODE" == "remote" ]]; then - CMD=( "${RSYNC_BASE[@]}" -e "ssh ${SSH_OPTS[*]}" "$SRC_DIR/" "$DEST" ) - else - CMD=( "${RSYNC_BASE[@]}" "$SRC_DIR/" "$DEST" ) - fi - - # In verify mode, capture output to detect drift - CHANGES=0 - if [[ $VERIFY -eq 1 ]]; then - TMP="$(mktemp)" - set +e - ionice -c3 nice -n 19 "${CMD[@]}" >"$TMP" 2>&1 - RC=$? - set -e - # Count itemized change lines (exclude rsync headers/footers) - if grep -qE '^[<>ch\*\.][^ ]{9} ' "$TMP"; then - CHANGES=1 - fi - cat "$TMP" | tee -a "$LOG_FILE" - rm -f "$TMP" - - if [[ $RC -ne 0 ]]; then - log "Verify run encountered rsync errors (rc=$RC)." - exit $RC - fi - - if [[ $CHANGES -eq 1 ]]; then - log "VERIFY: Drift detected between source and destination." - exit 3 - else - log "VERIFY: Source and destination are in sync." - exit 0 - fi - else - # Normal (or dry-run) run without drift check exit code - ionice -c3 nice -n 19 "${CMD[@]}" - RC=$? - if [[ $RC -eq 0 ]]; then - log "Completed successfully." - else - log "Rsync exited with code $RC." - fi - exit $RC - fi - -} 9>"$LOCK_FILE" diff --git a/db/mysql_template.sql b/db/mysql_template.sql deleted file mode 100644 index d63f5760..00000000 --- a/db/mysql_template.sql +++ /dev/null @@ -1,1447 +0,0 @@ --- phpMyAdmin SQL Dump --- version 4.9.5deb2 --- https://www.phpmyadmin.net/ --- --- Host: localhost:3306 --- Generation Time: Sep 08, 2025 at 11:28 AM --- Server version: 5.7.42-log --- PHP Version: 7.4.3-4ubuntu2.24 - -SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; -SET AUTOCOMMIT = 0; -START TRANSACTION; -SET time_zone = "+00:00"; - - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; - --- --- Database: `panel_template` --- - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_addons` --- - -CREATE TABLE `ogp_addons` ( - `addon_id` int(10) UNSIGNED NOT NULL, - `name` varchar(80) NOT NULL, - `url` varchar(200) NOT NULL, - `path` varchar(80) NOT NULL, - `addon_type` varchar(7) NOT NULL, - `home_cfg_id` varchar(7) NOT NULL, - `post_script` longtext NOT NULL, - `group_id` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_adminexternallinks` --- - -CREATE TABLE `ogp_adminexternallinks` ( - `link_id` int(10) UNSIGNED NOT NULL, - `name` varchar(80) NOT NULL, - `url` varchar(200) NOT NULL, - `user_id` varchar(7) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_adminlte_serverstats` --- - -CREATE TABLE `ogp_adminlte_serverstats` ( - `home_id` int(4) NOT NULL, - `users_online` int(4) NOT NULL, - `current_stamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_adminlte_settings` --- - -CREATE TABLE `ogp_adminlte_settings` ( - `id` int(20) NOT NULL, - `user` int(4) NOT NULL, - `name` varchar(255) NOT NULL, - `value` mediumtext NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_api_tokens` --- - -CREATE TABLE `ogp_api_tokens` ( - `user_id` int(11) NOT NULL, - `token` varchar(64) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_arrange_ports` --- - -CREATE TABLE `ogp_arrange_ports` ( - `range_id` int(11) NOT NULL, - `ip_id` int(11) NOT NULL, - `home_cfg_id` int(11) NOT NULL, - `start_port` smallint(11) UNSIGNED NOT NULL, - `end_port` smallint(11) UNSIGNED NOT NULL, - `port_increment` smallint(11) UNSIGNED NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Remote servers and IPs'; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_backup_restore` --- - -CREATE TABLE `ogp_backup_restore` ( - `id` int(11) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_ban_list` --- - -CREATE TABLE `ogp_ban_list` ( - `client_ip` varchar(255) NOT NULL, - `logging_attempts` int(11) NOT NULL DEFAULT '0', - `banned_until` varchar(16) NOT NULL DEFAULT '0' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_billing_carts` --- - -CREATE TABLE `ogp_billing_carts` ( - `cart_id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `paid` int(11) DEFAULT '0', - `date` varchar(16) NOT NULL DEFAULT '0', - `tax_amount` varchar(16) NOT NULL DEFAULT '0', - `currency` varchar(3) NOT NULL DEFAULT '0', - `coupon_id` varchar(11) DEFAULT '0' -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_billing_coupons` --- - -CREATE TABLE `ogp_billing_coupons` ( - `id` int(11) NOT NULL, - `code` varchar(16) NOT NULL, - `name` varchar(255) NOT NULL, - `discount` int(11) NOT NULL DEFAULT '0', - `recurring` int(11) NOT NULL DEFAULT '0', - `count` int(11) NOT NULL DEFAULT '-1', - `expires` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_billing_orders` --- - -CREATE TABLE `ogp_billing_orders` ( - `order_id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `service_id` int(11) NOT NULL, - `home_name` varchar(255) NOT NULL, - `ip` varchar(255) NOT NULL, - `qty` int(11) NOT NULL, - `invoice_duration` varchar(16) NOT NULL, - `max_players` int(11) NOT NULL, - `price` float(15,2) NOT NULL, - `remote_control_password` varchar(10) DEFAULT NULL, - `ftp_password` varchar(10) DEFAULT NULL, - `cart_id` int(11) NOT NULL, - `home_id` varchar(255) NOT NULL DEFAULT '0', - `status` varchar(16) NOT NULL DEFAULT '0', - `finish_date` varchar(16) NOT NULL DEFAULT '0', - `extended` tinyint(1) NOT NULL, - `coupon_id` int(11) NOT NULL DEFAULT '0' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_billing_services` --- - -CREATE TABLE `ogp_billing_services` ( - `service_id` int(11) NOT NULL, - `home_cfg_id` int(11) NOT NULL, - `mod_cfg_id` int(11) NOT NULL, - `service_name` varchar(255) NOT NULL, - `remote_server_id` varchar(255) NOT NULL, - `out_of_stock` varchar(255) NOT NULL, - `slot_max_qty` int(11) NOT NULL, - `slot_min_qty` int(11) NOT NULL, - `price_daily` float(15,4) NOT NULL, - `price_monthly` float(15,4) NOT NULL, - `price_year` float(15,4) NOT NULL, - `description` varchar(1000) NOT NULL, - `img_url` varchar(255) NOT NULL, - `ftp` varchar(255) NOT NULL, - `install_method` varchar(255) NOT NULL, - `manual_url` varchar(255) NOT NULL, - `access_rights` varchar(255) NOT NULL, - `enabled` int(11) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_circular` --- - -CREATE TABLE `ogp_circular` ( - `circular_id` int(11) NOT NULL, - `subject` text NOT NULL, - `message` text NOT NULL, - `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_circular_recipients` --- - -CREATE TABLE `ogp_circular_recipients` ( - `user_id` int(11) NOT NULL, - `circular_id` int(11) NOT NULL, - `status` tinyint(4) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_config_homes` --- - -CREATE TABLE `ogp_config_homes` ( - `home_cfg_id` int(20) NOT NULL, - `game_key` varchar(64) NOT NULL, - `game_name` varchar(255) NOT NULL, - `home_cfg_file` varchar(64) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_config_mods` --- - -CREATE TABLE `ogp_config_mods` ( - `mod_cfg_id` int(50) NOT NULL, - `home_cfg_id` varchar(50) NOT NULL, - `mod_key` varchar(100) NOT NULL COMMENT 'mod short name - used by the game server for startup commands - ex cstrike', - `mod_name` varchar(255) NOT NULL COMMENT 'Mod value is user defined string - like Counter-Strike', - `def_precmd` text, - `def_postcmd` text -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_game_mods` --- - -CREATE TABLE `ogp_game_mods` ( - `mod_id` int(50) NOT NULL, - `home_id` int(255) NOT NULL, - `mod_cfg_id` int(11) NOT NULL, - `max_players` smallint(3) DEFAULT NULL, - `extra_params` varchar(255) DEFAULT NULL, - `cpu_affinity` varchar(64) DEFAULT NULL, - `nice` smallint(3) DEFAULT '0', - `precmd` text, - `postcmd` text -) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='utf8mb4_general_ci'; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_home_ip_ports` --- - -CREATE TABLE `ogp_home_ip_ports` ( - `ip_id` int(11) NOT NULL, - `port` int(11) NOT NULL, - `home_id` int(11) NOT NULL, - `force_mod_id` int(11) NOT NULL DEFAULT '0' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_lgsl` --- - -CREATE TABLE `ogp_lgsl` ( - `id` int(11) NOT NULL, - `type` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', - `ip` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', - `c_port` varchar(5) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', - `q_port` varchar(5) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', - `s_port` varchar(5) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', - `zone` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', - `disabled` tinyint(1) NOT NULL DEFAULT '0', - `comment` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', - `status` tinyint(1) NOT NULL DEFAULT '0', - `cache` text COLLATE utf8_unicode_ci NOT NULL, - `cache_time` text COLLATE utf8_unicode_ci NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_logger` --- - -CREATE TABLE `ogp_logger` ( - `log_id` int(10) UNSIGNED NOT NULL, - `date` varchar(20) NOT NULL, - `user_id` int(11) NOT NULL, - `ip` varchar(15) NOT NULL, - `message` varchar(250) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_master_server_homes` --- - -CREATE TABLE `ogp_master_server_homes` ( - `home_id` int(11) NOT NULL, - `home_cfg_id` int(11) NOT NULL, - `remote_server_id` int(11) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_modules` --- - -CREATE TABLE `ogp_modules` ( - `id` smallint(5) UNSIGNED NOT NULL, - `title` varchar(100) NOT NULL DEFAULT '', - `folder` varchar(100) NOT NULL DEFAULT '', - `version` varchar(10) NOT NULL DEFAULT '0', - `db_version` int(10) NOT NULL DEFAULT '0' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_module_access_rights` --- - -CREATE TABLE `ogp_module_access_rights` ( - `module_id` int(11) NOT NULL COMMENT 'This references to modules.id', - `flag` char(1) NOT NULL, - `description` varchar(64) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_module_menus` --- - -CREATE TABLE `ogp_module_menus` ( - `module_id` int(11) NOT NULL COMMENT 'This references to modules.id', - `subpage` varchar(64) NOT NULL DEFAULT '', - `group` varchar(32) NOT NULL, - `menu_name` varchar(128) NOT NULL, - `pos` int(10) UNSIGNED NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_mysql_databases` --- - -CREATE TABLE `ogp_mysql_databases` ( - `db_id` int(11) NOT NULL, - `mysql_server_id` int(11) NOT NULL, - `home_id` int(11) NOT NULL, - `db_user` varchar(50) NOT NULL, - `db_passwd` varchar(50) NOT NULL, - `db_name` varchar(50) NOT NULL, - `enabled` int(11) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_mysql_servers` --- - -CREATE TABLE `ogp_mysql_servers` ( - `mysql_server_id` int(11) NOT NULL, - `remote_server_id` int(11) NOT NULL, - `mysql_name` varchar(100) NOT NULL, - `mysql_ip` varchar(255) NOT NULL, - `mysql_port` int(11) NOT NULL, - `mysql_root_passwd` varchar(32) DEFAULT NULL, - `privilegies_str` longtext -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_notification` --- - -CREATE TABLE `ogp_notification` ( - `notification_id` int(11) NOT NULL, - `subject` text NOT NULL, - `message` text NOT NULL, - `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_notification_recipients` --- - -CREATE TABLE `ogp_notification_recipients` ( - `user_id` int(11) NOT NULL, - `notification_id` int(11) NOT NULL, - `status` tinyint(4) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_rcon_presets` --- - -CREATE TABLE `ogp_rcon_presets` ( - `preset_id` int(50) NOT NULL, - `name` varchar(20) NOT NULL, - `command` varchar(100) NOT NULL, - `home_cfg_id` int(50) NOT NULL, - `mod_cfg_id` int(50) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_remote_servers` --- - -CREATE TABLE `ogp_remote_servers` ( - `remote_server_id` int(11) NOT NULL, - `remote_server_name` varchar(100) NOT NULL, - `ogp_user` varchar(100) NOT NULL, - `agent_ip` varchar(255) NOT NULL, - `agent_port` int(11) NOT NULL, - `ftp_port` int(11) NOT NULL, - `encryption_key` varchar(50) NOT NULL, - `timeout` int(11) NOT NULL, - `use_nat` int(11) NOT NULL, - `ftp_ip` varchar(255) NOT NULL, - `firewall_settings` longtext, - `display_public_ip` varchar(255) NOT NULL, - `enabled` int(11) NOT NULL DEFAULT '1' -) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='Remote servers and IPs'; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_remote_server_ips` --- - -CREATE TABLE `ogp_remote_server_ips` ( - `ip_id` int(11) NOT NULL, - `remote_server_id` int(11) NOT NULL, - `ip` varchar(255) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_reseller_accounts` --- - -CREATE TABLE `ogp_reseller_accounts` ( - `account_id` int(11) NOT NULL, - `service_id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `qty` int(11) DEFAULT NULL, - `invoice_duration` varchar(7) NOT NULL, - `discount` int(11) NOT NULL, - `price` int(11) NOT NULL, - `payment_date` varchar(20) NOT NULL DEFAULT '0', - `cart_id` int(11) NOT NULL, - `status` varchar(16) NOT NULL DEFAULT '0', - `available_months` int(11) NOT NULL DEFAULT '0', - `available_slots` int(11) NOT NULL DEFAULT '0' -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_reseller_carts` --- - -CREATE TABLE `ogp_reseller_carts` ( - `cart_id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `paid` int(11) DEFAULT NULL, - `tax_amount` varchar(20) NOT NULL DEFAULT '0', - `currency` varchar(3) NOT NULL DEFAULT '0' -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_reseller_discount_codes` --- - -CREATE TABLE `ogp_reseller_discount_codes` ( - `discount_id` int(11) NOT NULL, - `service_id` int(11) NOT NULL, - `percentage` int(11) NOT NULL, - `description` varchar(255) NOT NULL DEFAULT '0', - `code` varchar(255) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_reseller_homes` --- - -CREATE TABLE `ogp_reseller_homes` ( - `home_id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `account_id` int(11) NOT NULL, - `assigned_slots` int(11) NOT NULL, - `status` varchar(16) NOT NULL DEFAULT '0' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_reseller_services` --- - -CREATE TABLE `ogp_reseller_services` ( - `service_id` int(11) NOT NULL, - `service_name` varchar(60) NOT NULL, - `slot_max_qty` int(11) NOT NULL, - `price_per_month` float(15,4) NOT NULL, - `price_per_year` float(15,4) NOT NULL, - `description` varchar(1000) NOT NULL, - `remote_server_id` int(11) NOT NULL, - `start_port` int(11) NOT NULL, - `end_port` int(11) NOT NULL, - `max_access_rights` varchar(255) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_server_homes` --- - -CREATE TABLE `ogp_server_homes` ( - `home_id` int(50) NOT NULL, - `remote_server_id` int(11) NOT NULL, - `user_id_main` int(11) NOT NULL, - `home_path` varchar(500) DEFAULT NULL, - `home_cfg_id` int(50) NOT NULL, - `home_name` varchar(500) DEFAULT NULL, - `control_password` varchar(128) DEFAULT NULL, - `ftp_password` varchar(128) DEFAULT NULL, - `last_param` longtext, - `ftp_login` varchar(32) DEFAULT NULL, - `ftp_status` int(11) NOT NULL DEFAULT '0', - `custom_fields` longtext, - `server_expiration_date` varchar(21) NOT NULL DEFAULT 'X', - `home_user_order` int(11) NOT NULL DEFAULT '99999' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_settings` --- - -CREATE TABLE `ogp_settings` ( - `setting` varchar(63) NOT NULL, - `value` varchar(1024) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_status_cache` --- - -CREATE TABLE `ogp_status_cache` ( - `date_timestamp` char(16) NOT NULL, - `ip_id` char(3) NOT NULL, - `port` char(6) NOT NULL, - `server_status_cache` longtext NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_tickets` --- - -CREATE TABLE `ogp_tickets` ( - `tid` int(11) NOT NULL, - `uid` varchar(32) NOT NULL, - `user_id` int(11) NOT NULL, - `parent_id` int(11) NOT NULL, - `user_ip` varbinary(16) NOT NULL, - `subject` varchar(64) NOT NULL, - `service_id` int(11) DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `last_updated` varchar(22) DEFAULT NULL, - `status` tinyint(4) NOT NULL, - `assigned_to` tinyint(4) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_ticket_attachments` --- - -CREATE TABLE `ogp_ticket_attachments` ( - `attachment_id` int(11) NOT NULL, - `ticket_id` int(11) NOT NULL, - `reply_id` int(11) DEFAULT NULL, - `original_name` varchar(255) NOT NULL, - `unique_name` varchar(32) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_ticket_messages` --- - -CREATE TABLE `ogp_ticket_messages` ( - `reply_id` int(11) NOT NULL, - `ticket_id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `user_ip` varbinary(16) NOT NULL, - `message` text NOT NULL, - `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `rating` tinyint(4) DEFAULT '0', - `is_admin` int(11) DEFAULT '0' -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_ticket_settings` --- - -CREATE TABLE `ogp_ticket_settings` ( - `id` int(11) NOT NULL, - `setting_name` varchar(32) NOT NULL, - `setting_value` text NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_ts3_homes` --- - -CREATE TABLE `ogp_ts3_homes` ( - `ts3_id` int(50) NOT NULL, - `rserver_id` int(50) NOT NULL, - `ip` varchar(20) NOT NULL, - `pwd` varchar(40) NOT NULL, - `vserver_id` int(50) NOT NULL, - `user_id` int(50) NOT NULL, - `port` int(11) DEFAULT '10011' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_tshock` --- - -CREATE TABLE `ogp_tshock` ( - `token_id` int(11) NOT NULL, - `ip` varchar(255) NOT NULL, - `port` int(11) NOT NULL, - `token` varchar(64) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_update_blacklist` --- - -CREATE TABLE `ogp_update_blacklist` ( - `file_path` varchar(1000) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_users` --- - -CREATE TABLE `ogp_users` ( - `user_id` int(11) NOT NULL, - `users_login` varchar(255) NOT NULL, - `users_passwd` varchar(255) NOT NULL, - `users_lang` varchar(20) NOT NULL DEFAULT 'English', - `users_role` varchar(30) NOT NULL DEFAULT 'user', - `users_group` varchar(100) DEFAULT NULL, - `users_fname` varchar(255) DEFAULT NULL, - `users_lname` varchar(255) DEFAULT NULL, - `users_email` varchar(255) DEFAULT NULL, - `users_phone` varchar(12) DEFAULT NULL, - `users_city` varchar(255) DEFAULT NULL, - `users_province` varchar(255) DEFAULT NULL, - `users_country` varchar(255) DEFAULT NULL, - `users_comment` text, - `users_theme` varchar(255) DEFAULT NULL, - `user_expires` varchar(30) NOT NULL DEFAULT 'X', - `users_parent` int(11) DEFAULT NULL, - `users_page_limit` int(11) DEFAULT '25', - `user_receives_emails` tinyint(1) NOT NULL DEFAULT '1' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_user_groups` --- - -CREATE TABLE `ogp_user_groups` ( - `user_id` int(11) NOT NULL, - `role_id` int(11) DEFAULT NULL, - `group_id` int(11) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_user_group_homes` --- - -CREATE TABLE `ogp_user_group_homes` ( - `home_id` int(11) NOT NULL, - `group_id` int(11) NOT NULL, - `access_rights` varchar(63) DEFAULT NULL, - `user_group_expiration_date` varchar(21) NOT NULL DEFAULT 'X' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_user_group_info` --- - -CREATE TABLE `ogp_user_group_info` ( - `group_id` int(11) NOT NULL, - `group_name` varchar(255) DEFAULT NULL, - `main_user_id` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_user_group_remote_servers` --- - -CREATE TABLE `ogp_user_group_remote_servers` ( - `remote_server_id` int(11) NOT NULL, - `group_id` int(11) NOT NULL, - `access_rights` varchar(63) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_user_homes` --- - -CREATE TABLE `ogp_user_homes` ( - `home_id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `access_rights` varchar(63) DEFAULT NULL, - `user_expiration_date` varchar(21) NOT NULL DEFAULT 'X' -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_user_role_info` --- - -CREATE TABLE `ogp_user_role_info` ( - `role_id` int(11) NOT NULL, - `role_name` varchar(100) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_widgets` --- - -CREATE TABLE `ogp_widgets` ( - `id` int(11) NOT NULL, - `column_id` int(11) NOT NULL, - `sort_no` int(11) NOT NULL, - `collapsed` tinyint(4) NOT NULL, - `title` varchar(100) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- -------------------------------------------------------- - --- --- Table structure for table `ogp_widgets_users` --- - -CREATE TABLE `ogp_widgets_users` ( - `user_id` int(11) NOT NULL, - `widget_id` int(11) NOT NULL, - `column_id` int(11) NOT NULL, - `sort_no` int(11) NOT NULL, - `collapsed` tinyint(4) NOT NULL, - `title` varchar(100) NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1; - --- --- Indexes for dumped tables --- - --- --- Indexes for table `ogp_addons` --- -ALTER TABLE `ogp_addons` - ADD PRIMARY KEY (`addon_id`); - --- --- Indexes for table `ogp_adminexternallinks` --- -ALTER TABLE `ogp_adminexternallinks` - ADD PRIMARY KEY (`link_id`); - --- --- Indexes for table `ogp_adminlte_settings` --- -ALTER TABLE `ogp_adminlte_settings` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `UniqueSetting` (`user`,`name`); - --- --- Indexes for table `ogp_api_tokens` --- -ALTER TABLE `ogp_api_tokens` - ADD PRIMARY KEY (`user_id`), - ADD UNIQUE KEY `user_id` (`user_id`); - --- --- Indexes for table `ogp_arrange_ports` --- -ALTER TABLE `ogp_arrange_ports` - ADD PRIMARY KEY (`range_id`), - ADD UNIQUE KEY `ip_id` (`ip_id`,`home_cfg_id`); - --- --- Indexes for table `ogp_backup_restore` --- -ALTER TABLE `ogp_backup_restore` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `ogp_ban_list` --- -ALTER TABLE `ogp_ban_list` - ADD PRIMARY KEY (`client_ip`); - --- --- Indexes for table `ogp_billing_carts` --- -ALTER TABLE `ogp_billing_carts` - ADD PRIMARY KEY (`cart_id`); - --- --- Indexes for table `ogp_billing_coupons` --- -ALTER TABLE `ogp_billing_coupons` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `ogp_billing_orders` --- -ALTER TABLE `ogp_billing_orders` - ADD PRIMARY KEY (`order_id`); - --- --- Indexes for table `ogp_billing_services` --- -ALTER TABLE `ogp_billing_services` - ADD PRIMARY KEY (`service_id`); - --- --- Indexes for table `ogp_circular` --- -ALTER TABLE `ogp_circular` - ADD PRIMARY KEY (`circular_id`); - --- --- Indexes for table `ogp_circular_recipients` --- -ALTER TABLE `ogp_circular_recipients` - ADD PRIMARY KEY (`user_id`,`circular_id`); - --- --- Indexes for table `ogp_config_homes` --- -ALTER TABLE `ogp_config_homes` - ADD PRIMARY KEY (`home_cfg_id`), - ADD UNIQUE KEY `game_key` (`game_key`); - --- --- Indexes for table `ogp_config_mods` --- -ALTER TABLE `ogp_config_mods` - ADD PRIMARY KEY (`mod_cfg_id`), - ADD UNIQUE KEY `home_cfg_id` (`home_cfg_id`,`mod_key`); - --- --- Indexes for table `ogp_game_mods` --- -ALTER TABLE `ogp_game_mods` - ADD PRIMARY KEY (`mod_id`), - ADD UNIQUE KEY `home_id` (`home_id`,`mod_cfg_id`); - --- --- Indexes for table `ogp_home_ip_ports` --- -ALTER TABLE `ogp_home_ip_ports` - ADD PRIMARY KEY (`ip_id`,`port`); - --- --- Indexes for table `ogp_lgsl` --- -ALTER TABLE `ogp_lgsl` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `ogp_logger` --- -ALTER TABLE `ogp_logger` - ADD PRIMARY KEY (`log_id`); - --- --- Indexes for table `ogp_master_server_homes` --- -ALTER TABLE `ogp_master_server_homes` - ADD PRIMARY KEY (`remote_server_id`,`home_cfg_id`); - --- --- Indexes for table `ogp_modules` --- -ALTER TABLE `ogp_modules` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `folder` (`folder`); - --- --- Indexes for table `ogp_module_access_rights` --- -ALTER TABLE `ogp_module_access_rights` - ADD UNIQUE KEY `flag` (`flag`); - --- --- Indexes for table `ogp_module_menus` --- -ALTER TABLE `ogp_module_menus` - ADD PRIMARY KEY (`module_id`,`subpage`,`group`); - --- --- Indexes for table `ogp_mysql_databases` --- -ALTER TABLE `ogp_mysql_databases` - ADD PRIMARY KEY (`db_id`), - ADD UNIQUE KEY `mysql_server_id` (`mysql_server_id`,`db_name`), - ADD UNIQUE KEY `mysql_server_id_2` (`mysql_server_id`,`db_user`); - --- --- Indexes for table `ogp_mysql_servers` --- -ALTER TABLE `ogp_mysql_servers` - ADD PRIMARY KEY (`mysql_server_id`); - --- --- Indexes for table `ogp_notification` --- -ALTER TABLE `ogp_notification` - ADD PRIMARY KEY (`notification_id`); - --- --- Indexes for table `ogp_notification_recipients` --- -ALTER TABLE `ogp_notification_recipients` - ADD PRIMARY KEY (`user_id`,`notification_id`); - --- --- Indexes for table `ogp_rcon_presets` --- -ALTER TABLE `ogp_rcon_presets` - ADD PRIMARY KEY (`preset_id`); - --- --- Indexes for table `ogp_remote_servers` --- -ALTER TABLE `ogp_remote_servers` - ADD PRIMARY KEY (`remote_server_id`), - ADD UNIQUE KEY `agent_ip` (`agent_ip`,`agent_port`); - --- --- Indexes for table `ogp_remote_server_ips` --- -ALTER TABLE `ogp_remote_server_ips` - ADD PRIMARY KEY (`ip_id`); - --- --- Indexes for table `ogp_reseller_accounts` --- -ALTER TABLE `ogp_reseller_accounts` - ADD PRIMARY KEY (`account_id`); - --- --- Indexes for table `ogp_reseller_carts` --- -ALTER TABLE `ogp_reseller_carts` - ADD PRIMARY KEY (`cart_id`); - --- --- Indexes for table `ogp_reseller_discount_codes` --- -ALTER TABLE `ogp_reseller_discount_codes` - ADD PRIMARY KEY (`discount_id`); - --- --- Indexes for table `ogp_reseller_homes` --- -ALTER TABLE `ogp_reseller_homes` - ADD PRIMARY KEY (`home_id`); - --- --- Indexes for table `ogp_reseller_services` --- -ALTER TABLE `ogp_reseller_services` - ADD PRIMARY KEY (`service_id`); - --- --- Indexes for table `ogp_server_homes` --- -ALTER TABLE `ogp_server_homes` - ADD PRIMARY KEY (`home_id`); - --- --- Indexes for table `ogp_settings` --- -ALTER TABLE `ogp_settings` - ADD PRIMARY KEY (`setting`); - --- --- Indexes for table `ogp_tickets` --- -ALTER TABLE `ogp_tickets` - ADD PRIMARY KEY (`tid`), - ADD UNIQUE KEY `uid` (`uid`); - --- --- Indexes for table `ogp_ticket_attachments` --- -ALTER TABLE `ogp_ticket_attachments` - ADD PRIMARY KEY (`attachment_id`), - ADD UNIQUE KEY `unique_name` (`unique_name`); - --- --- Indexes for table `ogp_ticket_messages` --- -ALTER TABLE `ogp_ticket_messages` - ADD PRIMARY KEY (`reply_id`), - ADD KEY `ogp_ticket_messages_fk0` (`ticket_id`); - --- --- Indexes for table `ogp_ticket_settings` --- -ALTER TABLE `ogp_ticket_settings` - ADD PRIMARY KEY (`id`), - ADD UNIQUE KEY `setting_name` (`setting_name`); - --- --- Indexes for table `ogp_ts3_homes` --- -ALTER TABLE `ogp_ts3_homes` - ADD PRIMARY KEY (`ts3_id`), - ADD UNIQUE KEY `rserver_id` (`rserver_id`,`vserver_id`,`user_id`); - --- --- Indexes for table `ogp_tshock` --- -ALTER TABLE `ogp_tshock` - ADD PRIMARY KEY (`token_id`); - --- --- Indexes for table `ogp_update_blacklist` --- -ALTER TABLE `ogp_update_blacklist` - ADD UNIQUE KEY `file_path` (`file_path`), - ADD UNIQUE KEY `file_path_2` (`file_path`); - --- --- Indexes for table `ogp_users` --- -ALTER TABLE `ogp_users` - ADD PRIMARY KEY (`users_login`), - ADD UNIQUE KEY `id` (`user_id`), - ADD UNIQUE KEY `email` (`users_email`); - --- --- Indexes for table `ogp_user_groups` --- -ALTER TABLE `ogp_user_groups` - ADD PRIMARY KEY (`user_id`,`group_id`); - --- --- Indexes for table `ogp_user_group_homes` --- -ALTER TABLE `ogp_user_group_homes` - ADD PRIMARY KEY (`home_id`,`group_id`); - --- --- Indexes for table `ogp_user_group_info` --- -ALTER TABLE `ogp_user_group_info` - ADD PRIMARY KEY (`group_id`), - ADD UNIQUE KEY `group_name` (`group_name`); - --- --- Indexes for table `ogp_user_group_remote_servers` --- -ALTER TABLE `ogp_user_group_remote_servers` - ADD PRIMARY KEY (`remote_server_id`,`group_id`); - --- --- Indexes for table `ogp_user_homes` --- -ALTER TABLE `ogp_user_homes` - ADD PRIMARY KEY (`user_id`,`home_id`); - --- --- Indexes for table `ogp_user_role_info` --- -ALTER TABLE `ogp_user_role_info` - ADD PRIMARY KEY (`role_id`), - ADD UNIQUE KEY `role_name` (`role_name`); - --- --- Indexes for table `ogp_widgets` --- -ALTER TABLE `ogp_widgets` - ADD PRIMARY KEY (`id`); - --- --- AUTO_INCREMENT for dumped tables --- - --- --- AUTO_INCREMENT for table `ogp_addons` --- -ALTER TABLE `ogp_addons` - MODIFY `addon_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=134; - --- --- AUTO_INCREMENT for table `ogp_adminexternallinks` --- -ALTER TABLE `ogp_adminexternallinks` - MODIFY `link_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; - --- --- AUTO_INCREMENT for table `ogp_adminlte_settings` --- -ALTER TABLE `ogp_adminlte_settings` - MODIFY `id` int(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=15; - --- --- AUTO_INCREMENT for table `ogp_arrange_ports` --- -ALTER TABLE `ogp_arrange_ports` - MODIFY `range_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=259; - --- --- AUTO_INCREMENT for table `ogp_backup_restore` --- -ALTER TABLE `ogp_backup_restore` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `ogp_billing_carts` --- -ALTER TABLE `ogp_billing_carts` - MODIFY `cart_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=556; - --- --- AUTO_INCREMENT for table `ogp_billing_coupons` --- -ALTER TABLE `ogp_billing_coupons` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8; - --- --- AUTO_INCREMENT for table `ogp_billing_orders` --- -ALTER TABLE `ogp_billing_orders` - MODIFY `order_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=540; - --- --- AUTO_INCREMENT for table `ogp_billing_services` --- -ALTER TABLE `ogp_billing_services` - MODIFY `service_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=124; - --- --- AUTO_INCREMENT for table `ogp_circular` --- -ALTER TABLE `ogp_circular` - MODIFY `circular_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=13; - --- --- AUTO_INCREMENT for table `ogp_config_homes` --- -ALTER TABLE `ogp_config_homes` - MODIFY `home_cfg_id` int(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=280; - --- --- AUTO_INCREMENT for table `ogp_config_mods` --- -ALTER TABLE `ogp_config_mods` - MODIFY `mod_cfg_id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=874; - --- --- AUTO_INCREMENT for table `ogp_game_mods` --- -ALTER TABLE `ogp_game_mods` - MODIFY `mod_id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1666; - --- --- AUTO_INCREMENT for table `ogp_lgsl` --- -ALTER TABLE `ogp_lgsl` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `ogp_logger` --- -ALTER TABLE `ogp_logger` - MODIFY `log_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=63213; - --- --- AUTO_INCREMENT for table `ogp_modules` --- -ALTER TABLE `ogp_modules` - MODIFY `id` smallint(5) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=197; - --- --- AUTO_INCREMENT for table `ogp_mysql_databases` --- -ALTER TABLE `ogp_mysql_databases` - MODIFY `db_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=348; - --- --- AUTO_INCREMENT for table `ogp_mysql_servers` --- -ALTER TABLE `ogp_mysql_servers` - MODIFY `mysql_server_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; - --- --- AUTO_INCREMENT for table `ogp_notification` --- -ALTER TABLE `ogp_notification` - MODIFY `notification_id` int(11) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `ogp_rcon_presets` --- -ALTER TABLE `ogp_rcon_presets` - MODIFY `preset_id` int(50) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `ogp_remote_servers` --- -ALTER TABLE `ogp_remote_servers` - MODIFY `remote_server_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=54; - --- --- AUTO_INCREMENT for table `ogp_remote_server_ips` --- -ALTER TABLE `ogp_remote_server_ips` - MODIFY `ip_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=72; - --- --- AUTO_INCREMENT for table `ogp_reseller_accounts` --- -ALTER TABLE `ogp_reseller_accounts` - MODIFY `account_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; - --- --- AUTO_INCREMENT for table `ogp_reseller_carts` --- -ALTER TABLE `ogp_reseller_carts` - MODIFY `cart_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; - --- --- AUTO_INCREMENT for table `ogp_reseller_discount_codes` --- -ALTER TABLE `ogp_reseller_discount_codes` - MODIFY `discount_id` int(11) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `ogp_reseller_services` --- -ALTER TABLE `ogp_reseller_services` - MODIFY `service_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; - --- --- AUTO_INCREMENT for table `ogp_server_homes` --- -ALTER TABLE `ogp_server_homes` - MODIFY `home_id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1516; - --- --- AUTO_INCREMENT for table `ogp_tickets` --- -ALTER TABLE `ogp_tickets` - MODIFY `tid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=26; - --- --- AUTO_INCREMENT for table `ogp_ticket_attachments` --- -ALTER TABLE `ogp_ticket_attachments` - MODIFY `attachment_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5; - --- --- AUTO_INCREMENT for table `ogp_ticket_messages` --- -ALTER TABLE `ogp_ticket_messages` - MODIFY `reply_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=43; - --- --- AUTO_INCREMENT for table `ogp_ticket_settings` --- -ALTER TABLE `ogp_ticket_settings` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8; - --- --- AUTO_INCREMENT for table `ogp_ts3_homes` --- -ALTER TABLE `ogp_ts3_homes` - MODIFY `ts3_id` int(50) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2; - --- --- AUTO_INCREMENT for table `ogp_tshock` --- -ALTER TABLE `ogp_tshock` - MODIFY `token_id` int(11) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `ogp_users` --- -ALTER TABLE `ogp_users` - MODIFY `user_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=636; - --- --- AUTO_INCREMENT for table `ogp_user_group_info` --- -ALTER TABLE `ogp_user_group_info` - MODIFY `group_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=27; - --- --- AUTO_INCREMENT for table `ogp_user_role_info` --- -ALTER TABLE `ogp_user_role_info` - MODIFY `role_id` int(11) NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `ogp_widgets` --- -ALTER TABLE `ogp_widgets` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7; - --- --- Constraints for dumped tables --- - --- --- Constraints for table `ogp_ticket_messages` --- -ALTER TABLE `ogp_ticket_messages` - ADD CONSTRAINT `ogp_ticket_messages_fk0` FOREIGN KEY (`ticket_id`) REFERENCES `ogp_tickets` (`tid`); - --- --- Dumping data for consolidated modules --- - --- Dashboard widgets -INSERT INTO `ogp_widgets` (`id`, `column_id`, `sort_no`, `collapsed`, `title`) VALUES -(1, 1, 1, 0, 'Game Monitor'), -(2, 2, 0, 0, 'Online Server'), -(3, 2, 1, 0, 'Currently Online'), -(4, 3, 0, 0, 'FTP'), -(5, 3, 1, 0, 'Support'); - --- Ticket system default settings -INSERT INTO `ogp_ticket_settings` (setting_name, setting_value) VALUES ('ratings_enabled', 'true') ON DUPLICATE KEY UPDATE `setting_name` = 'ratings_enabled', `setting_value` = 'true'; -INSERT INTO `ogp_ticket_settings` (setting_name, setting_value) VALUES ('attachments_enabled', 'true') ON DUPLICATE KEY UPDATE `setting_name` = 'attachments_enabled', `setting_value` = 'true'; -INSERT INTO `ogp_ticket_settings` (setting_name, setting_value) VALUES ('attachment_max_size', '52428800') ON DUPLICATE KEY UPDATE `setting_name` = 'attachment_max_size', `setting_value` = '52428800'; -INSERT INTO `ogp_ticket_settings` (setting_name, setting_value) VALUES ('attachment_limit', '5') ON DUPLICATE KEY UPDATE `setting_name` = 'attachment_limit', `setting_value` = '5'; -INSERT INTO `ogp_ticket_settings` (setting_name, setting_value) VALUES ('attachment_save_dir', 'modules/tickets/uploads') ON DUPLICATE KEY UPDATE `setting_name` = 'attachment_save_dir', `setting_value` = 'modules/tickets/uploads'; -INSERT INTO `ogp_ticket_settings` (setting_name, setting_value) VALUES ('attachment_extensions', 'jpg, gif, jpeg, jpg, png, pdf, txt, sql, zip') ON DUPLICATE KEY UPDATE `setting_name` = 'attachment_extensions', `setting_value` = 'jpg, gif, jpeg, jpg, png, pdf, txt, sql, zip'; -INSERT INTO `ogp_ticket_settings` (setting_name, setting_value) VALUES ('notifications_enabled', 'true') ON DUPLICATE KEY UPDATE `setting_name` = 'notifications_enabled', `setting_value` = 'true'; - -COMMIT; - -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/ftp/Client.zip b/ftp/Client.zip new file mode 100644 index 00000000..f3c5d917 Binary files /dev/null and b/ftp/Client.zip differ diff --git a/game_titles.txt b/game_titles.txt new file mode 100644 index 00000000..22b3b852 --- /dev/null +++ b/game_titles.txt @@ -0,0 +1,57 @@ +# Game Titles Reference File +# This file contains the complete list of games to generate comprehensive server admin guides for +# Format: Game Title | Engine | AppID | Workshop Support | LinuxGSM Support | OGP Module Support + +# Existing games from data/games/ (verified) +7 Days to Die | Unity | 294420 | No | Yes | Yes +ARK: Survival Evolved | Unreal Engine 4 | 376030 | Yes | Yes | Yes +ARMA 3 | Real Virtuality 4 | 107410 | Yes | Yes | Yes +ARMA 2: Operation Arrowhead | Real Virtuality 3 | 33930 | No | Yes | Yes +Counter-Strike: Global Offensive | Source | 730 | Yes | Yes | Yes +DayZ | Enfusion | 221100 | Yes | Yes | Yes +Garry's Mod | Source | 4000 | Yes | Yes | Yes +Minecraft | Java | N/A | No | Yes | Yes +Rust | Unity | 258550 | No | Yes | Yes +Squad | Unreal Engine 4 | 393380 | Yes | Yes | Yes +Team Fortress 2 | Source | 440 | Yes | Yes | Yes +Terraria | XNA/MonoGame | 105600 | Yes | Yes | Yes +Unturned | Unity | 304930 | Yes | Yes | Yes +Valheim | Unity | 892970 | Yes | Yes | Yes + +# Additional popular games from OGP, LinuxGSM, and top providers +Conan Exiles | Unreal Engine 4 | 440900 | Yes | Yes | Yes +Space Engineers | VRAGE 2.0 | 244850 | Yes | Yes | Yes +Killing Floor 2 | Unreal Engine 3 | 232090 | Yes | Yes | Yes +Left 4 Dead 2 | Source | 550 | Yes | Yes | Yes +Counter-Strike 2 | Source 2 | 730 | Yes | Yes | Yes +Call of Duty 4: Modern Warfare | IW 3.0 | N/A | No | Yes | Yes +Call of Duty: World at War | IW 3.0 | N/A | No | Yes | Yes +Factorio | Custom | 427520 | No | Yes | Yes +Project Zomboid | Java | 108600 | Yes | Yes | Yes +Insurgency: Sandstorm | Unreal Engine 4 | 581320 | Yes | Yes | Yes +Rising Storm 2: Vietnam | Unreal Engine 3 | 418460 | Yes | Yes | Yes +Red Orchestra 2 | Unreal Engine 3 | 35450 | Yes | Yes | Yes +SCUM | Unreal Engine 4 | 513710 | No | Yes | Yes +The Forest | Unity | 242760 | No | Yes | Yes +Green Hell | Unity | 815370 | No | Yes | Yes +V Rising | Unity | 1604030 | No | Yes | Yes +Satisfactory | Unreal Engine 4 | 526870 | No | Yes | Yes +Subnautica | Unity | 264710 | No | Yes | Yes +Don't Starve Together | Custom | 322330 | Yes | Yes | Yes +Avorion | Custom | 445220 | Yes | Yes | Yes +Astroneer | Unreal Engine 4 | 361420 | No | Yes | Yes +Eco | Unity | 382310 | No | Yes | Yes +Atlas | Unreal Engine 4 | 834910 | Yes | Yes | Yes +Stationeers | Unity | 544550 | No | Yes | Yes +Citadel: Forged with Fire | Unreal Engine 4 | 487120 | Yes | Yes | Yes +Blackwake | Unity | 420290 | No | Yes | Yes +Mordhau | Unreal Engine 4 | 629760 | Yes | Yes | Yes +Starbound | Custom | 211820 | Yes | Yes | Yes +OpenTTD | Custom | N/A | No | Yes | Yes +Multi Theft Auto | Custom | N/A | No | Yes | Yes +San Andreas Multiplayer | Custom | N/A | No | Yes | Yes +FiveM (GTA V) | RAGE | N/A | No | Yes | Yes +Minecraft Bedrock | C++ | N/A | No | Yes | Yes +CS2D | Custom | N/A | No | Yes | Yes +Trackmania Nations | Custom | N/A | No | Yes | Yes +Trackmania Forever | Custom | N/A | No | Yes | Yes \ No newline at end of file diff --git a/images/logo.png b/images/logo.png index 4487e926..a3c63973 100644 Binary files a/images/logo.png and b/images/logo.png differ diff --git a/images/online_big.png.bak b/images/online_big.png.bak new file mode 100644 index 00000000..d2679a42 Binary files /dev/null and b/images/online_big.png.bak differ diff --git a/index.orig.php b/index.orig.php new file mode 100644 index 00000000..a80f6c08 --- /dev/null +++ b/index.orig.php @@ -0,0 +1,384 @@ +Session ID is " . session_id() . "

"; +// echo "

Lifetime is: " . $cookie_lifetime . "
Dir is " . rtrim(dirname($_SERVER["SCRIPT_NAME"]),"/") . "/" . "
Session cookie domain path is " . $session_cookie_domain_path . "
SSL is " . $ssl . "

"; + +//Config Check +$config_inc_readable = is_readable(CONFIG_FILE); +if ( !$config_inc_readable && file_exists("install.php") ) { + header('Location: install.php'); + exit(); +} +if ( '' == file_get_contents(CONFIG_FILE) ) { + header('Location: install.php'); + exit(); +} + +require_once CONFIG_FILE; +// Connect to the database server and select database. +$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix); + +// Load languages. +include_once("includes/lang.php"); + +if (!$db instanceof OGPDatabase) { + ogpLang(); + die(get_lang('no_db_connection')); +} + +// Logged in user settings - access this global variable where needed +if(hasValue($_SESSION['user_id'])){ + $loggedInUserInfo = $db->getUserById($_SESSION['user_id']); +} + +$settings = $db->getSettings(); +@$GLOBALS['panel_language'] = $settings['panel_language']; +ogpLang(); + +require_once("includes/view.php"); +$view = new OGPView(); +$view->setCharset( get_lang('lang_charset') ); +if(isset($_GET['type']) && $_GET['type'] == 'cleared') +{ + heading(true); + $view->printView(true); +} +else +{ + ogpHome(); + $view->printView(); +} + +function heading() +{ + + global $db,$view,$settings; + + $view->setCharset( get_lang('lang_charset') ); + $view->setTimeZone($settings['time_zone']); + + if ( !file_exists(CONFIG_FILE) ) + { + print_failure( get_lang("failed_to_read_config") ); + $view->refresh("index.php"); + return; + } + // Start Output Buffering + + if( isset($settings['maintenance_mode']) && $settings['maintenance_mode'] == "1" ) + { + if ($_SESSION['users_group'] != "admin" ) + { + echo "

".$settings['maintenance_title']."

"; + echo "

".$settings['maintenance_message']."

"; + $view->setTitle("OGP: Maintenance."); + echo "

". get_lang("logging_out_10") ."...

"; + $view->refresh("index.php", 10); + session_destroy(); + return; + } + } + include "includes/navig.php"; + if(isset($maintenance))echo $maintenance; +} + +function ogpHome() +{ + global $db,$view,$settings; + + if( isset($_GET['lang']) AND $_GET['lang'] != "-") + $lang = $_GET['lang']; + elseif( isset($settings['panel_language']) ) + $lang = $settings['panel_language']; + else + $lang = "English"; + + $locale_files = makefilelist("lang/", ".|..|.svn", true, "folders"); + $lang_sel = "\n"; + $lang_switch = ( isset( $_GET['lang'] ) AND $_GET['lang'] != "-" ) ? "&lang=" . $_GET['lang'] : ""; + ?> + %top% + + %topbody% + $value) + $postdata .= ",'$key': '$value'"; + $postdata = substr($postdata,1); + $postdata = "{".$postdata."}"; + */ + } + else + { + $default_page = $db->isModuleInstalled('dashboard') ? "m=dashboard&p=dashboard" : "m=gamemanager&p=game_monitor"; + if ( isset($_SESSION['users_login']) ) + { + $userInfo = $db->getUser($_SESSION['users_login']); + if( isset($_SESSION['users_passwd']) AND !empty($_SESSION['users_passwd']) AND $_SESSION['users_passwd'] == $userInfo['users_passwd']) + { + print_success( get_lang("already_logged_in_redirecting_to_dashboard") ."."); + $view->refresh("home.php?$default_page",2); + echo "%botbody% + %bottom%"; + return; + } + } + + if ( isset($_POST['login']) ) + { + $client_ip = getClientIPAddress(); + + $ban_list = $db->resultQuery("SHOW TABLES LIKE 'OGP_DB_PREFIXban_list';"); + if ( empty( $ban_list ) ) + { + $db->query("CREATE TABLE IF NOT EXISTS `OGP_DB_PREFIXban_list` ( + `client_ip` varchar(255) NOT NULL, + `logging_attempts` int(11) NOT NULL DEFAULT '0', + `banned_until` varchar(16) NOT NULL DEFAULT '0', + PRIMARY KEY (`client_ip`) + ) ENGINE=MyISAM DEFAULT CHARSET=latin1;"); + } + + $banlist_info = $db->resultQuery("SELECT logging_attempts, banned_until FROM `OGP_DB_PREFIXban_list` WHERE client_ip='".$client_ip."';"); + $login_attempts = !$banlist_info ? 0 : $banlist_info['0']['logging_attempts']; + + if( $banlist_info AND $banlist_info['0']['banned_until'] > 0 AND $banlist_info['0']['banned_until'] <= time() ) + { + $db->query("DELETE FROM `OGP_DB_PREFIXban_list` WHERE client_ip='$client_ip';"); + $login_attempts = 0; + } + + if( $login_attempts == $settings["login_attempts_before_banned"] ) + { + print_failure("Banned until " . date("r",$banlist_info['0']['banned_until'])); + echo "%botbody% + %bottom%"; + return; + } + + $userInfo = $db->getUser($_POST['ulogin']); + + // If result matched $myusername and $mypassword, table row must be 1 row + if( isset($userInfo['users_passwd']) && md5($_POST['upassword']) == $userInfo['users_passwd']) + { + // Handle recaptcha if enabled + // But admins don't have to do this :) + if($settings['recaptcha_use_login'] == "1" && !empty($settings['recaptcha_site_key']) && !empty($settings['recaptcha_secret_key']) && $userInfo['users_role'] != "admin"){ + $gRecaptchaResponse = sanitizeInputStr($_REQUEST['g-recaptcha-response']); + + $sitekey = $settings['recaptcha_site_key']; + $secretkey = $settings['recaptcha_secret_key']; + + require_once('includes/classes/recaptcha/autoload.php'); + $recaptcha = new \ReCaptcha\ReCaptcha($secretkey); + $resp = $recaptcha->verify($gRecaptchaResponse, $client_ip); + + if (empty($gRecaptchaResponse) || !$resp->isSuccess()){ + print_failure("Recaptcha failed. Try again!"); + $view->refresh("index.php",5); + return; + } + } + + $_SESSION['user_id'] = $userInfo['user_id']; + $_SESSION['users_login'] = $userInfo['users_login']; + $_SESSION['users_passwd'] = $userInfo['users_passwd']; + $_SESSION['users_group'] = $userInfo['users_role']; + $_SESSION['users_lang'] = isset( $_GET['lang'] ) ? $_GET['lang'] : $userInfo['users_lang']; + $_SESSION['users_theme'] = $userInfo['users_theme']; + $_SESSION['users_api_key'] = $db->getApiToken($userInfo['user_id']); + print_success( get_lang("logging_in") ."..."); + $db->logger( get_lang("logging_in") ."..."); + $db->query("DELETE FROM `OGP_DB_PREFIXban_list` WHERE client_ip='$client_ip';"); + $view->refresh("home.php?$default_page",2); + } + else + { + print_failure( get_lang("bad_login") ); + $login_attempts++; + if( $login_attempts == $settings["login_attempts_before_banned"] ) + { + $banned_until = time() + (array_key_exists("login_ban_time" , $settings) && !empty($settings["login_ban_time"]) && is_numeric($settings["login_ban_time"]) ? $settings["login_ban_time"] : 300); // Five minutes or user defined setting. + + if( !$banlist_info ) + $db->query("INSERT INTO `OGP_DB_PREFIXban_list` (`client_ip`) VALUES('$client_ip');"); + + $db->logger( get_lang("bad_login") . " ( Banned until " . date("r", $banned_until) . " ) [ " . get_lang("login") . ": " . sanitizeInputStr($_POST["ulogin"]) . ", " . get_lang("password") . ": ******** ]" ); + $db->query("UPDATE `OGP_DB_PREFIXban_list` SET logging_attempts='$login_attempts', banned_until='$banned_until' WHERE client_ip='$client_ip';"); + print_failure("Banned until " . date("r",$banned_until)); + } + else + { + if( !$banlist_info ) + $db->query("INSERT INTO `OGP_DB_PREFIXban_list` (`client_ip`) VALUES('$client_ip');"); + + $db->logger( get_lang("bad_login") . " ( $login_attempts ) [ " . get_lang("login") . ": " . sanitizeInputStr($_POST["ulogin"]) . ", " . get_lang("password") . ": ******** ]" ); + $db->query("UPDATE `OGP_DB_PREFIXban_list` SET logging_attempts='$login_attempts' WHERE client_ip='$client_ip';"); + $view->refresh("index.php",2); + } + } + echo "%botbody% + %bottom%"; + return; + } + ?> + + + + + + +
+
+

+
+
" name="login_form" method="post"> + + + + + + + + + + + + + + + + + + + + + + + +
:
:
:
: + +
+
+
+ +
+
+
+ +
+ %botbody% + %bottom% + diff --git a/index.php b/index.php index cf3835b6..6a119121 100644 --- a/index.php +++ b/index.php @@ -144,13 +144,11 @@ function ogpHome() $lang_sel .= "\n"; $lang_switch = ( isset( $_GET['lang'] ) AND $_GET['lang'] != "-" ) ? "&lang=" . $_GET['lang'] : ""; ?> -
- %top%