@@ -610,18 +610,89 @@ function get_user_attributes($user){
610610 * Edit the owner of a file
611611 *
612612 */
613- function chown ($ file , $ owner , $ group = '' ){
614- $ owner_change = @chown ($ file , $ owner );
615- if ($ group != '' ){
616- $ group_change = @chgrp ($ file , $ group );
617- } else {
618- $ group_change = 1 ;
613+ function chown ($ file , $ owner , $ allow_symlink = false ){
614+ if ($ allow_symlink == false && $ this ->checkpath ($ file ) == false ) {
615+ $ app ->log ("Action aborted, file is a symlink: $ file " ,LOGLEVEL_WARN );
616+ return false ;
619617 }
620- if ($ owner_change && $ group_change ){
621- return true ;
622- } else {
623- return false ;
618+ return chown ($ file , $ owner );
619+ }
620+
621+ function chgrp ($ file , $ group = '' , $ allow_symlink = false ){
622+ if ($ allow_symlink == false && $ this ->checkpath ($ file ) == false ) {
623+ $ app ->log ("Action aborted, file is a symlink: $ file " ,LOGLEVEL_WARN );
624+ return false ;
624625 }
626+ return chgrp ($ file , $ group );
627+ }
628+
629+ //* Change the mode of a file
630+ function chmod ($ file , $ mode , $ allow_symlink = false ) {
631+ if ($ allow_symlink == false && $ this ->checkpath ($ file ) == false ) {
632+ $ app ->log ("Action aborted, file is a symlink: $ file " ,LOGLEVEL_WARN );
633+ return false ;
634+ }
635+ return chmod ($ file , $ mode );
636+ }
637+
638+ function file_put_contents ($ filename , $ data , $ allow_symlink = false ) {
639+ if ($ allow_symlink == false && $ this ->checkpath ($ filename ) == false ) {
640+ $ app ->log ("Action aborted, file is a symlink: $ filename " ,LOGLEVEL_WARN );
641+ return false ;
642+ }
643+ unlink ($ filename );
644+ return file_put_contents ($ filename , $ data );
645+ }
646+
647+ function file_get_contents ($ filename , $ allow_symlink = false ) {
648+ if ($ allow_symlink == false && $ this ->checkpath ($ filename ) == false ) {
649+ $ app ->log ("Action aborted, file is a symlink: $ filename " ,LOGLEVEL_WARN );
650+ return false ;
651+ }
652+ return file_put_contents ($ filename , $ data );
653+ }
654+
655+ function rename ($ filename , $ new_filename , $ allow_symlink = false ) {
656+ if ($ allow_symlink == false && $ this ->checkpath ($ filename ) == false ) {
657+ $ app ->log ("Action aborted, file is a symlink: $ filename " ,LOGLEVEL_WARN );
658+ return false ;
659+ }
660+ return rename ($ filename , $ new_filename );
661+ }
662+
663+ function mkdir ($ dirname , $ allow_symlink = false ) {
664+ if ($ allow_symlink == false && $ this ->checkpath ($ dirname ) == false ) {
665+ $ app ->log ("Action aborted, file is a symlink: $ dirname " ,LOGLEVEL_WARN );
666+ return false ;
667+ }
668+ return mkdir ($ dirname );
669+ }
670+
671+ function unlink ($ file ) {
672+ return unlink ($ file );
673+ }
674+
675+ function copy ($ file1 ,$ file2 ) {
676+ return copy ($ file1 ,$ file2 );
677+ }
678+
679+ function checkpath ($ path ) {
680+ $ path = trim ($ path );
681+ //* We allow only absolute paths
682+ if (substr ($ path ,0 ,1 ) != '/ ' ) return false ;
683+
684+ //* We allow only some characters in the path
685+ if (!preg_match ('/[a-zA-Z0-9_\.\-]{1,}/ ' ,$ path )) return false ;
686+
687+ //* Check path for symlinks
688+ $ path_parts = explode ($ path );
689+ $ testpath = '' ;
690+ foreach ($ path_parts as $ p ) {
691+ $ testpath .= '/ ' .$ p ;
692+ if (is_link ($ testpath )) return false ;
693+ }
694+
695+ return true ;
625696 }
626697
627698 /**
@@ -1132,6 +1203,10 @@ function get_time(){
11321203 }
11331204
11341205 function replaceLine ($ filename ,$ search_pattern ,$ new_line ,$ strict = 0 ,$ append = 1 ) {
1206+ if ($ this ->checkpath ($ filename ) == false ) {
1207+ $ app ->log ("Action aborted, file is a symlink: $ filename " ,LOGLEVEL_WARN );
1208+ return false ;
1209+ }
11351210 $ lines = @file ($ filename );
11361211 $ out = '' ;
11371212 $ found = 0 ;
@@ -1167,6 +1242,10 @@ function replaceLine($filename,$search_pattern,$new_line,$strict = 0,$append = 1
11671242 }
11681243
11691244 function removeLine ($ filename ,$ search_pattern ,$ strict = 0 ) {
1245+ if ($ this ->checkpath ($ filename ) == false ) {
1246+ $ app ->log ("Action aborted, file is a symlink: $ filename " ,LOGLEVEL_WARN );
1247+ return false ;
1248+ }
11701249 if ($ lines = @file ($ filename )) {
11711250 $ out = '' ;
11721251 foreach ($ lines as $ line ) {
@@ -1200,8 +1279,8 @@ function maildirmake($maildir_path, $user = '', $subfolder = '') {
12001279 $ user = escapeshellcmd ($ user );
12011280 // I assume that the name of the (vmail group) is the same as the name of the mail user in ISPConfig 3
12021281 $ group = $ user ;
1203- if (is_dir ($ dir )) chown ($ dir ,$ user );
1204- if (is_dir ($ dir )) chgrp ($ dir ,$ group );
1282+ if (is_dir ($ dir )) $ this -> chown ($ dir ,$ user );
1283+ if (is_dir ($ dir )) $ this -> chgrp ($ dir ,$ group );
12051284
12061285 $ chown_mdsub = true ;
12071286 }
@@ -1262,10 +1341,10 @@ function mkdirpath($path, $mode = 0755, $user = '', $group = '') {
12621341 foreach ($ path_parts as $ part ) {
12631342 $ new_path .= '/ ' .$ part ;
12641343 if (!@is_dir ($ new_path )) {
1265- mkdir ($ new_path );
1266- chmod ($ new_path ,$ mode );
1267- if ($ user != '' ) chown ($ new_path ,$ user );
1268- if ($ group != '' ) chgrp ($ new_path ,$ group );
1344+ $ this -> mkdir ($ new_path );
1345+ $ this -> chmod ($ new_path ,$ mode );
1346+ if ($ user != '' ) $ this -> chown ($ new_path ,$ user );
1347+ if ($ group != '' ) $ this -> chgrp ($ new_path ,$ group );
12691348 }
12701349 }
12711350 }
@@ -1285,6 +1364,11 @@ function is_installed($appname) {
12851364 function web_folder_protection ($ document_root ,$ protect ) {
12861365 global $ app ,$ conf ;
12871366
1367+ if ($ this ->checkpath ($ document_root ) == false ) {
1368+ $ app ->log ("Action aborted, target is a symlink: $ document_root " ,LOGLEVEL_DEBUG );
1369+ return false ;
1370+ }
1371+
12881372 //* load the server configuration options
12891373 $ app ->uses ('getconf ' );
12901374 $ web_config = $ app ->getconf ->get_server_config ($ conf ['server_id ' ], 'web ' );
0 commit comments