Index: openacs-4/packages/acs-tcl/acs-tcl.info
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/acs-tcl.info,v
diff -u -r1.95.2.49 -r1.95.2.50
--- openacs-4/packages/acs-tcl/acs-tcl.info 11 Aug 2022 13:49:46 -0000 1.95.2.49
+++ openacs-4/packages/acs-tcl/acs-tcl.info 25 Aug 2022 11:25:10 -0000 1.95.2.50
@@ -9,7 +9,7 @@
f
t
-
+
OpenACS
The Kernel Tcl API library.
2021-09-15
@@ -18,7 +18,7 @@
GPL version 2
3
-
+
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.70 -r1.126.2.71
--- openacs-4/packages/acs-tcl/tcl/security-procs.tcl 24 Aug 2022 14:51:25 -0000 1.126.2.70
+++ openacs-4/packages/acs-tcl/tcl/security-procs.tcl 25 Aug 2022 11:25:10 -0000 1.126.2.71
@@ -1172,7 +1172,60 @@
host_node_id $host_node_id]
}
+ad_proc security::safe_tmpfile_p {tmpfile} {
+ Checks that a file is a safe tmpfile, that is, it belongs to the
+ configured tmpdir.
+
+ When the file exists, we also enforce additional criteria:
+ - file must belong to the current system user
+ - file must be readable and writeable by the current system user
+
+ @param tmpfile absolute path to a possibly existing tmpfile
+
+ @return boolean
+} {
+ if {[ad_file dir $tmpfile] ne [ns_config ns/parameters tmpdir]} {
+ #
+ # File does not belong to the tmpdir: not safe
+ #
+ return false
+ }
+
+ if {![ad_file exists $tmpfile]} {
+ #
+ # File does not exist yet: safe
+ #
+ return true
+ }
+
+ if {![ad_file owned $tmpfile]} {
+ #
+ # File does not belong to us: not safe
+ #
+ return false
+ }
+
+ if {![ad_file readable $tmpfile]} {
+ #
+ # We cannot read the file: not safe
+ #
+ return false
+ }
+
+ if {![ad_file writable $tmpfile]} {
+ #
+ # We cannot write the file: not safe
+ #
+ return false
+ }
+
+ #
+ # The file is safe
+ #
+ return true
+}
+
ad_proc -public ad_get_login_url {
{-authority_id ""}
{-username ""}
Index: openacs-4/packages/acs-tcl/tcl/test/security-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/test/security-procs.tcl,v
diff -u -r1.1.2.4 -r1.1.2.5
--- openacs-4/packages/acs-tcl/tcl/test/security-procs.tcl 2 Aug 2021 17:36:36 -0000 1.1.2.4
+++ openacs-4/packages/acs-tcl/tcl/test/security-procs.tcl 25 Aug 2022 11:25:11 -0000 1.1.2.5
@@ -90,3 +90,48 @@
ns_unregister_op GET $test_url
}
}
+
+aa_register_case \
+ -cats { api } \
+ -procs {
+ security::safe_tmpfile_p
+ ad_tmpnam
+ acs_root_dir
+ ad_file
+ } \
+ safe_tmpfile_p {
+
+ Test security::safe_tmpfile_p proc
+
+ } {
+ set tmpfile [ad_tmpnam]
+ aa_section {Path to a tmpfile that does not exist yet}
+ aa_true "A temporary filename is safe" [security::safe_tmpfile_p $tmpfile]
+
+ aa_section {Path to an existing tmpfile}
+ set wfd [open $tmpfile w]
+ puts $wfd 1234
+ close $wfd
+ aa_true "An existing tmpfile is safe" [security::safe_tmpfile_p $tmpfile]
+ file delete -- $tmpfile
+
+ aa_section {Path to a tmpfile in a folder of the tmpdir}
+ set tmpfile [ad_tmpnam]/test
+ aa_false "A safe tmpfile can only be a direct child of the tmpdir" \
+ [security::safe_tmpfile_p $tmpfile]
+
+ aa_section {Trying to confuse the proc with ".."}
+ set tmpfile [ad_tmpnam]/../test
+ aa_false "Proc is not fooled by .." \
+ [security::safe_tmpfile_p $tmpfile]
+
+ aa_section {Trying to confuse the proc with "~"}
+ set tmpfile ~/../../test
+ aa_false "Proc is not fooled by ~" \
+ [security::safe_tmpfile_p $tmpfile]
+
+ aa_section {Path to a file outside of the tmpdir}
+ set tmpfile [acs_root_dir]/mypreciouscode
+ aa_false "A safe tmpfile can only be a direct child of the tmpdir" \
+ [security::safe_tmpfile_p $tmpfile]
+ }