Your IP : 216.73.216.26


Current Path : /opt/cpanel/ea-tomcat100/
Upload File :
Current File : //opt/cpanel/ea-tomcat100/ea-podman-local-dir-setup

#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - ea-podman-local-dir-setup                 Copyright 2022 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

use strict;
use warnings;

package scripts::ea_podman_local_dir_setup;

use File::Path::Tiny ();    # Path::Tiny’s version is overly complicated
use Path::Tiny 'path';
use XML::LibXML ();
use Cwd         ();

run(@ARGV) if !caller;

sub run {
    my ( $host_path, @ports ) = @_;

    die "Must have 2 ports ($host_path) :" . @ports . ":" if @ports != 2;

    return add( $host_path, @ports );
}

################
#### commands ##
################

sub add {
    my ( $host_path, $http_port, $ajp_port ) = @_;

    my ( $user, $homedir ) = ( getpwuid($>) )[ 0, 7 ];

    _bail("$host_path appears to have setup already; aborting so we don’t break anything") if -d $host_path && !_tomcat100_dir_is_empty_or_apps_only($host_path);

    print "Adding a tomcat 10.0 instance for “$user” …\n";

    my $curdir = Cwd::cwd();

    {
        my $orig_umask = umask(0027);

        mkdir $host_path;    # it may exist so don’t check it’s RV
        die "Could not create directory “$host_path”" if !-d $host_path;
        chdir $host_path or die "Could not change into “$host_path”: $!\n";

        for my $dir (qw(conf bin logs run temp webapps/ROOT work/Catalina/localhost/ROOT)) {
            File::Path::Tiny::mk($dir) or die "Could not create directory “$dir”: $!\n";
        }

        system("cp -r /opt/cpanel/ea-tomcat100/user-conf/* conf/");
        system("chmod -R 640 conf/*");

        my $dom = XML::LibXML->load_xml( location => "conf/server.xml", load_ext_dtd => 0, ext_ent_handler => sub { } );
        $dom->findnodes('//Server[@shutdown="SHUTDOWN"]')->shift()->setAttribute( port => -1 );    # disable the shutdown port

        my $ajp_connector_exists = 0;
        for my $conn ( $dom->findnodes("//Server/Service/Connector") ) {

            # hide version exposure
            # Could set `server` in addition to xpoweredBy but:
            #    1. it is a generic value for tomcat 4.1-10.0 so all an attacker can gelan is that it is tomcat
            #    2. if we set it to something else it will be a known value and they will be able to
            #       determine not only that its tomcat but also the version
            $conn->setAttribute( xpoweredBy => "false" );

            # set the ports to the user’s ports
            if ( $conn->getAttribute('protocol') eq 'HTTP/1.1' ) {
                $conn->removeAttribute('redirectPort');
            }
            elsif ( $conn->getAttribute('protocol') eq 'AJP/1.3' ) {
                $conn->setAttribute( port => 8009 );
                $conn->removeAttribute('redirectPort');
                $conn->setAttribute( secretRequired => "false" );

                # don’t listen on just 127.0.0.1 or you can’t do AJP proxy
                # this is normally a undesirable but since its being done in a podman container its ok
                $conn->setAttribute( address => "0.0.0.0" );

                $ajp_connector_exists = 1;
            }
        }

        if ( !$ajp_connector_exists ) {

            # Create <Connector port="8009" protocol="AJP/1.3" xpoweredBy="false"/>
            my $ajp = $dom->createElement('Connector');
            $ajp->setAttribute( port           => 8009 );
            $ajp->setAttribute( protocol       => 'AJP/1.3' );
            $ajp->setAttribute( xpoweredBy     => "false" );
            $ajp->setAttribute( secretRequired => "false" );

            # don’t listen on just 127.0.0.1 or you can’t do AJP proxy
            # this is normally a undesirable but since its being done in a podman container its ok
            $ajp->setAttribute( address => "0.0.0.0" );

            $dom->findnodes('//Server/Service[@name="Catalina"]')->shift()->addChild($ajp);
        }

        my $valve = $dom->createElement("Valve");
        $valve->setAttribute( className      => "org.apache.catalina.valves.ErrorReportValve" );
        $valve->setAttribute( showReport     => "false" );
        $valve->setAttribute( showServerInfo => "false" );
        for my $host ( $dom->findnodes("//Host") ) {

            # hide version exposure: Create a ErrorReportValve w/ showServerInfo and showReport attributes to false
            $host->addChild($valve);

            # Host – autoDeploy, deployOnStartup, unpackWARs, and deployXML false
            #   - FWiW, ASF does exploded deploys instead of ^^^
            $host->setAttribute( autoDeploy      => "false" );
            $host->setAttribute( deployOnStartup => "false" );
            $host->setAttribute( deployXML       => "false" );
            $host->setAttribute( unpackWARs      => "false" );
        }

        _write_dom( "conf/server.xml" => $dom );

        umask($orig_umask);
    }

    chdir $curdir or warn "Could not chdir back to “$curdir”: $!\n";
    print " … done!\n";

    return;
}

###############
#### helpers ##
###############

sub _bail {
    my ($msg) = @_;

    chomp($msg);
    warn "$msg\n";

    exit(1);    # there is no return()ing from this lol
}

sub _write_dom {
    my ( $path, $dom ) = @_;

    # get nicely indented XML (from http://grantm.github.io/perl-libxml-by-example/dom.html#modifying-the-dom)
    for my $node ( $dom->findnodes('//text()') ) {
        $node->parentNode->removeChild($node) unless $node =~ /\S/;
    }

    return path($path)->spew( $dom->toString(1) );
}

sub _tomcat100_dir_is_empty_or_apps_only {
    my ($tomcat100_dir) = @_;
    my @contents = path($tomcat100_dir)->children;
    return 1 if !@contents || ( -d "$tomcat100_dir/webapps" && @contents == 1 );
    return;
}

1;