From: cattaghia on
Hi again everyone! Quick ones now...

1) Is it possible to load "normal" Tk in a SafeBase interp? Or does
the SafeBase interp force Tk to init itself with Tk_SafeInit?

2) The Tk commands which are removed by Tk_SafeInit (bell, grab, menu)
are really *removed* or are them only hidden, like the some Tcl
commands in safe interps?

3) According to the documentation, ::safe::loadTk allows a "-use"
option which kinds of redirect the slave interp's "." window to
another one. Is there something like this available for normal,
"trusted" interps?

Thanks!

Fabricio Rocha
Brasilia, Brasil
From: Gerald W. Lester on
cattaghia wrote:
> Hi again everyone! Quick ones now...
>
> 1) Is it possible to load "normal" Tk in a SafeBase interp? Or does
> the SafeBase interp force Tk to init itself with Tk_SafeInit?

I believe it will use Tk_SafeInit.

> 2) The Tk commands which are removed by Tk_SafeInit (bell, grab, menu)
> are really *removed* or are them only hidden, like the some Tcl
> commands in safe interps?

Not sure, but I believe they are hidden.

> 3) According to the documentation, ::safe::loadTk allows a "-use"
> option which kinds of redirect the slave interp's "." window to
> another one. Is there something like this available for normal,
> "trusted" interps?

Yes, see man/help wish and man/help toplevel.


--- news://freenews.netfront.net/ - complaints: news(a)netfront.net ---
From: cattaghia on
Hi, Gerald,

Do you mean the "argv" contents for wish? I found this one earlier,
indeed, and I had already used the toplevel's "-use" option. But
"interp" does not create another instance of wish or tclsh, does it?
If it does, then passing command-line options would make sense; if it
doesn't, something like "interp create ... -use $myContainerWidgetID"
would be perfect, but in the docs I could find such option only for
the Safe Base interps and SafeTk.

I've been studying "interp" and its derivatives for a couple of days,
but I could not find clear answers to these questions in the Wiki
pages, in the manpages and in other sources like Brent Welch's online
book and "Tcl and the Tk Toolkit" 2nd ed...

Thanks!

Fabricio Rocha
Brasilia, Brasil
From: Keith Nash on
Hello Fabricio,

I think you are asking: is it possible to create an unsafe slave interpreter
and then, when loading Tk, embed the slave's toplevel "." in a container
frame of the master interpreter.

I think the answer is "no": this operation is tied to the Safe Base.
Running a standard unsafe interpreter this way is probably not what you want
to do, because when "exit" is evaluated in the slave interpreter it will
also cause the master to exit. The Safe Base provides a workaround for this
problem, and a possible way to do what you want is to launch a Safe Base
interpreter and then expose the unsafe commands (except exit) that the Safe
Base has hidden.

The command below does this, but I have not checked carefully whether it
does all the initialisation needed to make the slave interpreter behave like
an ordinary unsafe slave interpreter. Use ::safe::interpDelete to delete
the interpreter.

Keith.



proc unsafeInterpInContainer {int winId} {

# Create a Safe Base interpreter with Tk:
safe::interpCreate $int
::safe::loadTk $int -use $winId

# Get a list of hidden commands (except "exit"):
set cmdList [interp hidden $int]
set pos [lsearch -exact $cmdList exit]
if {$pos != -1} {
set cmdList [lreplace $cmdList $pos $pos]
}

# Remove Safe Base replacements for unsafe commands (except "exit"):
foreach cmd $cmdList {$int eval [list catch [list rename $cmd {}]]}

# Expose the hidden commands:
foreach cmd $cmdList {interp expose $int $cmd}

# Get rid of Safe Base directory tokens and use the same paths
# as the present interpreter:
$int eval [list set tcl_library $::tcl_library]
$int eval [list set tk_library $::tk_library]
$int eval [list set auto_path $::auto_path]
$int eval [list set tcl_pkgPath $::tcl_pkgPath]
$int eval {::tcl::tm::path remove {*}[::tcl::tm::path list]}
$int eval [list ::tcl::tm::path add \
{*}[lreverse [::tcl::tm::path list]]]
foreach {cmd instr} [$int eval array get ::auto_index] {
$int eval [list set ::auto_index($cmd) \
[::safe::TranslatePath $int $instr]]
}

# Copy the environment and all elements of tcl_platform:
$int eval [list array set ::tcl_platform [array get ::tcl_platform]]
$int eval [list array set ::env [array get ::env]]

# Mark the interpreter as trusted:
interp marktrusted $int

return $int
}

From: cattaghia on
Hello, Keith, thanks for the attention and the tips!


Actually, what I would like to do was being able to use Tk stuff which
is forbidden by ::safe::loadTk (menus, grab, clipboard) in a
interpreter with some of the SafeBase protections. I did not reach
this stage in my experiments yet, but it looks like the security model
in ::safe::loadTk is way too restrictive for what I want (but
completely justified for the purpose it was intended to, which AFAIK
was the Tcl web plugin), so I will probably opt for using normal
interps with some restricted aliases implemented.

Before someone suggests, I found the "pluginmgr" package in tcllib and
it seems to do a lot of what I'd like, but:

a) of course, I want to create an app, but I am a hobbyist programmer.
Learning Tcl is my actual goal, and the app will be a consequence and
exercise. I'd rather spend some time studying interps and all these
things instead of heading to a ready solution...

b) pluginmgr requires Snit, and there's an enormous list of things I
have to learn before trying the OO systems for Tcl (plus, I still have
not found any comprehensive tutorial for any of these systems).

So I have decided to make some experiments (Tcl/Tk 8.5.8) and got some
conclusions:

1) "package require Tk" in a normal ("trusted") interp works
flawlessly and fast. In a "vanilla safe" interp (created by "interp
create -safe") it does not work, period. In a SafeBase interp created
without values passed through the -accessPath option, all the
directories in the master's auto_path and tcl_pkgPath are scanned for
pkgIndex.tcl files (in my system, this includes a browse through all
the directories under /usr/lib, which results in a +-25s delay) and
finally the error message "not allowed to start Tk by master's
safe::TkInit" appears.

2) "::safe::loadTk" does not work in the normal interp, as documented.
In the vanilla safe interp, it generates the error message "can't read
"Ssafeone(access_path,n)": no such element in array"; the
documentation states that the safe interp must have been initialized
or created by the SafeBase commands, so it seems that ::safe::loadTk
is written for working only with the SafeBase token-based file access
system. Not surprisingly, the command works perfectly in the SafeBase
interp, but still does a search on every directory and subdirectories
passed through -accessPath or those found in the master if the option
is omitted. In BOTH cases an independent, decorated window appears
(titled "Untrusted script", with a bottom panel in red borders with
the same message and a "Delete" button), but when ::safe::loadTk is
called in the vanilla safe interp this window does not have an "empty"
space in it.

After discovering how Tk can or cannot be loaded in the various kinds
of interps, I tried another script which should embed the interps-
created windows in a "Main Window" created in the master interpreter,
with two labelframes "-container true" in it. This was somewhat
surprising:

3) The "normal" interpreter had Tk loaded to it with "package
require", and I created and packed on its main window a label. With
the following line placed before the package require...

interp eval normal [list set ::argv [dict create -use [winfo
id .lblfrm1]]]

.... the normal's window was correctly created in the master's
container (.lblfrm1). But the labelframe's decoration and title
disappeared!

4) The SafeBase interp had Tk loaded with "::safe::loadTk -use [winfo
id .lblfrm2]". As expected, the "Untrusted script" second window did
not appear. But it did not appear embedded in the master window, as I
expected, and all the decoration of .lblfrm2 disappeared as well! I
tried to replace .lblfrm2 with a regular frame, but this did not
change anything.

The container labelframes losing their decorations looked pretty
strange and unexpected to me. It seems that something like [winfo
id .lblfrm2] identifies the *whole area* of the labelframe, not its
"inner frame", and all the "outer" decoration is lost when the
labelframe's ID is given as value for the "-use" option for a
toplevel. This is not in the docs and I think this is a bug, but you
will certainly tell me I am wrong in something...

Regards,

Fabricio Rocha
Brasilia, Brasil