Line data Source code
1 : /*
2 : Python interface to cli_mdssvc
3 :
4 : Copyright (C) Ralph Boehme 2019
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
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"
31 :
32 4 : static PyObject *search_get_results(PyObject *self,
33 : PyObject *args,
34 : PyObject *kwargs)
35 : {
36 4 : TALLOC_CTX *frame = talloc_stackframe();
37 4 : const char * const kwnames[] = {"pipe", NULL};
38 4 : PyObject *pypipe = NULL;
39 4 : PyObject *result = NULL;
40 4 : dcerpc_InterfaceObject *pipe = NULL;
41 4 : struct tevent_req *req = NULL;
42 4 : struct mdscli_search_ctx *search = NULL;
43 4 : uint64_t *cnids = NULL;
44 : size_t i;
45 : size_t ncnids;
46 : NTSTATUS status;
47 : int ret;
48 : bool ok;
49 :
50 4 : if (!PyArg_ParseTupleAndKeywords(args,
51 : kwargs,
52 : "O",
53 : discard_const_p(char *, kwnames),
54 : &pypipe)) {
55 0 : PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
56 0 : goto out;
57 : }
58 :
59 4 : ok = py_check_dcerpc_type(pypipe,
60 : "samba.dcerpc.base",
61 : "ClientConnection");
62 4 : if (!ok) {
63 0 : goto out;
64 : }
65 :
66 4 : pipe = (dcerpc_InterfaceObject *)pypipe;
67 :
68 4 : search = pytalloc_get_type(self, struct mdscli_search_ctx);
69 4 : if (search == NULL) {
70 0 : goto out;
71 : }
72 :
73 : /*
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
79 : *
80 : * dcerpc_bh_raw_call_send()
81 : * -> dcerpc_request_send()
82 : * -> dcerpc_schedule_io_trigger()
83 : * -> dcerpc_send_request()
84 : * -> tstream_writev_queue_send()
85 : *
86 : * on an hardcoded event context allocated via
87 : *
88 : * py_dcerpc_interface_init_helper()
89 : * -> dcerpc_pipe_connect()
90 : */
91 4 : again:
92 4 : req = mdscli_get_results_send(frame,
93 : pipe->ev,
94 : search);
95 4 : if (req == NULL) {
96 0 : PyErr_NoMemory();
97 0 : goto out;
98 : }
99 :
100 4 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
101 0 : PyErr_SetNTSTATUS(status);
102 0 : goto out;
103 : }
104 :
105 4 : status = mdscli_get_results_recv(req, frame, &cnids);
106 4 : TALLOC_FREE(req);
107 4 : if (NT_STATUS_EQUAL(status, NT_STATUS_PENDING)) {
108 0 : sleep(1);
109 0 : goto again;
110 : }
111 4 : if (!NT_STATUS_IS_OK(status) &&
112 0 : !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
113 : {
114 0 : PyErr_SetNTSTATUS(status);
115 0 : goto out;
116 : }
117 :
118 4 : result = Py_BuildValue("[]");
119 :
120 4 : ncnids = talloc_array_length(cnids);
121 26 : for (i = 0; i < ncnids; i++) {
122 22 : char *path = NULL;
123 22 : PyObject *pypath = NULL;
124 :
125 22 : req = mdscli_get_path_send(frame,
126 : pipe->ev,
127 : search->mdscli_ctx,
128 22 : cnids[i]);
129 22 : if (req == NULL) {
130 0 : PyErr_NoMemory();
131 0 : Py_DECREF(result);
132 0 : result = NULL;
133 0 : goto out;
134 : }
135 :
136 22 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
137 0 : PyErr_SetNTSTATUS(status);
138 0 : Py_DECREF(result);
139 0 : result = NULL;
140 0 : goto out;
141 : }
142 :
143 22 : status = mdscli_get_path_recv(req, frame, &path);
144 22 : TALLOC_FREE(req);
145 22 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
146 :
147 22 : pypath = PyUnicode_FromString(path);
148 22 : if (pypath == NULL) {
149 0 : PyErr_NoMemory();
150 0 : Py_DECREF(result);
151 0 : result = NULL;
152 0 : goto out;
153 : }
154 :
155 22 : ret = PyList_Append(result, pypath);
156 22 : Py_DECREF(pypath);
157 22 : if (ret == -1) {
158 0 : PyErr_SetString(PyExc_RuntimeError,
159 : "list append failed");
160 0 : Py_DECREF(result);
161 0 : result = NULL;
162 0 : goto out;
163 : }
164 : }
165 :
166 4 : out:
167 4 : talloc_free(frame);
168 4 : return result;
169 : }
170 :
171 4 : static PyObject *search_close(PyObject *self,
172 : PyObject *args,
173 : PyObject *kwargs)
174 : {
175 4 : TALLOC_CTX *frame = talloc_stackframe();
176 4 : const char * const kwnames[] = {"pipe", NULL};
177 4 : PyObject *pypipe = NULL;
178 4 : dcerpc_InterfaceObject *pipe = NULL;
179 4 : struct tevent_req *req = NULL;
180 4 : struct mdscli_search_ctx *search = NULL;
181 : NTSTATUS status;
182 : bool ok;
183 :
184 4 : if (!PyArg_ParseTupleAndKeywords(args,
185 : kwargs,
186 : "O",
187 : discard_const_p(char *, kwnames),
188 : &pypipe)) {
189 0 : PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
190 0 : goto fail;
191 : }
192 :
193 4 : ok = py_check_dcerpc_type(pypipe,
194 : "samba.dcerpc.base",
195 : "ClientConnection");
196 4 : if (!ok) {
197 0 : goto fail;
198 : }
199 :
200 4 : pipe = (dcerpc_InterfaceObject *)pypipe;
201 :
202 4 : search = pytalloc_get_type(self, struct mdscli_search_ctx);
203 4 : if (search == NULL) {
204 0 : goto fail;
205 : }
206 :
207 4 : req = mdscli_close_search_send(frame,
208 : pipe->ev,
209 : &search);
210 4 : if (req == NULL) {
211 0 : PyErr_NoMemory();
212 0 : goto fail;
213 : }
214 :
215 4 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
216 0 : PyErr_SetNTSTATUS(status);
217 0 : goto fail;
218 : }
219 :
220 4 : status = mdscli_close_search_recv(req);
221 4 : if (!NT_STATUS_IS_OK(status) &&
222 0 : !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
223 : {
224 0 : PyErr_SetNTSTATUS(status);
225 0 : goto fail;
226 : }
227 4 : TALLOC_FREE(req);
228 :
229 4 : talloc_free(frame);
230 4 : Py_INCREF(Py_None);
231 4 : return Py_None;
232 :
233 0 : fail:
234 0 : talloc_free(frame);
235 0 : return NULL;
236 : }
237 :
238 : static PyMethodDef search_methods[] = {
239 : {
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 = "",
244 : },
245 : {
246 : .ml_name = "close",
247 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, search_close),
248 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
249 : .ml_doc = "",
250 : },
251 : {0},
252 : };
253 :
254 0 : static PyObject *search_new(PyTypeObject *type,
255 : PyObject *args,
256 : PyObject *kwds)
257 : {
258 0 : TALLOC_CTX *frame = talloc_stackframe();
259 0 : struct mdscli_search_ctx *search = NULL;
260 0 : PyObject *self = NULL;
261 :
262 0 : search = talloc_zero(frame, struct mdscli_search_ctx);
263 0 : if (search == NULL) {
264 0 : PyErr_NoMemory();
265 0 : talloc_free(frame);
266 0 : return NULL;
267 : }
268 :
269 0 : self = pytalloc_steal(type, search);
270 0 : talloc_free(frame);
271 0 : return self;
272 : }
273 :
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,
280 : };
281 :
282 4 : static PyObject *conn_sharepath(PyObject *self,
283 : PyObject *unused)
284 : {
285 4 : TALLOC_CTX *frame = talloc_stackframe();
286 4 : struct mdscli_ctx *ctx = NULL;
287 4 : char *sharepath = NULL;
288 4 : PyObject *result = NULL;
289 :
290 4 : ctx = pytalloc_get_type(self, struct mdscli_ctx);
291 4 : if (ctx == NULL) {
292 0 : goto fail;
293 : }
294 :
295 4 : sharepath = mdscli_get_basepath(frame, ctx);
296 4 : if (sharepath == NULL) {
297 0 : PyErr_NoMemory();
298 0 : goto fail;
299 : }
300 :
301 4 : result = PyUnicode_FromString(sharepath);
302 :
303 4 : fail:
304 4 : talloc_free(frame);
305 4 : return result;
306 : }
307 :
308 4 : static PyObject *conn_search(PyObject *self,
309 : PyObject *args,
310 : PyObject *kwargs)
311 : {
312 4 : TALLOC_CTX *frame = talloc_stackframe();
313 4 : PyObject *pypipe = NULL;
314 4 : dcerpc_InterfaceObject *pipe = NULL;
315 4 : struct mdscli_ctx *ctx = NULL;
316 4 : PyObject *result = NULL;
317 4 : char *query = NULL;
318 4 : char *basepath = NULL;
319 4 : struct tevent_req *req = NULL;
320 4 : struct mdscli_search_ctx *search = NULL;
321 4 : const char * const kwnames[] = {
322 : "pipe", "query", "basepath", NULL
323 : };
324 : NTSTATUS status;
325 : bool ok;
326 :
327 4 : if (!PyArg_ParseTupleAndKeywords(args,
328 : kwargs,
329 : "Oss",
330 : discard_const_p(char *, kwnames),
331 : &pypipe,
332 : &query,
333 : &basepath)) {
334 0 : PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
335 0 : goto fail;
336 : }
337 :
338 4 : ok = py_check_dcerpc_type(pypipe,
339 : "samba.dcerpc.base",
340 : "ClientConnection");
341 4 : if (!ok) {
342 0 : goto fail;
343 : }
344 :
345 4 : pipe = (dcerpc_InterfaceObject *)pypipe;
346 :
347 4 : ctx = pytalloc_get_type(self, struct mdscli_ctx);
348 4 : if (ctx == NULL) {
349 0 : goto fail;
350 : }
351 :
352 4 : req = mdscli_search_send(frame,
353 : pipe->ev,
354 : ctx,
355 : query,
356 : basepath,
357 : false);
358 4 : if (req == NULL) {
359 0 : PyErr_NoMemory();
360 0 : goto fail;
361 : }
362 :
363 4 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
364 0 : PyErr_SetNTSTATUS(status);
365 0 : goto fail;
366 : }
367 :
368 4 : status = mdscli_search_recv(req, frame, &search);
369 4 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
370 :
371 4 : result = pytalloc_steal(&search_type, search);
372 :
373 4 : fail:
374 4 : talloc_free(frame);
375 4 : return result;
376 : }
377 :
378 8 : static PyObject *conn_disconnect(PyObject *self,
379 : PyObject *args,
380 : PyObject *kwargs)
381 : {
382 8 : TALLOC_CTX *frame = talloc_stackframe();
383 8 : PyObject *pypipe = NULL;
384 8 : dcerpc_InterfaceObject *pipe = NULL;
385 8 : struct mdscli_ctx *ctx = NULL;
386 8 : struct tevent_req *req = NULL;
387 8 : const char * const kwnames[] = {"pipe", NULL};
388 : NTSTATUS status;
389 : bool ok;
390 :
391 8 : if (!PyArg_ParseTupleAndKeywords(args,
392 : kwargs,
393 : "O",
394 : discard_const_p(char *, kwnames),
395 : &pypipe)) {
396 0 : PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
397 0 : goto fail;
398 : }
399 :
400 8 : ok = py_check_dcerpc_type(pypipe,
401 : "samba.dcerpc.base",
402 : "ClientConnection");
403 8 : if (!ok) {
404 0 : goto fail;
405 : }
406 :
407 8 : pipe = (dcerpc_InterfaceObject *)pypipe;
408 :
409 8 : ctx = pytalloc_get_type(self, struct mdscli_ctx);
410 8 : if (ctx == NULL) {
411 0 : goto fail;
412 : }
413 :
414 8 : req = mdscli_disconnect_send(frame, pipe->ev, ctx);
415 8 : if (req == NULL) {
416 0 : PyErr_NoMemory();
417 0 : goto fail;
418 : }
419 :
420 8 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
421 0 : PyErr_SetNTSTATUS(status);
422 0 : goto fail;
423 : }
424 :
425 8 : status = mdscli_disconnect_recv(req);
426 8 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
427 :
428 8 : talloc_free(frame);
429 8 : Py_INCREF(Py_None);
430 8 : return Py_None;
431 :
432 0 : fail:
433 0 : talloc_free(frame);
434 0 : return NULL;
435 : }
436 :
437 : static PyMethodDef conn_methods[] = {
438 : {
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",
443 : },
444 : {
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",
449 : },
450 : {
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",
455 : },
456 : {0},
457 : };
458 :
459 8 : static PyObject *conn_new(PyTypeObject *type,
460 : PyObject *args,
461 : PyObject *kwargs)
462 : {
463 8 : TALLOC_CTX *frame = talloc_stackframe();
464 8 : const char * const kwnames[] = { "pipe", "share", "mountpoint", NULL };
465 8 : PyObject *pypipe = NULL;
466 8 : dcerpc_InterfaceObject *pipe = NULL;
467 8 : struct tevent_req *req = NULL;
468 8 : char *share = NULL;
469 8 : char *mountpoint = NULL;
470 8 : struct mdscli_ctx *ctx = NULL;
471 8 : PyObject *self = NULL;
472 : NTSTATUS status;
473 : bool ok;
474 :
475 8 : if (!PyArg_ParseTupleAndKeywords(args,
476 : kwargs,
477 : "Oss",
478 : discard_const_p(char *, kwnames),
479 : &pypipe,
480 : &share,
481 : &mountpoint)) {
482 0 : PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
483 0 : goto fail;
484 : }
485 :
486 8 : ok = py_check_dcerpc_type(pypipe,
487 : "samba.dcerpc.base",
488 : "ClientConnection");
489 8 : if (!ok) {
490 0 : goto fail;
491 : }
492 :
493 8 : pipe = (dcerpc_InterfaceObject *)pypipe;
494 :
495 8 : req = mdscli_connect_send(frame,
496 : pipe->ev,
497 : pipe->binding_handle,
498 : share,
499 : mountpoint);
500 8 : if (req == NULL) {
501 0 : PyErr_NoMemory();
502 0 : goto fail;
503 : }
504 :
505 8 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
506 0 : PyErr_SetNTSTATUS(status);
507 0 : goto fail;
508 : }
509 :
510 8 : status = mdscli_connect_recv(req, frame, &ctx);
511 8 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
512 :
513 8 : self = pytalloc_steal(type, ctx);
514 :
515 8 : fail:
516 8 : talloc_free(frame);
517 8 : return self;
518 : }
519 :
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,
526 : };
527 :
528 : static PyMethodDef mdscli_methods[] = {
529 : {0},
530 : };
531 :
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,
538 : };
539 :
540 4 : MODULE_INIT_FUNC(mdscli)
541 : {
542 4 : TALLOC_CTX *frame = talloc_stackframe();
543 4 : PyObject *m = NULL;
544 : int ret;
545 :
546 4 : ret = pytalloc_BaseObject_PyType_Ready(&conn_type);
547 4 : if (ret < 0) {
548 0 : TALLOC_FREE(frame);
549 0 : return NULL;
550 : }
551 :
552 4 : ret = pytalloc_BaseObject_PyType_Ready(&search_type);
553 4 : if (ret < 0) {
554 0 : TALLOC_FREE(frame);
555 0 : return NULL;
556 : }
557 :
558 4 : m = PyModule_Create(&moduledef);
559 4 : if (m == NULL) {
560 0 : TALLOC_FREE(frame);
561 0 : return NULL;
562 : }
563 :
564 4 : Py_INCREF(&conn_type);
565 4 : PyModule_AddObject(m, "conn", (PyObject *)&conn_type);
566 :
567 4 : Py_INCREF(&search_type);
568 4 : PyModule_AddObject(m, "search", (PyObject *)&search_type);
569 :
570 4 : TALLOC_FREE(frame);
571 4 : return m;
572 : }
|