diff --git a/server/lib/classes/cron.d/600-jailkit_maintenance.inc.php b/server/lib/classes/cron.d/600-jailkit_maintenance.inc.php index 3ddea13e99d88bdec313a66ed66f40e160b87b8e..9916b72e57246892ac373fb15e1093b5e4cc8e5b 100644 --- a/server/lib/classes/cron.d/600-jailkit_maintenance.inc.php +++ b/server/lib/classes/cron.d/600-jailkit_maintenance.inc.php @@ -58,12 +58,12 @@ class cronjob_jailkit_maintenance extends cronjob { $jailkit_config = $app->getconf->get_server_config($conf['server_id'], 'jailkit'); if (isset($this->jailkit_config) && isset($this->jailkit_config['jailkit_hardlinks'])) { if ($this->jailkit_config['jailkit_hardlinks'] == 'yes') { - $update_options = array('hardlink'); + $options = array('hardlink'); } elseif ($this->jailkit_config['jailkit_hardlinks'] == 'no') { - $update_options = array(); + $options = array(); } } else { - $update_options = array('allow_hardlink'); + $options = array('allow_hardlink'); } // limit the number of jails we update at one time according to time of day @@ -86,6 +86,14 @@ class cronjob_jailkit_maintenance extends cronjob { // check for any cron job using this jail $cron_inuse = $app->db->queryOneRecord('SELECT id FROM `cron` WHERE `parent_domain_id` = ? AND `type` = ? AND `server_id` = ?', $rec['domain_id'], 'chrooted', $conf['server_id']); + $records2 = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $rec['domain_id'], $rec['document_root'], $conf['server_id']); + foreach ($records2 as $record2) { + if ($record2['web_folder'] == NULL || $record2['web_folder'] == '') { + continue; + } + $options[] = 'skip='.$record2['web_folder']; + } + if ($shell_user_inuse || $cron_inuse || $rec['php_fpm_chroot'] == 'y' || $rec['delete_unused_jailkit'] != 'y') { $sections = $jailkit_config['jailkit_chroot_app_sections']; if (isset($rec['jailkit_chroot_app_sections']) && $rec['jailkit_chroot_app_sections'] != '') { @@ -104,7 +112,7 @@ class cronjob_jailkit_maintenance extends cronjob { if ($update_hash != $rec['last_jailkit_hash']) { $app->system->web_folder_protection($rec['document_root'], false); - $app->system->update_jailkit_chroot($rec['document_root'], $sections, $programs, $update_options); + $app->system->update_jailkit_chroot($rec['document_root'], $sections, $programs, $options); $app->system->web_folder_protection($rec['document_root'], true); $app->db->query("UPDATE `web_domain` SET `last_jailkit_update` = NOW(), `last_jailkit_hash` = ? WHERE `document_root` = ?", $update_hash, $rec['document_root']); } else { @@ -114,7 +122,7 @@ class cronjob_jailkit_maintenance extends cronjob { //$app->log('Removing unused jail: '.$rec['document_root'], LOGLEVEL_DEBUG); print 'Removing unused jail: '.$rec['document_root']."\n"; $app->system->web_folder_protection($rec['document_root'], false); - $app->system->delete_jailkit_chroot($rec['document_root']); + $app->system->delete_jailkit_chroot($rec['document_root'], $options); $app->system->web_folder_protection($rec['document_root'], true); $app->db->query("UPDATE `web_domain` SET `last_jailkit_update` = NOW(), `last_jailkit_hash` = NULL WHERE `document_root` = ?", $rec['document_root']); diff --git a/server/lib/classes/system.inc.php b/server/lib/classes/system.inc.php index 3aceb82c5dcfc8529c4daad5c8ce7f2ae7f87726..131d10f2442f2f5115a757ab0e49a249adb270d5 100644 --- a/server/lib/classes/system.inc.php +++ b/server/lib/classes/system.inc.php @@ -2415,6 +2415,9 @@ class system{ # /etc/jailkit/jk_init.ini is the default path, probably not needed? $program_args .= ' -c /etc/jailkit/jk_init.ini -j ?'; foreach($app_sections as $app_section) { + if ($app_section == '') { + continue; + } # should check that section exists with jk_init --list ? $program_args .= ' ' . escapeshellarg($app_section); } @@ -2494,6 +2497,9 @@ class system{ $bad_paths = array(); foreach($programs as $prog) { + if ($prog == '') { + continue; + } foreach ($blacklisted_paths_regex as $re) { if (preg_match($re, $prog, $matches)) { $bad_paths[] = $matches[0]; @@ -2531,9 +2537,23 @@ $app->log("update_jailkit_chroot called for $home_dir with options ".print_r($op return false; } + $jailkit_directories = array( + 'bin', + 'dev', + 'etc', + 'lib', + 'lib32', + 'lib64', + 'opt', + 'sys', + 'usr', + 'var', + ); + $opts = array(); $jk_update_args = ''; $jk_cp_args = ''; + $skips = ''; foreach ($options as $opt) { switch ($opt) { case '-k': @@ -2547,6 +2567,16 @@ $app->log("update_jailkit_chroot called for $home_dir with options ".print_r($op $opts[] = 'force'; $jk_cp_args .= ' -f'; break; + default: + if (preg_match('@^skip[ =]/?(.+)$@', $opt, $matches) ) { + if (in_array($matches[1], $jailkit_directories)) { + $app->log("update_jailkit_chroot: skipping update of jailkit directory $home_dir/".$matches[1] + . "; if this is in use as a web folder, it is insecure and should be fixed.", LOGLEVEL_WARN); + } + $jailkit_directories = $app->functions->array_unset_by_value($jailkit_directories, $matches[1]); + $skips .= ' --skip=/'.escapeshellarg($matches[1]); + } + break; } } @@ -2554,20 +2584,6 @@ $app->log("update_jailkit_chroot called for $home_dir with options ".print_r($op $this->chown($home_dir, 'root'); $this->chgrp($home_dir, 'root'); - $jailkit_directories = array( - 'bin', - 'dev', - 'etc', - 'lib', - 'lib32', - 'lib64', - 'opt', - 'sys', - 'usr', - 'var', - ); - - $skips = ''; $multiple_links = array(); foreach ($jailkit_directories as $dir) { $root_dir = '/'.$dir; @@ -2739,9 +2755,10 @@ $app->log("update_jailkit_chroot: removing deprecated directory which jk_update return true; } - public function delete_jailkit_chroot($home_dir) { + public function delete_jailkit_chroot($home_dir, $options = array()) { global $app; +$app->log("delete_jailkit_chroot called for $home_dir with options ".print_r($options, true), LOGLEVEL_DEBUG); $app->uses('ini_parser'); // Disallow operating on root directory @@ -2769,6 +2786,21 @@ $app->log("update_jailkit_chroot: removing deprecated directory which jk_update 'run', # not used by jailkit, but added for cleanup ); + foreach ($options as $opt) { + switch ($opt) { + default: + if (preg_match('@^skip[ =]/?(.+)$@', $opt, $matches) ) { + $matches[1] = ltrim($matches[1], '/'); + if (in_array($matches[1], $jailkit_directories)) { + $app->log("delete_jailkit_chroot: skipping removal of jailkit directory .$home_dir/".$matches[1] + . "; if this is in use as a web folder, it is insecure and should be fixed.", LOGLEVEL_WARN); + } + $jailkit_directories = $app->functions->array_unset_by_value($jailkit_directories, $matches[1]); + } + break; + } + } + $removed = ''; foreach ($jailkit_directories as $dir) { $jail_dir = rtrim($home_dir, '/') . '/'.$dir; diff --git a/server/plugins-available/apache2_plugin.inc.php b/server/plugins-available/apache2_plugin.inc.php index 103cfef339b7fb5564a6c98633b0b19eedadbb7f..cc4bea9f600fa334653edeb58c5becf10b0cdf9d 100644 --- a/server/plugins-available/apache2_plugin.inc.php +++ b/server/plugins-available/apache2_plugin.inc.php @@ -831,6 +831,11 @@ class apache2_plugin { $programs = $jailkit_config['jailkit_chroot_app_programs'] . ' ' . $jailkit_config['jailkit_chroot_cron_programs']; + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $data['new']['domain_id'], $data['new']['document_root'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + // don't update if last_jailkit_hash is the same $tmp = $app->db->queryOneRecord('SELECT `last_jailkit_hash` FROM web_domain WHERE domain_id = ?', $data['new']['parent_domain_id']); if ($update_hash != $tmp['last_jailkit_hash']) { @@ -3683,7 +3688,7 @@ class apache2_plugin { function _setup_jailkit_chroot() { - global $app; + global $app, $conf; $app->uses('system'); @@ -3746,6 +3751,11 @@ class apache2_plugin { return; } + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $this->website['domain_id'], $this->website['document_root'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + $app->system->update_jailkit_chroot($this->website['document_root'], $sections, $programs, $options); } @@ -3824,7 +3834,13 @@ class apache2_plugin { return; } - $app->system->delete_jailkit_chroot($parent_domain['document_root']); + $options = array(); + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $parent_domain_id, $parent_domain['document_root'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + + $app->system->delete_jailkit_chroot($parent_domain['document_root'], $options); // this gets last_jailkit_update out of sync with master db, but that is ok, // as it is only used as a timestamp to moderate the frequency of updating on the slaves diff --git a/server/plugins-available/cron_jailkit_plugin.inc.php b/server/plugins-available/cron_jailkit_plugin.inc.php index deb6211f0e47bd9d82659e8a4286a64cc885ad2a..a186a128867f8d941a4591aa60c35aca72d4eac7 100644 --- a/server/plugins-available/cron_jailkit_plugin.inc.php +++ b/server/plugins-available/cron_jailkit_plugin.inc.php @@ -296,6 +296,11 @@ class cron_jailkit_plugin { return; } + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $this->parent_domain['domain_id'], $this->parent_domain['document_root'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + $app->system->update_jailkit_chroot($this->parent_domain['document_root'], $sections, $programs, $options); } @@ -392,7 +397,13 @@ class cron_jailkit_plugin { return; } - $app->system->delete_jailkit_chroot($parent_domain['document_root']); + $options = array(); + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $parent_domain_id, $parent_domain['document_root'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + + $app->system->delete_jailkit_chroot($parent_domain['document_root'], $options); // this gets last_jailkit_update out of sync with master db, but that is ok, // as it is only used as a timestamp to moderate the frequency of updating on the slaves diff --git a/server/plugins-available/nginx_plugin.inc.php b/server/plugins-available/nginx_plugin.inc.php index fc2088fefbd275976c4961d430d5d23b57e2b244..59cc56bf0889bf80c3bb929641c468d3071623ee 100644 --- a/server/plugins-available/nginx_plugin.inc.php +++ b/server/plugins-available/nginx_plugin.inc.php @@ -669,6 +669,11 @@ class nginx_plugin { $programs = $jailkit_config['jailkit_chroot_app_programs'] . ' ' . $jailkit_config['jailkit_chroot_cron_programs']; + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $data['new']['domain_id'], $data['new']['document_root'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + // don't update if last_jailkit_hash is the same $tmp = $app->db->queryOneRecord('SELECT `last_jailkit_hash` FROM web_domain WHERE domain_id = ?', $data['new']['parent_domain_id']); if ($update_hash != $tmp['last_jailkit_hash']) { @@ -3462,7 +3467,7 @@ class nginx_plugin { function _setup_jailkit_chroot() { - global $app; + global $app, $conf; $app->uses('system'); @@ -3525,6 +3530,11 @@ class nginx_plugin { return; } + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $this->website['domain_id'], $this->website['document_root'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + $app->system->update_jailkit_chroot($this->website['document_root'], $sections, $programs, $options); } @@ -3602,7 +3612,13 @@ class nginx_plugin { return; } - $app->system->delete_jailkit_chroot($parent_domain['document_root']); + $options = array(); + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $parent_domain_id, $parent_domain['document_root'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + + $app->system->delete_jailkit_chroot($parent_domain['document_root'], $options); // this gets last_jailkit_update out of sync with master db, but that is ok, // as it is only used as a timestamp to moderate the frequency of updating on the slaves diff --git a/server/plugins-available/shelluser_jailkit_plugin.inc.php b/server/plugins-available/shelluser_jailkit_plugin.inc.php index 7c003e44683e6a3dda2585b179fef099e0ad03fd..3f8d94d2a7787251f355f60fe41989db49f84e24 100755 --- a/server/plugins-available/shelluser_jailkit_plugin.inc.php +++ b/server/plugins-available/shelluser_jailkit_plugin.inc.php @@ -286,7 +286,7 @@ class shelluser_jailkit_plugin { function _setup_jailkit_chroot() { - global $app; + global $app, $conf; if (isset($this->jailkit_config) && isset($this->jailkit_config['jailkit_hardlinks'])) { if ($this->jailkit_config['jailkit_hardlinks'] == 'yes') { @@ -356,6 +356,11 @@ class shelluser_jailkit_plugin { return; } + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $this->data['new']['parent_domain_id'], $this->data['new']['dir'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + $app->system->update_jailkit_chroot($this->data['new']['dir'], $sections, $programs, $options); } @@ -621,7 +626,13 @@ class shelluser_jailkit_plugin { return; } - $app->system->delete_jailkit_chroot($parent_domain['document_root']); + $options = array(); + $records = $app->db->queryAllRecords('SELECT web_folder FROM `web_domain` WHERE `parent_domain_id` = ? AND `document_root` = ? AND web_folder != \'\' AND web_folder IS NOT NULL AND `server_id` = ?', $parent_domain_id, $parent_domain['document_root'], $conf['server_id']); + foreach ($records as $record) { + $options[] = 'skip='.$record['web_folder']; + } + + $app->system->delete_jailkit_chroot($parent_domain['document_root'], $options); // this gets last_jailkit_update out of sync with master db, but that is ok, // as it is only used as a timestamp to moderate the frequency of updating on the slaves