Coverage Report

Created: 2026-05-24 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/libcli/smb2/request.c
Line
Count
Source
1
/* 
2
   Unix SMB/CIFS implementation.
3
4
   SMB2 client request handling
5
6
   Copyright (C) Andrew Tridgell  2005
7
   Copyright (C) Stefan Metzmacher  2005
8
   
9
   This program is free software; you can redistribute it and/or modify
10
   it under the terms of the GNU General Public License as published by
11
   the Free Software Foundation; either version 3 of the License, or
12
   (at your option) any later version.
13
   
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
   
19
   You should have received a copy of the GNU General Public License
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
*/
22
23
#include "includes.h"
24
#include "libcli/raw/libcliraw.h"
25
#include "libcli/smb2/smb2.h"
26
#include "../lib/util/dlinklist.h"
27
#include "lib/events/events.h"
28
#include "libcli/smb2/smb2_calls.h"
29
30
/* fill in the bufinfo */
31
void smb2_setup_bufinfo(struct smb2_request *req)
32
0
{
33
0
  req->in.bufinfo.mem_ctx    = req;
34
0
  req->in.bufinfo.flags      = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
35
0
  req->in.bufinfo.align_base = req->in.buffer;
36
0
  if (req->in.dynamic) {
37
0
    req->in.bufinfo.data       = req->in.dynamic;
38
0
    req->in.bufinfo.data_size  = req->in.body_size - req->in.body_fixed;
39
0
  } else {
40
0
    req->in.bufinfo.data       = NULL;
41
0
    req->in.bufinfo.data_size  = 0;
42
0
  }
43
0
}
44
45
/*
46
  initialise a smb2 request
47
*/
48
struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
49
               uint16_t body_fixed_size, bool body_dynamic_present,
50
               uint32_t body_dynamic_size)
51
0
{
52
0
  struct smb2_request *req;
53
0
  uint32_t hdr_offset;
54
0
  bool compound = false;
55
56
0
  if (body_dynamic_present) {
57
0
    if (body_dynamic_size == 0) {
58
0
      body_dynamic_size = 1;
59
0
    }
60
0
  } else {
61
0
    body_dynamic_size = 0;
62
0
  }
63
64
0
  req = talloc_zero(transport, struct smb2_request);
65
0
  if (req == NULL) return NULL;
66
67
0
  req->state     = SMB2_REQUEST_INIT;
68
0
  req->transport = transport;
69
70
0
  hdr_offset = NBT_HDR_SIZE;
71
72
0
  req->out.size      = hdr_offset + SMB2_HDR_BODY + body_fixed_size;
73
0
  req->out.allocated = req->out.size + body_dynamic_size;
74
75
0
  req->out.buffer = talloc_realloc(req, req->out.buffer,
76
0
           uint8_t, req->out.allocated);
77
0
  if (req->out.buffer == NULL) {
78
0
    talloc_free(req);
79
0
    return NULL;
80
0
  }
81
82
0
  req->out.hdr       = req->out.buffer + hdr_offset;
83
0
  req->out.body      = req->out.hdr + SMB2_HDR_BODY;
84
0
  req->out.body_fixed= body_fixed_size;
85
0
  req->out.body_size = body_fixed_size;
86
0
  req->out.dynamic   = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
87
88
0
  SIVAL(req->out.hdr, 0,       SMB2_MAGIC);
89
0
  SSVAL(req->out.hdr, SMB2_HDR_LENGTH,   SMB2_HDR_BODY);
90
0
  SSVAL(req->out.hdr, SMB2_HDR_CREDIT_CHARGE,  0);
91
0
  SIVAL(req->out.hdr, SMB2_HDR_STATUS,   0);
92
0
  SSVAL(req->out.hdr, SMB2_HDR_OPCODE,   opcode);
93
0
  SSVAL(req->out.hdr, SMB2_HDR_CREDIT,   0);
94
0
  SIVAL(req->out.hdr, SMB2_HDR_FLAGS,    0);
95
0
  SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0);
96
0
  SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, 0);
97
0
  SIVAL(req->out.hdr, SMB2_HDR_PID,    0);
98
0
  SIVAL(req->out.hdr, SMB2_HDR_TID,    0);
99
0
  SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID,   0);
100
0
  memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16);
101
102
  /* set the length of the fixed body part and +1 if there's a dynamic part also */
103
0
  SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
104
105
  /* 
106
   * if we have a dynamic part, make sure the first byte
107
   * which is always be part of the packet is initialized
108
   */
109
0
  if (body_dynamic_size && !compound) {
110
0
    req->out.size += 1;
111
0
    SCVAL(req->out.dynamic, 0, 0);
112
0
  }
113
114
0
  return req;
115
0
}
116
117
/*
118
    initialise a smb2 request for tree operations
119
*/
120
struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
121
              uint16_t body_fixed_size, bool body_dynamic_present,
122
              uint32_t body_dynamic_size)
123
0
{
124
0
  struct smb2_request *req = smb2_request_init(tree->session->transport, opcode, 
125
0
                 body_fixed_size, body_dynamic_present,
126
0
                 body_dynamic_size);
127
0
  if (req == NULL) return NULL;
128
129
0
  req->session = tree->session;
130
0
  req->tree = tree;
131
132
0
  return req; 
133
0
}
134
135
/* destroy a request structure and return final status */
136
NTSTATUS smb2_request_destroy(struct smb2_request *req)
137
0
{
138
0
  NTSTATUS status;
139
140
  /* this is the error code we give the application for when a
141
     _send() call fails completely */
142
0
  if (!req) return NT_STATUS_UNSUCCESSFUL;
143
144
0
  if (req->state == SMB2_REQUEST_ERROR &&
145
0
      NT_STATUS_IS_OK(req->status)) {
146
0
    status = NT_STATUS_INTERNAL_ERROR;
147
0
  } else {
148
0
    status = req->status;
149
0
  }
150
151
0
  talloc_free(req);
152
0
  return status;
153
0
}
154
155
/*
156
  receive a response to a packet
157
*/
158
bool smb2_request_receive(struct smb2_request *req)
159
0
{
160
  /* req can be NULL when a send has failed. This eliminates lots of NULL
161
     checks in each module */
162
0
  if (!req) return false;
163
164
  /* keep receiving packets until this one is replied to */
165
0
  while (req->state <= SMB2_REQUEST_RECV) {
166
0
    if (tevent_loop_once(req->transport->ev) != 0) {
167
0
      return false;
168
0
    }
169
0
  }
170
171
0
  return req->state == SMB2_REQUEST_DONE;
172
0
}
173
174
/* Return true if the last packet was in error */
175
bool smb2_request_is_error(struct smb2_request *req)
176
0
{
177
0
  return NT_STATUS_IS_ERR(req->status);
178
0
}
179
180
/* Return true if the last packet was OK */
181
bool smb2_request_is_ok(struct smb2_request *req)
182
0
{
183
0
  return NT_STATUS_IS_OK(req->status);
184
0
}
185
186
/*
187
  check if a range in the reply body is out of bounds
188
*/
189
bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
190
0
{
191
0
  if (size == 0) {
192
    /* zero bytes is never out of range */
193
0
    return false;
194
0
  }
195
  /* be careful with wraparound! */
196
0
  if ((uintptr_t)ptr < (uintptr_t)buf->body ||
197
0
      (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size ||
198
0
      size > buf->body_size ||
199
0
      (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) {
200
0
    return true;
201
0
  }
202
0
  return false;
203
0
}
204
205
size_t smb2_padding_size(uint32_t offset, size_t n)
206
0
{
207
0
  if ((offset & (n-1)) == 0) return 0;
208
0
  return n - (offset & (n-1));
209
0
}
210
211
static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
212
0
{
213
0
  if (buf->dynamic == (buf->body + buf->body_fixed)) {
214
0
    if (buf->dynamic != (buf->buffer + buf->size)) {
215
0
      return 1;
216
0
    }
217
0
  }
218
0
  return 0;
219
0
}
220
221
/*
222
  grow a SMB2 buffer by the specified amount
223
*/
224
NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
225
0
{
226
0
  size_t hdr_ofs;
227
0
  size_t dynamic_ofs;
228
0
  uint8_t *buffer_ptr;
229
0
  uint32_t newsize = buf->size + increase;
230
231
  /* a packet size should be limited a bit */
232
0
  if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
233
234
0
  if (newsize <= buf->allocated) return NT_STATUS_OK;
235
236
0
  hdr_ofs = buf->hdr - buf->buffer;
237
0
  dynamic_ofs = buf->dynamic - buf->buffer;
238
239
0
  buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
240
0
  NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
241
242
0
  buf->buffer = buffer_ptr;
243
0
  buf->hdr  = buf->buffer + hdr_ofs;
244
0
  buf->body = buf->hdr    + SMB2_HDR_BODY;
245
0
  buf->dynamic  = buf->buffer + dynamic_ofs;
246
0
  buf->allocated  = newsize;
247
248
0
  return NT_STATUS_OK;
249
0
}
250
251
/*
252
  pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
253
  the ptr points to the start of the offset/length pair
254
*/
255
NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
256
0
{
257
0
  uint16_t ofs, size;
258
0
  if (smb2_oob(buf, ptr, 4)) {
259
0
    return NT_STATUS_INVALID_PARAMETER;
260
0
  }
261
0
  ofs  = SVAL(ptr, 0);
262
0
  size = SVAL(ptr, 2);
263
0
  if (ofs == 0) {
264
0
    *blob = data_blob(NULL, 0);
265
0
    return NT_STATUS_OK;
266
0
  }
267
0
  if (smb2_oob(buf, buf->hdr + ofs, size)) {
268
0
    return NT_STATUS_INVALID_PARAMETER;
269
0
  }
270
0
  *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
271
0
  NT_STATUS_HAVE_NO_MEMORY(blob->data);
272
0
  return NT_STATUS_OK;
273
0
}
274
275
/*
276
  push a uint16_t ofs/ uint16_t length/blob triple into a data blob
277
  the ofs points to the start of the offset/length pair, and is relative
278
  to the body start
279
*/
280
NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, 
281
             uint16_t ofs, DATA_BLOB blob)
282
0
{
283
0
  NTSTATUS status;
284
0
  size_t offset;
285
0
  size_t padding_length;
286
0
  size_t padding_fix;
287
0
  uint8_t *ptr = buf->body+ofs;
288
289
0
  if (buf->dynamic == NULL) {
290
0
    return NT_STATUS_INVALID_PARAMETER;
291
0
  }
292
293
  /* we have only 16 bit for the size */
294
0
  if (blob.length > 0xFFFF) {
295
0
    return NT_STATUS_INVALID_PARAMETER;
296
0
  }
297
298
  /* check if there're enough room for ofs and size */
299
0
  if (smb2_oob(buf, ptr, 4)) {
300
0
    return NT_STATUS_INVALID_PARAMETER;
301
0
  }
302
303
0
  if (blob.data == NULL) {
304
0
    if (blob.length != 0) {
305
0
      return NT_STATUS_INTERNAL_ERROR;
306
0
    }
307
0
    SSVAL(ptr, 0, 0);
308
0
    SSVAL(ptr, 2, 0);
309
0
    return NT_STATUS_OK;
310
0
  }
311
312
0
  offset = buf->dynamic - buf->hdr;
313
0
  padding_length = smb2_padding_size(offset, 2);
314
0
  offset += padding_length;
315
0
  padding_fix = smb2_padding_fix(buf);
316
317
0
  SSVAL(ptr, 0, offset);
318
0
  SSVAL(ptr, 2, blob.length);
319
320
0
  status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
321
0
  NT_STATUS_NOT_OK_RETURN(status);
322
323
0
  memset(buf->dynamic, 0, padding_length);
324
0
  buf->dynamic += padding_length;
325
326
0
  memcpy(buf->dynamic, blob.data, blob.length);
327
0
  buf->dynamic += blob.length;
328
329
0
  buf->size += blob.length + padding_length - padding_fix;
330
0
  buf->body_size += blob.length + padding_length;
331
332
0
  return NT_STATUS_OK;
333
0
}
334
335
336
/*
337
  push a uint16_t ofs/ uint32_t length/blob triple into a data blob
338
  the ofs points to the start of the offset/length pair, and is relative
339
  to the body start
340
*/
341
NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, 
342
             uint16_t ofs, DATA_BLOB blob)
343
0
{
344
0
  NTSTATUS status;
345
0
  size_t offset;
346
0
  size_t padding_length;
347
0
  size_t padding_fix;
348
0
  uint8_t *ptr = buf->body+ofs;
349
350
0
  if (buf->dynamic == NULL) {
351
0
    return NT_STATUS_INVALID_PARAMETER;
352
0
  }
353
354
  /* check if there're enough room for ofs and size */
355
0
  if (smb2_oob(buf, ptr, 6)) {
356
0
    return NT_STATUS_INVALID_PARAMETER;
357
0
  }
358
359
0
  if (blob.data == NULL) {
360
0
    if (blob.length != 0) {
361
0
      return NT_STATUS_INTERNAL_ERROR;
362
0
    }
363
0
    SSVAL(ptr, 0, 0);
364
0
    SIVAL(ptr, 2, 0);
365
0
    return NT_STATUS_OK;
366
0
  }
367
368
0
  offset = buf->dynamic - buf->hdr;
369
0
  padding_length = smb2_padding_size(offset, 2);
370
0
  offset += padding_length;
371
0
  padding_fix = smb2_padding_fix(buf);
372
373
0
  SSVAL(ptr, 0, offset);
374
0
  SIVAL(ptr, 2, blob.length);
375
376
0
  status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
377
0
  NT_STATUS_NOT_OK_RETURN(status);
378
379
0
  memset(buf->dynamic, 0, padding_length);
380
0
  buf->dynamic += padding_length;
381
382
0
  memcpy(buf->dynamic, blob.data, blob.length);
383
0
  buf->dynamic += blob.length;
384
385
0
  buf->size += blob.length + padding_length - padding_fix;
386
0
  buf->body_size += blob.length + padding_length;
387
388
0
  return NT_STATUS_OK;
389
0
}
390
391
392
/*
393
  push a uint32_t ofs/ uint32_t length/blob triple into a data blob
394
  the ofs points to the start of the offset/length pair, and is relative
395
  to the body start
396
*/
397
NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, 
398
             uint32_t ofs, DATA_BLOB blob)
399
0
{
400
0
  NTSTATUS status;
401
0
  size_t offset;
402
0
  size_t padding_length;
403
0
  size_t padding_fix;
404
0
  uint8_t *ptr = buf->body+ofs;
405
406
0
  if (buf->dynamic == NULL) {
407
0
    return NT_STATUS_INVALID_PARAMETER;
408
0
  }
409
410
  /* check if there're enough room for ofs and size */
411
0
  if (smb2_oob(buf, ptr, 8)) {
412
0
    return NT_STATUS_INVALID_PARAMETER;
413
0
  }
414
415
0
  if (blob.data == NULL) {
416
0
    if (blob.length != 0) {
417
0
      return NT_STATUS_INTERNAL_ERROR;
418
0
    }
419
0
    SIVAL(ptr, 0, 0);
420
0
    SIVAL(ptr, 4, 0);
421
0
    return NT_STATUS_OK;
422
0
  }
423
424
0
  offset = buf->dynamic - buf->hdr;
425
0
  padding_length = smb2_padding_size(offset, 8);
426
0
  offset += padding_length;
427
0
  padding_fix = smb2_padding_fix(buf);
428
429
0
  SIVAL(ptr, 0, offset);
430
0
  SIVAL(ptr, 4, blob.length);
431
432
0
  status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
433
0
  NT_STATUS_NOT_OK_RETURN(status);
434
435
0
  memset(buf->dynamic, 0, padding_length);
436
0
  buf->dynamic += padding_length;
437
438
0
  memcpy(buf->dynamic, blob.data, blob.length);
439
0
  buf->dynamic += blob.length;
440
441
0
  buf->size += blob.length + padding_length - padding_fix;
442
0
  buf->body_size += blob.length + padding_length;
443
444
0
  return NT_STATUS_OK;
445
0
}
446
447
448
/*
449
  push a uint32_t length/ uint32_t ofs/blob triple into a data blob
450
  the ofs points to the start of the length/offset pair, and is relative
451
  to the body start
452
*/
453
NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf, 
454
             uint32_t ofs, DATA_BLOB blob)
455
0
{
456
0
  NTSTATUS status;
457
0
  size_t offset;
458
0
  size_t padding_length;
459
0
  size_t padding_fix;
460
0
  uint8_t *ptr = buf->body+ofs;
461
462
0
  if (buf->dynamic == NULL) {
463
0
    return NT_STATUS_INVALID_PARAMETER;
464
0
  }
465
466
  /* check if there're enough room for ofs and size */
467
0
  if (smb2_oob(buf, ptr, 8)) {
468
0
    return NT_STATUS_INVALID_PARAMETER;
469
0
  }
470
471
0
  if (blob.data == NULL) {
472
0
    if (blob.length != 0) {
473
0
      return NT_STATUS_INTERNAL_ERROR;
474
0
    }
475
0
    SIVAL(ptr, 0, 0);
476
0
    SIVAL(ptr, 4, 0);
477
0
    return NT_STATUS_OK;
478
0
  }
479
480
0
  offset = buf->dynamic - buf->hdr;
481
0
  padding_length = smb2_padding_size(offset, 8);
482
0
  offset += padding_length;
483
0
  padding_fix = smb2_padding_fix(buf);
484
485
0
  SIVAL(ptr, 0, blob.length);
486
0
  SIVAL(ptr, 4, offset);
487
488
0
  status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
489
0
  NT_STATUS_NOT_OK_RETURN(status);
490
491
0
  memset(buf->dynamic, 0, padding_length);
492
0
  buf->dynamic += padding_length;
493
494
0
  memcpy(buf->dynamic, blob.data, blob.length);
495
0
  buf->dynamic += blob.length;
496
497
0
  buf->size += blob.length + padding_length - padding_fix;
498
0
  buf->body_size += blob.length + padding_length;
499
500
0
  return NT_STATUS_OK;
501
0
}
502
503
/*
504
  pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
505
  the ptr points to the start of the offset/length pair
506
*/
507
NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
508
0
{
509
0
  uint16_t ofs;
510
0
  uint32_t size;
511
512
0
  if (smb2_oob(buf, ptr, 6)) {
513
0
    return NT_STATUS_INVALID_PARAMETER;
514
0
  }
515
0
  ofs  = SVAL(ptr, 0);
516
0
  size = IVAL(ptr, 2);
517
0
  if (ofs == 0) {
518
0
    *blob = data_blob(NULL, 0);
519
0
    return NT_STATUS_OK;
520
0
  }
521
0
  if (smb2_oob(buf, buf->hdr + ofs, size)) {
522
0
    return NT_STATUS_INVALID_PARAMETER;
523
0
  }
524
0
  *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
525
0
  NT_STATUS_HAVE_NO_MEMORY(blob->data);
526
0
  return NT_STATUS_OK;
527
0
}
528
529
/*
530
  pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
531
  the ptr points to the start of the offset/length pair
532
*/
533
NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
534
0
{
535
0
  uint32_t ofs, size;
536
0
  if (smb2_oob(buf, ptr, 8)) {
537
0
    return NT_STATUS_INVALID_PARAMETER;
538
0
  }
539
0
  ofs  = IVAL(ptr, 0);
540
0
  size = IVAL(ptr, 4);
541
0
  if (ofs == 0) {
542
0
    *blob = data_blob(NULL, 0);
543
0
    return NT_STATUS_OK;
544
0
  }
545
0
  if (smb2_oob(buf, buf->hdr + ofs, size)) {
546
0
    return NT_STATUS_INVALID_PARAMETER;
547
0
  }
548
0
  *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
549
0
  NT_STATUS_HAVE_NO_MEMORY(blob->data);
550
0
  return NT_STATUS_OK;
551
0
}
552
553
/*
554
  pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
555
  the ptr points to the start of the offset/length pair
556
  
557
  In this variant the uint16_t is padded by an extra 2 bytes, making
558
  the size aligned on 4 byte boundary
559
*/
560
NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
561
0
{
562
0
  uint32_t ofs, size;
563
0
  if (smb2_oob(buf, ptr, 8)) {
564
0
    return NT_STATUS_INVALID_PARAMETER;
565
0
  }
566
0
  ofs  = SVAL(ptr, 0);
567
0
  size = IVAL(ptr, 4);
568
0
  if (ofs == 0) {
569
0
    *blob = data_blob(NULL, 0);
570
0
    return NT_STATUS_OK;
571
0
  }
572
0
  if (smb2_oob(buf, buf->hdr + ofs, size)) {
573
0
    return NT_STATUS_INVALID_PARAMETER;
574
0
  }
575
0
  *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
576
0
  NT_STATUS_HAVE_NO_MEMORY(blob->data);
577
0
  return NT_STATUS_OK;
578
0
}
579
580
/*
581
  pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
582
  the ptr points to the start of the offset/length pair
583
*/
584
NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
585
0
{
586
0
  uint32_t ofs, size;
587
0
  if (smb2_oob(buf, ptr, 8)) {
588
0
    return NT_STATUS_INVALID_PARAMETER;
589
0
  }
590
0
  size = IVAL(ptr, 0);
591
0
  ofs  = IVAL(ptr, 4);
592
0
  if (ofs == 0) {
593
0
    *blob = data_blob(NULL, 0);
594
0
    return NT_STATUS_OK;
595
0
  }
596
0
  if (smb2_oob(buf, buf->hdr + ofs, size)) {
597
0
    return NT_STATUS_INVALID_PARAMETER;
598
0
  }
599
0
  *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
600
0
  NT_STATUS_HAVE_NO_MEMORY(blob->data);
601
0
  return NT_STATUS_OK;
602
0
}
603
604
/*
605
  pull a uint32_t length/ uint16_t ofs/blob triple from a data blob
606
  the ptr points to the start of the offset/length pair
607
*/
608
NTSTATUS smb2_pull_s32o16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
609
0
{
610
0
  uint32_t ofs, size;
611
0
  if (smb2_oob(buf, ptr, 8)) {
612
0
    return NT_STATUS_INVALID_PARAMETER;
613
0
  }
614
0
  size = IVAL(ptr, 0);
615
0
  ofs  = SVAL(ptr, 4);
616
0
  if (ofs == 0) {
617
0
    *blob = data_blob(NULL, 0);
618
0
    return NT_STATUS_OK;
619
0
  }
620
0
  if (smb2_oob(buf, buf->hdr + ofs, size)) {
621
0
    return NT_STATUS_INVALID_PARAMETER;
622
0
  }
623
0
  *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
624
0
  NT_STATUS_HAVE_NO_MEMORY(blob->data);
625
0
  return NT_STATUS_OK;
626
0
}
627
628
/*
629
  pull a string in a uint16_t ofs/ uint16_t length/blob format
630
  UTF-16 without termination
631
*/
632
NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
633
         uint8_t *ptr, const char **str)
634
0
{
635
0
  DATA_BLOB blob;
636
0
  NTSTATUS status;
637
0
  void *vstr;
638
0
  size_t converted_size = 0;
639
0
  bool ret;
640
641
0
  status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
642
0
  NT_STATUS_NOT_OK_RETURN(status);
643
644
0
  if (blob.data == NULL) {
645
0
    *str = NULL;
646
0
    return NT_STATUS_OK;
647
0
  }
648
649
0
  if (blob.length == 0) {
650
0
    char *s;
651
0
    s = talloc_strdup(mem_ctx, "");
652
0
    NT_STATUS_HAVE_NO_MEMORY(s);
653
0
    *str = s;
654
0
    return NT_STATUS_OK;
655
0
  }
656
657
0
  ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
658
0
             blob.data, blob.length, &vstr, &converted_size);
659
0
  data_blob_free(&blob);
660
0
  (*str) = (char *)vstr;
661
0
  if (!ret) {
662
0
    return NT_STATUS_ILLEGAL_CHARACTER;
663
0
  }
664
0
  return NT_STATUS_OK;
665
0
}
666
667
/*
668
  push a string in a uint16_t ofs/ uint16_t length/blob format
669
  UTF-16 without termination
670
*/
671
NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
672
         uint16_t ofs, const char *str)
673
0
{
674
0
  DATA_BLOB blob;
675
0
  NTSTATUS status;
676
0
  bool ret;
677
0
  void *ptr = NULL;
678
679
0
  if (str == NULL) {
680
0
    return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
681
0
  }
682
683
0
  if (*str == 0) {
684
0
    blob.data = discard_const_p(uint8_t, str);
685
0
    blob.length = 0;
686
0
    return smb2_push_o16s16_blob(buf, ofs, blob);
687
0
  }
688
689
0
  ret = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16, 
690
0
            str, strlen(str), &ptr, &blob.length);
691
0
  if (!ret) {
692
0
    return NT_STATUS_ILLEGAL_CHARACTER;
693
0
  }
694
0
  blob.data = (uint8_t *)ptr;
695
696
0
  status = smb2_push_o16s16_blob(buf, ofs, blob);
697
0
  data_blob_free(&blob);
698
0
  return status;
699
0
}
700
701
/*
702
  push a file handle into a buffer
703
*/
704
void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
705
0
{
706
0
  SBVAL(data, 0, h->data[0]);
707
0
  SBVAL(data, 8, h->data[1]);
708
0
}
709
710
/*
711
  pull a file handle from a buffer
712
*/
713
void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
714
0
{
715
0
  h->data[0] = BVAL(ptr, 0);
716
0
  h->data[1] = BVAL(ptr, 8);
717
0
}