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

Generated by: LCOV version 1.13