/***************************************************************************** * * Copyright (c) 2003, 2004 Zope Foundation and Contributors. * All Rights Reserved. * * This software is subject to the provisions of the Zope Public License, * Version 2.1 (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. * ****************************************************************************** Security Proxy Implementation */ #include #include "zope/proxy/proxy.h" static PyObject *__class__str = 0, *__name__str = 0, *__module__str = 0; #define PyInt_FromLong PyLong_FromLong #define IS_STRING PyUnicode_Check #define MAKE_STRING(name) PyBytes_AS_STRING( \ PyUnicode_AsUTF8String(name)) #define FROM_STRING PyUnicode_FromString #define FROM_STRING_FORMAT PyUnicode_FromFormat #define INTERN PyUnicode_InternFromString #define MOD_ERROR_VAL NULL #define MOD_SUCCESS_VAL(val) val #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) #define MOD_DEF(ob, name, doc, methods) \ static struct PyModuleDef moduledef = { \ PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \ ob = PyModule_Create(&moduledef); #define DECLARE_STRING(N) static PyObject *str_##N DECLARE_STRING(__3pow__); DECLARE_STRING(__bool__); DECLARE_STRING(__call__); DECLARE_STRING(check); DECLARE_STRING(check_getattr); DECLARE_STRING(check_setattr); DECLARE_STRING(__cmp__); DECLARE_STRING(__contains__); DECLARE_STRING(__delitem__); DECLARE_STRING(__getitem__); DECLARE_STRING(__hash__); DECLARE_STRING(__iter__); DECLARE_STRING(__len__); DECLARE_STRING(next); DECLARE_STRING(op_abs); DECLARE_STRING(op_add); DECLARE_STRING(op_and); DECLARE_STRING(op_divmod); DECLARE_STRING(op_float); DECLARE_STRING(op_floordiv); DECLARE_STRING(op_iadd); DECLARE_STRING(op_iand); DECLARE_STRING(op_ifloordiv); DECLARE_STRING(op_ilshift); DECLARE_STRING(op_imod); DECLARE_STRING(op_imul); DECLARE_STRING(op_int); DECLARE_STRING(op_invert); DECLARE_STRING(op_ior); DECLARE_STRING(op_ipow); DECLARE_STRING(op_irshift); DECLARE_STRING(op_isub); DECLARE_STRING(op_itruediv); DECLARE_STRING(op_ixor); DECLARE_STRING(op_lshift); DECLARE_STRING(op_mod); DECLARE_STRING(op_mul); DECLARE_STRING(op_neg); DECLARE_STRING(op_or); DECLARE_STRING(op_pos); DECLARE_STRING(op_radd); DECLARE_STRING(op_rand); DECLARE_STRING(op_rdivmod); DECLARE_STRING(op_rfloordiv); DECLARE_STRING(op_rlshift); DECLARE_STRING(op_rmod); DECLARE_STRING(op_rmul); DECLARE_STRING(op_ror); DECLARE_STRING(op_rrshift); DECLARE_STRING(op_rshift); DECLARE_STRING(op_rsub); DECLARE_STRING(op_rtruediv); DECLARE_STRING(op_rxor); DECLARE_STRING(op_sub); DECLARE_STRING(op_truediv); DECLARE_STRING(op_xor); DECLARE_STRING(__pow__); DECLARE_STRING(proxy); DECLARE_STRING(__repr__); DECLARE_STRING(__rpow__); DECLARE_STRING(__setitem__); DECLARE_STRING(__str__); typedef struct { ProxyObject proxy; PyObject *proxy_checker; } SecurityProxy; #define CLEAR(O) if (O) {PyObject *t = O; O = 0; Py_DECREF(t); } #undef Proxy_Check #define Proxy_Check(proxy) \ PyObject_TypeCheck(proxy, &SecurityProxyType) static PyTypeObject SecurityProxyType; /* * Machinery to call the checker. */ static int check(SecurityProxy *self, PyObject *meth, PyObject *name) { PyObject *r; /* If the checker has __setitem__, we call it's slot rather than calling check or check_getattr. Why? Because calling operator slots is much faster than calling methods and security checks are done so often that speed matters. So we have this hack of using almost-arbitrary operations to represent methods that we call alot. */ if (self->proxy_checker->ob_type->tp_as_mapping != NULL && self->proxy_checker->ob_type->tp_as_mapping->mp_ass_subscript != NULL && meth != str_check_setattr) return self->proxy_checker->ob_type->tp_as_mapping-> mp_ass_subscript(self->proxy_checker, self->proxy.proxy_object, name); r = PyObject_CallMethodObjArgs(self->proxy_checker, meth, self->proxy.proxy_object, name, NULL); if (r == NULL) return -1; Py_DECREF(r); return 0; } /* If the checker has __getitem__, we call it's slot rather than calling proxy. Why? Because calling operator slots is much faster than calling methods and security checks are done so often that speed matters. So we have this hack of using almost-arbitrary operations to represent methods that we call alot. */ #define PROXY_RESULT(self, result) \ if (result != NULL) { \ PyObject *tmp; \ if (self->proxy_checker->ob_type->tp_as_mapping != NULL \ && self->proxy_checker->ob_type->tp_as_mapping->mp_subscript != NULL) \ tmp = self->proxy_checker->ob_type->tp_as_mapping-> \ mp_subscript(self->proxy_checker, result); \ else \ tmp = PyObject_CallMethodObjArgs(self->proxy_checker, str_proxy, \ result, NULL); \ Py_DECREF(result); \ result = tmp; \ } typedef PyObject *(*function1)(PyObject *); static PyObject * check1(SecurityProxy *self, PyObject *opname, function1 operation) { PyObject *result = NULL; if (check(self, str_check, opname) >= 0) { result = operation(self->proxy.proxy_object); PROXY_RESULT(self, result); } return result; } static PyObject * check2(PyObject *self, PyObject *other, PyObject *opname, PyObject *ropname, binaryfunc operation) { PyObject *result = NULL; if (Proxy_Check(self)) { if (check((SecurityProxy*)self, str_check, opname) >= 0) { result = operation(((SecurityProxy*)self)->proxy.proxy_object, other); PROXY_RESULT(((SecurityProxy*)self), result); } } else if (Proxy_Check(other)) { if (check((SecurityProxy*)other, str_check, ropname) >= 0) { result = operation(self, ((SecurityProxy*)other)->proxy.proxy_object); PROXY_RESULT(((SecurityProxy*)other), result); } } else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } return result; } static PyObject * check2i(SecurityProxy *self, PyObject *other, PyObject *opname, binaryfunc operation) { PyObject *result = NULL; if (check(self, str_check, opname) >= 0) { result = operation(self->proxy.proxy_object, other); if (result == self->proxy.proxy_object) { /* If the operation was really carried out inplace, don't create a new proxy, but use the old one. */ Py_DECREF(result); Py_INCREF((PyObject *)self); result = (PyObject *)self; } else PROXY_RESULT(self, result); } return result; } #define UNOP(NAME, CALL) \ static PyObject *proxy_##NAME(PyObject *self) \ { return check1((SecurityProxy *)self, str_op_##NAME, CALL); } #define BINOP(NAME, CALL) \ static PyObject *proxy_##NAME(PyObject *self, PyObject *other) \ { return check2(self, other, str_op_##NAME, str_op_r##NAME, CALL); } #define INPLACE(NAME, CALL) \ static PyObject *proxy_i##NAME(PyObject *self, PyObject *other) \ { return check2i((SecurityProxy *)self, other, str_op_i##NAME, CALL); } /* * Slot methods. */ static PyObject * proxy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"object", "checker", 0}; SecurityProxy *self; PyObject *object; PyObject *checker; if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:_Proxy.__new__", kwlist, &object, &checker)) return NULL; if (checker == Py_None) { PyErr_SetString(PyExc_ValueError, "None passed as proxy checker"); return NULL; } self = (SecurityProxy *)type->tp_alloc(type, 0); if (self == NULL) return NULL; Py_INCREF(object); Py_INCREF(checker); self->proxy.proxy_object = object; self->proxy_checker = checker; return (PyObject *)self; } /* This is needed to avoid calling the base class tp_init, which we don't need. */ static int proxy_init(PyObject *self, PyObject *args, PyObject *kw) { return 0; } static int proxy_clear(SecurityProxy *self) { CLEAR(self->proxy_checker); SecurityProxyType.tp_base->tp_clear((PyObject*)self); return 0; } static void proxy_dealloc(SecurityProxy *self) { PyObject_GC_UnTrack((PyObject*)self); proxy_clear(self); SecurityProxyType.tp_base->tp_dealloc((PyObject*)self); } static int proxy_traverse(SecurityProxy *self, visitproc visit, void *arg) { Py_VISIT(self->proxy.proxy_object); Py_VISIT(self->proxy_checker); return 0; } static PyObject * proxy_richcompare(SecurityProxy* self, PyObject* other, int op) { PyObject *result = NULL; result = PyObject_RichCompare(self->proxy.proxy_object, other, op); if (result == Py_True || result == Py_False) return result; PROXY_RESULT(self, result); return result; } static PyObject * proxy_iter(SecurityProxy *self) { PyObject *result = NULL; if (check(self, str_check, str___iter__) >= 0) { result = PyObject_GetIter(self->proxy.proxy_object); PROXY_RESULT(self, result); } return result; } static PyObject * proxy_iternext(SecurityProxy *self) { PyObject *result = NULL; if (check(self, str_check_getattr, str_next) >= 0) { result = PyIter_Next(self->proxy.proxy_object); PROXY_RESULT(self, result); } return result; } static PyObject * proxy_getattro(SecurityProxy *self, PyObject *name) { PyObject *result = NULL; if (check(self, str_check_getattr, name) >= 0) { result = PyObject_GetAttr(self->proxy.proxy_object, name); PROXY_RESULT(self, result); } return result; } static int proxy_setattro(SecurityProxy *self, PyObject *name, PyObject *value) { if (check(self, str_check_setattr, name) >= 0) return PyObject_SetAttr(self->proxy.proxy_object, name, value); return -1; } static PyObject * default_repr(PyObject *object) { PyObject *klass, *name = 0, *module = 0, *result = 0; char *sname, *smodule; klass = PyObject_GetAttr(object, __class__str); if (klass == NULL) return NULL; name = PyObject_GetAttr(klass, __name__str); if (name == NULL) goto err; sname = MAKE_STRING(name); if (sname == NULL) goto err; module = PyObject_GetAttr(klass, __module__str); if (module != NULL) { smodule = MAKE_STRING(module); if (smodule == NULL) goto err; result = FROM_STRING_FORMAT("", smodule, sname, object); } else { PyErr_Clear(); result = FROM_STRING_FORMAT("", sname, object); } err: Py_DECREF(klass); Py_XDECREF(name); Py_XDECREF(module); return result; } static PyObject * proxy_str(SecurityProxy *self) { PyObject *result = NULL; if (check(self, str_check, str___str__) >= 0) { result = PyObject_Str(self->proxy.proxy_object); } else { PyErr_Clear(); result = default_repr(self->proxy.proxy_object); } return result; } static PyObject * proxy_repr(SecurityProxy *self) { PyObject *result = NULL; if (check(self, str_check, str___repr__) >= 0) { result = PyObject_Repr(self->proxy.proxy_object); } else { PyErr_Clear(); result = default_repr(self->proxy.proxy_object); } return result; } static long proxy_hash(SecurityProxy *self) { return PyObject_Hash(self->proxy.proxy_object); } static PyObject * proxy_call(SecurityProxy *self, PyObject *args, PyObject *kwds) { PyObject *result = NULL; if (check(self, str_check, str___call__) >= 0) { result = PyObject_Call(self->proxy.proxy_object, args, kwds); PROXY_RESULT(self, result); } return result; } /* * Number methods. */ #define NUMBER_METHOD(M) \ static PyObject * \ call_##M(PyObject *self) \ { \ PyNumberMethods *nb = self->ob_type->tp_as_number; \ if (nb == NULL || nb->nb_##M == NULL) { \ PyErr_SetString(PyExc_TypeError, \ "object can't be converted to " #M); \ return NULL; \ } \ return nb->nb_##M(self); \ } NUMBER_METHOD(int) NUMBER_METHOD(float) static PyObject * call_ipow(PyObject *self, PyObject *other) { /* PyNumber_InPlacePower has three args. How silly. :-) */ return PyNumber_InPlacePower(self, other, Py_None); } BINOP(add, PyNumber_Add) BINOP(sub, PyNumber_Subtract) BINOP(mul, PyNumber_Multiply) BINOP(mod, PyNumber_Remainder) BINOP(divmod, PyNumber_Divmod) static PyObject * proxy_pow(PyObject *self, PyObject *other, PyObject *modulus) { PyObject *result = NULL; if (Proxy_Check(self)) { if (check((SecurityProxy*)self, str_check, str___pow__) >= 0) { result = PyNumber_Power(((SecurityProxy*)self)->proxy.proxy_object, other, modulus); PROXY_RESULT(((SecurityProxy*)self), result); } } else if (Proxy_Check(other)) { if (check((SecurityProxy*)other, str_check, str___rpow__) >= 0) { result = PyNumber_Power(self, ((SecurityProxy*)other)->proxy.proxy_object, modulus); PROXY_RESULT(((SecurityProxy*)other), result); } } else if (modulus != NULL && Proxy_Check(modulus)) { if (check((SecurityProxy*)modulus, str_check, str___3pow__) >= 0) { result = PyNumber_Power(self, other, ((SecurityProxy*)modulus)->proxy.proxy_object); PROXY_RESULT(((SecurityProxy*)modulus), result); } } else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } return result; } BINOP(lshift, PyNumber_Lshift) BINOP(rshift, PyNumber_Rshift) BINOP(and, PyNumber_And) BINOP(xor, PyNumber_Xor) BINOP(or, PyNumber_Or) UNOP(neg, PyNumber_Negative) UNOP(pos, PyNumber_Positive) UNOP(abs, PyNumber_Absolute) static int proxy_bool(PyObject *self) { return PyObject_IsTrue(((SecurityProxy*)self)->proxy.proxy_object); } UNOP(invert, PyNumber_Invert) UNOP(int, call_int) UNOP(float, call_float) INPLACE(add, PyNumber_InPlaceAdd) INPLACE(sub, PyNumber_InPlaceSubtract) INPLACE(mul, PyNumber_InPlaceMultiply) INPLACE(mod, PyNumber_InPlaceRemainder) INPLACE(pow, call_ipow) INPLACE(lshift, PyNumber_InPlaceLshift) INPLACE(rshift, PyNumber_InPlaceRshift) INPLACE(and, PyNumber_InPlaceAnd) INPLACE(xor, PyNumber_InPlaceXor) INPLACE(or, PyNumber_InPlaceOr) BINOP(floordiv, PyNumber_FloorDivide) BINOP(truediv, PyNumber_TrueDivide) INPLACE(floordiv, PyNumber_InPlaceFloorDivide) INPLACE(truediv, PyNumber_InPlaceTrueDivide) /* * Sequence methods. */ static Py_ssize_t proxy_length(SecurityProxy *self) { if (check(self, str_check, str___len__) >= 0) return PyObject_Length(self->proxy.proxy_object); return -1; } static PyObject * proxy_length_hint(SecurityProxy *self) { PyObject *result = NULL; result = PyObject_CallMethod(self->proxy.proxy_object, "__length_hint__", NULL); if (result == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); result = Py_NotImplemented; Py_INCREF(result); } } return result; } /* sq_item and sq_ass_item may be called by PySequece_{Get,Set}Item(). */ static PyObject *proxy_getitem(SecurityProxy *, PyObject *); static int proxy_setitem(SecurityProxy *, PyObject *, PyObject *); static PyObject * proxy_igetitem(SecurityProxy *self, Py_ssize_t i) { PyObject *key = PyInt_FromLong(i); PyObject *res = NULL; if (key != NULL) { res = proxy_getitem(self, key); Py_DECREF(key); } return res; } static int proxy_isetitem(SecurityProxy *self, Py_ssize_t i, PyObject *value) { PyObject *key = PyInt_FromLong(i); int res = -1; if (key != NULL) { res = proxy_setitem(self, key, value); Py_DECREF(key); } return res; } static int proxy_contains(SecurityProxy *self, PyObject *value) { if (check(self, str_check, str___contains__) >= 0) return PySequence_Contains(self->proxy.proxy_object, value); return -1; } /* * Mapping methods. */ static PyObject * proxy_getitem(SecurityProxy *self, PyObject *key) { PyObject *result = NULL; if (check(self, str_check, str___getitem__) >= 0) { result = PyObject_GetItem(self->proxy.proxy_object, key); PROXY_RESULT(self, result); } return result; } static int proxy_setitem(SecurityProxy *self, PyObject *key, PyObject *value) { if (value == NULL) { if (check(self, str_check, str___delitem__) >= 0) return PyObject_DelItem(self->proxy.proxy_object, key); } else { if (check(self, str_check, str___setitem__) >= 0) return PyObject_SetItem(self->proxy.proxy_object, key, value); } return -1; } /* * Normal methods. */ static PyNumberMethods proxy_as_number = { proxy_add, /* nb_add */ proxy_sub, /* nb_subtract */ proxy_mul, /* nb_multiply */ proxy_mod, /* nb_remainder */ proxy_divmod, /* nb_divmod */ proxy_pow, /* nb_power */ proxy_neg, /* nb_negative */ proxy_pos, /* nb_positive */ proxy_abs, /* nb_absolute */ proxy_bool, /* nb_bool */ proxy_invert, /* nb_invert */ proxy_lshift, /* nb_lshift */ proxy_rshift, /* nb_rshift */ proxy_and, /* nb_and */ proxy_xor, /* nb_xor */ proxy_or, /* nb_or */ proxy_int, /* nb_int */ 0, /* nb_reserved, formerly nb_long */ proxy_float, /* nb_float */ /* Added in release 2.0 */ /* These require the Py_TPFLAGS_HAVE_INPLACEOPS flag */ proxy_iadd, /* nb_inplace_add */ proxy_isub, /* nb_inplace_subtract */ proxy_imul, /* nb_inplace_multiply */ proxy_imod, /* nb_inplace_remainder */ (ternaryfunc)proxy_ipow, /* nb_inplace_power */ proxy_ilshift, /* nb_inplace_lshift */ proxy_irshift, /* nb_inplace_rshift */ proxy_iand, /* nb_inplace_and */ proxy_ixor, /* nb_inplace_xor */ proxy_ior, /* nb_inplace_or */ /* Added in release 2.2 */ /* These require the Py_TPFLAGS_HAVE_CLASS flag */ proxy_floordiv, /* nb_floor_divide */ proxy_truediv, /* nb_true_divide */ proxy_ifloordiv, /* nb_inplace_floor_divide */ proxy_itruediv, /* nb_inplace_true_divide */ }; static PySequenceMethods proxy_as_sequence = { (lenfunc)proxy_length, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ (ssizeargfunc)proxy_igetitem, /* sq_item */ 0, /* sq_slice, unused in PY3 */ (ssizeobjargproc)proxy_isetitem, /* sq_ass_item */ 0, /* sq_ass_slice, unused in PY3 */ (objobjproc)proxy_contains, /* sq_contains */ }; static PyMappingMethods proxy_as_mapping = { (lenfunc)proxy_length, /* mp_length */ (binaryfunc)proxy_getitem, /* mp_subscript */ (objobjargproc)proxy_setitem, /* mp_ass_subscript */ }; static char proxy_doc[] = "\ Security proxy class. Constructor: _Proxy(object, checker)\n\ where 'object' is an arbitrary object, and 'checker' is an object\n\ whose signature is described by the IChecker interface.\n\ A checker should have the following methods:\n\ check(object, operation) # operation is e.g. '__add__' or '__hash__'\n\ check_getattr(object, name)\n\ check_setattr(object, name)\n\ proxy(object)\n\ The check methods should raise an exception if the operation is\n\ disallowed. The proxy method should return a proxy for the object\n\ if one is needed, otherwise the object itself.\n\ "; static PyMethodDef proxy_methods[] = { {"__length_hint__", (PyCFunction)proxy_length_hint, METH_NOARGS, "Guess the length of the object"}, {NULL, NULL} /* sentinel */ }; static PyTypeObject SecurityProxyType = { PyVarObject_HEAD_INIT(NULL, 0) "zope.security._proxy._Proxy", sizeof(SecurityProxy), 0, (destructor)proxy_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved, was tp_compare */ (reprfunc)proxy_repr, /* tp_repr */ &proxy_as_number, /* tp_as_number */ &proxy_as_sequence, /* tp_as_sequence */ &proxy_as_mapping, /* tp_as_mapping */ (hashfunc)proxy_hash, /* tp_hash */ (ternaryfunc)proxy_call, /* tp_call */ (reprfunc)proxy_str, /* tp_str */ (getattrofunc)proxy_getattro, /* tp_getattro */ (setattrofunc)proxy_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ proxy_doc, /* tp_doc */ (traverseproc)proxy_traverse, /* tp_traverse */ 0, /* tp_clear */ (richcmpfunc)proxy_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)proxy_iter, /* tp_iter */ (iternextfunc)proxy_iternext, /* tp_iternext */ proxy_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ proxy_init, /* tp_init */ 0, /*PyType_GenericAlloc,*/ /* tp_alloc */ proxy_new, /* tp_new */ 0, /*_PyObject_GC_Del,*/ /* tp_free */ }; static PyObject * module_getChecker(PyObject *self, PyObject *arg) { PyObject *result; if (!Proxy_Check(arg)) { PyErr_SetString(PyExc_TypeError, "getChecker argument must be a _Proxy"); return NULL; } result = ((SecurityProxy*)arg)->proxy_checker; Py_INCREF(result); return result; } static PyObject * module_getObject(PyObject *self, PyObject *arg) { PyObject *result; if (!Proxy_Check(arg)) result = arg; else result = ((SecurityProxy*)arg)->proxy.proxy_object; Py_INCREF(result); return result; } static char module___doc__[] = "Security proxy implementation."; static PyMethodDef module_functions[] = { {"getChecker", module_getChecker, METH_O, "get checker from proxy"}, {"getObject", module_getObject, METH_O, "Get the proxied object\n\nReturn the original object if not proxied."}, {NULL} }; MOD_INIT(_proxy) { PyObject *m; MOD_DEF(m, "_proxy", module___doc__, module_functions) if (m == NULL) return MOD_ERROR_VAL; if (Proxy_Import() < 0) return MOD_ERROR_VAL; #define INIT_STRING(S) \ if((str_##S = INTERN(#S)) == NULL) return MOD_ERROR_VAL #define INIT_STRING_OP(S) \ if((str_op_##S = INTERN("__" #S "__")) == NULL) return MOD_ERROR_VAL INIT_STRING(__3pow__); INIT_STRING(__bool__); INIT_STRING(__call__); INIT_STRING(check); INIT_STRING(check_getattr); INIT_STRING(check_setattr); INIT_STRING(__cmp__); INIT_STRING(__contains__); INIT_STRING(__delitem__); INIT_STRING(__getitem__); INIT_STRING(__hash__); INIT_STRING(__iter__); INIT_STRING(__len__); INIT_STRING(next); INIT_STRING_OP(abs); INIT_STRING_OP(add); INIT_STRING_OP(and); INIT_STRING_OP(divmod); INIT_STRING_OP(float); INIT_STRING_OP(floordiv); INIT_STRING_OP(iadd); INIT_STRING_OP(iand); INIT_STRING_OP(ifloordiv); INIT_STRING_OP(ilshift); INIT_STRING_OP(imod); INIT_STRING_OP(imul); INIT_STRING_OP(int); INIT_STRING_OP(invert); INIT_STRING_OP(ior); INIT_STRING_OP(ipow); INIT_STRING_OP(irshift); INIT_STRING_OP(isub); INIT_STRING_OP(itruediv); INIT_STRING_OP(ixor); INIT_STRING_OP(lshift); INIT_STRING_OP(mod); INIT_STRING_OP(mul); INIT_STRING_OP(neg); INIT_STRING_OP(or); INIT_STRING_OP(pos); INIT_STRING_OP(radd); INIT_STRING_OP(rand); INIT_STRING_OP(rdivmod); INIT_STRING_OP(rfloordiv); INIT_STRING_OP(rlshift); INIT_STRING_OP(rmod); INIT_STRING_OP(rmul); INIT_STRING_OP(ror); INIT_STRING_OP(rrshift); INIT_STRING_OP(rshift); INIT_STRING_OP(rsub); INIT_STRING_OP(rtruediv); INIT_STRING_OP(rxor); INIT_STRING_OP(sub); INIT_STRING_OP(truediv); INIT_STRING_OP(xor); INIT_STRING(__pow__); INIT_STRING(proxy); INIT_STRING(__repr__); INIT_STRING(__rpow__); INIT_STRING(__setitem__); INIT_STRING(__str__); __class__str = FROM_STRING("__class__"); if (! __class__str) return MOD_ERROR_VAL; __name__str = FROM_STRING("__name__"); if (! __name__str) return MOD_ERROR_VAL; __module__str = FROM_STRING("__module__"); if (! __module__str) return MOD_ERROR_VAL; SecurityProxyType.tp_alloc = PyType_GenericAlloc; SecurityProxyType.tp_free = PyObject_GC_Del; SecurityProxyType.tp_base = &ProxyType; if (PyType_Ready(&SecurityProxyType) < 0) return MOD_ERROR_VAL; Py_INCREF(&SecurityProxyType); PyModule_AddObject(m, "_Proxy", (PyObject *)&SecurityProxyType); return MOD_SUCCESS_VAL(m); }