LCOV - code coverage report
Current view: top level - source3/rpc_server - rpc_server.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 42 116 36.2 %
Date: 2024-02-14 10:14:15 Functions: 5 10 50.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/Netbios implementation.
       3             :    Generic infrstructure for RPC Daemons
       4             :    Copyright (C) Simo Sorce 2010
       5             :    Copyright (C) Andrew Bartlett 2011
       6             :    Copyright (C) Andreas Schneider 2011
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "librpc/rpc/dcesrv_core.h"
      24             : #include "rpc_server/rpc_pipes.h"
      25             : #include "rpc_server/rpc_server.h"
      26             : #include "rpc_server/rpc_config.h"
      27             : #include "rpc_dce.h"
      28             : #include "librpc/gen_ndr/netlogon.h"
      29             : #include "librpc/gen_ndr/auth.h"
      30             : #include "lib/tsocket/tsocket.h"
      31             : #include "libcli/named_pipe_auth/npa_tstream.h"
      32             : #include "../auth/auth_sam_reply.h"
      33             : #include "auth.h"
      34             : #include "rpc_server/rpc_ncacn_np.h"
      35             : #include "rpc_server/srv_pipe_hnd.h"
      36             : #include "lib/util/idtree_random.h"
      37             : 
      38             : #undef DBGC_CLASS
      39             : #define DBGC_CLASS DBGC_RPC_SRV
      40             : 
      41             : /* Start listening on the appropriate unix socket and setup all is needed to
      42             :  * dispatch requests to the pipes rpc implementation */
      43             : 
      44             : struct dcerpc_ncacn_listen_state {
      45             :         int fd;
      46             : 
      47             :         struct tevent_context *ev_ctx;
      48             :         struct messaging_context *msg_ctx;
      49             :         struct dcesrv_context *dce_ctx;
      50             :         struct dcesrv_endpoint *endpoint;
      51             :         dcerpc_ncacn_termination_fn termination_fn;
      52             :         void *termination_data;
      53             : };
      54             : 
      55             : static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
      56             :                                        const char *reason);
      57             : 
      58         255 : NTSTATUS dcesrv_auth_gensec_prepare(
      59             :         TALLOC_CTX *mem_ctx,
      60             :         struct dcesrv_call_state *call,
      61             :         struct gensec_security **out,
      62             :         void *private_data)
      63             : {
      64         255 :         struct gensec_security *gensec = NULL;
      65             :         NTSTATUS status;
      66             : 
      67         255 :         if (out == NULL) {
      68           0 :                 return NT_STATUS_INVALID_PARAMETER;
      69             :         }
      70             : 
      71         255 :         status = auth_generic_prepare(mem_ctx,
      72         255 :                                       call->conn->remote_address,
      73         255 :                                       call->conn->local_address,
      74             :                                       "DCE/RPC",
      75             :                                       &gensec);
      76         255 :         if (!NT_STATUS_IS_OK(status)) {
      77           0 :                 DBG_ERR("Failed to prepare gensec: %s\n", nt_errstr(status));
      78           0 :                 return status;
      79             :         }
      80             : 
      81         255 :         *out = gensec;
      82             : 
      83         255 :         return NT_STATUS_OK;
      84             : }
      85             : 
      86         518 : void dcesrv_log_successful_authz(
      87             :         struct dcesrv_call_state *call,
      88             :         void *private_data)
      89             : {
      90         518 :         TALLOC_CTX *frame = talloc_stackframe();
      91         518 :         struct auth4_context *auth4_context = NULL;
      92         518 :         struct dcesrv_auth *auth = call->auth_state;
      93         518 :         enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
      94         518 :                         call->conn->endpoint->ep_description);
      95         518 :         const char *auth_type = derpc_transport_string_by_transport(transport);
      96         518 :         const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
      97             :         NTSTATUS status;
      98             : 
      99         518 :         if (frame == NULL) {
     100           0 :                 DBG_ERR("No memory");
     101           0 :                 return;
     102             :         }
     103             : 
     104         518 :         if (transport == NCACN_NP) {
     105         282 :                 transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
     106             :         }
     107             : 
     108         518 :         become_root();
     109         518 :         status = make_auth4_context(frame, &auth4_context);
     110         518 :         unbecome_root();
     111         518 :         if (!NT_STATUS_IS_OK(status)) {
     112           0 :                 DBG_ERR("Unable to make auth context for authz log.\n");
     113           0 :                 TALLOC_FREE(frame);
     114           0 :                 return;
     115             :         }
     116             : 
     117             :         /*
     118             :          * Log the authorization to this RPC interface.  This
     119             :          * covered ncacn_np pass-through auth, and anonymous
     120             :          * DCE/RPC (eg epmapper, netlogon etc)
     121             :          */
     122         518 :         log_successful_authz_event(auth4_context->msg_ctx,
     123         518 :                                    auth4_context->lp_ctx,
     124         518 :                                    call->conn->remote_address,
     125         518 :                                    call->conn->local_address,
     126             :                                    "DCE/RPC",
     127             :                                    auth_type,
     128             :                                    transport_protection,
     129             :                                    auth->session_info);
     130             : 
     131         518 :         auth->auth_audited = true;
     132             : 
     133         518 :         TALLOC_FREE(frame);
     134             : }
     135             : 
     136           0 : static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
     137             : {
     138             :         int ret;
     139           0 :         ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr,
     140           0 :                          assoc_group->id);
     141           0 :         if (ret != 0) {
     142           0 :                 DBG_ERR("Failed to remove assoc_group 0x%08x\n",
     143             :                         assoc_group->id);
     144             :         }
     145           0 :         return 0;
     146             : }
     147             : 
     148           0 : static NTSTATUS dcesrv_assoc_group_new(struct dcesrv_call_state *call)
     149             : {
     150           0 :         struct dcesrv_connection *conn = call->conn;
     151           0 :         struct dcesrv_context *dce_ctx = conn->dce_ctx;
     152           0 :         const struct dcesrv_endpoint *endpoint = conn->endpoint;
     153             :         enum dcerpc_transport_t transport =
     154           0 :                 dcerpc_binding_get_transport(endpoint->ep_description);
     155           0 :         struct dcesrv_assoc_group *assoc_group = NULL;
     156             :         int id;
     157             : 
     158           0 :         assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
     159           0 :         if (assoc_group == NULL) {
     160           0 :                 return NT_STATUS_NO_MEMORY;
     161             :         }
     162             : 
     163           0 :         id = idr_get_new_random(dce_ctx->assoc_groups_idr,
     164             :                                 assoc_group,
     165             :                                 1,
     166             :                                 UINT16_MAX);
     167           0 :         if (id == -1) {
     168           0 :                 TALLOC_FREE(assoc_group);
     169           0 :                 DBG_ERR("Out of association groups!\n");
     170           0 :                 return NT_STATUS_RPC_OUT_OF_RESOURCES;
     171             :         }
     172             : 
     173           0 :         assoc_group->transport = transport;
     174           0 :         assoc_group->id = id;
     175           0 :         assoc_group->dce_ctx = dce_ctx;
     176             : 
     177           0 :         call->conn->assoc_group = assoc_group;
     178             : 
     179           0 :         talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
     180             : 
     181           0 :         return NT_STATUS_OK;
     182             : }
     183             : 
     184           0 : static NTSTATUS dcesrv_assoc_group_reference(struct dcesrv_call_state *call,
     185             :                                              uint32_t assoc_group_id)
     186             : {
     187           0 :         struct dcesrv_connection *conn = call->conn;
     188           0 :         const struct dcesrv_endpoint *endpoint = conn->endpoint;
     189             :         enum dcerpc_transport_t transport =
     190           0 :                 dcerpc_binding_get_transport(endpoint->ep_description);
     191           0 :         struct dcesrv_assoc_group *assoc_group = NULL;
     192           0 :         void *id_ptr = NULL;
     193             : 
     194             :         /* find an association group given a assoc_group_id */
     195           0 :         id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, assoc_group_id);
     196           0 :         if (id_ptr == NULL) {
     197             :                 /*
     198             :                  * FIXME If the association group is not found it has
     199             :                  * been created in other process (preforking daemons).
     200             :                  * Until this is properly fixed we just create a new
     201             :                  * association group in this process
     202             :                  */
     203           0 :                 DBG_NOTICE("Failed to find assoc_group 0x%08x in this "
     204             :                            "server process, creating a new one\n",
     205             :                            assoc_group_id);
     206           0 :                 return dcesrv_assoc_group_new(call);
     207             :         }
     208           0 :         assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
     209             : 
     210           0 :         if (assoc_group->transport != transport) {
     211             :                 const char *at =
     212           0 :                         derpc_transport_string_by_transport(
     213             :                                 assoc_group->transport);
     214             :                 const char *ct =
     215           0 :                         derpc_transport_string_by_transport(
     216             :                                 transport);
     217             : 
     218           0 :                 DBG_NOTICE("assoc_group 0x%08x (transport %s) "
     219             :                            "is not available on transport %s",
     220             :                            assoc_group_id, at, ct);
     221           0 :                 return NT_STATUS_UNSUCCESSFUL;
     222             :         }
     223             : 
     224           0 :         conn->assoc_group = talloc_reference(conn, assoc_group);
     225           0 :         return NT_STATUS_OK;
     226             : }
     227             : 
     228           0 : NTSTATUS dcesrv_assoc_group_find(
     229             :         struct dcesrv_call_state *call,
     230             :         void *private_data)
     231             : {
     232           0 :         uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
     233             : 
     234           0 :         if (assoc_group_id != 0) {
     235           0 :                 return dcesrv_assoc_group_reference(call, assoc_group_id);
     236             :         }
     237             : 
     238             :         /* If not requested by client create a new association group */
     239           0 :         return dcesrv_assoc_group_new(call);
     240             : }
     241             : 
     242         699 : void dcesrv_transport_terminate_connection(struct dcesrv_connection *dce_conn,
     243             :                                            const char *reason)
     244             : {
     245         699 :        struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
     246             :                        dce_conn->transport.private_data,
     247             :                        struct dcerpc_ncacn_conn);
     248             : 
     249         699 :        ncacn_terminate_connection(ncacn_conn, reason);
     250         699 : }
     251             : 
     252         699 : static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
     253             :                                        const char *reason)
     254             : {
     255         699 :        if (reason == NULL) {
     256           0 :                reason = "Unknown reason";
     257             :        }
     258             : 
     259         699 :        DBG_NOTICE("Terminating connection - '%s'\n", reason);
     260             : 
     261         699 :        talloc_free(conn);
     262         699 : }
     263             : 
     264           0 : NTSTATUS dcesrv_endpoint_by_ncacn_np_name(struct dcesrv_context *dce_ctx,
     265             :                                           const char *pipe_name,
     266             :                                           struct dcesrv_endpoint **out)
     267             : {
     268           0 :         struct dcesrv_endpoint *e = NULL;
     269             : 
     270           0 :         for (e = dce_ctx->endpoint_list; e; e = e->next) {
     271             :                 enum dcerpc_transport_t transport =
     272           0 :                         dcerpc_binding_get_transport(e->ep_description);
     273           0 :                 const char *endpoint = NULL;
     274             : 
     275           0 :                 if (transport != NCACN_NP) {
     276           0 :                         continue;
     277             :                 }
     278             : 
     279           0 :                 endpoint = dcerpc_binding_get_string_option(e->ep_description,
     280             :                                                             "endpoint");
     281           0 :                 if (endpoint == NULL) {
     282           0 :                         continue;
     283             :                 }
     284             : 
     285           0 :                 if (strncmp(endpoint, "\\pipe\\", 6) == 0) {
     286           0 :                         endpoint += 6;
     287             :                 }
     288             : 
     289           0 :                 if (strequal(endpoint, pipe_name)) {
     290           0 :                         *out = e;
     291           0 :                         return NT_STATUS_OK;
     292             :                 }
     293             :         }
     294             : 
     295           0 :         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     296             : }
     297             : 
     298        9975 : struct pipes_struct *dcesrv_get_pipes_struct(struct dcesrv_connection *conn)
     299             : {
     300        9975 :         struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
     301             :                         conn->transport.private_data,
     302             :                         struct dcerpc_ncacn_conn);
     303             : 
     304        9975 :         return &ncacn_conn->p;
     305             : }
     306             : 
     307             : /* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */

Generated by: LCOV version 1.14