LCOV - code coverage report
Current view: top level - source3/smbd - smb1_pipes.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 102 198 51.5 %
Date: 2024-04-21 15:09:00 Functions: 5 7 71.4 %

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

Generated by: LCOV version 1.14