asda?‰PNG  IHDR ? f ??C1 sRGB ??é gAMA ±? üa pHYs ? ??o¨d GIDATx^íüL”÷e÷Y?a?("Bh?_ò???¢§?q5k?*:t0A-o??¥]VkJ¢M??f?±8\k2íll£1]q?ù???T pre_transaction/ea-__WILDCARD__/001-ensure-nobody000075500000004261151027703750015336 0ustar00#!/usr/bin/perl use strict; use warnings; system("touch /etc/systemd/dont-synthesize-nobody") if -d "/etc/systemd"; my $uid = getpwnam("nobody"); my $gid = getgrnam("nobody"); my @ids = ( 65534, 99 ); my $user_needs_informed = 0; if ( !defined $gid ) { $user_needs_informed = 1; my $addgroup = -x '/usr/sbin/groupadd' ? "groupadd" : "addgroup"; for my $id (@ids) { system("$addgroup --system --gid $id nobody"); $gid = getgrnam("nobody"); last if defined $gid; } if ( !defined $gid ) { system("$addgroup --system nobody"); } $gid = getgrnam("nobody"); die "Could not ensure `nobody` group\n" if !defined $gid; } if ( !defined $uid ) { $user_needs_informed = 1; my $flags = -x '/usr/sbin/groupadd' ? "" : "--disabled-password --disabled-login"; for my $id (@ids) { system("adduser --system --uid $id --gid $gid --home / --no-create-home --shell /sbin/nologin $flags nobody"); $uid = getpwnam("nobody"); last if defined $uid; } if ( !defined $uid ) { system("adduser --system --gid $gid --home / --no-create-home --shell /sbin/nologin $flags nobody"); } $uid = getpwnam("nobody"); die "Could not ensure `nobody` user\n" if !defined $uid; } # if already done, its a noop. adduser’s --gid does not make this happen system("usermod -g $gid nobody"); my $home = ( getpwnam("nobody") )[7]; if ( !-d $home ) { # We do not want to create it for them in case there are other implications in /nonexistent existing. # We can’t `usermod --home / nobody` for them because we’d have to hard stop all nobody processes first. my $sep = "#" x 42; print <<"END_HOMEDIR"; $sep [WARN] Detected non-existent home directory for `nobody`. This situation can result in some harmless STDERR going to your web server’s error log as errors. If you experience this your options are: 1. Ignore the log entries 2. Create the directory “$home” if it is safe to do so. 3. Change the `nobody` user’s home directory to one that exists. e.g. `usermod --home / nobody` $sep END_HOMEDIR } print "[INFO] `nobody` user created with UID $uid and GID $gid\n" if $user_needs_informed; transaction/ea-__WILDCARD__nginx__WILDCARD__/007-restartsrv_nginx000075500000004557151027703750020311 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # cpanel - SOURCES/007-restatsrv_nginx Copyright 2021 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 ea_nginx::SOURCES::restartsrv_nginx; use strict; use warnings; use Cpanel::AppPort (); run(@ARGV) unless caller(); =head1 DESCRIPTION Ensure nginx is able to bind to port 80/443 by forcing apache to release them if necessary =cut sub run { my $stopped_apache = 0; if ( _is_listening_on_80_or_443('httpd') ) { print "Stopping apache …\n"; system('/usr/local/cpanel/scripts/restartsrv_httpd --stop'); $stopped_apache = 1; } # Ensure apache stops before continuing if ($stopped_apache) { print "Waiting on apache to fully stop before continuing …\n"; my $httpd_is_listening = 0; for ( 1 .. 5 ) { $httpd_is_listening = _is_listening_on_80_or_443('httpd'); last unless $httpd_is_listening; select( undef, undef, undef, 0.25 ); } die "Apache is still bound to ports 80/443\n" if $httpd_is_listening; } # hard restart here in order to ensure that the new binary is used # in the event that this is an nginx upgrade print "Starting nginx …\n"; system('/usr/local/cpanel/scripts/restartsrv_nginx --hard'); print "Waiting on nginx to come up …\n"; my $nginx_is_listening = 0; for ( 1 .. 5 ) { $nginx_is_listening = _is_listening_on_80_or_443('nginx'); last if $nginx_is_listening; select( undef, undef, undef, 0.25 ); } die "Nginx was unable to start\n" unless $nginx_is_listening; print "Starting apache …\n"; system('/usr/local/cpanel/scripts/restartsrv_httpd --start'); print "… done\n"; return 0; } sub _is_listening_on_80_or_443 { my ($service) = @_; die "_is_listening_on_80_or_443: service arg is required\n" unless $service; my @ports = ( 80, 443, ); my $app_pid_ref = Cpanel::AppPort::get_pids_bound_to_ports( \@ports ); foreach my $pid ( keys %$app_pid_ref ) { return 1 if $app_pid_ref->{$pid}{process} =~ /^\Q$service\E|\/\Q$service\E/; } return 0; } 1; transaction/ea-__WILDCARD__/011-modsec_cpanel_conf_init000075500000000135151027703750016520 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl exec '/usr/local/cpanel/bin/modsec_cpanel_conf_init'; transaction/ea-__WILDCARD__/300-fixmailman.pl000075500000003412151027703750014435 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # cpanel - SOURCES/300-fixmailman.pl Copyright(c) 2016 cPanel, Inc. # All Rights Reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited package ea_apache24_config_runtime::SOURCES::300_fixmailman; use strict; use warnings; use Cpanel::Mailman::Perms (); use Cpanel::SafeRun::Simple (); use Cpanel::Daemonizer::Tiny (); our @Steps = ( { name => 'Fix mailman package directories', code => \&fix_pkg_dirs, }, { name => 'Fix mailing list perms', code => \&fix_list_dirs, }, ); # Fixes the mailing list archive directories based on Apache environment sub fix_list_dirs { my $script = '/usr/local/cpanel/scripts/fixmailman'; Cpanel::SafeRun::Simple::saferun($script) if -x $script; return 1; # it doesn't return a proper exit code on success, so we ignore it } # Fixes the permissions of the core mailman directories... # because this used to installed without a package on systems < 11.57 sub fix_pkg_dirs { my $perm = Cpanel::Mailman::Perms->new(); $perm->set_perms(); # this always assumes success, so no point in checking retval return 1; } sub main { my $argv = shift; for my $step (@Steps) { print "$step->{name} …\n"; my $pid = Cpanel::Daemonizer::Tiny::run_as_daemon( sub { $0 = $step->{name}; $step->{code}->($argv); return; # nobody is listening } ); print " … PID $pid\n"; } return 0; } exit( __PACKAGE__->main( \@ARGV ) ) unless caller(); 1; __END__ transaction/ea-__WILDCARD__/030-update-apachectl000075500000000132151027703750015076 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl exec '/usr/local/cpanel/scripts/update_apachectl'; transaction/ea-__WILDCARD__/500-restartsrv_httpd000075500000004666151027703750015336 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # Copyright (c) 2023, cPanel, L.L.C. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package ea_apache24_config_runtime::SOURCES::restartsrv_httpd; use strict; use warnings; our $disable_flag_file = '/var/cpanel/ea4-disable-500-restartsrv_httpd-for-glibc'; run(@ARGV) unless caller(); sub run { my @args = @_; my ($path) = map( { m/^--pkg_list=(.*)$/ ? ($1) : () } @args ); my $hard_restart = 0; if ( defined $path && -e $path ) { if ( open( my $fh, '<', $path ) ) { my @lines = <$fh>; close($fh); if ( grep { m/^ea-apache24$/ || m/^ea-apache24-mod[_\-]/ } @lines ) { $hard_restart = 1; } } else { warn "Failed to open “$path”: $!\n"; $hard_restart = 1; # err on the side of caution } } if( $0 =~ m{glibc-restartsrv_httpd$} ) { return 0 if -e $disable_flag_file; $hard_restart = 1 } if ($hard_restart) { system('/usr/local/cpanel/scripts/restartsrv_httpd --stop'); system('/usr/local/cpanel/scripts/restartsrv_httpd'); } else { system('/usr/local/cpanel/scripts/restartsrv_httpd'); } } 1; transaction/ea-__WILDCARD__/400-patch_mod_security2.pl000075500000007443151027703750016270 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # Copyright (c) 2016, cPanel, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use warnings; use Cpanel::FileUtils; use Cpanel::Version::Compare; use File::Copy; use Whostmgr::Version; use Whostmgr::ModSecurity; print "Aligning modsec config to Whostmgr\n"; my $whm_version = Whostmgr::Version::getversion(); print "- Whostmgr version $whm_version\n"; if ( !supports_new_location($whm_version) ) { print "- Whostmgr supports conf.d location only\n"; print "- Migrating modsec2 files to conf.d\n"; unmigrate_modsec2_config_move(); } else { print "- Whostmgr supports conf.d/modsec location\n"; print "- No change necessary\n"; } exit 0; sub supports_new_location { my $version = shift; # explicit returns because we will need to add more conditions as we backport # the WHM UI interface to each particular version. # # Future lines should look like: # return 1 if ( Cpanel::Version::Compare::compare....( $version, '>=', 'version guaranteed to have backport' ) ); return 1 if ( Cpanel::Version::Compare::compare_major_release( $version, '>=', '11.58' ) ); return 0; } sub unmigrate_modsec2_config_move { my $config_prefix = Whostmgr::ModSecurity::config_prefix(); print "- moving $config_prefix/modsec/modsec2.cpanel.conf $config_prefix/modsec2.cpanel.conf\n"; File::Copy::move( "$config_prefix/modsec/modsec2.cpanel.conf", "$config_prefix/modsec2.cpanel.conf" ); print "- moving $config_prefix/modsec/modsec2.cpanel.conf.PREVIOUS $config_prefix/modsec2.cpanel.conf.PREVIOUS\n"; File::Copy::move( "$config_prefix/modsec/modsec2.cpanel.conf.PREVIOUS", "$config_prefix/modsec2.cpanel.conf.PREVIOUS" ); print "- moving $config_prefix/modsec/modsec2.user.conf $config_prefix/modsec2.user.conf\n"; File::Copy::move( "$config_prefix/modsec/modsec2.user.conf", "$config_prefix/modsec2.user.conf" ); print "- moving $config_prefix/modsec/modsec2.user.conf.PREVIOUS $config_prefix/modsec2.user.conf.PREVIOUS\n"; File::Copy::move( "$config_prefix/modsec/modsec2.user.conf.PREVIOUS", "$config_prefix/modsec2.user.conf.PREVIOUS" ); print "- removing modsec2.cpanel.conf include in $config_prefix/modsec2.conf\n"; Cpanel::FileUtils::regex_rep_file( "$config_prefix/modsec2.conf", { qr{^\s*Include\s+.*/modsec/modsec2\.cpanel\.conf\s*} => "" } ); print "- removing modsec2.user.conf include in $config_prefix/modsec2.conf\n"; Cpanel::FileUtils::regex_rep_file( "$config_prefix/modsec2.conf", { qr{^\s*Include\s+.*/modsec/modsec2\.user\.conf\s*} => "" } ); return 1; } transaction/ea-__WILDCARD__/520-enablefileprotect000075500000000226151027703750015371 0ustar00#!/bin/bash if [[ -e /var/cpanel/fileprotect ]] then /usr/local/cpanel/scripts/enablefileprotect else /usr/local/cpanel/scripts/disablefileprotect fi transaction/ea-__WILDCARD__/020-rebuild-httpdconf000075500000000132151027703750015306 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl exec '/usr/local/cpanel/scripts/rebuildhttpdconf'; transaction/ea-__WILDCARD__/009-phpconf.pl000075500000046167151027703750013771 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # Copyright (c) 2015, cPanel, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package ea_apache2_config::phpconf; use strict; use Cpanel::Imports; use Cpanel::PackMan (); use Try::Tiny; use Cpanel::ConfigFiles::Apache (); use Cpanel::Config::LoadUserDomains (); use Cpanel::Config::LoadCpUserFile (); use Cpanel::Exception (); use Cpanel::WebServer::Userdata (); use Cpanel::DataStore (); use Cpanel::EA4::Util (); use Cpanel::Notify (); use Cpanel::ProgLang (); use Cpanel::WebServer (); use Getopt::Long (); use POSIX qw( :sys_wait_h ); our @PreferredHandlers = qw( suphp dso cgi ); our $cpanel_default_php_pkg = "ea-php" . Cpanel::EA4::Util::get_default_php_version(); $cpanel_default_php_pkg =~ s/\.//g; my ( $php, $server ); sub debug { my $cfg = shift; my $t = localtime; print "[$t] DEBUG: @_\n" if $cfg->{args}->{debug}; } sub is_handler_supported { my ( $handler, $package ) = @_; $php ||= Cpanel::ProgLang->new( type => 'php' ); $server ||= Cpanel::WebServer->new()->get_server( type => 'apache' ); my $ref = $server->get_available_handlers( lang => $php, package => $package ); return 1 if $ref->{$handler}; return 0; } sub send_notification { my ( $package, $language, $webserver, $missing_handler, $replacement_handler ) = @_; my %args = ( class => q{EasyApache::EA4_LangHandlerMissing}, application => q{universal_hook_phpconf}, constructor_args => [ package => $package, language => $language, webserver => $webserver, missing_handler => $missing_handler || 'UNDEFINED', replacement_handler => $replacement_handler ], ); # No point in catching the failure since we can't do anything # about here anyways. try { my $class = Cpanel::Notify::notification_class(%args); waitpid( $class->{'_icontact_pid'}, WNOHANG ); }; return 1; } sub get_preferred_handler { my $package = shift; my $cfg = shift; my $old_handler = $cfg->{$package} || $PreferredHandlers[0]; my $new_handler; if ( is_handler_supported( $old_handler, $package ) ) { $new_handler = $old_handler; } else { for my $handler (@PreferredHandlers) { last if $new_handler; $new_handler = $handler if is_handler_supported( $handler, $package ); } } if ( !$new_handler ) { my $def = Cpanel::EA4::Util::get_default_php_handler(); logger->info("Could not find a handler for $package. Defaulting to “$def” so that, at worst case, we get an error instead of source code."); $new_handler = $def; } return $new_handler; } # EA-3819: The cpanel api calls depend on php.conf having all known packages # to be in php.conf. This will update php.conf with some temporary # values just in case they're missing. This will also remove entries # if they no longer installed. sub sanitize_php_config { my $cfg = shift; my $prog = shift; return 1 unless scalar @{ $cfg->{packages} }; # The %save hash is used to ensure cpanel has a basic php.conf that will # not break the MultiPHP EA4 code if a package or handler is removed # from the system while it's configured. It will iterate over all # possible handler attempting to find a suitable (and supported) # handler. It will resort to the Cpanel::EA4::Util::get_default_php_handler() handler if nothing else # is supported. # # Finally, the cfg_ref hash is what this applications uses to update # packages/handlers to a "preferred" one if the current is missing or # no longer installed. my %save = %{ $cfg->{cfg_ref} }; my $default = delete $cfg->{cfg_ref}{default}; # remove packages which are no longer installed for my $pkg ( keys %{ $cfg->{cfg_ref} } ) { unless ( grep( /\A\Q$pkg\E\z/, @{ $cfg->{packages} } ) ) { delete $cfg->{cfg_ref}->{$pkg}; delete $save{$pkg}; } } # add packages which are newly installed and at least make sure it's a valid handler for my $pkg ( @{ $cfg->{packages} } ) { $save{$pkg} = get_preferred_handler( $pkg, \%save ); } # make sure the default package has been assigned if ( !defined $default ) { my @packages = sort @{ $cfg->{packages} }; # if we have $cpanel_default_php_pkg use that, otherwise use the latest that is installed $default = grep( { $_ eq $cpanel_default_php_pkg } @packages ) ? $cpanel_default_php_pkg : $packages[-1]; } $save{default} = $default; # and only allow a single dso handler, set the rest to Cpanel::EA4::Util::get_default_php_handler() !$cfg->{args}{dryrun} && $prog->set_conf( conf => \%save ); return 1; } # Retrieves current PHP sub get_php_config { my $argv = shift || []; my %cfg = ( packages => [], args => { dryrun => 0, debug => 0 } ); Getopt::Long::Configure(qw( pass_through )); # not sure if we're passed any args by the universal hooks plugin Getopt::Long::GetOptionsFromArray( $argv, dryrun => \$cfg{args}{dryrun}, debug => \$cfg{args}{debug}, ); my $apacheconf = Cpanel::ConfigFiles::Apache->new(); eval { require Cpanel::ProgLang; require Cpanel::ProgLang::Conf; }; # Need to use the old API, not new one if ($@) { $cfg{api} = 'old'; $cfg{apache_path} = $apacheconf->file_conf_php_conf(); $cfg{cfg_path} = $cfg{apache_path} . '.yaml'; try { require Cpanel::Lang::PHP::Settings; my $php = Cpanel::Lang::PHP::Settings->new(); $cfg{php} = $php; $cfg{packages} = $php->php_get_installed_versions(); $cfg{cfg_ref} = Cpanel::DataStore::fetch_ref( $cfg{cfg_path} ); }; } else { # get basic information in %cfg in case php isn't installed my $prog = Cpanel::ProgLang::Conf->new( type => 'php' ); $cfg{api} = 'new'; $cfg{apache_path} = $apacheconf->file_conf_php_conf(); # hack until we can add this API to Cpanel::WebServer $cfg{cfg_path} = $prog->get_file_path(); try { my $php = Cpanel::ProgLang->new( type => 'php' ); # this will die if PHP isn't installed $cfg{php} = $php; $cfg{packages} = $php->get_installed_packages(); $cfg{cfg_ref} = $prog->get_conf(); }; sanitize_php_config( \%cfg, $prog ); } return \%cfg; } sub get_rebuild_settings { my $cfg = shift; my $ref = $cfg->{cfg_ref}; my %settings; return {} unless @{ $cfg->{packages} }; my $php = $cfg->{php}; # We can't assume that suphp will always be available for each package. # This will iterate over each package and verify that the handler is # installed. If it's not, then revert to the Cpanel::EA4::Util::get_default_php_handler() handler, # which should be installed (if it is 'cgi' then it is available by default). for my $package ( @{ $cfg->{packages} } ) { my $old_handler = $ref->{$package} || ''; my $new_handler = get_preferred_handler( $package, $ref ); if ( $old_handler ne '' && $old_handler ne $new_handler ) { print locale->maketext(q{WARNING: You removed a configured [asis,Apache] handler.}), "\n"; print locale->maketext( q{The “[_1]” package will revert to the “[_2]”[comment,the web server handler that will be used in its place (e.g. cgi)] “[_3]” handler.}, $package, 'Apache', $new_handler ), "\n"; $cfg->{args}->{dryrun} && send_notification( $package, 'PHP', 'Apache', $old_handler, $new_handler ); } $settings{$package} = $new_handler; } if ( $cfg->{api} eq 'old' ) { my $cur_sys_default = eval { $php->php_get_system_default_version() }; $settings{phpversion} = _ensure_default_key_is_valid( $cur_sys_default => $cfg ); } else { my $cur_sys_default = $php->get_system_default_package(); $settings{default} = _ensure_default_key_is_valid( $cur_sys_default => $cfg ); } return \%settings; } sub _ensure_default_key_is_valid { my ( $cur_sys_default, $cfg ) = @_; $cur_sys_default = undef if !$cur_sys_default || !grep { $cur_sys_default eq $_ } @{ $cfg->{packages} }; my $def = $cur_sys_default || Cpanel::EA4::Util::get_default_php_version(); if ( $def =~ m/\./ ) { $def = "ea-php$def"; $def =~ s/\.//g; } my $def_hr = Cpanel::PackMan->instance->pkg_hr($def) || {}; $def = $cfg->{packages}[-1] if !$def_hr->{version_installed}; return $def; } sub apply_rebuild_settings { my $cfg = shift; my $settings = shift; if ( $#{ $cfg->{packages} } == -1 ) { debug( $cfg, "No PHP packages installed. Removing configuration files." ); logger->info("!!!! No PHPs installed! !!\nUsers’ PHP settings will be left as is. That way PHP requests will get an error instead of serving source code and potentially sensitive data like database credentials."); !$cfg->{args}->{dryrun} && unlink( $cfg->{apache_path}, $cfg->{cfg_path} ); return 1; } try { if ( $cfg->{api} eq 'old' ) { my %rebuild = %$settings; $rebuild{restart} = 0; $rebuild{dryrun} = 0; $rebuild{version} = $settings->{phpversion}; debug( $cfg, "Updating PHP using old API" ); !$cfg->{args}->{dryrun} && $cfg->{php}->php_set_system_default_version(%rebuild); } else { my %pkginfo = %$settings; my $default = delete $pkginfo{default}; debug( $cfg, "Setting the system default PHP package to the '$default' handler" ); !$cfg->{args}->{dryrun} && $cfg->{php}->set_system_default_package( package => $default ); debug( $cfg, "Successfully updated the system default PHP package" ); require Cpanel::WebServer; my $apache = Cpanel::WebServer->new->get_server( type => "apache" ); my $disable_flag_file = "/var/cpanel/ea4-disable_009-phpconf.pl_user_setting_validation_and_risk_breaking_PHP_based_sites_and_exposing_sensitive_data_in_PHP_source_code"; while ( my ( $pkg, $handler ) = each(%pkginfo) ) { debug( $cfg, "Setting the '$pkg' package to the '$handler' handler" ); if ( !$cfg->{args}->{dryrun} ) { $apache->set_package_handler( type => $handler, lang => $cfg->{php}, package => $pkg, ); try { if ( -e $disable_flag_file ) { die "Ensuring that user settings are still valid is disabled via the existence of $disable_flag_file:\n\t!!!! your PHP based sites may be broken and exposing sensitive data in the source code !!\n"; } $apache->update_user_package_handlers( type => $handler, lang => $cfg->{php}, package => $pkg ); } catch { logger->info("Error updating user package handlers for $pkg: $_"); }; } debug( $cfg, "Successfully updated the '$pkg' package" ); } # now that existing packages are ship shape, let’s handle users still set to non-existent version if ( -e $disable_flag_file ) { logger->info("Ensuring that user settings are still valid is disabled via the existence of $disable_flag_file:\n\t!!!! your PHP based sites may be broken and exposing sensitive data in the source code !!"); } else { update_users_set_to_non_existant_phps( $apache, $cfg->{php}, "inherit" ); } } } catch { logger->die("$_"); # copy $_ since it can be magical }; return 1; } sub update_users_set_to_non_existant_phps { my ( $apache, $lang, $default ) = @_; my ( %users, @error ); Cpanel::Config::LoadUserDomains::loadtrueuserdomains( \%users, 1 ); my %installed; @installed{ @{ $lang->get_installed_packages() } } = (); # this should not be possible *but* just in case if ( !keys %installed ) { logger->info("!!!! No PHPs installed! !!\nUsers’ PHP settings will be left as is. That way PHP requests will get an error instead of serving source code and potentially sensitive data like database credentials."); return; } for my $user ( keys %users ) { next unless $users{$user}; # some accounts are invalid and don't contain a domain in the /etc/trueusersdomain configuration file my $cfg = try { Cpanel::Config::LoadCpUserFile::load_or_die($user) }; next unless $cfg; next if $cfg->{PLAN} =~ /Cpanel\s+Ticket\s+System/i; # Accounts like this are created by the autofixer2 create_temp_reseller_for_ticket_access script when cpanel support logs in my $userdata = Cpanel::WebServer::Userdata->new( user => $user ); for my $vhost ( @{ $userdata->get_vhost_list() } ) { try { my $pkg = $userdata->get_vhost_lang_package( lang => $lang, vhost => $vhost ); if ( $pkg ne "inherit" && !exists $installed{$pkg} ) { # This PHP is no longer installed so set them to the default (their code may break but at least we ensure their source code is not served) logger->info("User $user’s vhost “$vhost” is set to PHP “$pkg” which is no longer installed. Setting them to inherit …"); $apache->set_vhost_lang_package( userdata => $userdata, vhost => $vhost, lang => $lang, package => $default ); $userdata->set_vhost_lang_package( vhost => $vhost, lang => $lang, package => $default ); } } catch { push @error, $_; }; } } die Cpanel::Exception::create( 'Collection', [ exceptions => \@error ] ) if @error > 1; die $error[0] if @error == 1; return 1; } sub setup_session_save_path { require Cpanel::ProgLang::Supported::php::Ini; if ( Cpanel::ProgLang::Supported::php::Ini->can('setup_session_save_path') ) { my $rv = eval { Cpanel::ProgLang::Supported::php::Ini::setup_session_save_path() }; return 2 if ref($@) eq "Cpanel::Exception::FeatureNotEnabled"; # ignore failures from PHP not being installed return $rv; } return; } unless ( caller() ) { my $cfg = get_php_config( \@ARGV ); my $settings = get_rebuild_settings($cfg); apply_rebuild_settings( $cfg, $settings ); setup_session_save_path(); } 1; __END__ =encoding utf8 =head1 NAME 009-phpconf.pl -- package manager universal hook =head1 SYNOPSIS Executed by various package managers via this package: https://github.com/CpanelInc/yum-plugin-universal-hooks =head1 DESCRIPTION This scripts updates the cPanel and Apache MultiPHP configurations. It's important for this script to run after packages have been added, removed, or updated via the package manager because the cPanel MultiPHP system depends on the configuration (default: /etc/cpanel/ea4/php.conf) always being correct. Some of the things it does are as follows: =over 2 =item * If no PHP packages are installed on the system, it will remove all cPanel and Apache configuration information related to PHP. It will leave users’ configurations as-is in case it was a temporary situation or a mistake. It also acts as a security benefit because they will get an error instead of the source code. =item * If a PHP package is removed using the package manager, configuration for that package is removed. Users assigned to it will be moved to the newest PHP installed. This uses userdata for efficiency and reliability. It will not traverse the file system looking for C<.htaccess> files that have PHP looking handlers. That would be an expensive and fragile operation. As long as they use MultiPHP Manager (or CL’s PHP selector/cagefs system?) they will be in ship shape. =item * If a PHP package is added using the package manager, a default configuration is applied. =item * If an Apache handler for PHP is removed using the package manager, a default Apache handler is used instead. =back =head1 DEFAULT SYSTEM PACKAGE If the default PHP package is removed, C<$cpanel_default_php_pkg> (AKA C) is used if its installed. Otherwise the latest (according to PHP version number) is used. =head1 APACHE HANDLER FOR PHP If the Apache handler assigned to a PHP package is missing, the following checks are performed. If a check succeeds, no further checks are performed. =over 2 =item 1. Attempt to assign a package to the 'suphp' handler if the mod_suphp Apache module is installed. =item 2. Attempt to assign a package to the 'dso' handler if the correct package is installed. =over 2 =item * IMPORTANT NOTE: Only one 'dso' handler can be assigned at a time. =back =item 3. Attempt to assign a package to the Cpanel::EA4::Util::get_default_php_handler() (which if it is cgi, will work since the mod_cgi or mod_cgid Apache modules should be installed (and in the weird case it isn't then at leats they'll get errors instead of source code)). =back =head1 ADDITIONAL INFORMATION This script depends on the packages setting up the correct dependencies and conflicts. For example, this script doesn't check the Apache configuration for MPM ITK when assigning PHP to the SuPHP handler since it assumes the package should already have a conflict detected by the package manager during installation. transaction/ea-__WILDCARD__/001-ensure-nobody000075500000004261151027703750014470 0ustar00#!/usr/bin/perl use strict; use warnings; system("touch /etc/systemd/dont-synthesize-nobody") if -d "/etc/systemd"; my $uid = getpwnam("nobody"); my $gid = getgrnam("nobody"); my @ids = ( 65534, 99 ); my $user_needs_informed = 0; if ( !defined $gid ) { $user_needs_informed = 1; my $addgroup = -x '/usr/sbin/groupadd' ? "groupadd" : "addgroup"; for my $id (@ids) { system("$addgroup --system --gid $id nobody"); $gid = getgrnam("nobody"); last if defined $gid; } if ( !defined $gid ) { system("$addgroup --system nobody"); } $gid = getgrnam("nobody"); die "Could not ensure `nobody` group\n" if !defined $gid; } if ( !defined $uid ) { $user_needs_informed = 1; my $flags = -x '/usr/sbin/groupadd' ? "" : "--disabled-password --disabled-login"; for my $id (@ids) { system("adduser --system --uid $id --gid $gid --home / --no-create-home --shell /sbin/nologin $flags nobody"); $uid = getpwnam("nobody"); last if defined $uid; } if ( !defined $uid ) { system("adduser --system --gid $gid --home / --no-create-home --shell /sbin/nologin $flags nobody"); } $uid = getpwnam("nobody"); die "Could not ensure `nobody` user\n" if !defined $uid; } # if already done, its a noop. adduser’s --gid does not make this happen system("usermod -g $gid nobody"); my $home = ( getpwnam("nobody") )[7]; if ( !-d $home ) { # We do not want to create it for them in case there are other implications in /nonexistent existing. # We can’t `usermod --home / nobody` for them because we’d have to hard stop all nobody processes first. my $sep = "#" x 42; print <<"END_HOMEDIR"; $sep [WARN] Detected non-existent home directory for `nobody`. This situation can result in some harmless STDERR going to your web server’s error log as errors. If you experience this your options are: 1. Ignore the log entries 2. Create the directory “$home” if it is safe to do so. 3. Change the `nobody` user’s home directory to one that exists. e.g. `usermod --home / nobody` $sep END_HOMEDIR } print "[INFO] `nobody` user created with UID $uid and GID $gid\n" if $user_needs_informed; transaction/ea-__WILDCARD__/070-cloudlinux-cagefs.pl000075500000004364151027703750015737 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # Copyright (c) 2015, cPanel, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use Cpanel::Imports; use Cpanel::CloudLinux (); if ( Cpanel::CloudLinux::installed() && _has_lines_matching( '/etc/cagefs/cagefs.mp', qr{^\s*[!@#]?/\w+} ) ) { print locale->maketext('Updating the [asis,CloudLinux CageFS] virtual filesystem …') . "\n"; system('/usr/sbin/cagefsctl --update --force-update') && logger->warn("/usr/sbin/cagefsctl exited non-zero: $?"); print "\n"; print locale->maketext(' … done.') . "\n"; } sub _has_lines_matching { my ( $file, $regexp ) = @_; return if !-s $file || !-f _; my $matches = 0; if ( open( my $fh, '<', $file ) ) { while ( my $line = <$fh> ) { if ( $line =~ $regexp ) { $matches = 1; last; } } close($fh); return 1 if $matches; } else { logger->warn("Could not read $file: $!"); } return; }transaction/ea-__WILDCARD__/060-setup_apache_symlinks.pl000075500000012242151027703750016706 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # Copyright (c) 2015, cPanel, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use warnings; use Cpanel::ConfigFiles::Apache (); use Cpanel::FileUtils (); # Get the paths from the paths.conf file my $apacheconf = Cpanel::ConfigFiles::Apache->new(); # These are the old Easy Apache 3 paths my $ea3_basedir = '/usr/local/apache'; my $ea3_confdir = "$ea3_basedir/conf"; my $ea3_bindir = "$ea3_basedir/bin"; my %ea3_paths = ( dir_logs => "$ea3_basedir/logs", dir_domlogs => "$ea3_basedir/domlogs", dir_modules => "$ea3_basedir/modules", dir_conf_includes => "$ea3_confdir/includes", dir_conf_userdata => "$ea3_confdir/userdata", dir_docroot => "$ea3_basedir/htdocs", file_access_log => "$ea3_basedir/access_log", file_error_log => "$ea3_basedir/error_log", file_conf => "$ea3_confdir/httpd.conf", file_conf_mime_types => "$ea3_confdir/mime.types", file_conf_srm_conf => "$ea3_confdir/srm.conf", file_conf_php_conf => "$ea3_confdir/php.conf", bin_httpd => "$ea3_bindir/httpd", bin_apachectl => "$ea3_bindir/apachectl", bin_suexec => "$ea3_bindir/suexec", ); for my $dir ( $ea3_basedir, $ea3_bindir, $ea3_confdir ) { next if -d $dir; if ( !mkdir($dir) ) { die "Unable to create $dir: $!\n"; } } # Make a symlink from all the old ea3 paths to the new folders my $verbose = grep /^--verbose/, @ARGV; my $had_errors = 0; foreach my $key ( sort keys %ea3_paths ) { eval { # If the old and the new are the same, no symlink required if ( $apacheconf->{$key} eq $ea3_paths{$key} ) { print "Source and destination same, $ea3_paths{$key}, no need to link\n" if $verbose; return; } # No sense in trying to link to something that doesn't exist if ( !-e $apacheconf->{$key} ) { print "Target $apacheconf->{$key} doesn't exist, can't link to it\n" if $verbose; return; } # If a symlink already exists, it may be old/wrong, remake it if ( -l $ea3_paths{$key} ) { if ( readlink( $ea3_paths{$key} ) ne $apacheconf->{$key} ) { print "Previous symlink at $ea3_paths{$key}, unlinking\n" if $verbose; unlink( $ea3_paths{$key} ) or die("Unable to unlink $ea3_paths{$key}: $!\n"); } else { print "Link already exists: $ea3_paths{$key} -> $apacheconf->{$key}\n" if $verbose; return; } } # If we can see the item to be linked, it is possibly visible # due to its parent being linked. # If not, backup and move the EA3 file before creating the link if ( -e $ea3_paths{$key} ) { # Test if they are actually the same file by virtue of parent # directory linkage if ( Cpanel::FileUtils::equivalent_files( $ea3_paths{$key}, $apacheconf->{$key} ) ) { print "$ea3_paths{$key} already linked via parent directory, no need to link\n" if $verbose; return; } # Move the file out of the way so we can create the link # Passing "-fa" to safemv will cause it to uniquely rename # the destination file if it already exists print "Renaming $ea3_paths{$key} to $ea3_paths{$key}.ea3 to create link\n" if $verbose; Cpanel::FileUtils::safemv( "-fa", $ea3_paths{$key}, $ea3_paths{$key} . '.ea3' ) or die("Unable to rename $ea3_paths{$key}: $!\n"); } print "Linking $ea3_paths{$key} -> $apacheconf->{$key}\n" if $verbose; symlink( $apacheconf->{$key}, $ea3_paths{$key} ) or die("Unable to symlink $ea3_paths{$key} to $apacheconf->{$key}: $!\n"); }; if ($@) { warn "Error: $@"; $had_errors++; } } if ($had_errors) { exit 1; } transaction/ea-__WILDCARD__/010-suphpconf.pl000075500000007614151027703750014323 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # cpanel - 010-suphpconf.pl Copyright 2017 cPanel, Inc. # All rights Reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited package suphpconf; use strict; use warnings; use Cpanel::SysPkgs::SCL (); our $suphpconf = '/etc/suphp.conf'; run() unless caller; sub run { if ( -e $suphpconf ) { if ( !-e "/usr/local/bin/ea_convert_php_ini" ) { # This madness will go away with EA-5696 warn "Unable to update /etc/suphp.conf without the ea-cpanel-tools package installed.\n"; } else { require "/usr/local/bin/ea_convert_php_ini"; ##no critic (RequireBarewordIncludes) This madness will go away with EA-5696 my $parser = Parse::PHP::Ini->new; my $tree = $parser->parse( path => $suphpconf ); my $handlers = $parser->get_matching_section( $tree, 'handlers' ); if ( !$handlers ) { $handlers = $parser->make_section_node( 'handlers', -1 ); $tree->add_daughter($handlers); } my %packages; @packages{ @{ Cpanel::SysPkgs::SCL::get_scl_versions(qr/\w+-php/) } } = (); # update/cleanout existing entries for my $daughter ( @{ $handlers->{daughters} } ) { if ( $daughter->{name} =~ m{application/x-httpd-(.*)} ) { my $pkg = $1; if ( exists $packages{$pkg} ) { my $cgi_path = _get_cgi_path($pkg); my $count = $daughter->{attributes}{line}; # TODO: make this something else? my $tmp = $parser->make_setting_node( "application/x-httpd-$pkg", qq{"php:$cgi_path"}, $count ); my $attr = $tmp->attribute(); $parser->update_node( $daughter, $attr ); print "Ensuring current entry for “$pkg” is correct …\n"; $packages{$pkg} = "update"; } else { print "Ignoring current entry for “$pkg” …\n"; $packages{$pkg} = "ignore"; } } } # add entries reflecting the actual state for my $pkg ( keys %packages ) { if ( !$packages{$pkg} ) { my $cgi_path = _get_cgi_path($pkg); my $count = 0; # TODO: make this something else? my $setting = $parser->make_setting_node( "application/x-httpd-$pkg", qq{"php:$cgi_path"}, $count ); $handlers->add_daughter($setting); print "Adding entry for “$pkg” …\n"; $packages{$pkg} = "add"; } } # write $suphpconf _write_suphpconf($tree); } } else { print "Nothing to do ($suphpconf does not exist)\n"; } return; } ############### #### helpers ## ############### sub _get_cgi_path { my ($pkg) = @_; my $cgi_path = Cpanel::SysPkgs::SCL::get_scl_prefix($pkg) . "/root/usr/bin/php-cgi"; if ( !-x $cgi_path ) { warn "$cgi_path is not executable, please rectify (e.g. a symlink …/root to the right spot should do the trick)\n"; } return $cgi_path; } sub _write_suphpconf { my ($tree) = @_; # Encapsualte the madness here, NS use noted in /usr/local/bin/ea_convert_php_ini no warnings "once"; local $ea_convert_php_ini_file::Cfg{force} = 1; ea_convert_php_ini_file::write_php_ini( $tree, $suphpconf ); } transaction/ea-__WILDCARD__/010-purge_cache.pl000075500000005503151027703750014556 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # Copyright (c) 2015, cPanel, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use warnings; use Cpanel::CachedCommand::Utils (); # # First purge all the CachedCommand caches # purge_cached_commands(); # # Rebuild the global cache # print "Rebuilding global cache\n"; system('/usr/local/cpanel/bin/build_global_cache'); sub purge_cached_commands { print "Purging all relevant cached command results\n"; # Get the directory where the CachedCommand cache files live my $cache_dir = Cpanel::CachedCommand::Utils::_get_datastore_dir(); if ( !defined $cache_dir or !$cache_dir ) { print STDERR "Unable to obtain the cached command datastore directory\n"; return; } # Guard against getting back something like "/", make sure it is a real cPanel cache dir if ( $cache_dir !~ /\.cpanel\/datastore$/ ) { print STDERR "Invalid cached command datastore directory: $cache_dir\n"; return; } if ( !-d $cache_dir ) { print STDERR "$cache_dir is not a directory\n"; return; } my $dh; if ( !opendir( $dh, $cache_dir ) ) { print STDERR "Unable to open $cache_dir: $!\n"; return; } while ( my $file = readdir($dh) ) { my $full_path = "$cache_dir/$file"; # Only actual files, no subdirs, no . or .. next unless -f $full_path; # Only actions run on apache next unless ( $file =~ /http/ ); print "Removing: $full_path\n"; unlink $full_path or print STDERR "Unable to delete $file: $!\n"; } closedir($dh); } transaction/ea-php__WILDCARD__-php-fpm/100-phpfpm_cleanup.pl000075500000016424151027703750017373 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl ############################################################################################## # # Copyright (c) 2016, cPanel, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ############################################################################################## package unihook::phpfpm_clean; use strict; use warnings; use Cpanel::Version::Tiny (); use Cpanel::Version::Compare (); use Cpanel::PackMan (); my $debuglvl = 1; my $script_name = $0; $script_name =~ s/.+\/(.+?)\.pl$/$1/; run(@ARGV) unless caller; sub run { my @args = @_; # The libraries needed to run this script weren't introduced until this release. return 0 if Cpanel::Version::Compare::compare( $Cpanel::Version::Tiny::VERSION_BUILD, '<', '11.60.0.1' ); require Cpanel::PHP::Config; require Cpanel::PHPFPM; require Cpanel::HttpUtils::ApRestart::BgSafe; ############################################################################################## my $phpfpm_version = ''; my @pkgs; foreach my $arg (@args) { if ( $arg =~ m/^--pkg_list=(.+)$/ ) { my $pkgs_path = $1; if ( open( my $pkgs_list_fh, '<', $pkgs_path ) ) { @pkgs = <$pkgs_list_fh>; chomp @pkgs; close $pkgs_list_fh; } else { die "Found path to packages “$pkgs_path” but could not read from it: $!\n"; } } } my $restart_needed = 0; foreach my $pkg (@pkgs) { msglog( 2, "Processing package '$pkg'" ); if ( $pkg =~ m/^ea-php(\d{2})-php-fpm$/ ) { $phpfpm_version = $1; } else { # This is not the package we are looking for /waveshand next; } # Try to determine if we are removing the package or installing it. # At this point, if we are installing, it should now exist. If we are removing, it should not. my $installing = 0; my $pkg_hr = Cpanel::PackMan->instance->pkg_hr($pkg); if ( !$pkg_hr || $pkg_hr->{version_installed} eq "" ) { $installing = 0; } else { $installing = 1; } # If we are installing, there presumably isn't anything to clean up. Otherwise, proceed with the purge. -.- if ($installing) { msglog( 0, "[$pkg] No need to clean user files since we are installing." ); next; } else { msglog( 0, "Cleaning up PHP-FPM configs for version $phpfpm_version since we are removing the package." ); } # If we get here, we're going to want to restart Apache $restart_needed = 1; # Build a list of users on a certain version of PHP-FPM my $users_ref = get_users_on_fpm_version($phpfpm_version); # Disable any user currently configured for this version of PHP-FPM disable_all_fpm_users_for_version( $phpfpm_version, $users_ref ); # Rebuild the Apache config my $php_cfg_ref = Cpanel::PHP::Config::get_php_config_for_users($users_ref); if ( !%$php_cfg_ref ) { msglog( 0, "No domains were on ea-php${phpfpm_version}-php-fpm." ); } elsif ( Cpanel::PHPFPM::rebuild_files( $php_cfg_ref, 0, 1, 1 ) ) { msglog( 0, "All domains that were on ea-php${phpfpm_version}-php-fpm should be back to system defaults." ); } else { msglog( 0, "Problem encountered while trying to rebuild the PHP-FPM related configuration files. Please check the Apache server to be sure it is running correctly." ); } } if ($restart_needed) { # Finally, restart apache with the updated config msglog( 0, "Restarting Apache" ); Cpanel::HttpUtils::ApRestart::BgSafe::restart(); } } ############################################################################################## # Functions ############################################################################################## sub get_users_on_fpm_version { my ($version) = @_; my @users; require Cpanel::PHPFPM::Constants; no warnings qw( once ); my $conf_dir_path = "$Cpanel::PHPFPM::Constants::opt_cpanel/ea-php$version/root/etc/php-fpm.d/"; use warnings qw( once ); if ( opendir( my $user_confs_dir, $conf_dir_path ) ) { foreach my $file ( readdir($user_confs_dir) ) { if ( $file =~ m/.+\.conf$/ ) { if ( open( my $cnf_fh, '<', "$conf_dir_path/$file" ) ) { while ( my $line = <$cnf_fh> ) { $line =~ s/\s+//g; chomp($line); if ( $line =~ m/^user=\"*([^\"]*)\"*$/ ) { my $username = $1; push( @users, $username ); } } close $cnf_fh; } } } close $user_confs_dir; } return \@users; } sub disable_all_fpm_users_for_version { my ( $version, $users_ref ) = @_; # We might get $version as just the numbers like 55, 56, 70, etc, or a full string, like ea-php55, ea-php56 or ea-php70 if ( $version =~ m/ea-php(\d+)/ ) { $version = $1; } # We'll iterate through all the .conf files in this version's php-fom.d config directory and build a list of users on this version. # Then we'll go through those users and remove their yaml configs ? foreach my $user ( @{$users_ref} ) { if ( opendir( my $userdata_dir, '/var/cpanel/userdata/' . $user ) ) { foreach my $file ( readdir($userdata_dir) ) { if ( $file =~ m/.+\.php\-fpm\.yaml$/ ) { unlink( $userdata_dir, '/var/cpanel/userdata/' . $user . '/' . $file ); } } close($userdata_dir); } } return; } sub msglog { my ( $lvl, $text ) = @_; if ( $lvl <= $debuglvl ) { my $ts = scalar( localtime(time) ); my @caller = caller(); print STDOUT "[$ts] [$script_name] $text\n"; } return; } 1; transaction/__WILDCARD__-php__WILDCARD__/009-phpconf.pl000075500000046167151027703750016101 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # Copyright (c) 2015, cPanel, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package ea_apache2_config::phpconf; use strict; use Cpanel::Imports; use Cpanel::PackMan (); use Try::Tiny; use Cpanel::ConfigFiles::Apache (); use Cpanel::Config::LoadUserDomains (); use Cpanel::Config::LoadCpUserFile (); use Cpanel::Exception (); use Cpanel::WebServer::Userdata (); use Cpanel::DataStore (); use Cpanel::EA4::Util (); use Cpanel::Notify (); use Cpanel::ProgLang (); use Cpanel::WebServer (); use Getopt::Long (); use POSIX qw( :sys_wait_h ); our @PreferredHandlers = qw( suphp dso cgi ); our $cpanel_default_php_pkg = "ea-php" . Cpanel::EA4::Util::get_default_php_version(); $cpanel_default_php_pkg =~ s/\.//g; my ( $php, $server ); sub debug { my $cfg = shift; my $t = localtime; print "[$t] DEBUG: @_\n" if $cfg->{args}->{debug}; } sub is_handler_supported { my ( $handler, $package ) = @_; $php ||= Cpanel::ProgLang->new( type => 'php' ); $server ||= Cpanel::WebServer->new()->get_server( type => 'apache' ); my $ref = $server->get_available_handlers( lang => $php, package => $package ); return 1 if $ref->{$handler}; return 0; } sub send_notification { my ( $package, $language, $webserver, $missing_handler, $replacement_handler ) = @_; my %args = ( class => q{EasyApache::EA4_LangHandlerMissing}, application => q{universal_hook_phpconf}, constructor_args => [ package => $package, language => $language, webserver => $webserver, missing_handler => $missing_handler || 'UNDEFINED', replacement_handler => $replacement_handler ], ); # No point in catching the failure since we can't do anything # about here anyways. try { my $class = Cpanel::Notify::notification_class(%args); waitpid( $class->{'_icontact_pid'}, WNOHANG ); }; return 1; } sub get_preferred_handler { my $package = shift; my $cfg = shift; my $old_handler = $cfg->{$package} || $PreferredHandlers[0]; my $new_handler; if ( is_handler_supported( $old_handler, $package ) ) { $new_handler = $old_handler; } else { for my $handler (@PreferredHandlers) { last if $new_handler; $new_handler = $handler if is_handler_supported( $handler, $package ); } } if ( !$new_handler ) { my $def = Cpanel::EA4::Util::get_default_php_handler(); logger->info("Could not find a handler for $package. Defaulting to “$def” so that, at worst case, we get an error instead of source code."); $new_handler = $def; } return $new_handler; } # EA-3819: The cpanel api calls depend on php.conf having all known packages # to be in php.conf. This will update php.conf with some temporary # values just in case they're missing. This will also remove entries # if they no longer installed. sub sanitize_php_config { my $cfg = shift; my $prog = shift; return 1 unless scalar @{ $cfg->{packages} }; # The %save hash is used to ensure cpanel has a basic php.conf that will # not break the MultiPHP EA4 code if a package or handler is removed # from the system while it's configured. It will iterate over all # possible handler attempting to find a suitable (and supported) # handler. It will resort to the Cpanel::EA4::Util::get_default_php_handler() handler if nothing else # is supported. # # Finally, the cfg_ref hash is what this applications uses to update # packages/handlers to a "preferred" one if the current is missing or # no longer installed. my %save = %{ $cfg->{cfg_ref} }; my $default = delete $cfg->{cfg_ref}{default}; # remove packages which are no longer installed for my $pkg ( keys %{ $cfg->{cfg_ref} } ) { unless ( grep( /\A\Q$pkg\E\z/, @{ $cfg->{packages} } ) ) { delete $cfg->{cfg_ref}->{$pkg}; delete $save{$pkg}; } } # add packages which are newly installed and at least make sure it's a valid handler for my $pkg ( @{ $cfg->{packages} } ) { $save{$pkg} = get_preferred_handler( $pkg, \%save ); } # make sure the default package has been assigned if ( !defined $default ) { my @packages = sort @{ $cfg->{packages} }; # if we have $cpanel_default_php_pkg use that, otherwise use the latest that is installed $default = grep( { $_ eq $cpanel_default_php_pkg } @packages ) ? $cpanel_default_php_pkg : $packages[-1]; } $save{default} = $default; # and only allow a single dso handler, set the rest to Cpanel::EA4::Util::get_default_php_handler() !$cfg->{args}{dryrun} && $prog->set_conf( conf => \%save ); return 1; } # Retrieves current PHP sub get_php_config { my $argv = shift || []; my %cfg = ( packages => [], args => { dryrun => 0, debug => 0 } ); Getopt::Long::Configure(qw( pass_through )); # not sure if we're passed any args by the universal hooks plugin Getopt::Long::GetOptionsFromArray( $argv, dryrun => \$cfg{args}{dryrun}, debug => \$cfg{args}{debug}, ); my $apacheconf = Cpanel::ConfigFiles::Apache->new(); eval { require Cpanel::ProgLang; require Cpanel::ProgLang::Conf; }; # Need to use the old API, not new one if ($@) { $cfg{api} = 'old'; $cfg{apache_path} = $apacheconf->file_conf_php_conf(); $cfg{cfg_path} = $cfg{apache_path} . '.yaml'; try { require Cpanel::Lang::PHP::Settings; my $php = Cpanel::Lang::PHP::Settings->new(); $cfg{php} = $php; $cfg{packages} = $php->php_get_installed_versions(); $cfg{cfg_ref} = Cpanel::DataStore::fetch_ref( $cfg{cfg_path} ); }; } else { # get basic information in %cfg in case php isn't installed my $prog = Cpanel::ProgLang::Conf->new( type => 'php' ); $cfg{api} = 'new'; $cfg{apache_path} = $apacheconf->file_conf_php_conf(); # hack until we can add this API to Cpanel::WebServer $cfg{cfg_path} = $prog->get_file_path(); try { my $php = Cpanel::ProgLang->new( type => 'php' ); # this will die if PHP isn't installed $cfg{php} = $php; $cfg{packages} = $php->get_installed_packages(); $cfg{cfg_ref} = $prog->get_conf(); }; sanitize_php_config( \%cfg, $prog ); } return \%cfg; } sub get_rebuild_settings { my $cfg = shift; my $ref = $cfg->{cfg_ref}; my %settings; return {} unless @{ $cfg->{packages} }; my $php = $cfg->{php}; # We can't assume that suphp will always be available for each package. # This will iterate over each package and verify that the handler is # installed. If it's not, then revert to the Cpanel::EA4::Util::get_default_php_handler() handler, # which should be installed (if it is 'cgi' then it is available by default). for my $package ( @{ $cfg->{packages} } ) { my $old_handler = $ref->{$package} || ''; my $new_handler = get_preferred_handler( $package, $ref ); if ( $old_handler ne '' && $old_handler ne $new_handler ) { print locale->maketext(q{WARNING: You removed a configured [asis,Apache] handler.}), "\n"; print locale->maketext( q{The “[_1]” package will revert to the “[_2]”[comment,the web server handler that will be used in its place (e.g. cgi)] “[_3]” handler.}, $package, 'Apache', $new_handler ), "\n"; $cfg->{args}->{dryrun} && send_notification( $package, 'PHP', 'Apache', $old_handler, $new_handler ); } $settings{$package} = $new_handler; } if ( $cfg->{api} eq 'old' ) { my $cur_sys_default = eval { $php->php_get_system_default_version() }; $settings{phpversion} = _ensure_default_key_is_valid( $cur_sys_default => $cfg ); } else { my $cur_sys_default = $php->get_system_default_package(); $settings{default} = _ensure_default_key_is_valid( $cur_sys_default => $cfg ); } return \%settings; } sub _ensure_default_key_is_valid { my ( $cur_sys_default, $cfg ) = @_; $cur_sys_default = undef if !$cur_sys_default || !grep { $cur_sys_default eq $_ } @{ $cfg->{packages} }; my $def = $cur_sys_default || Cpanel::EA4::Util::get_default_php_version(); if ( $def =~ m/\./ ) { $def = "ea-php$def"; $def =~ s/\.//g; } my $def_hr = Cpanel::PackMan->instance->pkg_hr($def) || {}; $def = $cfg->{packages}[-1] if !$def_hr->{version_installed}; return $def; } sub apply_rebuild_settings { my $cfg = shift; my $settings = shift; if ( $#{ $cfg->{packages} } == -1 ) { debug( $cfg, "No PHP packages installed. Removing configuration files." ); logger->info("!!!! No PHPs installed! !!\nUsers’ PHP settings will be left as is. That way PHP requests will get an error instead of serving source code and potentially sensitive data like database credentials."); !$cfg->{args}->{dryrun} && unlink( $cfg->{apache_path}, $cfg->{cfg_path} ); return 1; } try { if ( $cfg->{api} eq 'old' ) { my %rebuild = %$settings; $rebuild{restart} = 0; $rebuild{dryrun} = 0; $rebuild{version} = $settings->{phpversion}; debug( $cfg, "Updating PHP using old API" ); !$cfg->{args}->{dryrun} && $cfg->{php}->php_set_system_default_version(%rebuild); } else { my %pkginfo = %$settings; my $default = delete $pkginfo{default}; debug( $cfg, "Setting the system default PHP package to the '$default' handler" ); !$cfg->{args}->{dryrun} && $cfg->{php}->set_system_default_package( package => $default ); debug( $cfg, "Successfully updated the system default PHP package" ); require Cpanel::WebServer; my $apache = Cpanel::WebServer->new->get_server( type => "apache" ); my $disable_flag_file = "/var/cpanel/ea4-disable_009-phpconf.pl_user_setting_validation_and_risk_breaking_PHP_based_sites_and_exposing_sensitive_data_in_PHP_source_code"; while ( my ( $pkg, $handler ) = each(%pkginfo) ) { debug( $cfg, "Setting the '$pkg' package to the '$handler' handler" ); if ( !$cfg->{args}->{dryrun} ) { $apache->set_package_handler( type => $handler, lang => $cfg->{php}, package => $pkg, ); try { if ( -e $disable_flag_file ) { die "Ensuring that user settings are still valid is disabled via the existence of $disable_flag_file:\n\t!!!! your PHP based sites may be broken and exposing sensitive data in the source code !!\n"; } $apache->update_user_package_handlers( type => $handler, lang => $cfg->{php}, package => $pkg ); } catch { logger->info("Error updating user package handlers for $pkg: $_"); }; } debug( $cfg, "Successfully updated the '$pkg' package" ); } # now that existing packages are ship shape, let’s handle users still set to non-existent version if ( -e $disable_flag_file ) { logger->info("Ensuring that user settings are still valid is disabled via the existence of $disable_flag_file:\n\t!!!! your PHP based sites may be broken and exposing sensitive data in the source code !!"); } else { update_users_set_to_non_existant_phps( $apache, $cfg->{php}, "inherit" ); } } } catch { logger->die("$_"); # copy $_ since it can be magical }; return 1; } sub update_users_set_to_non_existant_phps { my ( $apache, $lang, $default ) = @_; my ( %users, @error ); Cpanel::Config::LoadUserDomains::loadtrueuserdomains( \%users, 1 ); my %installed; @installed{ @{ $lang->get_installed_packages() } } = (); # this should not be possible *but* just in case if ( !keys %installed ) { logger->info("!!!! No PHPs installed! !!\nUsers’ PHP settings will be left as is. That way PHP requests will get an error instead of serving source code and potentially sensitive data like database credentials."); return; } for my $user ( keys %users ) { next unless $users{$user}; # some accounts are invalid and don't contain a domain in the /etc/trueusersdomain configuration file my $cfg = try { Cpanel::Config::LoadCpUserFile::load_or_die($user) }; next unless $cfg; next if $cfg->{PLAN} =~ /Cpanel\s+Ticket\s+System/i; # Accounts like this are created by the autofixer2 create_temp_reseller_for_ticket_access script when cpanel support logs in my $userdata = Cpanel::WebServer::Userdata->new( user => $user ); for my $vhost ( @{ $userdata->get_vhost_list() } ) { try { my $pkg = $userdata->get_vhost_lang_package( lang => $lang, vhost => $vhost ); if ( $pkg ne "inherit" && !exists $installed{$pkg} ) { # This PHP is no longer installed so set them to the default (their code may break but at least we ensure their source code is not served) logger->info("User $user’s vhost “$vhost” is set to PHP “$pkg” which is no longer installed. Setting them to inherit …"); $apache->set_vhost_lang_package( userdata => $userdata, vhost => $vhost, lang => $lang, package => $default ); $userdata->set_vhost_lang_package( vhost => $vhost, lang => $lang, package => $default ); } } catch { push @error, $_; }; } } die Cpanel::Exception::create( 'Collection', [ exceptions => \@error ] ) if @error > 1; die $error[0] if @error == 1; return 1; } sub setup_session_save_path { require Cpanel::ProgLang::Supported::php::Ini; if ( Cpanel::ProgLang::Supported::php::Ini->can('setup_session_save_path') ) { my $rv = eval { Cpanel::ProgLang::Supported::php::Ini::setup_session_save_path() }; return 2 if ref($@) eq "Cpanel::Exception::FeatureNotEnabled"; # ignore failures from PHP not being installed return $rv; } return; } unless ( caller() ) { my $cfg = get_php_config( \@ARGV ); my $settings = get_rebuild_settings($cfg); apply_rebuild_settings( $cfg, $settings ); setup_session_save_path(); } 1; __END__ =encoding utf8 =head1 NAME 009-phpconf.pl -- package manager universal hook =head1 SYNOPSIS Executed by various package managers via this package: https://github.com/CpanelInc/yum-plugin-universal-hooks =head1 DESCRIPTION This scripts updates the cPanel and Apache MultiPHP configurations. It's important for this script to run after packages have been added, removed, or updated via the package manager because the cPanel MultiPHP system depends on the configuration (default: /etc/cpanel/ea4/php.conf) always being correct. Some of the things it does are as follows: =over 2 =item * If no PHP packages are installed on the system, it will remove all cPanel and Apache configuration information related to PHP. It will leave users’ configurations as-is in case it was a temporary situation or a mistake. It also acts as a security benefit because they will get an error instead of the source code. =item * If a PHP package is removed using the package manager, configuration for that package is removed. Users assigned to it will be moved to the newest PHP installed. This uses userdata for efficiency and reliability. It will not traverse the file system looking for C<.htaccess> files that have PHP looking handlers. That would be an expensive and fragile operation. As long as they use MultiPHP Manager (or CL’s PHP selector/cagefs system?) they will be in ship shape. =item * If a PHP package is added using the package manager, a default configuration is applied. =item * If an Apache handler for PHP is removed using the package manager, a default Apache handler is used instead. =back =head1 DEFAULT SYSTEM PACKAGE If the default PHP package is removed, C<$cpanel_default_php_pkg> (AKA C) is used if its installed. Otherwise the latest (according to PHP version number) is used. =head1 APACHE HANDLER FOR PHP If the Apache handler assigned to a PHP package is missing, the following checks are performed. If a check succeeds, no further checks are performed. =over 2 =item 1. Attempt to assign a package to the 'suphp' handler if the mod_suphp Apache module is installed. =item 2. Attempt to assign a package to the 'dso' handler if the correct package is installed. =over 2 =item * IMPORTANT NOTE: Only one 'dso' handler can be assigned at a time. =back =item 3. Attempt to assign a package to the Cpanel::EA4::Util::get_default_php_handler() (which if it is cgi, will work since the mod_cgi or mod_cgid Apache modules should be installed (and in the weird case it isn't then at leats they'll get errors instead of source code)). =back =head1 ADDITIONAL INFORMATION This script depends on the packages setting up the correct dependencies and conflicts. For example, this script doesn't check the Apache configuration for MPM ITK when assigning PHP to the SuPHP handler since it assumes the package should already have a conflict detected by the package manager during installation. transaction/__WILDCARD__-php__WILDCARD__/010-suphpconf.pl000075500000007614151027703750016433 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # cpanel - 010-suphpconf.pl Copyright 2017 cPanel, Inc. # All rights Reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited package suphpconf; use strict; use warnings; use Cpanel::SysPkgs::SCL (); our $suphpconf = '/etc/suphp.conf'; run() unless caller; sub run { if ( -e $suphpconf ) { if ( !-e "/usr/local/bin/ea_convert_php_ini" ) { # This madness will go away with EA-5696 warn "Unable to update /etc/suphp.conf without the ea-cpanel-tools package installed.\n"; } else { require "/usr/local/bin/ea_convert_php_ini"; ##no critic (RequireBarewordIncludes) This madness will go away with EA-5696 my $parser = Parse::PHP::Ini->new; my $tree = $parser->parse( path => $suphpconf ); my $handlers = $parser->get_matching_section( $tree, 'handlers' ); if ( !$handlers ) { $handlers = $parser->make_section_node( 'handlers', -1 ); $tree->add_daughter($handlers); } my %packages; @packages{ @{ Cpanel::SysPkgs::SCL::get_scl_versions(qr/\w+-php/) } } = (); # update/cleanout existing entries for my $daughter ( @{ $handlers->{daughters} } ) { if ( $daughter->{name} =~ m{application/x-httpd-(.*)} ) { my $pkg = $1; if ( exists $packages{$pkg} ) { my $cgi_path = _get_cgi_path($pkg); my $count = $daughter->{attributes}{line}; # TODO: make this something else? my $tmp = $parser->make_setting_node( "application/x-httpd-$pkg", qq{"php:$cgi_path"}, $count ); my $attr = $tmp->attribute(); $parser->update_node( $daughter, $attr ); print "Ensuring current entry for “$pkg” is correct …\n"; $packages{$pkg} = "update"; } else { print "Ignoring current entry for “$pkg” …\n"; $packages{$pkg} = "ignore"; } } } # add entries reflecting the actual state for my $pkg ( keys %packages ) { if ( !$packages{$pkg} ) { my $cgi_path = _get_cgi_path($pkg); my $count = 0; # TODO: make this something else? my $setting = $parser->make_setting_node( "application/x-httpd-$pkg", qq{"php:$cgi_path"}, $count ); $handlers->add_daughter($setting); print "Adding entry for “$pkg” …\n"; $packages{$pkg} = "add"; } } # write $suphpconf _write_suphpconf($tree); } } else { print "Nothing to do ($suphpconf does not exist)\n"; } return; } ############### #### helpers ## ############### sub _get_cgi_path { my ($pkg) = @_; my $cgi_path = Cpanel::SysPkgs::SCL::get_scl_prefix($pkg) . "/root/usr/bin/php-cgi"; if ( !-x $cgi_path ) { warn "$cgi_path is not executable, please rectify (e.g. a symlink …/root to the right spot should do the trick)\n"; } return $cgi_path; } sub _write_suphpconf { my ($tree) = @_; # Encapsualte the madness here, NS use noted in /usr/local/bin/ea_convert_php_ini no warnings "once"; local $ea_convert_php_ini_file::Cfg{force} = 1; ea_convert_php_ini_file::write_php_ini( $tree, $suphpconf ); } transaction/ea-apache24-config/000-local_template_check000075500000006312151027703750016664 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # cpanel - SOURCES/000-local_template_check Copyright 2017 cPanel, Inc. # All Rights Reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited package ea_apache24_config_runtime::SOURCES::000_local_template_check; use strict; use warnings; use Cpanel::MD5 (); use Cpanel::JSON (); our $tt_dir = "/var/cpanel/templates/apache2_4"; our %templates = ( 'ea4_main.default' => 'ea4_main.local', 'ssl_vhost.default' => 'ssl_vhost.local', 'vhost.default' => 'vhost.local', ); exit( run(@ARGV) ) unless caller; sub run { my @args = @_; print "Checking ea4 templates …\n"; my @notify; my $had_local = 0; my $tt_data = _get_tt_data($tt_dir); for my $tt ( sort keys %templates ) { next if !-f "$tt_dir/$templates{$tt}"; $had_local++; push( @notify, $tt ) if $tt_data->{_}{just_created} || $tt_data->{$tt}{previous} ne $tt_data->{$tt}{current}; } if (@notify) { if ( $tt_data->{_}{just_created} ) { _send( 1, @notify ); } else { _regen_tt_data($tt_dir); _send( 0, @notify ); } } else { if ($had_local) { print "\tNo updates to ea4 templates, local templates should still be fine.\n"; } else { print "\tNo local templates; nothing to do.\n"; } } print " … done!\n"; return 0; # exit clean } ############### #### helpers ## ############### sub _get_tt_data { my ($dir) = @_; my $just_created = 0; if ( !-f "$dir/000-local_template_check.json" || -z _ ) { _regen_tt_data($dir); $just_created = 1; } my $hr = Cpanel::JSON::LoadFile("$dir/000-local_template_check.json"); $hr->{_}{just_created} = $just_created; for my $tt ( sort keys %templates ) { $hr->{$tt}{current} = Cpanel::MD5::getmd5sum("$dir/$tt"); } return $hr; } sub _regen_tt_data { my ($dir) = @_; my $hr = {}; for my $tt ( sort keys %templates ) { $hr->{$tt}{previous} = Cpanel::MD5::getmd5sum("$dir/$tt"); } Cpanel::JSON::DumpFile( "$dir/000-local_template_check.json", $hr ); return; } sub _send { my ( $first_time, @has_local ) = @_; if ( eval "require Cpanel::iContact::Class::EasyApache::EA4_TemplateCheckUpdated;1" ) { print "\tSending iContact (EA4_TemplateCheckUpdated)\n"; my @templates_aoh; for my $tt (@has_local) { push @templates_aoh, { name => $tt, name_full_path => "$tt_dir/$tt", local => $templates{$tt}, local_full_path => " $tt_dir/$templates{$tt}" }; } Cpanel::iContact::Class::EasyApache::EA4_TemplateCheckUpdated->new( templates => \@templates_aoh, first_time => $first_time ); # yes, new() actually results in message delivery } else { print "\tN/A: System does not have the iContact module “EA4_TemplateCheckUpdated”\n"; } return; } 1; transaction/ea-php__WILDCARD__/011-migrate_extension_to_pecl_ini000075500000006521151027703750020501 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl ############################################################################################## # # Copyright (c) 2017, cPanel, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ############################################################################################## use strict; use warnings; use Cpanel::Version::Tiny (); use Cpanel::Version::Compare (); use File::Slurp (); # because we are not sure if older versions all have the same Cpanel:: modules/functions/behavior # The libraries needed to run this script weren't introduced until this release. exit 0 unless Cpanel::Version::Compare::compare( $Cpanel::Version::Tiny::VERSION_BUILD, '>=', '11.66' ); require Cpanel::ProgLang; # oooold versions do not have this so require it after the version check my $php = Cpanel::ProgLang->new( type => 'php' ); my $installed_phps = $php->get_installed_packages(); # this always returns an array ref for my $php_pkg ( @{$installed_phps} ) { next if ($php_pkg =~ m/alt-php/); print "Processing $php_pkg …\n"; my $source = $php->get_ini( package => $php_pkg )->get_default_system_ini(); my $pecl = $source; $pecl =~ s{/php\.ini$}{/php.d/zzzzzzz-pecl.ini}; print "\t… moving zend_extension and extension directives from php.ini to php.d/zzzzzzz-pecl.ini …\n"; _migrate_extension_directives( $source, $pecl ); } ############### #### helpers ## ############### sub _migrate_extension_directives { my ( $from, $to ) = @_; # 1. grab all extension directives from $from my @from_cont = File::Slurp::read_file($from); $from_cont[-1] .= "\n" if substr( $from_cont[-1], -1, 1 ) ne "\n"; # ensure trailing newline on last line my @extensions = grep { m/^\s*(?:zend_)?extension\s*=/ } @from_cont; if (@extensions) { # 2. write them to $to my @to_cont = -e $to ? File::Slurp::read_file($to) : (); File::Slurp::write_file( $to, ( @extensions, @to_cont ) ); # 3. remove them from $from File::Slurp::write_file( $from, grep( !m/\s*(?:zend_)?extension\s*=/, @from_cont ) ); } return 1; } transaction/ea-php__WILDCARD__/490-restartsrv_apache_php_fpm000075500000002736151027703750017661 0ustar00#!/usr/local/cpanel/3rdparty/bin/perl # Copyright (c) 2016, cPanel, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use strict; use warnings; my $fpm_restart = '/usr/local/cpanel/scripts/restartsrv_apache_php_fpm'; system($fpm_restart) if -x $fpm_restart;