LCOV - code coverage report
Current view: top level - source4/samba - service_named_pipe.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 54 92 58.7 %
Date: 2024-06-13 04:01:37 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        4923 : static void named_pipe_accept(struct stream_connection *conn)
      50             : {
      51             :         struct tstream_context *plain_tstream;
      52             :         int fd;
      53             :         struct tevent_req *subreq;
      54             :         int ret;
      55             : 
      56             :         /* Let tstream take over fd operations */
      57             : 
      58        4923 :         fd = socket_get_fd(conn->socket);
      59        4923 :         socket_set_flags(conn->socket, SOCKET_FLAG_NOCLOSE);
      60        4923 :         TALLOC_FREE(conn->event.fde);
      61        4923 :         TALLOC_FREE(conn->socket);
      62             : 
      63        4923 :         ret = tstream_bsd_existing_socket(conn, fd, &plain_tstream);
      64        4923 :         if (ret != 0) {
      65           0 :                 stream_terminate_connection(conn,
      66             :                                 "named_pipe_accept: out of memory");
      67           0 :                 return;
      68             :         }
      69             : 
      70        4923 :         subreq = tstream_npa_accept_existing_send(conn, conn->event.ctx,
      71             :                                                   plain_tstream,
      72             :                                                   FILE_TYPE_MESSAGE_MODE_PIPE,
      73             :                                                   0xff | 0x0400 | 0x0100,
      74             :                                                   4096);
      75        4923 :         if (subreq == NULL) {
      76           0 :                 stream_terminate_connection(conn,
      77             :                         "named_pipe_accept: "
      78             :                         "no memory for tstream_npa_accept_existing_send");
      79           0 :                 return;
      80             :         }
      81        4923 :         tevent_req_set_callback(subreq, named_pipe_accept_done, conn);
      82             : }
      83             : 
      84        4923 : static void named_pipe_accept_done(struct tevent_req *subreq)
      85             : {
      86        4923 :         struct stream_connection *conn = tevent_req_callback_data(subreq,
      87             :                                                 struct stream_connection);
      88        3576 :         struct named_pipe_socket *pipe_sock =
      89        4923 :                                 talloc_get_type(conn->private_data,
      90             :                                                 struct named_pipe_socket);
      91             :         enum dcerpc_transport_t transport;
      92             :         struct tsocket_address *remote_client_addr;
      93             :         char *remote_client_name;
      94             :         struct tsocket_address *local_server_addr;
      95             :         char *local_server_name;
      96             :         struct auth_session_info_transport *session_info_transport;
      97        4923 :         const char *reason = NULL;
      98             :         TALLOC_CTX *tmp_ctx;
      99             :         int error;
     100             :         int ret;
     101             : 
     102        4923 :         tmp_ctx = talloc_new(conn);
     103        4923 :         if (!tmp_ctx) {
     104           0 :                 reason = "Out of memory!\n";
     105           0 :                 goto out;
     106             :         }
     107             : 
     108        4923 :         ret = tstream_npa_accept_existing_recv(subreq, &error, tmp_ctx,
     109             :                                                &conn->tstream,
     110             :                                                NULL,
     111             :                                                &transport,
     112             :                                                &remote_client_addr,
     113             :                                                &remote_client_name,
     114             :                                                &local_server_addr,
     115             :                                                &local_server_name,
     116             :                                                &session_info_transport);
     117        4923 :         TALLOC_FREE(subreq);
     118        4923 :         if (ret != 0) {
     119           0 :                 reason = talloc_asprintf(conn,
     120             :                                          "tstream_npa_accept_existing_recv()"
     121             :                                          " failed: %s", strerror(error));
     122           0 :                 goto out;
     123             :         }
     124             : 
     125        4923 :         conn->local_address = talloc_move(conn, &local_server_addr);
     126        4923 :         conn->remote_address = talloc_move(conn, &remote_client_addr);
     127             : 
     128        4923 :         DBG_DEBUG("Accepted npa connection from %s. "
     129             :                   "Client: %s (%s). Server: %s (%s)\n",
     130             :                   tsocket_address_string(conn->remote_address, tmp_ctx),
     131             :                   local_server_name,
     132             :                   tsocket_address_string(local_server_addr, tmp_ctx),
     133             :                   remote_client_name,
     134             :                   tsocket_address_string(remote_client_addr, tmp_ctx));
     135             : 
     136        4923 :         conn->session_info = auth_session_info_from_transport(conn, session_info_transport,
     137             :                                                               conn->lp_ctx,
     138             :                                                               &reason);
     139        4923 :         if (!conn->session_info) {
     140           0 :                 goto out;
     141             :         }
     142             : 
     143        4923 :         if (transport == NCACN_NP) {
     144        4474 :                 if (security_token_is_system(conn->session_info->security_token)) {
     145           0 :                         reason = talloc_asprintf(
     146             :                                 conn,
     147             :                                 "System token not allowed on transport %d\n",
     148             :                                 transport);
     149           0 :                         goto out;
     150             :                 }
     151         449 :         } else if (transport == NCALRPC) {
     152             :                 /*
     153             :                  * TODO:
     154             :                  * we should somehow remember the given transport on
     155             :                  * the connection, but that's a task for another day
     156             :                  * as it's not trivial to do...
     157             :                  */
     158             :         } else {
     159           0 :                 reason = talloc_asprintf(
     160             :                         conn,
     161             :                         "Only allow NCACN_NP or NCALRPC transport on named pipes, "
     162             :                         "got %d\n",
     163             :                         (int)transport);
     164           0 :                 goto out;
     165             :         }
     166             : 
     167             :         /*
     168             :          * hand over to the real pipe implementation,
     169             :          * now that we have setup the transport session_info
     170             :          */
     171        4923 :         conn->ops = pipe_sock->ops;
     172        4923 :         conn->private_data = pipe_sock->private_data;
     173        4923 :         conn->ops->accept_connection(conn);
     174             : 
     175        4923 :         DBG_DEBUG("named pipe connection [%s] established\n", conn->ops->name);
     176             : 
     177        4923 :         talloc_free(tmp_ctx);
     178        4923 :         return;
     179             : 
     180           0 : out:
     181           0 :         talloc_free(tmp_ctx);
     182           0 :         if (!reason) {
     183           0 :                 reason = "Internal error";
     184             :         }
     185           0 :         stream_terminate_connection(conn, reason);
     186             : }
     187             : 
     188             : /*
     189             :   called when a pipe socket becomes readable
     190             : */
     191           0 : static void named_pipe_recv(struct stream_connection *conn, uint16_t flags)
     192             : {
     193           0 :         stream_terminate_connection(conn, "named_pipe_recv: called");
     194           0 : }
     195             : 
     196             : /*
     197             :   called when a pipe socket becomes writable
     198             : */
     199           0 : static void named_pipe_send(struct stream_connection *conn, uint16_t flags)
     200             : {
     201           0 :         stream_terminate_connection(conn, "named_pipe_send: called");
     202           0 : }
     203             : 
     204             : static const struct stream_server_ops named_pipe_stream_ops = {
     205             :         .name                   = "named_pipe",
     206             :         .accept_connection      = named_pipe_accept,
     207             :         .recv_handler           = named_pipe_recv,
     208             :         .send_handler           = named_pipe_send,
     209             : };
     210             : 
     211         666 : NTSTATUS tstream_setup_named_pipe(TALLOC_CTX *mem_ctx,
     212             :                                   struct tevent_context *event_context,
     213             :                                   struct loadparm_context *lp_ctx,
     214             :                                   const struct model_ops *model_ops,
     215             :                                   const struct stream_server_ops *stream_ops,
     216             :                                   const char *pipe_name,
     217             :                                   void *private_data,
     218             :                                   void *process_context)
     219             : {
     220             :         char *dirname;
     221             :         struct named_pipe_socket *pipe_sock;
     222         666 :         NTSTATUS status = NT_STATUS_NO_MEMORY;;
     223             : 
     224         666 :         pipe_sock = talloc(mem_ctx, struct named_pipe_socket);
     225         666 :         if (pipe_sock == NULL) {
     226           0 :                 goto fail;
     227             :         }
     228             : 
     229             :         /* remember the details about the pipe */
     230         666 :         pipe_sock->pipe_name = strlower_talloc(pipe_sock, pipe_name);
     231         666 :         if (pipe_sock->pipe_name == NULL) {
     232           0 :                 goto fail;
     233             :         }
     234             : 
     235         666 :         if (!directory_create_or_exist(lpcfg_ncalrpc_dir(lp_ctx), 0755)) {
     236           0 :                 status = map_nt_error_from_unix_common(errno);
     237           0 :                 DBG_ERR("Failed to create ncalrpc pipe directory '%s' - %s\n",
     238             :                         lpcfg_ncalrpc_dir(lp_ctx), nt_errstr(status));
     239           0 :                 goto fail;
     240             :         }
     241             : 
     242         666 :         dirname = talloc_asprintf(pipe_sock, "%s/np", lpcfg_ncalrpc_dir(lp_ctx));
     243         666 :         if (dirname == NULL) {
     244           0 :                 goto fail;
     245             :         }
     246             : 
     247         666 :         if (!directory_create_or_exist_strict(dirname, geteuid(), 0700)) {
     248           0 :                 status = map_nt_error_from_unix_common(errno);
     249           0 :                 DBG_ERR("Failed to create stream pipe directory '%s' - %s\n",
     250             :                         dirname, nt_errstr(status));
     251           0 :                 goto fail;
     252             :         }
     253             : 
     254         666 :         if (strncmp(pipe_name, "\\pipe\\", 6) == 0) {
     255         666 :                 pipe_name += 6;
     256             :         }
     257             : 
     258         666 :         pipe_sock->pipe_path = talloc_asprintf(pipe_sock, "%s/%s", dirname,
     259             :                                                pipe_name);
     260         666 :         if (pipe_sock->pipe_path == NULL) {
     261           0 :                 goto fail;
     262             :         }
     263             : 
     264         666 :         talloc_free(dirname);
     265             : 
     266         666 :         pipe_sock->ops = stream_ops;
     267         666 :         pipe_sock->private_data      = private_data;
     268             : 
     269         666 :         status = stream_setup_socket(pipe_sock,
     270             :                                      event_context,
     271             :                                      lp_ctx,
     272             :                                      model_ops,
     273             :                                      &named_pipe_stream_ops,
     274             :                                      "unix",
     275             :                                      pipe_sock->pipe_path,
     276             :                                      NULL,
     277             :                                      NULL,
     278             :                                      pipe_sock,
     279             :                                      process_context);
     280         666 :         if (!NT_STATUS_IS_OK(status)) {
     281           0 :                 goto fail;
     282             :         }
     283         666 :         return NT_STATUS_OK;
     284             : 
     285           0 :  fail:
     286           0 :         talloc_free(pipe_sock);
     287           0 :         return status;
     288             : }

Generated by: LCOV version 1.13