LCOV - code coverage report
Current view: top level - source3/rpc_client - py_mdscli.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 161 249 64.7 %
Date: 2021-09-23 10:06:22 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 <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             : }

Generated by: LCOV version 1.13