Newer
Older
function is_mounted($mountpoint){
//$cmd = 'df 2>/dev/null | grep " '.$mountpoint.'$"';
$cmd = 'mount 2>/dev/null | grep ?';
$this->exec_safe($cmd, ' on '. $mountpoint . ' type ');
$return_var = $this->last_exec_retcode();
return $return_var == 0 ? true : false;
function mount_backup_dir($backup_dir, $mount_cmd = '/usr/local/ispconfig/server/scripts/backup_dir_mount.sh'){
Florian Schaal
committed
global $app, $conf;
if($this->is_mounted($backup_dir)) return true;
$mounted = true;
if ( is_file($mount_cmd) &&
is_executable($mount_cmd) &&
fileowner($mount_cmd) === 0
) {
if (!$this->is_mounted($backup_dir)){
exec($mount_cmd);
sleep(1);
if (!$this->is_mounted($backup_dir)) $mounted = false;
}
} else $mounted = false;
Florian Schaal
committed
if (!$mounted) {
//* send email to admin that backup directory could not be mounted
$global_config = $app->getconf->get_global_config('mail');
if($global_config['admin_mail'] != ''){
$subject = 'Backup directory '.$backup_dir.' could not be mounted';
$message = "Backup directory ".$backup_dir." could not be mounted.\n\nThe command\n\n".$mount_cmd."\n\nfailed.";
mail($global_config['admin_mail'], $subject, $message);
}
}
return $mounted;
}
function umount_backup_dir($backup_dir, $mount_cmd = '/usr/local/ispconfig/server/scripts/backup_dir_umount.sh'){
Florian Schaal
committed
global $app, $conf;
if ( is_file($mount_cmd) &&
is_executable($mount_cmd) &&
fileowner($mount_cmd) === 0
) {
if ($this->is_mounted($backup_dir)){
exec($mount_cmd);
sleep(1);
$unmounted = $this->is_mounted($backup_dir) == 0 ? true : false;
if(!$unmounted) {
//* send email to admin that backup directory could not be unmounted
$global_config = $app->getconf->get_global_config('mail');
if($global_config['admin_mail'] != ''){
$subject = 'Backup directory '.$backup_dir.' could not be unmounted';
$message = "Backup directory ".$backup_dir." could not be unmounted.\n\nThe command\n\n".$mount_cmd."\n\nfailed.";
mail($global_config['admin_mail'], $subject, $message);
}
}
Florian Schaal
committed
}
}
return $unmounted;
Florian Schaal
committed
function _getinitcommand($servicename, $action, $init_script_directory = '', $check_service) {
global $conf, $app;
/* removed upstart support - deprecated
if(is_executable('/sbin/initctl')){
exec('/sbin/initctl version 2>/dev/null | /bin/grep -q upstart', $retval['output'], $retval['retval']);
if(intval($retval['retval']) == 0) return 'service '.$servicename.' '.$action;
}
*/
if(!in_array($action,array('restart','reload','force-reload'))) {
$app->log('Invalid init command action '.$action,LOGLEVEL_WARN);
return false;
}
Florian Schaal
committed
//* systemd (now default in all supported OS)
if(is_executable('/bin/systemd') || is_executable('/usr/bin/systemctl')){
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
$app->log('Trying to use Systemd to restart service',LOGLEVEL_DEBUG);
//* Test service name via regex
if(preg_match('/[a-zA-Z0-9\.\-\_]/',$servicename)) {
//* Test if systemd service is enabled
if ($check_service) {
$this->exec_safe("systemctl is-enabled ? 2>&1", $servicename);
$ret_val = $this->last_exec_retcode();
} else {
$app->log('Systemd service '.$servicename.' not found or not enabled.',LOGLEVEL_DEBUG);
}
//* Return service command
if ($ret_val == 0 || !$check_service) {
return 'systemctl '.$action.' '.$servicename.'.service';
} else {
$app->log('Failed to use Systemd to restart service '.$servicename.', we try init script instead.',LOGLEVEL_DEBUG);
}
} else {
$app->log('Systemd service name contains invalid chars: '.$servicename,LOGLEVEL_DEBUG);
Florian Schaal
committed
}
} else {
$app->log('Not using Systemd to restart services',LOGLEVEL_DEBUG);
Florian Schaal
committed
//* sysvinit fallback
$app->log('Using init script to restart service',LOGLEVEL_DEBUG);
//* Get init script directory
if($init_script_directory == '') $init_script_directory = $conf['init_scripts'];
if(substr($init_script_directory, -1) === '/') $init_script_directory = substr($init_script_directory, 0, -1);
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
$init_script_directory = realpath($init_script_directory);
//* Check init script dir
if(!is_dir($init_script_directory)) {
$app->log('Init script directory '.$init_script_directory.' not found',LOGLEVEL_WARN);
return false;
}
//* Forbidden init script paths
if(substr($init_script_directory,0,4) == '/var' || substr($init_script_directory,0,4) == '/tmp') {
$app->log('Do not put init scripts in /var or /tmp folder.',LOGLEVEL_WARN);
return false;
}
//* Check init script dir owner
if(fileowner($init_script_directory) !== 0) {
$app->log('Init script directory '.$init_script_directory.' not owned by root user',LOGLEVEL_WARN);
return false;
}
$full_init_script_path = realpath($init_script_directory.'/'.$servicename);
if($full_init_script_path == '') {
$app->log('No init script, we quit here.',LOGLEVEL_WARN);
return false;
}
//* Check init script
if(!is_file($full_init_script_path)) {
$app->log('Init script '.$full_init_script_path.' not found',LOGLEVEL_WARN);
return false;
}
//* Check init script owner
if(fileowner($full_init_script_path) !== 0) {
$app->log('Init script '.$full_init_script_path.' not owned by root user',LOGLEVEL_WARN);
return false;
}
if($check_service && is_executable($full_init_script_path)) {
return $full_init_script_path.' '.$action;
Florian Schaal
committed
}
if (!$check_service) {
return $full_init_script_path.' '.$action;
Florian Schaal
committed
}
Florian Schaal
committed
function getinitcommand($servicename, $action, $init_script_directory = '', $check_service=true) {
Florian Schaal
committed
if (is_array($servicename)) {
foreach($servicename as $service) {
$out = $this->_getinitcommand($service, $action, $init_script_directory, true);
if ($out != '') return $out;
}
} else {
return $this->_getinitcommand($servicename, $action, $init_script_directory, $check_service);
}
}
Michael Seevogel
committed
function getopensslversion($get_minor = false) {
global $app;
if($this->is_installed('openssl')) $cmd = 'openssl version';
else {
$app->log("Could not check OpenSSL version, openssl not found.", LOGLEVEL_DEBUG);
return '1.0.1';
}
exec($cmd, $output, $return_var);
Michael Seevogel
committed
if($return_var != 0 || !$output[0]) {
$app->log("Could not check OpenSSL version, openssl did not return any data.", LOGLEVEL_WARN);
return '1.0.1';
}
if(preg_match('/OpenSSL\s*(\d+)(\.(\d+)(\.(\d+))*)?(\D|$)/i', $output[0], $matches)) {
return $matches[1] . (isset($matches[3]) ? '.' . $matches[3] : '') . (isset($matches[5]) && $get_minor == true ? '.' . $matches[5] : '');
} else {
$app->log("Could not check OpenSSL version, did not find version string in openssl output.", LOGLEVEL_WARN);
return '1.0.1';
}
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
}
function getnginxversion($get_minor = false) {
global $app;
if($this->is_installed('nginx')) $cmd = 'nginx -v 2>&1';
else {
$app->log("Could not check Nginx version, nginx not found.", LOGLEVEL_DEBUG);
return false;
}
exec($cmd, $output, $return_var);
if($return_var != 0 || !$output[0]) {
$app->log("Could not check Nginx version, nginx did not return any data.", LOGLEVEL_WARN);
return false;
}
if(preg_match('/nginx version: nginx\/\s*(\d+)(\.(\d+)(\.(\d+))*)?(\D|$)/i', $output[0], $matches)) {
return $matches[1] . (isset($matches[3]) ? '.' . $matches[3] : '') . (isset($matches[5]) && $get_minor == true ? '.' . $matches[5] : '');
} else {
$app->log("Could not check Nginx version, did not find version string in nginx output.", LOGLEVEL_WARN);
return false;
}
}
Michael Seevogel
committed
function getapacheversion($get_minor = false) {
global $app;
$cmd = '';
if($this->is_installed('apache2ctl')) $cmd = 'apache2ctl -v';
elseif($this->is_installed('apachectl')) $cmd = 'apachectl -v';
else {
$app->log("Could not check apache version, apachectl not found.", LOGLEVEL_DEBUG);
exec($cmd, $output, $return_var);
if($return_var != 0 || !$output[0]) {
$app->log("Could not check apache version, apachectl did not return any data.", LOGLEVEL_WARN);
return '2.2';
}
if(preg_match('/version:\s*Apache\/(\d+)(\.(\d+)(\.(\d+))*)?(\D|$)/i', $output[0], $matches)) {
return $matches[1] . (isset($matches[3]) ? '.' . $matches[3] : '') . (isset($matches[5]) && $get_minor == true ? '.' . $matches[5] : '');
} else {
$app->log("Could not check apache version, did not find version string in apachectl output.", LOGLEVEL_WARN);
return '2.2';
}
}
function getapachemodules() {
global $app;
$cmd = '';
if($this->is_installed('apache2ctl')) $cmd = 'apache2ctl -t -D DUMP_MODULES';
elseif($this->is_installed('apachectl')) $cmd = 'apachectl -t -D DUMP_MODULES';
else {
$app->log("Could not check apache modules, apachectl not found.", LOGLEVEL_WARN);
return array();
}
exec($cmd . ' 2>/dev/null', $output, $return_var);
if($return_var != 0 || !$output[0]) {
$app->log("Could not check apache modules, apachectl did not return any data.", LOGLEVEL_WARN);
return array();
}
$modules = array();
for($i = 0; $i < count($output); $i++) {
if(preg_match('/^\s*(\w+)\s+\((shared|static)\)\s*$/', $output[$i], $matches)) {
$modules[] = $matches[1];
}
}
return $modules;
}
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
//* ISPConfig mail function
public function mail($to, $subject, $text, $from, $filepath = '', $filetype = 'application/pdf', $filename = '', $cc = '', $bcc = '', $from_name = '') {
global $app, $conf;
if($conf['demo_mode'] == true) $app->error("Mail sending disabled in demo mode.");
$app->uses('getconf,ispcmail');
$mail_config = $app->getconf->get_global_config('mail');
if($mail_config['smtp_enabled'] == 'y') {
$mail_config['use_smtp'] = true;
$app->ispcmail->setOptions($mail_config);
}
$app->ispcmail->setSender($from, $from_name);
$app->ispcmail->setSubject($subject);
$app->ispcmail->setMailText($text);
if($filepath != '') {
if(!file_exists($filepath)) $app->error("Mail attachement does not exist ".$filepath);
$app->ispcmail->readAttachFile($filepath);
}
if($cc != '') $app->ispcmail->setHeader('Cc', $cc);
if($bcc != '') $app->ispcmail->setHeader('Bcc', $bcc);
$app->ispcmail->send($to);
$app->ispcmail->finish();
return true;
}
public function is_allowed_user($username, $check_id = true, $restrict_names = false) {
global $app;
$name_blacklist = array('root','ispconfig','vmail','getmail');
if(in_array($username,$name_blacklist)) return false;
if(preg_match('/^[a-zA-Z0-9\.\-_]{1,32}$/', $username) == false) return false;
if($check_id && intval($this->getuid($username)) < $this->min_uid) return false;
if($restrict_names == true && preg_match('/^web\d+$/', $username) == false) return false;
public function is_allowed_group($groupname, $check_id = true, $restrict_names = false) {
$name_blacklist = array('root','ispconfig','vmail','getmail');
if(in_array($groupname,$name_blacklist)) return false;
if(preg_match('/^[a-zA-Z0-9\.\-_]{1,32}$/', $groupname) == false) return false;
if($check_id && intval($this->getgid($groupname)) < $this->min_gid) return false;
if($restrict_names == true && preg_match('/^client\d+$/', $groupname) == false) return false;
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
public function is_allowed_path($path) {
global $app;
$path = $app->functions->normalize_path($path);
if(file_exists($path)) {
$path = realpath($path);
}
$blacklisted_paths_regex = array(
'@^/$@',
'@^/proc(/.*)?$@',
'@^/sys(/.*)?$@',
'@^/etc(/.*)?$@',
'@^/dev(/.*)?$@',
'@^/tmp(/.*)?$@',
'@^/run(/.*)?$@',
'@^/boot(/.*)?$@',
'@^/root(/.*)?$@',
'@^/var(/?|/backups?(/.*)?)?$@',
);
foreach($blacklisted_paths_regex as $regex) {
if(preg_match($regex, $path)) {
return false;
}
}
return true;
}
public function last_exec_out() {
return $this->_last_exec_out;
}
public function last_exec_retcode() {
return $this->_last_exec_retcode;
}
public function exec_safe($cmd) {
$args = func_get_args();
$arg_count = func_num_args();
Marius Burkard
committed
if($arg_count != substr_count($cmd, '?') + 1) {
trigger_error('Placeholder count not matching argument list.', E_USER_WARNING);
return false;
}
array_shift($args);
$pos = 0;
$a = 0;
foreach($args as $value) {
$a++;
$pos = strpos($cmd, '?', $pos);
if($pos === false) {
break;
}
$value = escapeshellarg($value);
$cmd = substr_replace($cmd, $value, $pos, 1);
$pos += strlen($value);
}
}
$this->_last_exec_out = null;
$this->_last_exec_retcode = null;
$ret = exec($cmd, $this->_last_exec_out, $this->_last_exec_retcode);
$app->log("safe_exec cmd: " . $cmd . " - return code: " . $this->_last_exec_retcode, LOGLEVEL_DEBUG);
public function system_safe($cmd) {
call_user_func_array(array($this, 'exec_safe'), func_get_args());
return implode("\n", $this->_last_exec_out);
}
public function create_jailkit_user($username, $home_dir, $user_home_dir, $shell = '/bin/bash', $p_user = null, $p_user_home_dir = null) {
// Disallow operating on root directory
if(realpath($home_dir) == '/') {
$app->log("create_jailkit_user: invalid home_dir: $home_dir", LOGLEVEL_WARN);
return false;
}
// Check if USERHOMEDIR already exists
if(!is_dir($home_dir . '/.' . $user_home_dir)) {
$this->mkdirpath($home_dir . '/.' . $user_home_dir, 0755, $username);
}
// Reconfigure the chroot home directory for the user
$cmd = 'usermod --home=? ? 2>/dev/null';
$this->exec_safe($cmd, $home_dir . '/.' . $user_home_dir, $username);
// Add the chroot user
$cmd = 'jk_jailuser -n -s ? -j ? ?';
$this->exec_safe($cmd, $shell, $home_dir, $username);
// We have to reconfigure the chroot home directory for the parent user
if($p_user !== null) {
$cmd = 'usermod --home=? ? 2>/dev/null';
$this->exec_safe($cmd, $home_dir . '/.' . $p_user_home_dir, $p_user);
}
return true;
}
public function create_jailkit_chroot($home_dir, $app_sections = array(), $options = array()) {
$app->log("create_jailkit_chroot: called for home_dir $home_dir with options: " . print_r($options, true), LOGLEVEL_DEBUG);
// Disallow operating on root directory
if(realpath($home_dir) == '/') {
$app->log("create_jailkit_chroot: invalid home_dir: $home_dir", LOGLEVEL_WARN);
return false;
}
$app->log("create_jailkit_chroot: jail directory does not exist: $home_dir", LOGLEVEL_WARN);
return false;
}
if(empty($app_sections)) {
return true;
} elseif(is_string($app_sections)) {
$app_sections = preg_split('/[\s,]+/', $app_sections);
}
if(! is_array($options)) {
$options = (is_string($options) ? preg_split('/[\s,]+/', $options) : array());
}
// Change ownership of the chroot directory to root
$this->chown($home_dir, 'root');
$this->chgrp($home_dir, 'root');
$program_args = '';
foreach ($options as $opt) {
switch ($opt) {
$program_args .= ' -f';
break;
}
}
# /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);
}
// Initialize the chroot into the specified directory with the specified applications
$cmd = 'jk_init' . $program_args;
$this->exec_safe($cmd, $home_dir);
if(!is_dir($home_dir . '/tmp')) {
$this->mkdirpath($home_dir . '/tmp', 0770);
} else {
$this->chmod($home_dir . '/tmp', 0770, true);
}
if(!is_dir($home_dir . '/var/run')) {
$this->mkdirpath($home_dir . '/var/run', 0755);
} else {
$this->chmod($home_dir . '/var/run', 0755, true);
}
if(!is_dir($home_dir . '/var/tmp')) {
$this->mkdirpath($home_dir . '/var/tmp', 0770);
} else {
$this->chmod($home_dir . '/var/tmp', 0770, true);
}
$this->chmod($home_dir . '/bin', 0755, true); // was chmod g-w $CHROOT_HOMEDIR/bin
return true;
}
public function create_jailkit_programs($home_dir, $programs = array(), $options = array()) {
$app->log("create_jailkit_programs: called for home_dir $home_dir with options: " . print_r($options, true), LOGLEVEL_DEBUG);
// Disallow operating on root directory
if(realpath($home_dir) == '/') {
$app->log("create_jailkit_programs: invalid home_dir: $home_dir", LOGLEVEL_WARN);
return false;
}
$app->log("create_jailkit_programs: jail directory does not exist: $home_dir", LOGLEVEL_WARN);
if(empty($programs)) {
return true;
} elseif(is_string($programs)) {
$programs = preg_split('/[\s,]+/', $programs);
if(! is_array($options)) {
$options = (is_string($options) ? preg_split('/[\s,]+/', $options) : array());
}
# prohibit ill-advised copying paths known to be sensitive/problematic
# (easy to bypass if needed, eg. use /./etc)
$blacklisted_paths_regex = array(
'@^/$@',
'@^/proc(/.*)?$@',
'@^/sys(/.*)?$@',
'@^/etc/?$@',
'@^/dev/?$@',
'@^/tmp/?$@',
'@^/run/?$@',
'@^/boot/?$@',
'@^/var(/?|/backups?/?)?$@',
$program_args = '';
foreach ($options as $opt) {
switch ($opt) {
$program_args .= ' -f';
break;
}
}
$program_args .= ' -j ?';
$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];
}
}
if (count($bad_paths) > 0) {
$app->log("Prohibited path not added to jail $home_dir: " . implode(", ", $bad_paths), LOGLEVEL_WARN);
} else {
$program_args .= ' ' . escapeshellarg($prog);
}
if (count($programs) > count($bad_paths)) {
$cmd = 'jk_cp' . $program_args;
$this->exec_safe($cmd, $home_dir);
}
return true;
}
public function update_jailkit_chroot($home_dir, $sections = array(), $programs = array(), $options = array()) {
$app->log("update_jailkit_chroot called for $home_dir with options ".print_r($options, true), LOGLEVEL_DEBUG);
// Disallow operating on root directory
if(realpath($home_dir) == '/') {
$app->log("update_jailkit_chroot: invalid home_dir: $home_dir", LOGLEVEL_WARN);
return false;
}
$app->log("update_jailkit_chroot: jail directory does not exist: $home_dir", LOGLEVEL_WARN);
$jailkit_directories = array(
'bin',
'dev',
'etc',
'lib',
'lib32',
'lib64',
'opt',
'sys',
'usr',
'var',
);
$jk_update_args = '';
$jk_cp_args = '';
$skips = '';
foreach ($options as $opt) {
switch ($opt) {
$jk_update_args .= ' -k';
$jk_cp_args .= ' -k';
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;
// Change ownership of the chroot directory to root
$this->chown($home_dir, 'root');
$this->chgrp($home_dir, 'root');
foreach ($jailkit_directories as $dir) {
$root_dir = '/'.$dir;
$jail_dir = rtrim($home_dir, '/') . '/'.$dir;
if (!is_dir($jail_dir)) {
continue;
}
// if directory exists in jail but not in root, remove it
if (is_dir($jail_dir) && !is_dir($root_dir)) {
$this->rmdir($jail_dir, true);
$this->remove_broken_symlinks($jail_dir, true);
$this->remove_recursive_symlinks($jail_dir, $home_dir, true);
if (!(in_array('hardlink', $opts) || in_array('allow_hardlink', $options))) {
$app->log("update_jailkit_chroot: searching for hardlinks in $jail_dir", LOGLEVEL_DEBUG);
$find_multiple_links = function ( $path ) use ( &$find_multiple_links ) {
$found = array();
$objects = array_diff(scandir($path), array('.', '..'));
foreach ($objects as $object) {
$ret = $find_multiple_links( "$path/$object" );
if (count($ret) > 0) {
$found = array_merge($found, $ret);
}
}
} elseif (is_file($path)) {
$stat = lstat($path);
if ($stat['nlink'] > 1) {
$found[$path] = $path;
}
}
return $found;
};
if (count($ret) > 0) {
$multiple_links = array_merge($multiple_links, $ret);
}
// remove broken symlinks a second time after hardlink cleanup
$this->remove_broken_symlinks($jail_dir, true);
}
else { $app->log("update_jailkit_chroot: NOT searching for hardlinks in $jail_dir, options: ".print_r($options, true), LOGLEVEL_DEBUG); }
foreach ($multiple_links as $file) {
$app->log("update_jailkit_chroot: removing hardlinked file: $file", LOGLEVEL_DEBUG);
unlink($file);
}
$cmd = 'jk_update --jail=?' . $jk_update_args . $skips;
$this->exec_safe($cmd, $home_dir);
$app->log('jk_update returned: '.print_r($this->_last_exec_out, true), LOGLEVEL_DEBUG);
# handle jk_update output
# jk_update sample output:
# skip /var/www/clients/client1/web1/opt/
# removing outdated file /var/www/clients/client15/web19/usr/bin/host
# removing deprecated directory /var/www/clients/client15/web19/usr/lib/x86_64-linux-gnu/libtasn1.so.6.5.3
# Creating symlink /var/www/clients/client15/web19/lib/x86_64-linux-gnu/libicudata.so.65 to libicudata.so.65.1
# Copying /usr/bin/mysql to /var/www/clients/client15/web19/usr/bin/mysql
if (preg_match('@^(skip|removing (outdated|deprecated)|Creating|Copying)@', $line)) {
# jk_update sample output:
# ERROR: failed to remove deprecated directory /var/www/clients/client1/web10/usr/lib/x86_64-linux-gnu/libGeoIP.so.1.6.9
if (preg_match('@^(?:[^ ]+ ){6}(?:.+)('.preg_quote($home_dir, '@').'.+)@', $line, $matches)) {
# remove deprecated files that jk_update failed to remove
if (is_file($matches[1]) || is_link($matches[1])) {
$app->log("update_jailkit_chroot: removing deprecated file which jk_update failed to remove: ".$matches[1], LOGLEVEL_DEBUG);
} elseif (is_dir($matches[1]) && !is_link($matches[1])) {
$app->log("update_jailkit_chroot: removing deprecated directory which jk_update failed to remove: ".$matches[1], LOGLEVEL_DEBUG);
} else {
# unhandled error
//$app->log("jk_update error for jail $home_dir: ".$matches[1], LOGLEVEL_DEBUG);
// at least for 3.2 beta, lets gather some of this info:
$app->log("jk_update error for jail $home_dir, feel free to pass to ispconfig developers: ".print_r( $matches, true), LOGLEVEL_DEBUG);
# any other ERROR or WARNING
# sample so far:
# ERROR: /usr/bin/nano does not exist
# WARNING: section [whatever] does not exist in /etc/jailkit/jk_init.ini
} elseif (preg_match('/^(WARNING|ERROR)/', $line, $matches)) {
$app->log("jk_update: $line", LOGLEVEL_DEBUG);
// reinstall jailkit sections and programs
if(!(empty($sections) && empty($programs))) {
$this->create_jailkit_chroot($home_dir, $sections, $opts);
$this->create_jailkit_programs($home_dir, $programs, $opts);
}
if(!is_dir($home_dir . '/tmp')) {
$this->mkdirpath($home_dir . '/tmp', 0770);
$this->chmod($home_dir . '/tmp', 0770, true);
}
if(!is_dir($home_dir . '/var/run')) {
$this->mkdirpath($home_dir . '/var/run', 0755);
} else {
$this->chmod($home_dir . '/var/run', 0755, true);
}
if(!is_dir($home_dir . '/var/tmp')) {
$this->mkdirpath($home_dir . '/var/tmp', 0770);
} else {
$this->chmod($home_dir . '/var/tmp', 0770, true);
}
// TODO: Set /usr/bin/php symlink to php version of the website.
//
// Currently server_php does not have a field for the cli path;
// we can guess/determing according to OS-specific conventions or add that field.
// Then symlink /usr/bin/php (or correct OS-specific path) to that location.
// search for any hardlinked files which are now missing
if (!(in_array('hardlink', $opts) || in_array('allow_hardlink', $options))) {
foreach ($multiple_links as $file) {
if (!is_file($file)) {
// strip $home_dir from $file
if (substr($file, 0, strlen(rtrim($home_dir, '/'))) == rtrim($home_dir, '/')) {
$file = substr($file, strlen(rtrim($home_dir, '/')));
}
if (is_file($file)) { // file exists in root
$app->log("update_jailkit_chroot: previously hardlinked file still missing, running jk_cp to restore: $file", LOGLEVEL_DEBUG);
$cmd = 'jk_cp -j ? ' . $jk_cp_args . ' ' . escapeshellarg($file);
$this->exec_safe($cmd, $home_dir);
} else {
// not necessarily an error
$app->log("update_jailkit_chroot: previously hardlinked file was not restored and is no longer present in system: $file", LOGLEVEL_DEBUG);
}
// Fix permissions of the root firectory
$this->chmod($home_dir . '/bin', 0755, true); // was chmod g-w $CHROOT_HOMEDIR/bin
// remove non-existent jails from /etc/jailkit/jk_socketd.ini
if (is_file('/etc/jailkit/jk_socketd.ini')) {
$rewrite = false;
$jk_socketd_ini = $app->ini_parser->parse_ini_file('/etc/jailkit/jk_socketd.ini');
foreach ($jk_socketd_ini as $log => $settings) {
if ($jail != $log && !is_dir($jail)) {
unset($jk_socketd_ini[$log]);
$rewrite=true;
}
}
if ($rewrite) {
$app->log('update_jailkit_chroot: writing /etc/jailkit/jk_socketd.ini', LOGLEVEL_DEBUG);
$app->ini_parse->write_ini_file($jk_socketd_ini, '/etc/jailkit/jk_socketd.ini');
}
}
return true;
}
public function delete_jailkit_chroot($home_dir, $options = array()) {
$app->log("delete_jailkit_chroot called for $home_dir with options ".print_r($options, true), LOGLEVEL_DEBUG);
// Disallow operating on root directory
if(realpath($home_dir) == '/') {
$app->log("delete_jailkit_chroot: invalid home_dir: $home_dir", LOGLEVEL_WARN);
return false;
}
$app->log("delete_jailkit_chroot: jail directory does not exist: $home_dir", LOGLEVEL_DEBUG);
return false;
}
$jailkit_directories = array(
'bin',
'dev',
'etc',
'lib',
'lib32',
'lib64',
'opt',
'sys',
'usr',
'var',
'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;
if (is_link($jail_dir)) {
unlink($jail_dir);
$removed .= ' /'.$dir;
} elseif (is_dir($jail_dir)) {
$this->rmdir($jail_dir, true);
$removed .= ' /'.$dir;
}
}
$app->log("delete_jailkit_chroot: removed from jail $home_dir: $removed", LOGLEVEL_DEBUG);
$home = rtrim($home_dir, '/') . '/home';
@rmdir($home); # ok to fail if non-empty
$private = rtrim($home_dir, '/') . '/private';
if (is_dir($home) && is_dir($private)) {
$archive = $private.'/home-'.date('c');
rename($home, $archive);
}
// remove $home_dir from /etc/jailkit/jk_socketd.ini
if (is_file('/etc/jailkit/jk_socketd.ini')) {
$jk_socketd_ini = $app->ini_parser->parse_ini_file('/etc/jailkit/jk_socketd.ini');
$log = $home . '/dev/log';
if (isset($jk_socketd_ini[$log])) {
unset($jk_socketd_ini[$log]);
$app->log('delete_jailkit_chroot: writing /etc/jailkit/jk_socketd.ini', LOGLEVEL_DEBUG);
$app->ini_parse->write_ini_file($jk_socketd_ini, '/etc/jailkit/jk_socketd.ini');
}
}
Marius Burkard
committed
public function pipe_exec($cmd, $stdin, &$retval = null, &$stderr = null) {
$descriptors = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
);
Marius Burkard
committed
$result = '';
$pipes = null;
$proc = proc_open($cmd, $descriptors, $pipes);
if(is_resource($proc)) {
fwrite($pipes[0], $stdin);
fclose($pipes[0]);
Marius Burkard
committed
$result = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
Marius Burkard
committed
$retval = proc_close($proc);
Marius Burkard
committed
return $result;
} else {
return false;
}
}
private function get_sudo_command($cmd, $run_as_user) {
return 'sudo -u ' . escapeshellarg($run_as_user) . ' sh -c ' . escapeshellarg($cmd);
}
private function check_run_as_user($username) {
if(preg_match('/^[a-zA-Z0-9_\-]+$/', $username)) {
return true;
} else{
return false;
}
}