messaging4: Postpone messages to the right tevent context
[Samba.git] / source4 / lib / messaging / messaging.c
blob6fca9b8433ad334144f1231adcdc83ed45db996f
1 /*
2 Unix SMB/CIFS implementation.
4 Samba internal messaging functions
6 Copyright (C) Andrew Tridgell 2004
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 "includes.h"
23 #include "lib/events/events.h"
24 #include "system/filesys.h"
25 #include "messaging/messaging.h"
26 #include "../lib/util/dlinklist.h"
27 #include "lib/socket/socket.h"
28 #include "librpc/gen_ndr/ndr_irpc.h"
29 #include "lib/messaging/irpc.h"
30 #include "../lib/util/unix_privs.h"
31 #include "librpc/rpc/dcerpc.h"
32 #include "cluster/cluster.h"
33 #include "../lib/util/tevent_ntstatus.h"
34 #include "lib/param/param.h"
35 #include "lib/util/server_id_db.h"
36 #include "lib/util/talloc_report.h"
37 #include "../source3/lib/messages_dgm.h"
38 #include "../source3/lib/messages_dgm_ref.h"
39 #include "../source3/lib/messages_util.h"
40 #include <tdb.h>
42 /* change the message version with any incompatible changes in the protocol */
43 #define IMESSAGING_VERSION 1
46 a pending irpc call
48 struct irpc_request {
49 struct imessaging_context *msg_ctx;
50 int callid;
51 struct {
52 void (*handler)(struct irpc_request *irpc, struct irpc_message *m);
53 void *private_data;
54 } incoming;
57 struct imessaging_context {
58 struct imessaging_context *prev, *next;
59 struct tevent_context *ev;
60 struct server_id server_id;
61 const char *sock_dir;
62 const char *lock_dir;
63 struct dispatch_fn **dispatch;
64 uint32_t num_types;
65 struct idr_context *dispatch_tree;
66 struct irpc_list *irpc;
67 struct idr_context *idr;
68 struct server_id_db *names;
69 struct timeval start_time;
70 void *msg_dgm_ref;
73 /* we have a linked list of dispatch handlers for each msg_type that
74 this messaging server can deal with */
75 struct dispatch_fn {
76 struct dispatch_fn *next, *prev;
77 uint32_t msg_type;
78 void *private_data;
79 msg_callback_t fn;
82 /* an individual message */
84 static void irpc_handler(struct imessaging_context *, void *,
85 uint32_t, struct server_id, DATA_BLOB *);
89 A useful function for testing the message system.
91 static void ping_message(struct imessaging_context *msg, void *private_data,
92 uint32_t msg_type, struct server_id src, DATA_BLOB *data)
94 struct server_id_buf idbuf;
95 DEBUG(1,("INFO: Received PING message from server %s [%.*s]\n",
96 server_id_str_buf(src, &idbuf), (int)data->length,
97 data->data?(const char *)data->data:""));
98 imessaging_send(msg, src, MSG_PONG, data);
101 static void pool_message(struct imessaging_context *msg, void *private_data,
102 uint32_t msg_type, struct server_id src,
103 DATA_BLOB *data)
105 char *report;
107 report = talloc_report_str(msg, NULL);
109 if (report != NULL) {
110 DATA_BLOB blob = { .data = (uint8_t *)report,
111 .length = talloc_get_size(report) - 1};
112 imessaging_send(msg, src, MSG_POOL_USAGE, &blob);
114 talloc_free(report);
118 return uptime of messaging server via irpc
120 static NTSTATUS irpc_uptime(struct irpc_message *msg,
121 struct irpc_uptime *r)
123 struct imessaging_context *ctx = talloc_get_type(msg->private_data, struct imessaging_context);
124 *r->out.start_time = timeval_to_nttime(&ctx->start_time);
125 return NT_STATUS_OK;
128 static struct dispatch_fn *imessaging_find_dispatch(
129 struct imessaging_context *msg, uint32_t msg_type)
131 /* temporary IDs use an idtree, the rest use a array of pointers */
132 if (msg_type >= MSG_TMP_BASE) {
133 return (struct dispatch_fn *)idr_find(msg->dispatch_tree,
134 msg_type);
136 if (msg_type < msg->num_types) {
137 return msg->dispatch[msg_type];
139 return NULL;
143 Register a dispatch function for a particular message type.
145 NTSTATUS imessaging_register(struct imessaging_context *msg, void *private_data,
146 uint32_t msg_type, msg_callback_t fn)
148 struct dispatch_fn *d;
150 /* possibly expand dispatch array */
151 if (msg_type >= msg->num_types) {
152 struct dispatch_fn **dp;
153 uint32_t i;
154 dp = talloc_realloc(msg, msg->dispatch, struct dispatch_fn *, msg_type+1);
155 NT_STATUS_HAVE_NO_MEMORY(dp);
156 msg->dispatch = dp;
157 for (i=msg->num_types;i<=msg_type;i++) {
158 msg->dispatch[i] = NULL;
160 msg->num_types = msg_type+1;
163 d = talloc_zero(msg->dispatch, struct dispatch_fn);
164 NT_STATUS_HAVE_NO_MEMORY(d);
165 d->msg_type = msg_type;
166 d->private_data = private_data;
167 d->fn = fn;
169 DLIST_ADD(msg->dispatch[msg_type], d);
171 return NT_STATUS_OK;
175 register a temporary message handler. The msg_type is allocated
176 above MSG_TMP_BASE
178 NTSTATUS imessaging_register_tmp(struct imessaging_context *msg, void *private_data,
179 msg_callback_t fn, uint32_t *msg_type)
181 struct dispatch_fn *d;
182 int id;
184 d = talloc_zero(msg->dispatch, struct dispatch_fn);
185 NT_STATUS_HAVE_NO_MEMORY(d);
186 d->private_data = private_data;
187 d->fn = fn;
189 id = idr_get_new_above(msg->dispatch_tree, d, MSG_TMP_BASE, UINT16_MAX);
190 if (id == -1) {
191 talloc_free(d);
192 return NT_STATUS_TOO_MANY_CONTEXT_IDS;
195 d->msg_type = (uint32_t)id;
196 (*msg_type) = d->msg_type;
198 return NT_STATUS_OK;
202 De-register the function for a particular message type.
204 void imessaging_deregister(struct imessaging_context *msg, uint32_t msg_type, void *private_data)
206 struct dispatch_fn *d, *next;
208 if (msg_type >= msg->num_types) {
209 d = (struct dispatch_fn *)idr_find(msg->dispatch_tree,
210 msg_type);
211 if (!d) return;
212 idr_remove(msg->dispatch_tree, msg_type);
213 talloc_free(d);
214 return;
217 for (d = msg->dispatch[msg_type]; d; d = next) {
218 next = d->next;
219 if (d->private_data == private_data) {
220 DLIST_REMOVE(msg->dispatch[msg_type], d);
221 talloc_free(d);
227 Send a message to a particular server
229 NTSTATUS imessaging_send(struct imessaging_context *msg, struct server_id server,
230 uint32_t msg_type, const DATA_BLOB *data)
232 uint8_t hdr[MESSAGE_HDR_LENGTH];
233 struct iovec iov[2];
234 int num_iov, ret;
235 pid_t pid;
236 void *priv;
238 if (!cluster_node_equal(&msg->server_id, &server)) {
239 /* No cluster in source4... */
240 return NT_STATUS_OK;
243 message_hdr_put(hdr, msg_type, msg->server_id, server);
245 iov[0] = (struct iovec) { .iov_base = &hdr, .iov_len = sizeof(hdr) };
246 num_iov = 1;
248 if (data != NULL) {
249 iov[1] = (struct iovec) { .iov_base = data->data,
250 .iov_len = data->length };
251 num_iov += 1;
254 pid = server.pid;
255 if (pid == 0) {
256 pid = getpid();
259 ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
261 if (ret == EACCES) {
262 priv = root_privileges();
263 ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
264 TALLOC_FREE(priv);
267 if (ret != 0) {
268 return map_nt_error_from_unix_common(ret);
270 return NT_STATUS_OK;
274 Send a message to a particular server, with the message containing a single pointer
276 NTSTATUS imessaging_send_ptr(struct imessaging_context *msg, struct server_id server,
277 uint32_t msg_type, void *ptr)
279 DATA_BLOB blob;
281 blob.data = (uint8_t *)&ptr;
282 blob.length = sizeof(void *);
284 return imessaging_send(msg, server, msg_type, &blob);
290 int imessaging_cleanup(struct imessaging_context *msg)
292 if (!msg) {
293 return 0;
295 return 0;
298 static void imessaging_dgm_recv(struct tevent_context *ev,
299 const uint8_t *buf, size_t buf_len,
300 int *fds, size_t num_fds,
301 void *private_data);
303 /* Keep a list of imessaging contexts */
304 static struct imessaging_context *msg_ctxs;
306 static int imessaging_context_destructor(struct imessaging_context *msg)
308 DLIST_REMOVE(msg_ctxs, msg);
309 TALLOC_FREE(msg->msg_dgm_ref);
310 return 0;
314 * Cleanup messaging dgm contexts
316 * We must make sure to unref all messaging_dgm_ref's *before* the
317 * tevent context goes away. Only when the last ref is freed, the
318 * refcounted messaging dgm context will be freed.
320 void imessaging_dgm_unref_all(void)
322 struct imessaging_context *msg = NULL;
324 for (msg = msg_ctxs; msg != NULL; msg = msg->next) {
325 TALLOC_FREE(msg->msg_dgm_ref);
330 create the listening socket and setup the dispatcher
332 struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
333 struct loadparm_context *lp_ctx,
334 struct server_id server_id,
335 struct tevent_context *ev)
337 struct imessaging_context *msg;
338 bool ok;
339 int ret;
340 const char *lock_dir = NULL;
341 int tdb_flags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST;
343 if (ev == NULL) {
344 return NULL;
347 msg = talloc_zero(mem_ctx, struct imessaging_context);
348 if (msg == NULL) {
349 return NULL;
351 msg->ev = ev;
353 talloc_set_destructor(msg, imessaging_context_destructor);
355 /* create the messaging directory if needed */
357 lock_dir = lpcfg_lock_directory(lp_ctx);
358 if (lock_dir == NULL) {
359 goto fail;
362 msg->sock_dir = lpcfg_private_path(msg, lp_ctx, "msg.sock");
363 if (msg->sock_dir == NULL) {
364 goto fail;
366 ok = directory_create_or_exist_strict(msg->sock_dir, geteuid(), 0700);
367 if (!ok) {
368 goto fail;
371 msg->lock_dir = lpcfg_lock_path(msg, lp_ctx, "msg.lock");
372 if (msg->lock_dir == NULL) {
373 goto fail;
375 ok = directory_create_or_exist_strict(msg->lock_dir, geteuid(), 0755);
376 if (!ok) {
377 goto fail;
380 msg->msg_dgm_ref = messaging_dgm_ref(
381 msg, ev, &server_id.unique_id, msg->sock_dir, msg->lock_dir,
382 imessaging_dgm_recv, msg, &ret);
384 if (msg->msg_dgm_ref == NULL) {
385 goto fail;
388 msg->server_id = server_id;
389 msg->idr = idr_init(msg);
390 if (msg->idr == NULL) {
391 goto fail;
394 msg->dispatch_tree = idr_init(msg);
395 if (msg->dispatch_tree == NULL) {
396 goto fail;
399 msg->start_time = timeval_current();
401 tdb_flags |= lpcfg_tdb_flags(lp_ctx, 0);
403 msg->names = server_id_db_init(msg, server_id, lock_dir, 0, tdb_flags);
404 if (msg->names == NULL) {
405 goto fail;
408 imessaging_register(msg, NULL, MSG_PING, ping_message);
409 imessaging_register(msg, NULL, MSG_REQ_POOL_USAGE, pool_message);
410 imessaging_register(msg, NULL, MSG_IRPC, irpc_handler);
411 IRPC_REGISTER(msg, irpc, IRPC_UPTIME, irpc_uptime, msg);
413 DLIST_ADD(msg_ctxs, msg);
415 return msg;
416 fail:
417 talloc_free(msg);
418 return NULL;
421 struct imessaging_post_state {
422 struct imessaging_context *msg_ctx;
423 size_t buf_len;
424 uint8_t buf[];
427 static void imessaging_post_handler(struct tevent_context *ev,
428 struct tevent_immediate *ti,
429 void *private_data)
431 struct imessaging_post_state *state = talloc_get_type_abort(
432 private_data, struct imessaging_post_state);
433 imessaging_dgm_recv(ev, state->buf, state->buf_len, NULL, 0,
434 state->msg_ctx);
435 TALLOC_FREE(state);
438 static int imessaging_post_self(struct imessaging_context *msg,
439 const uint8_t *buf, size_t buf_len)
441 struct tevent_immediate *ti;
442 struct imessaging_post_state *state;
444 state = talloc_size(
445 msg, offsetof(struct imessaging_post_state, buf) + buf_len);
446 if (state == NULL) {
447 return ENOMEM;
449 talloc_set_name_const(state, "struct imessaging_post_state");
451 ti = tevent_create_immediate(state);
452 if (ti == NULL) {
453 TALLOC_FREE(state);
454 return ENOMEM;
457 state->msg_ctx = msg;
458 state->buf_len = buf_len;
459 memcpy(state->buf, buf, buf_len);
461 tevent_schedule_immediate(ti, msg->ev, imessaging_post_handler,
462 state);
464 return 0;
467 static void imessaging_dgm_recv(struct tevent_context *ev,
468 const uint8_t *buf, size_t buf_len,
469 int *fds, size_t num_fds,
470 void *private_data)
472 struct imessaging_context *msg = talloc_get_type_abort(
473 private_data, struct imessaging_context);
474 uint32_t msg_type;
475 struct server_id src, dst;
476 struct server_id_buf srcbuf, dstbuf;
477 DATA_BLOB data;
479 if (buf_len < MESSAGE_HDR_LENGTH) {
480 /* Invalid message, ignore */
481 return;
484 if (num_fds != 0) {
486 * Source4 based messaging does not expect fd's yet
488 return;
491 if (ev != msg->ev) {
492 int ret;
493 ret = imessaging_post_self(msg, buf, buf_len);
494 if (ret != 0) {
495 DBG_WARNING("imessaging_post_self failed: %s\n",
496 strerror(ret));
498 return;
501 message_hdr_get(&msg_type, &src, &dst, buf);
503 data.data = discard_const_p(uint8_t, buf + MESSAGE_HDR_LENGTH);
504 data.length = buf_len - MESSAGE_HDR_LENGTH;
506 if ((cluster_id_equal(&dst, &msg->server_id)) ||
507 ((dst.task_id == 0) && (msg->server_id.pid == 0))) {
508 struct dispatch_fn *d, *next;
510 DEBUG(10, ("%s: dst %s matches my id: %s, type=0x%x\n",
511 __func__,
512 server_id_str_buf(dst, &dstbuf),
513 server_id_str_buf(msg->server_id, &srcbuf),
514 (unsigned)msg_type));
516 d = imessaging_find_dispatch(msg, msg_type);
518 for (; d; d = next) {
519 next = d->next;
520 d->fn(msg, d->private_data, d->msg_type, src, &data);
522 } else {
523 DEBUG(10, ("%s: Ignoring type=0x%x dst %s, I am %s, \n",
524 __func__, (unsigned)msg_type,
525 server_id_str_buf(dst, &dstbuf),
526 server_id_str_buf(msg->server_id, &srcbuf)));
531 A hack, for the short term until we get 'client only' messaging in place
533 struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
534 struct loadparm_context *lp_ctx,
535 struct tevent_context *ev)
537 struct server_id id;
538 ZERO_STRUCT(id);
539 id.pid = getpid();
540 id.task_id = generate_random();
541 id.vnn = NONCLUSTER_VNN;
543 /* This is because we are not in the s3 serverid database */
544 id.unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
546 return imessaging_init(mem_ctx, lp_ctx, id, ev);
549 a list of registered irpc server functions
551 struct irpc_list {
552 struct irpc_list *next, *prev;
553 struct GUID uuid;
554 const struct ndr_interface_table *table;
555 int callnum;
556 irpc_function_t fn;
557 void *private_data;
562 register a irpc server function
564 NTSTATUS irpc_register(struct imessaging_context *msg_ctx,
565 const struct ndr_interface_table *table,
566 int callnum, irpc_function_t fn, void *private_data)
568 struct irpc_list *irpc;
570 /* override an existing handler, if any */
571 for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
572 if (irpc->table == table && irpc->callnum == callnum) {
573 break;
576 if (irpc == NULL) {
577 irpc = talloc(msg_ctx, struct irpc_list);
578 NT_STATUS_HAVE_NO_MEMORY(irpc);
579 DLIST_ADD(msg_ctx->irpc, irpc);
582 irpc->table = table;
583 irpc->callnum = callnum;
584 irpc->fn = fn;
585 irpc->private_data = private_data;
586 irpc->uuid = irpc->table->syntax_id.uuid;
588 return NT_STATUS_OK;
593 handle an incoming irpc reply message
595 static void irpc_handler_reply(struct imessaging_context *msg_ctx, struct irpc_message *m)
597 struct irpc_request *irpc;
599 irpc = (struct irpc_request *)idr_find(msg_ctx->idr, m->header.callid);
600 if (irpc == NULL) return;
602 irpc->incoming.handler(irpc, m);
606 send a irpc reply
608 NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
610 struct ndr_push *push;
611 DATA_BLOB packet;
612 enum ndr_err_code ndr_err;
614 m->header.status = status;
616 /* setup the reply */
617 push = ndr_push_init_ctx(m->ndr);
618 if (push == NULL) {
619 status = NT_STATUS_NO_MEMORY;
620 goto failed;
623 m->header.flags |= IRPC_FLAG_REPLY;
624 m->header.creds.token= NULL;
626 /* construct the packet */
627 ndr_err = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
628 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
629 status = ndr_map_error2ntstatus(ndr_err);
630 goto failed;
633 ndr_err = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
634 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
635 status = ndr_map_error2ntstatus(ndr_err);
636 goto failed;
639 /* send the reply message */
640 packet = ndr_push_blob(push);
641 status = imessaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
642 if (!NT_STATUS_IS_OK(status)) goto failed;
644 failed:
645 talloc_free(m);
646 return status;
650 handle an incoming irpc request message
652 static void irpc_handler_request(struct imessaging_context *msg_ctx,
653 struct irpc_message *m)
655 struct irpc_list *i;
656 void *r;
657 enum ndr_err_code ndr_err;
659 for (i=msg_ctx->irpc; i; i=i->next) {
660 if (GUID_equal(&i->uuid, &m->header.uuid) &&
661 i->table->syntax_id.if_version == m->header.if_version &&
662 i->callnum == m->header.callnum) {
663 break;
667 if (i == NULL) {
668 /* no registered handler for this message */
669 talloc_free(m);
670 return;
673 /* allocate space for the structure */
674 r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
675 if (r == NULL) goto failed;
677 m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
679 /* parse the request data */
680 ndr_err = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
681 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
683 /* make the call */
684 m->private_data= i->private_data;
685 m->defer_reply = false;
686 m->no_reply = false;
687 m->msg_ctx = msg_ctx;
688 m->irpc = i;
689 m->data = r;
691 m->header.status = i->fn(m, r);
693 if (m->no_reply) {
694 /* the server function won't ever be replying to this request */
695 talloc_free(m);
696 return;
699 if (m->defer_reply) {
700 /* the server function has asked to defer the reply to later */
701 talloc_steal(msg_ctx, m);
702 return;
705 irpc_send_reply(m, m->header.status);
706 return;
708 failed:
709 talloc_free(m);
713 handle an incoming irpc message
715 static void irpc_handler(struct imessaging_context *msg_ctx, void *private_data,
716 uint32_t msg_type, struct server_id src, DATA_BLOB *packet)
718 struct irpc_message *m;
719 enum ndr_err_code ndr_err;
721 m = talloc(msg_ctx, struct irpc_message);
722 if (m == NULL) goto failed;
724 m->from = src;
726 m->ndr = ndr_pull_init_blob(packet, m);
727 if (m->ndr == NULL) goto failed;
729 m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
731 ndr_err = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
732 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
734 if (m->header.flags & IRPC_FLAG_REPLY) {
735 irpc_handler_reply(msg_ctx, m);
736 } else {
737 irpc_handler_request(msg_ctx, m);
739 return;
741 failed:
742 talloc_free(m);
747 destroy a irpc request
749 static int irpc_destructor(struct irpc_request *irpc)
751 if (irpc->callid != -1) {
752 idr_remove(irpc->msg_ctx->idr, irpc->callid);
753 irpc->callid = -1;
756 return 0;
760 add a string name that this irpc server can be called on
762 NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name)
764 int ret;
766 ret = server_id_db_add(msg_ctx->names, name);
767 if (ret != 0) {
768 return map_nt_error_from_unix_common(ret);
770 return NT_STATUS_OK;
774 return a list of server ids for a server name
776 NTSTATUS irpc_servers_byname(struct imessaging_context *msg_ctx,
777 TALLOC_CTX *mem_ctx, const char *name,
778 unsigned *num_servers,
779 struct server_id **servers)
781 int ret;
783 ret = server_id_db_lookup(msg_ctx->names, name, mem_ctx,
784 num_servers, servers);
785 if (ret != 0) {
786 return map_nt_error_from_unix_common(ret);
788 return NT_STATUS_OK;
791 static int all_servers_func(const char *name, unsigned num_servers,
792 const struct server_id *servers,
793 void *private_data)
795 struct irpc_name_records *name_records = talloc_get_type(
796 private_data, struct irpc_name_records);
797 struct irpc_name_record *name_record;
798 uint32_t i;
800 name_records->names
801 = talloc_realloc(name_records, name_records->names,
802 struct irpc_name_record *, name_records->num_records+1);
803 if (!name_records->names) {
804 return -1;
807 name_records->names[name_records->num_records] = name_record
808 = talloc(name_records->names,
809 struct irpc_name_record);
810 if (!name_record) {
811 return -1;
814 name_records->num_records++;
816 name_record->name = talloc_strdup(name_record, name);
817 if (!name_record->name) {
818 return -1;
821 name_record->count = num_servers;
822 name_record->ids = talloc_array(name_record, struct server_id,
823 num_servers);
824 if (name_record->ids == NULL) {
825 return -1;
827 for (i=0;i<name_record->count;i++) {
828 name_record->ids[i] = servers[i];
830 return 0;
834 return a list of server ids for a server name
836 struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx,
837 TALLOC_CTX *mem_ctx)
839 int ret;
840 struct irpc_name_records *name_records = talloc_zero(mem_ctx, struct irpc_name_records);
841 if (name_records == NULL) {
842 return NULL;
845 ret = server_id_db_traverse_read(msg_ctx->names, all_servers_func,
846 name_records);
847 if (ret == -1) {
848 TALLOC_FREE(name_records);
849 return NULL;
852 return name_records;
856 remove a name from a messaging context
858 void irpc_remove_name(struct imessaging_context *msg_ctx, const char *name)
860 server_id_db_remove(msg_ctx->names, name);
863 struct server_id imessaging_get_server_id(struct imessaging_context *msg_ctx)
865 return msg_ctx->server_id;
868 struct irpc_bh_state {
869 struct imessaging_context *msg_ctx;
870 struct server_id server_id;
871 const struct ndr_interface_table *table;
872 uint32_t timeout;
873 struct security_token *token;
876 static bool irpc_bh_is_connected(struct dcerpc_binding_handle *h)
878 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
879 struct irpc_bh_state);
881 if (!hs->msg_ctx) {
882 return false;
885 return true;
888 static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle *h,
889 uint32_t timeout)
891 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
892 struct irpc_bh_state);
893 uint32_t old = hs->timeout;
895 hs->timeout = timeout;
897 return old;
900 struct irpc_bh_raw_call_state {
901 struct irpc_request *irpc;
902 uint32_t opnum;
903 DATA_BLOB in_data;
904 DATA_BLOB in_packet;
905 DATA_BLOB out_data;
908 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
909 struct irpc_message *m);
911 static struct tevent_req *irpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
912 struct tevent_context *ev,
913 struct dcerpc_binding_handle *h,
914 const struct GUID *object,
915 uint32_t opnum,
916 uint32_t in_flags,
917 const uint8_t *in_data,
918 size_t in_length)
920 struct irpc_bh_state *hs =
921 dcerpc_binding_handle_data(h,
922 struct irpc_bh_state);
923 struct tevent_req *req;
924 struct irpc_bh_raw_call_state *state;
925 bool ok;
926 struct irpc_header header;
927 struct ndr_push *ndr;
928 NTSTATUS status;
929 enum ndr_err_code ndr_err;
931 req = tevent_req_create(mem_ctx, &state,
932 struct irpc_bh_raw_call_state);
933 if (req == NULL) {
934 return NULL;
936 state->opnum = opnum;
937 state->in_data.data = discard_const_p(uint8_t, in_data);
938 state->in_data.length = in_length;
940 ok = irpc_bh_is_connected(h);
941 if (!ok) {
942 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
943 return tevent_req_post(req, ev);
946 state->irpc = talloc_zero(state, struct irpc_request);
947 if (tevent_req_nomem(state->irpc, req)) {
948 return tevent_req_post(req, ev);
951 state->irpc->msg_ctx = hs->msg_ctx;
952 state->irpc->callid = idr_get_new(hs->msg_ctx->idr,
953 state->irpc, UINT16_MAX);
954 if (state->irpc->callid == -1) {
955 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
956 return tevent_req_post(req, ev);
958 state->irpc->incoming.handler = irpc_bh_raw_call_incoming_handler;
959 state->irpc->incoming.private_data = req;
961 talloc_set_destructor(state->irpc, irpc_destructor);
963 /* setup the header */
964 header.uuid = hs->table->syntax_id.uuid;
966 header.if_version = hs->table->syntax_id.if_version;
967 header.callid = state->irpc->callid;
968 header.callnum = state->opnum;
969 header.flags = 0;
970 header.status = NT_STATUS_OK;
971 header.creds.token= hs->token;
973 /* construct the irpc packet */
974 ndr = ndr_push_init_ctx(state->irpc);
975 if (tevent_req_nomem(ndr, req)) {
976 return tevent_req_post(req, ev);
979 ndr_err = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
980 status = ndr_map_error2ntstatus(ndr_err);
981 if (!NT_STATUS_IS_OK(status)) {
982 tevent_req_nterror(req, status);
983 return tevent_req_post(req, ev);
986 ndr_err = ndr_push_bytes(ndr, in_data, in_length);
987 status = ndr_map_error2ntstatus(ndr_err);
988 if (!NT_STATUS_IS_OK(status)) {
989 tevent_req_nterror(req, status);
990 return tevent_req_post(req, ev);
993 /* and send it */
994 state->in_packet = ndr_push_blob(ndr);
995 status = imessaging_send(hs->msg_ctx, hs->server_id,
996 MSG_IRPC, &state->in_packet);
997 if (!NT_STATUS_IS_OK(status)) {
998 tevent_req_nterror(req, status);
999 return tevent_req_post(req, ev);
1002 if (hs->timeout != IRPC_CALL_TIMEOUT_INF) {
1003 /* set timeout-callback in case caller wants that */
1004 ok = tevent_req_set_endtime(req, ev, timeval_current_ofs(hs->timeout, 0));
1005 if (!ok) {
1006 return tevent_req_post(req, ev);
1010 return req;
1013 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
1014 struct irpc_message *m)
1016 struct tevent_req *req =
1017 talloc_get_type_abort(irpc->incoming.private_data,
1018 struct tevent_req);
1019 struct irpc_bh_raw_call_state *state =
1020 tevent_req_data(req,
1021 struct irpc_bh_raw_call_state);
1023 talloc_steal(state, m);
1025 if (!NT_STATUS_IS_OK(m->header.status)) {
1026 tevent_req_nterror(req, m->header.status);
1027 return;
1030 state->out_data = data_blob_talloc(state,
1031 m->ndr->data + m->ndr->offset,
1032 m->ndr->data_size - m->ndr->offset);
1033 if ((m->ndr->data_size - m->ndr->offset) > 0 && !state->out_data.data) {
1034 tevent_req_oom(req);
1035 return;
1038 tevent_req_done(req);
1041 static NTSTATUS irpc_bh_raw_call_recv(struct tevent_req *req,
1042 TALLOC_CTX *mem_ctx,
1043 uint8_t **out_data,
1044 size_t *out_length,
1045 uint32_t *out_flags)
1047 struct irpc_bh_raw_call_state *state =
1048 tevent_req_data(req,
1049 struct irpc_bh_raw_call_state);
1050 NTSTATUS status;
1052 if (tevent_req_is_nterror(req, &status)) {
1053 tevent_req_received(req);
1054 return status;
1057 *out_data = talloc_move(mem_ctx, &state->out_data.data);
1058 *out_length = state->out_data.length;
1059 *out_flags = 0;
1060 tevent_req_received(req);
1061 return NT_STATUS_OK;
1064 struct irpc_bh_disconnect_state {
1065 uint8_t _dummy;
1068 static struct tevent_req *irpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
1069 struct tevent_context *ev,
1070 struct dcerpc_binding_handle *h)
1072 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
1073 struct irpc_bh_state);
1074 struct tevent_req *req;
1075 struct irpc_bh_disconnect_state *state;
1076 bool ok;
1078 req = tevent_req_create(mem_ctx, &state,
1079 struct irpc_bh_disconnect_state);
1080 if (req == NULL) {
1081 return NULL;
1084 ok = irpc_bh_is_connected(h);
1085 if (!ok) {
1086 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1087 return tevent_req_post(req, ev);
1090 hs->msg_ctx = NULL;
1092 tevent_req_done(req);
1093 return tevent_req_post(req, ev);
1096 static NTSTATUS irpc_bh_disconnect_recv(struct tevent_req *req)
1098 NTSTATUS status;
1100 if (tevent_req_is_nterror(req, &status)) {
1101 tevent_req_received(req);
1102 return status;
1105 tevent_req_received(req);
1106 return NT_STATUS_OK;
1109 static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
1111 return true;
1114 static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
1115 .name = "wbint",
1116 .is_connected = irpc_bh_is_connected,
1117 .set_timeout = irpc_bh_set_timeout,
1118 .raw_call_send = irpc_bh_raw_call_send,
1119 .raw_call_recv = irpc_bh_raw_call_recv,
1120 .disconnect_send = irpc_bh_disconnect_send,
1121 .disconnect_recv = irpc_bh_disconnect_recv,
1123 .ref_alloc = irpc_bh_ref_alloc,
1126 /* initialise a irpc binding handle */
1127 struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
1128 struct imessaging_context *msg_ctx,
1129 struct server_id server_id,
1130 const struct ndr_interface_table *table)
1132 struct dcerpc_binding_handle *h;
1133 struct irpc_bh_state *hs;
1135 h = dcerpc_binding_handle_create(mem_ctx,
1136 &irpc_bh_ops,
1137 NULL,
1138 table,
1139 &hs,
1140 struct irpc_bh_state,
1141 __location__);
1142 if (h == NULL) {
1143 return NULL;
1145 hs->msg_ctx = msg_ctx;
1146 hs->server_id = server_id;
1147 hs->table = table;
1148 hs->timeout = IRPC_CALL_TIMEOUT;
1150 return h;
1153 struct dcerpc_binding_handle *irpc_binding_handle_by_name(TALLOC_CTX *mem_ctx,
1154 struct imessaging_context *msg_ctx,
1155 const char *dest_task,
1156 const struct ndr_interface_table *table)
1158 struct dcerpc_binding_handle *h;
1159 unsigned num_sids;
1160 struct server_id *sids;
1161 struct server_id sid;
1162 NTSTATUS status;
1164 /* find the server task */
1166 status = irpc_servers_byname(msg_ctx, mem_ctx, dest_task,
1167 &num_sids, &sids);
1168 if (!NT_STATUS_IS_OK(status)) {
1169 errno = EADDRNOTAVAIL;
1170 return NULL;
1172 sid = sids[0];
1173 talloc_free(sids);
1175 h = irpc_binding_handle(mem_ctx, msg_ctx,
1176 sid, table);
1177 if (h == NULL) {
1178 return NULL;
1181 return h;
1184 void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle *h,
1185 struct security_token *token)
1187 struct irpc_bh_state *hs =
1188 dcerpc_binding_handle_data(h,
1189 struct irpc_bh_state);
1191 hs->token = token;