Coverage Report

Created: 2026-09-03 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/lib/messaging/messaging.c
Line
Count
Source
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_printf.h"
39
#include "lib/messaging/messages_dgm.h"
40
#include "lib/messaging/messages_dgm_ref.h"
41
#include "../source3/lib/messages_util.h"
42
#include <tdb.h>
43
#include "lib/util/idtree.h"
44
45
/* change the message version with any incompatible changes in the protocol */
46
#define IMESSAGING_VERSION 1
47
48
/*
49
  a pending irpc call
50
*/
51
struct irpc_request {
52
  struct irpc_request *prev, *next;
53
  struct imessaging_context *msg_ctx;
54
  int callid;
55
  struct {
56
    void (*handler)(struct irpc_request *irpc, struct irpc_message *m);
57
    void *private_data;
58
  } incoming;
59
};
60
61
/* we have a linked list of dispatch handlers for each msg_type that
62
   this messaging server can deal with */
63
struct dispatch_fn {
64
  struct dispatch_fn *next, *prev;
65
  uint32_t msg_type;
66
  void *private_data;
67
  msg_callback_t fn;
68
};
69
70
/* an individual message */
71
72
static void irpc_handler(struct imessaging_context *,
73
       void *,
74
       uint32_t,
75
       struct server_id,
76
       size_t,
77
       int *,
78
       DATA_BLOB *);
79
80
81
/*
82
 A useful function for testing the message system.
83
*/
84
static void ping_message(struct imessaging_context *msg,
85
       void *private_data,
86
       uint32_t msg_type,
87
       struct server_id src,
88
       size_t num_fds,
89
       int *fds,
90
       DATA_BLOB *data)
91
0
{
92
0
  struct server_id_buf idbuf;
93
94
0
  if (num_fds != 0) {
95
0
    DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
96
0
    return;
97
0
  }
98
99
0
  DEBUG(1,("INFO: Received PING message from server %s [%.*s]\n",
100
0
     server_id_str_buf(src, &idbuf), (int)data->length,
101
0
     data->data?(const char *)data->data:""));
102
0
  imessaging_send(msg, src, MSG_PONG, data);
103
0
}
104
105
static void pool_message(struct imessaging_context *msg,
106
       void *private_data,
107
       uint32_t msg_type,
108
       struct server_id src,
109
       size_t num_fds,
110
       int *fds,
111
       DATA_BLOB *data)
112
0
{
113
0
  FILE *f = NULL;
114
115
0
  if (num_fds != 1) {
116
0
    DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
117
0
    return;
118
0
  }
119
120
0
  f = fdopen(fds[0], "w");
121
0
  if (f == NULL) {
122
0
    DBG_DEBUG("fopen failed: %s\n", strerror(errno));
123
0
    return;
124
0
  }
125
126
0
  talloc_full_report_printf(NULL, f);
127
0
  fclose(f);
128
0
}
129
130
static void ringbuf_log_msg(struct imessaging_context *msg,
131
          void *private_data,
132
          uint32_t msg_type,
133
          struct server_id src,
134
          size_t num_fds,
135
          int *fds,
136
          DATA_BLOB *data)
137
0
{
138
0
  char *log = debug_get_ringbuf();
139
0
  size_t logsize = debug_get_ringbuf_size();
140
0
  DATA_BLOB blob;
141
142
0
  if (num_fds != 0) {
143
0
    DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
144
0
    return;
145
0
  }
146
147
0
  if (log == NULL) {
148
0
    log = discard_const_p(char, "*disabled*\n");
149
0
    logsize = strlen(log) + 1;
150
0
  }
151
152
0
  blob.data = (uint8_t *)log;
153
0
  blob.length = logsize;
154
155
0
  imessaging_send(msg, src, MSG_RINGBUF_LOG, &blob);
156
0
}
157
158
/****************************************************************************
159
 Receive a "set debug level" message.
160
****************************************************************************/
161
162
static void debug_imessage(struct imessaging_context *msg_ctx,
163
         void *private_data,
164
         uint32_t msg_type,
165
         struct server_id src,
166
         size_t num_fds,
167
         int *fds,
168
         DATA_BLOB *data)
169
0
{
170
0
  const char *params_str = (const char *)data->data;
171
0
  struct server_id_buf src_buf;
172
0
  struct server_id dst = imessaging_get_server_id(msg_ctx);
173
0
  struct server_id_buf dst_buf;
174
175
0
  if (num_fds != 0) {
176
0
    DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
177
0
    return;
178
0
  }
179
180
  /* Check, it's a proper string! */
181
0
  if (params_str[(data->length)-1] != '\0') {
182
0
    DBG_ERR("Invalid debug message from pid %s to pid %s\n",
183
0
      server_id_str_buf(src, &src_buf),
184
0
      server_id_str_buf(dst, &dst_buf));
185
0
    return;
186
0
  }
187
188
0
  DBG_ERR("INFO: Remote set of debug to `%s' (pid %s from pid %s)\n",
189
0
    params_str,
190
0
    server_id_str_buf(dst, &dst_buf),
191
0
    server_id_str_buf(src, &src_buf));
192
193
0
  debug_parse_levels(params_str);
194
0
}
195
196
/****************************************************************************
197
 Return current debug level.
198
****************************************************************************/
199
200
static void debuglevel_imessage(struct imessaging_context *msg_ctx,
201
        void *private_data,
202
        uint32_t msg_type,
203
        struct server_id src,
204
        size_t num_fds,
205
        int *fds,
206
        DATA_BLOB *data)
207
0
{
208
0
  char *message = debug_list_class_names_and_levels();
209
0
  DATA_BLOB blob = data_blob_null;
210
0
  struct server_id_buf src_buf;
211
0
  struct server_id dst = imessaging_get_server_id(msg_ctx);
212
0
  struct server_id_buf dst_buf;
213
214
0
  if (num_fds != 0) {
215
0
    DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
216
0
    return;
217
0
  }
218
219
0
  DBG_DEBUG("Received REQ_DEBUGLEVEL message (pid %s from pid %s)\n",
220
0
      server_id_str_buf(dst, &dst_buf),
221
0
      server_id_str_buf(src, &src_buf));
222
223
0
  if (message == NULL) {
224
0
    DBG_ERR("debug_list_class_names_and_levels returned NULL\n");
225
0
    return;
226
0
  }
227
228
0
  blob = data_blob_string_const_null(message);
229
0
  imessaging_send(msg_ctx, src, MSG_DEBUGLEVEL, &blob);
230
231
0
  TALLOC_FREE(message);
232
0
}
233
234
/*
235
  return uptime of messaging server via irpc
236
*/
237
static NTSTATUS irpc_uptime(struct irpc_message *msg,
238
          struct irpc_uptime *r)
239
0
{
240
0
  struct imessaging_context *ctx = talloc_get_type(msg->private_data, struct imessaging_context);
241
0
  *r->out.start_time = timeval_to_nttime(&ctx->start_time);
242
0
  return NT_STATUS_OK;
243
0
}
244
245
static struct dispatch_fn *imessaging_find_dispatch(
246
  struct imessaging_context *msg, uint32_t msg_type)
247
0
{
248
  /* temporary IDs use an idtree, the rest use a array of pointers */
249
0
  if (msg_type >= MSG_TMP_BASE) {
250
0
    return (struct dispatch_fn *)idr_find(msg->dispatch_tree,
251
0
                  msg_type);
252
0
  }
253
0
  if (msg_type < msg->num_types) {
254
0
    return msg->dispatch[msg_type];
255
0
  }
256
0
  return NULL;
257
0
}
258
259
/*
260
  Register a dispatch function for a particular message type.
261
*/
262
NTSTATUS imessaging_register(struct imessaging_context *msg, void *private_data,
263
          uint32_t msg_type, msg_callback_t fn)
264
0
{
265
0
  struct dispatch_fn *d;
266
267
  /* possibly expand dispatch array */
268
0
  if (msg_type >= msg->num_types) {
269
0
    struct dispatch_fn **dp;
270
0
    uint32_t i;
271
0
    dp = talloc_realloc(msg, msg->dispatch, struct dispatch_fn *, msg_type+1);
272
0
    NT_STATUS_HAVE_NO_MEMORY(dp);
273
0
    msg->dispatch = dp;
274
0
    for (i=msg->num_types;i<=msg_type;i++) {
275
0
      msg->dispatch[i] = NULL;
276
0
    }
277
0
    msg->num_types = msg_type+1;
278
0
  }
279
280
0
  d = talloc_zero(msg->dispatch, struct dispatch_fn);
281
0
  NT_STATUS_HAVE_NO_MEMORY(d);
282
0
  d->msg_type = msg_type;
283
0
  d->private_data = private_data;
284
0
  d->fn = fn;
285
286
0
  DLIST_ADD(msg->dispatch[msg_type], d);
287
288
0
  return NT_STATUS_OK;
289
0
}
290
291
/*
292
  register a temporary message handler. The msg_type is allocated
293
  above MSG_TMP_BASE
294
*/
295
NTSTATUS imessaging_register_tmp(struct imessaging_context *msg, void *private_data,
296
        msg_callback_t fn, uint32_t *msg_type)
297
0
{
298
0
  struct dispatch_fn *d;
299
0
  int id;
300
301
0
  d = talloc_zero(msg->dispatch, struct dispatch_fn);
302
0
  NT_STATUS_HAVE_NO_MEMORY(d);
303
0
  d->private_data = private_data;
304
0
  d->fn = fn;
305
306
0
  id = idr_get_new_above(msg->dispatch_tree, d, MSG_TMP_BASE, UINT16_MAX);
307
0
  if (id == -1) {
308
0
    talloc_free(d);
309
0
    return NT_STATUS_TOO_MANY_CONTEXT_IDS;
310
0
  }
311
312
0
  d->msg_type = (uint32_t)id;
313
0
  (*msg_type) = d->msg_type;
314
315
0
  return NT_STATUS_OK;
316
0
}
317
318
/*
319
  De-register the function for a particular message type. Return the number of
320
  functions deregistered.
321
*/
322
size_t imessaging_deregister(struct imessaging_context *msg, uint32_t msg_type, void *private_data)
323
0
{
324
0
  struct dispatch_fn *d, *next;
325
0
  size_t removed = 0;
326
327
0
  if (msg_type >= msg->num_types) {
328
0
    d = (struct dispatch_fn *)idr_find(msg->dispatch_tree,
329
0
               msg_type);
330
0
    if (!d) return 0;
331
0
    idr_remove(msg->dispatch_tree, msg_type);
332
0
    talloc_free(d);
333
0
    return 1;
334
0
  }
335
336
0
  for (d = msg->dispatch[msg_type]; d; d = next) {
337
0
    next = d->next;
338
0
    if (d->private_data == private_data) {
339
0
      DLIST_REMOVE(msg->dispatch[msg_type], d);
340
0
      talloc_free(d);
341
0
      ++removed;
342
0
    }
343
0
  }
344
345
0
  return removed;
346
0
}
347
348
/*
349
*/
350
int imessaging_cleanup(struct imessaging_context *msg)
351
0
{
352
0
  return 0;
353
0
}
354
355
static void imessaging_dgm_recv(struct tevent_context *ev,
356
        const uint8_t *buf, size_t buf_len,
357
        int *fds, size_t num_fds,
358
        void *private_data);
359
360
/* Keep a list of imessaging contexts */
361
static struct imessaging_context *msg_ctxs;
362
363
/*
364
 * A process has terminated, clean-up any names it has registered.
365
 */
366
NTSTATUS imessaging_process_cleanup(
367
  struct imessaging_context *msg_ctx,
368
  pid_t pid)
369
0
{
370
0
  struct irpc_name_records *names = NULL;
371
0
  uint32_t i = 0;
372
0
  uint32_t j = 0;
373
0
  TALLOC_CTX *mem_ctx = talloc_new(NULL);
374
375
0
  if (mem_ctx == NULL) {
376
0
    DBG_ERR("OOM unable to clean up messaging for process (%d)\n",
377
0
      pid);
378
0
    return NT_STATUS_NO_MEMORY;
379
0
  }
380
381
0
  names = irpc_all_servers(msg_ctx, mem_ctx);
382
0
  if (names == NULL) {
383
0
    TALLOC_FREE(mem_ctx);
384
0
    return NT_STATUS_OK;
385
0
  }
386
0
  for (i = 0; i < names->num_records; i++) {
387
0
    for (j = 0; j < names->names[i]->count; j++) {
388
0
      if (names->names[i]->ids[j].pid == pid) {
389
0
        int ret = server_id_db_prune_name(
390
0
          msg_ctx->names,
391
0
          names->names[i]->name,
392
0
          names->names[i]->ids[j]);
393
0
        if (ret != 0 && ret != ENOENT) {
394
0
          TALLOC_FREE(mem_ctx);
395
0
          return map_nt_error_from_unix_common(
396
0
              ret);
397
0
        }
398
0
      }
399
0
    }
400
0
  }
401
0
  TALLOC_FREE(mem_ctx);
402
0
  return NT_STATUS_OK;
403
0
}
404
405
static int imessaging_context_destructor(struct imessaging_context *msg)
406
0
{
407
0
  struct irpc_request *irpc = NULL;
408
0
  struct irpc_request *next = NULL;
409
410
0
  for (irpc = msg->requests; irpc != NULL; irpc = next) {
411
0
    next = irpc->next;
412
413
0
    DLIST_REMOVE(msg->requests, irpc);
414
0
    irpc->callid = -1;
415
0
  }
416
417
0
  DLIST_REMOVE(msg_ctxs, msg);
418
0
  TALLOC_FREE(msg->msg_dgm_ref);
419
0
  return 0;
420
0
}
421
422
/*
423
 * Cleanup messaging dgm contexts on a specific event context.
424
 *
425
 * We must make sure to unref all messaging_dgm_ref's *before* the
426
 * tevent context goes away. Only when the last ref is freed, the
427
 * refcounted messaging dgm context will be freed.
428
 */
429
void imessaging_dgm_unref_ev(struct tevent_context *ev)
430
0
{
431
0
  struct imessaging_context *msg = NULL;
432
433
0
  for (msg = msg_ctxs; msg != NULL; msg = msg->next) {
434
0
    if (msg->ev == ev) {
435
0
      TALLOC_FREE(msg->msg_dgm_ref);
436
0
    }
437
0
  }
438
0
}
439
440
static NTSTATUS imessaging_reinit(struct imessaging_context *msg)
441
0
{
442
0
  int ret = -1;
443
0
  struct irpc_request *irpc = NULL;
444
0
  struct irpc_request *next = NULL;
445
446
0
  for (irpc = msg->requests; irpc != NULL; irpc = next) {
447
0
    next = irpc->next;
448
449
0
    DLIST_REMOVE(msg->requests, irpc);
450
0
    irpc->callid = -1;
451
0
  }
452
453
0
  TALLOC_FREE(msg->msg_dgm_ref);
454
455
0
  if (msg->discard_incoming) {
456
0
    msg->num_incoming_listeners = 0;
457
0
  } else {
458
0
    msg->num_incoming_listeners = 1;
459
0
  }
460
461
0
  msg->server_id.pid = getpid();
462
463
0
  msg->msg_dgm_ref = messaging_dgm_ref(msg,
464
0
        msg->ev,
465
0
        &msg->server_id.unique_id,
466
0
        msg->sock_dir,
467
0
        msg->lock_dir,
468
0
        imessaging_dgm_recv,
469
0
        msg,
470
0
        &ret);
471
472
0
  if (msg->msg_dgm_ref == NULL) {
473
0
    DEBUG(2, ("messaging_dgm_ref failed: %s\n",
474
0
      strerror(ret)));
475
0
    return map_nt_error_from_unix_common(ret);
476
0
  }
477
478
0
  server_id_db_reinit(msg->names, msg->server_id);
479
0
  return NT_STATUS_OK;
480
0
}
481
482
/*
483
 * Must be called after a fork.
484
 */
485
NTSTATUS imessaging_reinit_all(void)
486
0
{
487
0
  struct imessaging_context *msg = NULL;
488
489
0
  for (msg = msg_ctxs; msg != NULL; msg = msg->next) {
490
0
    NTSTATUS status = imessaging_reinit(msg);
491
0
    if (!NT_STATUS_IS_OK(status)) {
492
0
      return status;
493
0
    }
494
0
  }
495
0
  return NT_STATUS_OK;
496
0
}
497
498
/*
499
  create the listening socket and setup the dispatcher
500
*/
501
static struct imessaging_context *imessaging_init_internal(
502
             TALLOC_CTX *mem_ctx,
503
             bool discard_incoming,
504
             struct loadparm_context *lp_ctx,
505
             struct server_id server_id,
506
             struct tevent_context *ev)
507
0
{
508
0
  NTSTATUS status;
509
0
  struct imessaging_context *msg;
510
0
  bool ok;
511
0
  int ret;
512
0
  const char *lock_dir = NULL;
513
0
  int tdb_flags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST;
514
515
0
  if (ev == NULL) {
516
0
    return NULL;
517
0
  }
518
519
0
  msg = talloc_zero(mem_ctx, struct imessaging_context);
520
0
  if (msg == NULL) {
521
0
    return NULL;
522
0
  }
523
0
  msg->ev = ev;
524
0
  msg->discard_incoming = discard_incoming;
525
0
  if (msg->discard_incoming) {
526
0
    msg->num_incoming_listeners = 0;
527
0
  } else {
528
0
    msg->num_incoming_listeners = 1;
529
0
  }
530
531
0
  talloc_set_destructor(msg, imessaging_context_destructor);
532
533
  /* create the messaging directory if needed */
534
535
0
  lock_dir = lpcfg_lock_directory(lp_ctx);
536
0
  if (lock_dir == NULL) {
537
0
    goto fail;
538
0
  }
539
540
0
  msg->sock_dir = lpcfg_private_path(msg, lp_ctx, "msg.sock");
541
0
  if (msg->sock_dir == NULL) {
542
0
    goto fail;
543
0
  }
544
0
  ok = directory_create_or_exist_strict(msg->sock_dir, geteuid(), 0700);
545
0
  if (!ok) {
546
0
    goto fail;
547
0
  }
548
549
0
  msg->lock_dir = lpcfg_lock_path(msg, lp_ctx, "msg.lock");
550
0
  if (msg->lock_dir == NULL) {
551
0
    goto fail;
552
0
  }
553
0
  ok = directory_create_or_exist_strict(msg->lock_dir, geteuid(), 0755);
554
0
  if (!ok) {
555
0
    goto fail;
556
0
  }
557
558
0
  msg->msg_dgm_ref = messaging_dgm_ref(
559
0
    msg, ev, &server_id.unique_id, msg->sock_dir, msg->lock_dir,
560
0
    imessaging_dgm_recv, msg, &ret);
561
562
0
  if (msg->msg_dgm_ref == NULL) {
563
0
    goto fail;
564
0
  }
565
566
0
  msg->server_id     = server_id;
567
0
  msg->idr           = idr_init(msg);
568
0
  if (msg->idr == NULL) {
569
0
    goto fail;
570
0
  }
571
572
0
  msg->dispatch_tree = idr_init(msg);
573
0
  if (msg->dispatch_tree == NULL) {
574
0
    goto fail;
575
0
  }
576
577
0
  msg->start_time    = timeval_current();
578
579
0
  tdb_flags |= lpcfg_tdb_flags(lp_ctx, 0);
580
581
  /*
582
   * This context holds a destructor that cleans up any names
583
   * registered on this context on talloc_free()
584
   */
585
0
  msg->names = server_id_db_init(msg, server_id, lock_dir, 0, tdb_flags);
586
0
  if (msg->names == NULL) {
587
0
    goto fail;
588
0
  }
589
590
0
  status = imessaging_register(msg, NULL, MSG_PING, ping_message);
591
0
  if (!NT_STATUS_IS_OK(status)) {
592
0
    goto fail;
593
0
  }
594
0
  status = imessaging_register(msg, NULL, MSG_REQ_POOL_USAGE,
595
0
             pool_message);
596
0
  if (!NT_STATUS_IS_OK(status)) {
597
0
    goto fail;
598
0
  }
599
0
  status = imessaging_register(msg, NULL, MSG_IRPC, irpc_handler);
600
0
  if (!NT_STATUS_IS_OK(status)) {
601
0
    goto fail;
602
0
  }
603
0
  status = imessaging_register(msg, NULL, MSG_REQ_RINGBUF_LOG,
604
0
             ringbuf_log_msg);
605
0
  if (!NT_STATUS_IS_OK(status)) {
606
0
    goto fail;
607
0
  }
608
0
  status = imessaging_register(msg, NULL, MSG_DEBUG,
609
0
             debug_imessage);
610
0
  if (!NT_STATUS_IS_OK(status)) {
611
0
    goto fail;
612
0
  }
613
0
  status = imessaging_register(msg, NULL, MSG_REQ_DEBUGLEVEL,
614
0
             debuglevel_imessage);
615
0
  if (!NT_STATUS_IS_OK(status)) {
616
0
    goto fail;
617
0
  }
618
0
  status = IRPC_REGISTER(msg, irpc, IRPC_UPTIME, irpc_uptime, msg);
619
0
  if (!NT_STATUS_IS_OK(status)) {
620
0
    goto fail;
621
0
  }
622
0
#if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
623
  /*
624
   * Register handlers for messages specific to developer and
625
   * self test builds
626
   */
627
0
  status = imessaging_register_extra_handlers(msg);
628
0
  if (!NT_STATUS_IS_OK(status)) {
629
0
    goto fail;
630
0
  }
631
0
#endif /* defined(DEVELOPER) || defined(ENABLE_SELFTEST) */
632
633
0
  DLIST_ADD(msg_ctxs, msg);
634
635
0
  return msg;
636
0
fail:
637
0
  talloc_free(msg);
638
0
  return NULL;
639
0
}
640
641
/*
642
  create the listening socket and setup the dispatcher
643
*/
644
struct imessaging_context *imessaging_init(TALLOC_CTX *mem_ctx,
645
             struct loadparm_context *lp_ctx,
646
             struct server_id server_id,
647
             struct tevent_context *ev)
648
0
{
649
0
  bool discard_incoming = false;
650
0
  return imessaging_init_internal(mem_ctx,
651
0
          discard_incoming,
652
0
          lp_ctx,
653
0
          server_id,
654
0
          ev);
655
0
}
656
657
struct imessaging_context *imessaging_init_discard_incoming(
658
            TALLOC_CTX *mem_ctx,
659
            struct loadparm_context *lp_ctx,
660
            struct server_id server_id,
661
            struct tevent_context *ev)
662
0
{
663
0
  bool discard_incoming = true;
664
0
  return imessaging_init_internal(mem_ctx,
665
0
          discard_incoming,
666
0
          lp_ctx,
667
0
          server_id,
668
0
          ev);
669
0
}
670
671
struct imessaging_post_state {
672
  struct imessaging_context *msg_ctx;
673
  struct imessaging_post_state **busy_ref;
674
  size_t buf_len;
675
  uint8_t buf[];
676
};
677
678
static int imessaging_post_state_destructor(struct imessaging_post_state *state)
679
0
{
680
0
  if (state->busy_ref != NULL) {
681
0
    *state->busy_ref = NULL;
682
0
    state->busy_ref = NULL;
683
0
  }
684
0
  return 0;
685
0
}
686
687
static void imessaging_post_handler(struct tevent_context *ev,
688
            struct tevent_immediate *ti,
689
            void *private_data)
690
0
{
691
0
  struct imessaging_post_state *state = talloc_get_type_abort(
692
0
    private_data, struct imessaging_post_state);
693
694
0
  if (state == NULL) {
695
0
    return;
696
0
  }
697
698
  /*
699
   * In usecases like using messaging_client_init() with irpc processing
700
   * we may free the imessaging_context during the messaging handler.
701
   * imessaging_post_state is a child of imessaging_context and
702
   * might be implicitly free'ed before the explicit TALLOC_FREE(state).
703
   *
704
   * The busy_ref pointer makes sure the destructor clears
705
   * the local 'state' variable.
706
   */
707
708
0
  SMB_ASSERT(state->busy_ref == NULL);
709
0
  state->busy_ref = &state;
710
711
0
  imessaging_dgm_recv(ev, state->buf, state->buf_len, NULL, 0,
712
0
          state->msg_ctx);
713
714
0
  state->busy_ref = NULL;
715
0
  TALLOC_FREE(state);
716
0
}
717
718
static int imessaging_post_self(struct imessaging_context *msg,
719
        const uint8_t *buf, size_t buf_len)
720
0
{
721
0
  struct tevent_immediate *ti;
722
0
  struct imessaging_post_state *state;
723
724
0
  state = talloc_size(
725
0
    msg, offsetof(struct imessaging_post_state, buf) + buf_len);
726
0
  if (state == NULL) {
727
0
    return ENOMEM;
728
0
  }
729
0
  talloc_set_name_const(state, "struct imessaging_post_state");
730
731
0
  talloc_set_destructor(state, imessaging_post_state_destructor);
732
733
0
  ti = tevent_create_immediate(state);
734
0
  if (ti == NULL) {
735
0
    TALLOC_FREE(state);
736
0
    return ENOMEM;
737
0
  }
738
739
0
  state->msg_ctx = msg;
740
0
  state->busy_ref = NULL;
741
0
  state->buf_len = buf_len;
742
0
  memcpy(state->buf, buf, buf_len);
743
744
0
  tevent_schedule_immediate(ti, msg->ev, imessaging_post_handler,
745
0
          state);
746
747
0
  return 0;
748
0
}
749
750
static void imessaging_dgm_recv(struct tevent_context *ev,
751
        const uint8_t *buf, size_t buf_len,
752
        int *fds, size_t num_fds,
753
        void *private_data)
754
0
{
755
0
  struct imessaging_context *msg = talloc_get_type_abort(
756
0
    private_data, struct imessaging_context);
757
0
  uint32_t msg_type;
758
0
  struct server_id src, dst;
759
0
  struct server_id_buf srcbuf, dstbuf;
760
0
  DATA_BLOB data;
761
762
0
  if (buf_len < MESSAGE_HDR_LENGTH) {
763
    /* Invalid message, ignore */
764
0
    return;
765
0
  }
766
767
0
  if (msg->num_incoming_listeners == 0) {
768
0
    struct server_id_buf selfbuf;
769
770
0
    message_hdr_get(&msg_type, &src, &dst, buf);
771
772
0
    DBG_DEBUG("not listening - discarding message from "
773
0
        "src[%s] to dst[%s] (self[%s]) type=0x%x "
774
0
        "on %s event context\n",
775
0
         server_id_str_buf(src, &srcbuf),
776
0
         server_id_str_buf(dst, &dstbuf),
777
0
         server_id_str_buf(msg->server_id, &selfbuf),
778
0
         (unsigned)msg_type,
779
0
         (ev != msg->ev) ? "different" : "main");
780
0
    return;
781
0
  }
782
783
0
  if (ev != msg->ev) {
784
0
    int ret;
785
0
    ret = imessaging_post_self(msg, buf, buf_len);
786
0
    if (ret != 0) {
787
0
      DBG_WARNING("imessaging_post_self failed: %s\n",
788
0
            strerror(ret));
789
0
    }
790
0
    return;
791
0
  }
792
793
0
  message_hdr_get(&msg_type, &src, &dst, buf);
794
795
0
  data.data = discard_const_p(uint8_t, buf + MESSAGE_HDR_LENGTH);
796
0
  data.length = buf_len - MESSAGE_HDR_LENGTH;
797
798
0
  if ((cluster_id_equal(&dst, &msg->server_id)) ||
799
0
      ((dst.task_id == 0) && (msg->server_id.pid == 0))) {
800
0
    struct dispatch_fn *d, *next;
801
802
0
    DEBUG(10, ("%s: dst %s matches my id: %s, type=0x%x\n",
803
0
         __func__,
804
0
         server_id_str_buf(dst, &dstbuf),
805
0
         server_id_str_buf(msg->server_id, &srcbuf),
806
0
         (unsigned)msg_type));
807
808
0
    d = imessaging_find_dispatch(msg, msg_type);
809
810
0
    for (; d; d = next) {
811
0
      next = d->next;
812
0
      d->fn(msg,
813
0
            d->private_data,
814
0
            d->msg_type,
815
0
            src,
816
0
            num_fds,
817
0
            fds,
818
0
            &data);
819
0
    }
820
0
  } else {
821
0
    DEBUG(10, ("%s: Ignoring type=0x%x dst %s, I am %s, \n",
822
0
         __func__, (unsigned)msg_type,
823
0
         server_id_str_buf(dst, &dstbuf),
824
0
         server_id_str_buf(msg->server_id, &srcbuf)));
825
0
  }
826
0
}
827
828
/*
829
   A hack, for the short term until we get 'client only' messaging in place
830
*/
831
struct imessaging_context *imessaging_client_init(TALLOC_CTX *mem_ctx,
832
              struct loadparm_context *lp_ctx,
833
            struct tevent_context *ev)
834
0
{
835
0
  struct server_id id = {
836
0
    .pid = getpid(),
837
0
    .task_id = generate_random(),
838
0
    .vnn = NONCLUSTER_VNN,
839
840
    /* This is because we are not in the s3 serverid database */
841
0
    .unique_id = SERVERID_UNIQUE_ID_NOT_TO_VERIFY,
842
0
  };
843
844
0
  return imessaging_init_discard_incoming(mem_ctx, lp_ctx, id, ev);
845
0
}
846
847
/*
848
  a list of registered irpc server functions
849
*/
850
struct irpc_list {
851
  struct irpc_list *next, *prev;
852
  struct GUID uuid;
853
  const struct ndr_interface_table *table;
854
  int callnum;
855
  irpc_function_t fn;
856
  void *private_data;
857
};
858
859
860
/*
861
  register a irpc server function
862
*/
863
NTSTATUS irpc_register(struct imessaging_context *msg_ctx,
864
           const struct ndr_interface_table *table,
865
           int callnum, irpc_function_t fn, void *private_data)
866
0
{
867
0
  struct irpc_list *irpc;
868
869
  /* override an existing handler, if any */
870
0
  for (irpc=msg_ctx->irpc; irpc; irpc=irpc->next) {
871
0
    if (irpc->table == table && irpc->callnum == callnum) {
872
0
      break;
873
0
    }
874
0
  }
875
0
  if (irpc == NULL) {
876
0
    irpc = talloc(msg_ctx, struct irpc_list);
877
0
    NT_STATUS_HAVE_NO_MEMORY(irpc);
878
0
    DLIST_ADD(msg_ctx->irpc, irpc);
879
0
  }
880
881
0
  irpc->table   = table;
882
0
  irpc->callnum = callnum;
883
0
  irpc->fn      = fn;
884
0
  irpc->private_data = private_data;
885
0
  irpc->uuid = irpc->table->syntax_id.uuid;
886
887
0
  return NT_STATUS_OK;
888
0
}
889
890
891
/*
892
  handle an incoming irpc reply message
893
*/
894
static void irpc_handler_reply(struct imessaging_context *msg_ctx, struct irpc_message *m)
895
0
{
896
0
  struct irpc_request *irpc;
897
898
0
  irpc = (struct irpc_request *)idr_find(msg_ctx->idr, m->header.callid);
899
0
  if (irpc == NULL) return;
900
901
0
  irpc->incoming.handler(irpc, m);
902
0
}
903
904
/*
905
  send a irpc reply
906
*/
907
NTSTATUS irpc_send_reply(struct irpc_message *m, NTSTATUS status)
908
0
{
909
0
  struct ndr_push *push;
910
0
  DATA_BLOB packet;
911
0
  enum ndr_err_code ndr_err;
912
913
0
  m->header.status = status;
914
915
  /* setup the reply */
916
0
  push = ndr_push_init_ctx(m->ndr);
917
0
  if (push == NULL) {
918
0
    status = NT_STATUS_NO_MEMORY;
919
0
    goto failed;
920
0
  }
921
922
0
  m->header.flags |= IRPC_FLAG_REPLY;
923
0
  m->header.creds.token= NULL;
924
925
  /* construct the packet */
926
0
  ndr_err = ndr_push_irpc_header(push, NDR_SCALARS|NDR_BUFFERS, &m->header);
927
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
928
0
    status = ndr_map_error2ntstatus(ndr_err);
929
0
    goto failed;
930
0
  }
931
932
0
  ndr_err = m->irpc->table->calls[m->irpc->callnum].ndr_push(push, NDR_OUT, m->data);
933
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
934
0
    status = ndr_map_error2ntstatus(ndr_err);
935
0
    goto failed;
936
0
  }
937
938
  /* send the reply message */
939
0
  packet = ndr_push_blob(push);
940
0
  status = imessaging_send(m->msg_ctx, m->from, MSG_IRPC, &packet);
941
0
  if (!NT_STATUS_IS_OK(status)) goto failed;
942
943
0
failed:
944
0
  talloc_free(m);
945
0
  return status;
946
0
}
947
948
/*
949
  handle an incoming irpc request message
950
*/
951
static void irpc_handler_request(struct imessaging_context *msg_ctx,
952
         struct irpc_message *m)
953
0
{
954
0
  struct irpc_list *i;
955
0
  void *r;
956
0
  enum ndr_err_code ndr_err;
957
958
0
  for (i=msg_ctx->irpc; i; i=i->next) {
959
0
    if (GUID_equal(&i->uuid, &m->header.uuid) &&
960
0
        i->table->syntax_id.if_version == m->header.if_version &&
961
0
        i->callnum == m->header.callnum) {
962
0
      break;
963
0
    }
964
0
  }
965
966
0
  if (i == NULL) {
967
    /* no registered handler for this message */
968
0
    talloc_free(m);
969
0
    return;
970
0
  }
971
972
  /* allocate space for the structure */
973
0
  r = talloc_zero_size(m->ndr, i->table->calls[m->header.callnum].struct_size);
974
0
  if (r == NULL) goto failed;
975
976
0
  m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
977
978
  /* parse the request data */
979
0
  ndr_err = i->table->calls[i->callnum].ndr_pull(m->ndr, NDR_IN, r);
980
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
981
982
  /* make the call */
983
0
  m->private_data= i->private_data;
984
0
  m->defer_reply = false;
985
0
  m->no_reply    = false;
986
0
  m->msg_ctx     = msg_ctx;
987
0
  m->irpc        = i;
988
0
  m->data        = r;
989
990
0
  m->header.status = i->fn(m, r);
991
992
0
  if (m->no_reply) {
993
    /* the server function won't ever be replying to this request */
994
0
    talloc_free(m);
995
0
    return;
996
0
  }
997
998
0
  if (m->defer_reply) {
999
    /* the server function has asked to defer the reply to later */
1000
0
    talloc_steal(msg_ctx, m);
1001
0
    return;
1002
0
  }
1003
1004
0
  irpc_send_reply(m, m->header.status);
1005
0
  return;
1006
1007
0
failed:
1008
0
  talloc_free(m);
1009
0
}
1010
1011
/*
1012
  handle an incoming irpc message
1013
*/
1014
static void irpc_handler(struct imessaging_context *msg_ctx,
1015
       void *private_data,
1016
       uint32_t msg_type,
1017
       struct server_id src,
1018
       size_t num_fds,
1019
       int *fds,
1020
       DATA_BLOB *packet)
1021
0
{
1022
0
  struct irpc_message *m;
1023
0
  enum ndr_err_code ndr_err;
1024
1025
0
  if (num_fds != 0) {
1026
0
    DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
1027
0
    return;
1028
0
  }
1029
1030
0
  m = talloc(msg_ctx, struct irpc_message);
1031
0
  if (m == NULL) goto failed;
1032
1033
0
  m->from = src;
1034
1035
0
  m->ndr = ndr_pull_init_blob(packet, m);
1036
0
  if (m->ndr == NULL) goto failed;
1037
1038
0
  m->ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
1039
1040
0
  ndr_err = ndr_pull_irpc_header(m->ndr, NDR_BUFFERS|NDR_SCALARS, &m->header);
1041
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) goto failed;
1042
1043
0
  if (m->header.flags & IRPC_FLAG_REPLY) {
1044
0
    irpc_handler_reply(msg_ctx, m);
1045
0
  } else {
1046
0
    irpc_handler_request(msg_ctx, m);
1047
0
  }
1048
0
  return;
1049
1050
0
failed:
1051
0
  talloc_free(m);
1052
0
}
1053
1054
1055
/*
1056
  destroy a irpc request
1057
*/
1058
static int irpc_destructor(struct irpc_request *irpc)
1059
0
{
1060
0
  if (irpc->callid != -1) {
1061
0
    DLIST_REMOVE(irpc->msg_ctx->requests, irpc);
1062
0
    idr_remove(irpc->msg_ctx->idr, irpc->callid);
1063
0
    if (irpc->msg_ctx->discard_incoming) {
1064
0
      SMB_ASSERT(irpc->msg_ctx->num_incoming_listeners > 0);
1065
0
    } else {
1066
0
      SMB_ASSERT(irpc->msg_ctx->num_incoming_listeners > 1);
1067
0
    }
1068
0
    irpc->msg_ctx->num_incoming_listeners -= 1;
1069
0
    irpc->callid = -1;
1070
0
  }
1071
1072
0
  return 0;
1073
0
}
1074
1075
/*
1076
  add a string name that this irpc server can be called on
1077
1078
  It will be removed from the DB either via irpc_remove_name or on
1079
  talloc_free(msg_ctx->names).
1080
*/
1081
NTSTATUS irpc_add_name(struct imessaging_context *msg_ctx, const char *name)
1082
0
{
1083
0
  int ret;
1084
1085
0
  ret = server_id_db_add(msg_ctx->names, name);
1086
0
  if (ret != 0) {
1087
0
    return map_nt_error_from_unix_common(ret);
1088
0
  }
1089
0
  return NT_STATUS_OK;
1090
0
}
1091
1092
static int all_servers_func(const char *name, unsigned num_servers,
1093
          const struct server_id *servers,
1094
          void *private_data)
1095
0
{
1096
0
  struct irpc_name_records *name_records = talloc_get_type(
1097
0
    private_data, struct irpc_name_records);
1098
0
  struct irpc_name_record *name_record;
1099
0
  uint32_t i;
1100
1101
0
  name_records->names
1102
0
    = talloc_realloc(name_records, name_records->names,
1103
0
         struct irpc_name_record *, name_records->num_records+1);
1104
0
  if (!name_records->names) {
1105
0
    return -1;
1106
0
  }
1107
1108
0
  name_records->names[name_records->num_records] = name_record
1109
0
    = talloc(name_records->names,
1110
0
       struct irpc_name_record);
1111
0
  if (!name_record) {
1112
0
    return -1;
1113
0
  }
1114
1115
0
  name_records->num_records++;
1116
1117
0
  name_record->name = talloc_strdup(name_record, name);
1118
0
  if (!name_record->name) {
1119
0
    return -1;
1120
0
  }
1121
1122
0
  name_record->count = num_servers;
1123
0
  name_record->ids = talloc_array(name_record, struct server_id,
1124
0
          num_servers);
1125
0
  if (name_record->ids == NULL) {
1126
0
    return -1;
1127
0
  }
1128
0
  for (i=0;i<name_record->count;i++) {
1129
0
    name_record->ids[i] = servers[i];
1130
0
  }
1131
0
  return 0;
1132
0
}
1133
1134
/*
1135
  return a list of server ids for a server name
1136
*/
1137
struct irpc_name_records *irpc_all_servers(struct imessaging_context *msg_ctx,
1138
             TALLOC_CTX *mem_ctx)
1139
0
{
1140
0
  int ret;
1141
0
  struct irpc_name_records *name_records = talloc_zero(mem_ctx, struct irpc_name_records);
1142
0
  if (name_records == NULL) {
1143
0
    return NULL;
1144
0
  }
1145
1146
0
  ret = server_id_db_traverse_read(msg_ctx->names, all_servers_func,
1147
0
           name_records);
1148
0
  if (ret == -1) {
1149
0
    TALLOC_FREE(name_records);
1150
0
    return NULL;
1151
0
  }
1152
1153
0
  return name_records;
1154
0
}
1155
1156
/*
1157
  remove a name from a messaging context
1158
*/
1159
void irpc_remove_name(struct imessaging_context *msg_ctx, const char *name)
1160
0
{
1161
0
  server_id_db_remove(msg_ctx->names, name);
1162
0
}
1163
1164
struct server_id imessaging_get_server_id(struct imessaging_context *msg_ctx)
1165
0
{
1166
0
  return msg_ctx->server_id;
1167
0
}
1168
1169
struct irpc_bh_state {
1170
  struct imessaging_context *msg_ctx;
1171
  const struct dcerpc_binding *binding;
1172
  struct server_id server_id;
1173
  const struct ndr_interface_table *table;
1174
  uint32_t timeout;
1175
  struct security_token *token;
1176
};
1177
1178
static const struct dcerpc_binding *irpc_bh_get_binding(struct dcerpc_binding_handle *h)
1179
0
{
1180
0
  struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
1181
0
           struct irpc_bh_state);
1182
1183
0
  return hs->binding;
1184
0
}
1185
1186
static bool irpc_bh_is_connected(struct dcerpc_binding_handle *h)
1187
0
{
1188
0
  struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
1189
0
           struct irpc_bh_state);
1190
1191
0
  if (!hs->msg_ctx) {
1192
0
    return false;
1193
0
  }
1194
1195
0
  return true;
1196
0
}
1197
1198
static uint32_t irpc_bh_set_timeout(struct dcerpc_binding_handle *h,
1199
            uint32_t timeout)
1200
0
{
1201
0
  struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
1202
0
           struct irpc_bh_state);
1203
0
  uint32_t old = hs->timeout;
1204
1205
0
  hs->timeout = timeout;
1206
1207
0
  return old;
1208
0
}
1209
1210
struct irpc_bh_raw_call_state {
1211
  struct irpc_request *irpc;
1212
  uint32_t opnum;
1213
  DATA_BLOB in_data;
1214
  DATA_BLOB in_packet;
1215
  DATA_BLOB out_data;
1216
};
1217
1218
static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
1219
                struct irpc_message *m);
1220
1221
static struct tevent_req *irpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
1222
            struct tevent_context *ev,
1223
            struct dcerpc_binding_handle *h,
1224
            const struct GUID *object,
1225
            uint32_t opnum,
1226
            uint32_t in_flags,
1227
            const uint8_t *in_data,
1228
            size_t in_length)
1229
0
{
1230
0
  struct irpc_bh_state *hs =
1231
0
    dcerpc_binding_handle_data(h,
1232
0
    struct irpc_bh_state);
1233
0
  struct tevent_req *req;
1234
0
  struct irpc_bh_raw_call_state *state;
1235
0
  bool ok;
1236
0
  struct irpc_header header;
1237
0
  struct ndr_push *ndr;
1238
0
  NTSTATUS status;
1239
0
  enum ndr_err_code ndr_err;
1240
1241
0
  req = tevent_req_create(mem_ctx, &state,
1242
0
        struct irpc_bh_raw_call_state);
1243
0
  if (req == NULL) {
1244
0
    return NULL;
1245
0
  }
1246
0
  state->opnum = opnum;
1247
0
  state->in_data.data = discard_const_p(uint8_t, in_data);
1248
0
  state->in_data.length = in_length;
1249
1250
0
  ok = irpc_bh_is_connected(h);
1251
0
  if (!ok) {
1252
0
    tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1253
0
    return tevent_req_post(req, ev);
1254
0
  }
1255
1256
0
  state->irpc = talloc_zero(state, struct irpc_request);
1257
0
  if (tevent_req_nomem(state->irpc, req)) {
1258
0
    return tevent_req_post(req, ev);
1259
0
  }
1260
1261
0
  state->irpc->msg_ctx  = hs->msg_ctx;
1262
0
  state->irpc->callid   = idr_get_new(hs->msg_ctx->idr,
1263
0
              state->irpc, UINT16_MAX);
1264
0
  if (state->irpc->callid == -1) {
1265
0
    tevent_req_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1266
0
    return tevent_req_post(req, ev);
1267
0
  }
1268
0
  state->irpc->incoming.handler = irpc_bh_raw_call_incoming_handler;
1269
0
  state->irpc->incoming.private_data = req;
1270
1271
  /* make sure we accept incoming messages */
1272
0
  SMB_ASSERT(state->irpc->msg_ctx->num_incoming_listeners < UINT64_MAX);
1273
0
  state->irpc->msg_ctx->num_incoming_listeners += 1;
1274
0
  DLIST_ADD_END(state->irpc->msg_ctx->requests, state->irpc);
1275
0
  talloc_set_destructor(state->irpc, irpc_destructor);
1276
1277
  /* setup the header */
1278
0
  header.uuid = hs->table->syntax_id.uuid;
1279
1280
0
  header.if_version = hs->table->syntax_id.if_version;
1281
0
  header.callid     = state->irpc->callid;
1282
0
  header.callnum    = state->opnum;
1283
0
  header.flags      = 0;
1284
0
  header.status     = NT_STATUS_OK;
1285
0
  header.creds.token= hs->token;
1286
1287
  /* construct the irpc packet */
1288
0
  ndr = ndr_push_init_ctx(state->irpc);
1289
0
  if (tevent_req_nomem(ndr, req)) {
1290
0
    return tevent_req_post(req, ev);
1291
0
  }
1292
1293
0
  ndr_err = ndr_push_irpc_header(ndr, NDR_SCALARS|NDR_BUFFERS, &header);
1294
0
  status = ndr_map_error2ntstatus(ndr_err);
1295
0
  if (!NT_STATUS_IS_OK(status)) {
1296
0
    tevent_req_nterror(req, status);
1297
0
    return tevent_req_post(req, ev);
1298
0
  }
1299
1300
0
  ndr_err = ndr_push_bytes(ndr, in_data, in_length);
1301
0
  status = ndr_map_error2ntstatus(ndr_err);
1302
0
  if (!NT_STATUS_IS_OK(status)) {
1303
0
    tevent_req_nterror(req, status);
1304
0
    return tevent_req_post(req, ev);
1305
0
  }
1306
1307
  /* and send it */
1308
0
  state->in_packet = ndr_push_blob(ndr);
1309
0
  status = imessaging_send(hs->msg_ctx, hs->server_id,
1310
0
        MSG_IRPC, &state->in_packet);
1311
0
  if (!NT_STATUS_IS_OK(status)) {
1312
0
    tevent_req_nterror(req, status);
1313
0
    return tevent_req_post(req, ev);
1314
0
  }
1315
1316
0
  if (hs->timeout != IRPC_CALL_TIMEOUT_INF) {
1317
    /* set timeout-callback in case caller wants that */
1318
0
    ok = tevent_req_set_endtime(req, ev, timeval_current_ofs(hs->timeout, 0));
1319
0
    if (!ok) {
1320
0
      return tevent_req_post(req, ev);
1321
0
    }
1322
0
  }
1323
1324
0
  return req;
1325
0
}
1326
1327
static void irpc_bh_raw_call_incoming_handler(struct irpc_request *irpc,
1328
                struct irpc_message *m)
1329
0
{
1330
0
  struct tevent_req *req =
1331
0
    talloc_get_type_abort(irpc->incoming.private_data,
1332
0
    struct tevent_req);
1333
0
  struct irpc_bh_raw_call_state *state =
1334
0
    tevent_req_data(req,
1335
0
    struct irpc_bh_raw_call_state);
1336
1337
0
  talloc_steal(state, m);
1338
1339
0
  if (!NT_STATUS_IS_OK(m->header.status)) {
1340
0
    tevent_req_nterror(req, m->header.status);
1341
0
    return;
1342
0
  }
1343
1344
0
  state->out_data = data_blob_talloc(state,
1345
0
    m->ndr->data + m->ndr->offset,
1346
0
    m->ndr->data_size - m->ndr->offset);
1347
0
  if ((m->ndr->data_size - m->ndr->offset) > 0 && !state->out_data.data) {
1348
0
    tevent_req_oom(req);
1349
0
    return;
1350
0
  }
1351
1352
0
  tevent_req_done(req);
1353
0
}
1354
1355
static NTSTATUS irpc_bh_raw_call_recv(struct tevent_req *req,
1356
          TALLOC_CTX *mem_ctx,
1357
          uint8_t **out_data,
1358
          size_t *out_length,
1359
          uint32_t *out_flags)
1360
0
{
1361
0
  struct irpc_bh_raw_call_state *state =
1362
0
    tevent_req_data(req,
1363
0
    struct irpc_bh_raw_call_state);
1364
0
  NTSTATUS status;
1365
1366
0
  if (tevent_req_is_nterror(req, &status)) {
1367
0
    tevent_req_received(req);
1368
0
    return status;
1369
0
  }
1370
1371
0
  *out_data = talloc_move(mem_ctx, &state->out_data.data);
1372
0
  *out_length = state->out_data.length;
1373
0
  *out_flags = 0;
1374
0
  tevent_req_received(req);
1375
0
  return NT_STATUS_OK;
1376
0
}
1377
1378
struct irpc_bh_disconnect_state {
1379
  uint8_t _dummy;
1380
};
1381
1382
static struct tevent_req *irpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
1383
            struct tevent_context *ev,
1384
            struct dcerpc_binding_handle *h)
1385
0
{
1386
0
  struct irpc_bh_state *hs = dcerpc_binding_handle_data(h,
1387
0
             struct irpc_bh_state);
1388
0
  struct tevent_req *req;
1389
0
  struct irpc_bh_disconnect_state *state;
1390
0
  bool ok;
1391
1392
0
  req = tevent_req_create(mem_ctx, &state,
1393
0
        struct irpc_bh_disconnect_state);
1394
0
  if (req == NULL) {
1395
0
    return NULL;
1396
0
  }
1397
1398
0
  ok = irpc_bh_is_connected(h);
1399
0
  if (!ok) {
1400
0
    tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
1401
0
    return tevent_req_post(req, ev);
1402
0
  }
1403
1404
0
  hs->msg_ctx = NULL;
1405
1406
0
  tevent_req_done(req);
1407
0
  return tevent_req_post(req, ev);
1408
0
}
1409
1410
static NTSTATUS irpc_bh_disconnect_recv(struct tevent_req *req)
1411
0
{
1412
0
  NTSTATUS status;
1413
1414
0
  if (tevent_req_is_nterror(req, &status)) {
1415
0
    tevent_req_received(req);
1416
0
    return status;
1417
0
  }
1418
1419
0
  tevent_req_received(req);
1420
0
  return NT_STATUS_OK;
1421
0
}
1422
1423
static bool irpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
1424
0
{
1425
0
  return true;
1426
0
}
1427
1428
static void irpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
1429
         ndr_flags_type ndr_flags,
1430
         const void *_struct_ptr,
1431
         const struct ndr_interface_call *call)
1432
0
{
1433
0
  void *struct_ptr = discard_const(_struct_ptr);
1434
0
  bool print_in = false;
1435
0
  bool print_out = false;
1436
1437
0
  if (CHECK_DEBUGLVLC(DBGC_RPC_PARSE, 11)) {
1438
0
    print_in = true;
1439
0
    print_out = true;
1440
0
  }
1441
1442
0
  if (ndr_flags & NDR_IN) {
1443
0
    if (print_in) {
1444
0
      ndr_print_function_debug(call->ndr_print,
1445
0
             call->name,
1446
0
             ndr_flags,
1447
0
             struct_ptr);
1448
0
    }
1449
0
  }
1450
0
  if (ndr_flags & NDR_OUT) {
1451
0
    if (print_out) {
1452
0
      ndr_print_function_debug(call->ndr_print,
1453
0
             call->name,
1454
0
             ndr_flags,
1455
0
             struct_ptr);
1456
0
    }
1457
0
  }
1458
0
}
1459
1460
static const struct dcerpc_binding_handle_ops irpc_bh_ops = {
1461
  .name     = "wbint",
1462
  .get_binding    = irpc_bh_get_binding,
1463
  .is_connected   = irpc_bh_is_connected,
1464
  .set_timeout    = irpc_bh_set_timeout,
1465
  .raw_call_send    = irpc_bh_raw_call_send,
1466
  .raw_call_recv    = irpc_bh_raw_call_recv,
1467
  .disconnect_send  = irpc_bh_disconnect_send,
1468
  .disconnect_recv  = irpc_bh_disconnect_recv,
1469
1470
  .ref_alloc    = irpc_bh_ref_alloc,
1471
  .do_ndr_print   = irpc_bh_do_ndr_print,
1472
};
1473
1474
/* initialise a irpc binding handle */
1475
struct dcerpc_binding_handle *irpc_binding_handle(TALLOC_CTX *mem_ctx,
1476
              struct imessaging_context *msg_ctx,
1477
              struct server_id server_id,
1478
              const struct ndr_interface_table *table)
1479
0
{
1480
0
  struct dcerpc_binding_handle *h = NULL;
1481
0
  struct irpc_bh_state *hs = NULL;
1482
0
  struct dcerpc_binding *b = NULL;
1483
0
  NTSTATUS status;
1484
1485
0
  h = dcerpc_binding_handle_create(mem_ctx,
1486
0
           &irpc_bh_ops,
1487
0
           NULL,
1488
0
           table,
1489
0
           &hs,
1490
0
           struct irpc_bh_state,
1491
0
           __location__);
1492
0
  if (h == NULL) {
1493
0
    return NULL;
1494
0
  }
1495
0
  hs->msg_ctx = msg_ctx;
1496
0
  hs->server_id = server_id;
1497
0
  hs->table = table;
1498
0
  hs->timeout = IRPC_CALL_TIMEOUT;
1499
1500
0
  status = dcerpc_parse_binding(hs, "", &b);
1501
0
  if (!NT_STATUS_IS_OK(status)) {
1502
0
    TALLOC_FREE(h);
1503
0
    return NULL;
1504
0
  }
1505
0
  status = dcerpc_binding_set_transport(b, NCACN_INTERNAL);
1506
0
  if (!NT_STATUS_IS_OK(status)) {
1507
0
    TALLOC_FREE(h);
1508
0
    return NULL;
1509
0
  }
1510
0
  status = dcerpc_binding_set_string_option(b, "host", "localhost");
1511
0
  if (!NT_STATUS_IS_OK(status)) {
1512
0
    TALLOC_FREE(h);
1513
0
    return NULL;
1514
0
  }
1515
0
  status = dcerpc_binding_set_string_option(b, "endpoint", "irpc");
1516
0
  if (!NT_STATUS_IS_OK(status)) {
1517
0
    TALLOC_FREE(h);
1518
0
    return NULL;
1519
0
  }
1520
0
  status = dcerpc_binding_set_abstract_syntax(b, &table->syntax_id);
1521
0
  if (!NT_STATUS_IS_OK(status)) {
1522
0
    TALLOC_FREE(h);
1523
0
    return NULL;
1524
0
  }
1525
1526
0
  hs->binding = b;
1527
1528
0
  return h;
1529
0
}
1530
1531
struct dcerpc_binding_handle *irpc_binding_handle_by_name(TALLOC_CTX *mem_ctx,
1532
                struct imessaging_context *msg_ctx,
1533
                const char *dest_task,
1534
                const struct ndr_interface_table *table)
1535
0
{
1536
0
  struct dcerpc_binding_handle *h;
1537
0
  unsigned num_sids;
1538
0
  struct server_id *sids;
1539
0
  struct server_id sid;
1540
0
  NTSTATUS status;
1541
1542
  /* find the server task */
1543
1544
0
  status = irpc_servers_byname(msg_ctx, mem_ctx, dest_task,
1545
0
             &num_sids, &sids);
1546
0
  if (!NT_STATUS_IS_OK(status)) {
1547
0
    errno = EADDRNOTAVAIL;
1548
0
    return NULL;
1549
0
  }
1550
0
  sid = sids[0];
1551
0
  talloc_free(sids);
1552
1553
0
  h = irpc_binding_handle(mem_ctx, msg_ctx,
1554
0
        sid, table);
1555
0
  if (h == NULL) {
1556
0
    return NULL;
1557
0
  }
1558
1559
0
  return h;
1560
0
}
1561
1562
void irpc_binding_handle_add_security_token(struct dcerpc_binding_handle *h,
1563
              struct security_token *token)
1564
0
{
1565
0
  struct irpc_bh_state *hs =
1566
0
    dcerpc_binding_handle_data(h,
1567
0
    struct irpc_bh_state);
1568
1569
0
  hs->token = token;
1570
0
}