⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 safe.tcl

📁 tcl是工具命令语言
💻 TCL
📖 第 1 页 / 共 2 页
字号:
	# The allowed slave variables already have been set	# by Tcl_MakeSafe(3)	# Source init.tcl into the slave, to get auto_load and other	# procedures defined:	# We don't try to use the -rsrc on the mac because it would get	# confusing if you would want to customize init.tcl	# for a given set of safe slaves, on all the platforms	# you just need to give a specific access_path and	# the mac should be no exception. As there is no	# obvious full "safe ressources" design nor implementation	# for the mac, safe interps there will just don't	# have that ability. (A specific app can still reenable	# that using custom aliases if they want to).	# It would also make the security analysis and the Safe Tcl security	# model platform dependant and thus more error prone.	if {[catch {::interp eval $slave\		{source [file join $tcl_library init.tcl]}} msg]} {	    Log $slave "can't source init.tcl ($msg)"	    error "can't source init.tcl into slave $slave ($msg)"	}	return $slave    }    # Add (only if needed, avoid duplicates) 1 level of    # sub directories to an existing path list.    # Also removes non directories from the returned list.    proc AddSubDirs {pathList} {	set res {}	foreach dir $pathList {	    if {[file isdirectory $dir]} {		# check that we don't have it yet as a children		# of a previous dir		if {[lsearch -exact $res $dir]<0} {		    lappend res $dir		}		foreach sub [glob -directory $dir -nocomplain *] {		    if {([file isdirectory $sub]) \			    && ([lsearch -exact $res $sub]<0) } {			# new sub dir, add it !	                lappend res $sub	            }		}	    }	}	return $res    }    # This procedure deletes a safe slave managed by Safe Tcl and    # cleans up associated state:proc ::safe::interpDelete {slave} {        Log $slave "About to delete" NOTICE	# If the slave has a cleanup hook registered, call it.	# check the existance because we might be called to delete an interp	# which has not been registered with us at all	set hookname [DeleteHookName $slave]	if {[Exists $hookname]} {	    set hook [Set $hookname]	    if {![::tcl::Lempty $hook]} {		# remove the hook now, otherwise if the hook		# calls us somehow, we'll loop		Unset $hookname		if {[catch {eval $hook [list $slave]} err]} {		    Log $slave "Delete hook error ($err)"		}	    }	}	# Discard the global array of state associated with the slave, and	# delete the interpreter.	set statename [InterpStateName $slave]	if {[Exists $statename]} {	    Unset $statename	}	# if we have been called twice, the interp might have been deleted	# already	if {[::interp exists $slave]} {	    ::interp delete $slave	    Log $slave "Deleted" NOTICE	}	return    }    # Set (or get) the loging mecanism proc ::safe::setLogCmd {args} {    variable Log    if {[llength $args] == 0} {	return $Log    } else {	if {[llength $args] == 1} {	    set Log [lindex $args 0]	} else {	    set Log $args	}    }}    # internal variable    variable Log {}    # ------------------- END OF PUBLIC METHODS ------------    #    # sets the slave auto_path to the master recorded value.    # also sets tcl_library to the first token of the virtual path.    #    proc SyncAccessPath {slave} {	set slave_auto_path [Set [VirtualPathListName $slave]]	::interp eval $slave [list set auto_path $slave_auto_path]	Log $slave "auto_path in $slave has been set to $slave_auto_path"\		NOTICE	::interp eval $slave [list set tcl_library [lindex $slave_auto_path 0]]    }    # base name for storing all the slave states    # the array variable name for slave foo is thus "Sfoo"    # and for sub slave {foo bar} "Sfoo bar" (spaces are handled    # ok everywhere (or should))    # We add the S prefix to avoid that a slave interp called "Log"    # would smash our "Log" variable.    proc InterpStateName {slave} {	return "S$slave"    }    # Check that the given slave is "one of us"    proc IsInterp {slave} {	expr {[Exists [InterpStateName $slave]] && [::interp exists $slave]}    }    # returns the virtual token for directory number N    # if the slave argument is given,     # it will return the corresponding master global variable name    proc PathToken {n {slave ""}} {	if {$slave ne ""} {	    return "[InterpStateName $slave](access_path,$n)"	} else {	    # We need to have a ":" in the token string so	    # [file join] on the mac won't turn it into a relative	    # path.	    return "p(:$n:)"	}    }    # returns the variable name of the complete path list    proc PathListName {slave} {	return "[InterpStateName $slave](access_path)"    }    # returns the variable name of the complete path list    proc VirtualPathListName {slave} {	return "[InterpStateName $slave](access_path_slave)"    }    # returns the variable name of the number of items    proc PathNumberName {slave} {	return "[InterpStateName $slave](access_path,n)"    }    # returns the staticsok flag var name    proc StaticsOkName {slave} {	return "[InterpStateName $slave](staticsok)"    }    # returns the nestedok flag var name    proc NestedOkName {slave} {	return "[InterpStateName $slave](nestedok)"    }    # Run some code at the namespace toplevel    proc Toplevel {args} {	namespace eval [namespace current] $args    }    # set/get values    proc Set {args} {	eval [list Toplevel set] $args    }    # lappend on toplevel vars    proc Lappend {args} {	eval [list Toplevel lappend] $args    }    # unset a var/token (currently just an global level eval)    proc Unset {args} {	eval [list Toplevel unset] $args    }    # test existance     proc Exists {varname} {	Toplevel info exists $varname    }    # short cut for access path getting    proc GetAccessPath {slave} {	Set [PathListName $slave]    }    # short cut for statics ok flag getting    proc StaticsOk {slave} {	Set [StaticsOkName $slave]    }    # short cut for getting the multiples interps sub loading ok flag    proc NestedOk {slave} {	Set [NestedOkName $slave]    }    # interp deletion storing hook name    proc DeleteHookName {slave} {	return [InterpStateName $slave](cleanupHook)    }    #    # translate virtual path into real path    #    proc TranslatePath {slave path} {	# somehow strip the namespaces 'functionality' out (the danger	# is that we would strip valid macintosh "../" queries... :	if {[regexp {(::)|(\.\.)} $path]} {	    error "invalid characters in path $path"	}	set n [expr {[Set [PathNumberName $slave]]-1}]	for {} {$n>=0} {incr n -1} {	    # fill the token virtual names with their real value	    set [PathToken $n] [Set [PathToken $n $slave]]	}	# replaces the token by their value	subst -nobackslashes -nocommands $path    }    # Log eventually log an error    # to enable error logging, set Log to {puts stderr} for instance    proc Log {slave msg {type ERROR}} {	variable Log	if {[info exists Log] && [llength $Log]} {	    eval $Log [list "$type for slave $slave : $msg"]	}    }    # file name control (limit access to files/ressources that should be    # a valid tcl source file)    proc CheckFileName {slave file} {	# This used to limit what can be sourced to ".tcl" and forbid files	# with more than 1 dot and longer than 14 chars, but I changed that	# for 8.4 as a safe interp has enough internal protection already	# to allow sourcing anything. - hobbs	if {![file exists $file]} {	    # don't tell the file path	    error "no such file or directory"	}	if {![file readable $file]} {	    # don't tell the file path	    error "not readable"	}    }    # AliasSource is the target of the "source" alias in safe interpreters.    proc AliasSource {slave args} {	set argc [llength $args]	# Allow only "source filename"	# (and not mac specific -rsrc for instance - see comment in ::init	# for current rationale)	if {$argc != 1} {	    set msg "wrong # args: should be \"source fileName\""	    Log $slave "$msg ($args)"	    return -code error $msg	}	set file [lindex $args 0]		# get the real path from the virtual one.	if {[catch {set file [TranslatePath $slave $file]} msg]} {	    Log $slave $msg	    return -code error "permission denied"	}		# check that the path is in the access path of that slave	if {[catch {FileInAccessPath $slave $file} msg]} {	    Log $slave $msg	    return -code error "permission denied"	}	# do the checks on the filename :	if {[catch {CheckFileName $slave $file} msg]} {	    Log $slave "$file:$msg"	    return -code error $msg	}	# passed all the tests , lets source it:	if {[catch {::interp invokehidden $slave source $file} msg]} {	    Log $slave $msg	    return -code error "script error"	}	return $msg    }    # AliasLoad is the target of the "load" alias in safe interpreters.    proc AliasLoad {slave file args} {	set argc [llength $args]	if {$argc > 2} {	    set msg "load error: too many arguments"	    Log $slave "$msg ($argc) {$file $args}"	    return -code error $msg	}	# package name (can be empty if file is not).	set package [lindex $args 0]	# Determine where to load. load use a relative interp path	# and {} means self, so we can directly and safely use passed arg.	set target [lindex $args 1]	if {[string length $target]} {	    # we will try to load into a sub sub interp	    # check that we want to authorize that.	    if {![NestedOk $slave]} {		Log $slave "loading to a sub interp (nestedok)\			disabled (trying to load $package to $target)"		return -code error "permission denied (nested load)"	    }	    	}	# Determine what kind of load is requested	if {[string length $file] == 0} {	    # static package loading	    if {[string length $package] == 0} {		set msg "load error: empty filename and no package name"		Log $slave $msg		return -code error $msg	    }	    if {![StaticsOk $slave]} {		Log $slave "static packages loading disabled\			(trying to load $package to $target)"		return -code error "permission denied (static package)"	    }	} else {	    # file loading	    # get the real path from the virtual one.	    if {[catch {set file [TranslatePath $slave $file]} msg]} {		Log $slave $msg		return -code error "permission denied"	    }	    # check the translated path	    if {[catch {FileInAccessPath $slave $file} msg]} {		Log $slave $msg		return -code error "permission denied (path)"	    }	}	if {[catch {::interp invokehidden\		$slave load $file $package $target} msg]} {	    Log $slave $msg	    return -code error $msg	}	return $msg    }    # FileInAccessPath raises an error if the file is not found in    # the list of directories contained in the (master side recorded) slave's    # access path.    # the security here relies on "file dirname" answering the proper    # result.... needs checking ?    proc FileInAccessPath {slave file} {	set access_path [GetAccessPath $slave]	if {[file isdirectory $file]} {	    error "\"$file\": is a directory"	}	set parent [file dirname $file]	if {[lsearch -exact $access_path $parent] == -1} {	    error "\"$file\": not in access_path"	}    }    # This procedure enables access from a safe interpreter to only a subset of    # the subcommands of a command:    proc Subset {slave command okpat args} {	set subcommand [lindex $args 0]	if {[regexp $okpat $subcommand]} {	    return [eval [list $command $subcommand] [lrange $args 1 end]]	}	set msg "not allowed to invoke subcommand $subcommand of $command"	Log $slave $msg	error $msg    }    # This procedure installs an alias in a slave that invokes "safesubset"    # in the master to execute allowed subcommands. It precomputes the pattern    # of allowed subcommands; you can use wildcards in the pattern if you wish    # to allow subcommand abbreviation.    #    # Syntax is: AliasSubset slave alias target subcommand1 subcommand2...    proc AliasSubset {slave alias target args} {	set pat ^(; set sep ""	foreach sub $args {	    append pat $sep$sub	    set sep |	}	append pat )\$	::interp alias $slave $alias {}\		[namespace current]::Subset $slave $target $pat    }    # AliasEncoding is the target of the "encoding" alias in safe interpreters.    proc AliasEncoding {slave args} {	set argc [llength $args]	set okpat "^(name.*|convert.*)\$"	set subcommand [lindex $args 0]	if {[regexp $okpat $subcommand]} {	    return [eval ::interp invokehidden $slave encoding $subcommand \		    [lrange $args 1 end]]	}	if {[string match $subcommand system]} {	    if {$argc == 1} {		# passed all the tests , lets source it:		if {[catch {::interp invokehidden \			$slave encoding system} msg]} {		    Log $slave $msg		    return -code error "script error"		}	    } else {		set msg "wrong # args: should be \"encoding system\""		Log $slave $msg		error $msg	    }	} else {	    set msg "wrong # args: should be \"encoding option ?arg ...?\""	    Log $slave $msg	    error $msg	}	return $msg    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -