Skip to content

v1.25.0 — Account deletion is now atomic, resumable and verifiable. Pr

Choose a tag to compare

@Tux82 Tux82 released this 06 Aug 17:41
· 40 commits to main since this release

Account deletion is now atomic, resumable and verifiable. Previously a deletion could fail half-way through, report success anyway, and leave resources behind that the panel had already forgotten about — four accounts on one server were each found in a different state of partial deletion.

The root cause

delete_account.sh, delete_user.sh and remove_domain.sh all ended on an echo, so they exited 0 no matter how many steps had failed. The panel gates its database cleanup on that exit code, so it deleted the hosting_users row — the only record naming what still needed removing — and the leftover became invisible in the UI.

Every step in those scripts now verifies its own post-condition and the script exits non-zero if any of them failed. Re-running a deletion against a partially deleted account completes the job rather than refusing to start.

Fixed

Databases were never dropped when an account was deleted. delete_user.sh dropped none at all, and remove_domain.sh only dropped a database named after the domain — so any database created through the account portal survived every deletion.

User crontabs outlived the account. userdel -r removes /var/spool/cron/crontabs/<user>, but only while the passwd entry still exists, and one code path removed the home directory without going through userdel. The file is keyed by name but owned by the numeric uid, and that uid returns to the free pool — so a future account could inherit, and read, a dead account's scheduled jobs. Crontabs are now removed before the system user, and verified.

remove_domain.sh could drop the wrong databases. It matched LIKE '<user>_<domain>%', where _ is a single-character wildcard in MySQL and the trailing % matched anything sharing the prefix. Removing example.com could take example_com_dev and example_com_backup with it. It now matches the exact name.

Deleting an account whose system user was already gone was impossible. delete_account.sh exited immediately on "System user does not exist" — precisely the state a failed deletion leaves behind, so the panel could not clean up after itself.

FTP and portal access could survive deletion. The /etc/vsftpd.userlist cleanup silently did nothing when the account being removed was the only entry in the file. That file also authorizes hosting-portal login, so the entry was a live credential, not cosmetic.

Ports were burned permanently. The Listen line was only removed if the vhost file still existed, so a vhost that had already gone left its port allocated forever.

Accounts silently stopped being backed up. A hosting account whose home directory was missing was skipped with no message, no log entry and no counter — so it looked healthy in the UI while nothing was being saved. Two accounts were lost this way, having aged past the retention window while orphaned. Backups also now check tar's exit status instead of reporting success unconditionally, and the retention sweep no longer descends into subdirectories.

Added

inetp audit_orphans — reconciles hosting accounts against /etc/passwd, /home, the FTP allowlist, crontabs, databases, MariaDB users, Apache vhosts, PHP-FPM pools, certificates and ports, reporting divergence in both directions:

sudo inetp audit_orphans              # whole server
sudo inetp audit_orphans --user bob   # one account

It is read-only and has no --fix mode by design. Exit codes: 0 clean, 1 something was found, 2 could not check.

A last-chance backup before deletion. Written to /backup/deleted/, which the retention sweep cannot reach. If it fails, the deletion aborts with nothing destroyed.

Deletion intent is recorded before anything is destroyed, under /var/lib/inetpanel/deleting/, and cleared only once every step has confirmed success. An interrupted deletion leaves a findable record instead of an invisible orphan, and the panel refuses to create a new account with a name whose deletion never finished.

A MariaDB plugin-version check (#22). When mariadb-plugin-provider-* packages fall out of step with mariadb-server, the daemon refuses to start on its next restart. The audit now reports this before something restarts MariaDB, rather than after.

Upgrading

Nothing runs automatically on update. After upgrading, sudo inetp audit_orphans is worth running once — it will tell you whether any previous deletion left something behind.