diff options
Diffstat (limited to 'Lib/rexec.py')
-rw-r--r-- | Lib/rexec.py | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/Lib/rexec.py b/Lib/rexec.py new file mode 100644 index 0000000..0e6ba20 --- /dev/null +++ b/Lib/rexec.py @@ -0,0 +1,184 @@ +# Implement restricted execution of Python code + +import __builtin__ +import new +import os +import sys +import types + +def trace(fmt, *args): + if 0: + sys.stderr.write(fmt % args + '\n') + +def copydict(src, dst, exceptions = [], only = None): + if only is None: + for key in src.keys(): + if key not in exceptions: + dst[key] = src[key] + else: + for key in only: + dst[key] = src[key] + +def copymodule(src, dst, exceptions = [], only = None): + copydict(src.__dict__, dst.__dict__, exceptions, only) + +safe_path = ['/ufs/guido/lib/python'] +safe_modules = ['array', 'math', 'regex', 'strop', 'time'] +unsafe_builtin_names = ['open', 'reload', '__import__', + 'eval', 'execfile', 'dir', 'vars', + 'raw_input', 'input'] +safe_posix_names = ['error', 'fstat', 'listdir', 'lstat', 'readlink', 'stat', + 'times', 'uname', 'getpid', 'getppid', 'getcwd', + 'getuid', 'getgid', 'geteuid', 'getegid'] + +safe_sys = new.module('sys') +safe_sys.modules = {} +safe_sys.modules['sys'] = safe_sys +safe_sys.path = safe_path[:] +safe_sys.argv = ['-'] +safe_sys.builtin_module_names = safe_modules[:] + ['posix'] +safe_sys.builtin_module_names.sort() +safe_sys.copyright = sys.copyright +safe_sys.version = sys.version + ' [restricted mode]' +safe_sys.exit = sys.exit + +def new_module(name): + safe_sys.modules[name] = m = new.module(name) + return m + +safe_builtin = new_module('__builtin__') +copymodule(__builtin__, safe_builtin, unsafe_builtin_names) + +safe_main = new_module('__main__') + +safe_posix = new_module('posix') +import posix +copymodule(posix, safe_posix, None, safe_posix_names) +safe_posix.environ = {} +copydict(posix.environ, safe_posix.environ) + +safe_types = new_module('types') +copymodule(types, safe_types) + +def safe_import(name): + if safe_sys.modules.has_key(name): + return safe_sys.modules[name] + if name in safe_modules: + temp = {} + exec "import "+name in temp + m = new_module(name) + copymodule(temp[name], m) + return m + for dirname in safe_path: + filename = os.path.join(dirname, name + '.py') + try: + f = open(filename, 'r') + f.close() + except IOError: + continue + m = new_module(name) + rexecfile(filename, m.__dict__) + return m + raise ImportError, name +safe_builtin.__import__ = safe_import + +def safe_open(file, mode = 'r'): + if type(file) != types.StringType or type(mode) != types.StringType: + raise TypeError, 'open argument(s) must be string(s)' + if mode not in ('r', 'rb'): + raise IOError, 'open for writing not allowed' + if '/' in file: + raise IOError, 'open pathname not allowed' + return open(file, mode) +safe_builtin.open = safe_open + +def safe_dir(object = safe_main): + keys = object.__dict__.keys() + keys.sort() + return keys +safe_builtin.dir = safe_dir + +def safe_vars(object = safe_main): + keys = safe_dir(object) + dict = {} + copydict(object.__dict__, dict, None, keys) + return dict +safe_builtin.vars = safe_vars + + +def exterior(): + """Return env of caller's caller, as triple: (name, locals, globals). + + Name will be None if env is __main__, and locals will be None if same + as globals, ie local env is global env.""" + + import sys, __main__ + + bogus = 'bogus' # A locally usable exception + try: raise bogus # Force an exception + except bogus: + at = sys.exc_traceback.tb_frame.f_back # The external frame. + if at.f_back: at = at.f_back # And further, if any. + where, globals, locals = at.f_code, at.f_globals, at.f_locals + if locals == globals: # Exterior is global? + locals = None + if where: + where = where.co_name + return (where, locals, globals) + + +def rexec(str, globals = None, locals = None): + trace('rexec(%s, ...)', `str`) + if globals is None: + globals = locals = exterior()[2] + elif locals is None: + locals = globals + globals['__builtins__'] = safe_builtin.__dict__ + safe_sys.stdout = sys.stdout + safe_sys.stderr = sys.stderr + exec str in globals, locals + +def rexecfile(file, globals = None, locals = None): + trace('rexecfile(%s, ...)', `file`) + if globals is None: + globals = locals = exterior()[2] + elif locals is None: + locals = globals + globals['__builtins__'] = safe_builtin.__dict__ + safe_sys.stdout = sys.stdout + safe_sys.stderr = sys.stderr + return execfile(file, globals, locals) + +def reval(str, globals = None, locals = None): + trace('reval(%s, ...)', `str`) + if globals is None: + globals = locals = exterior()[2] + elif locals is None: + locals = globals + globals['__builtins__'] = safe_builtin.__dict__ + safe_sys.stdout = sys.stdout + safe_sys.stderr = sys.stderr + return eval(str, globals, locals) +safe_builtin.eval = reval + + +def test(): + import traceback + g = {} + while 1: + try: + s = raw_input('--> ') + except EOFError: + break + try: + try: + c = compile(s, '', 'eval') + except: + rexec(s, g) + else: + print reval(c, g) + except: + traceback.print_exc() + +if __name__ == '__main__': + test() |