diff --git a/filemin/delete.cgi b/filemin/delete.cgi index 73b82d1a6..4c87846e4 100755 --- a/filemin/delete.cgi +++ b/filemin/delete.cgi @@ -8,6 +8,10 @@ get_paths(); my @errors; foreach $name (split(/\0/, $in{'name'})) { + if(!can_write($cwd.'/'.$name)) { + push @errors, "$name - $text{'error_write'}"; + next; + } if(!&unlink_file($cwd.'/'.$name)) { push @errors, "$name - $text{'error_delete'}: $!"; } diff --git a/filemin/filemin-lib.pl b/filemin/filemin-lib.pl index e52caaf18..2bf37d87c 100644 --- a/filemin/filemin-lib.pl +++ b/filemin/filemin-lib.pl @@ -39,6 +39,37 @@ sub get_selinux_command { return get_selinux_command_type() ? 'ls -d --scontext ' : 'ls -dmZ '; } +sub can_write { + my ($file) = @_; + if (&webmin_user_is_admin()) { + return 1; + } + # Check if the file is a symbolic link + if (-l $file) { + # Resolve symbolic link + my $resolved_file = readlink($file); + # If the link is broken, allow writing to the link itself + return -w $file if (!$resolved_file); + # Otherwise, check the resolved file + $file = $resolved_file; + } + # Check if the file itself is writable + return -w $file; +} + +sub can_move { + my ($file, $sdir, $tdir) = @_; + # Check if the file itself is writable + return 0 if (!&can_write($file)); + # Check if the source directory is writable + return 0 if (!-w $sdir); + # Check if the target directory is writable (if given) + return 1 if (!$tdir); + return -w $tdir; + # All checks passed + return 1; +} + sub get_paths { %access = &get_module_acl(); diff --git a/filemin/lang/en b/filemin/lang/en index ce7f01d18..c47ddf9ac 100644 --- a/filemin/lang/en +++ b/filemin/lang/en @@ -155,6 +155,9 @@ notallowed=You are not allowed to access $1. The only allowed directories are: $ error_upload_emax=Uploaded file is larger than the limit of $1 extract_etype=Unsupported archive file type +error_write=you do not have write permission to this file +error_move=you do not have permission to move this file + info_total1=Total: $1 file and $2 directory info_total2=Total: $1 files and $2 directory info_total3=Total: $1 file and $2 directories diff --git a/filemin/paste.cgi b/filemin/paste.cgi index a7f231183..e1025fc4d 100755 --- a/filemin/paste.cgi +++ b/filemin/paste.cgi @@ -29,7 +29,10 @@ if ($cwd eq $from) { } } elsif ($act eq "cut") { - if (-e "$cwd/$arr[$i]") { + if (!can_move("$from/$arr[$i]", $cwd, $from)) { + push @errors, "$from/$arr[$i] - $text{'error_move'}"; + } + elsif (-e "$cwd/$arr[$i]") { push @errors, "$cwd/$arr[$i] $text{'error_exists'}"; } else { system("mv ".quotemeta("$from/$arr[$i]"). diff --git a/filemin/rename.cgi b/filemin/rename.cgi index ce7f9f7ef..2c8b0808a 100755 --- a/filemin/rename.cgi +++ b/filemin/rename.cgi @@ -11,7 +11,10 @@ get_paths(); if (-e "$cwd/$in{'name'}") { print_errors("$in{'name'} $text{'error_exists'}"); } else { - if(&rename_file($cwd.'/'.$in{'file'}, $cwd.'/'.$in{'name'})) { + if(!can_move("$cwd/$in{'file'}", $cwd)) { + print_errors("$in{'file'} - $text{'error_move'}"); + } + elsif(&rename_file($cwd.'/'.$in{'file'}, $cwd.'/'.$in{'name'})) { &redirect("index.cgi?path=".&urlize($path)); } else { print_errors("$text{'error_rename'} $in{'file'}: $!"); diff --git a/filemin/save_file.cgi b/filemin/save_file.cgi index 27c734313..720049400 100755 --- a/filemin/save_file.cgi +++ b/filemin/save_file.cgi @@ -10,6 +10,8 @@ my @errors; # Validate inputs my $file = &simplify_path($cwd.'/'.$in{'file'}); &check_allowed_path($file); +&error($text{'error_saving_file'}." : ".ucfirst($text{'error_write'})) + if (!can_write($file)); $data = $in{'data'}; $data =~ s/\r\n/\n/g;