Commit 8997c967 authored by matt@zope.com's avatar matt@zope.com

Document Template accelerations and additonal C Security Manager accelerations

from cAccessControl-review-branch.
parent a7131d9f
......@@ -89,6 +89,11 @@ Zope Changes
- API help topics can now document functions as well as classes.
- Security accelerations in c
- Accelerated C Document Template handling; Document Templates
can now do additional rendering in C, improving performance.
Bugs fixed
- WebDAV: Zope escaped nested object properties derived from
......
......@@ -148,6 +148,16 @@ Security issues
2.5+)
ZSP_OWNEROUS_SKIP
If set, will cause the Zope Security Policy to skip checks relating
to ownership, for servers on which ownership is not important.
ZSP_AUTHENTICATED_SKIP
If set, will cause the Zope Security Policy to skip checks relating
to authentication, for servers which serve only anonymous content.
DISALLOW_LOCAL_PRODUCTS
unknown
......
......@@ -84,26 +84,42 @@
##############################################################################
'''Add security system support to Document Templates
$Id: DTML.py,v 1.7 2001/06/21 17:16:31 shane Exp $'''
__version__='$Revision: 1.7 $'[11:-2]
$Id: DTML.py,v 1.8 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.8 $'[11:-2]
from DocumentTemplate import DT_Util
import SecurityManagement, string, math, whrandom, random
import DocumentTemplate.sequence
from ZopeGuards import guarded_getattr, guarded_getitem, _marker
from ZopeGuards import guarded_getattr, guarded_getitem
class RestrictedDTML:
'''
A mix-in for derivatives of DT_String.String that adds Zope security.
'''
def guarded_getattr(self, ob, name, default=_marker):
return guarded_getattr(ob, name, default)
def guarded_getattr(self, *args): # ob, name [, default]
return guarded_getattr(*args)
def guarded_getitem(self, ob, index):
return guarded_getitem(ob, index)
try:
#raise ImportError
import os
if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
raise ImportError # :)
from cAccessControl import RestrictedDTMLMixin
except ImportError:
pass
else:
class RestrictedDTML(RestrictedDTMLMixin, RestrictedDTML):
'''
A mix-in for derivatives of DT_String.String that adds Zope security.
'''
# Allow access to unprotected attributes
DT_Util.TemplateDict.__allow_access_to_unprotected_subobjects__=1
string.__allow_access_to_unprotected_subobjects__=1
......
......@@ -85,8 +85,8 @@
__doc__='''Objects that implement Permission-based roles.
$Id: PermissionRole.py,v 1.12 2001/10/19 15:12:25 shane Exp $'''
__version__='$Revision: 1.12 $'[11:-2]
$Id: PermissionRole.py,v 1.13 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.13 $'[11:-2]
_use_python_impl = 0
import os
......
......@@ -85,8 +85,21 @@
__doc__='''short description
$Id: SecurityManagement.py,v 1.4 2001/07/02 16:29:55 evan Exp $'''
__version__='$Revision: 1.4 $'[11:-2]
$Id: SecurityManagement.py,v 1.5 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.5 $'[11:-2]
def getSecurityManager():
"""Get a security manager, for the current thread.
"""
thread_id=get_ident()
manager=_managers.get(thread_id, None)
if manager is None:
manager=SecurityManager(
thread_id,
SecurityContext(SpecialUsers.nobody))
_managers[thread_id]=manager
return manager
import SpecialUsers
from SecurityManager import SecurityManager
......@@ -110,19 +123,6 @@ def noSecurityManager():
except: pass
def getSecurityManager():
"""Get a security manager, for the current thread.
"""
thread_id=get_ident()
manager=_managers.get(thread_id, None)
if manager is None:
manager=SecurityManager(
thread_id,
SecurityContext(SpecialUsers.nobody))
_managers[thread_id]=manager
return manager
def setSecurityPolicy(aSecurityPolicy):
"""Set the system default security policy.
......
......@@ -85,8 +85,8 @@
__doc__='''short description
$Id: SecurityManager.py,v 1.7 2001/10/19 15:12:25 shane Exp $'''
__version__='$Revision: 1.7 $'[11:-2]
$Id: SecurityManager.py,v 1.8 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.8 $'[11:-2]
import ZopeSecurityPolicy, os, string
......@@ -95,7 +95,12 @@ _noroles = ZopeSecurityPolicy._noroles
try: max_stack_size=string.atoi(os.environ.get('Z_MAX_STACK_SIZE','100'))
except: max_stack_size=100
_defaultPolicy=ZopeSecurityPolicy.ZopeSecurityPolicy()
if os.environ.has_key("ZSP_OWNEROUS_SKIP"): ownerous=0
else: ownerous=1
if os.environ.has_key("ZSP_AUTHENTICATION_SKIP"): authenticated=0
else: authenticated=1
_defaultPolicy=ZopeSecurityPolicy.ZopeSecurityPolicy(ownerous=ownerous,
authenticated=authenticated)
def setSecurityPolicy(aSecurityPolicy):
"""Set the system default security policy.
......@@ -107,6 +112,7 @@ def setSecurityPolicy(aSecurityPolicy):
_defaultPolicy=aSecurityPolicy
return last
class SecurityManager:
"""A security manager provides methods for checking access and managing
executable context and policies
......@@ -120,7 +126,7 @@ class SecurityManager:
def __init__(self, thread_id, context):
self._thread_id=thread_id
self._context=context
self._policy=None
self._policy=_defaultPolicy
def validate(self, accessed=None, container=None, name=None, value=None,
roles=_noroles):
......@@ -144,7 +150,6 @@ class SecurityManager:
all the values possible.
"""
policy=self._policy
if policy is None: policy=_defaultPolicy
if roles is _noroles:
return policy.validate(accessed, container, name, value,
self._context)
......@@ -153,7 +158,7 @@ class SecurityManager:
self._context, roles)
def DTMLValidate(self, accessed=None, container=None, name=None,
value=None,md=None):
value=None, md=None):
"""Validate access.
* THIS EXISTS FOR DTML COMPATIBILITY *
......@@ -177,7 +182,6 @@ class SecurityManager:
"""
policy=self._policy
if policy is None: policy=_defaultPolicy
return policy.validate(accessed, container, name, value,
self._context)
......@@ -185,7 +189,6 @@ class SecurityManager:
"""Convenience for common case of simple value validation.
"""
policy=self._policy
if policy is None: policy=_defaultPolicy
if roles is _noroles:
return policy.validate(None, None, None, value,
self._context)
......@@ -204,7 +207,6 @@ class SecurityManager:
object -- The object being accessed according to the permission
"""
policy=self._policy
if policy is None: policy=_defaultPolicy
return policy.checkPermission(permission, object,
self._context)
......@@ -218,7 +220,10 @@ class SecurityManager:
raise SystemError, 'Excessive recursion'
stack.append(anExecutableObject)
p=getattr(anExecutableObject, '_customSecurityPolicy', None)
if p is not None: p=p()
if p is not None:
p=p()
else:
p=_defaultPolicy
self._policy=p
def removeContext(self, anExecutableObject,
......@@ -245,10 +250,13 @@ class SecurityManager:
if stack:
top=stack[-1]
p=getattr(top, '_customSecurityPolicy', None)
if p is not None: p=p()
if p is not None:
p=p()
else:
p=_defaultPolicy
self._policy=p
else:
self._policy=None
self._policy=_defaultPolicy
def getUser(self):
"""Get the current authenticated user"""
......@@ -260,3 +268,17 @@ class SecurityManager:
return len(self._context.stack)
try:
#raise ImportError
import os
if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
raise ImportError # :)
from cAccessControl import SecurityManager as cSecurityManager
except ImportError:
pass
else:
class SecurityManager(cSecurityManager, SecurityManager):
"""A security manager provides methods for checking access and managing
executable context and policies
"""
......@@ -83,7 +83,7 @@
#
##############################################################################
__version__='$Revision: 1.7 $'[11:-2]
__version__='$Revision: 1.8 $'[11:-2]
from RestrictedPython.Guards import safe_builtins, _full_read_guard, \
full_write_guard
......@@ -98,10 +98,21 @@ _marker = [] # Create a new marker object.
safe_builtins = safe_builtins.copy()
safe_builtins.update(utility_builtins)
def aq_validate(inst, obj, name, v, validate):
try:
#raise ImportError
import os
if os.environ.get("ZOPE_SECURITY_POLICY", None) == "PYTHON":
raise ImportError # :)
from cAccessControl import aq_validate, guarded_getattr
except ImportError:
def aq_validate(inst, obj, name, v, validate):
return validate(inst, obj, name, v)
def guarded_getattr(inst, name, default=_marker):
def guarded_getattr(inst, name, default=_marker):
if name[:1] != '_':
# Try to get the attribute normally so that unusual
# exceptions are caught early.
......@@ -121,6 +132,7 @@ def guarded_getattr(inst, name, default=_marker):
if validate(inst, inst, name, v):
return v
raise Unauthorized, name
safe_builtins['getattr'] = guarded_getattr
def guarded_hasattr(object, name):
......
......@@ -85,8 +85,8 @@
__doc__='''Define Zope\'s default security policy
$Id: ZopeSecurityPolicy.py,v 1.14 2001/10/19 15:12:25 shane Exp $'''
__version__='$Revision: 1.14 $'[11:-2]
$Id: ZopeSecurityPolicy.py,v 1.15 2001/10/26 16:07:50 matt Exp $'''
__version__='$Revision: 1.15 $'[11:-2]
_use_python_impl = 0
......@@ -119,8 +119,32 @@ if _use_python_impl:
class ZopeSecurityPolicy:
def __init__(self, ownerous=1):
def __init__(self, ownerous=1, authenticated=1):
"""Create a Zope security policy.
Two optional keyword arguments may be provided:
ownerous -- Untrusted users can create code
(e.g. Python scripts or templates),
so check that code owners can access resources.
The argument must have a truth value.
The default is true.
authenticated -- Allow access to resources based on the
privaledges of the authenticated user.
The argument must have a truth value.
The default is true.
This (somewhat experimental) option can be set
to false on sites that allow only public
(unauthenticated) access. An anticipated
scenario is a ZEO configuration in which some
clients allow only public access and other
clients allow full management.
"""
self._ownerous=ownerous
self._authenticated=authenticated
def validate(self, accessed, container, name, value, context,
roles=_noroles, None=None, type=type, IntType=type(0),
......@@ -239,7 +263,8 @@ if _use_python_impl:
try:
if context.user.allowed(value, roles): return 1
if self._authenticated and context.user.allowed(value, roles):
return 1
except AttributeError: pass
# We don't want someone to acquire if they can't get an unacquired!
......@@ -254,4 +279,3 @@ if _use_python_impl:
if type(roles) is StringType:
roles=[roles]
return context.user.allowed(object, roles)
......@@ -36,7 +36,7 @@
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
$Id: cAccessControl.c,v 1.11 2001/10/19 15:12:25 shane Exp $
$Id: cAccessControl.c,v 1.12 2001/10/26 16:07:50 matt Exp $
If you have questions regarding this software,
contact:
......@@ -49,6 +49,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include "ExtensionClass.h"
#include "Acquisition.h"
......@@ -66,18 +67,24 @@ PyVar_Assign(PyObject **v, PyObject *e)
#define OBJECT(o) ((PyObject *) (o))
static PyObject *
callmethod1(PyObject *self, PyObject *name, PyObject *arg)
callfunction1(PyObject *function, PyObject *arg)
{
UNLESS(self = PyObject_GetAttr(self,name)) return NULL;
name = PyTuple_New(1);
if (name == NULL) {
Py_DECREF(self);
PyObject *t, *r;
t = PyTuple_New(1);
if (t == NULL)
return NULL;
}
Py_INCREF(arg);
PyTuple_SET_ITEM(name, 0, arg);
ASSIGN(self, PyObject_CallObject(self, name));
Py_DECREF(name);
PyTuple_SET_ITEM(t, 0, arg);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static PyObject *
callmethod1(PyObject *self, PyObject *name, PyObject *arg)
{
UNLESS(self = PyObject_GetAttr(self,name)) return NULL;
ASSIGN(self, callfunction1(self, arg));
return self;
}
......@@ -97,6 +104,198 @@ callfunction2(PyObject *function, PyObject *arg0, PyObject *arg1)
return r;
}
static PyObject *
callfunction3(PyObject *function,
PyObject *arg0, PyObject *arg1,
PyObject *arg2
)
{
PyObject *t, *r;
t = PyTuple_New(3);
if (t == NULL)
return NULL;
Py_INCREF(arg0);
Py_INCREF(arg1);
Py_INCREF(arg2);
PyTuple_SET_ITEM(t, 0, arg0);
PyTuple_SET_ITEM(t, 1, arg1);
PyTuple_SET_ITEM(t, 2, arg2);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static PyObject *
callfunction4(PyObject *function,
PyObject *arg0, PyObject *arg1,
PyObject *arg2, PyObject *arg3
)
{
PyObject *t, *r;
t = PyTuple_New(4);
if (t == NULL)
return NULL;
Py_INCREF(arg0);
Py_INCREF(arg1);
Py_INCREF(arg2);
Py_INCREF(arg3);
PyTuple_SET_ITEM(t, 0, arg0);
PyTuple_SET_ITEM(t, 1, arg1);
PyTuple_SET_ITEM(t, 2, arg2);
PyTuple_SET_ITEM(t, 3, arg3);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static PyObject *
callfunction5(PyObject *function,
PyObject *arg0, PyObject *arg1,
PyObject *arg2, PyObject *arg3, PyObject *arg4
)
{
PyObject *t, *r;
t = PyTuple_New(5);
if (t == NULL)
return NULL;
Py_INCREF(arg0);
Py_INCREF(arg1);
Py_INCREF(arg2);
Py_INCREF(arg3);
Py_INCREF(arg4);
PyTuple_SET_ITEM(t, 0, arg0);
PyTuple_SET_ITEM(t, 1, arg1);
PyTuple_SET_ITEM(t, 2, arg2);
PyTuple_SET_ITEM(t, 3, arg3);
PyTuple_SET_ITEM(t, 4, arg4);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static PyObject *
callfunction6(PyObject *function,
PyObject *arg0, PyObject *arg1,
PyObject *arg2, PyObject *arg3,
PyObject *arg4, PyObject *arg5
)
{
PyObject *t, *r;
t = PyTuple_New(6);
if (t == NULL)
return NULL;
Py_INCREF(arg0);
Py_INCREF(arg1);
Py_INCREF(arg2);
Py_INCREF(arg3);
Py_INCREF(arg4);
Py_INCREF(arg5);
PyTuple_SET_ITEM(t, 0, arg0);
PyTuple_SET_ITEM(t, 1, arg1);
PyTuple_SET_ITEM(t, 2, arg2);
PyTuple_SET_ITEM(t, 3, arg3);
PyTuple_SET_ITEM(t, 4, arg4);
PyTuple_SET_ITEM(t, 5, arg5);
r = PyObject_CallObject(function, t);
Py_DECREF(t);
return r;
}
static int
unpacktuple1(PyObject *args, char *name, int min, PyObject **a0)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
return 0;
}
static int
unpacktuple2(PyObject *args, char *name, int min,
PyObject **a0, PyObject **a1)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
if (l > 1) *a1=PyTuple_GET_ITEM(args, 1);
return 0;
}
static int
unpacktuple3(PyObject *args, char *name, int min,
PyObject **a0, PyObject **a1, PyObject **a2)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
if (l > 1) *a1=PyTuple_GET_ITEM(args, 1);
if (l > 2) *a2=PyTuple_GET_ITEM(args, 2);
return 0;
}
static int
unpacktuple5(PyObject *args, char *name, int min,
PyObject **a0, PyObject **a1, PyObject **a2,
PyObject **a3, PyObject **a4)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
if (l > 1) *a1=PyTuple_GET_ITEM(args, 1);
if (l > 2) *a2=PyTuple_GET_ITEM(args, 2);
if (l > 3) *a3=PyTuple_GET_ITEM(args, 3);
if (l > 4) *a4=PyTuple_GET_ITEM(args, 4);
return 0;
}
static int
unpacktuple6(PyObject *args, char *name, int min,
PyObject **a0, PyObject **a1, PyObject **a2,
PyObject **a3, PyObject **a4, PyObject **a5)
{
int l;
l=PyTuple_Size(args);
if (l < 0) return -1;
if (l < min)
{
PyErr_Format(PyExc_TypeError, "expected %d arguments, got %d", min, l);
return -1;
}
if (l > 0) *a0=PyTuple_GET_ITEM(args, 0);
if (l > 1) *a1=PyTuple_GET_ITEM(args, 1);
if (l > 2) *a2=PyTuple_GET_ITEM(args, 2);
if (l > 3) *a3=PyTuple_GET_ITEM(args, 3);
if (l > 4) *a4=PyTuple_GET_ITEM(args, 4);
if (l > 5) *a5=PyTuple_GET_ITEM(args, 5);
return 0;
}
/*
** Structures
......@@ -106,6 +305,15 @@ typedef struct {
PyObject_HEAD
} ZopeSecurityPolicy;
typedef struct {
PyObject_HEAD
PyObject *thread_id;
PyObject *context;
PyObject *policy;
PyObject *validate;
PyObject *checkPermission;
} SecurityManager;
typedef struct {
PyObject_HEAD
PyObject *__name__;
......@@ -142,11 +350,26 @@ static PyObject *imPermissionRole_get(imPermissionRole *self,
static void imPermissionRole_dealloc(imPermissionRole *self);
static PyObject *rolesForPermissionOn(PyObject *self, PyObject *args);
static PyObject *module_guarded_getattr(PyObject *self, PyObject *args);
static PyObject *module_aq_validate(PyObject *self, PyObject *args);
static PyObject *c_rolesForPermissionOn(PyObject *self, PyObject *perm,
PyObject *object, PyObject *deflt);
static PyObject *permissionName(PyObject *name);
static PyObject *SecurityManager_validate(SecurityManager *self,
PyObject *args);
static PyObject *SecurityManager_validateValue(SecurityManager *self,
PyObject *args);
static PyObject *SecurityManager_DTMLValidate(SecurityManager *self,
PyObject *args);
static PyObject *SecurityManager_checkPermission(SecurityManager *self,
PyObject *args);
static void SecurityManager_dealloc(SecurityManager *self);
static PyObject *SecurityManager_getattro(SecurityManager *self,
PyObject *name);
static int SecurityManager_setattro(SecurityManager *self,
PyObject *name, PyObject *value);
/*
** Constants
*/
......@@ -157,6 +380,16 @@ static PyMethodDef cAccessControl_methods[] = {
METH_VARARGS,
""
},
{"guarded_getattr",
(PyCFunction)module_guarded_getattr,
METH_VARARGS,
""
},
{"aq_validate",
(PyCFunction)module_aq_validate,
METH_VARARGS,
""
},
{ NULL, NULL }
};
......@@ -214,6 +447,70 @@ static PyExtensionClass ZopeSecurityPolicyType = {
};
static char SecurityManager__doc__[] = "ZopeSecurityPolicy C implementation";
static PyMethodDef SecurityManager_methods[] = {
{"validate",
(PyCFunction)SecurityManager_validate,
METH_VARARGS,
""
},
{"DTMLValidate",
(PyCFunction)SecurityManager_DTMLValidate,
METH_VARARGS,
""
},
{"validateValue",
(PyCFunction)SecurityManager_validateValue,
METH_VARARGS,
""
},
{"checkPermission",
(PyCFunction)SecurityManager_checkPermission,
METH_VARARGS,
""
},
{ NULL, NULL }
};
static PyExtensionClass SecurityManagerType = {
PyObject_HEAD_INIT(NULL) 0,
"SecurityManager", /* tp_name */
sizeof(SecurityManager), /* tp_basicsize */
0, /* tp_itemsize */
/* Standard methods */
(destructor) SecurityManager_dealloc,/* tp_dealloc */
NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_compare */
NULL, /* tp_repr */
/* Method suites */
NULL, /* tp_as_number */
NULL, /* tp_as_sequence*/
NULL, /* tp_as_mapping */
/* More standard ops */
NULL, /* tp_hash */
NULL, /* tp_call */
NULL, /* tp_str */
(getattrofunc)SecurityManager_getattro, /* tp_getattro */
(setattrofunc)SecurityManager_setattro, /* tp_setattro */
/* Reserved fields */
0, /* tp_xxx3 */
0, /* tp_xxx4 */
/* Docstring */
SecurityManager__doc__, /* tp_doc */
#ifdef COUNT_ALLOCS
0, /* tp_alloc */
0, /* tp_free */
0, /* tp_maxalloc */
NULL, /* tp_next */
#endif
METHOD_CHAIN(SecurityManager_methods), /* methods */
0, /* flags */
};
static char PermissionRole__doc__[] = "PermissionRole C implementation";
static PyMethodDef PermissionRole_methods[] = {
......@@ -353,9 +650,15 @@ static PyObject *__of__ = NULL;
static PyObject *__allow_access_to_unprotected_subobjects__ = NULL;
static PyObject *stack_str = NULL;
static PyObject *user_str = NULL;
static PyObject *validate_str = NULL;
static PyObject *_proxy_roles_str = NULL;
static PyObject *allowed_str = NULL;
static PyObject *getOwner_str = NULL;
static PyObject *checkPermission_str = NULL;
static PyObject *getSecurityManager = NULL;
static PyObject *aq_validate = NULL;
static int ownerous = 1;
static int authenticated = 1;
/* --------------------------------------------------------------
** ZopeSecurityPolicy Methods
......@@ -383,14 +686,22 @@ ZopeSecurityPolicy_setup(void) {
UNLESS (AnonymousTuple = Py_BuildValue("(s)", "Anonymous")) return -1;
UNLESS (stack_str = PyString_FromString("stack")) return -1;
UNLESS (user_str = PyString_FromString("user")) return -1;
UNLESS (validate_str = PyString_FromString("validate")) return -1;
UNLESS (_proxy_roles_str = PyString_FromString("_proxy_roles"))
return -1;
UNLESS (allowed_str = PyString_FromString("allowed")) return -1;
UNLESS (getOwner_str = PyString_FromString("getOwner")) return -1;
UNLESS (checkPermission_str = PyString_FromString("checkPermission"))
return -1;
UNLESS (__allow_access_to_unprotected_subobjects__ =
PyString_FromString(
"__allow_access_to_unprotected_subobjects__"))
return -1;
if (getenv("ZSP_OWNEROUS_SKIP") != NULL) ownerous = 0;
if (getenv("ZSP_AUTHENTICATED_SKIP") != NULL) authenticated = 0;
return 0;
}
......@@ -438,8 +749,9 @@ static PyObject *ZopeSecurityPolicy_validate(PyObject *self, PyObject *args) {
**| roles=_noroles ...
*/
if (!PyArg_ParseTuple(args, "OOOOO|O", &accessed, &container,
&name, &value, &context, &roles)) return NULL;
if (unpacktuple6(args, "validate", 5, &accessed, &container,
&name, &value, &context, &roles) < 0)
return NULL;
/*| # Provide special rules for acquisition attributes
**| if type(name) is StringType:
......@@ -704,6 +1016,8 @@ static PyObject *ZopeSecurityPolicy_validate(PyObject *self, PyObject *args) {
eo = PySequence_GetItem(stack, -1);
if (eo == NULL) goto err;
if (ownerous) { /* Tabbing not adjusted for diff reasons*/
owner = PyObject_GetAttr(eo, getOwner_str);
if (owner) ASSIGN(owner, PyObject_CallObject(owner, NULL));
if (owner ==NULL)
......@@ -735,6 +1049,8 @@ static PyObject *ZopeSecurityPolicy_validate(PyObject *self, PyObject *args) {
}
Py_DECREF(owner);
} /* End of if ownerous */
/*| # Proxy roles, which are a lot safer now
**| proxy_roles = getattr(eo, "_proxy_roles", None)
**| if proxy_roles:
......@@ -805,6 +1121,7 @@ static PyObject *ZopeSecurityPolicy_validate(PyObject *self, PyObject *args) {
**| if context.user.allowed(value, roles): return 1
**| except AttributeError: pass
*/
if (authenticated) { /* Authentication skip for public only access */
user = PyObject_GetAttr(context, user_str);
if (user) ASSIGN(user, PyObject_GetAttr(user, allowed_str));
if (user == NULL)
......@@ -826,6 +1143,7 @@ static PyObject *ZopeSecurityPolicy_validate(PyObject *self, PyObject *args) {
}
Py_DECREF(user);
}
} /* End of authentiction skip for public only access */
/*| # we don't want someone to acquire if they can't get an
**| # unacquired!
......@@ -869,7 +1187,8 @@ static PyObject *ZopeSecurityPolicy_checkPermission(PyObject *self,
/*| def checkPermission(self, permission, object, context)
*/
if (!PyArg_ParseTuple(args, "OOO", &permission, &object, &context))
if (unpacktuple3(args, "checkPermission", 3,
&permission, &object, &context) < 0)
return NULL;
/*| roles = rolesForPermissionOn(permission, object)
......@@ -921,10 +1240,180 @@ static PyObject *ZopeSecurityPolicy_checkPermission(PyObject *self,
static void ZopeSecurityPolicy_dealloc(ZopeSecurityPolicy *self) {
Py_DECREF(self->ob_type); /* Extensionclass init incref'd */
PyMem_DEL(self);
}
/* SecurityManager */
#define CHECK_SECURITY_MANAGER_STATE(self, R) \
UNLESS (self->policy) { \
PyErr_SetString(PyExc_AttributeError, "_policy"); return R; } \
UNLESS (self->context) { \
PyErr_SetString(PyExc_AttributeError, "_policy"); return R; }
#define GET_SECURITY_MANAGER_VALIDATE(self, R) \
if (self->validate == NULL && \
((self->validate = PyObject_GetAttr(self->policy, validate_str)) \
== NULL)) return R;
static PyObject *
SecurityManager_validate(SecurityManager *self, PyObject *args)
{
PyObject *accessed=Py_None, *container=Py_None, *name=Py_None,
*value=Py_None, *roles=NULL;
if (unpacktuple5(args, "validate", 0,
&accessed, &container, &name, &value, &roles) < 0)
return NULL;
CHECK_SECURITY_MANAGER_STATE(self, NULL);
GET_SECURITY_MANAGER_VALIDATE(self, NULL);
if (roles== NULL)
return callfunction5(self->validate,
accessed, container, name, value, self->context);
return callfunction6(self->validate,
accessed, container, name, value, self->context, roles);
}
static PyObject *
SecurityManager_validateValue(SecurityManager *self, PyObject *args)
{
PyObject *value=Py_None, *roles=NULL;
if (unpacktuple2(args, "validateValue", 1, &value, &roles) < 0) return NULL;
CHECK_SECURITY_MANAGER_STATE(self, NULL);
GET_SECURITY_MANAGER_VALIDATE(self, NULL);
if (roles==NULL)
return callfunction5(self->validate,
Py_None, Py_None, Py_None, value, self->context);
return callfunction6(self->validate,
Py_None, Py_None, Py_None, value, self->context, roles);
}
static PyObject *
SecurityManager_DTMLValidate(SecurityManager *self, PyObject *args)
{
PyObject *accessed=Py_None, *container=Py_None, *name=Py_None,
*value=Py_None, *md=NULL;
if (unpacktuple5(args, "DTMLValidate", 0,
&accessed, &container, &name, &value, &md) < 0)
return NULL;
CHECK_SECURITY_MANAGER_STATE(self, NULL);
GET_SECURITY_MANAGER_VALIDATE(self, NULL);
return callfunction5(self->validate,
accessed, container, name, value, self->context);
}
static PyObject *
SecurityManager_checkPermission(SecurityManager *self, PyObject *args)
{
PyObject *permission, *object;
if (unpacktuple2(args, "checkPermission", 2, &permission, &object) < 0)
return NULL;
CHECK_SECURITY_MANAGER_STATE(self, NULL);
if (self->checkPermission == NULL &&
((self->checkPermission = PyObject_GetAttr(self->policy,
checkPermission_str))
== NULL)) return NULL;
return callfunction3(self->checkPermission,
permission, object, self->context);
}
static void
SecurityManager_dealloc(SecurityManager *self)
{
Py_XDECREF(self->thread_id);
Py_XDECREF(self->context);
Py_XDECREF(self->policy);
Py_XDECREF(self->validate);
Py_XDECREF(self->checkPermission);
Py_DECREF(self->ob_type); /* Extensionclass init incref'd */
PyMem_DEL(self);
}
static PyObject *
SecurityManager_getattro(SecurityManager *self, PyObject *name)
{
if (PyString_Check(name) && PyString_AS_STRING(name)[0]=='_')
{
if (strcmp(PyString_AS_STRING(name), "_thread_id")==0
&& self->thread_id)
{
Py_INCREF(self->thread_id);
return self->thread_id;
}
else if (strcmp(PyString_AS_STRING(name), "_context")==0
&& self->context)
{
Py_INCREF(self->context);
return self->context;
}
else if (strcmp(PyString_AS_STRING(name), "_policy")==0
&& self->policy)
{
Py_INCREF(self->policy);
return self->policy;
}
}
return Py_FindAttr(OBJECT(self), name);
}
static int
SecurityManager_setattro(SecurityManager *self, PyObject *name, PyObject *v)
{
if (v && PyString_Check(name) && PyString_AS_STRING(name)[0]=='_')
{
if (strcmp(PyString_AS_STRING(name), "_thread_id")==0)
{
Py_INCREF(v);
ASSIGN(self->thread_id, v);
return 0;
}
else if (strcmp(PyString_AS_STRING(name), "_context")==0)
{
Py_INCREF(v);
ASSIGN(self->context, v);
return 0;
}
else if (strcmp(PyString_AS_STRING(name), "_policy")==0)
{
Py_INCREF(v);
ASSIGN(self->policy, v);
if (self->validate)
{
Py_DECREF(self->validate);
self->validate=0;
}
if (self->checkPermission)
{
Py_DECREF(self->checkPermission);
self->checkPermission=0;
}
return 0;
}
}
PyErr_SetObject(PyExc_AttributeError, name);
return -1;
}
/*
** PermissionRole_init
**
......@@ -941,7 +1430,7 @@ static PyObject *PermissionRole_init(PermissionRole *self, PyObject *args) {
**| self._d = default
*/
if (!PyArg_ParseTuple(args, "O|O", &name, &deflt)) return NULL;
if (unpacktuple2(args, "__init__", 1, &name, &deflt) < 0) return NULL;
if (deflt == NULL) deflt = defaultPermission;
......@@ -972,7 +1461,7 @@ static PyObject *PermissionRole_of(PermissionRole *self, PyObject *args) {
/*|def __of__(self, parent):
*/
if (!PyArg_ParseTuple(args,"O", &parent)) return NULL;
if (unpacktuple1(args,"__of__", 1, &parent) < 0) return NULL;
/*| r = imPermissionRole()
*/
......@@ -1061,7 +1550,7 @@ static PyObject *imPermissionRole_of(imPermissionRole *self, PyObject *args) {
**| r = None
*/
if (!PyArg_ParseTuple(args, "O", &parent)) return NULL;
if (unpacktuple1(args, "__of__", 1, &parent) < 0) return NULL;
obj = parent;
Py_INCREF(obj);
......@@ -1345,7 +1834,8 @@ static PyObject *rolesForPermissionOn(PyObject *self, PyObject *args) {
**| """Return the roles that have the permisson on the given object"""
*/
if (!PyArg_ParseTuple(args, "OO|O", &perm, &object, &deflt))
if (unpacktuple3(args, "rolesForPermissionOn", 2,
&perm, &object, &deflt) < 0)
return NULL;
return c_rolesForPermissionOn(self, perm, object, deflt);
}
......@@ -1428,6 +1918,153 @@ static PyObject *permissionName(PyObject *name) {
}
/* def guarded_getattr(inst, name, default=_marker): */
static PyObject *
guarded_getattr(PyObject *inst, PyObject *name, PyObject *default_,
PyObject *validate)
{
PyObject *v=0, *t=0;
int i;
/* if name[:1] != '_': */
if (PyString_Check(name) && PyString_AS_STRING(name)[0] != '_')
{
/*
# Try to get the attribute normally so that unusual
# exceptions are caught early.
try: v = getattr(inst, name)
except AttributeError:
if default is not _marker:
return default
raise
*/
v=PyObject_GetAttr(inst, name);
if (v==NULL)
{
if (default_ && PyErr_Occurred() == PyExc_AttributeError)
{
PyErr_Clear();
Py_INCREF(default_);
return default_;
}
return NULL;
}
/*
if Containers(type(inst)):
# Simple type. Short circuit.
return v
*/
t=callfunction1(Containers, OBJECT(inst->ob_type));
if (t==NULL) goto err;
i=PyObject_IsTrue(t);
if (i < 0) goto err;
Py_DECREF(t);
if (i) return v;
/*
# Filter out the objects we can't access.
if hasattr(inst, 'aq_acquire'):
return inst.aq_acquire(name, aq_validate, validate)
*/
if (aq_isWrapper(inst))
{
ASSIGN(v, aq_Acquire(inst, name, aq_validate, validate, 1, NULL, 0));
return v;
}
/*
# Or just try to get the attribute directly.
if validate(inst, inst, name, v):
return v
*/
validate=callfunction4(validate, inst, inst, name, v);
if (validate==NULL) goto err;
i=PyObject_IsTrue(validate);
Py_DECREF(validate);
if (i < 0) goto err;
if (i > 0) return v;
unauthErr(name, v);
err:
Py_DECREF(v);
return NULL;
}
/* raise Unauthorized, name */
PyErr_SetObject(Unauthorized, name);
return NULL;
}
static PyObject *
module_guarded_getattr(PyObject *ignored, PyObject *args)
{
PyObject *inst, *name, *default_=0, *validate;
if (unpacktuple3(args, "guarded_getattr", 2, &inst, &name, &default_) < 0)
return NULL;
/*
validate = getSecurityManager().validate
*/
validate=PyObject_CallObject(getSecurityManager, NULL);
if (! validate) return NULL;
ASSIGN(validate, PyObject_GetAttr(validate, validate_str));
if (! validate) return NULL;
ASSIGN(validate, guarded_getattr(inst, name, default_, validate));
return validate;
}
/*
def aq_validate(inst, obj, name, v, validate):
return validate(inst, obj, name, v)
*/
static PyObject *
module_aq_validate(PyObject *ignored, PyObject *args)
{
PyObject *inst, *obj, *name, *v, *validate;
if (unpacktuple5(args, "validate", 0,
&inst, &obj, &name, &v, &validate) < 0) return NULL;
return callfunction4(validate, inst, obj, name, v);
}
static PyObject *
dtml_guarded_getattr(PyObject *self, PyObject *args)
{
PyObject *ob, *name, *default_=0, *validate;
if (unpacktuple3(args, "guarded_getattr", 2, &ob, &name, &default_) < 0)
return NULL;
UNLESS (validate = PyObject_GetAttr(self, validate_str))
{
/* This section is pure paranoia at this point. It was necessary
while debugging. */
PyErr_Clear();
validate=PyObject_CallObject(getSecurityManager, NULL);
if (! validate) return NULL;
ASSIGN(validate, PyObject_GetAttr(validate, validate_str));
if (! validate) return NULL;
}
ASSIGN(validate, guarded_getattr(ob, name, default_, validate));
return validate;
}
static struct PyMethodDef dtml_methods[] = {
{"guarded_getattr", (PyCFunction)dtml_guarded_getattr,
METH_VARARGS|METH_KEYWORDS, "" },
{NULL, NULL}
};
/* ----------------------------------------------------------------
** Module initialization
** ----------------------------------------------------------------
......@@ -1438,7 +2075,11 @@ static PyObject *permissionName(PyObject *name) {
void initcAccessControl(void) {
PyObject *module;
PyObject *dict;
char *rev = "$Revision: 1.11 $";
char *rev = "$Revision: 1.12 $";
PURE_MIXIN_CLASS(RestrictedDTMLMixin,
"A mix-in for derivatives of DT_String.String "
"that adds Zope security."
, dtml_methods);
if (!ExtensionClassImported) return;
......@@ -1455,41 +2096,38 @@ void initcAccessControl(void) {
module = Py_InitModule3("cAccessControl",
cAccessControl_methods,
"$Id: cAccessControl.c,v 1.11 2001/10/19 15:12:25 shane Exp $\n");
"$Id: cAccessControl.c,v 1.12 2001/10/26 16:07:50 matt Exp $\n");
aq_init(); /* For Python <= 2.1.1, aq_init() should be after
Py_InitModule(). */
dict = PyModule_GetDict(module);
ZopeSecurityPolicyType.ob_type = &PyType_Type;
PyDict_SetItemString(dict, "ZopeSecurityPolicyType",
OBJECT(&ZopeSecurityPolicyType));
PermissionRoleType.ob_type = &PyType_Type;
PyDict_SetItemString(dict, "PermissionRoleType",
OBJECT(&PermissionRoleType));
imPermissionRoleType.ob_type = &PyType_Type;
PyDict_SetItemString(dict, "imPermissionRoleType",
OBJECT(&imPermissionRoleType));
PyDict_SetItemString(dict, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
PyDict_SetItemString(dict, "_what_not_even_god_should_do",
_what_not_even_god_should_do);
PyExtensionClass_Export(dict, "RestrictedDTMLMixin",
RestrictedDTMLMixinType);
PyExtensionClass_Export(dict, "ZopeSecurityPolicy",
ZopeSecurityPolicyType);
PyExtensionClass_Export(dict,"SecurityManager",
SecurityManagerType);
PyExtensionClass_Export(dict, "PermissionRole",
PermissionRoleType);
PyExtensionClass_Export(dict, "imPermissionRole",
imPermissionRoleType);
imPermissionRoleObj = PyDict_GetItemString(dict, "imPermissionRole");
imPermissionRoleObj = PyMapping_GetItemString(dict,
"imPermissionRole");
aq_validate = PyMapping_GetItemString(dict, "aq_validate");
/*| from SimpleObjectPolicies import Containers
*/
......@@ -1507,6 +2145,14 @@ void initcAccessControl(void) {
Py_DECREF(module);
module = NULL;
/*| from AccessControl.SecurityManagement import getSecurityManager
*/
IMPORT(module, "AccessControl.SecurityManagement");
GETATTR(module, getSecurityManager);
Py_DECREF(module);
module = NULL;
/*| from zLOG import LOG, PROBLEM
*/
......
......@@ -147,8 +147,8 @@ __doc__='''Conditional insertion
variable is not reevaluated.
'''
__rcs_id__='$Id: DT_If.py,v 1.16 1999/03/10 00:15:07 klm Exp $'
__version__='$Revision: 1.16 $'[11:-2]
__rcs_id__='$Id: DT_If.py,v 1.17 2001/10/26 16:07:50 matt Exp $'
__version__='$Revision: 1.17 $'[11:-2]
from DT_Util import ParseError, parse_params, name_param, str
......@@ -192,7 +192,7 @@ class If:
if elses is not None: sections.append(elses)
self.simple_form=tuple(sections)
self.simple_form=('i',)+tuple(sections)
class Unless:
name='unless'
......@@ -204,7 +204,7 @@ class Unless:
name,expr=name_param(args,'unless',1)
if expr is None: cond=name
else: cond=expr.eval
self.simple_form=(cond,None,section.blocks)
self.simple_form=('i',cond,None,section.blocks)
class Else(Unless):
# The else tag is included for backward compatibility and is deprecated.
......
......@@ -217,8 +217,8 @@ Evaluating expressions without rendering results
''' # '
__rcs_id__='$Id: DT_Var.py,v 1.44 2001/10/02 14:23:32 shane Exp $'
__version__='$Revision: 1.44 $'[11:-2]
__rcs_id__='$Id: DT_Var.py,v 1.45 2001/10/26 16:07:50 matt Exp $'
__version__='$Revision: 1.45 $'[11:-2]
from DT_Util import parse_params, name_param, str
import re, string, sys
......@@ -254,7 +254,11 @@ class Var:
if len(args)==1 and fmt=='s':
if expr is None: expr=name
else: expr=expr.eval
self.simple_form=expr,
self.simple_form=('v', expr)
elif len(args)==2 and fmt=='s' and args.has_key('html_quote'):
if expr is None: expr=name
else: expr=expr.eval
self.simple_form=('v', expr, 'h')
def render(self, md):
args=self.args
......@@ -353,7 +357,7 @@ class Call:
name, expr = name_param(args,'call',1)
if expr is None: expr=name
else: expr=expr.eval
self.simple_form=expr,None
self.simple_form=('i', expr, None)
def url_quote(v, name='(Unknown name)', md={}):
......
......@@ -84,7 +84,7 @@
****************************************************************************/
static char cDocumentTemplate_module_documentation[] =
""
"\n$Id: cDocumentTemplate.c,v 1.39 2001/06/21 19:08:59 shane Exp $"
"\n$Id: cDocumentTemplate.c,v 1.40 2001/10/26 16:07:50 matt Exp $"
;
#include "ExtensionClass.h"
......@@ -94,7 +94,7 @@ static PyObject *py___call__, *py___roles__, *py_AUTHENTICATED_USER;
static PyObject *py_hasRole, *py__proxy_roles, *py_Unauthorized;
static PyObject *py_Unauthorized_fmt, *py_guarded_getattr;
static PyObject *py__push, *py__pop, *py_aq_base, *py_renderNS;
static PyObject *py___class__;
static PyObject *py___class__, *html_quote;
/* ----------------------------------------------------- */
......@@ -398,13 +398,29 @@ static PyObject *
MM_cget(MM *self, PyObject *key, int call)
{
long i;
PyObject *e, *rr, *tb;
PyObject *e, *rr;
UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
while (--i >= 0)
{
e=PyList_GetItem(self->data,i);
if ((e=PyObject_GetItem(e,key)))
e=PyList_GET_ITEM(self->data,i);
if (PyDict_Check(e))
{
e=PyDict_GetItem(e, key);
Py_XINCREF(e);
}
else
{
UNLESS (e=PyObject_GetItem(e,key))
{
if (PyErr_Occurred() == PyExc_KeyError)
PyErr_Clear();
else
return NULL;
}
}
if (e)
{
if (!call) return e;
......@@ -437,17 +453,8 @@ MM_cget(MM *self, PyObject *key, int call)
}
return e;
}
PyErr_Fetch(&e, &rr, &tb);
if (e != PyExc_KeyError)
{
PyErr_Restore(e,rr,tb);
return NULL;
}
Py_XDECREF(e);
Py_XDECREF(rr);
Py_XDECREF(tb);
}
PyErr_SetObject(PyExc_KeyError,key);
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
......@@ -726,7 +733,7 @@ static int
render_blocks_(PyObject *blocks, PyObject *rendered,
PyObject *md, PyObject *mda)
{
PyObject *block;
PyObject *block, *t;
int l, i, k=0, append;
if ((l=PyList_Size(blocks)) < 0) return -1;
......@@ -735,27 +742,48 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
block=PyList_GET_ITEM(((PyListObject*)blocks), i);
append=1;
if (PyTuple_Check(block))
if (PyTuple_Check(block)
&& PyTuple_GET_SIZE(block) > 1
&& PyTuple_GET_ITEM(block, 0)
&& PyString_Check(PyTuple_GET_ITEM(block, 0)))
{
switch (PyString_AS_STRING(PyTuple_GET_ITEM(block, 0))[0])
{
int bs;
case 'v': /* var */
t=PyTuple_GET_ITEM(block,1);
bs=((PyTupleObject*)block)->ob_size;
if (t == NULL) return -1;
if (bs==1)
if (PyString_Check(t)) t=PyObject_GetItem(md, t);
else t=PyObject_CallObject(t, mda);
if (t == NULL || (! PyString_Check(t)))
{
/* Simple var */
block=PyTuple_GET_ITEM(block,0);
if (PyString_Check(block)) block=PyObject_GetItem(md,block);
else block=PyObject_CallObject(block,mda);
if (block) ASSIGN(block, PyObject_Str(block));
UNLESS(block) return -1;
if (t) ASSIGN(t, PyObject_Str(t));
UNLESS(t) return -1;
}
else
if (PyString_Check(t)
&& PyTuple_GET_SIZE(block) == 3) /* html_quote */
{
if (strchr(PyString_AS_STRING(t), '&')
&& strchr(PyString_AS_STRING(t), '<')
&& strchr(PyString_AS_STRING(t), '>')
&& strchr(PyString_AS_STRING(t), '"')
)
ASSIGN(t, PyObject_CallFunction(html_quote, "O", t));
if (t == NULL) return -1;
}
block = t;
break;
case 'i': /* if */
{
/* if */
int icond, m;
int icond, m, bs;
PyObject *cond, *n, *cache;
bs = PyTuple_GET_SIZE(block) - 1; /* subtract code */
UNLESS(cache=PyDict_New()) return -1;
cond=PyObject_GetAttr(md,py__push);
if (cond) ASSIGN(cond, PyObject_CallFunction(cond,"O",cache));
......@@ -767,7 +795,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
m=bs-1;
for (icond=0; icond < m; icond += 2)
{
cond=PyTuple_GET_ITEM(block,icond);
cond=PyTuple_GET_ITEM(block,icond+1);
if (PyString_Check(cond))
{
/* We have to be careful to handle key errors here */
......@@ -804,7 +832,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
if (PyObject_IsTrue(cond))
{
Py_DECREF(cond);
block=PyTuple_GET_ITEM(block,icond+1);
block=PyTuple_GET_ITEM(block,icond+1+1);
if (block!=Py_None &&
render_blocks_(block, rendered, md, mda) < 0)
return if_finally(md,1);
......@@ -815,7 +843,7 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
}
if (icond==m)
{
block=PyTuple_GET_ITEM(block,icond);
block=PyTuple_GET_ITEM(block,icond+1);
if (block!=Py_None &&
render_blocks_(block, rendered, md, mda) < 0)
return if_finally(md,1);
......@@ -823,6 +851,13 @@ render_blocks_(PyObject *blocks, PyObject *rendered,
if (if_finally(md,0) == -2) return -1;
}
break;
default:
PyErr_Format(PyExc_ValueError,
"Invalid DTML command code, %s",
PyString_AS_STRING(PyTuple_GET_ITEM(block, 0)));
return -1;
}
}
else if (PyString_Check(block))
{
......@@ -904,10 +939,14 @@ void
initcDocumentTemplate(void)
{
PyObject *m, *d;
char *rev="$Revision: 1.39 $";
char *rev="$Revision: 1.40 $";
DictInstanceType.ob_type=&PyType_Type;
UNLESS (html_quote = PyImport_ImportModule("html_quote")) return;
ASSIGN(html_quote, PyObject_GetAttrString(html_quote, "html_quote"));
UNLESS (html_quote) return;
UNLESS(py_isDocTemp=PyString_FromString("isDocTemp")) return;
UNLESS(py_renderNS=PyString_FromString("__render_with_namespace__")) return;
UNLESS(py_blocks=PyString_FromString("blocks")) return;
......@@ -946,6 +985,4 @@ initcDocumentTemplate(void)
PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
if (PyErr_Occurred())
Py_FatalError("can't initialize module cDocumentTemplate");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment