blob: 22b1bb26228897dda6df1439cde6d8aba1e17b66 [file] [log] [blame]
Guido van Rossum40d1ea31995-08-04 03:59:03 +00001"""Restricted execution facilities.
Guido van Rossum9a22de11995-01-12 12:29:47 +00002
Guido van Rossumfdd45cb1996-05-28 23:07:17 +00003The class RExec exports methods r_exec(), r_eval(), r_execfile(), and
4r_import(), which correspond roughly to the built-in operations
Guido van Rossum40d1ea31995-08-04 03:59:03 +00005exec, eval(), execfile() and import, but executing the code in an
6environment that only exposes those built-in operations that are
7deemed safe. To this end, a modest collection of 'fake' modules is
8created which mimics the standard modules by the same names. It is a
9policy decision which built-in modules and operations are made
10available; this module provides a reasonable default, but derived
11classes can change the policies e.g. by overriding or extending class
12variables like ok_builtin_modules or methods like make_sys().
13
Guido van Rossum13833561995-08-07 20:19:27 +000014XXX To do:
15- r_open should allow writing tmp dir
16- r_exec etc. with explicit globals/locals? (Use rexec("exec ... in ...")?)
Guido van Rossum13833561995-08-07 20:19:27 +000017
Guido van Rossum40d1ea31995-08-04 03:59:03 +000018"""
Brett Cannon4c1f8812008-05-10 02:27:04 +000019from warnings import warnpy3k
20warnpy3k("the rexec module has been removed in Python 3.0", stacklevel=2)
21del warnpy3k
Guido van Rossum40d1ea31995-08-04 03:59:03 +000022
23
Guido van Rossum9a22de11995-01-12 12:29:47 +000024import sys
Guido van Rossum40d1ea31995-08-04 03:59:03 +000025import __builtin__
26import os
Guido van Rossum40d1ea31995-08-04 03:59:03 +000027import ihooks
Guido van Rossum59b2a742002-05-31 21:12:53 +000028import imp
Guido van Rossum9a22de11995-01-12 12:29:47 +000029
Skip Montanaro0de65802001-02-15 22:15:14 +000030__all__ = ["RExec"]
Guido van Rossum9a22de11995-01-12 12:29:47 +000031
Guido van Rossum13833561995-08-07 20:19:27 +000032class FileBase:
33
Guido van Rossum3ec38f01998-03-26 22:10:50 +000034 ok_file_methods = ('fileno', 'flush', 'isatty', 'read', 'readline',
Gustavo Niemeyerd5ae01a2002-12-16 13:11:57 +000035 'readlines', 'seek', 'tell', 'write', 'writelines', 'xreadlines',
36 '__iter__')
Guido van Rossum13833561995-08-07 20:19:27 +000037
38
39class FileWrapper(FileBase):
40
Guido van Rossum3ec38f01998-03-26 22:10:50 +000041 # XXX This is just like a Bastion -- should use that!
Guido van Rossumcd6aab91996-06-28 17:28:51 +000042
Guido van Rossum3ec38f01998-03-26 22:10:50 +000043 def __init__(self, f):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000044 for m in self.ok_file_methods:
45 if not hasattr(self, m) and hasattr(f, m):
46 setattr(self, m, getattr(f, m))
47
48 def close(self):
49 self.flush()
Guido van Rossum13833561995-08-07 20:19:27 +000050
51
52TEMPLATE = """
53def %s(self, *args):
Guido van Rossum68468eb2003-02-27 20:14:51 +000054 return getattr(self.mod, self.name).%s(*args)
Guido van Rossum13833561995-08-07 20:19:27 +000055"""
56
57class FileDelegate(FileBase):
58
Guido van Rossum3ec38f01998-03-26 22:10:50 +000059 def __init__(self, mod, name):
60 self.mod = mod
61 self.name = name
62
63 for m in FileBase.ok_file_methods + ('close',):
64 exec TEMPLATE % (m, m)
Guido van Rossum13833561995-08-07 20:19:27 +000065
66
Guido van Rossum40d1ea31995-08-04 03:59:03 +000067class RHooks(ihooks.Hooks):
Guido van Rossum9a22de11995-01-12 12:29:47 +000068
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000069 def __init__(self, *args):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000070 # Hacks to support both old and new interfaces:
71 # old interface was RHooks(rexec[, verbose])
72 # new interface is RHooks([verbose])
73 verbose = 0
74 rexec = None
75 if args and type(args[-1]) == type(0):
76 verbose = args[-1]
77 args = args[:-1]
78 if args and hasattr(args[0], '__class__'):
79 rexec = args[0]
80 args = args[1:]
81 if args:
82 raise TypeError, "too many arguments"
83 ihooks.Hooks.__init__(self, verbose)
84 self.rexec = rexec
Guido van Rossum9a22de11995-01-12 12:29:47 +000085
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000086 def set_rexec(self, rexec):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000087 # Called by RExec instance to complete initialization
88 self.rexec = rexec
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000089
Guido van Rossum59b2a742002-05-31 21:12:53 +000090 def get_suffixes(self):
91 return self.rexec.get_suffixes()
92
Guido van Rossum40d1ea31995-08-04 03:59:03 +000093 def is_builtin(self, name):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000094 return self.rexec.is_builtin(name)
Guido van Rossum9a22de11995-01-12 12:29:47 +000095
Guido van Rossum40d1ea31995-08-04 03:59:03 +000096 def init_builtin(self, name):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000097 m = __import__(name)
98 return self.rexec.copy_except(m, ())
Guido van Rossum9a22de11995-01-12 12:29:47 +000099
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000100 def init_frozen(self, name): raise SystemError, "don't use this"
101 def load_source(self, *args): raise SystemError, "don't use this"
102 def load_compiled(self, *args): raise SystemError, "don't use this"
Guido van Rossum8b3282b1998-06-29 20:32:57 +0000103 def load_package(self, *args): raise SystemError, "don't use this"
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000104
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000105 def load_dynamic(self, name, filename, file):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000106 return self.rexec.load_dynamic(name, filename, file)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000107
108 def add_module(self, name):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000109 return self.rexec.add_module(name)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000110
111 def modules_dict(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000112 return self.rexec.modules
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000113
114 def default_path(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000115 return self.rexec.modules['sys'].path
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000116
117
Guido van Rossumf07029e1998-09-21 14:53:26 +0000118# XXX Backwards compatibility
119RModuleLoader = ihooks.FancyModuleLoader
120RModuleImporter = ihooks.ModuleImporter
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000121
122
123class RExec(ihooks._Verbose):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000124 """Basic restricted execution framework.
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000125
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000126 Code executed in this restricted environment will only have access to
127 modules and functions that are deemed safe; you can subclass RExec to
128 add or remove capabilities as desired.
129
130 The RExec class can prevent code from performing unsafe operations like
131 reading or writing disk files, or using TCP/IP sockets. However, it does
132 not protect against code using extremely large amounts of memory or
133 processor time.
134
135 """
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000136
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000137 ok_path = tuple(sys.path) # That's a policy decision
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000138
Guido van Rossume7b9fde1996-09-25 18:47:39 +0000139 ok_builtin_modules = ('audioop', 'array', 'binascii',
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000140 'cmath', 'errno', 'imageop',
141 'marshal', 'math', 'md5', 'operator',
Neal Norwitz10be10c2006-03-16 06:50:13 +0000142 'parser', 'select',
Gustavo Niemeyerd5ae01a2002-12-16 13:11:57 +0000143 'sha', '_sre', 'strop', 'struct', 'time',
Andrew M. Kuchling810b76a2004-08-31 13:31:42 +0000144 '_weakref')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000145
146 ok_posix_names = ('error', 'fstat', 'listdir', 'lstat', 'readlink',
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000147 'stat', 'times', 'uname', 'getpid', 'getppid',
148 'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000149
Fred Drakea0f453b2002-10-11 16:20:45 +0000150 ok_sys_names = ('byteorder', 'copyright', 'exit', 'getdefaultencoding',
151 'getrefcount', 'hexversion', 'maxint', 'maxunicode',
152 'platform', 'ps1', 'ps2', 'version', 'version_info')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000153
Tim Peters8fa45672001-09-13 21:01:29 +0000154 nok_builtin_names = ('open', 'file', 'reload', '__import__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000155
Guido van Rossum59b2a742002-05-31 21:12:53 +0000156 ok_file_types = (imp.C_EXTENSION, imp.PY_SOURCE)
157
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000158 def __init__(self, hooks = None, verbose = 0):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000159 """Returns an instance of the RExec class.
160
161 The hooks parameter is an instance of the RHooks class or a subclass
162 of it. If it is omitted or None, the default RHooks class is
163 instantiated.
164
165 Whenever the RExec module searches for a module (even a built-in one)
166 or reads a module's code, it doesn't actually go out to the file
167 system itself. Rather, it calls methods of an RHooks instance that
168 was passed to or created by its constructor. (Actually, the RExec
169 object doesn't make these calls --- they are made by a module loader
170 object that's part of the RExec object. This allows another level of
171 flexibility, which can be useful when changing the mechanics of
172 import within the restricted environment.)
173
174 By providing an alternate RHooks object, we can control the file
175 system accesses made to import a module, without changing the
176 actual algorithm that controls the order in which those accesses are
177 made. For instance, we could substitute an RHooks object that
178 passes all filesystem requests to a file server elsewhere, via some
179 RPC mechanism such as ILU. Grail's applet loader uses this to support
180 importing applets from a URL for a directory.
181
182 If the verbose parameter is true, additional debugging output may be
183 sent to standard output.
184
185 """
Guido van Rossum34a2e082003-01-06 15:43:34 +0000186
Georg Brandle2d827d2007-04-12 07:01:19 +0000187 raise RuntimeError, "This code is not secure in Python 2.2 and later"
Guido van Rossum34a2e082003-01-06 15:43:34 +0000188
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000189 ihooks._Verbose.__init__(self, verbose)
190 # XXX There's a circular reference here:
191 self.hooks = hooks or RHooks(verbose)
192 self.hooks.set_rexec(self)
193 self.modules = {}
194 self.ok_dynamic_modules = self.ok_builtin_modules
195 list = []
196 for mname in self.ok_builtin_modules:
197 if mname in sys.builtin_module_names:
198 list.append(mname)
199 self.ok_builtin_modules = tuple(list)
200 self.set_trusted_path()
201 self.make_builtin()
202 self.make_initial_modules()
203 # make_sys must be last because it adds the already created
204 # modules to its builtin_module_names
205 self.make_sys()
206 self.loader = RModuleLoader(self.hooks, verbose)
207 self.importer = RModuleImporter(self.loader, verbose)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000208
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000209 def set_trusted_path(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000210 # Set the path from which dynamic modules may be loaded.
211 # Those dynamic modules must also occur in ok_builtin_modules
212 self.trusted_path = filter(os.path.isabs, sys.path)
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000213
214 def load_dynamic(self, name, filename, file):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000215 if name not in self.ok_dynamic_modules:
216 raise ImportError, "untrusted dynamic module: %s" % name
Raymond Hettinger54f02222002-06-01 14:18:47 +0000217 if name in sys.modules:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000218 src = sys.modules[name]
219 else:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000220 src = imp.load_dynamic(name, filename, file)
221 dst = self.copy_except(src, [])
222 return dst
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000223
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000224 def make_initial_modules(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000225 self.make_main()
226 self.make_osname()
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000227
228 # Helpers for RHooks
229
Guido van Rossum59b2a742002-05-31 21:12:53 +0000230 def get_suffixes(self):
231 return [item # (suff, mode, type)
232 for item in imp.get_suffixes()
233 if item[2] in self.ok_file_types]
234
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000235 def is_builtin(self, mname):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000236 return mname in self.ok_builtin_modules
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000237
238 # The make_* methods create specific built-in modules
239
240 def make_builtin(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000241 m = self.copy_except(__builtin__, self.nok_builtin_names)
242 m.__import__ = self.r_import
243 m.reload = self.r_reload
Tim Peters8fa45672001-09-13 21:01:29 +0000244 m.open = m.file = self.r_open
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000245
246 def make_main(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000247 m = self.add_module('__main__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000248
249 def make_osname(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000250 osname = os.name
251 src = __import__(osname)
252 dst = self.copy_only(src, self.ok_posix_names)
253 dst.environ = e = {}
254 for key, value in os.environ.items():
255 e[key] = value
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000256
257 def make_sys(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000258 m = self.copy_only(sys, self.ok_sys_names)
259 m.modules = self.modules
260 m.argv = ['RESTRICTED']
261 m.path = map(None, self.ok_path)
Guido van Rossumeeb64281998-07-09 13:52:38 +0000262 m.exc_info = self.r_exc_info
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000263 m = self.modules['sys']
264 l = self.modules.keys() + list(self.ok_builtin_modules)
265 l.sort()
266 m.builtin_module_names = tuple(l)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000267
268 # The copy_* methods copy existing modules with some changes
269
270 def copy_except(self, src, exceptions):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000271 dst = self.copy_none(src)
272 for name in dir(src):
273 setattr(dst, name, getattr(src, name))
274 for name in exceptions:
275 try:
276 delattr(dst, name)
277 except AttributeError:
278 pass
279 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000280
281 def copy_only(self, src, names):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000282 dst = self.copy_none(src)
283 for name in names:
284 try:
285 value = getattr(src, name)
286 except AttributeError:
287 continue
288 setattr(dst, name, value)
289 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000290
291 def copy_none(self, src):
Guido van Rossum1f40cd61998-06-09 21:33:44 +0000292 m = self.add_module(src.__name__)
293 m.__doc__ = src.__doc__
294 return m
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000295
296 # Add a module -- return an existing module or create one
297
298 def add_module(self, mname):
Guido van Rossum7f7c3d02002-09-15 06:00:43 +0000299 m = self.modules.get(mname)
300 if m is None:
301 self.modules[mname] = m = self.hooks.new_module(mname)
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000302 m.__builtins__ = self.modules['__builtin__']
303 return m
Guido van Rossum9a22de11995-01-12 12:29:47 +0000304
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000305 # The r* methods are public interfaces
Guido van Rossum9a22de11995-01-12 12:29:47 +0000306
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000307 def r_exec(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000308 """Execute code within a restricted environment.
309
310 The code parameter must either be a string containing one or more
311 lines of Python code, or a compiled code object, which will be
312 executed in the restricted environment's __main__ module.
313
314 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000315 m = self.add_module('__main__')
316 exec code in m.__dict__
Guido van Rossum9a22de11995-01-12 12:29:47 +0000317
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000318 def r_eval(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000319 """Evaluate code within a restricted environment.
320
321 The code parameter must either be a string containing a Python
322 expression, or a compiled code object, which will be evaluated in
323 the restricted environment's __main__ module. The value of the
324 expression or code object will be returned.
325
326 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000327 m = self.add_module('__main__')
328 return eval(code, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000329
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000330 def r_execfile(self, file):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000331 """Execute the Python code in the file in the restricted
332 environment's __main__ module.
333
334 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000335 m = self.add_module('__main__')
Fred Drakef9022962001-10-13 18:34:42 +0000336 execfile(file, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000337
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000338 def r_import(self, mname, globals={}, locals={}, fromlist=[]):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000339 """Import a module, raising an ImportError exception if the module
340 is considered unsafe.
341
342 This method is implicitly called by code executing in the
343 restricted environment. Overriding this method in a subclass is
344 used to change the policies enforced by a restricted environment.
345
346 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000347 return self.importer.import_module(mname, globals, locals, fromlist)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000348
Guido van Rossum13833561995-08-07 20:19:27 +0000349 def r_reload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000350 """Reload the module object, re-parsing and re-initializing it.
351
352 This method is implicitly called by code executing in the
353 restricted environment. Overriding this method in a subclass is
354 used to change the policies enforced by a restricted environment.
355
356 """
Guido van Rossum13833561995-08-07 20:19:27 +0000357 return self.importer.reload(m)
Guido van Rossumbebe5151995-08-09 02:32:08 +0000358
359 def r_unload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000360 """Unload the module.
361
362 Removes it from the restricted environment's sys.modules dictionary.
363
364 This method is implicitly called by code executing in the
365 restricted environment. Overriding this method in a subclass is
366 used to change the policies enforced by a restricted environment.
367
368 """
Guido van Rossumbebe5151995-08-09 02:32:08 +0000369 return self.importer.unload(m)
Tim Peters0c9886d2001-01-15 01:18:21 +0000370
Guido van Rossum13833561995-08-07 20:19:27 +0000371 # The s_* methods are similar but also swap std{in,out,err}
372
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000373 def make_delegate_files(self):
Guido van Rossum13833561995-08-07 20:19:27 +0000374 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000375 self.delegate_stdin = FileDelegate(s, 'stdin')
376 self.delegate_stdout = FileDelegate(s, 'stdout')
377 self.delegate_stderr = FileDelegate(s, 'stderr')
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000378 self.restricted_stdin = FileWrapper(sys.stdin)
379 self.restricted_stdout = FileWrapper(sys.stdout)
380 self.restricted_stderr = FileWrapper(sys.stderr)
381
382 def set_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000383 if not hasattr(self, 'save_stdin'):
384 self.save_files()
385 if not hasattr(self, 'delegate_stdin'):
386 self.make_delegate_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000387 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000388 s.stdin = self.restricted_stdin
389 s.stdout = self.restricted_stdout
390 s.stderr = self.restricted_stderr
391 sys.stdin = self.delegate_stdin
392 sys.stdout = self.delegate_stdout
393 sys.stderr = self.delegate_stderr
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000394
395 def reset_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000396 self.restore_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000397 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000398 self.restricted_stdin = s.stdin
399 self.restricted_stdout = s.stdout
400 self.restricted_stderr = s.stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000401
Guido van Rossum13833561995-08-07 20:19:27 +0000402
403 def save_files(self):
404 self.save_stdin = sys.stdin
405 self.save_stdout = sys.stdout
406 self.save_stderr = sys.stderr
407
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000408 def restore_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000409 sys.stdin = self.save_stdin
410 sys.stdout = self.save_stdout
411 sys.stderr = self.save_stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000412
Guido van Rossum68468eb2003-02-27 20:14:51 +0000413 def s_apply(self, func, args=(), kw={}):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000414 self.save_files()
415 try:
416 self.set_files()
Guido van Rossum68468eb2003-02-27 20:14:51 +0000417 r = func(*args, **kw)
Guido van Rossum13833561995-08-07 20:19:27 +0000418 finally:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000419 self.restore_files()
Guido van Rossum183a2f22001-06-18 12:33:36 +0000420 return r
Tim Peters0c9886d2001-01-15 01:18:21 +0000421
Guido van Rossum13833561995-08-07 20:19:27 +0000422 def s_exec(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000423 """Execute code within a restricted environment.
424
425 Similar to the r_exec() method, but the code will be granted access
426 to restricted versions of the standard I/O streams sys.stdin,
427 sys.stderr, and sys.stdout.
428
429 The code parameter must either be a string containing one or more
430 lines of Python code, or a compiled code object, which will be
431 executed in the restricted environment's __main__ module.
432
433 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000434 return self.s_apply(self.r_exec, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000435
Guido van Rossum13833561995-08-07 20:19:27 +0000436 def s_eval(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000437 """Evaluate code within a restricted environment.
438
439 Similar to the r_eval() method, but the code will be granted access
440 to restricted versions of the standard I/O streams sys.stdin,
441 sys.stderr, and sys.stdout.
442
443 The code parameter must either be a string containing a Python
444 expression, or a compiled code object, which will be evaluated in
445 the restricted environment's __main__ module. The value of the
446 expression or code object will be returned.
Tim Peters0c9886d2001-01-15 01:18:21 +0000447
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000448 """
Raymond Hettinger1dbe6c02002-05-30 00:06:01 +0000449 return self.s_apply(self.r_eval, args)
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000450
Guido van Rossum13833561995-08-07 20:19:27 +0000451 def s_execfile(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000452 """Execute the Python code in the file in the restricted
453 environment's __main__ module.
454
455 Similar to the r_execfile() method, but the code will be granted
456 access to restricted versions of the standard I/O streams sys.stdin,
457 sys.stderr, and sys.stdout.
458
459 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000460 return self.s_apply(self.r_execfile, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000461
Guido van Rossum13833561995-08-07 20:19:27 +0000462 def s_import(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000463 """Import a module, raising an ImportError exception if the module
464 is considered unsafe.
465
466 This method is implicitly called by code executing in the
467 restricted environment. Overriding this method in a subclass is
468 used to change the policies enforced by a restricted environment.
469
470 Similar to the r_import() method, but has access to restricted
471 versions of the standard I/O streams sys.stdin, sys.stderr, and
472 sys.stdout.
473
474 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000475 return self.s_apply(self.r_import, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000476
Guido van Rossum13833561995-08-07 20:19:27 +0000477 def s_reload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000478 """Reload the module object, re-parsing and re-initializing it.
479
480 This method is implicitly called by code executing in the
481 restricted environment. Overriding this method in a subclass is
482 used to change the policies enforced by a restricted environment.
483
484 Similar to the r_reload() method, but has access to restricted
485 versions of the standard I/O streams sys.stdin, sys.stderr, and
486 sys.stdout.
487
488 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000489 return self.s_apply(self.r_reload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000490
Guido van Rossumbebe5151995-08-09 02:32:08 +0000491 def s_unload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000492 """Unload the module.
493
494 Removes it from the restricted environment's sys.modules dictionary.
495
496 This method is implicitly called by code executing in the
497 restricted environment. Overriding this method in a subclass is
498 used to change the policies enforced by a restricted environment.
499
500 Similar to the r_unload() method, but has access to restricted
501 versions of the standard I/O streams sys.stdin, sys.stderr, and
502 sys.stdout.
503
504 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000505 return self.s_apply(self.r_unload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000506
Guido van Rossum13833561995-08-07 20:19:27 +0000507 # Restricted open(...)
Tim Peters0c9886d2001-01-15 01:18:21 +0000508
Guido van Rossum13833561995-08-07 20:19:27 +0000509 def r_open(self, file, mode='r', buf=-1):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000510 """Method called when open() is called in the restricted environment.
511
512 The arguments are identical to those of the open() function, and a
513 file object (or a class instance compatible with file objects)
514 should be returned. RExec's default behaviour is allow opening
515 any file for reading, but forbidding any attempt to write a file.
516
517 This method is implicitly called by code executing in the
518 restricted environment. Overriding this method in a subclass is
519 used to change the policies enforced by a restricted environment.
520
521 """
Gustavo Niemeyerd5ae01a2002-12-16 13:11:57 +0000522 mode = str(mode)
Guido van Rossum13833561995-08-07 20:19:27 +0000523 if mode not in ('r', 'rb'):
524 raise IOError, "can't open files for writing in restricted mode"
Guido van Rossumbebe5151995-08-09 02:32:08 +0000525 return open(file, mode, buf)
Guido van Rossum13833561995-08-07 20:19:27 +0000526
Guido van Rossumeeb64281998-07-09 13:52:38 +0000527 # Restricted version of sys.exc_info()
528
529 def r_exc_info(self):
530 ty, va, tr = sys.exc_info()
531 tr = None
532 return ty, va, tr
533
Guido van Rossum9a22de11995-01-12 12:29:47 +0000534
535def test():
Guido van Rossum97dbec92001-08-13 15:58:26 +0000536 import getopt, traceback
Guido van Rossumeeb64281998-07-09 13:52:38 +0000537 opts, args = getopt.getopt(sys.argv[1:], 'vt:')
538 verbose = 0
539 trusted = []
540 for o, a in opts:
541 if o == '-v':
542 verbose = verbose+1
543 if o == '-t':
544 trusted.append(a)
545 r = RExec(verbose=verbose)
546 if trusted:
547 r.ok_builtin_modules = r.ok_builtin_modules + tuple(trusted)
548 if args:
549 r.modules['sys'].argv = args
550 r.modules['sys'].path.insert(0, os.path.dirname(args[0]))
551 else:
552 r.modules['sys'].path.insert(0, "")
553 fp = sys.stdin
554 if args and args[0] != '-':
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000555 try:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000556 fp = open(args[0])
557 except IOError, msg:
Walter Dörwald70a6b492004-02-12 17:35:32 +0000558 print "%s: can't open file %r" % (sys.argv[0], args[0])
Guido van Rossumeeb64281998-07-09 13:52:38 +0000559 return 1
560 if fp.isatty():
Guido van Rossum2aabac82002-06-14 13:48:25 +0000561 try:
Guido van Rossum7f7c3d02002-09-15 06:00:43 +0000562 import readline
563 except ImportError:
564 pass
565 import code
566 class RestrictedConsole(code.InteractiveConsole):
567 def runcode(self, co):
568 self.locals['__builtins__'] = r.modules['__builtin__']
569 r.s_apply(code.InteractiveConsole.runcode, (self, co))
570 try:
571 RestrictedConsole(r.modules['__main__'].__dict__).interact()
Guido van Rossum2aabac82002-06-14 13:48:25 +0000572 except SystemExit, n:
573 return n
Guido van Rossumeeb64281998-07-09 13:52:38 +0000574 else:
575 text = fp.read()
576 fp.close()
577 c = compile(text, fp.name, 'exec')
578 try:
579 r.s_exec(c)
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000580 except SystemExit, n:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000581 return n
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000582 except:
583 traceback.print_exc()
Guido van Rossumeeb64281998-07-09 13:52:38 +0000584 return 1
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000585
Guido van Rossum9a22de11995-01-12 12:29:47 +0000586
587if __name__ == '__main__':
Guido van Rossumeeb64281998-07-09 13:52:38 +0000588 sys.exit(test())