Cleanup references to module objects returned from PyImport_ImportModule
[gd/samba-autobuild/.git] / source4 / librpc / rpc / pyrpc_util.c
index 314ad2cc8d79d566e9d345693fdb122e253131b3..29fd281f54daddac19925730c4777318a3a07bc2 100644 (file)
@@ -21,6 +21,7 @@
 */
 
 #include <Python.h>
+#include "python/py3compat.h"
 #include "includes.h"
 #include "librpc/rpc/pyrpc_util.h"
 #include "librpc/rpc/dcerpc.h"
@@ -83,6 +84,12 @@ static NTSTATUS pyrpc_irpc_connect(TALLOC_CTX *mem_ctx, const char *irpc_server,
                return NT_STATUS_INVALID_PIPE_STATE;
        }
 
+       /*
+        * Note: this allows nested event loops to happen,
+        * but as there's no top level event loop it's not that critical.
+        */
+       dcerpc_binding_handle_set_sync_ev(*binding_handle, event_ctx);
+
        return NT_STATUS_OK;
 }
 
@@ -93,11 +100,12 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
        const char *binding_string;
        PyObject *py_lp_ctx = Py_None, *py_credentials = Py_None, *py_basis = Py_None;
        NTSTATUS status;
+       unsigned int timeout = (unsigned int)-1;
        const char *kwnames[] = {
-               "binding", "lp_ctx", "credentials", "basis_connection", NULL
+               "binding", "lp_ctx", "credentials", "timeout", "basis_connection", NULL
        };
 
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOO:samr", discard_const_p(char *, kwnames), &binding_string, &py_lp_ctx, &py_credentials, &py_basis)) {
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOIO:samr", discard_const_p(char *, kwnames), &binding_string, &py_lp_ctx, &py_credentials, &timeout, &py_basis)) {
                return NULL;
        }
 
@@ -108,6 +116,11 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
        }
 
        ret = PyObject_New(dcerpc_InterfaceObject, type);
+       if (ret == NULL) {
+               PyErr_NoMemory();
+               return NULL;
+       }
+
        ret->pipe = NULL;
        ret->binding_handle = NULL;
        ret->mem_ctx = talloc_new(NULL);
@@ -124,6 +137,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (event_ctx == NULL) {
                        PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
                        return NULL;
                }
 
@@ -131,6 +145,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (lp_ctx == NULL) {
                        PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
                        return NULL;
                }
 
@@ -139,6 +154,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (!NT_STATUS_IS_OK(status)) {
                        PyErr_SetNTSTATUS(status);
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
                        return NULL;
                }
        } else if (py_basis != Py_None) {
@@ -149,6 +165,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                py_base = PyImport_ImportModule("samba.dcerpc.base");
                if (py_base == NULL) {
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
                        return NULL;
                }
 
@@ -156,12 +173,17 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (ClientConnection_Type == NULL) {
                        PyErr_SetNone(PyExc_TypeError);
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
+                       Py_DECREF(py_base);
                        return NULL;
                }
 
                if (!PyObject_TypeCheck(py_basis, ClientConnection_Type)) {
                        PyErr_SetString(PyExc_TypeError, "basis_connection must be a DCE/RPC connection");
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
+                       Py_DECREF(py_base);
+                       Py_DECREF(ClientConnection_Type);
                        return NULL;
                }
 
@@ -170,6 +192,9 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (base_pipe == NULL) {
                        PyErr_NoMemory();
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
+                       Py_DECREF(py_base);
+                       Py_DECREF(ClientConnection_Type);
                        return NULL;
                }
 
@@ -177,10 +202,15 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (!NT_STATUS_IS_OK(status)) {
                        PyErr_SetNTSTATUS(status);
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
+                       Py_DECREF(py_base);
+                       Py_DECREF(ClientConnection_Type);
                        return NULL;
                }
 
                ret->pipe = talloc_steal(ret->mem_ctx, ret->pipe);
+               Py_XDECREF(ClientConnection_Type);
+               Py_XDECREF(py_base);
        } else {
                struct tevent_context *event_ctx;
                struct loadparm_context *lp_ctx;
@@ -190,6 +220,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (event_ctx == NULL) {
                        PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
                        return NULL;
                }
 
@@ -197,6 +228,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (lp_ctx == NULL) {
                        PyErr_SetString(PyExc_TypeError, "Expected loadparm context");
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
                        return NULL;
                }
 
@@ -204,6 +236,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (credentials == NULL) {
                        PyErr_SetString(PyExc_TypeError, "Expected credentials");
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
                        return NULL;
                }
                status = dcerpc_pipe_connect(ret->mem_ctx, &ret->pipe, binding_string,
@@ -211,6 +244,7 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                if (!NT_STATUS_IS_OK(status)) {
                        PyErr_SetNTSTATUS(status);
                        TALLOC_FREE(ret->mem_ctx);
+                       Py_DECREF(ret);
                        return NULL;
                }
 
@@ -225,6 +259,12 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py
                ret->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
                ret->binding_handle = ret->pipe->binding_handle;
        }
+
+       /* reset timeout for the handle */
+       if ((timeout != ((unsigned int)-1)) && (ret->binding_handle != NULL)) {
+               dcerpc_binding_handle_set_timeout(ret->binding_handle, timeout);
+       }
+
        return (PyObject *)ret;
 }
 
@@ -320,7 +360,7 @@ PyObject *py_dcerpc_syntax_init_helper(PyTypeObject *type, PyObject *args, PyObj
                return NULL;
        }
 
-       obj = (struct ndr_syntax_id *)pytalloc_get_ptr(ret);
+       obj = pytalloc_get_type(ret, struct ndr_syntax_id);
        *obj = *syntax;
 
        return ret;
@@ -343,12 +383,16 @@ void PyErr_SetDCERPCStatus(struct dcerpc_pipe *p, NTSTATUS status)
 
   r_ctx is the context that is a parent of r. It will be referenced by
   the resulting python object
+
+  This MUST only be used by objects that are based on pytalloc_Object
+  otherwise the pytalloc_reference_ex() will fail.
  */
 PyObject *py_return_ndr_struct(const char *module_name, const char *type_name,
                               TALLOC_CTX *r_ctx, void *r)
 {
        PyTypeObject *py_type;
        PyObject *module;
+       PyObject *result = NULL;
 
        if (r == NULL) {
                Py_RETURN_NONE;
@@ -361,10 +405,14 @@ PyObject *py_return_ndr_struct(const char *module_name, const char *type_name,
 
        py_type = (PyTypeObject *)PyObject_GetAttrString(module, type_name);
        if (py_type == NULL) {
+               Py_DECREF(module);
                return NULL;
        }
 
-       return pytalloc_reference_ex(py_type, r_ctx, r);
+       result = pytalloc_reference_ex(py_type, r_ctx, r);
+       Py_CLEAR(module);
+       Py_CLEAR(py_type);
+       return result;
 }
 
 PyObject *PyString_FromStringOrNULL(const char *str)
@@ -372,5 +420,91 @@ PyObject *PyString_FromStringOrNULL(const char *str)
        if (str == NULL) {
                Py_RETURN_NONE;
        }
-       return PyString_FromString(str);
+       return PyStr_FromString(str);
+}
+
+PyObject *pyrpc_import_union(PyTypeObject *type, TALLOC_CTX *mem_ctx, int level,
+                            const void *in, const char *typename)
+{
+       PyObject *mem_ctx_obj = NULL;
+       PyObject *in_obj = NULL;
+       PyObject *ret = NULL;
+
+       mem_ctx_obj = pytalloc_GenericObject_reference(mem_ctx);
+       if (mem_ctx_obj == NULL) {
+               return NULL;
+       }
+
+       in_obj = pytalloc_GenericObject_reference_ex(mem_ctx, discard_const(in));
+       if (in_obj == NULL) {
+               Py_XDECREF(mem_ctx_obj);
+               return NULL;
+       }
+
+       ret = PyObject_CallMethod((PyObject *)type,
+                                 discard_const_p(char, "__import__"),
+                                 discard_const_p(char, "OiO"),
+                                 mem_ctx_obj, level, in_obj);
+       Py_XDECREF(mem_ctx_obj);
+       Py_XDECREF(in_obj);
+       if (ret == NULL) {
+               return NULL;
+       }
+
+       return ret;
+}
+
+void *pyrpc_export_union(PyTypeObject *type, TALLOC_CTX *mem_ctx, int level,
+                        PyObject *in, const char *typename)
+{
+       PyObject *mem_ctx_obj = NULL;
+       PyObject *ret_obj = NULL;
+       void *ret = NULL;
+
+       mem_ctx_obj = pytalloc_GenericObject_reference(mem_ctx);
+       if (mem_ctx_obj == NULL) {
+               return NULL;
+       }
+
+       ret_obj = PyObject_CallMethod((PyObject *)type,
+                                     discard_const_p(char, "__export__"),
+                                     discard_const_p(char, "OiO"),
+                                     mem_ctx_obj, level, in);
+       Py_XDECREF(mem_ctx_obj);
+       if (ret_obj == NULL) {
+               return NULL;
+       }
+
+       ret = _pytalloc_get_type(ret_obj, typename);
+       Py_XDECREF(ret_obj);
+       return ret;
+}
+
+PyObject *py_dcerpc_ndr_pointer_deref(PyTypeObject *type, PyObject *obj)
+{
+       if (!PyObject_TypeCheck(obj, type)) {
+               PyErr_Format(PyExc_TypeError,
+                            "Expected type '%s' but got type '%s'",
+                            (type)->tp_name, Py_TYPE(obj)->tp_name);
+               return NULL;
+       }
+
+       return PyObject_GetAttrString(obj, discard_const_p(char, "value"));
+}
+
+PyObject *py_dcerpc_ndr_pointer_wrap(PyTypeObject *type, PyObject *obj)
+{
+       PyObject *args = NULL;
+       PyObject *ret_obj = NULL;
+
+       args = PyTuple_New(1);
+       if (args == NULL) {
+               return NULL;
+       }
+       Py_XINCREF(obj);
+       PyTuple_SetItem(args, 0, obj);
+
+       ret_obj = PyObject_Call((PyObject *)type, args, NULL);
+       Py_XDECREF(args);
+       return ret_obj;
 }