Coverage Report

Created: 2025-12-31 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/libcli/smb/smb1cli_trans.c
Line
Count
Source
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
static void smb1cli_trans_cleanup_primary(struct smb1cli_trans_state *state)
74
0
{
75
0
  if (state->primary_subreq) {
76
0
    smb1cli_req_set_mid(state->primary_subreq, 0);
77
0
    smbXcli_req_unset_pending(state->primary_subreq);
78
0
    TALLOC_FREE(state->primary_subreq);
79
0
  }
80
0
}
81
82
static int smb1cli_trans_state_destructor(struct smb1cli_trans_state *state)
83
0
{
84
0
  smb1cli_trans_cleanup_primary(state);
85
0
  return 0;
86
0
}
87
88
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
0
{
102
0
  uint32_t param_ofs, data_ofs;
103
0
  uint8_t expected_num_setup;
104
0
  uint32_t max_bytes = UINT32_MAX - bytes_ofs;
105
0
  uint32_t bytes_end;
106
107
0
  if (num_bytes > max_bytes) {
108
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
109
0
  }
110
111
0
  bytes_end = bytes_ofs + num_bytes;
112
113
0
  if (expect_first_reply) {
114
0
    if ((wct != 0) || (num_bytes != 0)) {
115
0
      return NT_STATUS_INVALID_NETWORK_RESPONSE;
116
0
    }
117
0
    return NT_STATUS_OK;
118
0
  }
119
120
0
  switch (smb_cmd) {
121
0
  case SMBtrans:
122
0
  case SMBtrans2:
123
0
    if (wct < 10) {
124
0
      return NT_STATUS_INVALID_NETWORK_RESPONSE;
125
0
    }
126
0
    expected_num_setup = wct - 10;
127
0
    *ptotal_param = SVAL(vwv + 0, 0);
128
0
    *ptotal_data  = SVAL(vwv + 1, 0);
129
0
    *pnum_param = SVAL(vwv + 3, 0);
130
0
    param_ofs = SVAL(vwv + 4, 0);
131
0
    *pparam_disp  = SVAL(vwv + 5, 0);
132
0
    *pnum_data  = SVAL(vwv + 6, 0);
133
0
    data_ofs  = SVAL(vwv + 7, 0);
134
0
    *pdata_disp = SVAL(vwv + 8, 0);
135
0
    *pnum_setup = CVAL(vwv + 9, 0);
136
0
    if (expected_num_setup < (*pnum_setup)) {
137
0
      return NT_STATUS_INVALID_NETWORK_RESPONSE;
138
0
    }
139
0
    *psetup = vwv + 10;
140
141
0
    break;
142
0
  case SMBnttrans:
143
0
    if (wct < 18) {
144
0
      return NT_STATUS_INVALID_NETWORK_RESPONSE;
145
0
    }
146
0
    expected_num_setup = wct - 18;
147
0
    *ptotal_param = IVAL(vwv, 3);
148
0
    *ptotal_data  = IVAL(vwv, 7);
149
0
    *pnum_param = IVAL(vwv, 11);
150
0
    param_ofs = IVAL(vwv, 15);
151
0
    *pparam_disp  = IVAL(vwv, 19);
152
0
    *pnum_data  = IVAL(vwv, 23);
153
0
    data_ofs  = IVAL(vwv, 27);
154
0
    *pdata_disp = IVAL(vwv, 31);
155
0
    *pnum_setup = CVAL(vwv, 35);
156
0
    if (expected_num_setup < (*pnum_setup)) {
157
0
      return NT_STATUS_INVALID_NETWORK_RESPONSE;
158
0
    }
159
0
    *psetup   = vwv + 18;
160
0
    break;
161
162
0
  default:
163
0
    return NT_STATUS_INTERNAL_ERROR;
164
0
  }
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
0
  if (smb_buffer_oob(bytes_end, param_ofs, *pnum_param)
173
0
      || smb_buffer_oob(*ptotal_param, *pparam_disp, *pnum_param)
174
0
      || smb_buffer_oob(bytes_end, data_ofs, *pnum_data)
175
0
      || smb_buffer_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
176
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
177
0
  }
178
179
0
  *pparam = (uint8_t *)inhdr + param_ofs;
180
0
  *pdata = (uint8_t *)inhdr + data_ofs;
181
182
0
  return NT_STATUS_OK;
183
0
}
184
185
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
0
{
190
0
  if (blob->data == NULL) {
191
0
    if (total > blob->max) {
192
0
      return NT_STATUS_INVALID_NETWORK_RESPONSE;
193
0
    }
194
0
    blob->total = total;
195
0
    blob->data = talloc_array(mem_ctx, uint8_t, total);
196
0
    if (blob->data == NULL) {
197
0
      return NT_STATUS_NO_MEMORY;
198
0
    }
199
0
  }
200
201
0
  if (total > blob->total) {
202
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
203
0
  }
204
205
0
  if (thistime) {
206
0
    memcpy(blob->data + displacement, buf, thistime);
207
0
    blob->received += thistime;
208
0
  }
209
210
0
  return NT_STATUS_OK;
211
0
}
212
213
static void smb1cli_trans_format(struct smb1cli_trans_state *state,
214
         uint8_t *pwct,
215
         int *piov_count)
216
0
{
217
0
  uint8_t wct = 0;
218
0
  struct iovec *iov = state->iov;
219
0
  uint8_t *pad = state->pad;
220
0
  uint16_t *vwv = state->vwv;
221
0
  uint32_t param_offset;
222
0
  uint32_t this_param = 0;
223
0
  uint32_t param_pad;
224
0
  uint32_t data_offset;
225
0
  uint32_t this_data = 0;
226
0
  uint32_t data_pad;
227
0
  uint32_t useable_space;
228
0
  uint8_t cmd;
229
0
  uint32_t max_trans = smb1cli_conn_max_xmit(state->conn);
230
231
0
  cmd = state->cmd;
232
233
0
  if ((state->param_sent != 0) || (state->data_sent != 0)) {
234
    /* The secondary commands are one after the primary ones */
235
0
    cmd += 1;
236
0
  }
237
238
0
  param_offset = MIN_SMB_SIZE;
239
240
0
  switch (cmd) {
241
0
  case SMBtrans:
242
0
    if (smbXcli_conn_use_unicode(state->conn)) {
243
0
      pad[0] = 0;
244
0
      iov[0].iov_base = (void *)pad;
245
0
      iov[0].iov_len = 1;
246
0
      param_offset += 1;
247
0
      iov += 1;
248
0
    }
249
0
    iov[0].iov_base = (void *)state->pipe_name_conv;
250
0
    iov[0].iov_len = state->pipe_name_conv_len;
251
0
    wct = 14 + state->num_setup;
252
0
    param_offset += iov[0].iov_len;
253
0
    iov += 1;
254
0
    break;
255
0
  case SMBtrans2:
256
0
    pad[0] = 0;
257
0
    pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
258
0
    pad[2] = ' ';
259
0
    iov[0].iov_base = (void *)pad;
260
0
    iov[0].iov_len = 3;
261
0
    wct = 14 + state->num_setup;
262
0
    param_offset += 3;
263
0
    iov += 1;
264
0
    break;
265
0
  case SMBtranss:
266
0
    wct = 8;
267
0
    break;
268
0
  case SMBtranss2:
269
0
    wct = 9;
270
0
    break;
271
0
  case SMBnttrans:
272
0
    wct = 19 + state->num_setup;
273
0
    break;
274
0
  case SMBnttranss:
275
0
    wct = 18;
276
0
    break;
277
0
  }
278
279
0
  param_offset += wct * sizeof(uint16_t);
280
0
  useable_space = max_trans - param_offset;
281
282
0
  param_pad = param_offset % 4;
283
0
  if (param_pad > 0) {
284
0
    param_pad = MIN(param_pad, useable_space);
285
0
    iov[0].iov_base = (void *)state->zero_pad;
286
0
    iov[0].iov_len = param_pad;
287
0
    iov += 1;
288
0
    param_offset += param_pad;
289
0
  }
290
0
  useable_space = max_trans - param_offset;
291
292
0
  if (state->param_sent < state->num_param) {
293
0
    this_param = MIN(state->num_param - state->param_sent,
294
0
         useable_space);
295
0
    iov[0].iov_base = (void *)(state->param + state->param_sent);
296
0
    iov[0].iov_len = this_param;
297
0
    iov += 1;
298
0
  }
299
300
0
  data_offset = param_offset + this_param;
301
0
  useable_space = max_trans - data_offset;
302
303
0
  data_pad = data_offset % 4;
304
0
  if (data_pad > 0) {
305
0
    data_pad = MIN(data_pad, useable_space);
306
0
    iov[0].iov_base = (void *)state->zero_pad;
307
0
    iov[0].iov_len = data_pad;
308
0
    iov += 1;
309
0
    data_offset += data_pad;
310
0
  }
311
0
  useable_space = max_trans - data_offset;
312
313
0
  if (state->data_sent < state->num_data) {
314
0
    this_data = MIN(state->num_data - state->data_sent,
315
0
        useable_space);
316
0
    iov[0].iov_base = (void *)(state->data + state->data_sent);
317
0
    iov[0].iov_len = this_data;
318
0
    iov += 1;
319
0
  }
320
321
0
  DEBUG(10, ("num_setup=%u, max_setup=%u, "
322
0
       "param_total=%u, this_param=%u, max_param=%u, "
323
0
       "data_total=%u, this_data=%u, max_data=%u, "
324
0
       "param_offset=%u, param_pad=%u, param_disp=%u, "
325
0
       "data_offset=%u, data_pad=%u, data_disp=%u\n",
326
0
       (unsigned)state->num_setup, (unsigned)state->max_setup,
327
0
       (unsigned)state->num_param, (unsigned)this_param,
328
0
       (unsigned)state->rparam.max,
329
0
       (unsigned)state->num_data, (unsigned)this_data,
330
0
       (unsigned)state->rdata.max,
331
0
       (unsigned)param_offset, (unsigned)param_pad,
332
0
       (unsigned)state->param_sent,
333
0
       (unsigned)data_offset, (unsigned)data_pad,
334
0
       (unsigned)state->data_sent));
335
336
0
  switch (cmd) {
337
0
  case SMBtrans:
338
0
  case SMBtrans2:
339
0
    SSVAL(vwv + 0, 0, state->num_param);
340
0
    SSVAL(vwv + 1, 0, state->num_data);
341
0
    SSVAL(vwv + 2, 0, state->rparam.max);
342
0
    SSVAL(vwv + 3, 0, state->rdata.max);
343
0
    SCVAL(vwv + 4, 0, state->max_setup);
344
0
    SCVAL(vwv + 4, 1, 0);  /* reserved */
345
0
    SSVAL(vwv + 5, 0, state->flags);
346
0
    SIVAL(vwv + 6, 0, 0);  /* timeout */
347
0
    SSVAL(vwv + 8, 0, 0);  /* reserved */
348
0
    SSVAL(vwv + 9, 0, this_param);
349
0
    SSVAL(vwv +10, 0, param_offset);
350
0
    SSVAL(vwv +11, 0, this_data);
351
0
    SSVAL(vwv +12, 0, data_offset);
352
0
    SCVAL(vwv +13, 0, state->num_setup);
353
0
    SCVAL(vwv +13, 1, 0);  /* reserved */
354
0
    if (state->num_setup > 0) {
355
0
      memcpy(vwv + 14, state->setup,
356
0
             sizeof(uint16_t) * state->num_setup);
357
0
    }
358
0
    break;
359
0
  case SMBtranss:
360
0
  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
0
    }
372
0
    break;
373
0
  case SMBnttrans:
374
0
    SCVAL(vwv + 0, 0, state->max_setup);
375
0
    SSVAL(vwv + 0, 1, 0); /* reserved */
376
0
    SIVAL(vwv + 1, 1, state->num_param);
377
0
    SIVAL(vwv + 3, 1, state->num_data);
378
0
    SIVAL(vwv + 5, 1, state->rparam.max);
379
0
    SIVAL(vwv + 7, 1, state->rdata.max);
380
0
    SIVAL(vwv + 9, 1, this_param);
381
0
    SIVAL(vwv +11, 1, param_offset);
382
0
    SIVAL(vwv +13, 1, this_data);
383
0
    SIVAL(vwv +15, 1, data_offset);
384
0
    SCVAL(vwv +17, 1, state->num_setup);
385
0
    SSVAL(vwv +18, 0, state->function);
386
0
    memcpy(vwv + 19, state->setup,
387
0
           sizeof(uint16_t) * state->num_setup);
388
0
    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
0
  }
403
404
0
  state->param_sent += this_param;
405
0
  state->data_sent += this_data;
406
407
0
  *pwct = wct;
408
0
  *piov_count = iov - state->iov;
409
0
}
410
411
static bool smb1cli_trans_cancel(struct tevent_req *req);
412
static void smb1cli_trans_done(struct tevent_req *subreq);
413
414
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
0
{
428
0
  struct tevent_req *req, *subreq;
429
0
  struct smb1cli_trans_state *state;
430
0
  int iov_count;
431
0
  uint8_t wct;
432
0
  NTSTATUS status;
433
0
  charset_t charset;
434
435
0
  req = tevent_req_create(mem_ctx, &state,
436
0
        struct smb1cli_trans_state);
437
0
  if (req == NULL) {
438
0
    return NULL;
439
0
  }
440
441
0
  if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
442
0
    if ((num_param > 0xffff) || (max_param > 0xffff)
443
0
        || (num_data > 0xffff) || (max_data > 0xffff)) {
444
0
      DEBUG(3, ("Attempt to send invalid trans2 request "
445
0
          "(setup %u, params %u/%u, data %u/%u)\n",
446
0
          (unsigned)num_setup,
447
0
          (unsigned)num_param, (unsigned)max_param,
448
0
          (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
0
    }
452
0
  }
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
0
  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
0
  }
463
464
0
  state->conn = conn;
465
0
  state->ev = ev;
466
0
  state->cmd = cmd;
467
0
  state->additional_flags = additional_flags;
468
0
  state->clear_flags = clear_flags;
469
0
  state->additional_flags2 = additional_flags2;
470
0
  state->clear_flags2 = clear_flags2;
471
0
  state->timeout_msec = timeout_msec;
472
0
  state->flags = flags;
473
0
  state->num_rsetup = 0;
474
0
  state->rsetup = NULL;
475
0
  state->pid = pid;
476
0
  state->tcon = tcon;
477
0
  state->session = session;
478
0
  ZERO_STRUCT(state->rparam);
479
0
  ZERO_STRUCT(state->rdata);
480
481
0
  if (smbXcli_conn_use_unicode(conn)) {
482
0
    charset = CH_UTF16LE;
483
0
  } else {
484
0
    charset = CH_DOS;
485
0
  }
486
487
0
  if ((pipe_name != NULL)
488
0
      && (!convert_string_talloc(state, CH_UNIX, charset,
489
0
               pipe_name, strlen(pipe_name) + 1,
490
0
               &state->pipe_name_conv,
491
0
               &state->pipe_name_conv_len))) {
492
0
    tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
493
0
    return tevent_req_post(req, ev);
494
0
  }
495
0
  state->fid = fid; /* trans2 */
496
0
  state->function = function; /* nttrans */
497
498
0
  state->setup = setup;
499
0
  state->num_setup = num_setup;
500
0
  state->max_setup = max_setup;
501
502
0
  state->param = param;
503
0
  state->num_param = num_param;
504
0
  state->param_sent = 0;
505
0
  state->rparam.max = max_param;
506
507
0
  state->data = data;
508
0
  state->num_data = num_data;
509
0
  state->data_sent = 0;
510
0
  state->rdata.max = max_data;
511
512
0
  smb1cli_trans_format(state, &wct, &iov_count);
513
514
0
  subreq = smb1cli_req_create(state, ev, conn, cmd,
515
0
            state->additional_flags,
516
0
            state->clear_flags,
517
0
            state->additional_flags2,
518
0
            state->clear_flags2,
519
0
            state->timeout_msec,
520
0
            state->pid,
521
0
            state->tcon,
522
0
            state->session,
523
0
            wct, state->vwv,
524
0
            iov_count, state->iov);
525
0
  if (tevent_req_nomem(subreq, req)) {
526
0
    return tevent_req_post(req, ev);
527
0
  }
528
0
  status = smb1cli_req_chain_submit(&subreq, 1);
529
0
  if (tevent_req_nterror(req, status)) {
530
0
    return tevent_req_post(req, state->ev);
531
0
  }
532
0
  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
0
  state->mid = smb1cli_req_mid(subreq);
542
0
  smb1cli_req_set_mid(subreq, state->mid);
543
0
  state->primary_subreq = subreq;
544
0
  talloc_set_destructor(state, smb1cli_trans_state_destructor);
545
546
0
  tevent_req_set_cancel_fn(req, smb1cli_trans_cancel);
547
548
0
  return req;
549
0
}
550
551
static bool smb1cli_trans_cancel(struct tevent_req *req)
552
0
{
553
0
  struct smb1cli_trans_state *state =
554
0
    tevent_req_data(req,
555
0
    struct smb1cli_trans_state);
556
557
0
  if (state->primary_subreq == NULL) {
558
0
    return false;
559
0
  }
560
561
0
  return tevent_req_cancel(state->primary_subreq);
562
0
}
563
564
static void smb1cli_trans_done2(struct tevent_req *subreq);
565
566
static void smb1cli_trans_done(struct tevent_req *subreq)
567
0
{
568
0
  struct tevent_req *req =
569
0
    tevent_req_callback_data(subreq,
570
0
    struct tevent_req);
571
0
  struct smb1cli_trans_state *state =
572
0
    tevent_req_data(req,
573
0
    struct smb1cli_trans_state);
574
0
  NTSTATUS status;
575
0
  bool sent_all;
576
0
  struct iovec *recv_iov = NULL;
577
0
  uint8_t *inhdr;
578
0
  uint8_t wct;
579
0
  uint16_t *vwv;
580
0
  uint32_t vwv_ofs;
581
0
  uint32_t num_bytes;
582
0
  uint8_t *bytes;
583
0
  uint32_t bytes_ofs;
584
0
  uint8_t num_setup = 0;
585
0
  uint16_t *setup   = NULL;
586
0
  uint32_t total_param  = 0;
587
0
  uint32_t num_param  = 0;
588
0
  uint32_t param_disp = 0;
589
0
  uint32_t total_data = 0;
590
0
  uint32_t num_data = 0;
591
0
  uint32_t data_disp  = 0;
592
0
  uint8_t *param    = NULL;
593
0
  uint8_t *data   = NULL;
594
595
0
  status = smb1cli_req_recv(subreq, state,
596
0
          &recv_iov,
597
0
          &inhdr,
598
0
          &wct,
599
0
          &vwv,
600
0
          &vwv_ofs,
601
0
          &num_bytes,
602
0
          &bytes,
603
0
          &bytes_ofs,
604
0
          NULL, /* pinbuf */
605
0
          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
0
  if (NT_STATUS_IS_ERR(status)) {
617
0
    goto fail;
618
0
  }
619
620
0
  if (recv_iov == NULL) {
621
0
    status = NT_STATUS_INVALID_NETWORK_RESPONSE;
622
0
    goto fail;
623
0
  }
624
0
  state->status = status;
625
626
0
  sent_all = ((state->param_sent == state->num_param)
627
0
        && (state->data_sent == state->num_data));
628
629
0
  status = smb1cli_pull_trans(
630
0
    inhdr, wct, vwv, vwv_ofs,
631
0
    num_bytes, bytes, bytes_ofs,
632
0
    state->cmd, !sent_all, &num_setup, &setup,
633
0
    &total_param, &num_param, &param_disp, &param,
634
0
    &total_data, &num_data, &data_disp, &data);
635
636
0
  if (!NT_STATUS_IS_OK(status)) {
637
0
    goto fail;
638
0
  }
639
640
0
  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
0
               state->timeout_msec,
653
0
               state->pid,
654
0
               state->tcon,
655
0
               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
0
    }
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
0
    }
668
0
    tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
669
670
0
    return;
671
0
  }
672
673
0
  status = smb1cli_trans_pull_blob(
674
0
    state, &state->rparam, total_param, num_param, param,
675
0
    param_disp);
676
677
0
  if (!NT_STATUS_IS_OK(status)) {
678
0
    DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
679
0
    goto fail;
680
0
  }
681
682
0
  status = smb1cli_trans_pull_blob(
683
0
    state, &state->rdata, total_data, num_data, data,
684
0
    data_disp);
685
686
0
  if (!NT_STATUS_IS_OK(status)) {
687
0
    DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
688
0
    goto fail;
689
0
  }
690
691
0
  if ((state->rparam.total == state->rparam.received)
692
0
      && (state->rdata.total == state->rdata.received)) {
693
0
    state->recv_flags2 = SVAL(inhdr, HDR_FLG2);
694
0
    smb1cli_trans_cleanup_primary(state);
695
0
    tevent_req_done(req);
696
0
    return;
697
0
  }
698
699
0
  TALLOC_FREE(recv_iov);
700
701
0
  return;
702
703
0
 fail:
704
0
  smb1cli_trans_cleanup_primary(state);
705
0
  tevent_req_nterror(req, status);
706
0
}
707
708
static void smb1cli_trans_done2(struct tevent_req *subreq2)
709
0
{
710
0
  struct tevent_req *req =
711
0
    tevent_req_callback_data(subreq2,
712
0
    struct tevent_req);
713
0
  struct smb1cli_trans_state *state =
714
0
    tevent_req_data(req,
715
0
    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
0
          NULL, /* recv_iov */
730
0
          NULL, /* phdr */
731
0
          NULL, /* pwct */
732
0
          NULL, /* pvwv */
733
0
          NULL, /* pvwv_offset */
734
0
          NULL, /* pnum_bytes */
735
0
          NULL, /* pbytes */
736
0
          NULL, /* pbytes_offset */
737
0
          NULL, /* pinbuf */
738
0
          NULL, 0); /* expected */
739
0
  TALLOC_FREE(subreq2);
740
741
0
  if (!NT_STATUS_IS_OK(status)) {
742
0
    goto fail;
743
0
  }
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
0
               state->timeout_msec,
761
0
               state->pid,
762
0
               state->tcon,
763
0
               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
0
    }
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
0
    }
776
0
    tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
777
0
    return;
778
0
  }
779
780
0
  return;
781
782
0
 fail:
783
0
  smb1cli_trans_cleanup_primary(state);
784
0
  tevent_req_nterror(req, status);
785
0
}
786
787
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
0
{
796
0
  struct smb1cli_trans_state *state =
797
0
    tevent_req_data(req,
798
0
    struct smb1cli_trans_state);
799
0
  NTSTATUS status;
800
801
0
  smb1cli_trans_cleanup_primary(state);
802
803
0
  if (tevent_req_is_nterror(req, &status)) {
804
0
    if (!NT_STATUS_IS_ERR(status)) {
805
0
      status = NT_STATUS_INVALID_NETWORK_RESPONSE;
806
0
    }
807
0
    tevent_req_received(req);
808
0
    return status;
809
0
  }
810
811
0
  if ((state->num_rsetup < min_setup)
812
0
      || (state->rparam.total < min_param)
813
0
      || (state->rdata.total < min_data)) {
814
0
    tevent_req_received(req);
815
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
816
0
  }
817
818
0
  if (recv_flags2 != NULL) {
819
0
    *recv_flags2 = state->recv_flags2;
820
0
  }
821
822
0
  if (setup != NULL) {
823
0
    *setup = talloc_move(mem_ctx, &state->rsetup);
824
0
    *num_setup = state->num_rsetup;
825
0
  }
826
827
0
  if (param != NULL) {
828
0
    *param = talloc_move(mem_ctx, &state->rparam.data);
829
0
    *num_param = state->rparam.total;
830
0
  }
831
832
0
  if (data != NULL) {
833
0
    *data = talloc_move(mem_ctx, &state->rdata.data);
834
0
    *num_data = state->rdata.total;
835
0
  }
836
837
0
  status = state->status;
838
0
  tevent_req_received(req);
839
0
  return status;
840
0
}