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: //usr/local/cwaf/scripts/cwaf-cli.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 Getopt::Long;
use Data::Dumper;

BEGIN { require '/etc/cwaf/use_lib.pl' if -f '/etc/cwaf/use_lib.pl'; }
use Comodo::CWAF::Main;# qw(%conf do_log get_name create_pid_file test_version);
use Comodo::CWAF::ClientAPI;
use Comodo::CWAF::Platform;
use Comodo::CWAF::Excludes;
use Comodo::CWAF::CatalogUpdate;

no warnings 'redefine';

# redefining functions to get more friendly domain names
sub get_domainlist_redef() {
    my $list = Comodo::CWAF::Platform::get_domainlist();
    $_ =~ s/(:[0-9|]+)// for @$list;
    return $list;
}

sub get_disabled_domainlist_redef {
    my $list = Comodo::CWAF::Excludes::get_disabled_domainlist();
    $_ =~ s/(:[0-9|]+)// for @$list;
    return $list;
}


# steps to run Webmin script
if(&is_webmin()) {
   $ENV{'WEBMIN_CONFIG'} = '/etc/webmin';
   my $var = '/var/webmin';
   chop($var = `cat /etc/webmin/var-path`);
   $ENV{'WEBMIN_VAR'} = $var;

   my $root = &Comodo::CWAF::Webmin::get_webmin_root();
   die "Can't get Webmin root directory. Please check if /etc/webmin/miniserv.conf is present and readable." unless $root;

   chdir($root);
   $0 = "$root/cwaf-cli.pl";
   eval "use WebminCore;";
   &init_config();
}

#Init vars
our (%conf, $pr_name);
my ($var,$command,%opts,$log_file,$domain, $catalog);
my $force_domain = 0;

# Prototypes
sub do_console_log($);

# undef - STDOUT
$pr_name = get_name();
$log_file = "$conf{'log_dir'}/$pr_name.log";
# PID file
$conf{'pid_dir'} = $conf{'cwaf_path'} . '/run';
######################################## BEGIN ####################################
$| = 1;

# open logfile for stderr
#open(LOGFILE, ">/dev/null");

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');
  }
LOGFILE->autoflush(1);

# default values
$domain = 'global';
$catalog = undef;

# set avail arguments
$var = GetOptions(\%opts,'help|h','version|v','loglevel|g=i','domain|d=s','domain_list|l',
'exclude_add|xa=i@{1,}','exclude_del|xd=i@{1,}','exclude_add_cat|xac=s@{1,}',
'exclude_del_cat|xdc=s@{1,}','exclude_add_grp|xag=s@{1,}','exclude_del_grp|xdg=s@{1,}',
'exclude_list|xl','exclude_list_extended|xlx','list_cat|lc','list_grp|lg','force_domain|f',
'enable_domain|de=s@{1,}','disable_domain|dd=s@{1,}','disabled_list|dl',
'gui_start|gstart','gui_stop|gstop');

# check pid file
$var = create_pid_file();
if($var == 0 || $var > 1) {
  print "ERROR: can't create pid file" if($var == 0);
  print "WARN: another process is started ($var)" if($var > 1);
  exit(0);
}

$domain = $opts{'domain'} if( $opts{'domain'} );

# argument --loglevel, -g
if( $opts{'loglevel'} ) {
   if($opts{'loglevel'} > 0 && $opts{'loglevel'} < 12 ) {
      $conf{'debug'} = $opts{'loglevel'};
   } else {
     print "loglevel should be from 1 to 10\n";
     exit(0);
   }
}

# argument --force_domain, -f
if( $opts{'force_domain'} ) {
   $force_domain = 1;
}

# create catalog object if required
if($opts{'exclude_add'} || $opts{'exclude_del'} || $opts{'exclude_add_cat'} || $opts{'exclude_del_cat'} || $opts{'exclude_add_grp'} ||
                           $opts{'exclude_del_grp'} || $opts{'exclude_list'} || $opts{'exclude_list_extended'} || $opts{'list_cat'} || $opts{'list_grp'}) {

# check if rules exists
   if(! &rules_exist()) {
      print "No Comodo rules found. Please download latest ruleset with $conf{'cwaf_path'}/$conf{'updater_bin'} \n";
      exit (1);
   }

  $catalog = Comodo::CWAF::CatalogUpdate->new('yml_path' => $conf{'cwaf_path'}.'/etc/yml',
                                            'cache_path' => $conf{'cwaf_path'}.'/tmp/CACHE',
                                            'verbose' => ( $conf{'debug'} eq 11 ) ? 1 : 0,
                                            'cpanel_log' => 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 "Last available version=".get_available_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 --exclude_add, -xa
elsif( $opts{'exclude_add'} ) {
   my @data;

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }

   my $excludes = $opts{'exclude_add'};
   print "turning off rules:".join(',', @$excludes)."\n";
   print "domain: $domain\n";
   foreach my $ruleid (@$excludes) {
	   	my $rstats = $catalog->find_rule_by('id' => $ruleid);
	   	if(defined($rstats->{'category'}) && defined($rstats->{'group'})) {
		   	my %ex;
		   	$ex{'category'} = $rstats->{'category'};
		   	$ex{'group'} = $rstats->{'group'};
		   	$ex{'id'} = $ruleid;
		   	$ex{'status'} = 0;
		   	push(@data, \%ex);
		}
   }
   
   $var = $catalog->update_exclude_list_by('domain' => $domain, 'data' => \@data);
   unless($var) {
     print "ERROR: ".$catalog->error."\n";
   }

  $domain = undef unless($force_domain);
  my ($status, $errmsg) = create_exclude_list($domain, 1);
  print "ERROR: ".$errmsg."\n" unless($status);
  &fix_permissions();
}

# argument --exclude_del, -xd
elsif( $opts{'exclude_del'} ) {
   my @data;

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }

   my $excludes = $opts{'exclude_del'};
   print "turning on rules:".join(',', @$excludes)."\n";
   print "domain: $domain\n";
   foreach my $ruleid (@$excludes) {
	   	my $rstats = $catalog->find_rule_by('id' => $ruleid);
	   	if(defined($rstats->{'category'}) && defined($rstats->{'group'})) {
		   	my %ex;
		   	$ex{'category'} = $rstats->{'category'};
		   	$ex{'group'} = $rstats->{'group'};
		   	$ex{'id'} = $ruleid;
		   	$ex{'status'} = 1;
		   	push(@data, \%ex);
		}
   }

   $var = $catalog->update_exclude_list_by('domain' => $domain, 'data' => \@data);
   unless($var) {
     print "ERROR: ".$catalog->error."\n";
   }

  $domain = undef unless($force_domain);
  my ($status, $errmsg) = create_exclude_list($domain, 1);
  print "ERROR: ".$errmsg."\n" unless($status);
  &fix_permissions();
}

# argument --exclude_add_cat, -xac
elsif( $opts{'exclude_add_cat'} ) {
   my @data;

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }

   my $excludes = $opts{'exclude_add_cat'};
   print "turning off categories:".join(',', @$excludes)."\n";
   print "domain: $domain\n";
   foreach my $category (@$excludes) {
	   	my $rstats = $catalog->find_category_by('category' => $category);
	   	if(defined($rstats->{'category'})) {
		   	my %ex;
		   	$ex{'category'} = $rstats->{'category'};
		   	$ex{'status'} = 0;
		   	push(@data, \%ex);
		}
   }
   
   $var = $catalog->update_exclude_list_by('domain' => $domain, 'data' => \@data);
   unless($var) {
     print "ERROR: ".$catalog->error."\n";
   }

  $domain = undef unless($force_domain);
  my ($status, $errmsg) = create_exclude_list($domain, 1);
  print "ERROR: ".$errmsg."\n" unless($status);
  &fix_permissions();
}

# argument --exclude_del_cat, -xdc
elsif( $opts{'exclude_del_cat'} ) {
   my @data;

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }

   my $excludes = $opts{'exclude_del_cat'};
   print "turning on categories:".join(',', @$excludes)."\n";
   print "domain: $domain\n";
   foreach my $category (@$excludes) {
	   	my $rstats = $catalog->find_category_by('category' => $category);
	   	if(defined($rstats->{'category'})) {
		   	my %ex;
		   	$ex{'category'} = $rstats->{'category'};
		   	$ex{'status'} = 1;
		   	push(@data, \%ex);
		}
   }

   $var = $catalog->update_exclude_list_by('domain' => $domain, 'data' => \@data);
   unless($var) {
     print "ERROR: ".$catalog->error."\n";
   }

  $domain = undef unless($force_domain);
  my ($status, $errmsg) = create_exclude_list($domain, 1);
  print "ERROR: ".$errmsg."\n" unless($status);
  &fix_permissions();
}

# argument --exclude_add_grp, -xag
elsif( $opts{'exclude_add_grp'} ) {
   my @data;

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }

   my $excludes = $opts{'exclude_add_grp'};
   print "turning off groups:".join(',', @$excludes)."\n";
   print "domain: $domain\n";
   foreach my $group (@$excludes) {
	   	my $rstats = $catalog->find_group_by('group' => $group);
	   	if(defined($rstats->{'category'}) && defined($rstats->{'group'})) {
		   	my %ex;
		   	$ex{'category'} = $rstats->{'category'};
		   	$ex{'group'} = $rstats->{'group'};
		   	$ex{'status'} = 0;
		   	push(@data, \%ex);
		}
   }
   
   $var = $catalog->update_exclude_list_by('domain' => $domain, 'data' => \@data);
   unless($var) {
     print "ERROR: ".$catalog->error."\n";
   }

  $domain = undef unless($force_domain);
  my ($status, $errmsg) = create_exclude_list($domain, 1);
  print "ERROR: ".$errmsg."\n" unless($status);
  &fix_permissions();
}

# argument --exclude_del_grp, -xdg
elsif( $opts{'exclude_del_grp'} ) {
   my @data;

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }

   my $excludes = $opts{'exclude_del_grp'};
   print "turning on groups:".join(',', @$excludes)."\n";
   print "domain: $domain\n";
   foreach my $group (@$excludes) {
	   	my $rstats = $catalog->find_group_by('group' => $group);
	   	if(defined($rstats->{'category'}) && defined($rstats->{'group'})) {
		   	my %ex;
		   	$ex{'category'} = $rstats->{'category'};
		   	$ex{'group'} = $rstats->{'group'};
		   	$ex{'status'} = 1;
		   	push(@data, \%ex);
		}
   }

   $var = $catalog->update_exclude_list_by('domain' => $domain, 'data' => \@data);
   unless($var) {
     print "ERROR: ".$catalog->error."\n";
   }

  $domain = undef unless($force_domain);
  my ($status, $errmsg) = create_exclude_list($domain, 1);
  print "ERROR: ".$errmsg."\n" unless($status);
  &fix_permissions();
}

# argument --exclude_list, -xl
elsif( $opts{'exclude_list'} ) {
   my %out_hash;

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }

   print "list of excluded rules for domain: $domain\n";
   my $exs = $catalog->list_excludes('domain' => $domain);
   foreach my $category (keys %$exs) {
     #print "category: $category\n";
     foreach my $group (keys %{$exs->{$category}}) {
     #print "group: $group\n";
       foreach my $rule_id (keys %{$exs->{$category}->{$group}}) {
         my $rule_parent = $catalog->find_rule_by('id' => $rule_id)->{'parent'};
         if( $rule_id eq $rule_parent ) {
           unless(defined $out_hash{$rule_id}) {
             #print "$rule_id\n";
             $out_hash{$rule_id} = 0;
           }
         }
       } #foreach rule
     } # foreach group
   } # foreach category
  my @output = sort(keys %out_hash);
  print join("\n", @output)."\n";
}

# argument --exclude_list_extended, -xlx
elsif( $opts{'exclude_list_extended'} ) {
   my %out_hash;

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }

   print "list of excluded rules for domain: $domain\n";
   my $exs = $catalog->list_excludes('domain' => $domain);
   foreach my $category (sort keys %$exs) {
     print '-'x 25 ."\n$category (category)\n".'-'x 25 ."\n";
     foreach my $group (sort keys %{$exs->{$category}}) {
     next if ($group eq '_LIST_');
     print "$group (group)\n";
       foreach my $rule_id (sort keys %{$exs->{$category}->{$group}}) {
         my $rule_parent = $catalog->find_rule_by('id' => $rule_id)->{'parent'};
         if( $rule_id eq $rule_parent ) {
#           unless(defined $out_hash{$rule_id}) {
             print "  $rule_id (parent)\n";
#             $out_hash{$rule_id} = 0;
#           }
         } else {
           print "    $rule_id\n";
         }
       } #foreach rule
     } # foreach group
   } # foreach category
  my @output = sort(keys %out_hash);
  print join("\n", @output)."\n";
}

# argument --list_cat, -lc
elsif( $opts{'list_cat'} ) {

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }
   
   print "list of categories for domain: $domain\n";
   my $cats = $catalog->list_category_by('domain' => $domain)->{'list'};
   foreach my $category (sort keys %$cats) {
     my $status;
     $status = ($cats->{$category}->{status} == 1) ? 'ON' : 'OFF';
     printf "%-16s %s\n", $category, $status;
   }

}

# argument --list_grp, -lg
elsif( $opts{'list_grp'} ) {

   if(! &domain_exist($domain)) {
	   print "no domain found $domain\n";
	   exit (1);
   }

   print "list of excluded groups for domain: $domain\n";
   my $cats = $catalog->list_category_by('domain' => $domain)->{'list'};
   foreach my $category (sort keys %$cats) {
     my $status;
     $status = ($cats->{$category}->{status} == 1) ? 'ON' : 'OFF';
     printf "%-17s (%s)\n", $category, $status;
     my $grps = $catalog->list_group_by('category' => $category, 'domain' => $domain)->{'list'};
     foreach my $group (sort keys %$grps) {
       $status = ($grps->{$group}->{status} == 1) ? 'ON' : 'OFF';
       printf "   %-15s %s\n", $group, $status;
     }
   }

}

# argument --enable_domain, -nd
elsif( $opts{'enable_domain'} ) {
   my (%domains_hash, $disabled);

   my $domains = $opts{'enable_domain'};
   print "enabling domains:".join(',', @$domains)."\n";

   #@domains_hash{@$domains} = 0;
   map { $domains_hash{$_} = 0; } @$domains;

   my $prev_disabled = &get_disabled_domainlist();

   foreach my $domn (@$prev_disabled) {
     push(@$disabled, $domn) unless(defined $domains_hash{$domn});
   }

   set_disabled_domainlist($disabled);
   &fix_permissions();
}

# argument --disable_domain, -dd
elsif( $opts{'disable_domain'} ) {
   my (%prev_hash, %all_hash, $disabled);

   my $domains = $opts{'disable_domain'};
   print "disabling domains:".join(',', @$domains)."\n";

   if( $force_domain ) {
      # go straight to domain disabling
      push(@$disabled, @$domains);
   } else {
      # make check if domain exists and not disabled yet
      my $all_domains = &get_domainlist();
      #@all_hash{@$all_domains} = 0;
      map { $all_hash{$_} = 0; } @$all_domains;

      my $prev_disabled = &get_disabled_domainlist();
      #@prev_hash{@$prev_disabled} = 0;
      map { $prev_hash{$_} = 0; } @$prev_disabled;
      push(@$disabled, @$prev_disabled);

      foreach my $domn (@$domains) {
       unless(defined $all_hash{$domn}) {
        print "no domain found: $domn\n";
        next;
       }
        push(@$disabled, $domn) unless(defined $prev_hash{$domn});
      }
   }

   set_disabled_domainlist($disabled);
   &fix_permissions();
}

# argument --disabled_list, -dl
elsif( $opts{'disabled_list'} ) {
   print "list of disabled domains:\n";

   my $domains = &get_disabled_domainlist();
   foreach my $domn (@$domains) {
     print "$domn\n";
   }
}

# argument --domain_list, -l
elsif( $opts{'domain_list'} ) {
   print "list of all domains:\n";

#   if(! &is_webpanel() ) {
#      print "Not available for standalone installation\n";
#   } else {
      my $domains = &get_domainlist();
      foreach my $domn (@$domains) {
        print "$domn\n";
      }
#   }
}

# argument --gui_start, -gstart
elsif( $opts{'gui_start'} ) {
  unless (-e "$conf{'cwaf_path'}/scripts/standalone-gui.pl") { print "GUI script $conf{'cwaf_path'}/scripts/standalone-gui.pl not found\n"; exit (1); }
  unless (-e "$conf{'cwaf_path'}/etc/standalone-gui.conf")   { print "Config file $conf{'cwaf_path'}/etc/standalone-gui.conf not found\n"; exit (1); }
  our ($gui_log, $web_port);
  require "$conf{'cwaf_path'}/etc/standalone-gui.conf";
  my $t_cmd = $conf{'cwaf_path'}.'/scripts/standalone-gui.pl 2>&1 > '.$gui_log.' &';
  system($t_cmd);
  print "Standalone GUI Server starting on port $web_port\n";
  print " Now you can setup SSH tunnel on your client host, for example:\n";
  print ' ssh -N -p <ssh_port> ssh_user@ssh.server.host -L <local_port>:localhost:'.$web_port."\n";
  print " and connect to GUI by accessing http://localhost:<local_port>/manage/\n";
}

# argument --gui_stop, -gstop
elsif( $opts{'gui_stop'} ) {
  unless(-e "$conf{'cwaf_path'}/etc/standalone-gui.conf") { print "Config file $conf{'cwaf_path'}/etc/standalone-gui.conf not found\n"; exit (1); }
  our $gui_pid;
  require "$conf{'cwaf_path'}/etc/standalone-gui.conf";
  my $t_cmd = 'kill -9 $(cat '.$gui_pid.')';
  system($t_cmd);
  print "Standalone GUI Server stopped\n";
}
elsif( $var ) {
  &do_print_help_message; 
  exit(0);
}

##################################### FUNCTIONS ###################################

# &domain_exist()
# check if domain exists
#
# RETURN: 0 or 1
sub domain_exist($) {
   my ($domain) = @_;
   my (%dom_hash);

   return 1 if ($domain eq 'global');
   return 1 if ($force_domain);
   my $all_domains = &get_domainlist();
   #@dom_hash{@$all_domains} = 0;
   map { $dom_hash{$_} = 0; } @$all_domains;
   return defined $dom_hash{$domain};
}

# &rules_exist()
# check if rules exists
#
# RETURN: 0 or 1
sub rules_exist() {
   return get_local_rules_version();
}

# &help_message()
# print help message
#
# RETURN: none
sub do_print_help_message {
my $sgui_msg = is_standalone_gui() ? 
<<SGUI

 Standalone GUI Manager (root required):
  To start Standalone GUI Server please run $conf{'cwaf_path'}/scripts/standalone-gui.pl and follow instructions
SGUI
 : '';
print <<END;
Usage: $0 [arguments]

Arguments:
-h, --help         - this help message
-g, --loglevel     - set loglevel (1 - 10)
-v, --version      - show client version
-l, --domain_list  - show list of domains
-f, --force_domain - apply domain even if it not found

 Exclude rules:
  -d, --domain - set domain for exclude operation (global exclude list if not specified)
  -xa,  --exclude_add [rule_ID1 rule_ID2...]  - add rules to exclude list
  -xac, --exclude_add_cat [cat1 cat2...]      - add categories to exclude list
  -xag, --exclude_add_grp [grp1 grp2...]      - add groups to exclude list
  -xd,  --exclude_del [rule_ID1 rule_ID2...]  - remove rules from exclude list
  -xdc, --exclude_del_cat [cat1 cat2...]      - remove categories from exclude list
  -xdg, --exclude_del_grp [grp1 grp2...]      - remove groups from exclude list
  -xl,  --exclude_list                        - show list of excluded rules
  -xlx, --exclude_list_extended               - show structured list of excluded rules
  -lc,  --list_cat                            - show list of categories
  -lg,  --list_grp                            - show list of groups

 Disable/enable mod_security for domains:
  -dd,  --disable_domain [domain1 domain2...] - disable mod_security for domains
  -de,  --enable_domain [domain1 domain2...]  - enable mod_security for domains
  -dl,  --disabled_list                       - show list of disabled domains
$sgui_msg
END
}

# &do_exit($return_code)
# log "exit"-message and exit
#
# RETURN: none
sub do_exit($) {
  my ($rcode) = @_;
  do_console_log("console process finished!");
  &fix_permissions();
  exit($rcode);
}

# &do_console_log($msg, $level)
# log to console
# log to logfile if $log_flag set
#
# RETURN: none
sub do_console_log($) {
  my ($msg) = @_;
  print("$msg\n");
}