nsswitch/winbind_nss_aix: reimplement fetching the SID of a user
[Samba.git] / source4 / lib / messaging / pymessaging.c
blob6e64bb9a0600255199dd58a3a3abd2dcdd2c71e5
1 /*
2 Unix SMB/CIFS implementation.
3 Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
5 Based on the equivalent for EJS:
6 Copyright © Andrew Tridgell <tridge@samba.org> 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <Python.h>
23 #include "python/py3compat.h"
24 #include "includes.h"
25 #include "python/modules.h"
26 #include "libcli/util/pyerrors.h"
27 #include "librpc/rpc/pyrpc_util.h"
28 #include "librpc/ndr/libndr.h"
29 #include "lib/messaging/messaging.h"
30 #include "lib/messaging/irpc.h"
31 #include "lib/events/events.h"
32 #include "cluster/cluster.h"
33 #include "param/param.h"
34 #include "param/pyparam.h"
35 #include "librpc/rpc/dcerpc.h"
36 #include "librpc/gen_ndr/server_id.h"
37 #include <pytalloc.h>
38 #include "messaging_internal.h"
41 extern PyTypeObject imessaging_Type;
43 static bool server_id_from_py(PyObject *object, struct server_id *server_id)
45 if (!PyTuple_Check(object)) {
46 if (!py_check_dcerpc_type(object, "samba.dcerpc.server_id", "server_id")) {
48 PyErr_SetString(PyExc_ValueError, "Expected tuple or server_id");
49 return false;
51 *server_id = *pytalloc_get_type(object, struct server_id);
52 return true;
54 if (PyTuple_Size(object) == 3) {
55 unsigned long long pid;
56 int task_id, vnn;
58 if (!PyArg_ParseTuple(object, "KII", &pid, &task_id, &vnn)) {
59 return false;
61 server_id->pid = pid;
62 server_id->task_id = task_id;
63 server_id->vnn = vnn;
64 return true;
65 } else if (PyTuple_Size(object) == 2) {
66 unsigned long long pid;
67 int task_id;
68 if (!PyArg_ParseTuple(object, "KI", &pid, &task_id))
69 return false;
70 *server_id = cluster_id(pid, task_id);
71 return true;
72 } else {
73 unsigned long long pid = getpid();
74 int task_id;
75 if (!PyArg_ParseTuple(object, "I", &task_id))
76 return false;
77 *server_id = cluster_id(pid, task_id);
78 return true;
82 typedef struct {
83 PyObject_HEAD
84 TALLOC_CTX *mem_ctx;
85 struct imessaging_context *msg_ctx;
86 } imessaging_Object;
88 static PyObject *py_imessaging_connect(PyTypeObject *self, PyObject *args, PyObject *kwargs)
90 struct tevent_context *ev;
91 const char *kwnames[] = { "own_id", "lp_ctx", NULL };
92 PyObject *own_id = Py_None;
93 PyObject *py_lp_ctx = Py_None;
94 imessaging_Object *ret;
95 struct loadparm_context *lp_ctx;
97 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:connect",
98 discard_const_p(char *, kwnames), &own_id, &py_lp_ctx)) {
99 return NULL;
102 ret = PyObject_New(imessaging_Object, &imessaging_Type);
103 if (ret == NULL)
104 return NULL;
106 ret->mem_ctx = talloc_new(NULL);
108 lp_ctx = lpcfg_from_py_object(ret->mem_ctx, py_lp_ctx);
109 if (lp_ctx == NULL) {
110 PyErr_SetString(PyExc_RuntimeError, "imessaging_connect unable to interpret loadparm_context");
111 talloc_free(ret->mem_ctx);
112 return NULL;
115 ev = s4_event_context_init(ret->mem_ctx);
117 if (own_id != Py_None) {
118 struct server_id server_id;
120 if (!server_id_from_py(own_id, &server_id))
121 return NULL;
123 ret->msg_ctx = imessaging_init(ret->mem_ctx,
124 lp_ctx,
125 server_id,
126 ev);
127 } else {
128 ret->msg_ctx = imessaging_client_init(ret->mem_ctx,
129 lp_ctx,
130 ev);
133 if (ret->msg_ctx == NULL) {
134 PyErr_SetString(PyExc_RuntimeError, "imessaging_connect unable to create a messaging context");
135 talloc_free(ret->mem_ctx);
136 return NULL;
139 return (PyObject *)ret;
142 static void py_imessaging_dealloc(PyObject *self)
144 imessaging_Object *iface = (imessaging_Object *)self;
145 talloc_free(iface->msg_ctx);
146 self->ob_type->tp_free(self);
149 static PyObject *py_imessaging_send(PyObject *self, PyObject *args, PyObject *kwargs)
151 imessaging_Object *iface = (imessaging_Object *)self;
152 uint32_t msg_type;
153 DATA_BLOB data;
154 PyObject *target;
155 NTSTATUS status;
156 struct server_id server;
157 const char *kwnames[] = { "target", "msg_type", "data", NULL };
158 Py_ssize_t length;
160 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Ois#:send",
161 discard_const_p(char *, kwnames), &target, &msg_type, &data.data, &length)) {
163 return NULL;
166 data.length = length;
168 if (!server_id_from_py(target, &server))
169 return NULL;
171 status = imessaging_send(iface->msg_ctx, server, msg_type, &data);
172 if (NT_STATUS_IS_ERR(status)) {
173 PyErr_SetNTSTATUS(status);
174 return NULL;
177 Py_RETURN_NONE;
180 static void py_msg_callback_wrapper(struct imessaging_context *msg, void *private_data,
181 uint32_t msg_type,
182 struct server_id server_id, DATA_BLOB *data)
184 PyObject *py_server_id, *callback_and_tuple = (PyObject *)private_data;
185 PyObject *callback, *py_private;
187 struct server_id *p_server_id = talloc(NULL, struct server_id);
188 if (!p_server_id) {
189 PyErr_NoMemory();
190 return;
192 *p_server_id = server_id;
194 if (!PyArg_ParseTuple(callback_and_tuple, "OO",
195 &callback,
196 &py_private)) {
197 return;
200 py_server_id = py_return_ndr_struct("samba.dcerpc.server_id", "server_id", p_server_id, p_server_id);
201 talloc_unlink(NULL, p_server_id);
203 PyObject_CallFunction(callback, discard_const_p(char, "OiOs#"),
204 py_private,
205 msg_type,
206 py_server_id,
207 data->data, data->length);
210 static PyObject *py_imessaging_register(PyObject *self, PyObject *args, PyObject *kwargs)
212 imessaging_Object *iface = (imessaging_Object *)self;
213 int msg_type = -1;
214 PyObject *callback_and_context;
215 NTSTATUS status;
216 const char *kwnames[] = { "callback_and_context", "msg_type", NULL };
218 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:register",
219 discard_const_p(char *, kwnames),
220 &callback_and_context, &msg_type)) {
221 return NULL;
223 if (!PyTuple_Check(callback_and_context)
224 || PyTuple_Size(callback_and_context) != 2) {
225 PyErr_SetString(PyExc_ValueError, "Expected of size 2 for callback_and_context");
226 return NULL;
229 Py_INCREF(callback_and_context);
231 if (msg_type == -1) {
232 uint32_t msg_type32 = msg_type;
233 status = imessaging_register_tmp(iface->msg_ctx, callback_and_context,
234 py_msg_callback_wrapper, &msg_type32);
235 msg_type = msg_type32;
236 } else {
237 status = imessaging_register(iface->msg_ctx, callback_and_context,
238 msg_type, py_msg_callback_wrapper);
240 if (NT_STATUS_IS_ERR(status)) {
241 PyErr_SetNTSTATUS(status);
242 return NULL;
245 return PyLong_FromLong(msg_type);
248 static PyObject *py_imessaging_deregister(PyObject *self, PyObject *args, PyObject *kwargs)
250 imessaging_Object *iface = (imessaging_Object *)self;
251 int msg_type = -1;
252 PyObject *callback;
253 const char *kwnames[] = { "callback", "msg_type", NULL };
255 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:deregister",
256 discard_const_p(char *, kwnames), &callback, &msg_type)) {
257 return NULL;
260 imessaging_deregister(iface->msg_ctx, msg_type, callback);
262 Py_DECREF(callback);
264 Py_RETURN_NONE;
267 static void simple_timer_handler(struct tevent_context *ev,
268 struct tevent_timer *te,
269 struct timeval current_time,
270 void *private_data)
272 return;
275 static PyObject *py_imessaging_loop_once(PyObject *self, PyObject *args, PyObject *kwargs)
277 imessaging_Object *iface = (imessaging_Object *)self;
278 double offset;
279 int seconds;
280 struct timeval next_event;
281 struct tevent_timer *timer = NULL;
282 const char *kwnames[] = { "timeout", NULL };
284 TALLOC_CTX *frame = talloc_stackframe();
286 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d",
287 discard_const_p(char *, kwnames), &offset)) {
288 TALLOC_FREE(frame);
289 return NULL;
292 if (offset != 0.0) {
293 seconds = offset;
294 offset -= seconds;
295 next_event = tevent_timeval_current_ofs(seconds, (int)(offset*1000000));
297 timer = tevent_add_timer(iface->msg_ctx->ev, frame, next_event, simple_timer_handler,
298 NULL);
299 if (timer == NULL) {
300 PyErr_NoMemory();
301 TALLOC_FREE(frame);
302 return NULL;
306 tevent_loop_once(iface->msg_ctx->ev);
308 TALLOC_FREE(frame);
310 Py_RETURN_NONE;
313 static PyObject *py_irpc_add_name(PyObject *self, PyObject *args, PyObject *kwargs)
315 imessaging_Object *iface = (imessaging_Object *)self;
316 char *server_name;
317 NTSTATUS status;
319 if (!PyArg_ParseTuple(args, "s", &server_name)) {
320 return NULL;
323 status = irpc_add_name(iface->msg_ctx, server_name);
324 if (!NT_STATUS_IS_OK(status)) {
325 PyErr_SetNTSTATUS(status);
326 return NULL;
329 Py_RETURN_NONE;
332 static PyObject *py_irpc_remove_name(PyObject *self, PyObject *args, PyObject *kwargs)
334 imessaging_Object *iface = (imessaging_Object *)self;
335 char *server_name;
337 if (!PyArg_ParseTuple(args, "s", &server_name)) {
338 return NULL;
341 irpc_remove_name(iface->msg_ctx, server_name);
343 Py_RETURN_NONE;
346 static PyObject *py_irpc_servers_byname(PyObject *self, PyObject *args, PyObject *kwargs)
348 imessaging_Object *iface = (imessaging_Object *)self;
349 char *server_name;
350 unsigned i, num_ids;
351 struct server_id *ids;
352 PyObject *pylist;
353 TALLOC_CTX *mem_ctx = talloc_new(NULL);
354 NTSTATUS status;
356 if (!mem_ctx) {
357 PyErr_NoMemory();
358 return NULL;
361 if (!PyArg_ParseTuple(args, "s", &server_name)) {
362 TALLOC_FREE(mem_ctx);
363 return NULL;
366 status = irpc_servers_byname(iface->msg_ctx, mem_ctx, server_name,
367 &num_ids, &ids);
368 if (!NT_STATUS_IS_OK(status)) {
369 TALLOC_FREE(mem_ctx);
370 PyErr_SetString(PyExc_KeyError, "No such name");
371 return NULL;
374 pylist = PyList_New(num_ids);
375 if (pylist == NULL) {
376 TALLOC_FREE(mem_ctx);
377 PyErr_NoMemory();
378 return NULL;
380 for (i = 0; i < num_ids; i++) {
381 PyObject *py_server_id;
382 struct server_id *p_server_id = talloc(NULL, struct server_id);
383 if (!p_server_id) {
384 PyErr_NoMemory();
385 return NULL;
387 *p_server_id = ids[i];
389 py_server_id = py_return_ndr_struct("samba.dcerpc.server_id", "server_id", p_server_id, p_server_id);
390 if (!py_server_id) {
391 return NULL;
393 PyList_SetItem(pylist, i, py_server_id);
394 talloc_unlink(NULL, p_server_id);
396 TALLOC_FREE(mem_ctx);
397 return pylist;
400 static PyObject *py_irpc_all_servers(PyObject *self, PyObject *args, PyObject *kwargs)
402 imessaging_Object *iface = (imessaging_Object *)self;
403 PyObject *pylist;
404 int i;
405 struct irpc_name_records *records;
406 TALLOC_CTX *mem_ctx = talloc_new(NULL);
407 if (!mem_ctx) {
408 PyErr_NoMemory();
409 return NULL;
412 records = irpc_all_servers(iface->msg_ctx, mem_ctx);
413 if (records == NULL) {
414 return NULL;
417 pylist = PyList_New(records->num_records);
418 if (pylist == NULL) {
419 TALLOC_FREE(mem_ctx);
420 PyErr_NoMemory();
421 return NULL;
423 for (i = 0; i < records->num_records; i++) {
424 PyObject *py_name_record
425 = py_return_ndr_struct("samba.dcerpc.irpc",
426 "name_record",
427 records->names[i],
428 records->names[i]);
429 if (!py_name_record) {
430 return NULL;
432 PyList_SetItem(pylist, i,
433 py_name_record);
435 TALLOC_FREE(mem_ctx);
436 return pylist;
439 static PyMethodDef py_imessaging_methods[] = {
440 { "send", (PyCFunction)py_imessaging_send, METH_VARARGS|METH_KEYWORDS,
441 "S.send(target, msg_type, data) -> None\nSend a message" },
442 { "register", (PyCFunction)py_imessaging_register, METH_VARARGS|METH_KEYWORDS,
443 "S.register((callback, context), msg_type=None) -> msg_type\nRegister a message handler. "
444 "The callback and context must be supplied as a two-element tuple." },
445 { "deregister", (PyCFunction)py_imessaging_deregister, METH_VARARGS|METH_KEYWORDS,
446 "S.deregister((callback, context), msg_type) -> None\nDeregister a message handler "
447 "The callback and context must be supplied as the exact same two-element tuple "
448 "as was used as registration time." },
449 { "loop_once", (PyCFunction)py_imessaging_loop_once, METH_VARARGS|METH_KEYWORDS,
450 "S.loop_once(timeout) -> None\n"
451 "Loop on the internal event context until we get an event "
452 "(which might be a message calling the callback), "
453 "timeout after timeout seconds (if not 0)" },
454 { "irpc_add_name", (PyCFunction)py_irpc_add_name, METH_VARARGS,
455 "S.irpc_add_name(name) -> None\n"
456 "Add this context to the list of server_id values that "
457 "are registered for a particular name" },
458 { "irpc_remove_name", (PyCFunction)py_irpc_remove_name, METH_VARARGS,
459 "S.irpc_remove_name(name) -> None\n"
460 "Remove this context from the list of server_id values that "
461 "are registered for a particular name" },
462 { "irpc_servers_byname", (PyCFunction)py_irpc_servers_byname, METH_VARARGS,
463 "S.irpc_servers_byname(name) -> list\nGet list of server_id values that are registered for a particular name" },
464 { "irpc_all_servers", (PyCFunction)py_irpc_all_servers, METH_NOARGS,
465 "S.irpc_all_servers() -> list\n"
466 "Get list of all registered names and the associated server_id values" },
467 { NULL, NULL, 0, NULL }
470 static PyObject *py_imessaging_server_id(PyObject *obj, void *closure)
472 imessaging_Object *iface = (imessaging_Object *)obj;
473 PyObject *py_server_id;
474 struct server_id server_id = imessaging_get_server_id(iface->msg_ctx);
475 struct server_id *p_server_id = talloc(NULL, struct server_id);
476 if (!p_server_id) {
477 PyErr_NoMemory();
478 return NULL;
480 *p_server_id = server_id;
482 py_server_id = py_return_ndr_struct("samba.dcerpc.server_id", "server_id", p_server_id, p_server_id);
483 talloc_unlink(NULL, p_server_id);
485 return py_server_id;
488 static PyGetSetDef py_imessaging_getset[] = {
489 { discard_const_p(char, "server_id"), py_imessaging_server_id, NULL,
490 discard_const_p(char, "local server id") },
491 { NULL },
495 PyTypeObject imessaging_Type = {
496 PyVarObject_HEAD_INIT(NULL, 0)
497 .tp_name = "messaging.Messaging",
498 .tp_basicsize = sizeof(imessaging_Object),
499 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
500 .tp_new = py_imessaging_connect,
501 .tp_dealloc = py_imessaging_dealloc,
502 .tp_methods = py_imessaging_methods,
503 .tp_getset = py_imessaging_getset,
504 .tp_doc = "Messaging(own_id=None)\n" \
505 "Create a new object that can be used to communicate with the peers in the specified messaging path.\n"
508 static struct PyModuleDef moduledef = {
509 PyModuleDef_HEAD_INIT,
510 .m_name = "messaging",
511 .m_doc = "Internal RPC",
512 .m_size = -1,
513 .m_methods = NULL,
516 MODULE_INIT_FUNC(messaging)
518 PyObject *mod;
520 if (PyType_Ready(&imessaging_Type) < 0)
521 return NULL;
523 mod = PyModule_Create(&moduledef);
524 if (mod == NULL)
525 return NULL;
527 Py_INCREF((PyObject *)&imessaging_Type);
528 PyModule_AddObject(mod, "Messaging", (PyObject *)&imessaging_Type);
529 PyModule_AddObject(mod, "IRPC_CALL_TIMEOUT", PyInt_FromLong(IRPC_CALL_TIMEOUT));
530 PyModule_AddObject(mod, "IRPC_CALL_TIMEOUT_INF", PyInt_FromLong(IRPC_CALL_TIMEOUT_INF));
532 return mod;