LCOV - code coverage report
Current view: top level - source3/smbd - smb1_pipes.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 184 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Pipe SMB reply routines
       4             :    Copyright (C) Andrew Tridgell 1992-1998
       5             :    Copyright (C) Luke Kenneth Casson Leighton 1996-1998
       6             :    Copyright (C) Paul Ashton  1997-1998.
       7             :    Copyright (C) Jeremy Allison 2005.
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : /*
      23             :    This file handles reply_ calls on named pipes that the server
      24             :    makes to handle specific protocols
      25             : */
      26             : 
      27             : 
      28             : #include "includes.h"
      29             : #include "smbd/smbd.h"
      30             : #include "smbd/globals.h"
      31             : #include "libcli/security/security.h"
      32             : #include "rpc_server/srv_pipe_hnd.h"
      33             : #include "auth/auth_util.h"
      34             : #include "librpc/rpc/dcerpc_helper.h"
      35             : 
      36             : /****************************************************************************
      37             :  Reply to an open and X on a named pipe.
      38             :  This code is basically stolen from reply_open_and_X with some
      39             :  wrinkles to handle pipes.
      40             : ****************************************************************************/
      41             : 
      42           0 : void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req)
      43             : {
      44           0 :         const char *fname = NULL;
      45           0 :         char *pipe_name = NULL;
      46             :         files_struct *fsp;
      47           0 :         TALLOC_CTX *ctx = talloc_tos();
      48             :         NTSTATUS status;
      49             : 
      50             :         /* XXXX we need to handle passed times, sattr and flags */
      51           0 :         srvstr_pull_req_talloc(ctx, req, &pipe_name, req->buf, STR_TERMINATE);
      52           0 :         if (!pipe_name) {
      53           0 :                 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
      54             :                                 ERRDOS, ERRbadpipe);
      55           0 :                 return;
      56             :         }
      57             : 
      58             :         /* If the name doesn't start \PIPE\ then this is directed */
      59             :         /* at a mailslot or something we really, really don't understand, */
      60             :         /* not just something we really don't understand. */
      61             : 
      62             : #define PIPE            "PIPE\\"
      63             : #define PIPELEN         strlen(PIPE)
      64             : 
      65           0 :         fname = pipe_name;
      66           0 :         while (fname[0] == '\\') {
      67           0 :                 fname++;
      68             :         }
      69           0 :         if (!strnequal(fname, PIPE, PIPELEN)) {
      70           0 :                 reply_nterror(req, NT_STATUS_OBJECT_PATH_SYNTAX_BAD);
      71           0 :                 return;
      72             :         }
      73           0 :         fname += PIPELEN;
      74           0 :         while (fname[0] == '\\') {
      75           0 :                 fname++;
      76             :         }
      77             : 
      78           0 :         DEBUG(4,("Opening pipe %s => %s.\n", pipe_name, fname));
      79             : 
      80             : #if 0
      81             :         /*
      82             :          * Hack for NT printers... JRA.
      83             :          */
      84             :         if(should_fail_next_srvsvc_open(fname)) {
      85             :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
      86             :                 return;
      87             :         }
      88             : #endif
      89             : 
      90           0 :         status = open_np_file(req, fname, &fsp);
      91           0 :         if (!NT_STATUS_IS_OK(status)) {
      92           0 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
      93           0 :                         reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
      94             :                                         ERRDOS, ERRbadpipe);
      95           0 :                         return;
      96             :                 }
      97           0 :                 reply_nterror(req, status);
      98           0 :                 return;
      99             :         }
     100             : 
     101             :         /* Prepare the reply */
     102           0 :         reply_smb1_outbuf(req, 15, 0);
     103             : 
     104           0 :         SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
     105           0 :         SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
     106             : 
     107             :         /* Mark the opened file as an existing named pipe in message mode. */
     108           0 :         SSVAL(req->outbuf,smb_vwv9,2);
     109           0 :         SSVAL(req->outbuf,smb_vwv10,0xc700);
     110             : 
     111           0 :         SSVAL(req->outbuf, smb_vwv2, fsp->fnum);
     112           0 :         SSVAL(req->outbuf, smb_vwv3, 0);     /* fmode */
     113           0 :         srv_put_dos_date3((char *)req->outbuf, smb_vwv4, 0); /* mtime */
     114           0 :         SIVAL(req->outbuf, smb_vwv6, 0);     /* size */
     115           0 :         SSVAL(req->outbuf, smb_vwv8, 0);     /* rmode */
     116           0 :         SSVAL(req->outbuf, smb_vwv11, 0x0001);
     117             : }
     118             : 
     119             : /****************************************************************************
     120             :  Reply to a write and X.
     121             : 
     122             :  This code is basically stolen from reply_write_and_X with some
     123             :  wrinkles to handle pipes.
     124             : ****************************************************************************/
     125             : 
     126             : struct pipe_write_andx_state {
     127             :         bool pipe_start_message_raw;
     128             :         size_t numtowrite;
     129             : };
     130             : 
     131             : static void pipe_write_andx_done(struct tevent_req *subreq);
     132             : 
     133           0 : void reply_pipe_write_and_X(struct smb_request *req)
     134             : {
     135           0 :         files_struct *fsp = file_fsp(req, SVAL(req->vwv+2, 0));
     136           0 :         int smb_doff = SVAL(req->vwv+11, 0);
     137             :         const uint8_t *data;
     138             :         struct pipe_write_andx_state *state;
     139             :         struct tevent_req *subreq;
     140             : 
     141           0 :         if (!fsp_is_np(fsp)) {
     142           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     143           0 :                 return;
     144             :         }
     145             : 
     146           0 :         if (fsp->vuid != req->vuid) {
     147           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     148           0 :                 return;
     149             :         }
     150             : 
     151           0 :         state = talloc(req, struct pipe_write_andx_state);
     152           0 :         if (state == NULL) {
     153           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     154           0 :                 return;
     155             :         }
     156           0 :         req->async_priv = state;
     157             : 
     158           0 :         state->numtowrite = SVAL(req->vwv+10, 0);
     159           0 :         state->pipe_start_message_raw =
     160           0 :                 ((SVAL(req->vwv+7, 0) & (PIPE_START_MESSAGE|PIPE_RAW_MODE))
     161           0 :                  == (PIPE_START_MESSAGE|PIPE_RAW_MODE));
     162             : 
     163           0 :         DEBUG(6, ("reply_pipe_write_and_X: %s, name: %s len: %d\n",
     164             :                   fsp_fnum_dbg(fsp), fsp_str_dbg(fsp), (int)state->numtowrite));
     165             : 
     166           0 :         data = (const uint8_t *)smb_base(req->inbuf) + smb_doff;
     167             : 
     168           0 :         if (state->pipe_start_message_raw) {
     169             :                 /*
     170             :                  * For the start of a message in named pipe byte mode,
     171             :                  * the first two bytes are a length-of-pdu field. Ignore
     172             :                  * them (we don't trust the client). JRA.
     173             :                  */
     174           0 :                 if (state->numtowrite < 2) {
     175           0 :                         DEBUG(0,("reply_pipe_write_and_X: start of message "
     176             :                                  "set and not enough data sent.(%u)\n",
     177             :                                  (unsigned int)state->numtowrite ));
     178           0 :                         reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     179           0 :                         return;
     180             :                 }
     181             : 
     182           0 :                 data += 2;
     183           0 :                 state->numtowrite -= 2;
     184             :         }
     185             : 
     186           0 :         subreq = np_write_send(state, req->sconn->ev_ctx,
     187             :                                fsp->fake_file_handle, data, state->numtowrite);
     188           0 :         if (subreq == NULL) {
     189           0 :                 TALLOC_FREE(state);
     190           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     191           0 :                 return;
     192             :         }
     193           0 :         tevent_req_set_callback(subreq, pipe_write_andx_done,
     194           0 :                                 talloc_move(req->conn, &req));
     195             : }
     196             : 
     197           0 : static void pipe_write_andx_done(struct tevent_req *subreq)
     198             : {
     199           0 :         struct smb_request *req = tevent_req_callback_data(
     200             :                 subreq, struct smb_request);
     201           0 :         struct pipe_write_andx_state *state = talloc_get_type_abort(
     202             :                 req->async_priv, struct pipe_write_andx_state);
     203             :         NTSTATUS status;
     204           0 :         ssize_t nwritten = -1;
     205             : 
     206           0 :         status = np_write_recv(subreq, &nwritten);
     207           0 :         TALLOC_FREE(subreq);
     208             : 
     209           0 :         if (!NT_STATUS_IS_OK(status)) {
     210           0 :                 reply_nterror(req, status);
     211           0 :                 goto done;
     212             :         }
     213             : 
     214             :         /* Looks bogus to me now. Is this error message correct ? JRA. */
     215           0 :         if (nwritten != state->numtowrite) {
     216           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
     217           0 :                 goto done;
     218             :         }
     219             : 
     220           0 :         reply_smb1_outbuf(req, 6, 0);
     221             : 
     222           0 :         SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
     223           0 :         SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
     224             : 
     225           0 :         nwritten = (state->pipe_start_message_raw ? nwritten + 2 : nwritten);
     226           0 :         SSVAL(req->outbuf,smb_vwv2,nwritten);
     227             : 
     228           0 :         DEBUG(3,("writeX-IPC nwritten=%d\n", (int)nwritten));
     229             : 
     230           0 :  done:
     231             :         /*
     232             :          * We must free here as the ownership of req was
     233             :          * moved to the connection struct in reply_pipe_write_and_X().
     234             :          */
     235           0 :         smb_request_done(req);
     236           0 : }
     237             : 
     238             : /****************************************************************************
     239             :  Reply to a read and X.
     240             :  This code is basically stolen from reply_read_and_X with some
     241             :  wrinkles to handle pipes.
     242             : ****************************************************************************/
     243             : 
     244             : struct pipe_read_andx_state {
     245             :         uint8_t *outbuf;
     246             :         int smb_mincnt;
     247             :         int smb_maxcnt;
     248             : };
     249             : 
     250             : static void pipe_read_andx_done(struct tevent_req *subreq);
     251             : 
     252           0 : void reply_pipe_read_and_X(struct smb_request *req)
     253             : {
     254           0 :         files_struct *fsp = file_fsp(req, SVAL(req->vwv+0, 0));
     255             :         uint8_t *data;
     256             :         struct pipe_read_andx_state *state;
     257             :         struct tevent_req *subreq;
     258             : 
     259             :         /* we don't use the offset given to use for pipe reads. This
     260             :            is deliberate, instead we always return the next lump of
     261             :            data on the pipe */
     262             : #if 0
     263             :         uint32_t smb_offs = IVAL(req->vwv+3, 0);
     264             : #endif
     265             : 
     266           0 :         if (!fsp_is_np(fsp)) {
     267           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     268           0 :                 return;
     269             :         }
     270             : 
     271           0 :         if (fsp->vuid != req->vuid) {
     272           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     273           0 :                 return;
     274             :         }
     275             : 
     276           0 :         state = talloc(req, struct pipe_read_andx_state);
     277           0 :         if (state == NULL) {
     278           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     279           0 :                 return;
     280             :         }
     281           0 :         req->async_priv = state;
     282             : 
     283           0 :         state->smb_maxcnt = SVAL(req->vwv+5, 0);
     284           0 :         state->smb_mincnt = SVAL(req->vwv+6, 0);
     285             : 
     286           0 :         reply_smb1_outbuf(req, 12, state->smb_maxcnt + 1 /* padding byte */);
     287           0 :         SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */
     288           0 :         SSVAL(req->outbuf, smb_vwv1, 0);    /* no andx offset */
     289           0 :         SCVAL(smb_buf(req->outbuf), 0, 0); /* padding byte */
     290             : 
     291           0 :         data = (uint8_t *)smb_buf(req->outbuf) + 1 /* padding byte */;
     292             : 
     293             :         /*
     294             :          * We have to tell the upper layers that we're async.
     295             :          */
     296           0 :         state->outbuf = req->outbuf;
     297           0 :         req->outbuf = NULL;
     298             : 
     299           0 :         subreq = np_read_send(state, req->sconn->ev_ctx,
     300             :                               fsp->fake_file_handle, data,
     301           0 :                               state->smb_maxcnt);
     302           0 :         if (subreq == NULL) {
     303           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     304           0 :                 return;
     305             :         }
     306           0 :         tevent_req_set_callback(subreq, pipe_read_andx_done,
     307           0 :                                 talloc_move(req->conn, &req));
     308             : }
     309             : 
     310           0 : static void pipe_read_andx_done(struct tevent_req *subreq)
     311             : {
     312           0 :         struct smb_request *req = tevent_req_callback_data(
     313             :                 subreq, struct smb_request);
     314           0 :         struct pipe_read_andx_state *state = talloc_get_type_abort(
     315             :                 req->async_priv, struct pipe_read_andx_state);
     316             :         NTSTATUS status;
     317             :         ssize_t nread;
     318             :         bool is_data_outstanding;
     319             : 
     320           0 :         status = np_read_recv(subreq, &nread, &is_data_outstanding);
     321           0 :         TALLOC_FREE(subreq);
     322           0 :         if (!NT_STATUS_IS_OK(status)) {
     323           0 :                 NTSTATUS old = status;
     324           0 :                 status = nt_status_np_pipe(old);
     325           0 :                 reply_nterror(req, status);
     326           0 :                 goto done;
     327             :         }
     328             : 
     329           0 :         req->outbuf = state->outbuf;
     330           0 :         state->outbuf = NULL;
     331             : 
     332           0 :         srv_smb1_set_message((char *)req->outbuf, 12, nread + 1 /* padding byte */,
     333             :                         false);
     334             : 
     335             : #if 0
     336             :         /*
     337             :          * we should return STATUS_BUFFER_OVERFLOW if there's
     338             :          * out standing data.
     339             :          *
     340             :          * But we can't enable it yet, as it has bad interactions
     341             :          * with fixup_chain_error_packet() in chain_reply().
     342             :          */
     343             :         if (is_data_outstanding) {
     344             :                 error_packet_set((char *)req->outbuf, ERRDOS, ERRmoredata,
     345             :                                  STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__);
     346             :         }
     347             : #endif
     348             : 
     349           0 :         SSVAL(req->outbuf,smb_vwv5,nread);
     350           0 :         SSVAL(req->outbuf,smb_vwv6,
     351             :               (smb_wct - 4)     /* offset from smb header to wct */
     352             :               + 1               /* the wct field */
     353             :               + 12 * sizeof(uint16_t) /* vwv */
     354             :               + 2               /* the buflen field */
     355             :               + 1);             /* padding byte */
     356             : 
     357           0 :         DEBUG(3,("readX-IPC min=%d max=%d nread=%d\n",
     358             :                  state->smb_mincnt, state->smb_maxcnt, (int)nread));
     359             : 
     360           0 :  done:
     361             :         /*
     362             :          * We must free here as the ownership of req was
     363             :          * moved to the connection struct in reply_pipe_read_and_X().
     364             :          */
     365           0 :         smb_request_done(req);
     366           0 : }
     367             : 
     368             : /****************************************************************************
     369             :  Reply to a write on a pipe.
     370             : ****************************************************************************/
     371             : 
     372             : struct pipe_write_state {
     373             :         size_t numtowrite;
     374             : };
     375             : 
     376             : static void pipe_write_done(struct tevent_req *subreq);
     377             : 
     378           0 : void reply_pipe_write(struct smb_request *req)
     379             : {
     380           0 :         files_struct *fsp = file_fsp(req, SVAL(req->vwv+0, 0));
     381             :         const uint8_t *data;
     382             :         struct pipe_write_state *state;
     383             :         struct tevent_req *subreq;
     384             : 
     385           0 :         if (!fsp_is_np(fsp)) {
     386           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     387           0 :                 return;
     388             :         }
     389             : 
     390           0 :         if (fsp->vuid != req->vuid) {
     391           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     392           0 :                 return;
     393             :         }
     394             : 
     395           0 :         state = talloc(req, struct pipe_write_state);
     396           0 :         if (state == NULL) {
     397           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     398           0 :                 return;
     399             :         }
     400           0 :         req->async_priv = state;
     401             : 
     402           0 :         state->numtowrite = SVAL(req->vwv+1, 0);
     403             : 
     404           0 :         data = req->buf + 3;
     405             : 
     406           0 :         DEBUG(6, ("reply_pipe_write: %s, name: %s len: %d\n", fsp_fnum_dbg(fsp),
     407             :                   fsp_str_dbg(fsp), (int)state->numtowrite));
     408             : 
     409           0 :         subreq = np_write_send(state, req->sconn->ev_ctx,
     410             :                                fsp->fake_file_handle, data, state->numtowrite);
     411           0 :         if (subreq == NULL) {
     412           0 :                 TALLOC_FREE(state);
     413           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     414           0 :                 return;
     415             :         }
     416           0 :         tevent_req_set_callback(subreq, pipe_write_done,
     417           0 :                                 talloc_move(req->conn, &req));
     418             : }
     419             : 
     420           0 : static void pipe_write_done(struct tevent_req *subreq)
     421             : {
     422           0 :         struct smb_request *req = tevent_req_callback_data(
     423             :                 subreq, struct smb_request);
     424           0 :         struct pipe_write_state *state = talloc_get_type_abort(
     425             :                 req->async_priv, struct pipe_write_state);
     426             :         NTSTATUS status;
     427           0 :         ssize_t nwritten = -1;
     428             : 
     429           0 :         status = np_write_recv(subreq, &nwritten);
     430           0 :         TALLOC_FREE(subreq);
     431           0 :         if (nwritten < 0) {
     432           0 :                 reply_nterror(req, status);
     433           0 :                 goto send;
     434             :         }
     435             : 
     436             :         /* Looks bogus to me now. Needs to be removed ? JRA. */
     437           0 :         if ((nwritten == 0 && state->numtowrite != 0)) {
     438           0 :                 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
     439           0 :                 goto send;
     440             :         }
     441             : 
     442           0 :         reply_smb1_outbuf(req, 1, 0);
     443             : 
     444           0 :         SSVAL(req->outbuf,smb_vwv0,nwritten);
     445             : 
     446           0 :         DEBUG(3,("write-IPC nwritten=%d\n", (int)nwritten));
     447             : 
     448           0 :  send:
     449           0 :         if (!smb1_srv_send(req->xconn, (char *)req->outbuf,
     450           0 :                           true, req->seqnum+1,
     451           0 :                           IS_CONN_ENCRYPTED(req->conn)||req->encrypted,
     452             :                           &req->pcd)) {
     453           0 :                 exit_server_cleanly("construct_reply: smb1_srv_send failed.");
     454             :         }
     455           0 :         TALLOC_FREE(req);
     456           0 : }

Generated by: LCOV version 1.13