blob: 203a1e9e735069e4c4f6250c65430b71ea7b024c [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"""
19
20
Guido van Rossum9a22de11995-01-12 12:29:47 +000021import sys
Guido van Rossum40d1ea31995-08-04 03:59:03 +000022import __builtin__
23import os
Guido van Rossum40d1ea31995-08-04 03:59:03 +000024import ihooks
Guido van Rossum59b2a742002-05-31 21:12:53 +000025import imp
Guido van Rossum9a22de11995-01-12 12:29:47 +000026
Skip Montanaro0de65802001-02-15 22:15:14 +000027__all__ = ["RExec"]
Guido van Rossum9a22de11995-01-12 12:29:47 +000028
Guido van Rossum13833561995-08-07 20:19:27 +000029class FileBase:
30
Guido van Rossum3ec38f01998-03-26 22:10:50 +000031 ok_file_methods = ('fileno', 'flush', 'isatty', 'read', 'readline',
Gustavo Niemeyerd5ae01a2002-12-16 13:11:57 +000032 'readlines', 'seek', 'tell', 'write', 'writelines', 'xreadlines',
33 '__iter__')
Guido van Rossum13833561995-08-07 20:19:27 +000034
35
36class FileWrapper(FileBase):
37
Guido van Rossum3ec38f01998-03-26 22:10:50 +000038 # XXX This is just like a Bastion -- should use that!
Guido van Rossumcd6aab91996-06-28 17:28:51 +000039
Guido van Rossum3ec38f01998-03-26 22:10:50 +000040 def __init__(self, f):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000041 for m in self.ok_file_methods:
42 if not hasattr(self, m) and hasattr(f, m):
43 setattr(self, m, getattr(f, m))
44
45 def close(self):
46 self.flush()
Guido van Rossum13833561995-08-07 20:19:27 +000047
48
49TEMPLATE = """
50def %s(self, *args):
Guido van Rossum68468eb2003-02-27 20:14:51 +000051 return getattr(self.mod, self.name).%s(*args)
Guido van Rossum13833561995-08-07 20:19:27 +000052"""
53
54class FileDelegate(FileBase):
55
Guido van Rossum3ec38f01998-03-26 22:10:50 +000056 def __init__(self, mod, name):
57 self.mod = mod
58 self.name = name
59
60 for m in FileBase.ok_file_methods + ('close',):
61 exec TEMPLATE % (m, m)
Guido van Rossum13833561995-08-07 20:19:27 +000062
63
Guido van Rossum40d1ea31995-08-04 03:59:03 +000064class RHooks(ihooks.Hooks):
Guido van Rossum9a22de11995-01-12 12:29:47 +000065
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000066 def __init__(self, *args):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000067 # Hacks to support both old and new interfaces:
68 # old interface was RHooks(rexec[, verbose])
69 # new interface is RHooks([verbose])
70 verbose = 0
71 rexec = None
72 if args and type(args[-1]) == type(0):
73 verbose = args[-1]
74 args = args[:-1]
75 if args and hasattr(args[0], '__class__'):
76 rexec = args[0]
77 args = args[1:]
78 if args:
79 raise TypeError, "too many arguments"
80 ihooks.Hooks.__init__(self, verbose)
81 self.rexec = rexec
Guido van Rossum9a22de11995-01-12 12:29:47 +000082
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000083 def set_rexec(self, rexec):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000084 # Called by RExec instance to complete initialization
85 self.rexec = rexec
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000086
Guido van Rossum59b2a742002-05-31 21:12:53 +000087 def get_suffixes(self):
88 return self.rexec.get_suffixes()
89
Guido van Rossum40d1ea31995-08-04 03:59:03 +000090 def is_builtin(self, name):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000091 return self.rexec.is_builtin(name)
Guido van Rossum9a22de11995-01-12 12:29:47 +000092
Guido van Rossum40d1ea31995-08-04 03:59:03 +000093 def init_builtin(self, name):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000094 m = __import__(name)
95 return self.rexec.copy_except(m, ())
Guido van Rossum9a22de11995-01-12 12:29:47 +000096
Guido van Rossum40d1ea31995-08-04 03:59:03 +000097 def init_frozen(self, name): raise SystemError, "don't use this"
98 def load_source(self, *args): raise SystemError, "don't use this"
99 def load_compiled(self, *args): raise SystemError, "don't use this"
Guido van Rossum8b3282b1998-06-29 20:32:57 +0000100 def load_package(self, *args): raise SystemError, "don't use this"
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000101
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000102 def load_dynamic(self, name, filename, file):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000103 return self.rexec.load_dynamic(name, filename, file)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000104
105 def add_module(self, name):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000106 return self.rexec.add_module(name)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000107
108 def modules_dict(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000109 return self.rexec.modules
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000110
111 def default_path(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000112 return self.rexec.modules['sys'].path
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000113
114
Guido van Rossumf07029e1998-09-21 14:53:26 +0000115# XXX Backwards compatibility
116RModuleLoader = ihooks.FancyModuleLoader
117RModuleImporter = ihooks.ModuleImporter
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000118
119
120class RExec(ihooks._Verbose):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000121 """Basic restricted execution framework.
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000122
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000123 Code executed in this restricted environment will only have access to
124 modules and functions that are deemed safe; you can subclass RExec to
125 add or remove capabilities as desired.
126
127 The RExec class can prevent code from performing unsafe operations like
128 reading or writing disk files, or using TCP/IP sockets. However, it does
129 not protect against code using extremely large amounts of memory or
130 processor time.
131
132 """
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000133
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000134 ok_path = tuple(sys.path) # That's a policy decision
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000135
Guido van Rossume7b9fde1996-09-25 18:47:39 +0000136 ok_builtin_modules = ('audioop', 'array', 'binascii',
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000137 'cmath', 'errno', 'imageop',
138 'marshal', 'math', 'md5', 'operator',
139 'parser', 'regex', 'pcre', 'rotor', 'select',
Gustavo Niemeyerd5ae01a2002-12-16 13:11:57 +0000140 'sha', '_sre', 'strop', 'struct', 'time',
141 'xreadlines', '_weakref')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000142
143 ok_posix_names = ('error', 'fstat', 'listdir', 'lstat', 'readlink',
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000144 'stat', 'times', 'uname', 'getpid', 'getppid',
145 'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000146
Fred Drakea0f453b2002-10-11 16:20:45 +0000147 ok_sys_names = ('byteorder', 'copyright', 'exit', 'getdefaultencoding',
148 'getrefcount', 'hexversion', 'maxint', 'maxunicode',
149 'platform', 'ps1', 'ps2', 'version', 'version_info')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000150
Tim Peters8fa45672001-09-13 21:01:29 +0000151 nok_builtin_names = ('open', 'file', 'reload', '__import__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000152
Guido van Rossum59b2a742002-05-31 21:12:53 +0000153 ok_file_types = (imp.C_EXTENSION, imp.PY_SOURCE)
154
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000155 def __init__(self, hooks = None, verbose = 0):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000156 """Returns an instance of the RExec class.
157
158 The hooks parameter is an instance of the RHooks class or a subclass
159 of it. If it is omitted or None, the default RHooks class is
160 instantiated.
161
162 Whenever the RExec module searches for a module (even a built-in one)
163 or reads a module's code, it doesn't actually go out to the file
164 system itself. Rather, it calls methods of an RHooks instance that
165 was passed to or created by its constructor. (Actually, the RExec
166 object doesn't make these calls --- they are made by a module loader
167 object that's part of the RExec object. This allows another level of
168 flexibility, which can be useful when changing the mechanics of
169 import within the restricted environment.)
170
171 By providing an alternate RHooks object, we can control the file
172 system accesses made to import a module, without changing the
173 actual algorithm that controls the order in which those accesses are
174 made. For instance, we could substitute an RHooks object that
175 passes all filesystem requests to a file server elsewhere, via some
176 RPC mechanism such as ILU. Grail's applet loader uses this to support
177 importing applets from a URL for a directory.
178
179 If the verbose parameter is true, additional debugging output may be
180 sent to standard output.
181
182 """
Guido van Rossum34a2e082003-01-06 15:43:34 +0000183
184 raise RuntimeError, "This code is not secure in Python 2.2 and 2.3"
185
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000186 ihooks._Verbose.__init__(self, verbose)
187 # XXX There's a circular reference here:
188 self.hooks = hooks or RHooks(verbose)
189 self.hooks.set_rexec(self)
190 self.modules = {}
191 self.ok_dynamic_modules = self.ok_builtin_modules
192 list = []
193 for mname in self.ok_builtin_modules:
194 if mname in sys.builtin_module_names:
195 list.append(mname)
196 self.ok_builtin_modules = tuple(list)
197 self.set_trusted_path()
198 self.make_builtin()
199 self.make_initial_modules()
200 # make_sys must be last because it adds the already created
201 # modules to its builtin_module_names
202 self.make_sys()
203 self.loader = RModuleLoader(self.hooks, verbose)
204 self.importer = RModuleImporter(self.loader, verbose)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000205
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000206 def set_trusted_path(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000207 # Set the path from which dynamic modules may be loaded.
208 # Those dynamic modules must also occur in ok_builtin_modules
209 self.trusted_path = filter(os.path.isabs, sys.path)
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000210
211 def load_dynamic(self, name, filename, file):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000212 if name not in self.ok_dynamic_modules:
213 raise ImportError, "untrusted dynamic module: %s" % name
Raymond Hettinger54f02222002-06-01 14:18:47 +0000214 if name in sys.modules:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000215 src = sys.modules[name]
216 else:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000217 src = imp.load_dynamic(name, filename, file)
218 dst = self.copy_except(src, [])
219 return dst
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000220
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000221 def make_initial_modules(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000222 self.make_main()
223 self.make_osname()
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000224
225 # Helpers for RHooks
226
Guido van Rossum59b2a742002-05-31 21:12:53 +0000227 def get_suffixes(self):
228 return [item # (suff, mode, type)
229 for item in imp.get_suffixes()
230 if item[2] in self.ok_file_types]
231
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000232 def is_builtin(self, mname):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000233 return mname in self.ok_builtin_modules
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000234
235 # The make_* methods create specific built-in modules
236
237 def make_builtin(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000238 m = self.copy_except(__builtin__, self.nok_builtin_names)
239 m.__import__ = self.r_import
240 m.reload = self.r_reload
Tim Peters8fa45672001-09-13 21:01:29 +0000241 m.open = m.file = self.r_open
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000242
243 def make_main(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000244 m = self.add_module('__main__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000245
246 def make_osname(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000247 osname = os.name
248 src = __import__(osname)
249 dst = self.copy_only(src, self.ok_posix_names)
250 dst.environ = e = {}
251 for key, value in os.environ.items():
252 e[key] = value
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000253
254 def make_sys(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000255 m = self.copy_only(sys, self.ok_sys_names)
256 m.modules = self.modules
257 m.argv = ['RESTRICTED']
258 m.path = map(None, self.ok_path)
Guido van Rossumeeb64281998-07-09 13:52:38 +0000259 m.exc_info = self.r_exc_info
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000260 m = self.modules['sys']
261 l = self.modules.keys() + list(self.ok_builtin_modules)
262 l.sort()
263 m.builtin_module_names = tuple(l)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000264
265 # The copy_* methods copy existing modules with some changes
266
267 def copy_except(self, src, exceptions):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000268 dst = self.copy_none(src)
269 for name in dir(src):
270 setattr(dst, name, getattr(src, name))
271 for name in exceptions:
272 try:
273 delattr(dst, name)
274 except AttributeError:
275 pass
276 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000277
278 def copy_only(self, src, names):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000279 dst = self.copy_none(src)
280 for name in names:
281 try:
282 value = getattr(src, name)
283 except AttributeError:
284 continue
285 setattr(dst, name, value)
286 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000287
288 def copy_none(self, src):
Guido van Rossum1f40cd61998-06-09 21:33:44 +0000289 m = self.add_module(src.__name__)
290 m.__doc__ = src.__doc__
291 return m
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000292
293 # Add a module -- return an existing module or create one
294
295 def add_module(self, mname):
Guido van Rossum7f7c3d02002-09-15 06:00:43 +0000296 m = self.modules.get(mname)
297 if m is None:
298 self.modules[mname] = m = self.hooks.new_module(mname)
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000299 m.__builtins__ = self.modules['__builtin__']
300 return m
Guido van Rossum9a22de11995-01-12 12:29:47 +0000301
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000302 # The r* methods are public interfaces
Guido van Rossum9a22de11995-01-12 12:29:47 +0000303
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000304 def r_exec(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000305 """Execute code within a restricted environment.
306
307 The code parameter must either be a string containing one or more
308 lines of Python code, or a compiled code object, which will be
309 executed in the restricted environment's __main__ module.
310
311 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000312 m = self.add_module('__main__')
313 exec code in m.__dict__
Guido van Rossum9a22de11995-01-12 12:29:47 +0000314
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000315 def r_eval(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000316 """Evaluate code within a restricted environment.
317
318 The code parameter must either be a string containing a Python
319 expression, or a compiled code object, which will be evaluated in
320 the restricted environment's __main__ module. The value of the
321 expression or code object will be returned.
322
323 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000324 m = self.add_module('__main__')
325 return eval(code, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000326
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000327 def r_execfile(self, file):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000328 """Execute the Python code in the file in the restricted
329 environment's __main__ module.
330
331 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000332 m = self.add_module('__main__')
Fred Drakef9022962001-10-13 18:34:42 +0000333 execfile(file, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000334
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000335 def r_import(self, mname, globals={}, locals={}, fromlist=[]):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000336 """Import a module, raising an ImportError exception if the module
337 is considered unsafe.
338
339 This method is implicitly called by code executing in the
340 restricted environment. Overriding this method in a subclass is
341 used to change the policies enforced by a restricted environment.
342
343 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000344 return self.importer.import_module(mname, globals, locals, fromlist)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000345
Guido van Rossum13833561995-08-07 20:19:27 +0000346 def r_reload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000347 """Reload the module object, re-parsing and re-initializing it.
348
349 This method is implicitly called by code executing in the
350 restricted environment. Overriding this method in a subclass is
351 used to change the policies enforced by a restricted environment.
352
353 """
Guido van Rossum13833561995-08-07 20:19:27 +0000354 return self.importer.reload(m)
Guido van Rossumbebe5151995-08-09 02:32:08 +0000355
356 def r_unload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000357 """Unload the module.
358
359 Removes it from the restricted environment's sys.modules dictionary.
360
361 This method is implicitly called by code executing in the
362 restricted environment. Overriding this method in a subclass is
363 used to change the policies enforced by a restricted environment.
364
365 """
Guido van Rossumbebe5151995-08-09 02:32:08 +0000366 return self.importer.unload(m)
Tim Peters0c9886d2001-01-15 01:18:21 +0000367
Guido van Rossum13833561995-08-07 20:19:27 +0000368 # The s_* methods are similar but also swap std{in,out,err}
369
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000370 def make_delegate_files(self):
Guido van Rossum13833561995-08-07 20:19:27 +0000371 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000372 self.delegate_stdin = FileDelegate(s, 'stdin')
373 self.delegate_stdout = FileDelegate(s, 'stdout')
374 self.delegate_stderr = FileDelegate(s, 'stderr')
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000375 self.restricted_stdin = FileWrapper(sys.stdin)
376 self.restricted_stdout = FileWrapper(sys.stdout)
377 self.restricted_stderr = FileWrapper(sys.stderr)
378
379 def set_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000380 if not hasattr(self, 'save_stdin'):
381 self.save_files()
382 if not hasattr(self, 'delegate_stdin'):
383 self.make_delegate_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000384 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000385 s.stdin = self.restricted_stdin
386 s.stdout = self.restricted_stdout
387 s.stderr = self.restricted_stderr
388 sys.stdin = self.delegate_stdin
389 sys.stdout = self.delegate_stdout
390 sys.stderr = self.delegate_stderr
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000391
392 def reset_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000393 self.restore_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000394 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000395 self.restricted_stdin = s.stdin
396 self.restricted_stdout = s.stdout
397 self.restricted_stderr = s.stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000398
Guido van Rossum13833561995-08-07 20:19:27 +0000399
400 def save_files(self):
401 self.save_stdin = sys.stdin
402 self.save_stdout = sys.stdout
403 self.save_stderr = sys.stderr
404
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000405 def restore_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000406 sys.stdin = self.save_stdin
407 sys.stdout = self.save_stdout
408 sys.stderr = self.save_stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000409
Guido van Rossum68468eb2003-02-27 20:14:51 +0000410 def s_apply(self, func, args=(), kw={}):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000411 self.save_files()
412 try:
413 self.set_files()
Guido van Rossum68468eb2003-02-27 20:14:51 +0000414 r = func(*args, **kw)
Guido van Rossum13833561995-08-07 20:19:27 +0000415 finally:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000416 self.restore_files()
Guido van Rossum183a2f22001-06-18 12:33:36 +0000417 return r
Tim Peters0c9886d2001-01-15 01:18:21 +0000418
Guido van Rossum13833561995-08-07 20:19:27 +0000419 def s_exec(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000420 """Execute code within a restricted environment.
421
422 Similar to the r_exec() method, but the code will be granted access
423 to restricted versions of the standard I/O streams sys.stdin,
424 sys.stderr, and sys.stdout.
425
426 The code parameter must either be a string containing one or more
427 lines of Python code, or a compiled code object, which will be
428 executed in the restricted environment's __main__ module.
429
430 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000431 return self.s_apply(self.r_exec, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000432
Guido van Rossum13833561995-08-07 20:19:27 +0000433 def s_eval(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000434 """Evaluate code within a restricted environment.
435
436 Similar to the r_eval() method, but the code will be granted access
437 to restricted versions of the standard I/O streams sys.stdin,
438 sys.stderr, and sys.stdout.
439
440 The code parameter must either be a string containing a Python
441 expression, or a compiled code object, which will be evaluated in
442 the restricted environment's __main__ module. The value of the
443 expression or code object will be returned.
Tim Peters0c9886d2001-01-15 01:18:21 +0000444
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000445 """
Raymond Hettinger1dbe6c02002-05-30 00:06:01 +0000446 return self.s_apply(self.r_eval, args)
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000447
Guido van Rossum13833561995-08-07 20:19:27 +0000448 def s_execfile(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000449 """Execute the Python code in the file in the restricted
450 environment's __main__ module.
451
452 Similar to the r_execfile() method, but the code will be granted
453 access to restricted versions of the standard I/O streams sys.stdin,
454 sys.stderr, and sys.stdout.
455
456 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000457 return self.s_apply(self.r_execfile, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000458
Guido van Rossum13833561995-08-07 20:19:27 +0000459 def s_import(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000460 """Import a module, raising an ImportError exception if the module
461 is considered unsafe.
462
463 This method is implicitly called by code executing in the
464 restricted environment. Overriding this method in a subclass is
465 used to change the policies enforced by a restricted environment.
466
467 Similar to the r_import() method, but has access to restricted
468 versions of the standard I/O streams sys.stdin, sys.stderr, and
469 sys.stdout.
470
471 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000472 return self.s_apply(self.r_import, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000473
Guido van Rossum13833561995-08-07 20:19:27 +0000474 def s_reload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000475 """Reload the module object, re-parsing and re-initializing it.
476
477 This method is implicitly called by code executing in the
478 restricted environment. Overriding this method in a subclass is
479 used to change the policies enforced by a restricted environment.
480
481 Similar to the r_reload() method, but has access to restricted
482 versions of the standard I/O streams sys.stdin, sys.stderr, and
483 sys.stdout.
484
485 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000486 return self.s_apply(self.r_reload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000487
Guido van Rossumbebe5151995-08-09 02:32:08 +0000488 def s_unload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000489 """Unload the module.
490
491 Removes it from the restricted environment's sys.modules dictionary.
492
493 This method is implicitly called by code executing in the
494 restricted environment. Overriding this method in a subclass is
495 used to change the policies enforced by a restricted environment.
496
497 Similar to the r_unload() method, but has access to restricted
498 versions of the standard I/O streams sys.stdin, sys.stderr, and
499 sys.stdout.
500
501 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000502 return self.s_apply(self.r_unload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000503
Guido van Rossum13833561995-08-07 20:19:27 +0000504 # Restricted open(...)
Tim Peters0c9886d2001-01-15 01:18:21 +0000505
Guido van Rossum13833561995-08-07 20:19:27 +0000506 def r_open(self, file, mode='r', buf=-1):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000507 """Method called when open() is called in the restricted environment.
508
509 The arguments are identical to those of the open() function, and a
510 file object (or a class instance compatible with file objects)
511 should be returned. RExec's default behaviour is allow opening
512 any file for reading, but forbidding any attempt to write a file.
513
514 This method is implicitly called by code executing in the
515 restricted environment. Overriding this method in a subclass is
516 used to change the policies enforced by a restricted environment.
517
518 """
Gustavo Niemeyerd5ae01a2002-12-16 13:11:57 +0000519 mode = str(mode)
Guido van Rossum13833561995-08-07 20:19:27 +0000520 if mode not in ('r', 'rb'):
521 raise IOError, "can't open files for writing in restricted mode"
Guido van Rossumbebe5151995-08-09 02:32:08 +0000522 return open(file, mode, buf)
Guido van Rossum13833561995-08-07 20:19:27 +0000523
Guido van Rossumeeb64281998-07-09 13:52:38 +0000524 # Restricted version of sys.exc_info()
525
526 def r_exc_info(self):
527 ty, va, tr = sys.exc_info()
528 tr = None
529 return ty, va, tr
530
Guido van Rossum9a22de11995-01-12 12:29:47 +0000531
532def test():
Guido van Rossum97dbec92001-08-13 15:58:26 +0000533 import getopt, traceback
Guido van Rossumeeb64281998-07-09 13:52:38 +0000534 opts, args = getopt.getopt(sys.argv[1:], 'vt:')
535 verbose = 0
536 trusted = []
537 for o, a in opts:
538 if o == '-v':
539 verbose = verbose+1
540 if o == '-t':
541 trusted.append(a)
542 r = RExec(verbose=verbose)
543 if trusted:
544 r.ok_builtin_modules = r.ok_builtin_modules + tuple(trusted)
545 if args:
546 r.modules['sys'].argv = args
547 r.modules['sys'].path.insert(0, os.path.dirname(args[0]))
548 else:
549 r.modules['sys'].path.insert(0, "")
550 fp = sys.stdin
551 if args and args[0] != '-':
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000552 try:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000553 fp = open(args[0])
554 except IOError, msg:
555 print "%s: can't open file %s" % (sys.argv[0], `args[0]`)
556 return 1
557 if fp.isatty():
Guido van Rossum2aabac82002-06-14 13:48:25 +0000558 try:
Guido van Rossum7f7c3d02002-09-15 06:00:43 +0000559 import readline
560 except ImportError:
561 pass
562 import code
563 class RestrictedConsole(code.InteractiveConsole):
564 def runcode(self, co):
565 self.locals['__builtins__'] = r.modules['__builtin__']
566 r.s_apply(code.InteractiveConsole.runcode, (self, co))
567 try:
568 RestrictedConsole(r.modules['__main__'].__dict__).interact()
Guido van Rossum2aabac82002-06-14 13:48:25 +0000569 except SystemExit, n:
570 return n
Guido van Rossumeeb64281998-07-09 13:52:38 +0000571 else:
572 text = fp.read()
573 fp.close()
574 c = compile(text, fp.name, 'exec')
575 try:
576 r.s_exec(c)
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000577 except SystemExit, n:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000578 return n
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000579 except:
580 traceback.print_exc()
Guido van Rossumeeb64281998-07-09 13:52:38 +0000581 return 1
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000582
Guido van Rossum9a22de11995-01-12 12:29:47 +0000583
584if __name__ == '__main__':
Guido van Rossumeeb64281998-07-09 13:52:38 +0000585 sys.exit(test())