Often you'll wish to customize the restricted environment in various ways, most commonly by adding or subtracting variables or functions from the modules available. At a more advanced level, you might wish to write replacements for existing functions; for example, a Web browser that executes Python applets would have an import function that allows retrieving modules via HTTP and importing them.
An easy way to add or remove functions is to create the RExec
instance, get the namespace dictionary for the desired module, and add
or delete the desired function. For example, the RExec class
provides a restricted open()
that allows opening files for
reading. If you wish to disallow this, you can simply delete 'open'
from the RExec instance's __builtin__
module.
module = r_env.add_module('__builtin__') mod_dict = module.__dict__ del mod_dict['open']
(This isn't enough to prevent code from accessing the filesystem;
the RExec class also allows access
via some of the functions in the posix
module, which is usually
aliased to the os
module. See below for how to change this.)
This is fine if only a single function is being added or removed, but for more complicated changes, subclassing the RExec class is a better idea.
Subclassing can potentially be quite simple. The RExec class
defines some class attributes that are used to initialize the restricted
versions of modules such as os
and sys
. Changing the
environment's policy then requires just changing the class attribute in
your subclass. For example, the default environment allows restricted
code to use the posix
module to get its process and group ID. If
you decide to disallow this, you can do it with the following custom
class:
class MyRExec(rexec.RExec): ok_posix_names = ('error', 'fstat', 'listdir', 'lstat', 'readlink', 'stat', 'times', 'uname')
More elaborate customizations may require overriding one of the methods
called to create the corresponding module. The functions to be
overridden are make_builtin
, make_main
,
make_osname
, and make_sys
. The r_import
,
r_open
, and r_reload
methods are made available to
restricted code, so by overriding these functions, you can change the
capabilities available.
For example, defining a new import function requires overriding
r_import
:
class MyRExec(rexec.RExec): def r_import(self, mname, globals={}, locals={}, fromlist=[]): raise ImportError, "No imports allowed--ever"
Obviously, a less trivial function could import modules using HTTP, or do something else of interest.