From 9edea9976bd605071e0694a90d704266c0b7e0f9 Mon Sep 17 00:00:00 2001
From: Till Brehm <tbrehm@ispconfig.org>
Date: Thu, 14 Aug 2014 11:30:03 -0400
Subject: [PATCH] - Added warning in the interface when a path for a shelluser is set that is outside of the website docroot. - Added security settings feature to allow the root user of a server to control most aspects of whet the admin user of the controlpanel is allowed to do in system settings. This is especially useful for managed severs where the ispconfig admin user and the root user of the server are different persons.

---
 server/plugins-available/apache2_plugin.inc.php |   79 +++++++++++++++++++++++++++------------
 1 files changed, 55 insertions(+), 24 deletions(-)

diff --git a/server/plugins-available/apache2_plugin.inc.php b/server/plugins-available/apache2_plugin.inc.php
index 654c87a..a533957 100644
--- a/server/plugins-available/apache2_plugin.inc.php
+++ b/server/plugins-available/apache2_plugin.inc.php
@@ -344,8 +344,9 @@
 			if($data['new']['type'] == 'vhost' || $data['new']['type'] == 'vhostsubdomain') $app->log('document_root not set', LOGLEVEL_WARN);
 			return 0;
 		}
-		if($data['new']['system_user'] == 'root' or $data['new']['system_group'] == 'root') {
-			$app->log('Websites cannot be owned by the root user or group.', LOGLEVEL_WARN);
+		if($app->system->is_allowed_user($data['new']['system_user'], $app->system->is_user($data['new']['system_user']), true) == false
+			|| $app->system->is_allowed_group($data['new']['system_group'], $app->system->is_group($data['new']['system_group']), true) == false) {
+			$app->log('Websites cannot be owned by the root user or group. User: '.$data['new']['system_user'].' Group: '.$data['new']['system_group'], LOGLEVEL_WARN);
 			return 0;
 		}
 		if(trim($data['new']['domain']) == '') {
@@ -355,13 +356,26 @@
 
 		$web_folder = 'web';
 		$log_folder = 'log';
+		$old_web_folder = 'web';
+		$old_log_folder = 'log';
 		if($data['new']['type'] == 'vhostsubdomain') {
+			// new one
 			$tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($data['new']['parent_domain_id']));
 			$subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $data['new']['domain']);
 			if($subdomain_host == '') $subdomain_host = 'web'.$data['new']['domain_id'];
 			$web_folder = $data['new']['web_folder'];
 			$log_folder .= '/' . $subdomain_host;
 			unset($tmp);
+			
+			if(isset($data['old']['parent_domain_id'])) {
+				// old one
+				$tmp = $app->db->queryOneRecord('SELECT `domain` FROM web_domain WHERE domain_id = '.intval($data['old']['parent_domain_id']));
+				$subdomain_host = preg_replace('/^(.*)\.' . preg_quote($tmp['domain'], '/') . '$/', '$1', $data['old']['domain']);
+				if($subdomain_host == '') $subdomain_host = 'web'.$data['old']['domain_id'];
+				$old_web_folder = $data['old']['web_folder'];
+				$old_log_folder .= '/' . $subdomain_host;
+				unset($tmp);
+			}
 		}
 
 		// Create group and user, if not exist
@@ -448,6 +462,9 @@
 					$app->system->rename($data['new']['document_root'], $data['new']['document_root'].'_bak_'.date('Y_m_d_H_i_s'));
 					$app->log('Renaming existing directory in new docroot location. mv '.$data['new']['document_root'].' '.$data['new']['document_root'].'_bak_'.date('Y_m_d_H_i_s'), LOGLEVEL_DEBUG);
 				}
+				
+				//* Unmount the old log directory bfore we move the log dir
+				exec('umount '.escapeshellcmd($old_dir.'/log'));
 
 				//* Create new base directory, if it does not exist yet
 				if(!is_dir($new_dir)) $app->system->mkdirpath($new_dir);
@@ -473,10 +490,14 @@
 			if($apache_chrooted) $this->_exec('chroot '.escapeshellcmd($web_config['website_basedir']).' '.$command);
 
 			//* Change the log mount
-			$fstab_line = '/var/log/ispconfig/httpd/'.$data['old']['domain'].' '.$data['old']['document_root'].'/'.$log_folder.'    none    bind';
+			$fstab_line = '/var/log/ispconfig/httpd/'.$data['old']['domain'].' '.$data['old']['document_root'].'/'.$old_log_folder.'    none    bind';
 			$app->system->removeLine('/etc/fstab', $fstab_line);
-			$fstab_line = '/var/log/ispconfig/httpd/'.$data['new']['domain'].' '.$data['new']['document_root'].'/'.$log_folder.'    none    bind,nobootwait    0 0';
+			$fstab_line = '/var/log/ispconfig/httpd/'.$data['old']['domain'].' '.$data['old']['document_root'].'/'.$old_log_folder.'    none    bind,nobootwait';
+			$app->system->removeLine('/etc/fstab', $fstab_line);
+			$fstab_line = '/var/log/ispconfig/httpd/'.$data['new']['domain'].' '.$data['new']['document_root'].'/'.$log_folder.'    none    bind,nobootwait,_netdev    0 0';
 			$app->system->replaceLine('/etc/fstab', $fstab_line, $fstab_line, 1, 1);
+			
+			exec('mount --bind '.escapeshellarg('/var/log/ispconfig/httpd/'.$data['new']['domain']).' '.escapeshellarg($data['new']['document_root'].'/'.$log_folder));
 
 		}
 
@@ -505,14 +526,14 @@
 		// Remove the symlink for the site, if site is renamed
 		if($this->action == 'update' && $data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain']) {
 			if(is_dir('/var/log/ispconfig/httpd/'.$data['old']['domain'])) exec('rm -rf /var/log/ispconfig/httpd/'.$data['old']['domain']);
-			if(is_link($data['old']['document_root'].'/'.$log_folder)) $app->system->unlink($data['old']['document_root'].'/'.$log_folder);
+			if(is_link($data['old']['document_root'].'/'.$old_log_folder)) $app->system->unlink($data['old']['document_root'].'/'.$old_log_folder);
 
 			//* remove old log mount
-			$fstab_line = '/var/log/ispconfig/httpd/'.$data['old']['domain'].' '.$data['old']['document_root'].'/'.$log_folder.'    none    bind';
+			$fstab_line = '/var/log/ispconfig/httpd/'.$data['old']['domain'].' '.$data['old']['document_root'].'/'.$old_log_folder.'    none    bind';
 			$app->system->removeLine('/etc/fstab', $fstab_line);
 
 			//* Unmount log directory
-			exec('umount '.escapeshellarg($data['old']['document_root'].'/'.$log_folder));
+			exec('umount '.escapeshellarg($data['old']['document_root'].'/'.$old_log_folder));
 		}
 
 		//* Create the log dir if nescessary and mount it
@@ -525,7 +546,7 @@
 			$app->system->chmod($data['new']['document_root'].'/'.$log_folder, 0755);
 			exec('mount --bind '.escapeshellarg('/var/log/ispconfig/httpd/'.$data['new']['domain']).' '.escapeshellarg($data['new']['document_root'].'/'.$log_folder));
 			//* add mountpoint to fstab
-			$fstab_line = '/var/log/ispconfig/httpd/'.$data['new']['domain'].' '.$data['new']['document_root'].'/'.$log_folder.'    none    bind,nobootwait    0 0';
+			$fstab_line = '/var/log/ispconfig/httpd/'.$data['new']['domain'].' '.$data['new']['document_root'].'/'.$log_folder.'    none    bind,nobootwait,_netdev    0 0';
 			$app->system->replaceLine('/etc/fstab', $fstab_line, $fstab_line, 1, 1);
 		}
 
@@ -695,7 +716,7 @@
 				$app->system->chmod($data['new']['document_root'].'/ssl', 0755);
 
 				// make tmp directory writable for Apache and the website users
-				$app->system->chmod($data['new']['document_root'].'/tmp', 0777);
+				$app->system->chmod($data['new']['document_root'].'/tmp', 0770);
 
 				// Set Log directory to 755 to make the logs accessible by the FTP user
 				if(realpath($data['new']['document_root'].'/'.$log_folder . '/error.log') == '/var/log/ispconfig/httpd/'.$data['new']['domain'].'/error.log') {
@@ -755,7 +776,7 @@
 				$app->system->chmod($data['new']['document_root'].'/cgi-bin', 0755);
 
 				// make temp directory writable for Apache and the website users
-				$app->system->chmod($data['new']['document_root'].'/tmp', 0777);
+				$app->system->chmod($data['new']['document_root'].'/tmp', 0770);
 
 				// Set Log directory to 755 to make the logs accessible by the FTP user
 				if(realpath($data['new']['document_root'].'/'.$log_folder . '/error.log') == '/var/log/ispconfig/httpd/'.$data['new']['domain'].'/error.log') {
@@ -892,6 +913,8 @@
 		// Make sure we only have Unix linebreaks
 		$vhost_data['apache_directives'] = str_replace("\r\n", "\n", $vhost_data['apache_directives']);
 		$vhost_data['apache_directives'] = str_replace("\r", "\n", $vhost_data['apache_directives']);
+		$trans = array('{DOCROOT}' => $vhost_data['web_document_root_www']);
+		$vhost_data['apache_directives'] = strtr($vhost_data['apache_directives'], $trans);
 
 		// Check if a SSL cert exists
 		$ssl_dir = $data['new']['document_root'].'/ssl';
@@ -1165,6 +1188,7 @@
 				$fcgi_tpl->setVar('php_fcgi_bin', escapeshellcmd($custom_fastcgi_php_executable));
 			}
 			$fcgi_tpl->setVar('security_level', intval($web_config['security_level']));
+			$fcgi_tpl->setVar('domain', escapeshellcmd($data['new']['domain']));
 
 			$php_open_basedir = ($data['new']['php_open_basedir'] == '')?$data['new']['document_root']:$data['new']['php_open_basedir'];
 			$fcgi_tpl->setVar('open_basedir', escapeshellcmd($php_open_basedir));
@@ -1187,18 +1211,15 @@
 
 		} else {
 			//remove the php fastgi starter script if available
+			$fastcgi_starter_script = $fastcgi_config['fastcgi_starter_script'].($data['old']['type'] == 'vhostsubdomain' ? '_web' . $data['old']['domain_id'] : '');
 			if ($data['old']['php'] == 'fast-cgi') {
 				$fastcgi_starter_path = str_replace('[system_user]', $data['old']['system_user'], $fastcgi_config['fastcgi_starter_path']);
 				$fastcgi_starter_path = str_replace('[client_id]', $client_id, $fastcgi_starter_path);
 				if($data['old']['type'] == 'vhost') {
-					if (is_dir($fastcgi_starter_path)) {
-						exec('rm -rf '.$fastcgi_starter_path);
-					}
+					if(is_file($fastcgi_starter_script)) @unlink($fastcgi_starter_script);
+					if (is_dir($fastcgi_starter_path)) @rmdir($fastcgi_starter_path);
 				} else {
-					$fcgi_starter_script = $fastcgi_starter_path.$fastcgi_config['fastcgi_starter_script'].'_web' . $data['old']['domain_id'];
-					if (file_exists($fcgi_starter_script)) {
-						exec('rm -f '.$fcgi_starter_script);
-					}
+					if(is_file($fastcgi_starter_script)) @unlink($fastcgi_starter_script);
 				}
 			}
 		}
@@ -1615,7 +1636,6 @@
 
 		//* Unset action to clean it for next processed vhost.
 		$this->action = '';
-
 	}
 
 	function delete($event_name, $data) {
@@ -1992,7 +2012,7 @@
 		//* Create empty .htpasswd file, if it does not exist
 		if(!is_file($folder_path.'.htpasswd')) {
 			$app->system->touch($folder_path.'.htpasswd');
-			$app->system->chmod($folder_path.'.htpasswd', 0750);
+			$app->system->chmod($folder_path.'.htpasswd', 0751);
 			$app->system->chown($folder_path.'.htpasswd', $website['system_user']);
 			$app->system->chgrp($folder_path.'.htpasswd', $website['system_group']);
 			$app->log('Created file '.$folder_path.'.htpasswd', LOGLEVEL_DEBUG);
@@ -2046,7 +2066,7 @@
 		unset($old_content);
 
 		$app->system->file_put_contents($folder_path.'.htaccess', $ht_file);
-		$app->system->chmod($folder_path.'.htaccess', 0750);
+		$app->system->chmod($folder_path.'.htaccess', 0751);
 		$app->system->chown($folder_path.'.htaccess', $website['system_user']);
 		$app->system->chgrp($folder_path.'.htaccess', $website['system_group']);
 		$app->log('Created/modified file '.$folder_path.'.htaccess', LOGLEVEL_DEBUG);
@@ -2208,10 +2228,19 @@
 			}
 
 			$app->system->file_put_contents($new_folder_path.'.htaccess', $ht_file);
-			$app->system->chmod($new_folder_path.'.htaccess', 0750);
+			$app->system->chmod($new_folder_path.'.htaccess', 0751);
 			$app->system->chown($new_folder_path.'.htaccess', $website['system_user']);
 			$app->system->chgrp($new_folder_path.'.htaccess', $website['system_group']);
 			$app->log('Created/modified file '.$new_folder_path.'.htaccess', LOGLEVEL_DEBUG);
+			
+			//* Create empty .htpasswd file, if it does not exist
+			if(!is_file($folder_path.'.htpasswd')) {
+				$app->system->touch($new_folder_path.'.htpasswd');
+				$app->system->chmod($new_folder_path.'.htpasswd', 0751);
+				$app->system->chown($new_folder_path.'.htpasswd', $website['system_user']);
+				$app->system->chgrp($new_folder_path.'.htpasswd', $website['system_group']);
+				$app->log('Created file '.$new_folder_path.'.htpasswd', LOGLEVEL_DEBUG);
+			}
 		}
 
 		//* Remove .htaccess file
@@ -2628,6 +2657,7 @@
 
 		$fpm_socket = $socket_dir.$pool_name.'.sock';
 		$tpl->setVar('fpm_socket', $fpm_socket);
+		$tpl->setVar('fpm_listen_mode', '0660');
 
 		$tpl->setVar('fpm_pool', $pool_name);
 		$tpl->setVar('fpm_port', $web_config['php_fpm_start_port'] + $data['new']['domain_id'] - 1);
@@ -2642,6 +2672,7 @@
 		$tpl->setVar('pm_max_requests', $data['new']['pm_max_requests']);
 		$tpl->setVar('document_root', $data['new']['document_root']);
 		$tpl->setVar('security_level', $web_config['security_level']);
+		$tpl->setVar('domain', $data['new']['domain']);
 		$php_open_basedir = ($data['new']['php_open_basedir'] == '')?escapeshellcmd($data['new']['document_root']):escapeshellcmd($data['new']['php_open_basedir']);
 		$tpl->setVar('php_open_basedir', $php_open_basedir);
 		if($php_open_basedir != ''){
@@ -2664,9 +2695,9 @@
 					if(substr($ini_setting, 0, 1) == ';') continue;
 					if(substr($ini_setting, 0, 1) == '#') continue;
 					if(substr($ini_setting, 0, 2) == '//') continue;
-					list($key, $value) = explode('=', $ini_setting);
-					if($value){
-						$value = trim($value);
+					list($key, $value) = explode('=', $ini_setting, 2);
+					$value = trim($value);
+					if($value != ''){
 						$key = trim($key);
 						switch (strtolower($value)) {
 						case '0':

--
Gitblit v1.9.1