Newer
Older
$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;
// upstart
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;
}
Florian Schaal
committed
// systemd
if(is_executable('/bin/systemd') || is_executable('/usr/bin/systemctl')){
Florian Schaal
committed
if ($check_service) {
$this->exec_safe("systemctl is-enabled ? 2>&1", $servicename);
$ret_val = $this->last_exec_retcode();
Florian Schaal
committed
}
if ($ret_val == 0 || !$check_service) {
return 'systemctl '.$action.' '.$servicename.'.service';
}
Florian Schaal
committed
// sysvinit
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);
Florian Schaal
committed
if($check_service && is_executable($init_script_directory.'/'.$servicename)) {
return $init_script_directory.'/'.$servicename.' '.$action;
}
if (!$check_service) {
return $init_script_directory.'/'.$servicename.' '.$action;
}
Florian Schaal
committed
function getinitcommand($servicename, $action, $init_script_directory = '', $check_service=false) {
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);
}
}
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;
}
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
//* 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;
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) {
// 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()) {
if(!is_dir($home_dir)) {
$app->log("create_jailkit_chroot: jail directory does not exist: $home_dir", LOGLEVEL_WARN);
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
return false;
}
if(empty($app_sections)) {
return true;
} elseif(is_string($app_sections)) {
$app_sections = preg_split('/[\s,]+/', $app_sections);
}
// 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) {
case '-k|hardlink':
$program_args .= ' -k';
break;
case '-f|force':
$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) {
# 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);
// Create the temp directory
if(!is_dir($home_dir . '/tmp')) {
$this->mkdirpath($home_dir . '/tmp', 0770);
} else {
$this->chmod($home_dir . '/tmp', 0770, true);
}
// Fix permissions of the root firectory
$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()) {
if(!is_dir($home_dir)) {
$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);
# 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/?$|',
$program_args = '';
foreach ($options as $opt) {
switch ($opt) {
case '-k|hardlink':
$program_args .= ' -k';
break;
case '-f|force':
$program_args .= ' -f';
break;
}
}
$program_args .= ' -j ?';
$bad_paths = array();
foreach($programs as $prog) {
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()) {
if(!is_dir($home_dir)) {
$app->log("update_jailkit_chroot: jail directory does not exist: $home_dir", LOGLEVEL_WARN);
foreach ($options as $opt) {
switch ($opt) {
case '-k|hardlink':
$opts[] = 'hardlink';
break;
case '-f|force':
$opts[] = 'force';
break;
// Change ownership of the chroot directory to root
$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;
$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);
continue;
}
// remove dangling symlinks
$app->log("TODO: search for and remove dangling symlinks", LOGLEVEL_DEBUG);
if (!in_array($opts, 'hardlink') && !in_array($options, 'allow_hardlink')) {
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
$find_multiple_links = function ( $path ) use ( &$find_multiple_links ) {
$found = array();
if (is_dir($path)) {
$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);
}
}
} else {
$stat = stat($path);
if ($stat['nlink'] > 1) {
$found[$path] = $path;
}
}
return $found;
};
$ret = $find_multiple_links( $jail_dir );
if (count($ret) > 0) {
$multiple_links = array_merge($multiple_links, $ret);
}
}
}
$cmd = 'jk_update --jail='.escapeshellarg($home_dir) . $skips;
exec($cmd, $out, $ret);
foreach ($out as $line) {
if (substr( $line, 0, 4 ) === "skip")) {
continue;
}
if (preg_match('|^(? [^ ]+){6}(.+)$'.preg_quote($home_dir, '|').'|', $line, $matches)) {
# remove deprecated files that jk_update failed to remove
if (is_file($matches[1])) {
$app->log("removing deprecated file which jk_update failed to remove: ".$matches[1], LOGLEVEL_DEBUG);
unlink($matches[1]);
} elseif (is_dir($matches[1])) {
$app->log("removing deprecated directory which jk_update failed to remove: ".$matches[1], LOGLEVEL_DEBUG);
$this->rmdir($matches[1], true);
}
# unhandled error
$app->log("jk_update error for jail $home_dir: ".$matches[1], 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);
}
// Create the temp directory
if(!is_dir($home_dir . '/tmp')) {
$this->mkdirpath($home_dir . '/tmp', 0770);
$this->chmod($home_dir . '/tmp', 0770, true);
}
// search for any hardlinked files which are now missing
if (!in_array($opts, 'hardlink') && !in_array($options, 'allow_hardlink')) {
foreach ($multiple_links as $file) {
if (!is_file($file)) {
// strip $home_dir from $file
if (substr($file, 0, strlen(rtrim($home_dir, '/'))) == strlen(rtrim($home_dir, '/'))) {
$file = substr($file, strlen(rtrim($home_dir, '/')));
}
if (is_file($file)) { // file exists in root
$app->log("file with multiple links still missing, running jk_cp to restore: $file", LOGLEVEL_DEBUG);
$cmd = 'jk_cp -j ? ' . escapeshellarg($file);
$this->exec_safe($cmd, $home_dir);
} else {
// not necessarily an error
$app->log("previously hardlinked file was not found to restore: $file", LOGLEVEL_DEBUG);
}
}
}
}
// Fix permissions of the root firectory
$this->chmod($home_dir . '/bin', 0755, true); // was chmod g-w $CHROOT_HOMEDIR/bin
return true;
}
public function delete_jailkit_chroot($home_dir) {
$app->log("delete_jailkit_chroot: jail directory does not exist: $home_dir", LOGLEVEL_DEBUG);
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
return false;
}
$jailkit_directories = array(
'bin',
'dev',
'etc',
'lib',
'lib32',
'lib64',
'opt',
'sys',
'usr',
'var',
);
$removed = '';
foreach ($jailkit_directories as $dir) {
$jail_dir = rtrim($home_dir, '/') . '/'.$dir;
if (is_dir($jail_dir)) {
$this->rmdir($jail_dir, true);
$removed .= ' /'.$dir;
}
}
$app->log("delete_jailkit_chroot: removed from jail $home_dir: $removed", LOGLEVEL_DEBUG);
// handle etc and home special
$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);
}
return true;
}
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;
}
}