935951f3fbae075b1324b1f15c80c8b6935663a6
[samba.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 on a specific event context.
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_ev(struct tevent_context *ev)
266 {
267         struct imessaging_context *msg = NULL;
268
269         for (msg = msg_ctxs; msg != NULL; msg = msg->next) {
270                 if (msg->ev == ev) {
271                         TALLOC_FREE(msg->msg_dgm_ref);
272                 }
273         }
274 }
275
276 static NTSTATUS imessaging_reinit(struct imessaging_context *msg)
277 {
278         int ret = -1;
279
280         TALLOC_FREE(msg->msg_dgm_ref);
281
282         msg->server_id.pid = getpid();
283
284         msg->msg_dgm_ref = messaging_dgm_ref(msg,
285                                 msg->ev,
286                                 &msg->server_id.unique_id,
287                                 msg->sock_dir,
288                                 msg->lock_dir,
289                                 imessaging_dgm_recv,
290                                 msg,
291                                 &ret);
292
293         if (msg->msg_dgm_ref == NULL) {
294                 DEBUG(2, ("messaging_dgm_ref failed: %s\n",
295                         strerror(ret)));
296                 return map_nt_error_from_unix_common(ret);
297         }
298
299         server_id_db_reinit(msg->names, msg->server_id);
300         return NT_STATUS_OK;
301 }
302
303 /*
304  * Must be called after a fork.
305  */
306 NTSTATUS imessaging_reinit_all(void)
307 {
308         struct imessaging_context *msg = NULL;
309
310         for (msg = msg_ctxs; msg != NULL; msg = msg->next) {
311                 NTSTATUS status = imessaging_reinit(msg);
312                 if (!NT_STATUS_IS_OK(status)) {
313                         return status;
314                 }
315         }
316         return NT_STATUS_OK;
317 }
318
319 /*
320   create the listening socket and setup the dispatcher
321 */
322 static struct imessaging_context *imessaging_init_internal(TALLOC_CTX *mem_ctx,
323                                            struct loadparm_context *lp_ctx,
324                                            struct server_id server_id,
325                                            struct tevent_context *ev)
326 {
327         NTSTATUS status;
328         struct imessaging_context *msg;
329         bool ok;
330         int ret;
331         const char *lock_dir = NULL;
332         int tdb_flags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST;
333
334         if (ev == NULL) {
335                 return NULL;
336         }
337
338         msg = talloc_zero(mem_ctx, struct imessaging_context);
339         if (msg == NULL) {
340                 return NULL;
341         }
342         msg->ev = ev;
343
344         talloc_set_destructor(msg, imessaging_context_destructor);
345
346         /* create the messaging directory if needed */
347
348         lock_dir = lpcfg_lock_directory(lp_ctx);
349         if (lock_dir == NULL) {
350                 goto fail;
351         }
352
353         msg->sock_dir = lpcfg_private_path(msg, lp_ctx, "msg.sock");
354         if (msg->sock_dir == NULL) {
355                 goto fail;
356         }
357         ok = directory_create_or_exist_strict(msg->sock_dir, geteuid(), 0700);
358         if (!ok) {
359                 goto fail;
360         }
361
362         msg->lock_dir = lpcfg_lock_path(msg, lp_ctx, "msg.lock");
363         if (msg->lock_dir == NULL) {
364                 goto fail;
365         }
366         ok = directory_create_or_exist_strict(msg->lock_dir, geteuid(), 0755);
367         if (!ok) {
368                 goto fail;
369         }
370
371         msg->msg_dgm_ref = messaging_dgm_ref(
372                 msg, ev, &server_id.unique_id, msg->sock_dir, msg->lock_dir,
373                 imessaging_dgm_recv, msg, &ret);
374
375         if (msg->msg_dgm_ref == NULL) {
376                 goto fail;
377         }
378
379         msg->server_id     = server_id;
380         msg->idr           = idr_init(msg);
381         if (msg->idr == NULL) {
382                 goto fail;
383         }
384
385         msg->dispatch_tree = idr_init(msg);
386         if (msg->dispatch_tree == NULL) {
387                 goto fail;
388         }
389
390         msg->start_time    = timeval_current();
391
392         tdb_flags |= lpcfg_tdb_flags(lp_ctx, 0);
393
394         /*
395          * This context holds a destructor that cleans up any names
396          * registered on this context on talloc_free()
397          */
398         msg->names = server_id_db_init(msg, server_id, lock_dir, 0, tdb_flags);
399         if (msg->names == NULL) {
400                 goto fail;
401         }
402
403         status = imessaging_register(msg, NULL, MSG_PING, ping_message);
404         if (!NT_STATUS_IS_OK(status)) {
405                 goto fail;
406         }
407         status = imessaging_register(msg, NULL, MSG_REQ_POOL_USAGE,
408                                      pool_message);
409         if (!NT_STATUS_IS_OK(status)) {
410                 goto fail;
411         }
412         status = imessaging_register(msg, NULL, MSG_IRPC, irpc_handler);
413         if (!NT_STATUS_IS_OK(status)) {
414                 goto fail;
415         }
416         status = imessaging_register(msg, NULL, MSG_REQ_RINGBUF_LOG,
417                                      ringbuf_log_msg);
418         if (!NT_STATUS_IS_OK(status)) {
419                 goto fail;
420         }
421         status = IRPC_REGISTER(msg, irpc, IRPC_UPTIME, irpc_uptime, msg);
422         if (!NT_STATUS_IS_OK(status)) {
423                 goto fail;
424         }
425
426         DLIST_ADD(msg_ctxs, msg);
427
428         return msg;
429 fail:
430         talloc_free(msg);
431         return NULL;
432 }
433
434 struct imessaging_post_state {
435         struct imessaging_context *msg_ctx;
436         struct imessaging_post_state **busy_ref;
437         size_t buf_len;
438         uint8_t buf[];
439 };
440
441 static int imessaging_post_state_destructor(struct imessaging_post_state *state)
442 {
443         if (state->busy_ref != NULL) {
444                 *state->busy_ref = NULL;
445                 state->busy_ref = NULL;
446         }
447         return 0;
448 }
449
450 static void imessaging_post_handler(struct tevent_context *ev,
451                                     struct tevent_immediate *ti,
452                                     void *private_data)
453 {
454         struct imessaging_post_state *state = talloc_get_type_abort(
455                 private_data, struct imessaging_post_state);
456
457         /*
458          * In usecases like using messaging_client_init() with irpc processing
459          * we may free the imessaging_context during the messaging handler.
460          * imessaging_post_state is a child of imessaging_context and
461          * might be implicitly free'ed before the explicit TALLOC_FREE(state).
462          *
463          * The busy_ref pointer makes sure the destructor clears
464          * the local 'state' variable.
465          */
466
467         SMB_ASSERT(state->busy_ref == NULL);
468         state->busy_ref = &state;
469
470         imessaging_dgm_recv(ev, state->buf, state->buf_len, NULL, 0,
471                             state->msg_ctx);
472
473         if (state == NULL) {
474                 return;
475         }
476
477         state->busy_ref = NULL;
478         TALLOC_FREE(state);
479 }
480
481 static int imessaging_post_self(struct imessaging_context *msg,
482                                 const uint8_t *buf, size_t buf_len)
483 {
484         struct tevent_immediate *ti;
485         struct imessaging_post_state *state;
486
487         state = talloc_size(
488                 msg, offsetof(struct imessaging_post_state, buf) + buf_len);
489         if (state == NULL) {
490                 return ENOMEM;
491         }
492         talloc_set_name_const(state, "struct imessaging_post_state");
493
494         talloc_set_destructor(state, imessaging_post_state_destructor);
495
496         ti = tevent_create_immediate(state);
497         if (ti == NULL) {
498                 TALLOC_FREE(state);
499                 return ENOMEM;
500         }
501
502         state->msg_ctx = msg;
503         state->busy_ref = NULL;
504         state->buf_len = buf_len;
505         memcpy(state->buf, buf, buf_len);
506
507         tevent_schedule_immediate(ti, msg->ev, imessaging_post_handler,
508                                   state);
509
510         return 0;
511 }
512
513 static void imessaging_dgm_recv(struct tevent_context *ev,
514                                 const uint8_t *buf, size_t buf_len,
515                                 int *fds, size_t num_fds,
516                                 void *private_data)
517 {
518         struct imessaging_context *msg = talloc_get_type_abort(
519                 private_data, struct imessaging_context);
520         uint32_t msg_type;
521         struct server_id src, dst;
522         struct server_id_buf srcbuf, dstbuf;
523         DATA_BLOB data;
524
525         if (buf_len < MESSAGE_HDR_LENGTH) {
526                 /* Invalid message, ignore */
527                 return;
528         }
529
530         if (num_fds != 0) {
531                 /*
532                  * Source4 based messaging does not expect fd's yet
533                  */
534                 return;
535         }
536
537         if (ev != msg->ev) {
538                 int ret;
539                 ret = imessaging_post_self(msg, buf, buf_len);
540                 if (ret != 0) {
541                         DBG_WARNING("imessaging_post_self failed: %s\n",
542                                     strerror(ret));
543                 }
544                 return;
545         }
546
547         message_hdr_get(&msg_type, &src, &dst, buf);
548
549         data.data = discard_const_p(uint8_t, buf + MESSAGE_HDR_LENGTH);
550         data.length = buf_len - MESSAGE_HDR_LENGTH;
551
552         if ((cluster_id_equal(&dst, &msg->server_id)) ||
553             ((dst.task_id == 0) && (msg->server_id.pid == 0))) {
554                 struct dispatch_fn *d, *next;
555
556                 DEBUG(10, ("%s: dst %s matches my id: %s, type=0x%x\n",
557                            __func__,
558                            server_id_str_buf(dst, &dstbuf),
559                            server_id_str_buf(msg->server_id, &srcbuf),
560                            (unsigned)msg_type));
561
562                 d = imessaging_find_dispatch(msg, msg_type);
563
564                 for (; d; d = next) {
565                         next = d->next;
566                         d->fn(msg, d->private_data, d->msg_type, src, &data);
567                 }
568         } else {
569                 DEBUG(10, ("%s: Ignoring type=0x%x dst %s, I am %s, \n",
570                            __func__, (unsigned)msg_type,
571                            server_id_str_buf(dst, &dstbuf),
572                            server_id_str_buf(msg->server_id, &srcbuf)));
573         }
574 }
575
576 struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
577                                            struct loadparm_context *lp_ctx,
578                                            struct server_id server_id,
579                                            struct tevent_context *ev)
580 {
581         if (ev == NULL) {
582                 return NULL;
583         }
584
585         if (tevent_context_is_wrapper(ev)) {
586                 /*
587                  * This is really a programmer error!
588                  *
589                  * The main/raw tevent context should
590                  * have been registered first!
591                  */
592                 DBG_ERR("Should not be used with a wrapper tevent context\n");
593                 errno = EINVAL;
594                 return NULL;
595         }
596
597         return imessaging_init_internal(mem_ctx, lp_ctx, server_id, ev);
598 }
599
600 /*
601    A hack, for the short term until we get 'client only' messaging in place
602 */
603 struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
604                                                   struct loadparm_context *lp_ctx,
605                                                 struct tevent_context *ev)
606 {
607         struct server_id id;
608         ZERO_STRUCT(id);
609         id.pid = getpid();
610         id.task_id = generate_random();
611         id.vnn = NONCLUSTER_VNN;
612
613         /* This is because we are not in the s3 serverid database */
614         id.unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
615
616         return imessaging_init_internal(mem_ctx, lp_ctx, id, ev);
617 }
618 /*
619   a list of registered irpc server functions
620 */
621 struct irpc_list {
622         struct irpc_list *next, *prev;
623         struct GUID uuid;
624         const struct ndr_interface_table *table;
625         int callnum;
626         irpc_function_t fn;
627         void *private_data;
628 };
629
630
631 /*
632   register a irpc server function
633 */
634 NTSTATUS irpc_register(struct imessaging_context *msg_ctx,
635                        const struct ndr_interface_table *table,
636                        int callnum, irpc_function_t fn, void *private_data)
637 {
638         struct irpc_list *irpc;
639
640         /* override an existing handler, if any */
641         for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
642                 if (irpc->table == table && irpc->callnum == callnum) {
643                         break;
644                 }
645         }
646         if (irpc == NULL) {
647                 irpc = talloc(msg_ctx, struct irpc_list);
648                 NT_STATUS_HAVE_NO_MEMORY(irpc);
649                 DLIST_ADD(msg_ctx->irpc, irpc);
650         }
651
652         irpc->table   = table;
653         irpc->callnum = callnum;
654         irpc->fn      = fn;
655         irpc->private_data = private_data;
656         irpc->uuid = irpc->table->syntax_id.uuid;
657
658         return NT_STATUS_OK;
659 }
660
661
662 /*
663   handle an incoming irpc reply message
664 */
665 static void irpc_handler_reply(struct imessaging_context *msg_ctx, struct irpc_message *m)
666 {
667         struct irpc_request *irpc;
668
669         irpc = (struct irpc_request *)idr_find(msg_ctx->idr, m->header.callid);
670         if (irpc == NULL) return;
671
672         irpc->incoming.handler(irpc, m);
673 }
674
675 /*
676   send a irpc reply
677 */
678 NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
679 {
680         struct ndr_push *push;
681         DATA_BLOB packet;
682         enum ndr_err_code ndr_err;
683
684         m->header.status = status;
685
686         /* setup the reply */
687         push = ndr_push_init_ctx(m->ndr);
688         if (push == NULL) {
689                 status = NT_STATUS_NO_MEMORY;
690                 goto failed;
691         }
692
693         m->header.flags |= IRPC_FLAG_REPLY;
694         m->header.creds.token= NULL;
695
696         /* construct the packet */
697         ndr_err = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
698         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
699                 status = ndr_map_error2ntstatus(ndr_err);
700                 goto failed;
701         }
702
703         ndr_err = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
704         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
705                 status = ndr_map_error2ntstatus(ndr_err);
706                 goto failed;
707         }
708
709         /* send the reply message */
710         packet = ndr_push_blob(push);
711         status = imessaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
712         if (!NT_STATUS_IS_OK(status)) goto failed;
713
714 failed:
715         talloc_free(m);
716         return status;
717 }
718
719 /*
720   handle an incoming irpc request message
721 */
722 static void irpc_handler_request(struct imessaging_context *msg_ctx,
723                                  struct irpc_message *m)
724 {
725         struct irpc_list *i;
726         void *r;
727         enum ndr_err_code ndr_err;
728
729         for (i=msg_ctx->irpc; i; i=i->next) {
730                 if (GUID_equal(&i->uuid, &m->header.uuid) &&
731                     i->table->syntax_id.if_version == m->header.if_version &&
732                     i->callnum == m->header.callnum) {
733                         break;
734                 }
735         }
736
737         if (i == NULL) {
738                 /* no registered handler for this message */
739                 talloc_free(m);
740                 return;
741         }
742
743         /* allocate space for the structure */
744         r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
745         if (r == NULL) goto failed;
746
747         m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
748
749         /* parse the request data */
750         ndr_err = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
751         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
752
753         /* make the call */
754         m->private_data= i->private_data;
755         m->defer_reply = false;
756         m->no_reply    = false;
757         m->msg_ctx     = msg_ctx;
758         m->irpc        = i;
759         m->data        = r;
760
761         m->header.status = i->fn(m, r);
762
763         if (m->no_reply) {
764                 /* the server function won't ever be replying to this request */
765                 talloc_free(m);
766                 return;
767         }
768
769         if (m->defer_reply) {
770                 /* the server function has asked to defer the reply to later */
771                 talloc_steal(msg_ctx, m);
772                 return;
773         }
774
775         irpc_send_reply(m, m->header.status);
776         return;
777
778 failed:
779         talloc_free(m);
780 }
781
782 /*
783   handle an incoming irpc message
784 */
785 static void irpc_handler(struct imessaging_context *msg_ctx, void *private_data,
786                          uint32_t msg_type, struct server_id src, DATA_BLOB *packet)
787 {
788         struct irpc_message *m;
789         enum ndr_err_code ndr_err;
790
791         m = talloc(msg_ctx, struct irpc_message);
792         if (m == NULL) goto failed;
793
794         m->from = src;
795
796         m->ndr = ndr_pull_init_blob(packet, m);
797         if (m->ndr == NULL) goto failed;
798
799         m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
800
801         ndr_err = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
802         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
803
804         if (m->header.flags & IRPC_FLAG_REPLY) {
805                 irpc_handler_reply(msg_ctx, m);
806         } else {
807                 irpc_handler_request(msg_ctx, m);
808         }
809         return;
810
811 failed:
812         talloc_free(m);
813 }
814
815
816 /*
817   destroy a irpc request
818 */
819 static int irpc_destructor(struct irpc_request *irpc)
820 {
821         if (irpc->callid != -1) {
822                 idr_remove(irpc->msg_ctx->idr, irpc->callid);
823                 irpc->callid = -1;
824         }
825
826         return 0;
827 }
828
829 /*
830   add a string name that this irpc server can be called on
831
832   It will be removed from the DB either via irpc_remove_name or on
833   talloc_free(msg_ctx->names).
834 */
835 NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name)
836 {
837         int ret;
838
839         ret = server_id_db_add(msg_ctx->names, name);
840         if (ret != 0) {
841                 return map_nt_error_from_unix_common(ret);
842         }
843         return NT_STATUS_OK;
844 }
845
846 static int all_servers_func(const char *name, unsigned num_servers,
847                             const struct server_id *servers,
848                             void *private_data)
849 {
850         struct irpc_name_records *name_records = talloc_get_type(
851                 private_data, struct irpc_name_records);
852         struct irpc_name_record *name_record;
853         uint32_t i;
854
855         name_records->names
856                 = talloc_realloc(name_records, name_records->names,
857                                  struct irpc_name_record *, name_records->num_records+1);
858         if (!name_records->names) {
859                 return -1;
860         }
861
862         name_records->names[name_records->num_records] = name_record
863                 = talloc(name_records->names,
864                          struct irpc_name_record);
865         if (!name_record) {
866                 return -1;
867         }
868
869         name_records->num_records++;
870
871         name_record->name = talloc_strdup(name_record, name);
872         if (!name_record->name) {
873                 return -1;
874         }
875
876         name_record->count = num_servers;
877         name_record->ids = talloc_array(name_record, struct server_id,
878                                         num_servers);
879         if (name_record->ids == NULL) {
880                 return -1;
881         }
882         for (i=0;i<name_record->count;i++) {
883                 name_record->ids[i] = servers[i];
884         }
885         return 0;
886 }
887
888 /*
889   return a list of server ids for a server name
890 */
891 struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx,
892                                            TALLOC_CTX *mem_ctx)
893 {
894         int ret;
895         struct irpc_name_records *name_records = talloc_zero(mem_ctx, struct irpc_name_records);
896         if (name_records == NULL) {
897                 return NULL;
898         }
899
900         ret = server_id_db_traverse_read(msg_ctx->names, all_servers_func,
901                                          name_records);
902         if (ret == -1) {
903                 TALLOC_FREE(name_records);
904                 return NULL;
905         }
906
907         return name_records;
908 }
909
910 /*
911   remove a name from a messaging context
912 */
913 void irpc_remove_name(struct imessaging_context *msg_ctx, const char *name)
914 {
915         server_id_db_remove(msg_ctx->names, name);
916 }
917
918 struct server_id imessaging_get_server_id(struct imessaging_context *msg_ctx)
919 {
920         return msg_ctx->server_id;
921 }
922
923 struct irpc_bh_state {
924         struct imessaging_context *msg_ctx;
925         struct server_id server_id;
926         const struct ndr_interface_table *table;
927         uint32_t timeout;
928         struct security_token *token;
929 };
930
931 static bool irpc_bh_is_connected(struct dcerpc_binding_handle *h)
932 {
933         struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
934                                    struct irpc_bh_state);
935
936         if (!hs->msg_ctx) {
937                 return false;
938         }
939
940         return true;
941 }
942
943 static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle *h,
944                                     uint32_t timeout)
945 {
946         struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
947                                    struct irpc_bh_state);
948         uint32_t old = hs->timeout;
949
950         hs->timeout = timeout;
951
952         return old;
953 }
954
955 struct irpc_bh_raw_call_state {
956         struct irpc_request *irpc;
957         uint32_t opnum;
958         DATA_BLOB in_data;
959         DATA_BLOB in_packet;
960         DATA_BLOB out_data;
961 };
962
963 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
964                                               struct irpc_message *m);
965
966 static struct tevent_req *irpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
967                                                 struct tevent_context *ev,
968                                                 struct dcerpc_binding_handle *h,
969                                                 const struct GUID *object,
970                                                 uint32_t opnum,
971                                                 uint32_t in_flags,
972                                                 const uint8_t *in_data,
973                                                 size_t in_length)
974 {
975         struct irpc_bh_state *hs =
976                 dcerpc_binding_handle_data(h,
977                 struct irpc_bh_state);
978         struct tevent_req *req;
979         struct irpc_bh_raw_call_state *state;
980         bool ok;
981         struct irpc_header header;
982         struct ndr_push *ndr;
983         NTSTATUS status;
984         enum ndr_err_code ndr_err;
985
986         req = tevent_req_create(mem_ctx, &state,
987                                 struct irpc_bh_raw_call_state);
988         if (req == NULL) {
989                 return NULL;
990         }
991         state->opnum = opnum;
992         state->in_data.data = discard_const_p(uint8_t, in_data);
993         state->in_data.length = in_length;
994
995         ok = irpc_bh_is_connected(h);
996         if (!ok) {
997                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
998                 return tevent_req_post(req, ev);
999         }
1000
1001         state->irpc = talloc_zero(state, struct irpc_request);
1002         if (tevent_req_nomem(state->irpc, req)) {
1003                 return tevent_req_post(req, ev);
1004         }
1005
1006         state->irpc->msg_ctx  = hs->msg_ctx;
1007         state->irpc->callid   = idr_get_new(hs->msg_ctx->idr,
1008                                             state->irpc, UINT16_MAX);
1009         if (state->irpc->callid == -1) {
1010                 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1011                 return tevent_req_post(req, ev);
1012         }
1013         state->irpc->incoming.handler = irpc_bh_raw_call_incoming_handler;
1014         state->irpc->incoming.private_data = req;
1015
1016         talloc_set_destructor(state->irpc, irpc_destructor);
1017
1018         /* setup the header */
1019         header.uuid = hs->table->syntax_id.uuid;
1020
1021         header.if_version = hs->table->syntax_id.if_version;
1022         header.callid     = state->irpc->callid;
1023         header.callnum    = state->opnum;
1024         header.flags      = 0;
1025         header.status     = NT_STATUS_OK;
1026         header.creds.token= hs->token;
1027
1028         /* construct the irpc packet */
1029         ndr = ndr_push_init_ctx(state->irpc);
1030         if (tevent_req_nomem(ndr, req)) {
1031                 return tevent_req_post(req, ev);
1032         }
1033
1034         ndr_err = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
1035         status = ndr_map_error2ntstatus(ndr_err);
1036         if (!NT_STATUS_IS_OK(status)) {
1037                 tevent_req_nterror(req, status);
1038                 return tevent_req_post(req, ev);
1039         }
1040
1041         ndr_err = ndr_push_bytes(ndr, in_data, in_length);
1042         status = ndr_map_error2ntstatus(ndr_err);
1043         if (!NT_STATUS_IS_OK(status)) {
1044                 tevent_req_nterror(req, status);
1045                 return tevent_req_post(req, ev);
1046         }
1047
1048         /* and send it */
1049         state->in_packet = ndr_push_blob(ndr);
1050         status = imessaging_send(hs->msg_ctx, hs->server_id,
1051                                 MSG_IRPC, &state->in_packet);
1052         if (!NT_STATUS_IS_OK(status)) {
1053                 tevent_req_nterror(req, status);
1054                 return tevent_req_post(req, ev);
1055         }
1056
1057         if (hs->timeout != IRPC_CALL_TIMEOUT_INF) {
1058                 /* set timeout-callback in case caller wants that */
1059                 ok = tevent_req_set_endtime(req, ev, timeval_current_ofs(hs->timeout, 0));
1060                 if (!ok) {
1061                         return tevent_req_post(req, ev);
1062                 }
1063         }
1064
1065         return req;
1066 }
1067
1068 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
1069                                               struct irpc_message *m)
1070 {
1071         struct tevent_req *req =
1072                 talloc_get_type_abort(irpc->incoming.private_data,
1073                 struct tevent_req);
1074         struct irpc_bh_raw_call_state *state =
1075                 tevent_req_data(req,
1076                 struct irpc_bh_raw_call_state);
1077
1078         talloc_steal(state, m);
1079
1080         if (!NT_STATUS_IS_OK(m->header.status)) {
1081                 tevent_req_nterror(req, m->header.status);
1082                 return;
1083         }
1084
1085         state->out_data = data_blob_talloc(state,
1086                 m->ndr->data + m->ndr->offset,
1087                 m->ndr->data_size - m->ndr->offset);
1088         if ((m->ndr->data_size - m->ndr->offset) > 0 && !state->out_data.data) {
1089                 tevent_req_oom(req);
1090                 return;
1091         }
1092
1093         tevent_req_done(req);
1094 }
1095
1096 static NTSTATUS irpc_bh_raw_call_recv(struct tevent_req *req,
1097                                         TALLOC_CTX *mem_ctx,
1098                                         uint8_t **out_data,
1099                                         size_t *out_length,
1100                                         uint32_t *out_flags)
1101 {
1102         struct irpc_bh_raw_call_state *state =
1103                 tevent_req_data(req,
1104                 struct irpc_bh_raw_call_state);
1105         NTSTATUS status;
1106
1107         if (tevent_req_is_nterror(req, &status)) {
1108                 tevent_req_received(req);
1109                 return status;
1110         }
1111
1112         *out_data = talloc_move(mem_ctx, &state->out_data.data);
1113         *out_length = state->out_data.length;
1114         *out_flags = 0;
1115         tevent_req_received(req);
1116         return NT_STATUS_OK;
1117 }
1118
1119 struct irpc_bh_disconnect_state {
1120         uint8_t _dummy;
1121 };
1122
1123 static struct tevent_req *irpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
1124                                                 struct tevent_context *ev,
1125                                                 struct dcerpc_binding_handle *h)
1126 {
1127         struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
1128                                      struct irpc_bh_state);
1129         struct tevent_req *req;
1130         struct irpc_bh_disconnect_state *state;
1131         bool ok;
1132
1133         req = tevent_req_create(mem_ctx, &state,
1134                                 struct irpc_bh_disconnect_state);
1135         if (req == NULL) {
1136                 return NULL;
1137         }
1138
1139         ok = irpc_bh_is_connected(h);
1140         if (!ok) {
1141                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1142                 return tevent_req_post(req, ev);
1143         }
1144
1145         hs->msg_ctx = NULL;
1146
1147         tevent_req_done(req);
1148         return tevent_req_post(req, ev);
1149 }
1150
1151 static NTSTATUS irpc_bh_disconnect_recv(struct tevent_req *req)
1152 {
1153         NTSTATUS status;
1154
1155         if (tevent_req_is_nterror(req, &status)) {
1156                 tevent_req_received(req);
1157                 return status;
1158         }
1159
1160         tevent_req_received(req);
1161         return NT_STATUS_OK;
1162 }
1163
1164 static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
1165 {
1166         return true;
1167 }
1168
1169 static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
1170         .name                   = "wbint",
1171         .is_connected           = irpc_bh_is_connected,
1172         .set_timeout            = irpc_bh_set_timeout,
1173         .raw_call_send          = irpc_bh_raw_call_send,
1174         .raw_call_recv          = irpc_bh_raw_call_recv,
1175         .disconnect_send        = irpc_bh_disconnect_send,
1176         .disconnect_recv        = irpc_bh_disconnect_recv,
1177
1178         .ref_alloc              = irpc_bh_ref_alloc,
1179 };
1180
1181 /* initialise a irpc binding handle */
1182 struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
1183                                                   struct imessaging_context *msg_ctx,
1184                                                   struct server_id server_id,
1185                                                   const struct ndr_interface_table *table)
1186 {
1187         struct dcerpc_binding_handle *h;
1188         struct irpc_bh_state *hs;
1189
1190         h = dcerpc_binding_handle_create(mem_ctx,
1191                                          &irpc_bh_ops,
1192                                          NULL,
1193                                          table,
1194                                          &hs,
1195                                          struct irpc_bh_state,
1196                                          __location__);
1197         if (h == NULL) {
1198                 return NULL;
1199         }
1200         hs->msg_ctx = msg_ctx;
1201         hs->server_id = server_id;
1202         hs->table = table;
1203         hs->timeout = IRPC_CALL_TIMEOUT;
1204
1205         return h;
1206 }
1207
1208 struct dcerpc_binding_handle *irpc_binding_handle_by_name(TALLOC_CTX *mem_ctx,
1209                                                           struct imessaging_context *msg_ctx,
1210                                                           const char *dest_task,
1211                                                           const struct ndr_interface_table *table)
1212 {
1213         struct dcerpc_binding_handle *h;
1214         unsigned num_sids;
1215         struct server_id *sids;
1216         struct server_id sid;
1217         NTSTATUS status;
1218
1219         /* find the server task */
1220
1221         status = irpc_servers_byname(msg_ctx, mem_ctx, dest_task,
1222                                      &num_sids, &sids);
1223         if (!NT_STATUS_IS_OK(status)) {
1224                 errno = EADDRNOTAVAIL;
1225                 return NULL;
1226         }
1227         sid = sids[0];
1228         talloc_free(sids);
1229
1230         h = irpc_binding_handle(mem_ctx, msg_ctx,
1231                                 sid, table);
1232         if (h == NULL) {
1233                 return NULL;
1234         }
1235
1236         return h;
1237 }
1238
1239 void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle *h,
1240                                             struct security_token *token)
1241 {
1242         struct irpc_bh_state *hs =
1243                 dcerpc_binding_handle_data(h,
1244                 struct irpc_bh_state);
1245
1246         hs->token = token;
1247 }