blob: 081fe27ec5864b9887e3e04dfe2991e0d11c6c88 [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',
32 'readlines', 'seek', 'tell', 'write', 'writelines')
Guido van Rossum13833561995-08-07 20:19:27 +000033
34
35class FileWrapper(FileBase):
36
Guido van Rossum3ec38f01998-03-26 22:10:50 +000037 # XXX This is just like a Bastion -- should use that!
Guido van Rossumcd6aab91996-06-28 17:28:51 +000038
Guido van Rossum3ec38f01998-03-26 22:10:50 +000039 def __init__(self, f):
40 self.f = f
41 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 Rossum3ec38f01998-03-26 22:10:50 +000051 return apply(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',
Fred Drakea2d848e2001-06-22 18:19:16 +0000140 'sha', '_sre', 'strop', 'struct', 'time')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000141
142 ok_posix_names = ('error', 'fstat', 'listdir', 'lstat', 'readlink',
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000143 'stat', 'times', 'uname', 'getpid', 'getppid',
144 'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000145
146 ok_sys_names = ('ps1', 'ps2', 'copyright', 'version',
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000147 'platform', 'exit', 'maxint')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000148
Tim Peters8fa45672001-09-13 21:01:29 +0000149 nok_builtin_names = ('open', 'file', 'reload', '__import__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000150
Guido van Rossum59b2a742002-05-31 21:12:53 +0000151 ok_file_types = (imp.C_EXTENSION, imp.PY_SOURCE)
152
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000153 def __init__(self, hooks = None, verbose = 0):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000154 """Returns an instance of the RExec class.
155
156 The hooks parameter is an instance of the RHooks class or a subclass
157 of it. If it is omitted or None, the default RHooks class is
158 instantiated.
159
160 Whenever the RExec module searches for a module (even a built-in one)
161 or reads a module's code, it doesn't actually go out to the file
162 system itself. Rather, it calls methods of an RHooks instance that
163 was passed to or created by its constructor. (Actually, the RExec
164 object doesn't make these calls --- they are made by a module loader
165 object that's part of the RExec object. This allows another level of
166 flexibility, which can be useful when changing the mechanics of
167 import within the restricted environment.)
168
169 By providing an alternate RHooks object, we can control the file
170 system accesses made to import a module, without changing the
171 actual algorithm that controls the order in which those accesses are
172 made. For instance, we could substitute an RHooks object that
173 passes all filesystem requests to a file server elsewhere, via some
174 RPC mechanism such as ILU. Grail's applet loader uses this to support
175 importing applets from a URL for a directory.
176
177 If the verbose parameter is true, additional debugging output may be
178 sent to standard output.
179
180 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000181 ihooks._Verbose.__init__(self, verbose)
182 # XXX There's a circular reference here:
183 self.hooks = hooks or RHooks(verbose)
184 self.hooks.set_rexec(self)
185 self.modules = {}
186 self.ok_dynamic_modules = self.ok_builtin_modules
187 list = []
188 for mname in self.ok_builtin_modules:
189 if mname in sys.builtin_module_names:
190 list.append(mname)
191 self.ok_builtin_modules = tuple(list)
192 self.set_trusted_path()
193 self.make_builtin()
194 self.make_initial_modules()
195 # make_sys must be last because it adds the already created
196 # modules to its builtin_module_names
197 self.make_sys()
198 self.loader = RModuleLoader(self.hooks, verbose)
199 self.importer = RModuleImporter(self.loader, verbose)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000200
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000201 def set_trusted_path(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000202 # Set the path from which dynamic modules may be loaded.
203 # Those dynamic modules must also occur in ok_builtin_modules
204 self.trusted_path = filter(os.path.isabs, sys.path)
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000205
206 def load_dynamic(self, name, filename, file):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000207 if name not in self.ok_dynamic_modules:
208 raise ImportError, "untrusted dynamic module: %s" % name
Raymond Hettinger54f02222002-06-01 14:18:47 +0000209 if name in sys.modules:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000210 src = sys.modules[name]
211 else:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000212 src = imp.load_dynamic(name, filename, file)
213 dst = self.copy_except(src, [])
214 return dst
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000215
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000216 def make_initial_modules(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000217 self.make_main()
218 self.make_osname()
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000219
220 # Helpers for RHooks
221
Guido van Rossum59b2a742002-05-31 21:12:53 +0000222 def get_suffixes(self):
223 return [item # (suff, mode, type)
224 for item in imp.get_suffixes()
225 if item[2] in self.ok_file_types]
226
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000227 def is_builtin(self, mname):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000228 return mname in self.ok_builtin_modules
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000229
230 # The make_* methods create specific built-in modules
231
232 def make_builtin(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000233 m = self.copy_except(__builtin__, self.nok_builtin_names)
234 m.__import__ = self.r_import
235 m.reload = self.r_reload
Tim Peters8fa45672001-09-13 21:01:29 +0000236 m.open = m.file = self.r_open
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000237
238 def make_main(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000239 m = self.add_module('__main__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000240
241 def make_osname(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000242 osname = os.name
243 src = __import__(osname)
244 dst = self.copy_only(src, self.ok_posix_names)
245 dst.environ = e = {}
246 for key, value in os.environ.items():
247 e[key] = value
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000248
249 def make_sys(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000250 m = self.copy_only(sys, self.ok_sys_names)
251 m.modules = self.modules
252 m.argv = ['RESTRICTED']
253 m.path = map(None, self.ok_path)
Guido van Rossumeeb64281998-07-09 13:52:38 +0000254 m.exc_info = self.r_exc_info
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000255 m = self.modules['sys']
256 l = self.modules.keys() + list(self.ok_builtin_modules)
257 l.sort()
258 m.builtin_module_names = tuple(l)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000259
260 # The copy_* methods copy existing modules with some changes
261
262 def copy_except(self, src, exceptions):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000263 dst = self.copy_none(src)
264 for name in dir(src):
265 setattr(dst, name, getattr(src, name))
266 for name in exceptions:
267 try:
268 delattr(dst, name)
269 except AttributeError:
270 pass
271 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000272
273 def copy_only(self, src, names):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000274 dst = self.copy_none(src)
275 for name in names:
276 try:
277 value = getattr(src, name)
278 except AttributeError:
279 continue
280 setattr(dst, name, value)
281 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000282
283 def copy_none(self, src):
Guido van Rossum1f40cd61998-06-09 21:33:44 +0000284 m = self.add_module(src.__name__)
285 m.__doc__ = src.__doc__
286 return m
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000287
288 # Add a module -- return an existing module or create one
289
290 def add_module(self, mname):
Guido van Rossum7f7c3d02002-09-15 06:00:43 +0000291 m = self.modules.get(mname)
292 if m is None:
293 self.modules[mname] = m = self.hooks.new_module(mname)
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000294 m.__builtins__ = self.modules['__builtin__']
295 return m
Guido van Rossum9a22de11995-01-12 12:29:47 +0000296
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000297 # The r* methods are public interfaces
Guido van Rossum9a22de11995-01-12 12:29:47 +0000298
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000299 def r_exec(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000300 """Execute code within a restricted environment.
301
302 The code parameter must either be a string containing one or more
303 lines of Python code, or a compiled code object, which will be
304 executed in the restricted environment's __main__ module.
305
306 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000307 m = self.add_module('__main__')
308 exec code in m.__dict__
Guido van Rossum9a22de11995-01-12 12:29:47 +0000309
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000310 def r_eval(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000311 """Evaluate code within a restricted environment.
312
313 The code parameter must either be a string containing a Python
314 expression, or a compiled code object, which will be evaluated in
315 the restricted environment's __main__ module. The value of the
316 expression or code object will be returned.
317
318 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000319 m = self.add_module('__main__')
320 return eval(code, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000321
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000322 def r_execfile(self, file):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000323 """Execute the Python code in the file in the restricted
324 environment's __main__ module.
325
326 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000327 m = self.add_module('__main__')
Fred Drakef9022962001-10-13 18:34:42 +0000328 execfile(file, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000329
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000330 def r_import(self, mname, globals={}, locals={}, fromlist=[]):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000331 """Import a module, raising an ImportError exception if the module
332 is considered unsafe.
333
334 This method is implicitly called by code executing in the
335 restricted environment. Overriding this method in a subclass is
336 used to change the policies enforced by a restricted environment.
337
338 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000339 return self.importer.import_module(mname, globals, locals, fromlist)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000340
Guido van Rossum13833561995-08-07 20:19:27 +0000341 def r_reload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000342 """Reload the module object, re-parsing and re-initializing it.
343
344 This method is implicitly called by code executing in the
345 restricted environment. Overriding this method in a subclass is
346 used to change the policies enforced by a restricted environment.
347
348 """
Guido van Rossum13833561995-08-07 20:19:27 +0000349 return self.importer.reload(m)
Guido van Rossumbebe5151995-08-09 02:32:08 +0000350
351 def r_unload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000352 """Unload the module.
353
354 Removes it from the restricted environment's sys.modules dictionary.
355
356 This method is implicitly called by code executing in the
357 restricted environment. Overriding this method in a subclass is
358 used to change the policies enforced by a restricted environment.
359
360 """
Guido van Rossumbebe5151995-08-09 02:32:08 +0000361 return self.importer.unload(m)
Tim Peters0c9886d2001-01-15 01:18:21 +0000362
Guido van Rossum13833561995-08-07 20:19:27 +0000363 # The s_* methods are similar but also swap std{in,out,err}
364
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000365 def make_delegate_files(self):
Guido van Rossum13833561995-08-07 20:19:27 +0000366 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000367 self.delegate_stdin = FileDelegate(s, 'stdin')
368 self.delegate_stdout = FileDelegate(s, 'stdout')
369 self.delegate_stderr = FileDelegate(s, 'stderr')
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000370 self.restricted_stdin = FileWrapper(sys.stdin)
371 self.restricted_stdout = FileWrapper(sys.stdout)
372 self.restricted_stderr = FileWrapper(sys.stderr)
373
374 def set_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000375 if not hasattr(self, 'save_stdin'):
376 self.save_files()
377 if not hasattr(self, 'delegate_stdin'):
378 self.make_delegate_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000379 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000380 s.stdin = self.restricted_stdin
381 s.stdout = self.restricted_stdout
382 s.stderr = self.restricted_stderr
383 sys.stdin = self.delegate_stdin
384 sys.stdout = self.delegate_stdout
385 sys.stderr = self.delegate_stderr
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000386
387 def reset_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000388 self.restore_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000389 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000390 self.restricted_stdin = s.stdin
391 self.restricted_stdout = s.stdout
392 self.restricted_stderr = s.stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000393
Guido van Rossum13833561995-08-07 20:19:27 +0000394
395 def save_files(self):
396 self.save_stdin = sys.stdin
397 self.save_stdout = sys.stdout
398 self.save_stderr = sys.stderr
399
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000400 def restore_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000401 sys.stdin = self.save_stdin
402 sys.stdout = self.save_stdout
403 sys.stderr = self.save_stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000404
Guido van Rossume7b9fde1996-09-25 18:47:39 +0000405 def s_apply(self, func, args=(), kw=None):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000406 self.save_files()
407 try:
408 self.set_files()
409 if kw:
410 r = apply(func, args, kw)
411 else:
412 r = apply(func, args)
Guido van Rossum13833561995-08-07 20:19:27 +0000413 finally:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000414 self.restore_files()
Guido van Rossum183a2f22001-06-18 12:33:36 +0000415 return r
Tim Peters0c9886d2001-01-15 01:18:21 +0000416
Guido van Rossum13833561995-08-07 20:19:27 +0000417 def s_exec(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000418 """Execute code within a restricted environment.
419
420 Similar to the r_exec() method, but the code will be granted access
421 to restricted versions of the standard I/O streams sys.stdin,
422 sys.stderr, and sys.stdout.
423
424 The code parameter must either be a string containing one or more
425 lines of Python code, or a compiled code object, which will be
426 executed in the restricted environment's __main__ module.
427
428 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000429 return self.s_apply(self.r_exec, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000430
Guido van Rossum13833561995-08-07 20:19:27 +0000431 def s_eval(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000432 """Evaluate code within a restricted environment.
433
434 Similar to the r_eval() method, but the code will be granted access
435 to restricted versions of the standard I/O streams sys.stdin,
436 sys.stderr, and sys.stdout.
437
438 The code parameter must either be a string containing a Python
439 expression, or a compiled code object, which will be evaluated in
440 the restricted environment's __main__ module. The value of the
441 expression or code object will be returned.
Tim Peters0c9886d2001-01-15 01:18:21 +0000442
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000443 """
Raymond Hettinger1dbe6c02002-05-30 00:06:01 +0000444 return self.s_apply(self.r_eval, args)
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000445
Guido van Rossum13833561995-08-07 20:19:27 +0000446 def s_execfile(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000447 """Execute the Python code in the file in the restricted
448 environment's __main__ module.
449
450 Similar to the r_execfile() method, but the code will be granted
451 access to restricted versions of the standard I/O streams sys.stdin,
452 sys.stderr, and sys.stdout.
453
454 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000455 return self.s_apply(self.r_execfile, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000456
Guido van Rossum13833561995-08-07 20:19:27 +0000457 def s_import(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000458 """Import a module, raising an ImportError exception if the module
459 is considered unsafe.
460
461 This method is implicitly called by code executing in the
462 restricted environment. Overriding this method in a subclass is
463 used to change the policies enforced by a restricted environment.
464
465 Similar to the r_import() method, but has access to restricted
466 versions of the standard I/O streams sys.stdin, sys.stderr, and
467 sys.stdout.
468
469 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000470 return self.s_apply(self.r_import, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000471
Guido van Rossum13833561995-08-07 20:19:27 +0000472 def s_reload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000473 """Reload the module object, re-parsing and re-initializing it.
474
475 This method is implicitly called by code executing in the
476 restricted environment. Overriding this method in a subclass is
477 used to change the policies enforced by a restricted environment.
478
479 Similar to the r_reload() method, but has access to restricted
480 versions of the standard I/O streams sys.stdin, sys.stderr, and
481 sys.stdout.
482
483 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000484 return self.s_apply(self.r_reload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000485
Guido van Rossumbebe5151995-08-09 02:32:08 +0000486 def s_unload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000487 """Unload the module.
488
489 Removes it from the restricted environment's sys.modules dictionary.
490
491 This method is implicitly called by code executing in the
492 restricted environment. Overriding this method in a subclass is
493 used to change the policies enforced by a restricted environment.
494
495 Similar to the r_unload() method, but has access to restricted
496 versions of the standard I/O streams sys.stdin, sys.stderr, and
497 sys.stdout.
498
499 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000500 return self.s_apply(self.r_unload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000501
Guido van Rossum13833561995-08-07 20:19:27 +0000502 # Restricted open(...)
Tim Peters0c9886d2001-01-15 01:18:21 +0000503
Guido van Rossum13833561995-08-07 20:19:27 +0000504 def r_open(self, file, mode='r', buf=-1):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000505 """Method called when open() is called in the restricted environment.
506
507 The arguments are identical to those of the open() function, and a
508 file object (or a class instance compatible with file objects)
509 should be returned. RExec's default behaviour is allow opening
510 any file for reading, but forbidding any attempt to write a file.
511
512 This method is implicitly called by code executing in the
513 restricted environment. Overriding this method in a subclass is
514 used to change the policies enforced by a restricted environment.
515
516 """
Guido van Rossum13833561995-08-07 20:19:27 +0000517 if mode not in ('r', 'rb'):
518 raise IOError, "can't open files for writing in restricted mode"
Guido van Rossumbebe5151995-08-09 02:32:08 +0000519 return open(file, mode, buf)
Guido van Rossum13833561995-08-07 20:19:27 +0000520
Guido van Rossumeeb64281998-07-09 13:52:38 +0000521 # Restricted version of sys.exc_info()
522
523 def r_exc_info(self):
524 ty, va, tr = sys.exc_info()
525 tr = None
526 return ty, va, tr
527
Guido van Rossum9a22de11995-01-12 12:29:47 +0000528
529def test():
Guido van Rossum97dbec92001-08-13 15:58:26 +0000530 import getopt, traceback
Guido van Rossumeeb64281998-07-09 13:52:38 +0000531 opts, args = getopt.getopt(sys.argv[1:], 'vt:')
532 verbose = 0
533 trusted = []
534 for o, a in opts:
535 if o == '-v':
536 verbose = verbose+1
537 if o == '-t':
538 trusted.append(a)
539 r = RExec(verbose=verbose)
540 if trusted:
541 r.ok_builtin_modules = r.ok_builtin_modules + tuple(trusted)
542 if args:
543 r.modules['sys'].argv = args
544 r.modules['sys'].path.insert(0, os.path.dirname(args[0]))
545 else:
546 r.modules['sys'].path.insert(0, "")
547 fp = sys.stdin
548 if args and args[0] != '-':
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000549 try:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000550 fp = open(args[0])
551 except IOError, msg:
552 print "%s: can't open file %s" % (sys.argv[0], `args[0]`)
553 return 1
554 if fp.isatty():
Guido van Rossum2aabac82002-06-14 13:48:25 +0000555 try:
Guido van Rossum7f7c3d02002-09-15 06:00:43 +0000556 import readline
557 except ImportError:
558 pass
559 import code
560 class RestrictedConsole(code.InteractiveConsole):
561 def runcode(self, co):
562 self.locals['__builtins__'] = r.modules['__builtin__']
563 r.s_apply(code.InteractiveConsole.runcode, (self, co))
564 try:
565 RestrictedConsole(r.modules['__main__'].__dict__).interact()
Guido van Rossum2aabac82002-06-14 13:48:25 +0000566 except SystemExit, n:
567 return n
Guido van Rossumeeb64281998-07-09 13:52:38 +0000568 else:
569 text = fp.read()
570 fp.close()
571 c = compile(text, fp.name, 'exec')
572 try:
573 r.s_exec(c)
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000574 except SystemExit, n:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000575 return n
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000576 except:
577 traceback.print_exc()
Guido van Rossumeeb64281998-07-09 13:52:38 +0000578 return 1
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000579
Guido van Rossum9a22de11995-01-12 12:29:47 +0000580
581if __name__ == '__main__':
Guido van Rossumeeb64281998-07-09 13:52:38 +0000582 sys.exit(test())