LCOV - code coverage report
Current view: top level - source3/rpc_client - py_mdscli.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 163 253 64.4 %
Date: 2024-04-21 15:09:00 Functions: 7 8 87.5 %

          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             : }

Generated by: LCOV version 1.14