Guest User

kova-playve

a guest
Apr 7th, 2017
228
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 105.19 KB | None | 0 0
  1. #!/usr/bin/perl
  2. #
  3. # OGP - Open Game Panel
  4. # Copyright (C) 2008 - 2014 The OGP Development Team
  5. #
  6. # http://www.opengamepanel.org/
  7. #
  8. # This program is free software; you can redistribute it and/or
  9. # modify it under the terms of the GNU General Public License
  10. # as published by the Free Software Foundation; either version 2
  11. # of the License, or any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program; if not, write to the Free Software
  20. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21. #
  22.  
  23. use warnings;
  24. use strict;
  25.  
  26. use Cwd;             # Fast way to get the current directory
  27. use lib getcwd();
  28. use Frontier::Daemon::Forking;  # Forking XML-RPC server
  29. use File::Copy;                # Simple file copy functions
  30. use File::Copy::Recursive
  31.   qw(fcopy rcopy dircopy fmove rmove dirmove pathempty pathrmdir)
  32.   ;                            # Used to copy whole directories
  33. use File::Basename; # Used to get the file name or the directory name from a given path
  34. use Crypt::XXTEA;   # Encryption between webpages and agent.
  35. use Cfg::Config;     # Config file
  36. use Cfg::Preferences;   # Preferences file
  37. use Fcntl ':flock';  # Import LOCK_* constants for file locking
  38. use LWP::UserAgent; # Used for fetching URLs
  39. use MIME::Base64;   # Used to ensure data travelling right through the network.
  40. use Getopt::Long;   # Used for command line params.
  41. use Path::Class::File;  # Used to handle files and directories.
  42. use File::Path qw(mkpath);
  43. use Archive::Extract;    # Used to handle archived files.
  44. use File::Find;
  45. use Schedule::Cron; # Used for scheduling tasks
  46.  
  47. # Compression tools
  48. use IO::Compress::Bzip2 qw(bzip2 $Bzip2Error); # Used to compress files to bz2.
  49. use Compress::Zlib; # Used to compress file download buffers to zlib.
  50. use Archive::Tar; # Used to create tar, tgz or tbz archives.
  51. use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); # Used to create zip archives.
  52.  
  53. # Current location of the agent.
  54. use constant AGENT_RUN_DIR => getcwd();
  55.  
  56. # Load our config file values
  57. use constant AGENT_KEY    => $Cfg::Config{key};
  58. use constant AGENT_IP      => $Cfg::Config{listen_ip};
  59. use constant AGENT_LOG_FILE => $Cfg::Config{logfile};
  60. use constant AGENT_PORT  => $Cfg::Config{listen_port};
  61. use constant AGENT_VERSION  => $Cfg::Config{version};
  62. use constant SCREEN_LOG_LOCAL  => $Cfg::Preferences{screen_log_local};
  63. use constant DELETE_LOGS_AFTER  => $Cfg::Preferences{delete_logs_after};
  64. use constant AGENT_PID_FILE =>
  65.   Path::Class::File->new(AGENT_RUN_DIR, 'ogp_agent.pid');
  66. use constant STEAM_LICENSE_OK => "Accept";
  67. use constant STEAM_LICENSE  => $Cfg::Config{steam_license};
  68. use constant MANUAL_TMP_DIR   => Path::Class::Dir->new(AGENT_RUN_DIR, 'tmp');
  69. use constant STEAMCMD_CLIENT_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'steamcmd');
  70. use constant STEAMCMD_CLIENT_BIN =>
  71.   Path::Class::File->new(STEAMCMD_CLIENT_DIR, 'steamcmd.sh');
  72. use constant SCREEN_LOGS_DIR =>
  73.   Path::Class::Dir->new(AGENT_RUN_DIR, 'screenlogs');
  74. use constant GAME_STARTUP_DIR =>
  75.   Path::Class::Dir->new(AGENT_RUN_DIR, 'startups');
  76. use constant SCREENRC_FILE =>
  77.   Path::Class::File->new(AGENT_RUN_DIR, 'ogp_screenrc');
  78. use constant SCREENRC_TMP_FILE =>
  79.   Path::Class::File->new(AGENT_RUN_DIR, 'ogp_screenrc.tmp');
  80. use constant SCREEN_TYPE_HOME   => "HOME";
  81. use constant SCREEN_TYPE_UPDATE => "UPDATE";
  82. use constant FD_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'FastDownload');
  83. use constant FD_ALIASES_DIR => Path::Class::Dir->new(FD_DIR, 'aliases');
  84. use constant FD_PID_FILE => Path::Class::File->new(FD_DIR, 'fd.pid');
  85. use constant SCHED_PID => Path::Class::File->new(AGENT_RUN_DIR, 'scheduler.pid');
  86. use constant SCHED_TASKS => Path::Class::File->new(AGENT_RUN_DIR, 'scheduler.tasks');
  87. use constant SCHED_LOG_FILE => Path::Class::File->new(AGENT_RUN_DIR, 'scheduler.log');
  88.  
  89. $Cfg::Config{sudo_password} =~ s/('+)/'\"$1\"'/g;
  90. our $SUDOPASSWD = $Cfg::Config{sudo_password};
  91. my $no_startups = 0;
  92. my $clear_startups = 0;
  93. our $log_std_out = 0;
  94.  
  95. GetOptions(
  96.            'no-startups'    => \$no_startups,
  97.            'clear-startups' => \$clear_startups,
  98.            'log-stdout'  => \$log_std_out
  99.           );
  100.  
  101. # Starting the agent as root user is not supported anymore.
  102. if ($< == 0)
  103. {
  104.     print "ERROR: You are trying to start the agent as root user.";
  105.     print "This is not currently supported. If you wish to start the";
  106.     print "you need to create a normal user account for it.";
  107.     exit 1;
  108. }
  109.  
  110. ### Logger function.
  111. ### @param line the line that is put to the log file.
  112. sub logger
  113. {
  114.     my $logcmd   = $_[0];
  115.     my $also_print = 0;
  116.  
  117.     if (@_ == 2)
  118.     {
  119.         ($also_print) = $_[1];
  120.     }
  121.  
  122.     $logcmd = localtime() . " $logcmd\n";
  123.  
  124.     if ($log_std_out == 1)
  125.     {
  126.         print "$logcmd";
  127.         return;
  128.     }
  129.     if ($also_print == 1)
  130.     {
  131.         print "$logcmd";
  132.     }
  133.  
  134.     open(LOGFILE, '>>', AGENT_LOG_FILE)
  135.       or die("Can't open " . AGENT_LOG_FILE . " - $!");
  136.     flock(LOGFILE, LOCK_EX) or die("Failed to lock log file.");
  137.     seek(LOGFILE, 0, 2) or die("Failed to seek to end of file.");
  138.     print LOGFILE "$logcmd" or die("Failed to write to log file.");
  139.     flock(LOGFILE, LOCK_UN) or die("Failed to unlock log file.");
  140.     close(LOGFILE) or die("Failed to close log file.");
  141. }
  142.  
  143. # Rotate the log file
  144. if (-e AGENT_LOG_FILE)
  145. {
  146.     if (-e AGENT_LOG_FILE . ".bak")
  147.     {
  148.         unlink(AGENT_LOG_FILE . ".bak");
  149.     }
  150.     logger "Rotating log file";
  151.     move(AGENT_LOG_FILE, AGENT_LOG_FILE . ".bak");
  152.     logger "New log file created";
  153. }
  154.  
  155. open INPUTFILE, "<", SCREENRC_FILE or die $!;
  156. open OUTPUTFILE, ">", SCREENRC_TMP_FILE or die $!;
  157. my $dest = SCREEN_LOGS_DIR . "/screenlog.%t";
  158. while (<INPUTFILE>)
  159. {
  160.     $_ =~ s/logfile.*/logfile $dest/g;
  161.     print OUTPUTFILE $_;
  162. }
  163. close INPUTFILE;
  164. close OUTPUTFILE;
  165. unlink SCREENRC_FILE;
  166. move(SCREENRC_TMP_FILE,SCREENRC_FILE);
  167.  
  168. # Check the screen logs folder
  169. if (!-d SCREEN_LOGS_DIR && !mkdir SCREEN_LOGS_DIR)
  170. {
  171.     logger "Could not create " . SCREEN_LOGS_DIR . " directory $!.", 1;
  172.     exit -1;
  173. }
  174.  
  175. if (check_steam_cmd_client() == -1)
  176. {
  177.     print "ERROR: You must download and uncompress the new steamcmd package.";
  178.     print "BE SURE TO INSTALL IT IN " . AGENT_RUN_DIR . "/steamcmd directory,";
  179.     print "so it can be managed by the agent to install servers.";
  180.     exit 1;
  181. }
  182.  
  183. # create the directory for startup flags
  184. if (!-e GAME_STARTUP_DIR)
  185. {
  186.     logger "Creating the startups directory " . GAME_STARTUP_DIR . "";
  187.     if (!mkdir GAME_STARTUP_DIR)
  188.     {
  189.         my $message =
  190.             "Failed to create the "
  191.           . GAME_STARTUP_DIR
  192.           . " directory - check permissions. Errno: $!";
  193.         logger $message, 1;
  194.         exit 1;
  195.     }
  196. }
  197. elsif ($clear_startups)
  198. {
  199.     opendir(STARTUPDIR, GAME_STARTUP_DIR);
  200.     while (my $startup_file = readdir(STARTUPDIR))
  201.     {
  202.  
  203.         # Skip . and ..
  204.         next if $startup_file =~ /^\./;
  205.         $startup_file = Path::Class::File->new(GAME_STARTUP_DIR, $startup_file);
  206.         logger "Removing " . $startup_file . ".";
  207.         unlink($startup_file);
  208.     }
  209.     closedir(STARTUPDIR);
  210. }
  211. # If the directory already existed check if we need to start some games.
  212. elsif ($no_startups != 1)
  213. {
  214.  
  215.     # Loop through all the startup flags, and call universal startup
  216.     opendir(STARTUPDIR, GAME_STARTUP_DIR);
  217.     logger "Reading startup flags from " . GAME_STARTUP_DIR . "";
  218.     while (my $dirlist = readdir(STARTUPDIR))
  219.     {
  220.  
  221.         # Skip . and ..
  222.         next if $dirlist =~ /^\./;
  223.         logger "Found $dirlist";
  224.         open(STARTFILE, '<', Path::Class::Dir->new(GAME_STARTUP_DIR, $dirlist))
  225.           || logger "Error opening start flag $!";
  226.         while (<STARTFILE>)
  227.         {
  228.             my (
  229.                 $home_id,   $home_path,   $server_exe,
  230.                 $run_dir,   $startup_cmd, $server_port,
  231.                 $server_ip, $cpu, $nice, $preStart, $envVars
  232.                ) = split(',', $_);
  233.  
  234.             if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) ==
  235.                 1)
  236.             {
  237.                 logger
  238.                   "This server ($server_exe on $server_ip : $server_port) is already running (ID: $home_id).";
  239.                 next;
  240.             }
  241.  
  242.             logger "Starting server_exe $server_exe from home $home_path.";
  243.             universal_start_without_decrypt(
  244.                                          $home_id,   $home_path,   $server_exe,
  245.                                          $run_dir,   $startup_cmd, $server_port,
  246.                                          $server_ip, $cpu,  $nice, $preStart, $envVars
  247.                                            );
  248.         }
  249.         close(STARTFILE);
  250.     }
  251.     closedir(STARTUPDIR);
  252. }
  253.  
  254. # Create the pid file
  255. open(PID, '>', AGENT_PID_FILE)
  256.   or die("Can't write to pid file - " . AGENT_PID_FILE . "\n");
  257. print PID "$$\n";
  258. close(PID);
  259.  
  260. logger "Open Game Panel - Agent started - "
  261.   . AGENT_VERSION
  262.   . " - port "
  263.   . AGENT_PORT
  264.   . " - PID $$", 1;
  265.  
  266. # Stop previous scheduler process if exists
  267. scheduler_stop();  
  268. # Create new object with default dispatcher for scheduled tasks
  269. my $cron = new Schedule::Cron( \&scheduler_dispatcher, {
  270.                                         nofork => 1,
  271.                                         loglevel => 0,
  272.                                         log => sub { print $_[1], "\n"; }
  273.                                        } );
  274.  
  275. $cron->add_entry( "* * * * * *", \&scheduler_read_tasks );
  276. # Run scheduler
  277. $cron->run( {detach=>1, pid_file=>SCHED_PID} );
  278.  
  279. if(-e Path::Class::File->new(FD_DIR, 'Settings.pm'))
  280. {
  281.     require "FastDownload/Settings.pm"; # Settings for Fast Download Daemon.
  282.     if(defined($FastDownload::Settings{autostart_on_agent_startup}) && $FastDownload::Settings{autostart_on_agent_startup} eq "1")
  283.     {
  284.         start_fastdl();
  285.     }
  286. }
  287.  
  288. my $d = Frontier::Daemon::Forking->new(
  289.              methods => {
  290.                  is_screen_running              => \&is_screen_running,
  291.                  universal_start                => \&universal_start,
  292.                  renice_process                 => \&renice_process,
  293.                  cpu_count                      => \&cpu_count,
  294.                  rfile_exists                   => \&rfile_exists,
  295.                  quick_chk                      => \&quick_chk,
  296.                  steam_cmd                      => \&steam_cmd,
  297.                  fetch_steam_version            => \&fetch_steam_version,
  298.                  installed_steam_version        => \&installed_steam_version,
  299.                  automatic_steam_update         => \&automatic_steam_update,
  300.                  get_log                        => \&get_log,
  301.                  stop_server                    => \&stop_server,
  302.                  send_rcon_command              => \&send_rcon_command,
  303.                  dirlist                        => \&dirlist,
  304.                  dirlistfm                      => \&dirlistfm,
  305.                  readfile                       => \&readfile,
  306.                  writefile                      => \&writefile,
  307.                  rebootnow                      => \&rebootnow,
  308.                  what_os                        => \&what_os,
  309.                  start_file_download            => \&start_file_download,
  310.                  lock_additional_files          => \&lock_additional_files,
  311.                  is_file_download_in_progress   => \&is_file_download_in_progress,
  312.                  uncompress_file                => \&uncompress_file,
  313.                  discover_ips                   => \&discover_ips,
  314.                  mon_stats                      => \&mon_stats,
  315.                  exec                           => \&exec,
  316.                  clone_home                     => \&clone_home,
  317.                  remove_home                    => \&remove_home,
  318.                  start_rsync_install            => \&start_rsync_install,
  319.                  rsync_progress                 => \&rsync_progress,
  320.                  restart_server                 => \&restart_server,
  321.                  sudo_exec                      => \&sudo_exec,
  322.                  master_server_update           => \&master_server_update,
  323.                  secure_path                    => \&secure_path,
  324.                  get_chattr                     => \&get_chattr,
  325.                  ftp_mgr                        => \&ftp_mgr,
  326.                  compress_files                 => \&compress_files,
  327.                  stop_fastdl                    => \&stop_fastdl,
  328.                  restart_fastdl                 => \&restart_fastdl,
  329.                  fastdl_status                  => \&fastdl_status,
  330.                  fastdl_get_aliases             => \&fastdl_get_aliases,
  331.                  fastdl_add_alias               => \&fastdl_add_alias,
  332.                  fastdl_del_alias               => \&fastdl_del_alias,
  333.                  fastdl_get_info                => \&fastdl_get_info,
  334.                  fastdl_create_config           => \&fastdl_create_config,
  335.                  agent_restart                  => \&agent_restart,
  336.                  scheduler_add_task             => \&scheduler_add_task,
  337.                  scheduler_del_task             => \&scheduler_del_task,
  338.                  scheduler_list_tasks           => \&scheduler_list_tasks,
  339.                  scheduler_edit_task            => \&scheduler_edit_task,
  340.                  get_file_part                  => \&get_file_part,
  341.                  stop_update                    => \&stop_update,
  342.                  shell_action                   => \&shell_action,
  343.                  remote_query                   => \&remote_query
  344.              },
  345.              debug   => 4,
  346.              LocalPort => AGENT_PORT,
  347.              LocalAddr => AGENT_IP,
  348.              ReuseAddr => '1'
  349. ) or die "Couldn't start OGP Agent: $!";
  350.  
  351. sub backup_home_log
  352. {
  353.     my ($home_id, $log_file) = @_;
  354.    
  355.     my $home_backup_dir = SCREEN_LOGS_DIR . "/home_id_" . $home_id;
  356.        
  357.     if( ! -e $home_backup_dir )
  358.     {
  359.         if( ! mkdir $home_backup_dir )
  360.         {
  361.             logger "Can not create a backup directory at $home_backup_dir.";
  362.             return 1;
  363.         }
  364.     }
  365.    
  366.     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  367.    
  368.     my $backup_file_name =  $mday . $mon . $year . '_' . $hour . 'h' . $min . 'm' . $sec . "s.log";
  369.    
  370.     my $output_path = $home_backup_dir . "/" . $backup_file_name;
  371.    
  372.     # Used for deleting log files older than DELETE_LOGS_AFTER
  373.     my @file_list;
  374.     my @find_dirs; # directories to search
  375.     my $now = time(); # get current time
  376.     my $days;
  377.     if((DELETE_LOGS_AFTER =~ /^[+-]?\d+$/) && (DELETE_LOGS_AFTER > 0)){
  378.         $days = DELETE_LOGS_AFTER; # how many days old
  379.     }else{
  380.         $days = 30; # how many days old
  381.     }
  382.     my $seconds_per_day = 60*60*24; # seconds in a day
  383.     my $AGE = $days*$seconds_per_day; # age in seconds
  384.     push (@find_dirs, $home_backup_dir);
  385.    
  386.     # Create local copy of log file backup in the log_backups folder and current user home directory if SCREEN_LOG_LOCAL = 1
  387.     if(SCREEN_LOG_LOCAL == 1)
  388.     {
  389.         # Create local backups folder
  390.         my $local_log_folder = Path::Class::Dir->new("logs_backup");
  391.        
  392.         if(!-e $local_log_folder){
  393.             mkdir($local_log_folder);
  394.         }
  395.        
  396.         # Add full path to @find_dirs so that log files older than DELETE_LOGS_AFTER are deleted
  397.         my $fullpath_to_local_logs = Path::Class::Dir->new(getcwd(), "logs_backup");
  398.         push (@find_dirs, $fullpath_to_local_logs);
  399.        
  400.         my $log_local = $local_log_folder . "/" . $backup_file_name;
  401.        
  402.         # Delete the local log file if it already exists
  403.         if(-e $log_local){
  404.             unlink $log_local;
  405.         }
  406.        
  407.         # If the log file contains UPDATE in the filename, do not allow users to see it since it will contain steam credentials
  408.         # Will return -1 for not existing
  409.         my $isUpdate = index($log_file,SCREEN_TYPE_UPDATE);
  410.        
  411.         if($isUpdate == -1){
  412.             copy($log_file,$log_local);
  413.         }
  414.     }
  415.    
  416.     # Delete all files in @find_dirs older than DELETE_LOGS_AFTER days
  417.     find ( sub {
  418.         my $file = $File::Find::name;
  419.         if ( -f $file ) {
  420.             push (@file_list, $file);
  421.         }
  422.     }, @find_dirs);
  423.  
  424.     for my $file (@file_list) {
  425.         my @stats = stat($file);
  426.         if ($now-$stats[9] > $AGE) {
  427.             unlink $file;
  428.         }
  429.     }
  430.    
  431.     move($log_file,$output_path);
  432.    
  433.     return 0;
  434. }
  435.  
  436. sub get_home_pids
  437. {
  438.     my ($home_id) = @_;
  439.     my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id);
  440.     my ($pid, @pids);
  441.     ($pid) = split(/\./, `screen -ls | grep -E -o "[0-9]+\.$screen_id"`, 2);
  442.     chomp($pid);
  443.     while ($pid =~ /^[0-9]+$/)
  444.     {
  445.         push(@pids,$pid);
  446.         $pid = `pgrep -P $pid`;
  447.         chomp($pid);
  448.     }
  449.     return @pids;
  450. }
  451.  
  452. sub create_screen_id
  453. {
  454.     my ($screen_type, $home_id) = @_;
  455.     return sprintf("OGP_%s_%09d", $screen_type, $home_id);
  456. }
  457.  
  458. sub create_screen_cmd
  459. {
  460.     my ($screen_id, $exec_cmd) = @_;
  461.     $exec_cmd = replace_OGP_Vars($screen_id, $exec_cmd);
  462.     return
  463.       sprintf('export WINEDEBUG="fixme-all" && export DISPLAY=:1 && screen -d -m -t "%1$s" -c ' . SCREENRC_FILE . ' -S %1$s %2$s',
  464.               $screen_id, $exec_cmd);
  465.  
  466. }
  467.  
  468. sub create_screen_cmd_loop
  469. {
  470.     my ($screen_id, $exec_cmd, $envVars) = @_;
  471.     my $server_start_bashfile = $screen_id . "_startup_scr.sh";
  472.     chmod 0770, $server_start_bashfile;
  473.     #chown -R jesus, $home_path;
  474.     $exec_cmd = replace_OGP_Vars($screen_id, $exec_cmd);
  475.    
  476.     # Allow file to be overwritten
  477.     if(-e $server_start_bashfile){
  478.         secure_path_without_decrypt('chattr-i', $server_start_bashfile);
  479.     }
  480.    
  481.     # Create bash file that screen will run which spawns the server
  482.     # If it crashes without user intervention, it will restart
  483.     open (SERV_START_SCRIPT, '>', $server_start_bashfile);
  484.    
  485.     my $respawn_server_command = "#!/bin/bash" . "\n"
  486.     . "function startServer(){" . "\n" ;
  487.    
  488.     if(defined $envVars && $envVars ne ""){
  489.         $respawn_server_command .= $envVars;
  490.     }
  491.    
  492.     $respawn_server_command .= "NUMSECONDS=`expr \$(date +%s)`" . "\n"
  493.     . "until " . $exec_cmd . "; do" . "\n"
  494.     . "let DIFF=(`date +%s` - \"\$NUMSECONDS\")" . "\n"
  495.     . "if [ \"\$DIFF\" -gt 15 ]; then" . "\n"
  496.     . "NUMSECONDS=`expr \$(date +%s)`" . "\n"
  497.     . "echo \"Server '" . $exec_cmd . "' crashed with exit code \$?.  Respawning...\" >&2 " . "\n"
  498.     . "fi" . "\n"
  499.     . "sleep 3" . "\n"
  500.     . "done" . "\n"
  501.     . "let DIFF=(`date +%s` - \"\$NUMSECONDS\")" . "\n"
  502.    
  503.     . "if [ ! -e \"SERVER_STOPPED\" ] && [ \"\$DIFF\" -gt 15 ]; then" . "\n"
  504.     . "startServer" . "\n"
  505.     . "fi" . "\n"
  506.     . "}" . "\n"
  507.     . "startServer" . "\n";
  508.    
  509.     print SERV_START_SCRIPT $respawn_server_command;
  510.     close (SERV_START_SCRIPT);
  511.    
  512.     # Secure file
  513.     secure_path_without_decrypt('chattr-i', $server_start_bashfile);
  514.    
  515.     my $screen_exec_script = "bash " . $server_start_bashfile;
  516.    
  517.     return
  518.       sprintf('export WINEDEBUG="fixme-all" && export DISPLAY=:1 && screen -d -m -t "%1$s" -c ' . SCREENRC_FILE . ' -S %1$s %2$s',
  519.               $screen_id, $screen_exec_script);
  520.  
  521. }
  522.  
  523. sub replace_OGP_Vars{
  524.     # This function replaces constants from game server XML Configs with OGP paths for Steam Auto Updates for example
  525.     my ($screen_id, $exec_cmd) = @_;
  526.     my $screen_id_for_txt_update = substr ($screen_id, rindex($screen_id, '_') + 1);
  527.     my $steamInsFile = $screen_id_for_txt_update . "_install.txt";
  528.     my $steamCMDPath = STEAMCMD_CLIENT_DIR;
  529.     my $fullPath = Path::Class::File->new($steamCMDPath, $steamInsFile);
  530.    
  531.     # If the install file exists, the game can be auto updated, else it will be ignored by the game for improper syntax
  532.     # To generate the install file, the "Install/Update via Steam" button must be clicked on at least once!
  533.     if(-e $fullPath){
  534.         $exec_cmd =~ s/{OGP_STEAM_CMD_DIR}/$steamCMDPath/g;
  535.         $exec_cmd =~ s/{STEAMCMD_INSTALL_FILE}/$steamInsFile/g;
  536.     }
  537.    
  538.     return $exec_cmd;
  539. }
  540.  
  541. sub replace_OGP_Env_Vars{
  542.     # This function replaces constants from environment variables set in the XML
  543.     my ($homeid, $homepath, $strToReplace) = @_;
  544.  
  545.     $strToReplace =~ s/{OGP_HOME_DIR}/$homepath/g;
  546.    
  547.     return $strToReplace;
  548. }
  549.  
  550. sub encode_list
  551. {
  552.     my $encoded_content = '';
  553.     if(@_)
  554.     {
  555.         foreach my $line (@_)
  556.         {
  557.             $encoded_content .= encode_base64($line, "") . '\n';
  558.         }
  559.     }
  560.     return $encoded_content;
  561. }
  562.  
  563. sub decrypt_param
  564. {
  565.     my ($param) = @_;
  566.     $param = decode_base64($param);
  567.     $param = Crypt::XXTEA::decrypt($param, AGENT_KEY);
  568.     $param = decode_base64($param);
  569.     return $param;
  570. }
  571.  
  572. sub decrypt_params
  573. {
  574.     my @params;
  575.     foreach my $param (@_)
  576.     {
  577.         $param = &decrypt_param($param);
  578.         push(@params, $param);
  579.     }
  580.     return @params;
  581. }
  582.  
  583. sub check_steam_cmd_client
  584. {
  585.     if (STEAM_LICENSE ne STEAM_LICENSE_OK)
  586.     {
  587.         logger "Steam license not accepted, stopping Steam client check.";
  588.         return 0;
  589.     }
  590.     if (!-d STEAMCMD_CLIENT_DIR && !mkdir STEAMCMD_CLIENT_DIR)
  591.     {
  592.         logger "Could not create " . STEAMCMD_CLIENT_DIR . " directory $!.", 1;
  593.         exit -1;
  594.     }
  595.     if (!-w STEAMCMD_CLIENT_DIR)
  596.     {
  597.         logger "Steam client dir '"
  598.           . STEAMCMD_CLIENT_DIR
  599.           . "' not writable. Unable to get Steam client.";
  600.         return -1;
  601.     }
  602.     if (!-f STEAMCMD_CLIENT_BIN)
  603.     {
  604.         logger "The Steam client, steamcmd, does not exist yet, installing...";
  605.         my $steam_client_file = 'steamcmd_linux.tar.gz';
  606.         my $steam_client_path = Path::Class::File->new(STEAMCMD_CLIENT_DIR, $steam_client_file);
  607.         my $steam_client_url =
  608.           "http://media.steampowered.com/client/" . $steam_client_file;
  609.         logger "Downloading the Steam client from $steam_client_url to '"
  610.           . $steam_client_path . "'.";
  611.        
  612.         my $ua = LWP::UserAgent->new;
  613.         $ua->agent('Mozilla/5.0');
  614.         my $response = $ua->get($steam_client_url, ':content_file' => "$steam_client_path");
  615.        
  616.         unless ($response->is_success)
  617.         {
  618.             logger "Failed to download steam installer from "
  619.               . $steam_client_url
  620.               . ".", 1;
  621.             return -1;
  622.         }
  623.         if (-f $steam_client_path)
  624.         {
  625.             logger "Uncompressing $steam_client_path";
  626.             if ( uncompress_file_without_decrypt($steam_client_path, STEAMCMD_CLIENT_DIR) != 1 )
  627.             {
  628.                 unlink($steam_client_path);
  629.                 logger "Unable to uncompress $steam_client_path, the file has been removed.";
  630.                 return -1;
  631.             }
  632.             unlink($steam_client_path);
  633.         }
  634.     }
  635.     if (!-x STEAMCMD_CLIENT_BIN)
  636.     {
  637.         if ( ! chmod 0755, STEAMCMD_CLIENT_BIN )
  638.         {
  639.             logger "Unable to apply execution permission to ".STEAMCMD_CLIENT_BIN.".";
  640.         }
  641.     }
  642.     return 1;
  643. }
  644.  
  645. sub is_screen_running
  646. {
  647.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  648.     my ($screen_type, $home_id) = decrypt_params(@_);
  649.     return is_screen_running_without_decrypt($screen_type, $home_id);
  650. }
  651.  
  652. sub is_screen_running_without_decrypt
  653. {
  654.     my ($screen_type, $home_id) = @_;
  655.  
  656.     my $screen_id = create_screen_id($screen_type, $home_id);
  657.  
  658.     my $is_running = `screen -list | grep $screen_id`;
  659.  
  660.     if ($is_running =~ /^\s*$/)
  661.     {
  662.         return 0;
  663.     }
  664.     else
  665.     {
  666.         return 1;
  667.     }
  668. }
  669.  
  670. # Delete Server Stopped Status File:
  671. sub deleteStoppedStatFile
  672. {
  673.     my ($home_path) = @_;
  674.     my $server_stop_status_file = Path::Class::File->new($home_path, "SERVER_STOPPED");
  675.     if(-e $server_stop_status_file)
  676.     {
  677.         unlink $server_stop_status_file;
  678.     }
  679. }
  680.  
  681. # Universal startup function
  682. sub universal_start
  683. {
  684.     chomp(@_);
  685.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  686.     return universal_start_without_decrypt(decrypt_params(@_));
  687. }
  688.  
  689. # Split to two parts because of internal calls.
  690. sub universal_start_without_decrypt
  691. {
  692.     my (
  693.         $home_id, $home_path, $server_exe, $run_dir,
  694.         $startup_cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars
  695.        ) = @_;
  696.        
  697.     # Replace any {OGP_HOME_DIR} in the $start_cmd with the server's home directory path
  698.     $startup_cmd = replace_OGP_Env_Vars($home_id, $home_path, $startup_cmd);
  699.        
  700.     if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1)
  701.     {
  702.         logger "This server is already running (ID: $home_id).";
  703.         return -14;
  704.     }
  705.    
  706.     if (!-e $home_path)
  707.     {
  708.         logger "Can't find server's install path [ $home_path ].";
  709.         return -10;
  710.     }
  711.    
  712.     my $uid = `id -u`;
  713.     chomp $uid;
  714.     my $gid = `id -g`;
  715.     chomp $gid;
  716.     my $path = $home_path;
  717.     $path =~ s/('+)/'\"$1\"'/g;
  718.     sudo_exec_without_decrypt('chown -Rf jesus:'.$gid.' \''.$path.'\'');
  719.    
  720.     # Some game require that we are in the directory where the binary is.
  721.     my $game_binary_dir = Path::Class::Dir->new($home_path, $run_dir);
  722.     if ( -e $game_binary_dir && !chdir $game_binary_dir)
  723.     {
  724.         logger "Could not change to server binary directory $game_binary_dir.";
  725.         return -12;
  726.     }
  727.    
  728.     #secure_path_without_decrypt('chattr-i', $server_exe);
  729.    
  730.     if (!-x $server_exe)
  731.     {
  732.         if (!chmod 0755, $server_exe)
  733.         {
  734.             logger "The $server_exe file is not executable.";
  735.             return -13;
  736.         }
  737.     }
  738.    
  739.     if(defined $preStart && $preStart ne ""){
  740.         # Get it in the format that the startup file can use
  741.         $preStart = multiline_to_startup_comma_format($preStart);
  742.     }else{
  743.         $preStart = "";
  744.     }
  745.    
  746.     if(defined $envVars && $envVars ne ""){
  747.         # Replace variables in the envvars if they exist
  748.         my @prestartenvvars = split /[\r\n]+/, $envVars;
  749.         my $envVarStr = "";
  750.         foreach my $line (@prestartenvvars) {
  751.             $line = replace_OGP_Env_Vars($home_id, $home_path, $line);
  752.             if($line ne ""){
  753.                 logger "Configuring environment variable: $line";
  754.                 $envVarStr .= "$line\n";
  755.             }
  756.         }
  757.            
  758.         if(defined $envVarStr && $envVarStr ne ""){
  759.             $envVars = $envVarStr;
  760.         }  
  761.        
  762.         # Get it in the format that the startup file can use
  763.         $envVars = multiline_to_startup_comma_format($envVars);
  764.     }else{
  765.         $envVars = "";
  766.     }
  767.    
  768.     #secure_path_without_decrypt('chattr-i', $server_exe);
  769.    
  770.     # Create startup file for the server.
  771.     my $startup_file =
  772.       Path::Class::File->new(GAME_STARTUP_DIR, "$server_ip-$server_port");
  773.     if (open(STARTUP, '>', $startup_file))
  774.     {
  775.         print STARTUP
  776.           "$home_id,$home_path,$server_exe,$run_dir,$startup_cmd,$server_port,$server_ip,$cpu,$nice,$preStart,$envVars";
  777.         logger "Created startup flag for $server_ip-$server_port";
  778.         close(STARTUP);
  779.     }
  780.     else
  781.     {
  782.         logger "Cannot create file in " . $startup_file . " : $!";
  783.     }
  784.    
  785.     if(defined $preStart && $preStart ne ""){
  786.         # Get it in the format that the startup file can use
  787.         $preStart = startup_comma_format_to_multiline($preStart);
  788.     }else{
  789.         $preStart = "";
  790.     }
  791.    
  792.     if(defined $envVars && $envVars ne ""){
  793.         # Get it in the format that the startup file can use
  794.         $envVars = startup_comma_format_to_multiline($envVars);
  795.     }else{
  796.         $envVars = "";
  797.     }
  798.    
  799.     # Create the startup string.
  800.     my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id);
  801.     my $file_extension = substr $server_exe, -4;
  802.     my $cli_bin;
  803.     my $command;
  804.     my $run_before_start;
  805.    
  806.     if($file_extension eq ".exe" or $file_extension eq ".bat")
  807.     {
  808.         $command = "wine $server_exe $startup_cmd";
  809.        
  810.         if ($cpu ne 'NA')
  811.         {
  812.             $command = "taskset -c $cpu wine $server_exe $startup_cmd";
  813.         }
  814.        
  815.         if(defined($Cfg::Preferences{ogp_autorestart_server}) &&  $Cfg::Preferences{ogp_autorestart_server} eq "1"){
  816.             deleteStoppedStatFile($home_path);
  817.             $cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars);
  818.         }else{
  819.             $cli_bin = create_screen_cmd($screen_id, $command);
  820.         }
  821.     }
  822.     elsif($file_extension eq ".jar")
  823.     {
  824.         $command = "$startup_cmd";
  825.        
  826.         if ($cpu ne 'NA')
  827.         {
  828.             $command = "taskset -c $cpu $startup_cmd";
  829.         }
  830.        
  831.         if(defined($Cfg::Preferences{ogp_autorestart_server}) &&  $Cfg::Preferences{ogp_autorestart_server} eq "1"){
  832.             deleteStoppedStatFile($home_path);
  833.             $cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars);
  834.         }else{
  835.             $cli_bin = create_screen_cmd($screen_id, $command);
  836.         }
  837.     }
  838.     else
  839.     {
  840.         $command = "./$server_exe $startup_cmd";
  841.        
  842.         if ($cpu ne 'NA')
  843.         {
  844.             $command = "taskset -c $cpu ./$server_exe $startup_cmd";
  845.         }
  846.        
  847.         if(defined($Cfg::Preferences{ogp_autorestart_server}) &&  $Cfg::Preferences{ogp_autorestart_server} eq "1"){
  848.             deleteStoppedStatFile($home_path);
  849.             $cli_bin = create_screen_cmd_loop($screen_id, $command, $envVars);
  850.         }else{
  851.             $cli_bin = create_screen_cmd($screen_id, $command);
  852.         }
  853.     }
  854.        
  855.     my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id");
  856.     backup_home_log( $home_id, $log_file );
  857.    
  858.     logger
  859.       "Startup command [ $cli_bin ] will be executed in dir $game_binary_dir.";
  860.    
  861.     # Run before start script and set environment variables which will affect create_screen_cmd only... loop already has the envvars as well
  862.     $run_before_start = run_before_start_commands($home_id, $home_path, $preStart, $envVars);
  863.    
  864.     system($cli_bin);
  865.    
  866.     sleep(1);
  867.    
  868.     renice_process_without_decrypt($home_id, $nice);
  869.        
  870.     chdir AGENT_RUN_DIR;
  871.     return 1;
  872. }
  873.  
  874. # This is used to change the priority of process
  875. # @return 1 if successfully set prosess priority
  876. # @return -1 in case of an error.
  877. sub renice_process
  878. {
  879.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  880.     return renice_process_without_decrypt(decrypt_params(@_));
  881. }
  882.  
  883. sub renice_process_without_decrypt
  884. {
  885.     my ($home_id, $nice) = @_; 
  886.     if ($nice != 0)
  887.     {              
  888.         my @pids = get_home_pids($home_id);
  889.         logger
  890.           "Renicing pids [ @pids ] from home_id $home_id with nice value $nice.";
  891.         foreach my $pid (@pids)
  892.         {
  893.             my $rpid = kill 0, $pid;
  894.             if ($rpid == 1)
  895.             {
  896.                 my $ret = sudo_exec_without_decrypt('/usr/bin/renice '.$nice.' '.$pid);
  897.                 ($ret) = split(/;/, $ret, 2);
  898.                 if($ret != 1)
  899.                 {
  900.                     logger "Unable to renice process, probably bad sudo password or not in sudoers list.";
  901.                     return -1
  902.                 }
  903.             }
  904.         }
  905.     }
  906.     return 1;
  907. }
  908.  
  909. # This is used to force a process to run on a particular CPU
  910. sub force_cpu
  911. {
  912.     return force_cpu_without_decrypt(decrypt_params(@_));
  913. }
  914.  
  915. sub force_cpu_without_decrypt
  916. {
  917.     my ($home_id, $cpu) = @_;
  918.     if ($cpu ne 'NA')
  919.     {
  920.         my @pids = get_home_pids($home_id);
  921.         logger
  922.           "Setting server from home_id $home_id with pids @pids to run on CPU $cpu.";
  923.         foreach my $pid (@pids)
  924.         {
  925.             my $rpid = kill 0, $pid;
  926.             if ($rpid == 1)
  927.             {
  928.                 my $ret = sudo_exec_without_decrypt('/usr/bin/taskset -pc '.$cpu.' '.$pid);
  929.                 ($ret) = split(/;/, $ret, 2);
  930.                 if($ret != 1)
  931.                 {
  932.                     logger "Unable to set cpu, probably a bad sudo password or not in sudoers list.";
  933.                     return -1
  934.                 }
  935.             }
  936.         }
  937.     }
  938.     return 1;
  939. }
  940.  
  941. # Returns the number of CPUs available.
  942. sub cpu_count
  943. {
  944.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  945.     if (!-e "/proc/cpuinfo")
  946.     {
  947.         return "ERROR - Missing /proc/cpuinfo";
  948.     }
  949.  
  950.     open(CPUINFO, '<', "/proc/cpuinfo")
  951.       or return "ERROR - Cannot open /proc/cpuinfo";
  952.  
  953.     my $cpu_count = 0;
  954.  
  955.     while (<CPUINFO>)
  956.     {
  957.         chomp;
  958.         next if $_ !~ /^processor/;
  959.         $cpu_count++;
  960.     }
  961.     close(CPUINFO);
  962.     return "$cpu_count";
  963. }
  964.  
  965. ### File exists check ####
  966. # Simple a way to check if a file exists using the remote agent
  967. #
  968. # @return 0 when file exists.
  969. # @return 1 when file does not exist.
  970. sub rfile_exists
  971. {
  972.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  973.     chdir AGENT_RUN_DIR;
  974.     my $checkFile = decrypt_param(@_);
  975.  
  976.     if (-e $checkFile)
  977.     {
  978.         return 0;
  979.     }
  980.     else
  981.     {
  982.         return 1;
  983.     }
  984. }
  985.  
  986. #### Quick check to verify agent is up and running
  987. # Used to quickly see if the agent is online, and if the keys match.
  988. # The message that is sent to the agent must be hello, if not then
  989. # it is intrepret as encryption key missmatch.
  990. #
  991. # @return 1 when encrypted message is not 'hello'
  992. # @return 0 when check is ok.
  993. sub quick_chk
  994. {
  995.     my $dec_check = &decrypt_param(@_);
  996.     if ($dec_check ne 'hello')
  997.     {
  998.         logger "ERROR - Encryption key mismatch! Returning 1 to asker.";
  999.         return 1;
  1000.     }
  1001.     return 0;
  1002. }
  1003.  
  1004. ### Return -10 If home path is not found.
  1005. ### Return -9  If log type was invalid.
  1006. ### Return -8  If log file was not found.
  1007. ### 0 reserved for connection problems.
  1008. ### Return 1;content If log found and screen running.
  1009. ### Return 2;content If log found but screen is not running.
  1010. sub get_log
  1011. {
  1012.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1013.     my ($screen_type, $home_id, $home_path, $nb_of_lines, $log_file) = decrypt_params(@_);
  1014.  
  1015.     if (!chdir $home_path)
  1016.     {
  1017.         logger "Can't change to server's install path [ $home_path ].";
  1018.         return -10;
  1019.     }
  1020.  
  1021.     if (   ($screen_type eq SCREEN_TYPE_UPDATE)
  1022.         && ($screen_type eq SCREEN_TYPE_HOME))
  1023.     {
  1024.         logger "Invalid screen type '$screen_type'.";
  1025.         return -9;
  1026.     }
  1027.  
  1028.     if(!$log_file)
  1029.     {
  1030.         my $screen_id = create_screen_id($screen_type, $home_id);
  1031.         $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id");
  1032.     }
  1033.     else
  1034.     {
  1035.         $log_file = Path::Class::File->new($home_path, $log_file);
  1036.     }
  1037.    
  1038.    
  1039.     chmod 0644, $log_file;
  1040.    
  1041.     # Create local copy of current log file if SCREEN_LOG_LOCAL = 1
  1042.     if(SCREEN_LOG_LOCAL == 1)
  1043.     {
  1044.         my $log_local = Path::Class::File->new($home_path, "LOG_$screen_type.txt");
  1045.         if ( -e $log_local )
  1046.         {
  1047.             unlink $log_local;
  1048.         }
  1049.        
  1050.         # Copy log file only if it's not an UPDATE type as it may contain steam credentials
  1051.         if($screen_type eq SCREEN_TYPE_HOME){
  1052.             copy($log_file, $log_local);
  1053.         }
  1054.     }
  1055.    
  1056.     # Regenerate the log file if it doesn't exist
  1057.     unless ( -e $log_file )
  1058.     {
  1059.         if (open(NEWLOG, '>', $log_file))
  1060.         {
  1061.             logger "Log file missing, regenerating: " . $log_file;
  1062.             print NEWLOG "Log file missing, started new log\n";
  1063.             close(NEWLOG);
  1064.         }
  1065.         else
  1066.         {
  1067.             logger "Cannot regenerate log file in " . $log_file . " : $!";
  1068.             return -8;
  1069.         }
  1070.     }
  1071.    
  1072.     # Return a few lines of output to the web browser
  1073.     my(@modedlines) = `tail -n $nb_of_lines $log_file`;
  1074.    
  1075.     my $linecount = 0;
  1076.    
  1077.     foreach my $line (@modedlines) {
  1078.         #Text replacements to remove the Steam user login from steamcmd logs for security reasons.
  1079.         $line =~ s/login .*//g;
  1080.         $line =~ s/Logging .*//g;
  1081.         $line =~ s/set_steam_guard_code.*//g;
  1082.         $line =~ s/force_install_dir.*//g;
  1083.         #Text replacements to remove empty lines.
  1084.         $line =~ s/^ +//g;
  1085.         $line =~ s/^\t+//g;
  1086.         $line =~ s/^\e+//g;
  1087.         #Remove � from console output when master server update is running.
  1088.         $line =~ s/�//g;
  1089.         $modedlines[$linecount]=$line;
  1090.         $linecount++;
  1091.     }
  1092.    
  1093.     my $encoded_content = encode_list(@modedlines);
  1094.     chdir AGENT_RUN_DIR;
  1095.     if(is_screen_running_without_decrypt($screen_type, $home_id) == 1)
  1096.     {
  1097.         return "1;" . $encoded_content;
  1098.     }
  1099.     else
  1100.     {
  1101.         return "2;" . $encoded_content;
  1102.     }
  1103. }
  1104.  
  1105. # stop server function
  1106. sub stop_server
  1107. {
  1108.     chomp(@_);
  1109.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1110.     return stop_server_without_decrypt(decrypt_params(@_));
  1111. }
  1112.  
  1113. ##### Stop server without decrypt
  1114. ### Return 1 when error occurred on decryption.
  1115. ### Return 0 on success
  1116. sub stop_server_without_decrypt
  1117. {
  1118.     my ($home_id, $server_ip, $server_port, $control_protocol,
  1119.         $control_password, $control_type, $home_path) = @_;
  1120.        
  1121.     my $startup_file = Path::Class::File->new(GAME_STARTUP_DIR, "$server_ip-$server_port");
  1122.    
  1123.     if (-e $startup_file)
  1124.     {
  1125.         logger "Removing startup flag " . $startup_file . "";
  1126.         unlink($startup_file)
  1127.           or logger "Cannot remove the startup flag file $startup_file $!";
  1128.     }
  1129.    
  1130.     # Create file indicator that the game server has been stopped if defined
  1131.     if(defined($Cfg::Preferences{ogp_autorestart_server}) &&  $Cfg::Preferences{ogp_autorestart_server} eq "1"){
  1132.        
  1133.         # Get current directory and chdir into the game's home dir
  1134.         my $curDir = getcwd();
  1135.         chdir $home_path;
  1136.  
  1137.         # Create stopped indicator file used by autorestart of OGP if server crashes
  1138.         open(STOPFILE, '>', "SERVER_STOPPED");
  1139.         close(STOPFILE);
  1140.        
  1141.         # Return to original directory
  1142.         chdir $curDir;
  1143.     }
  1144.    
  1145.     # Some validation checks for the variables.
  1146.     if ($server_ip =~ /^\s*$/ || $server_port < 0 || $server_port > 65535)
  1147.     {
  1148.         logger("Invalid IP:Port given $server_ip:$server_port.");
  1149.         return 1;
  1150.     }
  1151.  
  1152.     if ($control_password !~ /^\s*$/ and $control_protocol ne "")
  1153.     {
  1154.         if ($control_protocol eq "rcon")
  1155.         {
  1156.             use KKrcon::KKrcon;
  1157.             my $rcon = new KKrcon(
  1158.                                   Password => $control_password,
  1159.                                   Host   => $server_ip,
  1160.                                   Port   => $server_port,
  1161.                                   Type   => $control_type
  1162.                                  );
  1163.  
  1164.             my $rconCommand = "quit";
  1165.             $rcon->execute($rconCommand);
  1166.         }
  1167.         elsif ($control_protocol eq "rcon2")
  1168.         {
  1169.             use KKrcon::HL2;
  1170.             my $rcon2 = new HL2(
  1171.                                   hostname => $server_ip,
  1172.                                   port   => $server_port,
  1173.                                   password => $control_password,
  1174.                                   timeout  => 2
  1175.                                  );
  1176.  
  1177.             my $rconCommand = "quit";
  1178.             $rcon2->run($rconCommand);
  1179.         }
  1180.        
  1181.         if (is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 0)
  1182.         {
  1183.             logger "Stopped server $server_ip:$server_port with rcon quit.";
  1184.             return 0;
  1185.         }
  1186.         else
  1187.         {
  1188.             logger "Failed to send rcon quit. Stopping server with kill command.";
  1189.         }
  1190.  
  1191.         my @server_pids = get_home_pids($home_id);
  1192.        
  1193.         my $cnt;
  1194.         foreach my $pid (@server_pids)
  1195.         {
  1196.             chomp($pid);
  1197.             $cnt = kill 15, $pid;
  1198.            
  1199.             if ($cnt != 1)
  1200.             {
  1201.                 $cnt = kill 9, $pid;
  1202.                 if ($cnt == 1)
  1203.                 {
  1204.                     logger "Stopped process with pid $pid successfully using kill 9.";
  1205.                 }
  1206.                 else
  1207.                 {
  1208.                     logger "Process $pid can not be stopped.";
  1209.                 }
  1210.             }
  1211.             else
  1212.             {
  1213.                 logger "Stopped process with pid $pid successfully using kill 15.";
  1214.             }
  1215.         }
  1216.         system('screen -wipe > /dev/null 2>&1');
  1217.         return 0;
  1218.     }
  1219.     else
  1220.     {
  1221.         logger "Remote control protocol not available or PASSWORD NOT SET. Using kill signal instead.";
  1222.         my @server_pids = get_home_pids($home_id);
  1223.        
  1224.         my $cnt;
  1225.         foreach my $pid (@server_pids)
  1226.         {
  1227.             chomp($pid);
  1228.             $cnt = kill 15, $pid;
  1229.            
  1230.             if ($cnt != 1)
  1231.             {
  1232.                 $cnt = kill 9, $pid;
  1233.                 if ($cnt == 1)
  1234.                 {
  1235.                     logger "Stopped process with pid $pid successfully using kill 9.";
  1236.                 }
  1237.                 else
  1238.                 {
  1239.                     logger "Process $pid can not be stopped.";
  1240.                 }
  1241.             }
  1242.             else
  1243.             {
  1244.                 logger "Stopped process with pid $pid successfully using kill 15.";
  1245.             }
  1246.         }
  1247.         system('screen -wipe > /dev/null 2>&1');
  1248.         return 0;
  1249.     }
  1250. }
  1251.  
  1252. ##### Send RCON command
  1253. ### Return 0 when error occurred on decryption.
  1254. ### Return 1 on success
  1255. sub send_rcon_command
  1256. {
  1257.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1258.     my ($home_id, $server_ip, $server_port, $control_protocol,
  1259.         $control_password, $control_type, $rconCommand) = decrypt_params(@_);
  1260.  
  1261.     # legacy console
  1262.     if ($control_protocol eq "lcon")
  1263.     {
  1264.         my $screen_id = create_screen_id(SCREEN_TYPE_HOME, $home_id);
  1265.         system('screen -S '.$screen_id.' -p 0 -X stuff "'.$rconCommand.'$(printf \\\\r)"');
  1266.         logger "Sending legacy console command to ".$screen_id.": \n$rconCommand \n .";
  1267.         if ($? == -1)
  1268.         {
  1269.             my(@modedlines) = "$rconCommand";
  1270.             my $encoded_content = encode_list(@modedlines);
  1271.             return "1;" . $encoded_content;
  1272.         }
  1273.         return 0;
  1274.     }
  1275.    
  1276.     # Some validation checks for the variables.
  1277.     if ($server_ip =~ /^\s*$/ || $server_port < 0 || $server_port > 65535)
  1278.     {
  1279.         logger("Invalid IP:Port given $server_ip:$server_port.");
  1280.         return 0;
  1281.     }
  1282.    
  1283.     if ($control_password !~ /^\s*$/)
  1284.     {
  1285.         if ($control_protocol eq "rcon")
  1286.         {
  1287.             use KKrcon::KKrcon;
  1288.             my $rcon = new KKrcon(
  1289.                                   Password => $control_password,
  1290.                                   Host   => $server_ip,
  1291.                                   Port   => $server_port,
  1292.                                   Type   => $control_type
  1293.                                  );
  1294.  
  1295.             logger "Sending RCON command to $server_ip:$server_port: \n$rconCommand \n  .";
  1296.                        
  1297.             my(@modedlines) = $rcon->execute($rconCommand);
  1298.             my $encoded_content = encode_list(@modedlines);
  1299.             return "1;" . $encoded_content;
  1300.         }
  1301.         else
  1302.         {      
  1303.             if ($control_protocol eq "rcon2")
  1304.             {
  1305.                 use KKrcon::HL2;
  1306.                 my $rcon2 = new HL2(
  1307.                                       hostname => $server_ip,
  1308.                                       port   => $server_port,
  1309.                                       password => $control_password,
  1310.                                       timeout  => 2
  1311.                                      );
  1312.                                                    
  1313.                 logger "Sending RCON command to $server_ip:$server_port: \n $rconCommand \n  .";
  1314.                        
  1315.                 my(@modedlines) = $rcon2->run($rconCommand);
  1316.                 my $encoded_content = encode_list(@modedlines);
  1317.                 return "1;" . $encoded_content;
  1318.             }
  1319.         }
  1320.     }
  1321.     else
  1322.     {
  1323.         logger "Control protocol PASSWORD NOT SET.";
  1324.         return -10;
  1325.     }
  1326. }
  1327.  
  1328. ##### Returns a directory listing
  1329. ### @return List of directories if everything OK.
  1330. ### @return 0 If the directory is not found.
  1331. ### @return -1 If cannot open the directory.
  1332. sub dirlist
  1333. {
  1334.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1335.     my ($datadir) = &decrypt_param(@_);
  1336.     logger "Asked for dirlist of $datadir directory.";
  1337.     if (!-d $datadir)
  1338.     {
  1339.         logger "ERROR - Directory [ $datadir ] not found!";
  1340.         return -1;
  1341.     }
  1342.     if (!opendir(DIR, $datadir))
  1343.     {
  1344.         logger "ERROR - Can't open $datadir: $!";
  1345.         return -2;
  1346.     }
  1347.     my @dirlist = readdir(DIR);
  1348.     closedir(DIR);
  1349.     return join(";", @dirlist);
  1350. }
  1351.  
  1352. ##### Returns a directory listing with extra info the filemanager
  1353. ### @return List of directories if everything OK.
  1354. ### @return 1 If the directory is empty.
  1355. ### @return -1 If the directory is not found.
  1356. ### @return -2 If cannot open the directory.
  1357. sub dirlistfm
  1358. {
  1359.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1360.     my $datadir = &decrypt_param(@_);
  1361.    
  1362.     logger "Asked for dirlist of $datadir directory.";
  1363.    
  1364.     if (!-d $datadir)
  1365.     {
  1366.         logger "ERROR - Directory [ $datadir ] not found!";
  1367.         return -1;
  1368.     }
  1369.    
  1370.     if (!opendir(DIR, $datadir))
  1371.     {
  1372.         logger "ERROR - Can't open $datadir: $!";
  1373.         return -2;
  1374.     }
  1375.    
  1376.     my $dir = $datadir;
  1377.     $dir =~ s/('+)/'"$1"'/g;
  1378.     my $lsattr = `lsattr '$dir' 2>/dev/null`;
  1379.    
  1380.     my @attr_all = split /\n+/, $lsattr;
  1381.    
  1382.     my %attr = ();
  1383.    
  1384.     my ($a, $p, @f);
  1385.    
  1386.     foreach (@attr_all)
  1387.     {
  1388.         ($a, $p) = split(/\s/, $_, 2);
  1389.         @f = split /\//, $p;
  1390.         $attr{$f[-1]}   = $a;
  1391.     }
  1392.    
  1393.     my %dirfiles = ();
  1394.    
  1395.     my (
  1396.         $dev,  $ino,   $mode,  $nlink, $uid,     $gid, $rdev,
  1397.         $size, $atime, $mtime, $ctime, $blksize, $blocks
  1398.        );
  1399.    
  1400.     my $count = 0;
  1401.    
  1402.     chdir($datadir);
  1403.    
  1404.     while (my $item = readdir(DIR))
  1405.     {
  1406.         #skip the . and .. special dirs
  1407.         next if $item eq '.';
  1408.         next if $item eq '..';
  1409.         #print "Dir list is" . $item."\n";
  1410.         #Stat the file to get ownership and size
  1411.         (
  1412.          $dev,  $ino,   $mode,  $nlink, $uid,    $gid, $rdev,
  1413.          $size, $atime, $mtime, $ctime, $blksize, $blocks
  1414.         ) = stat($item);
  1415.        
  1416.         $uid = getpwuid($uid);
  1417.         $gid = getgrgid($gid);
  1418.  
  1419.         #This if else logic determines what it is, File, Directory, other  
  1420.         if (-T $item)
  1421.         {
  1422.             # print "File\n";
  1423.             $dirfiles{'files'}{$count}{'filename'}  = encode_base64($item);
  1424.             $dirfiles{'files'}{$count}{'size'}      = $size;
  1425.             $dirfiles{'files'}{$count}{'user'}      = $uid;
  1426.             $dirfiles{'files'}{$count}{'group'}     = $gid;
  1427.             $dirfiles{'files'}{$count}{'attr'}      = $attr{$item};
  1428.         }
  1429.         elsif (-d $item)
  1430.         {
  1431.             # print "Dir\n";
  1432.             $dirfiles{'directorys'}{$count}{'filename'} = encode_base64($item);
  1433.             $dirfiles{'directorys'}{$count}{'size'}     = $size;
  1434.             $dirfiles{'directorys'}{$count}{'user'}     = $uid;
  1435.             $dirfiles{'directorys'}{$count}{'group'}    = $gid;
  1436.         }
  1437.         elsif (-B $item)
  1438.         {
  1439.             #print "File\n";
  1440.             $dirfiles{'binarys'}{$count}{'filename'}    = encode_base64($item);
  1441.             $dirfiles{'binarys'}{$count}{'size'}        = $size;
  1442.             $dirfiles{'binarys'}{$count}{'user'}        = $uid;
  1443.             $dirfiles{'binarys'}{$count}{'group'}       = $gid;
  1444.             $dirfiles{'binarys'}{$count}{'attr'}        = $attr{$item};
  1445.         }
  1446.         else
  1447.         {
  1448.             #print "Unknown\n"
  1449.             #will be listed as common files;
  1450.             $dirfiles{'files'}{$count}{'filename'}  = encode_base64($item);
  1451.             $dirfiles{'files'}{$count}{'size'}      = $size;
  1452.             $dirfiles{'files'}{$count}{'user'}      = $uid;
  1453.             $dirfiles{'files'}{$count}{'group'}     = $gid;
  1454.             $dirfiles{'files'}{$count}{'attr'}      = $attr{$item};
  1455.         }
  1456.         $count++;
  1457.     }
  1458.     closedir(DIR);
  1459.    
  1460.     if ($count eq 0)
  1461.     {
  1462.         logger "Empty directory $datadir.";
  1463.         return 1;
  1464.     }
  1465.        
  1466.     chdir AGENT_RUN_DIR;
  1467.     #Now we return it to the webpage, as array
  1468.     return {%dirfiles};
  1469. }
  1470.  
  1471. ###### Returns the contents of a text file
  1472. sub readfile
  1473. {
  1474.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1475.     chdir AGENT_RUN_DIR;
  1476.     my $userfile = &decrypt_param(@_);
  1477.  
  1478.     unless ( -e $userfile )
  1479.     {
  1480.         if (open(BLANK, '>', $userfile))
  1481.         {
  1482.             close(BLANK);
  1483.         }
  1484.     }
  1485.    
  1486.     if (!open(USERFILE, '<', $userfile))
  1487.     {
  1488.         logger "ERROR - Can't open file $userfile for reading.";
  1489.         return -1;
  1490.     }
  1491.  
  1492.     my ($wholefile, $buf);
  1493.  
  1494.     while (read(USERFILE, $buf, 60 * 57))
  1495.     {
  1496.         $wholefile .= encode_base64($buf);
  1497.     }
  1498.     close(USERFILE);
  1499.    
  1500.     if(!defined $wholefile)
  1501.     {
  1502.         return "1; ";
  1503.     }
  1504.    
  1505.     return "1;" . $wholefile;
  1506. }
  1507.  
  1508. ###### Backs up file, then writes data to new file
  1509. ### @return 1 On success
  1510. ### @return 0 In case of a failure
  1511. sub writefile
  1512. {
  1513.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1514.     chdir AGENT_RUN_DIR;
  1515.     # $writefile = file we're editing, $filedata = the contents were writing to it
  1516.     my ($writefile, $filedata) = &decrypt_params(@_);
  1517.     if (!-e $writefile)
  1518.     {
  1519.         open FILE, ">", $writefile;
  1520.     }
  1521.     else
  1522.     {
  1523.         # backup the existing file
  1524.         logger
  1525.           "Backing up file $writefile to $writefile.bak before writing new data.";
  1526.         if (!copy("$writefile", "$writefile.bak"))
  1527.         {
  1528.             logger
  1529.               "ERROR - Failed to backup $writefile to $writefile.bak. Error: $!";
  1530.             return 0;
  1531.         }
  1532.     }
  1533.     if (!-w $writefile)
  1534.     {
  1535.         logger "ERROR - File [ $writefile ] is not writeable!";
  1536.         return 0;
  1537.     }
  1538.     if (!open(WRITER, '>', $writefile))
  1539.     {
  1540.         logger "ERROR - Failed to open $writefile for writing.";
  1541.         return 0;
  1542.     }
  1543.     $filedata = decode_base64($filedata);
  1544.     $filedata =~ s/\r//g;
  1545.     print WRITER "$filedata";
  1546.     close(WRITER);
  1547.     logger "Wrote $writefile successfully!";
  1548.     return 1;
  1549. }
  1550.  
  1551. ###### Reboots the server remotely through panel
  1552. ### @return 1 On success
  1553. ### @return 0 In case of a failure
  1554. sub rebootnow
  1555. {
  1556.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1557.     sudo_exec_without_decrypt('sleep 10s; shutdown -r now');
  1558.     logger "Scheduled system reboot to occur in 10 seconds successfully!";
  1559.     return 1;
  1560. }
  1561.  
  1562. # Determine the os of the agent machine.
  1563. sub what_os
  1564. {
  1565.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1566.     logger "Asking for OS type";
  1567.     my $which_uname = `which uname`;
  1568.     chomp $which_uname;
  1569.     if ($which_uname ne "")
  1570.     {
  1571.         my $os;
  1572.         my $os_name;
  1573.         my $os_arch;
  1574.         my $wine_ver = "";
  1575.         $os_name = `$which_uname`;
  1576.         chomp $os_name;
  1577.         $os_arch = `$which_uname -m`;
  1578.         chomp $os_arch;
  1579.         my $which_wine = `which wine`;
  1580.         chomp $which_wine;
  1581.         if ($which_wine ne "")
  1582.         {
  1583.             $wine_ver = `$which_wine --version`;
  1584.             chomp $wine_ver;
  1585.             $wine_ver = "|".$wine_ver;
  1586.         }
  1587.         $os = $os_name." ".$os_arch.$wine_ver;
  1588.         logger "OS is $os";
  1589.         return "$os";
  1590.     }
  1591.     else
  1592.     {
  1593.         logger "Cannot determine OS..that is odd";
  1594.         return "Unknown";
  1595.     }
  1596. }
  1597.  
  1598. ### @return PID of the download process if started succesfully.
  1599. ### @return -1 If could not create temporary download directory.
  1600. ### @return -2 If could not create destination directory.
  1601. ### @return -3 If resources unavailable.
  1602. sub start_file_download
  1603. {
  1604.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1605.     my ($url, $destination, $filename, $action, $post_script) = &decrypt_params(@_);
  1606.     logger
  1607.       "Starting to download URL $url. Destination: $destination - Filename: $filename";
  1608.  
  1609.     if (!-e $destination)
  1610.     {
  1611.         logger "Creating destination directory.";
  1612.         if (!mkpath $destination )
  1613.         {
  1614.             logger "Could not create destination '$destination' directory : $!";
  1615.             return -2;
  1616.         }
  1617.     }
  1618.    
  1619.     my $download_file_path = Path::Class::File->new($destination, "$filename");
  1620.  
  1621.     my $pid = fork();
  1622.     if (not defined $pid)
  1623.     {
  1624.         logger "Could not allocate resources for download.";
  1625.         return -3;
  1626.     }
  1627.    
  1628.     # Only the forked child goes here.
  1629.     elsif ($pid == 0)
  1630.     {
  1631.         my $ua = LWP::UserAgent->new( ssl_opts => { verify_hostname => 0,
  1632.                                                     SSL_verify_mode => 0x00 } );
  1633.         $ua->agent('Mozilla/5.0');
  1634.         my $response = $ua->get($url, ':content_file' => "$download_file_path");
  1635.        
  1636.         if ($response->is_success)
  1637.         {
  1638.             logger "Successfully fetched $url and stored it to $download_file_path. Retval: ".$response->status_line;
  1639.            
  1640.             if (!-e $download_file_path)
  1641.             {
  1642.                 logger "File $download_file_path does not exist.";
  1643.                 exit(0);
  1644.             }
  1645.  
  1646.             if ($action eq "uncompress")
  1647.             {
  1648.                 logger "Starting file uncompress as ordered.";
  1649.                 uncompress_file_without_decrypt($download_file_path,
  1650.                                                 $destination);
  1651.             }
  1652.         }
  1653.         else
  1654.         {
  1655.             logger
  1656.               "Unable to fetch $url, or save to $download_file_path. Retval: ".$response->status_line;
  1657.             exit(0);
  1658.         }
  1659.  
  1660.         # Child process must exit.
  1661.         exit(0);
  1662.     }
  1663.     else
  1664.     {
  1665.         if ($post_script ne "")
  1666.         {
  1667.             logger "Running postscript commands.";
  1668.             my @postcmdlines = split /[\r\n]+/, $post_script;
  1669.             my $postcmdfile = $destination."/".'postinstall.sh';
  1670.             open  FILE, '>', $postcmdfile;
  1671.             print FILE "cd $destination\n";
  1672.             print FILE "while kill -0 $pid >/dev/null 2>&1\n";
  1673.             print FILE "do\n";
  1674.             print FILE "    sleep 1\n";
  1675.             print FILE "done\n";
  1676.             foreach my $line (@postcmdlines) {
  1677.                 print FILE "$line\n";
  1678.             }
  1679.             print FILE "rm -f $destination/postinstall.sh\n";
  1680.             close FILE;
  1681.             chmod 0755, $postcmdfile;
  1682.             my $screen_id = create_screen_id("post_script", $pid);
  1683.             my $cli_bin = create_screen_cmd($screen_id, "bash $postcmdfile");
  1684.             system($cli_bin);
  1685.         }
  1686.         logger "Download process for $download_file_path has pid number $pid.";
  1687.         return "$pid";
  1688.     }
  1689. }
  1690.  
  1691. sub lock_additional_files{
  1692.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1693.     my ($homedir, $files, $action) = &decrypt_params(@_);
  1694.     return lock_additional_files_logic($homedir, $files, $action);
  1695. }
  1696.  
  1697. sub lock_additional_files_logic{
  1698.     my ($homedir, $filesToLock, $action, $returnType) = @_;
  1699.    
  1700.     logger "Locking additional files specified in the XML.";
  1701.    
  1702.     my $commandStr = "";
  1703.     $filesToLock = startup_comma_format_to_multiline($filesToLock);
  1704.     $filesToLock = replace_OGP_Env_Vars("", $homedir, $filesToLock);
  1705.     my @filesToProcess = split /[\r\n]+/, $filesToLock;
  1706.     foreach my $line (@filesToProcess) {
  1707.         my $fullPath = $homedir . "/" . $line;
  1708.         if($action eq "lock"){
  1709.             if(defined $returnType && $returnType eq "str"){
  1710.                 $commandStr .= "echo '".$SUDOPASSWD."' | sudo -S -p \"\" sh -c \"" . secure_path_without_decrypt("chattr+i", $fullPath, $returnType) . "\" > /dev/null 2>&1" . "\n";
  1711.                 $commandStr .= "echo '".$SUDOPASSWD."' | sudo -S -p \"\" sh -c \"" . secure_path_without_decrypt("chattr+i", $line, $returnType) . "\" > /dev/null 2>&1" . "\n";
  1712.             }else{
  1713.                 secure_path_without_decrypt("chattr+i", $fullPath);
  1714.                 secure_path_without_decrypt("chattr+i", $line);
  1715.             }
  1716.         }else{
  1717.             if(defined $returnType && $returnType eq "str"){
  1718.                 $commandStr .= "echo '".$SUDOPASSWD."' | sudo -S -p \"\" sh -c \"" . secure_path_without_decrypt("chattr-i", $fullPath, $returnType) . "\" > /dev/null 2>&1" . "\n";
  1719.                 $commandStr .= "echo '".$SUDOPASSWD."' | sudo -S -p \"\" sh -c \"" . secure_path_without_decrypt("chattr-i", $line, $returnType) . "\" > /dev/null 2>&1" . "\n";
  1720.             }else{
  1721.                 secure_path_without_decrypt("chattr-i", $fullPath);
  1722.                 secure_path_without_decrypt("chattr-i", $line);
  1723.             }
  1724.         }
  1725.     }
  1726.    
  1727.     if($commandStr ne ""){
  1728.         return $commandStr;
  1729.     }
  1730.    
  1731.     return "";
  1732. }
  1733.  
  1734. sub run_before_start_commands
  1735. {
  1736.     #return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1737.     my ($server_id, $homedir, $beforestartcmd, $envVars) = @_;
  1738.    
  1739.     if ($homedir ne "" && $server_id ne ""){
  1740.         # Run any prestart scripts
  1741.         if (defined $beforestartcmd && $beforestartcmd ne "")
  1742.         {      
  1743.             logger "Running pre-start XML commands before starting server ID $server_id with a home directory of $homedir.";
  1744.             my @prestartcmdlines = split /[\r\n]+/, $beforestartcmd;
  1745.             my $prestartcmdfile = $homedir."/".'prestart_ogp.sh';
  1746.             open  FILE, '>', $prestartcmdfile;
  1747.             print FILE "#!/bin/bash" . "\n";
  1748.             print FILE "cd $homedir\n";
  1749.             foreach my $line (@prestartcmdlines) {
  1750.                 print FILE "$line\n";
  1751.             }
  1752.             print FILE "rm -f $prestartcmdfile\n";
  1753.             close FILE;
  1754.             chmod 0755, $prestartcmdfile;
  1755.             system("bash $prestartcmdfile");
  1756.         }
  1757.        
  1758.        
  1759.         # Set and export any environment variables for game server developers unwilling to properly learn Linux
  1760.         if (defined $envVars && $envVars ne ""){
  1761.             my @prestartenvvars = split /[\r\n]+/, $envVars;
  1762.             foreach my $line (@prestartenvvars) {
  1763.                 $line = replace_OGP_Env_Vars($server_id, $homedir, $line);
  1764.                 if($line ne ""){
  1765.                     logger "Configuring environment variable: $line";
  1766.                     system($line);
  1767.                 }
  1768.             }
  1769.         }
  1770.        
  1771.     }else{
  1772.         return -2;
  1773.     }
  1774.    
  1775.     return 1;
  1776. }
  1777.  
  1778. sub multiline_to_startup_comma_format{
  1779.     my ($multiLineVar) = @_;
  1780.     $multiLineVar =~ s/,//g; # commas are invalid anyways in bash
  1781.     $multiLineVar =~ s/[\r]+//g;
  1782.     $multiLineVar =~ s/[\n]+/{OGPNEWLINE}/g;
  1783.     return $multiLineVar;
  1784. }
  1785.  
  1786. sub startup_comma_format_to_multiline{
  1787.     my ($multiLineVar) = @_;
  1788.     $multiLineVar =~ s/{OGPNEWLINE}/\n/g;
  1789.     return $multiLineVar;
  1790. }
  1791.  
  1792. sub create_secure_script
  1793. {  
  1794.     my ($home_path, $exec_folder_path, $exec_path) = @_;
  1795.     secure_path_without_decrypt('chattr-i', $home_path);
  1796.     my $secure = "$home_path/secure.sh";
  1797.     $home_path =~ s/('+)/'\"$1\"'/g;
  1798.     $exec_folder_path =~ s/('+)/'\"$1\"'/g;
  1799.     $exec_path =~ s/('+)/'\"$1\"'/g;
  1800.     my $sec = $secure;
  1801.     $sec =~ s/('+)/'\"$1\"'/g;
  1802.     open  FILE, '>', $secure;
  1803.     print FILE  "chmod 771 '$exec_folder_path'\n".
  1804.                 "chmod 750 '$exec_path'\n".
  1805.                 "chmod +x '$exec_path'\n".
  1806.                 "chattr +i '$exec_path'\n".
  1807.                 "rm -f '$sec'";
  1808.     close FILE;
  1809.     chmod 0770, $secure;
  1810.     sudo_exec_without_decrypt("chown 0:0 '$sec'");
  1811.     return 0;
  1812. }
  1813.  
  1814. sub check_b4_chdir
  1815. {
  1816.     my ( $path ) = @_;
  1817.    
  1818.     my $uid = `id -u`;
  1819.     chomp $uid;
  1820.     my $gid = `id -g`;
  1821.     chomp $gid;
  1822.        
  1823.     if (!-e $path)
  1824.     {
  1825.         logger "$path does not exist yet. Trying to create it...";
  1826.  
  1827.         if (!mkpath($path))
  1828.         {
  1829.             logger "Error creating $path . Errno: $!";
  1830.             return -1;
  1831.         }
  1832.        
  1833.         # Set perms on it as well
  1834.         #sudo_exec_without_decrypt('chown -Rf '.$uid.':'.$gid.' \''.$path.'\'');
  1835.        
  1836.     }
  1837.     else
  1838.     {  
  1839.         # File or directory already exists
  1840.         # Make sure it's owned by the agent
  1841.         secure_path_without_decrypt('chattr-i', $path);
  1842.     }
  1843.    
  1844.     if (!chdir $path)
  1845.     {
  1846.         logger "Unable to change dir to '$path'.";
  1847.         return -1;
  1848.     }
  1849.    
  1850.     return 0;
  1851. }
  1852.  
  1853. sub create_bash_scripts
  1854. {
  1855.     my ( $home_path, $bash_scripts_path, $precmd, $postcmd, @installcmds ) = @_;
  1856.    
  1857.     $home_path         =~ s/('+)/'\"$1\"'/g;
  1858.     $bash_scripts_path =~ s/('+)/'\"$1\"'/g;
  1859.    
  1860.     my @precmdlines = split /[\r\n]+/, $precmd;
  1861.     my $precmdfile = 'preinstall.sh';
  1862.     open  FILE, '>', $precmdfile;
  1863.     print FILE "cd '$home_path'\n";
  1864.     foreach my $line (@precmdlines) {
  1865.         print FILE "$line\n";
  1866.     }
  1867.     close FILE;
  1868.     chmod 0755, $precmdfile;
  1869.    
  1870.     my @postcmdlines = split /[\r\n]+/, $postcmd;
  1871.     my $postcmdfile = 'postinstall.sh';
  1872.     open  FILE, '>', $postcmdfile;
  1873.     print FILE "cd '$home_path'\n";
  1874.     foreach my $line (@postcmdlines) {
  1875.         print FILE "$line\n";
  1876.     }
  1877.     print FILE "cd '$home_path'\n".
  1878.                "echo '".$SUDOPASSWD."' | sudo -S -p \"\" bash secure.sh\n".
  1879.                "rm -f secure.sh\n".
  1880.                "cd '$bash_scripts_path'\n".
  1881.                "rm -f preinstall.sh\n".
  1882.                "rm -f postinstall.sh\n".
  1883.                "rm -f runinstall.sh\n";
  1884.     close FILE;
  1885.     chmod 0755, $postcmdfile;
  1886.    
  1887.     my $installfile = 'runinstall.sh';
  1888.     open  FILE, '>', $installfile;
  1889.     print FILE "#!/bin/bash\n".
  1890.                "cd '$bash_scripts_path'\n".
  1891.                "./$precmdfile\n";
  1892.     foreach my $installcmd (@installcmds)
  1893.     {
  1894.         print FILE "$installcmd\n";
  1895.     }
  1896.     print FILE "wait ".'${!}'."\n".
  1897.                "cd '$bash_scripts_path'\n".
  1898.                "./$postcmdfile\n";
  1899.     close FILE;
  1900.     chmod 0755, $installfile;
  1901.    
  1902.     return $installfile;
  1903. }
  1904.  
  1905. #### Run the rsync update ####
  1906. ### @return 1 If update started
  1907. ### @return 0 In error case.
  1908. sub start_rsync_install
  1909. {
  1910.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1911.     my ($home_id, $home_path, $url, $exec_folder_path, $exec_path, $precmd, $postcmd, $filesToLockUnlock) = decrypt_params(@_);
  1912.  
  1913.     if ( check_b4_chdir($home_path) != 0)
  1914.     {
  1915.         return 0;
  1916.     }
  1917.    
  1918.     secure_path_without_decrypt('chattr-i', $home_path);
  1919.    
  1920.     create_secure_script($home_path, $exec_folder_path, $exec_path);
  1921.  
  1922.     my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id;
  1923.    
  1924.     if ( check_b4_chdir($bash_scripts_path) != 0)
  1925.     {
  1926.         return 0;
  1927.     }
  1928.    
  1929.     # Rsync install require the rsync binary to exist in the system
  1930.     # to enable this functionality.
  1931.     my $rsync_binary = Path::Class::File->new("/usr/bin", "rsync");
  1932.    
  1933.     if (!-f $rsync_binary)
  1934.     {
  1935.         logger "Failed to start rsync update from "
  1936.           . $url
  1937.           . " to $home_path. Error: Rsync client not installed.";
  1938.         return 0;
  1939.     }
  1940.  
  1941.     my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id);
  1942.    
  1943.     my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id");
  1944.    
  1945.     if(defined $filesToLockUnlock && $filesToLockUnlock ne ""){
  1946.         $postcmd .= "\n" . lock_additional_files_logic($home_path, $filesToLockUnlock, "lock", "str");
  1947.     }
  1948.    
  1949.     backup_home_log( $home_id, $log_file );
  1950.     my $path    = $home_path;
  1951.     $path       =~ s/('+)/'\"$1\"'/g;
  1952.     my @installcmds = ("/usr/bin/rsync --archive --compress --copy-links --update --verbose rsync://$url '$path'");
  1953.     my $installfile = create_bash_scripts( $home_path, $bash_scripts_path, $precmd, $postcmd, @installcmds );
  1954.  
  1955.     my $screen_cmd = create_screen_cmd($screen_id, "./$installfile");
  1956.     logger "Running rsync update: /usr/bin/rsync --archive --compress --copy-links --update --verbose rsync://$url '$home_path'";
  1957.     system($screen_cmd);
  1958.    
  1959.     chdir AGENT_RUN_DIR;
  1960.     return 1;
  1961. }
  1962.  
  1963. ### @return PID of the download process if started succesfully.
  1964. ### @return -1 If could not create temporary download directory.
  1965. ### @return -2 If could not create destination directory.
  1966. ### @return -3 If resources unavailable.
  1967. sub master_server_update
  1968. {
  1969.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  1970.     my ($home_id,$home_path,$ms_home_id,$ms_home_path,$exec_folder_path,$exec_path,$precmd,$postcmd) = decrypt_params(@_);
  1971.    
  1972.     if ( check_b4_chdir($home_path) != 0)
  1973.     {
  1974.         return 0;
  1975.     }
  1976.    
  1977.     secure_path_without_decrypt('chattr-i', $home_path);
  1978.        
  1979.     create_secure_script($home_path, $exec_folder_path, $exec_path);
  1980.            
  1981.     my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id;
  1982.    
  1983.     if ( check_b4_chdir($bash_scripts_path) != 0)
  1984.     {
  1985.         return 0;
  1986.     }
  1987.  
  1988.     my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id);
  1989.    
  1990.     my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id");
  1991.    
  1992.     backup_home_log( $home_id, $log_file );
  1993.    
  1994.     my $my_home_path = $home_path;
  1995.     $my_home_path =~ s/('+)/'\"$1\"'/g;
  1996.     $exec_path =~ s/\Q$home_path\E//g;
  1997.     $exec_path =~ s/^\///g;
  1998.     $exec_path =~ s/('+)/'\"$1\"'/g;
  1999.     $ms_home_path =~ s/('+)/'\"$1\"'/g;
  2000.    
  2001.     my @installcmds = ("cd '$ms_home_path'");
  2002.    
  2003.     ## Copy files that match the extensions listed at extPatterns.txt
  2004.     open(EXT_PATTERNS, '<', Path::Class::File->new(AGENT_RUN_DIR, "extPatterns.txt"))
  2005.           || logger "Error reading patterns file $!";
  2006.     my @ext_paterns = <EXT_PATTERNS>;
  2007.     foreach my $patern (@ext_paterns)
  2008.     {
  2009.         chop $patern;
  2010.         push (@installcmds, "find  -iname \\\*.$patern -exec cp -Rfp --parents {} '$my_home_path'/ \\\;");
  2011.     }
  2012.     close EXT_PATTERNS;
  2013.    
  2014.     ## Copy the server executable so it can be secured with chattr +i
  2015.     push (@installcmds, "cp -vf --parents '$exec_path' '$my_home_path'");
  2016.    
  2017.     ## Do symlinks for each of the other files
  2018.     push (@installcmds, "cp -vuRfs  '$ms_home_path'/* '$my_home_path'");
  2019.    
  2020.     my $installfile = create_bash_scripts( $home_path, $bash_scripts_path, $precmd, $postcmd, @installcmds );
  2021.  
  2022.     my $screen_cmd = create_screen_cmd($screen_id, "./$installfile");
  2023.     logger "Running master server update from home ID $home_id to home ID $ms_home_id";
  2024.     system($screen_cmd);
  2025.    
  2026.     chdir AGENT_RUN_DIR;
  2027.     return 1;
  2028. }
  2029.  
  2030. sub steam_cmd
  2031. {
  2032.     chomp(@_);
  2033.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2034.     return steam_cmd_without_decrypt(decrypt_params(@_));
  2035. }
  2036.  
  2037. #### Run the steam client ####
  2038. ### @return 1 If update started
  2039. ### @return 0 In error case.
  2040. sub steam_cmd_without_decrypt
  2041. {
  2042.     my ($home_id, $home_path, $mod, $modname, $betaname, $betapwd, $user, $pass, $guard, $exec_folder_path, $exec_path, $precmd, $postcmd, $cfg_os, $filesToLockUnlock) = @_;
  2043.    
  2044.     if ( check_b4_chdir($home_path) != 0)
  2045.     {
  2046.         return 0;
  2047.     }
  2048.    
  2049.     secure_path_without_decrypt('chattr-i', $home_path);
  2050.    
  2051.     create_secure_script($home_path, $exec_folder_path, $exec_path);
  2052.    
  2053.     my $bash_scripts_path = MANUAL_TMP_DIR . "/home_id_" . $home_id;
  2054.    
  2055.     if ( check_b4_chdir($bash_scripts_path) != 0)
  2056.     {
  2057.         return 0;
  2058.     }
  2059.    
  2060.     my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id);
  2061.     my $screen_id_for_txt_update = substr ($screen_id, rindex($screen_id, '_') + 1);
  2062.     my $steam_binary = Path::Class::File->new(STEAMCMD_CLIENT_DIR, "steamcmd.sh");
  2063.     my $installSteamFile =  $screen_id_for_txt_update . "_install.txt";
  2064.  
  2065.     my $installtxt = Path::Class::File->new(STEAMCMD_CLIENT_DIR, $installSteamFile);
  2066.     open  FILE, '>', $installtxt;
  2067.     print FILE "\@ShutdownOnFailedCommand 1\n";
  2068.     print FILE "\@NoPromptForPassword 1\n";
  2069.     if($cfg_os eq 'windows')
  2070.     {
  2071.         print FILE "\@sSteamCmdForcePlatformType windows\n";
  2072.     }
  2073.     if($guard ne '')
  2074.     {
  2075.         print FILE "set_steam_guard_code $guard\n";
  2076.     }
  2077.     if($user ne '' && $user ne 'anonymous')
  2078.     {
  2079.         print FILE "login $user $pass\n";
  2080.     }
  2081.     else
  2082.     {
  2083.         print FILE "login anonymous\n";
  2084.     }
  2085.    
  2086.     print FILE "force_install_dir \"$home_path\"\n";
  2087.  
  2088.     if($modname ne "")
  2089.     {
  2090.         print FILE "app_set_config $mod mod $modname\n";
  2091.         print FILE "app_update $mod mod $modname validate\n";  
  2092.     }
  2093.  
  2094.     if($betaname ne "" && $betapwd ne "")
  2095.     {
  2096.         print FILE "app_update $mod -beta $betaname -betapassword $betapwd\n";
  2097.     }
  2098.     elsif($betaname ne "" && $betapwd eq "")
  2099.     {
  2100.         print FILE "app_update $mod -beta $betaname\n";
  2101.     }
  2102.     else
  2103.     {
  2104.         print FILE "app_update $mod\n";
  2105.     }
  2106.    
  2107.     print FILE "exit\n";
  2108.     close FILE;
  2109.    
  2110.     my $log_file = Path::Class::File->new(SCREEN_LOGS_DIR, "screenlog.$screen_id");
  2111.     backup_home_log( $home_id, $log_file );
  2112.    
  2113.     my $postcmd_mod = $postcmd;
  2114.    
  2115.     if(defined $filesToLockUnlock && $filesToLockUnlock ne ""){
  2116.         $postcmd_mod .= "\n" . lock_additional_files_logic($home_path, $filesToLockUnlock, "lock", "str");
  2117.     }
  2118.    
  2119.     my @installcmds = ("$steam_binary +runscript $installtxt +exit");
  2120.    
  2121.     my $installfile = create_bash_scripts( $home_path, $bash_scripts_path, $precmd, $postcmd_mod, @installcmds );
  2122.    
  2123.     my $screen_cmd = create_screen_cmd($screen_id, "./$installfile");
  2124.    
  2125.     logger "Running steam update: $steam_binary +runscript $installtxt +exit";
  2126.     system($screen_cmd);
  2127.  
  2128.     return 1;
  2129. }
  2130.  
  2131. sub fetch_steam_version
  2132. {
  2133.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2134.     my ($appId, $pureOutput) = &decrypt_params(@_);
  2135.  
  2136.     my $steam_binary = Path::Class::File->new(STEAMCMD_CLIENT_DIR, "steamcmd.sh");
  2137.     my $steam_options = "+login anonymous +app_info_update 1 +app_info_print \"$appId\" +quit";
  2138.     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';
  2139.  
  2140.     logger "Getting latest version info for AppId $appId";
  2141.     my $response = `$steam_binary $steam_options $grep`;
  2142.  
  2143.     return $response;
  2144. }
  2145.  
  2146. sub installed_steam_version
  2147. {
  2148.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2149.     my ($game_home, $mod, $pureOutput) = &decrypt_params(@_);
  2150.     my $appFile = $game_home."/steamapps/appmanifest_$mod.acf";
  2151.     my $grep = $pureOutput != "0" ? "" : '| grep buildid | tr \'[:blank:]"\' \' \' | tr -s \' \' | cut -d\' \' -f3';
  2152.  
  2153.     if ( ! -f $appFile)
  2154.     {
  2155.         return "-10";
  2156.     }
  2157.  
  2158.     return `cat $appFile $grep`;
  2159. }
  2160.  
  2161. sub automatic_steam_update
  2162. {
  2163.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2164.     my ($home_id, $game_home, $server_ip, $server_port, $exec_path, $exec_folder_path,
  2165.         $control_protocol, $control_password, $control_type,
  2166.         $appId, $modname, $betaname, $betapwd, $user, $pass, $guard, $precmd, $postcmd, $cfg_os, $filesToLockUnlock,
  2167.         $startup_cmd, $cpu, $nice, $preStart, $envVars) = &decrypt_params(@_);
  2168.  
  2169.     # Is the server currently running? if it is, we'll try to start it after updating.
  2170.     my $isServerRunning = is_screen_running_without_decrypt(SCREEN_TYPE_HOME, $home_id) == 1 ? 1 : 0;
  2171.  
  2172.     # Check if an update is already happening.
  2173.     if (is_screen_running_without_decrypt(SCREEN_TYPE_UPDATE, $home_id) == 1)
  2174.     {
  2175.         logger("Update already running for server $home_id, unable to start automatic update.");
  2176.         return -10;
  2177.     }
  2178.  
  2179.     # Stop the server if it's running.
  2180.     if ($isServerRunning == 1)
  2181.     {
  2182.         logger("Stopping server $home_id for automatic update.");
  2183.  
  2184.         if (stop_server_without_decrypt($home_id, $server_ip, $server_port, $control_protocol, $control_password, $control_type, $game_home) != 0)
  2185.         {
  2186.             logger("Failed to stop server $home_id for automatic update. Exiting update procedure.");
  2187.             return -9
  2188.         }
  2189.  
  2190.     }
  2191.  
  2192.     # 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.
  2193.     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) == 0)
  2194.     {
  2195.         logger("Failed to start steam_cmd for server $home_id.");
  2196.         return -8;
  2197.  
  2198.     } else {
  2199.  
  2200.         if ($isServerRunning == 1)
  2201.         {
  2202.             while (1)
  2203.             {
  2204.                 # If the update screen for $home_id isn't running, attempt to start the server.
  2205.                 if (is_screen_running_without_decrypt(SCREEN_TYPE_UPDATE, $home_id) == 0)
  2206.                 {
  2207.  
  2208.                     if (universal_start_without_decrypt($home_id, $game_home, $exec_path, $exec_folder_path, $startup_cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars) != 1)
  2209.                     {
  2210.                         logger("Failed to start server $home_id after automatic update.");
  2211.                         return -7;
  2212.                     } else {
  2213.                         logger("Starting server $home_id after automatic update.");
  2214.                         return 1;
  2215.                     }
  2216.  
  2217.                     last;
  2218.                 }
  2219.  
  2220.                 sleep 5;
  2221.             }
  2222.  
  2223.         } else {
  2224.             # Update was started, but server wasn't initially running.
  2225.             return 2;
  2226.         }
  2227.  
  2228.     }
  2229.  
  2230. }
  2231.  
  2232. sub rsync_progress
  2233. {
  2234.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2235.     my ($running_home) = &decrypt_param(@_);
  2236.     logger "User requested progress on rsync job on home $running_home.";
  2237.     if (-r $running_home)
  2238.     {
  2239.         $running_home =~ s/('+)/'"$1"'/g;
  2240.         my $progress = `du -sk '$running_home'`;
  2241.         chomp($progress);
  2242.         my ($bytes, $junk) = split(/\s+/, $progress);
  2243.         logger("Found $bytes and $junk");
  2244.         return $bytes;
  2245.     }
  2246.     return "0";
  2247. }
  2248.  
  2249. sub is_file_download_in_progress
  2250. {
  2251.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2252.     my ($pid) = &decrypt_param(@_);
  2253.     logger "User requested if download is in progress with pid $pid.";
  2254.     my @pids = `ps -ef`;
  2255.     @pids = grep(/$pid/, @pids);
  2256.     logger "Number of pids for file download: @pids";
  2257.     if (@pids > '0')
  2258.     {
  2259.         return 1;
  2260.     }
  2261.     return 0;
  2262. }
  2263.  
  2264. ### \return 1 If file is uncompressed succesfully.
  2265. ### \return 0 If file does not exist.
  2266. ### \return -1 If file could not be uncompressed.
  2267. sub uncompress_file
  2268. {
  2269.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2270.     return uncompress_file_without_decrypt(decrypt_params(@_));
  2271. }
  2272.  
  2273. sub uncompress_file_without_decrypt
  2274. {
  2275.  
  2276.     # File must include full path.
  2277.     my ($file, $destination) = @_;
  2278.  
  2279.     logger "Uncompression called for file $file to dir $destination.";
  2280.  
  2281.     if (!-e $file)
  2282.     {
  2283.         logger "File $file could not be found for uncompression.";
  2284.         return 0;
  2285.     }
  2286.  
  2287.     if (!-e $destination)
  2288.     {
  2289.         mkpath($destination, {error => \my $err});
  2290.         if (@$err)
  2291.         {
  2292.             logger "Failed to create destination dir $destination.";
  2293.             return 0;
  2294.         }
  2295.     }
  2296.  
  2297.     my $ae = Archive::Extract->new(archive => $file);
  2298.  
  2299.     if (!$ae)
  2300.     {
  2301.         logger "Could not create archive instance for file $file.";
  2302.         return -1;
  2303.     }
  2304.  
  2305.     my $ok = $ae->extract(to => $destination);
  2306.  
  2307.     if (!$ok)
  2308.     {
  2309.         logger "File $file could not be uncompressed.";
  2310.         return -1;
  2311.     }
  2312.  
  2313.     logger "File uncompressed/extracted successfully.";
  2314.     return 1;
  2315. }
  2316.  
  2317. ### \return 1 If files are compressed succesfully.
  2318. ### \return -1 If files could not be compressed.
  2319. sub compress_files
  2320. {
  2321.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2322.     return compress_files_without_decrypt(decrypt_params(@_));
  2323. }
  2324.  
  2325. sub compress_files_without_decrypt
  2326. {
  2327.     my ($files,$destination,$archive_name,$archive_type) = @_;
  2328.  
  2329.     if (!-e $destination)
  2330.     {
  2331.         logger "compress_files: Destination path ( $destination ) could not be found.";
  2332.         return -1;
  2333.     }
  2334.    
  2335.     chdir $destination;
  2336.     my @items = split /\Q\n/, $files;
  2337.     my @inventory;
  2338.     if($archive_type eq "zip")
  2339.     {
  2340.         logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type";
  2341.         my $zip = Archive::Zip->new();
  2342.         foreach my $item (@items) {
  2343.             if(-e $item)
  2344.             {
  2345.                 if (-f $item)
  2346.                 {
  2347.                     $zip->addFile( $item );
  2348.                 }
  2349.                 elsif (-d $item)
  2350.                 {
  2351.                     $zip->addTree( $item, $item );
  2352.                 }
  2353.             }
  2354.         }
  2355.         # Save the file
  2356.         unless ( $zip->writeToFileNamed($archive_name.'.zip') == AZ_OK ) {
  2357.             logger "Write Error at $destination/$archive_name.$archive_type";
  2358.             return -1
  2359.         }
  2360.         logger $archive_type." archive $destination$archive_name.$archive_type created successfully";
  2361.         return 1;
  2362.     }
  2363.     elsif($archive_type eq "tbz")
  2364.     {
  2365.         logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type";
  2366.         my $tar = Archive::Tar->new;
  2367.         foreach my $item (@items) {
  2368.             if(-e $item)
  2369.             {
  2370.                 if (-f $item)
  2371.                 {
  2372.                     $tar->add_files( $item );
  2373.                 }
  2374.                 elsif (-d $item)
  2375.                 {
  2376.                     @inventory = ();
  2377.                     find (sub { push @inventory, $File::Find::name }, $item);
  2378.                     $tar->add_files( @inventory );
  2379.                 }
  2380.             }
  2381.         }
  2382.         # Save the file
  2383.         unless ( $tar->write("$archive_name.$archive_type", COMPRESS_BZIP) ) {
  2384.             logger "Write Error at $destination/$archive_name.$archive_type";
  2385.             return -1
  2386.         }
  2387.         logger $archive_type." archive $destination$archive_name.$archive_type created successfully";
  2388.         return 1;
  2389.     }
  2390.     elsif($archive_type eq "tgz")
  2391.     {
  2392.         logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type";
  2393.         my $tar = Archive::Tar->new;
  2394.         foreach my $item (@items) {
  2395.             if(-e $item)
  2396.             {
  2397.                 if (-f $item)
  2398.                 {
  2399.                     $tar->add_files( $item );
  2400.                 }
  2401.                 elsif (-d $item)
  2402.                 {
  2403.                     @inventory = ();
  2404.                     find (sub { push @inventory, $File::Find::name }, $item);
  2405.                     $tar->add_files( @inventory );
  2406.                 }
  2407.             }
  2408.         }
  2409.         # Save the file
  2410.         unless ( $tar->write("$archive_name.$archive_type", COMPRESS_GZIP) ) {
  2411.             logger "Write Error at $destination/$archive_name.$archive_type";
  2412.             return -1
  2413.         }
  2414.         logger $archive_type." archive $destination$archive_name.$archive_type created successfully";
  2415.         return 1;
  2416.     }
  2417.     elsif($archive_type eq "tar")
  2418.     {
  2419.         logger $archive_type." compression called, destination archive is: $destination$archive_name.$archive_type";
  2420.         my $tar = Archive::Tar->new;
  2421.         foreach my $item (@items) {
  2422.             if(-e $item)
  2423.             {
  2424.                 if (-f $item)
  2425.                 {
  2426.                     $tar->add_files( $item );
  2427.                 }
  2428.                 elsif (-d $item)
  2429.                 {
  2430.                     @inventory = ();
  2431.                     find (sub { push @inventory, $File::Find::name }, $item);
  2432.                     $tar->add_files( @inventory );
  2433.                 }
  2434.             }
  2435.         }
  2436.         # Save the file
  2437.         unless ( $tar->write("$archive_name.$archive_type") ) {
  2438.             logger "Write Error at $destination/$archive_name.$archive_type";
  2439.             return -1
  2440.         }
  2441.         logger $archive_type." archive $destination$archive_name.$archive_type created successfully";
  2442.         return 1;
  2443.     }
  2444.     elsif($archive_type eq "bz2")
  2445.     {
  2446.         logger $archive_type." compression called.";
  2447.         foreach my $item (@items) {
  2448.             if(-e $item)
  2449.             {
  2450.                 if (-f $item)
  2451.                 {
  2452.                     bzip2 $item => "$item.bz2";
  2453.                 }
  2454.                 elsif (-d $item)
  2455.                 {
  2456.                     @inventory = ();
  2457.                     find (sub { push @inventory, $File::Find::name }, $item);
  2458.                     foreach my $relative_item (@inventory) {
  2459.                         bzip2 $relative_item => "$relative_item.bz2";
  2460.                     }
  2461.                 }
  2462.             }
  2463.         }
  2464.         logger $archive_type." archives created successfully at $destination";
  2465.         return 1;
  2466.     }
  2467. }
  2468.  
  2469. sub discover_ips
  2470. {
  2471.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2472.     my ($check) = decrypt_params(@_);
  2473.  
  2474.     if ($check ne "chk")
  2475.     {
  2476.         logger "Invalid parameter '$check' given for discover_ips function.";
  2477.         return "";
  2478.     }
  2479.  
  2480.     my $iplist = "";
  2481.     my $ipfound;
  2482.     my $junk;
  2483.  
  2484.     my @ipraw = `/sbin/ifconfig`;
  2485.     while (<@ipraw>)
  2486.     {
  2487.         chomp;
  2488.         next if $_ !~ /^inet:/ ;
  2489.         logger "Found addr on line: $_";
  2490.         ($junk, $ipfound) = split(":", $_);
  2491.         next if $ipfound eq '';
  2492.         next if $ipfound eq '127.0.0.1';
  2493.  
  2494.         logger "Found an IP $ipfound";
  2495.         $iplist .= "$ipfound,";
  2496.         logger "IPlist is now $iplist";
  2497.     }
  2498.     while (<@ipraw>)
  2499.     {
  2500.         chomp;
  2501.         next if $_ !~ /^addr:/ ;
  2502.         logger "Found addr on line: $_";
  2503.         ($junk, $ipfound) = split(":", $_);
  2504.         next if $ipfound eq '';
  2505.         next if $ipfound eq '127.0.0.1';
  2506.  
  2507.         logger "Found an IP $ipfound";
  2508.         $iplist .= "$ipfound,";
  2509.         logger "IPlist is now $iplist";
  2510.     }
  2511.     chop $iplist;
  2512.     return "$iplist";
  2513. }
  2514.  
  2515. ### Return -1 In case of invalid param
  2516. ### Return 1;content in case of success
  2517. sub mon_stats
  2518. {
  2519.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2520.     my ($mon_stats) = decrypt_params(@_);
  2521.     if ($mon_stats ne "mon_stats")
  2522.     {
  2523.         logger "Invalid parameter '$mon_stats' given for $mon_stats function.";
  2524.         return -1;
  2525.     }
  2526.  
  2527.     my @disk            = `df -hP -x tmpfs`;
  2528.     my $encoded_content = encode_list(@disk);
  2529.     my @uptime          = `uptime`;
  2530.     $encoded_content   .= encode_list(@uptime);
  2531.     return "1;$encoded_content";
  2532. }
  2533.  
  2534. sub exec
  2535. {
  2536.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2537.     my ($command)       = decrypt_params(@_);
  2538.     my @cmdret          = `$command 2>/dev/null`;
  2539.     my $encoded_content = encode_list(@cmdret);
  2540.     return "1;$encoded_content";
  2541. }
  2542.  
  2543. # used in conjunction with the clone_home feature in the web panel
  2544. # this actually does the file copies
  2545. sub clone_home
  2546. {
  2547.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2548.     my ($source_home, $dest_home, $owner) = decrypt_params(@_);
  2549.     my ($time_start, $time_stop, $time_diff);
  2550.     logger "Copying from $source_home to $dest_home...";
  2551.  
  2552.     # check size of source_home, make sure we have space to copy
  2553.     if (!-e $source_home)
  2554.     {
  2555.         logger "ERROR - $source_home does not exist";
  2556.         return 0;
  2557.     }
  2558.     logger "Game home $source_home exists...copy will proceed";
  2559.  
  2560.     # start the copy, and a timer
  2561.     $time_start = time();
  2562.     if (!dircopy("$source_home", "$dest_home"))
  2563.     {
  2564.         $time_stop = time();
  2565.         $time_diff = $time_stop - $time_start;
  2566.         logger
  2567.           "Error occured after $time_diff seconds during copy of $source_home to $dest_home - $!";
  2568.         return 0;
  2569.     }
  2570.     else
  2571.     {
  2572.         $time_stop = time();
  2573.         $time_diff = $time_stop - $time_start;
  2574.         logger
  2575.           "Home clone completed successfully to $dest_home in $time_diff seconds";
  2576.         return 1;
  2577.     }
  2578. }
  2579.  
  2580. # used to delete the game home from the file system when it's removed from the panel
  2581. sub remove_home
  2582. {
  2583.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2584.     my ($home_path_del) = decrypt_params(@_);
  2585.  
  2586.     if (!-e $home_path_del)
  2587.     {
  2588.         logger "ERROR - $home_path_del does not exist...nothing to do";
  2589.         return 0;
  2590.     }
  2591.  
  2592.     secure_path_without_decrypt('chattr-i', $home_path_del);
  2593.     sleep 1 while ( !pathrmdir("$home_path_del") );
  2594.     logger "Deletetion of $home_path_del successful!";
  2595.     return 1;
  2596. }
  2597.  
  2598. sub restart_server
  2599. {
  2600.     chomp(@_);
  2601.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2602.     return restart_server_without_decrypt(decrypt_params(@_));
  2603. }
  2604.  
  2605. ### Restart the server
  2606. ## return -2 CANT STOP
  2607. ## return -1  CANT START (no startup file found that mach the home_id, port and ip)
  2608. ## return 1 Restart OK
  2609. sub restart_server_without_decrypt
  2610. {
  2611.     my ($home_id, $server_ip, $server_port, $control_protocol,
  2612.         $control_password, $control_type, $home_path, $server_exe, $run_dir,
  2613.         $cmd, $cpu, $nice, $preStart, $envVars) = @_;
  2614.  
  2615.     if (stop_server_without_decrypt($home_id, $server_ip,
  2616.                                     $server_port, $control_protocol,
  2617.                                     $control_password, $control_type, $home_path) == 0)
  2618.     {
  2619.         if (universal_start_without_decrypt($home_id, $home_path, $server_exe, $run_dir,
  2620.                                             $cmd, $server_port, $server_ip, $cpu, $nice, $preStart, $envVars) == 1)
  2621.         {
  2622.             return 1;
  2623.         }
  2624.         else
  2625.         {
  2626.             return -1;
  2627.         }
  2628.     }
  2629.     else
  2630.     {
  2631.         return -2;
  2632.     }
  2633. }
  2634.  
  2635. sub sudo_exec
  2636. {
  2637.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2638.     my $sudo_exec = &decrypt_param(@_);
  2639.     return sudo_exec_without_decrypt($sudo_exec);
  2640. }
  2641.  
  2642. sub sudo_exec_without_decrypt
  2643. {
  2644.     my ($sudo_exec) = @_;
  2645.     $sudo_exec =~ s/('+)/'"$1"'/g;
  2646.     my $command = "echo '$SUDOPASSWD'|sudo -kS -p \"\" su -c '$sudo_exec;echo \$?' root 2>&1";
  2647.     my @cmdret = qx($command);
  2648.     chomp(@cmdret);
  2649.     my $ret = pop(@cmdret);
  2650.     chomp($ret);
  2651.     if ("X$ret" eq "X0")
  2652.     {
  2653.         return "1;".encode_list(@cmdret);
  2654.     }
  2655.     return -1;
  2656. }
  2657.  
  2658. sub secure_path
  2659. {
  2660.     chomp(@_);
  2661.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2662.     return secure_path_without_decrypt(decrypt_params(@_));
  2663. }
  2664.  
  2665. sub secure_path_without_decrypt
  2666. {  
  2667.     my ($action, $file_path, $returnType) = @_;
  2668.     my $checkIfFileExists = 1;
  2669.    
  2670.     if(defined $returnType && $returnType eq "str"){
  2671.         $checkIfFileExists = 0;
  2672.     }
  2673.    
  2674.     if($checkIfFileExists){
  2675.         if(! -e $file_path){
  2676.             return -1;
  2677.         }
  2678.     }
  2679.    
  2680.     my $uid = `id -u`;
  2681.     chomp $uid;
  2682.     my $gid = `id -g`;
  2683.     chomp $gid;
  2684.     $file_path =~ s/('+)/'\"$1\"'/g;
  2685.     if($action eq "chattr+i")
  2686.     {
  2687.         if(defined $returnType && $returnType eq "str"){
  2688.             #return 'chown -Rf '.$uid.':'.$gid.' \''.$file_path.'\' && chattr -Rf +i \''.$file_path.'\'';
  2689.         }else{
  2690.             #return sudo_exec_without_decrypt('chown -Rf '.$uid.':'.$gid.' \''.$file_path.'\' && chattr -Rf +i \''.$file_path.'\'');
  2691.         }
  2692.     }
  2693.     elsif($action eq "chattr-i")
  2694.     {
  2695.         if(defined $returnType && $returnType eq "str"){
  2696.             #return 'chattr -Rf -i \''.$file_path.'\' && chown -Rf '.$uid.':'.$gid.' \''.$file_path.'\'';
  2697.         }else{
  2698.             #return sudo_exec_without_decrypt('chattr -Rf -i \''.$file_path.'\' && chown -Rf '.$uid.':'.$gid.' \''.$file_path.'\'');
  2699.         }
  2700.     }
  2701.    
  2702.     return -1;
  2703. }
  2704.  
  2705. sub get_chattr
  2706. {  
  2707.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2708.     my ($file_path) = decrypt_params(@_);
  2709.     my $file = $file_path;
  2710.     $file_path =~ s/('+)/'\"$1\"'/g;
  2711.     return sudo_exec_without_decrypt('(lsattr \''.$file_path.'\' | sed -e "s#'.$file.'##g")|grep -o i');
  2712. }
  2713.  
  2714. sub ftp_mgr
  2715. {
  2716.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  2717.     my ($action, $login, $password, $home_path) = decrypt_params(@_);
  2718.    
  2719.     my $uid = `id -u`;
  2720.     chomp $uid;
  2721.     my $gid = `id -g`;
  2722.     chomp $gid;
  2723.    
  2724.     $login =~ s/('+)/'\"$1\"'/g;
  2725.     $password =~ s/('+)/'\"$1\"'/g;
  2726.     $home_path =~ s/('+)/'\"$1\"'/g;
  2727.    
  2728.     if(!defined($Cfg::Preferences{ogp_manages_ftp}) || (defined($Cfg::Preferences{ogp_manages_ftp}) &&  $Cfg::Preferences{ogp_manages_ftp} eq "1")){
  2729.         if( defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "IspConfig")
  2730.         {
  2731.             use constant ISPCONFIG_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'IspConfig');
  2732.             use constant FTP_USERS_DIR => Path::Class::Dir->new(ISPCONFIG_DIR, 'ftp_users');
  2733.                
  2734.             if (!-d FTP_USERS_DIR && !mkdir FTP_USERS_DIR)
  2735.             {
  2736.                 print "Could not create " . FTP_USERS_DIR . " directory $!.";
  2737.                 return -1;
  2738.             }
  2739.            
  2740.             chdir ISPCONFIG_DIR;
  2741.            
  2742.             if($action eq "list")
  2743.             {
  2744.                 my $users_list;
  2745.                 opendir(USERS, FTP_USERS_DIR);
  2746.                 while (my $username = readdir(USERS))
  2747.                 {
  2748.                     # Skip . and ..
  2749.                     next if $username =~ /^\./;
  2750.                     $users_list .= `php-cgi -f sites_ftp_user_get.php username=\'$username\'`;
  2751.                 }
  2752.                 closedir(USERS);
  2753.                 if( defined($users_list) )
  2754.                 {
  2755.                     return "1;".encode_list($users_list);
  2756.                 }
  2757.             }
  2758.             elsif($action eq "userdel")
  2759.             {
  2760.                 return "1;".encode_list(`php-cgi -f sites_ftp_user_delete.php username=\'$login\'`);
  2761.             }
  2762.             elsif($action eq "useradd")
  2763.             {
  2764.                 return "1;".encode_list(`php-cgi -f sites_ftp_user_add.php username=\'$login\' password=\'$password\' dir=\'$home_path\' uid=$uid gid=$gid`);
  2765.             }
  2766.             elsif($action eq "passwd")
  2767.             {
  2768.                 return "1;".encode_list(`php-cgi -f sites_ftp_user_update.php type=passwd username=\'$login\' password=\'$password\'`);
  2769.             }
  2770.             elsif($action eq "show")
  2771.             {
  2772.                 return "1;".encode_list(`php-cgi -f sites_ftp_user_get.php type=detail username=\'$login\'`);
  2773.             }
  2774.             elsif($action eq "usermod")
  2775.             {
  2776.                 return "1;".encode_list(`php-cgi -f sites_ftp_user_update.php username=\'$login\' password=\'$password\'`);
  2777.             }
  2778.         }
  2779.         elsif(defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "EHCP" && -e "/etc/init.d/ehcp")
  2780.         {
  2781.             use constant EHCP_DIR => Path::Class::Dir->new(AGENT_RUN_DIR, 'EHCP');
  2782.  
  2783.             chdir EHCP_DIR;
  2784.             my $phpScript;
  2785.             my $phpOut;
  2786.            
  2787.             chmod 0777, 'ehcp_ftp_log.txt';
  2788.            
  2789.             # In order to access the FTP files, the vsftpd user needs to be added to the ogp group
  2790.             sudo_exec_without_decrypt("usermod -a -G '$gid' ftp");
  2791.             sudo_exec_without_decrypt("usermod -a -G '$gid' vsftpd");
  2792.            
  2793.             if($action eq "list")
  2794.             {
  2795.                 return "1;".encode_list(`php-cgi -f listAllUsers.php`);
  2796.             }
  2797.             elsif($action eq "userdel")
  2798.             {
  2799.                 $phpScript = `php-cgi -f delAccount.php username=\'$login\'`;
  2800.                 $phpOut = `php-cgi -f syncftp.php`;
  2801.                 return $phpScript;
  2802.             }
  2803.             elsif($action eq "useradd")
  2804.             {
  2805.                 $phpScript = `php-cgi -f addAccount.php username=\'$login\' password=\'$password\' dir=\'$home_path\' uid=$uid gid=$gid`;
  2806.                 $phpOut = `php-cgi -f syncftp.php`;
  2807.                 return $phpScript; 
  2808.             }
  2809.             elsif($action eq "passwd")
  2810.             {
  2811.                 $phpScript = `php-cgi -f updatePass.php username=\'$login\' password=\'$password\'`;
  2812.                 $phpOut = `php-cgi -f syncftp.php`;
  2813.                 return $phpScript ;
  2814.             }
  2815.             elsif($action eq "show")
  2816.             {
  2817.                 return "1;".encode_list(`php-cgi -f showAccount.php username=\'$login\'`);
  2818.             }
  2819.             elsif($action eq "usermod")
  2820.             {
  2821.                 $phpScript = `php-cgi -f updateInfo.php username=\'$login\' password=\'$password\'`;
  2822.                 $phpOut = `php-cgi -f syncftp.php`;
  2823.                 return $phpScript;
  2824.             }
  2825.         }
  2826.         elsif(defined($Cfg::Preferences{ftp_method}) && $Cfg::Preferences{ftp_method} eq "proftpd" && -e $Cfg::Preferences{proftpd_conf_path})
  2827.         {
  2828.             chdir $Cfg::Preferences{proftpd_conf_path};
  2829.             if($action eq "list")
  2830.             {
  2831.                 my $users;
  2832.                 open(PASSWD, 'ftpd.passwd');
  2833.                 while (<PASSWD>) {
  2834.                     chomp;
  2835.                     my($login, $passwd, $uid, $gid, $gcos, $home, $shell) = split(/:/);
  2836.                     $users .= "$login\t$home\n";
  2837.                 }
  2838.                 close(PASSWD);
  2839.                 return "1;".encode_list($users);
  2840.             }
  2841.             elsif($action eq "userdel")
  2842.             {
  2843.                 return sudo_exec_without_decrypt("ftpasswd --passwd --delete-user --name='$login'");
  2844.             }
  2845.             elsif($action eq "useradd")
  2846.             {
  2847.                 return sudo_exec_without_decrypt("echo '$password' | ftpasswd --passwd --name='$login' --home='$home_path' --shell=/bin/false --uid=$uid --gid=$gid --stdin");
  2848.             }
  2849.             elsif($action eq "passwd")
  2850.             {
  2851.                 return sudo_exec_without_decrypt("echo '$password' | ftpasswd --passwd --change-password --name='$login' --stdin");
  2852.             }
  2853.             elsif($action eq "show")
  2854.             {
  2855.                 return 1;
  2856.             }
  2857.             elsif($action eq "usermod")
  2858.             {
  2859.                 return 1;
  2860.             }
  2861.             chdir AGENT_RUN_DIR;
  2862.         }
  2863.         else
  2864.         {
  2865.             if($action eq "list")
  2866.             {
  2867.                 return sudo_exec_without_decrypt("pure-pw list");
  2868.             }
  2869.             elsif($action eq "userdel")
  2870.             {
  2871.                 return sudo_exec_without_decrypt("pure-pw userdel '$login' && pure-pw mkdb");
  2872.             }
  2873.             elsif($action eq "useradd")
  2874.             {
  2875.                 return sudo_exec_without_decrypt("(echo '$password'; echo '$password') | pure-pw useradd '$login' -u $uid -g $gid -d '$home_path' && pure-pw mkdb");
  2876.             }
  2877.             elsif($action eq "passwd")
  2878.             {
  2879.                 return sudo_exec_without_decrypt("(echo '$password'; echo '$password') | pure-pw passwd '$login' && pure-pw mkdb");
  2880.             }
  2881.             elsif($action eq "show")
  2882.             {
  2883.                 return sudo_exec_without_decrypt("pure-pw show '$login'");
  2884.             }
  2885.             elsif($action eq "usermod")
  2886.             {
  2887.                 my $update_account = "pure-pw usermod '$login' -u $uid -g $gid";
  2888.                
  2889.                 my @account_settings = split /[\n]+/, $password;
  2890.                
  2891.                 foreach my $setting (@account_settings) {
  2892.                     my ($key, $value) = split /[\t]+/, $setting;
  2893.                    
  2894.                     if( $key eq 'Directory' )
  2895.                     {
  2896.                         $value =~ s/('+)/'\"$1\"'/g;
  2897.                         $update_account .= " -d '$value'";
  2898.                     }
  2899.                        
  2900.                     if( $key eq 'Full_name' )
  2901.                     {
  2902.                         if(  $value ne "" )
  2903.                         {
  2904.                             $value =~ s/('+)/'\"$1\"'/g;
  2905.                             $update_account .= " -c '$value'";
  2906.                         }
  2907.                         else
  2908.                         {
  2909.                             $update_account .= ' -c ""';
  2910.                         }
  2911.                     }
  2912.                    
  2913.                     if( $key eq 'Download_bandwidth' && $value ne ""  )
  2914.                     {
  2915.                         my $Download_bandwidth;
  2916.                         if($value eq 0)
  2917.                         {
  2918.                             $Download_bandwidth = "\"\"";
  2919.                         }
  2920.                         else
  2921.                         {
  2922.                             $Download_bandwidth = $value;
  2923.                         }
  2924.                         $update_account .= " -t " . $Download_bandwidth;
  2925.                     }
  2926.                    
  2927.                     if( $key eq 'Upload___bandwidth' && $value ne "" )
  2928.                     {
  2929.                         my $Upload___bandwidth;
  2930.                         if($value eq 0)
  2931.                         {
  2932.                             $Upload___bandwidth = "\"\"";
  2933.                         }
  2934.                         else
  2935.                         {
  2936.                             $Upload___bandwidth = $value;
  2937.                         }
  2938.                         $update_account .= " -T " . $Upload___bandwidth;
  2939.                     }
  2940.                    
  2941.                     if( $key eq 'Max_files' )
  2942.                     {
  2943.                         if( $value eq "0" )
  2944.                         {
  2945.                             $update_account .= ' -n ""';
  2946.                         }
  2947.                         elsif( $value ne "" )
  2948.                         {
  2949.                             $update_account .= " -n " . $value;
  2950.                         }
  2951.                         else
  2952.                         {
  2953.                             $update_account .= ' -n ""';
  2954.                         }
  2955.                     }
  2956.                                        
  2957.                     if( $key eq 'Max_size' )
  2958.                     {
  2959.                         if( $value ne "" && $value ne "0" )
  2960.                         {
  2961.                             $update_account .= " -N " . $value;
  2962.                         }
  2963.                         else
  2964.                         {
  2965.                             $update_account .= ' -N ""';
  2966.                         }
  2967.                     }
  2968.                                        
  2969.                     if( $key eq 'Ratio' && $value ne ""  )
  2970.                     {
  2971.                         my($upload_ratio,$download_ratio) = split/:/,$value;
  2972.                        
  2973.                         if($upload_ratio eq "0")
  2974.                         {
  2975.                             $upload_ratio = "\"\"";
  2976.                         }
  2977.                         $update_account .= " -q " . $upload_ratio;
  2978.                        
  2979.                         if($download_ratio eq "0")
  2980.                         {
  2981.                             $download_ratio = "\"\"";
  2982.                         }
  2983.                         $update_account .= " -Q " . $download_ratio;
  2984.                     }
  2985.                    
  2986.                     if( $key eq 'Allowed_client_IPs' )
  2987.                     {
  2988.                         if( $value ne "" )
  2989.                         {
  2990.                             $update_account .= " -r " . $value;
  2991.                         }
  2992.                         else
  2993.                         {
  2994.                             $update_account .= ' -r ""';
  2995.                         }
  2996.                     }
  2997.                                        
  2998.                     if( $key eq 'Denied__client_IPs' )
  2999.                     {
  3000.                         if( $value ne "" )
  3001.                         {
  3002.                             $update_account .= " -R " . $value;
  3003.                         }
  3004.                         else
  3005.                         {
  3006.                             $update_account .= ' -R ""';
  3007.                         }
  3008.                     }
  3009.                    
  3010.                     if( $key eq 'Allowed_local__IPs' )
  3011.                     {
  3012.                         if( $value ne "" )
  3013.                         {
  3014.                             $update_account .= " -i " . $value;
  3015.                         }
  3016.                         else
  3017.                         {
  3018.                             $update_account .= ' -i ""';
  3019.                         }
  3020.                     }
  3021.                                        
  3022.                     if( $key eq 'Denied__local__IPs' )
  3023.                     {
  3024.                         if( $value ne "" )
  3025.                         {
  3026.                             $update_account .= " -I " . $value;
  3027.                         }
  3028.                         else
  3029.                         {
  3030.                             $update_account .= ' -I ""';
  3031.                         }
  3032.                     }
  3033.                    
  3034.                        
  3035.                     if( $key eq 'Max_sim_sessions' && $value ne "" )
  3036.                     {
  3037.                         $update_account .= " -y " . $value;
  3038.                     }
  3039.                    
  3040.                     if ( $key eq 'Time_restrictions'  )
  3041.                     {
  3042.                         if( $value eq "0000-0000")
  3043.                         {
  3044.                             $update_account .= ' -z ""';
  3045.                         }
  3046.                         elsif( $value ne "" )
  3047.                         {
  3048.                             $update_account .= " -z " . $value;
  3049.                         }
  3050.                         else
  3051.                         {
  3052.                             $update_account .= ' -z ""';
  3053.                         }
  3054.                     }
  3055.                 }
  3056.                 $update_account .=" && pure-pw mkdb";
  3057.                 # print $update_account;
  3058.                 return sudo_exec_without_decrypt($update_account);
  3059.             }
  3060.         }
  3061.     }
  3062.     return 0;
  3063. }
  3064.  
  3065. sub start_fastdl
  3066. {
  3067.     if(-e Path::Class::File->new(FD_DIR, 'Settings.pm'))
  3068.     {
  3069.         system('perl FastDownload/ForkedDaemon.pm &');
  3070.         sleep(1);
  3071.         return 1;
  3072.     }
  3073.     else
  3074.     {
  3075.         return -2;
  3076.     }
  3077. }
  3078.  
  3079. sub stop_fastdl
  3080. {
  3081.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3082.     return stop_fastdl_without_decrypt();
  3083. }
  3084.  
  3085. sub stop_fastdl_without_decrypt
  3086. {
  3087.     my $pid;
  3088.     open(PIDFILE, '<', FD_PID_FILE)
  3089.       || logger "Error reading pid file $!",1;
  3090.     while (<PIDFILE>)
  3091.     {
  3092.         $pid = $_;
  3093.         chomp $pid;
  3094.     }
  3095.     close(PIDFILE);
  3096.     my $cnt = kill 9, $pid;
  3097.     if ($cnt == 1)
  3098.     {
  3099.         logger "Fast Download Daemon Stopped.",1;
  3100.         return 1;
  3101.     }
  3102.     else
  3103.     {
  3104.         logger "Fast Download Daemon with pid $pid can not be stopped.",1;
  3105.         return -1;
  3106.     }
  3107. }
  3108.  
  3109. sub restart_fastdl
  3110. {
  3111.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3112.     return restart_fastdl_without_decrypt();
  3113. }
  3114.  
  3115. sub restart_fastdl_without_decrypt
  3116. {
  3117.     if((fastdl_status_without_decrypt() == -1) || (stop_fastdl_without_decrypt() == 1))
  3118.     {
  3119.         if(start_fastdl() == 1)
  3120.         {
  3121.             # Success
  3122.             return 1;
  3123.         }
  3124.         # Cant start
  3125.         return -2;
  3126.     }
  3127.     # Cant stop
  3128.     return -3;
  3129. }
  3130.  
  3131. sub fastdl_status
  3132. {
  3133.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3134.     return fastdl_status_without_decrypt();
  3135. }
  3136.  
  3137. sub fastdl_status_without_decrypt
  3138. {
  3139.     my $pid;
  3140.     if(!open(PIDFILE, '<', FD_PID_FILE))
  3141.     {
  3142.         logger "Error reading pid file $!";
  3143.         return -1;
  3144.     }
  3145.     while (<PIDFILE>)
  3146.     {
  3147.         $pid = $_;
  3148.         chomp $pid;
  3149.     }
  3150.     close(PIDFILE);
  3151.     my $cnt = kill 0, $pid;
  3152.     if ($cnt == 1)
  3153.     {
  3154.         return 1;
  3155.     }
  3156.     else
  3157.     {
  3158.         return -1;
  3159.     }
  3160. }
  3161.  
  3162. sub fastdl_get_aliases
  3163. {
  3164.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3165.     my %aliases;
  3166.     my $i;
  3167.     my @file_lines;
  3168.     if(-d FD_ALIASES_DIR)
  3169.     {
  3170.         if( !opendir(ALIASES, FD_ALIASES_DIR) )
  3171.         {
  3172.             logger "Error openning aliases directory " . FD_ALIASES_DIR . ", $!";
  3173.         }
  3174.         else
  3175.         {
  3176.             while (my $alias = readdir(ALIASES))
  3177.             {
  3178.                 # Skip . and ..
  3179.                 next if $alias =~ /^\./;
  3180.                 if( !open(ALIAS, '<', Path::Class::Dir->new(FD_ALIASES_DIR, $alias)) )
  3181.                 {
  3182.                     logger "Error reading alias '$alias', $!";
  3183.                 }
  3184.                 else
  3185.                 {
  3186.                     $i = 0;
  3187.                     @file_lines = ();
  3188.                     while (<ALIAS>)
  3189.                     {
  3190.                         chomp $_;
  3191.                         $file_lines[$i] = $_;
  3192.                         $i++;
  3193.                     }
  3194.                     close(ALIAS);
  3195.                     $aliases{$alias}{home}                  = $file_lines[0];
  3196.                     $aliases{$alias}{match_file_extension}  = $file_lines[1];
  3197.                     $aliases{$alias}{match_client_ip}       = $file_lines[2];
  3198.                 }
  3199.             }
  3200.             closedir(ALIASES);
  3201.         }
  3202.     }
  3203.     else
  3204.     {
  3205.         logger "Aliases directory '" . FD_ALIASES_DIR . "' does not exist or is inaccessible.";
  3206.     }
  3207.     return {%aliases};
  3208. }
  3209.  
  3210. sub fastdl_del_alias
  3211. {
  3212.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3213.     foreach my $alias (decrypt_params(@_))
  3214.     {
  3215.         unlink Path::Class::File->new(FD_ALIASES_DIR, $alias);
  3216.     }
  3217.     return restart_fastdl_without_decrypt();
  3218. }
  3219.  
  3220. sub fastdl_add_alias
  3221. {
  3222.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3223.     my ($alias,$home,$match_file_extension,$match_client_ip) = decrypt_params(@_);
  3224.     if(!-e FD_ALIASES_DIR)
  3225.     {
  3226.         if(!mkdir FD_ALIASES_DIR)
  3227.         {
  3228.             logger "ERROR - Failed to create " . FD_ALIASES_DIR . " directory.";
  3229.             return -1;
  3230.         }
  3231.     }
  3232.     my $alias_path = Path::Class::File->new(FD_ALIASES_DIR, $alias);
  3233.     if (!open(ALIAS, '>', $alias_path))
  3234.     {
  3235.         logger "ERROR - Failed to open ".$alias_path." for writing.";
  3236.         return -1;
  3237.     }
  3238.     else
  3239.     {
  3240.         print ALIAS "$home\n";
  3241.         print ALIAS "$match_file_extension\n";
  3242.         print ALIAS "$match_client_ip";
  3243.         close(ALIAS);
  3244.         return restart_fastdl_without_decrypt();
  3245.     }
  3246. }
  3247.  
  3248. sub fastdl_get_info
  3249. {
  3250.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3251.     if(-e Path::Class::File->new(FD_DIR, 'Settings.pm'))
  3252.     {
  3253.         delete $INC{"FastDownload/Settings.pm"};
  3254.         require "FastDownload/Settings.pm"; # Settings for Fast Download Daemon.
  3255.         if(not defined $FastDownload::Settings{autostart_on_agent_startup})
  3256.         {
  3257.             $FastDownload::Settings{autostart_on_agent_startup} = 0;
  3258.         }
  3259.         return {'port'                      =>  $FastDownload::Settings{port},
  3260.                 'ip'                        =>  $FastDownload::Settings{ip},
  3261.                 'listing'                   =>  $FastDownload::Settings{listing},
  3262.                 'autostart_on_agent_startup'=>  $FastDownload::Settings{autostart_on_agent_startup}};
  3263.     }
  3264.     return -1
  3265. }
  3266.  
  3267. sub fastdl_create_config
  3268. {
  3269.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3270.     if(!-e FD_DIR)
  3271.     {
  3272.         if(!mkdir FD_DIR)
  3273.         {
  3274.             logger "ERROR - Failed to create " . FD_DIR . " directory.";
  3275.             return -1;
  3276.         }
  3277.     }
  3278.     my ($fd_address, $fd_port, $listing, $autostart_on_agent_startup) = decrypt_params(@_);
  3279.     my $settings_string = "%FastDownload::Settings = (\n".
  3280.                           "\tport  => $fd_port,\n".
  3281.                           "\tip => '$fd_address',\n".
  3282.                           "\tlisting => $listing,\n".
  3283.                           "\tautostart_on_agent_startup => $autostart_on_agent_startup,\n".
  3284.                           ");";
  3285.     my $settings = Path::Class::File->new(FD_DIR, 'Settings.pm');
  3286.     if (!open(SETTINGS, '>', $settings))
  3287.     {
  3288.         logger "ERROR - Failed to open $settings for writing.";
  3289.         return -1;
  3290.     }
  3291.     else
  3292.     {
  3293.         print SETTINGS $settings_string;
  3294.         close(SETTINGS);
  3295.     }
  3296.     logger "$settings file written successfully.";
  3297.     return 1;
  3298. }
  3299.  
  3300. sub agent_restart
  3301. {
  3302.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3303.     my $dec_check = decrypt_param(@_);
  3304.     if ($dec_check eq 'restart')
  3305.     {
  3306.         chdir AGENT_RUN_DIR;
  3307.         if(-e "ogp_agent_run.pid")
  3308.         {
  3309.             my $init_pid    = `cat ogp_agent_run.pid`;
  3310.             chomp($init_pid);
  3311.            
  3312.             if(kill 0, $init_pid)
  3313.             {
  3314.                 my $or_exist    = "";
  3315.                 my $rm_pid_file = "";
  3316.                 if(-e "ogp_agent.pid")
  3317.                 {
  3318.                     $rm_pid_file    = " ogp_agent.pid";
  3319.                     my $agent_pid   = `cat ogp_agent.pid`;
  3320.                     chomp($agent_pid);
  3321.                     if( kill 0, $agent_pid )
  3322.                     {
  3323.                         $or_exist = " -o -e /proc/$agent_pid";
  3324.                     }
  3325.                 }
  3326.                
  3327.                 open (AGENT_RESTART_SCRIPT, '>', 'tmp_restart.sh');
  3328.                 my $restart = "echo -n \"Stopping OGP Agent...\"\n".
  3329.                               "kill $init_pid\n".
  3330.                               "while [ -e /proc/$init_pid $or_exist ];do echo -n .;sleep 1;done\n".
  3331.                               "rm -f ogp_agent_run.pid $rm_pid_file\necho \" [OK]\"\n".
  3332.                               "echo -n \"Starting OGP Agent...\"\n".
  3333.                               "screen -d -m -t \"ogp_agent\" -c \"" . SCREENRC_FILE . "\" -S ogp_agent bash ogp_agent_run -pidfile ogp_agent_run.pid\n".
  3334.                               "while [ ! -e ogp_agent_run.pid -o ! -e ogp_agent.pid ];do echo -n .;sleep 1;done\n".
  3335.                               "echo \" [OK]\"\n".
  3336.                               "rm -f tmp_restart.sh\n".
  3337.                               "exit 0\n";
  3338.                 print AGENT_RESTART_SCRIPT $restart;
  3339.                 close (AGENT_RESTART_SCRIPT);
  3340.                 if( -e 'tmp_restart.sh' )
  3341.                 {
  3342.                     system('screen -d -m -t "agent_restart" -c "' . SCREENRC_FILE . '" -S agent_restart bash tmp_restart.sh');
  3343.                 }
  3344.             }
  3345.         }
  3346.     }
  3347.     return -1;
  3348. }
  3349.  
  3350. # Subroutines to be called
  3351. sub scheduler_dispatcher {
  3352.     my ($task, $args) = @_;
  3353.     my $response = `$args`;
  3354.     chomp($response);
  3355.     my $log = "Executed command: $args";
  3356.     if($response ne "")
  3357.     {
  3358.         $log .= ", response:\n$response";
  3359.     }
  3360.     scheduler_log_events($log);
  3361. }
  3362.  
  3363. sub scheduler_server_action
  3364. {
  3365.     my ($task, $args) = @_;
  3366.     my ($action, @server_args) = split('\|\%\|', $args);
  3367.     if($action eq "%ACTION=start")
  3368.     {
  3369.         my ($home_id, $ip, $port) = ($server_args[0], $server_args[6], $server_args[5]);
  3370.         my $ret = universal_start_without_decrypt(@server_args);
  3371.         if($ret == 1)
  3372.         {
  3373.             scheduler_log_events("Started server home ID $home_id on address $ip:$port");
  3374.         }
  3375.         else
  3376.         {
  3377.             scheduler_log_events("Failed starting server home ID $home_id on address $ip:$port (Check agent log)");
  3378.         }
  3379.     }
  3380.     elsif($action eq "%ACTION=stop")
  3381.     {
  3382.         my ($home_id, $ip, $port) = ($server_args[0], $server_args[1], $server_args[2]);
  3383.         my $ret = stop_server_without_decrypt(@server_args);
  3384.         if($ret == 0)
  3385.         {
  3386.             scheduler_log_events("Stopped server home ID $home_id on address $ip:$port");
  3387.         }
  3388.         elsif($ret == 1)
  3389.         {
  3390.             scheduler_log_events("Failed stopping server home ID $home_id on address $ip:$port (Invalid IP:Port given)");
  3391.         }
  3392.     }
  3393.     elsif($action eq "%ACTION=restart")
  3394.     {
  3395.         my ($home_id, $ip, $port) = ($server_args[0], $server_args[1], $server_args[2]);
  3396.         my $ret = restart_server_without_decrypt(@server_args);
  3397.         if($ret == 1)
  3398.         {
  3399.             scheduler_log_events("Restarted server home ID $home_id on address $ip:$port");
  3400.         }
  3401.         elsif($ret == -1)
  3402.         {
  3403.             scheduler_log_events("Failed restarting server home ID $home_id on address $ip:$port (Server could not be started, check agent log)");
  3404.         }
  3405.         elsif($ret == -2)
  3406.         {
  3407.             scheduler_log_events("Failed restarting server home ID $home_id on address $ip:$port (Server could not be stopped, check agent log)");
  3408.         }
  3409.     }
  3410.     return 1;
  3411. }
  3412.  
  3413. sub scheduler_log_events
  3414. {
  3415.     my $logcmd   = $_[0];
  3416.     $logcmd = localtime() . " $logcmd\n";
  3417.     logger "Can't open " . SCHED_LOG_FILE . " - $!" unless open(LOGFILE, '>>', SCHED_LOG_FILE);
  3418.     logger "Failed to lock " . SCHED_LOG_FILE . "." unless flock(LOGFILE, LOCK_EX);
  3419.     logger "Failed to seek to end of " . SCHED_LOG_FILE . "." unless seek(LOGFILE, 0, 2);
  3420.     logger "Failed to write to " . SCHED_LOG_FILE . "." unless print LOGFILE "$logcmd";
  3421.     logger "Failed to unlock " . SCHED_LOG_FILE . "." unless flock(LOGFILE, LOCK_UN);
  3422.     logger "Failed to close " . SCHED_LOG_FILE . "." unless close(LOGFILE);
  3423. }
  3424.  
  3425. sub scheduler_add_task
  3426. {
  3427.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3428.     my $new_task = decrypt_param(@_);
  3429.     if (open(TASKS, '>>', SCHED_TASKS))
  3430.     {
  3431.         print TASKS "$new_task\n";
  3432.         logger "Created new task: $new_task";
  3433.         close(TASKS);
  3434.         scheduler_stop();  
  3435.         # Create new object with default dispatcher for scheduled tasks
  3436.         $cron = new Schedule::Cron( \&scheduler_dispatcher, {
  3437.                                                 nofork => 1,
  3438.                                                 loglevel => 0,
  3439.                                                 log => sub { print $_[1], "\n"; }
  3440.                                                } );
  3441.  
  3442.         $cron->add_entry( "* * * * * *", \&scheduler_read_tasks );
  3443.         # Run scheduler
  3444.         $cron->run( {detach=>1, pid_file=>SCHED_PID} );
  3445.         return 1;
  3446.     }
  3447.     logger "Cannot create task: $new_task ( $! )";
  3448.     return -1;
  3449. }
  3450.  
  3451. sub scheduler_del_task
  3452. {
  3453.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3454.     my $name = decrypt_param(@_);
  3455.     if( scheduler_read_tasks() == -1 )
  3456.     {
  3457.         return -1;
  3458.     }
  3459.     my @entries = $cron->list_entries();
  3460.     if(open(TASKS, '>', SCHED_TASKS))
  3461.     {
  3462.         foreach my $task ( @entries ) {
  3463.             next if $task->{args}[0] eq $name;
  3464.             next unless $task->{args}[0] =~ /task_[0-9]*/;
  3465.             if(defined $task->{args}[1])
  3466.             {
  3467.                 print TASKS join(" ", $task->{time}, $task->{args}[1]) . "\n";
  3468.             }
  3469.             else
  3470.             {
  3471.                 print TASKS $task->{time} . "\n";
  3472.             }
  3473.         }
  3474.         close( TASKS );
  3475.         scheduler_stop();
  3476.         # Create new object with default dispatcher for scheduled tasks
  3477.         $cron = new Schedule::Cron( \&scheduler_dispatcher, {
  3478.                                                 nofork => 1,
  3479.                                                 loglevel => 0,
  3480.                                                 log => sub { print $_[1], "\n"; }
  3481.                                                } );
  3482.  
  3483.         $cron->add_entry( "* * * * * *", \&scheduler_read_tasks );
  3484.         # Run scheduler
  3485.         $cron->run( {detach=>1, pid_file=>SCHED_PID} );
  3486.         return 1;
  3487.     }
  3488.     logger "Cannot open file " . SCHED_TASKS . " for deleting task id: $name ( $! )",1;
  3489.     return -1;
  3490. }
  3491.  
  3492. sub scheduler_edit_task
  3493. {
  3494.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3495.     my ($name, $new_task) = decrypt_params(@_);
  3496.     if( scheduler_read_tasks() == -1 )
  3497.     {
  3498.         return -1;
  3499.     }
  3500.     my @entries = $cron->list_entries();
  3501.     if(open(TASKS, '>', SCHED_TASKS))
  3502.     {
  3503.         foreach my $task ( @entries ) {
  3504.             next unless $task->{args}[0] =~ /task_[0-9]*/;
  3505.             if($name eq $task->{args}[0])
  3506.             {
  3507.                 print TASKS "$new_task\n";
  3508.             }
  3509.             else
  3510.             {
  3511.                 if(defined $task->{args}[1])
  3512.                 {
  3513.                     print TASKS join(" ", $task->{time}, $task->{args}[1]) . "\n";
  3514.                 }
  3515.                 else
  3516.                 {
  3517.                     print TASKS $task->{time} . "\n";
  3518.                 }
  3519.             }
  3520.         }
  3521.         close( TASKS );
  3522.         scheduler_stop();
  3523.         # Create new object with default dispatcher for scheduled tasks
  3524.         $cron = new Schedule::Cron( \&scheduler_dispatcher, {
  3525.                                                 nofork => 1,
  3526.                                                 loglevel => 0,
  3527.                                                 log => sub { print $_[1], "\n"; }
  3528.                                                } );
  3529.  
  3530.         $cron->add_entry( "* * * * * *", \&scheduler_read_tasks );
  3531.         # Run scheduler
  3532.         $cron->run( {detach=>1, pid_file=>SCHED_PID} );
  3533.         return 1;
  3534.     }
  3535.     logger "Cannot open file " . SCHED_TASKS . " for editing task id: $name ( $! )",1;
  3536.     return -1;
  3537. }
  3538.  
  3539. sub scheduler_read_tasks
  3540. {
  3541.     if( open(TASKS, '<', SCHED_TASKS) )
  3542.     {
  3543.         $cron->clean_timetable();
  3544.     }
  3545.     else
  3546.     {
  3547.         logger "Error reading tasks file $!";
  3548.         scheduler_stop();
  3549.         return -1;
  3550.     }
  3551.    
  3552.     my $i = 0;
  3553.     while (<TASKS>)
  3554.     {  
  3555.         next if $_ =~ /^(#.*|[\s|\t]*?\n)/;
  3556.         my ($minute, $hour, $dayOfTheMonth, $month, $dayOfTheWeek, @args) = split(' ', $_);
  3557.         my $time = "$minute $hour $dayOfTheMonth $month $dayOfTheWeek";
  3558.         if("@args" =~ /^\%ACTION.*/)
  3559.         {
  3560.             $cron->add_entry($time, \&scheduler_server_action, 'task_' . $i++, "@args");
  3561.         }
  3562.         else
  3563.         {
  3564.             $cron->add_entry($time, 'task_' . $i++, "@args");
  3565.         }
  3566.     }
  3567.     close(TASKS);
  3568.     return 1;
  3569. }
  3570.  
  3571. sub scheduler_stop
  3572. {
  3573.     my $pid;
  3574.     if(open(PIDFILE, '<', SCHED_PID))
  3575.     {
  3576.         $pid = <PIDFILE>;
  3577.         chomp $pid;
  3578.         close(PIDFILE);
  3579.         if($pid ne "")
  3580.         {
  3581.             if( kill 0, $pid )
  3582.             {
  3583.                 my $cnt = kill 9, $pid;
  3584.                 if ($cnt == 1)
  3585.                 {
  3586.                     unlink SCHED_PID;
  3587.                     return 1;
  3588.                 }
  3589.             }
  3590.         }
  3591.     }
  3592.     return -1;
  3593. }
  3594.  
  3595. sub scheduler_list_tasks
  3596. {
  3597.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3598.     if( scheduler_read_tasks() == -1 )
  3599.     {
  3600.         return -1;
  3601.     }
  3602.     my @entries = $cron->list_entries();
  3603.     my %entries_array;
  3604.     foreach my $task ( @entries ) {
  3605.         if( defined $task->{args}[1] )
  3606.         {
  3607.             $entries_array{$task->{args}[0]} = encode_base64(join(" ", $task->{time}, $task->{args}[1]));
  3608.         }
  3609.         else
  3610.         {
  3611.             $entries_array{$task->{args}[0]} = encode_base64($task->{time});
  3612.         }
  3613.     }
  3614.     if( %entries_array )
  3615.     {
  3616.         return {%entries_array};
  3617.     }
  3618.     return -1;
  3619. }
  3620.  
  3621. sub get_file_part
  3622. {
  3623.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3624.     my ($file, $offset) = decrypt_params(@_);
  3625.     if (!open(FILE, '<', $file))
  3626.     {
  3627.         logger "ERROR - Can't open file $file for reading.";
  3628.         return -1;
  3629.     }
  3630.    
  3631.     binmode(FILE);
  3632.    
  3633.     if($offset != 0)  
  3634.     {
  3635.         return -1 unless seek FILE, $offset, 0;
  3636.     }
  3637.    
  3638.     my $data = "";
  3639.     my ($n, $buf);
  3640.     my $limit = $offset + 60 * 57 * 1000; #Max 3420Kb (1000 iterations) (top statistics ~ VIRT 116m, RES 47m)
  3641.     while (($n = read FILE, $buf, 60 * 57) != 0 && $offset <= $limit ) {
  3642.         $data .= $buf;
  3643.         $offset += $n;
  3644.     }
  3645.     close(FILE);
  3646.    
  3647.     if( $data ne "" )
  3648.     {
  3649.         my $b64zlib = encode_base64(compress($data,9));
  3650.         return "$offset;$b64zlib";
  3651.     }
  3652.     else
  3653.     {
  3654.         return -1;
  3655.     }
  3656. }
  3657.  
  3658. sub stop_update
  3659. {
  3660.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3661.     my $home_id = decrypt_param(@_);
  3662.     my $screen_id = create_screen_id(SCREEN_TYPE_UPDATE, $home_id);
  3663.     system('screen -S '.$screen_id.' -p 0 -X stuff $\'\003\'');
  3664.     if ($? == 0)
  3665.     {
  3666.         return 0;
  3667.     }
  3668.     return 1
  3669. }
  3670.  
  3671. sub shell_action
  3672. {
  3673.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3674.     my ($action, $arguments) = decrypt_params(@_);
  3675.    
  3676.     if($action eq 'remove_file')
  3677.     {
  3678.         chomp($arguments);
  3679.         unlink($arguments);
  3680.         return "1;";
  3681.     }
  3682.     elsif($action eq 'remove_recursive')
  3683.     {
  3684.         my @items = split(';', $arguments);
  3685.         foreach my $item ( @items ) {
  3686.             chomp($item);
  3687.             if(-d $item)
  3688.             {
  3689.                 pathrmdir($item);
  3690.             }
  3691.             else
  3692.             {
  3693.                 unlink($item);
  3694.             }
  3695.         }
  3696.         return "1;";
  3697.     }
  3698.     elsif($action eq 'create_dir')
  3699.     {
  3700.         chomp($arguments);
  3701.         mkpath($arguments);
  3702.         return "1;";
  3703.     }
  3704.     elsif($action eq 'move')
  3705.     {
  3706.         my($src, $dest) = split(';', $arguments);
  3707.         chomp($src);
  3708.         chomp($dest);
  3709.         if(-d $src)
  3710.         {
  3711.             $dest = Path::Class::Dir->new($dest, basename($src));
  3712.             dirmove($src, $dest);
  3713.         }
  3714.         else
  3715.         {
  3716.             fmove($src, $dest);
  3717.         }
  3718.         return "1;";
  3719.     }
  3720.     elsif($action eq 'copy')
  3721.     {
  3722.         my($src, $dest) = split(';', $arguments);
  3723.         chomp($src);
  3724.         chomp($dest);
  3725.         if(-d $src)
  3726.         {
  3727.             $dest = Path::Class::Dir->new($dest, basename($src));
  3728.             dircopy($src, $dest);
  3729.         }
  3730.         else
  3731.         {
  3732.             fcopy($src, $dest);
  3733.         }
  3734.         return "1;";
  3735.     }
  3736.     elsif($action eq 'touch')
  3737.     {
  3738.         chomp($arguments);
  3739.         open(FH, '>', $arguments);
  3740.         print FH "";
  3741.         close(FH);
  3742.         return "1;";
  3743.     }
  3744.     elsif($action eq 'size')
  3745.     {
  3746.         chomp($arguments);
  3747.         my $size = 0;
  3748.         if(-d $arguments)
  3749.         {
  3750.             find(sub { $size += -s }, $arguments ? $arguments : '.');
  3751.         }
  3752.         else
  3753.         {
  3754.             $size += (stat($arguments))[7];
  3755.         }
  3756.         return "1;" . encode_list($size);
  3757.     }
  3758.     elsif($action eq 'get_cpu_usage')
  3759.     {
  3760.         my %prev_idle;
  3761.         my %prev_total;
  3762.         open(STAT, '/proc/stat');
  3763.         while (<STAT>) {
  3764.             next unless /^cpu([0-9]+)/;
  3765.             my @stat = split /\s+/, $_;
  3766.             $prev_idle{$1} = $stat[4];
  3767.             $prev_total{$1} = $stat[1] + $stat[2] + $stat[3] + $stat[4];
  3768.         }
  3769.         close STAT;
  3770.         sleep 1;
  3771.         my %idle;
  3772.         my %total;
  3773.         open(STAT, '/proc/stat');
  3774.         while (<STAT>) {
  3775.             next unless /^cpu([0-9]+)/;
  3776.             my @stat = split /\s+/, $_;
  3777.             $idle{$1} = $stat[4];
  3778.             $total{$1} = $stat[1] + $stat[2] + $stat[3] + $stat[4];
  3779.         }
  3780.         close STAT;
  3781.         my %cpu_percent_usage;
  3782.         foreach my $key ( keys %idle )
  3783.         {
  3784.             my $diff_idle = $idle{$key} - $prev_idle{$key};
  3785.             my $diff_total = $total{$key} - $prev_total{$key};
  3786.             my $percent = (100 * ($diff_total - $diff_idle)) / $diff_total;
  3787.             $percent = sprintf "%.2f", $percent unless $percent == 0;
  3788.             $cpu_percent_usage{$key} = encode_base64($percent);
  3789.         }
  3790.         return {%cpu_percent_usage};
  3791.     }
  3792.     elsif($action eq 'get_ram_usage')
  3793.     {
  3794.         my($total, $buffers, $cached, $free) = qw(0 0 0 0);
  3795.         open(STAT, '/proc/meminfo');
  3796.         while (<STAT>) {
  3797.             $total   += $1 if /MemTotal\:\s+(\d+) kB/;
  3798.             $buffers += $1 if /Buffers\:\s+(\d+) kB/;
  3799.             $cached  += $1 if /Cached\:\s+(\d+) kB/;
  3800.             $free    += $1 if /MemFree\:\s+(\d+) kB/;
  3801.         }
  3802.         close STAT;
  3803.         my $used = $total - $free - $cached - $buffers;
  3804.         my $percent = 100 * $used / $total;
  3805.         my %mem_usage;
  3806.         $mem_usage{'used'}    = encode_base64($used * 1024);
  3807.         $mem_usage{'total'}   = encode_base64($total * 1024);
  3808.         $mem_usage{'percent'} = encode_base64($percent);
  3809.         return {%mem_usage};
  3810.     }
  3811.     elsif($action eq 'get_disk_usage')
  3812.     {
  3813.         my($total, $used, $free) = split(' ', `df -lP 2>/dev/null|grep "^/dev/.*"|awk '{total+=\$2}{used+=\$3}{free+=\$4} END {print total, used, free}'`);
  3814.         my $percent = 100 * $used / $total;
  3815.         my %disk_usage;
  3816.         $disk_usage{'free'}    = encode_base64($free * 1024);
  3817.         $disk_usage{'used'}    = encode_base64($used * 1024);
  3818.         $disk_usage{'total'}   = encode_base64($total * 1024);
  3819.         $disk_usage{'percent'} = encode_base64($percent);
  3820.         return {%disk_usage};
  3821.     }
  3822.     elsif($action eq 'get_uptime')
  3823.     {
  3824.         open(STAT, '/proc/uptime');
  3825.         my $uptime = 0;
  3826.         while (<STAT>) {
  3827.             $uptime += $1 if /^([0-9]+)/;
  3828.         }
  3829.         close STAT;
  3830.         my %upsince;
  3831.         $upsince{'0'} = encode_base64($uptime);
  3832.         $upsince{'1'} = encode_base64(time - $uptime);
  3833.         return {%upsince};
  3834.     }
  3835.     elsif($action eq 'get_tasklist')
  3836.     {
  3837.         my %taskList;
  3838.         $taskList{'task'} = encode_base64(`ps -Ao user,pid,pcpu,pmem,comm,args --sort=-pcpu | head -n 30`);
  3839.         return {%taskList};
  3840.     }
  3841.     elsif($action eq 'get_timestamp')
  3842.     {
  3843.         return "1;" . encode_list(time);
  3844.     }
  3845.     return 0;
  3846. }
  3847.  
  3848. sub remote_query
  3849. {
  3850.     return "Bad Encryption Key" unless(decrypt_param(pop(@_)) eq "Encryption checking OK");
  3851.     my ($protocol, $game_type, $ip, $c_port, $q_port, $s_port) = decrypt_params(@_);
  3852.     my $command = "which php-cgi 2>&1;echo \$?";
  3853.     my @cmdret = qx($command);
  3854.     chomp(@cmdret);
  3855.     my $ret = pop(@cmdret);
  3856.     chomp($ret);
  3857.     if ("X$ret" ne "X0")
  3858.     {
  3859.         return -1;
  3860.     }
  3861.     my $PHP_CGI = "@cmdret";
  3862.     my $php_query_dir = Path::Class::Dir->new(AGENT_RUN_DIR, 'php-query');
  3863.     if($protocol eq 'lgsl')
  3864.     {
  3865.         chdir($php_query_dir->subdir('lgsl'));
  3866.         my $cmd = $PHP_CGI .
  3867.                 " -f lgsl_feed.php" .
  3868.                 " lgsl_type=" . $game_type .
  3869.                 " ip=" . $ip .
  3870.                 " c_port=" . $c_port .
  3871.                 " q_port=" . $q_port .
  3872.                 " s_port=" . $s_port .
  3873.                 " request=sp";
  3874.         my $response = `$cmd`;
  3875.         chomp($response);
  3876.         chdir(AGENT_RUN_DIR);
  3877.         if($response eq "FAILURE")
  3878.         {
  3879.             return -1;
  3880.         }
  3881.         return encode_base64($response, "");
  3882.     }
  3883.     elsif($protocol eq 'gameq')
  3884.     {
  3885.         chdir($php_query_dir->subdir('gameq'));
  3886.         my $cmd = $PHP_CGI .
  3887.                 " -f gameq_feed.php" .
  3888.                 " game_type=" . $game_type .
  3889.                 " ip=" . $ip .
  3890.                 " c_port=" . $c_port .
  3891.                 " q_port=" . $q_port .
  3892.                 " s_port=" . $s_port;
  3893.         my $response = `$cmd`;
  3894.         chomp($response);
  3895.         chdir(AGENT_RUN_DIR);
  3896.         if($response eq "FAILURE")
  3897.         {
  3898.             return -1;
  3899.         }
  3900.         return encode_base64($response, "");
  3901.     }
  3902.     return -1;
  3903. }
Add Comment
Please, Sign In to add comment