Skip to content

Commit d87f760

Browse files
committed
- Added new web folder named private to web folder layout. The folder is intended to store data that shall not be visible in the web directory, it is owned by the user of the web.
- Changed ownership of web root directory to root user in all security modes to prevent symlink attacks. - Apache log files are now owned by user root. - Improved functions in system library.
1 parent ff6a683 commit d87f760

File tree

2 files changed

+48
-56
lines changed

2 files changed

+48
-56
lines changed

server/lib/classes/system.inc.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,12 @@ function chown($file, $owner, $allow_symlink = false){
617617
return false;
618618
}
619619
if(file_exists($file)) {
620-
return chown($file, $owner);
620+
if(@chown($file, $owner)) {
621+
return true;
622+
} else {
623+
$app->log("chown failed: $file : $owner",LOGLEVEL_DEBUG);
624+
return false;
625+
}
621626
}
622627
}
623628

@@ -628,7 +633,12 @@ function chgrp($file, $group = '', $allow_symlink = false){
628633
return false;
629634
}
630635
if(file_exists($file)) {
631-
return chgrp($file, $group);
636+
if(@chgrp($file, $group)) {
637+
return true;
638+
} else {
639+
$app->log("chgrp failed: $file : $group",LOGLEVEL_DEBUG);
640+
return false;
641+
}
632642
}
633643
}
634644

@@ -639,7 +649,12 @@ function chmod($file, $mode, $allow_symlink = false) {
639649
$app->log("Action aborted, file is a symlink: $file",LOGLEVEL_WARN);
640650
return false;
641651
}
642-
return chmod($file, $mode);
652+
if(@chmod($file, $mode)) {
653+
return true;
654+
} else {
655+
$app->log("chmod failed: $file : $mode",LOGLEVEL_DEBUG);
656+
return false;
657+
}
643658
}
644659

645660
function file_put_contents($filename, $data, $allow_symlink = false) {
@@ -676,7 +691,12 @@ function mkdir($dirname, $allow_symlink = false) {
676691
$app->log("Action aborted, file is a symlink: $dirname",LOGLEVEL_WARN);
677692
return false;
678693
}
679-
return mkdir($dirname);
694+
if(@mkdir($dirname)) {
695+
return true;
696+
} else {
697+
$app->log("mkdir failed: $dirname",LOGLEVEL_DEBUG);
698+
return false;
699+
}
680700
}
681701

682702
function unlink($file) {

server/plugins-available/apache2_plugin.inc.php

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ function update($event_name,$data) {
433433
//print_r($data);
434434

435435
// Check if the directories are there and create them if necessary.
436+
$app->system->web_folder_protection($data['new']['document_root'],false);
437+
436438
if(!is_dir($data['new']['document_root'].'/web')) $app->system->mkdirpath($data['new']['document_root'].'/web');
437439
if(!is_dir($data['new']['document_root'].'/web/error') and $data['new']['errordocs']) $app->system->mkdirpath($data['new']['document_root'].'/web/error');
438440
//if(!is_dir($data['new']['document_root'].'/log')) exec('mkdir -p '.$data['new']['document_root'].'/log');
@@ -441,6 +443,16 @@ function update($event_name,$data) {
441443
if(!is_dir($data['new']['document_root'].'/tmp')) $app->system->mkdirpath($data['new']['document_root'].'/tmp');
442444
if(!is_dir($data['new']['document_root'].'/webdav')) $app->system->mkdirpath($data['new']['document_root'].'/webdav');
443445

446+
//* Create the new private directory
447+
if(!is_dir($data['new']['document_root'].'/private')) {
448+
$app->system->mkdirpath($data['new']['document_root'].'/private');
449+
$app->system->chmod($data['new']['document_root'].'/private',0710);
450+
$app->system->chown($data['new']['document_root'].'/private',$username);
451+
$app->system->chgrp($data['new']['document_root'].'/private',$groupname);
452+
}
453+
454+
$app->system->web_folder_protection($data['new']['document_root'],true);
455+
444456
// Remove the symlink for the site, if site is renamed
445457
if($this->action == 'update' && $data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain']) {
446458
if(is_dir('/var/log/ispconfig/httpd/'.$data['old']['domain'])) exec('rm -rf /var/log/ispconfig/httpd/'.$data['old']['domain']);
@@ -459,21 +471,6 @@ function update($event_name,$data) {
459471

460472
$app->log('Creating symlink: ln -s /var/log/ispconfig/httpd/'.$data['new']['domain'].' '.$data['new']['document_root'].'/log',LOGLEVEL_DEBUG);
461473
}
462-
/*
463-
// Create the symlink for the logfiles
464-
// This does not work as vlogger cannot log trough symlinks.
465-
if($this->action == 'update' && $data['old']['domain'] != '' && $data['new']['domain'] != $data['old']['domain']) {
466-
if(is_dir($data['old']['document_root'].'/log')) exec('rm -rf '.$data['old']['document_root'].'/log');
467-
if(is_link('/var/log/ispconfig/httpd/'.$data['old']['domain'])) $app->system->unlink('/var/log/ispconfig/httpd/'.$data['old']['domain']);
468-
}
469-
470-
// Create the symlink for the logfiles
471-
if(!is_dir($data['new']['document_root'].'/log')) exec('mkdir -p '.$data['new']['document_root'].'/log');
472-
if(!is_link('/var/log/ispconfig/httpd/'.$data['new']['domain'])) {
473-
exec('ln -s '.$data['new']['document_root'].'/log /var/log/ispconfig/httpd/'.$data['new']['domain']);
474-
$app->log('Creating symlink: ln -s '.$data['new']['document_root'].'/log /var/log/ispconfig/httpd/'.$data['new']['domain'],LOGLEVEL_DEBUG);
475-
}
476-
*/
477474

478475
// Get the client ID
479476
$client = $app->dbmaster->queryOneRecord('SELECT client_id FROM sys_group WHERE sys_group.groupid = '.intval($data['new']['sys_groupid']));
@@ -624,19 +621,16 @@ function update($event_name,$data) {
624621

625622
$app->system->web_folder_protection($data['new']['document_root'],false);
626623

624+
//* Check if we have the new private folder and create it if nescessary
625+
if(!is_dir($data['new']['document_root'].'/private')) $app->system->mkdir($data['new']['document_root'].'/private');
626+
627627
if($web_config['security_level'] == 20) {
628628

629-
$app->system->chmod($data['new']['document_root'],0751);
629+
$app->system->chmod($data['new']['document_root'],0755);
630630
$app->system->chmod($data['new']['document_root'].'/web',0710);
631631
$app->system->chmod($data['new']['document_root'].'/webdav',0710);
632+
$app->system->chmod($data['new']['document_root'].'/private',0710);
632633
$app->system->chmod($data['new']['document_root'].'/ssl',0755);
633-
634-
/*
635-
$this->_exec('chmod 751 '.escapeshellcmd($data['new']['document_root']));
636-
$this->_exec('chmod 751 '.escapeshellcmd($data['new']['document_root']).'/*');
637-
$this->_exec('chmod 710 '.escapeshellcmd($data['new']['document_root'].'/web'));
638-
$this->_exec('chmod 755 '.escapeshellcmd($data['new']['document_root'].'/ssl'));
639-
*/
640634

641635
// make tmp directory writable for Apache and the website users
642636
$app->system->chmod($data['new']['document_root'].'/tmp',0777);
@@ -669,16 +663,8 @@ function update($event_name,$data) {
669663
$app->system->add_user_to_group($groupname, escapeshellcmd($web_config['user']));
670664

671665
//* Chown all default directories
672-
/*
673-
$this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root']));
674-
$this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/cgi-bin'));
675-
$this->_exec('chown root:'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/log'));
676-
$this->_exec('chown root:root '.escapeshellcmd($data['new']['document_root'].'/ssl'));
677-
$this->_exec('chown '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/tmp'));
678-
$this->_exec('chown -R '.$username.':'.$groupname.' '.escapeshellcmd($data['new']['document_root'].'/web'));
679-
*/
680-
$app->system->chown($data['new']['document_root'],$username);
681-
$app->system->chgrp($data['new']['document_root'],$groupname);
666+
$app->system->chown($data['new']['document_root'],'root');
667+
$app->system->chgrp($data['new']['document_root'],'root');
682668
$app->system->chown($data['new']['document_root'].'/cgi-bin',$username);
683669
$app->system->chgrp($data['new']['document_root'].'/cgi-bin',$groupname);
684670
if(realpath($data['new']['document_root'].'/log') == '/var/log/ispconfig/httpd/'.$data['new']['domain'].'/error.log') {
@@ -697,22 +683,8 @@ function update($event_name,$data) {
697683
$app->system->chgrp($data['new']['document_root'].'/web/stats',$groupname);
698684
$app->system->chown($data['new']['document_root'].'/webdav',$username);
699685
$app->system->chgrp($data['new']['document_root'].'/webdav',$groupname);
700-
701-
702-
/*
703-
* Workaround for jailkit: If jailkit is enabled for the site, the
704-
* website root has to be owned by the root user and we have to chmod it to 755 then
705-
*/
706-
707-
//* Check if there is a jailkit user or cronjob for this site
708-
$tmp = $app->db->queryOneRecord('SELECT count(shell_user_id) as number FROM shell_user WHERE parent_domain_id = '.$data['new']['domain_id']." AND chroot = 'jailkit'");
709-
$tmp2 = $app->db->queryOneRecord('SELECT count(id) as number FROM cron WHERE parent_domain_id = '.$data['new']['domain_id']." AND `type` = 'chrooted'");
710-
if($tmp['number'] > 0 || $tmp2['number'] > 0) {
711-
$app->system->chmod($data['new']['document_root'],0755);
712-
$app->system->chown($data['new']['document_root'],'root');
713-
$app->system->chgrp($data['new']['document_root'],'root');
714-
}
715-
unset($tmp);
686+
$app->system->chown($data['new']['document_root'].'/private',$username);
687+
$app->system->chgrp($data['new']['document_root'].'/private',$groupname);
716688

717689
// If the security Level is set to medium
718690
} else {
@@ -755,10 +727,10 @@ function update($event_name,$data) {
755727
//* Protect web folders
756728
$app->system->web_folder_protection($data['new']['document_root'],true);
757729

758-
// Change the ownership of the error log to the owner of the website
730+
// Change the ownership of the error log to the root user
759731
if(!@is_file('/var/log/ispconfig/httpd/'.$data['new']['domain'].'/error.log')) exec('touch '.escapeshellcmd('/var/log/ispconfig/httpd/'.$data['new']['domain'].'/error.log'));
760-
$app->system->chown('/var/log/ispconfig/httpd/'.$data['new']['domain'].'/error.log',$username);
761-
$app->system->chgrp('/var/log/ispconfig/httpd/'.$data['new']['domain'].'/error.log',$groupname);
732+
$app->system->chown('/var/log/ispconfig/httpd/'.$data['new']['domain'].'/error.log','root');
733+
$app->system->chgrp('/var/log/ispconfig/httpd/'.$data['new']['domain'].'/error.log','root');
762734

763735

764736
//* Write the custom php.ini file, if custom_php_ini fieled is not empty

0 commit comments

Comments
 (0)