>From 6f80bfe7df65ea2adb0ef9b9f27c5450a0a3e2bd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 15 Feb 2014 10:12:04 +0100 Subject: [PATCH 1/2] s4:pyrpc: fix talloc hierachy in py_dcerpc_interface_init_helper() The tevent_context is cached under the connection, so we need to make sure it stays arround as long as the connection. Otherwise it will segfault while dereferencing the tevent_context on deallocation if a secondary connection is arround. This completes commit 4cc3388c034fa43c855fba802a30bbd2e78122be, which only fixed it in dcerpc_interface_new(). Signed-off-by: Stefan Metzmacher Reviewed-by: Andreas Schneider --- source4/librpc/rpc/pyrpc_util.c | 111 +++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 35 deletions(-) diff --git a/source4/librpc/rpc/pyrpc_util.c b/source4/librpc/rpc/pyrpc_util.c index ab6caac..cec8574 100644 --- a/source4/librpc/rpc/pyrpc_util.c +++ b/source4/librpc/rpc/pyrpc_util.c @@ -91,13 +91,8 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py { dcerpc_InterfaceObject *ret; const char *binding_string; - struct cli_credentials *credentials; - struct loadparm_context *lp_ctx = NULL; PyObject *py_lp_ctx = Py_None, *py_credentials = Py_None, *py_basis = Py_None; - TALLOC_CTX *mem_ctx = NULL; - struct tevent_context *event_ctx; NTSTATUS status; - const char *kwnames[] = { "binding", "lp_ctx", "credentials", "basis_connection", NULL }; @@ -106,35 +101,46 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py return NULL; } - mem_ctx = talloc_new(NULL); - if (mem_ctx == NULL) { - PyErr_NoMemory(); - return NULL; - } - - lp_ctx = lpcfg_from_py_object(mem_ctx, py_lp_ctx); - if (lp_ctx == NULL) { - PyErr_SetString(PyExc_TypeError, "Expected loadparm context"); - talloc_free(mem_ctx); - return NULL; - } - status = dcerpc_init(); if (!NT_STATUS_IS_OK(status)) { PyErr_SetNTSTATUS(status); - talloc_free(mem_ctx); return NULL; } ret = PyObject_New(dcerpc_InterfaceObject, type); - ret->mem_ctx = mem_ctx; - - event_ctx = s4_event_context_init(ret->mem_ctx); + ret->pipe = NULL; + ret->binding_handle = NULL; + ret->mem_ctx = talloc_new(NULL); + if (ret->mem_ctx == NULL) { + PyErr_NoMemory(); + return NULL; + } if (strncmp(binding_string, "irpc:", 5) == 0) { - ret->pipe = NULL; + struct tevent_context *event_ctx; + struct loadparm_context *lp_ctx; + + event_ctx = s4_event_context_init(ret->mem_ctx); + if (event_ctx == NULL) { + PyErr_SetString(PyExc_TypeError, "Expected loadparm context"); + TALLOC_FREE(ret->mem_ctx); + return NULL; + } + + lp_ctx = lpcfg_from_py_object(event_ctx, py_lp_ctx); + if (lp_ctx == NULL) { + PyErr_SetString(PyExc_TypeError, "Expected loadparm context"); + TALLOC_FREE(ret->mem_ctx); + return NULL; + } + status = pyrpc_irpc_connect(ret->mem_ctx, binding_string+5, table, event_ctx, lp_ctx, &ret->binding_handle); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + TALLOC_FREE(ret->mem_ctx); + return NULL; + } } else if (py_basis != Py_None) { struct dcerpc_pipe *base_pipe; PyObject *py_base; @@ -142,42 +148,77 @@ PyObject *py_dcerpc_interface_init_helper(PyTypeObject *type, PyObject *args, Py py_base = PyImport_ImportModule("samba.dcerpc.base"); if (py_base == NULL) { - talloc_free(mem_ctx); + TALLOC_FREE(ret->mem_ctx); return NULL; } ClientConnection_Type = (PyTypeObject *)PyObject_GetAttrString(py_base, "ClientConnection"); if (ClientConnection_Type == NULL) { PyErr_SetNone(PyExc_TypeError); - talloc_free(mem_ctx); + TALLOC_FREE(ret->mem_ctx); return NULL; } if (!PyObject_TypeCheck(py_basis, ClientConnection_Type)) { PyErr_SetString(PyExc_TypeError, "basis_connection must be a DCE/RPC connection"); - talloc_free(mem_ctx); + TALLOC_FREE(ret->mem_ctx); return NULL; } - base_pipe = talloc_reference(mem_ctx, ((dcerpc_InterfaceObject *)py_basis)->pipe); + base_pipe = talloc_reference(ret->mem_ctx, + ((dcerpc_InterfaceObject *)py_basis)->pipe); + if (base_pipe == NULL) { + PyErr_NoMemory(); + TALLOC_FREE(ret->mem_ctx); + return NULL; + } status = dcerpc_secondary_context(base_pipe, &ret->pipe, table); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + TALLOC_FREE(ret->mem_ctx); + return NULL; + } ret->pipe = talloc_steal(ret->mem_ctx, ret->pipe); } else { + struct tevent_context *event_ctx; + struct loadparm_context *lp_ctx; + struct cli_credentials *credentials; + + event_ctx = s4_event_context_init(ret->mem_ctx); + if (event_ctx == NULL) { + PyErr_SetString(PyExc_TypeError, "Expected loadparm context"); + TALLOC_FREE(ret->mem_ctx); + return NULL; + } + + lp_ctx = lpcfg_from_py_object(event_ctx, py_lp_ctx); + if (lp_ctx == NULL) { + PyErr_SetString(PyExc_TypeError, "Expected loadparm context"); + TALLOC_FREE(ret->mem_ctx); + return NULL; + } + credentials = cli_credentials_from_py_object(py_credentials); if (credentials == NULL) { PyErr_SetString(PyExc_TypeError, "Expected credentials"); - talloc_free(mem_ctx); + TALLOC_FREE(ret->mem_ctx); return NULL; } - status = dcerpc_pipe_connect(event_ctx, &ret->pipe, binding_string, - table, credentials, event_ctx, lp_ctx); - } - if (NT_STATUS_IS_ERR(status)) { - PyErr_SetNTSTATUS(status); - talloc_free(mem_ctx); - return NULL; + status = dcerpc_pipe_connect(ret->mem_ctx, &ret->pipe, binding_string, + table, credentials, event_ctx, lp_ctx); + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + TALLOC_FREE(ret->mem_ctx); + return NULL; + } + + /* + * the event context is cached under the connection, + * so let it be a child of it. + */ + talloc_steal(ret->pipe->conn, event_ctx); } if (ret->pipe) { -- 1.7.9.5 >From bddf81ced519f6fa540e3bcf460ab5750cdf93c0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 15 Feb 2014 10:19:29 +0100 Subject: [PATCH 2/2] s4:pyrpc: let dcerpc_interface_new() use py_dcerpc_interface_init_helper() Signed-off-by: Stefan Metzmacher --- source4/librpc/rpc/pyrpc.c | 100 ++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 74 deletions(-) diff --git a/source4/librpc/rpc/pyrpc.c b/source4/librpc/rpc/pyrpc.c index 0de3681..140d86c 100644 --- a/source4/librpc/rpc/pyrpc.c +++ b/source4/librpc/rpc/pyrpc.c @@ -296,7 +296,7 @@ static void dcerpc_interface_dealloc(PyObject* self) static PyObject *dcerpc_interface_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - dcerpc_InterfaceObject *ret; + PyObject *ret; const char *binding_string = NULL; PyObject *py_lp_ctx = Py_None; PyObject *py_credentials = Py_None; @@ -305,97 +305,49 @@ static PyObject *dcerpc_interface_new(PyTypeObject *type, PyObject *args, PyObje const char *kwnames[] = { "binding", "syntax", "lp_ctx", "credentials", "basis_connection", NULL }; - struct ndr_interface_table *table; - NTSTATUS status; + static struct ndr_interface_table dummy_table; + PyObject *args2 = Py_None; + PyObject *kwargs2 = Py_None; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|OOO:connect", discard_const_p(char *, kwnames), &binding_string, &syntax, &py_lp_ctx, &py_credentials, &py_basis)) { return NULL; } - ret = PyObject_New(dcerpc_InterfaceObject, type); - ret->pipe = NULL; - ret->binding_handle = NULL; - ret->mem_ctx = talloc_new(NULL); - if (ret->mem_ctx == NULL) { - PyErr_NoMemory(); + if (strncmp(binding_string, "irpc:", 5) == 0) { + PyErr_SetString(PyExc_ValueError, "irpc: transport not supported"); return NULL; } - /* Create a dummy interface table struct. TODO: In the future, we should + /* + * Fill a dummy interface table struct. TODO: In the future, we should * rather just allow connecting without requiring an interface table. + * + * We just fill the syntax during the connect, but keep the memory valid + * the whole time. */ - - table = talloc_zero(ret->mem_ctx, struct ndr_interface_table); - - if (table == NULL) { - PyErr_SetString(PyExc_MemoryError, "Allocating interface table"); - TALLOC_FREE(ret->mem_ctx); + if (!ndr_syntax_from_py_object(syntax, &dummy_table.syntax_id)) { return NULL; } - if (!ndr_syntax_from_py_object(syntax, &table->syntax_id)) { - TALLOC_FREE(ret->mem_ctx); + args2 = Py_BuildValue("(s)", binding_string); + if (args2 == NULL) { return NULL; } - if (py_basis != Py_None) { - struct dcerpc_pipe *base_pipe; - - if (!PyObject_TypeCheck(py_basis, &dcerpc_InterfaceType)) { - PyErr_SetString(PyExc_ValueError, "basis_connection must be a DCE/RPC connection"); - TALLOC_FREE(ret->mem_ctx); - return NULL; - } - - base_pipe = talloc_reference(ret->mem_ctx, - ((dcerpc_InterfaceObject *)py_basis)->pipe); - - status = dcerpc_secondary_context(base_pipe, &ret->pipe, table); - - ret->pipe = talloc_steal(ret->mem_ctx, ret->pipe); - } else { - struct tevent_context *event_ctx; - struct loadparm_context *lp_ctx; - struct cli_credentials *credentials; - - event_ctx = s4_event_context_init(ret->mem_ctx); - if (event_ctx == NULL) { - PyErr_SetString(PyExc_TypeError, "Expected loadparm context"); - TALLOC_FREE(ret->mem_ctx); - return NULL; - } - - lp_ctx = lpcfg_from_py_object(event_ctx, py_lp_ctx); - if (lp_ctx == NULL) { - PyErr_SetString(PyExc_TypeError, "Expected loadparm context"); - TALLOC_FREE(ret->mem_ctx); - return NULL; - } - - credentials = cli_credentials_from_py_object(py_credentials); - if (credentials == NULL) { - PyErr_SetString(PyExc_TypeError, "Expected credentials"); - TALLOC_FREE(ret->mem_ctx); - return NULL; - } - status = dcerpc_pipe_connect(ret->mem_ctx, &ret->pipe, binding_string, - table, credentials, event_ctx, lp_ctx); - - /* - * the event context is cached under the connection, - * so let it be a child of it. - */ - talloc_steal(ret->pipe->conn, event_ctx); - } - - if (!NT_STATUS_IS_OK(status)) { - PyErr_SetDCERPCStatus(ret->pipe, status); - TALLOC_FREE(ret->mem_ctx); + kwargs2 = Py_BuildValue("{s:O,s:O,s:O}", + "lp_ctx", py_lp_ctx, + "credentials", py_credentials, + "basis_connection", py_basis); + if (kwargs2 == NULL) { + Py_DECREF(args2); return NULL; } - ret->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC; - ret->binding_handle = ret->pipe->binding_handle; - return (PyObject *)ret; + + ret = py_dcerpc_interface_init_helper(type, args2, kwargs2, &dummy_table); + ZERO_STRUCT(dummy_table.syntax_id); + Py_DECREF(args2); + Py_DECREF(kwargs2); + return ret; } static PyTypeObject dcerpc_InterfaceType = { -- 1.7.9.5