s4: messaging. Minor cleanup. Check for error returns on imessaging_register calls.
[kai/samba-autobuild/.git] / source4 / lib / messaging / messaging.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Samba internal messaging functions
5
6    Copyright (C) Andrew Tridgell 2004
7
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.
12
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.
17
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/>.
20 */
21
22 #include "includes.h"
23 #include "lib/events/events.h"
24 #include "lib/util/server_id.h"
25 #include "system/filesys.h"
26 #include "messaging/messaging.h"
27 #include "messaging/messaging_internal.h"
28 #include "../lib/util/dlinklist.h"
29 #include "lib/socket/socket.h"
30 #include "librpc/gen_ndr/ndr_irpc.h"
31 #include "lib/messaging/irpc.h"
32 #include "../lib/util/unix_privs.h"
33 #include "librpc/rpc/dcerpc.h"
34 #include "cluster/cluster.h"
35 #include "../lib/util/tevent_ntstatus.h"
36 #include "lib/param/param.h"
37 #include "lib/util/server_id_db.h"
38 #include "lib/util/talloc_report.h"
39 #include "../source3/lib/messages_dgm.h"
40 #include "../source3/lib/messages_dgm_ref.h"
41 #include "../source3/lib/messages_util.h"
42 #include <tdb.h>
43
44 /* change the message version with any incompatible changes in the protocol */
45 #define IMESSAGING_VERSION 1
46
47 /*
48   a pending irpc call
49 */
50 struct irpc_request {
51         struct imessaging_context *msg_ctx;
52         int callid;
53         struct {
54                 void (*handler)(struct irpc_request *irpc, struct irpc_message *m);
55                 void *private_data;
56         } incoming;
57 };
58
59 /* we have a linked list of dispatch handlers for each msg_type that
60    this messaging server can deal with */
61 struct dispatch_fn {
62         struct dispatch_fn *next, *prev;
63         uint32_t msg_type;
64         void *private_data;
65         msg_callback_t fn;
66 };
67
68 /* an individual message */
69
70 static void irpc_handler(struct imessaging_context *, void *,
71                          uint32_t, struct server_id, DATA_BLOB *);
72
73
74 /*
75  A useful function for testing the message system.
76 */
77 static void ping_message(struct imessaging_context *msg, void *private_data,
78                          uint32_t msg_type, struct server_id src, DATA_BLOB *data)
79 {
80         struct server_id_buf idbuf;
81         DEBUG(1,("INFO: Received PING message from server %s [%.*s]\n",
82                  server_id_str_buf(src, &idbuf), (int)data->length,
83                  data->data?(const char *)data->data:""));
84         imessaging_send(msg, src, MSG_PONG, data);
85 }
86
87 static void pool_message(struct imessaging_context *msg, void *private_data,
88                          uint32_t msg_type, struct server_id src,
89                          DATA_BLOB *data)
90 {
91         char *report;
92
93         report = talloc_report_str(msg, NULL);
94
95         if (report != NULL) {
96                 DATA_BLOB blob = { .data = (uint8_t *)report,
97                                    .length = talloc_get_size(report) - 1};
98                 imessaging_send(msg, src, MSG_POOL_USAGE, &blob);
99         }
100         talloc_free(report);
101 }
102
103 static void ringbuf_log_msg(struct imessaging_context *msg,
104                             void *private_data,
105                             uint32_t msg_type,
106                             struct server_id src,
107                             DATA_BLOB *data)
108 {
109         char *log = debug_get_ringbuf();
110         size_t logsize = debug_get_ringbuf_size();
111         DATA_BLOB blob;
112
113         if (log == NULL) {
114                 log = discard_const_p(char, "*disabled*\n");
115                 logsize = strlen(log) + 1;
116         }
117
118         blob.data = (uint8_t *)log;
119         blob.length = logsize;
120
121         imessaging_send(msg, src, MSG_RINGBUF_LOG, &blob);
122 }
123
124 /*
125   return uptime of messaging server via irpc
126 */
127 static NTSTATUS irpc_uptime(struct irpc_message *msg,
128                             struct irpc_uptime *r)
129 {
130         struct imessaging_context *ctx = talloc_get_type(msg->private_data, struct imessaging_context);
131         *r->out.start_time = timeval_to_nttime(&ctx->start_time);
132         return NT_STATUS_OK;
133 }
134
135 static struct dispatch_fn *imessaging_find_dispatch(
136         struct imessaging_context *msg, uint32_t msg_type)
137 {
138         /* temporary IDs use an idtree, the rest use a array of pointers */
139         if (msg_type >= MSG_TMP_BASE) {
140                 return (struct dispatch_fn *)idr_find(msg->dispatch_tree,
141                                                       msg_type);
142         }
143         if (msg_type < msg->num_types) {
144                 return msg->dispatch[msg_type];
145         }
146         return NULL;
147 }
148
149 /*
150   Register a dispatch function for a particular message type.
151 */
152 NTSTATUS imessaging_register(struct imessaging_context *msg, void *private_data,
153                             uint32_t msg_type, msg_callback_t fn)
154 {
155         struct dispatch_fn *d;
156
157         /* possibly expand dispatch array */
158         if (msg_type >= msg->num_types) {
159                 struct dispatch_fn **dp;
160                 uint32_t i;
161                 dp = talloc_realloc(msg, msg->dispatch, struct dispatch_fn *, msg_type+1);
162                 NT_STATUS_HAVE_NO_MEMORY(dp);
163                 msg->dispatch = dp;
164                 for (i=msg->num_types;i<=msg_type;i++) {
165                         msg->dispatch[i] = NULL;
166                 }
167                 msg->num_types = msg_type+1;
168         }
169
170         d = talloc_zero(msg->dispatch, struct dispatch_fn);
171         NT_STATUS_HAVE_NO_MEMORY(d);
172         d->msg_type = msg_type;
173         d->private_data = private_data;
174         d->fn = fn;
175
176         DLIST_ADD(msg->dispatch[msg_type], d);
177
178         return NT_STATUS_OK;
179 }
180
181 /*
182   register a temporary message handler. The msg_type is allocated
183   above MSG_TMP_BASE
184 */
185 NTSTATUS imessaging_register_tmp(struct imessaging_context *msg, void *private_data,
186                                 msg_callback_t fn, uint32_t *msg_type)
187 {
188         struct dispatch_fn *d;
189         int id;
190
191         d = talloc_zero(msg->dispatch, struct dispatch_fn);
192         NT_STATUS_HAVE_NO_MEMORY(d);
193         d->private_data = private_data;
194         d->fn = fn;
195
196         id = idr_get_new_above(msg->dispatch_tree, d, MSG_TMP_BASE, UINT16_MAX);
197         if (id == -1) {
198                 talloc_free(d);
199                 return NT_STATUS_TOO_MANY_CONTEXT_IDS;
200         }
201
202         d->msg_type = (uint32_t)id;
203         (*msg_type) = d->msg_type;
204
205         return NT_STATUS_OK;
206 }
207
208 /*
209   De-register the function for a particular message type.
210 */
211 void imessaging_deregister(struct imessaging_context *msg, uint32_t msg_type, void *private_data)
212 {
213         struct dispatch_fn *d, *next;
214
215         if (msg_type >= msg->num_types) {
216                 d = (struct dispatch_fn *)idr_find(msg->dispatch_tree,
217                                                    msg_type);
218                 if (!d) return;
219                 idr_remove(msg->dispatch_tree, msg_type);
220                 talloc_free(d);
221                 return;
222         }
223
224         for (d = msg->dispatch[msg_type]; d; d = next) {
225                 next = d->next;
226                 if (d->private_data == private_data) {
227                         DLIST_REMOVE(msg->dispatch[msg_type], d);
228                         talloc_free(d);
229                 }
230         }
231 }
232
233 /*
234 */
235 int imessaging_cleanup(struct imessaging_context *msg)
236 {
237         if (!msg) {
238                 return 0;
239         }
240         return 0;
241 }
242
243 static void imessaging_dgm_recv(struct tevent_context *ev,
244                                 const uint8_t *buf, size_t buf_len,
245                                 int *fds, size_t num_fds,
246                                 void *private_data);
247
248 /* Keep a list of imessaging contexts */
249 static struct imessaging_context *msg_ctxs;
250
251 static int imessaging_context_destructor(struct imessaging_context *msg)
252 {
253         DLIST_REMOVE(msg_ctxs, msg);
254         TALLOC_FREE(msg->msg_dgm_ref);
255         return 0;
256 }
257
258 /*
259  * Cleanup messaging dgm contexts
260  *
261  * We must make sure to unref all messaging_dgm_ref's *before* the
262  * tevent context goes away. Only when the last ref is freed, the
263  * refcounted messaging dgm context will be freed.
264  */
265 void imessaging_dgm_unref_all(void)
266 {
267         struct imessaging_context *msg = NULL;
268
269         for (msg = msg_ctxs; msg != NULL; msg = msg->next) {
270                 TALLOC_FREE(msg->msg_dgm_ref);
271         }
272 }
273
274 static NTSTATUS imessaging_reinit(struct imessaging_context *msg)
275 {
276         int ret = -1;
277
278         TALLOC_FREE(msg->msg_dgm_ref);
279
280         msg->server_id.pid = getpid();
281
282         msg->msg_dgm_ref = messaging_dgm_ref(msg,
283                                 msg->ev,
284                                 &msg->server_id.unique_id,
285                                 msg->sock_dir,
286                                 msg->lock_dir,
287                                 imessaging_dgm_recv,
288                                 msg,
289                                 &ret);
290
291         if (msg->msg_dgm_ref == NULL) {
292                 DEBUG(2, ("messaging_dgm_ref failed: %s\n",
293                         strerror(ret)));
294                 return map_nt_error_from_unix_common(ret);
295         }
296
297         server_id_db_reinit(msg->names, msg->server_id);
298         return NT_STATUS_OK;
299 }
300
301 /*
302  * Must be called after a fork.
303  */
304 NTSTATUS imessaging_reinit_all(void)
305 {
306         struct imessaging_context *msg = NULL;
307
308         for (msg = msg_ctxs; msg != NULL; msg = msg->next) {
309                 NTSTATUS status = imessaging_reinit(msg);
310                 if (!NT_STATUS_IS_OK(status)) {
311                         return status;
312                 }
313         }
314         return NT_STATUS_OK;
315 }
316
317 /*
318   create the listening socket and setup the dispatcher
319 */
320 struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
321                                            struct loadparm_context *lp_ctx,
322                                            struct server_id server_id,
323                                            struct tevent_context *ev)
324 {
325         NTSTATUS status;
326         struct imessaging_context *msg;
327         bool ok;
328         int ret;
329         const char *lock_dir = NULL;
330         int tdb_flags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST;
331
332         if (ev == NULL) {
333                 return NULL;
334         }
335
336         msg = talloc_zero(mem_ctx, struct imessaging_context);
337         if (msg == NULL) {
338                 return NULL;
339         }
340         msg->ev = ev;
341
342         talloc_set_destructor(msg, imessaging_context_destructor);
343
344         /* create the messaging directory if needed */
345
346         lock_dir = lpcfg_lock_directory(lp_ctx);
347         if (lock_dir == NULL) {
348                 goto fail;
349         }
350
351         msg->sock_dir = lpcfg_private_path(msg, lp_ctx, "msg.sock");
352         if (msg->sock_dir == NULL) {
353                 goto fail;
354         }
355         ok = directory_create_or_exist_strict(msg->sock_dir, geteuid(), 0700);
356         if (!ok) {
357                 goto fail;
358         }
359
360         msg->lock_dir = lpcfg_lock_path(msg, lp_ctx, "msg.lock");
361         if (msg->lock_dir == NULL) {
362                 goto fail;
363         }
364         ok = directory_create_or_exist_strict(msg->lock_dir, geteuid(), 0755);
365         if (!ok) {
366                 goto fail;
367         }
368
369         msg->msg_dgm_ref = messaging_dgm_ref(
370                 msg, ev, &server_id.unique_id, msg->sock_dir, msg->lock_dir,
371                 imessaging_dgm_recv, msg, &ret);
372
373         if (msg->msg_dgm_ref == NULL) {
374                 goto fail;
375         }
376
377         msg->server_id     = server_id;
378         msg->idr           = idr_init(msg);
379         if (msg->idr == NULL) {
380                 goto fail;
381         }
382
383         msg->dispatch_tree = idr_init(msg);
384         if (msg->dispatch_tree == NULL) {
385                 goto fail;
386         }
387
388         msg->start_time    = timeval_current();
389
390         tdb_flags |= lpcfg_tdb_flags(lp_ctx, 0);
391
392         msg->names = server_id_db_init(msg, server_id, lock_dir, 0, tdb_flags);
393         if (msg->names == NULL) {
394                 goto fail;
395         }
396
397         status = imessaging_register(msg, NULL, MSG_PING, ping_message);
398         if (!NT_STATUS_IS_OK(status)) {
399                 goto fail;
400         }
401         status = imessaging_register(msg, NULL, MSG_REQ_POOL_USAGE,
402                                      pool_message);
403         if (!NT_STATUS_IS_OK(status)) {
404                 goto fail;
405         }
406         status = imessaging_register(msg, NULL, MSG_IRPC, irpc_handler);
407         if (!NT_STATUS_IS_OK(status)) {
408                 goto fail;
409         }
410         status = imessaging_register(msg, NULL, MSG_REQ_RINGBUF_LOG,
411                                      ringbuf_log_msg);
412         if (!NT_STATUS_IS_OK(status)) {
413                 goto fail;
414         }
415         status = IRPC_REGISTER(msg, irpc, IRPC_UPTIME, irpc_uptime, msg);
416         if (!NT_STATUS_IS_OK(status)) {
417                 goto fail;
418         }
419
420         DLIST_ADD(msg_ctxs, msg);
421
422         return msg;
423 fail:
424         talloc_free(msg);
425         return NULL;
426 }
427
428 struct imessaging_post_state {
429         struct imessaging_context *msg_ctx;
430         size_t buf_len;
431         uint8_t buf[];
432 };
433
434 static void imessaging_post_handler(struct tevent_context *ev,
435                                     struct tevent_immediate *ti,
436                                     void *private_data)
437 {
438         struct imessaging_post_state *state = talloc_get_type_abort(
439                 private_data, struct imessaging_post_state);
440         imessaging_dgm_recv(ev, state->buf, state->buf_len, NULL, 0,
441                             state->msg_ctx);
442         TALLOC_FREE(state);
443 }
444
445 static int imessaging_post_self(struct imessaging_context *msg,
446                                 const uint8_t *buf, size_t buf_len)
447 {
448         struct tevent_immediate *ti;
449         struct imessaging_post_state *state;
450
451         state = talloc_size(
452                 msg, offsetof(struct imessaging_post_state, buf) + buf_len);
453         if (state == NULL) {
454                 return ENOMEM;
455         }
456         talloc_set_name_const(state, "struct imessaging_post_state");
457
458         ti = tevent_create_immediate(state);
459         if (ti == NULL) {
460                 TALLOC_FREE(state);
461                 return ENOMEM;
462         }
463
464         state->msg_ctx = msg;
465         state->buf_len = buf_len;
466         memcpy(state->buf, buf, buf_len);
467
468         tevent_schedule_immediate(ti, msg->ev, imessaging_post_handler,
469                                   state);
470
471         return 0;
472 }
473
474 static void imessaging_dgm_recv(struct tevent_context *ev,
475                                 const uint8_t *buf, size_t buf_len,
476                                 int *fds, size_t num_fds,
477                                 void *private_data)
478 {
479         struct imessaging_context *msg = talloc_get_type_abort(
480                 private_data, struct imessaging_context);
481         uint32_t msg_type;
482         struct server_id src, dst;
483         struct server_id_buf srcbuf, dstbuf;
484         DATA_BLOB data;
485
486         if (buf_len < MESSAGE_HDR_LENGTH) {
487                 /* Invalid message, ignore */
488                 return;
489         }
490
491         if (num_fds != 0) {
492                 /*
493                  * Source4 based messaging does not expect fd's yet
494                  */
495                 return;
496         }
497
498         if (ev != msg->ev) {
499                 int ret;
500                 ret = imessaging_post_self(msg, buf, buf_len);
501                 if (ret != 0) {
502                         DBG_WARNING("imessaging_post_self failed: %s\n",
503                                     strerror(ret));
504                 }
505                 return;
506         }
507
508         message_hdr_get(&msg_type, &src, &dst, buf);
509
510         data.data = discard_const_p(uint8_t, buf + MESSAGE_HDR_LENGTH);
511         data.length = buf_len - MESSAGE_HDR_LENGTH;
512
513         if ((cluster_id_equal(&dst, &msg->server_id)) ||
514             ((dst.task_id == 0) && (msg->server_id.pid == 0))) {
515                 struct dispatch_fn *d, *next;
516
517                 DEBUG(10, ("%s: dst %s matches my id: %s, type=0x%x\n",
518                            __func__,
519                            server_id_str_buf(dst, &dstbuf),
520                            server_id_str_buf(msg->server_id, &srcbuf),
521                            (unsigned)msg_type));
522
523                 d = imessaging_find_dispatch(msg, msg_type);
524
525                 for (; d; d = next) {
526                         next = d->next;
527                         d->fn(msg, d->private_data, d->msg_type, src, &data);
528                 }
529         } else {
530                 DEBUG(10, ("%s: Ignoring type=0x%x dst %s, I am %s, \n",
531                            __func__, (unsigned)msg_type,
532                            server_id_str_buf(dst, &dstbuf),
533                            server_id_str_buf(msg->server_id, &srcbuf)));
534         }
535 }
536
537 /*
538    A hack, for the short term until we get 'client only' messaging in place
539 */
540 struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
541                                                   struct loadparm_context *lp_ctx,
542                                                 struct tevent_context *ev)
543 {
544         struct server_id id;
545         ZERO_STRUCT(id);
546         id.pid = getpid();
547         id.task_id = generate_random();
548         id.vnn = NONCLUSTER_VNN;
549
550         /* This is because we are not in the s3 serverid database */
551         id.unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
552
553         return imessaging_init(mem_ctx, lp_ctx, id, ev);
554 }
555 /*
556   a list of registered irpc server functions
557 */
558 struct irpc_list {
559         struct irpc_list *next, *prev;
560         struct GUID uuid;
561         const struct ndr_interface_table *table;
562         int callnum;
563         irpc_function_t fn;
564         void *private_data;
565 };
566
567
568 /*
569   register a irpc server function
570 */
571 NTSTATUS irpc_register(struct imessaging_context *msg_ctx,
572                        const struct ndr_interface_table *table,
573                        int callnum, irpc_function_t fn, void *private_data)
574 {
575         struct irpc_list *irpc;
576
577         /* override an existing handler, if any */
578         for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
579                 if (irpc->table == table && irpc->callnum == callnum) {
580                         break;
581                 }
582         }
583         if (irpc == NULL) {
584                 irpc = talloc(msg_ctx, struct irpc_list);
585                 NT_STATUS_HAVE_NO_MEMORY(irpc);
586                 DLIST_ADD(msg_ctx->irpc, irpc);
587         }
588
589         irpc->table   = table;
590         irpc->callnum = callnum;
591         irpc->fn      = fn;
592         irpc->private_data = private_data;
593         irpc->uuid = irpc->table->syntax_id.uuid;
594
595         return NT_STATUS_OK;
596 }
597
598
599 /*
600   handle an incoming irpc reply message
601 */
602 static void irpc_handler_reply(struct imessaging_context *msg_ctx, struct irpc_message *m)
603 {
604         struct irpc_request *irpc;
605
606         irpc = (struct irpc_request *)idr_find(msg_ctx->idr, m->header.callid);
607         if (irpc == NULL) return;
608
609         irpc->incoming.handler(irpc, m);
610 }
611
612 /*
613   send a irpc reply
614 */
615 NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
616 {
617         struct ndr_push *push;
618         DATA_BLOB packet;
619         enum ndr_err_code ndr_err;
620
621         m->header.status = status;
622
623         /* setup the reply */
624         push = ndr_push_init_ctx(m->ndr);
625         if (push == NULL) {
626                 status = NT_STATUS_NO_MEMORY;
627                 goto failed;
628         }
629
630         m->header.flags |= IRPC_FLAG_REPLY;
631         m->header.creds.token= NULL;
632
633         /* construct the packet */
634         ndr_err = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
635         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
636                 status = ndr_map_error2ntstatus(ndr_err);
637                 goto failed;
638         }
639
640         ndr_err = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
641         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
642                 status = ndr_map_error2ntstatus(ndr_err);
643                 goto failed;
644         }
645
646         /* send the reply message */
647         packet = ndr_push_blob(push);
648         status = imessaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
649         if (!NT_STATUS_IS_OK(status)) goto failed;
650
651 failed:
652         talloc_free(m);
653         return status;
654 }
655
656 /*
657   handle an incoming irpc request message
658 */
659 static void irpc_handler_request(struct imessaging_context *msg_ctx,
660                                  struct irpc_message *m)
661 {
662         struct irpc_list *i;
663         void *r;
664         enum ndr_err_code ndr_err;
665
666         for (i=msg_ctx->irpc; i; i=i->next) {
667                 if (GUID_equal(&i->uuid, &m->header.uuid) &&
668                     i->table->syntax_id.if_version == m->header.if_version &&
669                     i->callnum == m->header.callnum) {
670                         break;
671                 }
672         }
673
674         if (i == NULL) {
675                 /* no registered handler for this message */
676                 talloc_free(m);
677                 return;
678         }
679
680         /* allocate space for the structure */
681         r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
682         if (r == NULL) goto failed;
683
684         m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
685
686         /* parse the request data */
687         ndr_err = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
688         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
689
690         /* make the call */
691         m->private_data= i->private_data;
692         m->defer_reply = false;
693         m->no_reply    = false;
694         m->msg_ctx     = msg_ctx;
695         m->irpc        = i;
696         m->data        = r;
697
698         m->header.status = i->fn(m, r);
699
700         if (m->no_reply) {
701                 /* the server function won't ever be replying to this request */
702                 talloc_free(m);
703                 return;
704         }
705
706         if (m->defer_reply) {
707                 /* the server function has asked to defer the reply to later */
708                 talloc_steal(msg_ctx, m);
709                 return;
710         }
711
712         irpc_send_reply(m, m->header.status);
713         return;
714
715 failed:
716         talloc_free(m);
717 }
718
719 /*
720   handle an incoming irpc message
721 */
722 static void irpc_handler(struct imessaging_context *msg_ctx, void *private_data,
723                          uint32_t msg_type, struct server_id src, DATA_BLOB *packet)
724 {
725         struct irpc_message *m;
726         enum ndr_err_code ndr_err;
727
728         m = talloc(msg_ctx, struct irpc_message);
729         if (m == NULL) goto failed;
730
731         m->from = src;
732
733         m->ndr = ndr_pull_init_blob(packet, m);
734         if (m->ndr == NULL) goto failed;
735
736         m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
737
738         ndr_err = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
739         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
740
741         if (m->header.flags & IRPC_FLAG_REPLY) {
742                 irpc_handler_reply(msg_ctx, m);
743         } else {
744                 irpc_handler_request(msg_ctx, m);
745         }
746         return;
747
748 failed:
749         talloc_free(m);
750 }
751
752
753 /*
754   destroy a irpc request
755 */
756 static int irpc_destructor(struct irpc_request *irpc)
757 {
758         if (irpc->callid != -1) {
759                 idr_remove(irpc->msg_ctx->idr, irpc->callid);
760                 irpc->callid = -1;
761         }
762
763         return 0;
764 }
765
766 /*
767   add a string name that this irpc server can be called on
768 */
769 NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name)
770 {
771         int ret;
772
773         ret = server_id_db_add(msg_ctx->names, name);
774         if (ret != 0) {
775                 return map_nt_error_from_unix_common(ret);
776         }
777         return NT_STATUS_OK;
778 }
779
780 static int all_servers_func(const char *name, unsigned num_servers,
781                             const struct server_id *servers,
782                             void *private_data)
783 {
784         struct irpc_name_records *name_records = talloc_get_type(
785                 private_data, struct irpc_name_records);
786         struct irpc_name_record *name_record;
787         uint32_t i;
788
789         name_records->names
790                 = talloc_realloc(name_records, name_records->names,
791                                  struct irpc_name_record *, name_records->num_records+1);
792         if (!name_records->names) {
793                 return -1;
794         }
795
796         name_records->names[name_records->num_records] = name_record
797                 = talloc(name_records->names,
798                          struct irpc_name_record);
799         if (!name_record) {
800                 return -1;
801         }
802
803         name_records->num_records++;
804
805         name_record->name = talloc_strdup(name_record, name);
806         if (!name_record->name) {
807                 return -1;
808         }
809
810         name_record->count = num_servers;
811         name_record->ids = talloc_array(name_record, struct server_id,
812                                         num_servers);
813         if (name_record->ids == NULL) {
814                 return -1;
815         }
816         for (i=0;i<name_record->count;i++) {
817                 name_record->ids[i] = servers[i];
818         }
819         return 0;
820 }
821
822 /*
823   return a list of server ids for a server name
824 */
825 struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx,
826                                            TALLOC_CTX *mem_ctx)
827 {
828         int ret;
829         struct irpc_name_records *name_records = talloc_zero(mem_ctx, struct irpc_name_records);
830         if (name_records == NULL) {
831                 return NULL;
832         }
833
834         ret = server_id_db_traverse_read(msg_ctx->names, all_servers_func,
835                                          name_records);
836         if (ret == -1) {
837                 TALLOC_FREE(name_records);
838                 return NULL;
839         }
840
841         return name_records;
842 }
843
844 /*
845   remove a name from a messaging context
846 */
847 void irpc_remove_name(struct imessaging_context *msg_ctx, const char *name)
848 {
849         server_id_db_remove(msg_ctx->names, name);
850 }
851
852 struct server_id imessaging_get_server_id(struct imessaging_context *msg_ctx)
853 {
854         return msg_ctx->server_id;
855 }
856
857 struct irpc_bh_state {
858         struct imessaging_context *msg_ctx;
859         struct server_id server_id;
860         const struct ndr_interface_table *table;
861         uint32_t timeout;
862         struct security_token *token;
863 };
864
865 static bool irpc_bh_is_connected(struct dcerpc_binding_handle *h)
866 {
867         struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
868                                    struct irpc_bh_state);
869
870         if (!hs->msg_ctx) {
871                 return false;
872         }
873
874         return true;
875 }
876
877 static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle *h,
878                                     uint32_t timeout)
879 {
880         struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
881                                    struct irpc_bh_state);
882         uint32_t old = hs->timeout;
883
884         hs->timeout = timeout;
885
886         return old;
887 }
888
889 struct irpc_bh_raw_call_state {
890         struct irpc_request *irpc;
891         uint32_t opnum;
892         DATA_BLOB in_data;
893         DATA_BLOB in_packet;
894         DATA_BLOB out_data;
895 };
896
897 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
898                                               struct irpc_message *m);
899
900 static struct tevent_req *irpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
901                                                 struct tevent_context *ev,
902                                                 struct dcerpc_binding_handle *h,
903                                                 const struct GUID *object,
904                                                 uint32_t opnum,
905                                                 uint32_t in_flags,
906                                                 const uint8_t *in_data,
907                                                 size_t in_length)
908 {
909         struct irpc_bh_state *hs =
910                 dcerpc_binding_handle_data(h,
911                 struct irpc_bh_state);
912         struct tevent_req *req;
913         struct irpc_bh_raw_call_state *state;
914         bool ok;
915         struct irpc_header header;
916         struct ndr_push *ndr;
917         NTSTATUS status;
918         enum ndr_err_code ndr_err;
919
920         req = tevent_req_create(mem_ctx, &state,
921                                 struct irpc_bh_raw_call_state);
922         if (req == NULL) {
923                 return NULL;
924         }
925         state->opnum = opnum;
926         state->in_data.data = discard_const_p(uint8_t, in_data);
927         state->in_data.length = in_length;
928
929         ok = irpc_bh_is_connected(h);
930         if (!ok) {
931                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
932                 return tevent_req_post(req, ev);
933         }
934
935         state->irpc = talloc_zero(state, struct irpc_request);
936         if (tevent_req_nomem(state->irpc, req)) {
937                 return tevent_req_post(req, ev);
938         }
939
940         state->irpc->msg_ctx  = hs->msg_ctx;
941         state->irpc->callid   = idr_get_new(hs->msg_ctx->idr,
942                                             state->irpc, UINT16_MAX);
943         if (state->irpc->callid == -1) {
944                 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
945                 return tevent_req_post(req, ev);
946         }
947         state->irpc->incoming.handler = irpc_bh_raw_call_incoming_handler;
948         state->irpc->incoming.private_data = req;
949
950         talloc_set_destructor(state->irpc, irpc_destructor);
951
952         /* setup the header */
953         header.uuid = hs->table->syntax_id.uuid;
954
955         header.if_version = hs->table->syntax_id.if_version;
956         header.callid     = state->irpc->callid;
957         header.callnum    = state->opnum;
958         header.flags      = 0;
959         header.status     = NT_STATUS_OK;
960         header.creds.token= hs->token;
961
962         /* construct the irpc packet */
963         ndr = ndr_push_init_ctx(state->irpc);
964         if (tevent_req_nomem(ndr, req)) {
965                 return tevent_req_post(req, ev);
966         }
967
968         ndr_err = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
969         status = ndr_map_error2ntstatus(ndr_err);
970         if (!NT_STATUS_IS_OK(status)) {
971                 tevent_req_nterror(req, status);
972                 return tevent_req_post(req, ev);
973         }
974
975         ndr_err = ndr_push_bytes(ndr, in_data, in_length);
976         status = ndr_map_error2ntstatus(ndr_err);
977         if (!NT_STATUS_IS_OK(status)) {
978                 tevent_req_nterror(req, status);
979                 return tevent_req_post(req, ev);
980         }
981
982         /* and send it */
983         state->in_packet = ndr_push_blob(ndr);
984         status = imessaging_send(hs->msg_ctx, hs->server_id,
985                                 MSG_IRPC, &state->in_packet);
986         if (!NT_STATUS_IS_OK(status)) {
987                 tevent_req_nterror(req, status);
988                 return tevent_req_post(req, ev);
989         }
990
991         if (hs->timeout != IRPC_CALL_TIMEOUT_INF) {
992                 /* set timeout-callback in case caller wants that */
993                 ok = tevent_req_set_endtime(req, ev, timeval_current_ofs(hs->timeout, 0));
994                 if (!ok) {
995                         return tevent_req_post(req, ev);
996                 }
997         }
998
999         return req;
1000 }
1001
1002 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
1003                                               struct irpc_message *m)
1004 {
1005         struct tevent_req *req =
1006                 talloc_get_type_abort(irpc->incoming.private_data,
1007                 struct tevent_req);
1008         struct irpc_bh_raw_call_state *state =
1009                 tevent_req_data(req,
1010                 struct irpc_bh_raw_call_state);
1011
1012         talloc_steal(state, m);
1013
1014         if (!NT_STATUS_IS_OK(m->header.status)) {
1015                 tevent_req_nterror(req, m->header.status);
1016                 return;
1017         }
1018
1019         state->out_data = data_blob_talloc(state,
1020                 m->ndr->data + m->ndr->offset,
1021                 m->ndr->data_size - m->ndr->offset);
1022         if ((m->ndr->data_size - m->ndr->offset) > 0 && !state->out_data.data) {
1023                 tevent_req_oom(req);
1024                 return;
1025         }
1026
1027         tevent_req_done(req);
1028 }
1029
1030 static NTSTATUS irpc_bh_raw_call_recv(struct tevent_req *req,
1031                                         TALLOC_CTX *mem_ctx,
1032                                         uint8_t **out_data,
1033                                         size_t *out_length,
1034                                         uint32_t *out_flags)
1035 {
1036         struct irpc_bh_raw_call_state *state =
1037                 tevent_req_data(req,
1038                 struct irpc_bh_raw_call_state);
1039         NTSTATUS status;
1040
1041         if (tevent_req_is_nterror(req, &status)) {
1042                 tevent_req_received(req);
1043                 return status;
1044         }
1045
1046         *out_data = talloc_move(mem_ctx, &state->out_data.data);
1047         *out_length = state->out_data.length;
1048         *out_flags = 0;
1049         tevent_req_received(req);
1050         return NT_STATUS_OK;
1051 }
1052
1053 struct irpc_bh_disconnect_state {
1054         uint8_t _dummy;
1055 };
1056
1057 static struct tevent_req *irpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
1058                                                 struct tevent_context *ev,
1059                                                 struct dcerpc_binding_handle *h)
1060 {
1061         struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
1062                                      struct irpc_bh_state);
1063         struct tevent_req *req;
1064         struct irpc_bh_disconnect_state *state;
1065         bool ok;
1066
1067         req = tevent_req_create(mem_ctx, &state,
1068                                 struct irpc_bh_disconnect_state);
1069         if (req == NULL) {
1070                 return NULL;
1071         }
1072
1073         ok = irpc_bh_is_connected(h);
1074         if (!ok) {
1075                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1076                 return tevent_req_post(req, ev);
1077         }
1078
1079         hs->msg_ctx = NULL;
1080
1081         tevent_req_done(req);
1082         return tevent_req_post(req, ev);
1083 }
1084
1085 static NTSTATUS irpc_bh_disconnect_recv(struct tevent_req *req)
1086 {
1087         NTSTATUS status;
1088
1089         if (tevent_req_is_nterror(req, &status)) {
1090                 tevent_req_received(req);
1091                 return status;
1092         }
1093
1094         tevent_req_received(req);
1095         return NT_STATUS_OK;
1096 }
1097
1098 static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
1099 {
1100         return true;
1101 }
1102
1103 static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
1104         .name                   = "wbint",
1105         .is_connected           = irpc_bh_is_connected,
1106         .set_timeout            = irpc_bh_set_timeout,
1107         .raw_call_send          = irpc_bh_raw_call_send,
1108         .raw_call_recv          = irpc_bh_raw_call_recv,
1109         .disconnect_send        = irpc_bh_disconnect_send,
1110         .disconnect_recv        = irpc_bh_disconnect_recv,
1111
1112         .ref_alloc              = irpc_bh_ref_alloc,
1113 };
1114
1115 /* initialise a irpc binding handle */
1116 struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
1117                                                   struct imessaging_context *msg_ctx,
1118                                                   struct server_id server_id,
1119                                                   const struct ndr_interface_table *table)
1120 {
1121         struct dcerpc_binding_handle *h;
1122         struct irpc_bh_state *hs;
1123
1124         h = dcerpc_binding_handle_create(mem_ctx,
1125                                          &irpc_bh_ops,
1126                                          NULL,
1127                                          table,
1128                                          &hs,
1129                                          struct irpc_bh_state,
1130                                          __location__);
1131         if (h == NULL) {
1132                 return NULL;
1133         }
1134         hs->msg_ctx = msg_ctx;
1135         hs->server_id = server_id;
1136         hs->table = table;
1137         hs->timeout = IRPC_CALL_TIMEOUT;
1138
1139         return h;
1140 }
1141
1142 struct dcerpc_binding_handle *irpc_binding_handle_by_name(TALLOC_CTX *mem_ctx,
1143                                                           struct imessaging_context *msg_ctx,
1144                                                           const char *dest_task,
1145                                                           const struct ndr_interface_table *table)
1146 {
1147         struct dcerpc_binding_handle *h;
1148         unsigned num_sids;
1149         struct server_id *sids;
1150         struct server_id sid;
1151         NTSTATUS status;
1152
1153         /* find the server task */
1154
1155         status = irpc_servers_byname(msg_ctx, mem_ctx, dest_task,
1156                                      &num_sids, &sids);
1157         if (!NT_STATUS_IS_OK(status)) {
1158                 errno = EADDRNOTAVAIL;
1159                 return NULL;
1160         }
1161         sid = sids[0];
1162         talloc_free(sids);
1163
1164         h = irpc_binding_handle(mem_ctx, msg_ctx,
1165                                 sid, table);
1166         if (h == NULL) {
1167                 return NULL;
1168         }
1169
1170         return h;
1171 }
1172
1173 void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle *h,
1174                                             struct security_token *token)
1175 {
1176         struct irpc_bh_state *hs =
1177                 dcerpc_binding_handle_data(h,
1178                 struct irpc_bh_state);
1179
1180         hs->token = token;
1181 }