LCOV - code coverage report
Current view: top level - libcli/smb - smb1cli_trans.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 343 490 70.0 %
Date: 2024-04-13 12:30:31 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    client transaction calls
       4             :    Copyright (C) Andrew Tridgell 1994-1998
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "system/network.h"
      22             : #include "../lib/util/tevent_ntstatus.h"
      23             : #include "../libcli/smb/smb_common.h"
      24             : #include "../libcli/smb/smbXcli_base.h"
      25             : 
      26             : struct trans_recvblob {
      27             :         uint8_t *data;
      28             :         uint32_t max, total, received;
      29             : };
      30             : 
      31             : struct smb1cli_trans_state {
      32             :         struct smbXcli_conn *conn;
      33             :         struct tevent_context *ev;
      34             :         uint8_t cmd;
      35             :         uint8_t additional_flags;
      36             :         uint8_t clear_flags;
      37             :         uint16_t additional_flags2;
      38             :         uint16_t clear_flags2;
      39             :         uint32_t timeout_msec;
      40             :         uint16_t mid;
      41             :         uint32_t pid;
      42             :         struct smbXcli_tcon *tcon;
      43             :         struct smbXcli_session *session;
      44             :         const char *pipe_name;
      45             :         uint8_t *pipe_name_conv;
      46             :         size_t pipe_name_conv_len;
      47             :         uint16_t fid;
      48             :         uint16_t function;
      49             :         int flags;
      50             :         uint16_t *setup;
      51             :         uint8_t num_setup, max_setup;
      52             :         uint8_t *param;
      53             :         uint32_t num_param, param_sent;
      54             :         uint8_t *data;
      55             :         uint32_t num_data, data_sent;
      56             : 
      57             :         uint8_t num_rsetup;
      58             :         uint16_t *rsetup;
      59             :         struct trans_recvblob rparam;
      60             :         struct trans_recvblob rdata;
      61             :         uint16_t recv_flags2;
      62             : 
      63             :         struct iovec iov[6];
      64             :         uint8_t pad[4];
      65             :         uint8_t zero_pad[4];
      66             :         uint16_t vwv[32];
      67             : 
      68             :         NTSTATUS status;
      69             : 
      70             :         struct tevent_req *primary_subreq;
      71             : };
      72             : 
      73      282292 : static void smb1cli_trans_cleanup_primary(struct smb1cli_trans_state *state)
      74             : {
      75      282292 :         if (state->primary_subreq) {
      76       94096 :                 smb1cli_req_set_mid(state->primary_subreq, 0);
      77       94096 :                 smbXcli_req_unset_pending(state->primary_subreq);
      78       94096 :                 TALLOC_FREE(state->primary_subreq);
      79             :         }
      80      282292 : }
      81             : 
      82       94096 : static int smb1cli_trans_state_destructor(struct smb1cli_trans_state *state)
      83             : {
      84       94096 :         smb1cli_trans_cleanup_primary(state);
      85       94096 :         return 0;
      86             : }
      87             : 
      88       56040 : static NTSTATUS smb1cli_pull_trans(uint8_t *inhdr,
      89             :                                    uint8_t wct,
      90             :                                    uint16_t *vwv,
      91             :                                    uint32_t vwv_ofs,
      92             :                                    uint32_t num_bytes,
      93             :                                    uint8_t *bytes,
      94             :                                    uint32_t bytes_ofs,
      95             :                                    uint8_t smb_cmd, bool expect_first_reply,
      96             :                                    uint8_t *pnum_setup, uint16_t **psetup,
      97             :                                    uint32_t *ptotal_param, uint32_t *pnum_param,
      98             :                                    uint32_t *pparam_disp, uint8_t **pparam,
      99             :                                    uint32_t *ptotal_data, uint32_t *pnum_data,
     100             :                                    uint32_t *pdata_disp, uint8_t **pdata)
     101             : {
     102        1218 :         uint32_t param_ofs, data_ofs;
     103        1218 :         uint8_t expected_num_setup;
     104       56040 :         uint32_t max_bytes = UINT32_MAX - bytes_ofs;
     105        1218 :         uint32_t bytes_end;
     106             : 
     107       56040 :         if (num_bytes > max_bytes) {
     108           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     109             :         }
     110             : 
     111       56040 :         bytes_end = bytes_ofs + num_bytes;
     112             : 
     113       56040 :         if (expect_first_reply) {
     114           0 :                 if ((wct != 0) || (num_bytes != 0)) {
     115           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     116             :                 }
     117           0 :                 return NT_STATUS_OK;
     118             :         }
     119             : 
     120       56040 :         switch (smb_cmd) {
     121       39073 :         case SMBtrans:
     122             :         case SMBtrans2:
     123       39073 :                 if (wct < 10) {
     124           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     125             :                 }
     126       39073 :                 expected_num_setup = wct - 10;
     127       39073 :                 *ptotal_param   = SVAL(vwv + 0, 0);
     128       39073 :                 *ptotal_data    = SVAL(vwv + 1, 0);
     129       39073 :                 *pnum_param     = SVAL(vwv + 3, 0);
     130       39073 :                 param_ofs       = SVAL(vwv + 4, 0);
     131       39073 :                 *pparam_disp    = SVAL(vwv + 5, 0);
     132       39073 :                 *pnum_data      = SVAL(vwv + 6, 0);
     133       39073 :                 data_ofs        = SVAL(vwv + 7, 0);
     134       39073 :                 *pdata_disp     = SVAL(vwv + 8, 0);
     135       39073 :                 *pnum_setup     = CVAL(vwv + 9, 0);
     136       39073 :                 if (expected_num_setup < (*pnum_setup)) {
     137           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     138             :                 }
     139       39073 :                 *psetup = vwv + 10;
     140             : 
     141       39073 :                 break;
     142       16967 :         case SMBnttrans:
     143       16967 :                 if (wct < 18) {
     144           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     145             :                 }
     146       16967 :                 expected_num_setup = wct - 18;
     147       16967 :                 *ptotal_param   = IVAL(vwv, 3);
     148       16967 :                 *ptotal_data    = IVAL(vwv, 7);
     149       16967 :                 *pnum_param     = IVAL(vwv, 11);
     150       16967 :                 param_ofs       = IVAL(vwv, 15);
     151       16967 :                 *pparam_disp    = IVAL(vwv, 19);
     152       16967 :                 *pnum_data      = IVAL(vwv, 23);
     153       16967 :                 data_ofs        = IVAL(vwv, 27);
     154       16967 :                 *pdata_disp     = IVAL(vwv, 31);
     155       16967 :                 *pnum_setup     = CVAL(vwv, 35);
     156       16967 :                 if (expected_num_setup < (*pnum_setup)) {
     157           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     158             :                 }
     159       16967 :                 *psetup         = vwv + 18;
     160       16967 :                 break;
     161             : 
     162           0 :         default:
     163           0 :                 return NT_STATUS_INTERNAL_ERROR;
     164             :         }
     165             : 
     166             :         /*
     167             :          * Check for buffer overflows. data_ofs needs to be checked against
     168             :          * the incoming buffer length, data_disp against the total
     169             :          * length. Likewise for param_ofs/param_disp.
     170             :          */
     171             : 
     172       56040 :         if (smb_buffer_oob(bytes_end, param_ofs, *pnum_param)
     173       56040 :             || smb_buffer_oob(*ptotal_param, *pparam_disp, *pnum_param)
     174       56040 :             || smb_buffer_oob(bytes_end, data_ofs, *pnum_data)
     175       56040 :             || smb_buffer_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
     176           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     177             :         }
     178             : 
     179       56040 :         *pparam = (uint8_t *)inhdr + param_ofs;
     180       56040 :         *pdata = (uint8_t *)inhdr + data_ofs;
     181             : 
     182       56040 :         return NT_STATUS_OK;
     183             : }
     184             : 
     185      112080 : static NTSTATUS smb1cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
     186             :                                         struct trans_recvblob *blob,
     187             :                                         uint32_t total, uint32_t thistime,
     188             :                                         uint8_t *buf, uint32_t displacement)
     189             : {
     190      112080 :         if (blob->data == NULL) {
     191      111996 :                 if (total > blob->max) {
     192           8 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
     193             :                 }
     194      111988 :                 blob->total = total;
     195      111988 :                 blob->data = talloc_array(mem_ctx, uint8_t, total);
     196      111988 :                 if (blob->data == NULL) {
     197           0 :                         return NT_STATUS_NO_MEMORY;
     198             :                 }
     199             :         }
     200             : 
     201      112072 :         if (total > blob->total) {
     202           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     203             :         }
     204             : 
     205      112072 :         if (thistime) {
     206       83807 :                 memcpy(blob->data + displacement, buf, thistime);
     207       83807 :                 blob->received += thistime;
     208             :         }
     209             : 
     210      112072 :         return NT_STATUS_OK;
     211             : }
     212             : 
     213       94100 : static void smb1cli_trans_format(struct smb1cli_trans_state *state,
     214             :                                  uint8_t *pwct,
     215             :                                  int *piov_count)
     216             : {
     217       94100 :         uint8_t wct = 0;
     218       94100 :         struct iovec *iov = state->iov;
     219       94100 :         uint8_t *pad = state->pad;
     220       94100 :         uint16_t *vwv = state->vwv;
     221        1283 :         uint32_t param_offset;
     222       94100 :         uint32_t this_param = 0;
     223        1283 :         uint32_t param_pad;
     224        1283 :         uint32_t data_offset;
     225       94100 :         uint32_t this_data = 0;
     226        1283 :         uint32_t data_pad;
     227        1283 :         uint32_t useable_space;
     228        1283 :         uint8_t cmd;
     229       94100 :         uint32_t max_trans = smb1cli_conn_max_xmit(state->conn);
     230             : 
     231       94100 :         cmd = state->cmd;
     232             : 
     233       94100 :         if ((state->param_sent != 0) || (state->data_sent != 0)) {
     234             :                 /* The secondary commands are one after the primary ones */
     235           0 :                 cmd += 1;
     236             :         }
     237             : 
     238       94100 :         param_offset = MIN_SMB_SIZE;
     239             : 
     240       94100 :         switch (cmd) {
     241        1614 :         case SMBtrans:
     242        1614 :                 if (smbXcli_conn_use_unicode(state->conn)) {
     243        1614 :                         pad[0] = 0;
     244        1614 :                         iov[0].iov_base = (void *)pad;
     245        1614 :                         iov[0].iov_len = 1;
     246        1614 :                         param_offset += 1;
     247        1614 :                         iov += 1;
     248             :                 }
     249        1614 :                 iov[0].iov_base = (void *)state->pipe_name_conv;
     250        1614 :                 iov[0].iov_len = state->pipe_name_conv_len;
     251        1614 :                 wct = 14 + state->num_setup;
     252        1614 :                 param_offset += iov[0].iov_len;
     253        1614 :                 iov += 1;
     254        1614 :                 break;
     255       73826 :         case SMBtrans2:
     256       73826 :                 pad[0] = 0;
     257       73826 :                 pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
     258       73826 :                 pad[2] = ' ';
     259       73826 :                 iov[0].iov_base = (void *)pad;
     260       73826 :                 iov[0].iov_len = 3;
     261       73826 :                 wct = 14 + state->num_setup;
     262       73826 :                 param_offset += 3;
     263       73826 :                 iov += 1;
     264       73826 :                 break;
     265           0 :         case SMBtranss:
     266           0 :                 wct = 8;
     267           0 :                 break;
     268           0 :         case SMBtranss2:
     269           0 :                 wct = 9;
     270           0 :                 break;
     271       18660 :         case SMBnttrans:
     272       18660 :                 wct = 19 + state->num_setup;
     273       18660 :                 break;
     274           0 :         case SMBnttranss:
     275           0 :                 wct = 18;
     276           0 :                 break;
     277             :         }
     278             : 
     279       94100 :         param_offset += wct * sizeof(uint16_t);
     280       94100 :         useable_space = max_trans - param_offset;
     281             : 
     282       94100 :         param_pad = param_offset % 4;
     283       94100 :         if (param_pad > 0) {
     284       20274 :                 param_pad = MIN(param_pad, useable_space);
     285       20274 :                 iov[0].iov_base = (void *)state->zero_pad;
     286       20274 :                 iov[0].iov_len = param_pad;
     287       20274 :                 iov += 1;
     288       20274 :                 param_offset += param_pad;
     289             :         }
     290       94100 :         useable_space = max_trans - param_offset;
     291             : 
     292       94100 :         if (state->param_sent < state->num_param) {
     293       89649 :                 this_param = MIN(state->num_param - state->param_sent,
     294             :                                  useable_space);
     295       89649 :                 iov[0].iov_base = (void *)(state->param + state->param_sent);
     296       89649 :                 iov[0].iov_len = this_param;
     297       89649 :                 iov += 1;
     298             :         }
     299             : 
     300       94100 :         data_offset = param_offset + this_param;
     301       94100 :         useable_space = max_trans - data_offset;
     302             : 
     303       94100 :         data_pad = data_offset % 4;
     304       94100 :         if (data_pad > 0) {
     305       55231 :                 data_pad = MIN(data_pad, useable_space);
     306       55231 :                 iov[0].iov_base = (void *)state->zero_pad;
     307       55231 :                 iov[0].iov_len = data_pad;
     308       55231 :                 iov += 1;
     309       55231 :                 data_offset += data_pad;
     310             :         }
     311       94100 :         useable_space = max_trans - data_offset;
     312             : 
     313       94100 :         if (state->data_sent < state->num_data) {
     314       22084 :                 this_data = MIN(state->num_data - state->data_sent,
     315             :                                 useable_space);
     316       22084 :                 iov[0].iov_base = (void *)(state->data + state->data_sent);
     317       22084 :                 iov[0].iov_len = this_data;
     318       22084 :                 iov += 1;
     319             :         }
     320             : 
     321       94100 :         DEBUG(10, ("num_setup=%u, max_setup=%u, "
     322             :                    "param_total=%u, this_param=%u, max_param=%u, "
     323             :                    "data_total=%u, this_data=%u, max_data=%u, "
     324             :                    "param_offset=%u, param_pad=%u, param_disp=%u, "
     325             :                    "data_offset=%u, data_pad=%u, data_disp=%u\n",
     326             :                    (unsigned)state->num_setup, (unsigned)state->max_setup,
     327             :                    (unsigned)state->num_param, (unsigned)this_param,
     328             :                    (unsigned)state->rparam.max,
     329             :                    (unsigned)state->num_data, (unsigned)this_data,
     330             :                    (unsigned)state->rdata.max,
     331             :                    (unsigned)param_offset, (unsigned)param_pad,
     332             :                    (unsigned)state->param_sent,
     333             :                    (unsigned)data_offset, (unsigned)data_pad,
     334             :                    (unsigned)state->data_sent));
     335             : 
     336       94100 :         switch (cmd) {
     337       75440 :         case SMBtrans:
     338             :         case SMBtrans2:
     339       75440 :                 SSVAL(vwv + 0, 0, state->num_param);
     340       75440 :                 SSVAL(vwv + 1, 0, state->num_data);
     341       75440 :                 SSVAL(vwv + 2, 0, state->rparam.max);
     342       75440 :                 SSVAL(vwv + 3, 0, state->rdata.max);
     343       75440 :                 SCVAL(vwv + 4, 0, state->max_setup);
     344       75440 :                 SCVAL(vwv + 4, 1, 0);   /* reserved */
     345       75440 :                 SSVAL(vwv + 5, 0, state->flags);
     346       75440 :                 SIVAL(vwv + 6, 0, 0);   /* timeout */
     347       75440 :                 SSVAL(vwv + 8, 0, 0);   /* reserved */
     348       75440 :                 SSVAL(vwv + 9, 0, this_param);
     349       75440 :                 SSVAL(vwv +10, 0, param_offset);
     350       75440 :                 SSVAL(vwv +11, 0, this_data);
     351       75440 :                 SSVAL(vwv +12, 0, data_offset);
     352       75440 :                 SCVAL(vwv +13, 0, state->num_setup);
     353       75440 :                 SCVAL(vwv +13, 1, 0);   /* reserved */
     354       75440 :                 if (state->num_setup > 0) {
     355       76579 :                         memcpy(vwv + 14, state->setup,
     356       75296 :                                sizeof(uint16_t) * state->num_setup);
     357             :                 }
     358       74222 :                 break;
     359           0 :         case SMBtranss:
     360             :         case SMBtranss2:
     361           0 :                 SSVAL(vwv + 0, 0, state->num_param);
     362           0 :                 SSVAL(vwv + 1, 0, state->num_data);
     363           0 :                 SSVAL(vwv + 2, 0, this_param);
     364           0 :                 SSVAL(vwv + 3, 0, param_offset);
     365           0 :                 SSVAL(vwv + 4, 0, state->param_sent);
     366           0 :                 SSVAL(vwv + 5, 0, this_data);
     367           0 :                 SSVAL(vwv + 6, 0, data_offset);
     368           0 :                 SSVAL(vwv + 7, 0, state->data_sent);
     369           0 :                 if (cmd == SMBtranss2) {
     370           0 :                         SSVAL(vwv + 8, 0, state->fid);
     371             :                 }
     372           0 :                 break;
     373       18660 :         case SMBnttrans:
     374       18660 :                 SCVAL(vwv + 0, 0, state->max_setup);
     375       18660 :                 SSVAL(vwv + 0, 1, 0); /* reserved */
     376       18660 :                 SIVAL(vwv + 1, 1, state->num_param);
     377       18660 :                 SIVAL(vwv + 3, 1, state->num_data);
     378       18660 :                 SIVAL(vwv + 5, 1, state->rparam.max);
     379       18660 :                 SIVAL(vwv + 7, 1, state->rdata.max);
     380       18660 :                 SIVAL(vwv + 9, 1, this_param);
     381       18660 :                 SIVAL(vwv +11, 1, param_offset);
     382       18660 :                 SIVAL(vwv +13, 1, this_data);
     383       18660 :                 SIVAL(vwv +15, 1, data_offset);
     384       18660 :                 SCVAL(vwv +17, 1, state->num_setup);
     385       18660 :                 SSVAL(vwv +18, 0, state->function);
     386       19943 :                 memcpy(vwv + 19, state->setup,
     387       18660 :                        sizeof(uint16_t) * state->num_setup);
     388       18595 :                 break;
     389           0 :         case SMBnttranss:
     390           0 :                 SSVAL(vwv + 0, 0, 0); /* reserved */
     391           0 :                 SCVAL(vwv + 1, 0, 0); /* reserved */
     392           0 :                 SIVAL(vwv + 1, 1, state->num_param);
     393           0 :                 SIVAL(vwv + 3, 1, state->num_data);
     394           0 :                 SIVAL(vwv + 5, 1, this_param);
     395           0 :                 SIVAL(vwv + 7, 1, param_offset);
     396           0 :                 SIVAL(vwv + 9, 1, state->param_sent);
     397           0 :                 SIVAL(vwv +11, 1, this_data);
     398           0 :                 SIVAL(vwv +13, 1, data_offset);
     399           0 :                 SIVAL(vwv +15, 1, state->data_sent);
     400           0 :                 SCVAL(vwv +17, 1, 0); /* reserved */
     401           0 :                 break;
     402             :         }
     403             : 
     404       94100 :         state->param_sent += this_param;
     405       94100 :         state->data_sent += this_data;
     406             : 
     407       94100 :         *pwct = wct;
     408       94100 :         *piov_count = iov - state->iov;
     409       94100 : }
     410             : 
     411             : static bool smb1cli_trans_cancel(struct tevent_req *req);
     412             : static void smb1cli_trans_done(struct tevent_req *subreq);
     413             : 
     414       94100 : struct tevent_req *smb1cli_trans_send(
     415             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     416             :         struct smbXcli_conn *conn, uint8_t cmd,
     417             :         uint8_t additional_flags, uint8_t clear_flags,
     418             :         uint16_t additional_flags2, uint16_t clear_flags2,
     419             :         uint32_t timeout_msec,
     420             :         uint32_t pid,
     421             :         struct smbXcli_tcon *tcon,
     422             :         struct smbXcli_session *session,
     423             :         const char *pipe_name, uint16_t fid, uint16_t function, int flags,
     424             :         uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
     425             :         uint8_t *param, uint32_t num_param, uint32_t max_param,
     426             :         uint8_t *data, uint32_t num_data, uint32_t max_data)
     427             : {
     428        1283 :         struct tevent_req *req, *subreq;
     429        1283 :         struct smb1cli_trans_state *state;
     430        1283 :         int iov_count;
     431        1283 :         uint8_t wct;
     432        1283 :         NTSTATUS status;
     433        1283 :         charset_t charset;
     434             : 
     435       94100 :         req = tevent_req_create(mem_ctx, &state,
     436             :                                 struct smb1cli_trans_state);
     437       94100 :         if (req == NULL) {
     438           0 :                 return NULL;
     439             :         }
     440             : 
     441       94100 :         if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
     442       75440 :                 if ((num_param > 0xffff) || (max_param > 0xffff)
     443       75440 :                     || (num_data > 0xffff) || (max_data > 0xffff)) {
     444           0 :                         DEBUG(3, ("Attempt to send invalid trans2 request "
     445             :                                   "(setup %u, params %u/%u, data %u/%u)\n",
     446             :                                   (unsigned)num_setup,
     447             :                                   (unsigned)num_param, (unsigned)max_param,
     448             :                                   (unsigned)num_data, (unsigned)max_data));
     449           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
     450           0 :                         return tevent_req_post(req, ev);
     451             :                 }
     452             :         }
     453             : 
     454             :         /*
     455             :          * The largest wct will be for nttrans (19+num_setup). Make sure we
     456             :          * don't overflow state->vwv in smb1cli_trans_format.
     457             :          */
     458             : 
     459       94100 :         if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
     460           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
     461           0 :                 return tevent_req_post(req, ev);
     462             :         }
     463             : 
     464       94100 :         state->conn = conn;
     465       94100 :         state->ev = ev;
     466       94100 :         state->cmd = cmd;
     467       94100 :         state->additional_flags = additional_flags;
     468       94100 :         state->clear_flags = clear_flags;
     469       94100 :         state->additional_flags2 = additional_flags2;
     470       94100 :         state->clear_flags2 = clear_flags2;
     471       94100 :         state->timeout_msec = timeout_msec;
     472       94100 :         state->flags = flags;
     473       94100 :         state->num_rsetup = 0;
     474       94100 :         state->rsetup = NULL;
     475       94100 :         state->pid = pid;
     476       94100 :         state->tcon = tcon;
     477       94100 :         state->session = session;
     478       94100 :         ZERO_STRUCT(state->rparam);
     479       94100 :         ZERO_STRUCT(state->rdata);
     480             : 
     481       94100 :         if (smbXcli_conn_use_unicode(conn)) {
     482       92815 :                 charset = CH_UTF16LE;
     483             :         } else {
     484           2 :                 charset = CH_DOS;
     485             :         }
     486             : 
     487       94100 :         if ((pipe_name != NULL)
     488        1614 :             && (!convert_string_talloc(state, CH_UNIX, charset,
     489        1614 :                                        pipe_name, strlen(pipe_name) + 1,
     490        1614 :                                        &state->pipe_name_conv,
     491        1614 :                                        &state->pipe_name_conv_len))) {
     492           0 :                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
     493           0 :                 return tevent_req_post(req, ev);
     494             :         }
     495       94100 :         state->fid = fid;    /* trans2 */
     496       94100 :         state->function = function; /* nttrans */
     497             : 
     498       94100 :         state->setup = setup;
     499       94100 :         state->num_setup = num_setup;
     500       94100 :         state->max_setup = max_setup;
     501             : 
     502       94100 :         state->param = param;
     503       94100 :         state->num_param = num_param;
     504       94100 :         state->param_sent = 0;
     505       94100 :         state->rparam.max = max_param;
     506             : 
     507       94100 :         state->data = data;
     508       94100 :         state->num_data = num_data;
     509       94100 :         state->data_sent = 0;
     510       94100 :         state->rdata.max = max_data;
     511             : 
     512       94100 :         smb1cli_trans_format(state, &wct, &iov_count);
     513             : 
     514      188200 :         subreq = smb1cli_req_create(state, ev, conn, cmd,
     515       94100 :                                     state->additional_flags,
     516       94100 :                                     state->clear_flags,
     517       94100 :                                     state->additional_flags2,
     518       94100 :                                     state->clear_flags2,
     519       92817 :                                     state->timeout_msec,
     520       92817 :                                     state->pid,
     521       92817 :                                     state->tcon,
     522       92817 :                                     state->session,
     523       94100 :                                     wct, state->vwv,
     524       94100 :                                     iov_count, state->iov);
     525       94100 :         if (tevent_req_nomem(subreq, req)) {
     526           0 :                 return tevent_req_post(req, ev);
     527             :         }
     528       94100 :         status = smb1cli_req_chain_submit(&subreq, 1);
     529       94100 :         if (tevent_req_nterror(req, status)) {
     530           4 :                 return tevent_req_post(req, state->ev);
     531             :         }
     532       94096 :         tevent_req_set_callback(subreq, smb1cli_trans_done, req);
     533             : 
     534             :         /*
     535             :          * Now get the MID of the primary request
     536             :          * and mark it as persistent. This means
     537             :          * we will able to send and receive multiple
     538             :          * SMB pdus using this MID in both directions
     539             :          * (including correct SMB signing).
     540             :          */
     541       94096 :         state->mid = smb1cli_req_mid(subreq);
     542       94096 :         smb1cli_req_set_mid(subreq, state->mid);
     543       94096 :         state->primary_subreq = subreq;
     544       94096 :         talloc_set_destructor(state, smb1cli_trans_state_destructor);
     545             : 
     546       94096 :         tevent_req_set_cancel_fn(req, smb1cli_trans_cancel);
     547             : 
     548       94096 :         return req;
     549             : }
     550             : 
     551        1509 : static bool smb1cli_trans_cancel(struct tevent_req *req)
     552             : {
     553           0 :         struct smb1cli_trans_state *state =
     554        1509 :                 tevent_req_data(req,
     555             :                 struct smb1cli_trans_state);
     556             : 
     557        1509 :         if (state->primary_subreq == NULL) {
     558           0 :                 return false;
     559             :         }
     560             : 
     561        1509 :         return tevent_req_cancel(state->primary_subreq);
     562             : }
     563             : 
     564             : static void smb1cli_trans_done2(struct tevent_req *subreq);
     565             : 
     566       94138 : static void smb1cli_trans_done(struct tevent_req *subreq)
     567             : {
     568        1283 :         struct tevent_req *req =
     569       94138 :                 tevent_req_callback_data(subreq,
     570             :                 struct tevent_req);
     571        1283 :         struct smb1cli_trans_state *state =
     572       94138 :                 tevent_req_data(req,
     573             :                 struct smb1cli_trans_state);
     574        1283 :         NTSTATUS status;
     575        1283 :         bool sent_all;
     576       94138 :         struct iovec *recv_iov = NULL;
     577        1283 :         uint8_t *inhdr;
     578        1283 :         uint8_t wct;
     579        1283 :         uint16_t *vwv;
     580        1283 :         uint32_t vwv_ofs;
     581        1283 :         uint32_t num_bytes;
     582        1283 :         uint8_t *bytes;
     583        1283 :         uint32_t bytes_ofs;
     584       94138 :         uint8_t num_setup       = 0;
     585       94138 :         uint16_t *setup         = NULL;
     586       94138 :         uint32_t total_param    = 0;
     587       94138 :         uint32_t num_param      = 0;
     588       94138 :         uint32_t param_disp     = 0;
     589       94138 :         uint32_t total_data     = 0;
     590       94138 :         uint32_t num_data       = 0;
     591       94138 :         uint32_t data_disp      = 0;
     592       94138 :         uint8_t *param          = NULL;
     593       94138 :         uint8_t *data           = NULL;
     594             : 
     595       94138 :         status = smb1cli_req_recv(subreq, state,
     596             :                                   &recv_iov,
     597             :                                   &inhdr,
     598             :                                   &wct,
     599             :                                   &vwv,
     600             :                                   &vwv_ofs,
     601             :                                   &num_bytes,
     602             :                                   &bytes,
     603             :                                   &bytes_ofs,
     604             :                                   NULL, /* pinbuf */
     605             :                                   NULL, 0); /* expected */
     606             :         /*
     607             :          * Do not TALLOC_FREE(subreq) here, we might receive more than
     608             :          * one response for the same mid.
     609             :          */
     610             : 
     611             :         /*
     612             :          * We can receive something like STATUS_MORE_ENTRIES, so don't use
     613             :          * !NT_STATUS_IS_OK(status) here.
     614             :          */
     615             : 
     616       94138 :         if (NT_STATUS_IS_ERR(status)) {
     617       38098 :                 goto fail;
     618             :         }
     619             : 
     620       56040 :         if (recv_iov == NULL) {
     621           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
     622           0 :                 goto fail;
     623             :         }
     624       56040 :         state->status = status;
     625             : 
     626      112080 :         sent_all = ((state->param_sent == state->num_param)
     627       56040 :                     && (state->data_sent == state->num_data));
     628             : 
     629       57258 :         status = smb1cli_pull_trans(
     630             :                 inhdr, wct, vwv, vwv_ofs,
     631             :                 num_bytes, bytes, bytes_ofs,
     632       56040 :                 state->cmd, !sent_all, &num_setup, &setup,
     633             :                 &total_param, &num_param, &param_disp, &param,
     634       56040 :                 &total_data, &num_data, &data_disp, &data);
     635             : 
     636       56040 :         if (!NT_STATUS_IS_OK(status)) {
     637           0 :                 goto fail;
     638             :         }
     639             : 
     640       56040 :         if (!sent_all) {
     641           0 :                 int iov_count;
     642           0 :                 struct tevent_req *subreq2;
     643             : 
     644           0 :                 smb1cli_trans_format(state, &wct, &iov_count);
     645             : 
     646           0 :                 subreq2 = smb1cli_req_create(state, state->ev, state->conn,
     647           0 :                                              state->cmd + 1,
     648           0 :                                              state->additional_flags,
     649           0 :                                              state->clear_flags,
     650           0 :                                              state->additional_flags2,
     651           0 :                                              state->clear_flags2,
     652             :                                              state->timeout_msec,
     653             :                                              state->pid,
     654             :                                              state->tcon,
     655             :                                              state->session,
     656           0 :                                              wct, state->vwv,
     657           0 :                                              iov_count, state->iov);
     658           0 :                 if (tevent_req_nomem(subreq2, req)) {
     659           0 :                         return;
     660             :                 }
     661           0 :                 smb1cli_req_set_mid(subreq2, state->mid);
     662             : 
     663           0 :                 status = smb1cli_req_chain_submit(&subreq2, 1);
     664             : 
     665           0 :                 if (!NT_STATUS_IS_OK(status)) {
     666           0 :                         goto fail;
     667             :                 }
     668           0 :                 tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
     669             : 
     670           0 :                 return;
     671             :         }
     672             : 
     673       56040 :         status = smb1cli_trans_pull_blob(
     674             :                 state, &state->rparam, total_param, num_param, param,
     675             :                 param_disp);
     676             : 
     677       56040 :         if (!NT_STATUS_IS_OK(status)) {
     678           0 :                 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
     679           0 :                 goto fail;
     680             :         }
     681             : 
     682       56040 :         status = smb1cli_trans_pull_blob(
     683             :                 state, &state->rdata, total_data, num_data, data,
     684             :                 data_disp);
     685             : 
     686       56040 :         if (!NT_STATUS_IS_OK(status)) {
     687           8 :                 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
     688           8 :                 goto fail;
     689             :         }
     690             : 
     691       56032 :         if ((state->rparam.total == state->rparam.received)
     692       56032 :             && (state->rdata.total == state->rdata.received)) {
     693       55990 :                 state->recv_flags2 = SVAL(inhdr, HDR_FLG2);
     694       55990 :                 smb1cli_trans_cleanup_primary(state);
     695       55990 :                 tevent_req_done(req);
     696       55990 :                 return;
     697             :         }
     698             : 
     699          42 :         TALLOC_FREE(recv_iov);
     700             : 
     701          42 :         return;
     702             : 
     703       38106 :  fail:
     704       38106 :         smb1cli_trans_cleanup_primary(state);
     705       38106 :         tevent_req_nterror(req, status);
     706             : }
     707             : 
     708           0 : static void smb1cli_trans_done2(struct tevent_req *subreq2)
     709             : {
     710           0 :         struct tevent_req *req =
     711           0 :                 tevent_req_callback_data(subreq2,
     712             :                 struct tevent_req);
     713           0 :         struct smb1cli_trans_state *state =
     714           0 :                 tevent_req_data(req,
     715             :                 struct smb1cli_trans_state);
     716           0 :         NTSTATUS status;
     717           0 :         bool sent_all;
     718           0 :         uint32_t seqnum;
     719             : 
     720             :         /*
     721             :          * First backup the seqnum of the secondary request
     722             :          * and attach it to the primary request.
     723             :          */
     724           0 :         seqnum = smb1cli_req_seqnum(subreq2);
     725           0 :         smb1cli_req_set_seqnum(state->primary_subreq, seqnum);
     726             : 
     727             :         /* This was a one way request */
     728           0 :         status = smb1cli_req_recv(subreq2, state,
     729             :                                   NULL, /* recv_iov */
     730             :                                   NULL, /* phdr */
     731             :                                   NULL, /* pwct */
     732             :                                   NULL, /* pvwv */
     733             :                                   NULL, /* pvwv_offset */
     734             :                                   NULL, /* pnum_bytes */
     735             :                                   NULL, /* pbytes */
     736             :                                   NULL, /* pbytes_offset */
     737             :                                   NULL, /* pinbuf */
     738             :                                   NULL, 0); /* expected */
     739           0 :         TALLOC_FREE(subreq2);
     740             : 
     741           0 :         if (!NT_STATUS_IS_OK(status)) {
     742           0 :                 goto fail;
     743             :         }
     744             : 
     745           0 :         sent_all = ((state->param_sent == state->num_param)
     746           0 :                     && (state->data_sent == state->num_data));
     747             : 
     748           0 :         if (!sent_all) {
     749           0 :                 uint8_t wct;
     750           0 :                 int iov_count;
     751             : 
     752           0 :                 smb1cli_trans_format(state, &wct, &iov_count);
     753             : 
     754           0 :                 subreq2 = smb1cli_req_create(state, state->ev, state->conn,
     755           0 :                                              state->cmd + 1,
     756           0 :                                              state->additional_flags,
     757           0 :                                              state->clear_flags,
     758           0 :                                              state->additional_flags2,
     759           0 :                                              state->clear_flags2,
     760             :                                              state->timeout_msec,
     761             :                                              state->pid,
     762             :                                              state->tcon,
     763             :                                              state->session,
     764           0 :                                              wct, state->vwv,
     765           0 :                                              iov_count, state->iov);
     766           0 :                 if (tevent_req_nomem(subreq2, req)) {
     767           0 :                         return;
     768             :                 }
     769           0 :                 smb1cli_req_set_mid(subreq2, state->mid);
     770             : 
     771           0 :                 status = smb1cli_req_chain_submit(&subreq2, 1);
     772             : 
     773           0 :                 if (!NT_STATUS_IS_OK(status)) {
     774           0 :                         goto fail;
     775             :                 }
     776           0 :                 tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
     777           0 :                 return;
     778             :         }
     779             : 
     780           0 :         return;
     781             : 
     782           0 :  fail:
     783           0 :         smb1cli_trans_cleanup_primary(state);
     784           0 :         tevent_req_nterror(req, status);
     785             : }
     786             : 
     787       94100 : NTSTATUS smb1cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     788             :                             uint16_t *recv_flags2,
     789             :                             uint16_t **setup, uint8_t min_setup,
     790             :                             uint8_t *num_setup,
     791             :                             uint8_t **param, uint32_t min_param,
     792             :                             uint32_t *num_param,
     793             :                             uint8_t **data, uint32_t min_data,
     794             :                             uint32_t *num_data)
     795             : {
     796        1283 :         struct smb1cli_trans_state *state =
     797       94100 :                 tevent_req_data(req,
     798             :                 struct smb1cli_trans_state);
     799        1283 :         NTSTATUS status;
     800             : 
     801       94100 :         smb1cli_trans_cleanup_primary(state);
     802             : 
     803       94100 :         if (tevent_req_is_nterror(req, &status)) {
     804       38110 :                 if (!NT_STATUS_IS_ERR(status)) {
     805           0 :                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
     806             :                 }
     807       38110 :                 tevent_req_received(req);
     808       38110 :                 return status;
     809             :         }
     810             : 
     811       55990 :         if ((state->num_rsetup < min_setup)
     812       55990 :             || (state->rparam.total < min_param)
     813       55990 :             || (state->rdata.total < min_data)) {
     814           0 :                 tevent_req_received(req);
     815           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     816             :         }
     817             : 
     818       55990 :         if (recv_flags2 != NULL) {
     819       53659 :                 *recv_flags2 = state->recv_flags2;
     820             :         }
     821             : 
     822       55990 :         if (setup != NULL) {
     823       53659 :                 *setup = talloc_move(mem_ctx, &state->rsetup);
     824       53659 :                 *num_setup = state->num_rsetup;
     825             :         } else {
     826        2331 :                 TALLOC_FREE(state->rsetup);
     827             :         }
     828             : 
     829       55990 :         if (param != NULL) {
     830       54539 :                 *param = talloc_move(mem_ctx, &state->rparam.data);
     831       54539 :                 *num_param = state->rparam.total;
     832             :         } else {
     833        1451 :                 TALLOC_FREE(state->rparam.data);
     834             :         }
     835             : 
     836       55990 :         if (data != NULL) {
     837       55990 :                 *data = talloc_move(mem_ctx, &state->rdata.data);
     838       55990 :                 *num_data = state->rdata.total;
     839             :         } else {
     840           0 :                 TALLOC_FREE(state->rdata.data);
     841             :         }
     842             : 
     843       55990 :         status = state->status;
     844       55990 :         tevent_req_received(req);
     845       55990 :         return status;
     846             : }
     847             : 
     848           0 : NTSTATUS smb1cli_trans(TALLOC_CTX *mem_ctx, struct smbXcli_conn *conn,
     849             :                 uint8_t trans_cmd,
     850             :                 uint8_t additional_flags, uint8_t clear_flags,
     851             :                 uint16_t additional_flags2, uint16_t clear_flags2,
     852             :                 uint32_t timeout_msec,
     853             :                 uint32_t pid,
     854             :                 struct smbXcli_tcon *tcon,
     855             :                 struct smbXcli_session *session,
     856             :                 const char *pipe_name, uint16_t fid, uint16_t function,
     857             :                 int flags,
     858             :                 uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
     859             :                 uint8_t *param, uint32_t num_param, uint32_t max_param,
     860             :                 uint8_t *data, uint32_t num_data, uint32_t max_data,
     861             :                 uint16_t *recv_flags2,
     862             :                 uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
     863             :                 uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
     864             :                 uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
     865             : {
     866           0 :         TALLOC_CTX *frame = talloc_stackframe();
     867           0 :         struct tevent_context *ev;
     868           0 :         struct tevent_req *req;
     869           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     870             : 
     871           0 :         if (smbXcli_conn_has_async_calls(conn)) {
     872             :                 /*
     873             :                  * Can't use sync call while an async call is in flight
     874             :                  */
     875           0 :                 status = NT_STATUS_INVALID_PARAMETER_MIX;
     876           0 :                 goto fail;
     877             :         }
     878             : 
     879           0 :         ev = samba_tevent_context_init(frame);
     880           0 :         if (ev == NULL) {
     881           0 :                 goto fail;
     882             :         }
     883             : 
     884           0 :         req = smb1cli_trans_send(frame, ev, conn, trans_cmd,
     885             :                                  additional_flags, clear_flags,
     886             :                                  additional_flags2, clear_flags2,
     887             :                                  timeout_msec,
     888             :                                  pid, tcon, session,
     889             :                                  pipe_name, fid, function, flags,
     890             :                                  setup, num_setup, max_setup,
     891             :                                  param, num_param, max_param,
     892             :                                  data, num_data, max_data);
     893           0 :         if (req == NULL) {
     894           0 :                 goto fail;
     895             :         }
     896             : 
     897           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     898           0 :                 goto fail;
     899             :         }
     900             : 
     901           0 :         status = smb1cli_trans_recv(req, mem_ctx, recv_flags2,
     902             :                                     rsetup, min_rsetup, num_rsetup,
     903             :                                     rparam, min_rparam, num_rparam,
     904             :                                     rdata, min_rdata, num_rdata);
     905           0 :  fail:
     906           0 :         TALLOC_FREE(frame);
     907           0 :         return status;
     908             : }

Generated by: LCOV version 1.14