(null)
     �Æ¿Ç      File not found.
  #   !ˆl–Ðz¾”Jj"TÒ�zàœ¸”Å£Å„"y¿ÀÈ 3å    !#!/usr/local/cpanel/3rdparty/bin/perl

# cpanel - scripts/shrink_modsec_ip_database       Copyright 2022 cPanel, L.L.C.
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

package scripts::shrink_modsec_ip_database;

use strict;
use warnings;
use File::Temp                ();
use Cpanel::PwCache           ();
use Cpanel::FileUtils::Move   ();
use Cpanel::SafetyBits        ();
use Cpanel::SafetyBits::Chown ();
use Cpanel::AccessIds         ();
use Cpanel::SafeRun::Object   ();
use Cpanel::Imports;

our $MODSEC_SDBM_UTIL    = '/usr/sbin/modsec-sdbm-util';
our $DEFAULT_SECDATADIR  = '/var/cpanel/secdatadir';
our @DB_FILE_SUFFIXES    = qw( .pag .dir );                # Database file suffixes used by modsec-sdbm-util
our $NEW_DB_NAME         = 'new_db';                       # This name is hard-coded in modsec-sdbm-util
our $DB_PERMS            = 0640;                           # S_IRUSR | S_IWUSR | S_IRGRP
our $OTHER_EXECUTE_PERMS = 01;                             # S_IXOTH

sub new {
    my ( $pkg, $opts ) = @_;
    my $self = ref($opts) eq 'HASH' ? { %{$opts} } : {};
    bless $self, $pkg;
    return $self;
}

sub as_script {
    my $self = shift;
    logger->die('as_script() is a method call.') unless ref $self eq __PACKAGE__;

    if ( not $ARGV[0] or $ARGV[0] ne '-x' ) {
        my $msg = 'To execute, use the -x flag.';
        logger()->die($msg);
    }

    $self->run();

    return 1;
}

sub run {
    my $self = shift;
    logger->die('run() is a method call.') unless ref $self eq __PACKAGE__;

    return 0 unless $self->_bin_check;    # Bail out early and silently if the util is not installed

    my $databases = $self->_gather_databases();

    while ( my ( $db_path, $uid ) = each %{$databases} ) {
        if ( ( stat($MODSEC_SDBM_UTIL) )[2] & $OTHER_EXECUTE_PERMS ) {    # Can run util as "other" user?
            $self->_shrink_db_as_user( $uid, $db_path );
        }
        else {
            # Will have to settle for doing this as root.
            $self->_shrink_db( $uid, $db_path );
        }
    }
    return;
}

sub _bin_check {
    return -x $MODSEC_SDBM_UTIL ? 1 : 0;
}

sub _gather_databases {

    # All files that belong to the same database and that match @DB_FILE_SUFFIXES will need to have the same file owner or that database will not be in the final output
    my $self = shift;
    logger->die('_gather_databases() is a method call.') unless ref $self eq __PACKAGE__;

    return $self->{'databases'} if defined $self->{'databases'};

    my $secdatadir = $self->_secdatadir();

    my %databases;

    if ( opendir( my $dir_fh, $secdatadir ) ) {
      FILE: while ( my $filename = readdir($dir_fh) ) {
          SUFFIX: for my $suffix (@DB_FILE_SUFFIXES) {
                if ( $filename =~ m{ \A (.*) \Q$suffix\E \Z }xms ) {
                    my $short_name = $1;    # Filename without suffix

                    my $db_path = $secdatadir . '/' . $short_name;    # Database path name suitable for passing to modsec-sdbm-util
                    next FILE if exists $databases{$db_path};         # Move along if this belongs to a database already in the collection

                    my $owner = $self->_validate_database_files_owner($db_path);    # Check if there is a full set of files for this database path

                    if ( $self->_allowed_owner($owner) ) {
                        $databases{$db_path} = $owner;                              # Verified, add it to the collection
                        next FILE;
                    }

                }
            }
        }
        closedir($dir_fh);
    }
    return $self->{'databases'} = \%databases;
}

sub _shrink_db_as_user {
    my ( $self, $uid, $db_path ) = @_;
    logger->die('_shrink_db_as_user() is a method call.')                  unless ref $self eq __PACKA