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 <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 : req = mdscli_get_results_send(frame,
92 : pipe->ev,
93 : search);
94 4 : if (req == NULL) {
95 0 : PyErr_NoMemory();
96 0 : goto out;
97 : }
98 :
99 4 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
100 0 : PyErr_SetNTSTATUS(status);
101 0 : goto out;
102 : }
103 :
104 4 : status = mdscli_get_results_recv(req, frame, &cnids);
105 4 : if (!NT_STATUS_IS_OK(status) &&
106 0 : !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
107 : {
108 0 : PyErr_SetNTSTATUS(status);
109 0 : goto out;
110 : }
111 4 : TALLOC_FREE(req);
112 :
113 4 : result = Py_BuildValue("[]");
114 :
115 4 : ncnids = talloc_array_length(cnids);
116 52 : for (i = 0; i < ncnids; i++) {
117 22 : char *path = NULL;
118 22 : PyObject *pypath = NULL;
119 :
120 22 : req = mdscli_get_path_send(frame,
121 : pipe->ev,
122 : search->mdscli_ctx,
123 22 : cnids[i]);
124 22 : if (req == NULL) {
125 0 : PyErr_NoMemory();
126 0 : Py_DECREF(result);
127 0 : result = NULL;
128 0 : goto out;
129 : }
130 :
131 22 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
132 0 : PyErr_SetNTSTATUS(status);
133 0 : Py_DECREF(result);
134 0 : result = NULL;
135 0 : goto out;
136 : }
137 :
138 22 : status = mdscli_get_path_recv(req, frame, &path);
139 22 : TALLOC_FREE(req);
140 22 : PyErr_NTSTATUS_NOT_OK_RAISE(status);
141 :
142 22 : pypath = PyUnicode_FromString(path);
143 22 : if (pypath == NULL) {
144 0 : PyErr_NoMemory();
145 0 : Py_DECREF(result);
146 0 : result = NULL;
147 0 : goto out;
148 : }
149 :
150 22 : ret = PyList_Append(result, pypath);
151 22 : Py_DECREF(pypath);
152 22 : if (ret == -1) {
153 0 : PyErr_SetString(PyExc_RuntimeError,
154 : "list append failed");
155 0 : Py_DECREF(result);
156 0 : result = NULL;
157 0 : goto out;
158 : }
159 : }
160 :
161 4 : out:
162 4 : talloc_free(frame);
163 4 : return result;
164 : }
165 :
166 4 : static PyObject *search_close(PyObject *self,
167 : PyObject *args,
168 : PyObject *kwargs)
169 : {
170 4 : TALLOC_CTX *frame = talloc_stackframe();
171 4 : const char * const kwnames[] = {"pipe", NULL};
172 4 : PyObject *pypipe = NULL;
173 4 : dcerpc_InterfaceObject *pipe = NULL;
174 4 : struct tevent_req *req = NULL;
175 4 : struct mdscli_search_ctx *search = NULL;
176 : NTSTATUS status;
177 : bool ok;
178 :
179 4 : if (!PyArg_ParseTupleAndKeywords(args,
180 : kwargs,
181 : "O",
182 : discard_const_p(char *, kwnames),
183 : &pypipe)) {
184 0 : PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
185 0 : goto fail;
186 : }
187 :
188 4 : ok = py_check_dcerpc_type(pypipe,
189 : "samba.dcerpc.base",
190 : "ClientConnection");
191 4 : if (!ok) {
192 0 : goto fail;
193 : }
194 :
195 4 : pipe = (dcerpc_InterfaceObject *)pypipe;
196 :
197 4 : search = pytalloc_get_type(self, struct mdscli_search_ctx);
198 4 : if (search == NULL) {
199 0 : goto fail;
200 : }
201 :
202 4 : req = mdscli_close_search_send(frame,
203 : pipe->ev,
204 : &search);
205 4 : if (req == NULL) {
206 0 : PyErr_NoMemory();
207 0 : goto fail;
208 : }
209 :
210 4 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
211 0 : PyErr_SetNTSTATUS(status);
212 0 : goto fail;
213 : }
214 :
215 4 : status = mdscli_close_search_recv(req);
216 4 : if (!NT_STATUS_IS_OK(status) &&
217 0 : !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES))
218 : {
219 0 : PyErr_SetNTSTATUS(status);
220 0 : goto fail;
221 : }
222 4 : TALLOC_FREE(req);
223 :
224 4 : talloc_free(frame);
225 4 : Py_INCREF(Py_None);
226 4 : return Py_None;
227 :
228 0 : fail:
229 0 : talloc_free(frame);
230 0 : return NULL;
231 : }
232 :
233 : static PyMethodDef search_methods[] = {
234 : {
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 = "",
239 : },
240 : {
241 : .ml_name = "close",
242 : .ml_meth = PY_DISCARD_FUNC_SIG(PyCFunction, search_close),
243 : .ml_flags = METH_VARARGS|METH_KEYWORDS,
244 : .ml_doc = "",
245 : },
246 : {0},
247 : };
248 :
249 0 : static PyObject *search_new(PyTypeObject *type,
250 : PyObject *args,
251 : PyObject *kwds)
252 : {
253 0 : TALLOC_CTX *frame = talloc_stackframe();
254 0 : struct mdscli_search_ctx *search = NULL;
255 0 : PyObject *self = NULL;
256 :
257 0 : search = talloc_zero(frame, struct mdscli_search_ctx);
258 0 : if (search == NULL) {
259 0 : PyErr_NoMemory();
260 0 : talloc_free(frame);
261 0 : return NULL;
262 : }
263 :
264 0 : self = pytalloc_steal(type, search);
265 0 : talloc_free(frame);
266 0 : return self;
267 : }
268 :
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,
275 : };
276 :
277 6 : static PyObject *conn_sharepath(PyObject *self,
278 : PyObject *unused)
279 : {
280 6 : TALLOC_CTX *frame = talloc_stackframe();
281 6 : struct mdscli_ctx *ctx = NULL;
282 6 : char *sharepath = NULL;
283 6 : PyObject *result = NULL;
284 :
285 6 : ctx = pytalloc_get_type(self, struct mdscli_ctx);
286 6 : if (ctx == NULL) {
287 0 : goto fail;
288 : }
289 :
290 6 : sharepath = mdscli_get_basepath(frame, ctx);
291 6 : if (sharepath == NULL) {
292 0 : PyErr_NoMemory();
293 0 : goto fail;
294 : }
295 :
296 6 : result = PyUnicode_FromString(sharepath);
297 :
298 6 : fail:
299 6 : talloc_free(frame);
300 6 : return result;
301 : }
302 :
303 4 : static PyObject *conn_search(PyObject *self,
304 : PyObject *args,
305 : PyObject *kwargs)
306 : {
307 4 : TALLOC_CTX *frame = talloc_stackframe();
308 4 : PyObject *pypipe = NULL;
309 4 : dcerpc_InterfaceObject *pipe = NULL;
310 4 : struct mdscli_ctx *ctx = NULL;
311 4 : PyObject *result = NULL;
312 4 : char *query = NULL;
313 4 : char *basepath = NULL;
314 4 : struct tevent_req *req = NULL;
315 4 : struct mdscli_search_ctx *search = NULL;
316 4 : const char * const kwnames[] = {
317 : "pipe", "query", "basepath", NULL
318 : };
319 : NTSTATUS status;
320 : bool ok;
321 :
322 4 : if (!PyArg_ParseTupleAndKeywords(args,
323 : kwargs,
324 : "Oss",
325 : discard_const_p(char *, kwnames),
326 : &pypipe,
327 : &query,
328 : &basepath)) {
329 0 : PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
330 0 : goto fail;
331 : }
332 :
333 4 : ok = py_check_dcerpc_type(pypipe,
334 : "samba.dcerpc.base",
335 : "ClientConnection");
336 4 : if (!ok) {
337 0 : goto fail;
338 : }
339 :
340 4 : pipe = (dcerpc_InterfaceObject *)pypipe;
341 :
342 4 : ctx = pytalloc_get_type(self, struct mdscli_ctx);
343 4 : if (ctx == NULL) {
344 0 : goto fail;
345 : }
346 :
347 4 : req = mdscli_search_send(frame,
348 : pipe->ev,
349 : ctx,
350 : query,
351 : basepath,
352 : false);
353 4 : if (req == NULL) {
354 0 : PyErr_NoMemory();
355 0 : goto fail;
356 : }
357 :
358 4 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
359 0 : PyErr_SetNTSTATUS(status);
360 0 : goto fail;
361 : }
362 :
363 4 : status = mdscli_search_recv(req, frame, &search);
364 4 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
365 :
366 4 : result = pytalloc_steal(&search_type, search);
367 :
368 4 : fail:
369 4 : talloc_free(frame);
370 4 : return result;
371 : }
372 :
373 10 : static PyObject *conn_disconnect(PyObject *self,
374 : PyObject *args,
375 : PyObject *kwargs)
376 : {
377 10 : TALLOC_CTX *frame = talloc_stackframe();
378 10 : PyObject *pypipe = NULL;
379 10 : dcerpc_InterfaceObject *pipe = NULL;
380 10 : struct mdscli_ctx *ctx = NULL;
381 10 : struct tevent_req *req = NULL;
382 10 : const char * const kwnames[] = {"pipe", NULL};
383 : NTSTATUS status;
384 : bool ok;
385 :
386 10 : if (!PyArg_ParseTupleAndKeywords(args,
387 : kwargs,
388 : "O",
389 : discard_const_p(char *, kwnames),
390 : &pypipe)) {
391 0 : PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
392 0 : goto fail;
393 : }
394 :
395 10 : ok = py_check_dcerpc_type(pypipe,
396 : "samba.dcerpc.base",
397 : "ClientConnection");
398 10 : if (!ok) {
399 0 : goto fail;
400 : }
401 :
402 10 : pipe = (dcerpc_InterfaceObject *)pypipe;
403 :
404 10 : ctx = pytalloc_get_type(self, struct mdscli_ctx);
405 10 : if (ctx == NULL) {
406 0 : goto fail;
407 : }
408 :
409 10 : req = mdscli_disconnect_send(frame, pipe->ev, ctx);
410 10 : if (req == NULL) {
411 0 : PyErr_NoMemory();
412 0 : goto fail;
413 : }
414 :
415 10 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
416 0 : PyErr_SetNTSTATUS(status);
417 0 : goto fail;
418 : }
419 :
420 10 : status = mdscli_disconnect_recv(req);
421 10 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
422 :
423 10 : talloc_free(frame);
424 10 : Py_INCREF(Py_None);
425 10 : return Py_None;
426 :
427 0 : fail:
428 0 : talloc_free(frame);
429 0 : return NULL;
430 : }
431 :
432 : static PyMethodDef conn_methods[] = {
433 : {
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",
438 : },
439 : {
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",
444 : },
445 : {
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",
450 : },
451 : {0},
452 : };
453 :
454 10 : static PyObject *conn_new(PyTypeObject *type,
455 : PyObject *args,
456 : PyObject *kwargs)
457 : {
458 10 : TALLOC_CTX *frame = talloc_stackframe();
459 10 : const char * const kwnames[] = { "pipe", "share", "mountpoint", NULL };
460 10 : PyObject *pypipe = NULL;
461 10 : dcerpc_InterfaceObject *pipe = NULL;
462 10 : struct tevent_req *req = NULL;
463 10 : char *share = NULL;
464 10 : char *mountpoint = NULL;
465 10 : struct mdscli_ctx *ctx = NULL;
466 10 : PyObject *self = NULL;
467 : NTSTATUS status;
468 : bool ok;
469 :
470 10 : if (!PyArg_ParseTupleAndKeywords(args,
471 : kwargs,
472 : "Oss",
473 : discard_const_p(char *, kwnames),
474 : &pypipe,
475 : &share,
476 : &mountpoint)) {
477 0 : PyErr_SetString(PyExc_RuntimeError, "Failed to parse args");
478 0 : goto fail;
479 : }
480 :
481 10 : ok = py_check_dcerpc_type(pypipe,
482 : "samba.dcerpc.base",
483 : "ClientConnection");
484 10 : if (!ok) {
485 0 : goto fail;
486 : }
487 :
488 10 : pipe = (dcerpc_InterfaceObject *)pypipe;
489 :
490 10 : req = mdscli_connect_send(frame,
491 : pipe->ev,
492 : pipe->binding_handle,
493 : share,
494 : mountpoint);
495 10 : if (req == NULL) {
496 0 : PyErr_NoMemory();
497 0 : goto fail;
498 : }
499 :
500 10 : if (!tevent_req_poll_ntstatus(req, pipe->ev, &status)) {
501 0 : PyErr_SetNTSTATUS(status);
502 0 : goto fail;
503 : }
504 :
505 10 : status = mdscli_connect_recv(req, frame, &ctx);
506 10 : PyErr_NTSTATUS_IS_ERR_RAISE(status);
507 :
508 10 : self = pytalloc_steal(type, ctx);
509 :
510 10 : fail:
511 10 : talloc_free(frame);
512 10 : return self;
513 : }
514 :
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,
521 : };
522 :
523 : static PyMethodDef mdscli_methods[] = {
524 : {0},
525 : };
526 :
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,
533 : };
534 :
535 4 : MODULE_INIT_FUNC(mdscli)
536 : {
537 4 : TALLOC_CTX *frame = talloc_stackframe();
538 4 : PyObject *m = NULL;
539 : int ret;
540 :
541 4 : ret = pytalloc_BaseObject_PyType_Ready(&conn_type);
542 4 : if (ret < 0) {
543 0 : TALLOC_FREE(frame);
544 0 : return NULL;
545 : }
546 :
547 4 : ret = pytalloc_BaseObject_PyType_Ready(&search_type);
548 4 : if (ret < 0) {
549 0 : TALLOC_FREE(frame);
550 0 : return NULL;
551 : }
552 :
553 4 : m = PyModule_Create(&moduledef);
554 4 : if (m == NULL) {
555 0 : TALLOC_FREE(frame);
556 0 : return NULL;
557 : }
558 :
559 4 : Py_INCREF(&conn_type);
560 4 : PyModule_AddObject(m, "conn", (PyObject *)&conn_type);
561 :
562 4 : Py_INCREF(&search_type);
563 4 : PyModule_AddObject(m, "search", (PyObject *)&search_type);
564 :
565 4 : TALLOC_FREE(frame);
566 4 : return m;
567 : }
|