s3: smbd: Make extract_snapshot_token() a wrapper for extract_snapshot_token_internal().
[Samba.git] / source3 / rpc_client / py_mdscli.c
blob290be3f86d9c5c7c12bab54e42e23cf14a5c265a
1 /*
2 Python interface to cli_mdssvc
4 Copyright (C) Ralph Boehme 2019
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <Python.h>
21 #include <pytalloc.h>
22 #include "includes.h"
23 #include "python/py3compat.h"
24 #include "python/modules.h"
25 #include "lib/util/talloc_stack.h"
26 #include "lib/util/tevent_ntstatus.h"
27 #include "librpc/rpc/rpc_common.h"
28 #include "librpc/rpc/pyrpc_util.h"
29 #include "rpc_client/cli_mdssvc.h"
30 #include "rpc_client/cli_mdssvc_private.h"
32 static PyObject *search_get_results(PyObject *self,
33 PyObject *args,
34 PyObject *kwargs)
36 TALLOC_CTX *frame = talloc_stackframe();
37 const char * const kwnames[] = {"pipe", NULL};
38 PyObject *pypipe = NULL;
39 PyObject *result = NULL;
40 dcerpc_InterfaceObject *pipe = NULL;
41 struct tevent_req *req = NULL;
42 struct mdscli_search_ctx *search = NULL;
43 uint64_t *cnids = NULL;
44 size_t i;
45 size_t ncnids;
46 NTSTATUS status;
47 int ret;
48 bool ok;
50 if (!PyArg_ParseTupleAndKeywords(args,
51 kwargs,
52 "O",
53 discard_const_p(char *, kwnames),
54 &pypipe)) {
55 PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
56 goto out;
59 ok = py_check_dcerpc_type(pypipe,
60 "samba.dcerpc.base",
61 "ClientConnection");
62 if (!ok) {
63 goto out;
66 pipe = (dcerpc_InterfaceObject *)pypipe;
68 search = pytalloc_get_type(self, struct mdscli_search_ctx);
69 if (search == NULL) {
70 goto out;
74 * We must use the async send/recv versions in order to pass the correct
75 * tevent context, here and any other place we call mdscli_*
76 * functions. Using the sync version we would be polling a temporary
77 * event context, but unfortunately the s4 Python RPC bindings dispatch
78 * events through
80 * dcerpc_bh_raw_call_send()
81 * -> dcerpc_request_send()
82 * -> dcerpc_schedule_io_trigger()
83 * -> dcerpc_send_request()
84 * -> tstream_writev_queue_send()
86 * on an hardcoded event context allocated via
88 * py_dcerpc_interface_init_helper()
89 * -> dcerpc_pipe_connect()
91 req = mdscli_get_results_send(frame,
92 pipe->ev,
93 search);
94 if (req == NULL) {
95 PyErr_NoMemory();
96 goto out;
99 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
100 PyErr_SetNTSTATUS(status);
101 goto out;
104 status = mdscli_get_results_recv(req, frame, &cnids);
105 if (!NT_STATUS_IS_OK(status) &&
106 !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
108 PyErr_SetNTSTATUS(status);
109 goto out;
111 TALLOC_FREE(req);
113 result = Py_BuildValue("[]");
115 ncnids = talloc_array_length(cnids);
116 for (i = 0; i < ncnids; i++) {
117 char *path = NULL;
118 PyObject *pypath = NULL;
120 req = mdscli_get_path_send(frame,
121 pipe->ev,
122 search->mdscli_ctx,
123 cnids[i]);
124 if (req == NULL) {
125 PyErr_NoMemory();
126 Py_DECREF(result);
127 result = NULL;
128 goto out;
131 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
132 PyErr_SetNTSTATUS(status);
133 Py_DECREF(result);
134 result = NULL;
135 goto out;
138 status = mdscli_get_path_recv(req, frame, &path);
139 TALLOC_FREE(req);
140 PyErr_NTSTATUS_NOT_OK_RAISE(status);
142 pypath = PyUnicode_FromString(path);
143 if (pypath == NULL) {
144 PyErr_NoMemory();
145 Py_DECREF(result);
146 result = NULL;
147 goto out;
150 ret = PyList_Append(result, pypath);
151 Py_DECREF(pypath);
152 if (ret == -1) {
153 PyErr_SetString(PyExc_RuntimeError,
154 "list append failed");
155 Py_DECREF(result);
156 result = NULL;
157 goto out;
161 out:
162 talloc_free(frame);
163 return result;
166 static PyObject *search_close(PyObject *self,
167 PyObject *args,
168 PyObject *kwargs)
170 TALLOC_CTX *frame = talloc_stackframe();
171 const char * const kwnames[] = {"pipe", NULL};
172 PyObject *pypipe = NULL;
173 dcerpc_InterfaceObject *pipe = NULL;
174 struct tevent_req *req = NULL;
175 struct mdscli_search_ctx *search = NULL;
176 NTSTATUS status;
177 bool ok;
179 if (!PyArg_ParseTupleAndKeywords(args,
180 kwargs,
181 "O",
182 discard_const_p(char *, kwnames),
183 &pypipe)) {
184 PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
185 goto fail;
188 ok = py_check_dcerpc_type(pypipe,
189 "samba.dcerpc.base",
190 "ClientConnection");
191 if (!ok) {
192 goto fail;
195 pipe = (dcerpc_InterfaceObject *)pypipe;
197 search = pytalloc_get_type(self, struct mdscli_search_ctx);
198 if (search == NULL) {
199 goto fail;
202 req = mdscli_close_search_send(frame,
203 pipe->ev,
204 &search);
205 if (req == NULL) {
206 PyErr_NoMemory();
207 goto fail;
210 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
211 PyErr_SetNTSTATUS(status);
212 goto fail;
215 status = mdscli_close_search_recv(req);
216 if (!NT_STATUS_IS_OK(status) &&
217 !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
219 PyErr_SetNTSTATUS(status);
220 goto fail;
222 TALLOC_FREE(req);
224 talloc_free(frame);
225 Py_INCREF(Py_None);
226 return Py_None;
228 fail:
229 talloc_free(frame);
230 return NULL;
233 static PyMethodDef search_methods[] = {
235 .ml_name = "get_results",
236 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, search_get_results),
237 .ml_flags = METH_VARARGS|METH_KEYWORDS,
238 .ml_doc = "",
241 .ml_name = "close",
242 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, search_close),
243 .ml_flags = METH_VARARGS|METH_KEYWORDS,
244 .ml_doc = "",
246 {0},
249 static PyObject *search_new(PyTypeObject *type,
250 PyObject *args,
251 PyObject *kwds)
253 TALLOC_CTX *frame = talloc_stackframe();
254 struct mdscli_search_ctx *search = NULL;
255 PyObject *self = NULL;
257 search = talloc_zero(frame, struct mdscli_search_ctx);
258 if (search == NULL) {
259 PyErr_NoMemory();
260 talloc_free(frame);
261 return NULL;
264 self = pytalloc_steal(type, search);
265 talloc_free(frame);
266 return self;
269 static PyTypeObject search_type = {
270 .tp_name = "mdscli.ctx.search",
271 .tp_new = search_new,
272 .tp_flags = Py_TPFLAGS_DEFAULT,
273 .tp_doc = "search([....]) -> mdssvc client search context\n",
274 .tp_methods = search_methods,
277 static PyObject *conn_sharepath(PyObject *self,
278 PyObject *unused)
280 TALLOC_CTX *frame = talloc_stackframe();
281 struct mdscli_ctx *ctx = NULL;
282 char *sharepath = NULL;
283 PyObject *result = NULL;
285 ctx = pytalloc_get_type(self, struct mdscli_ctx);
286 if (ctx == NULL) {
287 goto fail;
290 sharepath = mdscli_get_basepath(frame, ctx);
291 if (sharepath == NULL) {
292 PyErr_NoMemory();
293 goto fail;
296 result = PyUnicode_FromString(sharepath);
298 fail:
299 talloc_free(frame);
300 return result;
303 static PyObject *conn_search(PyObject *self,
304 PyObject *args,
305 PyObject *kwargs)
307 TALLOC_CTX *frame = talloc_stackframe();
308 PyObject *pypipe = NULL;
309 dcerpc_InterfaceObject *pipe = NULL;
310 struct mdscli_ctx *ctx = NULL;
311 PyObject *result = NULL;
312 char *query = NULL;
313 char *basepath = NULL;
314 struct tevent_req *req = NULL;
315 struct mdscli_search_ctx *search = NULL;
316 const char * const kwnames[] = {
317 "pipe", "query", "basepath", NULL
319 NTSTATUS status;
320 bool ok;
322 if (!PyArg_ParseTupleAndKeywords(args,
323 kwargs,
324 "Oss",
325 discard_const_p(char *, kwnames),
326 &pypipe,
327 &query,
328 &basepath)) {
329 PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
330 goto fail;
333 ok = py_check_dcerpc_type(pypipe,
334 "samba.dcerpc.base",
335 "ClientConnection");
336 if (!ok) {
337 goto fail;
340 pipe = (dcerpc_InterfaceObject *)pypipe;
342 ctx = pytalloc_get_type(self, struct mdscli_ctx);
343 if (ctx == NULL) {
344 goto fail;
347 req = mdscli_search_send(frame,
348 pipe->ev,
349 ctx,
350 query,
351 basepath,
352 false);
353 if (req == NULL) {
354 PyErr_NoMemory();
355 goto fail;
358 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
359 PyErr_SetNTSTATUS(status);
360 goto fail;
363 status = mdscli_search_recv(req, frame, &search);
364 PyErr_NTSTATUS_IS_ERR_RAISE(status);
366 result = pytalloc_steal(&search_type, search);
368 fail:
369 talloc_free(frame);
370 return result;
373 static PyObject *conn_disconnect(PyObject *self,
374 PyObject *args,
375 PyObject *kwargs)
377 TALLOC_CTX *frame = talloc_stackframe();
378 PyObject *pypipe = NULL;
379 dcerpc_InterfaceObject *pipe = NULL;
380 struct mdscli_ctx *ctx = NULL;
381 struct tevent_req *req = NULL;
382 const char * const kwnames[] = {"pipe", NULL};
383 NTSTATUS status;
384 bool ok;
386 if (!PyArg_ParseTupleAndKeywords(args,
387 kwargs,
388 "O",
389 discard_const_p(char *, kwnames),
390 &pypipe)) {
391 PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
392 goto fail;
395 ok = py_check_dcerpc_type(pypipe,
396 "samba.dcerpc.base",
397 "ClientConnection");
398 if (!ok) {
399 goto fail;
402 pipe = (dcerpc_InterfaceObject *)pypipe;
404 ctx = pytalloc_get_type(self, struct mdscli_ctx);
405 if (ctx == NULL) {
406 goto fail;
409 req = mdscli_disconnect_send(frame, pipe->ev, ctx);
410 if (req == NULL) {
411 PyErr_NoMemory();
412 goto fail;
415 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
416 PyErr_SetNTSTATUS(status);
417 goto fail;
420 status = mdscli_disconnect_recv(req);
421 PyErr_NTSTATUS_IS_ERR_RAISE(status);
423 talloc_free(frame);
424 Py_INCREF(Py_None);
425 return Py_None;
427 fail:
428 talloc_free(frame);
429 return NULL;
432 static PyMethodDef conn_methods[] = {
434 .ml_name = "sharepath",
435 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, conn_sharepath),
436 .ml_flags = METH_NOARGS,
437 .ml_doc = "mdscli.conn.sharepath(...) -> get share basepath",
440 .ml_name = "search",
441 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, conn_search),
442 .ml_flags = METH_VARARGS|METH_KEYWORDS,
443 .ml_doc = "mdscli.conn.search(...) -> run mdssvc query",
446 .ml_name = "disconnect",
447 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, conn_disconnect),
448 .ml_flags = METH_VARARGS|METH_KEYWORDS,
449 .ml_doc = "mdscli.conn.disconnect(...) -> disconnect",
451 {0},
454 static PyObject *conn_new(PyTypeObject *type,
455 PyObject *args,
456 PyObject *kwargs)
458 TALLOC_CTX *frame = talloc_stackframe();
459 const char * const kwnames[] = { "pipe", "share", "mountpoint", NULL };
460 PyObject *pypipe = NULL;
461 dcerpc_InterfaceObject *pipe = NULL;
462 struct tevent_req *req = NULL;
463 char *share = NULL;
464 char *mountpoint = NULL;
465 struct mdscli_ctx *ctx = NULL;
466 PyObject *self = NULL;
467 NTSTATUS status;
468 bool ok;
470 if (!PyArg_ParseTupleAndKeywords(args,
471 kwargs,
472 "Oss",
473 discard_const_p(char *, kwnames),
474 &pypipe,
475 &share,
476 &mountpoint)) {
477 PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
478 goto fail;
481 ok = py_check_dcerpc_type(pypipe,
482 "samba.dcerpc.base",
483 "ClientConnection");
484 if (!ok) {
485 goto fail;
488 pipe = (dcerpc_InterfaceObject *)pypipe;
490 req = mdscli_connect_send(frame,
491 pipe->ev,
492 pipe->binding_handle,
493 share,
494 mountpoint);
495 if (req == NULL) {
496 PyErr_NoMemory();
497 goto fail;
500 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
501 PyErr_SetNTSTATUS(status);
502 goto fail;
505 status = mdscli_connect_recv(req, frame, &ctx);
506 PyErr_NTSTATUS_IS_ERR_RAISE(status);
508 self = pytalloc_steal(type, ctx);
510 fail:
511 talloc_free(frame);
512 return self;
515 static PyTypeObject conn_type = {
516 .tp_name = "mdscli.conn",
517 .tp_new = conn_new,
518 .tp_flags = Py_TPFLAGS_DEFAULT,
519 .tp_doc = "conn([....]) -> mdssvc connection\n",
520 .tp_methods = conn_methods,
523 static PyMethodDef mdscli_methods[] = {
524 {0},
527 static struct PyModuleDef moduledef = {
528 PyModuleDef_HEAD_INIT,
529 .m_name = "mdscli",
530 .m_doc = "RPC mdssvc client",
531 .m_size = -1,
532 .m_methods = mdscli_methods,
535 MODULE_INIT_FUNC(mdscli)
537 TALLOC_CTX *frame = talloc_stackframe();
538 PyObject *m = NULL;
539 int ret;
541 ret = pytalloc_BaseObject_PyType_Ready(&conn_type);
542 if (ret < 0) {
543 TALLOC_FREE(frame);
544 return NULL;
547 ret = pytalloc_BaseObject_PyType_Ready(&search_type);
548 if (ret < 0) {
549 TALLOC_FREE(frame);
550 return NULL;
553 m = PyModule_Create(&moduledef);
554 if (m == NULL) {
555 TALLOC_FREE(frame);
556 return NULL;
559 Py_INCREF(&conn_type);
560 PyModule_AddObject(m, "conn", (PyObject *)&conn_type);
562 Py_INCREF(&search_type);
563 PyModule_AddObject(m, "search", (PyObject *)&search_type);
565 TALLOC_FREE(frame);
566 return m;