messaging4: Fix signed/unsigned hickups
[Samba.git] / source4 / lib / messaging / messaging.c
blobc0b64be0f58a815079f050aa51daa4084d835fab
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 server_id server_id;
60 const char *sock_dir;
61 const char *lock_dir;
62 struct dispatch_fn **dispatch;
63 uint32_t num_types;
64 struct idr_context *dispatch_tree;
65 struct irpc_list *irpc;
66 struct idr_context *idr;
67 struct server_id_db *names;
68 struct timeval start_time;
69 void *msg_dgm_ref;
72 /* we have a linked list of dispatch handlers for each msg_type that
73 this messaging server can deal with */
74 struct dispatch_fn {
75 struct dispatch_fn *next, *prev;
76 uint32_t msg_type;
77 void *private_data;
78 msg_callback_t fn;
81 /* an individual message */
83 static void irpc_handler(struct imessaging_context *, void *,
84 uint32_t, struct server_id, DATA_BLOB *);
88 A useful function for testing the message system.
90 static void ping_message(struct imessaging_context *msg, void *private_data,
91 uint32_t msg_type, struct server_id src, DATA_BLOB *data)
93 struct server_id_buf idbuf;
94 DEBUG(1,("INFO: Received PING message from server %s [%.*s]\n",
95 server_id_str_buf(src, &idbuf), (int)data->length,
96 data->data?(const char *)data->data:""));
97 imessaging_send(msg, src, MSG_PONG, data);
100 static void pool_message(struct imessaging_context *msg, void *private_data,
101 uint32_t msg_type, struct server_id src,
102 DATA_BLOB *data)
104 char *report;
106 report = talloc_report_str(msg, NULL);
108 if (report != NULL) {
109 DATA_BLOB blob = { .data = (uint8_t *)report,
110 .length = talloc_get_size(report) - 1};
111 imessaging_send(msg, src, MSG_POOL_USAGE, &blob);
113 talloc_free(report);
117 return uptime of messaging server via irpc
119 static NTSTATUS irpc_uptime(struct irpc_message *msg,
120 struct irpc_uptime *r)
122 struct imessaging_context *ctx = talloc_get_type(msg->private_data, struct imessaging_context);
123 *r->out.start_time = timeval_to_nttime(&ctx->start_time);
124 return NT_STATUS_OK;
127 static struct dispatch_fn *imessaging_find_dispatch(
128 struct imessaging_context *msg, uint32_t msg_type)
130 /* temporary IDs use an idtree, the rest use a array of pointers */
131 if (msg_type >= MSG_TMP_BASE) {
132 return (struct dispatch_fn *)idr_find(msg->dispatch_tree,
133 msg_type);
135 if (msg_type < msg->num_types) {
136 return msg->dispatch[msg_type];
138 return NULL;
142 Register a dispatch function for a particular message type.
144 NTSTATUS imessaging_register(struct imessaging_context *msg, void *private_data,
145 uint32_t msg_type, msg_callback_t fn)
147 struct dispatch_fn *d;
149 /* possibly expand dispatch array */
150 if (msg_type >= msg->num_types) {
151 struct dispatch_fn **dp;
152 uint32_t i;
153 dp = talloc_realloc(msg, msg->dispatch, struct dispatch_fn *, msg_type+1);
154 NT_STATUS_HAVE_NO_MEMORY(dp);
155 msg->dispatch = dp;
156 for (i=msg->num_types;i<=msg_type;i++) {
157 msg->dispatch[i] = NULL;
159 msg->num_types = msg_type+1;
162 d = talloc_zero(msg->dispatch, struct dispatch_fn);
163 NT_STATUS_HAVE_NO_MEMORY(d);
164 d->msg_type = msg_type;
165 d->private_data = private_data;
166 d->fn = fn;
168 DLIST_ADD(msg->dispatch[msg_type], d);
170 return NT_STATUS_OK;
174 register a temporary message handler. The msg_type is allocated
175 above MSG_TMP_BASE
177 NTSTATUS imessaging_register_tmp(struct imessaging_context *msg, void *private_data,
178 msg_callback_t fn, uint32_t *msg_type)
180 struct dispatch_fn *d;
181 int id;
183 d = talloc_zero(msg->dispatch, struct dispatch_fn);
184 NT_STATUS_HAVE_NO_MEMORY(d);
185 d->private_data = private_data;
186 d->fn = fn;
188 id = idr_get_new_above(msg->dispatch_tree, d, MSG_TMP_BASE, UINT16_MAX);
189 if (id == -1) {
190 talloc_free(d);
191 return NT_STATUS_TOO_MANY_CONTEXT_IDS;
194 d->msg_type = (uint32_t)id;
195 (*msg_type) = d->msg_type;
197 return NT_STATUS_OK;
201 De-register the function for a particular message type.
203 void imessaging_deregister(struct imessaging_context *msg, uint32_t msg_type, void *private_data)
205 struct dispatch_fn *d, *next;
207 if (msg_type >= msg->num_types) {
208 d = (struct dispatch_fn *)idr_find(msg->dispatch_tree,
209 msg_type);
210 if (!d) return;
211 idr_remove(msg->dispatch_tree, msg_type);
212 talloc_free(d);
213 return;
216 for (d = msg->dispatch[msg_type]; d; d = next) {
217 next = d->next;
218 if (d->private_data == private_data) {
219 DLIST_REMOVE(msg->dispatch[msg_type], d);
220 talloc_free(d);
226 Send a message to a particular server
228 NTSTATUS imessaging_send(struct imessaging_context *msg, struct server_id server,
229 uint32_t msg_type, const DATA_BLOB *data)
231 uint8_t hdr[MESSAGE_HDR_LENGTH];
232 struct iovec iov[2];
233 int num_iov, ret;
234 pid_t pid;
235 void *priv;
237 if (!cluster_node_equal(&msg->server_id, &server)) {
238 /* No cluster in source4... */
239 return NT_STATUS_OK;
242 message_hdr_put(hdr, msg_type, msg->server_id, server);
244 iov[0] = (struct iovec) { .iov_base = &hdr, .iov_len = sizeof(hdr) };
245 num_iov = 1;
247 if (data != NULL) {
248 iov[1] = (struct iovec) { .iov_base = data->data,
249 .iov_len = data->length };
250 num_iov += 1;
253 pid = server.pid;
254 if (pid == 0) {
255 pid = getpid();
258 ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
260 if (ret == EACCES) {
261 priv = root_privileges();
262 ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
263 TALLOC_FREE(priv);
266 if (ret != 0) {
267 return map_nt_error_from_unix_common(ret);
269 return NT_STATUS_OK;
273 Send a message to a particular server, with the message containing a single pointer
275 NTSTATUS imessaging_send_ptr(struct imessaging_context *msg, struct server_id server,
276 uint32_t msg_type, void *ptr)
278 DATA_BLOB blob;
280 blob.data = (uint8_t *)&ptr;
281 blob.length = sizeof(void *);
283 return imessaging_send(msg, server, msg_type, &blob);
289 int imessaging_cleanup(struct imessaging_context *msg)
291 if (!msg) {
292 return 0;
294 return 0;
297 static void imessaging_dgm_recv(const uint8_t *buf, size_t buf_len,
298 int *fds, size_t num_fds,
299 void *private_data);
301 /* Keep a list of imessaging contexts */
302 static struct imessaging_context *msg_ctxs;
304 static int imessaging_context_destructor(struct imessaging_context *msg)
306 DLIST_REMOVE(msg_ctxs, msg);
307 TALLOC_FREE(msg->msg_dgm_ref);
308 return 0;
312 * Cleanup messaging dgm contexts
314 * We must make sure to unref all messaging_dgm_ref's *before* the
315 * tevent context goes away. Only when the last ref is freed, the
316 * refcounted messaging dgm context will be freed.
318 void imessaging_dgm_unref_all(void)
320 struct imessaging_context *msg = NULL;
322 for (msg = msg_ctxs; msg != NULL; msg = msg->next) {
323 TALLOC_FREE(msg->msg_dgm_ref);
328 create the listening socket and setup the dispatcher
330 struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
331 struct loadparm_context *lp_ctx,
332 struct server_id server_id,
333 struct tevent_context *ev)
335 struct imessaging_context *msg;
336 bool ok;
337 int ret;
338 const char *lock_dir = NULL;
339 int tdb_flags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST;
341 if (ev == NULL) {
342 return NULL;
345 msg = talloc_zero(mem_ctx, struct imessaging_context);
346 if (msg == NULL) {
347 return NULL;
350 talloc_set_destructor(msg, imessaging_context_destructor);
352 /* create the messaging directory if needed */
354 lock_dir = lpcfg_lock_directory(lp_ctx);
355 if (lock_dir == NULL) {
356 goto fail;
359 msg->sock_dir = lpcfg_private_path(msg, lp_ctx, "msg.sock");
360 if (msg->sock_dir == NULL) {
361 goto fail;
363 ok = directory_create_or_exist_strict(msg->sock_dir, geteuid(), 0700);
364 if (!ok) {
365 goto fail;
368 msg->lock_dir = lpcfg_lock_path(msg, lp_ctx, "msg.lock");
369 if (msg->lock_dir == NULL) {
370 goto fail;
372 ok = directory_create_or_exist_strict(msg->lock_dir, geteuid(), 0755);
373 if (!ok) {
374 goto fail;
377 msg->msg_dgm_ref = messaging_dgm_ref(
378 msg, ev, &server_id.unique_id, msg->sock_dir, msg->lock_dir,
379 imessaging_dgm_recv, msg, &ret);
381 if (msg->msg_dgm_ref == NULL) {
382 goto fail;
385 msg->server_id = server_id;
386 msg->idr = idr_init(msg);
387 if (msg->idr == NULL) {
388 goto fail;
391 msg->dispatch_tree = idr_init(msg);
392 if (msg->dispatch_tree == NULL) {
393 goto fail;
396 msg->start_time = timeval_current();
398 tdb_flags |= lpcfg_tdb_flags(lp_ctx, 0);
400 msg->names = server_id_db_init(msg, server_id, lock_dir, 0, tdb_flags);
401 if (msg->names == NULL) {
402 goto fail;
405 imessaging_register(msg, NULL, MSG_PING, ping_message);
406 imessaging_register(msg, NULL, MSG_REQ_POOL_USAGE, pool_message);
407 imessaging_register(msg, NULL, MSG_IRPC, irpc_handler);
408 IRPC_REGISTER(msg, irpc, IRPC_UPTIME, irpc_uptime, msg);
410 DLIST_ADD(msg_ctxs, msg);
412 return msg;
413 fail:
414 talloc_free(msg);
415 return NULL;
418 static void imessaging_dgm_recv(const uint8_t *buf, size_t buf_len,
419 int *fds, size_t num_fds,
420 void *private_data)
422 struct imessaging_context *msg = talloc_get_type_abort(
423 private_data, struct imessaging_context);
424 uint32_t msg_type;
425 struct server_id src, dst;
426 struct server_id_buf srcbuf, dstbuf;
427 DATA_BLOB data;
429 if (buf_len < MESSAGE_HDR_LENGTH) {
430 /* Invalid message, ignore */
431 return;
434 message_hdr_get(&msg_type, &src, &dst, buf);
436 data.data = discard_const_p(uint8_t, buf + MESSAGE_HDR_LENGTH);
437 data.length = buf_len - MESSAGE_HDR_LENGTH;
439 if ((cluster_id_equal(&dst, &msg->server_id)) ||
440 ((dst.task_id == 0) && (msg->server_id.pid == 0))) {
441 struct dispatch_fn *d, *next;
443 DEBUG(10, ("%s: dst %s matches my id: %s, type=0x%x\n",
444 __func__,
445 server_id_str_buf(dst, &dstbuf),
446 server_id_str_buf(msg->server_id, &srcbuf),
447 (unsigned)msg_type));
449 d = imessaging_find_dispatch(msg, msg_type);
451 for (; d; d = next) {
452 next = d->next;
453 d->fn(msg, d->private_data, d->msg_type, src, &data);
455 } else {
456 DEBUG(10, ("%s: Ignoring type=0x%x dst %s, I am %s, \n",
457 __func__, (unsigned)msg_type,
458 server_id_str_buf(dst, &dstbuf),
459 server_id_str_buf(msg->server_id, &srcbuf)));
464 A hack, for the short term until we get 'client only' messaging in place
466 struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
467 struct loadparm_context *lp_ctx,
468 struct tevent_context *ev)
470 struct server_id id;
471 ZERO_STRUCT(id);
472 id.pid = getpid();
473 id.task_id = generate_random();
474 id.vnn = NONCLUSTER_VNN;
476 /* This is because we are not in the s3 serverid database */
477 id.unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
479 return imessaging_init(mem_ctx, lp_ctx, id, ev);
482 a list of registered irpc server functions
484 struct irpc_list {
485 struct irpc_list *next, *prev;
486 struct GUID uuid;
487 const struct ndr_interface_table *table;
488 int callnum;
489 irpc_function_t fn;
490 void *private_data;
495 register a irpc server function
497 NTSTATUS irpc_register(struct imessaging_context *msg_ctx,
498 const struct ndr_interface_table *table,
499 int callnum, irpc_function_t fn, void *private_data)
501 struct irpc_list *irpc;
503 /* override an existing handler, if any */
504 for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
505 if (irpc->table == table && irpc->callnum == callnum) {
506 break;
509 if (irpc == NULL) {
510 irpc = talloc(msg_ctx, struct irpc_list);
511 NT_STATUS_HAVE_NO_MEMORY(irpc);
512 DLIST_ADD(msg_ctx->irpc, irpc);
515 irpc->table = table;
516 irpc->callnum = callnum;
517 irpc->fn = fn;
518 irpc->private_data = private_data;
519 irpc->uuid = irpc->table->syntax_id.uuid;
521 return NT_STATUS_OK;
526 handle an incoming irpc reply message
528 static void irpc_handler_reply(struct imessaging_context *msg_ctx, struct irpc_message *m)
530 struct irpc_request *irpc;
532 irpc = (struct irpc_request *)idr_find(msg_ctx->idr, m->header.callid);
533 if (irpc == NULL) return;
535 irpc->incoming.handler(irpc, m);
539 send a irpc reply
541 NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
543 struct ndr_push *push;
544 DATA_BLOB packet;
545 enum ndr_err_code ndr_err;
547 m->header.status = status;
549 /* setup the reply */
550 push = ndr_push_init_ctx(m->ndr);
551 if (push == NULL) {
552 status = NT_STATUS_NO_MEMORY;
553 goto failed;
556 m->header.flags |= IRPC_FLAG_REPLY;
557 m->header.creds.token= NULL;
559 /* construct the packet */
560 ndr_err = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
561 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
562 status = ndr_map_error2ntstatus(ndr_err);
563 goto failed;
566 ndr_err = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
567 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
568 status = ndr_map_error2ntstatus(ndr_err);
569 goto failed;
572 /* send the reply message */
573 packet = ndr_push_blob(push);
574 status = imessaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
575 if (!NT_STATUS_IS_OK(status)) goto failed;
577 failed:
578 talloc_free(m);
579 return status;
583 handle an incoming irpc request message
585 static void irpc_handler_request(struct imessaging_context *msg_ctx,
586 struct irpc_message *m)
588 struct irpc_list *i;
589 void *r;
590 enum ndr_err_code ndr_err;
592 for (i=msg_ctx->irpc; i; i=i->next) {
593 if (GUID_equal(&i->uuid, &m->header.uuid) &&
594 i->table->syntax_id.if_version == m->header.if_version &&
595 i->callnum == m->header.callnum) {
596 break;
600 if (i == NULL) {
601 /* no registered handler for this message */
602 talloc_free(m);
603 return;
606 /* allocate space for the structure */
607 r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
608 if (r == NULL) goto failed;
610 m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
612 /* parse the request data */
613 ndr_err = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
614 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
616 /* make the call */
617 m->private_data= i->private_data;
618 m->defer_reply = false;
619 m->no_reply = false;
620 m->msg_ctx = msg_ctx;
621 m->irpc = i;
622 m->data = r;
624 m->header.status = i->fn(m, r);
626 if (m->no_reply) {
627 /* the server function won't ever be replying to this request */
628 talloc_free(m);
629 return;
632 if (m->defer_reply) {
633 /* the server function has asked to defer the reply to later */
634 talloc_steal(msg_ctx, m);
635 return;
638 irpc_send_reply(m, m->header.status);
639 return;
641 failed:
642 talloc_free(m);
646 handle an incoming irpc message
648 static void irpc_handler(struct imessaging_context *msg_ctx, void *private_data,
649 uint32_t msg_type, struct server_id src, DATA_BLOB *packet)
651 struct irpc_message *m;
652 enum ndr_err_code ndr_err;
654 m = talloc(msg_ctx, struct irpc_message);
655 if (m == NULL) goto failed;
657 m->from = src;
659 m->ndr = ndr_pull_init_blob(packet, m);
660 if (m->ndr == NULL) goto failed;
662 m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
664 ndr_err = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
665 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
667 if (m->header.flags & IRPC_FLAG_REPLY) {
668 irpc_handler_reply(msg_ctx, m);
669 } else {
670 irpc_handler_request(msg_ctx, m);
672 return;
674 failed:
675 talloc_free(m);
680 destroy a irpc request
682 static int irpc_destructor(struct irpc_request *irpc)
684 if (irpc->callid != -1) {
685 idr_remove(irpc->msg_ctx->idr, irpc->callid);
686 irpc->callid = -1;
689 return 0;
693 add a string name that this irpc server can be called on
695 NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name)
697 int ret;
699 ret = server_id_db_add(msg_ctx->names, name);
700 if (ret != 0) {
701 return map_nt_error_from_unix_common(ret);
703 return NT_STATUS_OK;
707 return a list of server ids for a server name
709 NTSTATUS irpc_servers_byname(struct imessaging_context *msg_ctx,
710 TALLOC_CTX *mem_ctx, const char *name,
711 unsigned *num_servers,
712 struct server_id **servers)
714 int ret;
716 ret = server_id_db_lookup(msg_ctx->names, name, mem_ctx,
717 num_servers, servers);
718 if (ret != 0) {
719 return map_nt_error_from_unix_common(ret);
721 return NT_STATUS_OK;
724 static int all_servers_func(const char *name, unsigned num_servers,
725 const struct server_id *servers,
726 void *private_data)
728 struct irpc_name_records *name_records = talloc_get_type(
729 private_data, struct irpc_name_records);
730 struct irpc_name_record *name_record;
731 uint32_t i;
733 name_records->names
734 = talloc_realloc(name_records, name_records->names,
735 struct irpc_name_record *, name_records->num_records+1);
736 if (!name_records->names) {
737 return -1;
740 name_records->names[name_records->num_records] = name_record
741 = talloc(name_records->names,
742 struct irpc_name_record);
743 if (!name_record) {
744 return -1;
747 name_records->num_records++;
749 name_record->name = talloc_strdup(name_record, name);
750 if (!name_record->name) {
751 return -1;
754 name_record->count = num_servers;
755 name_record->ids = talloc_array(name_record, struct server_id,
756 num_servers);
757 if (name_record->ids == NULL) {
758 return -1;
760 for (i=0;i<name_record->count;i++) {
761 name_record->ids[i] = servers[i];
763 return 0;
767 return a list of server ids for a server name
769 struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx,
770 TALLOC_CTX *mem_ctx)
772 int ret;
773 struct irpc_name_records *name_records = talloc_zero(mem_ctx, struct irpc_name_records);
774 if (name_records == NULL) {
775 return NULL;
778 ret = server_id_db_traverse_read(msg_ctx->names, all_servers_func,
779 name_records);
780 if (ret == -1) {
781 TALLOC_FREE(name_records);
782 return NULL;
785 return name_records;
789 remove a name from a messaging context
791 void irpc_remove_name(struct imessaging_context *msg_ctx, const char *name)
793 server_id_db_remove(msg_ctx->names, name);
796 struct server_id imessaging_get_server_id(struct imessaging_context *msg_ctx)
798 return msg_ctx->server_id;
801 struct irpc_bh_state {
802 struct imessaging_context *msg_ctx;
803 struct server_id server_id;
804 const struct ndr_interface_table *table;
805 uint32_t timeout;
806 struct security_token *token;
809 static bool irpc_bh_is_connected(struct dcerpc_binding_handle *h)
811 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
812 struct irpc_bh_state);
814 if (!hs->msg_ctx) {
815 return false;
818 return true;
821 static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle *h,
822 uint32_t timeout)
824 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
825 struct irpc_bh_state);
826 uint32_t old = hs->timeout;
828 hs->timeout = timeout;
830 return old;
833 struct irpc_bh_raw_call_state {
834 struct irpc_request *irpc;
835 uint32_t opnum;
836 DATA_BLOB in_data;
837 DATA_BLOB in_packet;
838 DATA_BLOB out_data;
841 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
842 struct irpc_message *m);
844 static struct tevent_req *irpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
845 struct tevent_context *ev,
846 struct dcerpc_binding_handle *h,
847 const struct GUID *object,
848 uint32_t opnum,
849 uint32_t in_flags,
850 const uint8_t *in_data,
851 size_t in_length)
853 struct irpc_bh_state *hs =
854 dcerpc_binding_handle_data(h,
855 struct irpc_bh_state);
856 struct tevent_req *req;
857 struct irpc_bh_raw_call_state *state;
858 bool ok;
859 struct irpc_header header;
860 struct ndr_push *ndr;
861 NTSTATUS status;
862 enum ndr_err_code ndr_err;
864 req = tevent_req_create(mem_ctx, &state,
865 struct irpc_bh_raw_call_state);
866 if (req == NULL) {
867 return NULL;
869 state->opnum = opnum;
870 state->in_data.data = discard_const_p(uint8_t, in_data);
871 state->in_data.length = in_length;
873 ok = irpc_bh_is_connected(h);
874 if (!ok) {
875 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
876 return tevent_req_post(req, ev);
879 state->irpc = talloc_zero(state, struct irpc_request);
880 if (tevent_req_nomem(state->irpc, req)) {
881 return tevent_req_post(req, ev);
884 state->irpc->msg_ctx = hs->msg_ctx;
885 state->irpc->callid = idr_get_new(hs->msg_ctx->idr,
886 state->irpc, UINT16_MAX);
887 if (state->irpc->callid == -1) {
888 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
889 return tevent_req_post(req, ev);
891 state->irpc->incoming.handler = irpc_bh_raw_call_incoming_handler;
892 state->irpc->incoming.private_data = req;
894 talloc_set_destructor(state->irpc, irpc_destructor);
896 /* setup the header */
897 header.uuid = hs->table->syntax_id.uuid;
899 header.if_version = hs->table->syntax_id.if_version;
900 header.callid = state->irpc->callid;
901 header.callnum = state->opnum;
902 header.flags = 0;
903 header.status = NT_STATUS_OK;
904 header.creds.token= hs->token;
906 /* construct the irpc packet */
907 ndr = ndr_push_init_ctx(state->irpc);
908 if (tevent_req_nomem(ndr, req)) {
909 return tevent_req_post(req, ev);
912 ndr_err = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
913 status = ndr_map_error2ntstatus(ndr_err);
914 if (!NT_STATUS_IS_OK(status)) {
915 tevent_req_nterror(req, status);
916 return tevent_req_post(req, ev);
919 ndr_err = ndr_push_bytes(ndr, in_data, in_length);
920 status = ndr_map_error2ntstatus(ndr_err);
921 if (!NT_STATUS_IS_OK(status)) {
922 tevent_req_nterror(req, status);
923 return tevent_req_post(req, ev);
926 /* and send it */
927 state->in_packet = ndr_push_blob(ndr);
928 status = imessaging_send(hs->msg_ctx, hs->server_id,
929 MSG_IRPC, &state->in_packet);
930 if (!NT_STATUS_IS_OK(status)) {
931 tevent_req_nterror(req, status);
932 return tevent_req_post(req, ev);
935 if (hs->timeout != IRPC_CALL_TIMEOUT_INF) {
936 /* set timeout-callback in case caller wants that */
937 ok = tevent_req_set_endtime(req, ev, timeval_current_ofs(hs->timeout, 0));
938 if (!ok) {
939 return tevent_req_post(req, ev);
943 return req;
946 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
947 struct irpc_message *m)
949 struct tevent_req *req =
950 talloc_get_type_abort(irpc->incoming.private_data,
951 struct tevent_req);
952 struct irpc_bh_raw_call_state *state =
953 tevent_req_data(req,
954 struct irpc_bh_raw_call_state);
956 talloc_steal(state, m);
958 if (!NT_STATUS_IS_OK(m->header.status)) {
959 tevent_req_nterror(req, m->header.status);
960 return;
963 state->out_data = data_blob_talloc(state,
964 m->ndr->data + m->ndr->offset,
965 m->ndr->data_size - m->ndr->offset);
966 if ((m->ndr->data_size - m->ndr->offset) > 0 && !state->out_data.data) {
967 tevent_req_oom(req);
968 return;
971 tevent_req_done(req);
974 static NTSTATUS irpc_bh_raw_call_recv(struct tevent_req *req,
975 TALLOC_CTX *mem_ctx,
976 uint8_t **out_data,
977 size_t *out_length,
978 uint32_t *out_flags)
980 struct irpc_bh_raw_call_state *state =
981 tevent_req_data(req,
982 struct irpc_bh_raw_call_state);
983 NTSTATUS status;
985 if (tevent_req_is_nterror(req, &status)) {
986 tevent_req_received(req);
987 return status;
990 *out_data = talloc_move(mem_ctx, &state->out_data.data);
991 *out_length = state->out_data.length;
992 *out_flags = 0;
993 tevent_req_received(req);
994 return NT_STATUS_OK;
997 struct irpc_bh_disconnect_state {
998 uint8_t _dummy;
1001 static struct tevent_req *irpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
1002 struct tevent_context *ev,
1003 struct dcerpc_binding_handle *h)
1005 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
1006 struct irpc_bh_state);
1007 struct tevent_req *req;
1008 struct irpc_bh_disconnect_state *state;
1009 bool ok;
1011 req = tevent_req_create(mem_ctx, &state,
1012 struct irpc_bh_disconnect_state);
1013 if (req == NULL) {
1014 return NULL;
1017 ok = irpc_bh_is_connected(h);
1018 if (!ok) {
1019 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1020 return tevent_req_post(req, ev);
1023 hs->msg_ctx = NULL;
1025 tevent_req_done(req);
1026 return tevent_req_post(req, ev);
1029 static NTSTATUS irpc_bh_disconnect_recv(struct tevent_req *req)
1031 NTSTATUS status;
1033 if (tevent_req_is_nterror(req, &status)) {
1034 tevent_req_received(req);
1035 return status;
1038 tevent_req_received(req);
1039 return NT_STATUS_OK;
1042 static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
1044 return true;
1047 static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
1048 .name = "wbint",
1049 .is_connected = irpc_bh_is_connected,
1050 .set_timeout = irpc_bh_set_timeout,
1051 .raw_call_send = irpc_bh_raw_call_send,
1052 .raw_call_recv = irpc_bh_raw_call_recv,
1053 .disconnect_send = irpc_bh_disconnect_send,
1054 .disconnect_recv = irpc_bh_disconnect_recv,
1056 .ref_alloc = irpc_bh_ref_alloc,
1059 /* initialise a irpc binding handle */
1060 struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
1061 struct imessaging_context *msg_ctx,
1062 struct server_id server_id,
1063 const struct ndr_interface_table *table)
1065 struct dcerpc_binding_handle *h;
1066 struct irpc_bh_state *hs;
1068 h = dcerpc_binding_handle_create(mem_ctx,
1069 &irpc_bh_ops,
1070 NULL,
1071 table,
1072 &hs,
1073 struct irpc_bh_state,
1074 __location__);
1075 if (h == NULL) {
1076 return NULL;
1078 hs->msg_ctx = msg_ctx;
1079 hs->server_id = server_id;
1080 hs->table = table;
1081 hs->timeout = IRPC_CALL_TIMEOUT;
1083 return h;
1086 struct dcerpc_binding_handle *irpc_binding_handle_by_name(TALLOC_CTX *mem_ctx,
1087 struct imessaging_context *msg_ctx,
1088 const char *dest_task,
1089 const struct ndr_interface_table *table)
1091 struct dcerpc_binding_handle *h;
1092 unsigned num_sids;
1093 struct server_id *sids;
1094 struct server_id sid;
1095 NTSTATUS status;
1097 /* find the server task */
1099 status = irpc_servers_byname(msg_ctx, mem_ctx, dest_task,
1100 &num_sids, &sids);
1101 if (!NT_STATUS_IS_OK(status)) {
1102 errno = EADDRNOTAVAIL;
1103 return NULL;
1105 sid = sids[0];
1106 talloc_free(sids);
1108 h = irpc_binding_handle(mem_ctx, msg_ctx,
1109 sid, table);
1110 if (h == NULL) {
1111 return NULL;
1114 return h;
1117 void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle *h,
1118 struct security_token *token)
1120 struct irpc_bh_state *hs =
1121 dcerpc_binding_handle_data(h,
1122 struct irpc_bh_state);
1124 hs->token = token;