Guest User

ogp_agent.pl

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