selftest: add save.env.sh helper script.
[Samba.git] / source4 / lib / messaging / messaging.c
blob0fc180be2a454257a990d8024d2d7667f74a9cea
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 int 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 priv = root_privileges();
259 ret = messaging_dgm_send(pid, iov, num_iov, NULL, 0);
260 TALLOC_FREE(priv);
261 if (ret != 0) {
262 return map_nt_error_from_unix_common(ret);
264 return NT_STATUS_OK;
268 Send a message to a particular server, with the message containing a single pointer
270 NTSTATUS imessaging_send_ptr(struct imessaging_context *msg, struct server_id server,
271 uint32_t msg_type, void *ptr)
273 DATA_BLOB blob;
275 blob.data = (uint8_t *)&ptr;
276 blob.length = sizeof(void *);
278 return imessaging_send(msg, server, msg_type, &blob);
283 remove our messaging socket and database entry
285 int imessaging_cleanup(struct imessaging_context *msg)
287 if (!msg) {
288 return 0;
290 return 0;
293 static void imessaging_dgm_recv(const uint8_t *buf, size_t buf_len,
294 int *fds, size_t num_fds,
295 void *private_data);
298 create the listening socket and setup the dispatcher
300 use auto_remove=true when you want a destructor to remove the
301 associated messaging socket and database entry on talloc free. Don't
302 use this in processes that may fork and a child may talloc free this
303 memory
305 struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
306 struct loadparm_context *lp_ctx,
307 struct server_id server_id,
308 struct tevent_context *ev,
309 bool auto_remove)
311 struct imessaging_context *msg;
312 bool ok;
313 int ret;
314 const char *lock_dir = NULL;
315 int tdb_flags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST;
317 if (ev == NULL) {
318 return NULL;
321 msg = talloc_zero(mem_ctx, struct imessaging_context);
322 if (msg == NULL) {
323 return NULL;
326 /* create the messaging directory if needed */
328 lock_dir = lpcfg_lock_directory(lp_ctx);
329 if (lock_dir == NULL) {
330 goto fail;
333 msg->sock_dir = lpcfg_private_path(msg, lp_ctx, "msg.sock");
334 if (msg->sock_dir == NULL) {
335 goto fail;
337 ok = directory_create_or_exist_strict(msg->sock_dir, geteuid(), 0700);
338 if (!ok) {
339 goto fail;
342 msg->lock_dir = lpcfg_lock_path(msg, lp_ctx, "msg.lock");
343 if (msg->lock_dir == NULL) {
344 goto fail;
346 ok = directory_create_or_exist_strict(msg->lock_dir, geteuid(), 0755);
347 if (!ok) {
348 goto fail;
351 msg->msg_dgm_ref = messaging_dgm_ref(
352 msg, ev, &server_id.unique_id, msg->sock_dir, msg->lock_dir,
353 imessaging_dgm_recv, msg, &ret);
355 if (msg->msg_dgm_ref == NULL) {
356 goto fail;
359 msg->server_id = server_id;
360 msg->idr = idr_init(msg);
361 if (msg->idr == NULL) {
362 goto fail;
365 msg->dispatch_tree = idr_init(msg);
366 if (msg->dispatch_tree == NULL) {
367 goto fail;
370 msg->start_time = timeval_current();
372 tdb_flags |= lpcfg_tdb_flags(lp_ctx, 0);
374 msg->names = server_id_db_init(msg, server_id, lock_dir, 0, tdb_flags);
375 if (msg->names == NULL) {
376 goto fail;
379 if (auto_remove) {
380 talloc_set_destructor(msg, imessaging_cleanup);
383 imessaging_register(msg, NULL, MSG_PING, ping_message);
384 imessaging_register(msg, NULL, MSG_REQ_POOL_USAGE, pool_message);
385 imessaging_register(msg, NULL, MSG_IRPC, irpc_handler);
386 IRPC_REGISTER(msg, irpc, IRPC_UPTIME, irpc_uptime, msg);
388 return msg;
389 fail:
390 talloc_free(msg);
391 return NULL;
394 static void imessaging_dgm_recv(const uint8_t *buf, size_t buf_len,
395 int *fds, size_t num_fds,
396 void *private_data)
398 struct imessaging_context *msg = talloc_get_type_abort(
399 private_data, struct imessaging_context);
400 uint32_t msg_type;
401 struct server_id src, dst;
402 struct server_id_buf srcbuf, dstbuf;
403 DATA_BLOB data;
405 if (buf_len < MESSAGE_HDR_LENGTH) {
406 /* Invalid message, ignore */
407 return;
410 message_hdr_get(&msg_type, &src, &dst, buf);
412 data.data = discard_const_p(uint8_t, buf + MESSAGE_HDR_LENGTH);
413 data.length = buf_len - MESSAGE_HDR_LENGTH;
415 if ((cluster_id_equal(&dst, &msg->server_id)) ||
416 ((dst.task_id == 0) && (msg->server_id.pid == 0))) {
417 struct dispatch_fn *d, *next;
419 DEBUG(10, ("%s: dst %s matches my id: %s, type=0x%x\n",
420 __func__,
421 server_id_str_buf(dst, &dstbuf),
422 server_id_str_buf(msg->server_id, &srcbuf),
423 (unsigned)msg_type));
425 d = imessaging_find_dispatch(msg, msg_type);
427 for (; d; d = next) {
428 next = d->next;
429 d->fn(msg, d->private_data, d->msg_type, src, &data);
431 } else {
432 DEBUG(10, ("%s: Ignoring type=0x%x dst %s, I am %s, \n",
433 __func__, (unsigned)msg_type,
434 server_id_str_buf(dst, &dstbuf),
435 server_id_str_buf(msg->server_id, &srcbuf)));
440 A hack, for the short term until we get 'client only' messaging in place
442 struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
443 struct loadparm_context *lp_ctx,
444 struct tevent_context *ev)
446 struct server_id id;
447 ZERO_STRUCT(id);
448 id.pid = getpid();
449 id.task_id = generate_random();
450 id.vnn = NONCLUSTER_VNN;
452 /* This is because we are not in the s3 serverid database */
453 id.unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
455 return imessaging_init(mem_ctx, lp_ctx, id, ev, true);
458 a list of registered irpc server functions
460 struct irpc_list {
461 struct irpc_list *next, *prev;
462 struct GUID uuid;
463 const struct ndr_interface_table *table;
464 int callnum;
465 irpc_function_t fn;
466 void *private_data;
471 register a irpc server function
473 NTSTATUS irpc_register(struct imessaging_context *msg_ctx,
474 const struct ndr_interface_table *table,
475 int callnum, irpc_function_t fn, void *private_data)
477 struct irpc_list *irpc;
479 /* override an existing handler, if any */
480 for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
481 if (irpc->table == table && irpc->callnum == callnum) {
482 break;
485 if (irpc == NULL) {
486 irpc = talloc(msg_ctx, struct irpc_list);
487 NT_STATUS_HAVE_NO_MEMORY(irpc);
488 DLIST_ADD(msg_ctx->irpc, irpc);
491 irpc->table = table;
492 irpc->callnum = callnum;
493 irpc->fn = fn;
494 irpc->private_data = private_data;
495 irpc->uuid = irpc->table->syntax_id.uuid;
497 return NT_STATUS_OK;
502 handle an incoming irpc reply message
504 static void irpc_handler_reply(struct imessaging_context *msg_ctx, struct irpc_message *m)
506 struct irpc_request *irpc;
508 irpc = (struct irpc_request *)idr_find(msg_ctx->idr, m->header.callid);
509 if (irpc == NULL) return;
511 irpc->incoming.handler(irpc, m);
515 send a irpc reply
517 NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
519 struct ndr_push *push;
520 DATA_BLOB packet;
521 enum ndr_err_code ndr_err;
523 m->header.status = status;
525 /* setup the reply */
526 push = ndr_push_init_ctx(m->ndr);
527 if (push == NULL) {
528 status = NT_STATUS_NO_MEMORY;
529 goto failed;
532 m->header.flags |= IRPC_FLAG_REPLY;
533 m->header.creds.token= NULL;
535 /* construct the packet */
536 ndr_err = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
537 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
538 status = ndr_map_error2ntstatus(ndr_err);
539 goto failed;
542 ndr_err = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
543 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
544 status = ndr_map_error2ntstatus(ndr_err);
545 goto failed;
548 /* send the reply message */
549 packet = ndr_push_blob(push);
550 status = imessaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
551 if (!NT_STATUS_IS_OK(status)) goto failed;
553 failed:
554 talloc_free(m);
555 return status;
559 handle an incoming irpc request message
561 static void irpc_handler_request(struct imessaging_context *msg_ctx,
562 struct irpc_message *m)
564 struct irpc_list *i;
565 void *r;
566 enum ndr_err_code ndr_err;
568 for (i=msg_ctx->irpc; i; i=i->next) {
569 if (GUID_equal(&i->uuid, &m->header.uuid) &&
570 i->table->syntax_id.if_version == m->header.if_version &&
571 i->callnum == m->header.callnum) {
572 break;
576 if (i == NULL) {
577 /* no registered handler for this message */
578 talloc_free(m);
579 return;
582 /* allocate space for the structure */
583 r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
584 if (r == NULL) goto failed;
586 m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
588 /* parse the request data */
589 ndr_err = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
590 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
592 /* make the call */
593 m->private_data= i->private_data;
594 m->defer_reply = false;
595 m->no_reply = false;
596 m->msg_ctx = msg_ctx;
597 m->irpc = i;
598 m->data = r;
600 m->header.status = i->fn(m, r);
602 if (m->no_reply) {
603 /* the server function won't ever be replying to this request */
604 talloc_free(m);
605 return;
608 if (m->defer_reply) {
609 /* the server function has asked to defer the reply to later */
610 talloc_steal(msg_ctx, m);
611 return;
614 irpc_send_reply(m, m->header.status);
615 return;
617 failed:
618 talloc_free(m);
622 handle an incoming irpc message
624 static void irpc_handler(struct imessaging_context *msg_ctx, void *private_data,
625 uint32_t msg_type, struct server_id src, DATA_BLOB *packet)
627 struct irpc_message *m;
628 enum ndr_err_code ndr_err;
630 m = talloc(msg_ctx, struct irpc_message);
631 if (m == NULL) goto failed;
633 m->from = src;
635 m->ndr = ndr_pull_init_blob(packet, m);
636 if (m->ndr == NULL) goto failed;
638 m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
640 ndr_err = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
641 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
643 if (m->header.flags & IRPC_FLAG_REPLY) {
644 irpc_handler_reply(msg_ctx, m);
645 } else {
646 irpc_handler_request(msg_ctx, m);
648 return;
650 failed:
651 talloc_free(m);
656 destroy a irpc request
658 static int irpc_destructor(struct irpc_request *irpc)
660 if (irpc->callid != -1) {
661 idr_remove(irpc->msg_ctx->idr, irpc->callid);
662 irpc->callid = -1;
665 return 0;
669 add a string name that this irpc server can be called on
671 NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name)
673 int ret;
675 ret = server_id_db_add(msg_ctx->names, name);
676 if (ret != 0) {
677 return map_nt_error_from_unix_common(ret);
679 return NT_STATUS_OK;
683 return a list of server ids for a server name
685 NTSTATUS irpc_servers_byname(struct imessaging_context *msg_ctx,
686 TALLOC_CTX *mem_ctx, const char *name,
687 unsigned *num_servers,
688 struct server_id **servers)
690 int ret;
692 ret = server_id_db_lookup(msg_ctx->names, name, mem_ctx,
693 num_servers, servers);
694 if (ret != 0) {
695 return map_nt_error_from_unix_common(ret);
697 return NT_STATUS_OK;
700 static int all_servers_func(const char *name, unsigned num_servers,
701 const struct server_id *servers,
702 void *private_data)
704 struct irpc_name_records *name_records = talloc_get_type(
705 private_data, struct irpc_name_records);
706 struct irpc_name_record *name_record;
707 int i;
709 name_records->names
710 = talloc_realloc(name_records, name_records->names,
711 struct irpc_name_record *, name_records->num_records+1);
712 if (!name_records->names) {
713 return -1;
716 name_records->names[name_records->num_records] = name_record
717 = talloc(name_records->names,
718 struct irpc_name_record);
719 if (!name_record) {
720 return -1;
723 name_records->num_records++;
725 name_record->name = talloc_strdup(name_record, name);
726 if (!name_record->name) {
727 return -1;
730 name_record->count = num_servers;
731 name_record->ids = talloc_array(name_record, struct server_id,
732 num_servers);
733 if (name_record->ids == NULL) {
734 return -1;
736 for (i=0;i<name_record->count;i++) {
737 name_record->ids[i] = servers[i];
739 return 0;
743 return a list of server ids for a server name
745 struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx,
746 TALLOC_CTX *mem_ctx)
748 int ret;
749 struct irpc_name_records *name_records = talloc_zero(mem_ctx, struct irpc_name_records);
750 if (name_records == NULL) {
751 return NULL;
754 ret = server_id_db_traverse_read(msg_ctx->names, all_servers_func,
755 name_records);
756 if (ret == -1) {
757 TALLOC_FREE(name_records);
758 return NULL;
761 return name_records;
765 remove a name from a messaging context
767 void irpc_remove_name(struct imessaging_context *msg_ctx, const char *name)
769 server_id_db_remove(msg_ctx->names, name);
772 struct server_id imessaging_get_server_id(struct imessaging_context *msg_ctx)
774 return msg_ctx->server_id;
777 struct irpc_bh_state {
778 struct imessaging_context *msg_ctx;
779 struct server_id server_id;
780 const struct ndr_interface_table *table;
781 uint32_t timeout;
782 struct security_token *token;
785 static bool irpc_bh_is_connected(struct dcerpc_binding_handle *h)
787 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
788 struct irpc_bh_state);
790 if (!hs->msg_ctx) {
791 return false;
794 return true;
797 static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle *h,
798 uint32_t timeout)
800 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
801 struct irpc_bh_state);
802 uint32_t old = hs->timeout;
804 hs->timeout = timeout;
806 return old;
809 struct irpc_bh_raw_call_state {
810 struct irpc_request *irpc;
811 uint32_t opnum;
812 DATA_BLOB in_data;
813 DATA_BLOB in_packet;
814 DATA_BLOB out_data;
817 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
818 struct irpc_message *m);
820 static struct tevent_req *irpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
821 struct tevent_context *ev,
822 struct dcerpc_binding_handle *h,
823 const struct GUID *object,
824 uint32_t opnum,
825 uint32_t in_flags,
826 const uint8_t *in_data,
827 size_t in_length)
829 struct irpc_bh_state *hs =
830 dcerpc_binding_handle_data(h,
831 struct irpc_bh_state);
832 struct tevent_req *req;
833 struct irpc_bh_raw_call_state *state;
834 bool ok;
835 struct irpc_header header;
836 struct ndr_push *ndr;
837 NTSTATUS status;
838 enum ndr_err_code ndr_err;
840 req = tevent_req_create(mem_ctx, &state,
841 struct irpc_bh_raw_call_state);
842 if (req == NULL) {
843 return NULL;
845 state->opnum = opnum;
846 state->in_data.data = discard_const_p(uint8_t, in_data);
847 state->in_data.length = in_length;
849 ok = irpc_bh_is_connected(h);
850 if (!ok) {
851 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
852 return tevent_req_post(req, ev);
855 state->irpc = talloc_zero(state, struct irpc_request);
856 if (tevent_req_nomem(state->irpc, req)) {
857 return tevent_req_post(req, ev);
860 state->irpc->msg_ctx = hs->msg_ctx;
861 state->irpc->callid = idr_get_new(hs->msg_ctx->idr,
862 state->irpc, UINT16_MAX);
863 if (state->irpc->callid == -1) {
864 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
865 return tevent_req_post(req, ev);
867 state->irpc->incoming.handler = irpc_bh_raw_call_incoming_handler;
868 state->irpc->incoming.private_data = req;
870 talloc_set_destructor(state->irpc, irpc_destructor);
872 /* setup the header */
873 header.uuid = hs->table->syntax_id.uuid;
875 header.if_version = hs->table->syntax_id.if_version;
876 header.callid = state->irpc->callid;
877 header.callnum = state->opnum;
878 header.flags = 0;
879 header.status = NT_STATUS_OK;
880 header.creds.token= hs->token;
882 /* construct the irpc packet */
883 ndr = ndr_push_init_ctx(state->irpc);
884 if (tevent_req_nomem(ndr, req)) {
885 return tevent_req_post(req, ev);
888 ndr_err = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
889 status = ndr_map_error2ntstatus(ndr_err);
890 if (!NT_STATUS_IS_OK(status)) {
891 tevent_req_nterror(req, status);
892 return tevent_req_post(req, ev);
895 ndr_err = ndr_push_bytes(ndr, in_data, in_length);
896 status = ndr_map_error2ntstatus(ndr_err);
897 if (!NT_STATUS_IS_OK(status)) {
898 tevent_req_nterror(req, status);
899 return tevent_req_post(req, ev);
902 /* and send it */
903 state->in_packet = ndr_push_blob(ndr);
904 status = imessaging_send(hs->msg_ctx, hs->server_id,
905 MSG_IRPC, &state->in_packet);
906 if (!NT_STATUS_IS_OK(status)) {
907 tevent_req_nterror(req, status);
908 return tevent_req_post(req, ev);
911 if (hs->timeout != IRPC_CALL_TIMEOUT_INF) {
912 /* set timeout-callback in case caller wants that */
913 ok = tevent_req_set_endtime(req, ev, timeval_current_ofs(hs->timeout, 0));
914 if (!ok) {
915 return tevent_req_post(req, ev);
919 return req;
922 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
923 struct irpc_message *m)
925 struct tevent_req *req =
926 talloc_get_type_abort(irpc->incoming.private_data,
927 struct tevent_req);
928 struct irpc_bh_raw_call_state *state =
929 tevent_req_data(req,
930 struct irpc_bh_raw_call_state);
932 talloc_steal(state, m);
934 if (!NT_STATUS_IS_OK(m->header.status)) {
935 tevent_req_nterror(req, m->header.status);
936 return;
939 state->out_data = data_blob_talloc(state,
940 m->ndr->data + m->ndr->offset,
941 m->ndr->data_size - m->ndr->offset);
942 if ((m->ndr->data_size - m->ndr->offset) > 0 && !state->out_data.data) {
943 tevent_req_oom(req);
944 return;
947 tevent_req_done(req);
950 static NTSTATUS irpc_bh_raw_call_recv(struct tevent_req *req,
951 TALLOC_CTX *mem_ctx,
952 uint8_t **out_data,
953 size_t *out_length,
954 uint32_t *out_flags)
956 struct irpc_bh_raw_call_state *state =
957 tevent_req_data(req,
958 struct irpc_bh_raw_call_state);
959 NTSTATUS status;
961 if (tevent_req_is_nterror(req, &status)) {
962 tevent_req_received(req);
963 return status;
966 *out_data = talloc_move(mem_ctx, &state->out_data.data);
967 *out_length = state->out_data.length;
968 *out_flags = 0;
969 tevent_req_received(req);
970 return NT_STATUS_OK;
973 struct irpc_bh_disconnect_state {
974 uint8_t _dummy;
977 static struct tevent_req *irpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
978 struct tevent_context *ev,
979 struct dcerpc_binding_handle *h)
981 struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
982 struct irpc_bh_state);
983 struct tevent_req *req;
984 struct irpc_bh_disconnect_state *state;
985 bool ok;
987 req = tevent_req_create(mem_ctx, &state,
988 struct irpc_bh_disconnect_state);
989 if (req == NULL) {
990 return NULL;
993 ok = irpc_bh_is_connected(h);
994 if (!ok) {
995 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
996 return tevent_req_post(req, ev);
999 hs->msg_ctx = NULL;
1001 tevent_req_done(req);
1002 return tevent_req_post(req, ev);
1005 static NTSTATUS irpc_bh_disconnect_recv(struct tevent_req *req)
1007 NTSTATUS status;
1009 if (tevent_req_is_nterror(req, &status)) {
1010 tevent_req_received(req);
1011 return status;
1014 tevent_req_received(req);
1015 return NT_STATUS_OK;
1018 static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
1020 return true;
1023 static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
1024 .name = "wbint",
1025 .is_connected = irpc_bh_is_connected,
1026 .set_timeout = irpc_bh_set_timeout,
1027 .raw_call_send = irpc_bh_raw_call_send,
1028 .raw_call_recv = irpc_bh_raw_call_recv,
1029 .disconnect_send = irpc_bh_disconnect_send,
1030 .disconnect_recv = irpc_bh_disconnect_recv,
1032 .ref_alloc = irpc_bh_ref_alloc,
1035 /* initialise a irpc binding handle */
1036 struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
1037 struct imessaging_context *msg_ctx,
1038 struct server_id server_id,
1039 const struct ndr_interface_table *table)
1041 struct dcerpc_binding_handle *h;
1042 struct irpc_bh_state *hs;
1044 h = dcerpc_binding_handle_create(mem_ctx,
1045 &irpc_bh_ops,
1046 NULL,
1047 table,
1048 &hs,
1049 struct irpc_bh_state,
1050 __location__);
1051 if (h == NULL) {
1052 return NULL;
1054 hs->msg_ctx = msg_ctx;
1055 hs->server_id = server_id;
1056 hs->table = table;
1057 hs->timeout = IRPC_CALL_TIMEOUT;
1059 return h;
1062 struct dcerpc_binding_handle *irpc_binding_handle_by_name(TALLOC_CTX *mem_ctx,
1063 struct imessaging_context *msg_ctx,
1064 const char *dest_task,
1065 const struct ndr_interface_table *table)
1067 struct dcerpc_binding_handle *h;
1068 unsigned num_sids;
1069 struct server_id *sids;
1070 struct server_id sid;
1071 NTSTATUS status;
1073 /* find the server task */
1075 status = irpc_servers_byname(msg_ctx, mem_ctx, dest_task,
1076 &num_sids, &sids);
1077 if (!NT_STATUS_IS_OK(status)) {
1078 errno = EADDRNOTAVAIL;
1079 return NULL;
1081 sid = sids[0];
1082 talloc_free(sids);
1084 h = irpc_binding_handle(mem_ctx, msg_ctx,
1085 sid, table);
1086 if (h == NULL) {
1087 return NULL;
1090 return h;
1093 void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle *h,
1094 struct security_token *token)
1096 struct irpc_bh_state *hs =
1097 dcerpc_binding_handle_data(h,
1098 struct irpc_bh_state);
1100 hs->token = token;