#!/usr/local/cpanel/3rdparty/bin/perl
# cpanel - scripts/unsuspendacct Copyright 2019 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 scripts::unsuspendacct;
use strict;
use warnings;
use Try::Tiny;
use Cpanel::Passwd::Shell ();
use Cpanel::Auth::Shadow ();
use Cpanel::SafeFile ();
use AcctLock ();
use Cpanel::PwCache ();
use Cpanel::ConfigFiles ();
use Cpanel::Validate::Domain::Tiny ();
use Cpanel::Exception ();
use Cpanel::Dovecot::Action ();
use Cpanel::FileUtils::Match ();
use Cpanel::Hooks ();
use Cpanel::Hostname ();
use Cpanel::HttpUtils::ApRestart::BgSafe ();
use Cpanel::PwCache::Clear ();
use Cpanel::AccessIds::ReducedPrivileges ();
use Cpanel::AcctUtils::AccountingLog ();
use Cpanel::AcctUtils::Domain ();
use Cpanel::AcctUtils::Owner ();
use Cpanel::AcctUtils::DomainOwner::Tiny ();
use Cpanel::SafetyBits ();
use Cpanel::Config::LoadCpConf ();
use Cpanel::Config::LoadWwwAcctConf ();
use Cpanel::Config::CpUserGuard ();
use Cpanel::ConfigFiles ();
use Cpanel::IP::Remote ();
use Cpanel::Quota::Temp ();
use Cpanel::ServerTasks ();
use Cpanel::Logger ();
use Cpanel::Auth::Digest::DB::Manage ();
use Cpanel::Mailman::ListManager ();
use Cpanel::MysqlUtils::Suspension ();
use Whostmgr::Accounts::SuspensionData::Writer ();
use Whostmgr::Accounts::Email ();
use Whostmgr::Accounts::Unsuspend ();
use Whostmgr::Accounts::Unsuspend::Htaccess ();
use Cpanel::Validate::Domain::Normalize ();
use Cpanel::Notify ();
use Cpanel::Sys::Setsid::Fast ();
use Cpanel::Locale 'lh';
exit( run(@ARGV) ) unless caller;
my $logger;
sub run { ## no critic qw(Subroutines::ProhibitExcessComplexity)
my @argv = @_;
@argv = grep { $_ ne '--' } @argv;
my $user = $argv[0];
$logger = Cpanel::Logger->new();
local $ENV{'REMOTE_USER'} = $ENV{'REMOTE_USER'};
local $ENV{'USER'} = $ENV{'USER'};
if ( ( !$ENV{'USER'} || !$ENV{'REMOTE_USER'} ) && $> == 0 ) {
$ENV{'REMOTE_USER'} = 'root'; ## no critic qw(Variables::RequireLocalizedPunctuationVars) - local above
$ENV{'USER'} = 'root'; ## no critic qw(Variables::RequireLocalizedPunctuationVars) - local above
}
if ($user) {
$user =~ s/\///g;
}
if ( !$user || $user eq 'root' ) {
print "Usage: unsuspendacct user\n";
return 1;
}
my $pass = ( Cpanel::PwCache::getpwnam($user) )[1];
if ( !$pass ) {
print "“$user” is not a user on this system. Maybe it’s a domain?\n";
my $old_user = $user;
$user = Cpanel::AcctUtils::DomainOwner::Tiny::getdomainowner( $user, { default => undef } );
if ($user) {
print "“$user” is the user who owns that domain. Verifying user …\n";
$pass = ( Cpanel::PwCache::getpwnam($user) )[1] or do {
die "Invalid user ($user)\n";
};
}
else {
die "“$old_user” isn’t a domain, either. Exiting …\n";
}
if ( $old_user ne $user ) {
print "Domain lookup of domain '$old_user' yielded user '$user'\n";
}
}
unless ( $pass =~ m/^\!/ || $pass =~ m/^\*/ ) {
print lh->maketext( 'An error occurred while attempting to unsuspend “[_1]”. The user “[_1]” is not in a suspended state.', $user ) . "\n";
if ( -e "/var/cpanel/bwlimited/$user" ) {
print "\nThe user is currently bandwidth limited. You may remove this limitation by increasing their bandwidth limit.\n";
}
return 1;
}
if ( !do_hook( $user, 'pre' ) ) {
print "Pre-unsuspend hook script returned failure.\n";
return 1;
}
system '/usr/local/cpanel/scripts/preunsuspendacct', @argv if -x '/usr/local/cpanel/scripts/preunsuspendacct';
# Load account creation defaults
my $cref = Cpanel::Config::LoadWwwAcctConf::loadwwwacctconf();
# Determine default shell
my $shell = $cref->{'DEFSHELL'};
if ( !$shell || !-e $shell ) {
$shell = '/bin/bash';
}
my $homedir = Cpanel::PwCache::gethomedir($user);
my %CPCONF = Cpanel::Config::LoadCpConf::loadcpconf();
if ( exists $CPCONF{'acls'} && $CPCONF{'acls'} eq '1' ) {
if ( my $pid = fork() ) {
waitpid( $pid, 0 );
}
else {
Cpanel::Sys::Setsid::Fast::fast_setsid();
Cpanel::SafetyBits::setuids($user);
system(
'setfacl',
'-kb',
'-m', 'group:nobody:x',
'-m', 'group:mail:x',
'-m', 'group:cpanel:x',
'-m', 'group:mailnull:x',
'-m', 'group:65535:x',
'-m', 'group:ftp:x', '--',
$homedir
);
chmod 0750, $homedir;
exit;
}
}
else {
chmod( 0711, $homedir ); # root owns parent
}
if ( -e '/var/cpanel/fileprotect' ) {
my $httpgid = ( getgrnam('nobody') )[2];
my $useruid = ( getpwnam($user) )[2];
Cpanel::SafetyBits::safe_userchgid( $useruid, $httpgid, $homedir . '/public_html' );
Cpanel::SafetyBits::safe_chmod( 0750, $useruid, $homedir . '/public_html' );
Cpanel::SafetyBits::safe_userchgid( $useruid, $httpgid, $homedir . '/.htpasswds' );
Cpanel::SafetyBits::safe_chmod( 0750, $useruid, $homedir . '/.htpasswds' );
}
else {
Cpanel::SafetyBits::safe_chmod( 0755, $user, $homedir . '/public_html' );
Cpanel::SafetyBits::safe_chmod( 0755, $user, $homedir . '/.htpasswds' );
}
#
# Since scripts/suspendacct will chagne the permissions of this file to 0000,
# it is necessary to perform the chmod() operation as root to actually be able
# to restore the permissions.
#
if ( -e '/var/cpanel/noanonftp' ) {
Cpanel::SafetyBits::safe_chmod( 0750, $user, $homedir . '/public_ftp' );
}
else {
Cpanel::SafetyBits::safe_chmod( 0755, $user, $homedir . '/public_ftp' );
}
print "Unsuspending outgoing email....";
Whostmgr::Accounts::Email::unsuspend_outgoing_email( 'user' => $user );
print "Done\n";
my %SUINFO;
if ( open my $suspended_info_fh, '<', '/var/cpanel/suspendinfo/' . $user ) {
while ( readline $suspended_info_fh ) {
chomp;
my ( $name, $value ) = split( /=/, $_ );
next if ( !$name || !$value );
$SUINFO{$name} = $value;
}
close $suspended_info_fh;
unlink '/var/cpanel/suspendinfo/' . $user;
}
my $cpuser_guard = Cpanel::Config::CpUserGuard->new($user);
my $cpuser_data = $cpuser_guard->{'data'};
delete $cpuser_data->{'SUSPENDED'};
$cpuser_guard->save();
AcctLock::acctlock();
# Reset shell
my $newshell;
if ( !$SUINFO{'shell'} ) { $newshell = '/usr/local/cpanel/bin/noshell'; }
elsif ( -x $SUINFO{'shell'} ) { $newshell = $SUINFO{'shell'} }
else { $newshell = $shell; }
try {
Cpanel::Passwd::Shell::update_shell_without_acctlock( 'user' => $user, 'shell' => $newshell );
}
catch {
print Cpanel::Exception::get_string($_) . "\n";
};
my $crypted_pass = ( Cpanel::PwCache::getpwnam($user) )[1];
$crypted_pass =~ s{^\!+}{}g;
my ( $status, $statusmsg ) = Cpanel::Auth::Shadow::update_shadow_without_acctlock( $user, $crypted_pass );
print $statusmsg . "\n" if !$status;
AcctLock::acctunlock();
Cpanel::Auth::Digest::DB::Manage::unlock($user) if Cpanel::Auth::Digest::DB::Manage::has_entry($user);
my @DNS = ( $cpuser_data->{'DOMAIN'} );
if ( exists $cpuser_data->{'DOMAINS'} ) { push @DNS, @{ $cpuser_data->{'DOMAINS'} } }
{
my $tempquota = Cpanel::Quota::Temp->new( user => $user );
$tempquota->disable();
if ( -e "$homedir/etc/webdav/shadow" ) {
print "Unsuspending webdav users\n";
unsuspendshadowfile( $user, "$homedir/etc/webdav/shadow" );
}
foreach my $dns (@DNS) {
$dns = Cpanel::Validate::Domain::Normalize::normalize( $dns, 1 );
next if !Cpanel::Validate::Domain::Tiny::validdomainname($dns);
if ( -f "${homedir}/etc/${dns}/shadow" && !-l "${homedir}/etc/${dns}/shadow" ) {
print "Unsuspending email account logins for $dns .... ";
unsuspendshadowfile( $user, "${homedir}/etc/${dns}/shadow" );
print "Done\n";
}
}
Cpanel::Dovecot::Action::flush_all_auth_caches_for_user($user);
}
my @list_rebuilds;
my $dns_list = join( '|', map { quotemeta($_) } @DNS );
my $suspended_list_files = Cpanel::FileUtils::Match::get_matching_files(
"$Cpanel::ConfigFiles::MAILMAN_ROOT/suspended.lists",
"_(?:$dns_list)" . '$'
);
foreach my $list ( @{$suspended_list_files} ) {
my $unsuspended_list = $list;
$unsuspended_list =~ s/\/suspended.lists\//\/lists\//;
if ( -e $unsuspended_list ) { rename( $unsuspended_list, $unsuspended_list . '.' . time() ) }
rename( $list, $unsuspended_list );
Cpanel::Mailman::ListManager::regenerate_list($unsuspended_list);
}
#FIXME: Everything in this script should eventually be done via this function call.
try {
Whostmgr::Accounts::Unsuspend->new($user);
}
catch {
warn Cpanel::Exception::get_string($_);
};
warn if !eval {
Whostmgr::Accounts::SuspensionData::Writer->new()->unsuspend($user);
1;
};
print "Unsuspending websites...\n";
Whostmgr::Accounts::Unsuspend::Htaccess::unsuspend_htaccess( $user, \@DNS );
_generate_account_suspension_include($user);
my $ftpfile = "$Cpanel::ConfigFiles::FTP_PASSWD_DIR/$user";
# Manipulation of these files isn't thread safe.
# The root file is intentionally locked before checking the existence of the suspended file.
my $ftplock = Cpanel::SafeFile::safelock($ftpfile);
if ( -e $ftpfile . '.suspended' ) {
my $ftpsuspendedlock = Cpanel::SafeFile::safelock("$ftpfile.suspended");
print "Unsuspending FTP accounts...\n";
if ( -e $ftpfile ) {
unlink $ftpfile;
}
rename $ftpfile . '.suspended', $ftpfile or warn "Could not rename $ftpfile.suspended to $ftpfile";
Cpanel::SafeFile::safeunlock($ftpsuspendedlock);
}
Cpanel::SafeFile::safeunlock($ftplock);
Cpanel::ServerTasks::schedule_task( ['CpDBTasks'], 10, "ftpupdate" );
print "${user}'s account is now active\n";
my $domain = Cpanel::AcctUtils::Domain::getdomain($user);
if ( -f '/var/spool/cron.suspended/' . $user ) {
unlink '/var/spool/cron/' . $user;
rename '/var/spool/cron.suspended/' . $user, '/var/spool/cron/' . $user;
}
print "Unsuspending mysql users\n";
Cpanel::MysqlUtils::Suspension::unsuspend_mysql_users($user);
my $owner = Cpanel::AcctUtils::Owner::getowner($user);
$owner =~ s/\n//g;
my $host;
if ( $owner eq '' || $owner eq 'root' || $user eq $owner ) {
$host = Cpanel::Hostname::gethostname();
}
else {
$host = Cpanel::AcctUtils::Domain::getdomain($owner);
}
#if the account reseller does not exist on this server we fall back to root
if ( !$host ) {
$host = Cpanel::Hostname::gethostname();
$owner = 'root';
}
my %account_unsuspension_notification = (
'user' => $user,
'user_domain' => $domain,
'env_remote_user' => $ENV{'REMOTE_USER'},
'env_user' => $ENV{'USER'},
'host_server' => $host,
'origin' => 'Unsuspend Account',
'source_ip_address' => Cpanel::IP::Remote::get_current_remote_ip(),
);
# send root notification
Cpanel::Notify::notification_class(
'class' => 'unsuspendacct::Notify',
'application' => 'unsuspendacct::Notify',
'constructor_args' => [%account_unsuspension_notification]
);
# send one to account reseller as well as long as they are not root
if ( $owner ne 'root' ) {
Cpanel::Notify::notification_class(
'class' => 'unsuspendacct::Notify',
'application' => 'unsuspendacct::Notify',
'constructor_args' => [ %account_unsuspension_notification, 'to' => $owner, 'username' => $owner ]
);
}
Cpanel::AcctUtils::AccountingLog::append_entry( 'UNSUSPEND', [ $user, $domain ] );
Cpanel::PwCache::Clear::clear_global_cache();
do_hook( $user, 'post' );
system '/usr/local/cpanel/scripts/postunsuspendacct', @argv if -x '/usr/local/cpanel/scripts/postunsuspendacct';
print "$user\'s account has been unsuspended\n";
return 0;
}
sub do_hook {
my ( $user, $stage ) = @_;
my ( $result, $hooks_msgs ) = Cpanel::Hooks::hook(
{
'category' => 'Whostmgr',
'event' => 'Accounts::unsuspendacct',
'stage' => $stage,
'escalateprivs' => 1,
},
{
'args' => {
'user' => $user,
},
'result' => 1,
'user' => 'root',
},
);
if ( ref $hooks_msgs eq 'ARRAY' && @$hooks_msgs != 0 ) {
foreach my $error ( @{$hooks_msgs} ) {
print $error;
}
return 0;
}
return 1;
}
sub unsuspendshadowfile {
my ( $user, $file ) = @_;
my $access_ids = Cpanel::AccessIds::ReducedPrivileges->new($user);
return _unsuspendshadowfile($file);
}
sub _unsuspendshadowfile {
my ($file) = @_;
return if !-e $file;
my $shadowlock = Cpanel::SafeFile::safeopen( \*SHF, '+<', $file );
if ( !$shadowlock ) {
$logger->die("Could not update $file: $!");
}
my @CT = <SHF>;
seek( SHF, 0, 0 );
foreach (@CT) {
my @DC = split( /:/, $_ );
chomp( $DC[$#DC] );
foreach my $field ( 1, 8 ) {
while ( $DC[$field] =~ m/^\*LOCKED\*/ ) {
$DC[$field] =~ s/^\*LOCKED\*//;
}
}
print SHF join( ':', @DC ) . "\n";
}
truncate( SHF, tell(SHF) );
return Cpanel::SafeFile::safeclose( \*SHF, $shadowlock );
}
sub _generate_account_suspension_include {
my ($user) = @_;
require "/usr/local/cpanel/scripts/generate_account_suspension_include"; ## no critic qw(Modules::RequireBarewordIncludes) -- refactoring this is too large
generate_account_suspension_include::update_include( 0, $user );
Cpanel::HttpUtils::ApRestart::BgSafe::restart();
return 1;
}
1;
Copyright 2K16 - 2K18 Indonesian Hacker Rulez