util:datablob: data_blob_pad checks its alignment assumption
[samba.git] / source3 / rpc_client / py_mdscli.c
blobccb0342b86b630804fe5516a97927d8d5ad2e1ab
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 "lib/replace/system/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 again:
92 req = mdscli_get_results_send(frame,
93 pipe->ev,
94 search);
95 if (req == NULL) {
96 PyErr_NoMemory();
97 goto out;
100 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
101 PyErr_SetNTSTATUS(status);
102 goto out;
105 status = mdscli_get_results_recv(req, frame, &cnids);
106 TALLOC_FREE(req);
107 if (NT_STATUS_EQUAL(status, NT_STATUS_PENDING)) {
108 sleep(1);
109 goto again;
111 if (!NT_STATUS_IS_OK(status) &&
112 !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
114 PyErr_SetNTSTATUS(status);
115 goto out;
118 result = Py_BuildValue("[]");
120 ncnids = talloc_array_length(cnids);
121 for (i = 0; i < ncnids; i++) {
122 char *path = NULL;
123 PyObject *pypath = NULL;
125 req = mdscli_get_path_send(frame,
126 pipe->ev,
127 search->mdscli_ctx,
128 cnids[i]);
129 if (req == NULL) {
130 PyErr_NoMemory();
131 Py_DECREF(result);
132 result = NULL;
133 goto out;
136 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
137 PyErr_SetNTSTATUS(status);
138 Py_DECREF(result);
139 result = NULL;
140 goto out;
143 status = mdscli_get_path_recv(req, frame, &path);
144 TALLOC_FREE(req);
145 PyErr_NTSTATUS_NOT_OK_RAISE(status);
147 pypath = PyUnicode_FromString(path);
148 if (pypath == NULL) {
149 PyErr_NoMemory();
150 Py_DECREF(result);
151 result = NULL;
152 goto out;
155 ret = PyList_Append(result, pypath);
156 Py_DECREF(pypath);
157 if (ret == -1) {
158 PyErr_SetString(PyExc_RuntimeError,
159 "list append failed");
160 Py_DECREF(result);
161 result = NULL;
162 goto out;
166 out:
167 talloc_free(frame);
168 return result;
171 static PyObject *search_close(PyObject *self,
172 PyObject *args,
173 PyObject *kwargs)
175 TALLOC_CTX *frame = talloc_stackframe();
176 const char * const kwnames[] = {"pipe", NULL};
177 PyObject *pypipe = NULL;
178 dcerpc_InterfaceObject *pipe = NULL;
179 struct tevent_req *req = NULL;
180 struct mdscli_search_ctx *search = NULL;
181 NTSTATUS status;
182 bool ok;
184 if (!PyArg_ParseTupleAndKeywords(args,
185 kwargs,
186 "O",
187 discard_const_p(char *, kwnames),
188 &pypipe)) {
189 PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
190 goto fail;
193 ok = py_check_dcerpc_type(pypipe,
194 "samba.dcerpc.base",
195 "ClientConnection");
196 if (!ok) {
197 goto fail;
200 pipe = (dcerpc_InterfaceObject *)pypipe;
202 search = pytalloc_get_type(self, struct mdscli_search_ctx);
203 if (search == NULL) {
204 goto fail;
207 req = mdscli_close_search_send(frame,
208 pipe->ev,
209 &search);
210 if (req == NULL) {
211 PyErr_NoMemory();
212 goto fail;
215 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
216 PyErr_SetNTSTATUS(status);
217 goto fail;
220 status = mdscli_close_search_recv(req);
221 if (!NT_STATUS_IS_OK(status) &&
222 !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
224 PyErr_SetNTSTATUS(status);
225 goto fail;
227 TALLOC_FREE(req);
229 talloc_free(frame);
230 Py_INCREF(Py_None);
231 return Py_None;
233 fail:
234 talloc_free(frame);
235 return NULL;
238 static PyMethodDef search_methods[] = {
240 .ml_name = "get_results",
241 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, search_get_results),
242 .ml_flags = METH_VARARGS|METH_KEYWORDS,
243 .ml_doc = "",
246 .ml_name = "close",
247 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, search_close),
248 .ml_flags = METH_VARARGS|METH_KEYWORDS,
249 .ml_doc = "",
251 {0},
254 static PyObject *search_new(PyTypeObject *type,
255 PyObject *args,
256 PyObject *kwds)
258 TALLOC_CTX *frame = talloc_stackframe();
259 struct mdscli_search_ctx *search = NULL;
260 PyObject *self = NULL;
262 search = talloc_zero(frame, struct mdscli_search_ctx);
263 if (search == NULL) {
264 PyErr_NoMemory();
265 talloc_free(frame);
266 return NULL;
269 self = pytalloc_steal(type, search);
270 talloc_free(frame);
271 return self;
274 static PyTypeObject search_type = {
275 .tp_name = "mdscli.ctx.search",
276 .tp_new = search_new,
277 .tp_flags = Py_TPFLAGS_DEFAULT,
278 .tp_doc = "search([....]) -> mdssvc client search context\n",
279 .tp_methods = search_methods,
282 static PyObject *conn_sharepath(PyObject *self,
283 PyObject *unused)
285 TALLOC_CTX *frame = talloc_stackframe();
286 struct mdscli_ctx *ctx = NULL;
287 char *sharepath = NULL;
288 PyObject *result = NULL;
290 ctx = pytalloc_get_type(self, struct mdscli_ctx);
291 if (ctx == NULL) {
292 goto fail;
295 sharepath = mdscli_get_basepath(frame, ctx);
296 if (sharepath == NULL) {
297 PyErr_NoMemory();
298 goto fail;
301 result = PyUnicode_FromString(sharepath);
303 fail:
304 talloc_free(frame);
305 return result;
308 static PyObject *conn_search(PyObject *self,
309 PyObject *args,
310 PyObject *kwargs)
312 TALLOC_CTX *frame = talloc_stackframe();
313 PyObject *pypipe = NULL;
314 dcerpc_InterfaceObject *pipe = NULL;
315 struct mdscli_ctx *ctx = NULL;
316 PyObject *result = NULL;
317 char *query = NULL;
318 char *basepath = NULL;
319 struct tevent_req *req = NULL;
320 struct mdscli_search_ctx *search = NULL;
321 const char * const kwnames[] = {
322 "pipe", "query", "basepath", NULL
324 NTSTATUS status;
325 bool ok;
327 if (!PyArg_ParseTupleAndKeywords(args,
328 kwargs,
329 "Oss",
330 discard_const_p(char *, kwnames),
331 &pypipe,
332 &query,
333 &basepath)) {
334 PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
335 goto fail;
338 ok = py_check_dcerpc_type(pypipe,
339 "samba.dcerpc.base",
340 "ClientConnection");
341 if (!ok) {
342 goto fail;
345 pipe = (dcerpc_InterfaceObject *)pypipe;
347 ctx = pytalloc_get_type(self, struct mdscli_ctx);
348 if (ctx == NULL) {
349 goto fail;
352 req = mdscli_search_send(frame,
353 pipe->ev,
354 ctx,
355 query,
356 basepath,
357 false);
358 if (req == NULL) {
359 PyErr_NoMemory();
360 goto fail;
363 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
364 PyErr_SetNTSTATUS(status);
365 goto fail;
368 status = mdscli_search_recv(req, frame, &search);
369 PyErr_NTSTATUS_IS_ERR_RAISE(status);
371 result = pytalloc_steal(&search_type, search);
373 fail:
374 talloc_free(frame);
375 return result;
378 static PyObject *conn_disconnect(PyObject *self,
379 PyObject *args,
380 PyObject *kwargs)
382 TALLOC_CTX *frame = talloc_stackframe();
383 PyObject *pypipe = NULL;
384 dcerpc_InterfaceObject *pipe = NULL;
385 struct mdscli_ctx *ctx = NULL;
386 struct tevent_req *req = NULL;
387 const char * const kwnames[] = {"pipe", NULL};
388 NTSTATUS status;
389 bool ok;
391 if (!PyArg_ParseTupleAndKeywords(args,
392 kwargs,
393 "O",
394 discard_const_p(char *, kwnames),
395 &pypipe)) {
396 PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
397 goto fail;
400 ok = py_check_dcerpc_type(pypipe,
401 "samba.dcerpc.base",
402 "ClientConnection");
403 if (!ok) {
404 goto fail;
407 pipe = (dcerpc_InterfaceObject *)pypipe;
409 ctx = pytalloc_get_type(self, struct mdscli_ctx);
410 if (ctx == NULL) {
411 goto fail;
414 req = mdscli_disconnect_send(frame, pipe->ev, ctx);
415 if (req == NULL) {
416 PyErr_NoMemory();
417 goto fail;
420 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
421 PyErr_SetNTSTATUS(status);
422 goto fail;
425 status = mdscli_disconnect_recv(req);
426 PyErr_NTSTATUS_IS_ERR_RAISE(status);
428 talloc_free(frame);
429 Py_INCREF(Py_None);
430 return Py_None;
432 fail:
433 talloc_free(frame);
434 return NULL;
437 static PyMethodDef conn_methods[] = {
439 .ml_name = "sharepath",
440 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, conn_sharepath),
441 .ml_flags = METH_NOARGS,
442 .ml_doc = "mdscli.conn.sharepath(...) -> get share basepath",
445 .ml_name = "search",
446 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, conn_search),
447 .ml_flags = METH_VARARGS|METH_KEYWORDS,
448 .ml_doc = "mdscli.conn.search(...) -> run mdssvc query",
451 .ml_name = "disconnect",
452 .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, conn_disconnect),
453 .ml_flags = METH_VARARGS|METH_KEYWORDS,
454 .ml_doc = "mdscli.conn.disconnect(...) -> disconnect",
456 {0},
459 static PyObject *conn_new(PyTypeObject *type,
460 PyObject *args,
461 PyObject *kwargs)
463 TALLOC_CTX *frame = talloc_stackframe();
464 const char * const kwnames[] = { "pipe", "share", "mountpoint", NULL };
465 PyObject *pypipe = NULL;
466 dcerpc_InterfaceObject *pipe = NULL;
467 struct tevent_req *req = NULL;
468 char *share = NULL;
469 char *mountpoint = NULL;
470 struct mdscli_ctx *ctx = NULL;
471 PyObject *self = NULL;
472 NTSTATUS status;
473 bool ok;
475 if (!PyArg_ParseTupleAndKeywords(args,
476 kwargs,
477 "Oss",
478 discard_const_p(char *, kwnames),
479 &pypipe,
480 &share,
481 &mountpoint)) {
482 PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
483 goto fail;
486 ok = py_check_dcerpc_type(pypipe,
487 "samba.dcerpc.base",
488 "ClientConnection");
489 if (!ok) {
490 goto fail;
493 pipe = (dcerpc_InterfaceObject *)pypipe;
495 req = mdscli_connect_send(frame,
496 pipe->ev,
497 pipe->binding_handle,
498 share,
499 mountpoint);
500 if (req == NULL) {
501 PyErr_NoMemory();
502 goto fail;
505 if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
506 PyErr_SetNTSTATUS(status);
507 goto fail;
510 status = mdscli_connect_recv(req, frame, &ctx);
511 PyErr_NTSTATUS_IS_ERR_RAISE(status);
513 self = pytalloc_steal(type, ctx);
515 fail:
516 talloc_free(frame);
517 return self;
520 static PyTypeObject conn_type = {
521 .tp_name = "mdscli.conn",
522 .tp_new = conn_new,
523 .tp_flags = Py_TPFLAGS_DEFAULT,
524 .tp_doc = "conn([....]) -> mdssvc connection\n",
525 .tp_methods = conn_methods,
528 static PyMethodDef mdscli_methods[] = {
529 {0},
532 static struct PyModuleDef moduledef = {
533 PyModuleDef_HEAD_INIT,
534 .m_name = "mdscli",
535 .m_doc = "RPC mdssvc client",
536 .m_size = -1,
537 .m_methods = mdscli_methods,
540 MODULE_INIT_FUNC(mdscli)
542 TALLOC_CTX *frame = talloc_stackframe();
543 PyObject *m = NULL;
544 int ret;
546 ret = pytalloc_BaseObject_PyType_Ready(&conn_type);
547 if (ret < 0) {
548 TALLOC_FREE(frame);
549 return NULL;
552 ret = pytalloc_BaseObject_PyType_Ready(&search_type);
553 if (ret < 0) {
554 TALLOC_FREE(frame);
555 return NULL;
558 m = PyModule_Create(&moduledef);
559 if (m == NULL) {
560 TALLOC_FREE(frame);
561 return NULL;
564 Py_INCREF(&conn_type);
565 PyModule_AddObject(m, "conn", (PyObject *)&conn_type);
567 Py_INCREF(&search_type);
568 PyModule_AddObject(m, "search", (PyObject *)&search_type);
570 TALLOC_FREE(frame);
571 return m;