Skip to content

Commit

Permalink
add delete-userfiles flag for Domain.delete() to remove email-account…
Browse files Browse the repository at this point in the history
… data on the filesystem (if any); fixes #1239

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
  • Loading branch information
d00p committed Apr 28, 2024
1 parent 7d99244 commit d6b8eb0
Show file tree
Hide file tree
Showing 8 changed files with 23 additions and 37 deletions.
2 changes: 1 addition & 1 deletion admin_domains.php
Expand Up @@ -113,7 +113,7 @@
} elseif ($alias_check['count'] > 0) {
Response::standardError('domains_cantdeletedomainwithaliases');
} else {
HTML::askYesNo('admin_domain_reallydelete', $filename, [
HTML::askYesNoWithCheckbox('admin_domain_reallydelete', 'admin_customer_alsoremovemail', $filename, [
'id' => $id,
'page' => $page,
'action' => $action
Expand Down
2 changes: 1 addition & 1 deletion customer_domains.php
Expand Up @@ -26,7 +26,7 @@
const AREA = 'customer';
require __DIR__ . '/lib/init.php';

use Froxlor\Api\Commands\SubDomains as SubDomains;
use Froxlor\Api\Commands\SubDomains;
use Froxlor\CurrentUser;
use Froxlor\Database\Database;
use Froxlor\Domain\Domain;
Expand Down
13 changes: 12 additions & 1 deletion lib/Froxlor/Api/Commands/Domains.php
Expand Up @@ -2098,6 +2098,8 @@ public function update()
* @param bool $is_stdsubdomain
* optional, default false, specify whether it's a std-subdomain you are deleting as it does not count
* as subdomain-resource
* @param bool $delete_userfiles
* optional, delete email account files on filesystem (if any), default false
*
* @access admin
* @return string json-encoded array
Expand All @@ -2109,7 +2111,8 @@ public function delete()
$id = $this->getParam('id', true, 0);
$dn_optional = $id > 0;
$domainname = $this->getParam('domainname', $dn_optional, '');
$is_stdsubdomain = $this->getParam('is_stdsubdomain', true, 0);
$is_stdsubdomain = $this->getBoolParam('is_stdsubdomain', true, 0);
$delete_user_emailfiles = $this->getBoolParam('delete_userfiles', true, 0);

$result = $this->apiCall('Domains.get', [
'id' => $id,
Expand All @@ -2133,6 +2136,14 @@ public function delete()
$idString = implode(' OR ', $idString);

if ($idString != '') {
if ($delete_user_emailfiles) {
// determine all connected email-accounts
$emailaccount_sel = Database::prepare("SELECT `email`, `homedir`, `maildir` FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString);
Database::pexecute($emailaccount_sel, $paramString, true, true);
while ($emailacc_row = $emailaccount_sel->fetch(PDO::FETCH_ASSOC)) {
Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $emailacc_row['email'], FileDir::makeCorrectDir($emailacc_row['homedir'] . '/' . $emailacc_row['maildir']));
}
}
$del_stmt = Database::prepare("
DELETE FROM `" . TABLE_MAIL_USERS . "` WHERE " . $idString);
Database::pexecute($del_stmt, $paramString, true, true);
Expand Down
2 changes: 1 addition & 1 deletion lib/Froxlor/Api/Commands/EmailAccounts.php
Expand Up @@ -563,7 +563,7 @@ public function delete()
}

if ($delete_userfiles) {
Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], $result['email_full']);
Cronjob::inserttask(TaskId::DELETE_EMAIL_DATA, $customer['loginname'], FileDir::makeCorrectDir($result['homedir'] . '/' . $result['maildir']));
}

// decrease usage for customer
Expand Down
35 changes: 5 additions & 30 deletions lib/Froxlor/Cron/System/TasksCron.php
Expand Up @@ -348,24 +348,16 @@ private static function deleteEmailData($row = null)
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_INFO, 'TasksCron: Task7 started - deleting customer e-mail data');

if (is_array($row['data'])) {
if (isset($row['data']['loginname']) && isset($row['data']['email'])) {
if (isset($row['data']['loginname']) && isset($row['data']['emailpath'])) {
// remove specific maildir
$email_full = $row['data']['email'];
$email_full = $row['data']['emailpath'];
if (empty($email_full)) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'FATAL: Task7 asks to delete a email account but email field is empty!');
}
$email_user = substr($email_full, 0, strrpos($email_full, "@"));
$email_domain = substr($email_full, strrpos($email_full, "@") + 1);
$maildirname = trim(Settings::Get('system.vmail_maildirname'));
// Add trailing slash to Maildir if needed
$maildirpath = $maildirname;
if (!empty($maildirname) and substr($maildirname, -1) != "/") {
$maildirpath .= "/";
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_ERR, 'FATAL: Task7 asks to delete a email account but emailpath field is empty!');
}

$maildir = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $email_domain . '/' . $email_user);
$maildir = FileDir::makeCorrectDir($email_full);

if ($maildir != '/' && !empty($maildir) && !empty($email_full) && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && is_dir(FileDir::makeCorrectDir($maildir . '/' . $maildirpath)) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) {
if ($maildir != '/' && !empty($maildir) && $maildir != Settings::Get('system.vmail_homedir') && substr($maildir, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir) && fileowner($maildir) == Settings::Get('system.vmail_uid') && filegroup($maildir) == Settings::Get('system.vmail_gid')) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir));
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
$return = false;
Expand All @@ -377,23 +369,6 @@ private static function deleteEmailData($row = null)
'~',
'?'
]);
} else {
// backward-compatibility for old folder-structure
$maildir_old = FileDir::makeCorrectDir(Settings::Get('system.vmail_homedir') . '/' . $row['data']['loginname'] . '/' . $row['data']['email']);

if ($maildir_old != '/' && !empty($maildir_old) && $maildir_old != Settings::Get('system.vmail_homedir') && substr($maildir_old, 0, strlen(Settings::Get('system.vmail_homedir'))) == Settings::Get('system.vmail_homedir') && is_dir($maildir_old) && fileowner($maildir_old) == Settings::Get('system.vmail_uid') && filegroup($maildir_old) == Settings::Get('system.vmail_gid')) {
FroxlorLogger::getInstanceOf()->logAction(FroxlorLogger::CRON_ACTION, LOG_NOTICE, 'Running: rm -rf ' . escapeshellarg($maildir_old));
// mail-address allows many special characters, see http://en.wikipedia.org/wiki/Email_address#Local_part
$return = false;
FileDir::safe_exec('rm -rf ' . escapeshellarg($maildir_old), $return, [
'|',
'&',
'`',
'$',
'~',
'?'
]);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Froxlor/System/Cronjob.php
Expand Up @@ -183,7 +183,7 @@ public static function inserttask(int $type, ...$params)
} elseif ($type == TaskId::DELETE_EMAIL_DATA && count($params) == 2 && $params[0] != '' && $params[1] != '') {
$data = [];
$data['loginname'] = $params[0];
$data['email'] = $params[1];
$data['emailpath'] = $params[1];
$data = json_encode($data);
Database::pexecute($ins_stmt, [
'type' => TaskId::DELETE_EMAIL_DATA,
Expand Down
2 changes: 1 addition & 1 deletion lng/de.lng.php
Expand Up @@ -1283,7 +1283,7 @@
'question' => [
'question' => 'Sicherheitsabfrage',
'admin_customer_reallydelete' => 'Wollen Sie den Kunden "%s" wirklich löschen?<br />ACHTUNG! Alle Daten gehen unwiderruflich verloren! Nach dem Vorgang müssen die Daten manuell aus dem Dateisystem entfernt werden.',
'admin_domain_reallydelete' => 'Wollen Sie die Domain "%s" wirklich löschen?',
'admin_domain_reallydelete' => 'Wollen Sie die Domain "%s" wirklich löschen?<br><span class="text-danger"><strong>ACHTUNG:</strong> Alle Subdomains, FTP-Konten und E-Mail Adressen/Konten, welche mit dieser Domain verbunden sind, werden gelöscht!</span>',
'admin_domain_reallydisablesecuritysetting' => 'Wollen Sie die wichtige Sicherheitseinstellung \'OpenBasedir\' wirklich deaktivieren?',
'admin_admin_reallydelete' => 'Wollen Sie den Admin "%s" wirklich löschen?<br />Alle Kunden und Domains dieses Admins werden Ihnen zugeteilt.',
'admin_template_reallydelete' => 'Wollen Sie die Vorlage "%s" wirklich löschen?',
Expand Down
2 changes: 1 addition & 1 deletion lng/en.lng.php
Expand Up @@ -1398,7 +1398,7 @@
'question' => [
'question' => 'Security question',
'admin_customer_reallydelete' => 'Do you really want to delete the customer %s? This cannot be undone!',
'admin_domain_reallydelete' => 'Do you really want to delete the domain %s?',
'admin_domain_reallydelete' => 'Do you really want to delete the domain %s?<br><span class="text-danger"><strong>NOTE:</strong> All subdomains, ftp-accounts and email-addresses/accounts connected to this domain will be removed!</span>',
'admin_domain_reallydisablesecuritysetting' => 'Do you really want to disable this security setting OpenBasedir?',
'admin_admin_reallydelete' => 'Do you really want to delete the admin %s? Every customer and domain will be reassigned to your account.',
'admin_template_reallydelete' => 'Do you really want to delete the template \'%s\'?',
Expand Down

0 comments on commit d6b8eb0

Please sign in to comment.