blob: d399545016b4bd61d764cae613722bbe2e018d88 [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
Fred Drakea0f453b2002-10-11 16:20:45 +0000146 ok_sys_names = ('byteorder', 'copyright', 'exit', 'getdefaultencoding',
147 'getrefcount', 'hexversion', 'maxint', 'maxunicode',
148 'platform', 'ps1', 'ps2', 'version', 'version_info')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000149
Tim Peters8fa45672001-09-13 21:01:29 +0000150 nok_builtin_names = ('open', 'file', 'reload', '__import__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000151
Guido van Rossum59b2a742002-05-31 21:12:53 +0000152 ok_file_types = (imp.C_EXTENSION, imp.PY_SOURCE)
153
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000154 def __init__(self, hooks = None, verbose = 0):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000155 """Returns an instance of the RExec class.
156
157 The hooks parameter is an instance of the RHooks class or a subclass
158 of it. If it is omitted or None, the default RHooks class is
159 instantiated.
160
161 Whenever the RExec module searches for a module (even a built-in one)
162 or reads a module's code, it doesn't actually go out to the file
163 system itself. Rather, it calls methods of an RHooks instance that
164 was passed to or created by its constructor. (Actually, the RExec
165 object doesn't make these calls --- they are made by a module loader
166 object that's part of the RExec object. This allows another level of
167 flexibility, which can be useful when changing the mechanics of
168 import within the restricted environment.)
169
170 By providing an alternate RHooks object, we can control the file
171 system accesses made to import a module, without changing the
172 actual algorithm that controls the order in which those accesses are
173 made. For instance, we could substitute an RHooks object that
174 passes all filesystem requests to a file server elsewhere, via some
175 RPC mechanism such as ILU. Grail's applet loader uses this to support
176 importing applets from a URL for a directory.
177
178 If the verbose parameter is true, additional debugging output may be
179 sent to standard output.
180
181 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000182 ihooks._Verbose.__init__(self, verbose)
183 # XXX There's a circular reference here:
184 self.hooks = hooks or RHooks(verbose)
185 self.hooks.set_rexec(self)
186 self.modules = {}
187 self.ok_dynamic_modules = self.ok_builtin_modules
188 list = []
189 for mname in self.ok_builtin_modules:
190 if mname in sys.builtin_module_names:
191 list.append(mname)
192 self.ok_builtin_modules = tuple(list)
193 self.set_trusted_path()
194 self.make_builtin()
195 self.make_initial_modules()
196 # make_sys must be last because it adds the already created
197 # modules to its builtin_module_names
198 self.make_sys()
199 self.loader = RModuleLoader(self.hooks, verbose)
200 self.importer = RModuleImporter(self.loader, verbose)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000201
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000202 def set_trusted_path(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000203 # Set the path from which dynamic modules may be loaded.
204 # Those dynamic modules must also occur in ok_builtin_modules
205 self.trusted_path = filter(os.path.isabs, sys.path)
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000206
207 def load_dynamic(self, name, filename, file):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000208 if name not in self.ok_dynamic_modules:
209 raise ImportError, "untrusted dynamic module: %s" % name
Raymond Hettinger54f02222002-06-01 14:18:47 +0000210 if name in sys.modules:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000211 src = sys.modules[name]
212 else:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000213 src = imp.load_dynamic(name, filename, file)
214 dst = self.copy_except(src, [])
215 return dst
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000216
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000217 def make_initial_modules(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000218 self.make_main()
219 self.make_osname()
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000220
221 # Helpers for RHooks
222
Guido van Rossum59b2a742002-05-31 21:12:53 +0000223 def get_suffixes(self):
224 return [item # (suff, mode, type)
225 for item in imp.get_suffixes()
226 if item[2] in self.ok_file_types]
227
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000228 def is_builtin(self, mname):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000229 return mname in self.ok_builtin_modules
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000230
231 # The make_* methods create specific built-in modules
232
233 def make_builtin(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000234 m = self.copy_except(__builtin__, self.nok_builtin_names)
235 m.__import__ = self.r_import
236 m.reload = self.r_reload
Tim Peters8fa45672001-09-13 21:01:29 +0000237 m.open = m.file = self.r_open
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000238
239 def make_main(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000240 m = self.add_module('__main__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000241
242 def make_osname(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000243 osname = os.name
244 src = __import__(osname)
245 dst = self.copy_only(src, self.ok_posix_names)
246 dst.environ = e = {}
247 for key, value in os.environ.items():
248 e[key] = value
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000249
250 def make_sys(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000251 m = self.copy_only(sys, self.ok_sys_names)
252 m.modules = self.modules
253 m.argv = ['RESTRICTED']
254 m.path = map(None, self.ok_path)
Guido van Rossumeeb64281998-07-09 13:52:38 +0000255 m.exc_info = self.r_exc_info
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000256 m = self.modules['sys']
257 l = self.modules.keys() + list(self.ok_builtin_modules)
258 l.sort()
259 m.builtin_module_names = tuple(l)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000260
261 # The copy_* methods copy existing modules with some changes
262
263 def copy_except(self, src, exceptions):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000264 dst = self.copy_none(src)
265 for name in dir(src):
266 setattr(dst, name, getattr(src, name))
267 for name in exceptions:
268 try:
269 delattr(dst, name)
270 except AttributeError:
271 pass
272 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000273
274 def copy_only(self, src, names):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000275 dst = self.copy_none(src)
276 for name in names:
277 try:
278 value = getattr(src, name)
279 except AttributeError:
280 continue
281 setattr(dst, name, value)
282 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000283
284 def copy_none(self, src):
Guido van Rossum1f40cd61998-06-09 21:33:44 +0000285 m = self.add_module(src.__name__)
286 m.__doc__ = src.__doc__
287 return m
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000288
289 # Add a module -- return an existing module or create one
290
291 def add_module(self, mname):
Guido van Rossum7f7c3d02002-09-15 06:00:43 +0000292 m = self.modules.get(mname)
293 if m is None:
294 self.modules[mname] = m = self.hooks.new_module(mname)
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000295 m.__builtins__ = self.modules['__builtin__']
296 return m
Guido van Rossum9a22de11995-01-12 12:29:47 +0000297
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000298 # The r* methods are public interfaces
Guido van Rossum9a22de11995-01-12 12:29:47 +0000299
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000300 def r_exec(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000301 """Execute code within a restricted environment.
302
303 The code parameter must either be a string containing one or more
304 lines of Python code, or a compiled code object, which will be
305 executed in the restricted environment's __main__ module.
306
307 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000308 m = self.add_module('__main__')
309 exec code in m.__dict__
Guido van Rossum9a22de11995-01-12 12:29:47 +0000310
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000311 def r_eval(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000312 """Evaluate code within a restricted environment.
313
314 The code parameter must either be a string containing a Python
315 expression, or a compiled code object, which will be evaluated in
316 the restricted environment's __main__ module. The value of the
317 expression or code object will be returned.
318
319 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000320 m = self.add_module('__main__')
321 return eval(code, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000322
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000323 def r_execfile(self, file):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000324 """Execute the Python code in the file in the restricted
325 environment's __main__ module.
326
327 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000328 m = self.add_module('__main__')
Fred Drakef9022962001-10-13 18:34:42 +0000329 execfile(file, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000330
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000331 def r_import(self, mname, globals={}, locals={}, fromlist=[]):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000332 """Import a module, raising an ImportError exception if the module
333 is considered unsafe.
334
335 This method is implicitly called by code executing in the
336 restricted environment. Overriding this method in a subclass is
337 used to change the policies enforced by a restricted environment.
338
339 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000340 return self.importer.import_module(mname, globals, locals, fromlist)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000341
Guido van Rossum13833561995-08-07 20:19:27 +0000342 def r_reload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000343 """Reload the module object, re-parsing and re-initializing it.
344
345 This method is implicitly called by code executing in the
346 restricted environment. Overriding this method in a subclass is
347 used to change the policies enforced by a restricted environment.
348
349 """
Guido van Rossum13833561995-08-07 20:19:27 +0000350 return self.importer.reload(m)
Guido van Rossumbebe5151995-08-09 02:32:08 +0000351
352 def r_unload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000353 """Unload the module.
354
355 Removes it from the restricted environment's sys.modules dictionary.
356
357 This method is implicitly called by code executing in the
358 restricted environment. Overriding this method in a subclass is
359 used to change the policies enforced by a restricted environment.
360
361 """
Guido van Rossumbebe5151995-08-09 02:32:08 +0000362 return self.importer.unload(m)
Tim Peters0c9886d2001-01-15 01:18:21 +0000363
Guido van Rossum13833561995-08-07 20:19:27 +0000364 # The s_* methods are similar but also swap std{in,out,err}
365
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000366 def make_delegate_files(self):
Guido van Rossum13833561995-08-07 20:19:27 +0000367 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000368 self.delegate_stdin = FileDelegate(s, 'stdin')
369 self.delegate_stdout = FileDelegate(s, 'stdout')
370 self.delegate_stderr = FileDelegate(s, 'stderr')
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000371 self.restricted_stdin = FileWrapper(sys.stdin)
372 self.restricted_stdout = FileWrapper(sys.stdout)
373 self.restricted_stderr = FileWrapper(sys.stderr)
374
375 def set_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000376 if not hasattr(self, 'save_stdin'):
377 self.save_files()
378 if not hasattr(self, 'delegate_stdin'):
379 self.make_delegate_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000380 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000381 s.stdin = self.restricted_stdin
382 s.stdout = self.restricted_stdout
383 s.stderr = self.restricted_stderr
384 sys.stdin = self.delegate_stdin
385 sys.stdout = self.delegate_stdout
386 sys.stderr = self.delegate_stderr
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000387
388 def reset_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000389 self.restore_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000390 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000391 self.restricted_stdin = s.stdin
392 self.restricted_stdout = s.stdout
393 self.restricted_stderr = s.stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000394
Guido van Rossum13833561995-08-07 20:19:27 +0000395
396 def save_files(self):
397 self.save_stdin = sys.stdin
398 self.save_stdout = sys.stdout
399 self.save_stderr = sys.stderr
400
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000401 def restore_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000402 sys.stdin = self.save_stdin
403 sys.stdout = self.save_stdout
404 sys.stderr = self.save_stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000405
Guido van Rossume7b9fde1996-09-25 18:47:39 +0000406 def s_apply(self, func, args=(), kw=None):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000407 self.save_files()
408 try:
409 self.set_files()
410 if kw:
411 r = apply(func, args, kw)
412 else:
413 r = apply(func, args)
Guido van Rossum13833561995-08-07 20:19:27 +0000414 finally:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000415 self.restore_files()
Guido van Rossum183a2f22001-06-18 12:33:36 +0000416 return r
Tim Peters0c9886d2001-01-15 01:18:21 +0000417
Guido van Rossum13833561995-08-07 20:19:27 +0000418 def s_exec(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000419 """Execute code within a restricted environment.
420
421 Similar to the r_exec() method, but the code will be granted access
422 to restricted versions of the standard I/O streams sys.stdin,
423 sys.stderr, and sys.stdout.
424
425 The code parameter must either be a string containing one or more
426 lines of Python code, or a compiled code object, which will be
427 executed in the restricted environment's __main__ module.
428
429 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000430 return self.s_apply(self.r_exec, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000431
Guido van Rossum13833561995-08-07 20:19:27 +0000432 def s_eval(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000433 """Evaluate code within a restricted environment.
434
435 Similar to the r_eval() method, but the code will be granted access
436 to restricted versions of the standard I/O streams sys.stdin,
437 sys.stderr, and sys.stdout.
438
439 The code parameter must either be a string containing a Python
440 expression, or a compiled code object, which will be evaluated in
441 the restricted environment's __main__ module. The value of the
442 expression or code object will be returned.
Tim Peters0c9886d2001-01-15 01:18:21 +0000443
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000444 """
Raymond Hettinger1dbe6c02002-05-30 00:06:01 +0000445 return self.s_apply(self.r_eval, args)
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000446
Guido van Rossum13833561995-08-07 20:19:27 +0000447 def s_execfile(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000448 """Execute the Python code in the file in the restricted
449 environment's __main__ module.
450
451 Similar to the r_execfile() method, but the code will be granted
452 access to restricted versions of the standard I/O streams sys.stdin,
453 sys.stderr, and sys.stdout.
454
455 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000456 return self.s_apply(self.r_execfile, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000457
Guido van Rossum13833561995-08-07 20:19:27 +0000458 def s_import(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000459 """Import a module, raising an ImportError exception if the module
460 is considered unsafe.
461
462 This method is implicitly called by code executing in the
463 restricted environment. Overriding this method in a subclass is
464 used to change the policies enforced by a restricted environment.
465
466 Similar to the r_import() method, but has access to restricted
467 versions of the standard I/O streams sys.stdin, sys.stderr, and
468 sys.stdout.
469
470 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000471 return self.s_apply(self.r_import, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000472
Guido van Rossum13833561995-08-07 20:19:27 +0000473 def s_reload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000474 """Reload the module object, re-parsing and re-initializing it.
475
476 This method is implicitly called by code executing in the
477 restricted environment. Overriding this method in a subclass is
478 used to change the policies enforced by a restricted environment.
479
480 Similar to the r_reload() method, but has access to restricted
481 versions of the standard I/O streams sys.stdin, sys.stderr, and
482 sys.stdout.
483
484 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000485 return self.s_apply(self.r_reload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000486
Guido van Rossumbebe5151995-08-09 02:32:08 +0000487 def s_unload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000488 """Unload the module.
489
490 Removes it from the restricted environment's sys.modules dictionary.
491
492 This method is implicitly called by code executing in the
493 restricted environment. Overriding this method in a subclass is
494 used to change the policies enforced by a restricted environment.
495
496 Similar to the r_unload() method, but has access to restricted
497 versions of the standard I/O streams sys.stdin, sys.stderr, and
498 sys.stdout.
499
500 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000501 return self.s_apply(self.r_unload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000502
Guido van Rossum13833561995-08-07 20:19:27 +0000503 # Restricted open(...)
Tim Peters0c9886d2001-01-15 01:18:21 +0000504
Guido van Rossum13833561995-08-07 20:19:27 +0000505 def r_open(self, file, mode='r', buf=-1):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000506 """Method called when open() is called in the restricted environment.
507
508 The arguments are identical to those of the open() function, and a
509 file object (or a class instance compatible with file objects)
510 should be returned. RExec's default behaviour is allow opening
511 any file for reading, but forbidding any attempt to write a file.
512
513 This method is implicitly called by code executing in the
514 restricted environment. Overriding this method in a subclass is
515 used to change the policies enforced by a restricted environment.
516
517 """
Guido van Rossum13833561995-08-07 20:19:27 +0000518 if mode not in ('r', 'rb'):
519 raise IOError, "can't open files for writing in restricted mode"
Guido van Rossumbebe5151995-08-09 02:32:08 +0000520 return open(file, mode, buf)
Guido van Rossum13833561995-08-07 20:19:27 +0000521
Guido van Rossumeeb64281998-07-09 13:52:38 +0000522 # Restricted version of sys.exc_info()
523
524 def r_exc_info(self):
525 ty, va, tr = sys.exc_info()
526 tr = None
527 return ty, va, tr
528
Guido van Rossum9a22de11995-01-12 12:29:47 +0000529
530def test():
Guido van Rossum97dbec92001-08-13 15:58:26 +0000531 import getopt, traceback
Guido van Rossumeeb64281998-07-09 13:52:38 +0000532 opts, args = getopt.getopt(sys.argv[1:], 'vt:')
533 verbose = 0
534 trusted = []
535 for o, a in opts:
536 if o == '-v':
537 verbose = verbose+1
538 if o == '-t':
539 trusted.append(a)
540 r = RExec(verbose=verbose)
541 if trusted:
542 r.ok_builtin_modules = r.ok_builtin_modules + tuple(trusted)
543 if args:
544 r.modules['sys'].argv = args
545 r.modules['sys'].path.insert(0, os.path.dirname(args[0]))
546 else:
547 r.modules['sys'].path.insert(0, "")
548 fp = sys.stdin
549 if args and args[0] != '-':
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000550 try:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000551 fp = open(args[0])
552 except IOError, msg:
553 print "%s: can't open file %s" % (sys.argv[0], `args[0]`)
554 return 1
555 if fp.isatty():
Guido van Rossum2aabac82002-06-14 13:48:25 +0000556 try:
Guido van Rossum7f7c3d02002-09-15 06:00:43 +0000557 import readline
558 except ImportError:
559 pass
560 import code
561 class RestrictedConsole(code.InteractiveConsole):
562 def runcode(self, co):
563 self.locals['__builtins__'] = r.modules['__builtin__']
564 r.s_apply(code.InteractiveConsole.runcode, (self, co))
565 try:
566 RestrictedConsole(r.modules['__main__'].__dict__).interact()
Guido van Rossum2aabac82002-06-14 13:48:25 +0000567 except SystemExit, n:
568 return n
Guido van Rossumeeb64281998-07-09 13:52:38 +0000569 else:
570 text = fp.read()
571 fp.close()
572 c = compile(text, fp.name, 'exec')
573 try:
574 r.s_exec(c)
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000575 except SystemExit, n:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000576 return n
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000577 except:
578 traceback.print_exc()
Guido van Rossumeeb64281998-07-09 13:52:38 +0000579 return 1
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000580
Guido van Rossum9a22de11995-01-12 12:29:47 +0000581
582if __name__ == '__main__':
Guido van Rossumeeb64281998-07-09 13:52:38 +0000583 sys.exit(test())