HEX
Server: Apache/2
System: Linux nexus-01 4.18.0-553.120.1.el8_10.x86_64 #1 SMP Mon Apr 20 18:04:27 EDT 2026 x86_64
User: aglcoke (1118)
PHP: 8.2.31
Disabled: mail,exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Upload Files
File: //proc/1/cwd/usr/local/cwaf/scripts/updater.pl
#!/bin/sh
eval 'if [ -x /usr/local/cpanel/3rdparty/bin/perl ]; then exec /usr/local/cpanel/3rdparty/bin/perl -x -- $0 ${1+"$@"}; else exec /usr/bin/perl -x $0 ${1+"$@"}; fi;'
  if 0;
  
    
#!/usr/bin/perl
#SVN
use strict qw(refs subs);
use warnings;
use IO::Handle;
use File::Path qw(remove_tree);
use File::Find;
use Getopt::Long;

BEGIN { require '/etc/cwaf/use_lib.pl' if -f '/etc/cwaf/use_lib.pl'; }
use Comodo::CWAF::Main;
use Comodo::CWAF::ClientAPI;
use Comodo::CWAF::Excludes;

use POSIX;

no warnings 'redefine';

# prototypes
sub do_console_log($);
sub do_exit($);

#Init vars
our (%conf,$pr_name);
my ($var,$log_file,$tmp_log,$wpanel_flag,%opts);

# LOG file
# undef - STDOUT
# or some path to log file
$log_file = $conf{'log_dir'} . '/' . $conf{'utils_log'};
$tmp_log = $conf{'log_dir'} . '/' . $conf{'updater_log'};
$conf{'pid_dir'} = $conf{'cwaf_path'} . '/run';
######################################## BEGIN ####################################
$| = 1;
# script name for logging
$pr_name = get_name();   

# updater not ran by cpanel, set flag (default value)
$wpanel_flag = 0;

# set avail arguments
$var = GetOptions(\%opts,'help|h','version|v','wpanel|w','directadmin-postinstall|p=s','restore|r' );

# argument --directadmin-postinstall, -p
if( $opts{'directadmin-postinstall'} ) {
  eval "use Comodo::CWAF::Platform";
  eval "use Comodo::CWAF::Excludes";

  #if can't load required modules, exits
  do_error_exit("Can't load required perl modules, exiting") if($@);
  do_error_exit("No DirectAdmin system, exiting") unless (&is_directadmin());

  # if no errors, set wpanel_flag to true.
  $wpanel_flag = 1;  

  # set max debug level & print log to $tmp_log
  unlink($tmp_log) if( -e $tmp_log ); 
  open(LOGFILE, ">>$tmp_log");
  $conf{'debug'} = 10;

  my $file = $opts{'directadmin-postinstall'};
  do_log("Processing rules archive $file",8);
  &do_postdownload($file);
  &do_exit(0);
}

# argument --help, -h
if( $opts{'help'} )       { &do_print_help_message; exit(0); }

# argument --version, -v
elsif( $opts{'version'} ) { 
	print "Plugin version=".get_client_version()."\n";
	print "Installed rules version=".get_local_rules_version()."\n";
	print "Available rules version=".get_remote_rules_version()."\n";
	print "Installed for web platform=".get_web_platform()."\n";
	exit(0); 
}

# argument --wpanel, -w
elsif( $opts{'wpanel'} ) {  
  eval "use Comodo::CWAF::Platform";
  eval "use Comodo::CWAF::Excludes";

  #if can't load required modules, write logs to STDERR
  if($@) { open(LOGFILE, ">&STDERR"); }

  # if no errors, set wpanel_flag to true.
  else	{
    $wpanel_flag = 1;  
  
    # set max debug level & print log to $tmp_log
    unlink($tmp_log) if( -e $tmp_log ); 
    open(LOGFILE, ">>$tmp_log");
    $conf{'debug'} = 10;  
    }
}
# argument --restore, -r
elsif( $opts{'restore'} ) {
  my $restore_complete = 0;
  my ($status, $errmsg) = (0, '');

  if(&make_restore_rules()) {
    ($status, $errmsg) = create_exclude_list(undef,1);
    $restore_complete = $status ? 1 : 0;
  }

  if($restore_complete) {
     do_log("Previous version of rules has been restored", 1);
     do_console_log("Previous version of rules has been restored");
     do_exit(0);
  } else {
     do_log("Restore failed $errmsg", 1);
     do_console_log("Restore failed $errmsg");
     do_exit(1);
  }
}

# if not set any argument
elsif( $var ) {
  # open log handler
  if(defined($log_file)) {
    unless(open(LOGFILE, ">>$log_file")) {
      print STDERR "ERROR: can't open file $log_file\n";
      }
    # redirect errors to /dev/null if debug < 6
    # or redirect errors to logfile
    if(int($conf{'debug'}) < 6) {
      open(DEVNULL, ">/dev/null");
      STDERR->fdopen(\*DEVNULL, 'w');
      }
    else {
      STDERR->fdopen(\*LOGFILE, 'w');
      }
    }
  else {open(LOGFILE, ">&STDERR");}
    }

LOGFILE->autoflush(1);
do_log("debug is ON, level = $conf{'debug'}", 9);
  
# check pid file
do_log("create pid file", 10); 
$var = create_pid_file();

if($var == 0 || $var > 1) {
  do_log("ERROR: can't create pid file", 0) if($var == 0);
  do_log("WARN: another process is started ($var)", 0) if($var > 1);
  &do_exit(0);
  }

# start work        
&main_worker();
##################################### FUNCTIONS ###################################
# &do_exit($return_code)
# log "exit"-message and exit
#
# RETURN: none
sub do_exit($) {
  my ($rcode) = @_;
  # fix permissions for Plesk and DA if ran as root
  &fix_permissions();
  do_log("update process finished!",1);
  do_console_log("update process finished!");
  exit($rcode);
}

# &do_error_exit($exit_msg)
# log exit message and do_exit
#
# RETURN: none
sub do_error_exit {
  my ($msg) = @_;
  $msg = "Update failed. See logs for details." unless(defined($msg));
  do_console_log("$msg\n");
  &do_exit(1);
}

# &do_console_log($msg)
# log to console if $wpanel_flag not set
#
# RETURN: none
sub do_console_log($) {
  my ($msg) = @_;
  print("$msg\n") unless($wpanel_flag);
}

# &restore_rules_broken_update()
# restore previous rules version(if exists), if current rules is broken
#
# RETURN: none
sub restore_rules_broken_update {
	my ($work_dir1,$work_dir2,$new_workdir);
	$work_dir1 = $conf{'cwaf_path'} . '/tmp/rules/workdir1';
	$work_dir2 = $conf{'cwaf_path'} . '/tmp/rules/workdir2';
	# get current working directory
	$new_workdir = get_backupdir();

       do_log('update failed, restoring previous rules version',10);

	# check if backupdir contain rules
	if( ! -e "$new_workdir/rules/rules.dat") {
	  do_log("WARNING: can't revert, no previous rules version",5);
	  return;
	}

	# set new working directory & make new symlink to it
	set_workdir($new_workdir);
	make_symlink($new_workdir);
  }

# &link_userdata()
# link userdata to rules directory if present
#
# RETURN: 0 - if failed or 1 - if OK
sub do_link_userdata {
  my ($rulesdir) = @_;
  
  do_log('link userdata to rules',5);
  my $userdata_dir = "$conf{'cwaf_path'}/etc/userdata";
  mkdir $userdata_dir unless (-d $userdata_dir);
  
  unless( opendir(DIR, $rulesdir ) ) {
    do_log("Can't open rules directory ($rulesdir)",1);
    return 0;
    }

  while(my $file = readdir DIR) {
    next unless($file =~ /^userdata_/);
    # file->userfile if not stored
    rename "$rulesdir/$file", "$userdata_dir/$file" unless( -e "$userdata_dir/$file");
    do_log("rename $rulesdir/$file, $userdata_dir/$file",5) unless( -e "$userdata_dir/$file");
    # delete file in rulesdir if exists
    unlink "$rulesdir/$file" if( -e "$rulesdir/$file");
    do_log("unlink $rulesdir/$file",5) if( -e "$rulesdir/$file");
    # userfile->file if stored
    symlink("$userdata_dir/$file", "$rulesdir/$file") if( -e "$userdata_dir/$file");
    do_log("symlink $userdata_dir/$file, $rulesdir/$file",5) if( -e "$userdata_dir/$file");
  }

  closedir(DIR);

  return 1;
  }

# &main_worker()
#
# RETURN: none                        
sub main_worker	{
  my (%req, %resp);
  my ($md5sum_orig,$dfile,$var,$lver,$rules_dir);

    # fix symlink to exclude yaml
    &do_fix_yaml_links();

    # build path to archive with rules
    $dfile = $conf{'cwaf_path'} . '/tmp/rules.tgz';

    # build request, decide what to do - diff update or new install
    &build_req(\%req,$dfile);

    # if http request failed - exit with return code 1
    unless( get_http_content(\%req,\%resp) )  {
      do_log('HTTP response code: '.$resp{'r_code'},1);      
      do_log('Error reason: '.$resp{'x-error-reason'},1) if($resp{'x-error-reason'});
      do_log("ERROR: can't connect to CWAF rules server",0);
      do_error_exit("ERROR: can't connect to CWAF rules server. See logs for details.");
      }

    # check HTTP return code
    # if OK(200) =>  new version exists, start download
    if($resp{'r_code'} =~ "200") {
      do_log('file has been downloaded successfully: ' . $resp{'filename'},10);

      # check downloaded file
      do_error_exit() unless( check_downloaded_file($dfile,$resp{'md5_orig'}) );

      # post download steps
      &do_postdownload($dfile);

      do_log("update successful",1);
      do_console_log("update successful");

      }
    # Not Modified(304) - installed version is latest
    elsif($resp{'r_code'} =~ "304") {
      do_log('current version is up to date',1);
      do_console_log("current version is up to date");
      do_exit(0);
      }
    # client or server error => exit
    else {
      do_log('ERROR: unknown return code (' . $resp{'r_code'} . '), exit',0);
      do_error_exit('ERROR: unknown return code (' . $resp{'r_code'} . '), exit');
      }

    do_exit(0);
  }

# &help_message()
# print help message
#
# RETURN: none
sub do_print_help_message {
print <<END;
Usage: $0 [arguments]

Arguments:
-h, --help     - this help message
-w, --wpanel   - web panel update mode
-r, --restore  - restore previous rules
-p, --directadmin-postinstall - do postinstall steps on DirectAdmin
-v, --version  - show rules and plugin versions


END
  }

# &build_req($request_HASHREF)
# build request for CWAF rules server
#
# RETURN: none
sub build_req($) {
	my ($req,$dfile) = @_;
	my $lver = get_local_rules_version();

  # build request for download file
  %$req = ( 'url' =>   $conf{'cwaf_url'}, 
                    'post' => {
                    'login'     => $conf{'cwaf_login'},
                    'password'  => $conf{'cwaf_passwd'}, 
                    'client_version' => get_client_version()
                     },
           'content' => [ ':content_file' => $dfile ]
  );

	# if version defined
	if($lver) {
		# Enhancement #54347: Always get latest rules version
		$req->{'post'}{'version'} = get_remote_rules_version();
		$req->{'post'}{'local'} = $lver;
		$req->{'post'}{'act'} = 'download';
		}
	else {
		do_log('rules are not installed, try to install',10);

		# if rules not installed update not need, download full package
		$req->{'post'}{'act'} = 'download';
		}
	}

# &do_cpanel_steps()
# try to restart Apache HTTPD use Cpanel function and re-index CWAF catalog
#
# RETURN: none
sub do_web_panel_steps {
    #update user exclude lists with rules data
	#&update_global_exclude();
    #create exclude lists & reinit scheme
	#&create_exclude_list(undef,1); 

# init restart attempts counter
	for(my $j=1; $j<=3; $j++) {
		if(run_restart_apache()) {
			do_log("successful webserver restart",10);
			last; 
			}
		else {
			do_log("webserver restart failed (try $j)",2);
			
			# restore previous rules after 1st attempt
			&restore_rules_broken_update if($j == 1);
			}
		}

	}

# &do_create_dir(list_ARRAYREF)
# create all directories in list_ARRAYREF
#
# RETURN: 0 - error, 1 - ok
sub do_create_dir($) {
	my ($need_to_create) = @_;
	my ($var,$result);
	
	# if $directory is array, add all it items to @need_to_create array
	if( ref($need_to_create) ne 'ARRAY') {
		do_log("WARN: argument must be array, exit",8);
		return 0;
		}
	
	foreach my $item(@$need_to_create) {
		# if item is directory and readable - skip it
		if(-r $item && -d $item) {
			next;
			}

		# if can't create dir, exit 
		if( system("mkdir -p $item") ) {
			# print more info, if debug=10
			$var = "WARN: can't create directory $item";
			$var .= "($!)" if($conf{'debug'} == 10);
			do_log($var,8);
			return 0;
			}			
		}
	return 1;
	}

# &do_create_backupdir($path_to_directory,$clean_flag)
# create directory scheme and push it to "do_create_dir" funcion
#
# RETURN: none
sub do_create_backupdir($;$) {
	my ($dir,$clean_dir_before_make) = @_;
	my @dirs = ("$dir","$dir/yml","$dir/rules");

	# if set flag, try to clean $dir directory
	if($clean_dir_before_make) {
		return 0  unless( make_dir_clean('all',$dir) );
		}

	# try to create directories
	do_create_dir(\@dirs);

	return 1;
	}


# &set_workdir($path_to_working_directory)
# set current working dir 
#
# RETURN: 1 - ok, 0 - error
sub do_backup_rules($) {
	my ($new_workdir) = @_;
	my $work_dir1 = $conf{'cwaf_path'} . '/tmp/rules/workdir1';
	my $work_dir2 = $conf{'cwaf_path'} . '/tmp/rules/workdir2';

	# try to create directories for new version of rules
	&do_create_backupdir($work_dir1);
	&do_create_backupdir($work_dir2);

	if( my $cur_workdir = get_workdir() ) {
		$$new_workdir = get_backupdir();
    &do_create_backupdir($$new_workdir, 1);
    if( system("cp -fR $cur_workdir/yml/* $$new_workdir/yml/") ) {
      do_log("ERROR: can't copy excludes directory $cur_workdir/yml to $$new_workdir/yml($?)", 1);
      #do_error_exit("can't copy directory $cur_workdir/yml to $$new_workdir/yml($?)"); 
      }
    }
	else {
		$$new_workdir = $work_dir1;
		}

	&set_workdir($$new_workdir);
	&make_symlink($$new_workdir);
	}

# &do_fix_perms($path_to_working_directory)
# fix owner & group for directory
#
# RETURN: 1 - ok, 0 - error
sub do_fix_perms($) {
  my ($dirname) = @_;
  my ($curuid,$curgid,@filelist,$find_dir);
  # get uid & gid of current process

  $curuid = POSIX::getuid();
  $curgid = POSIX::getgid();
  $find_dir = ($dirname =~ /\/$/) ? $dirname : $dirname . "/";
  find sub { push(@filelist,$File::Find::name); }, ($find_dir);

  eval { chown $curuid, $curgid, @filelist; };
  if($@) {
    do_log("WARN: can't change permissions ($!)",8);
    return 0;
    }

  return 1;
  }

# &do_fix_yaml_links($dirname)
# fix links to exclude.yaml before update
#
# RETURN: 1 - ok, 0 - error
sub do_fix_yaml_links() {
    my ($var, $retval);
    $retval = 1;

    # fix symlink for exclude.yml
    if ( -l "$conf{'cwaf_path'}/etc/yml/exclude.yml" ) {
        unlink("$conf{'cwaf_path'}/etc/yml/exclude.yml");
        $var = system("cp -f $conf{'cwaf_path'}/$conf{'rules_dir'}/exclude.yml $conf{'cwaf_path'}/etc/yml/exclude.yml");
        if($var) {
         do_log("ERROR: can't fix symlink for exclude.yaml ($!)",0);
         $retval = 0;
        }
    }
    return $retval;
  }

# &make_yaml_link()
# create symlinks to exclude.yaml
# RETURN: 1 - ok, 0 - error
sub make_yaml_links() {
    unless(-e $conf{'cwaf_path'}.'/etc/yml/scheme.yml') {
        # copy original exclude yaml, only for 1st install
        $var = system("cp -f $conf{'cwaf_path'}/$conf{'rules_dir'}/exclude.yml $conf{'cwaf_path'}/etc/yml");
        if($var) {
            do_log("ERROR: can't copy original exclude.yaml($!)",0);
            }
        }
        # make symlink for scheme.yml
        unlink("$conf{'cwaf_path'}/etc/yml/scheme.yml") if( -e $conf{'cwaf_path'}.'/etc/yml/scheme.yml');
        $var = symlink(&get_workdir()."/rules/scheme.yml", "$conf{'cwaf_path'}/etc/yml/scheme.yml");
        unless($var) {
            do_log("ERROR: can't create symlink for scheme.yaml($!)",0);
            }
}

sub do_postdownload($) {
  my ($dfile) = @_;
  my ($rules_dir, $var);

  unless(defined $dfile) {
    do_log("No downloaded file provided, exiting",0);
    &do_exit(1);
  }

  unless(-e $dfile) {
    do_log("Can't find downloaded rules file, exiting",0);
    &do_exit(1);
  }

  # make rules backup
  do_log("make backup for previous rules version",10);
  do_error_exit() unless ( &do_backup_rules(\$rules_dir) );
  
  do_log("extract rules",10);
  $var = system("tar -zxof $dfile -C $rules_dir/rules");

  # get system() return code
  if($var)  {
    do_log("can't extract rules(error $@)",0);
    do_console_log("can't extract rules(error $@).\nRestoring previous rules version");
    &restore_rules_broken_update;
    }

  # link userdata to rules dir
  &do_link_userdata("$rules_dir/rules");

  # fixing directory permissions
  &do_fix_perms($rules_dir);

  # create yaml links after install
  &make_yaml_links();
  
  # update exclude lists
  &update_global_exclude();

  # if script runned from Cpanel or Plesk, try to restart apache
#  &do_web_panel_steps if($wpanel_flag);
}