Operating System & Version
CLOUDLINUX 6.10
cPanel & WHM Version
v86.0.18

digiwolf

Member
Apr 29, 2020
5
0
1
Brazil
cPanel Access Level
DataCenter Provider
Hi im having issues whem im trying to create a subdomain, the following error is show on the cpanel screen

Houve um problema na criação do subdomínio:
(XID r843e9) Undefined subroutine &Cpanel::Config::LoadCpUserFile::has_cpuser_file called at /usr/local/cpanel/Cpanel/SPF.pm line 32.
 

digiwolf

Member
Apr 29, 2020
5
0
1
Brazil
cPanel Access Level
DataCenter Provider
I solved the issue, is was e problem on the script perl, i modified and remains like this
Perl:
package Cpanel::SPF;

# cpanel - Cpanel/SPF.pm                             Copyright 2018 cPanel L.L.C.
#                                                           All rights Reserved.
# [email protected]                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

use strict;
use warnings;

use Cpanel::Config::LoadCpUserFile ();
use Cpanel::Config::HasCpUserFile  ();
use Cpanel::DnsUtils::Install      ();
use Cpanel::DnsUtils::AskDnsAdmin  ();
use Cpanel::DIp::MainIP            ();
use Cpanel::Debug                  ();
use Cpanel::DIp::Mail              ();
use Cpanel::LoadModule             ();
use Cpanel::NAT                    ();
use Cpanel::Validate::IP::v4       ();
use Cpanel::SPF::String            ();

sub remove_spf {
    my %OPTS = @_;
    return setup_spf( 'user' => $OPTS{'user'}, 'delete' => 1 );
}

sub remove_a_domains_spf {
    my %OPTS = @_;
    return setup_spf( 'domain' => $OPTS{'domain'}, 'delete' => 1 );
}

sub has_spf {
    my %OPTS = @_;

    my $user = $OPTS{'user'};
    return 0 unless ( $user && Cpanel::Config::HasCpUserFile::has_cpuser_file($user) );
    my $cpuser_ref = Cpanel::Config::LoadCpUserFile::loadcpuserfile($user);

    if ( !defined $cpuser_ref || ref $cpuser_ref ne 'HASH' ) {
        return 0;
    }

    return $cpuser_ref->{'HASSPF'} ? 1 : 0;
}

#Enforces default: +a +mx +ip4:<server IP> ~all
sub make_spf_string {    ## no critic qw(Subroutines::ProhibitExcessComplexity) -- see TODO
    my ( $mechanisms_ar, $mods_hr, $is_complete, $domain ) = @_;

    my $mainip = Cpanel::NAT::get_public_ip( Cpanel::DIp::MainIP::getmainserverip() );
    my @dedicated_ips;

    # We have to accept an IP here for account creation.
    if ($domain) {
        if ( Cpanel::Validate::IP::v4::is_valid_ipv4($domain) ) {
            @dedicated_ips = ($domain);
        }
        else {
            my ( $mail_ips, $from_where ) = Cpanel::DIp::Mail::get_mail_ip_for_domain($domain);

            # strip ipv6 addresses when falling back to the default handler; accounts must be explicitly assigned an address #
            @dedicated_ips = grep { $from_where eq 'DEDICATED' or $from_where eq 'DEFAULT' } split( m/;\s*/, $mail_ips || '' );
        }
    }

    # create the initial construct of the string and add any dedicated IPs to the string #
    my $string = "v=spf1 +a +mx +ip4:$mainip";
    require Cpanel::SPF::Include;
    my $spf_include_hosts_ar = Cpanel::SPF::Include::get_spf_include_hosts();

    if (@dedicated_ips) {
        my $ded_str = join( ' ', map { m/:/ ? "+ip6:$_" : "+ip4:" . Cpanel::NAT::get_public_ip($_) } grep { $_ ne $mainip } @dedicated_ips );
        $string .= ' ' . $ded_str if $ded_str;
    }
    Cpanel::SPF::String::add_spf_includes( \$string, $spf_include_hosts_ar );

    if ( 'ARRAY' eq ref $mechanisms_ar ) {
        #
        # TODO refactor this into _add_existing_spf_mechanisms
        # to reduce complexity
        #
        for my $mechanism (@$mechanisms_ar) {
            my $spf_part;
            if ( my $ref = ref $mechanism ) {
                if ( $ref eq 'ARRAY' ) {
                    $spf_part = ( $mechanism->[0] || '+' ) . lc( $mechanism->[1] ) . ( length $mechanism->[2] ? ":$mechanism->[2]" : q{} );
                }
                else {
                    Cpanel::Debug::log_warn("Invalid SPF reference: $ref");
                    next;
                }
            }
            else {
                if ( $mechanism !~ m{\A.?all\z}i && $mechanism !~ tr{:}{} ) {
                    Cpanel::Debug::log_warn("Invalid SPF string: $mechanism");
                    next;
                }
                if ( $mechanism =~ s/:([+~?-])/:/ ) {
                    $mechanism = "$1$mechanism";
                }
                if ( $mechanism =~ m{\A[+~?-]} ) {
                    $spf_part = $mechanism;
                }
                else {
                    $spf_part = "+$mechanism";
                }
            }

            next if $spf_part =~ m{\A\+?a\z}i;
            next if $spf_part =~ m{\A\+?mx\z}i;
            next if $spf_part =~ m{\A\+?ip4:\Q$mainip\E\z}i;
            next if grep { $spf_part =~ m{\A\+?ip[46]:\Q$_\E\z}i } @dedicated_ips;
            next if grep { $spf_part =~ m{\A\+?include:\Q$_\E\z}i } @$spf_include_hosts_ar;

            $string .= " $spf_part";
        }
    }

    if ( 'HASH' eq ref $mods_hr ) {

        #sort so that we know what the string will look like and can test more easily
        for ( sort keys %$mods_hr ) {
            $string .= " $_=$mods_hr->{$_}";
        }
    }

    if ( $string !~ m{\s[+~?-]all\b} ) {
        $string .= $is_complete ? ' -all' : ' ~all';
    }

    return $string;
}

#
# This function will overwrite existing records by default
#
# If the user already has SPF you
# should probably Cpanel::SPF::Update::update_spf_records
# unless you are creating a new domain
#
sub setup_spf {
    my %OPTS        = @_;
    my $delete      = $OPTS{'delete'};
    my $keys        = $OPTS{'spf_keys'};
    my $is_complete = $OPTS{'is_complete'};
    my $zone_ref    = $OPTS{'zone_ref'};             # Allow passing in the hashref in the format Cpanel::DnsUtils::Fetch returns
    my $overwrite   = $OPTS{'overwrite'};
    my $skipreload  = $OPTS{'skipreload'} ? 1 : 0;
    my $parent      = $OPTS{'parent'};               # may be undef

    # XXX BAD BAD
    # Do not use this flag if you can help it. It doesn’t have good
    # test coverage. Use Cpanel::SPF::Update instead.
    my $preserve = $OPTS{'preserve'};    # case 60047 - preserve custom SPF records

    my $domains_ref;
    my $domain;
    if ( exists $OPTS{'domain'} ) {
        $domain      = $OPTS{'domain'};
        $domains_ref = [$domain];
    }
    elsif ( exists $OPTS{'user'} ) {
        my $user = $OPTS{'user'};
        unless ( Cpanel::Config::HasCpUserFile::has_cpuser_file($user) ) {
            Cpanel::LoadModule::load_perl_module('Cpanel::Locale') if !$INC{'Cpanel/Locale.pm'};

            return ( 0, Cpanel::Locale->get_handle()->maketext( 'Invalid user “[_1]”.', $user ) );
        }
        my $cpuser_ref = Cpanel::Config::LoadCpUserFile::loadcpuserfile($user);
        $domain = $cpuser_ref->{'DOMAIN'};

        $domains_ref = [ $cpuser_ref->{'DOMAIN'} ];
        if ( ref $cpuser_ref->{'DOMAINS'} eq 'ARRAY' ) {
            push @{$domains_ref}, @{ $cpuser_ref->{'DOMAINS'} };
        }
    }
    else {
        Cpanel::LoadModule::load_perl_module('Cpanel::Locale') if !$INC{'Cpanel/Locale.pm'};

        return ( 0, Cpanel::Locale->get_handle()->maketext('No user or domain is specified.') );
    }

    # Silently discard these as they will break dns
    @{$domains_ref} = grep { index( $_, '*' ) == -1 } @{$domains_ref};

    my $mainip = Cpanel::NAT::get_public_ip( Cpanel::DIp::MainIP::getmainserverip() );

    my $spf_match;
    if ( !$delete ) {
        my @zone;
        if ( $zone_ref && $zone_ref->{$domain} ) {
            @zone = ref $zone_ref->{$domain} ? @{ $zone_ref->{$domain} } : split( m{\n}, $zone_ref->{$domain} );
        }
        else {
            @zone = split( /\n/, Cpanel::DnsUtils::AskDnsAdmin::askdnsadmin( "GETZONE", 0, $domain ) );

        }
        @zone = grep ( !/^;/, @zone );
        my @records = grep( / \s+ TXT \s+ "? v=spf /x, @zone );

        #NOTE: This is ok as long as SPF records don't exceed 255 characters
        #or otherwise span multiple character strings.
        if ( $records[0] && $records[0] =~ / \s+ TXT \s+ "? ([^"]+) /x ) {
            $spf_match = $1;
        }
    }
    else {
        $overwrite = 1;
    }

    my @keys_list;
    if ($keys) {
        $keys =~ s{[^\w\s./:,-]+}{}g;

        #Trim and reject (a|mx):$domain
        @keys_list = map { s{\A\s+|\s+\z}{}g; m{\A(?:a|mx):\Q$domain\E\z}i ? () : $_ } split m{,}, $keys;
    }

    if ( $spf_match && $preserve ) {
        push @keys_list, grep { /:/ } split( / +/, $spf_match );
        $is_complete ||= ( $spf_match =~ / -all/ );
    }

    my @installlist;
    foreach my $domain ( @{$domains_ref} ) {
        push @installlist,
          {
            'match'       => 'v=spf',
            'removematch' => ( ( $overwrite || !$spf_match ) ? 'v=spf' : $spf_match ),
            'domain'      => $domain,
            'record'      => $domain,
            'value'       => make_spf_string( \@keys_list, undef, $is_complete, $domain ),
            'zone'        => $parent
          };
    }

    return Cpanel::DnsUtils::Install::install_txt_records( \@installlist, $domains_ref, $delete, $skipreload, $zone_ref );
}

1;
 

cPanelLauren

Product Owner II
Staff member
Nov 14, 2017
13,266
1,304
363
Houston
Hello,

Are you saying that you modified one of cPanel's Perl modules? No changes to these need to be made nor will changes stay. If the issue with creating a subdomain is the error you were receiving indicates that there was a cpuser file in existence for the domain already.
 

digiwolf

Member
Apr 29, 2020
5
0
1
Brazil
cPanel Access Level
DataCenter Provider
It was tested, several times, creating a subdomain, every time changes the error to the lines 32 and the line 115, always creating differents subdomains, and tested with several accounts, and yes i modified the script, i keept all the code i just made a correction, and the problem was solved, the problem started since a upgrade, now the issue is gone.
 
Last edited:

cPanelLauren

Product Owner II
Staff member
Nov 14, 2017
13,266
1,304
363
Houston
It sounds a lot like you had a different issue but "resolved" it by making a change to compensate. I don't know what the issue really was but I'd suggest rather than change code - which isn't guaranteed to stay through an update you open a support ticket to have the issue investigated.
 

digiwolf

Member
Apr 29, 2020
5
0
1
Brazil
cPanel Access Level
DataCenter Provider
It was always the same error just changing the line where the error was, but now resolved, i'm planing to move that server to another 'cause it will lose support this year.