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