LCOV - code coverage report
Current view: top level - source4/lib/messaging - messaging.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 437 595 73.4 %
Date: 2024-02-14 10:14:15 Functions: 40 47 85.1 %

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

Generated by: LCOV version 1.14