| 21.4 Customizing Slave Interpreters |
|
|
The plugin relies on a Tcl command, interp, that creates a new interpreter that can be used to execute tclets. This command is introduced above in Executing Scripts from within Scripts. However, as shown there, interp only creates fully powered slave interpreters. What the plugin needs to do is create a slave which has only powers consistent with some security policy. In fact, the command set of any slave has some properties that are different
than the master interpreter created by tclsh, wish, or the plugin.
The commands are divided into two categories: CI eval $Scriptcan be executed from the master provided Script makes use of only exposed and alias commands. If there are any hidden commands in Script, they will not be executed. Hidden commands must be invoked from the master this way: CI invokehidden ?-global? HIDDEN_COMMAND_NAME ARGUMENTS Suppose the open command is hidden in a slave named S. Here is an example interactive session in the master which opens a file named sample and puts its contents into a variable, Contents, of the slave.
% CI invokehidden open sample
file5
% CI eval {set Contents [read file5]; close file5}
%
As the last exercise helps to show, the invokehidden action is not
particularly useful taken in isolation. Its value comes when it is used with
another unusual property of slaves. This property permits the creation of
some procedures which appear to be commands in a slave but are actually
procedures in a master. These procedures are called As an example of the usefulness of these features, suppose you want a version of the open command in a slave that refuses to open pipes and insists on opening files in one particular directory which cannot be chosen by scripts in the slave. You would accomplish this by hiding the slave's real open command and creating an alias which enforces the rules before using the hidden open command to actually open the file in the slave. The next section discusses the -safe switch to the interp command which creates a Safe Base Tcl interpreter. This section continues with explanations of how to hide commands and create aliases. Two interpreter object commands are provided for hiding and exposing members of the an interpreter's command set.
There are two substeps to creating an alias:
As an example, these two steps can permit a to open a file through p which checks to make sure the file being opened is acceptable for the current security policy. The procedure p runs in the master as it checks for authorization but it uses the hidden open procedure in the slave interpreter. Because it uses the slave's open command, the file is opened in the slave and not its master. The first substep in this method involves executing a hidden command h of a slave S from a procedure p in the master. Here is an example.
proc limited_open {Intrp Path Name {Mode r}} {
$Intrp invokehidden open [file join $Path [file tail $Name]] $Mode
}
This procedure will either open a file in the interpreter $Intrp and
return its file identifier or generate an error. The directory in which the
file must appear is determined by $Path. It may seem silly to separate
the directory from the file name this way when both are parameters to
limited_open. The reason it is not silly is that the alias which causes
limited_open to execute will accept only arguments for the last two
parameters. The first two arguments expected by limited_open will
be fixed at the time the alias is created.
The second substep involves creating an alias in a slave for a
procedure in a master. To make a procedure p in the master available in
the slave S under the name a, use the
S alias a p ?CON1 CON2 ... CONn?This will cause p to be invoked whenever a command line executed by the slave uses the command name a. For example, suppose the following command is executed in the slave. a ARG1 ARG2 ... ARGmThe effect will be to execute the following in the master. p ?SUBST_ARGS? SUBST_CON1 ... SUBST_CONn? ?SUBST_ARG1 ... SUBST_ARGm Here SUBST_ indicates the substituted version of the argument it prefixes. It is important to note that the CON?? arguments are substituted in the master at the time the alias command is executed and the ARG?? arguments are substituted in the slave at the time a is executed. As p executes in the master interpreter, over in the slave interpreter the namespace is unchanged from what it was when the command line containing a was executed. When the execution of p is finished, the return string is passed back to the slave as if it had come from a. Returning to the example in which a slave is given limited power to open files, let the slave be create this way: % interp create S S % S hide openAssuming DIRECTORY_FOR_S is a variable with the path name of the directory where scripts running in S are permitted to open files and that limited_open is a procedure as described above, the permission is given this way: % S alias open limited_open S $DIRECTORY_FOR_S openAfter the alias action has executed, open is an alias in S's command set. When it is executed, the procedure which actually executes is limited_open and the first two arguments of limited_open are S and $DIRECTORY_FOR_S. These two arguments are fixed at the time alias open is executed. The value of DIRECTORY_FOR_S comes from the master interpreter at this time, there is no way for the slave to change it. The last two arguments of limited_open are taken from any command line executing open in the slave. Assuming the value of $DIRECTORY_FOR_S was /users/jazimmer, this command in the slave, open MyFileactually causes this command, limited_open S /users/jazimmer MyFileto be executed in the master. This is like opening /users/jazimmer/MyFile for reading. The limitations of open in the slave become more apparent with two more examples. In the slave this command, set F [open "| pico"]would attempt to open a file named "| pico" in /users/jazimmer. The normal behavior of opening a pipe named "pico" is suppressed. In the slave this command, set F [open "/etc/passwd" w]would attempt to open /users/jazimmer/passwd for writing.
The alias action can be used to delete aliases. Use this pattern.
interpreter_object alias ALIAS_NAME {}
Deleting the alias does not delete the target command, only the ability to execute it from the subordinate interpreter. There is another method for customizing a slave which is almost archaic. I think its main usefulness lies in adding stdin, stdout, and stderr back to Safe Base slaves. I/O channels can be transferred to or shared among interpreters as explained in the following table.
|
Author's Home Page |
|
Order from Amazon. |