From 3a53ea59f8efc17dcd538224dcf8ceac7f88f26e Mon Sep 17 00:00:00 2001 From: Daniel Winzen Date: Tue, 28 Jan 2020 20:51:17 +0100 Subject: [PATCH] Hardlink chroot related files across all accounts to save disk space --- var/www/common.php | 12 ++++++++++-- var/www/cron.php | 9 ++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/var/www/common.php b/var/www/common.php index 2f30a00..d6a596a 100644 --- a/var/www/common.php +++ b/var/www/common.php @@ -941,17 +941,25 @@ function bytes_to_human_readable(int $bytes) : string { } } -function setup_chroot(string $account){ +function setup_chroot(string $account, string $last_account){ $system_account = sanitize_system_account($account); if($system_account === false){ echo "ERROR: Account $account looks strange\n"; return; } + $last_account = sanitize_system_account($last_account); $shell = ENABLE_SHELL_ACCESS ? '/bin/bash' : '/usr/sbin/nologin'; $user = posix_getpwnam($system_account); $passwd_line = "$user[name]:$user[passwd]:$user[uid]:$user[gid]:$user[gecos]:/:$user[shell]"; exec('/var/www/setup_chroot.sh ' . escapeshellarg("/home/$system_account")); file_put_contents("/home/$system_account/etc/passwd", $passwd_line, FILE_APPEND); + if($last_account !== false){ + exec('hardlink -c ' . escapeshellarg("/home/$system_account/bin") . ' ' . escapeshellarg("/home/$last_account/bin")); + exec('hardlink -c ' . escapeshellarg("/home/$system_account/etc") . ' ' . escapeshellarg("/home/$last_account/etc")); + exec('hardlink -c ' . escapeshellarg("/home/$system_account/lib") . ' ' . escapeshellarg("/home/$last_account/lib")); + exec('hardlink -c ' . escapeshellarg("/home/$system_account/lib64") . ' ' . escapeshellarg("/home/$last_account/lib64")); + exec('hardlink -c ' . escapeshellarg("/home/$system_account/usr") . ' ' . escapeshellarg("/home/$last_account/usr")); + } foreach(['.cache', '.composer', '.config', '.gnupg', '.local', '.ssh', 'data', 'Maildir'] as $dir){ if(!is_dir("/home/$system_account/$dir")){ mkdir("/home/$system_account/$dir", 0700); @@ -1010,7 +1018,7 @@ function update_system_user_password(string $user, string $password){ function sanitize_system_account(string $system_account){ $account = basename($system_account); $user = posix_getpwnam($account); - if($account !== $system_account || $user === false || $user['gid'] !== 33 || $user['uid'] < 1000){ + if(empty($system_account) || $account !== $system_account || $user === false || $user['gid'] !== 33 || $user['uid'] < 1000){ return false; } return $account; diff --git a/var/www/cron.php b/var/www/cron.php index 257d098..de3b8a0 100644 --- a/var/www/cron.php +++ b/var/www/cron.php @@ -11,9 +11,15 @@ while($tmp=$stmt->fetch(PDO::FETCH_NUM)){ $db->query('UPDATE service_instances SET reload=0 WHERE reload=1;'); //add new accounts +$newest_account=$db->query('SELECT system_account FROM users WHERE id NOT IN (SELECT user_id FROM new_account) AND todelete!=1 ORDER BY id DESC LIMIT 1;'); +$last_account = $newest_account->fetch(PDO::FETCH_NUM); +if(is_array($last_account)){ + $last_account = $last_account[0]; +} $del=$db->prepare("DELETE FROM new_account WHERE user_id=?;"); $approval = REQUIRE_APPROVAL ? 'WHERE new_account.approved=1': ''; $stmt=$db->query("SELECT users.system_account, new_account.password, users.id, users.instance FROM new_account INNER JOIN users ON (users.id=new_account.user_id) $approval LIMIT 100;"); + while($account=$stmt->fetch(PDO::FETCH_ASSOC)){ $system_account = basename($account['system_account']); if($system_account !== $account['system_account']){ @@ -29,7 +35,8 @@ while($account=$stmt->fetch(PDO::FETCH_ASSOC)){ $shell = ENABLE_SHELL_ACCESS ? '/bin/bash' : '/usr/sbin/nologin'; exec('useradd -l -g www-data -k /var/www/skel -m -s ' . escapeshellarg($shell) . ' ' . escapeshellarg($system_account)); update_system_user_password($system_account, $account['password']); - setup_chroot($system_account); + setup_chroot($system_account, $last_account); + $last_account = $system_account; //remove from to-add queue $del->execute([$account['id']]); }