LCOV - code coverage report
Current view: top level - source4/samba - service_named_pipe.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 70 108 64.8 %
Date: 2024-02-29 22:57:05 Functions: 3 5 60.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    helper functions for NAMED PIPE servers
       5             : 
       6             :    Copyright (C) Stefan (metze) Metzmacher      2008
       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 <tevent.h>
      24             : #include "samba/service.h"
      25             : #include "param/param.h"
      26             : #include "auth/auth.h"
      27             : #include "auth/session.h"
      28             : #include "auth/auth_sam_reply.h"
      29             : #include "lib/socket/socket.h"
      30             : #include "lib/tsocket/tsocket.h"
      31             : #include "libcli/util/tstream.h"
      32             : #include "librpc/gen_ndr/ndr_named_pipe_auth.h"
      33             : #include "system/passwd.h"
      34             : #include "system/network.h"
      35             : #include "libcli/raw/smb.h"
      36             : #include "auth/session.h"
      37             : #include "libcli/security/security.h"
      38             : #include "libcli/named_pipe_auth/npa_tstream.h"
      39             : 
      40             : struct named_pipe_socket {
      41             :         const char *pipe_name;
      42             :         const char *pipe_path;
      43             :         const struct stream_server_ops *ops;
      44             :         void *private_data;
      45             : };
      46             : 
      47             : static void named_pipe_accept_done(struct tevent_req *subreq);
      48             : 
      49        7624 : static void named_pipe_accept(struct stream_connection *conn)
      50             : {
      51         628 :         struct tstream_context *plain_tstream;
      52         628 :         int fd;
      53         628 :         struct tevent_req *subreq;
      54         628 :         int ret;
      55             : 
      56             :         /* Let tstream take over fd operations */
      57             : 
      58        7624 :         fd = socket_get_fd(conn->socket);
      59        7624 :         socket_set_flags(conn->socket, SOCKET_FLAG_NOCLOSE);
      60        7624 :         TALLOC_FREE(conn->event.fde);
      61        7624 :         TALLOC_FREE(conn->socket);
      62             : 
      63        7624 :         ret = tstream_bsd_existing_socket(conn, fd, &plain_tstream);
      64        7624 :         if (ret != 0) {
      65           0 :                 stream_terminate_connection(conn,
      66             :                                 "named_pipe_accept: out of memory");
      67           0 :                 return;
      68             :         }
      69             :         /* as server we want to fail early */
      70        7624 :         tstream_bsd_fail_readv_first_error(plain_tstream, true);
      71             : 
      72        7624 :         subreq = tstream_npa_accept_existing_send(conn, conn->event.ctx,
      73             :                                                   plain_tstream,
      74             :                                                   FILE_TYPE_MESSAGE_MODE_PIPE,
      75             :                                                   0xff | 0x0400 | 0x0100,
      76             :                                                   4096);
      77        7624 :         if (subreq == NULL) {
      78           0 :                 stream_terminate_connection(conn,
      79             :                         "named_pipe_accept: "
      80             :                         "no memory for tstream_npa_accept_existing_send");
      81           0 :                 return;
      82             :         }
      83        7624 :         tevent_req_set_callback(subreq, named_pipe_accept_done, conn);
      84             : }
      85             : 
      86        7624 : static void named_pipe_accept_done(struct tevent_req *subreq)
      87             : {
      88        7624 :         struct stream_connection *conn = tevent_req_callback_data(subreq,
      89             :                                                 struct stream_connection);
      90         628 :         struct named_pipe_socket *pipe_sock =
      91        7624 :                                 talloc_get_type(conn->private_data,
      92             :                                                 struct named_pipe_socket);
      93         628 :         enum dcerpc_transport_t transport;
      94         628 :         struct tsocket_address *remote_client_addr;
      95         628 :         char *remote_client_name;
      96         628 :         struct tsocket_address *local_server_addr;
      97         628 :         char *local_server_name;
      98         628 :         struct auth_session_info_transport *session_info_transport;
      99        7624 :         const char *reason = NULL;
     100         628 :         TALLOC_CTX *tmp_ctx;
     101         628 :         int error;
     102         628 :         int ret;
     103             : 
     104        7624 :         tmp_ctx = talloc_new(conn);
     105        7624 :         if (!tmp_ctx) {
     106           0 :                 reason = "Out of memory!\n";
     107           0 :                 goto out;
     108             :         }
     109             : 
     110        7624 :         ret = tstream_npa_accept_existing_recv(subreq, &error, tmp_ctx,
     111             :                                                &conn->tstream,
     112             :                                                NULL,
     113             :                                                &transport,
     114             :                                                &remote_client_addr,
     115             :                                                &remote_client_name,
     116             :                                                &local_server_addr,
     117             :                                                &local_server_name,
     118             :                                                &session_info_transport);
     119        7624 :         TALLOC_FREE(subreq);
     120        7624 :         if (ret != 0) {
     121           0 :                 reason = talloc_asprintf(conn,
     122             :                                          "tstream_npa_accept_existing_recv()"
     123             :                                          " failed: %s", strerror(error));
     124           0 :                 goto out;
     125             :         }
     126             : 
     127        7624 :         conn->local_address = talloc_move(conn, &local_server_addr);
     128        7624 :         conn->remote_address = talloc_move(conn, &remote_client_addr);
     129             : 
     130        7624 :         DBG_DEBUG("Accepted npa connection from %s. "
     131             :                   "Client: %s (%s). Server: %s (%s)\n",
     132             :                   tsocket_address_string(conn->remote_address, tmp_ctx),
     133             :                   local_server_name,
     134             :                   tsocket_address_string(local_server_addr, tmp_ctx),
     135             :                   remote_client_name,
     136             :                   tsocket_address_string(remote_client_addr, tmp_ctx));
     137             : 
     138        7624 :         conn->session_info = auth_session_info_from_transport(conn, session_info_transport,
     139             :                                                               conn->lp_ctx,
     140             :                                                               &reason);
     141        7624 :         if (!conn->session_info) {
     142           0 :                 goto out;
     143             :         }
     144             : 
     145        7624 :         if (transport == NCACN_NP) {
     146        6923 :                 if (security_token_is_system(conn->session_info->security_token)) {
     147           0 :                         reason = talloc_asprintf(
     148             :                                 conn,
     149             :                                 "System token not allowed on transport %d\n",
     150             :                                 transport);
     151           0 :                         goto out;
     152             :                 }
     153         701 :         } else if (transport == NCALRPC) {
     154             :                 /*
     155             :                  * TODO:
     156             :                  * we should somehow remember the given transport on
     157             :                  * the connection, but that's a task for another day
     158             :                  * as it's not trivial to do...
     159             :                  */
     160             :         } else {
     161           0 :                 reason = talloc_asprintf(
     162             :                         conn,
     163             :                         "Only allow NCACN_NP or NCALRPC transport on named pipes, "
     164             :                         "got %d\n",
     165             :                         (int)transport);
     166           0 :                 goto out;
     167             :         }
     168             : 
     169             :         /*
     170             :          * hand over to the real pipe implementation,
     171             :          * now that we have setup the transport session_info
     172             :          */
     173        7624 :         conn->ops = pipe_sock->ops;
     174        7624 :         conn->private_data = pipe_sock->private_data;
     175        7624 :         conn->ops->accept_connection(conn);
     176             : 
     177        7624 :         DBG_DEBUG("named pipe connection [%s] established\n", conn->ops->name);
     178             : 
     179        7624 :         talloc_free(tmp_ctx);
     180        7624 :         return;
     181             : 
     182           0 : out:
     183           0 :         talloc_free(tmp_ctx);
     184           0 :         if (!reason) {
     185           0 :                 reason = "Internal error";
     186             :         }
     187           0 :         stream_terminate_connection(conn, reason);
     188             : }
     189             : 
     190             : /*
     191             :   called when a pipe socket becomes readable
     192             : */
     193           0 : static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
     194             : {
     195           0 :         stream_terminate_connection(conn, "named_pipe_recv: called");
     196           0 : }
     197             : 
     198             : /*
     199             :   called when a pipe socket becomes writable
     200             : */
     201           0 : static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
     202             : {
     203           0 :         stream_terminate_connection(conn, "named_pipe_send: called");
     204           0 : }
     205             : 
     206             : static const struct stream_server_ops named_pipe_stream_ops = {
     207             :         .name                   = "named_pipe",
     208             :         .accept_connection      = named_pipe_accept,
     209             :         .recv_handler           = named_pipe_recv,
     210             :         .send_handler           = named_pipe_send,
     211             : };
     212             : 
     213         802 : NTSTATUS tstream_setup_named_pipe(TALLOC_CTX *mem_ctx,
     214             :                                   struct tevent_context *event_context,
     215             :                                   struct loadparm_context *lp_ctx,
     216             :                                   const struct model_ops *model_ops,
     217             :                                   const struct stream_server_ops *stream_ops,
     218             :                                   const char *pipe_name,
     219             :                                   void *private_data,
     220             :                                   void *process_context)
     221             : {
     222          22 :         char *dirname;
     223          22 :         struct named_pipe_socket *pipe_sock;
     224         802 :         NTSTATUS status = NT_STATUS_NO_MEMORY;;
     225             : 
     226         802 :         pipe_sock = talloc(mem_ctx, struct named_pipe_socket);
     227         802 :         if (pipe_sock == NULL) {
     228           0 :                 goto fail;
     229             :         }
     230             : 
     231             :         /* remember the details about the pipe */
     232         802 :         pipe_sock->pipe_name = strlower_talloc(pipe_sock, pipe_name);
     233         802 :         if (pipe_sock->pipe_name == NULL) {
     234           0 :                 goto fail;
     235             :         }
     236             : 
     237         802 :         if (!directory_create_or_exist(lpcfg_ncalrpc_dir(lp_ctx), 0755)) {
     238           0 :                 status = map_nt_error_from_unix_common(errno);
     239           0 :                 DBG_ERR("Failed to create ncalrpc pipe directory '%s' - %s\n",
     240             :                         lpcfg_ncalrpc_dir(lp_ctx), nt_errstr(status));
     241           0 :                 goto fail;
     242             :         }
     243             : 
     244         802 :         dirname = talloc_asprintf(pipe_sock, "%s/np", lpcfg_ncalrpc_dir(lp_ctx));
     245         802 :         if (dirname == NULL) {
     246           0 :                 goto fail;
     247             :         }
     248             : 
     249         802 :         if (!directory_create_or_exist_strict(dirname, geteuid(), 0700)) {
     250           0 :                 status = map_nt_error_from_unix_common(errno);
     251           0 :                 DBG_ERR("Failed to create stream pipe directory '%s' - %s\n",
     252             :                         dirname, nt_errstr(status));
     253           0 :                 goto fail;
     254             :         }
     255             : 
     256         802 :         if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
     257         802 :                 pipe_name += 6;
     258             :         }
     259             : 
     260         802 :         pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname,
     261             :                                                pipe_name);
     262         802 :         if (pipe_sock->pipe_path == NULL) {
     263           0 :                 goto fail;
     264             :         }
     265             : 
     266         802 :         talloc_free(dirname);
     267             : 
     268         802 :         pipe_sock->ops = stream_ops;
     269         802 :         pipe_sock->private_data      = private_data;
     270             : 
     271         802 :         status = stream_setup_socket(pipe_sock,
     272             :                                      event_context,
     273             :                                      lp_ctx,
     274             :                                      model_ops,
     275             :                                      &named_pipe_stream_ops,
     276             :                                      "unix",
     277             :                                      pipe_sock->pipe_path,
     278             :                                      NULL,
     279             :                                      NULL,
     280             :                                      pipe_sock,
     281             :                                      process_context);
     282         802 :         if (!NT_STATUS_IS_OK(status)) {
     283           0 :                 goto fail;
     284             :         }
     285         802 :         return NT_STATUS_OK;
     286             : 
     287           0 :  fail:
     288           0 :         talloc_free(pipe_sock);
     289           0 :         return status;
     290             : }

Generated by: LCOV version 1.14