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; require "agent.include.pl"; # makePasswordNode, generateDumpId, XmlNode, makeXmlNode, # makeMIMEBase64, urlDecode, addPermissionNode, addMailuserPermissionNode, # getSqlList use vars qw|@ISA|; 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(2, 5, 0)) { push @problems, "Migration from version >= " . PleskMaxVersion::get() . " is not supported"; } else { push @problems, "Migration from version < 2.5.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->{storage} = $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; #----- # Array of custom buttons IDs which are dumped within site applications #----- $self->{skip_custom_buttons} = []; 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->{base64} = makeMIMEBase64(); $self->{dbh} = Db::Connection::getConnection('type' => 'mysql', 'user' => 'admin', 'password' => AgentConfig::get('password'), 'name' => 'psa', 'host' => 'localhost', 'utf8names' => PleskVersion::atLeast(8, 0, 0)); PleskStructure::init($self->{dbh}); if (PleskVersion::atLeast(7, 1, 0)) { Encoding::setDefaultEncoding("UTF-8"); } } use vars qw|$FULL $SHALLOW $CONFIGURATION $ONLY_MAIL $ONLY_HOSTING|; $FULL = 0; $SHALLOW = 1; $CONFIGURATION = 2; $ONLY_MAIL = 4; $ONLY_HOSTING = 8; 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;} } sub setDescription { my ($self, $description) = @_; $self->{description} = $description; } sub selectDomains { my ($self, @inputDomains) = @_; @inputDomains = sort { $a cmp $b } @inputDomains; my @pleskDomains = sort { $a cmp $b } PleskStructure::getDomains(); my @missingDomains = arrayDifference(\@inputDomains, \@pleskDomains); if (@missingDomains) { die "The following domains were not found on the host: " . (join ",", @missingDomains); } $self->{domains} = \@inputDomains; } sub selectClients { my ($self, @inputClients) = @_; @inputClients = sort { $a cmp $b } @inputClients; my @pleskClients = sort { $a cmp $b } PleskStructure::getClients(); my @missingClients = arrayDifference(\@inputClients, \@pleskClients); if (@missingClients) { die "The following clients were not found on the host: " . (join ",", @missingClients); } $self->{clients} = \@inputClients; } sub excludeDomains { my ($self, @inputDomains) = @_; @inputDomains = sort { $a cmp $b } @inputDomains; $self->{domains} = [arrayDifference($self->{domains}, \@inputDomains)]; } sub excludeClients { my ($self, @inputClients) = @_; @inputClients = sort { $a cmp $b } @inputClients; $self->{clients} = [arrayDifference($self->{clients}, \@inputClients)]; } sub selectAll { 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; } sub dump { my ($self) = @_; my $root = XmlNode->new('migration-dump', 'attributes' => {'agent-name' => 'PleskX', 'dump-version' => PleskMaxVersion::get()}); if ($self->{description}) { $root->{'ADDCHILD'}->(XmlNode->new('description', 'content' => $self->{description})); } if (exists $self->{clients}) { my %clientsDesc; # if domains & accounts specified simultaneously, then it's a backup and only selected # domains should be included in backup if (!exists $self->{domains}) { my @domains = sort { $a cmp $b } PleskStructure::getDomains(); $self->{domains} = \@domains; } my $client; foreach $client (@{$self->{clients}}) { my @clientDomains = PleskStructure::getDomainsForClient($client); @clientDomains = sort { $a cmp $b } @clientDomains; my @domainsToDump = arrayIntersection(\@clientDomains, $self->{domains}); $clientsDesc{$client} = \@domainsToDump; } $self->createClientsDump($root, \%clientsDesc); $self->makeServerNode($root) if exists $self->{server_settings}; } elsif (exists $self->{domains}) { $self->createDomainsDump($root, $self->{domains}); $self->makeServerNode($root) if exists $self->{server_settings}; } elsif (exists $self->{server_settings}){ $self->makeServerNode($root); } else { die "No objects to dump found"; } return $self->{storage}->finish($root); } # --- Utility methods --- # # Converts the old country codes to the recent ones # sub normalizeCountry { my ($country) = @_; return 'RU' if $country eq 'SU'; return 'GB' if $country eq 'UK'; return $country; } # # Converts 'crypt' -> 'encrypted'. # Several versions of Plesk stored 'crypt' in psa.accounts.type table instead of 'encrypted' # bug 47030 # sub normalizePasswordType { my ($type) = @_; return "encrypted" if $type eq "crypt"; return $type; } # # Creates 'limit' node with given limit name and value # sub insertLimitNode { my ($node, $name, $value) = @_; $node->{'ADDCHILD'}->(XmlNode->new("limit", "attributes" => {"name" => $name}, "content" => $value)); } # # Creates named item in domain template node # sub addTemplateItem { my ($node, $name, $value) = @_; $node->{'ADDCHILD'}->(XmlNode->new("template-item", "attributes" => {"name" => $name}, "content" => $value)); } # # Creates node representing pre-8.0 DNS master record # sub makeOldMasterRec { my ($ipAddress) = @_; return XmlNode->new("dnsrec", "attributes" => {"src" => $ipAddress, "type" => "master"}); } sub addUrlDecodedTextNode { my ($parent, $name, $value) = @_; $parent->{'ADDCHILD'}->(XmlNode->new($name, "content" => urlDecode($value))) if $value; } sub makeAnonftpPermissionNode { my ($parent, $name) = @_; $parent->{'ADDCHILD'}->(XmlNode->new('anonftp-permission', "attributes" => {"name" => $name})); } sub makeAnonftpLimitNode { my ($parent, $name, $value) = @_; if($value != 0) { $parent->{'ADDCHILD'}->(XmlNode->new("anonftp-limit", "attributes" => {"name" => $name}, "content" => $value)); } } sub parseCustomButtonOptions { my ($node, $options) = @_; #CUSTOM_BUTTON_PUBLIC $node->{'ATTRIBUTE'}->('visible-to-sublogins', $options & 128 ? 'true' : 'false'); #CUSTOM_BUTTON_INTERNAL $node->{'ATTRIBUTE'}->('open-in-same-frame', $options & 256 ? 'true' : 'false'); my %options = ( "domain-id" => 1, #CUSTOM_BUTTON_DOM_ID "domain-name" => 32, #CUSTOM_BUTTON_DOM_NAME "ftp-login" => 512, #CUSTOM_BUTTON_FTP_USER "ftp-password" => 1024, #CUSTOM_BUTTON_FTP_PASS "client-id" => 2, #CUSTOM_BUTTON_CL_ID "client-company-name" => 4, #CUSTOM_BUTTON_CNAME "client-contact-name" => 8, #CUSTOM_BUTTON_PNAME "client-email" => 16, #CUSTOM_BUTTON_EMAIL ); while (my ($optname, $optmask) = each %options) { if ($options & $optmask) { $node->{'ADDCHILD'}->(XmlNode->new("url-option", "attributes" => {"name" => $optname})); } } } sub getPostgresqlVersion { my $psql = AgentConfig::psqlBin(); my @out = `$psql --version | awk '{print \$3}'`; chomp $out[0]; if ($out[0]=~/(\d+\.\d+\.\d+).*/){ return $1; } } # Returns the elements that present in first array, but not in the second. # Arrays must be sorted. # Linear complexity. sub arrayDifference { my ($a1, $a2) = @_; my @ret; my $i1 = 0; my $i2 = 0; while ($i1 < scalar(@$a1) && $i2 < scalar(@$a2)) { if ($a1->[$i1] eq $a2->[$i2]) { $i1++; $i2++; next; } if ($a1->[$i1] lt $a2->[$i2]) { push @ret, $a1->[$i1]; $i1++; next; } if ($a1->[$i1] gt $a2->[$i2]) { $i2++; next; } } while ($i1 < scalar(@$a1)) { push @ret, $a1->[$i1]; $i1++; } return @ret; } # Returns the elements that present in both arrays # Arrays must be storted # Linear complexity sub arrayIntersection { my ($a1, $a2) = @_; my @ret; my $i1 = 0; my $i2 = 0; while ($i1 < scalar(@$a1) && $i2 < scalar(@$a2)) { if ($a1->[$i1] eq $a2->[$i2]) { push @ret, $a1->[$i1]; $i1++; $i2++; next; } if ($a1->[$i1] lt $a2->[$i2]) { $i1++; next; } if ($a1->[$i1] gt $a2->[$i2]) { $i2++; next; } } return @ret; } # --- Private instance methods --- # # maps to translate xmlName => fieldName # my %xmlPermissions = ('create_domains'=>1, 'create_domains'=>1, 'manage_phosting'=>1, 'manage_php_safe_mode'=>1, 'manage_quota'=>1, 'manage_subdomains'=>1, 'change_limits'=>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, 'make_phosting'=>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_dashboard'=>1, 'dashboard'=>1, 'stdgui'=>1, 'manage_virusfilter'=>1, 'manage_spamfilter'=>1, 'manage_webstat'=>1, 'manage_performance'=>1, 'select_db_server'=>1 ); my %mailUserPermissions = ( 'cp_access' => 'cp-access', 'manage_virusfilter' => 'manage-virusfilter', 'manage_spamfilter' => 'manage-spamfilter' ); my %commonLimits = ('max_wu' => 1, 'max_db' => 1, 'max_pbox' => 1, 'mbox_quota' => 1, 'max_redir' => 1, 'max_mg' => 1, 'max_resp' => 1, 'disk_space' => 1, 'max_traffic' => 1 ); my %domainLimits25 = %commonLimits; $domainLimits25{'max_box'} = 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; my %clientLimits25 = %domainLimits25; $clientLimits25{'max_dom'} = 1; my %clientLimits = %domainLimits; $clientLimits{'max_dom'} = 1; my %typeOfField = ('expiration'=>'timestamp'); my %clientsAttribute = ('name'=>'login', 'contact'=>'pname', 'cr-date'=>'cr_date', ); my %clientsInfo = ('company'=>'cname', 'phone'=>'phone', 'fax'=>'fax', 'address'=>'address', 'city'=>'city', 'state'=>'state', 'zip'=>'pcode', 'country'=>'country', 'email'=>'email', ); my %domainUserAttribute = ('contact'=>'personalName',); my %domainUserInfo = ('company'=>'companyName', 'phone'=>'phone', 'fax'=>'fax', 'address'=>'address', 'city'=>'city', 'state'=>'state', 'zip'=>'zip', 'email'=>'email', 'country'=>'country',); my %hostingAttribute = ('https'=>'ssl', 'fp'=>'fp', 'fpssl'=>'fp_ssl', 'fpauth'=>'fp_enable', 'webstat'=>'webstat', # 'at-domains'=>'at_domains', ); my %hostingScripting = ('ssi'=>'ssi', 'php'=>'php', 'php_safe_mode'=>'php_safe_mode', 'cgi'=>'cgi', 'perl'=>'perl', 'asp'=>'asp', 'python'=>'python', 'coldfusion'=>'coldfusion', 'asp_dot_net'=>'asp_dot_net', 'fastcgi'=>'fastcgi', 'miva'=>'miva' ); my %webUserScripting = ('ssi'=>'ssi', 'php'=>'php', 'cgi'=>'cgi', 'perl'=>'perl', 'asp'=>'asp', 'python'=>'python', 'asp_dot_net'=>'asp_dot_net', 'fastcgi'=>'fastcgi', 'miva'=>'miva' ); 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' ); my %emptyableBoolElementInTemplate = ( 'asp' => 1, 'cgi' => 1, 'coldfusion' => 1, 'pdir_plesk_stat' => 1, 'perl' => 1, 'php' => 1, 'python' => 1, 'ssi' => 1 ); my %custom_button_owner_types = ( "admin" => 1, #IS_ADMIN "client" => 4, #IS_CLIENT "domain-admin" => 8, #IS_DOMAIN_OWNER "mailuser" => 16, #IS_MAIL_USER ); my %locale_map = ('bg' => 'bg', 'hk' => 'zh-HK', 'ru' => 'ru-RU', 'en' => 'en-US', 'nl' => 'nl-NL', 'br' => 'pt-BR', 'it' => 'it-IT', 'tr' => 'tr-TR', 'es' => 'es-ES', 'pl' => 'pl-PL', 'ca' => 'ca-ES', 'jp' => 'ja-JP', 'tw' => 'zh-TW', 'fi' => 'fi-FI', 'cn' => 'zh-CN', 'ko' => 'ko-KR', 'fr' => 'fr-FR', 'pt' => 'pt-PT', 'de' => 'de-DE', 'lt' => 'lt-LT' ); # list of attributes for template-item node in dump.xml # needs to synchronize with template-item's ATTLIST of plesk.dtd my %template_items = ('webmail' => 1, 'disk_space' => 1, 'wu_script' => 1, 'stat_ttl' => 1, 'maillists' => 1, 'nonexist_mail' => 1, 'catch_addr' => 1, 'bounce_mess' => 1, 'max_traffic' => 1, 'max_box' => 1, 'mbox_quota' => 1, 'max_redir' => 1, 'max_mg' => 1, 'max_resp' => 1, 'max_wu' => 1, 'max_db' => 1, 'max_maillists' => 1, 'max_webapps' => 1, 'max_subdom' => 1, 'expiration' => 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, 'coldfusion' => 1, 'webstat' => 1, 'errdocs' => 1, 'shell' => 1, 'pdir_plesk_stat' => 1, 'dns_type' => 1, 'max_dom_aliases' => 1, # client template 'allow_ftp_backups' => 1, 'allow_local_backups' => 1, 'change_limits' => 1, 'cp_access' => 1, 'create_domains' => 1, 'dashboard' => 1, 'excl_ip_num' => 1, 'manage_anonftp' => 1, 'manage_crontab' => 1, 'manage_dashboard' => 1, 'manage_dns' => 1, 'manage_domain_aliases' => 1, 'manage_drweb' => 1, 'manage_log' => 1, 'manage_maillists' => 1, 'manage_not_chroot_shell' => 1, 'manage_phosting' => 1, 'manage_quota' => 1, 'manage_sh_access' => 1, 'manage_spamfilter' => 1, 'manage_subdomains' => 1, 'manage_webapps' => 1, 'max_dom' => 1, 'remote_access_interface' => 1, 'stdgui' => 1, 'manage_php_safe_mode' => 1, 'manage_webstat' => 1, 'select_db_server' => 1 ); # # end maps # sub addTar { my $self = shift; return if $self->{configuration_dump}; return $self->{storage}->addTar(@_); } sub addDb { my $self = shift; return if $self->{configuration_dump}; return $self->{storage}->addDb(@_); } sub createFullDump { my ($self, $root) = @_; my @clients = PleskStructure::getClients(); my %clientsDesc; my $client; foreach $client (@clients) { my @domains = PleskStructure::getDomainsForClient($client); $clientsDesc{$client} = \@domains; } $self->createClientsDump($root, \%clientsDesc); } # $clients - ref to the hash clientNames to ref of array of domainNames sub createClientsDump { my ($self, $root, $clients) = @_; my $client; my $domainsCount = 0; $domainsCount += scalar(@{$clients->{$_}}) foreach keys %{$clients}; $self->{dump_status}->start(scalar(keys %{$clients}), $domainsCount); foreach $client (keys %{$clients}) { my $node = $self->makeClientNode($client,$clients->{$client}); $root->{'ADDCHILD'}->($node); $node->ReleaseCode(); #$root->{'ADDCHILD'}->($self->makeClientNode($client, $clients->{$client})); } $self->{dump_status}->finishObjects(); } # $domains - ref to the array of domain names sub createDomainsDump { my ($self, $root, $domains) = @_; $self->{dump_status}->start(0, scalar(@{$domains})); my $domain; foreach $domain (@{$domains}) { my $node = $self->makeDomainNode($domain); $root->{'ADDCHILD'}->( $node ); $node->ReleaseCode(); #$root->{'ADDCHILD'}->($self->makeDomainNode($domain)); } $self->{dump_status}->finishObjects(); } # Condition is not necessary if getting admin parameters sub getMaxButtonLength { my ($self, $parent, $table, $condition) = @_; my $sql = "SELECT val FROM $table WHERE param='max_button_length'"; $sql .= " AND $condition" if $condition; if ($self->{dbh}->execute_rownum($sql) and my $ptrRow = $self->{dbh}->fetchrow()) { if ($ptrRow->[0]) { $parent->{'ATTRIBUTE'}->('max-button-length', $ptrRow->[0]); } } $self->{dbh}->finish(); } #Condition is not necessary if getting admin parameters sub getSkin { my ($self, $parent, $table, $condition) = @_; return unless PleskVersion::atLeast(5, 0, 0); my ($skinId); if ($table eq 'dom_param' and !PleskVersion::atLeast(7,5,0)) { $skinId = "user_skin_id"; } else { $skinId = "skin_id"; } my $sql = "SELECT s.name FROM Skins as s, $table as t " . "WHERE t.param='$skinId' AND t.val = s.id"; $sql .= " AND $condition" if $condition; if ($self->{dbh}->execute_rownum($sql) and my $ptrRow = $self->{dbh}->fetchrow()) { $parent->{'ATTRIBUTE'}->('skin', $ptrRow->[0]); } $self->{dbh}->finish(); } sub getLockScreen { my ($self, $parent, $table, $condition) = @_; return unless PleskVersion::atLeast(7, 5, 2); my $sql = "SELECT val FROM $table WHERE param='disable_lock_screen'"; $sql .= " AND $condition" if $condition; my $ptrRow; if ($self->{dbh}->execute_rownum($sql) and $ptrRow = $self->{dbh}->fetchrow() and $ptrRow->[0] eq 'true') { $parent->{'ATTRIBUTE'}->('lock-screen', 'false'); } $self->{dbh}->finish(); } # # sub makeClientNode # # arguments: # $clientId - ID of client # $full - dump all domains # $ptrDomainHash # sub makeClientNode { my($self, $clientName, $domains)=@_; my ($item,$sql,$ptrHash,$value,%client,$ptrRow,$id,%clientParams); printToLog("Client '$clientName' is started"); $self->{dump_status}->startClient($clientName); $sql = "SELECT * FROM clients WHERE login = '$clientName'"; $self->{dbh}->execute($sql); %client = %{$self->{dbh}->fetchhash()}; $self->{dbh}->finish(); my $clientId = $client{'id'}; $client{'country'} = normalizeCountry($client{'country'}); my $root = XmlNode->new('client', 'attributes' => {'id' => $clientId}); if (defined $client{'uid'}) { $root->{'ATTRIBUTE'}->('uid', $client{'uid'}); $root->{'ATTRIBUTE'}->('ownership', $client{'ownership'} eq 'true' ? 'true' : 'false'); } $root->setAttribute('guid', $client{'guid'}) if (defined $client{'guid'}); my($attribute,$field,$name); if(exists $client{'locale'} && $client{'locale'}) { while (($name, $field) = each(%locale_map)) { if($client{'locale'} eq $name) { $client{'locale'} = $field; } } } while (($attribute,$field)=each(%clientsAttribute)){ if(exists($client{$field})){ unless (defined($client{$field})) { $client{$field} = ''; } $root->{'ATTRIBUTE'}->($attribute,$client{$field}); } } if (PleskVersion::atLeast(7, 1, 5)) { $sql = "SELECT password, type FROM accounts WHERE id = '" . $client{'account_id'} . "'"; $self->{dbh}->execute($sql); $ptrHash = $self->{dbh}->fetchhash(); $item = makePasswordNode($ptrHash->{'password'}, normalizePasswordType($ptrHash->{'type'})); $self->{dbh}->finish(); } else { $item = makePasswordNode($client{'passwd'},'plain'); } $root->{'ADDCHILD'}->($item); my $status = 0; if (PleskVersion::atLeast(5, 1, 0)) { $status = $client{'status'}; } else { $status |= $Status::ADMIN if $client{'status'} eq 'false'; } $root->{'ADDCHILD'}->(Status::make($status)); unless ($self->{shallow_dump}) { while (($name, $field) = each(%clientsInfo)) { if (exists($client{$field}) && $client{$field}) { $root->{'ADDCHILD'}->(XmlNode->new('pinfo', 'content' => $client{$field}, 'attributes' => {'name' => $name})); } } # Locale changed format since 7.5.0, and we # don't bother converting older formats if (PleskVersion::atLeast(7, 5, 0)) { if (exists($client{'locale'}) && $client{'locale'}) { $root->{'ADDCHILD'}->(XmlNode->new('pinfo', 'content' => $client{'locale'}, 'attributes' => {'name' => 'locale'})); } } unless (PleskVersion::atLeast(6, 0, 0)) { $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(); } # button length $self->getMaxButtonLength($root, "cl_param", "cl_id=$clientId"); $self->getSkin($root, "cl_param", "cl_id=$clientId"); $self->getLockScreen($root, "cl_param", "cl_id=$clientId"); # # limits # if (PleskVersion::atLeast(6, 0, 0)) { $self->addClientLimits($root, $client{'limits_id'}); } elsif (PleskVersion::atLeast(5, 0, 0)) { $self->addClientLimits($root, $clientParams{'lim_id'}); } else { $self->addClientLimits25($root, $clientId); } # # end limits # if (PleskVersion::atLeast(6, 0, 0)) { $self->addPermissions($root, $client{'perm_id'}); } elsif (PleskVersion::atLeast(5, 0, 0)) { $self->addPermissions($root, $clientParams{'perm_id'}); } else { $self->addPermissions25($root, $clientId); } #fix bug 88139 if ((PleskVersion::atLeast(7,5,1) and !$client{'perm_id'}) or !PleskVersion::atLeast(7,5,1)) { addPermissionNode($root,'cp_access', 'true'); } #fix bug 88544 if (!PleskVersion::atLeast(7,5,4)) { addPermissionNode($root,'manage_not_chroot_shell', 'true'); } if (!PleskVersion::atLeast(8,0,0)) { addPermissionNode($root,'stdgui', 'true'); } $self->addClientMulitpleLoginPermission($root, $clientId); # # Domain skeleton # if (PleskVersion::atLeast(6, 0, 0)) { my $skeletonPath = AgentConfig::get('HTTPD_VHOSTS_D') . "/.skel/$clientId"; my $dumpFile = $self->addTar("$client{'login'}.skel", 'directory' => $skeletonPath); $root->{'ATTRIBUTE'}->('cid-skeleton', $dumpFile) if $dumpFile; } } my @ips = PleskStructure::getClientIps($clientName); my $ip_pool = XmlNode->new('ip_pool'); $root->{'ADDCHILD'}->($ip_pool); foreach my $ip (@ips) { $ip_pool->{'ADDCHILD'}->(PleskStructure::makeIpNode($ip)); } # Site Applications pool $self->dumpSiteAppPool($root, $clientId); $self->dumpDomainTemplates($root, $clientId); # my @domains = PleskStructure::getDomainsForClient($clientName); # for my $domainName (@domains) { # $root->{'ADDCHILD'}->($self->makeDomainNode($domainName)); # } for my $domainName (@{$domains}) { my $dnode = $self->makeDomainNode($domainName); $root->{'ADDCHILD'}->($dnode); $dnode->ReleaseCode(); #$root->{'ADDCHILD'}->($self->makeDomainNode($domainName)); } $root->{'ADDCHILD'}->($_) foreach $self->getCustomButtonsByOwner("client", $clientId); $self->makeClientSiteBuilderNode($root, $clientId) if (PleskVersion::atLeast(8, 3, 0)); return $root; } sub makeClientSiteBuilderNode () { my ($self, $root, $clientId) = @_; my $sql = "SELECT sb_client_login, sb_reseller_id FROM SBResellers WHERE client_id='$clientId'"; if ($self->{dbh}->execute_rownum($sql)) { my $sbNode = XmlNode->new('sb-reseller'); while (my $ptrHash = $self->{dbh}->fetchhash()) { $sbNode->addChild(XmlNode->new('sb-client-login', 'content' => $ptrHash->{'sb_client_login'})); $sbNode->addChild(XmlNode->new('sb-reseller-id', 'content' => $ptrHash->{'sb_reseller_id'})); } $root->addChild($sbNode); } $self->{dbh}->finish(); } #----------------------------------------------------------------- # Dumps information about client's site applications pool #----------------------------------------------------------------- sub dumpSiteAppPool( $ $ ) { my ($self, $root, $cl_id) = @_; # There were no commercial site applications prior to Plesk 7.1.0 if (!PleskVersion::atLeast(7, 1, 0)) { return; } my $sql; if (PleskVersion::atLeast(8, 3, 0)) { $sql = "SELECT sap.name AS sapp_name, sap.version AS sapp_version, sap.release AS sapp_release, lt.license_type_hash AS license_type_id, ai.shared AS shared, cai.instances_limit AS instances_limit " . "FROM APSClientApplicationItems AS cai " . "INNER JOIN APSApplicationItems AS ai ON (ai.id = cai.app_item_id AND cai.client_id = '$cl_id') " . "INNER JOIN SiteAppPackages AS sap ON (sap.id=ai.pkg_id)" . "LEFT JOIN APSLicenseTypes AS lt ON (ai.license_type_id = lt.id) AND ai.shared = 'false'"; }elsif (PleskVersion::atLeast(7, 1, 0)) { $sql = "SELECT sp.name AS sapp_name, sp.version AS sapp_version, sp.release AS sapp_release " . "FROM clients c INNER JOIN Repository r ON c.sapp_pool_id=r.rep_id " . "LEFT JOIN SiteAppPackages sp ON r.component_id=sp.id " . "WHERE c.id='$cl_id' AND (sp.access_level & 1) <> 0"; } if ($self->{dbh}->execute_rownum($sql)) { my $sapp_pool = XmlNode->new('sapp-pool'); $root->{'ADDCHILD'}->($sapp_pool); while (my $ptrHash = $self->{dbh}->fetchhash()) { $self->makeSiteAppItemNode($sapp_pool, $ptrHash); } } $self->{dbh}->finish(); } sub addPermissions25 { my ($self, $root, $id) = @_; # [42098] migration from 7.14 to 7.50 fails return unless ($id); my ($perm_name, $sql, $ptrRow, $value, $item); my @perm_names = ('create_domains', 'manage_dns', 'manage_log'); foreach $perm_name (@perm_names) { $sql = "SELECT DISTINCT val FROM cl_param WHERE cl_id = '$id' AND param = '$perm_name'"; if ($self->{dbh}->execute_rownum($sql)) { my $value = @{$self->{dbh}->fetchrow()}[0]; addPermissionNode($root, $perm_name, $value); } $self->{dbh}->finish(); } $sql = "SELECT DISTINCT val FROM cl_param WHERE cl_id='$id' AND (param='ip_based_allow' OR param='nb_allow')"; if ($self->{dbh}->execute_rownum($sql)) { my $value = @{$self->{dbh}->fetchrow()}[0]; addPermissionNode($root, 'manage_phosting', $value); } $self->{dbh}->finish(); } sub addPermissions { my ($self, $root, $id) = @_; my ($sql, $ptrRow, $item, $name, $value); # [42098] migration from 7.14 to 7.50 fails return unless ($id); $sql = "SELECT permission,value FROM Permissions WHERE id=$id"; if ($self->{dbh}->execute_rownum($sql)) { while ($ptrRow = $self->{dbh}->fetchrow()) { $name = $ptrRow->[0]; $value = $ptrRow->[1]; $name = "manage_virusfilter" if $name eq "manage_drweb"; next unless exists $xmlPermissions{$name}; if ($name eq 'make_dumps') { addPermissionNode($root, 'allow_local_backups', $value); addPermissionNode($root, 'allow_ftp_backups', $value); next; } addPermissionNode($root, $name, $value); } } $self->{dbh}->finish(); $sql = "SELECT value FROM Permissions WHERE id = $id and (" . "permission = 'ipb_allow' or permission = 'nb_allow')"; if ($self->{dbh}->execute_rownum($sql)) { my $value = @{$self->{dbh}->fetchrow()}[0]; addPermissionNode($root, 'manage_phosting', $value); } $self->{dbh}->finish(); } sub addDomainUserMultipleLoginPermission { my ($self, $root, $id) = @_; my $sql = "SELECT val FROM dom_param WHERE dom_id=$id AND param='multiply_login'"; if ($self->{dbh}->execute_rownum($sql)) { my $multiple_sessions = $self->{dbh}->fetchrow()->[0]; # Old plesks have bug when mn_param table contains 1 instead of 'true'. Fixing. if ($multiple_sessions eq '1') { $multiple_sessions = 'true'; } addPermissionNode($root, 'multiple-sessions', $multiple_sessions eq 'true' ? 'true' : 'false'); } $self->{dbh}->finish(); } sub addClientMulitpleLoginPermission { my ($self, $root, $id) = @_; my $sql = "SELECT val FROM cl_param WHERE cl_id =$id AND param='multiply_login'"; if ($self->{dbh}->execute_rownum($sql)) { addPermissionNode($root, 'multiple-sessions', @{$self->{dbh}->fetchrow()}[0]); } $self->{dbh}->finish(); } sub addMailUserMultipleLoginPermission { my ($self, $root, $id) = @_; return unless PleskVersion::atLeast(6, 0, 0); my $sql = "SELECT val FROM mn_param WHERE mn_id=$id AND param='multiply_login'"; if ($self->{dbh}->execute_rownum($sql)) { my $multiple_sessions = $self->{dbh}->fetchrow()->[0]; # Old plesks have bug when mn_param table contains 1 instead of 'true'. Fixing. if ($multiple_sessions eq '1') { $multiple_sessions = 'true'; } addMailuserPermissionNode($root, 'multiple-sessions', $multiple_sessions); } $self->{dbh}->finish(); } sub insertLimit { my ($self, $root, $name, $value) = @_; if ($value eq '' || $value eq '-1') { insertLimitNode($root, $name, '-1'); return; } if ($name eq 'expiration') { my ($mday,$mon,$year) = (localtime($value))[3..5]; $mon++; $year += 1900; $value = sprintf('%04d-%02d-%02d', $year, $mon, $mday); } if (!PleskVersion::atLeast(7, 0, 0) && $name eq 'mbox_quota') { $value = $value * 1024; } insertLimitNode($root, $name, $value); } sub addClientLimits { my ($self, $root, $clientId) = @_; return $self->addLimits($root, $clientId, \%clientLimits); } sub addClientLimits25 { my ($self, $root, $clientId) = @_; return $self->addLimits25($root, $clientId, \%clientLimits25, 'cl_id', 'cl_param'); } sub addDomainLimits { my ($self, $root, $clientId) = @_; return $self->addLimits($root, $clientId, \%domainLimits); } sub addDomainLimits25 { my ($self, $root,$domainId) = @_; $self->addLimits25($root, $domainId, \%domainLimits25, 'dom_id', 'dom_param'); #fix bug 50361 my $ptrRow; my $sql ="SELECT traffic FROM hosting WHERE dom_id='$domainId'"; if ($self->{dbh}->execute_rownum($sql) && ($ptrRow = $self->{dbh}->fetchrow())){ $self->insertLimit($root, 'max_traffic', $ptrRow->[0]); } $self->{dbh}->finish(); $sql = "SELECT size FROM domains WHERE id='$domainId'"; if ($self->{dbh}->execute_rownum($sql) && ($ptrRow = $self->{dbh}->fetchrow())){ $self->insertLimit($root, 'disk_space', $ptrRow->[0]); } $self->{dbh}->finish(); } sub addLimits25 { my($self, $root, $limitId, $limitNames, $idName, $paramName)=@_; if(!$limitId) { return; } my($value, $name, $count, $sql, $ptrRow); $sql = "SELECT val, param FROM $paramName WHERE $idName='$limitId'"; if ($self->{dbh}->execute_rownum($sql)) { while ($ptrRow = $self->{dbh}->fetchrow()) { ($name, $value) = @{$ptrRow}; } } foreach $name (%{$limitNames}) { $sql = "SELECT val FROM $paramName WHERE $idName = '$limitId' AND param = '$name'"; if(($self->{dbh}->execute_rownum($sql)) && ($ptrRow = $self->{dbh}->fetchrow())) { ($value) = @{$ptrRow}; if($name eq 'max_pbox') { $name = 'max_box'; } $self->insertLimit($root, $name, $value); } $self->{dbh}->finish(); } } # # sub addLimits # # arguments: # $root - XML node to add 'limit' node # $limitID - limit id # # return: # $count - number of the added nodes # sub addLimits { my ($self, $root, $limitId, $limitNames) = @_; my $count; if (!$limitId) { foreach my $key (keys %{$limitNames}) { next if $key eq 'max_pbox'; $self->insertLimit($root, $key, "-1"); $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($root, $name, $value); $count++; } } $self->{dbh}->finish(); return $count; } # # Gather domain templates information # sub dumpDomainTemplates { my ($self, $root, $clientId, $tmpl_id) = @_; return unless PleskVersion::atLeast(5, 0, 0); my $sql; if ($clientId) { if (PleskVersion::atLeast(6, 0 ,0)) { $sql = "SELECT tmpl_id FROM clients WHERE id=$clientId"; } else { $sql = "SELECT val FROM cl_param WHERE cl_id=$clientId AND ". "param = 'dom_tmpl_list_id'"; } if ($self->{dbh}->execute_rownum($sql)) { $tmpl_id = @{$self->{dbh}->fetchrow()}[0]; } $self->{dbh}->finish(); } $self->dumpTemplates($root, $tmpl_id, 'domain-template'); } sub dumpTemplates { my ($self, $root, $tmpl_id, $node_name) = @_; return unless $tmpl_id; my $sql; my %templateNames; my %templateNotes; $sql = "SELECT t.id, t.name, t.note_id FROM Templates t, Repository r " . "WHERE r.rep_id=$tmpl_id AND r.component_id = t.id"; $self->{dbh}->execute($sql); while (my $ptrRow = $self->{dbh}->fetchrow()) { $templateNames{$ptrRow->[0]} = $ptrRow->[1]; $templateNotes{$ptrRow->[0]} = $ptrRow->[2]; } $self->{dbh}->finish(); while (my ($tmpl_id, $tmpl_name) = each %templateNames) { my $node = XmlNode->new($node_name, 'attributes' => {'name' => $tmpl_name}); if ($templateNotes{$tmpl_id}) { $node->{'ATTRIBUTE'}->('note-id', $templateNotes{$tmpl_id}); } my $logrotation_id; my $sql = "SELECT element, value FROM TmplData WHERE tmpl_id=$tmpl_id"; $self->{dbh}->execute($sql); while (my $ptrRow = $self->{dbh}->fetchrow()) { my ($element, $value) = @{$ptrRow}; if(!defined($value)) { $value = ''; } $value = -1 if ($element eq 'stat_ttl' and ($value == 0 or $value eq '')); $value = -1 if ($element eq 'disk_space' or $element eq 'max_traffic' or $element eq 'mbox_quota') and $value == 0; $value = 'physical' if ($element eq 'vh_type' and $value ne 'none' and !PleskVersion::atLeast(6, 0, 0)); if ($element eq 'logrotation_id') { $logrotation_id = $value; next; } next if not exists $template_items{$element}; if ($element eq 'quota' and ($value eq 'false' or $value == 0)) { $value = -1; } $value*= 1024 if ($element eq 'mbox_quota' and $value != -1 and !PleskVersion::atLeast(7, 0, 0)); $value*= 1024*1024 if ($element eq 'quota' and $value != -1 and !PleskVersion::atLeast(7, 0, 0)); if ($value eq '' and exists $emptyableBoolElementInTemplate{$element}) { $value = 'false'; } addTemplateItem($node, $element, $value); } $self->{dbh}->finish(); if ($logrotation_id and ($node_name eq 'domain-template')) { $self->makeLogrotationNode($node, $logrotation_id); } unless (PleskVersion::atLeast(6, 0, 0)) { addTemplateItem($node, 'dns_type', 'master'); } $root->{'ADDCHILD'}->($node); } } # # Returns the XML node if domain service is present and undef # otherwise # sub getDomainServiceStatus { my ($self, $domId, $service) = @_; my $status = 0; my $sql = "SELECT status FROM DomainServices " . " WHERE dom_id=$domId AND type='$service'"; if ($self->{dbh}->execute_rownum($sql) and my $ptrRow = $self->{dbh}->fetchrow()){ $status = $ptrRow->[0]; } else { $status = undef; } $self->{dbh}->finish(); if (defined($status)) { return Status::make($status); } } # # makeDomainNode # # arguments: # $domainId - domain id # # return: # $root - pointer to XML node # sub makeDomainNode { my($self, $domainName)=@_; printToLog("Domain '$domainName' is started"); $self->{dump_status}->startDomain($domainName); my($sql,%domain,%domParams,$ptrRow,$ptrHash,$id); # # get domain's info # my $domainNameColumn = 'name'; if (PleskVersion::atLeast(7, 1, 0)) { $domainNameColumn = 'displayName'; } printToLog("Getting domain info"); $sql = "SELECT * FROM domains WHERE $domainNameColumn = '$domainName'"; unless($self->{dbh}->execute_rownum($sql)){ $self->{dbh}->finish(); return undef; } unless($ptrHash = $self->{dbh}->fetchhash()){ $self->{dbh}->finish(); return undef; } %domain=%{$ptrHash}; $self->{dbh}->finish(); my $domainId = $domain{'id'}; $sql = "SELECT param,val FROM dom_param WHERE dom_id=$domainId"; if($self->{dbh}->execute_rownum($sql)){ while ($ptrRow = $self->{dbh}->fetchrow()){ $domParams{$ptrRow->[0]}=$ptrRow->[1]; } } $self->{dbh}->finish(); # # end get domain's info # if (PleskVersion::atLeast(7, 1, 0)) { $domainName = $domain{'displayName'}; } else { $domainName = $domain{'name'}; } my $root = XmlNode->new('domain', 'attributes' => {'name' => $domainName, 'id' => $domainId}); $root->setAttribute('cr-date', $domain{'cr_date'}) if exists $domain{'cr_date'}; $root->setAttribute('guid', $domain{'guid'}) if defined $domain{'guid'}; my $domainAsciiName = $domain{'name'}; my $domainType = $domain{'htype'}; $self->addWwwStatus($root, $domainId, $domainAsciiName); # Domain's IP address printToLog("Getting domain IP"); my $ip = PleskStructure::getDomainIp($domainName); if ($ip) { $root->{'ADDCHILD'}->(PleskStructure::makeIpNode($ip)); } # # Status # printToLog("Dupming domain status"); my $status = 0; if (PleskVersion::atLeast(5, 1, 0)) { $status = $domain{'status'}; } else { $status |= $Status::ADMIN if $domain{'admin_status'} eq 'false'; $status |= $Status::CLIENT if $domain{'status'} eq 'false'; } $root->{'ADDCHILD'}->(Status::make($status)); # # 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 printToLog("Dumping domain databases"); $sql = "SELECT id FROM data_bases WHERE dom_id=$domainId"; if ($self->{dbh}->execute_rownum($sql)) { my (@databases); while ($ptrRow = $self->{dbh}->fetchrow()) { push @databases,$ptrRow->[0]; } $self->{dbh}->finish(); foreach my $dbid (@databases) { my ($item) = $self->makeDatabaseNode($dbid); $root->addChild($item) if ref($item) =~ /XmlNode/; } } $self->{dbh}->finish(); return $root; } # Check whether this domain is default on IP if (PleskVersion::atLeast(6, 0, 0)) { $sql = "SELECT COUNT(*) FROM IP_Addresses WHERE default_domain_id=$domainId"; if ($self->{dbh}->execute_rownum($sql)) { if (@{$self->{dbh}->fetchrow()}[0] ne "0") { $root->{'ADDCHILD'}->(XmlNode->new('default-domain')); } } $self->{dbh}->finish(); } else { if (PleskStructure::isExclusiveIp($ip)) { $root->{'ADDCHILD'}->(XmlNode->new('default-domain')); } } printToLog("Getting domain limits"); # # limits # if (!$self->{only_mail_dump}) { if (PleskVersion::atLeast(6, 0, 0)) { $self->addDomainLimits($root,$domain{'limits_id'}); } elsif (PleskVersion::atLeast(5, 0, 0)) { $self->addDomainLimits($root,$domParams{'lim_id'}); } else { $self->addDomainLimits25($root,$domainId); } } # # end limits # # # permissions # # # end permissions # if (!$self->{only_hosting_dump}) { printToLog("Dumping domain mailsystem"); my $mailServiceStatus; if (PleskVersion::atLeast(6, 0, 0)) { $mailServiceStatus = $self->getDomainServiceStatus($domainId, 'mail'); } else { $mailServiceStatus = Status::make($Status::ENABLED); } if ($mailServiceStatus) { my $rootMail = XmlNode->new('mailsystem'); $rootMail->{'ADDCHILD'}->($mailServiceStatus); if (PleskVersion::atLeast(6, 0, 0)) { $sql = "SELECT m.id, a.password, a.type FROM mail m". " LEFT JOIN accounts a ON m.account_id=a.id ". " WHERE m.dom_id=$domainId ORDER BY m.mail_name"; } else { $sql = "SELECT id, password, 'plain' FROM mail ". " WHERE dom_id=$domainId ORDER BY mail_name"; } if ($self->{dbh}->execute_rownum($sql)){ my(@mails); while($ptrRow = $self->{dbh}->fetchrow()){ push @mails,[@{$ptrRow}]; } $self->{dbh}->finish(); foreach $ptrRow (@mails){ $ptrRow->[2] = normalizePasswordType($ptrRow->[2]); my $item = $self->makeMailUserNode(@{$ptrRow},$domainName, $domainAsciiName); $rootMail->{'ADDCHILD'}->($item) if ref($item) =~ /XmlNode/; $item->ReleaseCode() if ref($item) =~ /XmlNode/; } } else { $self->{dbh}->finish(); } $self->getCatchAllAddress($rootMail, $domainId); $self->getDomainKeysDomainSupport($rootMail, $domainId, $domainName, $domain{'dns_zone_id'}); $root->{'ADDCHILD'}->($rootMail); } } else{ printToLog("Skip domain mailsystem dump due to settings"); } my @SiteApplications; if (!$self->{only_mail_dump}) { # Domain's DNS settings my $dnsZoneNode = $self->makeDomainDnsZone(\%domain); $root->{'ADDCHILD'}->($dnsZoneNode) if $dnsZoneNode; # Domain's aliases $self->dumpDomainAliases($domainId, $root); #----------------------------------------------------------------- # Information about domain's site applications # should be extracted prior to database/hosting/custom-buttons # dump, as site applications' linked resources should be dumped # separately. #----------------------------------------------------------------- @SiteApplications = $self->getDomainSiteapps($domainId); #----------------------------------------------------------------- # Domain's databases #----------------------------------------------------------------- printToLog("Dumping domain databases"); # Site applications' databases should not be dumped here my $exclude_list = ''; { my @excluded_dbs; foreach my $sapp (@SiteApplications) { foreach my $row ($sapp->getDatabases()) { push @excluded_dbs, $row->{'id'}; } } if (@excluded_dbs) { $exclude_list = " AND id NOT IN(" . getSqlList(@excluded_dbs) . ")"; } } # Databases without those used in site apps $sql = "SELECT id FROM data_bases WHERE dom_id=$domainId" . $exclude_list; if ($self->{dbh}->execute_rownum($sql)) { my (@databases); while ($ptrRow = $self->{dbh}->fetchrow()) { push @databases,$ptrRow->[0]; } $self->{dbh}->finish(); foreach my $dbid (@databases) { my ($item) = $self->makeDatabaseNode($dbid); $root->addChild($item) if ref($item) =~ /XmlNode/; } } $self->{dbh}->finish(); } else{ printToLog("Skip dumping domain databases due to settings"); } # # maillist # if (!$self->{only_hosting_dump}) { printToLog("Dumping domain maillists"); if (PleskVersion::atLeast(6, 0, 0)) { my $maillistsStatus = $self->getDomainServiceStatus($domainId, 'maillists'); if ($maillistsStatus) { my $mlNode = XmlNode->new('maillists'); $mlNode->{'ADDCHILD'}->($maillistsStatus); $sql="SELECT id,name,status FROM MailLists WHERE dom_id=$domainId"; if($self->{dbh}->execute_rownum($sql)){ my (@mlists); while($ptrRow=$self->{dbh}->fetchrow()){ push @mlists,[@{$ptrRow}]; } $self->{dbh}->finish(); foreach $ptrRow (@mlists){ my $item = $self->makeMailListNode(@{$ptrRow}); if(ref($item)=~/XmlNode/){ $mlNode->{'ADDCHILD'}->($item); $item->ReleaseCode(); } } } $self->{dbh}->finish(); $root->{'ADDCHILD'}->($mlNode); } } } else{ printToLog("Skip dumping domain maillists due to settings"); } # # end maillist # if ($self->{only_mail_dump}) { return $root; } printToLog("Dumping domain statistics"); $self->addCurrentTraffic($root,$domainId); if (PleskVersion::atLeast(6, 0, 0)) { my $cert_id = $domain{'cert_rep_id'}; $cert_id = '' unless (defined($cert_id)); $sql = "SELECT c.id FROM certificates c, Repository r ". "WHERE c.id=r.component_id AND r.rep_id='$cert_id' ORDER BY c.id"; } else { $sql = "SELECT id FROM certificates WHERE dom_id=$domainId"; } my @ids; if ($self->{dbh}->execute_rownum($sql)) { while ($ptrRow = $self->{dbh}->fetchrow()) { push @ids, $ptrRow->[0]; } } $self->{dbh}->finish(); foreach $id (@ids) { my $item = $self->makeCertificateNode($id); if (ref($item)=~/XmlNode/) { $root->{'ADDCHILD'}->($item); } } my $tomcatServiceStatus; if (PleskVersion::atLeast(6, 0, 0)) { $tomcatServiceStatus = $self->getDomainServiceStatus($domainId, 'tomcat'); } if ($tomcatServiceStatus) { my $tomcatNode = XmlNode->new('tomcat'); $tomcatNode->{'ADDCHILD'}->($tomcatServiceStatus); $sql = "SELECT wa.name,wa.status FROM WebApps wa LEFT JOIN DomainServices ds ON wa.domain_service_id=ds.id WHERE ds.dom_id = $domainId"; my (%webapps,$webapp); if ($self->{dbh}->execute_rownum($sql)) { while ($ptrRow = $self->{dbh}->fetchrow()) { $webapps{$ptrRow->[0]} = $ptrRow->[1]; } } $self->{dbh}->finish(); foreach $webapp (keys %webapps) { $self->makeWebAppNode($tomcatNode,$webapp,$webapps{$webapp},$domainAsciiName); } $root->{'ADDCHILD'}->($tomcatNode); } my $item = $self->makeDomainUserNode($domainId); if(ref($item)=~/XmlNode/){ printToLog("Getting domain permissions"); # bug 79536 if ($id = $domParams{'perm_id'}) { $self->addPermissions($item,$id); } $root->{'ADDCHILD'}->($item); } my $hosting; if ($domainType eq "vrt_hst") { $hosting = $self->makePhostingNode(\%domain, \@SiteApplications); if (defined $domParams{'wu_script'} && $domParams{'wu_script'} eq 'true') { $hosting->{'ATTRIBUTE'}->('wu_script', 'true'); } } elsif ($domainType eq "std_fwd") { $hosting = $self->makeShostingNode(\%domain); } elsif ($domainType eq "frm_fwd") { $hosting = $self->makeFhostingNode(\%domain); } $root->{'ADDCHILD'}->($hosting) if $hosting; $root->{'ADDCHILD'}->($_) foreach $self->getCustomButtonsByOwner('domain-admin', $domainId); return $root; } #----------------------------------------------------------------- # Returns or xml elements #----------------------------------------------------------------- sub makeDomainDnsZone( $ ) { my ($self, $domainHashPtr) = @_; printToLog("Dumping domain DNS"); if (PleskVersion::atLeast(8, 0, 0)) { return $self->makeDnsZone($domainHashPtr->{'dns_zone_id'}); } else { return $self->makeDnsZoneOld($domainHashPtr->{'id'}); } } #----------------------------------------------------------------- # Returns xml node #----------------------------------------------------------------- sub makeDnsZoneParam( $ $ $ ) { my ($self, $name, $db_unit, $db_value) = @_; my $dnsZoneParam = XmlNode->new('dns-zone-param', 'attributes' => {'name' => $name, 'value' => $db_value}); my %units = ( 'second' => 1, 'minutes' => 60, 'hours' => 3600, 'days' => 86400, 'weeks' => 604800 ); my $string_unit; foreach my $quant (keys %units) { if ($units{$quant} == $db_unit) { $string_unit = $quant; last; } } $dnsZoneParam->{'ATTRIBUTE'}->('unit', $string_unit); return $dnsZoneParam; } #----------------------------------------------------------------- # Returns xml node or false if given record should not be dumped #----------------------------------------------------------------- sub makeDnsRecord( $ ) { my ($self, $ptrHash) = @_; return if $ptrHash->{'type'} =~ /none/; 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/\.$//; $ptrHash->{'val'} = PleskStructure::getDomainIp($ptrHash->{'val'}); } my $host = defined $ptrHash->{'displayHost'} ? $ptrHash->{'displayHost'} : $ptrHash->{'host'}; my $val = defined $ptrHash->{'displayVal'} ? $ptrHash->{'displayVal'} : $ptrHash->{'val'}; if ($ptrHash->{'type'} eq 'SRV') { $host =~ s/\.$//; $val =~ s/\.$//; } my ($item) = XmlNode->new('dnsrec', 'attributes' => {'type' => $ptrHash->{'type'}, 'src' => $host}); $item->setAttribute('dst', $val) if ($val); $item->setAttribute('opt', $ptrHash->{'opt'}) if (defined $ptrHash->{'opt'}); return $item; } sub makeDnsZone( $ ) { my ($self, $dnsZoneId) = @_; my $sql = "SELECT * FROM dns_zone WHERE id=$dnsZoneId"; if (!$self->{dbh}->execute_rownum($sql)) { $self->{dbh}->finish(); Logging::error("Broken referencial integrity: DNS zone id $dnsZoneId is not found in dns_zone"); return; } my $ptrHash = $self->{dbh}->fetchhash(); my $email; if (length($ptrHash->{'email'}) != 0) { $email = $ptrHash->{'email'}; } else { # should assume some default email or something... $email = 'root@localhost.localdomain'; } my $dnsZone = XmlNode->new('dns-zone', 'attributes' => {'email' => $email, 'type' => $ptrHash->{'type'}}, 'children' => [Status::make($ptrHash->{'status'})]); foreach my $zoneParam ('ttl', 'refresh', 'retry', 'expire', 'minimum') { $dnsZone->{'ADDCHILD'}->( $self->makeDnsZoneParam($zoneParam, $ptrHash->{$zoneParam . '_unit'}, $ptrHash->{$zoneParam})); } $self->{dbh}->finish(); # dns records $sql = "SELECT * FROM dns_recs WHERE dns_zone_id=$dnsZoneId"; if ($self->{dbh}->execute_rownum($sql)) { while (my $ptrHash = $self->{dbh}->fetchhash()) { my $dnsrec = $self->makeDnsRecord($ptrHash); if ($dnsrec) { $dnsZone->{'ADDCHILD'}->($dnsrec); } } } $self->{dbh}->finish(); return $dnsZone; } sub makeDnsZoneOld( $ ) { my ($self, $domainId) = @_; my $dnsNode = XmlNode->new('dns'); my $sql = "SELECT dns_zone"; if (PleskVersion::atLeast(5, 0, 0)) { $sql .= ",dns_type" } $sql .= " FROM domains WHERE id='$domainId'"; if ($self->{dbh}->execute_rownum($sql) and my $ptrRow = $self->{dbh}->fetchrow()) { $dnsNode->{'ATTRIBUTE'}->('enabled', $ptrRow->[0] eq 'false' ? 'false' : 'true'); $dnsNode->{'ATTRIBUTE'}->('type', (!$ptrRow->[1] or ($ptrRow->[1] eq 'master')) ? 'master' : 'slave'); } $self->{dbh}->finish(); $sql = "SELECT * FROM dns_recs WHERE dom_id=$domainId"; if ($self->{dbh}->execute_rownum($sql)) { my $ptrHash; while ($ptrHash = $self->{dbh}->fetchhash()) { my $dnsrec = $self->makeDnsRecord($ptrHash); if ($dnsrec) { $dnsNode->{'ADDCHILD'}->($dnsrec); } $ptrHash = undef; } } $self->{dbh}->finish(); # Add old master record $sql = "SELECT * FROM dns_masters WHERE dom_id = '$domainId'"; if ($self->{dbh}->execute_rownum($sql)) { while (my $ptrHash = $self->{dbh}->fetchhash()) { $dnsNode->{'ADDCHILD'}->(makeOldMasterRec($ptrHash->{'ip_address'})); } } $self->{dbh}->finish(); return $dnsNode; } #----------------------------------------------------------------- # Dumps domain aliases for given domain ID #----------------------------------------------------------------- sub dumpDomainAliases( $ $ ) { my ($self, $domainId, $root) = @_; # Domain aliases are introduced since Plesk 8.0.0 if (!PleskVersion::atLeast(8, 0, 0)) { return; } printToLog('Dumping domain aliases... ', 1); my @aliases; my $sql = "SELECT * FROM domainaliases WHERE dom_id='$domainId'"; if ($self->{dbh}->execute_rownum($sql)) { while (my $ptrHash = $self->{dbh}->fetchhash()) { push @aliases, $ptrHash; } } $self->{dbh}->finish(); foreach my $alias (@aliases) { my $aliasNode = XmlNode->new('domain-alias', 'attributes' => {'name' => $alias->{'displayName'}, 'mail' => $alias->{'mail'}, 'web' => $alias->{'web'}, 'dns' => defined $alias->{'dns'} ? $alias->{'dns'} : 'false'}, 'children' => [Status::make($alias->{'status'})]); $aliasNode->setAttribute('tomcat', $alias->{'tomcat'}) if defined $alias->{'tomcat'}; # DNS zone if ($alias->{'dns_zone_id'} != 0) { $aliasNode->{'ADDCHILD'}->($self->makeDnsZone($alias->{'dns_zone_id'})); } $root->{'ADDCHILD'}->($aliasNode); } printToLog('OK'); } #----------------------------------------------------------------- # Returns array of SiteApp objects, representing all site applications # installed on domain and its subdomains. #----------------------------------------------------------------- sub getDomainSiteapps( $ ) { my ($self, $dom_id) = @_; # Site applications migration is supported since Plesk 7.0.0 if (!PleskVersion::atLeast(7, 0, 0)) { return; } my @SiteApplications; my @sapp_ids; # ids of site apps installed on domain my $sql = "SELECT id FROM SiteApps WHERE dom_type='domain' AND dom_id='$dom_id'"; if ($self->{dbh}->execute_rownum($sql)) { while (my $idRow = $self->{dbh}->fetchrow()) { push @sapp_ids, $idRow->[0]; } } $self->{dbh}->finish(); # subdomains $sql = "SELECT id FROM subdomains WHERE dom_id=$dom_id"; my (@subdoms); if ($self->{dbh}->execute_rownum($sql)) { while (my $subdomRow = $self->{dbh}->fetchrow()) { push @subdoms, $subdomRow->[0]; } } $self->{dbh}->finish(); # ids of site apps installed on subdomains foreach my $subdom_id (@subdoms) { $sql = "SELECT id FROM SiteApps WHERE dom_type='subdomain' AND dom_id='$subdom_id'"; if ($self->{dbh}->execute_rownum($sql)) { while (my $idRow = $self->{dbh}->fetchrow()) { push @sapp_ids, $idRow->[0]; } } $self->{dbh}->finish(); } # create SiteApp objects foreach my $sapp_id (@sapp_ids) { my $sapp = new SiteApp($sapp_id, $self->{dbh}); if ($sapp->error()) { printToError($sapp->error()); next; } push @SiteApplications, $sapp; } return @SiteApplications; } sub addWwwStatus { my ($self, $parent, $domainId, $domainName) = @_; my $sql; if (PleskVersion::atLeast(8, 0, 0)) { $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' or r.type = 'A' ) AND r.host = 'www.$domainName.'"; } else { $sql = "SELECT * FROM dns_recs WHERE dom_id = $domainId AND ( type = 'CNAME' OR type = 'A' ) " . "AND host = 'www.$domainName.'"; } if ($self->{dbh}->execute_rownum($sql)) { $parent->{'ATTRIBUTE'}->('www', 'true'); } else { $parent->{'ATTRIBUTE'}->('www', 'false'); } $self->{dbh}->finish(); } sub makeDomainUserNode { my($self, $domainId) = @_; my($sql,$root,$item,$ptrHash,$xmlName,$fieldName); $sql="SELECT * FROM dom_level_usrs WHERE dom_id=$domainId"; unless($self->{dbh}->execute_rownum($sql)){ $self->{dbh}->finish(); return undef; } my %domainUser=%{$self->{dbh}->fetchhash()}; $self->{dbh}->finish(); $root = XmlNode->new('domainuser'); if (defined $domainUser{'uid'}) { $root->{'ATTRIBUTE'}->('uid', $domainUser{'uid'}); $root->{'ATTRIBUTE'}->('ownership', $domainUser{'ownership'} eq 'true' ? 'true' : 'false'); } if ($domainUser{'state'}) { $root->{'ATTRIBUTE'}->('status', $domainUser{'state'}); } if (PleskVersion::atLeast(7, 1, 5)) { if (defined $domainUser{'account_id'} and $domainUser{'account_id'} != 0) { $root->{'ADDCHILD'}->($self->makeAccountPasswordNode($domainUser{'account_id'})); } } else { $root->{'ADDCHILD'}->(makePasswordNode($domainUser{'passwd'}, 'plain')); } if (PleskVersion::atLeast(5, 0, 0) && defined($domainUser{'card_id'})) { $sql = "SELECT * from Cards WHERE id=$domainUser{'card_id'}"; if($self->{dbh}->execute_rownum($sql)){ $ptrHash = $self->{dbh}->fetchhash(); while (($xmlName,$fieldName)=each %domainUserAttribute){ if($ptrHash->{$fieldName}){ $root->{'ATTRIBUTE'}->($xmlName,$ptrHash->{$fieldName}); } } while (($xmlName, $fieldName) = each %domainUserInfo) { my $value = $ptrHash->{$fieldName}; if ($value) { $value = normalizeCountry($value) if $fieldName eq 'country'; $root->{'ADDCHILD'}->(XmlNode->new('pinfo', 'content' => $value, 'attributes' => {'name' => $xmlName})); } } } $self->{dbh}->finish(); } $self->addDomainUserLocale($root,$domainId); if (PleskVersion::atLeast(7, 1, 0)) { $self->addPermissions($root, $domainUser{'perm_id'}); } $self->addDomainUserMultipleLoginPermission($root, $domainId); if (!PleskVersion::atLeast(8,0,0)) { addPermissionNode($root,'stdgui', 'true'); } # max button length $self->getMaxButtonLength($root, "dom_param", "dom_id=$domainId"); $self->getSkin($root, "dom_param", "dom_id=$domainId"); $self->getLockScreen($root, "dom_param", "dom_id=$domainId"); return $root; } sub addDomainUserLocale { my ($self, $root, $domainId) = @_; my $locale = PleskVersion::atLeast(7, 1, 0) ? "locale" : "user_locale"; my $sql = "SELECT val FROM dom_param WHERE dom_id = $domainId AND param = '$locale'"; my $ptrRow; if ($self->{dbh}->execute_rownum($sql) && ($ptrRow = $self->{dbh}->fetchrow())) { if($ptrRow->[0]){ my ($key, $value); while (($key,$value) = each(%locale_map)){ if ($ptrRow->[0] eq $key) { $ptrRow->[0] = $value; } } $root->{'ADDCHILD'}->(XmlNode->new('pinfo', 'content' => $ptrRow->[0], 'attributes' =>{'name' => 'locale'})); } } $self->{dbh}->finish(); } # # addCurrentTraffic - add current traffic # # arguments: # $root - XML node to add traffic's nodes # $domainId - ID of domain # sub addCurrentTraffic { my ($self, $root, $domainId) = @_; my $trafficValue = ''; if (PleskVersion::atLeast(6, 0, 0)) { my $sql = "SELECT http_in, http_out, ftp_in, ftp_out, smtp_in, smtp_out, ". "pop3_imap_in, pop3_imap_out, date FROM DomainsTraffic WHERE dom_id=$domainId"; 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(); } else { my $sql = "SELECT transfer, date FROM stat WHERE dom_id=$domainId"; if ($self->{dbh}->execute_rownum($sql)) { my $ptrRow; while ($ptrRow = $self->{dbh}->fetchrow()) { if ($ptrRow->[0]) { $trafficValue .= $ptrRow->[1]; $trafficValue .= ' http in '; $trafficValue .= $ptrRow->[0]; $trafficValue .= "\n"; } } } $self->{dbh}->finish(); } $root->{'ADDCHILD'}->(XmlNode->new('traffic', 'content' => $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)) { $mode = @{$self->{dbh}->fetchrow()}[0]; } else { $mode = "bounce:This address no longer accepts mail."; } $self->{dbh}->finish(); return $mode; } sub getCatchAllAddress { my ($self, $parent, $domainId) = @_; my $sql; if (PleskVersion::atLeast(6, 0, 0)) { 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'"; } } elsif (PleskVersion::atLeast(5, 0, 0)) { $sql = "SELECT p.value FROM Parameters p, dom_param dp WHERE " . "dp.dom_id = $domainId AND dp.param='param_id' AND dp.val = p.id AND p.parameter = 'catch_addr'"; } else { $sql = "SELECT dp.val FROM dom_param dp WHERE dp.dom_id = $domainId AND dp.param = 'catch_addr'"; } # some not supported mode or default parameter [bug 43901] return unless ($sql); if ($self->{dbh}->execute_rownum($sql)) { my $catchAllAddr = @{$self->{dbh}->fetchrow()}[0]; if ($catchAllAddr) { $parent->{'ADDCHILD'}->(XmlNode->new('catch-all', 'content' => $catchAllAddr)); } } $self->{dbh}->finish(); } # # makeMailListNode # # arguments: # $mlistId - ID of the mail list # $mlistName - name # $mllistState - state of maillist # # return: # $root - XML node # sub makeMailListNode { my ($self, $mlistId, $mlistName, $mlistState) = @_; unless (defined Mailman::version()) { printToLog("Unable to found Mailman installation"); return; } my @owners = Mailman::getListOwners($mlistName); if (!@owners) { printToLog("Bad maillist $mlistName, skipped"); return; } my $root = XmlNode->new('maillist', 'attributes'=>{'name', $mlistName}, 'children' => [Status::make($mlistState)]); for my $listOwner (@owners) { $root->{'ADDCHILD'}->(XmlNode->new('owner', 'content' => $listOwner)); } $root->{'ADDCHILD'}->(makePasswordNode(Mailman::getListPassword($mlistName)), 'encrypted'); my %listMembers = Mailman::getListMembers($mlistName); for my $memberEmail (keys %listMembers) { my $member = XmlNode->new('recipient', 'content' => $memberEmail); if ($listMembers{$memberEmail} ne "") { $member->{'ATTRIBUTE'}->('fullname', $listMembers{$memberEmail}); } $root->{'ADDCHILD'}->($member); $member->ReleaseCode(); } my $archiveDir = AgentConfig::get("MAILMAN_VAR_D") . "/archives/private/$mlistName.mbox"; my $archive = "$mlistName.mbox"; if (-f "$archiveDir/$archive") { my $cid = $self->addTar("$mlistName.mlist", 'directory' => $archiveDir, 'include' => [$archive], 'follow_symlinks' => 1); $root->{'ATTRIBUTE'}->('cid', $cid) if ($cid); } return $root; } sub makeCertificateNode { my ($self, $certId) = @_; my($sql,$root,%cert,$item); $sql = "SELECT * FROM certificates WHERE id=$certId"; unless($self->{dbh}->execute_rownum($sql)){ &printToError("Error: makeCertificateNode: certificate ID '$certId' is not found"); return undef; } %cert= %{$self->{dbh}->fetchhash()}; $self->{dbh}->finish(); $root = XmlNode->new('certificate'); if (PleskVersion::atLeast(6, 0, 0)) { addUrlDecodedTextNode($root, 'certificate-data', $cert{'cert'}); addUrlDecodedTextNode($root, 'signing-request', $cert{'csr'}); addUrlDecodedTextNode($root, 'ca-certificate', $cert{'ca_cert'}); } elsif (PleskVersion::atLeast(5, 0, 0)) { addUrlDecodedTextNode($root, 'certificate-data', $cert{'pub_key'}); } addUrlDecodedTextNode($root, 'private-key', $cert{'pvt_key'}); if (PleskVersion::atLeast(6, 0, 0)) { $root->{'ATTRIBUTE'}->('name', $cert{'name'}); } else { # certificate names were not used in Plesk prior to 6.0 $root->{'ATTRIBUTE'}->('name', $certId); } return $root; } sub makeDatabaseNode { my ($self, $dbId) = @_; my ($ptrHash, $ptrRow, $item, $charset, $dbServerHost, $dbServerPort); my $sql = "SELECT name, type FROM data_bases WHERE id=$dbId"; unless ($self->{dbh}->execute_rownum($sql)) { $self->{dbh}->finish(); return; } my ($dbName, $dbType) = @{$self->{dbh}->fetchrow()}; $self->{dbh}->finish(); if ($dbName =~ /^-.*/) { Logging::error("Panel does not allow to back up databases which name starts with the dash (-) symbol. Please rename database " . $dbName . " and run tha backup task again"); return; } if ($dbType eq "postgres" or $dbType eq "postgresql") { $dbType = "postgresql"; } elsif ($dbType ne "mysql") { printToError("Unknown database type: $dbType"); return; } my $root = XmlNode->new('database', 'attributes' => {'name' => $dbName, 'type' => $dbType}); # Remote databases hosting was introduced in 8.0.0 if (PleskVersion::atLeast(8, 0, 0)) { my $sql = "SELECT host,port,ds.type FROM DatabaseServers as ds, data_bases as db WHERE " . "ds.id = db.db_server_id AND db.id = $dbId"; $self->{dbh}->execute_rownum($sql); $ptrRow = $self->{dbh}->fetchrow(); $dbServerHost = ($ptrRow->[0] ne 'localhost') ? $ptrRow->[0] : 'localhost'; $dbServerPort = $ptrRow->[1]; my $dbServerNode = XmlNode->new('db-server'); $dbServerNode->{'ATTRIBUTE'}->('type', $ptrRow->[2]); $dbServerNode->{'ADDCHILD'}->(XmlNode->new('host', 'content' => "$ptrRow->[0]")); $dbServerNode->{'ADDCHILD'}->(XmlNode->new('port', 'content' => "$ptrRow->[1]")); $self->{dbh}->finish(); $root->{'ADDCHILD'}->($dbServerNode); } return $root if $self->{shallow_dump}; printToLog("Database $dbName"); if (PleskVersion::atLeast(7, 5, 0)) { $sql = "SELECT login, password, type FROM db_users, accounts WHERE " . "db_users.db_id = $dbId AND db_users.account_id = accounts.id"; $self->{dbh}->execute_rownum($sql); while ($ptrHash = $self->{dbh}->fetchhash()) { $ptrHash->{'password'} ||= ''; # NULL -> '' my $dbUserRoot = XmlNode->new('dbuser', 'attributes' => {'name' => $ptrHash->{'login'}}); $item = makePasswordNode($ptrHash->{'password'}, normalizePasswordType($ptrHash->{'type'})); $dbUserRoot->{'ADDCHILD'}->($item); $root->{'ADDCHILD'}->($dbUserRoot); } } else { $self->{dbh}->execute_rownum("SELECT login, passwd FROM db_users WHERE db_id = $dbId"); while ($ptrHash = $self->{dbh}->fetchhash()) { my $dbPasswdType; # In Plesk 7.1.5 DB password type wasn't described in the DB. We # can distinguish the type only using length of password. if (length($ptrHash->{'passwd'}) > 14) { $dbPasswdType = 'encrypted'; } else { $dbPasswdType = 'plain'; } if (!defined $ptrHash->{'passwd'}) { $ptrHash->{'passwd'} = ''; } my $dbUserRoot = XmlNode->new('dbuser', 'attributes' => {'name' => $ptrHash->{'login'}}); $item = makePasswordNode($ptrHash->{'passwd'}, $dbPasswdType); $dbUserRoot->{'ADDCHILD'}->($item); $root->{'ADDCHILD'}->($dbUserRoot); } } $self->{dbh}->finish(); my ($dbUser, $dbPasswd, $plesk_7); # remote database hosting regularizes the database connectivity even for local hosts. # thanks goes to xman. if (PleskVersion::atLeast(8, 0, 0)) { my $sql = "SELECT admin_login, admin_password FROM DatabaseServers as ds, data_bases as db " . "WHERE ds.id = db.db_server_id AND db.id = $dbId"; $self->{dbh}->execute_rownum($sql); ($dbUser, $dbPasswd) = @{$self->{dbh}->fetchrow()}; $self->{dbh}->finish(); if ($dbType eq "mysql" and $dbServerHost eq 'localhost') { $dbPasswd = AgentConfig::get('password'); } if ($dbType eq "postgresql") { $root->{'ATTRIBUTE'}->('version', getPostgresqlVersion()); } } else { if ($dbType eq "mysql") { $dbUser = 'admin'; $dbPasswd = AgentConfig::get('password'); } else { $sql = "SELECT param, val FROM misc WHERE param RLIKE '^postgresql_admin_'"; if ($self->{dbh}->execute_rownum($sql)) { while ($ptrRow=$self->{dbh}->fetchrow()) { my ($name, $value) = @{$ptrRow}; $dbUser = $value if $name =~ /login$/; $dbPasswd = $value if $name =~ /passwd$/; } } $self->{dbh}->finish(); $plesk_7 = 1; } } my $cid = $self->addDb("$dbName.$dbType", "name" => $dbName, "type" => $dbType, "user" => $dbUser, "password" => $dbPasswd, "host" => $dbServerHost, "port" => $dbServerPort, "plesk_7" => $plesk_7); $root->{'ATTRIBUTE'}->('cid',$cid) if $cid; if ($dbType eq "postgresql") { my $psql = AgentConfig::psqlBin(); #[Bug 119082] #$charset = `PGUSER=$dbUser PGPASSWORD='$dbPasswd' $psql -l template1 | grep '^[ \t]*$dbName ' | awk '{print \$5}'`; my $wrapPgsql = 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 '') { $root->{'ATTRIBUTE'}->('charset', $charset); } } $wrapPgsql->{'FINISH'}->(); } } else{ printToLog( "Cannot connect to postgresql $dbServerHost:$dbServerPort (database '$dbName')" ) } } if ($dbType eq "mysql") { $root->{'ATTRIBUTE'}->('version', Db::MysqlUtils::getVersion()); my $wrapMysql = 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 = $ptrRow->[1] if $ptrRow; $root->{'ATTRIBUTE'}->('charset', $charset) if $charset; $wrapMysql->{'FINISH'}->(); } } } return $root; } # # makeMailUserNode # # argumets: # $mailId - mail ID # $passwd - password # $typePasswd - type of password # $domainName - name of domain # # return: # $root = XML node 'mailuser' # sub makeMailUserNode { my ($self, $mailId, $passwd, $typePasswd, $domainName, $domainAsciiName) = @_; my($sql,%mail,$item,$ptrRow,$ptrHash,$dir,$id, $mbox_quota); $sql = "SELECT * FROM mail WHERE id = $mailId"; unless($self->{dbh}->execute_rownum($sql)){ printToError("Error: makeMailUserNode: mail ID '$mailId' is not found"); return undef; } %mail = %{$self->{dbh}->fetchhash()}; $self->{dbh}->finish(); my $mailName = $mail{'mail_name'}; my $root = XmlNode->new('mailuser', 'attributes' => {'id' => $mailId, 'name' => $mailName}); if (defined($passwd) && $passwd) { if ($passwd =~ /NULL/) { $item = makePasswordNode('', 'plain'); } else { $item = makePasswordNode($passwd,$typePasswd); } $root->{'ADDCHILD'}->($item); } # bug 78844 if (defined $mail{'perm_id'}) { $sql = "SELECT permission, value FROM Permissions WHERE id = $mail{'perm_id'}"; unless($self->{dbh}->execute_rownum($sql)) { printToError("Error: makeMailUserNode: unable to get permissions for mail ID '$mailId'"); } while ($ptrRow = $self->{dbh}->fetchrow()) { my ($name, $value) = @{$ptrRow}; next unless exists $mailUserPermissions{$name}; addMailuserPermissionNode($root, $mailUserPermissions{$name}, $value); } $self->{dbh}->finish(); } else { addMailuserPermissionNode($root, 'cp-access', defined($mail{'cp_access'}) ? $mail{'cp_access'} : 'false'); } # multiple login $self->addMailUserMultipleLoginPermission($root, $mailId); if($mail{'mbox_quota'}){ $mbox_quota = $mail{'mbox_quota'}; if (!PleskVersion::atLeast(6, 0, 0) and $mbox_quota ne "-1") { $mbox_quota = $mbox_quota * 1024; } $root->{'ATTRIBUTE'}->('mailbox-quota',$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) { $item = XmlNode->new('mailbox', 'attributes' => {'type' => 'mdir'}); $root->{'ADDCHILD'}->($item); $item->{'ATTRIBUTE'}->('enabled', $mail{'postbox'} =~ /true/ ? 'true' : 'false'); $dir=AgentConfig::get('QMAIL_MAILNAMES_D')."/$domainAsciiName/$mailName/Maildir"; my $cid = $self->addTar("$mailName\@$domainAsciiName.mdir", 'directory' => $dir); $item->{'ATTRIBUTE'}->('cid',$cid) if $cid; } # # aliases # if (PleskVersion::atLeast(5, 0, 0)) { $sql="SELECT alias FROM mail_aliases WHERE mn_id=$mailId"; if($self->{dbh}->execute_rownum($sql)){ while ($ptrRow= $self->{dbh}->fetchrow()){ $item=XmlNode->new('alias', 'content' => $ptrRow->[0]); $root->{'ADDCHILD'}->($item); } } $self->{dbh}->finish(); } # # end aliases # # # redirect # if ($mail{'redir_addr'}) { $item = XmlNode->new('redirect', 'content' => $mail{'redir_addr'}, 'attributes' => {'enabled' => $mail{'redirect'}}); # $item->{'ATTRIBUTE'}->('enabled', $mail{'redirect'}); $root->{'ADDCHILD'}->($item); } # # end redirect # # # mail group # $root->{'ATTRIBUTE'}->('mailgroup-enabled', $mail{'mail_group'}); $sql="SELECT address FROM mail_redir WHERE mn_id=$mailId"; if($self->{dbh}->execute_rownum($sql)){ while ($ptrRow= $self->{dbh}->fetchrow()){ if($ptrRow->[0] ne $mailName . "@" . $domainName) { $item=XmlNode->new('mailgroup-member', 'content' => $ptrRow->[0]); $root->{'ADDCHILD'}->($item); } } } $self->{dbh}->finish(); # # end mail group # # # autoresponders # my $autorespondersNode = XmlNode->new('autoresponders', 'attributes' => {'enabled' => $mail{'autoresponder'}}); $dir=AgentConfig::get('QMAIL_MAILNAMES_D')."/$domainAsciiName/$mailName/\@attachments"; my $cid = $self->addTar("$mailName\@$domainAsciiName.attach", "directory" => $dir); $autorespondersNode->{'ATTRIBUTE'}->('cid_attaches',$cid) if $cid; 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 %attaches; my @autoresponders; foreach $id (@autos) { my $item = makeAutoresponderNode($self, $id, $mailName . "@" . $domainName); push @autoresponders, $item; } my $util = AgentConfig::get("PRODUCT_ROOT_D") . "/admin/sbin/"; if (PleskVersion::atLeast(6, 5, 0)) { $util .= "mailmng --list-attachments --domain-name=$domainName --mailname=$mailName"; } else { $util .= "list_files -1A '" . AgentConfig::get("QMAIL_MAILNAMES_D") . "/$domainAsciiName/$mailName/\@attachments/'"; } my @filelist; open(LIST, "$util |"); while () { chomp; my ($file) = split /\t/; push @filelist, $file; } #clear list if utility failed unless (close(LIST)) { @filelist = (); } # Old Plesk utilities printed return code on stdout (#66905) unless (PleskVersion::atLeast(7, 1, 0)) { if ($#filelist != -1 && $filelist[$#filelist] =~ /^\d$/) { $#filelist -= 1; } } unless($self->{configuration_dump}) { foreach my $file (@filelist) { $autorespondersNode->{'ADDCHILD'}->(XmlNode->new('attach', 'attributes' => {'file' => $file})); } } foreach my $autoresponder (@autoresponders) { $autorespondersNode->{'ADDCHILD'}->($autoresponder); } $root->{'ADDCHILD'}->($autorespondersNode); # # end autoresponders # # # Addressbook # if (PleskVersion::atLeast(6, 0, 0)) { $self->makeAddressbookNode($root, $mailName . '@' . $domainAsciiName); } # # Spamassassin # if (PleskVersion::atLeast(7, 0, 0)) { if (PleskVersion::atLeast(8, 1, 0)) { $item = $self->makeSpamassassinNode81($root,$mail{'mail_name'}.'@'.$domainAsciiName, $mail{'spamfilter'}); } else { $item = $self->makeSpamassassinNode70($root,$mail{'mail_name'}.'@'.$domainAsciiName); } if($item) { $dir = AgentConfig::get('QMAIL_MAILNAMES_D')."/$domainAsciiName/$mailName/.spamassassin"; my $cid = $self->addTar("$mailName\@$domainAsciiName.sa", "directory" => $dir); $item->{'ATTRIBUTE'}->('cid', $cid) if $cid; } } # # End Spamassassin # if (PleskVersion::atLeast(8, 1, 1)) { if ($mail{'virusfilter'} ne 'none') { my %states_map = ('incoming' => 'in', 'outgoing' => 'out', 'any' => 'inout'); if( defined( $states_map{$mail{'virusfilter'}} ) ) { my $item = XmlNode->new('virusfilter'); $item->{'ATTRIBUTE'}->('state', $states_map{$mail{'virusfilter'}} ); $root->{'ADDCHILD'}->($item); } } } # FIXME: why so crude check here? elsif (-e "/etc/drweb/users.conf") { $item = $self->makeDrwebNode($root, $mailName.'@'.$domainName); } if (PleskVersion::atLeast(6, 0, 0)) { $self->getMaxButtonLength($root, "mn_param", "mn_id=$mailId"); $self->getSkin($root, "mn_param", "mn_id=$mailId"); $self->getLockScreen($root, "mn_param", "mn_id=$mailId"); } $root->{'ADDCHILD'}->($_) foreach $self->getCustomButtonsByOwner('mailuser', $mailId); return $root; } # # makeAutoresponderNode # # arguments: # $id - ID of autoreponder # # return: # $root - XML node # 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)) { &printToError("Error: makeAutoresponderNode: autoresponder # $autoId is not found"); return undef; } %auto=%{$self->{dbh}->fetchhash()}; $self->{dbh}->finish(); my $root = XmlNode->new('autoresponder'); $value = $self->{base64}->{'ENCODE'}->($auto{'text'}); $item=XmlNode->new('text','content' => $value); if (exists $auto{'charset'} && $auto{'charset'} ne '') { $item->{'ATTRIBUTE'}->('charset', $auto{'charset'}); } $root->{'ADDCHILD'}->($item); if (exists $auto{'content_type'} && $auto{'content_type'}) { $root->{'ATTRIBUTE'}->('content-type', $auto{'content_type'}); } $name = $auto{'resp_name'}; $root->{'ATTRIBUTE'}->('name',$name); if ($auto{'resp_on'}=~/false/){ $root->{'ATTRIBUTE'}->('status','off'); } unless ($auto{'key_where'}=~/no/){ $value=$auto{'key_where'}.':'.$auto{'keystr'}; $root->{'ATTRIBUTE'}->('require',$value); } if($auto{'subject'}){ $value = $self->{base64}->{'ENCODE'}->($auto{'subject'}); chomp $value; $root->{'ATTRIBUTE'}->('subject',$value); } if ($auto{'reply_to'} and $auto{'reply_to'} ne $mailName) { $root->{'ATTRIBUTE'}->('replyto',$auto{'reply_to'}); } # # 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) { $root->{'ATTRIBUTE'}->('redirect',join(',',@list)); } } $self->{dbh}->finish(); # # end forward # $root->{'ADDCHILD'}->(XmlNode->new('autoresponder-limit', 'content' => $auto{'ans_freq'}, 'attributes' => {'name' => 'ans-freq'})); $root->{'ADDCHILD'}->(XmlNode->new('autoresponder-limit', 'content' => $auto{'mem_limit'}, 'attributes' => {'name' => 'ans-count'})); if (!$self->{configuration_dump}) { $sql = "SELECT filename FROM resp_attach WHERE rn_id=$autoId"; if ($self->{dbh}->execute_rownum($sql)) { while ($ptrRow = $self->{dbh}->fetchrow()) { $root->{'ADDCHILD'}->(XmlNode->new('attach', 'attributes' => {'file' => $ptrRow->[0]})); } } $self->{dbh}->finish(); } return $root; } sub makeAddressbookNode { my ($self, $parent, $mailName) = @_; my $sql = "SELECT Db FROM mysql.db WHERE db='horde'"; return unless $self->{dbh}->execute_rownum($sql); $self->{dbh}->finish(); $sql = "SHOW TABLES FROM horde LIKE 'turba_objects'"; return unless $self->{dbh}->execute_rownum($sql); $self->{dbh}->finish(); my $node = XmlNode->new('addressbook'); my %objectFields = ('id'=>'id', 'name'=>'name', 'alias'=>'alias', 'email'=>'email', 'title'=>'title', 'company'=>'company', 'home-phone'=>'homephone', 'work-phone'=>'workphone', 'mobile-phone'=>'cellphone', 'fax'=>'fax', 'home-address'=>'homeaddress', 'work-address'=>'workaddress', 'notes'=>'notes'); my $ptrHash; $sql = "SELECT * FROM horde.turba_objects WHERE owner_id = '$mailName'"; $self->{dbh}->execute_rownum($sql); while ($ptrHash = $self->{dbh}->fetchhash()) { if ($ptrHash->{'object_type'} eq 'Group') { my $group = XmlNode->new('addressbook-group', 'attributes' => {'id' => $ptrHash->{'object_id'}}); my $members = $ptrHash->{'object_members'}; while ($members =~ /"(.*?)"/g) { my $member = $1; chomp $member; $group->{'ADDCHILD'}->(XmlNode->new('addressbook-member', 'attributes' => {'id' => $member})); } $node->{'ADDCHILD'}->($group); } else { my $user = XmlNode->new('addressbook-contact'); my ($field, $attr); while (($field, $attr) = each %objectFields) { if (defined $ptrHash->{'object_' . $attr}) { # Here 'encoded' attribute means there is no meaning to # convert data to UTF as it was already converted manually my $value = $ptrHash->{'object_' . $attr}; $value = $self->{base64}->{'ENCODE'}->($value) if $attr ne 'id'; $user->{'ATTRIBUTE'}->($field, $value); } } $node->{'ADDCHILD'}->($user); } } $self->{dbh}->finish(); $parent->{'ADDCHILD'}->($node); } sub makePhostingNode { my ($self, $ptrDomain, $ptrSiteApplications) = @_; my @SiteApplications = @{$ptrSiteApplications}; unless(ref($ptrDomain)=~/HASH/){ &printToError("Error: makePhostNode: bag arguments"); return undef; } my $root=XmlNode->new('phosting'); my($domainName,$domainRoot,$path,$sql,%hosting,$domainId, $xmlName,$fieldName,$id,$item,$ptrRow,$ptrHash); $domainName = $ptrDomain->{'name'}; $domainId = $ptrDomain->{'id'}; # shared http/https content if (PleskVersion::atLeast(7, 5, 3)) { my $sql = "SELECT same_ssl FROM hosting WHERE dom_id=$domainId AND same_ssl='true'"; if ($self->{dbh}->execute_rownum($sql)) { $root->{'ATTRIBUTE'}->('shared-content', 'true'); } $self->{dbh}->finish(); } #----------------------------------------------------------------- # Site applications content should not be included into dump # together with other website content. #----------------------------------------------------------------- my @exclude_httpdocs_files; my @exclude_httpsdocs_files; my @exclude_cgi_bin_files; foreach my $sapp (@SiteApplications) { next if !$sapp->isDomainSiteapp(); 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 $domainRoot = AgentConfig::get("HTTPD_VHOSTS_D") . "/$domainName"; if (-d $domainRoot) { my $cid_docroot = $self->addTar("$domainName.httpdocs", "directory" => "$domainRoot/httpdocs", "exclude" => \@exclude_httpdocs_files); $root->{'ATTRIBUTE'}->('cid_docroot', $cid_docroot) if $cid_docroot; my $cid_docroot_ssl = $self->addTar("$domainName.httpsdocs", "directory" => "$domainRoot/httpsdocs", "exclude" => \@exclude_httpsdocs_files); $root->{'ATTRIBUTE'}->('cid_docroot_ssl', $cid_docroot_ssl) if $cid_docroot_ssl; my $cid_cgi = $self->addTar("$domainName.cgi-bin", "directory" => "$domainRoot/cgi-bin", "exclude" => \@exclude_cgi_bin_files); $root->{'ATTRIBUTE'}->('cid_cgi', $cid_cgi) if $cid_cgi; my $webstatRoot = (PleskVersion::atLeast(5,0,0)) ? $domainRoot."/statistics/webstat" : $domainRoot."/httpdocs/webstat"; my $cid_webstat = $self->addTar("$domainName.webstat", "directory" => "$webstatRoot"); $root->{'ATTRIBUTE'}->('cid_webstat', $cid_webstat) if $cid_webstat; my $cid_webstat_ssl = $self->addTar("$domainName.webstat-ssl", "directory" => "$domainRoot/statistics/webstat-ssl"); $root->{'ATTRIBUTE'}->('cid_webstat_ssl', $cid_webstat_ssl) if $cid_webstat_ssl; my $cid_ftpstat = $self->addTar("$domainName.ftpstat", "directory" => "$domainRoot/statistics/ftpstat"); $root->{'ATTRIBUTE'}->('cid_ftpstat', $cid_ftpstat) if $cid_ftpstat; my $cid_error_docs = $self->addTar("$domainName.error-docs", "directory" => "$domainRoot/error_docs"); $root->{'ATTRIBUTE'}->('cid_error_docs', $cid_error_docs) if $cid_error_docs; my $cid_private = $self->addTar("$domainName.private", "directory" => "$domainRoot/private"); $root->{'ATTRIBUTE'}->('cid_private', $cid_private) if $cid_private; my $cid_logs = $self->addTar("$domainName.logs", "directory" => "$domainRoot/statistics/logs") unless $self->{skip_logs}; $root->setAttribute('cid_logs', $cid_logs) if $cid_logs; my $cid_anon_ftpstat = $self->addTar("$domainName.anon-ftpstat", "directory" => "$domainRoot/statistics/anon_ftpstat"); $root->setAttribute('cid_anon_ftpstat', $cid_anon_ftpstat) if $cid_anon_ftpstat; } $sql = "SELECT * FROM hosting WHERE dom_id=$domainId"; if($self->{dbh}->execute_rownum($sql)) { %hosting = %{$self->{dbh}->fetchhash()}; } $self->{dbh}->finish(); while (($xmlName,$fieldName) = each(%hostingAttribute)) { # MySQL allows 'true', 'false' and '' in enums if (defined($hosting{$fieldName}) and $hosting{$fieldName} eq "true") { $root->{'ATTRIBUTE'}->($xmlName, 'true'); } } if (defined($hosting{'webstat'}) and $hosting{'webstat'}) { $root->{'ATTRIBUTE'}->('webstat', $hosting{'webstat'}); } $sql = "SELECT val FROM dom_param WHERE dom_id='$domainId' " . "AND param='apacheErrorDocs'"; if ($self->{dbh}->execute_rownum($sql)) { if ($ptrRow = $self->{dbh}->fetchrow()) { my $errdocs = (@{$ptrRow})[0]; if (defined($errdocs) and $errdocs eq 'true') { $root->{'ATTRIBUTE'}->('errdocs', 'true'); } } } $self->{dbh}->finish(); # # sysuser # Logging::info("Dumping system user"); if (PleskVersion::atLeast(5, 0, 0)) { if($id = $hosting{'sys_user_id'}){ $item= $self->makePleskSysUserNode($id); if(ref($item)=~/XmlNode/){ $root->{'ADDCHILD'}->($item); } } } else { $item = $self->makeSyntheticSysUserNode($hosting{'login'}, $hosting{'passwd'}, 'plain'); if(ref($item) =~ /XmlNode/) { $root->{'ADDCHILD'}->($item); } } # # end sysuser # # # scripting # $item = XmlNode->new('scripting'); while(($xmlName,$fieldName)=each(%hostingScripting)){ next if $fieldName=~/asp_dot_net/; if(defined($hosting{$fieldName}) and $hosting{$fieldName}=~/true/){ $item->{'ATTRIBUTE'}->($xmlName,'true'); } } $root->{'ADDCHILD'}->($item); # # end scripting # #----------------------------------------------------------------- # Dump of installed site applications #----------------------------------------------------------------- foreach my $sapp (@SiteApplications) { if (!$sapp->isDomainSiteapp()) { next; } $root->{'ADDCHILD'}->($self->dumpSiteApplication($sapp, AgentConfig::get("HTTPD_VHOSTS_D") . "/$domainName")); } # # frontpage user # if (exists $hosting{'fp_adm'} and $hosting{'fp_adm'}) { $item = XmlNode->new('fpuser', 'attributes' => {'name' => $hosting{'fp_adm'}}); if($hosting{'fp_pass'}){ my $passNode = &makePasswordNode($hosting{'fp_pass'},'plain'); $item->{'ADDCHILD'}->($passNode); } $root->{'ADDCHILD'}->($item); } elsif (exists $hosting{'fp'} and $hosting{'fp'} eq 'true' and !$hosting{'fp_adm'} and !$hosting{'fp_pass'}) { # Workaround for older Plesks: during upgrade 1.3 -> 2.0 (or something) # frontpage administrator records were lost $item = XmlNode->new('fpuser'); if (PleskVersion::atLeast(5, 0, 0)) { my %sysuser = $self->getSysUserInfo($hosting{'sys_user_id'}); $item->{'ATTRIBUTE'}->('name', lc($sysuser{'login'})); if (PleskVersion::atLeast(6, 0, 0)) { $item->{'ADDCHILD'}->($self->makeAccountPasswordNode($sysuser{'account_id'})); } else { $item->{'ADDCHILD'}->(makePasswordNode($sysuser{'passwd'}, 'plain')); } } else { $item->{'ATTRIBUTE'}->('name', $hosting{'login'}); $item->{'ADDCHILD'}->(makePasswordNode($hosting{'passwd'}, 'plain')); } $root->{'ADDCHILD'}->($item); } # # end frontpage user # $self->makeDomainLogrotationNode($root, $domainId); $self->addAnonFtp($root,$domainId,$domainName); # # protected dirs # if (PleskVersion::atLeast(8, 0, 0)) { $sql = "SELECT id,path,realm,non_ssl,`ssl`,cgi_bin FROM protected_dirs WHERE dom_id=$domainId ORDER BY id"; } elsif (PleskVersion::atLeast(6, 0, 0)) { $sql = "SELECT id,path,realm,non_ssl,`ssl` FROM protected_dirs WHERE dom_id=$domainId ORDER BY id"; } else { $sql = "SELECT id,path,realm FROM protected_dirs WHERE dom_id=$domainId ORDER BY id"; } if($self->{dbh}->execute_rownum($sql)){ my (@dirs); while ($ptrRow = $self->{dbh}->fetchrow()){ push @dirs,[@{$ptrRow}]; } $self->{dbh}->finish(); foreach $ptrRow (@dirs){ unless (defined($hosting{'ssl'}) and $hosting{'ssl'}=~/true/){ $ptrRow->[4] = 'false'; # bug 97159 } $item = $self->makeProtDirNode(@{$ptrRow}); if(ref($item)=~/XmlNode/){ $root->{'ADDCHILD'}->($item); } } } $self->{dbh}->finish(); # # end protected dirs # # # web users # $sql = "SELECT * FROM web_users WHERE dom_id=$domainId ORDER BY id"; if($self->{dbh}->execute_rownum($sql)){ my (@webs); while ($ptrHash = $self->{dbh}->fetchhash()){ push @webs,{%{$ptrHash}}; } $self->{dbh}->finish(); foreach $ptrHash (@webs){ $item = $self->makeWebUserNode($ptrHash,$domainName); if(ref($item)=~/XmlNode/){ $root->{'ADDCHILD'}->($item); } } } else { $self->{dbh}->finish(); } # # end web users # # # subdomains # if (PleskVersion::atLeast(7, 0, 0)) { $sql = "SELECT * FROM subdomains WHERE dom_id=$domainId ORDER BY id"; my (@subdoms); if($self->{dbh}->execute_rownum($sql)){ while ($ptrHash = $self->{dbh}->fetchhash()){ push @subdoms,{%{$ptrHash}}; } } $self->{dbh}->finish(); foreach $ptrHash (@subdoms){ $item = $self->dumpSubDomain($ptrHash, $domainName, \@SiteApplications); if(ref($item)=~/XmlNode/){ $root->addChild($item); } } } # # end subdomains # # # configuration files (conf/vhost[_ssl].conf) # $domainRoot = AgentConfig::get("HTTPD_VHOSTS_D").'/'.$domainName; my $confDir = $domainRoot . '/conf/'; my $vhostConf = 'vhost.conf'; my $vhostSslConf = 'vhost_ssl.conf'; my @confFiles; push @confFiles, $vhostConf if (-f $confDir . $vhostConf); push @confFiles, $vhostSslConf if (-f $confDir . $vhostSslConf); if ($#confFiles != -1) { my $cid_conf = $self->addTar("$domainName.conf", "directory" => $confDir, "include" => \@confFiles); $root->{'ATTRIBUTE'}->('cid_conf', $cid_conf) if $cid_conf; } # # end configuration files (conf/vhost[_ssl].conf) # # # Webalizer configuration # if (PleskVersion::atLeast(7, 5, 3)) { my $node = XmlNode->new("webalizer"); my $sql = "SELECT referrer FROM webalizer_hidden_referrer " . " WHERE dom_id=$domainId"; if ($self->{dbh}->execute_rownum($sql)) { while ($ptrRow = $self->{dbh}->fetchrow()) { if ($ptrRow->[0] eq "Direct Request") { $node->{'ATTRIBUTE'}->('hide-direct-referrer', 'true'); } else { $node->{'ADDCHILD'}->(XmlNode->new("webalizer-hidden-referrer", 'content' => $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 ($ptrRow = $self->{dbh}->fetchrow()) { $node->{'ADDCHILD'}->(XmlNode->new('webalizer-group-referrer', 'content' => $ptrRow->[0], 'attributes' => { 'group-name' => $ptrRow->[1] })); } } $self->{dbh}->finish(); $root->{'ADDCHILD'}->($node); } # # SiteBuilder connfiguration # $self->makeDomainSiteBuilderNode($root, $domainId) if PleskVersion::atLeast(8, 3, 0); # # Perfomance # if ((defined($hosting{'max_connection'}) and $hosting{'max_connection'}) or (defined($hosting{'traffic_bandwidth'}) and $hosting{'traffic_bandwidth'})) { my $perfomance = XmlNode->new('perfomance'); $perfomance->addChild(XmlNode->new('max-connections', 'content' => $hosting{'max_connection'})); $perfomance->addChild(XmlNode->new('traffic-bandwidth', 'content' => $hosting{'traffic_bandwidth'})); $root->addChild($perfomance); } # Cron return $root; } sub makeDomainSiteBuilderNode () { my ($self, $root, $domainId) = @_; my $sql = "SELECT sb_site_id, sb_siteowner_id, sb_siteowner_login FROM SBSites WHERE virtualHost_id = '$domainId'"; if ($self->{dbh}->execute_rownum($sql)) { my $sbNode = XmlNode->new('sb-domain'); while (my $ptrHash = $self->{dbh}->fetchhash()) { $sbNode->addChild(XmlNode->new('sb-site-id', 'content' => $ptrHash->{'sb_site_id'})); $sbNode->addChild(XmlNode->new('sb-siteowner-id', 'content' => $ptrHash->{'sb_siteowner_id'})); $sbNode->addChild(XmlNode->new('sb-siteowner-login', 'content' => $ptrHash->{'sb_siteowner_login'})); } $root->addChild($sbNode); } $self->{dbh}->finish(); } #----------------------------------------------------------------- # Returns XmlNode of sapp-installed type or false #----------------------------------------------------------------- sub dumpSiteApplication( $ $ ) { my ($self, $sapp, $vhost_path) = @_; my $sapp_installed = XmlNode->new('sapp-installed'); #----------------------------------------------------------------- # sapp-spec #----------------------------------------------------------------- my $sapp_spec = XmlNode->new('sapp-spec'); $sapp_spec->{'ADDCHILD'}->(XmlNode->new('sapp-name', 'content' => $sapp->getName())); if ($sapp->getVersion()) { $sapp_spec->{'ADDCHILD'}->(XmlNode->new('sapp-version', 'content' => $sapp->getVersion())); } if ($sapp->getRelease()) { $sapp_spec->{'ADDCHILD'}->(XmlNode->new('sapp-release', 'content' => $sapp->getRelease())); } if ($sapp->getDescription()) { my $desc = $self->{base64}->{'ENCODE'}->($sapp->getDescription()); $sapp_spec->{'ADDCHILD'}->(XmlNode->new('sapp-description', 'attributes' => {'encoding' => 'base64'}, 'content' => $desc)); } if ($sapp->isCommercial()) { $sapp_spec->{'ADDCHILD'}->(XmlNode->new('sapp-commercial')); } if ($sapp->isIntegrated()) { $sapp_spec->{'ADDCHILD'}->(XmlNode->new('sapp-integrated')); } $sapp_installed->{'ADDCHILD'}->($sapp_spec); #----------------------------------------------------------------- #sapp-param* #----------------------------------------------------------------- while (my ($param_name, $param_value) = each %{$sapp->getParams()}) { my $name = $self->{base64}->{'ENCODE'}->($param_name); my $value = $self->{base64}->{'ENCODE'}->($param_value); $sapp_installed->{'ADDCHILD'}->(XmlNode->new('sapp-param', 'children' => [XmlNode->new('sapp-param-name', 'attributes' => {'encoding' => 'base64'}, 'content' => $name), XmlNode->new('sapp-param-value', 'attributes' => {'encoding' => 'base64'}, 'content' => $value)])); } #----------------------------------------------------------------- # Linked resources #----------------------------------------------------------------- # Databases foreach my $row ($sapp->getDatabases()) { my $database = $self->makeDatabaseNode($row->{'id'}); if (ref($database) =~ /XmlNode/) { $database->{'ATTRIBUTE'}->('sapp-param', $row->{'param'}) if defined $row->{'param'}; $sapp_installed->{'ADDCHILD'}->($database); } } # Custom buttons foreach my $row ($sapp->getCustomButtons()) { my $cb = $self->getCustomButtonById71($row->{'id'}); if (ref($cb) =~ /XmlNode/) { $sapp_installed->{'ADDCHILD'}->($cb); push @{$self->{skip_custom_buttons}}, $row->{'id'}; } } #----------------------------------------------------------------- # Site application content #----------------------------------------------------------------- my $prefix = $sapp->getInstallPrefix(); # sapp-scripts { my $vault_dir = "$vhost_path/vault_scripts/$prefix"; my $dump_id = generateDumpId(); my $cid = $self->addTar("sapp-scripts." . $dump_id, "directory" => $vault_dir); $sapp_installed->{'ADDCHILD'}->(XmlNode->new('sapp-scripts', 'content' => $cid)) if $cid; $vault_dir = "$vhost_path/vault_https_scripts/$prefix"; $cid = $self->addTar("sapp-https-scripts." . $dump_id, "directory" => $vault_dir); $sapp_installed->{'ADDCHILD'}->(XmlNode->new('sapp-https-scripts', 'content' => $cid)) if $cid; } # sapp-installdir my $sapp_installdir = XmlNode->new('sapp-installdir', 'children' => [XmlNode->new('sapp-prefix', 'content' => $prefix)]); if ($sapp->isSsl()) { $sapp_installdir->{'ADDCHILD'}->(XmlNode->new('sapp-ssl')); } $sapp_installed->{'ADDCHILD'}->($sapp_installdir); # cgi-bin { my $cgibin_dir = "$vhost_path/cgi-bin/" . $prefix; my $cid = $self->addTar("sapp-cgi-bin." . generateDumpId(), "directory" => $cgibin_dir, "include" => $sapp->{cgi_bin}, "no_recursion" => 1); $sapp_installed->{'ADDCHILD'}->(XmlNode->new('sapp-cgi-bin', 'content' => $cid)) if $cid; } # htdocs my $htdocs_dir = $vhost_path . ($sapp->isSsl() ? "/httpsdocs/" : "/httpdocs/") . $prefix; # add '.htpasswd' files to dump, bug 93109 my ($file, %files); @files{@{$sapp->{htdocs}}} = (); foreach $file (@{$sapp->{htdocs}}) { if ($file =~ /\.htaccess$/) { my $_file = $file; $_file =~ s/\.htaccess$/.htpasswd/; if (!exists $files{$_file} && -e "$htdocs_dir/$_file") { push @{$sapp->{htdocs}}, $_file; } } } my $cid = $self->addTar("sapp-htdocs." . generateDumpId(), "directory" => $htdocs_dir, "include" => $sapp->{htdocs}, "no-recursion" => 1); $sapp_installed->{'ADDCHILD'}->(XmlNode->new('sapp-htdocs', 'content' => $cid)) if $cid; if (PleskVersion::atLeast(8, 3, 0)) { $sapp_installed->addChild(XmlNode->new('sapp-installed-license-type', 'content' => $sapp->getAPSClientItemLicenseType())); } return $sapp_installed; } sub makeDomainLogrotationNode { my ($self, $parent, $domainId) = @_; if (PleskVersion::atLeast(5, 0, 0)) { my $sql = "SELECT val FROM dom_param WHERE param = 'logrotation_id' " . "AND dom_id=$domainId"; if ($self->{dbh}->execute_rownum($sql) and my $ptrRow = $self->{dbh}->fetchrow()) { my $logrotation_id = $ptrRow->[0]; $self->{dbh}->finish(); $self->makeLogrotationNode($parent, $logrotation_id); } $self->{dbh}->finish(); } } sub makeLogrotationNode { my ($self, $parent, $logrotation_id) = @_; my $sql = "SELECT * FROM log_rotation WHERE id=$logrotation_id"; if($self->{dbh}->execute_rownum($sql) and my $hashPtr = $self->{dbh}->fetchhash()) { my %logRotation = %{$hashPtr}; if ($logRotation{'id'}) { my $item = XmlNode->new('logrotation', 'attributes' => { 'max-number-of-logfiles' => $logRotation{'max_number_of_logfiles'}, 'compress' => $logRotation{'compress_enable'}}); $item->{'ATTRIBUTE'}->('email', $logRotation{'email'}) unless $logRotation{'email'} eq ''; $item->{'ATTRIBUTE'}->('enabled', $logRotation{'turned_on'}); my $rottype; if($logRotation{'period_type'} eq 'by_time') { $rottype = XmlNode->new('logrotation-period', 'attributes' => { 'period' => $logRotation{'period'}}); } else { if (PleskVersion::atLeast(7, 0, 0)) { $rottype = XmlNode->new('logrotation-maxsize', 'content' => $logRotation{'period'}); } else { $rottype = XmlNode->new('logrotation-maxsize', 'content' => $logRotation{'period'}*1024); } } $item->{'ADDCHILD'}->($rottype); $parent->{'ADDCHILD'}->($item); } } $self->{dbh}->finish(); } #----------------------------------------------------------------- # $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, $ptrSubDomain, $domainName, $ptrSiteApplications) = @_; unless (ref($ptrSubDomain) =~ /HASH/) { printToError("Error: dumpSubDomain: bad argumets"); return undef; } my $root = XmlNode->new('subdomain'); my $subDomainName; if (PleskVersion::atLeast(7, 1, 0)) { $subDomainName = $ptrSubDomain->{'displayName'}; } else { $subDomainName = $ptrSubDomain->{'name'}; } $root->setAttribute('name', $subDomainName); # Subdomains may be SSL-enabled since 8.0 if (PleskVersion::atLeast(8, 0, 0)) { if ('true' eq $ptrSubDomain->{'ssl'}) { $root->setAttribute('https', 'true'); } if ('true' eq $ptrSubDomain->{'same_ssl'}) { $root->setAttribute('shared-content', 'true'); } } #----------------------------------------------------------------- # 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 $subDomainRoot = AgentConfig::get("HTTPD_VHOSTS_D") . "/$domainName/subdomains/$subDomainName"; if (-d $subDomainRoot) { my $cid_docroot = $self->addTar("$subDomainName.$domainName.httpdocs", "directory" => "$subDomainRoot/httpdocs", "exclude" => \@exclude_httpdocs_files); $root->setAttribute('cid_docroot', $cid_docroot) if $cid_docroot; my $cid_docroot_ssl = $self->addTar("$subDomainName.$domainName.httpsdocs", "directory" => "$subDomainRoot/httpsdocs", "exclude" => \@exclude_httpsdocs_files); $root->setAttribute('cid_docroot_ssl', $cid_docroot_ssl) if $cid_docroot_ssl; my $cid_cgi = $self->addTar("$subDomainName.$domainName.cgi-bin", "directory" => "$subDomainRoot/cgi-bin", "exclude" => \@exclude_cgi_bin_files); $root->setAttribute('cid_cgi', $cid_cgi) if $cid_cgi; my $cid_conf = $self->addTar("$subDomainName.$domainName.conf", "directory" => "$subDomainRoot/conf"); $root->setAttribute('cid_conf', $cid_conf) if $cid_conf; } # sysuser if ($ptrSubDomain->{'sys_user_type'} =~ /native/) { my $item = $self->makePleskSysUserNode($ptrSubDomain->{'sys_user_id'}); if (ref($item) =~ /XmlNode/) { $root->addChild($item); } } # scripting my $item = XmlNode->new('scripting'); while (my ($xmlName, $fieldName) = each(%subDomainScripting)) { if ($ptrSubDomain->{$fieldName} =~ /true/) { $item->setAttribute($xmlName, 'true'); } } $root->addChild($item); # Dump of installed site applications foreach my $sapp (@SiteApplications) { if (!$sapp->isSubdomainSiteapp($ptrSubDomain->{'id'})) { next; } $root->addChild($self->dumpSiteApplication($sapp, $subDomainRoot)); } return $root; } # # makeWebUserNode # # argumenets: # $ptrWebUser - pointer to hash with web user's info (row of table 'web_users') # $domainName - name of domain # # return: # $root = XML node # sub makeWebUserNode { my($self, $ptrWebUser, $domainName)=@_; unless(ref($ptrWebUser)=~/HASH/){ &printToError("Error: makeWebUserNode: bad argumets"); return undef; } my($root,$home,$fileName,$userName,$item,$xmlName,$fieldName); $root = XmlNode->new('webuser'); if (PleskVersion::atLeast(5, 0, 0)) { $item = $self->makePleskSysUserNode($ptrWebUser->{'sys_user_id'}); if(ref($item)=~/XmlNode/){ $root->addChild($item); my %sysUserInfo = $self->getSysUserInfo($ptrWebUser->{'sys_user_id'}); $userName = $sysUserInfo{'login'}; $root->setAttribute('name', $userName); } } else { $userName = $ptrWebUser->{'username'}; my @pwnam = getpwnam($userName); my $password = $pwnam[1]; $item = $self->makeSyntheticSysUserNode($userName, $password, 'encrypted'); $root->addChild($item); $root->setAttribute('name',$userName); } my $subDomainRoot=AgentConfig::get("HTTPD_VHOSTS_D")."/$domainName/web_users/$userName"; my $cid = $self->addTar("$domainName\_$userName", "directory" => $subDomainRoot); $root->setAttribute('cid',$cid) if $cid; my $privateData = AgentConfig::get("HTTPD_VHOSTS_D")."/$domainName/private/$userName"; my $cid_private = $self->addTar("$domainName\_$userName.private", "directory" => $privateData); $root->setAttribute('cid_private', $cid_private) if $cid_private; # # scripting # $item = XmlNode->new('scripting'); while(($xmlName,$fieldName)=each(%webUserScripting)){ if (defined $ptrWebUser->{$fieldName} and $ptrWebUser->{$fieldName}=~/true/) { $item->setAttribute($xmlName,'true'); } } $root->addChild($item); # # end scripting # return $root; } # # makeProtDirNode - make protected directory node # # arguments: # $pdirId - ID # $pdirPath - path of protected directory # $pdirTitle - header text # $pdirNonSSL - whether is directory in http # $pdirSSL - or in https # # return: # $root - XML node # sub makeProtDirNode { my($self, $pdirId, $pdirPath, $pdirTitle, $pdirNonSSL, $pdirSSL, $pdirCGI) = @_; my($root, $sql, $userNode, $item, $ptrRow); $root = XmlNode->new('pdir'); # workaround of CLI inabliity to create '' directory. if ($pdirPath eq '') { $pdirPath = '/'; } $root->{'ATTRIBUTE'}->('name', $pdirPath); if($pdirTitle) { $root->{'ATTRIBUTE'}->('title', $pdirTitle); } if ($pdirNonSSL) { $root->{'ATTRIBUTE'}->('nonssl', $pdirNonSSL); } if ($pdirSSL) { $root->{'ATTRIBUTE'}->('ssl', $pdirSSL); } if ($pdirCGI) { $root->{'ATTRIBUTE'}->('cgi', $pdirCGI); } if (PleskVersion::atLeast(7, 1, 0)) { $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"; } else { $sql = "SELECT p.login, p.passwd, 'plain' FROM pd_users p ". " WHERE p.pd_id=$pdirId ORDER BY p.id" } if ($self->{dbh}->execute_rownum($sql)) { while ($ptrRow=$self->{dbh}->fetchrow()) { $userNode = XmlNode->new('pduser'); $root->{'ADDCHILD'}->($userNode); $userNode->{'ATTRIBUTE'}->('name', $ptrRow->[0]); $item = makePasswordNode($ptrRow->[1], normalizePasswordType($ptrRow->[2])); $userNode->{'ADDCHILD'}->($item); } } $self->{dbh}->finish(); return $root; } sub addAnonFtp { my($self, $root, $domainId, $domainName) = @_; unless (ref($root) =~ /XmlNode/) { printToError("Error: addAnonFtp: bad argumets"); return; } my($anonRoot,$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()){ $anonRoot = XmlNode->new('anonftp'); $root->{'ADDCHILD'}->($anonRoot); if($ptrHash->{'status'}=~/true/){ $anonRoot->{'ATTRIBUTE'}->('pub','true'); } if($ptrHash->{'incoming'}=~/true/){ $anonRoot->{'ATTRIBUTE'}->('incoming','true'); } if (defined($ptrHash->{'max_conn'})) { makeAnonftpLimitNode($anonRoot,'max-connections', $ptrHash->{'max_conn'}); } if (defined($ptrHash->{'bandwidth'})) { makeAnonftpLimitNode($anonRoot, 'bandwidth', $ptrHash->{'bandwidth'}); } if (defined($ptrHash->{'quota'})) { makeAnonftpLimitNode($anonRoot, 'incoming-disk-quota', $ptrHash->{'quota'}); } if (defined($ptrHash->{'display_login'})) { $anonRoot->{'ATTRIBUTE'}->('display-login', $ptrHash->{'display_login'}); } if ($ptrHash->{'incoming_readable'} =~ /true/) { makeAnonftpPermissionNode($anonRoot, 'incoming-download'); } if ($ptrHash->{'incoming_subdirs'} =~ /true/) { makeAnonftpPermissionNode($anonRoot, 'incoming-mkdir'); } if (defined($ptrHash->{'login_text'})) { my $loginMessageNode = XmlNode->new('login-message', 'content' => $ptrHash->{'login_text'}); $anonRoot->{'ADDCHILD'}->($loginMessageNode); } $domainRoot = AgentConfig::get("HTTPD_VHOSTS_D") . '/' . $domainName; if (-d $domainRoot) { my $cid = $self->addTar("$domainName.anonftp.pub", "directory" => "$domainRoot/anon_ftp/pub"); $anonRoot->{'ATTRIBUTE'}->('cid',$cid) if $cid; my $cid_incoming = $self->addTar("$domainName.anonftp.incoming", "directory" => "$domainRoot/anon_ftp/incoming"); $anonRoot->{'ATTRIBUTE'}->('cid_incoming',$cid_incoming) if $cid_incoming; } $count++; } } $self->{dbh}->finish(); return $count; } sub getSysUserInfo { my ($self, $sysUserId) = @_; my $sql = "SELECT * FROM sys_users WHERE id=$sysUserId"; unless ($self->{dbh}->execute_rownum($sql)) { printToError("Error: makeSysUser: sys user #$sysUserId is not found"); return; } my %sysuser = %{$self->{dbh}->fetchhash()}; $self->{dbh}->finish(); return %sysuser; } sub makePleskSysUserNode { my ($self, $sysUserId) = @_; my %sysuser = $self->getSysUserInfo($sysUserId); Logging::trace("Making system user node: $sysuser{'login'}"); # # attributes # my $root = XmlNode->new('sysuser', 'attributes' => {'name' => lc($sysuser{'login'})}); $root->{'ATTRIBUTE'}->('shell',$sysuser{'shell'}) if $sysuser{'shell'}; my $quota; if($sysuser{'quota'}){ if (PleskVersion::atLeast(7, 0, 0)) { $quota = $sysuser{'quota'}; } else { if ($sysuser{'quota'} ne "-1") { $quota = $sysuser{'quota'}*1024*1024; } } $root->{'ATTRIBUTE'}->('quota',$quota) if $quota; } # # end attributes # # # password node # if (PleskVersion::atLeast(6, 0, 0)) { if ($sysuser{'account_id'} != 0) { $root->{'ADDCHILD'}->($self->makeAccountPasswordNode($sysuser{'account_id'})); } } else { $root->{'ADDCHILD'}->(makePasswordNode($sysuser{'passwd'}, 'plain')); } # # end password node # # # crontab node # my $crontabmng = AgentConfig::get("PRODUCT_ROOT_D") . "/admin/sbin/crontabmng"; if (-x $crontabmng) { open (CRONTAB, "$crontabmng get $sysuser{'login'} |"); my $crontab = ""; while () { last if $_ eq "0\n"; $crontab .= $_; } close (CRONTAB); if ($crontab ne "\n") { $root->{'ADDCHILD'}->(XmlNode->new('cron', 'content' => $crontab)); } } # # end crontab node # return $root; } sub makeSyntheticSysUserNode { my ($self, $name, $password, $passtype) = @_; my $root = XmlNode->new('sysuser', 'attributes' => { 'name' => lc($name)}); my $passwdNode = &makePasswordNode($password, $passtype); $root->{'ADDCHILD'}->($passwdNode); return $root; } sub makeFhostingNode { my ($self, $ptrDomain) = @_; unless(ref($ptrDomain)=~/HASH/){ &printToError("Error: makeFhostingNode: bag arguments"); return undef; } my($sql,$domainId,$root,$forward); $domainId=$ptrDomain->{'id'}; $sql="SELECT redirect FROM forwarding WHERE dom_id=$domainId"; if($self->{dbh}->execute_rownum($sql)){ ($forward)=@{$self->{dbh}->fetchrow()}; $root=XmlNode->new('fhosting','content' => $forward); }else{ &printToError("Error: makeFhostingNode: forward for domain '".$ptrDomain->{'name'}."' is not found"); } $self->{dbh}->finish(); return $root; } sub makeShostingNode { my ($self, $ptrDomain) = @_; unless(ref($ptrDomain)=~/HASH/){ &printToError("Error: makeShostingNode: bag arguments"); return undef; } my($sql,$domainId,$root,$forward); $domainId=$ptrDomain->{'id'}; $sql="SELECT redirect FROM forwarding WHERE dom_id=$domainId"; if($self->{dbh}->execute_rownum($sql)){ ($forward)=@{$self->{dbh}->fetchrow()}; $root=XmlNode->new('shosting','content' => $forward); }else{ &printToError("Error: makeShostingNode: forward for domain '".$ptrDomain->{'name'}."' is not found"); } $self->{dbh}->finish(); return $root; } # sub getClientIps { # my ($clientId) = @_; # if (PleskVersion::atLeast(6, 0, 0)) { # } elsif (PleskVersion::atLeast(5, 0, 0)) { # my $sql = "SELECT d.name, d.id, h.ip_address, a.status, d.cl_id FROM domains d " # . "LEFT JOIN hosting h ON h.dom_id = d.id " # . "LEFT JOIN anon_ftp a ON a.dom_id = d.id" # . "WHERE cl_id = $clientId"; # } else { # } # } # # Returns password node for given account ID # sub makeAccountPasswordNode { my ($self, $accountId) = @_; my $node; if ($self->{dbh}->execute_rownum("SELECT password, type FROM accounts WHERE id='$accountId'")) { my ($passwd, $type) = @{$self->{dbh}->fetchrow()}; $node = &makePasswordNode($passwd, normalizePasswordType($type)); } else { # generates a stub node $node = &makePasswordNode(); } $self->{dbh}->finish(); return $node; } sub makeSpamassassinNode81 { my ($self, $root, $mailname, $status) = @_; my $sql = "SELECT id, preferences, reject_spam FROM spamfilter WHERE username = '$mailname'"; unless($self->{dbh}->execute_rownum($sql)) { Logging::warning("Error during getting information about spam filter for $mailname"); $self->{dbh}->finish(); return; } my $row = $self->{dbh}->fetchrow(); my $filter_id = $row->[0]; my $reject_spam = $row->[2]; my $server = 0; do { $self->{dbh}->finish(); if ($server) { $sql = "SELECT id FROM spamfilter WHERE username = '*@*'"; $self->{dbh}->execute_rownum($sql); $row = $self->{dbh}->fetchrow(); $filter_id = $row->[0]; $self->{dbh}->finish(); } $sql = "SELECT preference, value FROM spamfilter_preferences WHERE spamfilter_id = '$filter_id' ORDER BY length(preference), preference"; } while (!$self->{dbh}->execute_rownum($sql) && !$server++); my $item = XmlNode->new('spamassassin', 'attributes' => { 'status' => $status eq 'true' ? 'on' : 'off', 'action' => $reject_spam eq 'true' ? 'del' : 'mark' }); while($row = $self->{dbh}->fetchrow()) { $item->addChild(XmlNode->new('blacklist-member', 'content' => $row->[1])) if $row->[0] eq "blacklist_from"; $item->addChild(XmlNode->new('whitelist-member', 'content' => $row->[1])) if $row->[0] eq "whitelist_from"; $item->addChild(XmlNode->new('unblacklist-member', 'content' => $row->[1])) if $row->[0] eq "unblacklist_from"; $item->addChild(XmlNode->new('unwhitelist-member', 'content' => $row->[1])) if $row->[0] eq "unwhitelist_from"; $item->setAttribute('hits', $row->[1]) if ($row->[0] eq "required_score"); if ($row->[0] eq "rewrite_header") { $row->[1] =~ s/^subject //; $item->setAttribute('subj-text', $row->[1]); } } $self->{dbh}->finish(); $root->addChild($item); return $item; } sub makeSpamassassinNode70 { my ($self, $root, $mailName) = @_; my $sql = "SELECT count(*) FROM sa_conf WHERE mailname='$mailName'"; unless($self->{dbh}->execute_rownum($sql)){ &printToError("Error during getting information about spam filter for $mailName "); return undef; } my @row = @{$self->{dbh}->fetchrow()}; $self->{dbh}->finish(); if ($row[0]==0) { return; } $sql = "SELECT * FROM sa_conf WHERE mailname='$mailName'"; unless ($self->{dbh}->execute_rownum($sql)) { printToError("Error during getting information about spam filter for $mailName"); return; } my %spam = %{$self->{dbh}->fetchhash()}; $self->{dbh}->finish(); my $item; if ($spam{'flt_enabled'} eq 'both') { $item = XmlNode->new('spamassassin', 'attributes' => { 'status' => 'on', 'server-conf' => 'true'}); } elsif ($spam{'flt_enabled'} eq 'user'){ $item = XmlNode->new('spamassassin', 'attributes' => { 'status' => 'on', 'server-conf' => 'false'}); } else { #skip creation return ; } $item->{'ATTRIBUTE'}->('hits', $spam{'hits_required'}); if ($spam{'spam_action'} eq 'save') { $item->{'ATTRIBUTE'}->('action', 'mark'); }else{ $item->{'ATTRIBUTE'}->('action', 'del'); } if ($spam{'rw_subject_tag'}) { $item->{'ATTRIBUTE'}->('modify-subj', 'true'); $item->{'ATTRIBUTE'}->('subj-text', $spam{'rw_subject_tag'}); } else { $item->{'ATTRIBUTE'}->('modify-subj', 'false'); } $self->addSpamassassinPatterns($item, $spam{'mailname'}, 'black'); $self->addSpamassassinPatterns($item, $spam{'mailname'}, 'white'); $root->{'ADDCHILD'}->($item); return $item; } sub addSpamassassinPatterns { my ($self, $root, $mailname, $color) = @_; my $sql = "SELECT pattern FROM sa_list WHERE mailname='$mailname' AND color = '$color'"; if (!$self->{dbh}->execute($sql)) { printToError("Error during getting information about ${color}list patterns for $mailname"); return; } my $row; while ($row = $self->{dbh}->fetchrow()) { my ($pattern) = @{$row}; $root->{'ADDCHILD'}->(XmlNode->new("${color}list-member", 'content' => $pattern)); } $self->{dbh}->finish(); } sub makeDrwebNode { my ($self, $root, $mailname) = @_; my $drwebFile = "/etc/drweb/users.conf"; unless (open(DRWEBFILE, "<$drwebFile")) { printToLog("Error: unable to open $drwebFile"); return; } while () { chomp; next if /^#/; #skip comments next if /^\[/; next if /^\s*$/; my @parts = split /\s+/, $_, 4; if ($parts[3] =~ /$mailname/) { my $item = XmlNode->new('drweb'); if ($parts[1] =~ /to/) { $item->{'ATTRIBUTE'}->('state', 'in'); } elsif ($parts[1] =~ /from/) { $item->{'ATTRIBUTE'}->('state', 'out'); } else { $item->{'ATTRIBUTE'}->('state', 'inout'); } $root->{'ADDCHILD'}->($item); last; } } close(DRWEBFILE); } sub makeWebAppNode { my ($self, $root, $webAppName, $webAppStatus, $dom_name) = @_; # webapp is useless without cid return if $self->{configuration_dump}; $webAppStatus ||= 0; my $item = XmlNode->new('webapp', 'attributes' => {'name' => $webAppName}, 'children' => [Status::make($webAppStatus)]); my $warDir = AgentConfig::get("CATALINA_HOME") . "/psa-wars/$dom_name"; my $warFile = "$webAppName.war"; my $cid = $self->addTar("$dom_name.$webAppName.webapp", "directory" => $warDir, "include" => [$warFile]); $item->{'ATTRIBUTE'}->('cid',$cid) if $cid; $root->{'ADDCHILD'}->($item); } sub getCustomButtonById71( $ ) { my ($self, $id) = @_; # several times there was empty button place in database, which is incorrect my $sql = "SELECT sort_key, place, text, url, conhelp, options, file FROM custom_buttons WHERE id=$id AND place!=''"; if (!$self->{dbh}->execute_rownum($sql)) { $self->{dbh}->finish(); return; } my $ptrHash = $self->{dbh}->fetchhash(); $self->{dbh}->finish(); my $node = XmlNode->new('custom-button'); my %attributes = ( 'url' => 'url', 'text' => 'text', 'sort_key' => 'sort-priority', 'place' => 'interface-place', 'conhelp' => 'conhelp' ); while (my ($dbfield, $nodefield) = each %attributes) { my $val = $ptrHash->{$dbfield}; $val = 'button' if ($dbfield eq 'text' && $val eq ''); $val = '/' if ($dbfield eq 'url' && $val eq ''); $node->setAttribute($nodefield, $val) if $val ne ''; } my $customButtonsDir = AgentConfig::get("PRODUCT_ROOT_D") . '/admin/htdocs/images/custom_buttons'; my $icon = $ptrHash->{'file'}; if (-e $customButtonsDir."/".$icon) { if ($icon) { my $cid_icon = (AgentConfig::tarVersionMoreThan15()) ? $self->addTar($icon.".".$id, "directory" => $customButtonsDir, "add_file" => $icon) :$self->addTar($icon.".".$id, "directory" => $customButtonsDir, "include" => [$icon]); $node->setAttribute('cid-icon', $cid_icon) if $cid_icon; } } parseCustomButtonOptions($node, $ptrHash->{'options'}); return $node; } sub getCustomButtonsByOwner71 { my ($self, $owner_type, $owner_id) = @_; my $level = $custom_button_owner_types{$owner_type}; my $sql = "SELECT id FROM custom_buttons WHERE level='$level' AND level_id='$owner_id'"; if (!$self->{dbh}->execute_rownum($sql)) { $self->{dbh}->finish(); return; } my @ids; while (my $ptrRow = $self->{dbh}->fetchrow()) { my $id = $ptrRow->[0]; if (grep /^$id$/, @{$self->{skip_custom_buttons}}) { next; } push @ids, $id; } $self->{dbh}->finish(); return map { $self->getCustomButtonById71($_) } @ids; } sub getCustomButtonsByOwner65 { my ($self, $owner_type, $owner_id) = @_; return if ($owner_type ne "client"); my $sql = "SELECT text, url, conhelp, options FROM custom_buttons WHERE " . "cl_id=$owner_id"; my @nodes; if ($self->{dbh}->execute_rownum($sql)) { my $ptrHash; while ($ptrHash = $self->{dbh}->fetchhash()) { my $node = XmlNode->new('custom-button', 'attributes' => {'sort-priority' => '100', 'interface-place' => 'domain'}); my %attributes = ( 'url' => 'url', 'text' => 'text', 'conhelp' => 'conhelp' ); while (my ($dbfield, $nodefield) = each %attributes) { $node->{'ATTRIBUTE'}->($nodefield, $ptrHash->{$dbfield}); } ## 128 == CUSTOM_BUTTON_PUBLIC parseCustomButtonOptions($node, $ptrHash->{'options'} | 128); push @nodes, $node; } } $self->{dbh}->finish(); return @nodes; } sub getCustomButtonsByOwner { my ($self, @args) = @_; return $self->getCustomButtonsByOwner71(@args) if (PleskVersion::atLeast(7, 1, 0)); return $self->getCustomButtonsByOwner65(@args) if (PleskVersion::atLeast(6, 5, 0)); return (); } sub makeDefaultIpNode { my ($self, $parent) = @_; my $sql = "SELECT ip_address FROM IP_Addresses ip, misc m WHERE ip.id = m.val AND m.param = 'def_ip_id'"; $self->{dbh}->execute_rownum($sql); my $ptrHash = $self->{dbh}->fetchhash(); $parent->{'ADDCHILD'}->(XmlNode->new('default-ip', 'content' => $ptrHash->{'ip_address'})); $self->{dbh}->finish(); } sub makeSystemIpNode { my ($self, $parent, $ptrIp) = @_; my $correctMask = $self->blockToNum($ptrIp->{'mask'}); $parent->{'ADDCHILD'}->(XmlNode->new('system-ip', 'attributes' => {'certificate' => $ptrIp->{'certificate'}}, 'children' => [XmlNode->new('ip', 'children' => [XmlNode->new('ip-type', 'content' => "$ptrIp->{'type'}"), XmlNode->new('ip-address', 'content' => $ptrIp->{'ip_address'})]), XmlNode->new('ip-netmask', 'content' => "$correctMask") , XmlNode->new('ip-interface', 'content' => "$ptrIp->{'iface'}")])); } sub makeAdminInfoNode { my ($self, $parent, $ptrAdmin) = @_; my ($name,$value); $parent->{'ADDCHILD'}->(XmlNode->new('admin-password', 'content' => AgentConfig::get{'password'})); while (($name, $value) = each(%{$ptrAdmin})) { #Attributes transformation. Bug 97408 $name=~s/^admin_//g; next if $name=~/_u?id$/; next if $name=~/isPrefEdit$/; next if $name=~/news_dismissed$/; next if $name=~/ownership$/; $name = 'zip' if $name=~/pcode/; $name = 'company' if $name=~/cname/; $name = 'name' if $name=~/pname/; $parent->{'ADDCHILD'}->(XmlNode->new('pinfo', 'attributes' => {'name' => $name}, 'content' => $value)); } } sub blockToNum { my ($self, $mask) = @_; my $longMask = unpack("N", pack("C4", split(/\./, $mask))); my $block; for ($block = 0; $block < 32; $block = $block + 1) { my $tmp = 2**(32-$block-1); last if !($longMask & $tmp); } return $block; } sub makeServerNode { my ($self, $parent) = @_; my $serverNode = XmlNode->new('server'); #Dump system and default ip my $sql = "SELECT ip_address, mask, iface, i.type, c.name certificate FROM IP_Addresses i INNER JOIN certificates c ON c.id = i.ssl_certificate_id"; my %ips; $self->{dbh}->execute_rownum($sql); while (my $ptrHash = $self->{dbh}->fetchhash()){ $self->makeSystemIpNode($serverNode, $ptrHash); } $self->{dbh}->finish(); $self->makeDefaultIpNode($serverNode); #Dump hostname $sql = "SELECT val FROM misc WHERE param = 'FullHostName'"; $self->{dbh}->execute_rownum($sql); my $ptrHash = $self->{dbh}->fetchhash(); $serverNode->{'ADDCHILD'}->(XmlNode->new('hostname', 'content' => "$ptrHash->{'val'}")); $self->{dbh}->finish(); #Dump admin info $sql = "SELECT param, val FROM misc WHERE param RLIKE '^admin'"; # do not use LIKE, bug #106566 my %admin; $self->{dbh}->execute_rownum($sql); while (my $ptrHash = $self->{dbh}->fetchhash()){ $admin{$ptrHash->{'param'}} = $ptrHash->{'val'}; } $self->{dbh}->finish(); $self->makeAdminInfoNode($serverNode, \%admin); # Dump database servers if(PleskVersion::atLeast(8,0,0)){ $sql = "SELECT param, val FROM misc WHERE param RLIKE '^default_server_'"; my %def; $self->{dbh}->execute_rownum($sql); while (my $ptrHash = $self->{dbh}->fetchhash()){ $def{$ptrHash->{'param'}} = $ptrHash->{'val'}; } $self->{dbh}->finish(); $sql = "SELECT id, host, port, type, admin_login, admin_password FROM DatabaseServers"; $self->{dbh}->execute_rownum($sql); while (my $ptrHash = $self->{dbh}->fetchhash()){ my $dbServerNode = XmlNode->new('db-server'); my $param = 'default_server_'.$ptrHash->{'type'}; if (exists $def{$param} && $def{$param} == $ptrHash->{'id'}) { $dbServerNode->{'ATTRIBUTE'}->('default', 'true'); } $dbServerNode->{'ATTRIBUTE'}->('type',$ptrHash->{'type'}); $dbServerNode->{'ADDCHILD'}->(XmlNode->new('host', 'content' => "$ptrHash->{'host'}")); $dbServerNode->{'ADDCHILD'}->(XmlNode->new('port', 'content' => "$ptrHash->{'port'}")); if ($ptrHash->{'admin_login'} ne '') { my $adminNode = XmlNode->new('admin',"attributes" => {"name" => "$ptrHash->{'admin_login'}"}); if ($ptrHash->{'type'} eq 'mysql' && $ptrHash->{'host'} eq 'localhost') { $ptrHash->{'admin_password'} = AgentConfig::get('password'); } my $passwordNode = makePasswordNode($ptrHash->{'admin_password'},'plain'); # password type for dbservers is always plain $adminNode->{'ADDCHILD'}->($passwordNode); $dbServerNode->{'ADDCHILD'}->($adminNode); } $serverNode->{'ADDCHILD'}->($dbServerNode); } $self->{dbh}->finish(); } if (!$self->{shallow_dump} and !$self->{configuration_dump}) { # Dump key info $sql = "SELECT * FROM key_history WHERE filename IS NOT NULL"; $self->{dbh}->execute_rownum($sql); while (my $ptrHash = $self->{dbh}->fetchhash()){ 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) { my $keyNode = XmlNode->new('key', 'attributes' => {'additional' => $additional}); my $cid = $self->addTar("$ptrHash->{'plesk_key_id'}.key", "directory" => $keyDir, "include" => [$keyName]); $keyNode->{'ATTRIBUTE'}->('cid', $cid) if $cid; $serverNode->{'ADDCHILD'}->($keyNode); } } $self->{dbh}->finish(); } my %params; # TODO: implement server settings backups for earlier Plesks if (PleskVersion::atLeast(8, 1, 0)) { # Dump server settings my $ptrRow; $self->{dbh}->execute_rownum('SELECT param, val FROM misc'); while($ptrRow = $self->{dbh}->fetchrow()) { $params{$ptrRow->[0]} = $ptrRow->[1]; } $self->{dbh}->finish(); my @unessential_params = ('spf_rules', 'spf-guess', 'spf-exp', 'rbl_server', 'spf_behavior', 'disable_pop_auth', 'disable_smtp_auth', 'spf_enabled', 'use_vocabulary', 'allow_short_pop3_names', 'dns_zone_status'); foreach my $param (@unessential_params) { if (!exists $params{$param}) { $params{$param} = ''; } } $params{'rbl_server'} =~ s/;/,/g; # Dump mail settings my $mailmng = AgentConfig::get('PRODUCT_ROOT_D') . '/admin/sbin/mailmng'; my $letter_size = `$mailmng --get-max-letter-size`; chomp($letter_size); my $mailNode = XmlNode->new('mail-settings', 'attributes' => { 'max-letter-size' => $letter_size, 'relay' => $params{'relay'}, 'use-vocabulary' => $params{'use_vocabulary'} eq 'true' ? 'true' : 'false', 'short-pop3-names' => $params{'allow_short_pop3_names'} eq 'enabled' ? 'true' : 'false', 'message-submission' => $params{'message_submission'} eq 'true' ? 'true' : 'false', 'sign-outgoing-mail' => $params{'domain_keys_sign'} eq 'true' ? 'true' : 'false', 'verify-incoming-mail' => $params{'domain_keys_verify'} eq 'true' ? 'true' : 'false', }); my $spfNode = XmlNode->new('spf', 'attributes' => { 'status' => (exists $params{'spf_enabled'} and $params{'spf_enabled'} eq 'true') ? 'true' : 'false'}); $spfNode->setAttribute('spf-behavior', ($params{'spf_behavior'} != '') ? $params{'spf_behavior'} : 1); $spfNode->{'ADDCHILD'}->(XmlNode->new('spf-rules', 'content' => $params{'spf_rules'})); $spfNode->{'ADDCHILD'}->(XmlNode->new('spf-guess', 'content' => $params{'spf_guess'})); $spfNode->{'ADDCHILD'}->(XmlNode->new('spf-exp', 'content' => $params{'spf_exp'})); $mailNode->{'ADDCHILD'}->($spfNode); my $rblNode = XmlNode->new('rbl', 'attributes' => { 'status' => (exists $params{'rbl'} and $params{'rbl'} eq 'true') ? 'true' : 'false'}); $rblNode->{'ADDCHILD'}->(XmlNode->new('rbl-server', 'content' => $params{'rbl_server'})); $mailNode->{'ADDCHILD'}->($rblNode); if ($params{'relay'} eq 'auth') { $mailNode->{'ATTRIBUTE'}->('pop-auth', $params{'disable_pop_auth'} ? 'false' : 'true'); $mailNode->{'ATTRIBUTE'}->('smtp-auth', $params{'disable_smtp_auth'} ? 'false' : 'true'); $mailNode->{'ATTRIBUTE'}->('poplock-time', $params{'poplock_time'}) if (!$params{'disable_pop_auth'}); } # black list my $listNode = XmlNode->new('black-list'); $self->{dbh}->execute_rownum('SELECT domain FROM badmailfrom'); while($ptrRow = $self->{dbh}->fetchrow()) { $listNode->{'ADDCHILD'}->(XmlNode->new('list-item', 'content' => $ptrRow->[0])); } $self->{dbh}->finish(); $mailNode->{'ADDCHILD'}->($listNode); # white list $listNode = XmlNode->new('white-list'); $self->{dbh}->execute_rownum('SELECT ip_address, ip_mask FROM smtp_poplocks'); while($ptrRow = $self->{dbh}->fetchrow()) { $listNode->{'ADDCHILD'}->(XmlNode->new('list-item', 'content' => $ptrRow->[0] . '/' . $ptrRow->[1])); } $self->{dbh}->finish(); $mailNode->{'ADDCHILD'}->($listNode); $serverNode->{'ADDCHILD'}->($mailNode); # dump dns my $dnsNode = XmlNode->new('dns-settings', 'attributes' => {'recursion' => defined $params{'dns_recursion'} ? $params{'dns_recursion'} : 'any'}); my $dnsZone = XmlNode->new('dns-zone', 'attributes' => {'email' => 'root@localhost.localdomain', 'type' => 'master'}, 'children' => [Status::make($params{'dns_zone_status'} ne 'false' ? 0 : 16)]); my %zone_params = ( 'ttl' => 1*86400, 'refresh' => 3*3600, 'retry' => 1*3600, 'expire' => 7*86400, 'minimum' => 3*3600 ); my %zone_units = ( 'ttl' => 86400, 'refresh' => 3600, 'retry' => 3600, 'expire' => 86400, 'minimum' => 3600 ); foreach my $param (keys %zone_params) { my $soa_param = 'soa_' . $param; $dnsZone->{'ADDCHILD'}->( $self->makeDnsZoneParam($param, exists $params{$soa_param.'_unit'} ? $params{$soa_param.'_unit'} : $zone_units{$param}, exists $params{$soa_param} ? $params{$soa_param} : $zone_params{$param}, ) ); } # dns records $self->{dbh}->execute_rownum('SELECT * FROM dns_recs_t'); while (my $ptrHash = $self->{dbh}->fetchhash()) { my $dnsrec = $self->makeDnsRecord($ptrHash); if ($dnsrec) { $dnsZone->{'ADDCHILD'}->($dnsrec); } } $self->{dbh}->finish(); $dnsNode->{'ADDCHILD'}->($dnsZone); # dump common acl for dns zone my $aclNode = XmlNode->new('common-acl'); foreach my $param (keys %params) { if ($param =~ /^DNS_Allow_Transfer/) { $aclNode->{'ADDCHILD'}->(XmlNode->new('list-item', 'content' => $params{$param})); } } $dnsNode->{'ADDCHILD'}->($aclNode); $serverNode->{'ADDCHILD'}->($dnsNode); # dump certificates my $cert_id = $params{'cert_rep_id'}; $sql = "SELECT c.id FROM certificates c, Repository r " . "WHERE c.id=r.component_id AND r.rep_id='$cert_id' ORDER BY c.id"; $self->{dbh}->execute_rownum($sql); my @ids; while ($ptrRow = $self->{dbh}->fetchrow()) { push @ids, $ptrRow->[0]; } $self->{dbh}->finish(); foreach my $id (@ids) { my $certNode = $self->makeCertificateNode($id); if ($params{'default_certificate_id'} == $id) { $certNode->{'ATTRIBUTE'}->('default', 'true'); } $serverNode->{'ADDCHILD'}->($certNode); } # dump custom buttons $serverNode->{'ADDCHILD'}->($_) foreach $self->getCustomButtonsByOwner('admin', 0); # dump domain templates $self->dumpTemplates($serverNode, $params{'dom_tmpl_list_id'}, 'domain-template'); # dump client templates $self->dumpTemplates($serverNode, $params{'cl_tmpl_list_id'}, 'client-template'); } if (PleskVersion::atLeast(8, 2, 0)) { # dump SSO if (defined $params{'sso_server'}) { my $ownership = defined $params{'admin_ownership'} && $params{'admin_ownership'} eq 'true' ? 'true' : 'false'; my $enabled = defined $params{'sso_enabled'} && $params{'sso_enabled'} eq 'true' ? 'true' : 'false'; my $ssoNode = XmlNode->new('sso-settings', 'attributes' => {'enabled' => $enabled, 'admin-ownership' => $ownership}); my @settings = ('sso_server', 'sso_relay', 'sso_application_id', 'sso_idp_api_version', 'sso_idp_id'); my %settings_map = ('sso_server' => 'sso-server', 'sso_relay' => 'sso-relay', 'sso_application_id' => 'sso-application-id', 'sso_idp_api_version' => 'sso-idp-api-version', 'sso_idp_id' => 'sso-idp-id'); foreach my $setting (@settings) { $ssoNode->{'ADDCHILD'}->(XmlNode->new($settings_map{$setting}, 'content' => $params{$setting})) if (defined $params{$setting}); } if (defined $params{'sso_certificate'} && -r $params{'sso_certificate'}) { my $cert; open(CERT, $params{'sso_certificate'}); read(CERT, $cert, -s CERT); close(CERT); $ssoNode->{'ADDCHILD'}->(XmlNode->new('sso-certificate', 'content' => $cert)); } if (defined $params{'sso_idp_cert'} && -r $params{'sso_idp_cert'}) { my $idpCert; open(IDPCERT, $params{'sso_idp_cert'}); read(IDPCERT, $idpCert, -s IDPCERT); close(IDPCERT); $ssoNode->addChild(XmlNode->new('sso-idp-cert', 'content' => $idpCert)); } if (PleskVersion::atLeast(8, 3, 0)) { # SSO branding my $ssoBrandingNode = XmlNode->new('sso-branding'); $sql = "SELECT * FROM SSOBranding"; if ($self->{dbh}->execute_rownum($sql)) { while (my $ptrRow = $self->{dbh}->fetchrow()) { my $recordNode = XmlNode->new('record', 'children' => [XmlNode->new('idp-url', 'content' => $ptrRow->[1]), XmlNode->new('http-request-domain', 'content' => $ptrRow->[0])]); $ssoBrandingNode->addChild($recordNode); } $ssoNode->addChild($ssoBrandingNode); } } $serverNode->{'ADDCHILD'}->($ssoNode); # Dump misc parameters if (defined $params{'force_db_prefix'}) { $serverNode->{'ADDCHILD'}->(XmlNode->new('force-db-prefix', 'content' => $params{'force_db_prefix'})); } } } if (PleskVersion::atLeast(8, 3, 0)) { # Application Vault my $appVaultNode = XmlNode->new('application-vault'); # Application Package my $appPackagePoolNode = XmlNode->new('sapp-packages-pool'); my $distrib_path = AgentConfig::get("PRODUCT_ROOT_D"). "/var/apspkgarc"; my %mapHash = $self->parseApsIndexFile($distrib_path."/archive-index.xml"); my $real_path; $sql = "SELECT `name`, `version`, `release` FROM SiteAppPackages"; $self->{dbh}->execute_rownum($sql); while (my $ptrRow = $self->{dbh}->fetchrow()) { my $packageNode = XmlNode->new('sapp-package'); $packageNode->addChild(XmlNode->new('sapp-name', 'content' => $ptrRow->[0])); $packageNode->addChild(XmlNode->new('sapp-version', 'content' => $ptrRow->[1])) if ($ptrRow->[1]); $packageNode->addChild(XmlNode->new('sapp-release', 'content' => $ptrRow->[2])) if ($ptrRow->[2]); my $distrib_name = $ptrRow->[0]."-".$ptrRow->[1]."-".$ptrRow->[2]; # What if 1 and 2 does not exist, or they exist always? my $file_name; foreach my $tfile_name (keys %mapHash) { if ($distrib_name eq join("-", @{$mapHash{$tfile_name}})) { $file_name = $tfile_name; } } $real_path = $distrib_path."/".$file_name; if (-f $real_path) { my $cid = $self->addTar("sapp-distrib.".generateDumpId(), "directory" => $distrib_path, "include" => [$file_name]); $packageNode->addChild(XmlNode->new('sapp-distrib', 'content' => $cid)) if $cid; }else {next;} $appPackagePoolNode->addChild($packageNode); } $self->{dbh}->finish(); $appVaultNode->addChild($appPackagePoolNode); #Application Item my $appItemPoolNode = XmlNode->new('sapp-items-pool'); $sql = "SELECT lt.license_type_hash AS license_type_id, sap.name AS sapp_name, sap.version AS sapp_version, sap.release AS sapp_release, ai.shared AS shared, ai.disabled AS disabled " ."FROM APSApplicationItems AS ai INNER JOIN SiteAppPackages sap ON (sap.id = ai.pkg_id) " ."LEFT JOIN APSLicenseTypes AS lt ON (lt.id = ai.license_type_id)"; $self->{dbh}->execute_rownum($sql); while ($ptrHash = $self->{dbh}->fetchhash()) { $self->makeSiteAppItemNode($appItemPoolNode, $ptrHash); } $self->{dbh}->finish(); $appVaultNode->addChild($appItemPoolNode); #Application License my $licensePoolNode = XmlNode->new('sapp-licenses-pool'); $sql = "SELECT l.key_number, l.source, lt.license_type_hash FROM APSLicenses l, APSLicenseTypes lt WHERE l.license_type_id = lt.id"; $self->{dbh}->execute_rownum($sql); while (my $ptrRow = $self->{dbh}->fetchrow()) { my $licenseNode = XmlNode->new('sapp-license', 'children' => [XmlNode->new('key-number', 'content' => $ptrRow->[0]), XmlNode->new('license-type', 'content' => $ptrRow->[2]), XmlNode->new('license-text', 'content' => $ptrRow->[1])]); $licensePoolNode->addChild($licenseNode); } $self->{dbh}->finish(); $appVaultNode->addChild($licensePoolNode); $serverNode->addChild($appVaultNode); # SiteBuilder Config $sql = "SELECT * FROM SBConfig"; if ($self->{dbh}->execute_rownum($sql)) { my $sbNode = XmlNode->new('sb-config'); while ($ptrHash = $self->{dbh}->fetchhash()) { $sbNode->addChild(XmlNode->new('sb-param', 'children' => [XmlNode->new('sb-param-name', 'content' => $ptrHash->{'param_name'}), XmlNode->new('sb-param-value', 'content' => $ptrHash->{'param_value'})])); } $serverNode->addChild($sbNode); } } if (PleskVersion::atLeast(8,4,0)) { my $serverPrefsNode = XmlNode->new('server-preferences'); if (defined $params{'forbid_create_dns_subzone'}) { $serverPrefsNode->{'ADDCHILD'}->(XmlNode->new('forbid-create-dns-subzone', 'content' => $params{'forbid_create_dns_subzone'})); } if (defined $params{'force_db_user_prefix'}) { $serverPrefsNode->{'ADDCHILD'}->(XmlNode->new('force-db-user-prefix', 'content' => $params{'force_db_user_prefix'})); } if (defined $params{'db_user_length'}) { $serverPrefsNode->{'ADDCHILD'}->(XmlNode->new('db-user-length', 'content' => $params{'db_user_length'})); } $serverNode->addChild($serverPrefsNode); } $parent->{'ADDCHILD'}->($serverNode); } sub makeSiteAppItemNode() { my ($self, $parent, $ptrParams) = @_; my $appItemNode = XmlNode->new('sapp-item'); $appItemNode->setAttribute('enabled', ($ptrParams->{'disabled'} eq 'true') ? 'false' : 'true') if defined $ptrParams->{'disabled'}; my $appSpecNode = XmlNode->new('sapp-spec'); $appSpecNode->addChild(XmlNode->new('sapp-name', 'content' => $ptrParams->{'sapp_name'})); $appSpecNode->addChild(XmlNode->new('sapp-version', 'content' => $ptrParams->{'sapp_version'})) if defined $ptrParams->{'sapp_version'}; $appSpecNode->addChild(XmlNode->new('sapp-release', 'content' => $ptrParams->{'sapp_release'})) if defined $ptrParams->{'sapp_release'}; $appItemNode->addChild($appSpecNode); $appItemNode->addChild(XmlNode->new('license-type', 'content' => defined($ptrParams->{'license_type_id'}) ? $ptrParams->{'license_type_id'}: "0")); $appItemNode->addChild(XmlNode->new('shared', 'content' => $ptrParams->{'shared'})) if defined $ptrParams->{'shared'}; $appItemNode->addChild(XmlNode->new('description', 'content' => $ptrParams->{'description'})) if defined $ptrParams->{'description'}; $appItemNode->addChild(XmlNode->new('instances-limit', 'content' => $ptrParams->{'instances_limit'})) if defined $ptrParams->{'instances_limit'}; $parent->addChild($appItemNode); } sub parseApsIndexFile() { my ($self, $file) = @_; my %xmlHash; my $name; if (open(FILE, $file)) { while() { chomp; if ($_=~/<([A-Za-z\-]*)\s+name=\"(.*)\">/) { $name = $2; }elsif ($_=~/<([A-Za-z\-]*)>(.*)<\/([A-Za-z\-]*)>/) { push @{$xmlHash{$name}}, $2 unless $1 eq "valid"; } } close FILE; }else{ printToError("Unable to open ".$file); } return %xmlHash; } sub getDomainKeysDomainSupport() { my ($self, $parent, $domainId, $domainName, $dnsZoneId) = @_; my $sql = "SELECT p.value FROM Parameters p, DomainServices ds " . "WHERE ds.parameters_id = p.id AND ds.dom_id = $domainId AND p.parameter = 'domain_keys_sign'"; my $state; if ($self->{dbh}->execute_rownum($sql)) { $state = @{$self->{dbh}->fetchrow()}[0]; } else { $self->{dbh}->finish(); return; } $self->{dbh}->finish(); my $domainKeysNode = XmlNode->new('domain-keys', 'attributes' => {'state' => $state }); if ($state) { my $privateKey = $self->addTar("$domainName.sfdk.privatekey", 'directory' => '/etc/domainkeys/'.$domainName, 'include' => ['default']); $domainKeysNode->setAttribute('private-key', $privateKey) if $privateKey; $sql = "SELECT * FROM dns_recs WHERE dns_zone_id=$dnsZoneId AND displayHost='default._domainkey.$domainName.'"; if ($self->{dbh}->execute_rownum($sql)) { while (my $ptrHash = $self->{dbh}->fetchhash()) { chop $ptrHash->{'val'}; my $str = substr($ptrHash->{'val'}, 2); $domainKeysNode->setAttribute('public-key', $str); } } $self->{dbh}->finish(); } $parent->addChild($domainKeysNode); } 1; # Local Variables: # mode: cperl # cperl-indent-level: 2 # indent-tabs-mode: nil # tab-width: 4 # End: