LCOV - code coverage report
Current view: top level - source4/lib/messaging - messaging.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 432 584 74.0 %
Date: 2024-06-13 04:01:37 Functions: 39 46 84.8 %

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

Generated by: LCOV version 1.13