LittleDemon WebShell


Linux sh00002.bigrock.com 5.14.0-687.29.1.el9_8.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Jul 23 16:18:48 EDT 2026 x86_64
Path : /scripts/
File Upload :
Command :
Current File : //scripts/builddovecotconf

#!/usr/local/cpanel/3rdparty/bin/perl

#                                      Copyright 2025 WebPros International, LLC
#                                                           All rights reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited.

package scripts::builddovecotconf;

use cPstrict;
use Try::Tiny;

use Cpanel::Config::LoadCpConf        ();
use Cpanel::AdvConfig                 ();
use Cpanel::AdvConfig::dovecot        ();
use Cpanel::AdvConfig::dovecotSNI     ();
use Cpanel::AdvConfig::dovecotSSL     ();
use Cpanel::AdvConfig::dovecot::utils ();
use Cpanel::Usage                     ();
use Cpanel::FileUtils::TouchFile      ();
use Cpanel::Autodie                   ();
use Cpanel::FileUtils::Access         ();
use Cpanel::Mkdir                     ();
use Cpanel::Rand                      ();
use Cpanel::Rand::Get                 ();
use Cpanel::Dovecot                   ();
use DBI                               ();
use DBD::SQLite                       ();
use Cpanel::DBI::SQLite               ();
use Cpanel::LoadModule                ();

our $CONF_PERMS = 0644;
our $itcd_file  = '/var/cpanel/imap_tcp_check_disabled';

__PACKAGE__->script(@ARGV) unless caller();

sub script ( $class, @args ) {
    my ( $force, $leave_broken, $now ) = ( 0, 0, time() );

    Cpanel::Usage::wrap_options(
        \@args, \&usage,
        {
            'force'        => \$force,
            'leave-broken' => \$leave_broken,
        },
    );

    my $cpconf_ref = Cpanel::Config::LoadCpConf::loadcpconf();

    if ( $> != 0 ) {
        die "Insufficient permissions to rebuild dovecot.conf";
    }
    my $dovecot_conf = Cpanel::AdvConfig::dovecot::utils::find_dovecot_conf();

    my $test_dovecot_conf = Cpanel::Rand::get_tmp_file_by_name($dovecot_conf);
    die 'Failed to get a temporary working file!' if ( $test_dovecot_conf eq '/dev/null' );
    chmod( $CONF_PERMS, $test_dovecot_conf ) or die "Could not set permissions on $test_dovecot_conf: $!";

    # make sure the local template is valid
    _check_local_template() if !$leave_broken;

    # It is a good idea to load "our" config and process any changes *before*
    # we rebuild "their" config.
    my $conf_hr = Cpanel::AdvConfig::dovecot::get_config();
    if ( $conf_hr->{'protocols'} =~ /imap(\s|$)/ ) {
        unlink $itcd_file;    # Doesn't matter if it does not exist
    }
    else {
        Cpanel::FileUtils::TouchFile::touchfile('/var/cpanel/imap_tcp_check_disabled');
    }

    # Check if conf values need updating for this upgrade.
    # use save_config as otherwise the changes don't persist in the UI, etc.
    # save_config also processes config changes, so we should invoke that
    # instead of merely process_config_changes.
    # *AMAZINGLY*, this saves a *whole lot more* keys than say whostmgr's UI
    # will save, though that's a consequence of it building config entirely
    # based off the formref instead of augmenting/replacing the existing
    # configuration.
    # This may in fact be a bug in that UI, but is longstanding behavior.
    # All that said, I'm not sure I'm a fan of some of the keys this adds,
    # as things like legacy_wildcard_safe and uniq just seem like garbage.
    Cpanel::AdvConfig::dovecot::save_config();

    my $values_to_change = _generate_config_and_check_syntax( $force, $test_dovecot_conf, $dovecot_conf, $leave_broken );

    # If dovecot complained certain values are too low, we need to adjust them
    if ( scalar keys %$values_to_change ) {
        _generate_config_and_check_syntax( $force, $test_dovecot_conf, $dovecot_conf, $leave_broken, $values_to_change );
    }

    _setup_dovecot_dirs();
    _setup_sqlite_dbs();

    rename $test_dovecot_conf, $dovecot_conf or do {
        warn "Failed to install $dovecot_conf: $!";
    };
    unlink $dovecot_conf . '.datastore';    # Just in case

    _build_includes();

    # Test the config one more time, as the includes may be invalid.
    my @status = Cpanel::AdvConfig::dovecot::check_syntax($dovecot_conf);
    if ( !$status[0] ) {
        print "Configuration test failed. Error details below:\n" . "Status: $status[0]\n" . "$status[1]\n";
        return 0;
    }

    return 1;
}

sub _build_includes {

    for my $include ( 'dovecotSSL', 'dovecotSNI' ) {

        try {
            my $module = "Cpanel::AdvConfig::$include";
            Cpanel::LoadModule::load_perl_module($module);
            $module->new()->rebuild_conf();
        }
        catch {
            warn "The system failed to rebuild Dovecot’s $include configuration file:\n$_";
        };
    }

    return 1;
}

sub _generate_config_and_check_syntax {
    my ( $force, $test_dovecot_conf, $dovecot_conf, $leave_broken, $values_to_change ) = @_;

    my $config_opts_hr = { 'service' => 'dovecot', 'force' => $force, '_target_conf_file' => $test_dovecot_conf };
    if ( $values_to_change and ref $values_to_change eq 'HASH' ) {
        $config_opts_hr->{'values_to_change'} = $values_to_change;
    }

    my ( $returnval, $message ) = Cpanel::AdvConfig::generate_config_file($config_opts_hr);
    if ( !$returnval ) {
        print "Failed to build $dovecot_conf\n$message\n";
        unlink $test_dovecot_conf;
        exit 1;
    }

    ( $returnval, $message, my $new_values_to_change ) = Cpanel::AdvConfig::dovecot::check_syntax($test_dovecot_conf);

    if ( !$returnval ) {
        print <<"EOM";
Configuration generation failed with the following message:

$message

EOM
        unless ($force) {
            unlink $test_dovecot_conf unless ($leave_broken);
            exit 1;
        }
    }

    return $new_values_to_change;
}

sub usage {
    print <<EO_USAGE;
Usage: builddovecotconf [options]

    Options:
      --help          Brief help message
      --force         Force installation of new conf file even if syntax check fails
      --leave-broken  Leave broken dovecot.conf on the disk so that it can be manually examined
EO_USAGE
    exit 0;
}

# Check the local template to make sure it is valid
sub _check_local_template {

    my %results;
    my $do_short_circuit = 1;

    for my $module_short (qw/dovecot dovecotSNI dovecotSSL/) {
        my $module = "Cpanel::AdvConfig::$module_short";

        # If we are a class, pass an object as the first argument:
        my @args_prefix;
        if ( $module->can('new') ) {
            $results{$module_short}->{'obj'} = $module->new();
            push @args_prefix, $results{$module_short}->{'obj'};
        }

        my ( $valid_or_not_found, @errs ) = $module->can('check_if_local_template_is_valid')->(@args_prefix);
        $do_short_circuit &&= $valid_or_not_found;    # If anything is invalid, don't return early.
        $results{$module_short}->@{ 'valid_or_not_found', 'errs' } = ( $valid_or_not_found, [@errs] );

        # If the main template is invalid, force all valid (and thus present) templates to be invalid too:
        if ( $module_short ne 'dovecot' && $module->can('has_local_template')->(@args_prefix) && !$results{'dovecot'}->{'valid_or_not_found'} ) {
            $results{$module_short}->{'valid_or_not_found'} = 0;
            push $results{$module_short}->{'errs'}->@*, 'Parent configuration file is invalid, so assuming included config file is invalid too.';
        }
    }

    return 1 if $do_short_circuit;

    for my $module_short ( keys %results ) {
        my $module = "Cpanel::AdvConfig::$module_short";

        # Skip if not invalid:
        next if $results{$module_short}->{'valid_or_not_found'};

        # Again, if we are a class, pass an object as the first argument:
        my @args_prefix;
        if ( defined $results{$module_short}->{'obj'} ) {
            push @args_prefix, $results{$module_short}->{'obj'};
        }

        my ( $local_template, $error ) = $module->can('get_template_file')->(@args_prefix);
        if ( !$local_template ) {
            print $error . "\n";
            next;
        }

        my $attempts        = 1;
        my $broken_template = _generate_broken_local_template_name($local_template);
        while ( -e $broken_template && $attempts < 11 ) {
            sleep(1);
            $broken_template = _generate_broken_local_template_name($local_template);
        }

        if ( -e $broken_template ) {
            print "The local template file '$local_template' is invalid, but the system was unable to determine an unused filename to rename it to.\n";
            next;
        }

        print "The local template file '$local_template' is invalid. The system will rename it to $broken_template.\n";

        # yes, there is a small race condition here, but I'm betting we never hit it unless we start calling this script a lot more
        rename $local_template, $broken_template;

        # FIXME: Getting up to three iContact notices about the same thing is probably more annoying than it should be.
        $module->can('send_icontact')->( @args_prefix, $broken_template, $results{$module_short}->{'errs'}->@* );
    }

    return;
}

sub _generate_broken_local_template_name {
    my ($local_template) = @_;

    return $local_template . '.broken.' . time . '.' . Cpanel::Rand::Get::getranddata(16);
}

sub _setup_dovecot_dirs {
    Cpanel::Mkdir::ensure_directory_existence_and_mode( $Cpanel::Dovecot::CP_DOVECOT_STORAGE, 0770 );
    Cpanel::FileUtils::Access::ensure_mode_and_owner( $Cpanel::Dovecot::CP_DOVECOT_STORAGE, 0770, 'dovecot' );
    Cpanel::Mkdir::ensure_directory_existence_and_mode( $Cpanel::Dovecot::LASTLOGIN_DIR, 0700 );
    Cpanel::FileUtils::Access::ensure_mode_and_owner( $Cpanel::Dovecot::LASTLOGIN_DIR, 0700, 'dovecot' );
    return 1;
}

sub _setup_sqlite_dbs {
    Cpanel::Autodie::unlink_if_exists($Cpanel::Dovecot::SQLITE_LASTLOGIN_DB_FILE);

    return 1;
}

1;

LittleDemon - FACEBOOK
[ KELUAR ]
Page not found – Sparkplug Films
Small totara tree on ridge above Long Point

Page not found

The page you are looking for doesn't exist, or it has been moved. Please try searching using the form below.