1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00
samba-mirror/source3/rpc_client/py_mdscli.c
Andreas Schneider 9621a3d7a6 Use python.h from libreplace
BUG: https://bugzilla.samba.org/show_bug.cgi?id=15513

Signed-off-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2023-11-20 15:37:33 +00:00

573 lines
12 KiB
C

/*
Python interface to cli_mdssvc
Copyright (C) Ralph Boehme 2019
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lib/replace/system/python.h"
#include <pytalloc.h>
#include "includes.h"
#include "python/py3compat.h"
#include "python/modules.h"
#include "lib/util/talloc_stack.h"
#include "lib/util/tevent_ntstatus.h"
#include "librpc/rpc/rpc_common.h"
#include "librpc/rpc/pyrpc_util.h"
#include "rpc_client/cli_mdssvc.h"
#include "rpc_client/cli_mdssvc_private.h"
static PyObject *search_get_results(PyObject *self,
PyObject *args,
PyObject *kwargs)
{
TALLOC_CTX *frame = talloc_stackframe();
const char * const kwnames[] = {"pipe", NULL};
PyObject *pypipe = NULL;
PyObject *result = NULL;
dcerpc_InterfaceObject *pipe = NULL;
struct tevent_req *req = NULL;
struct mdscli_search_ctx *search = NULL;
uint64_t *cnids = NULL;
size_t i;
size_t ncnids;
NTSTATUS status;
int ret;
bool ok;
if (!PyArg_ParseTupleAndKeywords(args,
kwargs,
"O",
discard_const_p(char *, kwnames),
&pypipe)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
goto out;
}
ok = py_check_dcerpc_type(pypipe,
"samba.dcerpc.base",
"ClientConnection");
if (!ok) {
goto out;
}
pipe = (dcerpc_InterfaceObject *)pypipe;
search = pytalloc_get_type(self, struct mdscli_search_ctx);
if (search == NULL) {
goto out;
}
/*
* We must use the async send/recv versions in order to pass the correct
* tevent context, here and any other place we call mdscli_*
* functions. Using the sync version we would be polling a temporary
* event context, but unfortunately the s4 Python RPC bindings dispatch
* events through
*
* dcerpc_bh_raw_call_send()
* -> dcerpc_request_send()
* -> dcerpc_schedule_io_trigger()
* -> dcerpc_send_request()
* -> tstream_writev_queue_send()
*
* on an hardcoded event context allocated via
*
* py_dcerpc_interface_init_helper()
* -> dcerpc_pipe_connect()
*/
again:
req = mdscli_get_results_send(frame,
pipe->ev,
search);
if (req == NULL) {
PyErr_NoMemory();
goto out;
}
if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
PyErr_SetNTSTATUS(status);
goto out;
}
status = mdscli_get_results_recv(req, frame, &cnids);
TALLOC_FREE(req);
if (NT_STATUS_EQUAL(status, NT_STATUS_PENDING)) {
sleep(1);
goto again;
}
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
{
PyErr_SetNTSTATUS(status);
goto out;
}
result = Py_BuildValue("[]");
ncnids = talloc_array_length(cnids);
for (i = 0; i < ncnids; i++) {
char *path = NULL;
PyObject *pypath = NULL;
req = mdscli_get_path_send(frame,
pipe->ev,
search->mdscli_ctx,
cnids[i]);
if (req == NULL) {
PyErr_NoMemory();
Py_DECREF(result);
result = NULL;
goto out;
}
if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
PyErr_SetNTSTATUS(status);
Py_DECREF(result);
result = NULL;
goto out;
}
status = mdscli_get_path_recv(req, frame, &path);
TALLOC_FREE(req);
PyErr_NTSTATUS_NOT_OK_RAISE(status);
pypath = PyUnicode_FromString(path);
if (pypath == NULL) {
PyErr_NoMemory();
Py_DECREF(result);
result = NULL;
goto out;
}
ret = PyList_Append(result, pypath);
Py_DECREF(pypath);
if (ret == -1) {
PyErr_SetString(PyExc_RuntimeError,
"list append failed");
Py_DECREF(result);
result = NULL;
goto out;
}
}
out:
talloc_free(frame);
return result;
}
static PyObject *search_close(PyObject *self,
PyObject *args,
PyObject *kwargs)
{
TALLOC_CTX *frame = talloc_stackframe();
const char * const kwnames[] = {"pipe", NULL};
PyObject *pypipe = NULL;
dcerpc_InterfaceObject *pipe = NULL;
struct tevent_req *req = NULL;
struct mdscli_search_ctx *search = NULL;
NTSTATUS status;
bool ok;
if (!PyArg_ParseTupleAndKeywords(args,
kwargs,
"O",
discard_const_p(char *, kwnames),
&pypipe)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
goto fail;
}
ok = py_check_dcerpc_type(pypipe,
"samba.dcerpc.base",
"ClientConnection");
if (!ok) {
goto fail;
}
pipe = (dcerpc_InterfaceObject *)pypipe;
search = pytalloc_get_type(self, struct mdscli_search_ctx);
if (search == NULL) {
goto fail;
}
req = mdscli_close_search_send(frame,
pipe->ev,
&search);
if (req == NULL) {
PyErr_NoMemory();
goto fail;
}
if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
PyErr_SetNTSTATUS(status);
goto fail;
}
status = mdscli_close_search_recv(req);
if (!NT_STATUS_IS_OK(status) &&
!NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
{
PyErr_SetNTSTATUS(status);
goto fail;
}
TALLOC_FREE(req);
talloc_free(frame);
Py_INCREF(Py_None);
return Py_None;
fail:
talloc_free(frame);
return NULL;
}
static PyMethodDef search_methods[] = {
{
.ml_name = "get_results",
.ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, search_get_results),
.ml_flags = METH_VARARGS|METH_KEYWORDS,
.ml_doc = "",
},
{
.ml_name = "close",
.ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, search_close),
.ml_flags = METH_VARARGS|METH_KEYWORDS,
.ml_doc = "",
},
{0},
};
static PyObject *search_new(PyTypeObject *type,
PyObject *args,
PyObject *kwds)
{
TALLOC_CTX *frame = talloc_stackframe();
struct mdscli_search_ctx *search = NULL;
PyObject *self = NULL;
search = talloc_zero(frame, struct mdscli_search_ctx);
if (search == NULL) {
PyErr_NoMemory();
talloc_free(frame);
return NULL;
}
self = pytalloc_steal(type, search);
talloc_free(frame);
return self;
}
static PyTypeObject search_type = {
.tp_name = "mdscli.ctx.search",
.tp_new = search_new,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "search([....]) -> mdssvc client search context\n",
.tp_methods = search_methods,
};
static PyObject *conn_sharepath(PyObject *self,
PyObject *unused)
{
TALLOC_CTX *frame = talloc_stackframe();
struct mdscli_ctx *ctx = NULL;
char *sharepath = NULL;
PyObject *result = NULL;
ctx = pytalloc_get_type(self, struct mdscli_ctx);
if (ctx == NULL) {
goto fail;
}
sharepath = mdscli_get_basepath(frame, ctx);
if (sharepath == NULL) {
PyErr_NoMemory();
goto fail;
}
result = PyUnicode_FromString(sharepath);
fail:
talloc_free(frame);
return result;
}
static PyObject *conn_search(PyObject *self,
PyObject *args,
PyObject *kwargs)
{
TALLOC_CTX *frame = talloc_stackframe();
PyObject *pypipe = NULL;
dcerpc_InterfaceObject *pipe = NULL;
struct mdscli_ctx *ctx = NULL;
PyObject *result = NULL;
char *query = NULL;
char *basepath = NULL;
struct tevent_req *req = NULL;
struct mdscli_search_ctx *search = NULL;
const char * const kwnames[] = {
"pipe", "query", "basepath", NULL
};
NTSTATUS status;
bool ok;
if (!PyArg_ParseTupleAndKeywords(args,
kwargs,
"Oss",
discard_const_p(char *, kwnames),
&pypipe,
&query,
&basepath)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
goto fail;
}
ok = py_check_dcerpc_type(pypipe,
"samba.dcerpc.base",
"ClientConnection");
if (!ok) {
goto fail;
}
pipe = (dcerpc_InterfaceObject *)pypipe;
ctx = pytalloc_get_type(self, struct mdscli_ctx);
if (ctx == NULL) {
goto fail;
}
req = mdscli_search_send(frame,
pipe->ev,
ctx,
query,
basepath,
false);
if (req == NULL) {
PyErr_NoMemory();
goto fail;
}
if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
PyErr_SetNTSTATUS(status);
goto fail;
}
status = mdscli_search_recv(req, frame, &search);
PyErr_NTSTATUS_IS_ERR_RAISE(status);
result = pytalloc_steal(&search_type, search);
fail:
talloc_free(frame);
return result;
}
static PyObject *conn_disconnect(PyObject *self,
PyObject *args,
PyObject *kwargs)
{
TALLOC_CTX *frame = talloc_stackframe();
PyObject *pypipe = NULL;
dcerpc_InterfaceObject *pipe = NULL;
struct mdscli_ctx *ctx = NULL;
struct tevent_req *req = NULL;
const char * const kwnames[] = {"pipe", NULL};
NTSTATUS status;
bool ok;
if (!PyArg_ParseTupleAndKeywords(args,
kwargs,
"O",
discard_const_p(char *, kwnames),
&pypipe)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
goto fail;
}
ok = py_check_dcerpc_type(pypipe,
"samba.dcerpc.base",
"ClientConnection");
if (!ok) {
goto fail;
}
pipe = (dcerpc_InterfaceObject *)pypipe;
ctx = pytalloc_get_type(self, struct mdscli_ctx);
if (ctx == NULL) {
goto fail;
}
req = mdscli_disconnect_send(frame, pipe->ev, ctx);
if (req == NULL) {
PyErr_NoMemory();
goto fail;
}
if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
PyErr_SetNTSTATUS(status);
goto fail;
}
status = mdscli_disconnect_recv(req);
PyErr_NTSTATUS_IS_ERR_RAISE(status);
talloc_free(frame);
Py_INCREF(Py_None);
return Py_None;
fail:
talloc_free(frame);
return NULL;
}
static PyMethodDef conn_methods[] = {
{
.ml_name = "sharepath",
.ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, conn_sharepath),
.ml_flags = METH_NOARGS,
.ml_doc = "mdscli.conn.sharepath(...) -> get share basepath",
},
{
.ml_name = "search",
.ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, conn_search),
.ml_flags = METH_VARARGS|METH_KEYWORDS,
.ml_doc = "mdscli.conn.search(...) -> run mdssvc query",
},
{
.ml_name = "disconnect",
.ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, conn_disconnect),
.ml_flags = METH_VARARGS|METH_KEYWORDS,
.ml_doc = "mdscli.conn.disconnect(...) -> disconnect",
},
{0},
};
static PyObject *conn_new(PyTypeObject *type,
PyObject *args,
PyObject *kwargs)
{
TALLOC_CTX *frame = talloc_stackframe();
const char * const kwnames[] = { "pipe", "share", "mountpoint", NULL };
PyObject *pypipe = NULL;
dcerpc_InterfaceObject *pipe = NULL;
struct tevent_req *req = NULL;
char *share = NULL;
char *mountpoint = NULL;
struct mdscli_ctx *ctx = NULL;
PyObject *self = NULL;
NTSTATUS status;
bool ok;
if (!PyArg_ParseTupleAndKeywords(args,
kwargs,
"Oss",
discard_const_p(char *, kwnames),
&pypipe,
&share,
&mountpoint)) {
PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
goto fail;
}
ok = py_check_dcerpc_type(pypipe,
"samba.dcerpc.base",
"ClientConnection");
if (!ok) {
goto fail;
}
pipe = (dcerpc_InterfaceObject *)pypipe;
req = mdscli_connect_send(frame,
pipe->ev,
pipe->binding_handle,
share,
mountpoint);
if (req == NULL) {
PyErr_NoMemory();
goto fail;
}
if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
PyErr_SetNTSTATUS(status);
goto fail;
}
status = mdscli_connect_recv(req, frame, &ctx);
PyErr_NTSTATUS_IS_ERR_RAISE(status);
self = pytalloc_steal(type, ctx);
fail:
talloc_free(frame);
return self;
}
static PyTypeObject conn_type = {
.tp_name = "mdscli.conn",
.tp_new = conn_new,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "conn([....]) -> mdssvc connection\n",
.tp_methods = conn_methods,
};
static PyMethodDef mdscli_methods[] = {
{0},
};
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
.m_name = "mdscli",
.m_doc = "RPC mdssvc client",
.m_size = -1,
.m_methods = mdscli_methods,
};
MODULE_INIT_FUNC(mdscli)
{
TALLOC_CTX *frame = talloc_stackframe();
PyObject *m = NULL;
int ret;
ret = pytalloc_BaseObject_PyType_Ready(&conn_type);
if (ret < 0) {
TALLOC_FREE(frame);
return NULL;
}
ret = pytalloc_BaseObject_PyType_Ready(&search_type);
if (ret < 0) {
TALLOC_FREE(frame);
return NULL;
}
m = PyModule_Create(&moduledef);
if (m == NULL) {
TALLOC_FREE(frame);
return NULL;
}
Py_INCREF(&conn_type);
PyModule_AddObject(m, "conn", (PyObject *)&conn_type);
Py_INCREF(&search_type);
PyModule_AddObject(m, "search", (PyObject *)&search_type);
TALLOC_FREE(frame);
return m;
}