[Zope-Checkins] CVS: Zope3/lib/python/Zope/Security - RestrictedBuiltins.py:1.1.2.1 Checker.py:1.1.4.5 RestrictedInterpreter.py:1.1.4.2

Jim Fulton jim@zope.com
Thu, 23 May 2002 14:01:52 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Security
In directory cvs.zope.org:/tmp/cvs-serv26429/lib/python/Zope/Security

Modified Files:
      Tag: Zope-3x-branch
	Checker.py RestrictedInterpreter.py 
Added Files:
      Tag: Zope-3x-branch
	RestrictedBuiltins.py 
Log Message:
This all started with wanting to be able to use url;view in a ZPT path. :)

That lead me to:

- Massive traversal refactoring.

  Namespace handling is now centralized in Zope.App.Traversing. 

- ZPT refactoring, including some renaming that touches pretty much everything. :)

  - The application specific ZPT support was moved into
    Zope.App.PageTemplate. 

  - To get page template files (for use in views):

    from Zope.App.PageTemplate import ViewPageTemplateFile

  - Fixed up security so that ZPT expressions only have access to 
    safe builtins and so that modules namespace does imports safely.

  - Got ZPTPage working!

- renaming url to absolute_url and got absolute_url to work in paths.

- Cleaned up the (as yet unused) RestrictedInterpreter module in
  Zope.Security. In particular, changed to use a separate
  RestrictedBuiltins module.



=== Added File Zope3/lib/python/Zope/Security/RestrictedBuiltins.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
# 
##############################################################################
"""

Revision information:
$Id: RestrictedBuiltins.py,v 1.1.2.1 2002/05/23 18:01:22 jim Exp $
"""
import sys

def RestrictedBuiltins():

    from Proxy import ProxyFactory
    from Checker import NamesChecker

    # It's better to say what is safe than it say what is not safe
    _safe = [
        'ArithmeticError', 'AssertionError', 'AttributeError',
        'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError',
        'Exception', 'FloatingPointError', 'IOError', 'ImportError',
        'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt',
        'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented',
        'NotImplementedError', 'OSError', 'OverflowError', 'OverflowWarning',
        'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError',
        'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
        'SystemExit', 'TabError', 'TypeError', 'UnboundLocalError',
        'UnicodeError', 'UserWarning', 'ValueError', 'Warning',
        'ZeroDivisionError',
        '__debug__', '__doc__', '__name__', 'abs', 'apply', 'buffer',
        'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile',
        'complex', 'copyright', 'credits', 'delattr', 'dict',
        'divmod', 'eval', 'filter', 'float', 'getattr', 'globals',
        'hasattr', 'hash', 'hex', 'id', 'int', 'isinstance',
        'issubclass', 'iter', 'len', 'license', 'list', 'locals',
        'long', 'map', 'max', 'min', 'object', 'oct', 'ord', 'pow',
        'property', 'quit', 'range', 'reduce', 'repr', 'round',
        'setattr', 'slice', 'staticmethod', 'str', 'super', 'tuple',
        'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip',
        ]

    # XXX dir segfaults with a seg fault due to a bas tuple check in
    # merge_class_dict in object.c. The assert macro seems to be doing
    # the wrong think. Basically, if an object has bases, then bases
    # is assumed to be a tuple.
    
    # Anything that accesses an external file is a no no:
    # 'open', 'execfile', 'file'

    # We dont want restricted code to call exit: 'SystemExit', 'exit'

    # Other no nos:
    #    help prints
    #    input does I/O
    #    raw_input does I/O
    #    intern's effect is too global
    #    reload does import, XXX doesn't it use __import__?

    _builtinTypeChecker = NamesChecker(
        ['__str__', '__repr__', '__name__', '__module__',
         '__bases__', '__call__'])

    import __builtin__

    builtins = {}
    for name in _safe:
        value = getattr(__builtin__, name)
        if isinstance(value, type):
            value = ProxyFactory(value, _builtinTypeChecker)
        else:
            value = ProxyFactory(value)
        builtins[name] = value

    def __import__(name, globals=None, locals=None, fromlist=()):
        # Waaa, we have to emulate __import__'s weird semantics.
        try:
            module = sys.modules[name]
            if fromlist:
                return module

            l = name.find('.')
            if l < 0:
                return module

            return sys.modules[name[:l]]                
            
        except KeyError:
            raise ImportError(name)

    builtins['__import__'] = ProxyFactory(__import__)

    return builtins

RestrictedBuiltins = RestrictedBuiltins()


=== Zope3/lib/python/Zope/Security/Checker.py 1.1.4.4 => 1.1.4.5 ===
 from Interface import Interface
 from _Proxy import _Proxy as Proxy
-from types import InstanceType, ClassType, FunctionType, MethodType, ModuleType
 from ISecurityProxyFactory import ISecurityProxyFactory
 from Zope.Security.SecurityManagement import getSecurityManager
-import sys, os
+import sys, os, types
 
 if os.environ.get('ZOPE_WATCH_CHECKERS'):
     WATCH_CHECKERS = 1
@@ -273,7 +272,7 @@
     float: NoProxy,
     long: NoProxy,
     complex: NoProxy,
-    type(None): NoProxy,
+    types.NoneType: NoProxy,
     str: NoProxy,
     unicode: NoProxy,
     type(not 1): NoProxy, # Boolean, if available :)
@@ -291,13 +290,15 @@
     # YAGNI: () a rock
     tuple: NamesChecker(['__getitem__', '__getslice__',
                          '__contains__', '__len__', '__iter__']),
-    InstanceType: _instanceChecker,
+    types.InstanceType: _instanceChecker,
     Proxy: NoProxy,
-    ClassType: _classChecker,
-    FunctionType: _callableChecker,
-    MethodType: _callableChecker,
+    types.ClassType: _classChecker,
+    types.FunctionType: _callableChecker,
+    types.MethodType: _callableChecker,
+    types.BuiltinFunctionType: _callableChecker,
+    types.BuiltinMethodType: _callableChecker,
     type: _typeChecker,
-    ModuleType: _moduleChecker,
+    types.ModuleType: _moduleChecker,
     type(iter([])): NamesChecker(['next']),
     type(Interface): _interfaceChecker,
     }


=== Zope3/lib/python/Zope/Security/RestrictedInterpreter.py 1.1.4.1 => 1.1.4.2 ===
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+# 
+##############################################################################
+"""
+
+Revision information:
+$Id$
+"""
+
 import sys
 
-from Zope.Security.Proxy import ProxyFactory
+from Proxy import ProxyFactory
+from RestrictedBuiltins import RestrictedBuiltins
 
 class RestrictedInterpreter:
 
-    ok_builtin_modules = ('audioop', 'array', 'binascii',
-                          'cmath', 'errno', 'imageop',
-                          'marshal', 'math', 'md5', 'operator',
-                          'parser', 'regex', 'pcre', 'rotor', 'select',
-                          'sha', '_sre', 'strop', 'struct', 'time')
-
-    ok_sys_names = ('ps1', 'ps2', 'copyright', 'version',
-                    'platform', 'exit', 'maxint')
-
-    nok_builtin_names = ('open', 'file', 'reload', '__import__')
-
-    def __init__(self, checker):
-        self.checker = checker
-        self.builtins = {}
-        self.globals = {'__builtins__' : self.builtins}
-        self.create_builtins()
+    def __init__(self):
+        self.globals = {'__builtins__' : RestrictedBuiltins}
 
     def ri_exec(self, code):
         # what is the type of code?
         exec code in self.globals
-
-    def create_builtins(self):
-        import __builtin__
-        for k, v in __builtin__.__dict__.iteritems():
-            if k not in self.nok_builtin_names:
-                self.builtins[k] = ProxyFactory(v, self.checker)
-        self.builtins['__import__'] = ProxyFactory(self.ri_import)
-
-    def ri_import(self, name, globals, locals, fromlist):
-        # XXX handle fromlist
-        return sys.modules[name]