blob: 6dc1585ab4d3746f852de1e680cc2c028c68e865 [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 Rossum9a22de11995-01-12 12:29:47 +000025
Skip Montanaro0de65802001-02-15 22:15:14 +000026__all__ = ["RExec"]
Guido van Rossum9a22de11995-01-12 12:29:47 +000027
Guido van Rossum13833561995-08-07 20:19:27 +000028class FileBase:
29
Guido van Rossum3ec38f01998-03-26 22:10:50 +000030 ok_file_methods = ('fileno', 'flush', 'isatty', 'read', 'readline',
31 'readlines', 'seek', 'tell', 'write', 'writelines')
Guido van Rossum13833561995-08-07 20:19:27 +000032
33
34class FileWrapper(FileBase):
35
Guido van Rossum3ec38f01998-03-26 22:10:50 +000036 # XXX This is just like a Bastion -- should use that!
Guido van Rossumcd6aab91996-06-28 17:28:51 +000037
Guido van Rossum3ec38f01998-03-26 22:10:50 +000038 def __init__(self, f):
39 self.f = f
40 for m in self.ok_file_methods:
41 if not hasattr(self, m) and hasattr(f, m):
42 setattr(self, m, getattr(f, m))
43
44 def close(self):
45 self.flush()
Guido van Rossum13833561995-08-07 20:19:27 +000046
47
48TEMPLATE = """
49def %s(self, *args):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000050 return apply(getattr(self.mod, self.name).%s, args)
Guido van Rossum13833561995-08-07 20:19:27 +000051"""
52
53class FileDelegate(FileBase):
54
Guido van Rossum3ec38f01998-03-26 22:10:50 +000055 def __init__(self, mod, name):
56 self.mod = mod
57 self.name = name
58
59 for m in FileBase.ok_file_methods + ('close',):
60 exec TEMPLATE % (m, m)
Guido van Rossum13833561995-08-07 20:19:27 +000061
62
Guido van Rossum40d1ea31995-08-04 03:59:03 +000063class RHooks(ihooks.Hooks):
Guido van Rossum9a22de11995-01-12 12:29:47 +000064
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000065 def __init__(self, *args):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000066 # Hacks to support both old and new interfaces:
67 # old interface was RHooks(rexec[, verbose])
68 # new interface is RHooks([verbose])
69 verbose = 0
70 rexec = None
71 if args and type(args[-1]) == type(0):
72 verbose = args[-1]
73 args = args[:-1]
74 if args and hasattr(args[0], '__class__'):
75 rexec = args[0]
76 args = args[1:]
77 if args:
78 raise TypeError, "too many arguments"
79 ihooks.Hooks.__init__(self, verbose)
80 self.rexec = rexec
Guido van Rossum9a22de11995-01-12 12:29:47 +000081
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000082 def set_rexec(self, rexec):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000083 # Called by RExec instance to complete initialization
84 self.rexec = rexec
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000085
Guido van Rossum40d1ea31995-08-04 03:59:03 +000086 def is_builtin(self, name):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000087 return self.rexec.is_builtin(name)
Guido van Rossum9a22de11995-01-12 12:29:47 +000088
Guido van Rossum40d1ea31995-08-04 03:59:03 +000089 def init_builtin(self, name):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000090 m = __import__(name)
91 return self.rexec.copy_except(m, ())
Guido van Rossum9a22de11995-01-12 12:29:47 +000092
Guido van Rossum40d1ea31995-08-04 03:59:03 +000093 def init_frozen(self, name): raise SystemError, "don't use this"
94 def load_source(self, *args): raise SystemError, "don't use this"
95 def load_compiled(self, *args): raise SystemError, "don't use this"
Guido van Rossum8b3282b1998-06-29 20:32:57 +000096 def load_package(self, *args): raise SystemError, "don't use this"
Guido van Rossum40d1ea31995-08-04 03:59:03 +000097
Guido van Rossumfdd45cb1996-05-28 23:07:17 +000098 def load_dynamic(self, name, filename, file):
Guido van Rossum3ec38f01998-03-26 22:10:50 +000099 return self.rexec.load_dynamic(name, filename, file)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000100
101 def add_module(self, name):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000102 return self.rexec.add_module(name)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000103
104 def modules_dict(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000105 return self.rexec.modules
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000106
107 def default_path(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000108 return self.rexec.modules['sys'].path
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000109
110
Guido van Rossumf07029e1998-09-21 14:53:26 +0000111# XXX Backwards compatibility
112RModuleLoader = ihooks.FancyModuleLoader
113RModuleImporter = ihooks.ModuleImporter
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000114
115
116class RExec(ihooks._Verbose):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000117 """Basic restricted execution framework.
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000118
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000119 Code executed in this restricted environment will only have access to
120 modules and functions that are deemed safe; you can subclass RExec to
121 add or remove capabilities as desired.
122
123 The RExec class can prevent code from performing unsafe operations like
124 reading or writing disk files, or using TCP/IP sockets. However, it does
125 not protect against code using extremely large amounts of memory or
126 processor time.
127
128 """
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000129
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000130 ok_path = tuple(sys.path) # That's a policy decision
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000131
Guido van Rossume7b9fde1996-09-25 18:47:39 +0000132 ok_builtin_modules = ('audioop', 'array', 'binascii',
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000133 'cmath', 'errno', 'imageop',
134 'marshal', 'math', 'md5', 'operator',
135 'parser', 'regex', 'pcre', 'rotor', 'select',
Fred Drakea2d848e2001-06-22 18:19:16 +0000136 'sha', '_sre', 'strop', 'struct', 'time')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000137
138 ok_posix_names = ('error', 'fstat', 'listdir', 'lstat', 'readlink',
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000139 'stat', 'times', 'uname', 'getpid', 'getppid',
140 'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000141
142 ok_sys_names = ('ps1', 'ps2', 'copyright', 'version',
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000143 'platform', 'exit', 'maxint')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000144
Tim Peters8fa45672001-09-13 21:01:29 +0000145 nok_builtin_names = ('open', 'file', 'reload', '__import__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000146
147 def __init__(self, hooks = None, verbose = 0):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000148 """Returns an instance of the RExec class.
149
150 The hooks parameter is an instance of the RHooks class or a subclass
151 of it. If it is omitted or None, the default RHooks class is
152 instantiated.
153
154 Whenever the RExec module searches for a module (even a built-in one)
155 or reads a module's code, it doesn't actually go out to the file
156 system itself. Rather, it calls methods of an RHooks instance that
157 was passed to or created by its constructor. (Actually, the RExec
158 object doesn't make these calls --- they are made by a module loader
159 object that's part of the RExec object. This allows another level of
160 flexibility, which can be useful when changing the mechanics of
161 import within the restricted environment.)
162
163 By providing an alternate RHooks object, we can control the file
164 system accesses made to import a module, without changing the
165 actual algorithm that controls the order in which those accesses are
166 made. For instance, we could substitute an RHooks object that
167 passes all filesystem requests to a file server elsewhere, via some
168 RPC mechanism such as ILU. Grail's applet loader uses this to support
169 importing applets from a URL for a directory.
170
171 If the verbose parameter is true, additional debugging output may be
172 sent to standard output.
173
174 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000175 ihooks._Verbose.__init__(self, verbose)
176 # XXX There's a circular reference here:
177 self.hooks = hooks or RHooks(verbose)
178 self.hooks.set_rexec(self)
179 self.modules = {}
180 self.ok_dynamic_modules = self.ok_builtin_modules
181 list = []
182 for mname in self.ok_builtin_modules:
183 if mname in sys.builtin_module_names:
184 list.append(mname)
185 self.ok_builtin_modules = tuple(list)
186 self.set_trusted_path()
187 self.make_builtin()
188 self.make_initial_modules()
189 # make_sys must be last because it adds the already created
190 # modules to its builtin_module_names
191 self.make_sys()
192 self.loader = RModuleLoader(self.hooks, verbose)
193 self.importer = RModuleImporter(self.loader, verbose)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000194
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000195 def set_trusted_path(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000196 # Set the path from which dynamic modules may be loaded.
197 # Those dynamic modules must also occur in ok_builtin_modules
198 self.trusted_path = filter(os.path.isabs, sys.path)
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000199
200 def load_dynamic(self, name, filename, file):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000201 if name not in self.ok_dynamic_modules:
202 raise ImportError, "untrusted dynamic module: %s" % name
203 if sys.modules.has_key(name):
204 src = sys.modules[name]
205 else:
206 import imp
207 src = imp.load_dynamic(name, filename, file)
208 dst = self.copy_except(src, [])
209 return dst
Guido van Rossumfdd45cb1996-05-28 23:07:17 +0000210
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000211 def make_initial_modules(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000212 self.make_main()
213 self.make_osname()
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000214
215 # Helpers for RHooks
216
217 def is_builtin(self, mname):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000218 return mname in self.ok_builtin_modules
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000219
220 # The make_* methods create specific built-in modules
221
222 def make_builtin(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000223 m = self.copy_except(__builtin__, self.nok_builtin_names)
224 m.__import__ = self.r_import
225 m.reload = self.r_reload
Tim Peters8fa45672001-09-13 21:01:29 +0000226 m.open = m.file = self.r_open
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000227
228 def make_main(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000229 m = self.add_module('__main__')
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000230
231 def make_osname(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000232 osname = os.name
233 src = __import__(osname)
234 dst = self.copy_only(src, self.ok_posix_names)
235 dst.environ = e = {}
236 for key, value in os.environ.items():
237 e[key] = value
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000238
239 def make_sys(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000240 m = self.copy_only(sys, self.ok_sys_names)
241 m.modules = self.modules
242 m.argv = ['RESTRICTED']
243 m.path = map(None, self.ok_path)
Guido van Rossumeeb64281998-07-09 13:52:38 +0000244 m.exc_info = self.r_exc_info
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000245 m = self.modules['sys']
246 l = self.modules.keys() + list(self.ok_builtin_modules)
247 l.sort()
248 m.builtin_module_names = tuple(l)
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000249
250 # The copy_* methods copy existing modules with some changes
251
252 def copy_except(self, src, exceptions):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000253 dst = self.copy_none(src)
254 for name in dir(src):
255 setattr(dst, name, getattr(src, name))
256 for name in exceptions:
257 try:
258 delattr(dst, name)
259 except AttributeError:
260 pass
261 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000262
263 def copy_only(self, src, names):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000264 dst = self.copy_none(src)
265 for name in names:
266 try:
267 value = getattr(src, name)
268 except AttributeError:
269 continue
270 setattr(dst, name, value)
271 return dst
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000272
273 def copy_none(self, src):
Guido van Rossum1f40cd61998-06-09 21:33:44 +0000274 m = self.add_module(src.__name__)
275 m.__doc__ = src.__doc__
276 return m
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000277
278 # Add a module -- return an existing module or create one
279
280 def add_module(self, mname):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000281 if self.modules.has_key(mname):
282 return self.modules[mname]
283 self.modules[mname] = m = self.hooks.new_module(mname)
284 m.__builtins__ = self.modules['__builtin__']
285 return m
Guido van Rossum9a22de11995-01-12 12:29:47 +0000286
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000287 # The r* methods are public interfaces
Guido van Rossum9a22de11995-01-12 12:29:47 +0000288
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000289 def r_exec(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000290 """Execute code within a restricted environment.
291
292 The code parameter must either be a string containing one or more
293 lines of Python code, or a compiled code object, which will be
294 executed in the restricted environment's __main__ module.
295
296 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000297 m = self.add_module('__main__')
298 exec code in m.__dict__
Guido van Rossum9a22de11995-01-12 12:29:47 +0000299
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000300 def r_eval(self, code):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000301 """Evaluate code within a restricted environment.
302
303 The code parameter must either be a string containing a Python
304 expression, or a compiled code object, which will be evaluated in
305 the restricted environment's __main__ module. The value of the
306 expression or code object will be returned.
307
308 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000309 m = self.add_module('__main__')
310 return eval(code, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000311
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000312 def r_execfile(self, file):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000313 """Execute the Python code in the file in the restricted
314 environment's __main__ module.
315
316 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000317 m = self.add_module('__main__')
Fred Drakef9022962001-10-13 18:34:42 +0000318 execfile(file, m.__dict__)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000319
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000320 def r_import(self, mname, globals={}, locals={}, fromlist=[]):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000321 """Import a module, raising an ImportError exception if the module
322 is considered unsafe.
323
324 This method is implicitly called by code executing in the
325 restricted environment. Overriding this method in a subclass is
326 used to change the policies enforced by a restricted environment.
327
328 """
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000329 return self.importer.import_module(mname, globals, locals, fromlist)
Guido van Rossum9a22de11995-01-12 12:29:47 +0000330
Guido van Rossum13833561995-08-07 20:19:27 +0000331 def r_reload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000332 """Reload the module object, re-parsing and re-initializing it.
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 Rossum13833561995-08-07 20:19:27 +0000339 return self.importer.reload(m)
Guido van Rossumbebe5151995-08-09 02:32:08 +0000340
341 def r_unload(self, m):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000342 """Unload the module.
343
344 Removes it from the restricted environment's sys.modules dictionary.
345
346 This method is implicitly called by code executing in the
347 restricted environment. Overriding this method in a subclass is
348 used to change the policies enforced by a restricted environment.
349
350 """
Guido van Rossumbebe5151995-08-09 02:32:08 +0000351 return self.importer.unload(m)
Tim Peters0c9886d2001-01-15 01:18:21 +0000352
Guido van Rossum13833561995-08-07 20:19:27 +0000353 # The s_* methods are similar but also swap std{in,out,err}
354
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000355 def make_delegate_files(self):
Guido van Rossum13833561995-08-07 20:19:27 +0000356 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000357 self.delegate_stdin = FileDelegate(s, 'stdin')
358 self.delegate_stdout = FileDelegate(s, 'stdout')
359 self.delegate_stderr = FileDelegate(s, 'stderr')
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000360 self.restricted_stdin = FileWrapper(sys.stdin)
361 self.restricted_stdout = FileWrapper(sys.stdout)
362 self.restricted_stderr = FileWrapper(sys.stderr)
363
364 def set_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000365 if not hasattr(self, 'save_stdin'):
366 self.save_files()
367 if not hasattr(self, 'delegate_stdin'):
368 self.make_delegate_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000369 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000370 s.stdin = self.restricted_stdin
371 s.stdout = self.restricted_stdout
372 s.stderr = self.restricted_stderr
373 sys.stdin = self.delegate_stdin
374 sys.stdout = self.delegate_stdout
375 sys.stderr = self.delegate_stderr
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000376
377 def reset_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000378 self.restore_files()
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000379 s = self.modules['sys']
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000380 self.restricted_stdin = s.stdin
381 self.restricted_stdout = s.stdout
382 self.restricted_stderr = s.stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000383
Guido van Rossum13833561995-08-07 20:19:27 +0000384
385 def save_files(self):
386 self.save_stdin = sys.stdin
387 self.save_stdout = sys.stdout
388 self.save_stderr = sys.stderr
389
Guido van Rossumcd6aab91996-06-28 17:28:51 +0000390 def restore_files(self):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000391 sys.stdin = self.save_stdin
392 sys.stdout = self.save_stdout
393 sys.stderr = self.save_stderr
Tim Peters0c9886d2001-01-15 01:18:21 +0000394
Guido van Rossume7b9fde1996-09-25 18:47:39 +0000395 def s_apply(self, func, args=(), kw=None):
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000396 self.save_files()
397 try:
398 self.set_files()
399 if kw:
400 r = apply(func, args, kw)
401 else:
402 r = apply(func, args)
Guido van Rossum13833561995-08-07 20:19:27 +0000403 finally:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000404 self.restore_files()
Guido van Rossum183a2f22001-06-18 12:33:36 +0000405 return r
Tim Peters0c9886d2001-01-15 01:18:21 +0000406
Guido van Rossum13833561995-08-07 20:19:27 +0000407 def s_exec(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000408 """Execute code within a restricted environment.
409
410 Similar to the r_exec() method, but the code will be granted access
411 to restricted versions of the standard I/O streams sys.stdin,
412 sys.stderr, and sys.stdout.
413
414 The code parameter must either be a string containing one or more
415 lines of Python code, or a compiled code object, which will be
416 executed in the restricted environment's __main__ module.
417
418 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000419 return self.s_apply(self.r_exec, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000420
Guido van Rossum13833561995-08-07 20:19:27 +0000421 def s_eval(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000422 """Evaluate code within a restricted environment.
423
424 Similar to the r_eval() method, but the code will be granted access
425 to restricted versions of the standard I/O streams sys.stdin,
426 sys.stderr, and sys.stdout.
427
428 The code parameter must either be a string containing a Python
429 expression, or a compiled code object, which will be evaluated in
430 the restricted environment's __main__ module. The value of the
431 expression or code object will be returned.
Guido van Rossum183a2f22001-06-18 12:33:36 +0000432 return self.s_apply(self.r_eval, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000433
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000434 """
435
Guido van Rossum13833561995-08-07 20:19:27 +0000436 def s_execfile(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000437 """Execute the Python code in the file in the restricted
438 environment's __main__ module.
439
440 Similar to the r_execfile() method, but the code will be granted
441 access to restricted versions of the standard I/O streams sys.stdin,
442 sys.stderr, and sys.stdout.
443
444 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000445 return self.s_apply(self.r_execfile, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000446
Guido van Rossum13833561995-08-07 20:19:27 +0000447 def s_import(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000448 """Import a module, raising an ImportError exception if the module
449 is considered unsafe.
450
451 This method is implicitly called by code executing in the
452 restricted environment. Overriding this method in a subclass is
453 used to change the policies enforced by a restricted environment.
454
455 Similar to the r_import() method, but has access to restricted
456 versions of the standard I/O streams sys.stdin, sys.stderr, and
457 sys.stdout.
458
459 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000460 return self.s_apply(self.r_import, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000461
Guido van Rossum13833561995-08-07 20:19:27 +0000462 def s_reload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000463 """Reload the module object, re-parsing and re-initializing it.
464
465 This method is implicitly called by code executing in the
466 restricted environment. Overriding this method in a subclass is
467 used to change the policies enforced by a restricted environment.
468
469 Similar to the r_reload() method, but has access to restricted
470 versions of the standard I/O streams sys.stdin, sys.stderr, and
471 sys.stdout.
472
473 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000474 return self.s_apply(self.r_reload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000475
Guido van Rossumbebe5151995-08-09 02:32:08 +0000476 def s_unload(self, *args):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000477 """Unload the module.
478
479 Removes it from the restricted environment's sys.modules dictionary.
480
481 This method is implicitly called by code executing in the
482 restricted environment. Overriding this method in a subclass is
483 used to change the policies enforced by a restricted environment.
484
485 Similar to the r_unload() method, but has access to restricted
486 versions of the standard I/O streams sys.stdin, sys.stderr, and
487 sys.stdout.
488
489 """
Guido van Rossum183a2f22001-06-18 12:33:36 +0000490 return self.s_apply(self.r_unload, args)
Tim Peters0c9886d2001-01-15 01:18:21 +0000491
Guido van Rossum13833561995-08-07 20:19:27 +0000492 # Restricted open(...)
Tim Peters0c9886d2001-01-15 01:18:21 +0000493
Guido van Rossum13833561995-08-07 20:19:27 +0000494 def r_open(self, file, mode='r', buf=-1):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000495 """Method called when open() is called in the restricted environment.
496
497 The arguments are identical to those of the open() function, and a
498 file object (or a class instance compatible with file objects)
499 should be returned. RExec's default behaviour is allow opening
500 any file for reading, but forbidding any attempt to write a file.
501
502 This method is implicitly called by code executing in the
503 restricted environment. Overriding this method in a subclass is
504 used to change the policies enforced by a restricted environment.
505
506 """
Guido van Rossum13833561995-08-07 20:19:27 +0000507 if mode not in ('r', 'rb'):
508 raise IOError, "can't open files for writing in restricted mode"
Guido van Rossumbebe5151995-08-09 02:32:08 +0000509 return open(file, mode, buf)
Guido van Rossum13833561995-08-07 20:19:27 +0000510
Guido van Rossumeeb64281998-07-09 13:52:38 +0000511 # Restricted version of sys.exc_info()
512
513 def r_exc_info(self):
514 ty, va, tr = sys.exc_info()
515 tr = None
516 return ty, va, tr
517
Guido van Rossum9a22de11995-01-12 12:29:47 +0000518
519def test():
Guido van Rossum97dbec92001-08-13 15:58:26 +0000520 import getopt, traceback
Guido van Rossumeeb64281998-07-09 13:52:38 +0000521 opts, args = getopt.getopt(sys.argv[1:], 'vt:')
522 verbose = 0
523 trusted = []
524 for o, a in opts:
525 if o == '-v':
526 verbose = verbose+1
527 if o == '-t':
528 trusted.append(a)
529 r = RExec(verbose=verbose)
530 if trusted:
531 r.ok_builtin_modules = r.ok_builtin_modules + tuple(trusted)
532 if args:
533 r.modules['sys'].argv = args
534 r.modules['sys'].path.insert(0, os.path.dirname(args[0]))
535 else:
536 r.modules['sys'].path.insert(0, "")
537 fp = sys.stdin
538 if args and args[0] != '-':
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000539 try:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000540 fp = open(args[0])
541 except IOError, msg:
542 print "%s: can't open file %s" % (sys.argv[0], `args[0]`)
543 return 1
544 if fp.isatty():
545 print "*** RESTRICTED *** Python", sys.version
Guido van Rossum97dbec92001-08-13 15:58:26 +0000546 print 'Type "help", "copyright", "credits" or "license" ' \
547 'for more information.'
548
Guido van Rossumeeb64281998-07-09 13:52:38 +0000549 while 1:
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000550 try:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000551 try:
552 s = raw_input('>>> ')
553 except EOFError:
554 print
555 break
556 if s and s[0] != '#':
557 s = s + '\n'
558 c = compile(s, '<stdin>', 'single')
559 r.s_exec(c)
560 except SystemExit, n:
561 return n
562 except:
563 traceback.print_exc()
564 else:
565 text = fp.read()
566 fp.close()
567 c = compile(text, fp.name, 'exec')
568 try:
569 r.s_exec(c)
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000570 except SystemExit, n:
Guido van Rossumeeb64281998-07-09 13:52:38 +0000571 return n
Guido van Rossum3ec38f01998-03-26 22:10:50 +0000572 except:
573 traceback.print_exc()
Guido van Rossumeeb64281998-07-09 13:52:38 +0000574 return 1
Guido van Rossum40d1ea31995-08-04 03:59:03 +0000575
Guido van Rossum9a22de11995-01-12 12:29:47 +0000576
577if __name__ == '__main__':
Guido van Rossumeeb64281998-07-09 13:52:38 +0000578 sys.exit(test())