Index: openacs-4/packages/acs-tcl/tcl/security-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/security-procs.tcl,v diff -u -r1.126.2.72 -r1.126.2.73 --- openacs-4/packages/acs-tcl/tcl/security-procs.tcl 25 Aug 2022 12:37:13 -0000 1.126.2.72 +++ openacs-4/packages/acs-tcl/tcl/security-procs.tcl 25 Aug 2022 15:37:01 -0000 1.126.2.73 @@ -1174,6 +1174,8 @@ ad_proc security::safe_tmpfile_p { -must_exist:boolean + -recursive:boolean + -subsite_id tmpfile } { @@ -1186,14 +1188,51 @@ @param tmpfile absolute path to a possibly existing tmpfile @param must_exist make sure the file exists + @param recursive accept also files in a subfolder of a valid + tmpfolder + @param subsite_id when specified, the list of allowed tmpdirs will + be taken from the TmpDir subsite + parameter. Server-wide configuration will be + used if no subsite is specified or if the + parameter turns out to be empty. @return boolean } { - if {[ad_file dir $tmpfile] ne [ns_config ns/parameters tmpdir]} { + # + # Ensure no ".." in the path + # + set tmpfile [ns_normalizepath $tmpfile] + + if {[info exists subsite_id]} { # - # File does not belong to the tmpdir: not safe + # We fetch the tmpdirs from the subsite parameter # + set tmpdirs [parameter::get -package_id $subsite_id -parameter TmpDir] + } else { + set tmpdirs [list] + } + + if {[llength $tmpdirs] == 0} { + # + # Server-wide tmpdirs + # + set tmpdirs [ns_config ns/parameters tmpdir] + } + + if {!$recursive_p && [ad_file dirname $tmpfile] ni $tmpdirs} { + # + # File is not a direct child of one of the tmpfolders: not safe + # return false + } else { + # + # File does not belong to the hierarchy of any of the + # tmpfolders: not safe + # + set separator [file separator] + if { ![regexp ^([join $tmpdirs |])${separator}.*\$ $tmpfile] } { + return false + } } if {![ad_file exists $tmpfile]} {