2019-07-28 16:08:29 +03:00
/*
Python interface to cli_mdssvc
Copyright ( C ) Ralph Boehme 2019
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2023-11-09 13:35:56 +03:00
# include "lib/replace/system/python.h"
2019-07-28 16:08:29 +03:00
# include <pytalloc.h>
# include "includes.h"
# include "python/py3compat.h"
# include "python/modules.h"
# include "lib/util/talloc_stack.h"
# include "lib/util/tevent_ntstatus.h"
# include "librpc/rpc/rpc_common.h"
# include "librpc/rpc/pyrpc_util.h"
# include "rpc_client/cli_mdssvc.h"
# include "rpc_client/cli_mdssvc_private.h"
static PyObject * search_get_results ( PyObject * self ,
PyObject * args ,
PyObject * kwargs )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
const char * const kwnames [ ] = { " pipe " , NULL } ;
PyObject * pypipe = NULL ;
PyObject * result = NULL ;
dcerpc_InterfaceObject * pipe = NULL ;
struct tevent_req * req = NULL ;
struct mdscli_search_ctx * search = NULL ;
uint64_t * cnids = NULL ;
size_t i ;
size_t ncnids ;
NTSTATUS status ;
int ret ;
bool ok ;
if ( ! PyArg_ParseTupleAndKeywords ( args ,
kwargs ,
" O " ,
discard_const_p ( char * , kwnames ) ,
& pypipe ) ) {
PyErr_SetString ( PyExc_RuntimeError , " Failed to parse args " ) ;
goto out ;
}
ok = py_check_dcerpc_type ( pypipe ,
" samba.dcerpc.base " ,
" ClientConnection " ) ;
if ( ! ok ) {
goto out ;
}
pipe = ( dcerpc_InterfaceObject * ) pypipe ;
search = pytalloc_get_type ( self , struct mdscli_search_ctx ) ;
if ( search = = NULL ) {
goto out ;
}
/*
* We must use the async send / recv versions in order to pass the correct
* tevent context , here and any other place we call mdscli_ *
* functions . Using the sync version we would be polling a temporary
* event context , but unfortunately the s4 Python RPC bindings dispatch
* events through
*
* dcerpc_bh_raw_call_send ( )
* - > dcerpc_request_send ( )
* - > dcerpc_schedule_io_trigger ( )
* - > dcerpc_send_request ( )
* - > tstream_writev_queue_send ( )
*
* on an hardcoded event context allocated via
*
* py_dcerpc_interface_init_helper ( )
* - > dcerpc_pipe_connect ( )
*/
2023-04-20 16:12:49 +03:00
again :
2019-07-28 16:08:29 +03:00
req = mdscli_get_results_send ( frame ,
pipe - > ev ,
search ) ;
if ( req = = NULL ) {
PyErr_NoMemory ( ) ;
goto out ;
}
if ( ! tevent_req_poll_ntstatus ( req , pipe - > ev , & status ) ) {
PyErr_SetNTSTATUS ( status ) ;
goto out ;
}
status = mdscli_get_results_recv ( req , frame , & cnids ) ;
2023-04-20 16:12:49 +03:00
TALLOC_FREE ( req ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_PENDING ) ) {
sleep ( 1 ) ;
goto again ;
}
2019-07-28 16:08:29 +03:00
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_NO_MORE_MATCHES ) )
{
PyErr_SetNTSTATUS ( status ) ;
goto out ;
}
result = Py_BuildValue ( " [] " ) ;
ncnids = talloc_array_length ( cnids ) ;
for ( i = 0 ; i < ncnids ; i + + ) {
char * path = NULL ;
PyObject * pypath = NULL ;
req = mdscli_get_path_send ( frame ,
pipe - > ev ,
search - > mdscli_ctx ,
cnids [ i ] ) ;
if ( req = = NULL ) {
PyErr_NoMemory ( ) ;
Py_DECREF ( result ) ;
result = NULL ;
goto out ;
}
if ( ! tevent_req_poll_ntstatus ( req , pipe - > ev , & status ) ) {
PyErr_SetNTSTATUS ( status ) ;
Py_DECREF ( result ) ;
result = NULL ;
goto out ;
}
status = mdscli_get_path_recv ( req , frame , & path ) ;
TALLOC_FREE ( req ) ;
PyErr_NTSTATUS_NOT_OK_RAISE ( status ) ;
pypath = PyUnicode_FromString ( path ) ;
if ( pypath = = NULL ) {
PyErr_NoMemory ( ) ;
Py_DECREF ( result ) ;
result = NULL ;
goto out ;
}
ret = PyList_Append ( result , pypath ) ;
Py_DECREF ( pypath ) ;
if ( ret = = - 1 ) {
PyErr_SetString ( PyExc_RuntimeError ,
" list append failed " ) ;
Py_DECREF ( result ) ;
result = NULL ;
goto out ;
}
}
out :
talloc_free ( frame ) ;
return result ;
}
static PyObject * search_close ( PyObject * self ,
PyObject * args ,
PyObject * kwargs )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
const char * const kwnames [ ] = { " pipe " , NULL } ;
PyObject * pypipe = NULL ;
dcerpc_InterfaceObject * pipe = NULL ;
struct tevent_req * req = NULL ;
struct mdscli_search_ctx * search = NULL ;
NTSTATUS status ;
bool ok ;
if ( ! PyArg_ParseTupleAndKeywords ( args ,
kwargs ,
" O " ,
discard_const_p ( char * , kwnames ) ,
& pypipe ) ) {
PyErr_SetString ( PyExc_RuntimeError , " Failed to parse args " ) ;
goto fail ;
}
ok = py_check_dcerpc_type ( pypipe ,
" samba.dcerpc.base " ,
" ClientConnection " ) ;
if ( ! ok ) {
goto fail ;
}
pipe = ( dcerpc_InterfaceObject * ) pypipe ;
search = pytalloc_get_type ( self , struct mdscli_search_ctx ) ;
if ( search = = NULL ) {
goto fail ;
}
req = mdscli_close_search_send ( frame ,
pipe - > ev ,
& search ) ;
if ( req = = NULL ) {
PyErr_NoMemory ( ) ;
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , pipe - > ev , & status ) ) {
PyErr_SetNTSTATUS ( status ) ;
goto fail ;
}
status = mdscli_close_search_recv ( req ) ;
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_NO_MORE_MATCHES ) )
{
PyErr_SetNTSTATUS ( status ) ;
goto fail ;
}
TALLOC_FREE ( req ) ;
talloc_free ( frame ) ;
Py_INCREF ( Py_None ) ;
return Py_None ;
fail :
talloc_free ( frame ) ;
return NULL ;
}
static PyMethodDef search_methods [ ] = {
{
. ml_name = " get_results " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction , search_get_results ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = " " ,
} ,
{
. ml_name = " close " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction , search_close ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = " " ,
} ,
2020-05-05 04:47:39 +03:00
{ 0 } ,
2019-07-28 16:08:29 +03:00
} ;
static PyObject * search_new ( PyTypeObject * type ,
PyObject * args ,
PyObject * kwds )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct mdscli_search_ctx * search = NULL ;
PyObject * self = NULL ;
search = talloc_zero ( frame , struct mdscli_search_ctx ) ;
if ( search = = NULL ) {
PyErr_NoMemory ( ) ;
talloc_free ( frame ) ;
return NULL ;
}
self = pytalloc_steal ( type , search ) ;
talloc_free ( frame ) ;
return self ;
}
static PyTypeObject search_type = {
. tp_name = " mdscli.ctx.search " ,
. tp_new = search_new ,
. tp_flags = Py_TPFLAGS_DEFAULT ,
. tp_doc = " search([....]) -> mdssvc client search context \n " ,
. tp_methods = search_methods ,
} ;
static PyObject * conn_sharepath ( PyObject * self ,
PyObject * unused )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct mdscli_ctx * ctx = NULL ;
char * sharepath = NULL ;
PyObject * result = NULL ;
ctx = pytalloc_get_type ( self , struct mdscli_ctx ) ;
if ( ctx = = NULL ) {
goto fail ;
}
sharepath = mdscli_get_basepath ( frame , ctx ) ;
if ( sharepath = = NULL ) {
PyErr_NoMemory ( ) ;
goto fail ;
}
result = PyUnicode_FromString ( sharepath ) ;
fail :
talloc_free ( frame ) ;
return result ;
}
static PyObject * conn_search ( PyObject * self ,
PyObject * args ,
PyObject * kwargs )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
PyObject * pypipe = NULL ;
dcerpc_InterfaceObject * pipe = NULL ;
struct mdscli_ctx * ctx = NULL ;
PyObject * result = NULL ;
char * query = NULL ;
char * basepath = NULL ;
struct tevent_req * req = NULL ;
struct mdscli_search_ctx * search = NULL ;
const char * const kwnames [ ] = {
" pipe " , " query " , " basepath " , NULL
} ;
NTSTATUS status ;
bool ok ;
if ( ! PyArg_ParseTupleAndKeywords ( args ,
kwargs ,
" Oss " ,
discard_const_p ( char * , kwnames ) ,
& pypipe ,
& query ,
& basepath ) ) {
PyErr_SetString ( PyExc_RuntimeError , " Failed to parse args " ) ;
goto fail ;
}
ok = py_check_dcerpc_type ( pypipe ,
" samba.dcerpc.base " ,
" ClientConnection " ) ;
if ( ! ok ) {
goto fail ;
}
pipe = ( dcerpc_InterfaceObject * ) pypipe ;
ctx = pytalloc_get_type ( self , struct mdscli_ctx ) ;
if ( ctx = = NULL ) {
goto fail ;
}
req = mdscli_search_send ( frame ,
pipe - > ev ,
ctx ,
query ,
basepath ,
false ) ;
if ( req = = NULL ) {
PyErr_NoMemory ( ) ;
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , pipe - > ev , & status ) ) {
PyErr_SetNTSTATUS ( status ) ;
goto fail ;
}
status = mdscli_search_recv ( req , frame , & search ) ;
PyErr_NTSTATUS_IS_ERR_RAISE ( status ) ;
result = pytalloc_steal ( & search_type , search ) ;
fail :
talloc_free ( frame ) ;
return result ;
}
static PyObject * conn_disconnect ( PyObject * self ,
PyObject * args ,
PyObject * kwargs )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
PyObject * pypipe = NULL ;
dcerpc_InterfaceObject * pipe = NULL ;
struct mdscli_ctx * ctx = NULL ;
struct tevent_req * req = NULL ;
const char * const kwnames [ ] = { " pipe " , NULL } ;
NTSTATUS status ;
bool ok ;
if ( ! PyArg_ParseTupleAndKeywords ( args ,
kwargs ,
" O " ,
discard_const_p ( char * , kwnames ) ,
& pypipe ) ) {
PyErr_SetString ( PyExc_RuntimeError , " Failed to parse args " ) ;
goto fail ;
}
ok = py_check_dcerpc_type ( pypipe ,
" samba.dcerpc.base " ,
" ClientConnection " ) ;
if ( ! ok ) {
goto fail ;
}
pipe = ( dcerpc_InterfaceObject * ) pypipe ;
ctx = pytalloc_get_type ( self , struct mdscli_ctx ) ;
if ( ctx = = NULL ) {
goto fail ;
}
req = mdscli_disconnect_send ( frame , pipe - > ev , ctx ) ;
if ( req = = NULL ) {
PyErr_NoMemory ( ) ;
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , pipe - > ev , & status ) ) {
PyErr_SetNTSTATUS ( status ) ;
goto fail ;
}
status = mdscli_disconnect_recv ( req ) ;
PyErr_NTSTATUS_IS_ERR_RAISE ( status ) ;
talloc_free ( frame ) ;
Py_INCREF ( Py_None ) ;
return Py_None ;
fail :
talloc_free ( frame ) ;
return NULL ;
}
static PyMethodDef conn_methods [ ] = {
{
. ml_name = " sharepath " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction , conn_sharepath ) ,
. ml_flags = METH_NOARGS ,
. ml_doc = " mdscli.conn.sharepath(...) -> get share basepath " ,
} ,
{
. ml_name = " search " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction , conn_search ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = " mdscli.conn.search(...) -> run mdssvc query " ,
} ,
{
. ml_name = " disconnect " ,
. ml_meth = PY_DISCARD_FUNC_SIG ( PyCFunction , conn_disconnect ) ,
. ml_flags = METH_VARARGS | METH_KEYWORDS ,
. ml_doc = " mdscli.conn.disconnect(...) -> disconnect " ,
} ,
2020-05-05 04:47:39 +03:00
{ 0 } ,
2019-07-28 16:08:29 +03:00
} ;
static PyObject * conn_new ( PyTypeObject * type ,
PyObject * args ,
PyObject * kwargs )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
const char * const kwnames [ ] = { " pipe " , " share " , " mountpoint " , NULL } ;
PyObject * pypipe = NULL ;
dcerpc_InterfaceObject * pipe = NULL ;
struct tevent_req * req = NULL ;
char * share = NULL ;
char * mountpoint = NULL ;
struct mdscli_ctx * ctx = NULL ;
PyObject * self = NULL ;
NTSTATUS status ;
bool ok ;
if ( ! PyArg_ParseTupleAndKeywords ( args ,
kwargs ,
" Oss " ,
discard_const_p ( char * , kwnames ) ,
& pypipe ,
& share ,
& mountpoint ) ) {
PyErr_SetString ( PyExc_RuntimeError , " Failed to parse args " ) ;
goto fail ;
}
ok = py_check_dcerpc_type ( pypipe ,
" samba.dcerpc.base " ,
" ClientConnection " ) ;
if ( ! ok ) {
goto fail ;
}
pipe = ( dcerpc_InterfaceObject * ) pypipe ;
req = mdscli_connect_send ( frame ,
pipe - > ev ,
pipe - > binding_handle ,
share ,
mountpoint ) ;
if ( req = = NULL ) {
PyErr_NoMemory ( ) ;
goto fail ;
}
if ( ! tevent_req_poll_ntstatus ( req , pipe - > ev , & status ) ) {
PyErr_SetNTSTATUS ( status ) ;
goto fail ;
}
status = mdscli_connect_recv ( req , frame , & ctx ) ;
PyErr_NTSTATUS_IS_ERR_RAISE ( status ) ;
self = pytalloc_steal ( type , ctx ) ;
fail :
talloc_free ( frame ) ;
return self ;
}
static PyTypeObject conn_type = {
. tp_name = " mdscli.conn " ,
. tp_new = conn_new ,
. tp_flags = Py_TPFLAGS_DEFAULT ,
. tp_doc = " conn([....]) -> mdssvc connection \n " ,
. tp_methods = conn_methods ,
} ;
static PyMethodDef mdscli_methods [ ] = {
2020-05-05 04:47:39 +03:00
{ 0 } ,
2019-07-28 16:08:29 +03:00
} ;
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT ,
. m_name = " mdscli " ,
. m_doc = " RPC mdssvc client " ,
. m_size = - 1 ,
. m_methods = mdscli_methods ,
} ;
MODULE_INIT_FUNC ( mdscli )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
PyObject * m = NULL ;
int ret ;
ret = pytalloc_BaseObject_PyType_Ready ( & conn_type ) ;
if ( ret < 0 ) {
TALLOC_FREE ( frame ) ;
return NULL ;
}
ret = pytalloc_BaseObject_PyType_Ready ( & search_type ) ;
if ( ret < 0 ) {
TALLOC_FREE ( frame ) ;
return NULL ;
}
m = PyModule_Create ( & moduledef ) ;
if ( m = = NULL ) {
TALLOC_FREE ( frame ) ;
return NULL ;
}
Py_INCREF ( & conn_type ) ;
PyModule_AddObject ( m , " conn " , ( PyObject * ) & conn_type ) ;
Py_INCREF ( & search_type ) ;
PyModule_AddObject ( m , " search " , ( PyObject * ) & search_type ) ;
TALLOC_FREE ( frame ) ;
return m ;
}