From d5434f0b4bcf744e5a5f0e933bdcf629d42a6478 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 26 May 2008 04:14:28 +0200 Subject: Allow using IRPC functions on the messaging bus from Python. (This used to be commit 6ecf81ae13dffa05356c1177c617206c120fb7d7) --- source4/lib/messaging/config.mk | 8 +- source4/lib/messaging/pyirpc.c | 547 -------------------------- source4/lib/messaging/pymessaging.c | 556 +++++++++++++++++++++++++++ source4/librpc/config.mk | 17 + source4/librpc/rpc/pyrpc.h | 2 + source4/pidl/lib/Parse/Pidl/Samba4/Python.pm | 2 +- source4/scripting/bin/smbstatus | 39 +- 7 files changed, 603 insertions(+), 568 deletions(-) delete mode 100644 source4/lib/messaging/pyirpc.c create mode 100644 source4/lib/messaging/pymessaging.c diff --git a/source4/lib/messaging/config.mk b/source4/lib/messaging/config.mk index f330ed7cab..e92f78c8e3 100644 --- a/source4/lib/messaging/config.mk +++ b/source4/lib/messaging/config.mk @@ -11,8 +11,8 @@ PUBLIC_DEPENDENCIES = \ MESSAGING_OBJ_FILES = $(libmessagingsrcdir)/messaging.o -[PYTHON::python_irpc] -LIBRARY_REALNAME = samba/irpc.$(SHLIBEXT) -PRIVATE_DEPENDENCIES = MESSAGING LIBEVENTS +[PYTHON::python_messaging] +LIBRARY_REALNAME = samba/messaging.$(SHLIBEXT) +PRIVATE_DEPENDENCIES = MESSAGING LIBEVENTS python_irpc -python_irpc_OBJ_FILES = $(libmessagingsrcdir)/pyirpc.o +python_messaging_OBJ_FILES = $(libmessagingsrcdir)/pymessaging.o diff --git a/source4/lib/messaging/pyirpc.c b/source4/lib/messaging/pyirpc.c deleted file mode 100644 index 41475daaff..0000000000 --- a/source4/lib/messaging/pyirpc.c +++ /dev/null @@ -1,547 +0,0 @@ -/* - Unix SMB/CIFS implementation. - Copyright © Jelmer Vernooij 2008 - - Based on the equivalent for EJS: - Copyright © Andrew Tridgell 2005 - - 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 . -*/ - -#include "includes.h" -#include -#include "libcli/util/pyerrors.h" -#include "librpc/rpc/pyrpc.h" -#include "lib/messaging/irpc.h" -#include "lib/messaging/messaging.h" -#include "lib/events/events.h" -#include "cluster/cluster.h" -#include "param/param.h" -#include "librpc/gen_ndr/py_irpc.h" - -PyAPI_DATA(PyTypeObject) messaging_Type; -PyAPI_DATA(PyTypeObject) irpc_InterfaceType; - -static bool server_id_from_py(PyObject *object, struct server_id *server_id) -{ - if (!PyTuple_Check(object)) { - PyErr_SetString(PyExc_ValueError, "Expected tuple"); - return false; - } - - if (PyTuple_Size(object) == 3) { - return PyArg_ParseTuple(object, "iii", &server_id->id, &server_id->id2, &server_id->node); - } else { - int id, id2; - if (!PyArg_ParseTuple(object, "ii", &id, &id2)) - return false; - *server_id = cluster_id(id, id2); - return true; - } -} - -typedef struct { - PyObject_HEAD - TALLOC_CTX *mem_ctx; - struct messaging_context *msg_ctx; -} messaging_Object; - -PyObject *py_messaging_connect(PyTypeObject *self, PyObject *args, PyObject *kwargs) -{ - struct event_context *ev; - const char *kwnames[] = { "own_id", "messaging_path", NULL }; - PyObject *own_id = Py_None; - const char *messaging_path = NULL; - messaging_Object *ret; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Os:connect", - discard_const_p(char *, kwnames), &own_id, &messaging_path)) { - return NULL; - } - - ret = PyObject_New(messaging_Object, &messaging_Type); - if (ret == NULL) - return NULL; - - ret->mem_ctx = talloc_new(NULL); - - ev = event_context_init(ret->mem_ctx); - - if (messaging_path == NULL) { - messaging_path = lp_messaging_path(ret, global_loadparm); - } else { - messaging_path = talloc_strdup(ret->mem_ctx, messaging_path); - } - - if (own_id != Py_None) { - struct server_id server_id; - - if (!server_id_from_py(own_id, &server_id)) - return NULL; - - ret->msg_ctx = messaging_init(ret->mem_ctx, - messaging_path, - server_id, - lp_iconv_convenience(global_loadparm), - ev); - } else { - ret->msg_ctx = messaging_client_init(ret->mem_ctx, - messaging_path, - lp_iconv_convenience(global_loadparm), - ev); - } - - if (ret->msg_ctx == NULL) { - PyErr_SetString(PyExc_RuntimeError, "messaging_connect unable to create a messaging context"); - talloc_free(ret->mem_ctx); - return NULL; - } - - return (PyObject *)ret; -} - -static void py_messaging_dealloc(PyObject *self) -{ - messaging_Object *iface = (messaging_Object *)self; - talloc_free(iface->msg_ctx); - PyObject_Del(self); -} - -static PyObject *py_messaging_send(PyObject *self, PyObject *args, PyObject *kwargs) -{ - messaging_Object *iface = (messaging_Object *)self; - uint32_t msg_type; - DATA_BLOB data; - PyObject *target; - NTSTATUS status; - struct server_id server; - const char *kwnames[] = { "target", "msg_type", "data", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ois#|:send", - discard_const_p(char *, kwnames), &target, &msg_type, &data.data, &data.length)) { - return NULL; - } - - if (!server_id_from_py(target, &server)) - return NULL; - - status = messaging_send(iface->msg_ctx, server, msg_type, &data); - if (NT_STATUS_IS_ERR(status)) { - PyErr_SetNTSTATUS(status); - return NULL; - } - - return Py_None; -} - -static void py_msg_callback_wrapper(struct messaging_context *msg, void *private, - uint32_t msg_type, - struct server_id server_id, DATA_BLOB *data) -{ - PyObject *callback = (PyObject *)private; - - PyObject_CallFunction(callback, discard_const_p(char, "i(iii)s#"), msg_type, - server_id.id, server_id.id2, server_id.node, - data->data, data->length); -} - -static PyObject *py_messaging_register(PyObject *self, PyObject *args, PyObject *kwargs) -{ - messaging_Object *iface = (messaging_Object *)self; - uint32_t msg_type = -1; - PyObject *callback; - NTSTATUS status; - const char *kwnames[] = { "callback", "msg_type", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:send", - discard_const_p(char *, kwnames), &callback, &msg_type)) { - return NULL; - } - - Py_INCREF(callback); - - if (msg_type == -1) { - status = messaging_register_tmp(iface->msg_ctx, callback, - py_msg_callback_wrapper, &msg_type); - } else { - status = messaging_register(iface->msg_ctx, callback, - msg_type, py_msg_callback_wrapper); - } - if (NT_STATUS_IS_ERR(status)) { - PyErr_SetNTSTATUS(status); - return NULL; - } - - return PyLong_FromLong(msg_type); -} - -static PyObject *py_messaging_deregister(PyObject *self, PyObject *args, PyObject *kwargs) -{ - messaging_Object *iface = (messaging_Object *)self; - uint32_t msg_type = -1; - PyObject *callback; - const char *kwnames[] = { "callback", "msg_type", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:send", - discard_const_p(char *, kwnames), &callback, &msg_type)) { - return NULL; - } - - messaging_deregister(iface->msg_ctx, msg_type, callback); - - Py_DECREF(callback); - - return Py_None; -} - -static PyObject *py_messaging_add_name(PyObject *self, PyObject *args, PyObject *kwargs) -{ - messaging_Object *iface = (messaging_Object *)self; - NTSTATUS status; - char *name; - const char *kwnames[] = { "name", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|:send", - discard_const_p(char *, kwnames), &name)) { - return NULL; - } - - status = irpc_add_name(iface->msg_ctx, name); - if (NT_STATUS_IS_ERR(status)) { - PyErr_SetNTSTATUS(status); - return NULL; - } - - return Py_None; -} - - -static PyObject *py_messaging_remove_name(PyObject *self, PyObject *args, PyObject *kwargs) -{ - messaging_Object *iface = (messaging_Object *)self; - char *name; - const char *kwnames[] = { "name", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|:send", - discard_const_p(char *, kwnames), &name)) { - return NULL; - } - - irpc_remove_name(iface->msg_ctx, name); - - return Py_None; -} - -static PyMethodDef py_messaging_methods[] = { - { "send", (PyCFunction)py_messaging_send, METH_VARARGS|METH_KEYWORDS, - "S.send(target, msg_type, data) -> None\nSend a message" }, - { "register", (PyCFunction)py_messaging_register, METH_VARARGS|METH_KEYWORDS, - "S.register(callback, msg_type=None) -> msg_type\nRegister a message handler" }, - { "deregister", (PyCFunction)py_messaging_deregister, METH_VARARGS|METH_KEYWORDS, - "S.deregister(callback, msg_type) -> None\nDeregister a message handler" }, - { "add_name", (PyCFunction)py_messaging_add_name, METH_VARARGS|METH_KEYWORDS, "S.add_name(name) -> None\nListen on another name" }, - { "remove_name", (PyCFunction)py_messaging_remove_name, METH_VARARGS|METH_KEYWORDS, "S.remove_name(name) -> None\nStop listening on a name" }, - { NULL, NULL, 0, NULL } -}; - -static PyObject *py_messaging_server_id(PyObject *obj, void *closure) -{ - messaging_Object *iface = (messaging_Object *)obj; - struct server_id server_id = messaging_get_server_id(iface->msg_ctx); - - return Py_BuildValue("(iii)", server_id.id, server_id.id2, - server_id.node); -} - -static PyGetSetDef py_messaging_getset[] = { - { discard_const_p(char, "server_id"), py_messaging_server_id, NULL, - discard_const_p(char, "local server id") }, - { NULL }, -}; - - -PyTypeObject messaging_Type = { - PyObject_HEAD_INIT(NULL) 0, - .tp_name = "irpc.Messaging", - .tp_basicsize = sizeof(messaging_Object), - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_new = py_messaging_connect, - .tp_dealloc = py_messaging_dealloc, - .tp_methods = py_messaging_methods, - .tp_getset = py_messaging_getset, -}; - - -/* - state of a irpc 'connection' -*/ -typedef struct { - PyObject_HEAD - const char *server_name; - struct server_id *dest_ids; - struct messaging_context *msg_ctx; - TALLOC_CTX *mem_ctx; -} irpc_InterfaceObject; - -/* - setup a context for talking to a irpc server - example: - status = irpc.connect("smb_server"); -*/ - -PyObject *py_irpc_connect(PyTypeObject *self, PyObject *args, PyObject *kwargs) -{ - struct event_context *ev; - const char *kwnames[] = { "server", "own_id", "messaging_path", NULL }; - char *server; - const char *messaging_path = NULL; - PyObject *own_id = Py_None; - irpc_InterfaceObject *ret; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|Os:connect", - discard_const_p(char *, kwnames), &server, &own_id, &messaging_path)) { - return NULL; - } - - ret = PyObject_New(irpc_InterfaceObject, &irpc_InterfaceType); - if (ret == NULL) - return NULL; - - ret->mem_ctx = talloc_new(NULL); - - ret->server_name = server; - - ev = event_context_init(ret->mem_ctx); - - if (messaging_path == NULL) { - messaging_path = lp_messaging_path(ret, global_loadparm); - } - - if (own_id != Py_None) { - struct server_id server_id; - - if (!server_id_from_py(own_id, &server_id)) - return NULL; - - ret->msg_ctx = messaging_init(ret->mem_ctx, - messaging_path, - server_id, - lp_iconv_convenience(global_loadparm), - ev); - } else { - ret->msg_ctx = messaging_client_init(ret->mem_ctx, - messaging_path, - lp_iconv_convenience(global_loadparm), - ev); - } - - if (ret->msg_ctx == NULL) { - PyErr_SetString(PyExc_RuntimeError, "irpc_connect unable to create a messaging context"); - talloc_free(ret->mem_ctx); - return NULL; - } - - ret->dest_ids = irpc_servers_byname(ret->msg_ctx, ret->mem_ctx, ret->server_name); - if (ret->dest_ids == NULL || ret->dest_ids[0].id == 0) { - talloc_free(ret->mem_ctx); - PyErr_SetNTSTATUS(NT_STATUS_OBJECT_NAME_NOT_FOUND); - return NULL; - } else { - return (PyObject *)ret; - } -} - -typedef struct { - PyObject_HEAD - struct irpc_request **reqs; - int count; - int current; - TALLOC_CTX *mem_ctx; - py_data_unpack_fn unpack_fn; -} irpc_ResultObject; - - -static PyObject *irpc_result_next(irpc_ResultObject *iterator) -{ - NTSTATUS status; - - if (iterator->current >= iterator->count) { - PyErr_SetString(PyExc_StopIteration, "No more results"); - return NULL; - } - - status = irpc_call_recv(iterator->reqs[iterator->current]); - iterator->current++; - if (!NT_STATUS_IS_OK(status)) { - PyErr_SetNTSTATUS(status); - return NULL; - } - - return iterator->unpack_fn(iterator->reqs[iterator->current-1]->r); -} - -static PyObject *irpc_result_len(irpc_ResultObject *self) -{ - return PyLong_FromLong(self->count); -} - -static PyMethodDef irpc_result_methods[] = { - { "__len__", (PyCFunction)irpc_result_len, METH_NOARGS, - "Number of elements returned"}, - { NULL } -}; - -static void irpc_result_dealloc(PyObject *self) -{ - talloc_free(((irpc_ResultObject *)self)->mem_ctx); - PyObject_Del(self); -} - -PyTypeObject irpc_ResultIteratorType = { - PyObject_HEAD_INIT(NULL) 0, - .tp_name = "irpc.ResultIterator", - .tp_basicsize = sizeof(irpc_ResultObject), - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_iter = (iternextfunc)irpc_result_next, - .tp_methods = irpc_result_methods, - .tp_dealloc = irpc_result_dealloc, -}; - -static PyObject *py_irpc_call(irpc_InterfaceObject *p, struct PyNdrRpcMethodDef *method_def, PyObject *args, PyObject *kwargs) -{ - void *ptr; - struct irpc_request **reqs; - int i, count; - NTSTATUS status; - TALLOC_CTX *mem_ctx = talloc_new(NULL); - irpc_ResultObject *ret; - - /* allocate the C structure */ - ptr = talloc_zero_size(mem_ctx, method_def->table->calls[method_def->opnum].struct_size); - if (ptr == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - - /* convert the mpr object into a C structure */ - if (!method_def->pack_in_data(args, kwargs, ptr)) { - talloc_free(mem_ctx); - return NULL; - } - - for (count=0;p->dest_ids[count].id;count++) /* noop */ ; - - /* we need to make a call per server */ - reqs = talloc_array(mem_ctx, struct irpc_request *, count); - if (reqs == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - - /* make the actual calls */ - for (i=0;imsg_ctx, p->dest_ids[i], - method_def->table, method_def->opnum, ptr, ptr); - if (reqs[i] == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - talloc_steal(reqs, reqs[i]); - } - - ret = PyObject_New(irpc_ResultObject, &irpc_ResultIteratorType); - ret->mem_ctx = mem_ctx; - ret->reqs = reqs; - ret->count = count; - ret->current = 0; - ret->unpack_fn = method_def->unpack_out_data; - - return (PyObject *)ret; -done: - talloc_free(mem_ctx); - PyErr_SetNTSTATUS(status); - return NULL; -} - -static PyObject *py_irpc_call_wrapper(PyObject *self, PyObject *args, void *wrapped, PyObject *kwargs) -{ - irpc_InterfaceObject *iface = (irpc_InterfaceObject *)self; - struct PyNdrRpcMethodDef *md = wrapped; - - return py_irpc_call(iface, md, args, kwargs); -} - -static void py_irpc_dealloc(PyObject *self) -{ - irpc_InterfaceObject *iface = (irpc_InterfaceObject *)self; - talloc_free(iface->mem_ctx); - PyObject_Del(self); -} - -PyTypeObject irpc_InterfaceType = { - PyObject_HEAD_INIT(NULL) 0, - .tp_name = "irpc.ClientConnection", - .tp_basicsize = sizeof(irpc_InterfaceObject), - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_new = py_irpc_connect, - .tp_dealloc = py_irpc_dealloc, -}; - -static bool irpc_AddNdrRpcMethods(PyTypeObject *ifacetype, struct PyNdrRpcMethodDef *mds) -{ - int i; - for (i = 0; mds[i].name; i++) { - PyObject *ret; - struct wrapperbase *wb = calloc(sizeof(struct wrapperbase), 1); - - wb->name = discard_const_p(char, mds[i].name); - wb->flags = PyWrapperFlag_KEYWORDS; - wb->wrapper = (wrapperfunc)py_irpc_call_wrapper; - wb->doc = discard_const_p(char, mds[i].doc); - - ret = PyDescr_NewWrapper(ifacetype, wb, &mds[i]); - - PyDict_SetItemString(ifacetype->tp_dict, mds[i].name, - (PyObject *)ret); - } - - return true; -} - -void initirpc(void) -{ - PyObject *mod; - - if (PyType_Ready(&irpc_InterfaceType) < 0) - return; - - if (PyType_Ready(&messaging_Type) < 0) - return; - - if (PyType_Ready(&irpc_ResultIteratorType) < 0) - return; - - if (!irpc_AddNdrRpcMethods(&irpc_InterfaceType, py_ndr_irpc_methods)) - return; - - mod = Py_InitModule3("irpc", NULL, "Internal RPC"); - if (mod == NULL) - return; - - Py_INCREF((PyObject *)&irpc_InterfaceType); - PyModule_AddObject(mod, "ClientConnection", (PyObject *)&irpc_InterfaceType); - - Py_INCREF((PyObject *)&messaging_Type); - PyModule_AddObject(mod, "Messaging", (PyObject *)&messaging_Type); -} diff --git a/source4/lib/messaging/pymessaging.c b/source4/lib/messaging/pymessaging.c new file mode 100644 index 0000000000..e05d5eb1f1 --- /dev/null +++ b/source4/lib/messaging/pymessaging.c @@ -0,0 +1,556 @@ +/* + Unix SMB/CIFS implementation. + Copyright © Jelmer Vernooij 2008 + + Based on the equivalent for EJS: + Copyright © Andrew Tridgell 2005 + + 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 . +*/ + +#include "includes.h" +#include +#include "libcli/util/pyerrors.h" +#include "librpc/rpc/pyrpc.h" +#include "lib/messaging/irpc.h" +#include "lib/messaging/messaging.h" +#include "lib/events/events.h" +#include "cluster/cluster.h" +#include "param/param.h" +#include "librpc/gen_ndr/py_irpc.h" + +PyAPI_DATA(PyTypeObject) messaging_Type; +PyAPI_DATA(PyTypeObject) irpc_ClientConnectionType; + +static bool server_id_from_py(PyObject *object, struct server_id *server_id) +{ + if (!PyTuple_Check(object)) { + PyErr_SetString(PyExc_ValueError, "Expected tuple"); + return false; + } + + if (PyTuple_Size(object) == 3) { + return PyArg_ParseTuple(object, "iii", &server_id->id, &server_id->id2, &server_id->node); + } else { + int id, id2; + if (!PyArg_ParseTuple(object, "ii", &id, &id2)) + return false; + *server_id = cluster_id(id, id2); + return true; + } +} + +typedef struct { + PyObject_HEAD + TALLOC_CTX *mem_ctx; + struct messaging_context *msg_ctx; +} messaging_Object; + +PyObject *py_messaging_connect(PyTypeObject *self, PyObject *args, PyObject *kwargs) +{ + struct event_context *ev; + const char *kwnames[] = { "own_id", "messaging_path", NULL }; + PyObject *own_id = Py_None; + const char *messaging_path = NULL; + messaging_Object *ret; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oz:connect", + discard_const_p(char *, kwnames), &own_id, &messaging_path)) { + return NULL; + } + + ret = PyObject_New(messaging_Object, &messaging_Type); + if (ret == NULL) + return NULL; + + ret->mem_ctx = talloc_new(NULL); + + ev = event_context_init(ret->mem_ctx); + + if (messaging_path == NULL) { + messaging_path = lp_messaging_path(ret, global_loadparm); + } else { + messaging_path = talloc_strdup(ret->mem_ctx, messaging_path); + } + + if (own_id != Py_None) { + struct server_id server_id; + + if (!server_id_from_py(own_id, &server_id)) + return NULL; + + ret->msg_ctx = messaging_init(ret->mem_ctx, + messaging_path, + server_id, + lp_iconv_convenience(global_loadparm), + ev); + } else { + ret->msg_ctx = messaging_client_init(ret->mem_ctx, + messaging_path, + lp_iconv_convenience(global_loadparm), + ev); + } + + if (ret->msg_ctx == NULL) { + PyErr_SetString(PyExc_RuntimeError, "messaging_connect unable to create a messaging context"); + talloc_free(ret->mem_ctx); + return NULL; + } + + return (PyObject *)ret; +} + +static void py_messaging_dealloc(PyObject *self) +{ + messaging_Object *iface = (messaging_Object *)self; + talloc_free(iface->msg_ctx); + PyObject_Del(self); +} + +static PyObject *py_messaging_send(PyObject *self, PyObject *args, PyObject *kwargs) +{ + messaging_Object *iface = (messaging_Object *)self; + uint32_t msg_type; + DATA_BLOB data; + PyObject *target; + NTSTATUS status; + struct server_id server; + const char *kwnames[] = { "target", "msg_type", "data", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ois#|:send", + discard_const_p(char *, kwnames), &target, &msg_type, &data.data, &data.length)) { + return NULL; + } + + if (!server_id_from_py(target, &server)) + return NULL; + + status = messaging_send(iface->msg_ctx, server, msg_type, &data); + if (NT_STATUS_IS_ERR(status)) { + PyErr_SetNTSTATUS(status); + return NULL; + } + + return Py_None; +} + +static void py_msg_callback_wrapper(struct messaging_context *msg, void *private, + uint32_t msg_type, + struct server_id server_id, DATA_BLOB *data) +{ + PyObject *callback = (PyObject *)private; + + PyObject_CallFunction(callback, discard_const_p(char, "i(iii)s#"), msg_type, + server_id.id, server_id.id2, server_id.node, + data->data, data->length); +} + +static PyObject *py_messaging_register(PyObject *self, PyObject *args, PyObject *kwargs) +{ + messaging_Object *iface = (messaging_Object *)self; + uint32_t msg_type = -1; + PyObject *callback; + NTSTATUS status; + const char *kwnames[] = { "callback", "msg_type", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:send", + discard_const_p(char *, kwnames), &callback, &msg_type)) { + return NULL; + } + + Py_INCREF(callback); + + if (msg_type == -1) { + status = messaging_register_tmp(iface->msg_ctx, callback, + py_msg_callback_wrapper, &msg_type); + } else { + status = messaging_register(iface->msg_ctx, callback, + msg_type, py_msg_callback_wrapper); + } + if (NT_STATUS_IS_ERR(status)) { + PyErr_SetNTSTATUS(status); + return NULL; + } + + return PyLong_FromLong(msg_type); +} + +static PyObject *py_messaging_deregister(PyObject *self, PyObject *args, PyObject *kwargs) +{ + messaging_Object *iface = (messaging_Object *)self; + uint32_t msg_type = -1; + PyObject *callback; + const char *kwnames[] = { "callback", "msg_type", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:send", + discard_const_p(char *, kwnames), &callback, &msg_type)) { + return NULL; + } + + messaging_deregister(iface->msg_ctx, msg_type, callback); + + Py_DECREF(callback); + + return Py_None; +} + +static PyObject *py_messaging_add_name(PyObject *self, PyObject *args, PyObject *kwargs) +{ + messaging_Object *iface = (messaging_Object *)self; + NTSTATUS status; + char *name; + const char *kwnames[] = { "name", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|:send", + discard_const_p(char *, kwnames), &name)) { + return NULL; + } + + status = irpc_add_name(iface->msg_ctx, name); + if (NT_STATUS_IS_ERR(status)) { + PyErr_SetNTSTATUS(status); + return NULL; + } + + return Py_None; +} + + +static PyObject *py_messaging_remove_name(PyObject *self, PyObject *args, PyObject *kwargs) +{ + messaging_Object *iface = (messaging_Object *)self; + char *name; + const char *kwnames[] = { "name", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|:send", + discard_const_p(char *, kwnames), &name)) { + return NULL; + } + + irpc_remove_name(iface->msg_ctx, name); + + return Py_None; +} + +static PyMethodDef py_messaging_methods[] = { + { "send", (PyCFunction)py_messaging_send, METH_VARARGS|METH_KEYWORDS, + "S.send(target, msg_type, data) -> None\nSend a message" }, + { "register", (PyCFunction)py_messaging_register, METH_VARARGS|METH_KEYWORDS, + "S.register(callback, msg_type=None) -> msg_type\nRegister a message handler" }, + { "deregister", (PyCFunction)py_messaging_deregister, METH_VARARGS|METH_KEYWORDS, + "S.deregister(callback, msg_type) -> None\nDeregister a message handler" }, + { "add_name", (PyCFunction)py_messaging_add_name, METH_VARARGS|METH_KEYWORDS, "S.add_name(name) -> None\nListen on another name" }, + { "remove_name", (PyCFunction)py_messaging_remove_name, METH_VARARGS|METH_KEYWORDS, "S.remove_name(name) -> None\nStop listening on a name" }, + { NULL, NULL, 0, NULL } +}; + +static PyObject *py_messaging_server_id(PyObject *obj, void *closure) +{ + messaging_Object *iface = (messaging_Object *)obj; + struct server_id server_id = messaging_get_server_id(iface->msg_ctx); + + return Py_BuildValue("(iii)", server_id.id, server_id.id2, + server_id.node); +} + +static PyGetSetDef py_messaging_getset[] = { + { discard_const_p(char, "server_id"), py_messaging_server_id, NULL, + discard_const_p(char, "local server id") }, + { NULL }, +}; + + +PyTypeObject messaging_Type = { + PyObject_HEAD_INIT(NULL) 0, + .tp_name = "irpc.Messaging", + .tp_basicsize = sizeof(messaging_Object), + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_new = py_messaging_connect, + .tp_dealloc = py_messaging_dealloc, + .tp_methods = py_messaging_methods, + .tp_getset = py_messaging_getset, + .tp_doc = "Messaging(own_id=None, messaging_path=None)\n" \ + "Create a new object that can be used to communicate with the peers in the specified messaging path.\n" \ + "If no path is specified, the default path from smb.conf will be used." +}; + + +/* + state of a irpc 'connection' +*/ +typedef struct { + PyObject_HEAD + const char *server_name; + struct server_id *dest_ids; + struct messaging_context *msg_ctx; + TALLOC_CTX *mem_ctx; +} irpc_ClientConnectionObject; + +/* + setup a context for talking to a irpc server + example: + status = irpc.connect("smb_server"); +*/ + +PyObject *py_irpc_connect(PyTypeObject *self, PyObject *args, PyObject *kwargs) +{ + struct event_context *ev; + const char *kwnames[] = { "server", "own_id", "messaging_path", NULL }; + char *server; + const char *messaging_path = NULL; + PyObject *own_id = Py_None; + irpc_ClientConnectionObject *ret; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|Oz:connect", + discard_const_p(char *, kwnames), &server, &own_id, &messaging_path)) { + return NULL; + } + + ret = PyObject_New(irpc_ClientConnectionObject, &irpc_ClientConnectionType); + if (ret == NULL) + return NULL; + + ret->mem_ctx = talloc_new(NULL); + + ret->server_name = server; + + ev = event_context_init(ret->mem_ctx); + + if (messaging_path == NULL) { + messaging_path = lp_messaging_path(ret, global_loadparm); + } else { + messaging_path = talloc_strdup(ret->mem_ctx, messaging_path); + } + + if (own_id != Py_None) { + struct server_id server_id; + + if (!server_id_from_py(own_id, &server_id)) + return NULL; + + ret->msg_ctx = messaging_init(ret->mem_ctx, + messaging_path, + server_id, + lp_iconv_convenience(global_loadparm), + ev); + } else { + ret->msg_ctx = messaging_client_init(ret->mem_ctx, + messaging_path, + lp_iconv_convenience(global_loadparm), + ev); + } + + if (ret->msg_ctx == NULL) { + PyErr_SetString(PyExc_RuntimeError, "irpc_connect unable to create a messaging context"); + talloc_free(ret->mem_ctx); + return NULL; + } + + ret->dest_ids = irpc_servers_byname(ret->msg_ctx, ret->mem_ctx, ret->server_name); + if (ret->dest_ids == NULL || ret->dest_ids[0].id == 0) { + talloc_free(ret->mem_ctx); + PyErr_SetNTSTATUS(NT_STATUS_OBJECT_NAME_NOT_FOUND); + return NULL; + } else { + return (PyObject *)ret; + } +} + +typedef struct { + PyObject_HEAD + struct irpc_request **reqs; + int count; + int current; + TALLOC_CTX *mem_ctx; + py_data_unpack_fn unpack_fn; +} irpc_ResultObject; + + +static PyObject *irpc_result_next(irpc_ResultObject *iterator) +{ + NTSTATUS status; + + if (iterator->current >= iterator->count) { + PyErr_SetString(PyExc_StopIteration, "No more results"); + return NULL; + } + + status = irpc_call_recv(iterator->reqs[iterator->current]); + iterator->current++; + if (!NT_STATUS_IS_OK(status)) { + PyErr_SetNTSTATUS(status); + return NULL; + } + + return iterator->unpack_fn(iterator->reqs[iterator->current-1]->r); +} + +static PyObject *irpc_result_len(irpc_ResultObject *self) +{ + return PyLong_FromLong(self->count); +} + +static PyMethodDef irpc_result_methods[] = { + { "__len__", (PyCFunction)irpc_result_len, METH_NOARGS, + "Number of elements returned"}, + { NULL } +}; + +static void irpc_result_dealloc(PyObject *self) +{ + talloc_free(((irpc_ResultObject *)self)->mem_ctx); + PyObject_Del(self); +} + +PyTypeObject irpc_ResultIteratorType = { + PyObject_HEAD_INIT(NULL) 0, + .tp_name = "irpc.ResultIterator", + .tp_basicsize = sizeof(irpc_ResultObject), + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_iternext = (iternextfunc)irpc_result_next, + .tp_iter = PyObject_SelfIter, + .tp_methods = irpc_result_methods, + .tp_dealloc = irpc_result_dealloc, +}; + +static PyObject *py_irpc_call(irpc_ClientConnectionObject *p, struct PyNdrRpcMethodDef *method_def, PyObject *args, PyObject *kwargs) +{ + void *ptr; + struct irpc_request **reqs; + int i, count; + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + irpc_ResultObject *ret; + + /* allocate the C structure */ + ptr = talloc_zero_size(mem_ctx, method_def->table->calls[method_def->opnum].struct_size); + if (ptr == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + /* convert the mpr object into a C structure */ + if (!method_def->pack_in_data(args, kwargs, ptr)) { + talloc_free(mem_ctx); + return NULL; + } + + for (count=0;p->dest_ids[count].id;count++) /* noop */ ; + + /* we need to make a call per server */ + reqs = talloc_array(mem_ctx, struct irpc_request *, count); + if (reqs == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + /* make the actual calls */ + for (i=0;imsg_ctx, p->dest_ids[i], + method_def->table, method_def->opnum, ptr, ptr); + if (reqs[i] == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + talloc_steal(reqs, reqs[i]); + } + + ret = PyObject_New(irpc_ResultObject, &irpc_ResultIteratorType); + ret->mem_ctx = mem_ctx; + ret->reqs = reqs; + ret->count = count; + ret->current = 0; + ret->unpack_fn = method_def->unpack_out_data; + + return (PyObject *)ret; +done: + talloc_free(mem_ctx); + PyErr_SetNTSTATUS(status); + return NULL; +} + +static PyObject *py_irpc_call_wrapper(PyObject *self, PyObject *args, void *wrapped, PyObject *kwargs) +{ + irpc_ClientConnectionObject *iface = (irpc_ClientConnectionObject *)self; + struct PyNdrRpcMethodDef *md = wrapped; + + return py_irpc_call(iface, md, args, kwargs); +} + +static void py_irpc_dealloc(PyObject *self) +{ + irpc_ClientConnectionObject *iface = (irpc_ClientConnectionObject *)self; + talloc_free(iface->mem_ctx); + PyObject_Del(self); +} + +PyTypeObject irpc_ClientConnectionType = { + PyObject_HEAD_INIT(NULL) 0, + .tp_name = "irpc.ClientConnection", + .tp_basicsize = sizeof(irpc_ClientConnectionObject), + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_new = py_irpc_connect, + .tp_dealloc = py_irpc_dealloc, + .tp_doc = "ClientConnection(server, own_id=None, messaging_path=None)\n" \ + "Create a new IRPC client connection to communicate with the servers in the specified path.\n" \ + "If no path is specified, the default path from smb.conf will be used." +}; + +static bool irpc_AddNdrRpcMethods(PyTypeObject *ifacetype, const struct PyNdrRpcMethodDef *mds) +{ + int i; + for (i = 0; mds[i].name; i++) { + PyObject *ret; + struct wrapperbase *wb = calloc(sizeof(struct wrapperbase), 1); + + wb->name = discard_const_p(char, mds[i].name); + wb->flags = PyWrapperFlag_KEYWORDS; + wb->wrapper = (wrapperfunc)py_irpc_call_wrapper; + wb->doc = discard_const_p(char, mds[i].doc); + + ret = PyDescr_NewWrapper(ifacetype, wb, discard_const_p(void, &mds[i])); + + PyDict_SetItemString(ifacetype->tp_dict, mds[i].name, + (PyObject *)ret); + } + + return true; +} + +void initmessaging(void) +{ + PyObject *mod; + + if (PyType_Ready(&irpc_ClientConnectionType) < 0) + return; + + if (PyType_Ready(&messaging_Type) < 0) + return; + + if (PyType_Ready(&irpc_ResultIteratorType) < 0) + return; + + if (!irpc_AddNdrRpcMethods(&irpc_ClientConnectionType, py_ndr_irpc_methods)) + return; + + mod = Py_InitModule3("messaging", NULL, "Internal RPC"); + if (mod == NULL) + return; + + Py_INCREF((PyObject *)&irpc_ClientConnectionType); + PyModule_AddObject(mod, "ClientConnection", (PyObject *)&irpc_ClientConnectionType); + + Py_INCREF((PyObject *)&messaging_Type); + PyModule_AddObject(mod, "Messaging", (PyObject *)&messaging_Type); +} diff --git a/source4/librpc/config.mk b/source4/librpc/config.mk index 2943c7b516..ab25921ef8 100644 --- a/source4/librpc/config.mk +++ b/source4/librpc/config.mk @@ -434,6 +434,11 @@ PUBLIC_DEPENDENCIES = dcerpc NDR_UNIXINFO RPC_NDR_UNIXINFO_OBJ_FILES = $(gen_ndrsrcdir)/ndr_unixinfo_c.o +[SUBSYSTEM::RPC_NDR_IRPC] +PUBLIC_DEPENDENCIES = dcerpc NDR_IRPC + +RPC_NDR_IRPC_OBJ_FILES = $(gen_ndrsrcdir)/ndr_irpc_c.o + [LIBRARY::dcerpc_samr] PUBLIC_DEPENDENCIES = dcerpc NDR_SAMR @@ -658,6 +663,12 @@ PRIVATE_DEPENDENCIES = dcerpc_atsvc PYTALLOC param swig_credentials python_dcer python_atsvc_OBJ_FILES = $(gen_ndrsrcdir)/py_atsvc.o +[PYTHON::python_nbt] +LIBRARY_REALNAME = samba/nbt.$(SHLIBEXT) +PRIVATE_DEPENDENCIES = NDR_NBT PYTALLOC param swig_credentials python_dcerpc + +python_nbt_OBJ_FILES = $(gen_ndrsrcdir)/py_nbt.o + [PYTHON::python_samr] LIBRARY_REALNAME = samba/dcerpc/samr.$(SHLIBEXT) PRIVATE_DEPENDENCIES = dcerpc_samr PYTALLOC python_dcerpc_security python_lsa python_dcerpc_misc swig_credentials param python_dcerpc @@ -694,6 +705,12 @@ PRIVATE_DEPENDENCIES = RPC_NDR_UNIXINFO PYTALLOC param swig_credentials python_d python_unixinfo_OBJ_FILES = $(gen_ndrsrcdir)/py_unixinfo.o +[PYTHON::python_irpc] +LIBRARY_REALNAME = samba/irpc.$(SHLIBEXT) +PRIVATE_DEPENDENCIES = RPC_NDR_IRPC PYTALLOC param swig_credentials python_dcerpc_security python_dcerpc_misc python_dcerpc python_nbt + +python_irpc_OBJ_FILES = $(gen_ndrsrcdir)/py_irpc.o + [PYTHON::python_drsuapi] LIBRARY_REALNAME = samba/dcerpc/drsuapi.$(SHLIBEXT) PRIVATE_DEPENDENCIES = RPC_NDR_DRSUAPI PYTALLOC param swig_credentials python_dcerpc_misc python_dcerpc_security python_dcerpc diff --git a/source4/librpc/rpc/pyrpc.h b/source4/librpc/rpc/pyrpc.h index 989aeecc7b..af9ca728d8 100644 --- a/source4/librpc/rpc/pyrpc.h +++ b/source4/librpc/rpc/pyrpc.h @@ -29,8 +29,10 @@ fail; \ } +#define dom_sid0_Type dom_sid_Type #define dom_sid2_Type dom_sid_Type #define dom_sid28_Type dom_sid_Type +#define dom_sid0_Check dom_sid_Check #define dom_sid2_Check dom_sid_Check #define dom_sid28_Check dom_sid_Check diff --git a/source4/pidl/lib/Parse/Pidl/Samba4/Python.pm b/source4/pidl/lib/Parse/Pidl/Samba4/Python.pm index 055ee13b10..b5ae801ff8 100644 --- a/source4/pidl/lib/Parse/Pidl/Samba4/Python.pm +++ b/source4/pidl/lib/Parse/Pidl/Samba4/Python.pm @@ -651,7 +651,7 @@ sub Interface($$$) } $self->pidl("const struct PyNdrRpcMethodDef py_ndr_$interface->{NAME}\_methods[] = {"); - $self->pidl_hdr("const struct PyNdrRpcMethodDef py_ndr_$interface->{NAME}\_methods[];"); + $self->pidl_hdr("extern const struct PyNdrRpcMethodDef py_ndr_$interface->{NAME}\_methods[];"); $self->indent; foreach my $d (@fns) { my ($infn, $outfn, $callfn, $prettyname, $docstring, $opnum) = @$d; diff --git a/source4/scripting/bin/smbstatus b/source4/scripting/bin/smbstatus index 782e83e4cf..6d852c279c 100755 --- a/source4/scripting/bin/smbstatus +++ b/source4/scripting/bin/smbstatus @@ -15,11 +15,12 @@ sys.path.insert(0, "bin/python") import optparse import samba.getopt as options -import samba.irpc +from samba import messaging, irpc -def show_sessions(): +def show_sessions(conn): """show open sessions""" - sessions = smbsrv_sessions() + conn = open_connection("smb_server") + sessions = conn.smbsrv_information(irpc.SMBSRV_INFO_SESSIONS).next() print "User Client Connected at" print "-------------------------------------------------------------------------------" for session in sessions: @@ -27,37 +28,43 @@ def show_sessions(): print "%-30s %16s %s" % (fulluser, session.client_ip, sys.httptime(session.connect_time)) print "" -def show_tcons(): +def show_tcons(open_connection): """show open tree connects""" - tcons = smbsrv_tcons() + conn = open_connection("smb_server") + tcons = conn.smbsrv_information(irpc.SMBSRV_INFO_TCONS).next() print "Share Client Connected at" print "-------------------------------------------------------------------------------" for tcon in tcons: print "%-30s %16s %s\n" % (tcon.share_name, tcon.client_ip, sys.httptime(tcon.connect_time)) -def show_nbt(): +def show_nbt(open_connection): """show nbtd information""" - stats = nbtd_statistics() - print "NBT server statistics:", + conn = open_connection("nbt_server") + stats = conn.nbtd_information(irpc.NBTD_INFO_STATISTICS).next() + print "NBT server statistics:" for r in stats: - print "\t" + r + ":\t" + stats[r] + "\n" + print "\t" + r + ":\t" + getattr(stats, r) + "\n" print "" parser = optparse.OptionParser("%s [options]" % sys.argv[0]) sambaopts = options.SambaOptions(parser) parser.add_option_group(sambaopts) -parser.add_option("--nbt", type="string", metavar="NBT", - help="show NetBIOS status") +parser.add_option("--messaging-path", type="string", metavar="PATH", + help="messaging path") +parser.add_option("--nbt", help="show NetBIOS status", action="store_true") + +opts, args = parser.parse_args() lp = sambaopts.get_loadparm() print "%s\n\n" % lp.get("server string") +def open_connection(name): + return messaging.ClientConnection(name, messaging_path=opts.messaging_path) + if opts.nbt: - show_nbt() + show_nbt(open_connection) else: - show_sessions() - show_tcons() - -return 0 + show_sessions(open_connection) + show_tcons(open_connection) -- cgit