#!/usr/local/cpanel/3rdparty/bin/perl
package scripts::xfertool;
# cpanel - scripts/xfertool Copyright 2013 cPanel, Inc.
# All rights Reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
use strict;
use warnings;
use Cpanel::DnsUtils::Fetch ();
use Cpanel::Hostname ();
use Cpanel::Encoder::URI ();
use Cpanel::DnsUtils::Stream ();
use Cpanel::DnsUtils::AskDnsAdmin ();
use Cpanel::ZoneFile ();
use Cpanel::PwCache ();
use Cpanel::Config ();
use Cpanel::Config::CpUserGuard ();
use Cpanel::ConfigFiles ();
use Cpanel::AccessIds::ReducedPrivileges ();
use Cpanel::Config::WebVhosts ();
use Cpanel::Config::userdata::Load ();
use Cpanel::AcctUtils::Domain ();
use Cpanel::AcctUtils::Owner ();
use Cpanel::AcctUtils::DomainOwner::Tiny ();
use Cpanel::MailTools::DBS ();
use Cpanel::Config::HasCpUserFile ();
use constant _ENOENT => 2;
## if invoked as a script, there is nothing in the call stack
my $invoked_as_script = !caller();
__PACKAGE__->script(@ARGV) if ($invoked_as_script);
sub script {
my ( $package, @args ) = @_;
my $opt = shift(@args);
my $user = shift(@args);
my @DOMAINS;
if ( !Cpanel::PwCache::getpwnam($user) ) {
# check if user looks like a valid domain
if ( $user !~ /.\../ ) {
print "Supplied user '$user' is not found.\n";
exit 1;
}
@DOMAINS = ($user);
# can return 'root' if no other owner found
$user = Cpanel::AcctUtils::DomainOwner::Tiny::getdomainowner( $DOMAINS[0] );
if ( $user eq 'root' ) {
print "Domain '$DOMAINS[0]' cannot be transferred.\n";
exit;
}
}
elsif ( Cpanel::Config::HasCpUserFile::has_cpuser_file($user) ) {
my $cpu_ref = Cpanel::Config::loadcpuserfile($user);
@DOMAINS = ( $cpu_ref->{'DOMAIN'} );
if ( ref $cpu_ref->{'DOMAINS'} ) {
push @DOMAINS, @{ $cpu_ref->{'DOMAINS'} };
}
}
else {
print "Supplied user '$user' is not found.\n";
exit 1;
}
if ( $user eq 'root' ) {
print "Cannot use 'root' user.\n";
exit(1);
}
if ( $opt =~ /(dis)?allowlogins/i ) {
my $dis = $1;
if ( !$user ) {
print "Usage: $0 --(dis)?allowlogins user\n";
exit(1);
}
if ($dis) {
_disallow_logins($user);
}
else {
_allow_logins($user);
}
}
elsif ( $opt =~ /(un)?blockdynamiccontent/i ) {
my $un = $1;
shift @args; # $dest
if ( !scalar @DOMAINS ) {
print "Usage: $0 --(un)?blockdynamiccontent domain/user\n";
exit(1);
}
_block_dynamic_content( $user, \@DOMAINS, ( $un ? 1 : 0 ) );
}
elsif ( $opt =~ /setupmaildest/i ) {
my $dest = shift(@args);
if ( !scalar @DOMAINS ) {
print "Usage: $0 --setupmaildest domain/user primary/secondary/remote\n";
exit(1);
}
_setmaildest( \@DOMAINS, $dest );
}
elsif ( $opt =~ /swapip/i ) {
my $sourceip = shift(@args);
my $targetip = shift(@args);
if ( !scalar @DOMAINS || !$sourceip || !$targetip ) {
print "Usage: $0 --swapip domain/user sourceip destip\n";
exit(1);
}
_changezones( 'SWAPIP', \@DOMAINS, $sourceip, $targetip );
}
elsif ( $opt =~ /changenameservers/i ) {
if ( !scalar @DOMAINS ) {
print "Usage: $0 --changenameservers domain/user NS1 NS2 NS3 ...\n";
exit(1);
}
my @NSLIST = @args;
_changezones( 'NAMESERVERS', \@DOMAINS, \@NSLIST );
}
else {
die "Usage: $0 (--changenameservers|--swapip|--setupmaildest|--blockdynamiccontent|--unblockdynamiccontent)";
}
return;
}
sub _changezones {
my $op = shift;
my $domainref = shift;
my %ZONES = %{ Cpanel::DnsUtils::Fetch::fetch_zones( 'zones' => $domainref ) };
if ( $op eq 'SWAPIP' ) {
my $sourceip = shift;
my $destip = shift;
foreach my $zone ( keys %ZONES ) {
my $zf = Cpanel::ZoneFile->new( text => $ZONES{$zone}, domain => $zone );
if ( $zf->{'status'} ) {
}
if ( !$sourceip || $sourceip == -1 ) {
my @main_a_records = $zf->find_records( 'type' => 'A', 'name' => $zone . '.' );
$sourceip = $main_a_records[0]->{'address'};
}
my @arecords = $zf->find_records( 'type' => 'A' );
if ( !$sourceip ) {
$sourceip = $arecords[0]->{'address'};
}
for ( my $i = 0; $i <= $#arecords; $i++ ) {
if ( $arecords[$i]->{'address'} eq $sourceip ) {
$arecords[$i]->{'address'} = $destip;
}
}
$zf->replace_records( \@arecords );
my $zref = $zf->serialize();
$ZONES{$zone} = $zref;
}
}
elsif ( $op eq 'NAMESERVERS' ) {
my $nsref = shift;
foreach my $zone ( keys %ZONES ) {
my $zf = Cpanel::ZoneFile->new( text => $ZONES{$zone}, domain => $zone );
if ( $zf->{'status'} ) {
}
my @soarecords = $zf->find_records( 'name' => $zone . '.', 'type' => 'SOA' );
$soarecords[0]->{'mname'} = $nsref->[0];
$zf->replace_records( \@soarecords );
my @nsrecords = $zf->find_records( 'name' => $zone . '.', 'type' => 'NS' );
my $first_record = $zf->get_first_record( \@nsrecords );
my $first_record_line = $first_record->{'Line'};
my $first_record_ttl = $first_record->{'ttl'};
$zf->remove_records( \@nsrecords );
foreach my $nameserver ( @{$nsref} ) {
$zf->insert_record_after_line(
{
'ttl' => $first_record_ttl,
'name' => $zone . '.',
'class' => 'IN',
'type' => 'NS',
'nsdname' => $nameserver
},
$first_record_line - 1
);
}
my $zref = $zf->serialize();
$ZONES{$zone} = $zref;
}
}
my $zdata;
my @RELOADLIST;
foreach my $zone ( keys %ZONES ) {
if ( !$ZONES{$zone} ) {
next();
}
my $zonedata = join( "\n", @{ $ZONES{$zone} } );
$zonedata =~ s/\n{4}/\n/g;
if ( $zonedata eq '' ) { next(); }
#we should just edit the soa?
$zonedata = Cpanel::DnsUtils::Stream::upsrnumstream($zonedata); #increase serial number
push @RELOADLIST, $zone;
$zdata .= 'cpdnszone-' . Cpanel::Encoder::URI::uri_encode_str($zone) . '=' . Cpanel::Encoder::URI::uri_encode_str($zonedata) . '&';
}
Cpanel::DnsUtils::AskDnsAdmin::askdnsadmin( 'SYNCZONES', 0, '', '', '', $zdata );
Cpanel::DnsUtils::AskDnsAdmin::askdnsadmin( 'RELOADZONES', 0, join( ',', @RELOADLIST ) );
return;
}
sub _setmaildest {
my $domainref = shift;
my $dest = shift;
if ( !$dest || ( $dest ne 'primary' && $dest ne 'secondary' ) ) {
$dest = 'remote';
}
foreach my $domain ( @{$domainref} ) {
print "Setting mail handling for $domain to : $dest\n";
if ( $dest eq 'primary' ) {
Cpanel::MailTools::DBS::setup( $domain, 'localdomains' => 1, 'remotedomains' => 0, 'secondarymx' => 0, 'update_proxy_subdomains' => 1 );
}
elsif ( $dest eq 'secondary' ) {
Cpanel::MailTools::DBS::setup( $domain, 'localdomains' => 0, 'remotedomains' => 1, 'secondarymx' => 1, 'update_proxy_subdomains' => 1 );
}
else {
Cpanel::MailTools::DBS::setup( $domain, 'localdomains' => 0, 'remotedomains' => 1, 'secondarymx' => 0, 'update_proxy_subdomains' => 1 );
}
}
return;
}
sub _block_dynamic_content {
my $user = shift;
my $domainref = shift;
my $unblock = shift;
my @DYNAMIC_EXTS = qw(dynamiccontent pl plx perl cgi php php4 php5 php6 php3 shtml);
my $host;
my $owner = Cpanel::AcctUtils::Owner::getowner($user);
$owner =~ s/\n//g;
if ( $owner eq '' || $owner eq 'root' || $user eq $owner ) {
$host = Cpanel::Hostname::gethostname();
}
else {
$host = Cpanel::AcctUtils::Domain::getdomain($owner);
}
if ( !$host ) { $host = Cpanel::Hostname::gethostname(); }
my $dynamic_regex = '\.(' . join( '|', @DYNAMIC_EXTS ) . ')$';
my $privs = Cpanel::AccessIds::ReducedPrivileges->new($user);
my $wvh = Cpanel::Config::WebVhosts->load($user);
my %seen_vhost;
for my $domain (@$domainref) {
my $vhost_name = $wvh->get_vhost_name_for_domain($domain) or do {
warn "“$user” has no web vhost for domain “$domain”!\n";
next;
};
next if $seen_vhost{$vhost_name};
my $vh_conf = Cpanel::Config::userdata::Load::load_userdata_domain( $user, $vhost_name );
if ( !$vh_conf || !%$vh_conf ) {
warn "“$user”’s web vhost “$vhost_name” has no configuration!\n";
next;
}
my $docroot = $vh_conf->{'documentroot'} or do {
warn "Configuration for “$user”’s web vhost “$vhost_name” has no document root!\n";
next;
};
my $htaccess = "$docroot/.htaccess";
if ($unblock) {
next if !-e $htaccess;
if ( open my $htaccess_fh, '+<', $htaccess ) {
my @HT = <$htaccess_fh>;
@HT = grep( !/^\s*redirectmatch\s+[\.\\\(]*dynamiccontent/i, @HT );
# Clear final empty line. Previously there was
# a bug in this logic that would leave an extra line in the
# file after every block/unblock cycle.
pop @HT if @HT && ( $HT[-1] eq "\n" );
seek( $htaccess_fh, 0, 0 );
print {$htaccess_fh} join( '', @HT );
truncate( $htaccess_fh, tell($htaccess_fh) );
close $htaccess_fh;
}
elsif ( $! != _ENOENT() ) {
warn "Failed to update htaccess @ $docroot file: $!";
}
}
else {
if ( open my $htaccess_fh, '>>', $htaccess ) {
print {$htaccess_fh} "\nRedirectMatch $dynamic_regex http://$host/cgi-sys/movingpage.cgi\n";
close $htaccess_fh;
}
else {
warn "Failed to update htaccess @ $docroot file: $!";
}
}
$seen_vhost{$vhost_name} = 1;
}
return;
}
sub _allow_logins {
my $user = shift;
$user =~ s/\\//g;
unlink("/var/cpanel/suspended/${user}");
if ( -e '/usr/sbin/pw' ) {
system( '/usr/sbin/pw', 'unlock', $user );
}
else {
system( 'passwd', '-u', $user );
}
# restore user's cron if previously suspended
my $suspended_cron = "/var/spool/cron.suspended/$user";
if ( -e $suspended_cron ) {
link( $suspended_cron, "/var/spool/cron/${user}" ) && unlink $suspended_cron;
}
my $cpuser_guard = Cpanel::Config::CpUserGuard->new($user);
delete $cpuser_guard->{'data'}->{'SUSPENDED'};
$cpuser_guard->save();
return;
}
sub _disallow_logins {
my $user = shift;
$user =~ s/\///g;
# very similar to the code in scripts/suspendacct,
# but cannot be used as webserver & co still need to be available
mkdir( '/var/cpanel/suspended', 0755 ) if ( !-d '/var/cpanel/suspended' );
open( my $sus_fh, ">", "/var/cpanel/suspended/${user}" );
print {$sus_fh} "User transferred to another server.";
close($sus_fh);
if ( -e '/usr/sbin/pw' ) {
system( '/usr/sbin/pw', 'lock', $user );
}
else {
system( 'passwd', '-l', $user );
}
# temporarily suspend crontab
_suspend_cron_for($user);
_suspend_ftp_for($user);
my $cpuser_guard = Cpanel::Config::CpUserGuard->new($user);
$cpuser_guard->{'data'}->{'SUSPENDTIME'} = time();
$cpuser_guard->{'data'}->{'SUSPENDED'} = 1;
$cpuser_guard->save();
return;
}
sub _suspend_cron_for {
my ($user) = @_;
return unless $user;
my $cron = "/var/spool/cron/$user";
return unless -e $cron;
# create cron.suspended dir if missing
my $suspended_dir = "/var/spool/cron.suspended";
mkdir( $suspended_dir, 0700 ) unless -e $suspended_dir;
# set the cron as suspended
link( $cron, "${suspended_dir}/${user}" ) && unlink($cron);
return;
}
sub _suspend_ftp_for {
my $user = shift || return;
my $ftpdir = $Cpanel::ConfigFiles::FTP_PASSWD_DIR; # this same directory is used for both proftpd and pure-ftpd
return if !-d $ftpdir;
my $ftpfile = $ftpdir . '/' . $user;
rename $ftpfile, $ftpfile . '.' . 'suspended';
system '/usr/local/cpanel/bin/ftpupdate', $user;
return;
}
Copyright 2K16 - 2K18 Indonesian Hacker Rulez