Tcl Source Code

Artifact [d56753ab01]
Login

Artifact d56753ab01d6ca61962c2c4ca8802f61411c4d5d:

Attachment "tm-safe-base.patch" to ticket [1999119fff] added by andreas_kupries 2008-06-25 22:57:34.
--- tcl85.orig/library/init.tcl	2008-06-24 10:26:11.000000000 -0700
+++ tcl85/library/init.tcl	2008-06-24 13:23:30.000000000 -0700
@@ -156,7 +156,7 @@
 
 
 if {[interp issafe]} {
-    package unknown ::tclPkgUnknown
+    package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
 } else {
     # Set up search for Tcl Modules (TIP #189).
     # and setup platform specific unknown package handlers
--- tcl85.orig/library/safe.tcl	2008-06-24 10:26:11.000000000 -0700
+++ tcl85/library/safe.tcl	2008-06-24 15:16:57.000000000 -0700
@@ -369,6 +369,18 @@
 	    lappend slave_auto_path "\$[PathToken $i]"
 	    incr i
 	}
+	# Extend the access list with the paths used to look for Tcl
+	# Modules. We safe the virtual form separately as well, as
+	# syncing it with the slave has to be defered until the
+	# necessary commands are present for setup.
+	foreach dir [::tcl::tm::list] {
+	    lappend access_path $dir
+	    Set [PathToken $i $slave] $dir
+	    lappend slave_auto_path "\$[PathToken $i]"
+	    lappend slave_tm_path   "\$[PathToken $i]"
+	    incr i
+	}
+	Set [TmPathListName      $slave] $slave_tm_path
 	Set $nname $i
 	Set [PathListName $slave] $access_path
 	Set [VirtualPathListName $slave] $slave_auto_path
@@ -448,6 +460,10 @@
 	::interp alias $slave encoding {} [namespace current]::AliasEncoding \
 		$slave
 
+	# Handling Tcl Modules, we need a restricted form of Glob.
+	::interp alias $slave glob {} [namespace current]::AliasGlob \
+		$slave
+
 	# This alias lets the slave have access to a subset of the 'file'
 	# command functionality.
 
@@ -463,8 +479,8 @@
 	# by Tcl_MakeSafe(3)
 
 
-	# Source init.tcl into the slave, to get auto_load and other
-	# procedures defined:
+	# Source init.tcl and tm.tcl into the slave, to get auto_load
+	# and other procedures defined:
 
 	if {[catch {::interp eval $slave\
 		{source [file join $tcl_library init.tcl]}} msg]} {
@@ -472,6 +488,16 @@
 	    error "can't source init.tcl into slave $slave ($msg)"
 	}
 
+	if {[catch {::interp eval $slave \
+		{source [file join $tcl_library tm.tcl]}} msg]} {
+	    Log $slave "can't source tm.tcl ($msg)"
+	    error "can't source tm.tcl into slave $slave ($msg)"
+	}
+
+	# Sync the paths used to search for Tcl modules. This can be
+	# done only now, after tm.tcl was loaded.
+	::interp eval $slave [list ::tcl::tm::add {*}[Set [TmPathListName $slave]]]
+
 	return $slave
     }
 
@@ -610,6 +636,10 @@
     proc VirtualPathListName {slave} {
 	return "[InterpStateName $slave](access_path_slave)"
     }
+    # returns the variable name of the complete tm path list
+    proc TmPathListName {slave} {
+	return "[InterpStateName $slave](tm_path_slave)"
+    }
     # returns the variable name of the number of items
     proc PathNumberName {slave} {
 	return "[InterpStateName $slave](access_path,n)"
@@ -707,19 +737,96 @@
 	}
     }
 
+    # AliasGlob is the target of the "glob" alias in safe interpreters.
+
+    proc AliasGlob {slave args} {
+	Log $slave "GLOB ! $args" NOTICE
+	set cmd {}
+	set at 0
+
+	set dir        {}
+	set virtualdir {}
+
+	while {$at < [llength $args]} {
+	    switch -glob -- [set opt [lindex $args $at]] {
+		-nocomplain -
+		-join       { lappend cmd $opt ; incr at }
+		-directory  {
+		    lappend cmd $opt ; incr at
+		    set virtualdir [lindex $args $at]
+
+		    # get the real path from the virtual one.
+		    if {[catch {set dir [TranslatePath $slave $virtualdir]} msg]} {
+			Log $slave $msg
+			return -code error "permission denied"
+		    }
+		    # check that the path is in the access path of that slave
+		    if {[catch {DirInAccessPath $slave $dir} msg]} {
+			Log $slave $msg
+			return -code error "permission denied"
+		    }
+		    lappend cmd $dir ; incr at
+		}
+		pkgIndex.tcl {
+		    # Oops, this is globbing a subdirectory in regular
+		    # package search. That is not wanted. Abort,
+		    # handler does catch already (because glob was not
+		    # defined before). See package.tcl, lines 484ff in
+		    # tclPkgUnknown.
+		    error "unknown command glob"
+		}
+		-* {
+		    Log $slave "Safe base rejecting glob option '$opt'"
+		    error      "Safe base rejecting glob option '$opt'"
+		}
+		default {
+		    lappend cmd $opt ; incr at
+		}
+	    }
+	}
+
+	Log $slave "GLOB = $cmd" NOTICE
+
+	if {[catch {::interp invokehidden $slave glob {*}$cmd} msg]} {
+	    Log $slave $msg
+	    return -code error "script error"
+	}
+
+	Log $slave "GLOB @ $msg" NOTICE
+
+	# Translate path back to what the slave should see.
+	set res {}
+	foreach p $msg {
+	    regsub -- ^$dir $p $virtualdir p
+	    lappend res $p
+	}
+
+	Log $slave "GLOB @ $res" NOTICE
+	return $res
+    }
 
     # AliasSource is the target of the "source" alias in safe interpreters.
 
     proc AliasSource {slave args} {
 
 	set argc [llength $args]
-	# Allow only "source filename"
+	# Extended for handling of Tcl Modules to allow not only
+	# "source filename", but "source -encoding E filename" as
+	# well.
+	if {[lindex $args 0] eq "-encoding"} {
+	    incr argc -2
+	    set encoding [lrange $args 0 1]
+	    set at 2
+	} else {
+	    set at 0
+	    set encoding {}
+	}
 	if {$argc != 1} {
-	    set msg "wrong # args: should be \"source fileName\""
+	    set msg "wrong # args: should be \"source ?-encoding E? fileName\""
 	    Log $slave "$msg ($args)"
 	    return -code error $msg
 	}
-	set file [lindex $args 0]
+	set file [lindex $args $at]
 	
 	# get the real path from the virtual one.
 	if {[catch {set file [TranslatePath $slave $file]} msg]} {
@@ -740,7 +847,7 @@
 	}
 
 	# passed all the tests , lets source it:
-	if {[catch {::interp invokehidden $slave source $file} msg]} {
+	if {[catch {::interp invokehidden $slave source {*}$encoding $file} msg]} {
 	    Log $slave $msg
 	    return -code error "script error"
 	}
@@ -840,6 +947,25 @@
 	}
     }
 
+    proc DirInAccessPath {slave dir} {
+	set access_path [GetAccessPath $slave]
+
+	if {[file isfile $dir]} {
+	    error "\"$dir\": is a file"
+	}
+
+	# Normalize paths for comparison since lsearch knows nothing of
+	# potential pathname anomalies.
+	set norm_dir [file normalize $dir]
+	foreach path $access_path {
+	    lappend norm_access_path [file normalize $path]
+	}
+
+	if {[lsearch -exact $norm_access_path $norm_dir] == -1} {
+	    error "\"$dir\": not in access_path"
+	}
+    }
+
     # This procedure enables access from a safe interpreter to only a subset of
     # the subcommands of a command:
 
--- tcl85.orig/library/tm.tcl	2008-06-24 10:26:10.000000000 -0700
+++ tcl85/library/tm.tcl	2008-06-24 14:37:02.000000000 -0700
@@ -214,11 +214,11 @@
 
 	set satisfied 0
 	foreach path $paths {
-	    if {![file exists $path]} {
+	    if {![interp issafe] && ![file exists $path]} {
 		continue
 	    }
 	    set currentsearchpath [file join $path $pkgroot]
-	    if {![file exists $currentsearchpath]} {
+	    if {![interp issafe] && ![file exists $currentsearchpath]} {
 		continue
 	    }
 	    set strip [llength [file split $path]]
@@ -352,9 +352,13 @@
     foreach pa $paths {
 	set p [file join $pa tcl$major]
 	for {set n $minor} {$n >= 0} {incr n -1} {
-	    path add [file normalize [file join $p ${major}.${n}]]
-	}
-	path add [file normalize [file join $p site-tcl]]
+	    set px [file join $p ${major}.${n}]
+	    if {![interp issafe]} { set px [file normalize $px] }
+	    path add $px
+	}
+	set px [file join $p site-tcl]
+	if {![interp issafe]} { set px [file normalize $px] }
+	path add $px
     }
     return
 }
@@ -362,4 +366,4 @@
 # Initialization. Set up the default paths, then insert the new
 # handler into the chain.
 
-::tcl::tm::Defaults
+if {![interp issafe]} { ::tcl::tm::Defaults }