# Copyright 1999-2014. Parallels IP Holdings GmbH. All Rights Reserved. package PleskX; # # Agent interface: # # ::checkHost() # # ::new($storagePolicy, $dumpStatusPolicy, $agentsSharedDir) # # ->setDumpType(FULL [default] | SHALLOW | CONFIGURATION | ONLY_MAIL) # # ->selectDomains(@domains) # ->selectClients(@clients) # ->selectAll() # ->selectAllDomains() # ->selectServerSettings() # # ->excludeDomains(@domains) # ->excludeClients(@clients) # # ->dump() # # Plesk agent interface: # # ->setDescription() # use strict; use PleskVersion; use PleskMaxVersion; use PleskStructure; use Status; use SiteApp; use Mailman; use AgentConfig; use DAL; use CommonPacker; use StopWatch; use Logging; use HelpFuncs; use Db::DbConnect; use Db::Connection; use Db::MysqlUtils; use ExtensionPackage; use CapabilityInfoDumper; use ObjectsFilter; use MiscConfigParser; use Encode; use Suspend; use XmlLogger; use vars qw|@ISA|; use vars qw|$FULL $SHALLOW $CONFIGURATION $ONLY_MAIL $ONLY_HOSTING $INCLUDE_APP_DISTRIB $NO_LICENSE %listOfInstalledApplicationsOnServer|; $FULL = 0; $SHALLOW = 1; $CONFIGURATION = 2; $ONLY_MAIL = 4; $ONLY_HOSTING = 8; $INCLUDE_APP_DISTRIB = 16; $NO_LICENSE = 32; sub new { my $self = {}; bless( $self, shift ); $self->_init(@_); return $self; } sub checkHost { my @problems; if ( !AgentConfig::init() ) { push @problems, "Unable to find /etc/psa/psa.conf configuration file"; } else { eval { PleskVersion::init( AgentConfig::get('PRODUCT_ROOT_D') ) }; if ($@) { push @problems, $@; } else { if ( !PleskVersion::isSupported() ) { if ( PleskVersion::atLeast( 8, 6, 0 ) ) { push @problems, "Migration from version >= " . PleskMaxVersion::get() . " is not supported"; } else { push @problems, "Migration from version < 8.6.0 is not supported"; } } } if ( !defined AgentConfig::iconvBin() ) { push @problems, "No 'iconv' binary found on the host"; } } return @problems; } # --- Public instance methods --- sub _init { my ( $self, $storagePolicy, $dumpStatusPolicy, $agentsSharedDir, $skipLogs ) = @_; $self->{collectStatistics} = $self->getCollectStatistics(); if ($self->{collectStatistics}) { $self->{stopWatch} = StopWatch->new(); $self->{stopWatch}->createMarker("all"); use StopWatchPacker; $self->{packer} = StopWatchPacker->new( PleskMaxVersion::get(), $storagePolicy ); } else { use Packer; $self->{packer} = Packer->new( PleskMaxVersion::get(), $storagePolicy ); } $self->{dump_status} = $dumpStatusPolicy; $self->{skip_logs} = $skipLogs; $self->{configuration_dump} = undef; $self->{shallow_dump} = undef; $self->{only_mail_dump} = undef; $self->{only_hosting_dump} = undef; $self->{description} = undef; $self->{dump_vhost} = 0; $self->{dump_full_mail} = 0; $self->{admin_info} = 0; $self->{server_settings} = 0; $self->{dumped_domains} = []; $self->{dumped_clients} = []; $self->{existing_remote_db_servers} = []; $self->{suspender} = Suspend->new(); # domain name => remote web node id # domain name => undef if local $self->{remoteWebNodes} = (); AgentConfig::init() or die "Error: Plesk config file 'psa.conf' is not found\n"; AgentConfig::setSharedDir($agentsSharedDir); AgentConfig::tarBin(); # Pre-caching of values AgentConfig::mysqlBin(); PleskVersion::init( AgentConfig::get('PRODUCT_ROOT_D') ); $self->{dbh} = Db::Connection::getConnection( 'type' => 'mysql', 'user' => 'admin', 'password' => AgentConfig::get('password'), 'name' => 'psa', 'host' => 'localhost', 'utf8names' => 1, 'connRetries' => AgentConfig::getMaxDbConnectionsRetries() ); die "Can not connect to the 'psa' database. Please, check database server is running and connection settings are valid" if (!$self->{dbh}); if ($self->{collectStatistics}) { $self->{dbh}->startCollectStatistics(); } DAL::init( $self->{dbh} ); PleskStructure::init( $self->{dbh} ); Encoding::setDefaultEncoding("UTF-8"); if ( PleskVersion::atLeast( 11, 1, 13 ) ) { ExtensionPackage::init( $self ); } $self->{capability} = CapabilityInfoDumper->new( $self ); $self->{filter} = ObjectsFilter->new( $self ); $self->{has_remote_db_server} = 0; foreach my $ptrHash (@{DAL::getDatabaseServers()}) { if (HelpFuncs::isRemoteHost($ptrHash->{'host'})) { $self->{has_remote_db_server} = 1; last; } } } sub getCollectStatistics { my $envVal = $ENV{'COLLECT_BACKUP_STAT'}; if ($envVal) { return $envVal; } return 0; } sub turnOnMigrationMode{ my ($self) = @_; $self->{packer}->turnOnMigrationMode(); } sub turnOnListingOnlyMode{ my ($self) = @_; $self->{packer}->turnOnListingOnlyMode(); } sub setDecryptFullDump { my ($self) = @_; $self->{packer}->setDecryptFullDump(); } sub setDumpWholeVHost{ my ($self) = @_; $self->{dump_vhost} = 1; } sub setDumpWholeMail{ my ($self) = @_; $self->{dump_full_mail} = 1; } sub setContentTransport{ my $self = shift; my $contentTransportType = shift; $self->{packer}->setContentTransport($contentTransportType, @_) } sub setBackupProfileFileName{ my ($self, $profileName, $profileId ) = @_; die "Invalid backup profile name '$profileName'\n" if index( $profileName, '/' )>=0; $self->{packer}->setBackupProfileFileName( $profileName, $profileId ) if $profileName; } sub setBackupOwnerGuid{ my ($self, $ownerGuid, $ownertype ) = @_; $ownerGuid = PleskStructure::getAdminGuid() if not $ownerGuid; $ownertype = 'server' if not $ownertype; $self->{packer}->setBackupOwnerGuid( $ownerGuid, $ownertype ); } sub getBackupOwnerGuid{ my ($self) = @_; $self->{packer}->getBackupOwnerGuid(); } sub setDumpType { my ( $self, $type ) = @_; if ( $type & $SHALLOW ) { $self->{shallow_dump} = 1; } if ( $type & $CONFIGURATION ) { $self->{configuration_dump} = 1; } if ( $type & $ONLY_MAIL ) { $self->{only_mail_dump} = 1; $self->{only_hosting_dump} = undef; } if ( $type & $ONLY_HOSTING ) { $self->{only_hosting_dump} = 1; $self->{only_mail_dump} = undef; } if ( $type & $INCLUDE_APP_DISTRIB) { $self->{include_app_distrib} = 1; } if ( $type & $NO_LICENSE ) { $self->{no_license} = 1; } } sub setDescription { my ( $self, $description ) = @_; $self->{description} = $description; } sub setExistingRemoteDbServers { my ( $self, $dbServers ) = @_; $self->{existing_remote_db_servers} = $dbServers; } sub selectDomains { my ( $self, @inputDomains ) = @_; @inputDomains = sort { $a cmp $b } @inputDomains; my @pleskDomains = sort { $a cmp $b } PleskStructure::getDomains(); my @missingDomains = HelpFuncs::arrayDifference( \@inputDomains, \@pleskDomains ); if (@missingDomains) { my $msg; my $sitesHash = PleskStructure::getSites(); my @sites = keys %{$sitesHash}; @sites = sort { $a cmp $b } @sites; my @missingDomainsAreSites = HelpFuncs::arrayIntersection(\@missingDomains, \@sites); if (@missingDomainsAreSites) { $msg = "The following domains are additional domains: " . ( join ",", @missingDomainsAreSites ) . ".\n"; $msg .= "Backups of specified domains will be included in backups of their subscriptions." . "\n"; foreach my $site (@missingDomainsAreSites) { $msg .= "Domain '" . $site ."' will be backed up with subscription '" . $sitesHash->{$site} . "'.\n"; } } else { $msg = "The following domains were not found on the host: " . ( join ",", @missingDomains ); } print STDERR "$msg\n"; Logging::warning( $msg, 'MissingDomains' ); @inputDomains = HelpFuncs::arrayIntersection( \@inputDomains, \@pleskDomains ); } $self->{domains} = \@inputDomains if @inputDomains; } sub selectDomainsById { my ( $self, @inputDomains ) = @_; my @pleskDomains = PleskStructure::getDomainsFromId( \@inputDomains ); if( @inputDomains ){ my $msg = "The following domain id's were not found on the host: " . ( join ",", @inputDomains ); print STDERR "$msg\n"; Logging::warning( $msg, 'MissingDomains' ); } $self->selectDomains( @pleskDomains ) if @pleskDomains; } sub selectClients { my ( $self, @inputClients ) = @_; @inputClients = sort { $a cmp $b } @inputClients; my @pleskClients = sort { $a cmp $b } PleskStructure::getClients(); my @missingClients = HelpFuncs::arrayDifference( \@inputClients, \@pleskClients ); if (@missingClients) { my $msg = "The following clients were not found on the host: " . ( join ",", @missingClients ); print STDERR "$msg\n"; Logging::warning( $msg, 'MissingClients' ); @inputClients = HelpFuncs::arrayIntersection( \@inputClients, \@pleskClients ); } $self->_selectClients( \@inputClients ) if @inputClients; } sub selectClientsById { my ( $self, @inputClients ) = @_; my @pleskClients = PleskStructure::getClientsFromId( \@inputClients); if( @inputClients ){ my $msg = "The following clients id's were not found on the host: " . ( join ",", @inputClients ); print STDERR "$msg\n"; Logging::warning( $msg, 'MissingClients' ); } $self->selectClients( @pleskClients ) if @pleskClients; } sub selectResellers { my ( $self, @inputResellers ) = @_; @inputResellers = sort { $a cmp $b } @inputResellers; my @pleskResellers = sort { $a cmp $b } PleskStructure::getResellers(); my @missingResellers = HelpFuncs::arrayDifference( \@inputResellers, \@pleskResellers ); if (@missingResellers) { my $msg = "The following resellers were not found on the host: " . ( join ",", @missingResellers ); print STDERR "$msg\n"; Logging::warning( $msg, 'MissingResellers' ); @inputResellers = HelpFuncs::arrayIntersection( \@inputResellers, \@pleskResellers ); } $self->_selectClients( \@inputResellers ) if @inputResellers; } sub selectResellersById { my ( $self, @inputResellers ) = @_; my @pleskResellers = PleskStructure::getResellersFromId( \@inputResellers); if( @inputResellers ){ my $msg = "The following reseller id's were not found on the host: " . ( join ",", @inputResellers ); print STDERR "$msg\n"; Logging::warning( $msg, 'MissingResellers' ); } $self->selectResellers( @pleskResellers ) if @pleskResellers; } sub _selectClients { my( $self, $logins ) = @_; my @clients; my @resellers; my $admin = 0; foreach my $client(@{$logins}){ my $clType = PleskStructure::getClientType( $client ); push @clients, $client if $clType eq 'client'; push @resellers, $client if $clType eq 'reseller'; $admin = 1 if $clType eq 'admin'; } $self->{resellers} = \@resellers if (@resellers); $self->{clients} = \@clients if (@clients); $self->{dump_all} = 1 if $admin; } sub excludeDomains { my ( $self, @inputDomains ) = @_; @inputDomains = PleskStructure::getDomains() if scalar(@inputDomains)==0; @inputDomains = sort { $a cmp $b } @inputDomains; $self->{exclude_domains} = \@inputDomains; $self->{domains} = [HelpFuncs::arrayDifference($self->{domains}, \@inputDomains)] if exists $self->{domains}; } sub excludeClients { my ( $self, @inputClients ) = @_; @inputClients = PleskStructure::getClients() if scalar(@inputClients)==0; @inputClients = sort { $a cmp $b } @inputClients; $self->{exclude_clients} = \@inputClients; $self->{clients} = [HelpFuncs::arrayDifference($self->{clients}, \@inputClients)] if exists $self->{clients}; } sub excludeResellers { my ( $self, @inputResellers ) = @_; @inputResellers = PleskStructure::getResellers() if scalar(@inputResellers)==0; @inputResellers = sort { $a cmp $b } @inputResellers; $self->{exclude_resellers} = \@inputResellers; $self->{resellers} = [HelpFuncs::arrayDifference($self->{resellers}, \@inputResellers)] if exists $self->{resellers}; } sub domainExcluded{ my ($self, $name ) = @_; if( exists $self->{exclude_domains} ){ foreach my $domain( @{$self->{exclude_domains}} ){ return 1 if $domain eq $name; } } return 0; } sub clientExcluded{ my ($self, $name ) = @_; if( exists $self->{exclude_clients} ){ foreach my $client( @{$self->{exclude_clients}} ){ return 1 if $client eq $name; } } return 0; } sub resellerExcluded{ my ($self, $name ) = @_; if( exists $self->{exclude_resellers} ){ foreach my $reseller( @{$self->{exclude_resellers}} ){ return 1 if $reseller eq $name; } } return 0; } sub selectAll { my ($self) = @_; $self->{dump_all} = 1; } sub selectAllResellers { my ($self) = @_; my @pleskResellers = sort { $a cmp $b } PleskStructure::getResellers(); $self->{resellers} = \@pleskResellers; } sub selectAllClients { my ($self) = @_; my @pleskClients = sort { $a cmp $b } PleskStructure::getClients(); $self->{clients} = \@pleskClients; } sub selectAllDomains { my ($self) = @_; my @pleskDomains = sort { $a cmp $b } PleskStructure::getDomains(); $self->{domains} = \@pleskDomains; } sub selectServerSettings { my ($self) = @_; $self->{server_settings} = 1; Logging::debug( "Select to backup server settings" ); } sub selectAdminInfo { my ($self) = @_; $self->{admin_info} = 1; Logging::debug( "Select to backup Administrator info" ); } sub setSuspend{ my ( $self, $suspend, $suspendSid ) = @_; $self->{suspender}->setSuspend($suspend, $suspendSid); } sub Cleanup{ my $self = shift; $self->{suspender}->unSuspendDomain(); } sub getListOfInstalledApplicationsOnServer { my ($self) = @_; if (scalar keys %listOfInstalledApplicationsOnServer == 0) { if (PleskVersion::atLeast( 10, 3, 0 )) { my @serverApplications = SiteApp::getServerSettingsForApplications(); if (@serverApplications) { foreach my $ptrRow ( @{DAL::getApsPackages103()} ) { my $application = $self->getConcreteApplicationInfo(\@serverApplications, $ptrRow->[6]); if (!$application) { Logging::debug("Can't get '$ptrRow->[0]-$ptrRow->[1]-$ptrRow->[2]' application info by '$ptrRow->[6]'", 'SiteappError'); next; } my $packageArchive = $application->getPackageArchive(); my $packageArchiveFileName = undef; my $packageArchiveDir = undef; my $idx = rindex( $packageArchive, '/' ); if ( $idx > 0 ) { $packageArchiveDir = substr( $packageArchive, 0, $idx); $packageArchiveFileName = substr( $packageArchive, $idx+1); } $listOfInstalledApplicationsOnServer{$application->getRegistryUid()} = [$ptrRow->[0], $ptrRow->[1], $ptrRow->[2], $packageArchiveDir, $packageArchiveFileName, $ptrRow->[4], $ptrRow->[5], $application]; } } } } return \%listOfInstalledApplicationsOnServer; } sub dump { my ($self) = @_; Logging::beginObject('server', 'server'); $self->{packer}->turnOffContent() if $self->{configuration_dump}; my $panelMode = DAL::getPanelMode(); $self->{packer}->setRoot( $self->{description}, $self->{configuration_dump} ? 0: 1, defined($panelMode) ? $panelMode : 'panel', PleskStructure::getAdminGuid() ); if( exists $self->{dump_all} ) { $self->createFullDump(); $self->makeAdminInfoNode() if $self->{admin_info}; eval { $self->makeServerNode() if $self->{server_settings}; $self->{packer}->addServerNodeToDump(); 1; } or do { $self->excludeProblemServerFromBackup( $@ ); } } else{ my $done; $self->beginWriteStatus(); if( $self->{admin_info} or $self->{server_settings} ) { $self->{packer}->addRootAdmin( PleskStructure::getAdminId(), PleskStructure::getAdminGuid() ); $done = 1; } if (exists $self->{resellers}){ $self->createResellersDump(); $done = 1; } if (exists $self->{clients}) { $self->createClientsDump(); $done = 1; } if ( exists $self->{domains} ) { $self->createDomainsDump(); $done = 1; } # Commented due to different behaviour for service plans and reseller plans until making desicion about correct case # $self->dumpResellersTemplates(\@{$self->{resellers}}); $self->{packer}->addRootRoles(); $self->{packer}->addRootUsers(); $self->{packer}->addRootDomains(); if( $self->{server_settings} ){ $self->makeAdminUsersAndRoles(); eval { $self->makeServerNode(); $done = 1; 1; } or do { $self->excludeProblemServerFromBackup( $@ ); } } if( $self->{admin_info} ) { $self->makeAdminInfoNode(); $done = 1; } $self->{packer}->addServerNodeToDump(); $self->{dump_status}->finishObjects(); if ( not $done ) { Logging::error("No objects to dump found"); Logging::endObject(); return 1; } } $self->{suspender}->unSuspendDomain(); my $ret = $self->{packer}->finish(PleskVersion::atLeast( 11, 0, 0 )); if ($self->{collectStatistics}) { $self->writeStatistics(); } Logging::endObject(); return $ret; } ###### Size mode functions ###### sub getSize { my ($self) = @_; use BackupSizeCalculator; my $backupSizeCalculator = BackupSizeCalculator->new( $self ); return $backupSizeCalculator->getSize(); } ###### End Size mode functions ###### sub writeStatistics { my $self = shift; my $logPath = $ENV{'COLLECT_BACKUP_STAT_LOG'}; if (!defined($logPath) || length($logPath) == 0) { $logPath = "perfomance-statistics.log"; } $logPath = ">>" . $logPath; open(LOGFILE, $logPath); print $logPath; print LOGFILE "Date: " . HelpFuncs::getTime() . "\n"; my $allTime = $self->{stopWatch}->getDiff("all"); print LOGFILE "All time: " . $allTime . "\n"; print LOGFILE "Sql time: " . $self->{dbh}->getStatistics()->{sqlTime} . "\n"; my $xmlTarTime = $self->{packer}->getStatistics()->{totalTime}; my $tarTime = $self->{packer}->getStatistics()->{tarTime}; print LOGFILE "Xml time: " . ($xmlTarTime - $tarTime) . "\n"; print LOGFILE "Files time: " . $tarTime . "\n"; print LOGFILE "\n"; close(LOGFILE); } my %commonLimits = ( 'max_wu' => 1, 'max_db' => 1, 'max_pbox' => 1, 'mbox_quota' => 1, 'disk_space' => 1, 'max_traffic' => 1, 'max_subftp_users' => 1, 'max_unity_mobile_sites' => 1, ); my %domainLimits = %commonLimits; $domainLimits{'max_box'} = 1; $domainLimits{'expiration'} = 1; $domainLimits{'max_subdom'} = 1; $domainLimits{'max_maillists'} = 1; $domainLimits{'max_webapps'} = 1; $domainLimits{'max_dom_aliases'} = 1; $domainLimits{'disk_space_soft'} = 1; $domainLimits{'max_traffic_soft'} = 1; $domainLimits{'max_site'} = 1; $domainLimits{'max_site_builder'} = 1; #windows specific limits $domainLimits{'max_cf_dsn'} = 1; $domainLimits{'max_fpse_users'} = 1; $domainLimits{'max_mssql_db'} = 1; $domainLimits{'max_odbc'} = 1; $domainLimits{'max_shared_ssl_links'} = 1; $domainLimits{'mssql_dbase_space'} = 1; $domainLimits{'mysql_dbase_space'} = 1; $domainLimits{'max_iis_app_pools'} = 1; my %clientLimits = %domainLimits; $clientLimits{'max_dom'} = 1; delete $clientLimits{'max_site'}; my %resellerLimits = %clientLimits; $resellerLimits{'max_cl'} = 1; sub getAdminRootPath{ my ($self) = @_; $self->{packer}->regAdminObjectBackupPath( '' ); } my %generalRolePermissions = ( 'userManagement' => 1, 'webSitesAndDomainsManagement' => 1, 'logRotationManagement' => 1, 'anonymousFtpManagement' => 1, 'scheduledTasksManagement' => 1, 'spamfilterManagement' => 1, 'antivirusManagement' => 1, 'databasesManagement' => 1, 'backupRestoreManagement' => 1, 'browseStats' => 1, 'applicationsManagement' => 1, 'sitebuilderManagement' => 1, 'filesManagement' => 1, 'ftpAccountsManagement' => 1, 'dnsManagement' => 1, 'javaApplicationsManagement' => 1, 'mailManagement' => 1, 'mailListsManagement' => 1, 'publishFilesOnTheWeb' => 1, ); sub getRolePermissions { my ($self, $roleId) = @_; my %permissions = %{DAL::getRolePermissions($roleId)}; %permissions = map { $_ => $permissions{$_} } grep { $generalRolePermissions{$_} } keys %permissions; return \%permissions; } sub createFullDump { my ($self) = @_; $self->getAdminRootPath(); $self->{packer}->addRootAdmin( PleskStructure::getAdminId(), PleskStructure::getAdminGuid() ); $self->{dump_status}->start(PleskStructure::getClientsCount(''), PleskStructure::getDomainsCount( '' ) ); my @resellers = sort { $a cmp $b } PleskStructure::getResellers(); @resellers = $self->{filter}->filterSelectedResellers( \@resellers ); foreach my $reseller (@resellers) { my @myclients = sort { $a cmp $b } PleskStructure::getMyClients($reseller); @myclients = $self->{filter}->filterSelectedClients( \@myclients ); my @domains = sort { $a cmp $b } PleskStructure::getDomainsForClient($reseller); @domains = $self->{filter}->filterSelectedDomains( \@domains ); eval { $self->makeClientNode($reseller, \@domains, \@myclients, 0 ); 1; } or do { $self->excludeProblemClientFromBackup( $reseller, $@ ); } } my @clients = sort { $a cmp $b } PleskStructure::getAdminClients(); foreach my $client (@clients) { if( PleskStructure::getClientType( $client ) eq 'client' ){ my @myclients = sort { $a cmp $b } PleskStructure::getMyClients($client); @myclients = $self->{filter}->filterSelectedClients( \@myclients ); my @domains = sort { $a cmp $b } PleskStructure::getDomainsForClient($client); @domains = $self->{filter}->filterSelectedDomains( \@domains ); eval { $self->makeClientNode($client, \@domains, \@myclients, 0 ); 1; } or do { $self->excludeProblemClientFromBackup( $client, $@ ); } } } $self->dumpResellersTemplates(\@resellers); my $adminName = PleskStructure::getAdminName(); $self->{dump_status}->startClient($adminName); my @adminDomains = PleskStructure::getAdminDomains(); @adminDomains = $self->{filter}->filterSelectedDomains( \@adminDomains ); foreach my $domainName(@adminDomains) { eval { $self->makeDomainNode($domainName, 0 ); 1; } or do { $self->excludeProblemDomainFromBackup($domainName, $@); }; } $self->makeAdminUsersAndRoles(); $self->{dump_status}->endClient($adminName); $self->{capability}->dumpServer(); $self->{dump_status}->finishObjects(); } sub excludeProblemClientFromBackup { my ( $self, $clientName, $reason ) = @_; my $clientType = PleskStructure::getClientType( $clientName ); my $clientId = PleskStructure::getClientId( $clientName ); Logging::warning( "$clientType $clientName is skipped from backup due to error: $reason" ); Logging::debug( "$clientType $clientName is skipped from backup due to error: $reason", 'fatal' ); if ( $clientType eq 'client' ) { delete $self->{packer}->{clientNodes}->{$clientId}; } elsif ( $clientType eq 'reseller' ) { delete $self->{packer}->{resellerNodes}->{$clientId}; } } sub excludeProblemDomainFromBackup { my ( $self, $domainName, $reason ) = @_; Logging::warning( "Domain $domainName is skipped from backup due to error: $reason" ); Logging::debug( "Domain $domainName is skipped from backup due to error: $reason", 'fatal' ); my $domainId = PleskStructure::getDomainId( $domainName ); delete $self->{packer}->{domainNodes}->{$domainId}; delete $self->{packer}->{domainShortNodes}->{$domainId}; $self->{suspender}->unSuspendDomain(); } sub excludeProblemSiteFromBackup { my ( $self, $domainId, $ptrSite, $reason ) = @_; Logging::warning( "Domain $ptrSite->{'name'} is skipped from backup due to error: $reason" ); Logging::debug( "Domain $ptrSite->{'name'} is skipped from backup due to error: $reason", 'fatal' ); $self->{packer}->removeSiteNode( $domainId, $ptrSite->{'name'} ); $self->{suspender}->unSuspendDomain(); } sub excludeProblemSubdomainFromBackup { my ( $self, $domainId, $ptrSubdomain, $reason ) = @_; Logging::warning( "Subdomain $ptrSubdomain->{'name'} is skipped from backup due to error: $reason" ); Logging::debug( "Subdomain $ptrSubdomain->{'name'} is skipped from backup due to error: $reason", 'fatal' ); $self->{packer}->removeSubdomainNode( $domainId, $ptrSubdomain->{'name'} ); delete $self->{packer}->{subDomainNodes}->{$ptrSubdomain->{'id'}}; } sub excludeProblemDatabaseFromBackup { my ( $self, $domainId, $db, $reason ) = @_; Logging::warning( "Database $db->{'name'}, type $db->{'type'} is skipped from backup due to error: $reason" ); Logging::debug( "Database $db->{'name'}, type $db->{'type'} is skipped from backup due to error: $reason", 'fatal' ); $self->{packer}->removeDatabaseNode( $domainId, $db ); } sub excludeProblemServerFromBackup { my ( $self, $reason ) = @_; Logging::warning( "Server settings are skipped from backup due to error: $reason" ); Logging::debug( "Server settings are skipped from backup due to error: $reason", 'fatal' ); $self->{packer}->removeServerNode(); } sub excludeProblemMailUserFromBackup { my ( $self, $domainId, $mail, $reason ) = @_; my $domainName = PleskStructure::getDomainNameFromId( $domainId ); Logging::warning( "Mail user $mail->{'mail_name'} on domain $domainName is skipped from backup due to error: $reason" ); Logging::debug( "Mail user $mail->{'mail_name'} on domain $domainName is skipped from backup due to error: $reason", 'fatal' ); $self->{packer}->removeMailuserNode( $domainId, $mail ); } sub excludeProblemMailSystemFromBackup { my ( $self, $domainId, $reason ) = @_; my $domainName = PleskStructure::getDomainNameFromId( $domainId ); Logging::warning( "Mail System on domain $domainName is skipped from backup due to error: $reason" ); Logging::debug( "Mail System on domain $domainName is skipped from backup due to error: $reason", 'fatal' ); $self->{packer}->removeMailSystemNode( $domainId ); } sub excludeProblemHostingFromBackup { my ( $self, $domainId, $hostingType, $reason ) = @_; my $domainName = PleskStructure::getDomainNameFromId( $domainId ); Logging::warning( "Hosting on domain $domainName is skipped from backup due to error: $reason" ); Logging::debug( "Hosting on domain $domainName is skipped from backup due to error: $reason", 'fatal' ); $self->{packer}->removeHostingNode( $domainId, $hostingType ); } sub excludeProblemDnsZoneFromBackup { my ( $self, $domainId, $reason ) = @_; my $domainName = PleskStructure::getDomainNameFromId( $domainId ); Logging::warning( "DNS Service on domain $domainName is skipped from backup due to error: $reason" ); Logging::debug( "DNS Service on domain $domainName is skipped from backup due to error: $reason", 'fatal' ); $self->{packer}->removeDomainDnsZone($domainId); } sub excludeProblemUserFromBackup { my ( $self, $userLogin, $callback, $reason ) = @_; Logging::warning( "User $userLogin is skipped from backup due to error: $reason" ); Logging::debug( "User $userLogin is skipped from backup due to error: $reason", 'fatal' ); $callback->( $userLogin ); } sub excludeProblemRoleFromBackup { my ( $self, $callback, $roleName, $reason ) = @_; Logging::warning( "Role $roleName is skipped from backup due to error: $reason" ); Logging::debug( "Role $roleName is skipped from backup due to error: $reason", 'fatal' ); $callback->( $roleName ); } sub makeAdminLimitsAndPermissions { my ($self) = @_; if ( PleskVersion::atLeast( 10, 4, 0 ) ) { my $permsHash = $self->getPermsHash(PleskStructure::getAdminId()); foreach my $key ( keys %{$permsHash} ) { $self->{packer}->addAdminPermission($key, $permsHash->{$key}); } } } sub makeAdminUsersAndRoles { my ( $self ) = @_; my $adminName = PleskStructure::getAdminName(); my @adminUsersLogins = PleskStructure::getUserLogins( $adminName ); my $callback = sub { $self->{packer}->addAdminUser( @_ ); }; my $callbackFailed = sub { $self->{packer}->removeAdminUser( @_ ); }; $self->addUsers( \@adminUsersLogins, $callback, $callbackFailed ); my $callbackRole = sub { $self->{packer}->removeAdminRole( @_ ); }; for my $roleId ( PleskStructure::getRoleIds( $adminName ) ) { my @role = grep {$_->{'id'}==$roleId and $_->{'isBuiltIn'}==0 } @{DAL::selectSmbRoles()}; eval { if ( @role ) { $self->{packer}->addAdminRole( $role[0]->{'name'}, 0, $self->getRolePermissions($roleId), DAL::getRoleServicePermissions($roleId) ) ; } 1; } or do { $self->excludeProblemRoleFromBackup( $callbackRole, $role[0]->{'name'}, $@ ); } } } sub getClientRootPath{ my ($self, $clientLogin ) = @_; my $clientId = PleskStructure::getClientId($clientLogin); my $clientType = PleskStructure::getClientType($clientLogin); if( $clientType eq 'reseller' ){ return $self->{packer}->regResellersObjectBackupPath( $self->getAdminRootPath(), $clientId, $clientLogin ); } elsif( $clientType eq 'client' ){ if ( PleskVersion::atLeast( 9, 0, 0 ) ) { my $parentId = PleskStructure::getClientParentId( $clientLogin ); my $parentLogin = PleskStructure::getClientNameFromId( $parentId ); return $self->{packer}->regClientObjectBackupPath( $self->getClientRootPath($parentLogin), $clientId, $clientLogin ); } else{ return $self->{packer}->regClientObjectBackupPath( $self->getAdminRootPath(), $clientId, $clientLogin ); } } else{ return $self->getAdminRootPath(); } } sub beginWriteStatus{ my ($self) = @_; my %accounts; my %domains; if( exists $self->{resellers} ){ foreach my $reseller ( @{ $self->{resellers} } ) { $accounts{$reseller} = 1; my @myclients = sort { $a cmp $b } PleskStructure::getMyClients($reseller); @myclients = $self->{filter}->filterSelectedClients( \@myclients ); for my $client( @myclients ){ $accounts{$client} = 1; } foreach my $client( @myclients ){ my @mydomains = sort { $a cmp $b } PleskStructure::getDomainsForClient($client); @mydomains = $self->{filter}->filterSelectedDomains( \@mydomains ); for my $domain( @mydomains ){ $domains{$domain} = 1; } } } } if( exists $self->{clients} ){ foreach my $client ( @{ $self->{clients} } ) { $accounts{$client} = 1; my @mydomains = sort { $a cmp $b } PleskStructure::getDomainsForClient($client); @mydomains = $self->{filter}->filterSelectedDomains( \@mydomains ); for my $domain( @mydomains ){ $domains{$domain} = 1; } } } if( exists $self->{domains} ){ for my $domain( @{$self->{domains}} ){ $domains{$domain} = 1; } } $self->{dump_status}->start( scalar( keys(%accounts) ), scalar( keys( %domains ) ) ); } sub createResellersDump{ my ($self) = @_; my( %clients, %domains ); my $client; foreach my $reseller ( @{ $self->{resellers} } ) { my @myclients = sort { $a cmp $b } PleskStructure::getMyClients($reseller); @myclients = $self->{filter}->filterSelectedClients( \@myclients ); $clients{$reseller} = \@myclients; my @mydomains = sort { $a cmp $b } PleskStructure::getDomainsForClient($reseller); @mydomains = $self->{filter}->filterSelectedDomains( \@mydomains ); $domains{$reseller} = \@mydomains; } foreach my $reseller ( @{ $self->{resellers} } ) { $self->getClientRootPath( $reseller ); eval { $self->makeClientNode($reseller, $domains{$reseller}, $clients{$reseller}, 1 ); 1; } or do { $self->excludeProblemClientFromBackup( $reseller, $@ ); } } } sub createClientsDump { my ( $self ) = @_; my (%clients); foreach my $client ( @{ $self->{clients} } ) { my @mydomains = sort { $a cmp $b } PleskStructure::getDomainsForClient($client); @mydomains = $self->{filter}->filterSelectedDomains( \@mydomains ); $clients{$client} = \@mydomains; } foreach my $client (keys %clients) { $self->getClientRootPath( $client ); eval { $self->makeClientNode( $client, $clients{$client}, undef, 1 ); 1; } or do { $self->excludeProblemClientFromBackup( $client, $@ ); } } } sub getDomainRootPath{ my ($self, $domainName ) = @_; my $sql = "SELECT id, cl_id, name FROM domains WHERE displayName = BINARY '$domainName'"; my $ptrHash; my $domainId; my $clientId; my $domainAscName; if( $self->{dbh}->execute($sql) ) { if ( $ptrHash = $self->{dbh}->fetchhash() ) { $domainId = $ptrHash->{'id'}; $clientId = $ptrHash->{'cl_id'}; $domainAscName = $ptrHash->{'name'}; } } $self->{dbh}->finish(); if ( defined $domainId and defined $clientId and defined $domainAscName) { return $self->{packer}->regDomainObjectBackupPath( $self->getClientRootPath( PleskStructure::getClientNameFromId( $clientId ) ), $domainId, $domainAscName ); } } sub createDomainsDump { my ( $self ) = @_; foreach my $domainName ( @{$self->{domains}} ) { if ( $self->getDomainRootPath( $domainName ) ) { eval { $self->makeDomainNode( $domainName, 1 ); 1; } or do { $self->excludeProblemDomainFromBackup($domainName, $@); }; } else { my $msg = "Unable to backup domain $domainName because of unappropriate database content"; print STDERR "$msg\n"; Logging::warning( $msg, 'PleskDbError' ); } } } sub dumpDomainPersonalPermissions { my ( $self, $domainId, $permId ) = @_; $self->addPermissions( $domainId, 'domain-personal', $permId ); } sub makeClientNode { my ( $self, $clientName, $domains, $childClients, $isroot ) = @_; my ($parent, $clientType ); $clientType = PleskStructure::getClientType( $clientName ); if( $clientType eq 'client' and $self->clientExcluded( $clientName ) ) { Logging::debug("Client '$clientName' is excluded from dump"); return; } if( $clientType eq 'reseller' and $self->resellerExcluded( $clientName ) ) { Logging::debug("Reseller '$clientName' is excluded from dump"); return; } foreach my $dumpedClient( @{$self->{dumped_clients}} ){ if( $dumpedClient eq $clientName ){ Logging::debug("Client '$dumpedClient' already dumped"); return; } } push @{$self->{dumped_clients}}, $clientName; my ( $item, $sql, $ptrHash, $value, %client, $ptrRow, $id, %clientParams ); Logging::beginObject($clientType,$clientName, $self->generateObjectUuidForLogging($clientType,$clientName)); Logging::debug("Client '$clientName' is started") if $clientType eq 'client'; Logging::debug("Reseller '$clientName' is started") if $clientType eq 'reseller'; $self->{dump_status}->startClient($clientName); $sql = "SELECT * FROM clients WHERE login = '$clientName'"; if ( $self->{dbh}->execute($sql) ) { if (my $ptrHash = $self->{dbh}->fetchhash() ) { %client = %{ $ptrHash }; } } $self->{dbh}->finish(); my $clientId = $client{'id'}; $parent = PleskStructure::getClientNameFromId( $client{'parent_id'} ) if exists $client{'parent_id'}; if ( exists $client{'vendor_id'} ){ my $vendorGuid = PleskStructure::getClientGuidFromId( $client{'vendor_id'} ); $client{'vendor-guid'} = $vendorGuid; } $client{'country'} = CommonPacker::normalizeCountry( $client{'country'} ); my %passwd; unless ( $self->{shallow_dump} ) { $sql = "SELECT password, type FROM accounts WHERE id = '" . $client{'account_id'} . "'"; if ( $self->{dbh}->execute($sql) ) { if ( $ptrHash = $self->{dbh}->fetchhash() ) { %passwd = ( 'password' => $ptrHash->{'password'}, 'type' => CommonPacker::normalizePasswordType( $ptrHash->{'type'} ) ); } else { %passwd = ( 'password' => '', 'type' => 'plain' ); my $msg = "Broken referencial integrity: Account password is not found for client " . $client{'account_id'}; print STDERR "$msg\n"; Logging::warning( $msg , 'BrokenDbIntegrity'); } } $self->{dbh}->finish(); } my $status = $client{'status'}; my $doNotDumpDomainTemplates = 0; my $parentType; if( $parent ) { $parentType = PleskStructure::getClientType( $parent ); $client{'owner-guid'} = PleskStructure::getClientGuid( $parent ); $client{'owner-name'} = $parent; } else{ $parentType = 'admin'; $client{'owner-guid'} = PleskStructure::getAdminGuid(); $client{'owner-name'} = 'admin'; } if( $clientType eq 'client' ){ if ( exists $client{'vendor_id'} ){ my $vendorLogin = PleskStructure::getClientNameFromId( $client{'vendor_id'} ); $client{'vendor-login'} = $vendorLogin; } if( $isroot ){ if ($self->{admin_info} or $self->{server_settings}) { $self->{packer}->addAdminClient( $clientId, \%client, \%passwd, $status ); } else { $self->{packer}->addRootClient( $clientId, \%client, \%passwd, $status ); } } else{ if( $parentType eq 'admin' ) { $self->{packer}->addAdminClient( $clientId, \%client, \%passwd, $status ); } elsif( $parentType eq 'reseller' ) { $doNotDumpDomainTemplates = 1; $self->{packer}->addResellerClient($client{'parent_id'}, $clientId, \%client, \%passwd, $status ); } else{ die "Cannot dump client '$clientName' of type '$clientType', parent '$parent' type '$parentType' not supported!"; } } } elsif( $clientType eq 'reseller' ){ if( $isroot ){ if ( $self->{admin_info} or $self->{server_settings} ) { $self->{packer}->addAdminReseller( $clientId, \%client, \%passwd, $status ); } else { $self->{packer}->addRootReseller( $clientId, \%client, \%passwd, $status ); } } else{ if( $parentType eq 'admin' ) { $self->{packer}->addAdminReseller( $clientId, \%client, \%passwd, $status ); } else{ die "Cannot dump client '$clientName' of type '$clientType', parent '$parent' type '$parentType' not supported!"; } } } else{ die "Cannot dump client '$clientName'. unknown type '$clientType'!"; } $sql = "SELECT param,val FROM cl_param WHERE cl_id = $clientId"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( $ptrRow = $self->{dbh}->fetchrow() ) { $clientParams{ $ptrRow->[0] } = $ptrRow->[1]; } } $self->{dbh}->finish(); unless ( $self->{shallow_dump} ) { $self->{packer}->setClientPinfo( $clientId, \%client ); if ( exists( $client{'locale'} ) && $client{'locale'} ) { $self->{packer}->setClientLocale( $clientId, $client{'locale'} ); } if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $self->{packer}->addClientGappsAccount($clientId, \%clientParams); } if ( ($clientType eq 'reseller') or !PleskVersion::atLeast(10, 0, 0) or (DAL::isBusinessModelUpgraded() and ($client{'limits_id'} or $client{'perm_id'})) ) { # # limits # if( $clientType eq 'reseller' ) { $self->addResellerLimits( $clientId, $client{'limits_id'} ); } else{ $self->addClientLimits( $clientId, $client{'limits_id'} ); } $self->addClientOverusePolicy( $clientId, \%clientParams ); $self->{packer}->fixDefaultLimits($clientType,$clientId); # # end limits # $self->addPermissions( $clientId, 'client', $client{'perm_id'} ); #fix bug 88139 if ( !$client{'perm_id'} ) { $self->{packer}->addClientPermission( $clientId, 'cp_access', 'true' ); } $self->addClientMulitpleLoginPermission($clientId, $clientParams{'multiply_login'} ) if exists $clientParams{'multiply_login'}; } # # Domain skeleton # my $skeletonPath = AgentConfig::get('HTTPD_VHOSTS_D') . "/.skel/$clientId"; if ( !$self->{configuration_dump} ) { $self->{packer}->addClientDomainSkeleton( $clientId, $skeletonPath, "skel" ); } } my %ips = PleskStructure::getClientIps($clientName); $self->{packer}->addClientIps( $clientId, \%ips ); $self->addClientTraffic($clientId); unless ($doNotDumpDomainTemplates) { $self->dumpDomainTemplates( $clientId, $clientType ); } if( $childClients and @{$childClients} and @{$domains} ) { # we are in reseller node and should add nodes and before processing of domains, as this could lead to creating users and roles $self->{packer}->addResellerDomainsClientsNodes( $clientId ); } # Make childs dump if( $childClients ){ foreach my $myClientName( @{$childClients} ) { #TO DO check excluded clients. Not worked now my @clientdomains = PleskStructure::getDomainsForClient( $myClientName ); @clientdomains = sort { $a cmp $b } @clientdomains; @clientdomains = $self->{filter}->filterSelectedDomains( \@clientdomains ); eval { $self->makeClientNode($myClientName, \@clientdomains, undef, 0 ); 1; } or do { $self->excludeProblemClientFromBackup( $myClientName, $@ ); } } $self->{packer}->removeResellerChildNodeIfEmpty( $clientId, 'clients' ); } for my $domainName ( @{$domains} ) { eval { $self->makeDomainNode( $domainName, 0 ); 1; } or do { $self->excludeProblemDomainFromBackup( $domainName, $@ ); }; } $self->{packer}->removeResellerChildNodeIfEmpty( $clientId, 'domains' ); my @users = PleskStructure::getUserLogins($clientName); my $callback = sub { $self->{packer}->addClientUser( $clientId, @_ ); }; my $callbackFailed = sub { $self->{packer}->removeClientUser( $clientId, @_ ); }; my $callbackRole = sub { $self->{packer}->removeClientRole( $clientId, @_ ); }; $self->addUsers( \@users, $callback, $callbackFailed ); for my $roleId (PleskStructure::getRoleIds($clientName) ) { my @role = grep {$_->{'id'}==$roleId and $_->{'isBuiltIn'}==0} @{DAL::selectSmbRoles()}; eval { if ( @role ) { $self->{packer}->addClientRole($clientId, $role[0]->{'name'}, 0, $self->getRolePermissions($roleId), DAL::getRoleServicePermissions($roleId)); } 1; } or do { $self->excludeProblemRoleFromBackup( $callbackRole, $role[0]->{'name'}, $@ ); } } $self->getCustomButtonsByOwner( $clientType, $clientId ); if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $self->getSubscription('client', $clientId); } if ( PleskVersion::atLeast( 11, 1, 0 ) ) { if (exists $clientParams{'theme_skin'} and not $self->{configuration_dump}) { if ( $clientType eq 'reseller' ) { $self->{packer}->makeSkinNode($clientParams{'theme_skin'}, $clientName, $clientId); } } } elsif ( PleskVersion::atLeast( 10, 1, 0 ) ) { if ( $clientType eq 'reseller' ) { $self->{packer}->makeBrandingThemeNode($clientName, $clientId); } } if ( PleskVersion::atLeast( 10, 1, 0 ) ) { $self->dumpApsBundle($clientId, 'client'); } $self->processExtensionPackage($clientType, $clientName, $clientId); if ( $clientType eq 'reseller' ) { my $clientsDescriptions = DAL::getClientsDescriptions( $clientId ); my $subscriptionsDescriptions = DAL::getSubscriptionsResellerDescriptions( $clientId ); my @allDescriptions = ( @{$clientsDescriptions}, @{$subscriptionsDescriptions} ); $self->{packer}->makeResellerDescriptionsNode( $clientId, \@allDescriptions ); } $self->{packer}->makeClParamNode( $clientId, $clientType, \%clientParams ); $self->{packer}->finishClient($clientId); $self->{dump_status}->endClient($clientName); Logging::endObject(); } sub addDomainOverusePolicy{ my( $self, $parentId, $params ) = @_; if( exists $params->{'DecompositionRule'} ){ my $oversell = ($params->{'DecompositionRule'} eq 'oversell')? 'true' : 'false'; $self->{packer}->addDomainLimit( $parentId, 'oversell', $oversell ); } my $overuse = 'normal'; if( exists $params->{'OveruseBlock'} ){ if( $params->{'OveruseBlock'} eq 'true' ){ if ( exists $params->{'OveruseSuspend'}) { if ( $params->{'OveruseSuspend'} eq 'true') { $overuse = 'block'; } else { if ( $params->{'OveruseNotify'} eq 'true') { $overuse = 'not_suspend_notify'; } else { $overuse = 'not_suspend'; } } } else { $overuse = 'not_suspend'; } } else { if( $params->{'OveruseNotify'} eq 'true' ){ $overuse = 'notify'; } else { $overuse = 'normal'; } } } $self->{packer}->addDomainLimit( $parentId, 'overuse', $overuse ); } sub addClientOverusePolicy{ my( $self, $parentId, $params ) = @_; if( exists $params->{'DecompositionRule'} ){ my $oversell = ($params->{'DecompositionRule'} eq 'oversell')? 'true' : 'false'; $self->{packer}->addClientLimit( $parentId, 'oversell', $oversell ); } my $overuse; if( $params->{'OveruseBlock'} eq 'true' ){ $overuse = 'block'; } elsif( $params->{'OveruseNotify'} eq 'true' ){ $overuse = 'notify'; } else { $overuse = 'normal'; } $self->{packer}->addClientLimit( $parentId, 'overuse', $overuse ); } sub addPermissions { my ( $self, $parent, $parentType, $id ) = @_; unless($parentType eq 'client' || $parentType eq 'domain-personal') { Logging::warning( "Error: addPermissions: Unexpected type of parent \"$parentType\"",'assert'); return; } my $permsHash = $self->getPermsHash($id); unless ($permsHash) { if ( $parentType eq 'client' ) { $permsHash = $self->fillDefaultClientPermissions(); } else { $permsHash = $self->fillDefaultDomainPermissions(); } } return unless $permsHash; foreach my $key ( keys %{$permsHash} ) { if ( $parentType eq 'client' ) { $self->{packer}->addClientPermission( $parent, $key, $permsHash->{$key} ); } else { $self->{packer}->addDomainPersonalPermission( $parent, $key, $permsHash->{$key} ); } } } sub getXmlPermissions { my ( $self ) = @_; my %xmlPermissions = ( 'create_domains' => 1, 'manage_phosting' => 1, 'manage_php_safe_mode' => 1, 'manage_quota' => 1, 'manage_subdomains' => 1, 'manage_dns' => 1, 'manage_log' => 1, 'manage_crontab' => 1, 'manage_anonftp' => 1, 'manage_webapps' => 1, 'manage_sh_access' => 1, 'manage_maillists' => 1, 'make_dumps' => 1, 'allow_local_backups' => 1, 'allow_ftp_backups' => 1, 'manage_quota' => 1, 'manage_not_chroot_shell' => 1, 'manage_ftp_password' => 1, 'cp_access' => 1, 'remote_access_interface' => 1, 'manage_domain_aliases' => 1, 'manage_virusfilter' => 1, 'manage_spamfilter' => 1, 'manage_webstat' => 1, 'manage_performance' => 1, 'allow_oversell' => 1, 'create_clients' => 1, 'select_db_server' => 1, 'manage_subftp' => 1, 'access_appcatalog' => 1, 'allow_insecure_sites' => 1, 'site_builder' => 1, 'manage_mail_settings' => 1, 'manage_protected_dirs' => 1, 'manage_website_maintenance' => 1, 'manage_php_settings' => 1, 'manage_server_actionlog'=> 1, 'manage_server_admin_access' => 1, 'manage_server_app_vault' => 1, 'manage_server_backup' => 1, 'manage_server_branding' => 1, 'manage_server_coldfusion' => 1, 'manage_server_components' => 1, 'manage_server_crontab' => 1, 'manage_server_custom_buttons' => 1, 'manage_server_db' => 1, 'manage_server_dns_template' => 1, 'manage_server_domain_traffic_report' => 1, 'manage_server_events' => 1, 'manage_server_filesharing' => 1, 'manage_server_firewall' => 1, 'manage_server_google_services' => 1, 'manage_server_info' => 1, 'manage_server_ip_addresses' => 1, 'manage_server_languages' => 1, 'manage_server_license' => 1, 'manage_server_mail' => 1, 'manage_server_maillist' => 1, 'manage_server_mass_email' => 1, 'manage_server_migration' => 1, 'manage_server_modules' => 1, 'manage_server_notifications' => 1, 'manage_server_optimization' => 1, 'manage_server_preview_domain' => 1, 'manage_server_reboot' => 1, 'manage_server_services' => 1, 'manage_server_sessions' => 1, 'manage_server_settings' => 1, 'manage_server_shutdown' => 1, 'manage_server_skeleton' => 1, 'manage_server_spam_filter' => 1, 'manage_server_ssl_certificates' => 1, 'manage_server_summary_report' => 1, 'manage_server_support' => 1, 'manage_server_time' => 1, 'manage_server_ui' => 1, 'manage_server_updates' => 1, 'manage_server_virus_protection' => 1, 'manage_server_vzpp' => 1, 'manage_server_webmail' => 1, 'manage_server_mail_black_white_lists' => 1, 'allow_license_stubs' => 1, 'manage_iis_app_pool' => 1, 'manage_shared_ssl' => 1, 'manage_additional_permissions' => 1, 'manage_server_mailgate' => 1, 'change_limits' => 1, 'access_service_users' => 1, 'remote_db_connection' => 1, 'manage_wordpress_toolkit' => 1, 'manage_security_wordpress_toolkit' => 1, ); return \%xmlPermissions; } sub getPermsHash { my ( $self, $permsId ) = @_; return unless $permsId; my $sql = "SELECT permission,value FROM Permissions WHERE id=$permsId"; my $xmlPermissions = $self->getXmlPermissions(); my %permsHash; if ( $self->{dbh}->execute_rownum($sql) ) { while ( my $ptrRow = $self->{dbh}->fetchrow() ) { my $name = $ptrRow->[0]; my $value = HelpFuncs::convertToTrueFalseString($ptrRow->[1]); $name = "manage_virusfilter" if $name eq "manage_drweb"; $name = "manage_php_settings" if $name eq "manage_php_safe_mode"; next unless exists $xmlPermissions->{$name}; if ( $name eq 'make_dumps' ) { $permsHash{'allow_local_backups'} = $value; $permsHash{'allow_ftp_backups'} = $value; next; } $permsHash{$name} = $value; } } $self->{dbh}->finish(); $sql = "SELECT value FROM Permissions WHERE id = $permsId and (" . "permission = 'ipb_allow' or permission = 'nb_allow')"; if ( $self->{dbh}->execute_rownum($sql) ) { if ( my $ptrRow = $self->{dbh}->fetchrow() ) { my $value = HelpFuncs::convertToTrueFalseString(@{ $ptrRow }[0]); $permsHash{'manage_phosting'} = $value; } } $self->{dbh}->finish(); return \%permsHash; } sub addClientMulitpleLoginPermission { my ( $self, $id, $multiple_sessions ) = @_; $self->{packer}->addClientPermission( $id, 'multiple-sessions', $multiple_sessions ); } sub insertLimit { my ( $self, $parent, $parentType, $name, $value ) = @_; if ( (!defined $value) || ($value eq '') ) { $value = '-1'; } if( $value ne '-1') { if ( $name eq 'expiration' ) { my ( $mday, $mon, $year ) = ( localtime($value) )[ 3 .. 5 ]; $mon++; $year += 1900; $value = sprintf( '%04d-%02d-%02d', $year, $mon, $mday ); } } if ( $parentType eq 'client' || $parentType eq 'reseller' ) { $self->{packer}->addClientLimit( $parent, $name, $value ); } elsif ( $parentType eq 'domain' ) { $self->{packer}->addDomainLimit( $parent, $name, $value ); } else { Logging::warning( "Error: insertLimits: Unexpected type of parent \"$parentType\"",'assert'); } } sub addResellerLimits { my ( $self, $resellerId, $limitsId ) = @_; return $self->addLimits( $resellerId, 'reseller', $limitsId, \%resellerLimits ); } sub addClientLimits { my ( $self, $clientId, $limitsId ) = @_; return $self->addLimits( $clientId, 'client', $limitsId, \%clientLimits ); } sub addDomainLimits { my ( $self, $domainId, $limitsId ) = @_; return $self->addLimits( $domainId, 'domain', $limitsId, \%domainLimits ); } sub addLimits { my ( $self, $parent, $parentType, $limitId, $limitNames ) = @_; my $count = 0; if ( !$limitId ) { if ( $limitNames ) { foreach my $key ( keys %{$limitNames} ) { next if $key eq 'max_pbox'; my $val = ($key eq 'max_site' && !PleskVersion::atLeast( 10, 0, 0 )) ? "1" : "-1"; $self->insertLimit( $parent, $parentType, $key, $val ); $count++; } } return $count; } my ( $sql, $ptrRow, $value, $name ); $sql = "SELECT limit_name,value FROM Limits WHERE id=$limitId"; if ( $self->{dbh}->execute_rownum($sql) ) { $count = 0; while ( $ptrRow = $self->{dbh}->fetchrow() ) { ( $name, $value ) = @{$ptrRow}; next unless exists $limitNames->{$name}; $self->insertLimit( $parent, $parentType, $name, $value ); $count++; } } $self->{dbh}->finish(); return $count; } sub dumpDomainTemplates { my ( $self, $clientId, $clientType ) = @_; if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $self->dumpTemplates( $clientId, $clientType, 'domain' ); $self->dumpTemplates( $clientId, $clientType, 'domain_addon' ); } else { my $sql; my $tmpl_id; if ($clientId) { $sql = "SELECT tmpl_id FROM clients WHERE id=$clientId"; if ( $self->{dbh}->execute_rownum($sql) ) { if( my $rowPtr = $self->{dbh}->fetchrow() ) { $tmpl_id = @{ $rowPtr }[0]; } } $self->{dbh}->finish(); $self->dumpTemplates9x( $clientId, $clientType, $tmpl_id, 'domain' ) if $tmpl_id; } } } sub dumpResellersTemplates { my ( $self, $resellers ) = @_; return unless (ref($resellers) =~ /ARRAY/ && $self->{packer}->{migrationMode} && PleskVersion::atLeast( 10, 0, 0 )); foreach my $reseller (@{$resellers}) { $self->dumpResellerTemplate(PleskStructure::getClientId($reseller)); } } sub dumpResellerTemplate { my ( $self, $resellerId ) = @_; return unless ($self->{packer}->{migrationMode} && PleskVersion::atLeast( 10, 0, 0 )); my $planId = PleskStructure::getResellerPlanId($resellerId); if (defined $planId) { my $adminId = PleskStructure::getAdminId(); $self->dumpTemplate($adminId, 'server', $planId, 'reseller'); } } sub dumpTemplates { my ( $self, $parent, $parentType, $templateType ) = @_; return $self->dumpTemplates9x($parent, $parentType, undef, $templateType); } # explicit function for dumping single plan to avoid legacy suffix 9x sub dumpTemplate { my ( $self, $parent, $parentType, $template, $templateType ) = @_; return $self->dumpTemplates9x($parent, $parentType, $template, $templateType); } # list of attributes for template-item node in dump.xml my %template_items = ( 'webmail' => 1, 'disk_space' => 1, 'disk_space_soft' => 1, 'stat_ttl' => 1, 'maillists' => 1, 'wu_script' => 1, 'max_traffic' => 1, 'max_traffic_soft' => 1, 'max_box' => 1, 'mbox_quota' => 1, 'max_wu' => 1, 'max_db' => 1, 'max_maillists' => 1, 'max_webapps' => 1, 'max_subdom' => 1, 'max_site' => 1, 'max_dom_aliases' => 1, 'expiration' => 1, 'max_subftp_users'=> 1, 'vh_type' => 1, 'quota' => 1, 'ssl' => 1, 'same_ssl' => 1, 'fp' => 1, 'fp_ssl' => 1, 'fp_auth' => 1, 'asp' => 1, 'ssi' => 1, 'php' => 1, 'cgi' => 1, 'perl' => 1, 'python' => 1, 'fastcgi' => 1, 'coldfusion' => 1, 'webstat' => 1, 'errdocs' => 1, 'shell' => 1, 'pdir_plesk_stat' => 1, 'dns_type' => 1, 'php_handler_type'=> 1, 'php_handler_id' => 1, 'php_safe_mode' => 1, 'max_connections' => 1, 'bandwidth' => 1, 'miva' => 1, 'sb_publish' => 1, 'nonexist_mail' => 1, 'catch_addr' => 1, 'bounce_mess' => 1, 'max_site_builder' => 1, 'max_unity_mobile_sites' => 1, 'upsell_site_builder' => 1, 'allow_license_stubs' => 1, 'mailservice' => 1, # client template 'cp_access' => 1, 'create_domains' => 1, 'manage_phosting' => 1, 'manage_php_safe_mode' => 1, 'manage_quota' => 1, 'manage_dns' => 1, 'manage_log' => 1, 'manage_crontab' => 1, 'manage_anonftp' => 1, 'manage_webapps' => 1, 'manage_maillists' => 1, 'manage_sh_access' => 1, 'manage_not_chroot_shell' => 1, 'manage_subdomains' => 1, 'manage_virusfilter' => 1, 'manage_drweb' => 1, 'allow_local_backups' => 1, 'allow_ftp_backups' => 1, 'remote_access_interface' => 1, 'manage_domain_aliases' => 1, 'manage_spamfilter' => 1, 'manage_webstat' => 1, 'manage_performance' => 1, 'select_db_server' => 1, 'manage_subftp' => 1, 'access_appcatalog' => 1, 'allow_insecure_sites' => 1, 'manage_website_maintenance' => 1, 'manage_protected_dirs' => 1, 'manage_mail_settings' => 1, 'manage_php_settings' => 1, 'excl_ip_num' => 1, 'excl_ipv6_num' => 1, 'max_dom' => 1, #reseller 'create_clients' => 1, 'allow_oversell' => 1, 'oversell' => 1, #overselling 'overuse' => 1, 'max_cl' => 1, #server 'shared' => 1, #windows specific permissions 'manage_additional_permissions' => 1, 'manage_iis_app_pool' => 1, 'manage_shared_ssl' => 1, #windows specific limits 'max_cf_dsn' => 1, 'max_fpse_users' => 1, 'max_mssql_db' => 1, 'max_odbc' => 1, 'max_shared_ssl_links' => 1, 'mssql_dbase_space' => 1, 'mysql_dbase_space' => 1, 'max_iis_app_pools' => 1, 'unpaid_website_status' => 1, 'remote_db_connection' => 1, 'outgoing_messages_domain_limit' => 1, 'outgoing_messages_mbox_limit' => 1, 'outgoing_messages_subscription_limit' => 1, 'outgoing_messages_enable_sendmail' => 1, 'manage_wordpress_toolkit' => 1, 'manage_security_wordpress_toolkit' => 1, ); my %dumped_templates; sub dumpTemplates9x { my ( $self, $parent, $parentType, $tmpl_id, $templateType ) = @_; my $sql; my $ownerGuid; my %templateNames; my %templateUuids; my %templateExtIds; if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $ownerGuid = PleskStructure::getClientGuidFromId($parent); $sql = "SELECT * FROM Templates WHERE "; if ($tmpl_id) { $sql .= "id = $tmpl_id"; } else { $sql .= "owner_id = $parent AND type = '$templateType'"; } if ( $self->{dbh}->execute($sql) ) { while ( my $ptrHash = $self->{dbh}->fetchhash() ) { my $id = $ptrHash->{'id'}; if (not exists $dumped_templates{$id}) { $dumped_templates{$id} = 1; $templateNames{ $id } = $ptrHash->{'name'}; $templateUuids{ $id } = $ptrHash->{'uuid'}; $templateExtIds{ $id } = $ptrHash->{'external_id'} if defined $ptrHash->{'external_id'} and $ptrHash->{'external_id'} ne ''; } } } } elsif ($tmpl_id) { $sql = "SELECT t.id, t.name FROM Templates t, Repository r WHERE r.rep_id=$tmpl_id AND r.component_id = t.id"; if ( $self->{dbh}->execute($sql) ) { while ( my $ptrRow = $self->{dbh}->fetchrow() ) { $templateNames{ $ptrRow->[0] } = $ptrRow->[1]; } } } else { Logging::debug("Warning: Empty template ID provided while dumping templates"); } $self->{dbh}->finish(); my %planItems; my @planItemNames = @{$self->getPlanItemNames()}; while ( my ( $template_id, $tmpl_name ) = each %templateNames ) { my @template; my $logrotation_id; my $ip_pool_id; my $overuse_block; my $overuse_notify; my $overuse_suspend; my $aps_bundle_filter_id = undef; my %phpSettings = undef; my @defaultDbServers; my %webServerSettings; if ( $self->{dbh}->execute("SELECT element, value FROM TmplData WHERE tmpl_id=$template_id") ) { my @tmplData; while ( my $ptrRow = $self->{dbh}->fetchrow() ) { my @tmplElem = @{$ptrRow}; push @tmplData, \@tmplElem; } foreach my $ptrRow (@tmplData) { my ( $element, $value ) = @{$ptrRow}; if ( !defined($value) ) { $value = ''; } if ( $element eq 'stat_ttl' and ( $value == 0 or $value eq '' ) ) { $value = -1; } if ( $element eq 'logrotation_id' ) { $logrotation_id = $value; next; } if ($element eq 'tmpl_pool_id') { $ip_pool_id = $value; next; } if( $element eq 'overuse_block' ){ $overuse_block = $value; next; } if( $element eq 'overuse_notify' ){ $overuse_notify = $value; next; } if ( $element eq 'overuse_suspend' ){ $overuse_suspend = $value; next; } if ( not exists $template_items{$element} ) { if ( PleskVersion::atLeast( 10, 1, 0 ) ) { if ( grep $_ eq $element, @planItemNames) { $planItems{ $element } = $value; } if ($element eq 'aps_bundle_filter_id') { $aps_bundle_filter_id = $value; } } if ( PleskVersion::atLeast( 10, 4, 0) ) { if ($element eq 'phpSettingsId') { %phpSettings = %{DAL::getPhpSettings($value)}; my $phpSettingsNoticeText = DAL::getPhpSettingsNoticeText($value); $phpSettings{'notice'} = $phpSettingsNoticeText if defined $phpSettingsNoticeText; } } if ( PleskVersion::atLeast( 11, 0, 0) ) { if ($element eq 'default_server_mysql' or $element eq 'default_server_postgresql' ) { foreach my $ptrHash (@{DAL::getDatabaseServers()}) { if ($value == $ptrHash->{'id'}) { push @defaultDbServers, $ptrHash; } } } } if ( PleskVersion::atLeast( 11, 5, 21 ) ) { if ($element eq 'webServerSettingsId') { foreach my $settings (@{DAL::getWebServerSettings($value)}) { my ( $settingName, $settingValue ) = @{$settings}; my @data = ( $settingName, $self->{packer}->{base64}->{'ENCODE'}->($settingValue) ); push @template, \@data; } } } next; } if ( 'domain_addon' eq $templateType ) { # skip items which are not allowed for domain_addon template my %template_items_ignore_addon = ( 'cp_access' => 1, 'remote_access_interface' => 1, 'disk_space_soft' => 1, 'max_traffic_soft' => 1, 'stat_ttl' => 1, 'maillists' => 1, 'overuse' => 1, 'dns_type' => 1, 'nonexist_mail' => 1 ); next if exists $template_items_ignore_addon{$element}; } if ( 'domain' eq $templateType ) { # skip items which are not allowed for domain template next if ($element eq 'cp_access' or $element eq 'remote_access_interface'); } if ( $element eq 'quota' and ( $value eq 'false' or $value == 0 ) ) { $value = -1; } my %emptyableBoolElementInTemplate = ( 'asp' => 1, 'cgi' => 1, 'coldfusion' => 1, 'pdir_plesk_stat' => 1, 'perl' => 1, 'php' => 1, 'python' => 1, 'ssi' => 1 ); if ( $value eq '' and exists $emptyableBoolElementInTemplate{$element} ) { $value = 'false'; } if ( $element eq 'php_handler_id' ){ my $phphandlers = HostingDumper::getPhpHandlers(); if (exists $phphandlers->{$value}) { my @phpHandlerType = ('php_handler_type', $phphandlers->{$value}{'type'}); push @template, \@phpHandlerType; my @phpVersion = ('php_version', $phphandlers->{$value}{'version'}); push @template, \@phpVersion; } } my @data = ( $element, $value ); push @template, \@data; } } $self->{dbh}->finish(); my $logRotation = {}; if ( $logrotation_id and ( $templateType eq 'domain' ) ) { $logRotation = DAL::getLogrotation($logrotation_id); } my %ipPool; if ( $ip_pool_id and ( $templateType eq 'reseller' or $templateType eq 'client' ) ) { %ipPool = $self->makeTemplateIpPool($ip_pool_id); } if( $overuse_block and ('domain_addon' ne $templateType )){ my @data = ( 'overuse' ); if( $overuse_block eq 'true' ) { if ( $overuse_suspend ) { if ($overuse_suspend eq 'true') { push @data, 'block'; } else { if ($overuse_notify eq 'true') { push @data, 'not_suspend_notify'; } else { push @data, 'not_suspend'; } } } else { push @data, 'block'; } } elsif( $overuse_notify and $overuse_notify eq 'true' ) { push @data, 'notify'; } else{ push @data, 'normal'; } push @template, \@data; } my @templateAttrs; if ( defined $templateUuids{$template_id} ) { my @guidAttr = ( 'guid', $templateUuids{$template_id}); push @templateAttrs, \@guidAttr; } if ( defined $templateExtIds{$template_id} ) { my @extIdAttr = ( 'external-id', $templateExtIds{$template_id}); push @templateAttrs, \@extIdAttr; } if ( defined $ownerGuid ) { my @ownerGuidAttr = ( 'owner-guid', $ownerGuid); push @templateAttrs, \@ownerGuidAttr; } if ( $templateType eq 'domain_addon') { my @isAddonAttr = ( 'is-addon', 'true'); push @templateAttrs, \@isAddonAttr; } my @apsFilterItems; my $filterType; if (defined($aps_bundle_filter_id)) { @apsFilterItems = @{DAL::getApsBundleFilterItems($aps_bundle_filter_id)}; $filterType = DAL::getApsBundleFilterType($aps_bundle_filter_id); } my %packerData; $packerData{'attributes'} = \@templateAttrs; $packerData{'data'} = \@template; $packerData{'items'} = \%planItems; $packerData{'log-rotation'} = $logRotation; $packerData{'ip-pool'} = \%ipPool; $packerData{'aps-filter-items'} = \@apsFilterItems; $packerData{'aps-filter-type'} = $filterType; $packerData{'php-settings'} = \%phpSettings; $packerData{'default-db-servers'} = \@defaultDbServers; if ( $parentType eq 'server' ) { $self->{packer}->addTemplateToServer($templateType, $tmpl_name, \%packerData); } elsif ( $parentType eq 'reseller' ) { if ( 'domain' eq $templateType or 'domain_addon' eq $templateType) { $self->{packer}->addResellerDomainTemplate( $parent, $tmpl_name, \%packerData); } else { Logging::warning("Error: dumpTemplates: unexpected template type \"$templateType\" for parent \"$parentType\"",'assert'); } } elsif ( $parentType eq 'client' ) { if ( 'domain' eq $templateType or 'domain_addon' eq $templateType) { $self->{packer}->addClientDomainTemplate( $parent, $tmpl_name, \%packerData); } else { Logging::warning("Error: dumpTemplates: unexpected template type \"$templateType\" for parent \"$parentType\"",'assert'); } } else { Logging::warning("Error: dumpTemplates: Unexpected type of parent \"$parentType\"",'assert'); } } } sub makeTemplateIpPool { my ( $self, $ip_pool_id ) = @_; my $sql = "SELECT IP_Addresses.`ip_address`, ip_pool.`type`" . " FROM ip_pool". " LEFT JOIN IP_Addresses ON ip_pool.`ip_address_id` = IP_Addresses.`id`" . " WHERE ip_pool.`id` = $ip_pool_id"; my %ipPool = (); if ( $self->{dbh}->execute_rownum($sql) ) { while ( my $ptrRow = $self->{dbh}->fetchrow() ) { $ipPool{ $ptrRow->[0] } = $ptrRow->[1]; } } $self->{dbh}->finish(); return %ipPool; } sub makeDomainNode { my ( $self, $domainName, $isroot ) = @_; if( $self->domainExcluded( $domainName ) ) { Logging::debug("Domain '$domainName' is excluded from dump"); return; } foreach my $dumpedDomain( @{$self->{dumped_domains}} ){ if( $dumpedDomain eq $domainName ){ Logging::debug("Domain '$domainName' already dumped"); return; } } push @{$self->{dumped_domains}}, $domainName; Logging::debug("Domain '$domainName' is started"); Logging::beginObject('domain',$domainName, $self->generateObjectUuidForLogging('domain', $domainName)); $self->{dump_status}->startDomain($domainName); my ( $sql, $ptrHash ); Logging::debug("Getting domain info"); my $domainPtr; $domainPtr = DAL::getDomainPtr($domainName); unless( $domainPtr ) { Logging::error("Failed to get domain hash for '$domainName'",'PleskDbError'); Logging::endObject(); return; } my %domain = %{$domainPtr}; # There are no guid field in 'domains' table in the old Plesk, but currently it is a required parameter, so we set empty guid here and it will be replaced with non-empty value by resolver $domain{'guid'} = '' if !defined $domain{'guid'}; my $domainId = $domain{'id'}; my $clientId = $domain{'cl_id'}; if ($self->{packer}->{migrationMode} && !$self->{admin_info} && !$self->{packer}->{listingOnlyMode} && $isroot && PleskVersion::atLeast( 10, 0, 0)) { my @roles = @{DAL::selectSmbRoles()}; foreach my $role ( @roles ) { my $roleAdded = 0; my @users = @{DAL::getUsersLoginsByRoleId($role->{'id'})}; foreach my $userLogin ( @users ) { my $userHash = DAL::getUserHash($userLogin); next if (! keys %$userHash); # if hash is empty (error occurred) if ((defined $userHash->{'subscriptionDomainId'} && $userHash->{'subscriptionDomainId'} == $domainId) || (defined $userHash->{'mailDomId'} && $userHash->{'mailDomId'} == $domainId)) { $userHash->{'subscriptionDomainId'} = $domainId; # restrict users, which is moved to admin, to block possible access of a customer to all admin's subscriptions if (!$roleAdded) { $self->{packer}->addRootRole( $role->{'name'}, $role->{'isBuiltIn'}, $self->getRolePermissions($role->{'id'}), DAL::getRoleServicePermissions($role->{'id'}) ) ; $roleAdded = 1; } $self->{packer}->addRootUser($userLogin, $userHash); } } } } my $embeddedInfo = undef; if (PleskVersion::atLeast(11, 1, 0)) { my $cmd = AgentConfig::getBackupRestoreHelperUtil(); $cmd .= " --backup-subscription " . $domain{'name'}; Logging::debug( "Exec: $cmd" ); my $ret = `$cmd`; my $retCode = $? >> 8; if ($retCode == 0) { eval {require XML::Simple; 1;}; my $xs = XML::Simple->new(ForceArray => 1, SuppressEmpty => ''); $embeddedInfo = $xs->XMLin($ret, KeyAttr => []); } else { Logging::warning( "Cannot execute backup helper: " . $cmd . ", STDOUT:" . $ret, 'UtilityError'); } } if ( exists $domain{'vendor_id'} ){ my $vendorGuid = PleskStructure::getClientGuidFromId( $domain{'vendor_id'} ); $domain{'vendor-guid'} = $vendorGuid; my $vendorLogin = PleskStructure::getClientNameFromId( $domain{'vendor_id'} ); $domain{'vendor-login'} = $vendorLogin; } if ( defined PleskStructure::getClientGuidFromId($clientId) ) { $domain{'owner-guid'} = PleskStructure::getClientGuidFromId($clientId); $domain{'owner-name'} = PleskStructure::getClientNameFromId($clientId); } my $clientPermsId; $sql = "SELECT perm_id FROM clients WHERE id = $clientId"; if ( $self->{dbh}->execute_rownum($sql) and my $ptrRow = $self->{dbh}->fetchrow() ) { $clientPermsId = $ptrRow->[0]; } $self->{dbh}->finish(); my $domainAsciiName; $domainName = $domain{'displayName'}; $domainAsciiName = $domain{'name'}; my $domainOwner = PleskStructure::getClientNameFromId( $domain{'cl_id'} ); my $parentType = PleskStructure::getClientType( $domainOwner ); if( $isroot ){ if ($self->{admin_info} or $self->{server_settings}) { $self->{packer}->addAdminDomain( $domainId, $domainName, $domainAsciiName, \%domain ); } else { $self->{packer}->addRootDomain( $domainId, $domainName, $domainAsciiName, \%domain, PleskStructure::getClientGuid($domainOwner) ); } } else{ if( $parentType eq 'admin' ){ $self->{packer}->addAdminDomain( $domainId, $domainName, $domainAsciiName, \%domain ); } elsif( $parentType eq 'reseller' ){ $self->{packer}->addResellerDomain( $domain{'cl_id'}, $domainId, $domainName, $domainAsciiName, \%domain ); } elsif( $parentType eq 'client' ){ $self->{packer}->addClientDomain( $domain{'cl_id'}, $domainId, $domainName, $domainAsciiName, \%domain ); } else{ die "Cannot dump domain '$domainName'. Domain owner '$domainOwner' type '$parentType' is not supported!"; } } $self->{suspender}->suspendDomain( $domainName ); $domainAsciiName = $domain{'name'}; my $domainType = $domain{'htype'}; $self->addWwwStatus( $domainId, $domainAsciiName ); # Domain's IP address Logging::debug("Getting domain IP"); my $ip = PleskStructure::getDomainIp($domainName); if ($ip) { foreach my $ipAddress (@{$ip}) { $self->{packer}->setDomainIP( $domainId, $ipAddress, PleskStructure::getClientIpType( $domainOwner, $ipAddress ) ); } } # # Status # Logging::debug("Dumping domain status"); my $status = 0; my $siteStatus = undef; $status = $domain{'status'}; if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $status += 0; $status = $domain{'webspace_status'}; $siteStatus = $self->getSiteStatus($domain{'status'}, \%domain); } elsif ( $domain{'status'} != $Status::ENABLED ) { $siteStatus = $self->getSiteStatus($Status::WITH_PARENT, \%domain); } else { $siteStatus = $self->getSiteStatus($domain{'status'}, \%domain); } $self->{packer}->setWebspaceStatus( $domainId, $status, $siteStatus ); if (!$self->{only_mail_dump}) { $self->_markDomainWithRemoteDbAsMigrated($domainPtr); } # # No further info required if shallow dump specified # if ( $self->{shallow_dump} && !$self->{only_mail_dump} ) { # Need to dump information about all databases for DbServers mapping Logging::debug("Dumping domain databases"); foreach my $db (@{DAL::getDomainDatabases($domainId)}) { eval { $self->makeDatabaseNode( $db->{'id'}, $domainId, 'domain', undef, undef, $embeddedInfo ); 1; } or do { $self->excludeProblemDatabaseFromBackup( $domainId, $db, $@ ); } } eval { # Domain's DNS settings $self->makeDomainDnsZone( \%domain ); if ((!defined $ip) && ( $domainType ne 'vrt_hst' ) ) { my $preferredIp = $self->{packer}->getDomainARecordIp($domainId); my $type; $ip = PleskStructure::getIp4DomainWoHosting($domainId, $preferredIp, \$type); if ( $ip ) { foreach my $ipAddress (@{$ip}) { $self->{packer}->setDomainIP( $domainId, $ipAddress, $type ); } } else { my $serviceIps = $self->getServiceIps( $domainId, 'mail', $ip ); if ($serviceIps) { foreach my $serviceIp (keys %{$serviceIps}) { $self->{packer}->setDomainIP( $domainId, $serviceIp, $serviceIps->{$serviceIp} ); last; } } } } 1; } or do { $self->excludeProblemDnsZoneFromBackup( $domainId, $@ ); }; $self->{packer}->removeDomainDnsZone($domainId); $self->{suspender}->unSuspendDomain(); $self->{capability}->dumpDomain($domainId, $domainName, $domainAsciiName); $self->{packer}->finishDomain($domainId); $self->{dump_status}->endDomain($domainName); Logging::endObject(); return; } # Check whether this domain is default on IP $sql = "SELECT COUNT(*) FROM IP_Addresses WHERE default_domain_id=$domainId"; if ( $self->{dbh}->execute_rownum($sql) ) { if ( @{ $self->{dbh}->fetchrow() }[0] ne "0" ) { $self->{packer}->setDomainDefault($domainId); } } $self->{dbh}->finish(); if ( !$self->{only_mail_dump} ) { # Domain's aliases $self->dumpDomainAliases($domainId); } my $domParams = $self->getDomainParams(\%domain); Logging::debug("Getting domain limits and permissions"); if ( !$self->{only_mail_dump} ) { if ( PleskVersion::atLeast( 11, 1, 16 ) ) { # # for limits and permissions at least 11.1.16 # my $subscriptionProperties = DAL::getDomainSuscriptionProperties($domainId); $self->addDomainLimits( $domainId, $subscriptionProperties->{'limitsId'} ); $self->addDomainOverusePolicy( $domainId, $subscriptionProperties ); # The following call of fixDefaultLimits should be before permissions dumping to avoid validation by schema fails $self->{packer}->fixDefaultLimits('domain',$domainId); $self->dumpDomainPersonalPermissions( $domainId, $subscriptionProperties->{'permissionsId'} ); } else { # # limits # $self->addDomainLimits( $domainId, $domain{'limits_id'} ); $self->addDomainOverusePolicy( $domainId, $domParams ); # # end limits # # The following call of fixDefaultLimits should be before permissions dumping to avoid validation by schema fails $self->{packer}->fixDefaultLimits('domain',$domainId); # # permissions # if ( PleskVersion::atLeast( 10, 0, 0) ) { $self->dumpDomainPersonalPermissions( $domainId, $domain{'permissions_id'} ); } else { $self->dumpDomainPersonalPermissions( $domainId, $clientPermsId ); } # # end permissions # } } if ( !$self->{only_hosting_dump} ) { eval { $self->dumpMailSystem( $parentType, $domParams, \%domain, $isroot, $ip ); 1; } or do { $self->excludeProblemMailSystemFromBackup( $domainId, $@ ); } } else { Logging::debug("Skip domain mailsystem dump due to settings"); } my @SiteApplications; my @excluded_dbs; my @excluded_dns_records; my $applicationsInstalled = 1; if ($self->{configuration_dump} && $self->{packer}->{listingOnlyMode}) { $applicationsInstalled = DAL::isInstalledApplicationsWithDatabases($domainId); } else { $applicationsInstalled = DAL::isInstalledApplications($domainId); } #----------------------------------------------------------------- # Information about domain's site applications # should be extracted prior to database/hosting/custom-buttons/dns-records # dump, as site applications' linked resources should be dumped # separately. #----------------------------------------------------------------- if ($applicationsInstalled) { @SiteApplications = SiteApp::getDomainSiteapps($domainId, $self->{dbh}); foreach my $sapp (@SiteApplications) { foreach my $row ( $sapp->getDatabases() ) { push @excluded_dbs, $row->{'id'}; } foreach my $row ( $sapp->getDnsRecords() ) { push @excluded_dns_records, $row->{'id'}; } } } if ( !$self->{only_mail_dump} ) { #----------------------------------------------------------------- # Domain's databases #----------------------------------------------------------------- Logging::debug("Dumping domain databases"); # Databases without those used in site apps foreach my $db (@{DAL::getDomainDatabases($domainId, \@excluded_dbs)}) { eval { $self->makeDatabaseNode( $db->{'id'}, $domainId, 'domain', undef, undef, $embeddedInfo ); 1; } or do { $self->excludeProblemDatabaseFromBackup( $domainId, $db, $@ ); } } if ( PleskVersion::atLeast( 11, 1, 0 ) ) { Logging::debug("Dumping database users belonging to any database"); $self->{packer}->makeDbUsersToAnyDatabasesNode( $domainId, DAL::getCommonDatabaseUsers( $domainId, $embeddedInfo ) ); } } else { Logging::debug("Skip dumping domain databases due to settings"); } eval { # Domain's DNS settings $self->makeDomainDnsZone( \%domain, \@excluded_dns_records ); if ((!defined $ip) && ( $domainType ne 'vrt_hst' ) ) { my $preferredIp = $self->{packer}->getDomainARecordIp($domainId); my $type; $ip = PleskStructure::getIp4DomainWoHosting($domainId, $preferredIp, \$type); if ( $ip ) { foreach my $ipAddress (@{$ip}) { $self->{packer}->setDomainIP( $domainId, $ipAddress, $type ); } } else { my $serviceIps = $self->getServiceIps( $domainId, 'mail', $ip ); if ($serviceIps) { foreach my $serviceIp (keys %{$serviceIps}) { $self->{packer}->setDomainIP( $domainId, $serviceIp, $serviceIps->{$serviceIp} ); last; } } } } 1; } or do { $self->excludeProblemDnsZoneFromBackup( $domainId, $@ ); }; $self->{packer}->makeDomainParamsNode($domainId, $domParams); $self->makeMailListsNode($domainId, $domainAsciiName, $ip); if ( !$self->{only_mail_dump} ) { Logging::debug("Dumping domain statistics"); $self->addDomainTraffic($domainId); $self->addDomainCertificates($domainId, $domainName, defined($domain{'cert_rep_id'}) ? $domain{'cert_rep_id'} : ''); my $tomcatServiceStatus = DAL::getDomainTomcatStatus($domainId); if (defined $tomcatServiceStatus) { my $serviceIps = $self->getServiceIps( $domainId, 'tomcat', $ip); $self->{packer}->setDomainTomcat( $domainId, $tomcatServiceStatus, $serviceIps ); my $webapps = DAL::getDomainWebApps($domainId); foreach my $webapp ( keys %{$webapps} ) { $self->makeWebAppNode( $domainId, $webapp, $webapps->{$webapp}, $domainAsciiName ); } } if( not PleskVersion::atLeast(10, 0, 0)) { if ( $isroot ) { $self->makeDomAdminUserRole('root', $domain{'cl_id'}, $domainId, $domParams); } else { $self->makeDomAdminUserRole(PleskStructure::getClientType( $domainOwner ), $domain{'cl_id'}, $domainId, $domParams); } } } my $subscriptionProperties = undef; if ( PleskVersion::atLeast(10, 4, 0)) { $subscriptionProperties = $self->getSubscriptionPropertiesHash($domainId, 'domain'); if (exists $subscriptionProperties->{'phpSettingsId'}) { my $phpSettingsId = $subscriptionProperties->{'phpSettingsId'}; my %phpSettings = %{DAL::getPhpSettings($phpSettingsId)}; my $phpSettingsNoticeText = DAL::getPhpSettingsNoticeText($phpSettingsId); $phpSettings{'notice'} = $phpSettingsNoticeText if defined $phpSettingsNoticeText; $self->{packer}->setDomainPhpSettingsNode($domainId, \%phpSettings); } } if ( not PleskVersion::atLeast(10, 0, 0) ) { use LegacyDomainUserDumper; my $ldud = LegacyDomainUserDumper->new($self); $ldud->makeDomainUserNode($domainId, $domParams); } eval { my $serviceIps = $self->getServiceIps( $domainId, 'web', $ip); if ( $domainType eq "vrt_hst" ) { $self->makePhostingNode( \%domain, $domParams, \@SiteApplications, 0, $serviceIps, $embeddedInfo); } elsif ( $domainType eq "std_fwd" ) { $self->makeShostingNode( \%domain, $serviceIps ); } elsif ( $domainType eq "frm_fwd" ) { $self->makeFhostingNode( \%domain, $serviceIps ); } 1; } or do { $self->excludeProblemHostingFromBackup( $domainId, $domainType, $@ ); }; my $subscriptionNode; if ( !$self->{only_mail_dump} ) { $self->getCustomButtonsByOwner( 'domain-admin', $domainId ); if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $subscriptionNode = $self->getSubscription('domain', $domainId); $self->{packer}->dumpUnityMobileIntegration($domainId, $domParams); if ( PleskVersion::atLeast( 10, 1, 0 ) ) { $self->getSubscriptionProperties('domain', $domainId); $self->dumpApsBundle($domainId, 'domain'); } if ( PleskVersion::atLeast( 11, 0, 0 ) ) { my @defaultDbServers; my @availableTypes = ('default_server_mysql','default_server_postgresql'); foreach my $defaultDbServerType (@availableTypes) { if ( exists $subscriptionProperties->{$defaultDbServerType}) { foreach my $ptrHash (@{DAL::getDatabaseServers()}) { if ($subscriptionProperties->{$defaultDbServerType} == $ptrHash->{'id'}) { push @defaultDbServers, $ptrHash; } } } } if (@defaultDbServers) { $self->{packer}->makeDomainDefaultDbServersNode($domainId, \@defaultDbServers); } } if ( PleskVersion::atLeast( 11, 5, 23 ) ) { if (ref($subscriptionNode) =~ /XmlNode/) { $self->{packer}->makeSubscriptionPropertiesNode($subscriptionNode, $subscriptionProperties); } if ($applicationsInstalled) { foreach my $sapp (@SiteApplications) { my $apsRegistryId = $sapp->getApplicationApsRegistryId(); foreach my $row ( $sapp->getMailUsers() ) { $self->{packer}->assignApplicationInfoToMailUser($apsRegistryId, $row); } } } } } } $self->{suspender}->unSuspendDomain(); $self->processExtensionPackage('domain', $domainName, $domainId); if ( exists $domainPtr->{'description'} ) { $self->{packer}->makeDomainDescriptionsNode( $domainId, $domainPtr->{'description'} ); } if ( !$self->{only_mail_dump} && PleskVersion::atLeast(12, 0, 11)) { my @wpInstances = @{DAL::getSubscriptionWordPressNonApsInstances($domainId)}; if ( @wpInstances ) { foreach my $instance (@wpInstances) { my @wpInstanceProperties = @{DAL::getWordPressInstanceProperties($instance->{'id'})}; $self->{packer}->setNonApsWordpressInstance($domainId, $instance, \@wpInstanceProperties, 'false'); } } } $self->{dump_status}->endDomain($domainName); $self->{packer}->finishDomain($domainId); Logging::endObject(); } sub dumpMailSystem { my ( $self, $parentType, $domParams, $domain, $isroot, $ip ) = @_; Logging::debug("Dumping domain mailsystem"); my $domainId = $domain->{'id'}; my $domainName = $domain->{'displayName'}; my $domainAsciiName = $domain->{'name'}; my $isSite = exists $domain->{'webspace_id'} ? $domain->{'webspace_id'} ne '0' : 0; my $mailServiceStatus = $self->getDomainMailStatus($domainId); if ( defined($mailServiceStatus) ) { my $serviceIps = $self->getServiceIps( $domainId, 'mail', $ip ); $self->{packer}->setDomainMailService( $domainId, $mailServiceStatus, $serviceIps ); my @mails = @{DAL::getDomainMails($domainId)}; if ( @mails ) { my $remoteMailIp = undef; while ( my ($ipAddress, $ipType) = each(%{$serviceIps})) { if (PleskStructure::isRemoteIp($ipAddress)) { Logging::debug("Mail for " . $domainName . " is placed on remote node with ip:" . $ipAddress); $remoteMailIp = $ipAddress; last; } } if ($self->{dump_full_mail}) { $self->{packer}->setDomainMailNamesContent( $domainId, $domainName, AgentConfig::getPleskMailnamesDir($domainAsciiName, undef), AgentConfig::mailContentUser(), $remoteMailIp ); } foreach my $ptrRow (@mails) { $ptrRow->[2] = CommonPacker::normalizePasswordType( $ptrRow->[2] ); if ($isroot and not PleskVersion::atLeast(10, 0, 0)) { $parentType = 'root'; } eval { $self->makeMailUserNode( $domainId, $ptrRow->[0], $ptrRow->[1], $ptrRow->[2], $domainName, $domainAsciiName, $parentType, $domain->{'cl_id'} ); 1; } or do { $self->excludeProblemMailUserFromBackup( $domainId, $ptrRow, $@ ); } } $self->{packer}->removeMailSystemChildNodeIfEmpty( $domainId, 'mailuser' ); } $self->getCatchAllAddress($domainId); $self->getDomainKeysDomainSupport( $domainId, $domainName, $domain->{'dns_zone_id'} ); my $oldWebMailFlag = undef; if ( !PleskVersion::atLeast( 9, 0, 0 ) ) { $oldWebMailFlag = $self->getOldWebMailStatus( $domain->{'dns_zone_id'} ); } my $webmail; if ( $isSite and !PleskVersion::atLeast( 12, 0, 0 ) ) { my $parentDomainParams = DAL::getDomainParams( $domain->{'webspace_id'} ); $webmail = exists $parentDomainParams->{'webmail'} ? $parentDomainParams->{'webmail'} : 'none'; } else { $webmail = exists $domParams->{'webmail'} ? $domParams->{'webmail'} : defined($oldWebMailFlag) ? 'horde' : 'none'; } $self->{packer}->setDomainWebMail( $domainId, $webmail ); $self->{packer}->setDomainGLSupport( $domainId, (exists $domParams->{'gl_filter'} ) ? $domParams->{'gl_filter'} : 'on' ); if (PleskVersion::atLeast(12, 0, 0)) { my $sql = "SELECT `parameter`, `value` FROM Parameters INNER JOIN DomainServices ON Parameters.id = DomainServices.parameters_id WHERE DomainServices.dom_id = $domainId AND Parameters.`parameter` LIKE 'outgoing_messages_%'"; if ( $self->{dbh}->execute_rownum($sql) ) { while (my $ptrRow = $self->{dbh}->fetchrow() ) { $self->{packer}->makeOutgoingMessagesParameter('mailsystem', $domainId, $ptrRow->[0], $ptrRow->[1]); } } $self->{dbh}->finish(); } } } sub _markDomainWithRemoteDbAsMigrated { my ($self, $domainPtr) = @_; return if !$self->{has_remote_db_server}; # Remote databases hosting was introduced in 8.0.0, so we will process corresponding versions and in migration mode only return if ($self->{packer}->{listingOnlyMode} || !$self->{packer}->{migrationMode}); my $domainId = $domainPtr->{'id'}; my $domParams = $self->getDomainParams($domainPtr); if (!exists $domParams->{'disable_remote_db_remove'} || $domParams->{'disable_remote_db_remove'} ne 'true') { my $hasRemoteDatabases = 0; my $sql = "SELECT DISTINCT host FROM data_bases INNER JOIN DatabaseServers ON data_bases.db_server_id = DatabaseServers.id WHERE dom_id = $domainId"; if ( $self->{dbh}->execute_rownum($sql) ) { while (my $ptrRow = $self->{dbh}->fetchrow()) { if (HelpFuncs::isRemoteHost($ptrRow->[0])) { $hasRemoteDatabases = 1; last; } } } if ($hasRemoteDatabases) { Logging::debug("Mark domain with remote database as migrated"); if (!exists $domParams->{'disable_remote_db_remove'}) { $self->{dbh}->execute("INSERT INTO dom_param (dom_id, param, val) VALUES($domainId, 'disable_remote_db_remove', 'true')"); } else { $self->{dbh}->execute("UPDATE dom_param SET val = 'true' WHERE dom_id = $domainId AND param = 'disable_remote_db_remove'"); } } } } sub getDomainMailStatus { my ($self, $domainId) = @_; return DAL::getDomainServiceStatus( $domainId, 'mail' ); } sub getDomainMaillistStatus { my ($self, $domainId) = @_; return DAL::getDomainServiceStatus( $domainId, 'maillists' ); } sub getDomainDefaultCert { my $self = shift; if ( PleskVersion::atLeast( 10, 2, 0 ) ) { return DAL::getDomainDefaultCert102(@_); } else { return DAL::getDomainDefaultCert101(@_); } } sub makeSiteNode { my ( $self, $domainAsciiName, $domainName, $ptrApplications, $embeddedInfo ) = @_; my ( $sql, $ptrHash ); Logging::beginObject( 'domain', $domainName, $self->generateObjectUuidForLogging( 'domain', $domainName ) ); my $domainPtr = DAL::getDomainPtrByAsciiName($domainAsciiName); unless( $domainPtr ) { Logging::error("Failed to get domain hash for '$domainName'",'PleskDbError'); Logging::endObject(); return; } my %domain = %{$domainPtr}; my $domainId = $domain{'id'}; my $webspaceId = $domain{'webspace_id'}; my $domainType = $domain{'htype'}; my $domainOwner = PleskStructure::getClientNameFromId( $domain{'cl_id'} ); my $parentType = PleskStructure::getClientType( $domainOwner ); $self->{packer}->addDomainSite( $webspaceId, $domainId, $domainAsciiName, $domainName, \%domain ); $self->{suspender}->suspendDomain( $domainName ); $self->addWwwStatus( $domainId, $domainAsciiName ); # # Status # Logging::debug("Dumping site status"); my $status = $self->getSiteStatus($domain{'status'}, \%domain); $self->{packer}->setDomainStatus( $domainId, $status ); if ( !$self->{only_mail_dump} ) { # Domain's aliases $self->dumpDomainAliases($domainId); } # # No further info required if shallow dump specified # if ( $self->{shallow_dump} && !$self->{only_mail_dump} ) { $self->{suspender}->unSuspendDomain(); $self->{packer}->finishDomain($domainId); Logging::endObject(); return; } my $domParams = $self->getDomainParams(\%domain); if ( !$self->{only_hosting_dump} ) { eval { $self->dumpMailSystem($parentType, $domParams, \%domain, 0, undef); 1; } or do { $self->excludeProblemMailSystemFromBackup( $domainId, $@ ); } } else { Logging::debug("Skip site mailsystem dump due to settings"); } my @SiteApplications; my @excluded_dbs; my @excluded_dns_records; my $applicationsInstalled = 1; if ($self->{configuration_dump} && $self->{packer}->{listingOnlyMode}) { $applicationsInstalled = DAL::isInstalledApplicationsWithDatabases($webspaceId); } else { $applicationsInstalled = DAL::isInstalledApplications($webspaceId); } #----------------------------------------------------------------- # Information about domain's site applications # should be extracted prior to database/hosting/custom-buttons/dns-records # dump, as site applications' linked resources should be dumped # separately. #----------------------------------------------------------------- if ($applicationsInstalled) { @SiteApplications = @{$ptrApplications}; foreach my $sapp (@SiteApplications) { foreach my $row ( $sapp->getDatabases() ) { push @excluded_dbs, $row->{'id'}; } foreach my $row ( $sapp->getDnsRecords() ) { push @excluded_dns_records, $row->{'id'}; } } } eval { # Domain's DNS settings $self->makeDomainDnsZone( \%domain, \@excluded_dns_records ); 1; } or do { $self->excludeProblemDnsZoneFromBackup( $domainId, $@ ); }; $self->{packer}->makeDomainParamsNode($domainId, $domParams); $self->makeMailListsNode($domainId, $domainAsciiName); if ( !$self->{only_mail_dump} ) { Logging::debug("Dumping site statistics"); $self->addDomainTraffic($domainId); $self->addDomainCertificates($domainId, $domainName, defined($domain{'cert_rep_id'}) ? $domain{'cert_rep_id'} : ''); my $tomcatServiceStatus= DAL::getDomainTomcatStatus($domainId); if (defined $tomcatServiceStatus) { $self->{packer}->setDomainTomcat( $domainId, $tomcatServiceStatus ); my $webapps = DAL::getDomainWebApps($domainId); foreach my $webapp ( keys %{$webapps} ) { $self->makeWebAppNode( $domainId, $webapp, $webapps->{$webapp}, $domainAsciiName ); } } if ( $domainType eq "vrt_hst" ) { $self->makePhostingNode( \%domain, $domParams, \@SiteApplications, 1, undef, $embeddedInfo ); } elsif ( $domainType eq "std_fwd" ) { $self->makeShostingNode( \%domain ); } elsif ( $domainType eq "frm_fwd" ) { $self->makeFhostingNode( \%domain ); } $self->getCustomButtonsByOwner( 'domain-admin', $domainId ); $self->getSubscription('domain', $domainId); $self->{packer}->dumpUnityMobileIntegration($domainId, $domParams); } if ( exists $domainPtr->{'description'} ) { $self->{packer}->makeDomainDescriptionsNode( $domainId, $domainPtr->{'description'} ); } $self->{suspender}->unSuspendDomain(); $self->{packer}->finishDomain($domainId); Logging::endObject(); } sub makeDomainDnsZone { my ( $self, $domainHashPtr, $excludedRecordsPtr) = @_; Logging::debug("Dumping domain DNS"); # dns_zone_id could be null for wildcard subdomains if ( $domainHashPtr->{'dns_zone_id'} != 0) { return $self->makeDnsZone( $domainHashPtr->{'dns_zone_id'}, $domainHashPtr->{'id'}, 'domain', $excludedRecordsPtr ); } } sub makeDnsRecord { my ( $self, $ptrHash) = @_; return unless $ptrHash->{'type'} =~ /^A|AAAA|NS|MX|CNAME|PTR|TXT|master|SRV|AXFR$/; return if $ptrHash->{'displayHost'} =~ /.*_domainkey.*/; if ( $ptrHash->{'type'} eq 'TXT' ) { $ptrHash->{'val'} =~ s/"(.*)"/$1/; } # Fix broken CNAME mail records (bug #110731) if ( $ptrHash->{'type'} eq 'CNAME' and $ptrHash->{'host'} eq "mail." . $ptrHash->{'val'} ) { $ptrHash->{'type'} = 'A'; $ptrHash->{'val'} =~ s/\.$//; if (defined($ptrHash->{'displayVal'})) { delete($ptrHash->{'displayVal'}); } my $ips = PleskStructure::getDomainIp( $ptrHash->{'val'} ) ; foreach my $ip (@{$ips}) { if ($ip =~/^\d+\.\d+\.\d+\.\d+$/) { $ptrHash->{'val'} = $ip; } } } return %{$ptrHash}; } sub geteDnsZone { my ( $self, $dnsZoneId, $paramsPtr, $recordsPtr, $excludedRecordsPtr ) = @_; my $sql = "SELECT * FROM dns_zone WHERE id=$dnsZoneId"; if ( !$self->{dbh}->execute_rownum($sql) ) { $self->{dbh}->finish(); my $msg = "Broken referencial integrity: DNS zone id $dnsZoneId is not found in dns_zone"; print STDERR "$msg\n"; Logging::error( $msg,'BrokenDbIntegrity' ); return; } if ( my $hashPtr = $self->{dbh}->fetchhash($sql) ) { %{$paramsPtr} = %{ $hashPtr }; } $self->{dbh}->finish(); # dns records if (PleskVersion::atLeast(10, 4)) { $sql = "SELECT dns_recs.*, dns_refs.status FROM dns_recs LEFT OUTER JOIN dns_refs ON dns_refs.zoneRecordId = dns_recs.id WHERE dns_zone_id = $dnsZoneId"; } else { $sql = "SELECT * FROM dns_recs WHERE dns_zone_id = $dnsZoneId"; } if( ref($excludedRecordsPtr) =~ /ARRAY/ ) { my @excludeIds = @{$excludedRecordsPtr}; if ( @excludeIds ) { $sql .= " AND id NOT IN (" . HelpFuncs::getSqlList(@excludeIds) . ")"; } } if ( $self->{dbh}->execute_rownum($sql) ) { while ( my $ptrHash = $self->{dbh}->fetchhash() ) { my %dnsrec = $self->makeDnsRecord($ptrHash); if (%dnsrec) { push @{$recordsPtr}, \%dnsrec; } } } $self->{dbh}->finish(); } sub makeDnsZone{ my ( $self, $dnsZoneId, $parent, $parentType, $excludedRecordsPtr ) = @_; my %params; my @records; $self->geteDnsZone( $dnsZoneId, \%params, \@records, $excludedRecordsPtr ); if ( 'domain' eq $parentType ) { $self->{packer}->setDomainDnsZone( $parent, \%params, \@records ); } else { Logging::warning('Error: makeDnsZone: Unexpected type of parent \"$parentType\"','assert'); } } sub dumpDomainAliases { my ( $self, $domainId ) = @_; Logging::debug( 'Dumping domain aliases... ', 1 ); my $aliases = DAL::getDomainAliases($domainId); foreach my $alias (@{$aliases}) { my %params; my @records; if ( $alias->{'dns_zone_id'} != 0 ) { $self->geteDnsZone( $alias->{'dns_zone_id'}, \%params, \@records ); } $self->{packer}->addDomainAlias( $domainId, $alias, \%params, \@records ); } Logging::debug('OK'); } sub addWwwStatus { my ( $self, $domainId, $domainName ) = @_; my $sql; # Domain is considered to have 'www' prefix when there is 'CNAME', 'A' or 'AAAA' record with 'www' name. # While domain has CNAME record Plesk prohibits creation of 'www' alias or subdomain. # If user remove CNAME records then it may create 'www' alias and 'www' A-records will be added to zone. # When deployer will restore backup of such domain then it will first create CNAME record (due to 'www' domain flag) # and then it will try to restore 'www' alias and will fail due to conflict. # So 'www' flag for domain is set only if CNAME records is found, 'A' and 'AAAA' are not checked. $sql = "SELECT r.* FROM dns_recs r, domains d WHERE d.id=$domainId " . "AND d.dns_zone_id=r.dns_zone_id AND r.type = 'CNAME' AND r.host = 'www.$domainName.'"; if ( $self->{dbh}->execute_rownum($sql) ) { $self->{packer}->setDomainWwwStatus( $domainId, 'true' ); } else { $self->{packer}->setDomainWwwStatus( $domainId, 'false' ); } $self->{dbh}->finish(); } sub makeDomAdminUserRole { my ( $self, $parentType, $clientId, $domainId, $domParams ) = @_; my %domAdminPermsToRolePerms = ( 'manage_log' => 'logRotationManagement', 'manage_anonftp' => 'anonymousFtpManagement', 'manage_crontab' => 'scheduledTasksManagement', 'manage_spamfilter' => 'spamfilterManagement', 'allow_local_backups'=> 'backupRestoreManagement', 'allow_ftp_backups' => 'backupRestoreManagement', 'manage_virusfilter' => 'antivirusManagement', 'manage_dns' => 'dnsManagement', 'manage_webapps' => 'javaApplicationsManagement', 'manage_maillists' => 'mailListsManagement', 'site_builder' => 'sitebuilderManagement' ); my %domAdminCardToUser = ( 'companyName' => 'companyName', 'personalName'=> 'contactName', 'phone' => 'phone', 'fax' => 'fax', 'email' => 'email', 'address' => 'address', 'city' => 'city', 'state' => 'state', 'zip' => 'zip', 'country' => 'country' ); my ( $sql, $item, $ptrHash, $xmlName, $fieldName ); $sql = "SELECT * FROM dom_level_usrs WHERE dom_id=$domainId"; unless ( $self->{dbh}->execute_rownum($sql) ) { $self->{dbh}->finish(); return; } my %domainUser; if ( $ptrHash = $self->{dbh}->fetchhash() ) { %domainUser = %{ $ptrHash }; } $self->{dbh}->finish(); my $state; if ( $domainUser{'state'} ) { $state = $domainUser{'state'}; } my $passwd; my $passwdType; if ( defined $domainUser{'account_id'} and $domainUser{'account_id'} != 0 ) { ( $passwd, $passwdType ) = $self->makeAccountPasswordNode( $domainUser{'account_id'} ); } my %cardHash; if ( defined( $domainUser{'card_id'} ) ) { $sql = "SELECT * from Cards WHERE id=$domainUser{'card_id'}"; if ( $self->{dbh}->execute_rownum($sql) ) { if ( $ptrHash = $self->{dbh}->fetchhash() ) { %cardHash = %{$ptrHash}; } else { my $msg = "Broken referencial integrity: Card info is not found for domain user"; print STDERR "$msg\n"; Logging::error( $msg ,'BrokenDbIntegrity'); } } $self->{dbh}->finish(); } my $domainName = PleskStructure::getDomainNameFromId( $domainId ); my $roleName = "Domain Administrator (" . $domainName . ")"; my %userHash; foreach my $item ( keys %cardHash ) { if ( exists $domAdminCardToUser{$item} ) { $userHash{ $domAdminCardToUser{$item} } = $cardHash{ $item }; } } if ( (!defined ($userHash{'contactName'}) ) || ($userHash{'contactName'} eq '') ) { $userHash{'contactName'} = "Domain Administrator (" . $domainName . ")"; } $userHash{'password'} = $passwd; $userHash{'SmbRoleName'} = $roleName; $userHash{'isDomainAdmin'} = '1'; $userHash{'isBuiltIn'} = 0; $userHash{'uuid'} = ''; $userHash{'isLocked'} = $state eq "true" ? 0 : 1; $userHash{'isBase64'} = '0'; $userHash{'subscriptionDomainId'} = $domainId; $userHash{'passwordType'} = $passwdType; my $permsHash = $self->getPermsHash( $domainUser{'perm_id'} ); my %rolePermsHash = (); foreach my $perm ( keys %{$permsHash} ) { if ( $permsHash->{$perm} eq 'true' && exists $domAdminPermsToRolePerms{$perm} ) { $rolePermsHash{ $domAdminPermsToRolePerms{$perm} } = 1; } } $rolePermsHash{'browseStats'} = 1; $self->addSpecificUserAndRole( $parentType, $domainName, $roleName, \%userHash, \%rolePermsHash, $clientId ); } sub makeMailAccessUserRole { my ( $self, $mailname, $domainName, $password, $passwordType, $parentType, $clientId, $antispam, $antivirus, $userUid ) = @_; return if PleskVersion::atLeast( 10, 0, 0 ); my $perms; $perms = (defined $antispam)? ( "antispam" . ((defined $antivirus)? "; antivirus" : '' ) ): ( (defined $antivirus)? "antivirus" : undef ); my $roleName = "Mail User" . ((defined $perms)? " ($perms)" : ''); my %userHash; $userHash{'SmbRoleName'} = $roleName; $userHash{'isDomainAdmin'} = '0'; $userHash{'isBuiltIn'} = 0; $userHash{'uuid'} = $userUid; $userHash{'isLocked'} = 0; $userHash{'contactName'} = $mailname; $userHash{'email'} = $mailname.'@'.$domainName; $userHash{'password'} = $password; $userHash{'passwordType'} = $passwordType; $userHash{'isBase64'} = '0'; $userHash{'subscriptionDomainId'} = PleskStructure::getDomainId($domainName); $userHash{'mailId'} = 1; # Needed to make user assigned to existing mail my %rolePermsHash = (); $rolePermsHash{ 'spamfilterManagement' } = 1 if defined $antispam; $rolePermsHash{ 'antivirusManagement' } = 1 if defined $antivirus; $self->addSpecificUserAndRole( $parentType, $mailname.'@'.$domainName, $roleName, \%userHash, \%rolePermsHash, $clientId ); } sub addSpecificUserAndRole { my ( $self, $parentType, $userName, $roleName, $userHash, $rolePermsHash, $ownerId ) = @_; my $callback; eval { if( $parentType eq 'root' ) { $callback = sub { $self->{packer}->removeRootUser( @_ ); }; $self->{packer}->addRootUser( $userName, $userHash); } elsif( $parentType eq 'admin' ) { $callback = sub { $self->{packer}->removeAdminUser( @_ ); }; $self->{packer}->addAdminUser( $userName, $userHash); } elsif( $parentType eq 'reseller' || $parentType eq 'client') { $callback = sub { $self->{packer}->removeClientUser( $ownerId, @_ ); }; $self->{packer}->addClientUser( $ownerId, $userName, $userHash); } 1; } or do { $self->excludeProblemUserFromBackup( $userName, $callback, $@ ); }; eval { if( $parentType eq 'root' ) { $callback = sub { $self->{packer}->removeRootRole( @_ ); }; $self->{packer}->addRootRole( $roleName, 0, $rolePermsHash, []); } elsif( $parentType eq 'admin' ) { $callback = sub { $self->{packer}->removeAdminRole( @_ ); }; $self->{packer}->addAdminRole( $roleName, 0, $rolePermsHash, []); } elsif( $parentType eq 'reseller' || $parentType eq 'client') { $callback = sub { $self->{packer}->removeClientRole( $ownerId, @_ ); }; $self->{packer}->addClientRole( $ownerId, $roleName, 0, $rolePermsHash, []); } 1; } or do { $self->excludeProblemRoleFromBackup( $callback, $roleName, $@ ); }; } sub getTrafficValue { my ( $self, $tableName, $whereCond ) = @_; my $trafficValue = ''; my $sql = "SELECT http_in, http_out, ftp_in, ftp_out, smtp_in, smtp_out, " . "pop3_imap_in, pop3_imap_out, date FROM $tableName WHERE $whereCond"; if ( $self->{dbh}->execute_rownum($sql) ) { my @keys = ( 'http', 'ftp', 'smtp', 'pop3-imap' ); my ( $key, $i, $ptrRow ); while ( $ptrRow = $self->{dbh}->fetchrow() ) { for ( $i = 0 ; $i < @keys * 2 ; ++$i ) { if ( $ptrRow->[$i] ) { $trafficValue .= $ptrRow->[8]; $trafficValue .= ' '; $trafficValue .= $keys[ $i / 2 ]; $trafficValue .= ' '; $trafficValue .= ( $i % 2 ? 'out' : 'in' ); $trafficValue .= ' '; $trafficValue .= $ptrRow->[$i]; $trafficValue .= "\n"; } } } } $self->{dbh}->finish(); return $trafficValue; } # # addDomainTraffic - add current traffic # # arguments: # $domainId - ID of domain # sub addDomainTraffic { my ( $self, $domainId ) = @_; my $trafficValue = ''; $trafficValue = $self->getTrafficValue( 'DomainsTraffic', "dom_id=$domainId" ); $self->{packer}->setDomainTraffic( $domainId, $trafficValue ) if $trafficValue; } sub addDomainCertificates { my ($self, $domainId, $domainName, $domainCertRepId) = @_; my @defaultCerts = @{$self->getDomainDefaultCert($domainId)}; my @domainCerts = @{DAL::getCertificateIds($domainCertRepId)}; foreach my $id (@domainCerts) { $self->makeCertificateNode($id, $domainId, 'domain', grep {$_ eq $id} @defaultCerts ? 1 : 0); } if ($self->{include_app_distrib}) { my %hostingParams = %{DAL::getHostingParams($domainId)}; if (exists($hostingParams{'certificate_id'}) and $hostingParams{'certificate_id'} != 0) { my $id = $hostingParams{'certificate_id'}; if (!(grep {$_ eq $id} @domainCerts)) { $self->{packer}->setServerSettings() unless defined $self->{packer}->{serverNode}; $self->makeCertificateNode($id, 0, 'server', 0); } } else { foreach my $id (@defaultCerts) { if (!(grep {$_ eq $id} @domainCerts)) { $self->{packer}->setServerSettings() unless defined $self->{packer}->{serverNode}; $self->makeCertificateNode($id, 0, 'server', 0); } } } } } sub addClientTraffic { my ( $self, $clientId ) = @_; my $trafficValue = ''; $trafficValue = $self->getTrafficValue( 'ClientsTraffic', "cl_id=$clientId" ); $self->{packer}->setClientTraffic( $clientId, $trafficValue ) if $trafficValue; } # There are 3 types of nonexistent user mail handling: # Bounce with message (bounce:message text) # Catch to address (email@address) # SMTP reject (reject) # Returns bounce|catch|reject or empty string sub getNonexistentMode { my ( $self, $domainId ) = @_; my $sql = "SELECT p.value FROM Parameters p, DomainServices ds " . "WHERE ds.parameters_id = p.id AND ds.dom_id = $domainId AND p.parameter = 'nonexist_mail'"; my $mode; if ( $self->{dbh}->execute_rownum($sql) ) { if (my $rowPtr = $self->{dbh}->fetchrow()) { $mode = @{ $rowPtr }[0]; } } else { $mode = "bounce:This address no longer accepts mail."; } $self->{dbh}->finish(); return $mode; } sub getCatchAllAddress { my ( $self, $domainId ) = @_; my $sql; my $mode = $self->getNonexistentMode($domainId); if ( $mode =~ /^catch$/ ) { $sql = "SELECT p.value FROM Parameters p, DomainServices ds " . "WHERE ds.parameters_id = p.id AND ds.dom_id = $domainId AND p.parameter = 'catch_addr'"; } elsif ( $mode =~ /^bounce$/ ) { $sql = "SELECT CONCAT('bounce:', p.value) FROM Parameters p, DomainServices ds " . "WHERE ds.parameters_id = p.id AND ds.dom_id = $domainId AND p.parameter = 'bounce_mess'"; } elsif ( $mode =~ /^reject$/ ) { $sql = "SELECT 'reject'"; } # some not supported mode or default parameter [bug 43901] return unless ($sql); if ( $self->{dbh}->execute_rownum($sql) ) { if ( my $rowPtr = $self->{dbh}->fetchrow() ) { my $catchAllAddr = @{ $rowPtr }[0]; if ($catchAllAddr) { $self->{packer}->setDomainCatchMail( $domainId, $catchAllAddr ); } } } $self->{dbh}->finish(); } sub makeMailmanMailListNode { my ( $self, $domainId, $mlistId, $mlistName, $mlistState ) = @_; unless ( defined Mailman::version() ) { Logging::debug("Unable to found Mailman installation"); return; } my @owners = Mailman::getListOwners($mlistName); if ( !@owners ) { Logging::debug("Bad maillist $mlistName, skipped"); return; } my %listMembers = Mailman::getListMembers($mlistName); $self->{packer}->addDomainMailList( $domainId, $mlistName, Mailman::getListPassword($mlistName), $mlistState, \@owners, \%listMembers ); } my %dumpedCerts; sub makeCertificateNode { my ( $self, $certId, $parent, $parentType, $default ) = @_; return if $dumpedCerts{$certId}; my ( $sql, %cert, $item ); $sql = "SELECT * FROM certificates WHERE id=$certId"; unless ( $self->{dbh}->execute_rownum($sql) ) { $self->{dbh}->finish(); my $msg = "Broken referencial integrity: certificate ID '$certId' is not found"; print STDERR "$msg\n"; Logging::error( $msg,'BrokenDbIntegrity' ); return; } if ( my $hashPtr = $self->{dbh}->fetchhash() ) { %cert = %{ $hashPtr }; } $self->{dbh}->finish(); my $cert; my $csr; my $ca_cert; my $name; $cert = $cert{'cert'}; $csr = $cert{'csr'}; $ca_cert = $cert{'ca_cert'}; $name = $cert{'name'}; my $pvt_key = $cert{'pvt_key'}; if ( 'server' eq $parentType ) { $self->{packer}->addServerCertificate( $name, $cert, $csr, $ca_cert, $pvt_key, $default ); } elsif ( 'domain' eq $parentType ) { $self->{packer}->addDomainCertificate( $parent, $name, $cert, $csr, $ca_cert, $pvt_key, $default ); } else { Logging::warning('Error: makeCertificateNode: unexpected parent type','assert'); } $dumpedCerts{$certId} = 1; } sub makeDatabaseNode { my ( $self, $dbId, $parent, $parentType, $sappId, $sappDb, $embeddedInfo ) = @_; my ( $ptrHash, $item, $charset, $dbServerId, $dbServerHost, $dbServerPort, $skipContent, $dbServerVersion ); $skipContent = 0; my $dbRow; unless ( ( $self->{dbh}->execute_rownum("SELECT name, type FROM data_bases WHERE id=$dbId") ) && ( $dbRow = $self->{dbh}->fetchrow() ) ) { $self->{dbh}->finish(); my $msg = "Broken referencial integrity: Database id $dbId is not found in data_bases"; print STDERR "$msg\n"; Logging::error( $msg ,'BrokenDbIntegrity'); return; } my ( $dbName, $dbType ) = @{ $dbRow }; $self->{dbh}->finish(); $dbName = HelpFuncs::trim($dbName); Logging::beginObject($dbType,$dbName, undef); if ( $dbType eq "postgres" or $dbType eq "postgresql" ) { $dbType = "postgresql"; } my %dbServer; my $sql = "SELECT host, port, ds.type, ds.server_version FROM DatabaseServers as ds, data_bases as db WHERE " . "ds.id = db.db_server_id AND db.id = $dbId"; if ( $self->{dbh}->execute_rownum($sql) ) { if( my $ptrRow = $self->{dbh}->fetchrow() ) { $dbServerHost = ( $ptrRow->[0] ne 'localhost' ) ? $ptrRow->[0] : 'localhost'; $dbServerPort = $ptrRow->[1]; $dbServerVersion = $ptrRow->[3]; $dbServer{'type'} = $ptrRow->[2]; $dbServer{'host'} = $ptrRow->[0]; $dbServer{'port'} = $ptrRow->[1]; } } $self->{dbh}->finish(); my @dbUsers; my %optional; if ( defined $sappDb ) { $optional{'sapp-param'} = $sappDb->{'param'} if ($sappDb->{'param'}); $optional{'aps-registry-id'} = $sappDb->{'apsRegistryId'} if exists $sappDb->{'apsRegistryId'}; $optional{'db-existent'} = $sappDb->{'db-existent'} if exists $sappDb->{'db-existent'}; $optional{'prefix'} = $sappDb->{'prefix'} if exists $sappDb->{'prefix'}; } my %contentDescription; if ( !$self->{shallow_dump} ) { Logging::debug("Database $dbName"); foreach my $dbUserHash ( @{DAL::getDatabaseUsers( $dbId, $embeddedInfo )} ) { $dbUserHash->{'password'} ||= ''; # NULL -> '' my %item; $item{'login'} = $dbUserHash->{'login'}; $item{'password'} = $dbUserHash->{'password'}; $item{'type'} = CommonPacker::normalizePasswordType( $dbUserHash->{'type'} ); $item{'id'} = $dbUserHash->{'id'}; if ( defined $sappDb->{'apsCreatedUser'} and $sappDb->{'apsCreatedUser'} eq $dbUserHash->{'login'} ) { $item{'aps-registry-id'} = $sappDb->{'apsRegistryId'}; } if (exists $dbUserHash->{'default_user_id'} && $dbUserHash->{'default_user_id'} eq $dbUserHash->{'id'}) { $item{'default'} = ''; } if (defined $sappDb && exists $sappDb->{'db-user-existent'}) { $item{'db-user-existent'} = $sappDb->{'db-user-existent'}; } if (exists $dbUserHash->{'acl'}) { $item{'acl'} = $dbUserHash->{'acl'}; } push @dbUsers, \%item; } my ( $dbUser, $dbPasswd ); my $sql = "SELECT admin_login, admin_password, ds.id FROM DatabaseServers as ds, data_bases as db " . "WHERE ds.id = db.db_server_id AND db.id = $dbId"; my $ptrRow; unless ( ( $self->{dbh}->execute_rownum($sql) ) && ( $ptrRow = $self->{dbh}->fetchrow() ) ) { $self->{dbh}->finish(); my $msg = "Broken referencial integrity: DatabaseServers vs data_bases for db id $dbId"; print STDERR "$msg\n"; Logging::error( $msg ,'BrokenDbIntegrity'); return; } ( $dbUser, $dbPasswd, $dbServerId ) = @{ $ptrRow }; $self->{dbh}->finish(); my %dbServerInfo; $dbServerInfo{'id'} = $dbServerId; $dbServerInfo{'type'} = $dbType; $dbServerInfo{'host'} = $dbServerHost; $dbServerInfo{'admin_password'} = $dbPasswd; $dbPasswd = PleskStructure::getDbServerAdminPassword(\%dbServerInfo); if (not defined $dbPasswd) { Logging::error("Unable to define superuser password for ". $dbType ." server on ". $dbServerHost); return; } if ( $dbType eq "postgresql" ) { $optional{'version'} = $dbServerVersion ne '' ? $dbServerVersion : AgentConfig::getPostgresqlVersion(); } if ( $dbType eq "mysql" ) { $optional{'version'} = $dbServerVersion ne '' ? $dbServerVersion : Db::MysqlUtils::getVersion(); } %contentDescription = ( "name" => $dbName, "type" => $dbType, "user" => $dbUser, "password" => $dbPasswd, "host" => $dbServerHost, "port" => $dbServerPort, "plesk_7" => 0 ); if ( $dbType eq "postgresql" ) { my $psql = AgentConfig::psqlBin(); if ( -e $psql ) { #[Bug 119082] #$charset = `PGUSER=$dbUser PGPASSWORD='$dbPasswd' $psql -l template1 | grep '^[ \t]*$dbName ' | awk '{print \$5}'`; my $wrapPgsql = Db::DbConnect::getDbConnect( $dbType, $dbUser, $dbPasswd, $dbName, $dbServerHost, undef, undef, undef, undef, $dbServerPort ); if ( ref($wrapPgsql) eq 'HASH' ) { if ( $wrapPgsql->{'EXECUTE'}->( "select pg_catalog.pg_encoding_to_char(d.encoding) FROM pg_catalog.pg_database d where d.datname='$dbName'" ) ) { my $ptrRow; if ( ( $ptrRow = $wrapPgsql->{'FETCHROW'}->() ) ) { $charset = $ptrRow->[0]; if ( $charset ne '' ) { $optional{'charset'} = $charset; } } $wrapPgsql->{'FINISH'}->(); } } else { Logging::error( "Cannot connect to PostgreSQL $dbServerHost:$dbServerPort (database '$dbName')" ); $skipContent = 1; } } else { Logging::error("The psql command is absent on a server, so the dump of PostgreSQL databases can not be created."); $skipContent = 1; } } if ( $dbType eq "mysql" ) { my $wrapMysql = Db::DbConnect::getDbConnect( $dbType, $dbUser, $dbPasswd, $dbName, $dbServerHost, undef, undef, undef, undef, $dbServerPort ); if ( ref($wrapMysql) eq 'HASH' ) { if ( $wrapMysql->{'EXECUTE'}->("SHOW VARIABLES LIKE \"character_set_database\"") ) { my $ptrRow = $wrapMysql->{'FETCHROW'}->(); my $charset; $charset = $ptrRow->[1] if $ptrRow; $optional{'charset'} = $charset if $charset; $wrapMysql->{'FINISH'}->(); } # We can't always use UTF8 for dump content because it may lead to corruption of latin1-only-databases. # See http://bugs.plesk.ru/show_bug.cgi?id=134509 for details. # However, using database charset may also lead to corruption if database has latin1 default # charset, but some tables or columns have non-latin1 charset. # The semi-solution is to query charset for tables and columns and if they all have # the same charset - use it, otherwise use utf-8. my $conn = $wrapMysql->{'CONNECTION'}; my %collations = Db::MysqlUtils::getCollations( $conn ); my %tablesCollations = Db::MysqlUtils::getTablesCollation( $conn ); my @tablesCharsets = map { $collations{$_} } values(%tablesCollations); my %usedCharsets = map { $_, 1 } @tablesCharsets; for my $table (keys %tablesCollations) { my %columnsCollations = Db::MysqlUtils::getColumnsCollation( $conn, $table ); $usedCharsets{$collations{$_}} = 1 for (values %columnsCollations); } my $dumpCharset = (scalar (keys %usedCharsets) == 1) ? (keys %usedCharsets)[0] : 'utf8'; $contentDescription{'dump_charset'} = $dumpCharset; # Dump database collation if ( $wrapMysql->{'EXECUTE'}->("SHOW VARIABLES LIKE \"collation_database\"") ) { my $ptrRow = $wrapMysql->{'FETCHROW'}->(); my $collation = $ptrRow->[1] if $ptrRow; $optional{'collation'} = $collation if $collation; $wrapMysql->{'FINISH'}->(); } } else { Logging::error( "Cannot connect to mysql $dbServerHost:$dbServerPort (database '$dbName')" ); $skipContent = 1; } } $contentDescription{'create_local_dump'} = $self->checkExistDbServerOnDestination($dbType, $dbServerHost, $dbServerPort); if ($contentDescription{'create_local_dump'} != 0) { $contentDescription{'dir_for_local_dump'} = AgentConfig::dumpDir() . '/databases'; } } $self->{packer}->setContentTransport($self->{packer}->getContentTransportType(), ($dbType eq 'mssql') ? 'windows' : 'unix'); if( $sappId ){ if ( 'domain' eq $parentType ) { $self->{packer}->addDomainSappDatabase( $dbId, $dbServerId, $parent, $sappId, $dbName, $dbType, \%optional, \%dbServer, \@dbUsers, \%contentDescription, $skipContent ); } elsif ( 'subdomain' eq $parentType ) { $self->{packer}->addSubDomainSappDatabase( $dbId, $dbServerId, $parent, $sappId, $dbName, $dbType, \%optional, \%dbServer, \@dbUsers, \%contentDescription, $skipContent ); } else { Logging::warning( "Error: makeDatabaseNode: Unexpected type of parent \"$parentType\"",'assert'); } } else{ if ( 'domain' eq $parentType ) { $self->{packer}->addDomainDatabase( $dbId, $dbServerId, $parent, $dbName, $dbType, \%optional, \%dbServer, \@dbUsers, \%contentDescription, $skipContent ); } else { Logging::warning( "Error: makeDatabaseNode: Unexpected type of parent \"$parentType\"",'assert'); } } Logging::endObject(); } sub checkExistDbServerOnDestination { my ( $self, $type, $host, $port ) = @_; if ( scalar(@{$self->{existing_remote_db_servers}}) != 0 ) { foreach my $dbServerString (@{$self->{existing_remote_db_servers}}) { my ($exType, $exHost, $exPort) = split(/:/, $dbServerString); if ( $type eq $exType and $host eq $exHost and $port eq $exPort ) { return 1; } } } return 0; } sub makeMailUserNode { my ( $self, $domainId, $mailId, $passwd, $typePasswd, $domainName, $domainAsciiName, $parentType, $clientId ) = @_; my ( $sql, %mail, $item, $ptrRow, $ptrHash, $dir, $mbox_quota); $sql = "SELECT * FROM mail WHERE id = $mailId"; unless ( ( $self->{dbh}->execute_rownum($sql) ) && ( $ptrHash = $self->{dbh}->fetchhash() ) ) { $self->{dbh}->finish(); my $msg = "Broken referencial integrity: Mail id $mailId is not found in mail"; print STDERR "$msg\n"; Logging::error( $msg,'BrokenDbIntegrity' ); return; } %mail = %{ $ptrHash }; $self->{dbh}->finish(); my $mailName = $mail{'mail_name'}; Logging::beginObject('mailname',$mailName, undef); my $userUid = undef; my $cpAccessDefault = undef; if (exists $mail{'userId'} and $mail{'userId'} != 0) { if (PleskVersion::atLeast(12, 0, 0)) { $sql = "SELECT uuid, login, email, isLocked FROM smb_users WHERE id = $mail{'userId'}"; if ( $self->{dbh}->execute_rownum($sql) ) { my $fullMailName = $mailName . "@" . $domainName; while ( $ptrRow = $self->{dbh}->fetchrow() ) { $userUid = $ptrRow->[0]; $cpAccessDefault = "true" if (!$self->{packer}->{migrationMode} && $ptrRow->[3] eq '0' && $ptrRow->[1] eq $fullMailName && $ptrRow->[2] eq $fullMailName); } } } else { $sql = "SELECT uuid FROM smb_users WHERE id = $mail{'userId'}"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( $ptrRow = $self->{dbh}->fetchrow() ) { $userUid = $ptrRow->[0]; } } } $self->{dbh}->finish(); } $userUid = HelpFuncs::generateUuid() if (!$userUid && !PleskVersion::atLeast(10, 0, 0)); $self->{packer}->addMail( $domainId, $mailId, $mailName, $passwd, $typePasswd, $userUid, $cpAccessDefault ); unless ( PleskVersion::atLeast(10, 0, 0) ) { if( defined $parentType && defined $clientId ) { my ( $access, $antispam, $antivirus ); if ( defined $mail{'perm_id'} ) { $sql = "SELECT permission FROM Permissions WHERE id = $mail{'perm_id'} AND value='true'"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( $ptrRow = $self->{dbh}->fetchrow() ) { if ( $ptrRow->[0] eq 'cp_access') { $access = 1; } elsif ( $ptrRow->[0] eq 'manage_spamfilter' ) { $antispam = 1; } elsif ( $ptrRow->[0] eq 'manage_virusfilter' ) { $antivirus = 1; } } if ( $access ) { $self->makeMailAccessUserRole($mailName, $domainName, $passwd, $typePasswd, $parentType, $clientId, $antispam, $antivirus, $userUid); } } $self->{dbh}->finish(); } elsif ( defined( $mail{'cp_access'} ) ) { $self->makeMailAccessUserRole($mailName, $domainName, $passwd, $typePasswd, $parentType, $clientId, undef, undef, $userUid); } } } if ( $mail{'mbox_quota'} ) { $mbox_quota = $mail{'mbox_quota'}; $self->{packer}->setMailBoxQuota( $mailId, $mbox_quota ); } my $enable_mailbox = $mail{'postbox'} =~ /true/; # Check whether there autoresponder with attach # On 'Olde Pleskes' there was bug allowing attaches # when mailbox in turned off, so we have to explicitly # turn mailbox on if there is attach. $sql = "SELECT COUNT(ra.filename) FROM mail_resp AS mr, resp_attach as ra " . "WHERE ra.rn_id = mr.id AND mr.mn_id = $mailId"; if ( $self->{dbh}->execute_rownum($sql) and ( $ptrRow = $self->{dbh}->fetchrow() ) and $ptrRow->[0] != 0 ) { $enable_mailbox = 1; } $self->{dbh}->finish(); if ($enable_mailbox) { $dir = AgentConfig::getPleskMailnamesDir($domainAsciiName, $mailName) . "Maildir"; $self->{packer}->setMailBox( $mailId, $mailName, $domainAsciiName, ( $mail{'postbox'} =~ /true/ ? 'true' : 'false' ), $dir ); } # # aliases # $sql = "SELECT alias FROM mail_aliases WHERE mn_id=$mailId"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( $ptrRow = $self->{dbh}->fetchrow() ) { $self->{packer}->addMailAliase( $mailId, $ptrRow->[0] ); } } $self->{dbh}->finish(); # # end aliases # # # mail forwarding # my @members = grep {$_ ne $mailName.'@'.$domainName} @{DAL::getMailRedirects($mailId)}; my $forwarding_enabled = ($mail{'mail_group'} eq 'true'); unless ( PleskVersion::atLeast( 10, 0, 0 ) ) { if ( $mail{'redir_addr'} ) { push @members, $mail{'redir_addr'}; } $forwarding_enabled = $forwarding_enabled || ($mail{'redirect'} eq 'true'); } $self->{packer}->setMailForwarding( $mailId, $forwarding_enabled, \@members ); # # end mail forwarding # # # autoresponders # $dir = AgentConfig::getPleskMailnamesDir($domainAsciiName, $mailName) . "\@attachments"; my (@autos); $sql = "SELECT id FROM mail_resp WHERE mn_id=$mailId ORDER BY id"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( $ptrRow = $self->{dbh}->fetchrow() ) { push @autos, $ptrRow->[0]; } } $self->{dbh}->finish(); my @autoresponders; my @filelist; foreach my $id (@autos) { my %item = makeAutoresponderNode( $self, $id, $mailName . "@" . $domainName ); push @autoresponders, \%item; if ( PleskVersion::atLeast( 11, 1, 0 ) ) { push @filelist, @{$item{'attach'}}; } } if ( PleskVersion::atLeast( 11, 1, 0 ) ) { # In Plesk 11.1.0 there is no separate repository for autoresponder attaches. Every autoreponder has its own attach. # So no needs to call mailmng utility. Proper information could be taken from database. } else { my $util = AgentConfig::getMailmngMailnameUtil(); my $mn = $mailName; $mn =~ s/\&/\\&/g; $util .= " --list-attachments --domain-name=$domainName --mailname=$mn"; Logging::debug("Executing " . $util); open( LIST, "$util |" ); while () { chomp; my ($file) = split /\t/; push @filelist, $file; } #clear list if utility failed unless ( close(LIST) ) { @filelist = (); } } $self->{packer}->setMailAutoresponders( $mailId, $mailName, $domainAsciiName, $dir, $mail{'autoresponder'}, \@autoresponders, \@filelist ); # # end autoresponders # # # Addressbook # $self->makeAddressbookNode( $mailId, $mailName . '@' . $domainAsciiName ); # # Spamassassin # $dir = AgentConfig::getPleskMailnamesDir($domainAsciiName, $mailName) . ".spamassassin"; $self->makeSpamassassinNode( $mailId, $mail{'mail_name'}, $domainAsciiName, $mail{'spamfilter'}, $dir ); # # End Spamassassin # if ( $mail{'virusfilter'} ne 'none' ) { my %states_map = ( 'incoming' => 'in', 'outgoing' => 'out', 'any' => 'inout' ); if ( defined( $states_map{ $mail{'virusfilter'} } ) ) { $self->{packer}->setMailVirusSettings( $mailId, $states_map{ $mail{'virusfilter'} } ); } } if ( exists $ptrHash->{'description'} ) { $self->{packer}->makeMailUserDescriptionNode( $mailId, $ptrHash->{'description'} ); } $self->_makeMailUserOutgoingMessagesNode($mailId); Logging::endObject(); } sub _makeMailUserOutgoingMessagesNode() { my ($self, $mailUserId) = @_; if (PleskVersion::atLeast(12, 0, 0)) { my $sql = "SELECT param, val FROM mn_param WHERE mn_id = $mailUserId AND param LIKE 'outgoing_messages_%'"; if ($self->{dbh}->execute_rownum($sql)) { while (my $ptrRow = $self->{dbh}->fetchrow()) { $self->{packer}->makeOutgoingMessagesParameter('mailuser', $mailUserId, $ptrRow->[0], $ptrRow->[1]); } } $self->{dbh}->finish(); } } sub makeAutoresponderNode { my ( $self, $autoId, $mailName ) = @_; my ( $name, $value, $sql, %auto, $ptrRow, $item ); $sql = "SELECT * FROM mail_resp WHERE id=$autoId"; unless ( ( $self->{dbh}->execute_rownum($sql) ) && ( $ptrRow = $self->{dbh}->fetchhash() ) ) { $self->{dbh}->finish(); my $msg = "Broken referencial integrity: autoresponder id $autoId is not found in mail_resp"; print STDERR "$msg\n"; Logging::error( $msg,'BrokenDbIntegrity' ); return; } %auto = %{ $ptrRow }; $self->{dbh}->finish(); # # forward # $sql = "SELECT address FROM resp_forward WHERE rn_id=$autoId"; if ( $self->{dbh}->execute_rownum($sql) ) { my (@list); while ( $ptrRow = $self->{dbh}->fetchrow() ) { # skip empty entries - found somewhere @ the wild Net push @list, $ptrRow->[0] if $ptrRow->[0]; } if (@list) { $auto{'redirect'} = join( ',', @list ); } } $self->{dbh}->finish(); my @attach; $sql = "SELECT filename FROM resp_attach WHERE rn_id=$autoId"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( $ptrRow = $self->{dbh}->fetchrow() ) { push @attach, $ptrRow->[0]; } } $self->{dbh}->finish(); $auto{'attach'} = \@attach; return %auto; } sub makeAddressbookNode { my ( $self, $mailId, $mailName ) = @_; my @params; my $sql = "SELECT Db FROM mysql.db WHERE db='horde'"; unless( $self->{dbh}->execute_rownum($sql) ){ $self->{dbh}->finish(); return; } $self->{dbh}->finish(); $sql = "SHOW TABLES FROM horde LIKE 'turba_objects'"; unless( $self->{dbh}->execute_rownum($sql) ) { $self->{dbh}->finish(); return; } $self->{dbh}->finish(); my $ptrHash; $sql = "SELECT * FROM horde.turba_objects WHERE owner_id = " . $self->{dbh}->quote($mailName); if ($self->{dbh}->execute_rownum($sql) ) { while ( $ptrHash = $self->{dbh}->fetchhash() ) { push @params, $ptrHash; } } $self->{dbh}->finish(); my $ptrRow; my %turbaVersion = undef; if (PleskVersion::atLeast( 11, 1, 13 )) { $sql = "SELECT value FROM ServiceNodeEnvironment WHERE section='componentsPackages' AND name = 'psa-turba' AND serviceNodeId=1"; }elsif (PleskVersion::atLeast( 11, 1, 0 )) { $sql = "SELECT value FROM ServiceNodeProperties WHERE name = 'components.packages.psa-turba' AND serviceNodeId=1"; } elsif (PleskVersion::atLeast( 10, 4, 0 )) { $sql = "SELECT value FROM ServiceNodeProperties WHERE name = 'server.packages.psa-turba' AND serviceNodeId=1"; } else { $sql = "SELECT version FROM Components WHERE name = 'psa-turba'"; } if ($self->{dbh}->execute_rownum($sql)) { while ( $ptrRow = $self->{dbh}->fetchrow() ) { # Format version is 2.3.5-cos5.build1011110311.18 if ($ptrRow->[0]=~/(\d+)\.(\d+)\.(\d+)-\S*/) { $turbaVersion{'majorVersion'} = $1; $turbaVersion{'minorVersion'} = $2; $turbaVersion{'patchVersion'} = $3; } } } $self->{dbh}->finish(); $self->{packer}->setMailAddressbook( $mailId, \@params, \%turbaVersion ); } sub getWebspaceId { my ( $self, $domainId ) = @_; my $use_webspaces = PleskVersion::atLeast( 10, 0, 0 ); return 0 unless $use_webspaces; my $webspace_id; my $sql = "SELECT webspace_id FROM domains WHERE id = $domainId"; if ( $self->{dbh}->execute_rownum($sql) and my $ptrRow = $self->{dbh}->fetchrow() ) { $webspace_id = $ptrRow->[0]; } $self->{dbh}->finish(); return $webspace_id; } sub getDomainWwwRoot { my ( $self, $domainId, $absolute ) = @_; my $use_webspaces = PleskVersion::atLeast( 10, 0, 0 ); if($use_webspaces){ my $www_root = DAL::getDomainWwwRoot($domainId); if($absolute) { return $www_root; } my $parentDomainName; my $webspace_id = $self->getWebspaceId($domainId); if($webspace_id) { $parentDomainName = PleskStructure::getDomainAsciiNameFromId($webspace_id); } else { $parentDomainName = PleskStructure::getDomainAsciiNameFromId($domainId); } my $parentDomainRoot = HostingDumper::getWebspaceRoot($parentDomainName, $self->{remoteWebNodes}); $www_root = substr($www_root,length($parentDomainRoot)); substr($www_root,0,1) = '' if substr($www_root,0,1) eq '/' || substr($www_root,0,1) eq '\\'; return $www_root; } else { return ($absolute? HostingDumper::getWebspaceRoot( PleskStructure::getDomainAsciiNameFromId($domainId), $self->{remoteWebNodes} ) . '/' : '' ) .'httpdocs'; } } sub getSubDomainWwwRoot { my ( $self, $subdomainId, $subdomainName, $domainId, $absolute ) = @_; my $use_webspaces = PleskVersion::atLeast( 10, 0, 0 ); if($use_webspaces){ my $www_root = DAL::getSubdomainWwwRoot($subdomainId); if($absolute) { return $www_root; } my $webspaceId = $self->getWebspaceId($domainId); $domainId = $webspaceId if $webspaceId; my $parentDomainRoot = HostingDumper::getWebspaceRoot( PleskStructure::getDomainAsciiNameFromId($domainId), $self->{remoteWebNodes} ); $www_root = substr($www_root,length($parentDomainRoot)); substr($www_root,0,1) = '' if substr($www_root,0,1) eq '/'; return $www_root; } else { return ($absolute? HostingDumper::getWebspaceRoot( PleskStructure::getDomainAsciiNameFromId($domainId), $self->{remoteWebNodes} ) . '/' : '' ) .'subdomains/' . $subdomainName . '/httpdocs'; } } sub getDomainCgiRoot { my ( $self, $domainId, $absolute ) = @_; my $use_webspaces = PleskVersion::atLeast( 10, 0, 0 ); if($use_webspaces){ my $parentDomainName; my $webspace_id = $self->getWebspaceId($domainId); if($webspace_id) { $parentDomainName = PleskStructure::getDomainAsciiNameFromId($webspace_id); } else { $parentDomainName = PleskStructure::getDomainAsciiNameFromId($domainId); } my $parentDomainRoot = HostingDumper::getWebspaceRoot($parentDomainName, $self->{remoteWebNodes}); my $cgi_root; if( DAL::getDomainCgiBinMode($domainId) eq 'www-root') { $cgi_root = DAL::getDomainWwwRoot($domainId) . '/cgi-bin'; } else { $cgi_root = $parentDomainRoot . '/cgi-bin'; } if($absolute) { return $cgi_root; } $cgi_root = substr($cgi_root,length($parentDomainRoot)); substr($cgi_root,0,1) = '' if substr($cgi_root,0,1) eq '/'; return $cgi_root; } else { return ($absolute? HostingDumper::getWebspaceRoot( PleskStructure::getDomainAsciiNameFromId($domainId), $self->{remoteWebNodes} ) . '/' : '' ) .'cgi-bin'; } } sub getSubDomainCgiRoot { my ( $self, $subdomainId, $subdomainName, $domainId, $absolute ) = @_; my $use_webspaces = PleskVersion::atLeast( 10, 0, 0 ); if($use_webspaces){ my $webspaceId = $self->getWebspaceId($domainId); my $parentDomainRoot = HostingDumper::getWebspaceRoot( PleskStructure::getDomainAsciiNameFromId($webspaceId? $webspaceId : $domainId), $self->{remoteWebNodes} ); my $cgi_root; if( DAL::getDomainCgiBinMode($domainId) eq 'www-root') { $cgi_root = DAL::getSubdomainWwwRoot($subdomainId) . '/cgi-bin'; } else { if($webspaceId) { $cgi_root = $parentDomainRoot . '/cgi-bin'; } else { $cgi_root = $parentDomainRoot . '/subdomains/' . $subdomainName . '/cgi-bin'; } } if($absolute) { return $cgi_root; } $cgi_root = substr($cgi_root,length($parentDomainRoot)); substr($cgi_root,0,1) = '' if substr($cgi_root,0,1) eq '/'; return $cgi_root; } else { return ($absolute? HostingDumper::getWebspaceRoot( PleskStructure::getDomainAsciiNameFromId($domainId), $self->{remoteWebNodes} ) . '/' : '' ) .'subdomains/' . $subdomainName . '/cgi-bin'; } } # Get domain name that could be safely used in Plesk CLI tools # This is a workaround for wildcard subdomains, to be correct display name should be # used instead of name, but there are problems passing it to Plesk CLI tool when there # are no locales installed (easy steps to reproduce such situation - obtain a Debian 6 Virtuozzo box) # and name contains UTF-8 symbols sub getCliDomainName { my ( $domainName ) = @_; $domainName =~ s/_/*/; return $domainName; } my %wwwRootIndex = {}; sub makePhostingNode { my ( $self, $ptrDomain, $ptrDomParams, $ptrSiteApplications, $is_site, $ips, $embeddedInfo ) = @_; Logging::beginObject('hosting',$ptrDomain->{'name'}, undef); my @SiteApplications = @{$ptrSiteApplications}; unless ( ref($ptrDomain) =~ /HASH/ ) { Logging::error("Error: makePhostNode: bad arguments",'assert'); Logging::endObject(); return undef; } my ( $domainName, $domainRoot, $path, $sql, $domainServiceDir, %hosting, $domainId, $xmlName, $fieldName, $id ); $domainName = $ptrDomain->{'name'}; $domainId = $ptrDomain->{'id'}; my $webspaceId = $self->getWebspaceId($domainId); # used for Site content-related subs my $webspaceName; my $remoteIp = undef; if ($is_site) { $webspaceName = PleskStructure::getDomainAsciiNameFromId($webspaceId); if (exists $self->{remoteWebNodes}->{$webspaceName} && defined $self->{remoteWebNodes}->{$webspaceName}) { $self->{remoteWebNodes}->{$domainName} = $self->{remoteWebNodes}->{$webspaceName}; } else { $self->{remoteWebNodes}->{$domainName} = undef; } } else { foreach my $ip (keys %{$ips}) { if ( PleskStructure::isRemoteIp($ip) ) { $remoteIp = PleskStructure::getCommunicationIp($ip); Logging::debug("Remote IP detected:" . $remoteIp); } } if ( defined $remoteIp ) { $self->{remoteWebNodes}->{$domainName} = PleskStructure::getRemoteNodeId($remoteIp); } else { $self->{remoteWebNodes}->{$domainName} = undef; } } my $osType = (PleskStructure::getServiceNodeProperty($self->{remoteWebNodes}->{$domainName}, "OS_WIN") eq "true") ? 'windows' : 'unix'; $self->{packer}->setContentTransport($self->{packer}->getContentTransportType(), $osType); my %hostingParams; %hosting = %{DAL::getHostingParams($domainId)}; if ( defined( $hosting{'webstat'} ) and $hosting{'webstat'} ) { $hostingParams{'webstat'} = $hosting{'webstat'}; } if ( defined( $hosting{'ssl'} ) and $hosting{'ssl'} ) { $hostingParams{'https'} = $hosting{'ssl'}; } if ( defined( $hosting{'same_ssl'} ) and ( $hosting{'same_ssl'} eq 'true' ) ) { $hostingParams{'shared-content'} = 'true'; } else { $hostingParams{'shared-content'} = 'false'; } my $wwwroot = $self->getDomainWwwRoot($domainId); if ($wwwroot eq '') { my $index = $webspaceId == 0 ? $domainId : $webspaceId; $wwwRootIndex{$index} += 1; $hostingParams{'www-root'} = "site" . $wwwRootIndex{$index}; } else { $hostingParams{'www-root'} = $wwwroot; } my $domParams = $self->getDomainParams($ptrDomain); $hostingParams{'errdocs'} = 'true' if ($domParams->{'apacheErrorDocs'} eq 'true'); if (defined $domParams->{'cgi_bin_mode'}) { $hostingParams{'cgi_bin_mode'} = $domParams->{'cgi_bin_mode'} if ($domParams->{'cgi_bin_mode'} =~ /^old-style$|^www-root$|^webspace$/); } elsif (!PleskVersion::atLeast( 11, 5, 0 )) { $hostingParams{'cgi_bin_mode'} = 'webspace'; } if (defined( $hosting{'maintenance_mode'} )) { $hostingParams{'maintenance_mode'} = $hosting{'maintenance_mode'}; } my %sysuser; # # sysuser # Logging::beginObject('sysuser', $domainName, undef); if ( $id = $hosting{'sys_user_id'} ) { %sysuser = $self->makePleskSysUserNode($id, $embeddedInfo); $sysuser{'relative_path'} = HostingDumper::getWebspaceRoot($domainName, $self->{remoteWebNodes}); } # # end sysuser # Logging::endObject(); my $domUser = lc( $sysuser{'login'} ); my ($phpSettings, $scripting) = HostingDumper::getScripting(\%hosting); my %phpSettings = %{$phpSettings}; # # end scripting # $hostingParams{'wu_script'} = 'true' if exists $ptrDomParams->{'wu_script'} && $ptrDomParams->{'wu_script'} eq 'true'; $hostingParams{'sitebuilder-site-id'} = $ptrDomParams->{'site_builder_site_id'} if exists $ptrDomParams->{'site_builder_site_id'}; if ( PleskVersion::atLeast( 10, 0, 0 ) ) { my $published = $self->{packer}->getSb5SitePublished(getCliDomainName($domainName)); $hostingParams{'sitebuilder-site-published'} = $published if defined $published; } my @sites; if ( PleskVersion::atLeast( 10, 0, 0 ) ) { @sites = @{ DAL::getSitesByWebspaceId($domainId) }; } my @subdoms; $sql = "SELECT * FROM subdomains WHERE dom_id=$domainId ORDER BY id"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( my $ptrHash = $self->{dbh}->fetchhash() ) { push @subdoms, { %{$ptrHash} }; } } $self->{dbh}->finish(); if ( PleskVersion::atLeast( 10, 2, 0 ) ) { my $pk = $self->getDomainCertificatePrivateKey($hosting{'certificate_id'}, $domainId); if ($pk) { $hostingParams{'certificate_ref'} = $self->getCertificateRef($pk); } } $domainRoot = HostingDumper::getDomainRoot($domainName, $self->{remoteWebNodes}); my $webspaceRoot = ($webspaceName && PleskVersion::atLeast( 11, 1, 18 )) ? HostingDumper::getDomainRoot($webspaceName, $self->{remoteWebNodes}) : $domainRoot; if (PleskVersion::atLeast(11, 5, 23)) { if (PleskStructure::getServiceNodeProperty($self->{remoteWebNodes}->{$domainName}, "OS_WIN") eq "true") { $domainServiceDir = "$webspaceRoot/.plesk"; } else { $domainServiceDir = HostingDumper::getSystemDomainRoot($domainName, $self->{remoteWebNodes}); } } else { $domainServiceDir = $webspaceRoot; } if ('unix' eq $osType) { if (PleskVersion::atLeast(11, 5, 23)) { if ('true' eq $self->{packer}->getContentTransport()->hasLink("$domainRoot/conf", "$domainServiceDir/conf", 'remoteip' => $remoteIp)) { $hostingParams{'original-conf-directory'} = "$domainRoot/conf/"; } elsif (defined($ptrDomain->{'parentDomainName'})) { my ($subDomainDirName) = $domainName =~ /([^.]+)/; my $parentDomainRoot = HostingDumper::getDomainRoot($ptrDomain->{'parentDomainName'}, $self->{remoteWebNodes}); if ('true' eq $self->{packer}->getContentTransport()->hasLink("$parentDomainRoot/subdomains/$subDomainDirName/conf", "$domainServiceDir/conf", 'remoteip' => $remoteIp)) { $hostingParams{'original-conf-directory'} = "$parentDomainRoot/subdomains/$subDomainDirName/conf/"; } else { $hostingParams{'original-conf-directory'} = "$domainServiceDir/conf/"; } } else { $hostingParams{'original-conf-directory'} = "$domainServiceDir/conf/"; } } else { $hostingParams{'original-conf-directory'} = "$domainServiceDir/conf/"; } } if ( !$self->{only_mail_dump} ) { if ( PleskVersion::atLeast( 10, 4, 0 ) ) { if (exists $domParams->{'phpSettingsId'}) { %phpSettings = %{DAL::getPhpSettings($domParams->{'phpSettingsId'})}; my $phpSettingsNoticeText = DAL::getPhpSettingsNoticeText($domParams->{'phpSettingsId'}); $phpSettings{'notice'} = $phpSettingsNoticeText if defined $phpSettingsNoticeText; } } $self->{packer}->setDomainPhosting( $domainId, \%hostingParams, $is_site? undef: \%sysuser, $scripting, $ips, \%phpSettings ); if (PleskVersion::atLeast( 11, 5, 19 )) { if (exists $embeddedInfo->{'web-settings'}) { foreach my $webSettings (@{$embeddedInfo->{'web-settings'}}) { if ($webSettings->{'vhost-name'} eq $domainName) { eval {require XML::Simple; 1;}; my $xs = XML::Simple->new(ForceArray => 1); my $webSettingsXml = $xs->XMLout($webSettings, RootName => 'web-settings'); $webSettingsXml = Encode::encode('UTF-8', $webSettingsXml); # workaround for UTF8 symbols $self->{packer}->appendNodeToPhosting($domainId, $webSettingsXml); } } } } } else { if( @sites ) { $self->{packer}->setDomainPhostingEmpty( $domainId, $is_site? undef: \%sysuser, $ips ); } } if ( !$self->{only_mail_dump} ) { #----------------------------------------------------------------- # Site applications content should not be included into dump # together with other website content. #----------------------------------------------------------------- my @exclude_httpdocs_files; push @exclude_httpdocs_files, 'plesk-stat'; my @exclude_httpsdocs_files; push @exclude_httpsdocs_files, 'plesk-stat'; my @exclude_cgi_bin_files; foreach my $sapp (@SiteApplications) { next if !$sapp->isDomainSiteapp($ptrDomain->{'displayName'}); if ( $sapp->isSsl() ) { push @exclude_httpsdocs_files, $sapp->getHtdocsFiles(); } else { push @exclude_httpdocs_files, $sapp->getHtdocsFiles(); } push @exclude_cgi_bin_files, $sapp->getCgibinFiles(); } # Hosting content dump if (!$self->{configuration_dump} ) { my @exclude_vhost_files; my $httpdocsDir = $self->getDomainWwwRoot($domainId); push @exclude_vhost_files, "$httpdocsDir/plesk-stat"; push @exclude_vhost_files, "httpsdocs/plesk-stat"; if(@sites) { foreach my $ptrHash (@sites) { my $siteHttpdocsDir = $self->getDomainWwwRoot($ptrHash->{'id'}); push @exclude_vhost_files, "$siteHttpdocsDir/plesk-stat"; # Fix to dump subdomains content, which became sites after upgrade to 11.5 and some its content unavailable for sysuser # http://plesk-process.parallels.com/TargetProcess2/Project/QA/Bug/View.aspx?BugID=141214 # Exclude conf directory, because its content must be moved to system directory on upgrade and exclude error_docs, because it does not used if (PleskVersion::atLeast(11, 5, 19)) { my $subdomainName = $ptrHash->{'name'}; $subdomainName =~ s/\.$ptrDomain->{'name'}//g; my $subdomainDataDir = "subdomains/$subdomainName"; push @exclude_vhost_files, "$subdomainDataDir/conf" if (-d "$domainRoot/$subdomainDataDir/conf"); push @exclude_vhost_files, "$subdomainDataDir/error_docs" if (-d "$domainRoot/$subdomainDataDir/error_docs"); } } } if (@subdoms and not PleskVersion::atLeast(11, 5, 19)) { foreach my $ptrHash (@subdoms) { my $subDomainRootDir = "subdomains/" . $ptrHash->{'name'}; push @exclude_vhost_files, $subDomainRootDir . "/error_docs"; push @exclude_vhost_files, $subDomainRootDir . "/conf"; push @exclude_vhost_files, $subDomainRootDir . "/httpdocs"; push @exclude_vhost_files, $subDomainRootDir . "/httpsdocs"; if ($ptrHash->{'sys_user_type'} eq 'native') { push @exclude_vhost_files, $subDomainRootDir . "/cgi-bin"; push @exclude_vhost_files, $self->getSubDomainWwwRoot($ptrHash->{'id'}, $ptrHash->{'name'}, $domainId, undef); } } } if (! PleskVersion::atLeast(11, 5, 19)) { push(@exclude_vhost_files, 'conf', '.plesk', 'pd', 'statistics' ); } push(@exclude_vhost_files, 'logs'); # chroot dirs: push(@exclude_vhost_files, 'bin', 'dev', 'lib', 'lib64', 'usr', 'libexec', 'etc', 'tmp', 'var'); if ($self->{dump_vhost}) { $self->{packer}->setDomainUserDataContent( $domainId, $domainName, $domainRoot, { 'sysuser' => $domUser, 'exclude' => \@exclude_vhost_files, 'remoteip' => $remoteIp } ); } elsif (!$is_site) { $self->{packer}->setDomainPhostingFullContent($domainId, $domainName, $domainRoot, { 'sysuser' => $domUser, 'exclude' => \@exclude_vhost_files, 'remoteip' => $remoteIp } ); } } my $domainWwwRoot = $self->getDomainWwwRoot($domainId, 'absolute'); if ( !$self->{configuration_dump} ) { if ($self->{dump_vhost}) { $self->{packer}->setDomainPhostingStatisticsContent( $domainId, $domainName, "$domainServiceDir/statistics", {"remoteip" => $remoteIp} ); } else { my $webstatRoot = $domainServiceDir . "/statistics/webstat"; $self->{packer}->setDomainPhostingWebstatContent( $domainId, $domainName, $webstatRoot ); $self->{packer}->setDomainPhostingWebstatSslContent( $domainId, $domainName, "$domainServiceDir/statistics/webstat-ssl" ); $self->{packer}->setDomainPhostingFtpstatContent( $domainId, $domainName, "$domainServiceDir/statistics/ftpstat" ); $self->{packer}->setDomainPhostingAnonFtpstatContent( $domainId, $domainName, "$domainServiceDir/statistics/anon_ftpstat" ); } $self->{packer}->setDomainPhostingProtectedDirContent( $domainId, $domainName, "$domainServiceDir/pd" ); if (!$self->{skip_logs}) { my $domainLogsDirPath; if (PleskVersion::atLeast( 11, 5, 23 )) { $domainLogsDirPath = "$domainServiceDir/logs"; } else { $domainLogsDirPath = "$domainRoot/statistics/logs"; } $self->{packer}->setDomainPhostingLogsContent( $domainId, $domainName, $domainLogsDirPath ); } } if ( PleskVersion::atLeast( 10, 0, 0 ) ) { if ( !$self->{configuration_dump} && !$self->{only_mail_dump} ) { $self->addSb5DomainContent( $domainId, $domainName, $ptrDomParams->{'site_builder_site_id'}); } else { Logging::debug("Skip domain sitebuilder content dumping due to settings"); } } #----------------------------------------------------------------- # Dump of installed site applications #----------------------------------------------------------------- foreach my $sapp (@SiteApplications) { if ( !$sapp->isDomainSiteapp($ptrDomain->{'displayName'}) ) { next; } $self->dumpSiteApplication( $sapp, $domainId, 'domain', $webspaceId? $webspaceId:$domainId, $embeddedInfo); } unless ($is_site) { # # frontpage user # if ( exists $hosting{'fp_adm'} && $hosting{'fp_adm'} ) { $self->{packer}->setDomainFrontPageAdmin( $domainId, $hosting{'fp_adm'}, $hosting{'fp_pass'}, 'plain' ); } elsif ( exists $hosting{'fp'} && $hosting{'fp'} eq 'true' && !$hosting{'fp_adm'} && !$hosting{'fp_pass'} ) { # Workaround for older Plesks: during upgrade 1.3 -> 2.0 (or something) # frontpage administrator records were lost my ( $fp_adm, $fp_pass, $fp_pass_type ); my %sysuserHash = %{ HostingDumper::getSysUserInfo( $hosting{'sys_user_id'} ) }; $fp_adm = lc( $sysuserHash{'login'} ); ($fp_pass, $fp_pass_type ) = $self->makeAccountPasswordNode( $sysuserHash{'account_id'} ); $self->{packer}->setDomainFrontPageAdmin( $domainId, $fp_adm, $fp_pass, $fp_pass_type ); } # # end frontpage user # } $self->makeDomainLogrotationNode($domainId); $self->addAnonFtp( $domainId, $domainName, { 'sysuser' => $domUser } ); # # protected dirs # if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $sql = "SELECT id, path, realm, non_ssl, cgi_bin, `ssl` FROM protected_dirs WHERE dom_id=$domainId ORDER BY id"; if ( $self->{dbh}->execute_rownum($sql) ) { my (@dirs); while ( my $ptrRow = $self->{dbh}->fetchrow() ) { push @dirs, [ @{$ptrRow} ]; } foreach my $ptrRow (@dirs) { my $pdirId = $ptrRow->[0]; my $pdirPath = $ptrRow->[1]; my $pdirTitle = $ptrRow->[2]; my $pdirNonSSL = $ptrRow->[3]; my $pdirCGI = $ptrRow->[4]; my $pdirSSL = $ptrRow->[5]; $self->makeProtDirNode( $domainId, $pdirId, $pdirPath, $pdirTitle, $pdirNonSSL, $pdirSSL, $pdirCGI); } } $self->{dbh}->finish(); } else { $sql = "SELECT id,path,realm,non_ssl,`ssl`,cgi_bin FROM protected_dirs WHERE dom_id=$domainId ORDER BY id"; if ( $self->{dbh}->execute_rownum($sql) ) { my (@dirs); while ( my $ptrRow = $self->{dbh}->fetchrow() ) { push @dirs, [ @{$ptrRow} ]; } foreach my $ptrRow (@dirs) { unless ( defined( $hosting{'ssl'} ) and $hosting{'ssl'} =~ /true/ ) { $ptrRow->[4] = 'false'; # bug 97159 } $self->makeProtDirNode( $domainId, @{$ptrRow} ); } } $self->{dbh}->finish(); } # # end protected dirs # unless ($is_site) { # # web users # my $webs = DAL::getWebUsers($domainId); foreach my $ptrHash (@{$webs}) { $self->makeWebUserNode( $ptrHash, $domainId, $domainName ); } # # end web users # } unless ($is_site) { # # ftpusers # my $ftps = DAL::getAdditionalFtpUsers($domainId); foreach my $ptrHash (@{$ftps}) { $self->makeSubFtpUserNode( $ptrHash, $domainId, $domainName ); } # # end ftpusers # } # # subdomains # $self->{packer}->setEmptySubFtpUsersNode($domainId); foreach my $ptrHash (@subdoms) { $ptrHash->{'www-root'} = $self->getSubDomainWwwRoot($ptrHash->{'id'}, $ptrHash->{'name'}, $domainId); eval { $self->dumpSubDomain( $domainId, $ptrHash, $domainName, \@SiteApplications, $embeddedInfo ); 1; } or do { $self->excludeProblemSubdomainFromBackup( $domainId, $ptrHash, $@ ); } } $self->{packer}->removePhostingChildNodeIfEmpty( $domainId, 'subdomain' ); $self->{packer}->removePhostingChildNodeIfEmpty( $domainId, 'ftpuser' ); # # end subdomains # } if( @sites ) { foreach my $ptrHash ( @sites ) { eval { $self->makeSiteNode( $ptrHash->{'name'}, $ptrHash->{'displayName'}, \@SiteApplications, $embeddedInfo ); 1; } or do { $self->excludeProblemSiteFromBackup( $domainId, $ptrHash, $@ ); } } $self->{packer}->removePhostingChildNodeIfEmpty( $domainId, 'site' ); } if ( !$self->{only_mail_dump} ) { # # configuration files (conf/vhost[_ssl].conf) # my $confDir = PleskVersion::atLeast( 11, 5, 0 ) ? "$domainServiceDir/conf/" : "$domainRoot/conf/"; my @excludeConfFiles; push(@excludeConfFiles, 'httpd.include', 'last_httpd.include', 'last_httpd.conf', '*.*_httpd.include', '*.*_httpd.conf'); push(@excludeConfFiles, 'last_nginx.conf', '*.*_nginx.conf', 'nginx.conf'); push(@excludeConfFiles, 'siteapp.d', 'stat_ttl.conf', 'webalizer.conf', 'prev_month.found'); Logging::debug('Exclude conf files: ' . join(", ", @excludeConfFiles)); $self->{packer}->setDomainPhostingConfContent( $domainId, $domainName, $confDir, { 'exclude' => \@excludeConfFiles } ); # # end configuration files (conf/vhost[_ssl].conf) # # # Webalizer configuration # my ( $directRef, @hiddenRefs, @groupRefs ); my $sql = "SELECT referrer FROM webalizer_hidden_referrer " . " WHERE dom_id=$domainId"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( my $ptrRow = $self->{dbh}->fetchrow() ) { if ( $ptrRow->[0] eq "Direct Request" ) { $directRef = 'true'; } else { push @hiddenRefs, $ptrRow->[0]; } } } $self->{dbh}->finish(); $sql = "SELECT referrer, group_name FROM webalizer_group_referrer " . " WHERE dom_id=$domainId"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( my $ptrRow = $self->{dbh}->fetchrow() ) { push @groupRefs, { 'ref' => $ptrRow->[0], 'name' => $ptrRow->[1] }; } } $self->{dbh}->finish(); $self->{packer}->setDomainWebalizer( $domainId, $directRef, \@hiddenRefs, \@groupRefs ); # # Perfomance # if ( ( defined( $hosting{'max_connection'} ) and $hosting{'max_connection'} ) or ( defined( $hosting{'traffic_bandwidth'} ) and $hosting{'traffic_bandwidth'} ) ) { $self->{packer}->setDomainPerfomance( $domainId, $hosting{'max_connection'}, $hosting{'traffic_bandwidth'} ); } if( exists $ptrDomParams->{'stat_ttl'} ){ $self->{packer}->setDomainWebStat( $domainId, $ptrDomParams->{'stat_ttl'} ); } if ( PleskVersion::atLeast( 11, 1, 0 ) and 'windows' eq $osType ) { if (exists $embeddedInfo->{'iis-application-pool'}) { my $iisAppPoolNode = $embeddedInfo->{'iis-application-pool'}->[0]; eval {require XML::Simple; 1;}; my $xs = XML::Simple->new(ForceArray => 1); $self->{packer}->setIisAppPool($domainId, $xs->XMLout($iisAppPoolNode, RootName => 'iis-application-pool')); } } } if ( !$self->{only_mail_dump} && PleskVersion::atLeast(12, 0, 11)) { my @wpInstances = @{DAL::getDomainWordPressInstances($domainId)}; if ( @wpInstances ) { foreach my $instance (@wpInstances) { my @wpInstanceProperties = @{DAL::getWordPressInstanceProperties($instance->{'id'})}; $self->{packer}->setNonApsWordpressInstance($domainId, $instance, \@wpInstanceProperties, 'true'); } } } Logging::endObject(); } sub dumpSiteApplication { my ( $self, $sapp, $parent, $parentType, $webspaceId, $embeddedInfo ) = @_; my $sapp_id = $parentType . "_" . $parent . "_" . $sapp->getInstallPrefix(); my $prefix = $sapp->getInstallPrefix(); my $licenseType = $sapp->getAPSClientItemLicenseType(); if ( 'domain' eq $parentType ) { $self->{packer}->addDomainSapp( $parent, $sapp_id, $sapp, $licenseType ); } elsif ( 'subdomain' eq $parentType ) { $self->{packer}->addSubDomainSapp( $parent, $sapp_id, $sapp, $licenseType ); } else { Logging::warning( "Error: dumpSiteApplication: Unexpected type of parent \"$parentType\"",'assert'); } $self->{packer}->setSappParams( $sapp_id, $sapp ); #----------------------------------------------------------------- # Linked resources #----------------------------------------------------------------- # Databases foreach my $row ( $sapp->getDatabases() ) { $self->makeDatabaseNode( $row->{'id'}, $parent, $parentType, $sapp_id, $row, $embeddedInfo ); } # Custom buttons foreach my $row ( $sapp->getCustomButtons() ) { $self->getCustomButtonById71( $row->{'id'}, $parent, $parentType, $sapp_id ); } my $installDirApsRegistryId = undef; if ( PleskVersion::atLeast( 10, 3, 0 )) { $installDirApsRegistryId = $sapp->getInstallDirApsRegistryId(); } $self->{packer}->makeSiteAppInstalled( $sapp_id, $prefix, $sapp->isSsl(), $installDirApsRegistryId ); if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $self->{packer}->setSappEntryPoints( $sapp_id, $sapp ); } if ( PleskVersion::atLeast( 10, 3, 0 ) ) { $self->{packer}->setSappApsControllerInfo( $sapp_id, $sapp ); } # backupArchive if ( PleskVersion::atLeast( 11, 0, 0 )) { my $backupArchiveFile = $sapp->getBackupArchiveFile(); unless ( open( BAFILE, "<$backupArchiveFile" ) ) { Logging::warning("Error: unable to open BackupArchive from APS controller:" . $backupArchiveFile); } my $backupArchiveContent; while() { $backupArchiveContent .= $_; } close(BAFILE); $self->{packer}->setSappApscNode($sapp_id, $backupArchiveContent); } elsif ( PleskVersion::atLeast( 10, 3, 0 )) { my $backupArchiveFile = $sapp->getBackupArchiveFile(); my $backupArchiveFileName = undef; my $backupArchiveDir = undef; my $idx = rindex( $backupArchiveFile, '/' ); if ( $idx > 0 ) { $backupArchiveDir = substr( $backupArchiveFile, 0, $idx); $backupArchiveFileName = substr( $backupArchiveFile, $idx+1); } if (defined $backupArchiveFileName) { if ( 'domain' eq $parentType ) { $self->{packer}->setDomainSappBackupArchiveContent( $parent, $sapp_id, $backupArchiveDir, $backupArchiveFileName, $webspaceId ); } elsif ( 'subdomain' eq $parentType ) { $self->{packer}->setSubDomainSappBackupArchiveContent( $parent, $sapp_id, $backupArchiveDir, $backupArchiveFileName, $webspaceId ); } } else { Logging::warning( "BackupArchive from APS controller is not found", 'assert' ); } } if ( PleskVersion::atLeast( 10, 3, 0 ) ) { $self->{packer}->setSappApsLicense($sapp_id, $sapp); } if ( PleskVersion::atLeast( 11, 5, 22 ) ) { $self->{packer}->setSappSettings($sapp_id, $sapp); } if ( PleskVersion::atLeast( 12, 0, 11 ) ) { my $apsResourceId = $sapp->getApplicationApsResourceId(); my $wpInstance = shift @{DAL::getWordPressInstancesByResourceId($apsResourceId)}; if ( $wpInstance ) { my @wpInstanceProperties = @{DAL::getWordPressInstanceProperties($wpInstance->{'id'})}; $self->{packer}->setSappWordPressInstance($sapp_id, $sapp, $wpInstance, \@wpInstanceProperties); } } if ($self->{include_app_distrib}) { if ( PleskVersion::atLeast( 10, 3, 0 ) ) { my %applicationsList = %{$self->getListOfInstalledApplicationsOnServer()}; foreach my $installedSiteAppOnServer (keys %applicationsList) { if ($installedSiteAppOnServer eq $sapp->getCacheId()) { my @applicationInfo = @{$applicationsList{$installedSiteAppOnServer}}; $self->{packer}->setServerSettings() unless defined $self->{packer}->{serverNode}; $self->{packer}->addServerAppPackage($sapp->getName(), $sapp->getVersion(), $sapp->getRelease(), $applicationInfo[3], $applicationInfo[4], $applicationInfo[5], $applicationInfo[6]); } } } elsif ( PleskVersion::atLeast( 10, 0, 0 ) ) { $self->{packer}->setServerAppVault(); $self->{packer}->setServerPackagesPool(); foreach my $ptrRow ( @{DAL::getApsPackages100()} ) { if ( $sapp->getName() eq $ptrRow->[0] && $sapp->getVersion() eq $ptrRow->[1] && $sapp->getRelease() eq $ptrRow->[2] ) { my $distrib_path = AgentConfig::get("PRODUCT_ROOT_D") . "/var/apspackages/" . $ptrRow->[3] ; my $file_name = $ptrRow->[3] . ".app.zip"; $self->{packer}->addServerAppPackage( $ptrRow->[0], $ptrRow->[1], $ptrRow->[2], $distrib_path, $file_name, $ptrRow->[4], $ptrRow->[5] ); } } } else { my $distrib_path = AgentConfig::get("PRODUCT_ROOT_D") . "/var/apspkgarc"; my $file_name = $self->getApsArchiveFileName($distrib_path, $sapp->getName()."-".$sapp->getVersion()."-".$sapp->getRelease()); # what about absent release??? $self->{packer}->setServerSettings() unless defined $self->{packer}->{serverNode}; $self->{packer}->addServerAppPackage($sapp->getName(), $sapp->getVersion(), $sapp->getRelease(), $distrib_path, $file_name); } } } sub makeDomainLogrotationNode { my ( $self, $domainId ) = @_; my $logrotation_id = DAL::getDomainParam($domainId, 'logrotation_id'); if ( defined $logrotation_id ) { $self->{packer}->setDomainLogrotation( $domainId, DAL::getLogrotation($logrotation_id) ); } } #----------------------------------------------------------------- # $ptrSubDomain - pointer to hash with subdomain's info (row of table 'subdomains') # $domainName - name of domain # $ptrSiteApplications - pointer to list of domain's site applications #----------------------------------------------------------------- sub dumpSubDomain { my ( $self, $domainId, $ptrSubDomain, $domainName, $ptrSiteApplications, $embeddedInfo ) = @_; unless ( ref($ptrSubDomain) =~ /HASH/ ) { Logging::warning("Error: dumpSubDomain: bad argumets",'assert'); return; } my $subDomainName; my $subAsciiDomainName; $subDomainName = $ptrSubDomain->{'displayName'}; $subAsciiDomainName = $ptrSubDomain->{'name'}; # Subdomains may be SSL-enabled since 8.0 my $https = ''; my $shared_content = ''; if ( 'true' eq $ptrSubDomain->{'ssl'} ) { $https = 'true'; } $shared_content = $ptrSubDomain->{'same_ssl'}; # sysuser my %sysuser; if ( $ptrSubDomain->{'sys_user_type'} =~ /native/ ) { my %additionalSysuser; $additionalSysuser{'sys_user_id'} = $ptrSubDomain->{'sys_user_id'}; $self->makeSubFtpUserNode(\%additionalSysuser, $domainId, $domainName); } # scripting my %subDomainScripting = ( 'ssi' => 'ssi', 'php' => 'php', 'cgi' => 'cgi', 'perl' => 'perl', 'asp' => 'asp', 'python' => 'python', 'coldfusion' => 'coldfusion', 'asp_dot_net' => 'asp_dot_net', 'fastcgi' => 'fastcgi', 'miva' => 'miva', 'php_handler_type' => 'php_handler_type' ); my %scripting; while ( my ( $xmlName, $fieldName ) = each(%subDomainScripting) ) { next if $fieldName =~ /asp_dot_net/; if ( $ptrSubDomain->{$fieldName} eq 'true' or $ptrSubDomain->{$fieldName} eq 'false' ) { $scripting{$xmlName} = $ptrSubDomain->{$fieldName}; } elsif( $xmlName eq 'php_handler_type' ){ $scripting{$xmlName} = $ptrSubDomain->{$fieldName} if $ptrSubDomain->{$fieldName}; } } delete $scripting{'php_handler_type'} if exists $scripting{'php_handler_type'} and ( not exists $scripting{'php'} or $scripting{'php'} eq 'false'); if ( PleskVersion::atLeast( 10, 2, 0 ) ) { my $pk = $self->getDomainCertificatePrivateKey($ptrSubDomain->{'certificate_id'}, $domainId); if ($pk) { $ptrSubDomain->{'certificate_ref'} = $self->getCertificateRef($pk); } } my $domainRoot = HostingDumper::getDomainRoot($domainName, $self->{remoteWebNodes}); my $webspaceRoot = HostingDumper::getWebspaceRoot($domainName, $self->{remoteWebNodes}); my $subDomainRoot = (PleskVersion::atLeast( 11, 1, 18 )) ? "$webspaceRoot/$subAsciiDomainName" : "$domainRoot/subdomains/$subAsciiDomainName"; $ptrSubDomain->{'original-conf-directory'} = "$subDomainRoot/conf/"; $self->{packer}->addSubDomain( $domainId, $ptrSubDomain, $subDomainName, $subAsciiDomainName, $https, $shared_content, \%sysuser, \%scripting ); #----------------------------------------------------------------- # Site applications content should not be included into dump # together with other subdomain's content. #----------------------------------------------------------------- my @SiteApplications = @{$ptrSiteApplications}; my @exclude_httpdocs_files; my @exclude_httpsdocs_files; my @exclude_cgi_bin_files; foreach my $sapp (@SiteApplications) { next if !$sapp->isSubdomainSiteapp( $ptrSubDomain->{'id'} ); if ( $sapp->isSsl() ) { push @exclude_httpsdocs_files, $sapp->getHtdocsFiles(); } else { push @exclude_httpdocs_files, $sapp->getHtdocsFiles(); } push @exclude_cgi_bin_files, $sapp->getCgibinFiles(); } # content my $webspaceId = $self->getWebspaceId($domainId); #used for Site content-related subs my $subDomainWwwRoot = $self->getSubDomainWwwRoot($ptrSubDomain->{'id'}, $subAsciiDomainName, $domainId, 'absolute'); if ( not $self->{configuration_dump} and not PleskVersion::atLeast(11,5,19)) { $self->{packer}->setSubDomainHttpdocsContent($ptrSubDomain->{'id'}, "$subDomainRoot/httpdocs", \@exclude_httpdocs_files, $ptrSubDomain->{'sys_user_type'} eq 'main' ? ($webspaceId ? $webspaceId : $domainId) : undef); $self->{packer}->setSubDomainHttpsdocsContent($ptrSubDomain->{'id'}, "$subDomainRoot/httpsdocs", \@exclude_httpsdocs_files); $self->{packer}->setSubDomainConfContent($ptrSubDomain->{'id'}, "$subDomainRoot/conf"); $self->{packer}->setSubDomainErrorDocsContent($ptrSubDomain->{'id'}, "$subDomainRoot/error_docs"); } # Dump of installed site applications foreach my $sapp (@SiteApplications) { if ( !$sapp->isSubdomainSiteapp( $ptrSubDomain->{'id'} ) ) { next; } $self->dumpSiteApplication( $sapp, $ptrSubDomain->{'id'}, 'subdomain', $webspaceId? $webspaceId:$domainId, $embeddedInfo); } } sub makeWebUserNode { my ( $self, $ptrWebUser, $domainId, $domainName ) = @_; unless ( ref($ptrWebUser) =~ /HASH/ ) { Logging::warning("Error: makeWebUserNode: bad argumets", 'assert'); return; } my ( $home, $userName, $item, $xmlName, $fieldName ); my %sysuser; %sysuser = $self->makePleskSysUserNode( $ptrWebUser->{'sys_user_id'} ); $userName = $sysuser{'login'}; my $domainRoot = HostingDumper::getDomainRoot($domainName, $self->{remoteWebNodes}); my $webUserHome = $domainRoot . "/web_users/$userName"; my $privateData = $domainRoot . "/private/$userName"; $self->{packer}->addDomainWebUser( $domainId, $domainName, \%sysuser, $ptrWebUser, $webUserHome, $privateData ); } # # makeSubFtpUserNode - make node for additionals ftp accounts # sub makeSubFtpUserNode { my ( $self, $ptrFtpUser, $domainId, $domainName ) = @_; my %sysuser = $self->makePleskSysUserNode($ptrFtpUser->{'sys_user_id'}); $sysuser{'relative_path'} = HostingDumper::getWebspaceRoot($domainName, $self->{remoteWebNodes}); $self->{packer}->addDomainSubFtpUser($domainId, $domainName, \%sysuser); } sub makeProtDirNode { my ( $self, $domainId, $pdirId, $pdirPath, $pdirTitle, $pdirNonSSL, $pdirSSL, $pdirCGI ) = @_; my ( $sql, $item, $ptrRow ); # workaround of CLI inabliity to create '' directory. if ( $pdirPath eq '' ) { $pdirPath = '/'; } $sql = "SELECT p.login, a.password, a.type FROM pd_users p " . " LEFT JOIN accounts a ON p.account_id = a.id " . " WHERE p.pd_id=$pdirId ORDER BY p.id"; my @users; if ( $self->{dbh}->execute_rownum($sql) ) { while ( $ptrRow = $self->{dbh}->fetchrow() ) { push @users, { 'login' => $ptrRow->[0], 'passwd' => $ptrRow->[1], 'passwdType' => $ptrRow->[2] }; } } $self->{dbh}->finish(); $self->{packer}->addDomainProtectedDir( $domainId, $pdirPath, $pdirTitle, $pdirNonSSL, $pdirSSL, $pdirCGI, \@users ); } sub addAnonFtp { my ( $self, $domainId, $domainName, $optPtr ) = @_; my ( $ptrHash, $count, $domainRoot, $sql ); $count = 0; $sql = "SELECT * FROM anon_ftp WHERE dom_id=$domainId"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( $ptrHash = $self->{dbh}->fetchhash() ) { $domainRoot = HostingDumper::getDomainRoot($domainName, $self->{remoteWebNodes}); my ( $pub_path, $incoming_path ); $pub_path = "$domainRoot/anon_ftp/pub"; $incoming_path = "$domainRoot/anon_ftp/incoming"; $self->{packer}->setDomainAnonFtp( $domainId, $domainName, $ptrHash, $pub_path, $incoming_path, $optPtr ); $count++; } } $self->{dbh}->finish(); return $count; } sub addSb5DomainContent { my ( $self, $domainId, $domainName, $uuid ) = @_; unless ( defined $uuid) { Logging::debug( "addSb5DomainContent: domain $domainName site_builder_site_id is not found. skip"); return; } $self->{packer}->setSb5DomainContent( $domainId, $domainName, $uuid); } sub makePleskSysUserNode { my ( $self, $sysUserId, $embeddedInfo ) = @_; my %sysuser = %{ HostingDumper::getSysUserInfo($sysUserId) }; Logging::trace("Making system user node: $sysuser{'login'}"); my $sysUserInfo = undef; if (PleskVersion::atLeast(11, 1, 0) && defined($embeddedInfo)) { $sysUserInfo = (grep { $_->{name} eq $sysuser{login} } @{$embeddedInfo->{sysuser}})[0]; } # # password node # if ( $sysuser{'account_id'} != 0 ) { ( $sysuser{'passwd'}, $sysuser{'passwdType'} ) = $self->makeAccountPasswordNode( $sysuser{'account_id'} ); } # # end password node # # # crontab node # if ( PleskVersion::atLeast( 11, 1, 0 ) ) { my $cron = $sysUserInfo->{cron}->[0]; if (ref($cron) =~ /HASH/) { if (defined $cron->{'failure'}) { my $message = $cron->{'failure'}[0]->{'message'}[0]; Logging::warning($message); } else { $sysuser{'cron'} = $cron->{'content'}; $sysuser{'cron-encoding'} = $cron->{'encoding'}; } } else { $sysuser{'cron'} = $sysUserInfo->{cron}->[0]; } } elsif ( ! $self->{configuration_dump} ) { my $cron = $self->getCron($sysuser{'login'}); if (defined $cron) { $sysuser{'cron'} = $cron; } } # # end crontab node # return %sysuser; } sub getCron { my ( $self, $account ) = @_; my $crontabmng = AgentConfig::get("PRODUCT_ROOT_D") . "/admin/sbin/crontabmng"; if ( -x $crontabmng ) { open( CRONTAB, "$crontabmng get $account |" ); my $crontab = ""; while () { last if $_ eq "0\n"; $crontab .= $_; } close(CRONTAB); if ( $crontab ne "\n" ) { return $crontab; } } } sub makeSyntheticSysUserNode { my ( $self, $name, $password, $passtype ) = @_; my %sysuser; $sysuser{'login'} = $name; $sysuser{'passwd'} = $password; $sysuser{'passwdType'} = $passtype; return %sysuser; } sub makeFhostingNode { my ( $self, $ptrDomain, $ips ) = @_; return if ( $self->{only_mail_dump} ); unless ( ref($ptrDomain) =~ /HASH/ ) { Logging::warning("Error: makeFhostingNode: bag arguments", 'assert'); return; } my ( $sql, $domainId, $forward, $rowPtr ); $domainId = $ptrDomain->{'id'}; $sql = "SELECT redirect FROM forwarding WHERE dom_id=$domainId"; unless ( ( $self->{dbh}->execute_rownum($sql) ) && ( $rowPtr = $self->{dbh}->fetchrow() ) ) { $self->{dbh}->finish(); my $msg = "Broken referencial integrity: forward for domain " . $ptrDomain->{'name'} . " is not found in forwarding"; print STDERR "$msg\n"; Logging::error( $msg,'BrokenDbIntegrity' ); return; } ($forward) = @{ $rowPtr }; $self->{packer}->setDomainFhosting( $domainId, $forward, $ips); $self->{dbh}->finish(); } sub makeShostingNode { my ( $self, $ptrDomain, $ips ) = @_; return if ( $self->{only_mail_dump} ); unless ( ref($ptrDomain) =~ /HASH/ ) { Logging::warning("Error: makeShostingNode: bag arguments", 'assert'); return; } my ( $sql, $domainId, %forward, $hashPtr ); $domainId = $ptrDomain->{'id'}; $sql = "SELECT * FROM forwarding WHERE dom_id=$domainId"; unless ( ( $self->{dbh}->execute_rownum($sql) ) && ( $hashPtr = $self->{dbh}->fetchhash() ) ) { $self->{dbh}->finish(); my $msg = "Broken referencial integrity: forward for domain " . $ptrDomain->{'name'} . " is not found in forwarding"; print STDERR "$msg\n"; Logging::error( $msg,'BrokenDbIntegrity' ); return; } $self->{dbh}->finish(); %forward = %{ $hashPtr }; $self->{packer}->setDomainShosting( $domainId, \%forward, $ips ); $self->{dbh}->finish(); } sub _makePasswordData{ my ($password, $type) = @_; if (!defined $password) { Logging::warning( "'undef' password passed to _makePasswordData. Change to empty!" ); $password = ''; } if (!$password) { $type = 'plain'; } return ($password, $type); } my $tableAccounts = undef; sub makeAccountPasswordNode { my ( $self, $accountId ) = @_; my ( $passwd, $type ); my %values; if( not defined $tableAccounts ){ if ( $self->{dbh}->execute( "SELECT id, password, type FROM accounts" ) ) { while( my $ptrRow = $self->{dbh}->fetchrow() ){ $values{$ptrRow->[0]} = (); push @{$values{$ptrRow->[0]}}, $ptrRow->[1]; push @{$values{$ptrRow->[0]}}, $ptrRow->[2]; } } $self->{dbh}->finish(); $tableAccounts = \%values; } if ( exists $tableAccounts->{$accountId} ) { ( $passwd, $type ) = @{$tableAccounts->{$accountId}}; ( $passwd, $type ) = _makePasswordData( $passwd, CommonPacker::normalizePasswordType($type) ); } else { # generates a stub node ( $passwd, $type ) = _makePasswordData(); } $self->{dbh}->finish(); return ( $passwd, $type ); } my @_planItemNames; sub getPlanItemNames { my ( $self ) = @_; return \@_planItemNames if ( not PleskVersion::atLeast( 10, 2, 0 ) ); if ( @_planItemNames ) { return \@_planItemNames; } my $planItemsPtr = DAL::getPlanItems(); foreach my $planItemPtr ( @{$planItemsPtr} ) { push @_planItemNames, $planItemPtr->{'name'}; } return \@_planItemNames; } sub getSubscriptionProperties { my ( $self, $type, $id ) = @_; my @planItemNames = @{$self->getPlanItemNames()}; my $subscriptionProperties = $self->getSubscriptionPropertiesHash($id, $type); foreach my $key (keys %{$subscriptionProperties}) { if ( grep $_ eq $key, @planItemNames) { my $templatePlanItemNode = $self->{packer}->makeTemplatePlanItem( $key, $subscriptionProperties->{$key} ); $self->{packer}->addToPreferences('domain', $id, $templatePlanItemNode) if defined $templatePlanItemNode; } } } sub getSubscriptionPropertiesHash { my ( $self, $id, $type ) = @_; my %subscriptionProperties; my $sql = "SELECT name, value FROM SubscriptionProperties INNER JOIN Subscriptions ON id=subscription_id WHERE object_id='$id' AND object_type='$type'"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( my $ptrHash = $self->{dbh}->fetchhash() ) { $subscriptionProperties{$ptrHash->{'name'}} = $ptrHash->{'value'}; } } $self->{dbh}->finish(); return \%subscriptionProperties; } sub getSubscription { my ( $self, $type, $id) = @_; my $subscriptionNode = $self->makeSubscriptionNode($type, $id); $self->{packer}->addToPreferences($type, $id, $subscriptionNode) if defined $subscriptionNode; return $subscriptionNode; } sub makeSubscriptionNode { my ( $self, $type, $id ) = @_; my $rowPtr; my $extraColumns = (PleskVersion::atLeast( 10, 0, 0 )) ? ", synchronized" : ""; my $sql = "SELECT id, locked $extraColumns FROM Subscriptions WHERE object_id = '$id' AND object_type = '$type'"; if ( PleskVersion::atLeast( 10, 1, 0 ) ) { $sql .= " AND custom = 'false' "; } unless ( ( $self->{dbh}->execute_rownum($sql) ) && ( $rowPtr = $self->{dbh}->fetchrow() ) ){ $self->{dbh}->finish(); return $self->{packer}->makeSubscriptionNode(undef, undef); # subscription node is needed for dump subscription properties } my $subscription_id = $rowPtr->[0]; my $locked = $rowPtr->[1]; my $synchronized = ($extraColumns) ? $rowPtr->[2] : undef; $self->{dbh}->finish(); my $subscriptionNode = $self->{packer}->makeSubscriptionNode($locked, $synchronized); my %planQuantity; $sql = "SELECT plan_id, quantity FROM PlansSubscriptions WHERE subscription_id = '$subscription_id'"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( my $row = $self->{dbh}->fetchrow() ) { $planQuantity{$row->[0]} = $row->[1]; } } $self->{dbh}->finish(); while ( my ($planId, $quantity) = each(%planQuantity) ) { $sql = "SELECT type, uuid FROM Templates WHERE id = '$planId'"; unless ( $self->{dbh}->execute_rownum($sql) ) { Logging::warning( "Error during getting uuid from plan '$planId'"); $self->{dbh}->finish(); next; } if ( my $row = $self->{dbh}->fetchrow() ) { my ($planType, $planGuid) = @$row; my $is_addon; if ($planType eq 'domain_addon') { $is_addon = 'true'; } $self->{packer}->addSubscriptionPlan($subscriptionNode, $quantity, $planGuid, $is_addon); } $self->{dbh}->finish(); } return $subscriptionNode; } sub makeSpamassassinNode { my ( $self, $mailId, $mailNm, $domainAsciiname, $status, $dir ) = @_; my $mailname = $mailNm . '@' . $domainAsciiname; my $is_server = $mailname eq '*@*'; my $spamFilter = DAL::getMailnameSpamfilter($mailname); unless ( exists $spamFilter->{'id'} ) { Logging::debug( "Unable get information about spam filter for $mailname"); return; } my ( @blacckList, @whiteList, @unblackList, @unwhiteList, $action, $requiredScore, $subj_text ); my $filter_id = $spamFilter->{'id'}; if ( exists $spamFilter->{'reject_spam'} ) { $action = ( $spamFilter->{'reject_spam'} eq 'true') ? 'delete' : 'mark'; } my $spamFilterPreferences = DAL::getSpamfilterPreferences($filter_id); unless ( $is_server || scalar(@$spamFilterPreferences) ) { $filter_id = DAL::getServerSpamfilterId(); $spamFilterPreferences = DAL::getSpamfilterPreferences($filter_id) if defined $filter_id; } if(@$spamFilterPreferences) { foreach my $row (@$spamFilterPreferences) { if ($row->[0] eq "blacklist_from") { push @blacckList, $row->[1]; } elsif ($row->[0] eq "whitelist_from") { push @whiteList, $row->[1]; } elsif ($row->[0] eq "unblacklist_from") { push @unblackList, $row->[1]; } elsif ($row->[0] eq "unwhitelist_from") { push @unwhiteList, $row->[1]; } elsif ($row->[0] eq "required_score") { $requiredScore = $row->[1]; } elsif ($row->[0] eq "rewrite_header") { $row->[1] =~ s/^subject //; $subj_text = $row->[1]; } elsif ($row->[0] eq "action") { if ($row->[1] ne 'delete' && $row->[1] ne 'move') { $action = 'mark'; } else { $action = $row->[1]; } } } } my $spamServerSettings; if ($is_server) { $spamServerSettings = DAL::getSpamServerSettings(); $status = $spamServerSettings->{'spamfilter_enabled'} if exists $spamServerSettings->{'spamfilter_enabled'}; } $self->{packer}->setMailSpamSettings( $mailId, $mailNm, $domainAsciiname, ( $status eq 'true' ? 'on' : 'off' ), undef, $action, $requiredScore, undef, $subj_text, \@blacckList, \@whiteList, \@unblackList, \@unwhiteList, $dir, (keys(%$spamServerSettings)? $spamServerSettings : undef) ); } sub makeWebAppNode { my ( $self, $domainId, $webAppName, $webAppStatus, $dom_name ) = @_; # webapp is useless without cid $webAppStatus ||= 0; my $warDir = AgentConfig::get("CATALINA_HOME") . "/psa-wars/$dom_name"; $self->{packer}->addDomainTomcatWebApp( $domainId, $dom_name, $webAppName, $webAppStatus, $warDir ); } sub getCustomButtonById71 { my ( $self, $id, $parent, $parentType, $sappId ) = @_; my $options; # several times there was empty button place in database, which is incorrect my $sql = "SELECT * FROM custom_buttons WHERE id=$id AND place!=''"; unless ( ( $self->{dbh}->execute_rownum($sql) ) && ( $options = $self->{dbh}->fetchhash() ) ) { $self->{dbh}->finish(); return; } $self->{dbh}->finish(); my $customButtonsDir = AgentConfig::get("PRODUCT_ROOT_D") . '/admin/htdocs/images/custom_buttons'; my $icon = $options->{'file'}; if( $sappId ){ if ( 'domain' eq $parentType ) { $self->{packer}->addDomainSappCustomButton( $parent, $sappId, $id, $options, $customButtonsDir, $icon ); } elsif ( 'subdomain' eq $parentType ) { $self->{packer}->addSubDomainSappCustomButton( $parent, $sappId, $id, $options, $customButtonsDir, $icon ); } else { Logging::warning( "Error: getCustomButtonById71: Unexpected type of siteapp parent '$parentType'",'assert'); } } else{ if ( 'server' eq $parentType ) { $self->{packer}->addServerCustomButton( $id, $options, $customButtonsDir, $icon ); } elsif ( 'client' eq $parentType || 'reseller' eq $parentType ) { $self->{packer}->addClientCustomButton( $parent, $id, $options, $customButtonsDir, $icon ); } elsif ( 'domain-admin' eq $parentType ) { $self->{packer}->addDomainCustomButton( $parent, $id, $options, $customButtonsDir, $icon ); } elsif ( 'mailuser' eq $parentType ) { $self->{packer}->addMailCustomButton( $parent, $id, $options, $customButtonsDir, $icon ); } elsif ( 'sapp' eq $parentType ) { $self->{packer}->addSappCustomButton( $parent, $id, $options, $customButtonsDir, $icon ); } else { Logging::warning("Error: getCustomButtonById71: Unexpected type of parent '$parentType'",'assert'); } } } sub getCustomButtonsByOwner71 { my ( $self, $owner_type, $owner_id ) = @_; my @ids = @{DAL::getCustomButtonIdsByOwner71($owner_type, $owner_id)}; return unless @ids; return map { $self->getCustomButtonById71( $_, $owner_id, $owner_type ) } @ids; } sub getCustomButtonsByOwner { my $self = shift; return $self->getCustomButtonsByOwner71(@_) } sub makeDefaultIpNode { my ( $self ) = @_; my $ip = DAL::getDefaultIpAddress(); $self->{packer}->setServerDefaultIp( $ip ) if $ip; } sub makeAdminInfoNode { my ( $self ) = @_; my ( $max_btn_len, $send_announce, $external_id ); my $ptrAdmin = DAL::getAdminMiscParams(); if( exists $ptrAdmin->{'max_button_length'} ){ $max_btn_len = $ptrAdmin->{'max_button_length'}; delete $ptrAdmin->{'max_button_length'} } if( exists $ptrAdmin->{'send_announce'} ){ $send_announce = $ptrAdmin->{'send_announce'}; delete $ptrAdmin->{'send_announce'}; } my %gappsInfo; if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $external_id = DAL::getClientExternalId( PleskStructure::getAdminId() ); %gappsInfo = %{DAL::getClientParams( PleskStructure::getAdminId() )}; } $self->{packer}->addRootAdmin( PleskStructure::getAdminId(), PleskStructure::getAdminGuid() ); my $passwd = AgentConfig::get { 'password' }; my $cron = $self->getCron('root'); my $subscriptionDescriptions = DAL::getSubscriptionsAdminDescriptions(); my $clientsDescriptions = DAL::getClientsDescriptions( PleskStructure::getAdminId() ); my @allAdminDescriptions = (@{$subscriptionDescriptions}, @{$clientsDescriptions}); $self->{packer}->setServerAdminInfo( $ptrAdmin, $passwd, $max_btn_len, $send_announce, $external_id, \%gappsInfo, $cron, \@allAdminDescriptions ); $self->makeAdminLimitsAndPermissions(); } sub dumpPlanItems { my ( $self) = @_; my @planItems = @{DAL::getPlanItems()}; if ( @planItems ) { my $customButtonsDir = AgentConfig::get("PRODUCT_ROOT_D") . '/admin/htdocs/images/custom_buttons'; foreach my $planItemPtr ( @planItems ) { my %planItemProps = %{DAL::getPlanItemProperties($planItemPtr->{'id'})}; if ( keys %planItemProps ) { $self->{packer}->addPlanItemToServer($planItemPtr, \%planItemProps, $customButtonsDir); } } } } sub addServerIps { my ($self, $certPtr, $ipPtr) = @_; foreach my $ptrHash (@{DAL::getServerIps($certPtr)}) { if (defined $ipPtr) { foreach my $domainIp (@{$ipPtr}) { if ($domainIp eq $ptrHash->{'ip_address'}) { $ptrHash->{'type' } = PleskStructure::isExclusiveIp( $ptrHash->{'ip_address'} ) ? 'exclusive' : 'shared'; $self->{packer}->addServerIp($ptrHash); } } } else { $ptrHash->{'type' } = PleskStructure::isExclusiveIp( $ptrHash->{'ip_address'} ) ? 'exclusive' : 'shared'; $self->{packer}->addServerIp($ptrHash); } } } sub makeServerNode { my ( $self ) = @_; $self->{packer}->setServerSettings(); if ( $self->{shallow_dump} ) { return; } my $embeddedInfo = undef; if (PleskVersion::atLeast(12, 0, 11)) { my $cmd = AgentConfig::getBackupRestoreHelperUtil() . " --backup-server"; Logging::debug("Exec: $cmd"); my $ret = `$cmd`; my $retCode = $? >> 8; if ($retCode == 0) { eval {require XML::Simple; 1;}; my $xs = XML::Simple->new(ForceArray => 1, SuppressEmpty => ''); $embeddedInfo = $xs->XMLin($ret, KeyAttr => []); } else { Logging::warning("Cannot execute backup helper: " . $cmd . ", STDOUT:" . $ret, 'UtilityError'); } } #Dump server skeleton my $skeletonPath = AgentConfig::get('HTTPD_VHOSTS_D') . "/.skel/0"; if ( !$self->{configuration_dump} ) { $self->{packer}->addServerSkeleton( $skeletonPath, "skel" ); my $customTemplatesPath = AgentConfig::get('PRODUCT_ROOT_D')."/admin/conf/templates/custom"; if (-d $customTemplatesPath) { $self->{packer}->addServerCustomApacheTemplates($customTemplatesPath); } if ( PleskVersion::atLeast( 10, 0, 0 ) ) { if (!$self->{only_mail_dump} ) { $self->{packer}->setSb5ServerContent(); $self->{packer}->addServerCustomHealthConfig(); } } if (!$self->{only_mail_dump}) { if (-d AgentConfig::get('HTTPD_VHOSTS_D')."/fs") { $self->{packer}->addFileSharingContent(AgentConfig::get('HTTPD_VHOSTS_D')."/fs"); } } } #Dump system and default ip $self->addServerIps(); $self->makeDefaultIpNode(); #Dump hostname my $fullHostName = DAL::getFullHostName(); $self->{packer}->setServerHostname($fullHostName) if $fullHostName; #Dump connection information to Billing my %adminClientParams = %{DAL::getAdminClientParams()}; $self->{packer}->setPpbConnection(\%adminClientParams); # Dump database servers my %def = %{DAL::getDefaultServerParams()}; foreach my $ptrHash (@{DAL::getDatabaseServers()}) { my $param = 'default_server_' . $ptrHash->{'type'}; my $default = exists $def{$param} && $def{$param} == $ptrHash->{'id'}; my $passwd; if ( $ptrHash->{'type'} eq 'mysql' && $ptrHash->{'host'} eq 'localhost' ) { $passwd = AgentConfig::get('password'); } $self->{packer}->addServerDb( $ptrHash, $passwd, $default ); } my %params = %{DAL::getMisc()}; my %mailSettings = %{DAL::getMailServerSettings()}; if( !$self->{configuration_dump} ){ # Dump key info if (!$self->{no_license}) { if ( PleskVersion::atLeast( 9, 0, 0 ) ) { my $phpini = AgentConfig::get('PRODUCT_ROOT_D') . "/admin/conf/php.ini"; my $swkeyrepo = '/etc/sw/keys'; if( -e $phpini ){ open PHPINI, $phpini; while () { chomp; next if /^#/; next if /^$/; if ( $_ =~ /swkey\.repository_dir\s*=\s*[\"\']?(.+)[\"\']\s*$/) { $swkeyrepo = $1; Logging::debug( "Found sw key repository: $swkeyrepo" ); last; } } close PHPINI; } if( -d "$swkeyrepo/keys" ){ my $keyDir = "$swkeyrepo/keys"; Logging::debug( "Load keys from '$keyDir'" ); opendir DIR, "$keyDir"; my @files = readdir( DIR ); closedir DIR; foreach my $key(@files){ if( $key ne '.' and $key ne '..' and -f "$keyDir/$key" ){ my $cmd = AgentConfig::getLicenseCommand(); if ($cmd) { $cmd .= " --get-instance-id $keyDir/$key"; my $exec = `$cmd`; chomp($exec); $self->{packer}->addServerKey( $key, $key, $keyDir, 'false', $exec); } } } } else{ Logging::warning( "Keys directory '$swkeyrepo/keys' is not found. The keys are not included to backup." ,'assert'); } } else{ foreach my $ptrHash (@{DAL::getKeyHistory()}) { next if ( $ptrHash->{'filename'} =~ /\~$/ ); my @keyPath = split( /\//, $ptrHash->{'filename'} ); my ( $keyName, $keyDir, $additional ); if ( $keyPath[3] eq 'key.d' ) { $keyName = $keyPath[4]; $keyDir = "/etc/psa/key.d/"; $additional = "true"; } else { $keyName = $keyPath[3]; $keyDir = "/etc/psa/"; $additional = "false"; } if ( -e "$keyDir/$keyName" ) { $self->{packer}->addServerKey( $ptrHash->{'plesk_key_id'}, $keyName, $keyDir, $additional ); } } } } } # Dump server settings $mailSettings{'rbl_server'} =~ s/;/,/g; # Dump mail settings my $mailmng = AgentConfig::getMailmngServerUtil(); my $letter_size = undef; if ( -e $mailmng ) { $letter_size = `$mailmng --get-max-letter-size`; chomp($letter_size); } my @blackList = @{DAL::getBadmailfrom()}; my %whiteList = %{DAL::getSmtpPoplocks()}; my %ipAddresses = %{DAL::getIpAddresses()}; my @externalWebmails = (PleskVersion::atLeast( 10, 1, 0 )) ? @{DAL::getExternalWebmail()} : undef; $self->{packer}->setServerMail($letter_size, \%params, \%mailSettings, \@blackList, \%whiteList, \%ipAddresses, \@externalWebmails); # dump dns $self->{packer}->setServerDNS( \%params, DAL::getDnsRecsT() ); $self->{packer}->setServerWebSettings($embeddedInfo); # dump certificates my $defaultCert; foreach my $id (@{DAL::getCertificateIds($params{'cert_rep_id'})}) { if ( $params{'default_certificate_id'} == $id ) { $defaultCert = 1; } else { $defaultCert = 0; } $self->makeCertificateNode( $id, 0, 'server', $defaultCert ); } $self->{packer}->addPanelCertificate() if (!$self->{packer}->{migrationMode}); # dump custom buttons $self->getCustomButtonsByOwner( 'server', 0 ); $self->{packer}->setControlsVisibility( \%params ); if ( PleskVersion::atLeast(10, 4, 0) ) { $self->{packer}->dumpUiMode(\%params); } if ( PleskVersion::atLeast( 10, 0, 0 ) ) { my $adminId = PleskStructure::getAdminId(); $self->dumpTemplates( $adminId, 'server', 'domain' ); $self->dumpTemplates( $adminId, 'server', 'domain_addon' ); $self->dumpTemplates( $adminId, 'server', 'reseller' ); if (PleskVersion::atLeast( 10, 1, 0 )) { $self->dumpPlanItems(); } } else { # dump domain templates $self->dumpTemplates9x( 0, 'server', $params{'dom_tmpl_list_id'}, 'domain' ); # dump reseller templates $self->dumpTemplates9x( 0, 'server', $params{'res_tmpl_list_id'}, 'reseller' ) if defined $params{'res_tmpl_list_id'}; } $self->dumpResellersTemplates(\@{$self->{resellers}}); # dump SSO if (defined $params{'sso_server'}) { my $cert; if ( defined $params{'sso_certificate'} && -r $params{'sso_certificate'} ) { open( CERT, $params{'sso_certificate'} ); read( CERT, $cert, -s CERT ); close(CERT); } my $idpCert; if ( defined $params{'sso_idp_cert'} && -r $params{'sso_idp_cert'} ) { open( IDPCERT, $params{'sso_idp_cert'} ); read( IDPCERT, $idpCert, -s IDPCERT ); close(IDPCERT); } $self->{packer}->setServerSSO( \%params, $cert, $idpCert ); # SSO branding $self->{packer}->setServerSSOBranding( DAL::getSSOBranding() ); } if ( PleskVersion::atLeast( 10, 3, 0 ) ) { my %applicationsList = %{$self->getListOfInstalledApplicationsOnServer()}; foreach my $application ( keys %applicationsList ) { my @applicationInfo = @{$applicationsList{$application}}; $self->{packer}->addServerAppPackage( $applicationInfo[0], $applicationInfo[1], $applicationInfo[2], $applicationInfo[3], $applicationInfo[4], $applicationInfo[5], $applicationInfo[6], $applicationInfo[7]); } } elsif ( PleskVersion::atLeast( 10, 0, 0 ) ) { $self->{packer}->setServerAppVault(); $self->{packer}->setServerPackagesPool(); foreach my $ptrRow ( @{DAL::getApsPackages100()} ) { my $distrib_path = AgentConfig::get("PRODUCT_ROOT_D") . "/var/apspackages/" . $ptrRow->[3] ; my $file_name = $ptrRow->[3] . ".app.zip"; $self->{packer}->addServerAppPackage( $ptrRow->[0], $ptrRow->[1], $ptrRow->[2], $distrib_path, $file_name, $ptrRow->[4], $ptrRow->[5] ); } } else { $self->{packer}->setServerAppVault(); my $distrib_path = AgentConfig::get("PRODUCT_ROOT_D") . "/var/apspkgarc"; $self->{packer}->setServerPackagesPool(); foreach my $ptrRow ( @{DAL::getSiteAppPackages()} ) { my $distrib_name = $ptrRow->[0] . "-" . $ptrRow->[1] . "-" . $ptrRow->[2]; # What if 1 and 2 does not exist, or they exist always? my $file_name = $self->getApsArchiveFileName($distrib_path, $distrib_name); $self->{packer}->addServerAppPackage( $ptrRow->[0], $ptrRow->[1], $ptrRow->[2], $distrib_path, $file_name ); } #Application Item $self->{packer}->setServerAppItemsPool(); my $aishared = "ai.shared"; if ( PleskVersion::atLeast( 9, 0, 0 ) ) { $aishared = "ai.disabled"; } foreach my $ptrHash ( @{DAL::getAPSApplicationItems($aishared)} ) { $self->{packer}->addServerAppItem($ptrHash); } #Application License $self->{packer}->setServerAppLicensesPool(); foreach my $license ( @{DAL::getAPSLicenses()} ) { $self->{packer}->addServerAppLicense( $license->[0], $license->[2], $license->[1] ); } } unless ( PleskVersion::atLeast( 10, 0, 0 ) ) { # SiteBuilder Config my $config = DAL::getSBConfig(); $self->{packer}->setServerSBConfig( $config ) if $config; } $self->{packer}->setServerBackupSettings( \%params ); $self->dumpServerPreferences( \%params ); $self->makeSpamassassinNode(undef, "*", "*", undef, undef); # Server wide grey-listing preferences if ( PleskVersion::atLeast( 9,0,0 ) ) { my $glParams = DAL::getGLParams(); $glParams->{'personal-conf'} = defined($mailSettings{'spamfilter_use_mailuser_prefs'}) ? $mailSettings{'spamfilter_use_mailuser_prefs'} : "false"; $self->{packer}->setGLServerSettings($glParams); } my $virusfilterNode = $self->{packer}->addServerVirusfilter($mailSettings{'virusfilter'}); if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $self->{packer}->setServerColdFusion(\%params); } if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $self->{packer}->setServerGappsInfo(\%params); } if ( PleskVersion::atLeast( 10, 0, 0 ) ) { #Dump event handler $self->{packer}->setServerEventHandler(DAL::getEvents(), DAL::getActions(), \%params); } if ( PleskVersion::atLeast( 10, 0, 0 ) ) { $self->{packer}->addServerSiteIsolationConfig(); $self->dumpServerNotifications(); } $self->{packer}->addServerMailmanConfiguration(); if (PleskVersion::atLeast(11, 1, 0)) { if (exists $params{'theme_skin'} and not $self->{configuration_dump}) { $self->{packer}->makeSkinNode($params{'theme_skin'}, 'admin', undef); } } elsif ( PleskVersion::atLeast( 10, 1, 0 ) ) { $self->{packer}->makeBrandingThemeNode('admin', undef); } if ( PleskVersion::atLeast( 10, 3, 0 ) ) { my %fsSettings = %{DAL::getFileSharingSettings()}; $self->{packer}->dumpFileSharingServerSettings(\%fsSettings); } $self->{packer}->setMiscParameters(\%params); $self->processExtensionPackage('server', PleskStructure::getAdminGuid(), undef); $self->{packer}->addCustomizationConfig(); $self->{packer}->addRestrictedDomains(); if (PleskVersion::atLeast(12, 0, 9)) { $self->{packer}->addFail2ban(); } if (PleskVersion::atLeast(12, 0, 11)) { $self->addModSecurityContent($embeddedInfo); } } sub dumpServerNotifications { my ( $self ) = @_; my $expirationWarnDays = DAL::getExpirationWarnDays() || 1; $self->{packer}->addServerNotifications( $expirationWarnDays, DAL::getNotifications(), DAL::getNotes() ); } sub dumpServerPreferences { my ( $self, $params ) = @_; $self->{packer}->addServerPreferences( $params ); foreach my $access ( @{DAL::getCpAccess()} ) { $self->{packer}->addRestrictionItem( $access->[0], $access->[1], $access->[2] ); } if ( PleskVersion::atLeast( 10, 1, 0 ) ) { if (defined($params->{'disable_mail_ui'})) { $self->{packer}->addDisableMailUiOption($params->{'disable_mail_ui'}); } if (defined($params->{'crontab_secure_shell'}) || defined($params->{'crontab_secure_shell_compatibility_mode'})) { $self->{packer}->addCrontabSecureSettings($params); } } if ( PleskVersion::atLeast( 10, 4, 0 ) ) { my $technicalDomainName = undef; if (defined($params->{'preview_zone_domain_id'})) { $technicalDomainName = DAL::getDomainNameById($params->{'preview_zone_domain_id'}); } elsif (defined($params->{'preview_zone_external_domain_name'})) { $technicalDomainName = $params->{'preview_zone_external_domain_name'}; } $self->{packer}->addTechnicalPreviewDomainNode($technicalDomainName) if $technicalDomainName; if (defined($params->{'show_commercial_apps'})) { $self->{packer}->addShowCommercialAppsNode($params->{'show_commercial_apps'} eq 'true' ? 'true' : 'false'); } my $autoUpdates = DAL::getSingleSmbSetting('automaticUpdates'); my $autoUpdatesValue = (defined($autoUpdates) && $autoUpdates eq 'true') ? 'true' : 'false'; my $autoUpgradeToStable = (defined($params->{'autoupgrade_to_stable'}) && $params->{'autoupgrade_to_stable'} eq 'true') ? 'true' : 'false'; my $autoUpgradeBranch = (defined($params->{'autoupgrade_branch'})) ? $params->{'autoupgrade_branch'} : 'release'; $self->{packer}->addUpdateSettings($autoUpdatesValue, $autoUpgradeToStable, $autoUpgradeBranch); } } sub getApsArchiveFileName { my ( $self, $distrib_path, $package_info ) = @_; my %mapHash = MiscConfigParser::parseApsIndexFile( $distrib_path . "/archive-index.xml" ); my $file_name; foreach my $tfile_name ( keys %mapHash ) { if ( $package_info eq join( "-", @{ $mapHash{$tfile_name} } ) ) { $file_name = $tfile_name; } } return $file_name; } sub getDomainKeysDomainSupport { my ( $self, $domainId, $domainName, $dnsZoneId ) = @_; my $state = DAL::getDomainKeysState($domainId); return unless defined $state; my $publickKey = DAL::getDomainKeysPublicKey($domainName, $dnsZoneId); $self->{packer}->setDomainKeysDomainSupport( $domainId, $domainName, $state, '/etc/domainkeys/' . $domainName, $publickKey ); } sub getOldWebMailStatus { my ($self, $dnsZoneId) = @_; my $sql; my $retCode = undef; $sql = "SELECT * FROM dns_recs WHERE dns_zone_id=$dnsZoneId"; if ( $self->{dbh}->execute_rownum($sql) ) { while ( my $ptrHash = $self->{dbh}->fetchhash() ) { if ($ptrHash->{'displayHost'} =~ /.*webmail.*/) { $retCode = 1; } } } $self->{dbh}->finish(); return $retCode; } sub dumpApsBundle { my ($self, $parentId, $parentType) = @_; my $properties = $self->getSubscriptionPropertiesHash($parentId, $parentType); my $filterId = $properties->{'aps_bundle_filter_id'}; if ($filterId eq '') { return; } my $filterType = DAL::getApsBundleFilterType($filterId); my $items = DAL::getApsBundleFilterItems($filterId); $self->{packer}->makeApsBundleFilterNode($parentId, $parentType, $filterType, $items, undef); } sub fillDefaultClientPermissions { my $self = @_; my %defaultClientPermissions = ( "allow_ftp_backups" => "false" , "allow_local_backups" => "false" , "cp_access" => "true" , "create_domains" => "false" , "manage_anonftp" => "false" , "manage_crontab" => "false" , "manage_dns" => "false" , "manage_domain_aliases" => "false" , "manage_log" => "false" , "manage_maillists" => "false" , "manage_not_chroot_shell" => "false" , "manage_performance" => "false" , "manage_phosting" => "false" , "manage_php_safe_mode" => "false" , "manage_quota" => "false" , "manage_sh_access" => "false" , "manage_spamfilter" => "false" , "manage_subdomains" => "false" , "manage_virusfilter" => "false" , "manage_webapps" => "false" , "manage_webstat" => "true" , "remote_access_interface" => "false" , "select_db_server" => "false" ); my %permissions; unless (PleskVersion::atLeast(10, 0, 0)) { %permissions = %defaultClientPermissions; } return \%permissions; } sub fillDefaultDomainPermissions { my $self = @_; my %defaultDomainPermissions = ( "allow_ftp_backups" => "false" , "allow_local_backups" => "false" , "cp_access" => "true" , "create_domains" => "false" , "manage_anonftp" => "false" , "manage_crontab" => "false" , "manage_dns" => "false" , "manage_domain_aliases" => "false" , "manage_log" => "false" , "manage_maillists" => "false" , "manage_not_chroot_shell" => "false" , "manage_performance" => "false" , "manage_phosting" => "false" , "manage_php_safe_mode" => "false" , "manage_quota" => "false" , "manage_sh_access" => "false" , "manage_spamfilter" => "false" , "manage_subdomains" => "false" , "manage_virusfilter" => "false" , "manage_webapps" => "false" , "manage_webstat" => "true" , "remote_access_interface" => "false" , "select_db_server" => "false" ); my %permissions; unless (PleskVersion::atLeast(10, 0, 0)) { %permissions = %defaultDomainPermissions; } return \%permissions; } sub getServiceIps { my ($self, $domainId, $service , $ip) = @_; my @ips; my %serviceIpAdresses; if ( PleskVersion::atLeast( 10, 2, 0 ) ) { @ips = @{DAL::getServiceIps( $domainId, $service)}; } else { if ($ip) { @ips = @{$ip}; } } foreach my $serviceIpAddress (@ips) { $serviceIpAdresses{$serviceIpAddress} = PleskStructure::getIpType($serviceIpAddress); } return \%serviceIpAdresses; } sub getConcreteApplicationInfo { my ( $self, $ptrApplications, $registryUid ) = @_; my @applications = @{$ptrApplications}; foreach my $application ( @applications ) { if ( $application->getRegistryUid() eq $registryUid) { return $application; } } } sub makeMailListsNode { my ($self, $domainId, $domainAsciiName, $ip) = @_; if ( !$self->{only_hosting_dump} ) { Logging::debug("Dumping maillists"); my $maillistsStatus = $self->getDomainMaillistStatus($domainId); if (defined $maillistsStatus) { my $serviceIps = $self->getServiceIps( $domainId, 'maillists', $ip); $self->{packer}->setDomainMailLists( $domainId, $maillistsStatus, $serviceIps); my $archiveDir = AgentConfig::get("MAILMAN_VAR_D") . "/archives/private"; my @maillists = @{DAL::getDomainMaillists($domainId)}; if ( @maillists ) { my @archiveDirs; for my $ptrRow ( @maillists ) { my $maillistDir = lc($ptrRow->[1]); push @archiveDirs, $maillistDir if -d "$archiveDir/" . $maillistDir; my $datafile = $maillistDir . ".mbox"; push @archiveDirs, $datafile if -d "$archiveDir/$datafile"; $self->makeMailmanMailListNode( $domainId, @{$ptrRow} ); } if (@archiveDirs) { my %mailmanUserInfo = AgentConfig::getMailmanUserInfo(); $self->{packer}->setDomainMailListContent( $domainId, $domainAsciiName, $archiveDir, { 'include' => \@archiveDirs, 'follow_symlinks' => 1, 'sysuser' => $mailmanUserInfo{'user'}} ); } } } } else { Logging::debug("Skip maillists due to settings"); } } sub processExtensionPackage { my ( $self, $objectType, $objectName, $objectId ) = @_; my $ok = eval { if ( PleskVersion::atLeast( 11, 1, 13 ) ) { my ( $filter, $extensionPackage, $extensionData, $logs ); $filter = ExtensionPackage::createFilterForExtensionPackage($objectType, $objectName); $extensionPackage = ExtensionPackage::getExtensionPackage($filter); if (defined $extensionPackage) { $extensionData = ExtensionPackage::getData($extensionPackage); $self->{packer}->makeExtensionPackageNode($objectType, $objectId, $extensionData); $logs = ExtensionPackage::getLogs($extensionPackage); foreach my $uuid (keys %{$logs}) { my $messages = $logs->{$uuid}; foreach my $message (@{$messages}) { my $loggingMethod = $message->getSeverity(); my $loggingMessage = $message->getText(); if (defined $message->getResolution()) { $loggingMessage .= $message->getResolution(); } if ($loggingMethod eq 'error') { Logging::error($loggingMessage , 'msgtext', $uuid); }elsif($loggingMethod eq 'warning') { Logging::warning($loggingMessage , 'msgtext', $uuid); }elsif($loggingMethod eq 'info') { Logging::debug($loggingMessage , 'msgtext', $uuid); } } } } } 1; }; unless ($ok) { Logging::warning("Processing ExtensionPackage failed: " . $@); } } sub generateObjectUuidForLogging { my $self = shift; return join('#', @_); } sub getSiteStatus { my ( $self, $status, $domainPtr ) = @_; my %domain = %{$domainPtr}; if ( $domain{'htype'} eq 'vrt_hst' && $Status::ENABLED == $status && !PleskVersion::atLeast(11, 5, 23) ) { my %hostingParams = %{DAL::getHostingParams($domain{'id'})}; if ( defined( $hostingParams{'maintenance_mode'} ) && $hostingParams{'maintenance_mode'} eq 'true' ) { $status = $Status::CLIENT; } } return $status; } sub getDomainParams { my ( $self, $domainPtr ) = @_; my %domain = %{$domainPtr}; my %domainParams = %{DAL::getDomainParams($domain{'id'})}; if ( $domain{'htype'} eq 'vrt_hst' && $Status::ENABLED == $domain{'status'} && !PleskVersion::atLeast(11, 5, 23) ) { my %hostingParams = %{DAL::getHostingParams($domain{'id'})}; if ( defined( $hostingParams{'maintenance_mode'} ) && $hostingParams{'maintenance_mode'} eq 'true' ) { $domainParams{'turnOffAction'} = 'suspend'; $domainParams{'selfTurnOffAction'} = 'suspend'; } } if (!PleskVersion::atLeast(11, 5, 23)) { $domainParams{'seoHttpRedirect'} = 'none'; } return \%domainParams; } sub addUsers { my ( $self, $usersList, $callback, $callbackFailed ) = @_; for my $userLogin ( @{$usersList} ) { eval { my $userHash = DAL::getUserHash( $userLogin ); next if (! keys %$userHash); # if hash is empty (error occurred) my $assignedApplications = DAL::getUserAssignedApplications( $userHash->{'id'} ); $userHash->{'assignedApplications'} = $assignedApplications; $callback->( $userLogin, $userHash ); 1; } or do { $self->excludeProblemUserFromBackup( $userLogin, $callbackFailed, $@ ); } } } sub addModSecurityContent { my ($self, $embeddedInfo) = @_; return unless ('' ne $embeddedInfo && defined($embeddedInfo->{'web-settings'})); my $ruleSet = ''; foreach my $webSettings (@{$embeddedInfo->{'web-settings'}}) { if ('' eq $webSettings) { last; } foreach my $setting (@{$webSettings->{'setting'}}) { my ($name) = @{$setting->{'name'}}; my ($value) = @{$setting->{'value'}}; if ('ruleSet' eq $name) { $ruleSet = $value; last; } } } return if ('' eq $ruleSet); my $rulesBaseDir = undef; my $cmd = AgentConfig::getModSecurityCtlUtil() . ' --rules-base-dir'; Logging::debug("Exec: $cmd"); my $ret = `$cmd`; if (0 == ($? >> 8)) { $rulesBaseDir = HelpFuncs::trim($ret); } else { Logging::warning('Cannot execute command: ' . $cmd . ', STDOUT: ' . $ret, 'UtilityError'); return; } my @ruleSetDirs = (); my $cmd = AgentConfig::getModSecurityCtlUtil() . ' --list-rulesets'; Logging::debug("Exec: $cmd"); my $ret = `$cmd`; if (0 == ($? >> 8)) { foreach my $ruleSetDir (split(/\n/, $ret)) { if ($ruleSetDir =~ /\.saved-\d+/) { next; } push(@ruleSetDirs, "$ruleSetDir/"); } } else { Logging::warning('Cannot execute command: ' . $cmd . ', STDOUT: ' . $ret, 'UtilityError'); return; } if (@ruleSetDirs) { $self->{packer}->addModSecurityContent($rulesBaseDir, @ruleSetDirs); } } sub getDomainCertificatePrivateKey { my ($self, $certificateId, $domainId) = @_; if (0 != $certificateId) { return DAL::getCertificatePrivateKey($certificateId); } my @defaultCerts = @{$self->getDomainDefaultCert($domainId)}; if (@defaultCerts) { return DAL::getCertificatePrivateKey($defaultCerts[0]); } return undef; } sub getCertificateRef { my ($self, $privateKey) = @_; my $md5 = PerlMD5->new(); $md5->add(HelpFuncs::urlDecode($privateKey)); return $md5->hexdigest(); } 1;