59c48cd44cb403316f915e37a600703d207f1f7d
[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 /*
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 #if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
468         /*
469          * Register handlers for messages specific to developer and
470          * self test builds
471          */
472         status = imessaging_register_extra_handlers(msg);
473         if (!NT_STATUS_IS_OK(status)) {
474                 goto fail;
475         }
476 #endif /* defined(DEVELOPER) || defined(ENABLE_SELFTEST) */
477
478         DLIST_ADD(msg_ctxs, msg);
479
480         return msg;
481 fail:
482         talloc_free(msg);
483         return NULL;
484 }
485
486 struct imessaging_post_state {
487         struct imessaging_context *msg_ctx;
488         struct imessaging_post_state **busy_ref;
489         size_t buf_len;
490         uint8_t buf[];
491 };
492
493 static int imessaging_post_state_destructor(struct imessaging_post_state *state)
494 {
495         if (state->busy_ref != NULL) {
496                 *state->busy_ref = NULL;
497                 state->busy_ref = NULL;
498         }
499         return 0;
500 }
501
502 static void imessaging_post_handler(struct tevent_context *ev,
503                                     struct tevent_immediate *ti,
504                                     void *private_data)
505 {
506         struct imessaging_post_state *state = talloc_get_type_abort(
507                 private_data, struct imessaging_post_state);
508
509         /*
510          * In usecases like using messaging_client_init() with irpc processing
511          * we may free the imessaging_context during the messaging handler.
512          * imessaging_post_state is a child of imessaging_context and
513          * might be implicitly free'ed before the explicit TALLOC_FREE(state).
514          *
515          * The busy_ref pointer makes sure the destructor clears
516          * the local 'state' variable.
517          */
518
519         SMB_ASSERT(state->busy_ref == NULL);
520         state->busy_ref = &state;
521
522         imessaging_dgm_recv(ev, state->buf, state->buf_len, NULL, 0,
523                             state->msg_ctx);
524
525         if (state == NULL) {
526                 return;
527         }
528
529         state->busy_ref = NULL;
530         TALLOC_FREE(state);
531 }
532
533 static int imessaging_post_self(struct imessaging_context *msg,
534                                 const uint8_t *buf, size_t buf_len)
535 {
536         struct tevent_immediate *ti;
537         struct imessaging_post_state *state;
538
539         state = talloc_size(
540                 msg, offsetof(struct imessaging_post_state, buf) + buf_len);
541         if (state == NULL) {
542                 return ENOMEM;
543         }
544         talloc_set_name_const(state, "struct imessaging_post_state");
545
546         talloc_set_destructor(state, imessaging_post_state_destructor);
547
548         ti = tevent_create_immediate(state);
549         if (ti == NULL) {
550                 TALLOC_FREE(state);
551                 return ENOMEM;
552         }
553
554         state->msg_ctx = msg;
555         state->busy_ref = NULL;
556         state->buf_len = buf_len;
557         memcpy(state->buf, buf, buf_len);
558
559         tevent_schedule_immediate(ti, msg->ev, imessaging_post_handler,
560                                   state);
561
562         return 0;
563 }
564
565 static void imessaging_dgm_recv(struct tevent_context *ev,
566                                 const uint8_t *buf, size_t buf_len,
567                                 int *fds, size_t num_fds,
568                                 void *private_data)
569 {
570         struct imessaging_context *msg = talloc_get_type_abort(
571                 private_data, struct imessaging_context);
572         uint32_t msg_type;
573         struct server_id src, dst;
574         struct server_id_buf srcbuf, dstbuf;
575         DATA_BLOB data;
576
577         if (buf_len < MESSAGE_HDR_LENGTH) {
578                 /* Invalid message, ignore */
579                 return;
580         }
581
582         if (num_fds != 0) {
583                 /*
584                  * Source4 based messaging does not expect fd's yet
585                  */
586                 return;
587         }
588
589         if (ev != msg->ev) {
590                 int ret;
591                 ret = imessaging_post_self(msg, buf, buf_len);
592                 if (ret != 0) {
593                         DBG_WARNING("imessaging_post_self failed: %s\n",
594                                     strerror(ret));
595                 }
596                 return;
597         }
598
599         message_hdr_get(&msg_type, &src, &dst, buf);
600
601         data.data = discard_const_p(uint8_t, buf + MESSAGE_HDR_LENGTH);
602         data.length = buf_len - MESSAGE_HDR_LENGTH;
603
604         if ((cluster_id_equal(&dst, &msg->server_id)) ||
605             ((dst.task_id == 0) && (msg->server_id.pid == 0))) {
606                 struct dispatch_fn *d, *next;
607
608                 DEBUG(10, ("%s: dst %s matches my id: %s, type=0x%x\n",
609                            __func__,
610                            server_id_str_buf(dst, &dstbuf),
611                            server_id_str_buf(msg->server_id, &srcbuf),
612                            (unsigned)msg_type));
613
614                 d = imessaging_find_dispatch(msg, msg_type);
615
616                 for (; d; d = next) {
617                         next = d->next;
618                         d->fn(msg, d->private_data, d->msg_type, src, &data);
619                 }
620         } else {
621                 DEBUG(10, ("%s: Ignoring type=0x%x dst %s, I am %s, \n",
622                            __func__, (unsigned)msg_type,
623                            server_id_str_buf(dst, &dstbuf),
624                            server_id_str_buf(msg->server_id, &srcbuf)));
625         }
626 }
627
628 struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
629                                            struct loadparm_context *lp_ctx,
630                                            struct server_id server_id,
631                                            struct tevent_context *ev)
632 {
633         if (ev == NULL) {
634                 return NULL;
635         }
636
637         if (tevent_context_is_wrapper(ev)) {
638                 /*
639                  * This is really a programmer error!
640                  *
641                  * The main/raw tevent context should
642                  * have been registered first!
643                  */
644                 DBG_ERR("Should not be used with a wrapper tevent context\n");
645                 errno = EINVAL;
646                 return NULL;
647         }
648
649         return imessaging_init_internal(mem_ctx, lp_ctx, server_id, ev);
650 }
651
652 /*
653    A hack, for the short term until we get 'client only' messaging in place
654 */
655 struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
656                                                   struct loadparm_context *lp_ctx,
657                                                 struct tevent_context *ev)
658 {
659         struct server_id id;
660         ZERO_STRUCT(id);
661         id.pid = getpid();
662         id.task_id = generate_random();
663         id.vnn = NONCLUSTER_VNN;
664
665         /* This is because we are not in the s3 serverid database */
666         id.unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY;
667
668         return imessaging_init_internal(mem_ctx, lp_ctx, id, ev);
669 }
670 /*
671   a list of registered irpc server functions
672 */
673 struct irpc_list {
674         struct irpc_list *next, *prev;
675         struct GUID uuid;
676         const struct ndr_interface_table *table;
677         int callnum;
678         irpc_function_t fn;
679         void *private_data;
680 };
681
682
683 /*
684   register a irpc server function
685 */
686 NTSTATUS irpc_register(struct imessaging_context *msg_ctx,
687                        const struct ndr_interface_table *table,
688                        int callnum, irpc_function_t fn, void *private_data)
689 {
690         struct irpc_list *irpc;
691
692         /* override an existing handler, if any */
693         for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
694                 if (irpc->table == table && irpc->callnum == callnum) {
695                         break;
696                 }
697         }
698         if (irpc == NULL) {
699                 irpc = talloc(msg_ctx, struct irpc_list);
700                 NT_STATUS_HAVE_NO_MEMORY(irpc);
701                 DLIST_ADD(msg_ctx->irpc, irpc);
702         }
703
704         irpc->table   = table;
705         irpc->callnum = callnum;
706         irpc->fn      = fn;
707         irpc->private_data = private_data;
708         irpc->uuid = irpc->table->syntax_id.uuid;
709
710         return NT_STATUS_OK;
711 }
712
713
714 /*
715   handle an incoming irpc reply message
716 */
717 static void irpc_handler_reply(struct imessaging_context *msg_ctx, struct irpc_message *m)
718 {
719         struct irpc_request *irpc;
720
721         irpc = (struct irpc_request *)idr_find(msg_ctx->idr, m->header.callid);
722         if (irpc == NULL) return;
723
724         irpc->incoming.handler(irpc, m);
725 }
726
727 /*
728   send a irpc reply
729 */
730 NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
731 {
732         struct ndr_push *push;
733         DATA_BLOB packet;
734         enum ndr_err_code ndr_err;
735
736         m->header.status = status;
737
738         /* setup the reply */
739         push = ndr_push_init_ctx(m->ndr);
740         if (push == NULL) {
741                 status = NT_STATUS_NO_MEMORY;
742                 goto failed;
743         }
744
745         m->header.flags |= IRPC_FLAG_REPLY;
746         m->header.creds.token= NULL;
747
748         /* construct the packet */
749         ndr_err = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
750         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
751                 status = ndr_map_error2ntstatus(ndr_err);
752                 goto failed;
753         }
754
755         ndr_err = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
756         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
757                 status = ndr_map_error2ntstatus(ndr_err);
758                 goto failed;
759         }
760
761         /* send the reply message */
762         packet = ndr_push_blob(push);
763         status = imessaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
764         if (!NT_STATUS_IS_OK(status)) goto failed;
765
766 failed:
767         talloc_free(m);
768         return status;
769 }
770
771 /*
772   handle an incoming irpc request message
773 */
774 static void irpc_handler_request(struct imessaging_context *msg_ctx,
775                                  struct irpc_message *m)
776 {
777         struct irpc_list *i;
778         void *r;
779         enum ndr_err_code ndr_err;
780
781         for (i=msg_ctx->irpc; i; i=i->next) {
782                 if (GUID_equal(&i->uuid, &m->header.uuid) &&
783                     i->table->syntax_id.if_version == m->header.if_version &&
784                     i->callnum == m->header.callnum) {
785                         break;
786                 }
787         }
788
789         if (i == NULL) {
790                 /* no registered handler for this message */
791                 talloc_free(m);
792                 return;
793         }
794
795         /* allocate space for the structure */
796         r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
797         if (r == NULL) goto failed;
798
799         m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
800
801         /* parse the request data */
802         ndr_err = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
803         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
804
805         /* make the call */
806         m->private_data= i->private_data;
807         m->defer_reply = false;
808         m->no_reply    = false;
809         m->msg_ctx     = msg_ctx;
810         m->irpc        = i;
811         m->data        = r;
812
813         m->header.status = i->fn(m, r);
814
815         if (m->no_reply) {
816                 /* the server function won't ever be replying to this request */
817                 talloc_free(m);
818                 return;
819         }
820
821         if (m->defer_reply) {
822                 /* the server function has asked to defer the reply to later */
823                 talloc_steal(msg_ctx, m);
824                 return;
825         }
826
827         irpc_send_reply(m, m->header.status);
828         return;
829
830 failed:
831         talloc_free(m);
832 }
833
834 /*
835   handle an incoming irpc message
836 */
837 static void irpc_handler(struct imessaging_context *msg_ctx, void *private_data,
838                          uint32_t msg_type, struct server_id src, DATA_BLOB *packet)
839 {
840         struct irpc_message *m;
841         enum ndr_err_code ndr_err;
842
843         m = talloc(msg_ctx, struct irpc_message);
844         if (m == NULL) goto failed;
845
846         m->from = src;
847
848         m->ndr = ndr_pull_init_blob(packet, m);
849         if (m->ndr == NULL) goto failed;
850
851         m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
852
853         ndr_err = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
854         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
855
856         if (m->header.flags & IRPC_FLAG_REPLY) {
857                 irpc_handler_reply(msg_ctx, m);
858         } else {
859                 irpc_handler_request(msg_ctx, m);
860         }
861         return;
862
863 failed:
864         talloc_free(m);
865 }
866
867
868 /*
869   destroy a irpc request
870 */
871 static int irpc_destructor(struct irpc_request *irpc)
872 {
873         if (irpc->callid != -1) {
874                 idr_remove(irpc->msg_ctx->idr, irpc->callid);
875                 irpc->callid = -1;
876         }
877
878         return 0;
879 }
880
881 /*
882   add a string name that this irpc server can be called on
883
884   It will be removed from the DB either via irpc_remove_name or on
885   talloc_free(msg_ctx->names).
886 */
887 NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name)
888 {
889         int ret;
890
891         ret = server_id_db_add(msg_ctx->names, name);
892         if (ret != 0) {
893                 return map_nt_error_from_unix_common(ret);
894         }
895         return NT_STATUS_OK;
896 }
897
898 static int all_servers_func(const char *name, unsigned num_servers,
899                             const struct server_id *servers,
900                             void *private_data)
901 {
902         struct irpc_name_records *name_records = talloc_get_type(
903                 private_data, struct irpc_name_records);
904         struct irpc_name_record *name_record;
905         uint32_t i;
906
907         name_records->names
908                 = talloc_realloc(name_records, name_records->names,
909                                  struct irpc_name_record *, name_records->num_records+1);
910         if (!name_records->names) {
911                 return -1;
912         }
913
914         name_records->names[name_records->num_records] = name_record
915                 = talloc(name_records->names,
916                          struct irpc_name_record);
917         if (!name_record) {
918                 return -1;
919         }
920
921         name_records->num_records++;
922
923         name_record->name = talloc_strdup(name_record, name);
924         if (!name_record->name) {
925                 return -1;
926         }
927
928         name_record->count = num_servers;
929         name_record->ids = talloc_array(name_record, struct server_id,
930                                         num_servers);
931         if (name_record->ids == NULL) {
932                 return -1;
933         }
934         for (i=0;i<name_record->count;i++) {
935                 name_record->ids[i] = servers[i];
936         }
937         return 0;
938 }
939
940 /*
941   return a list of server ids for a server name
942 */
943 struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx,
944                                            TALLOC_CTX *mem_ctx)
945 {
946         int ret;
947         struct irpc_name_records *name_records = talloc_zero(mem_ctx, struct irpc_name_records);
948         if (name_records == NULL) {
949                 return NULL;
950         }
951
952         ret = server_id_db_traverse_read(msg_ctx->names, all_servers_func,
953                                          name_records);
954         if (ret == -1) {
955                 TALLOC_FREE(name_records);
956                 return NULL;
957         }
958
959         return name_records;
960 }
961
962 /*
963   remove a name from a messaging context
964 */
965 void irpc_remove_name(struct imessaging_context *msg_ctx, const char *name)
966 {
967         server_id_db_remove(msg_ctx->names, name);
968 }
969
970 struct server_id imessaging_get_server_id(struct imessaging_context *msg_ctx)
971 {
972         return msg_ctx->server_id;
973 }
974
975 struct irpc_bh_state {
976         struct imessaging_context *msg_ctx;
977         struct server_id server_id;
978         const struct ndr_interface_table *table;
979         uint32_t timeout;
980         struct security_token *token;
981 };
982
983 static bool irpc_bh_is_connected(struct dcerpc_binding_handle *h)
984 {
985         struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
986                                    struct irpc_bh_state);
987
988         if (!hs->msg_ctx) {
989                 return false;
990         }
991
992         return true;
993 }
994
995 static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle *h,
996                                     uint32_t timeout)
997 {
998         struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
999                                    struct irpc_bh_state);
1000         uint32_t old = hs->timeout;
1001
1002         hs->timeout = timeout;
1003
1004         return old;
1005 }
1006
1007 struct irpc_bh_raw_call_state {
1008         struct irpc_request *irpc;
1009         uint32_t opnum;
1010         DATA_BLOB in_data;
1011         DATA_BLOB in_packet;
1012         DATA_BLOB out_data;
1013 };
1014
1015 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
1016                                               struct irpc_message *m);
1017
1018 static struct tevent_req *irpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
1019                                                 struct tevent_context *ev,
1020                                                 struct dcerpc_binding_handle *h,
1021                                                 const struct GUID *object,
1022                                                 uint32_t opnum,
1023                                                 uint32_t in_flags,
1024                                                 const uint8_t *in_data,
1025                                                 size_t in_length)
1026 {
1027         struct irpc_bh_state *hs =
1028                 dcerpc_binding_handle_data(h,
1029                 struct irpc_bh_state);
1030         struct tevent_req *req;
1031         struct irpc_bh_raw_call_state *state;
1032         bool ok;
1033         struct irpc_header header;
1034         struct ndr_push *ndr;
1035         NTSTATUS status;
1036         enum ndr_err_code ndr_err;
1037
1038         req = tevent_req_create(mem_ctx, &state,
1039                                 struct irpc_bh_raw_call_state);
1040         if (req == NULL) {
1041                 return NULL;
1042         }
1043         state->opnum = opnum;
1044         state->in_data.data = discard_const_p(uint8_t, in_data);
1045         state->in_data.length = in_length;
1046
1047         ok = irpc_bh_is_connected(h);
1048         if (!ok) {
1049                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1050                 return tevent_req_post(req, ev);
1051         }
1052
1053         state->irpc = talloc_zero(state, struct irpc_request);
1054         if (tevent_req_nomem(state->irpc, req)) {
1055                 return tevent_req_post(req, ev);
1056         }
1057
1058         state->irpc->msg_ctx  = hs->msg_ctx;
1059         state->irpc->callid   = idr_get_new(hs->msg_ctx->idr,
1060                                             state->irpc, UINT16_MAX);
1061         if (state->irpc->callid == -1) {
1062                 tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1063                 return tevent_req_post(req, ev);
1064         }
1065         state->irpc->incoming.handler = irpc_bh_raw_call_incoming_handler;
1066         state->irpc->incoming.private_data = req;
1067
1068         talloc_set_destructor(state->irpc, irpc_destructor);
1069
1070         /* setup the header */
1071         header.uuid = hs->table->syntax_id.uuid;
1072
1073         header.if_version = hs->table->syntax_id.if_version;
1074         header.callid     = state->irpc->callid;
1075         header.callnum    = state->opnum;
1076         header.flags      = 0;
1077         header.status     = NT_STATUS_OK;
1078         header.creds.token= hs->token;
1079
1080         /* construct the irpc packet */
1081         ndr = ndr_push_init_ctx(state->irpc);
1082         if (tevent_req_nomem(ndr, req)) {
1083                 return tevent_req_post(req, ev);
1084         }
1085
1086         ndr_err = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
1087         status = ndr_map_error2ntstatus(ndr_err);
1088         if (!NT_STATUS_IS_OK(status)) {
1089                 tevent_req_nterror(req, status);
1090                 return tevent_req_post(req, ev);
1091         }
1092
1093         ndr_err = ndr_push_bytes(ndr, in_data, in_length);
1094         status = ndr_map_error2ntstatus(ndr_err);
1095         if (!NT_STATUS_IS_OK(status)) {
1096                 tevent_req_nterror(req, status);
1097                 return tevent_req_post(req, ev);
1098         }
1099
1100         /* and send it */
1101         state->in_packet = ndr_push_blob(ndr);
1102         status = imessaging_send(hs->msg_ctx, hs->server_id,
1103                                 MSG_IRPC, &state->in_packet);
1104         if (!NT_STATUS_IS_OK(status)) {
1105                 tevent_req_nterror(req, status);
1106                 return tevent_req_post(req, ev);
1107         }
1108
1109         if (hs->timeout != IRPC_CALL_TIMEOUT_INF) {
1110                 /* set timeout-callback in case caller wants that */
1111                 ok = tevent_req_set_endtime(req, ev, timeval_current_ofs(hs->timeout, 0));
1112                 if (!ok) {
1113                         return tevent_req_post(req, ev);
1114                 }
1115         }
1116
1117         return req;
1118 }
1119
1120 static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
1121                                               struct irpc_message *m)
1122 {
1123         struct tevent_req *req =
1124                 talloc_get_type_abort(irpc->incoming.private_data,
1125                 struct tevent_req);
1126         struct irpc_bh_raw_call_state *state =
1127                 tevent_req_data(req,
1128                 struct irpc_bh_raw_call_state);
1129
1130         talloc_steal(state, m);
1131
1132         if (!NT_STATUS_IS_OK(m->header.status)) {
1133                 tevent_req_nterror(req, m->header.status);
1134                 return;
1135         }
1136
1137         state->out_data = data_blob_talloc(state,
1138                 m->ndr->data + m->ndr->offset,
1139                 m->ndr->data_size - m->ndr->offset);
1140         if ((m->ndr->data_size - m->ndr->offset) > 0 && !state->out_data.data) {
1141                 tevent_req_oom(req);
1142                 return;
1143         }
1144
1145         tevent_req_done(req);
1146 }
1147
1148 static NTSTATUS irpc_bh_raw_call_recv(struct tevent_req *req,
1149                                         TALLOC_CTX *mem_ctx,
1150                                         uint8_t **out_data,
1151                                         size_t *out_length,
1152                                         uint32_t *out_flags)
1153 {
1154         struct irpc_bh_raw_call_state *state =
1155                 tevent_req_data(req,
1156                 struct irpc_bh_raw_call_state);
1157         NTSTATUS status;
1158
1159         if (tevent_req_is_nterror(req, &status)) {
1160                 tevent_req_received(req);
1161                 return status;
1162         }
1163
1164         *out_data = talloc_move(mem_ctx, &state->out_data.data);
1165         *out_length = state->out_data.length;
1166         *out_flags = 0;
1167         tevent_req_received(req);
1168         return NT_STATUS_OK;
1169 }
1170
1171 struct irpc_bh_disconnect_state {
1172         uint8_t _dummy;
1173 };
1174
1175 static struct tevent_req *irpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
1176                                                 struct tevent_context *ev,
1177                                                 struct dcerpc_binding_handle *h)
1178 {
1179         struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
1180                                      struct irpc_bh_state);
1181         struct tevent_req *req;
1182         struct irpc_bh_disconnect_state *state;
1183         bool ok;
1184
1185         req = tevent_req_create(mem_ctx, &state,
1186                                 struct irpc_bh_disconnect_state);
1187         if (req == NULL) {
1188                 return NULL;
1189         }
1190
1191         ok = irpc_bh_is_connected(h);
1192         if (!ok) {
1193                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1194                 return tevent_req_post(req, ev);
1195         }
1196
1197         hs->msg_ctx = NULL;
1198
1199         tevent_req_done(req);
1200         return tevent_req_post(req, ev);
1201 }
1202
1203 static NTSTATUS irpc_bh_disconnect_recv(struct tevent_req *req)
1204 {
1205         NTSTATUS status;
1206
1207         if (tevent_req_is_nterror(req, &status)) {
1208                 tevent_req_received(req);
1209                 return status;
1210         }
1211
1212         tevent_req_received(req);
1213         return NT_STATUS_OK;
1214 }
1215
1216 static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
1217 {
1218         return true;
1219 }
1220
1221 static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
1222         .name                   = "wbint",
1223         .is_connected           = irpc_bh_is_connected,
1224         .set_timeout            = irpc_bh_set_timeout,
1225         .raw_call_send          = irpc_bh_raw_call_send,
1226         .raw_call_recv          = irpc_bh_raw_call_recv,
1227         .disconnect_send        = irpc_bh_disconnect_send,
1228         .disconnect_recv        = irpc_bh_disconnect_recv,
1229
1230         .ref_alloc              = irpc_bh_ref_alloc,
1231 };
1232
1233 /* initialise a irpc binding handle */
1234 struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
1235                                                   struct imessaging_context *msg_ctx,
1236                                                   struct server_id server_id,
1237                                                   const struct ndr_interface_table *table)
1238 {
1239         struct dcerpc_binding_handle *h;
1240         struct irpc_bh_state *hs;
1241
1242         h = dcerpc_binding_handle_create(mem_ctx,
1243                                          &irpc_bh_ops,
1244                                          NULL,
1245                                          table,
1246                                          &hs,
1247                                          struct irpc_bh_state,
1248                                          __location__);
1249         if (h == NULL) {
1250                 return NULL;
1251         }
1252         hs->msg_ctx = msg_ctx;
1253         hs->server_id = server_id;
1254         hs->table = table;
1255         hs->timeout = IRPC_CALL_TIMEOUT;
1256
1257         return h;
1258 }
1259
1260 struct dcerpc_binding_handle *irpc_binding_handle_by_name(TALLOC_CTX *mem_ctx,
1261                                                           struct imessaging_context *msg_ctx,
1262                                                           const char *dest_task,
1263                                                           const struct ndr_interface_table *table)
1264 {
1265         struct dcerpc_binding_handle *h;
1266         unsigned num_sids;
1267         struct server_id *sids;
1268         struct server_id sid;
1269         NTSTATUS status;
1270
1271         /* find the server task */
1272
1273         status = irpc_servers_byname(msg_ctx, mem_ctx, dest_task,
1274                                      &num_sids, &sids);
1275         if (!NT_STATUS_IS_OK(status)) {
1276                 errno = EADDRNOTAVAIL;
1277                 return NULL;
1278         }
1279         sid = sids[0];
1280         talloc_free(sids);
1281
1282         h = irpc_binding_handle(mem_ctx, msg_ctx,
1283                                 sid, table);
1284         if (h == NULL) {
1285                 return NULL;
1286         }
1287
1288         return h;
1289 }
1290
1291 void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle *h,
1292                                             struct security_token *token)
1293 {
1294         struct irpc_bh_state *hs =
1295                 dcerpc_binding_handle_data(h,
1296                 struct irpc_bh_state);
1297
1298         hs->token = token;
1299 }