Updated 2011-02-17 02:55:54 by RLE

How to Restrict The List of Exposed Commands

PT 10-Jul-2003: The suggestions and code on this page became TIP #120 [1] and have since been integrated into the Tcl 8.5a0 core.

By default the dde package, when used as a server, exposes all of the commands and variables available in the interpreter. This is not always what is desired. One solution might be to load the package into a safe slave interpreter and use interp alias to expose the required commands. Unfortunately the package doesn't support safe interpreters.
 From: Donal K. Fellows
 Subject: Re: calling tcl-procedures from outside tclsh
 View: Complete Thread (11 articles)
 Original Format
 Newsgroups: comp.lang.tcl
 Date: 2002-04-18 03:45:12 PST

 Pat Thoyts wrote:
 > On the other hand, significantly less work is involved in hacking the
 > dde command to read a list of permitted commands.
 > The attached patch lets you define a global tcl_ddeok list of
 > permitted command names (eg: set ::tcl_ddeok {ddemethod1 ddemethod2} )
 > and if this list exists only evaluates the script if the first word
 > [string match]es an element of this list.

That seems like a bad (i.e. insecure) way to go; imagine something evil in square brackets for the second argument to ddemethod1. A better way would be to allow a handler command to be nominated such that the whole incoming string gets passed as a single uninterpreted argument to the command in question (which in turn could pass things into a safe interpreter, of course, or anything else it feels like.) This is probably an even easier way to do it too.


Following on from Donal's suggestion, if we allow
 dde servername ?-handler procname? ?appname?

then we can set an optional handler procedure to handle all incoming DDE calls. Suitable handlers might be:
 # Allow all commands
 proc permissive {args} {
     uplevel #0 $args

 # restricted to info
 proc restricted_handler {args} {
     set cmd [lindex $args 0]
     switch -exact -- $cmd {
         info    { uplevel #0 $args }
         default { return -code error "permission denied" }

 package require dde
 dde servername -handler ::permissive TestInterp

This should permit the use of Dde within a safe interpreter. Currently the dde command is marked as hidden if the interpreter is safe although you cannot currently load the dde package into a safe interp. Fixing this we can do
 safe::interpCreate slave
 slave invokehidden load tcldde12d.dll Dde
 interp alias slave dde_cmd {} restricted_handler
 slave invokehidden dde servername -handler dde_cmd SafeSlave

to setup a dde server within a safe interpreter. As the dde command is hidden, the client cannot call the command. However, with a little aliasing we could change that - for instance, only permitting dde calls back to the originator. To make it secure by default, we will refuse to evaluate dde eval requests in the safe interpreter if there is no handler defined. We also disable the dde request handling in the server code.

PT - [deleted the pre-TIP document and patch code]

See also dde