#!/usr/local/cpanel/3rdparty/bin/perl # cpanel - scripts/buildeximconf 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 use strict; use warnings; use Cpanel::DKIM (); use Cpanel::Logger (); use Cpanel::Exim::Config (); use Cpanel::Exception (); use Cpanel::FileUtils::Lines (); use Cpanel::Signal (); use Cpanel::StringFunc::Replace (); use Cpanel::Encoder::Tiny (); use Cpanel::FileUtils::Write (); use Cpanel::IP::Neighbors (); use Cpanel::IP::GreyList (); use Cpanel::IP::cPanelMail (); use Cpanel::Email::Perms::System (); use Try::Tiny; local $SIG{'HUP'} = 'IGNORE'; umask(0022); my $logger = Cpanel::Logger->new(); require '/usr/local/cpanel/scripts/checkexim.pl'; Cpanel::IP::Neighbors::update_neighbor_netblocks_or_log(); Cpanel::IP::GreyList::update_trusted_netblocks_or_log(); Cpanel::IP::GreyList::update_common_mail_providers_or_log(); Cpanel::IP::cPanelMail::update_cpanel_mail_netblocks_or_log(); Cpanel::DKIM::setup_file_stores(); Cpanel::Email::Perms::System::ensure_system_perms(); my %OPTS = (); my $use_alt_config = @ARGV && grep( /--local/, @ARGV ) ? 1 : 0; my $acl_dry_run = @ARGV && grep( /--acl_dry_run/, @ARGV ) ? 1 : 0; my $no_chown_spool = @ARGV && grep( /--no_chown_spool/, @ARGV ) ? 1 : 0; my $debug = @ARGV && grep( /--debug/, @ARGV ) ? 1 : 0; if ($use_alt_config) { foreach my $alt_config ( grep( /--local/, @ARGV ) ) { my ( $filetype, $file ) = $alt_config =~ /--([^=]+)=(.*)$/; $OPTS{$filetype} = $file; } } $OPTS{'acl_dry_run'} = 1 if $acl_dry_run; $OPTS{'debug'} = $debug; # CPANEL-36167: Run hulkdsetup to ensure that keys for dovecot are present: system '/usr/local/cpanel/bin/hulkdsetup'; my $exim_cfgobj = Cpanel::Exim::Config->new(%OPTS); $exim_cfgobj->run_script('pre') if !$use_alt_config && !$acl_dry_run; my %CFDATA = $exim_cfgobj->generate_config_file(); my $rawout = $CFDATA{'rawout'}; if ( $use_alt_config || $acl_dry_run ) { if ( !$CFDATA{'goodconf'} ) { print "Dry Run failed\n"; print "Configuration file has an invalid syntax. " . ( $ENV{'WHM50'} ? "" : '' ) . "Please try the edit again." . ( $ENV{'WHM50'} ? "" : '' ) . "\n\n"; print $ENV{'WHM50'} ? "
" . Cpanel::Encoder::Tiny::safe_html_encode_str( $exim_cfgobj->{'broken_cfg_html'} ) . "
" : $exim_cfgobj->{'broken_cfg_text'}; print $rawout; exit 1; } else { print "Dry Run ok\n"; print $rawout; exit 0; } } if ( !$CFDATA{'goodconf'} ) { print "Configuration file has an invalid syntax. " . ( $ENV{'WHM50'} ? "" : '' ) . "Please try the edit again." . ( $ENV{'WHM50'} ? "" : '' ) . "\n\n"; print $rawout; # # We go back 12 lines and forward 2 as this is enough # to show almost all transport and router name which # will make it much easier to determine the failure # point. # print "-= BEGIN exim.conf chunk -=\n"; my @lines = split( /\n/, $exim_cfgobj->{'broken_cfg_text'} ); print join( "\n", @lines[ $exim_cfgobj->{'error_line'} - 12 .. $exim_cfgobj->{'error_line'} + 2 ] ) . "\n"; print "-= END exim.conf chunk -=\n"; $exim_cfgobj->install_virgin_config_if_missing( $CFDATA{'config_template'} ); $exim_cfgobj->run_script( 'post', 'fail' ); exit 1; } else { if ( Cpanel::FileUtils::Write::overwrite_no_exceptions( '/etc/exim.conf', $CFDATA{'cfg'}, 0644 ) ) { Cpanel::FileUtils::Write::overwrite_no_exceptions( '/usr/local/etc/exim/configure', $CFDATA{'cfg'}, 0644 ) if -e '/usr/local/etc/exim/configure'; # XXX ugly hack, because changes to files subject to .include or .include_if_exists can't do dry runs # SRS only gets away with it because it doesn't change, and if it does change, it's not the end of the world if ( $CFDATA{'settings'}->{'smarthost_routelist'} && $CFDATA{'settings'}->{'smarthost_auth_required'} ) { if ( !Cpanel::FileUtils::Write::overwrite_no_exceptions( $Cpanel::Exim::Config::SMARTHOST_AUTH_FILE, <<~EOS, smarthost_login: driver = plaintext public_name = LOGIN hide client_send = : $CFDATA{'settings'}->{'smarthost_username'} : $CFDATA{'settings'}->{'smarthost_password'} EOS 0600 ) ) { die "Unable to write $Cpanel::Exim::Config::SMARTHOST_AUTH_FILE: $!"; } } } else { die "Unable to write /etc/exim.conf: $!"; } print "Configuration file passes test! New configuration file was installed.\n\n"; $exim_cfgobj->setup_spamassassin_handling( $CFDATA{'acl_spam_handler'} ); $exim_cfgobj->build_and_install_exim_pl(); print $exim_cfgobj->{'rawout'}; # SPF is required for KAM and other rulesets so enable by default my $sa_init_pre_file = '/etc/mail/spamassassin/init.pre'; my $sa_match_regex_string = '^\s*#loadplugin Mail::SpamAssassin::Plugin::SPF'; if ( Cpanel::FileUtils::Lines::has_txt_in_file( $sa_init_pre_file, $sa_match_regex_string ) ) { Cpanel::StringFunc::Replace::regsrep( $sa_init_pre_file, $sa_match_regex_string, 'loadplugin Mail::SpamAssassin::Plugin::SPF' ); } $exim_cfgobj->run_script( 'post', 'ok' ); scripts::checkexim::checkeximperms($no_chown_spool); my $err; try { Cpanel::Exim::Config::configure_outgoing_spam_scanning(); } catch { $err = $_; if ( -t STDERR ) { require Cpanel::Term::ANSIColor::Solarize; print STDERR Cpanel::Term::ANSIColor::Solarize::colored( ["bold black on_red"], Cpanel::Exception::get_string($err) ) . "\n"; } else { print STDERR Cpanel::Exception::get_string($err) . "\n"; } }; system '/usr/local/cpanel/scripts/mailscannerupdate', '--force'; system '/usr/local/cpanel/scripts/smtpmailgidonly', '--refresh'; system '/usr/local/cpanel/scripts/update_exim_rejects'; my $exim_caps = $exim_cfgobj->{'exim_caps'}; my $needs_mail_gid_shadow = 0; my $configured_for_external_auth = 1; # dovecot always enabled # Signal cpsrvd to reload its config. Active page hits will not be killed. # do not restart cpsrvd on a fresh install ( cpsrvd is running but is restarted later ) # this avoids to solve continuously "perl dependencies issues" in the exim rpm Cpanel::Signal::send_hup_cpsrvd() if !$ENV{'CPANEL_BASE_INSTALL'}; exit 0; }