LCOV - code coverage report
Current view: top level - source3/rpc_server - rpc_worker.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 355 534 66.5 %
Date: 2024-02-29 22:57:05 Functions: 19 21 90.5 %

          Line data    Source code
       1             : /*
       2             :  *  Unix SMB/CIFS implementation.
       3             :  *
       4             :  *  This program is free software; you can redistribute it and/or modify
       5             :  *  it under the terms of the GNU General Public License as published by
       6             :  *  the Free Software Foundation; either version 3 of the License, or
       7             :  *  (at your option) any later version.
       8             :  *
       9             :  *  This program is distributed in the hope that it will be useful,
      10             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  *  GNU General Public License for more details.
      13             :  *
      14             :  *  You should have received a copy of the GNU General Public License
      15             :  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "source3/include/includes.h"
      19             : #include "lib/cmdline/cmdline.h"
      20             : #include "rpc_worker.h"
      21             : #include "rpc_config.h"
      22             : #include "librpc/rpc/dcesrv_core.h"
      23             : #include "librpc/rpc/dcerpc_util.h"
      24             : #include "source3/librpc/gen_ndr/ndr_rpc_host.h"
      25             : #include "lib/util/debug.h"
      26             : #include "lib/util/fault.h"
      27             : #include "rpc_server.h"
      28             : #include "rpc_pipes.h"
      29             : #include "source3/smbd/proto.h"
      30             : #include "source3/lib/smbd_shim.h"
      31             : #include "source3/lib/global_contexts.h"
      32             : #include "source3/lib/util_procid.h"
      33             : #include "lib/tsocket/tsocket.h"
      34             : #include "libcli/named_pipe_auth/npa_tstream.h"
      35             : #include "libcli/smb/smb_constants.h"
      36             : #include "lib/param/param.h"
      37             : #include "lib/util/idtree_random.h"
      38             : #include "lib/util/tevent_unix.h"
      39             : #include "lib/async_req/async_sock.h"
      40             : #include "lib/util/dlinklist.h"
      41             : #include "source3/include/auth.h"
      42             : #include "nsswitch/winbind_client.h"
      43             : #include "source3/include/messages.h"
      44             : #include "libcli/security/security_token.h"
      45             : #include "libcli/security/dom_sid.h"
      46             : #include "source3/include/proto.h"
      47             : 
      48             : /*
      49             :  * This is the generic code that becomes the
      50             :  * template that all rpcd_* instances that
      51             :  * serve DCERPC can use to provide services to samba-dcerpcd.
      52             :  *
      53             :  * The external entry point is:
      54             :  * rpc_worker_main() which takes an argc/argv list
      55             :  * and two functions:
      56             :  *
      57             :  * get_interfaces() - List all interfaces that this server provides
      58             :  * get_servers() - Provide the RPC server implementations
      59             :  *
      60             :  * Each rpcd_* service needs only to provide
      61             :  * the implementations of get_interfaces() and get_servers()
      62             :  * and call rpc_worker_main() from their main() function
      63             :  * to provide services that can be connected to from samba-dcerpcd.
      64             :  */
      65             : 
      66             : struct rpc_worker {
      67             :         struct dcerpc_ncacn_conn *conns;
      68             :         struct server_id rpc_host_pid;
      69             :         struct messaging_context *msg_ctx;
      70             :         struct dcesrv_context *dce_ctx;
      71             : 
      72             :         struct dcesrv_context_callbacks cb;
      73             : 
      74             :         struct rpc_worker_status status;
      75             : 
      76             :         bool done;
      77             : };
      78             : 
      79        1498 : static void rpc_worker_print_interface(
      80             :         FILE *f, const struct ndr_interface_table *t)
      81             : {
      82        1498 :         const struct ndr_interface_string_array *endpoints = t->endpoints;
      83             :         uint32_t i;
      84             :         struct ndr_syntax_id_buf id_buf;
      85             : 
      86        1498 :         fprintf(f,
      87             :                 "%s %s\n",
      88             :                 ndr_syntax_id_buf_string(&t->syntax_id, &id_buf),
      89        1498 :                 t->name);
      90             : 
      91        5275 :         for (i=0; i<endpoints->count; i++) {
      92        3777 :                 fprintf(f, " %s\n", endpoints->names[i]);
      93             :         }
      94        1498 : }
      95             : 
      96       36204 : static NTSTATUS rpc_worker_report_status(struct rpc_worker *worker)
      97             : {
      98             :         uint8_t buf[16];
      99       36204 :         DATA_BLOB blob = { .data = buf, .length = sizeof(buf), };
     100             :         enum ndr_err_code ndr_err;
     101             :         NTSTATUS status;
     102             : 
     103       36204 :         worker->status.num_association_groups = worker->dce_ctx->assoc_groups_num;
     104             : 
     105       36204 :         if (DEBUGLEVEL >= 10) {
     106           0 :                 NDR_PRINT_DEBUG(rpc_worker_status, &worker->status);
     107             :         }
     108             : 
     109       36204 :         ndr_err = ndr_push_struct_into_fixed_blob(
     110             :                 &blob,
     111       36204 :                 &worker->status,
     112             :                 (ndr_push_flags_fn_t)ndr_push_rpc_worker_status);
     113       36204 :         SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
     114             : 
     115       36204 :         status = messaging_send(
     116             :                 worker->msg_ctx,
     117             :                 worker->rpc_host_pid,
     118             :                 MSG_RPC_WORKER_STATUS,
     119             :                 &blob);
     120       36204 :         return status;
     121             : }
     122             : 
     123       35606 : static void rpc_worker_connection_terminated(
     124             :         struct dcesrv_connection *conn, void *private_data)
     125             : {
     126       35606 :         struct rpc_worker *worker = talloc_get_type_abort(
     127             :                 private_data, struct rpc_worker);
     128       35606 :         struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
     129             :                 conn->transport.private_data, struct dcerpc_ncacn_conn);
     130       35606 :         struct dcerpc_ncacn_conn *w = NULL;
     131             :         NTSTATUS status;
     132       35606 :         bool found = false;
     133             : 
     134             :         /*
     135             :          * We need to drop the association group reference
     136             :          * explicitly here in order to avoid the order given
     137             :          * by the destructors. rpc_worker_report_status() below,
     138             :          * expects worker->dce_ctx->assoc_groups_num to be updated
     139             :          * already.
     140             :          */
     141       35606 :         if (conn->assoc_group != NULL) {
     142       35599 :                 talloc_unlink(conn, conn->assoc_group);
     143       35599 :                 conn->assoc_group = NULL;
     144             :         }
     145             : 
     146       35606 :         SMB_ASSERT(worker->status.num_connections > 0);
     147             : 
     148       35788 :         for (w = worker->conns; w != NULL; w = w->next) {
     149       35788 :                 if (w == ncacn_conn) {
     150       35606 :                         found = true;
     151       35606 :                         break;
     152             :                 }
     153             :         }
     154       35606 :         SMB_ASSERT(found);
     155             : 
     156       35606 :         DLIST_REMOVE(worker->conns, ncacn_conn);
     157             : 
     158       35606 :         worker->status.num_connections -= 1;
     159             : 
     160       35606 :         status = rpc_worker_report_status(worker);
     161       35606 :         if (!NT_STATUS_IS_OK(status)) {
     162           0 :                 DBG_DEBUG("rpc_worker_report_status returned %s\n",
     163             :                           nt_errstr(status));
     164             :         }
     165       35606 : }
     166             : 
     167       35606 : static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
     168             : {
     169       35606 :         struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
     170             :                         conn->transport.private_data,
     171             :                         struct dcerpc_ncacn_conn);
     172             : 
     173       35606 :         if (ncacn_conn->termination_fn != NULL) {
     174       35606 :                 ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
     175             :         }
     176             : 
     177       35606 :         return 0;
     178             : }
     179             : 
     180             : /*
     181             :  * A new client has been passed to us from samba-dcerpcd.
     182             :  */
     183       35606 : static void rpc_worker_new_client(
     184             :         struct rpc_worker *worker,
     185             :         struct rpc_host_client *client,
     186             :         int sock)
     187             : {
     188       35606 :         struct dcesrv_context *dce_ctx = worker->dce_ctx;
     189       35606 :         struct named_pipe_auth_req_info8 *info8 = client->npa_info8;
     190       35606 :         struct tsocket_address *remote_client_addr = NULL;
     191       35606 :         struct tsocket_address *local_server_addr = NULL;
     192       35606 :         struct dcerpc_binding *b = NULL;
     193             :         enum dcerpc_transport_t transport;
     194       35606 :         struct dcesrv_endpoint *ep = NULL;
     195       35606 :         struct tstream_context *tstream = NULL;
     196       35606 :         struct dcerpc_ncacn_conn *ncacn_conn = NULL;
     197       35606 :         struct dcesrv_connection *dcesrv_conn = NULL;
     198       35606 :         DATA_BLOB buffer = { .data = NULL };
     199       35606 :         struct ncacn_packet *pkt = NULL;
     200       35606 :         struct security_token *token = NULL;
     201             :         uint32_t npa_flags, state_flags;
     202             :         bool found_npa_flags;
     203             :         NTSTATUS status;
     204             :         int ret;
     205             : 
     206       35606 :         DBG_DEBUG("Got new conn sock %d for binding %s\n",
     207             :                   sock,
     208             :                   client->binding);
     209             : 
     210       35606 :         status = dcerpc_parse_binding(client, client->binding, &b);
     211       35606 :         if (!NT_STATUS_IS_OK(status)) {
     212           0 :                 DBG_DEBUG("dcerpc_parse_binding(%s) failed: %s\n",
     213             :                           client->binding,
     214             :                           nt_errstr(status));
     215           0 :                 goto fail;
     216             :         }
     217       35606 :         transport = dcerpc_binding_get_transport(b);
     218             : 
     219       35606 :         status = dcesrv_find_endpoint(dce_ctx, b, &ep);
     220             : 
     221       35606 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) &&
     222          90 :             ((transport == NCACN_IP_TCP) || (transport == NCALRPC)) &&
     223          90 :             (dcerpc_binding_get_string_option(b, "endpoint") != NULL)) {
     224             :                 /*
     225             :                  * We have two kinds of servers: Those who explicitly
     226             :                  * bind to a port (e.g. 135 for epmapper) and those
     227             :                  * who just specify a transport. The client specified
     228             :                  * a port (or socket name), but we did not find this
     229             :                  * in the list of servers having specified a
     230             :                  * port. Retry just matching for the transport,
     231             :                  * catching the servers that did not explicitly
     232             :                  * specify a port.
     233             :                  *
     234             :                  * This is not fully correct, what we should do is
     235             :                  * that once the port the server listens on has been
     236             :                  * finalized we should mark this in the server list,
     237             :                  * but for now it works. We don't have the same RPC
     238             :                  * interface listening twice on different ports.
     239             :                  */
     240          90 :                 struct dcerpc_binding *b_without_port = dcerpc_binding_dup(
     241             :                         client, b);
     242          90 :                 if (b_without_port == NULL) {
     243           0 :                         status = NT_STATUS_NO_MEMORY;
     244           0 :                         goto fail;
     245             :                 }
     246             : 
     247          90 :                 status = dcerpc_binding_set_string_option(
     248             :                         b_without_port, "endpoint", NULL);
     249          90 :                 if (!NT_STATUS_IS_OK(status)) {
     250           0 :                         DBG_DEBUG("Could not delete endpoint: %s\n",
     251             :                                   nt_errstr(status));
     252           0 :                         TALLOC_FREE(b_without_port);
     253           0 :                         goto fail;
     254             :                 }
     255             : 
     256          90 :                 status = dcesrv_find_endpoint(dce_ctx, b_without_port, &ep);
     257             : 
     258          90 :                 TALLOC_FREE(b_without_port);
     259             :         }
     260             : 
     261       35606 :         if (!NT_STATUS_IS_OK(status)) {
     262           0 :                 DBG_DEBUG("Could not find endpoint for %s: %s\n",
     263             :                           client->binding,
     264             :                           nt_errstr(status));
     265           0 :                 goto fail;
     266             :         }
     267             : 
     268       35606 :         ncacn_conn = talloc(dce_ctx, struct dcerpc_ncacn_conn);
     269       35606 :         if (ncacn_conn == NULL) {
     270           0 :                 DBG_DEBUG("talloc failed\n");
     271           0 :                 goto fail;
     272             :         }
     273       35606 :         *ncacn_conn = (struct dcerpc_ncacn_conn) {
     274             :                 .endpoint = ep,
     275             :                 .sock = sock,
     276             :                 .termination_fn = rpc_worker_connection_terminated,
     277             :                 .termination_data = worker,
     278             :         };
     279             : 
     280       35606 :         if (transport == NCALRPC) {
     281         138 :                 ret = tsocket_address_unix_from_path(ncacn_conn,
     282             :                                                      info8->remote_client_addr,
     283             :                                                      &remote_client_addr);
     284         138 :                 if (ret == -1) {
     285           0 :                         DBG_DEBUG("tsocket_address_unix_from_path"
     286             :                                   "(%s) failed: %s\n",
     287             :                                   info8->remote_client_addr,
     288             :                                   strerror(errno));
     289           0 :                         goto fail;
     290             :                 }
     291             : 
     292         138 :                 ncacn_conn->remote_client_name =
     293         138 :                         talloc_strdup(ncacn_conn, info8->remote_client_name);
     294         138 :                 if (ncacn_conn->remote_client_name == NULL) {
     295           0 :                         DBG_DEBUG("talloc_strdup(%s) failed\n",
     296             :                                   info8->remote_client_name);
     297           0 :                         goto fail;
     298             :                 }
     299             : 
     300         138 :                 ret = tsocket_address_unix_from_path(ncacn_conn,
     301             :                                                      info8->local_server_addr,
     302             :                                                      &local_server_addr);
     303         138 :                 if (ret == -1) {
     304           0 :                         DBG_DEBUG("tsocket_address_unix_from_path"
     305             :                                   "(%s) failed: %s\n",
     306             :                                   info8->local_server_addr,
     307             :                                   strerror(errno));
     308           0 :                         goto fail;
     309             :                 }
     310             : 
     311         138 :                 ncacn_conn->local_server_name =
     312         138 :                         talloc_strdup(ncacn_conn, info8->local_server_name);
     313         138 :                 if (ncacn_conn->local_server_name == NULL) {
     314           0 :                         DBG_DEBUG("talloc_strdup(%s) failed\n",
     315             :                                   info8->local_server_name);
     316           0 :                         goto fail;
     317             :                 }
     318             :         } else {
     319       35468 :                 ret = tsocket_address_inet_from_strings(
     320             :                         ncacn_conn,
     321             :                         "ip",
     322             :                         info8->remote_client_addr,
     323             :                         info8->remote_client_port,
     324             :                         &remote_client_addr);
     325       35468 :                 if (ret == -1) {
     326           0 :                         DBG_DEBUG("tsocket_address_inet_from_strings"
     327             :                                   "(%s, %" PRIu16 ") failed: %s\n",
     328             :                                   info8->remote_client_addr,
     329             :                                   info8->remote_client_port,
     330             :                                   strerror(errno));
     331           0 :                         goto fail;
     332             :                 }
     333       35468 :                 ncacn_conn->remote_client_name =
     334       35468 :                         talloc_strdup(ncacn_conn, info8->remote_client_name);
     335       35468 :                 if (ncacn_conn->remote_client_name == NULL) {
     336           0 :                         DBG_DEBUG("talloc_strdup(%s) failed\n",
     337             :                                   info8->remote_client_name);
     338           0 :                         goto fail;
     339             :                 }
     340             : 
     341       35468 :                 ret = tsocket_address_inet_from_strings(
     342             :                         ncacn_conn,
     343             :                         "ip",
     344             :                         info8->local_server_addr,
     345             :                         info8->local_server_port,
     346             :                         &local_server_addr);
     347       35468 :                 if (ret == -1) {
     348           0 :                         DBG_DEBUG("tsocket_address_inet_from_strings"
     349             :                                   "(%s, %" PRIu16 ") failed: %s\n",
     350             :                                   info8->local_server_addr,
     351             :                                   info8->local_server_port,
     352             :                                   strerror(errno));
     353           0 :                         goto fail;
     354             :                 }
     355       35468 :                 ncacn_conn->local_server_name =
     356       35468 :                         talloc_strdup(ncacn_conn, info8->local_server_name);
     357       35468 :                 if (ncacn_conn->local_server_name == NULL) {
     358           0 :                         DBG_DEBUG("talloc_strdup(%s) failed\n",
     359             :                                   info8->local_server_name);
     360           0 :                         goto fail;
     361             :                 }
     362             :         }
     363             : 
     364       35606 :         if (transport == NCACN_NP) {
     365       34752 :                 ret = tstream_npa_existing_socket(
     366             :                         ncacn_conn,
     367             :                         sock,
     368             :                         FILE_TYPE_MESSAGE_MODE_PIPE,
     369             :                         &tstream);
     370       34752 :                 if (ret == -1) {
     371           0 :                         DBG_DEBUG("tstream_npa_existing_socket failed: %s\n",
     372             :                                   strerror(errno));
     373           0 :                         goto fail;
     374             :                 }
     375             : 
     376             :                 /*
     377             :                  * "transport" so far is implicitly assigned by the
     378             :                  * socket that the client connected to, passed in from
     379             :                  * samba-dcerpcd via the binding. For NCACN_NP (root
     380             :                  * only by unix permissions) we got a
     381             :                  * named_pipe_auth_req_info8 where the transport can
     382             :                  * be overridden.
     383             :                  */
     384       34752 :                 transport = info8->transport;
     385             :         } else {
     386         854 :                 ret = tstream_bsd_existing_socket(
     387             :                         ncacn_conn, sock, &tstream);
     388         854 :                 if (ret == -1) {
     389           0 :                         DBG_DEBUG("tstream_bsd_existing_socket failed: %s\n",
     390             :                                   strerror(errno));
     391           0 :                         goto fail;
     392             :                 }
     393             :                 /* as server we want to fail early */
     394         854 :                 tstream_bsd_fail_readv_first_error(tstream, true);
     395             :         }
     396       35606 :         sock = -1;
     397             : 
     398       35606 :         token = info8->session_info->session_info->security_token;
     399             : 
     400       35606 :         if (security_token_is_system(token) && (transport != NCALRPC)) {
     401           0 :                 DBG_DEBUG("System token only allowed on NCALRPC\n");
     402           0 :                 goto fail;
     403             :         }
     404             : 
     405       35606 :         state_flags = DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
     406             : 
     407       35606 :         found_npa_flags = security_token_find_npa_flags(token, &npa_flags);
     408       35606 :         if (found_npa_flags) {
     409       34752 :                 if (npa_flags & SAMBA_NPA_FLAGS_WINBIND_OFF) {
     410         234 :                         state_flags |=
     411             :                                 DCESRV_CALL_STATE_FLAG_WINBIND_OFF;
     412             :                 }
     413             : 
     414             :                 /*
     415             :                  * Delete the flags so that we don't bail in
     416             :                  * local_np_connect_send() on subsequent
     417             :                  * connects. Once we connect to another RPC service, a
     418             :                  * new flags sid will be added if required.
     419             :                  */
     420       34752 :                 security_token_del_npa_flags(token);
     421             :         }
     422             : 
     423       35606 :         ncacn_conn->p.msg_ctx = global_messaging_context();
     424       35606 :         ncacn_conn->p.transport = transport;
     425             : 
     426       35606 :         status = dcesrv_endpoint_connect(dce_ctx,
     427             :                                          ncacn_conn,
     428             :                                          ep,
     429       35606 :                                          info8->session_info->session_info,
     430             :                                          global_event_context(),
     431             :                                          state_flags,
     432             :                                          &dcesrv_conn);
     433       35606 :         if (!NT_STATUS_IS_OK(status)) {
     434           0 :                 DBG_DEBUG("Failed to connect to endpoint: %s\n",
     435             :                           nt_errstr(status));
     436           0 :                 goto fail;
     437             :         }
     438             : 
     439       35606 :         talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
     440             : 
     441       35606 :         dcesrv_conn->transport.private_data = ncacn_conn;
     442       35606 :         dcesrv_conn->transport.report_output_data =
     443             :                 dcesrv_sock_report_output_data;
     444       35606 :         dcesrv_conn->transport.terminate_connection =
     445             :                 dcesrv_transport_terminate_connection;
     446             : 
     447       35606 :         dcesrv_conn->send_queue = tevent_queue_create(
     448             :                 dcesrv_conn, "dcesrv send queue");
     449       35606 :         if (dcesrv_conn->send_queue == NULL) {
     450           0 :                 DBG_DEBUG("tevent_queue_create failed\n");
     451           0 :                 goto fail;
     452             :         }
     453             : 
     454       35606 :         dcesrv_conn->stream = talloc_move(dcesrv_conn, &tstream);
     455       71212 :         dcesrv_conn->local_address =
     456       35606 :                 talloc_move(dcesrv_conn, &local_server_addr);
     457       71212 :         dcesrv_conn->remote_address =
     458       35606 :                 talloc_move(dcesrv_conn, &remote_client_addr);
     459             : 
     460       35606 :         if (client->bind_packet.length == 0) {
     461           0 :                 DBG_DEBUG("Expected bind packet\n");
     462           0 :                 goto fail;
     463             :         }
     464             : 
     465       35606 :         buffer = (DATA_BLOB) {
     466       35606 :                 .data = talloc_move(dcesrv_conn, &client->bind_packet.data),
     467       35606 :                 .length = client->bind_packet.length,
     468             :         };
     469             : 
     470       35606 :         pkt = talloc(dcesrv_conn, struct ncacn_packet);
     471       35606 :         if (pkt == NULL) {
     472           0 :                 DBG_DEBUG("talloc failed\n");
     473           0 :                 goto fail;
     474             :         }
     475             : 
     476       35606 :         status = dcerpc_pull_ncacn_packet(pkt, &buffer, pkt);
     477       35606 :         if (!NT_STATUS_IS_OK(status)) {
     478           0 :                 DBG_DEBUG("dcerpc_pull_ncacn_packet failed: %s\n",
     479             :                           nt_errstr(status));
     480           0 :                 goto fail;
     481             :         }
     482             : 
     483       35606 :         TALLOC_FREE(client);
     484             : 
     485       35606 :         DLIST_ADD(worker->conns, ncacn_conn);
     486       35606 :         worker->status.num_connections += 1;
     487             : 
     488       35606 :         dcesrv_loop_next_packet(dcesrv_conn, pkt, buffer);
     489             : 
     490       35606 :         return;
     491           0 : fail:
     492           0 :         TALLOC_FREE(ncacn_conn);
     493           0 :         TALLOC_FREE(dcesrv_conn);
     494           0 :         TALLOC_FREE(client);
     495           0 :         if (sock != -1) {
     496           0 :                 close(sock);
     497             :         }
     498             : 
     499             :         /*
     500             :          * Parent thinks it successfully sent us a client. Tell it
     501             :          * that we declined.
     502             :          */
     503           0 :         status = rpc_worker_report_status(worker);
     504           0 :         if (!NT_STATUS_IS_OK(status)) {
     505           0 :                 DBG_DEBUG("rpc_worker_report_status returned %s\n",
     506             :                           nt_errstr(status));
     507             :         }
     508             : }
     509             : 
     510             : /*
     511             :  * New client message processing.
     512             :  */
     513       39558 : static bool rpc_worker_new_client_filter(
     514             :         struct messaging_rec *rec, void *private_data)
     515             : {
     516       39558 :         struct rpc_worker *worker = talloc_get_type_abort(
     517             :                 private_data, struct rpc_worker);
     518       39558 :         struct dcesrv_context *dce_ctx = worker->dce_ctx;
     519       39558 :         struct rpc_host_client *client = NULL;
     520             :         enum ndr_err_code ndr_err;
     521             :         int sock;
     522             : 
     523       39558 :         if (rec->msg_type != MSG_RPC_HOST_NEW_CLIENT) {
     524        3952 :                 return false;
     525             :         }
     526             : 
     527       35606 :         if (rec->num_fds != 1) {
     528           0 :                 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
     529           0 :                 return false;
     530             :         }
     531             : 
     532       35606 :         client = talloc(dce_ctx, struct rpc_host_client);
     533       35606 :         if (client == NULL) {
     534           0 :                 DBG_DEBUG("talloc failed\n");
     535           0 :                 return false;
     536             :         }
     537             : 
     538       35606 :         ndr_err = ndr_pull_struct_blob_all(
     539       35606 :                 &rec->buf,
     540             :                 client,
     541             :                 client,
     542             :                 (ndr_pull_flags_fn_t)ndr_pull_rpc_host_client);
     543       35606 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     544           0 :                 DBG_DEBUG("ndr_pull_rpc_host_client failed: %s\n",
     545             :                           ndr_errstr(ndr_err));
     546           0 :                 TALLOC_FREE(client);
     547           0 :                 return false;
     548             :         }
     549             : 
     550       35606 :         if (DEBUGLEVEL >= 10) {
     551           0 :                 NDR_PRINT_DEBUG(rpc_host_client, client);
     552             :         }
     553             : 
     554       35606 :         sock = rec->fds[0];
     555       35606 :         rec->fds[0] = -1;
     556             : 
     557       35606 :         rpc_worker_new_client(worker, client, sock);
     558             : 
     559       35606 :         return false;
     560             : }
     561             : 
     562             : /*
     563             :  * Return your status message processing.
     564             :  */
     565       39558 : static bool rpc_worker_status_filter(
     566             :         struct messaging_rec *rec, void *private_data)
     567             : {
     568       39558 :         struct rpc_worker *worker = talloc_get_type_abort(
     569             :                 private_data, struct rpc_worker);
     570       39558 :         struct dcerpc_ncacn_conn *conn = NULL;
     571       39558 :         FILE *f = NULL;
     572             :         int fd;
     573             : 
     574       39558 :         if (rec->msg_type != MSG_RPC_DUMP_STATUS) {
     575       39558 :                 return false;
     576             :         }
     577             : 
     578           0 :         if (rec->num_fds != 1) {
     579           0 :                 DBG_DEBUG("Got %"PRIu8" fds\n", rec->num_fds);
     580           0 :                 return false;
     581             :         }
     582             : 
     583           0 :         fd = dup(rec->fds[0]);
     584           0 :         if (fd == -1) {
     585           0 :                 DBG_DEBUG("dup(%"PRIi64") failed: %s\n",
     586             :                           rec->fds[0],
     587             :                           strerror(errno));
     588           0 :                 return false;
     589             :         }
     590             : 
     591           0 :         f = fdopen(fd, "w");
     592           0 :         if (f == NULL) {
     593           0 :                 DBG_DEBUG("fdopen failed: %s\n", strerror(errno));
     594           0 :                 close(fd);
     595           0 :                 return false;
     596             :         }
     597             : 
     598           0 :         for (conn = worker->conns; conn != NULL; conn = conn->next) {
     599           0 :                 char *endpoint = NULL;
     600             : 
     601           0 :                 endpoint = dcerpc_binding_string(
     602           0 :                         conn, conn->endpoint->ep_description);
     603             : 
     604           0 :                 fprintf(f,
     605             :                         "endpoint=%s client=%s server=%s\n",
     606             :                         endpoint ? endpoint : "UNKNOWN",
     607             :                         conn->remote_client_name,
     608             :                         conn->local_server_name);
     609           0 :                 TALLOC_FREE(endpoint);
     610             :         }
     611             : 
     612           0 :         fclose(f);
     613             : 
     614           0 :         return false;
     615             : }
     616             : 
     617             : /*
     618             :   take a reference to an existing association group
     619             :  */
     620          24 : static struct dcesrv_assoc_group *rpc_worker_assoc_group_reference(
     621             :         struct dcesrv_connection *conn,
     622             :         uint32_t id)
     623             : {
     624          24 :         const struct dcesrv_endpoint *endpoint = conn->endpoint;
     625          24 :         enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
     626          24 :                 endpoint->ep_description);
     627          24 :         struct dcesrv_assoc_group *assoc_group = NULL;
     628          24 :         void *id_ptr = NULL;
     629             : 
     630             :         /* find an association group given a assoc_group_id */
     631          24 :         id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, id & UINT16_MAX);
     632          24 :         if (id_ptr == NULL) {
     633           5 :                 DBG_NOTICE("Failed to find assoc_group 0x%08x\n", id);
     634           5 :                 return NULL;
     635             :         }
     636          19 :         assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
     637             : 
     638          19 :         if (assoc_group->transport != transport) {
     639           0 :                 const char *at = derpc_transport_string_by_transport(
     640             :                         assoc_group->transport);
     641           0 :                 const char *ct = derpc_transport_string_by_transport(
     642             :                         transport);
     643             : 
     644           0 :                 DBG_NOTICE("assoc_group 0x%08x (transport %s) "
     645             :                            "is not available on transport %s\n",
     646             :                            id, at, ct);
     647           0 :                 return NULL;
     648             :         }
     649             : 
     650             :         /*
     651             :          * Yes, this is a talloc_reference: The assoc group must be
     652             :          * removed when all connections go. This should be replaced by
     653             :          * adding a linked list of dcesrv_connection structs to the
     654             :          * assoc group.
     655             :          */
     656          19 :         return talloc_reference(conn, assoc_group);
     657             : }
     658             : 
     659       35580 : static int rpc_worker_assoc_group_destructor(
     660             :         struct dcesrv_assoc_group *assoc_group)
     661             : {
     662             :         int ret;
     663             : 
     664       35580 :         ret = idr_remove(
     665       35580 :                 assoc_group->dce_ctx->assoc_groups_idr,
     666       35580 :                 assoc_group->id & UINT16_MAX);
     667       35580 :         if (ret != 0) {
     668           0 :                 DBG_WARNING("Failed to remove assoc_group 0x%08x\n",
     669             :                             assoc_group->id);
     670             :         }
     671             : 
     672       35580 :         SMB_ASSERT(assoc_group->dce_ctx->assoc_groups_num > 0);
     673       35580 :         assoc_group->dce_ctx->assoc_groups_num -= 1;
     674       35580 :         return 0;
     675             : }
     676             : 
     677             : /*
     678             :   allocate a new association group
     679             :  */
     680       35580 : static struct dcesrv_assoc_group *rpc_worker_assoc_group_new(
     681             :         struct dcesrv_connection *conn, uint16_t worker_index)
     682             : {
     683       35580 :         struct dcesrv_context *dce_ctx = conn->dce_ctx;
     684       35580 :         const struct dcesrv_endpoint *endpoint = conn->endpoint;
     685       35580 :         enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
     686       35580 :                 endpoint->ep_description);
     687       35580 :         struct dcesrv_assoc_group *assoc_group = NULL;
     688             :         int id;
     689             : 
     690       35580 :         assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
     691       35580 :         if (assoc_group == NULL) {
     692           0 :                 return NULL;
     693             :         }
     694             : 
     695             :         /*
     696             :          * We use 16-bit to encode the worker index,
     697             :          * have 16-bits left within the worker to form a
     698             :          * 32-bit association group id.
     699             :          */
     700       35580 :         id = idr_get_new_random(
     701             :                 dce_ctx->assoc_groups_idr, assoc_group, 1, UINT16_MAX);
     702       35580 :         if (id == -1) {
     703           0 :                 talloc_free(assoc_group);
     704           0 :                 DBG_WARNING("Out of association groups!\n");
     705           0 :                 return NULL;
     706             :         }
     707       35580 :         assoc_group->id = (((uint32_t)worker_index) << 16) | id;
     708       35580 :         assoc_group->transport = transport;
     709       35580 :         assoc_group->dce_ctx = dce_ctx;
     710             : 
     711       35580 :         talloc_set_destructor(assoc_group, rpc_worker_assoc_group_destructor);
     712             : 
     713       35580 :         SMB_ASSERT(dce_ctx->assoc_groups_num < UINT16_MAX);
     714       35580 :         dce_ctx->assoc_groups_num += 1;
     715             : 
     716       35580 :         return assoc_group;
     717             : }
     718             : 
     719       35604 : static NTSTATUS rpc_worker_assoc_group_find(
     720             :         struct dcesrv_call_state *call,
     721             :         void *private_data)
     722             : {
     723       35604 :         struct rpc_worker *w = talloc_get_type_abort(
     724             :                 private_data, struct rpc_worker);
     725       35604 :         uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
     726             : 
     727       35604 :         if (assoc_group_id != 0) {
     728          24 :                 uint16_t worker_index = (assoc_group_id & 0xffff0000) >> 16;
     729          24 :                 if (worker_index != w->status.worker_index) {
     730           0 :                         DBG_DEBUG("Wrong worker id %"PRIu16", "
     731             :                                   "expected %"PRIu32"\n",
     732             :                                   worker_index,
     733             :                                   w->status.worker_index);
     734           0 :                         return NT_STATUS_NOT_FOUND;
     735             :                 }
     736          24 :                 call->conn->assoc_group = rpc_worker_assoc_group_reference(
     737             :                         call->conn, assoc_group_id);
     738             :         } else {
     739       35580 :                 call->conn->assoc_group = rpc_worker_assoc_group_new(
     740       35580 :                         call->conn, w->status.worker_index);
     741             :         }
     742             : 
     743       35604 :         if (call->conn->assoc_group == NULL) {
     744             :                 /* TODO Return correct status */
     745           5 :                 return NT_STATUS_UNSUCCESSFUL;
     746             :         }
     747             : 
     748       35599 :         return NT_STATUS_OK;
     749             : }
     750             : 
     751         598 : static struct rpc_worker *rpc_worker_new(
     752             :         TALLOC_CTX *mem_ctx,
     753             :         struct messaging_context *msg_ctx)
     754             : {
     755         598 :         struct rpc_worker *worker = NULL;
     756             : 
     757         598 :         worker = talloc_zero(mem_ctx, struct rpc_worker);
     758         598 :         if (worker == NULL) {
     759           0 :                 return NULL;
     760             :         }
     761             : 
     762         598 :         worker->rpc_host_pid = (struct server_id) { .pid = 0 };
     763         598 :         worker->msg_ctx = msg_ctx;
     764             : 
     765         598 :         worker->cb = (struct dcesrv_context_callbacks) {
     766             :                 .log.successful_authz = dcesrv_log_successful_authz,
     767             :                 .auth.gensec_prepare = dcesrv_auth_gensec_prepare,
     768             :                 .auth.become_root = become_root,
     769             :                 .auth.unbecome_root = unbecome_root,
     770             :                 .assoc_group.find = rpc_worker_assoc_group_find,
     771             :                 .assoc_group.private_data = worker,
     772             :         };
     773             : 
     774         598 :         worker->dce_ctx = global_dcesrv_context();
     775         598 :         if (worker->dce_ctx == NULL) {
     776           0 :                 goto fail;
     777             :         }
     778         598 :         dcesrv_context_set_callbacks(worker->dce_ctx, &worker->cb);
     779             : 
     780         598 :         return worker;
     781           0 : fail:
     782           0 :         TALLOC_FREE(worker);
     783           0 :         return NULL;
     784             : }
     785             : 
     786         598 : static struct dcesrv_context *rpc_worker_dce_ctx(struct rpc_worker *w)
     787             : {
     788         598 :         return w->dce_ctx;
     789             : }
     790             : 
     791             : struct rpc_worker_state {
     792             :         struct tevent_context *ev;
     793             :         struct rpc_worker *w;
     794             :         struct tevent_req *new_client_req;
     795             :         struct tevent_req *status_req;
     796             :         struct tevent_req *finish_req;
     797             : };
     798             : 
     799             : static void rpc_worker_done(struct tevent_req *subreq);
     800             : static void rpc_worker_shutdown(
     801             :         struct messaging_context *msg,
     802             :         void *private_data,
     803             :         uint32_t msg_type,
     804             :         struct server_id server_id,
     805             :         DATA_BLOB *data);
     806             : 
     807         598 : static struct tevent_req *rpc_worker_send(
     808             :         TALLOC_CTX *mem_ctx,
     809             :         struct tevent_context *ev,
     810             :         struct rpc_worker *w,
     811             :         pid_t rpc_host_pid,
     812             :         int server_index,
     813             :         int worker_index)
     814             : {
     815         598 :         struct tevent_req *req = NULL;
     816         598 :         struct rpc_worker_state *state = NULL;
     817             :         NTSTATUS status;
     818             : 
     819         598 :         req = tevent_req_create(mem_ctx, &state, struct rpc_worker_state);
     820         598 :         if (req == NULL) {
     821           0 :                 return NULL;
     822             :         }
     823         598 :         state->ev = ev;
     824         598 :         state->w = w;
     825             : 
     826         598 :         if ((server_index < 0) || ((unsigned)server_index > UINT32_MAX)) {
     827           0 :                 DBG_ERR("Invalid server index %d\n", server_index);
     828           0 :                 tevent_req_error(req, EINVAL);
     829           0 :                 return tevent_req_post(req, ev);
     830             :         }
     831         598 :         if ((worker_index < 0) || ((unsigned)worker_index > UINT16_MAX)) {
     832           0 :                 DBG_ERR("Invalid worker index %d\n", worker_index);
     833           0 :                 tevent_req_error(req, EINVAL);
     834           0 :                 return tevent_req_post(req, ev);
     835             :         }
     836         598 :         w->rpc_host_pid = pid_to_procid(rpc_host_pid);
     837             : 
     838         598 :         w->status = (struct rpc_worker_status) {
     839             :                 .server_index = server_index,
     840             :                 .worker_index = worker_index,
     841             :         };
     842             : 
     843             :         /* Wait for new client messages. */
     844         598 :         state->new_client_req = messaging_filtered_read_send(
     845             :                 w,
     846             :                 messaging_tevent_context(w->msg_ctx),
     847             :                 w->msg_ctx,
     848             :                 rpc_worker_new_client_filter,
     849             :                 w);
     850         598 :         if (tevent_req_nomem(state->new_client_req, req)) {
     851           0 :                 return tevent_req_post(req, ev);
     852             :         }
     853             : 
     854             :         /* Wait for report your status messages. */
     855         598 :         state->status_req = messaging_filtered_read_send(
     856             :                 w,
     857             :                 messaging_tevent_context(w->msg_ctx),
     858             :                 w->msg_ctx,
     859             :                 rpc_worker_status_filter,
     860             :                 w);
     861         598 :         if (tevent_req_nomem(state->status_req, req)) {
     862           0 :                 return tevent_req_post(req, ev);
     863             :         }
     864             : 
     865             :         /* Wait for shutdown messages. */
     866         598 :         status = messaging_register(
     867             :                 w->msg_ctx, req, MSG_SHUTDOWN, rpc_worker_shutdown);
     868         598 :         if (!NT_STATUS_IS_OK(status)) {
     869           0 :                 DBG_DEBUG("messaging_register failed: %s\n",
     870             :                           nt_errstr(status));
     871           0 :                 tevent_req_error(req, map_errno_from_nt_status(status));
     872           0 :                 return tevent_req_post(req, ev);
     873             :         }
     874             : 
     875         598 :         state->finish_req = wait_for_read_send(state, ev, 0, false);
     876         598 :         if (tevent_req_nomem(state->finish_req, req)) {
     877           0 :                 return tevent_req_post(req, ev);
     878             :         }
     879         598 :         tevent_req_set_callback(state->finish_req, rpc_worker_done, req);
     880             : 
     881         598 :         rpc_worker_report_status(w);
     882             : 
     883         598 :         return req;
     884             : }
     885             : 
     886          35 : static void rpc_worker_done(struct tevent_req *subreq)
     887             : {
     888          35 :         struct tevent_req *req = tevent_req_callback_data(
     889             :                 subreq, struct tevent_req);
     890          35 :         int err = 0;
     891             :         bool ok;
     892             : 
     893          35 :         ok = wait_for_read_recv(subreq, &err);
     894          35 :         TALLOC_FREE(subreq);
     895          35 :         if (!ok) {
     896           0 :                 tevent_req_error(req, err);
     897           0 :                 return;
     898             :         }
     899          35 :         tevent_req_done(req);
     900             : }
     901             : 
     902         563 : static void rpc_worker_shutdown(
     903             :         struct messaging_context *msg,
     904             :         void *private_data,
     905             :         uint32_t msg_type,
     906             :         struct server_id server_id,
     907             :         DATA_BLOB *data)
     908             : {
     909         563 :         struct tevent_req *req = talloc_get_type_abort(
     910             :                 private_data, struct tevent_req);
     911         563 :         tevent_req_done(req);
     912         563 : }
     913             : 
     914         598 : static int rpc_worker_recv(struct tevent_req *req)
     915             : {
     916         598 :         return tevent_req_simple_recv_unix(req);
     917             : }
     918             : 
     919           0 : static void sig_term_handler(
     920             :         struct tevent_context *ev,
     921             :         struct tevent_signal *se,
     922             :         int signum,
     923             :         int count,
     924             :         void *siginfo,
     925             :         void *private_data)
     926             : {
     927           0 :         exit(0);
     928             : }
     929             : 
     930           0 : static void sig_hup_handler(
     931             :         struct tevent_context *ev,
     932             :         struct tevent_signal *se,
     933             :         int signum,
     934             :         int count,
     935             :         void *siginfo,
     936             :         void *private_data)
     937             : {
     938           0 :         change_to_root_user();
     939           0 :         lp_load_with_shares(get_dyn_CONFIGFILE());
     940           0 : }
     941             : 
     942        1826 : static NTSTATUS register_ep_server(
     943             :         struct dcesrv_context *dce_ctx,
     944             :         const struct dcesrv_endpoint_server *ep_server)
     945             : {
     946             :         NTSTATUS status;
     947             : 
     948        1826 :         DBG_DEBUG("Registering server %s\n", ep_server->name);
     949             : 
     950        1826 :         status = dcerpc_register_ep_server(ep_server);
     951        1826 :         if (!NT_STATUS_IS_OK(status) &&
     952           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
     953           0 :                 DBG_ERR("Failed to register '%s' endpoint server: %s\n",
     954             :                         ep_server->name,
     955             :                         nt_errstr(status));
     956           0 :                 return status;
     957             :         }
     958             : 
     959        1826 :         status = dcesrv_init_ep_server(dce_ctx, ep_server->name);
     960        1826 :         if (!NT_STATUS_IS_OK(status)) {
     961           0 :                 DBG_ERR("dcesrv_init_ep_server(%s) failed: %s\n",
     962             :                         ep_server->name,
     963             :                         nt_errstr(status));
     964           0 :                 return status;
     965             :         }
     966             : 
     967        1826 :         return NT_STATUS_OK;
     968             : }
     969             : 
     970             : /**
     971             :  * @brief Main function for RPC server implementations
     972             :  *
     973             :  * This function provides all that is necessary to run a RPC server
     974             :  * inside the samba-dcerpcd framework. Just pass argv and argc on to
     975             :  * this function.
     976             :  *
     977             :  * The get_interfaces() callback provides the information that is
     978             :  * passed to samba-dcerpcd via --list-interfaces, it should not do any
     979             :  * real RPC server initialization work. Quickly after this function is
     980             :  * called by rpc_worker_main, the process exits again. It should
     981             :  * return the number of interfaces provided.
     982             :  *
     983             :  * get_servers() is called when the process is about to do the real
     984             :  * work. So more heavy-weight initialization should happen here. It
     985             :  * should return NT_STATUS_OK and the number of server implementations provided.
     986             :  *
     987             :  * @param[in] argc argc from main()
     988             :  * @param[in] argv argv from main()
     989             :  * @param[in] get_interfaces List all interfaces that this server provides
     990             :  * @param[in] get_servers Provide the RPC server implementations
     991             :  * @param[in] private_data Passed to the callback functions
     992             :  * @return 0 It should never return except on successful process exit
     993             :  */
     994             : 
     995        1398 : int rpc_worker_main(
     996             :         int argc,
     997             :         const char *argv[],
     998             :         const char *daemon_config_name,
     999             :         int num_workers,
    1000             :         int idle_seconds,
    1001             :         size_t (*get_interfaces)(
    1002             :                 const struct ndr_interface_table ***ifaces,
    1003             :                 void *private_data),
    1004             :         NTSTATUS (*get_servers)(
    1005             :                 struct dcesrv_context *dce_ctx,
    1006             :                 const struct dcesrv_endpoint_server ***ep_servers,
    1007             :                 size_t *num_ep_servers,
    1008             :                 void *private_data),
    1009             :         void *private_data)
    1010             : {
    1011             :         const struct loadparm_substitution *lp_sub =
    1012        1398 :                 loadparm_s3_global_substitution();
    1013        1398 :         const char *progname = getprogname();
    1014        1398 :         TALLOC_CTX *frame = NULL;
    1015        1398 :         struct tevent_context *ev_ctx = NULL;
    1016        1398 :         struct tevent_req *req = NULL;
    1017        1398 :         struct messaging_context *msg_ctx = NULL;
    1018        1398 :         struct dcesrv_context *dce_ctx = NULL;
    1019        1398 :         struct tevent_signal *se = NULL;
    1020             :         poptContext pc;
    1021             :         int opt;
    1022             :         NTSTATUS status;
    1023             :         int ret;
    1024        1398 :         int worker_group = -1;
    1025        1398 :         int worker_index = -1;
    1026             :         bool log_stdout;
    1027        1398 :         int list_interfaces = 0;
    1028        1398 :         struct rpc_worker *worker = NULL;
    1029             :         const struct dcesrv_endpoint_server **ep_servers;
    1030             :         size_t i, num_servers;
    1031             :         bool ok;
    1032             : 
    1033        2796 :         struct poptOption long_options[] = {
    1034             :                 POPT_AUTOHELP
    1035             :                 {
    1036             :                         .longName   = "list-interfaces",
    1037             :                         .argInfo    = POPT_ARG_NONE,
    1038             :                         .arg        = &list_interfaces,
    1039             :                         .descrip    = "List the interfaces provided",
    1040             :                 },
    1041             :                 {
    1042             :                         .longName   = "worker-group",
    1043             :                         .argInfo    = POPT_ARG_INT,
    1044             :                         .arg        = &worker_group,
    1045             :                         .descrip    = "Group index in status message",
    1046             :                 },
    1047             :                 {
    1048             :                         .longName   = "worker-index",
    1049             :                         .argInfo    = POPT_ARG_INT,
    1050             :                         .arg        = &worker_index,
    1051             :                         .descrip    = "Worker index in status message",
    1052             :                 },
    1053        1398 :                 POPT_COMMON_SAMBA
    1054             :                 POPT_TABLEEND
    1055             :         };
    1056             :         static const struct smbd_shim smbd_shim_fns = {
    1057             :                 .become_authenticated_pipe_user =
    1058             :                 smbd_become_authenticated_pipe_user,
    1059             :                 .unbecome_authenticated_pipe_user =
    1060             :                 smbd_unbecome_authenticated_pipe_user,
    1061             :                 .become_root = smbd_become_root,
    1062             :                 .unbecome_root = smbd_unbecome_root,
    1063             :         };
    1064             : 
    1065        1398 :         closefrom(3);
    1066        1398 :         talloc_enable_null_tracking();
    1067        1398 :         frame = talloc_stackframe();
    1068        1398 :         umask(0);
    1069        1398 :         smb_init_locale();
    1070             : 
    1071        1398 :         ok = samba_cmdline_init(frame,
    1072             :                                 SAMBA_CMDLINE_CONFIG_SERVER,
    1073             :                                 true /* require_smbconf */);
    1074        1398 :         if (!ok) {
    1075           0 :                 DBG_ERR("Failed to init cmdline parser!\n");
    1076           0 :                 TALLOC_FREE(frame);
    1077           0 :                 exit(ENOMEM);
    1078             :         }
    1079             : 
    1080        1398 :         pc = samba_popt_get_context(progname, argc, argv, long_options, 0);
    1081        1398 :         if (pc == NULL) {
    1082           0 :                 DBG_ERR("Failed to setup popt context!\n");
    1083           0 :                 TALLOC_FREE(frame);
    1084           0 :                 exit(1);
    1085             :         }
    1086             : 
    1087        1398 :         while ((opt = poptGetNextOpt(pc)) != -1) {
    1088           0 :                 d_fprintf(stderr,
    1089             :                           "\nInvalid option %s: %s\n\n",
    1090             :                           poptBadOption(pc, 0),
    1091             :                           poptStrerror(opt));
    1092           0 :                 poptPrintUsage(pc, stderr, 0);
    1093           0 :                 TALLOC_FREE(frame);
    1094           0 :                 exit(1);
    1095             :         };
    1096        1398 :         poptFreeContext(pc);
    1097             : 
    1098        1398 :         if (list_interfaces != 0) {
    1099         800 :                 const struct ndr_interface_table **ifaces = NULL;
    1100             :                 size_t num_ifaces;
    1101             : 
    1102         800 :                 num_workers = lp_parm_int(
    1103             :                         -1, daemon_config_name, "num_workers", num_workers);
    1104         800 :                 idle_seconds = lp_parm_int(
    1105             :                         -1, daemon_config_name, "idle_seconds", idle_seconds);
    1106             : 
    1107         800 :                 DBG_DEBUG("daemon=%s, num_workers=%d, idle_seconds=%d\n",
    1108             :                           daemon_config_name,
    1109             :                           num_workers,
    1110             :                           idle_seconds);
    1111             : 
    1112         800 :                 fprintf(stdout, "%d\n%d\n", num_workers, idle_seconds);
    1113             : 
    1114         800 :                 num_ifaces = get_interfaces(&ifaces, private_data);
    1115             : 
    1116        2298 :                 for (i=0; i<num_ifaces; i++) {
    1117        1498 :                         rpc_worker_print_interface(stdout, ifaces[i]);
    1118             :                 }
    1119             : 
    1120         800 :                 TALLOC_FREE(frame);
    1121         800 :                 exit(0);
    1122             :         }
    1123             : 
    1124         598 :         log_stdout = (debug_get_log_type() == DEBUG_STDOUT);
    1125         598 :         if (log_stdout != 0) {
    1126           0 :                 setup_logging(argv[0], DEBUG_STDOUT);
    1127             :         } else {
    1128         598 :                 setup_logging(argv[0], DEBUG_FILE);
    1129             :         }
    1130             : 
    1131         598 :         set_smbd_shim(&smbd_shim_fns);
    1132             : 
    1133         598 :         dump_core_setup(progname, lp_logfile(talloc_tos(), lp_sub));
    1134             : 
    1135             :         /* POSIX demands that signals are inherited. If the invoking
    1136             :          * process has these signals masked, we will have problems, as
    1137             :          * we won't receive them. */
    1138         598 :         BlockSignals(False, SIGHUP);
    1139         598 :         BlockSignals(False, SIGUSR1);
    1140         598 :         BlockSignals(False, SIGTERM);
    1141             : 
    1142             : #if defined(SIGFPE)
    1143             :         /* we are never interested in SIGFPE */
    1144         598 :         BlockSignals(True,SIGFPE);
    1145             : #endif
    1146             :         /* We no longer use USR2... */
    1147             : #if defined(SIGUSR2)
    1148         598 :         BlockSignals(True, SIGUSR2);
    1149             : #endif
    1150             :         /* Ignore children - no zombies. */
    1151         598 :         CatchChild();
    1152             : 
    1153         598 :         reopen_logs();
    1154             : 
    1155         598 :         DBG_STARTUP_NOTICE("%s version %s started.\n%s\n",
    1156             :                            progname,
    1157             :                            samba_version_string(),
    1158             :                            samba_copyright_string());
    1159             : 
    1160         598 :         msg_ctx = global_messaging_context();
    1161         598 :         if (msg_ctx == NULL) {
    1162           0 :                 DBG_ERR("global_messaging_context() failed\n");
    1163           0 :                 TALLOC_FREE(frame);
    1164           0 :                 exit(1);
    1165             :         }
    1166         598 :         ev_ctx = messaging_tevent_context(msg_ctx);
    1167             : 
    1168         598 :         worker = rpc_worker_new(ev_ctx, msg_ctx);
    1169         598 :         if (worker == NULL) {
    1170           0 :                 DBG_ERR("rpc_worker_new failed\n");
    1171           0 :                 global_messaging_context_free();
    1172           0 :                 TALLOC_FREE(frame);
    1173           0 :                 exit(1);
    1174             :         }
    1175         598 :         dce_ctx = rpc_worker_dce_ctx(worker);
    1176             : 
    1177         598 :         se = tevent_add_signal(
    1178             :                 ev_ctx, ev_ctx, SIGTERM, 0, sig_term_handler, NULL);
    1179         598 :         if (se == NULL) {
    1180           0 :                 DBG_ERR("tevent_add_signal failed\n");
    1181           0 :                 global_messaging_context_free();
    1182           0 :                 TALLOC_FREE(frame);
    1183           0 :                 exit(1);
    1184             :         }
    1185         598 :         BlockSignals(false, SIGTERM);
    1186             : 
    1187         598 :         se = tevent_add_signal(
    1188             :                 ev_ctx, ev_ctx, SIGHUP, 0, sig_hup_handler, NULL);
    1189         598 :         if (se == NULL) {
    1190           0 :                 DBG_ERR("tevent_add_signal failed\n");
    1191           0 :                 global_messaging_context_free();
    1192           0 :                 TALLOC_FREE(frame);
    1193           0 :                 exit(1);
    1194             :         }
    1195         598 :         BlockSignals(false, SIGHUP);
    1196             : 
    1197         598 :         (void)winbind_off();
    1198         598 :         ok = init_guest_session_info(NULL);
    1199         598 :         (void)winbind_on();
    1200         598 :         if (!ok) {
    1201           0 :                 DBG_WARNING("init_guest_session_info failed\n");
    1202           0 :                 global_messaging_context_free();
    1203           0 :                 TALLOC_FREE(frame);
    1204           0 :                 exit(1);
    1205             :         }
    1206             : 
    1207         598 :         status = init_system_session_info(NULL);
    1208         598 :         if (!NT_STATUS_IS_OK(status)) {
    1209           0 :                 DBG_WARNING("init_system_session_info failed: %s\n",
    1210             :                             nt_errstr(status));
    1211           0 :                 global_messaging_context_free();
    1212           0 :                 TALLOC_FREE(frame);
    1213           0 :                 exit(1);
    1214             :         }
    1215             : 
    1216         598 :         DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
    1217             : 
    1218         598 :         status = get_servers(dce_ctx,
    1219             :                              &ep_servers,
    1220             :                              &num_servers,
    1221             :                              private_data);
    1222         598 :         if (!NT_STATUS_IS_OK(status)) {
    1223           0 :                 DBG_ERR("get_servers failed: %s\n", nt_errstr(status));
    1224           0 :                 global_messaging_context_free();
    1225           0 :                 TALLOC_FREE(frame);
    1226           0 :                 exit(1);
    1227             :         }
    1228             : 
    1229         598 :         DBG_DEBUG("get_servers() returned %zu servers\n", num_servers);
    1230             : 
    1231        2424 :         for (i=0; i<num_servers; i++) {
    1232        1826 :                 status = register_ep_server(dce_ctx, ep_servers[i]);
    1233        1826 :                 if (!NT_STATUS_IS_OK(status)) {
    1234           0 :                         DBG_ERR("register_ep_server failed: %s\n",
    1235             :                                 nt_errstr(status));
    1236           0 :                         global_messaging_context_free();
    1237           0 :                         TALLOC_FREE(frame);
    1238           0 :                         exit(1);
    1239             :                 }
    1240             :         }
    1241             : 
    1242         598 :         req = rpc_worker_send(
    1243             :                 ev_ctx, ev_ctx, worker, getppid(), worker_group, worker_index);
    1244         598 :         if (req == NULL) {
    1245           0 :                 DBG_ERR("rpc_worker_send failed\n");
    1246           0 :                 global_messaging_context_free();
    1247           0 :                 TALLOC_FREE(frame);
    1248           0 :                 exit(1);
    1249             :         }
    1250             : 
    1251         598 :         DBG_DEBUG("%s worker running\n", progname);
    1252             : 
    1253     2693109 :         while (tevent_req_is_in_progress(req)) {
    1254     2692511 :                 TALLOC_CTX *loop_frame = NULL;
    1255             : 
    1256     2692511 :                 loop_frame = talloc_stackframe();
    1257             : 
    1258     2692511 :                 ret = tevent_loop_once(ev_ctx);
    1259             : 
    1260     2692511 :                 TALLOC_FREE(loop_frame);
    1261             : 
    1262     2692511 :                 if (ret != 0) {
    1263           0 :                         DBG_WARNING("tevent_req_once() failed: %s\n",
    1264             :                                     strerror(errno));
    1265           0 :                         global_messaging_context_free();
    1266           0 :                         TALLOC_FREE(frame);
    1267           0 :                         exit(1);
    1268             :                 }
    1269             :         }
    1270             : 
    1271         598 :         status = dcesrv_shutdown_registered_ep_servers(dce_ctx);
    1272         598 :         if (!NT_STATUS_IS_OK(status)) {
    1273           0 :                 DBG_DEBUG("Shutdown failed with: %s\n",
    1274             :                         nt_errstr(status));
    1275             :         }
    1276             : 
    1277         598 :         ret = rpc_worker_recv(req);
    1278         598 :         if (ret != 0) {
    1279           0 :                 DBG_DEBUG("rpc_worker_recv returned %s\n", strerror(ret));
    1280           0 :                 global_messaging_context_free();
    1281           0 :                 TALLOC_FREE(frame);
    1282           0 :                 exit(1);
    1283             :         }
    1284             : 
    1285         598 :         TALLOC_FREE(frame);
    1286         598 :         return 0;
    1287             : }

Generated by: LCOV version 1.14