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

Generated by: LCOV version 1.14