LCOV - code coverage report
Current view: top level - source3/smbd - smb1_ipc.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 198 468 42.3 %
Date: 2024-05-31 13:13:24 Functions: 9 13 69.2 %

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

Generated by: LCOV version 1.14