LCOV - code coverage report
Current view: top level - source3/smbd - ipc.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 201 440 45.7 %
Date: 2021-08-25 13:27:56 Functions: 10 18 55.6 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    Inter-process communication and named pipe handling
       4             :    Copyright (C) Andrew Tridgell 1992-1998
       5             : 
       6             :    SMB Version handling
       7             :    Copyright (C) John H Terpstra 1995-1998
       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 the named pipe and mailslot calls
      24             :    in the SMBtrans protocol
      25             :    */
      26             : 
      27             : #include "includes.h"
      28             : #include "smbd/smbd.h"
      29             : #include "smbd/globals.h"
      30             : #include "smbprofile.h"
      31             : #include "rpc_server/srv_pipe_hnd.h"
      32             : 
      33             : #define NERR_notsupported 50
      34             : 
      35             : static void api_no_reply(connection_struct *conn, struct smb_request *req);
      36             : 
      37             : /*******************************************************************
      38             :  copies parameters and data, as needed, into the smb buffer
      39             : 
      40             :  *both* the data and params sections should be aligned.  this
      41             :  is fudged in the rpc pipes by 
      42             :  at present, only the data section is.  this may be a possible
      43             :  cause of some of the ipc problems being experienced.  lkcl26dec97
      44             : 
      45             :  ******************************************************************/
      46             : 
      47        1531 : static void copy_trans_params_and_data(char *outbuf, int align,
      48             :                                 char *rparam, int param_offset, int param_len,
      49             :                                 char *rdata, int data_offset, int data_len)
      50             : {
      51        1531 :         char *copy_into = smb_buf(outbuf);
      52             : 
      53        1531 :         if(param_len < 0)
      54           0 :                 param_len = 0;
      55             : 
      56        1531 :         if(data_len < 0)
      57           0 :                 data_len = 0;
      58             : 
      59        1531 :         DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d] (align %d)\n",
      60             :                         param_offset, param_offset + param_len,
      61             :                         data_offset , data_offset  + data_len,
      62             :                         align));
      63             : 
      64        1531 :         *copy_into = '\0';
      65             : 
      66        1531 :         copy_into += 1;
      67             : 
      68        1531 :         if (param_len)
      69         127 :                 memcpy(copy_into, &rparam[param_offset], param_len);
      70             : 
      71        1531 :         copy_into += param_len;
      72        1531 :         if (align) {
      73          44 :                 memset(copy_into, '\0', align);
      74             :         }
      75             : 
      76        1531 :         copy_into += align;
      77             : 
      78        1531 :         if (data_len )
      79        1496 :                 memcpy(copy_into, &rdata[data_offset], data_len);
      80        1531 : }
      81             : 
      82           1 : NTSTATUS nt_status_np_pipe(NTSTATUS status)
      83             : {
      84           1 :         if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_DISCONNECTED)) {
      85           1 :                 status = NT_STATUS_PIPE_DISCONNECTED;
      86           0 :         } else if (NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
      87           0 :                 status = NT_STATUS_PIPE_BROKEN;
      88             :         }
      89             : 
      90           1 :         return status;
      91             : }
      92             : 
      93             : /****************************************************************************
      94             :  Send a trans reply.
      95             :  ****************************************************************************/
      96             : 
      97        1531 : void send_trans_reply(connection_struct *conn,
      98             :                       struct smb_request *req,
      99             :                       char *rparam, int rparam_len,
     100             :                       char *rdata, int rdata_len,
     101             :                       bool buffer_too_large)
     102             : {
     103             :         int this_ldata,this_lparam;
     104        1531 :         int tot_data_sent = 0;
     105        1531 :         int tot_param_sent = 0;
     106             :         int align;
     107             : 
     108        1531 :         int ldata  = rdata  ? rdata_len : 0;
     109        1531 :         int lparam = rparam ? rparam_len : 0;
     110        1531 :         struct smbXsrv_connection *xconn = req->xconn;
     111        1531 :         int max_send = xconn->smb1.sessions.max_send;
     112             :         /* HACK: make sure we send at least 128 byte in one go */
     113        1531 :         int hdr_overhead = SMB_BUFFER_SIZE_MIN - 128;
     114             : 
     115        1531 :         if (buffer_too_large)
     116           0 :                 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
     117             : 
     118        1531 :         this_lparam = MIN(lparam,max_send - hdr_overhead);
     119        1531 :         this_ldata  = MIN(ldata,max_send - (hdr_overhead+this_lparam));
     120             : 
     121        1531 :         align = ((this_lparam)%4);
     122             : 
     123        1531 :         reply_outbuf(req, 10, 1+align+this_ldata+this_lparam);
     124             : 
     125             :         /*
     126             :          * We might have SMBtranss in req which was transferred to the outbuf,
     127             :          * fix that.
     128             :          */
     129        1531 :         SCVAL(req->outbuf, smb_com, SMBtrans);
     130             : 
     131        1531 :         copy_trans_params_and_data((char *)req->outbuf, align,
     132             :                                 rparam, tot_param_sent, this_lparam,
     133             :                                 rdata, tot_data_sent, this_ldata);
     134             : 
     135        1531 :         SSVAL(req->outbuf,smb_vwv0,lparam);
     136        1531 :         SSVAL(req->outbuf,smb_vwv1,ldata);
     137        1531 :         SSVAL(req->outbuf,smb_vwv3,this_lparam);
     138        1531 :         SSVAL(req->outbuf,smb_vwv4,
     139             :               smb_offset(smb_buf(req->outbuf)+1, req->outbuf));
     140        1531 :         SSVAL(req->outbuf,smb_vwv5,0);
     141        1531 :         SSVAL(req->outbuf,smb_vwv6,this_ldata);
     142        1531 :         SSVAL(req->outbuf,smb_vwv7,
     143             :               smb_offset(smb_buf(req->outbuf)+1+this_lparam+align,
     144             :                          req->outbuf));
     145        1531 :         SSVAL(req->outbuf,smb_vwv8,0);
     146        1531 :         SSVAL(req->outbuf,smb_vwv9,0);
     147             : 
     148        1531 :         if (buffer_too_large) {
     149           0 :                 error_packet_set((char *)req->outbuf, ERRDOS, ERRmoredata,
     150           0 :                                  STATUS_BUFFER_OVERFLOW, __LINE__, __FILE__);
     151             :         }
     152             : 
     153        1531 :         show_msg((char *)req->outbuf);
     154        4593 :         if (!srv_send_smb(xconn, (char *)req->outbuf,
     155        1531 :                           true, req->seqnum+1,
     156        1531 :                           IS_CONN_ENCRYPTED(conn), &req->pcd)) {
     157           0 :                 exit_server_cleanly("send_trans_reply: srv_send_smb failed.");
     158             :         }
     159             : 
     160        1531 :         TALLOC_FREE(req->outbuf);
     161             : 
     162        1531 :         tot_data_sent = this_ldata;
     163        1531 :         tot_param_sent = this_lparam;
     164             : 
     165        3062 :         while (tot_data_sent < ldata || tot_param_sent < lparam)
     166             :         {
     167           0 :                 this_lparam = MIN(lparam-tot_param_sent,
     168             :                                   max_send - hdr_overhead);
     169           0 :                 this_ldata  = MIN(ldata -tot_data_sent,
     170             :                                   max_send - (hdr_overhead+this_lparam));
     171             : 
     172           0 :                 if(this_lparam < 0)
     173           0 :                         this_lparam = 0;
     174             : 
     175           0 :                 if(this_ldata < 0)
     176           0 :                         this_ldata = 0;
     177             : 
     178           0 :                 align = (this_lparam%4);
     179             : 
     180           0 :                 reply_outbuf(req, 10, 1+align+this_ldata+this_lparam);
     181             : 
     182             :                 /*
     183             :                  * We might have SMBtranss in req which was transferred to the
     184             :                  * outbuf, fix that.
     185             :                  */
     186           0 :                 SCVAL(req->outbuf, smb_com, SMBtrans);
     187             : 
     188           0 :                 copy_trans_params_and_data((char *)req->outbuf, align,
     189             :                                            rparam, tot_param_sent, this_lparam,
     190             :                                            rdata, tot_data_sent, this_ldata);
     191             : 
     192           0 :                 SSVAL(req->outbuf,smb_vwv0,lparam);
     193           0 :                 SSVAL(req->outbuf,smb_vwv1,ldata);
     194             : 
     195           0 :                 SSVAL(req->outbuf,smb_vwv3,this_lparam);
     196           0 :                 SSVAL(req->outbuf,smb_vwv4,
     197             :                       smb_offset(smb_buf(req->outbuf)+1,req->outbuf));
     198           0 :                 SSVAL(req->outbuf,smb_vwv5,tot_param_sent);
     199           0 :                 SSVAL(req->outbuf,smb_vwv6,this_ldata);
     200           0 :                 SSVAL(req->outbuf,smb_vwv7,
     201             :                       smb_offset(smb_buf(req->outbuf)+1+this_lparam+align,
     202             :                                  req->outbuf));
     203           0 :                 SSVAL(req->outbuf,smb_vwv8,tot_data_sent);
     204           0 :                 SSVAL(req->outbuf,smb_vwv9,0);
     205             : 
     206           0 :                 if (buffer_too_large) {
     207           0 :                         error_packet_set((char *)req->outbuf,
     208             :                                          ERRDOS, ERRmoredata,
     209           0 :                                          STATUS_BUFFER_OVERFLOW,
     210             :                                          __LINE__, __FILE__);
     211             :                 }
     212             : 
     213           0 :                 show_msg((char *)req->outbuf);
     214           0 :                 if (!srv_send_smb(xconn, (char *)req->outbuf,
     215           0 :                                   true, req->seqnum+1,
     216           0 :                                   IS_CONN_ENCRYPTED(conn), &req->pcd))
     217           0 :                         exit_server_cleanly("send_trans_reply: srv_send_smb "
     218             :                                             "failed.");
     219             : 
     220           0 :                 tot_data_sent  += this_ldata;
     221           0 :                 tot_param_sent += this_lparam;
     222           0 :                 TALLOC_FREE(req->outbuf);
     223             :         }
     224        1531 : }
     225             : 
     226             : /****************************************************************************
     227             :  Start the first part of an RPC reply which began with an SMBtrans request.
     228             : ****************************************************************************/
     229             : 
     230             : struct dcerpc_cmd_state {
     231             :         struct fake_file_handle *handle;
     232             :         uint8_t *data;
     233             :         size_t num_data;
     234             :         size_t max_read;
     235             : };
     236             : 
     237             : static void api_dcerpc_cmd_write_done(struct tevent_req *subreq);
     238             : static void api_dcerpc_cmd_read_done(struct tevent_req *subreq);
     239             : 
     240        1404 : static void api_dcerpc_cmd(connection_struct *conn, struct smb_request *req,
     241             :                            files_struct *fsp, uint8_t *data, size_t length,
     242             :                            size_t max_read)
     243             : {
     244             :         struct tevent_req *subreq;
     245             :         struct dcerpc_cmd_state *state;
     246             :         bool busy;
     247             : 
     248        1404 :         if (!fsp_is_np(fsp)) {
     249           0 :                 api_no_reply(conn, req);
     250           0 :                 return;
     251             :         }
     252             : 
     253             :         /*
     254             :          * Trans requests are only allowed
     255             :          * if no other Trans or Read is active
     256             :          */
     257        1404 :         busy = np_read_in_progress(fsp->fake_file_handle);
     258        1404 :         if (busy) {
     259           0 :                 reply_nterror(req, NT_STATUS_PIPE_BUSY);
     260           0 :                 return;
     261             :         }
     262             : 
     263        1404 :         state = talloc(req, struct dcerpc_cmd_state);
     264        1404 :         if (state == NULL) {
     265           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     266           0 :                 return;
     267             :         }
     268        1404 :         req->async_priv = state;
     269             : 
     270        1404 :         state->handle = fsp->fake_file_handle;
     271             : 
     272             :         /*
     273             :          * This memdup severely sucks. But doing it properly essentially means
     274             :          * to rewrite lanman.c, something which I don't really want to do now.
     275             :          */
     276        1404 :         state->data = (uint8_t *)talloc_memdup(state, data, length);
     277        1404 :         if (state->data == NULL) {
     278           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     279           0 :                 return;
     280             :         }
     281        1404 :         state->num_data = length;
     282        1404 :         state->max_read = max_read;
     283             : 
     284        1404 :         subreq = np_write_send(state, req->sconn->ev_ctx, state->handle,
     285        1404 :                                state->data, length);
     286        1404 :         if (subreq == NULL) {
     287           0 :                 TALLOC_FREE(state);
     288           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     289           0 :                 return;
     290             :         }
     291        1404 :         tevent_req_set_callback(subreq, api_dcerpc_cmd_write_done,
     292             :                                 talloc_move(conn, &req));
     293             : }
     294             : 
     295        1404 : static void api_dcerpc_cmd_write_done(struct tevent_req *subreq)
     296             : {
     297        1404 :         struct smb_request *req = tevent_req_callback_data(
     298             :                 subreq, struct smb_request);
     299        1404 :         struct dcerpc_cmd_state *state = talloc_get_type_abort(
     300             :                 req->async_priv, struct dcerpc_cmd_state);
     301             :         NTSTATUS status;
     302        1404 :         ssize_t nwritten = -1;
     303             : 
     304        1404 :         status = np_write_recv(subreq, &nwritten);
     305        1404 :         TALLOC_FREE(subreq);
     306        1404 :         if (!NT_STATUS_IS_OK(status)) {
     307           0 :                 NTSTATUS old = status;
     308           0 :                 status = nt_status_np_pipe(old);
     309             : 
     310           0 :                 DEBUG(10, ("Could not write to pipe: %s%s%s\n",
     311             :                            nt_errstr(old),
     312             :                            NT_STATUS_EQUAL(old, status)?"":" => ",
     313             :                            NT_STATUS_EQUAL(old, status)?"":nt_errstr(status)));
     314           0 :                 reply_nterror(req, status);
     315           0 :                 goto send;
     316             :         }
     317        1404 :         if (nwritten != state->num_data) {
     318           0 :                 status = NT_STATUS_PIPE_NOT_AVAILABLE;
     319           0 :                 DEBUG(10, ("Could not write to pipe: (%d/%d) => %s\n",
     320             :                            (int)state->num_data,
     321             :                            (int)nwritten, nt_errstr(status)));
     322           0 :                 reply_nterror(req, status);
     323           0 :                 goto send;
     324             :         }
     325             : 
     326        1404 :         state->data = talloc_realloc(state, state->data, uint8_t,
     327             :                                            state->max_read);
     328        1404 :         if (state->data == NULL) {
     329           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     330           0 :                 goto send;
     331             :         }
     332             : 
     333        1404 :         subreq = np_read_send(state, req->sconn->ev_ctx,
     334             :                               state->handle, state->data, state->max_read);
     335        1404 :         if (subreq == NULL) {
     336           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     337           0 :                 goto send;
     338             :         }
     339        1404 :         tevent_req_set_callback(subreq, api_dcerpc_cmd_read_done, req);
     340        1404 :         return;
     341             : 
     342           0 :  send:
     343           0 :         if (!srv_send_smb(
     344           0 :                     req->xconn, (char *)req->outbuf,
     345           0 :                     true, req->seqnum+1,
     346           0 :                     IS_CONN_ENCRYPTED(req->conn) || req->encrypted,
     347             :                     &req->pcd)) {
     348           0 :                 exit_server_cleanly("api_dcerpc_cmd_write_done: "
     349             :                                     "srv_send_smb failed.");
     350             :         }
     351           0 :         TALLOC_FREE(req);
     352             : }
     353             : 
     354        1404 : static void api_dcerpc_cmd_read_done(struct tevent_req *subreq)
     355             : {
     356        1404 :         struct smb_request *req = tevent_req_callback_data(
     357             :                 subreq, struct smb_request);
     358        1404 :         struct dcerpc_cmd_state *state = talloc_get_type_abort(
     359             :                 req->async_priv, struct dcerpc_cmd_state);
     360             :         NTSTATUS status;
     361             :         ssize_t nread;
     362             :         bool is_data_outstanding;
     363             : 
     364        1404 :         status = np_read_recv(subreq, &nread, &is_data_outstanding);
     365        1404 :         TALLOC_FREE(subreq);
     366             : 
     367        1404 :         if (!NT_STATUS_IS_OK(status)) {
     368           0 :                 NTSTATUS old = status;
     369           0 :                 status = nt_status_np_pipe(old);
     370             : 
     371           0 :                 DEBUG(10, ("Could not read from to pipe: %s%s%s\n",
     372             :                            nt_errstr(old),
     373             :                            NT_STATUS_EQUAL(old, status)?"":" => ",
     374             :                            NT_STATUS_EQUAL(old, status)?"":nt_errstr(status)));
     375           0 :                 reply_nterror(req, status);
     376             : 
     377           0 :                 if (!srv_send_smb(req->xconn, (char *)req->outbuf,
     378           0 :                                   true, req->seqnum+1,
     379           0 :                                   IS_CONN_ENCRYPTED(req->conn)
     380           0 :                                   ||req->encrypted, &req->pcd)) {
     381           0 :                         exit_server_cleanly("api_dcerpc_cmd_read_done: "
     382             :                                             "srv_send_smb failed.");
     383             :                 }
     384           0 :                 TALLOC_FREE(req);
     385           0 :                 return;
     386             :         }
     387             : 
     388        1404 :         send_trans_reply(req->conn, req, NULL, 0, (char *)state->data, nread,
     389             :                          is_data_outstanding);
     390        1404 :         TALLOC_FREE(req);
     391             : }
     392             : 
     393             : /****************************************************************************
     394             :  WaitNamedPipeHandleState 
     395             : ****************************************************************************/
     396             : 
     397           0 : static void api_WNPHS(connection_struct *conn, struct smb_request *req,
     398             :                       struct files_struct *fsp, char *param, int param_len)
     399             : {
     400           0 :         if (!param || param_len < 2) {
     401           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     402           0 :                 return;
     403             :         }
     404             : 
     405           0 :         DEBUG(4,("WaitNamedPipeHandleState priority %x\n",
     406             :                  (int)SVAL(param,0)));
     407             : 
     408           0 :         send_trans_reply(conn, req, NULL, 0, NULL, 0, False);
     409             : }
     410             : 
     411             : 
     412             : /****************************************************************************
     413             :  SetNamedPipeHandleState 
     414             : ****************************************************************************/
     415             : 
     416           0 : static void api_SNPHS(connection_struct *conn, struct smb_request *req,
     417             :                       struct files_struct *fsp, char *param, int param_len)
     418             : {
     419           0 :         if (!param || param_len < 2) {
     420           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     421           0 :                 return;
     422             :         }
     423             : 
     424           0 :         DEBUG(4,("SetNamedPipeHandleState to code %x\n", (int)SVAL(param,0)));
     425             : 
     426           0 :         send_trans_reply(conn, req, NULL, 0, NULL, 0, False);
     427             : }
     428             : 
     429             : 
     430             : /****************************************************************************
     431             :  When no reply is generated, indicate unsupported.
     432             :  ****************************************************************************/
     433             : 
     434           0 : static void api_no_reply(connection_struct *conn, struct smb_request *req)
     435             : {
     436             :         char rparam[4];
     437             : 
     438             :         /* unsupported */
     439           0 :         SSVAL(rparam,0,NERR_notsupported);
     440           0 :         SSVAL(rparam,2,0); /* converter word */
     441             : 
     442           0 :         DEBUG(3,("Unsupported API fd command\n"));
     443             : 
     444             :         /* now send the reply */
     445           0 :         send_trans_reply(conn, req, rparam, 4, NULL, 0, False);
     446             : 
     447           0 :         return;
     448             : }
     449             : 
     450             : /****************************************************************************
     451             :  Handle remote api calls delivered to a named pipe already opened.
     452             :  ****************************************************************************/
     453             : 
     454        1414 : static void api_fd_reply(connection_struct *conn, uint64_t vuid,
     455             :                          struct smb_request *req,
     456             :                          uint16_t *setup, uint8_t *data, char *params,
     457             :                          int suwcnt, int tdscnt, int tpscnt,
     458             :                          int mdrcnt, int mprcnt)
     459             : {
     460             :         struct files_struct *fsp;
     461             :         int pnum;
     462             :         int subcommand;
     463             : 
     464        1414 :         DEBUG(5,("api_fd_reply\n"));
     465             : 
     466             :         /* First find out the name of this file. */
     467        1414 :         if (suwcnt != 2) {
     468           0 :                 DEBUG(0,("Unexpected named pipe transaction.\n"));
     469           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     470           0 :                 return;
     471             :         }
     472             : 
     473             :         /* Get the file handle and hence the file name. */
     474             :         /* 
     475             :          * NB. The setup array has already been transformed
     476             :          * via SVAL and so is in host byte order.
     477             :          */
     478        1414 :         pnum = ((int)setup[1]) & 0xFFFF;
     479        1414 :         subcommand = ((int)setup[0]) & 0xFFFF;
     480             : 
     481        1414 :         fsp = file_fsp(req, pnum);
     482             : 
     483        1414 :         if (!fsp_is_np(fsp)) {
     484           0 :                 if (subcommand == TRANSACT_WAITNAMEDPIPEHANDLESTATE) {
     485             :                         /* Win9x does this call with a unicode pipe name, not a pnum. */
     486             :                         /* Just return success for now... */
     487           0 :                         DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n"));
     488           0 :                         send_trans_reply(conn, req, NULL, 0, NULL, 0, False);
     489           0 :                         return;
     490             :                 }
     491             : 
     492           0 :                 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
     493           0 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     494           0 :                 return;
     495             :         }
     496             : 
     497        1414 :         if (vuid != fsp->vuid) {
     498          10 :                 DEBUG(1, ("Got pipe request (pnum %x) using invalid VUID %llu, "
     499             :                           "expected %llu\n", pnum, (unsigned long long)vuid,
     500             :                           (unsigned long long)fsp->vuid));
     501          10 :                 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
     502          10 :                 return;
     503             :         }
     504             : 
     505        1404 :         DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n",
     506             :                  subcommand, fsp_str_dbg(fsp), pnum));
     507             : 
     508        1404 :         DEBUG(10, ("api_fd_reply: p:%p max_trans_reply: %d\n", fsp, mdrcnt));
     509             : 
     510        1404 :         switch (subcommand) {
     511        1404 :         case TRANSACT_DCERPCCMD: {
     512             :                 /* dce/rpc command */
     513        1404 :                 api_dcerpc_cmd(conn, req, fsp, (uint8_t *)data, tdscnt,
     514             :                                mdrcnt);
     515        1404 :                 break;
     516             :         }
     517           0 :         case TRANSACT_WAITNAMEDPIPEHANDLESTATE:
     518             :                 /* Wait Named Pipe Handle state */
     519           0 :                 api_WNPHS(conn, req, fsp, params, tpscnt);
     520           0 :                 break;
     521           0 :         case TRANSACT_SETNAMEDPIPEHANDLESTATE:
     522             :                 /* Set Named Pipe Handle state */
     523           0 :                 api_SNPHS(conn, req, fsp, params, tpscnt);
     524           0 :                 break;
     525           0 :         default:
     526           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     527           0 :                 return;
     528             :         }
     529             : }
     530             : 
     531             : /****************************************************************************
     532             :  Handle named pipe commands.
     533             : ****************************************************************************/
     534             : 
     535        1541 : static void named_pipe(connection_struct *conn, uint64_t vuid,
     536             :                        struct smb_request *req,
     537             :                        const char *name, uint16_t *setup,
     538             :                        char *data, char *params,
     539             :                        int suwcnt, int tdscnt,int tpscnt,
     540             :                        int msrcnt, int mdrcnt, int mprcnt)
     541             : {
     542        1541 :         DEBUG(3,("named pipe command on <%s> name\n", name));
     543             : 
     544        1541 :         if (strequal(name,"LANMAN")) {
     545         127 :                 api_reply(conn, vuid, req,
     546             :                           data, params,
     547             :                           tdscnt, tpscnt,
     548             :                           mdrcnt, mprcnt);
     549         127 :                 return;
     550             :         }
     551             : 
     552        2828 :         if (strequal(name,"WKSSVC") ||
     553        2828 :             strequal(name,"SRVSVC") ||
     554        2828 :             strequal(name,"WINREG") ||
     555        2828 :             strequal(name,"SAMR") ||
     556        1414 :             strequal(name,"LSARPC")) {
     557             : 
     558           0 :                 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
     559             : 
     560           0 :                 api_fd_reply(conn, vuid, req,
     561             :                              setup, (uint8_t *)data, params,
     562             :                              suwcnt, tdscnt, tpscnt,
     563             :                              mdrcnt, mprcnt);
     564           0 :                 return;
     565             :         }
     566             : 
     567        1414 :         if (strlen(name) < 1) {
     568        1414 :                 api_fd_reply(conn, vuid, req,
     569             :                              setup, (uint8_t *)data,
     570             :                              params, suwcnt, tdscnt,
     571             :                              tpscnt, mdrcnt, mprcnt);
     572        1414 :                 return;
     573             :         }
     574             : 
     575           0 :         if (setup)
     576           0 :                 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n",
     577             :                          (int)setup[0],(int)setup[1]));
     578             : 
     579           0 :         reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
     580           0 :         return;
     581             : }
     582             : 
     583        1541 : static void handle_trans(connection_struct *conn, struct smb_request *req,
     584             :                          struct trans_state *state)
     585             : {
     586             :         char *local_machine_name;
     587        1541 :         int name_offset = 0;
     588             : 
     589        1541 :         DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
     590             :                  state->name,(unsigned int)state->total_data,(unsigned int)state->total_param,
     591             :                  (unsigned int)state->setup_count));
     592             : 
     593             :         /*
     594             :          * WinCE wierdness....
     595             :          */
     596             : 
     597        1541 :         local_machine_name = talloc_asprintf(state, "\\%s\\",
     598             :                                              get_local_machine_name());
     599             : 
     600        1541 :         if (local_machine_name == NULL) {
     601           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     602           0 :                 return;
     603             :         }
     604             : 
     605        1541 :         if (strnequal(state->name, local_machine_name,
     606             :                       strlen(local_machine_name))) {
     607           0 :                 name_offset = strlen(local_machine_name)-1;
     608             :         }
     609             : 
     610        1541 :         if (!strnequal(&state->name[name_offset], "\\PIPE",
     611             :                        strlen("\\PIPE"))) {
     612           0 :                 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
     613           0 :                 return;
     614             :         }
     615             : 
     616        1541 :         name_offset += strlen("\\PIPE");
     617             : 
     618             :         /* Win9x weirdness.  When talking to a unicode server Win9x
     619             :            only sends \PIPE instead of \PIPE\ */
     620             : 
     621        1541 :         if (state->name[name_offset] == '\\')
     622        1541 :                 name_offset++;
     623             : 
     624        1541 :         DEBUG(5,("calling named_pipe\n"));
     625       12328 :         named_pipe(conn, state->vuid, req,
     626        3082 :                    state->name+name_offset,
     627             :                    state->setup,state->data,
     628             :                    state->param,
     629        3082 :                    state->setup_count,state->total_data,
     630        1541 :                    state->total_param,
     631        1541 :                    state->max_setup_return,
     632        1541 :                    state->max_data_return,
     633        1541 :                    state->max_param_return);
     634             : 
     635        1541 :         if (state->close_on_completion) {
     636             :                 struct smbXsrv_tcon *tcon;
     637             :                 NTSTATUS status;
     638             : 
     639           0 :                 tcon = conn->tcon;
     640           0 :                 req->conn = NULL;
     641           0 :                 conn = NULL;
     642             : 
     643             :                 /*
     644             :                  * TODO: cancel all outstanding requests on the tcon
     645             :                  */
     646           0 :                 status = smbXsrv_tcon_disconnect(tcon, state->vuid);
     647           0 :                 if (!NT_STATUS_IS_OK(status)) {
     648           0 :                         DEBUG(0, ("handle_trans: "
     649             :                                   "smbXsrv_tcon_disconnect() failed: %s\n",
     650             :                                   nt_errstr(status)));
     651             :                         /*
     652             :                          * If we hit this case, there is something completely
     653             :                          * wrong, so we better disconnect the transport connection.
     654             :                          */
     655           0 :                         exit_server(__location__ ": smbXsrv_tcon_disconnect failed");
     656             :                         return;
     657             :                 }
     658             : 
     659           0 :                 TALLOC_FREE(tcon);
     660             :         }
     661             : 
     662        1541 :         return;
     663             : }
     664             : 
     665             : /****************************************************************************
     666             :  Reply to a SMBtrans.
     667             :  ****************************************************************************/
     668             : 
     669        1541 : void reply_trans(struct smb_request *req)
     670             : {
     671        1541 :         connection_struct *conn = req->conn;
     672             :         unsigned int dsoff;
     673             :         unsigned int dscnt;
     674             :         unsigned int psoff;
     675             :         unsigned int pscnt;
     676             :         struct trans_state *state;
     677             :         NTSTATUS result;
     678             : 
     679        1541 :         START_PROFILE(SMBtrans);
     680             : 
     681        1541 :         if (req->wct < 14) {
     682           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     683           0 :                 END_PROFILE(SMBtrans);
     684           0 :                 return;
     685             :         }
     686             : 
     687        1541 :         dsoff = SVAL(req->vwv+12, 0);
     688        1541 :         dscnt = SVAL(req->vwv+11, 0);
     689        1541 :         psoff = SVAL(req->vwv+10, 0);
     690        1541 :         pscnt = SVAL(req->vwv+9, 0);
     691             : 
     692        1541 :         result = allow_new_trans(conn->pending_trans, req->mid);
     693        1541 :         if (!NT_STATUS_IS_OK(result)) {
     694           0 :                 DEBUG(2, ("Got invalid trans request: %s\n",
     695             :                           nt_errstr(result)));
     696           0 :                 reply_nterror(req, result);
     697           0 :                 END_PROFILE(SMBtrans);
     698           0 :                 return;
     699             :         }
     700             : 
     701        1541 :         if ((state = talloc(conn, struct trans_state)) == NULL) {
     702           0 :                 DEBUG(0, ("talloc failed\n"));
     703           0 :                 reply_nterror(req, NT_STATUS_NO_MEMORY);
     704           0 :                 END_PROFILE(SMBtrans);
     705           0 :                 return;
     706             :         }
     707             : 
     708        1541 :         state->cmd = SMBtrans;
     709             : 
     710        1541 :         state->mid = req->mid;
     711        1541 :         state->vuid = req->vuid;
     712        1541 :         state->setup_count = CVAL(req->vwv+13, 0);
     713        1541 :         state->setup = NULL;
     714        1541 :         state->total_param = SVAL(req->vwv+0, 0);
     715        1541 :         state->param = NULL;
     716        1541 :         state->total_data = SVAL(req->vwv+1, 0);
     717        1541 :         state->data = NULL;
     718        1541 :         state->max_param_return = SVAL(req->vwv+2, 0);
     719        1541 :         state->max_data_return = SVAL(req->vwv+3, 0);
     720        1541 :         state->max_setup_return = CVAL(req->vwv+4, 0);
     721        1541 :         state->close_on_completion = BITSETW(req->vwv+5, 0);
     722        1541 :         state->one_way = BITSETW(req->vwv+5, 1);
     723             : 
     724        1541 :         srvstr_pull_req_talloc(state, req, &state->name, req->buf,
     725             :                                STR_TERMINATE);
     726             : 
     727        3082 :         if ((dscnt > state->total_data) || (pscnt > state->total_param) ||
     728        1541 :                         !state->name)
     729             :                 goto bad_param;
     730             : 
     731        1541 :         if (state->total_data)  {
     732             : 
     733        1427 :                 if (trans_oob(state->total_data, 0, dscnt)
     734        1427 :                     || trans_oob(smb_len(req->inbuf), dsoff, dscnt)) {
     735             :                         goto bad_param;
     736             :                 }
     737             : 
     738             :                 /* Can't use talloc here, the core routines do realloc on the
     739             :                  * params and data. Out of paranoia, 100 bytes too many. */
     740        1427 :                 state->data = (char *)SMB_MALLOC(state->total_data+100);
     741        1427 :                 if (state->data == NULL) {
     742           0 :                         DEBUG(0,("reply_trans: data malloc fail for %u "
     743             :                                  "bytes !\n", (unsigned int)state->total_data));
     744           0 :                         TALLOC_FREE(state);
     745           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
     746           0 :                         END_PROFILE(SMBtrans);
     747           0 :                         return;
     748             :                 }
     749             :                 /* null-terminate the slack space */
     750        1427 :                 memset(&state->data[state->total_data], 0, 100);
     751             : 
     752        1427 :                 memcpy(state->data,smb_base(req->inbuf)+dsoff,dscnt);
     753             :         }
     754             : 
     755        1541 :         if (state->total_param) {
     756             : 
     757         127 :                 if (trans_oob(state->total_param, 0, pscnt)
     758         127 :                     || trans_oob(smb_len(req->inbuf), psoff, pscnt)) {
     759             :                         goto bad_param;
     760             :                 }
     761             : 
     762             :                 /* Can't use talloc here, the core routines do realloc on the
     763             :                  * params and data. Out of paranoia, 100 bytes too many */
     764         127 :                 state->param = (char *)SMB_MALLOC(state->total_param+100);
     765         127 :                 if (state->param == NULL) {
     766           0 :                         DEBUG(0,("reply_trans: param malloc fail for %u "
     767             :                                  "bytes !\n", (unsigned int)state->total_param));
     768           0 :                         SAFE_FREE(state->data);
     769           0 :                         TALLOC_FREE(state);
     770           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
     771           0 :                         END_PROFILE(SMBtrans);
     772           0 :                         return;
     773             :                 } 
     774             :                 /* null-terminate the slack space */
     775         127 :                 memset(&state->param[state->total_param], 0, 100);
     776             : 
     777         127 :                 memcpy(state->param,smb_base(req->inbuf)+psoff,pscnt);
     778             :         }
     779             : 
     780        1541 :         state->received_data  = dscnt;
     781        1541 :         state->received_param = pscnt;
     782             : 
     783        1541 :         if (state->setup_count) {
     784             :                 unsigned int i;
     785             : 
     786             :                 /*
     787             :                  * No overflow possible here, state->setup_count is an
     788             :                  * unsigned int, being filled by a single byte from
     789             :                  * CVAL(req->vwv+13, 0) above. The cast in the comparison
     790             :                  * below is not necessary, it's here to clarify things. The
     791             :                  * validity of req->vwv and req->wct has been checked in
     792             :                  * init_smb_request already.
     793             :                  */
     794        1414 :                 if (state->setup_count + 14 > (unsigned int)req->wct) {
     795           0 :                         goto bad_param;
     796             :                 }
     797             : 
     798        1414 :                 if((state->setup = talloc_array(
     799             :                             state, uint16_t, state->setup_count)) == NULL) {
     800           0 :                         DEBUG(0,("reply_trans: setup malloc fail for %u "
     801             :                                  "bytes !\n", (unsigned int)
     802             :                                  (state->setup_count * sizeof(uint16_t))));
     803           0 :                         SAFE_FREE(state->data);
     804           0 :                         SAFE_FREE(state->param);
     805           0 :                         TALLOC_FREE(state);
     806           0 :                         reply_nterror(req, NT_STATUS_NO_MEMORY);
     807           0 :                         END_PROFILE(SMBtrans);
     808           0 :                         return;
     809             :                 } 
     810             : 
     811        4242 :                 for (i=0;i<state->setup_count;i++) {
     812        2828 :                         state->setup[i] = SVAL(req->vwv + 14 + i, 0);
     813             :                 }
     814             :         }
     815             : 
     816        1541 :         state->received_param = pscnt;
     817             : 
     818        3082 :         if ((state->received_param != state->total_param) ||
     819        1541 :             (state->received_data != state->total_data)) {
     820           0 :                 DLIST_ADD(conn->pending_trans, state);
     821             : 
     822             :                 /* We need to send an interim response then receive the rest
     823             :                    of the parameter/data bytes */
     824           0 :                 reply_outbuf(req, 0, 0);
     825           0 :                 show_msg((char *)req->outbuf);
     826           0 :                 END_PROFILE(SMBtrans);
     827           0 :                 return;
     828             :         }
     829             : 
     830        1541 :         talloc_steal(talloc_tos(), state);
     831             : 
     832        1541 :         handle_trans(conn, req, state);
     833             : 
     834        1541 :         SAFE_FREE(state->data);
     835        1541 :         SAFE_FREE(state->param);
     836        1541 :         TALLOC_FREE(state);
     837             : 
     838        1541 :         END_PROFILE(SMBtrans);
     839        1541 :         return;
     840             : 
     841           0 :   bad_param:
     842             : 
     843           0 :         DEBUG(0,("reply_trans: invalid trans parameters\n"));
     844           0 :         SAFE_FREE(state->data);
     845           0 :         SAFE_FREE(state->param);
     846           0 :         TALLOC_FREE(state);
     847           0 :         END_PROFILE(SMBtrans);
     848           0 :         reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     849           0 :         return;
     850             : }
     851             : 
     852             : /****************************************************************************
     853             :  Reply to a secondary SMBtrans.
     854             :  ****************************************************************************/
     855             : 
     856           0 : void reply_transs(struct smb_request *req)
     857             : {
     858           0 :         connection_struct *conn = req->conn;
     859             :         unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
     860             :         struct trans_state *state;
     861             : 
     862           0 :         START_PROFILE(SMBtranss);
     863             : 
     864           0 :         show_msg((const char *)req->inbuf);
     865             : 
     866           0 :         if (req->wct < 8) {
     867           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     868           0 :                 END_PROFILE(SMBtranss);
     869           0 :                 return;
     870             :         }
     871             : 
     872           0 :         for (state = conn->pending_trans; state != NULL;
     873           0 :              state = state->next) {
     874           0 :                 if (state->mid == req->mid) {
     875           0 :                         break;
     876             :                 }
     877             :         }
     878             : 
     879           0 :         if ((state == NULL) || (state->cmd != SMBtrans)) {
     880           0 :                 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     881           0 :                 END_PROFILE(SMBtranss);
     882           0 :                 return;
     883             :         }
     884             : 
     885             :         /* Revise total_params and total_data in case they have changed
     886             :          * downwards */
     887             : 
     888           0 :         if (SVAL(req->vwv+0, 0) < state->total_param)
     889           0 :                 state->total_param = SVAL(req->vwv+0, 0);
     890           0 :         if (SVAL(req->vwv+1, 0) < state->total_data)
     891           0 :                 state->total_data = SVAL(req->vwv+1, 0);
     892             : 
     893           0 :         pcnt = SVAL(req->vwv+2, 0);
     894           0 :         poff = SVAL(req->vwv+3, 0);
     895           0 :         pdisp = SVAL(req->vwv+4, 0);
     896             : 
     897           0 :         dcnt = SVAL(req->vwv+5, 0);
     898           0 :         doff = SVAL(req->vwv+6, 0);
     899           0 :         ddisp = SVAL(req->vwv+7, 0);
     900             : 
     901           0 :         state->received_param += pcnt;
     902           0 :         state->received_data += dcnt;
     903             : 
     904           0 :         if ((state->received_data > state->total_data) ||
     905           0 :             (state->received_param > state->total_param))
     906             :                 goto bad_param;
     907             : 
     908           0 :         if (pcnt) {
     909           0 :                 if (trans_oob(state->total_param, pdisp, pcnt)
     910           0 :                     || trans_oob(smb_len(req->inbuf), poff, pcnt)) {
     911             :                         goto bad_param;
     912             :                 }
     913           0 :                 memcpy(state->param+pdisp,smb_base(req->inbuf)+poff,pcnt);
     914             :         }
     915             : 
     916           0 :         if (dcnt) {
     917           0 :                 if (trans_oob(state->total_data, ddisp, dcnt)
     918           0 :                     || trans_oob(smb_len(req->inbuf), doff, dcnt)) {
     919             :                         goto bad_param;
     920             :                 }
     921           0 :                 memcpy(state->data+ddisp, smb_base(req->inbuf)+doff,dcnt);
     922             :         }
     923             : 
     924           0 :         if ((state->received_param < state->total_param) ||
     925           0 :             (state->received_data < state->total_data)) {
     926           0 :                 END_PROFILE(SMBtranss);
     927           0 :                 return;
     928             :         }
     929             : 
     930           0 :         talloc_steal(talloc_tos(), state);
     931             : 
     932           0 :         handle_trans(conn, req, state);
     933             : 
     934           0 :         DLIST_REMOVE(conn->pending_trans, state);
     935           0 :         SAFE_FREE(state->data);
     936           0 :         SAFE_FREE(state->param);
     937           0 :         TALLOC_FREE(state);
     938             : 
     939           0 :         END_PROFILE(SMBtranss);
     940           0 :         return;
     941             : 
     942           0 :   bad_param:
     943             : 
     944           0 :         DEBUG(0,("reply_transs: invalid trans parameters\n"));
     945           0 :         DLIST_REMOVE(conn->pending_trans, state);
     946           0 :         SAFE_FREE(state->data);
     947           0 :         SAFE_FREE(state->param);
     948           0 :         TALLOC_FREE(state);
     949           0 :         reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
     950           0 :         END_PROFILE(SMBtranss);
     951           0 :         return;
     952             : }

Generated by: LCOV version 1.13