2 Unix SMB/CIFS implementation.
4 SMB2 client request handling
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher 2005
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.
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.
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/>.
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"
30 /* fill in the bufinfo */
31 void smb2_setup_bufinfo(struct smb2_request
*req
)
33 req
->in
.bufinfo
.mem_ctx
= req
;
34 req
->in
.bufinfo
.flags
= BUFINFO_FLAG_UNICODE
| BUFINFO_FLAG_SMB2
;
35 req
->in
.bufinfo
.align_base
= req
->in
.buffer
;
36 if (req
->in
.dynamic
) {
37 req
->in
.bufinfo
.data
= req
->in
.dynamic
;
38 req
->in
.bufinfo
.data_size
= req
->in
.body_size
- req
->in
.body_fixed
;
40 req
->in
.bufinfo
.data
= NULL
;
41 req
->in
.bufinfo
.data_size
= 0;
46 /* destroy a request structure */
47 static int smb2_request_destructor(struct smb2_request
*req
)
50 /* remove it from the list of pending requests (a null op if
51 its not in the list) */
52 DLIST_REMOVE(req
->transport
->pending_recv
, req
);
58 initialise a smb2 request
60 struct smb2_request
*smb2_request_init(struct smb2_transport
*transport
, uint16_t opcode
,
61 uint16_t body_fixed_size
, bool body_dynamic_present
,
62 uint32_t body_dynamic_size
)
64 struct smb2_request
*req
;
67 if (body_dynamic_present
) {
68 if (body_dynamic_size
== 0) {
69 body_dynamic_size
= 1;
72 body_dynamic_size
= 0;
75 req
= talloc(transport
, struct smb2_request
);
76 if (req
== NULL
) return NULL
;
78 seqnum
= transport
->seqnum
++;
79 if (seqnum
== UINT64_MAX
) {
80 seqnum
= transport
->seqnum
++;
83 req
->state
= SMB2_REQUEST_INIT
;
84 req
->transport
= transport
;
88 req
->status
= NT_STATUS_OK
;
90 req
->next
= req
->prev
= NULL
;
92 ZERO_STRUCT(req
->cancel
);
95 req
->out
.size
= SMB2_HDR_BODY
+NBT_HDR_SIZE
+body_fixed_size
;
97 req
->out
.allocated
= req
->out
.size
+ body_dynamic_size
;
98 req
->out
.buffer
= talloc_array(req
, uint8_t, req
->out
.allocated
);
99 if (req
->out
.buffer
== NULL
) {
104 req
->out
.hdr
= req
->out
.buffer
+ NBT_HDR_SIZE
;
105 req
->out
.body
= req
->out
.hdr
+ SMB2_HDR_BODY
;
106 req
->out
.body_fixed
= body_fixed_size
;
107 req
->out
.body_size
= body_fixed_size
;
108 req
->out
.dynamic
= (body_dynamic_size
? req
->out
.body
+ body_fixed_size
: NULL
);
110 SIVAL(req
->out
.hdr
, 0, SMB2_MAGIC
);
111 SSVAL(req
->out
.hdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
112 SSVAL(req
->out
.hdr
, SMB2_HDR_EPOCH
, 0);
113 SIVAL(req
->out
.hdr
, SMB2_HDR_STATUS
, 0);
114 SSVAL(req
->out
.hdr
, SMB2_HDR_OPCODE
, opcode
);
115 SSVAL(req
->out
.hdr
, SMB2_HDR_CREDIT
, 0);
116 SIVAL(req
->out
.hdr
, SMB2_HDR_FLAGS
, 0);
117 SIVAL(req
->out
.hdr
, SMB2_HDR_NEXT_COMMAND
, 0);
118 SBVAL(req
->out
.hdr
, SMB2_HDR_MESSAGE_ID
, req
->seqnum
);
119 SIVAL(req
->out
.hdr
, SMB2_HDR_PID
, 0);
120 SIVAL(req
->out
.hdr
, SMB2_HDR_TID
, 0);
121 SBVAL(req
->out
.hdr
, SMB2_HDR_SESSION_ID
, 0);
122 memset(req
->out
.hdr
+SMB2_HDR_SIGNATURE
, 0, 16);
124 /* set the length of the fixed body part and +1 if there's a dynamic part also */
125 SSVAL(req
->out
.body
, 0, body_fixed_size
+ (body_dynamic_size
?1:0));
128 * if we have a dynamic part, make sure the first byte
129 * which is always be part of the packet is initialized
131 if (body_dynamic_size
) {
133 SCVAL(req
->out
.dynamic
, 0, 0);
136 talloc_set_destructor(req
, smb2_request_destructor
);
142 initialise a smb2 request for tree operations
144 struct smb2_request
*smb2_request_init_tree(struct smb2_tree
*tree
, uint16_t opcode
,
145 uint16_t body_fixed_size
, bool body_dynamic_present
,
146 uint32_t body_dynamic_size
)
148 struct smb2_request
*req
= smb2_request_init(tree
->session
->transport
, opcode
,
149 body_fixed_size
, body_dynamic_present
,
151 if (req
== NULL
) return NULL
;
153 SBVAL(req
->out
.hdr
, SMB2_HDR_SESSION_ID
, tree
->session
->uid
);
154 SIVAL(req
->out
.hdr
, SMB2_HDR_TID
, tree
->tid
);
155 req
->session
= tree
->session
;
161 /* destroy a request structure and return final status */
162 NTSTATUS
smb2_request_destroy(struct smb2_request
*req
)
166 /* this is the error code we give the application for when a
167 _send() call fails completely */
168 if (!req
) return NT_STATUS_UNSUCCESSFUL
;
170 if (req
->state
== SMB2_REQUEST_ERROR
&&
171 NT_STATUS_IS_OK(req
->status
)) {
172 status
= NT_STATUS_INTERNAL_ERROR
;
174 status
= req
->status
;
182 receive a response to a packet
184 bool smb2_request_receive(struct smb2_request
*req
)
186 /* req can be NULL when a send has failed. This eliminates lots of NULL
187 checks in each module */
188 if (!req
) return false;
190 /* keep receiving packets until this one is replied to */
191 while (req
->state
<= SMB2_REQUEST_RECV
) {
192 if (event_loop_once(req
->transport
->socket
->event
.ctx
) != 0) {
197 return req
->state
== SMB2_REQUEST_DONE
;
200 /* Return true if the last packet was in error */
201 bool smb2_request_is_error(struct smb2_request
*req
)
203 return NT_STATUS_IS_ERR(req
->status
);
206 /* Return true if the last packet was OK */
207 bool smb2_request_is_ok(struct smb2_request
*req
)
209 return NT_STATUS_IS_OK(req
->status
);
213 check if a range in the reply body is out of bounds
215 bool smb2_oob(struct smb2_request_buffer
*buf
, const uint8_t *ptr
, size_t size
)
218 /* zero bytes is never out of range */
221 /* be careful with wraparound! */
222 if ((uintptr_t)ptr
< (uintptr_t)buf
->body
||
223 (uintptr_t)ptr
>= (uintptr_t)buf
->body
+ buf
->body_size
||
224 size
> buf
->body_size
||
225 (uintptr_t)ptr
+ size
> (uintptr_t)buf
->body
+ buf
->body_size
) {
231 size_t smb2_padding_size(uint32_t offset
, size_t n
)
233 if ((offset
& (n
-1)) == 0) return 0;
234 return n
- (offset
& (n
-1));
237 static size_t smb2_padding_fix(struct smb2_request_buffer
*buf
)
239 if (buf
->dynamic
== (buf
->body
+ buf
->body_fixed
)) {
246 grow a SMB2 buffer by the specified amount
248 static NTSTATUS
smb2_grow_buffer(struct smb2_request_buffer
*buf
, size_t increase
)
252 uint32_t newsize
= buf
->size
+ increase
;
254 /* a packet size should be limited a bit */
255 if (newsize
>= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW
;
257 if (newsize
<= buf
->allocated
) return NT_STATUS_OK
;
259 dynamic_ofs
= buf
->dynamic
- buf
->buffer
;
261 buffer_ptr
= talloc_realloc(buf
, buf
->buffer
, uint8_t, newsize
);
262 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr
);
264 buf
->buffer
= buffer_ptr
;
265 buf
->hdr
= buf
->buffer
+ NBT_HDR_SIZE
;
266 buf
->body
= buf
->hdr
+ SMB2_HDR_BODY
;
267 buf
->dynamic
= buf
->buffer
+ dynamic_ofs
;
268 buf
->allocated
= newsize
;
274 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
275 the ptr points to the start of the offset/length pair
277 NTSTATUS
smb2_pull_o16s16_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
280 if (smb2_oob(buf
, ptr
, 4)) {
281 return NT_STATUS_INVALID_PARAMETER
;
286 *blob
= data_blob(NULL
, 0);
289 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
290 return NT_STATUS_INVALID_PARAMETER
;
292 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
293 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
298 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
299 the ofs points to the start of the offset/length pair, and is relative
302 NTSTATUS
smb2_push_o16s16_blob(struct smb2_request_buffer
*buf
,
303 uint16_t ofs
, DATA_BLOB blob
)
307 size_t padding_length
;
309 uint8_t *ptr
= buf
->body
+ofs
;
311 if (buf
->dynamic
== NULL
) {
312 return NT_STATUS_INVALID_PARAMETER
;
315 /* we have only 16 bit for the size */
316 if (blob
.length
> 0xFFFF) {
317 return NT_STATUS_INVALID_PARAMETER
;
320 /* check if there're enough room for ofs and size */
321 if (smb2_oob(buf
, ptr
, 4)) {
322 return NT_STATUS_INVALID_PARAMETER
;
325 if (blob
.data
== NULL
) {
326 if (blob
.length
!= 0) {
327 return NT_STATUS_INTERNAL_ERROR
;
334 offset
= buf
->dynamic
- buf
->hdr
;
335 padding_length
= smb2_padding_size(offset
, 2);
336 offset
+= padding_length
;
337 padding_fix
= smb2_padding_fix(buf
);
339 SSVAL(ptr
, 0, offset
);
340 SSVAL(ptr
, 2, blob
.length
);
342 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
343 NT_STATUS_NOT_OK_RETURN(status
);
345 memset(buf
->dynamic
, 0, padding_length
);
346 buf
->dynamic
+= padding_length
;
348 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
349 buf
->dynamic
+= blob
.length
;
351 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
352 buf
->body_size
+= blob
.length
+ padding_length
;
359 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
360 the ofs points to the start of the offset/length pair, and is relative
363 NTSTATUS
smb2_push_o16s32_blob(struct smb2_request_buffer
*buf
,
364 uint16_t ofs
, DATA_BLOB blob
)
368 size_t padding_length
;
370 uint8_t *ptr
= buf
->body
+ofs
;
372 if (buf
->dynamic
== NULL
) {
373 return NT_STATUS_INVALID_PARAMETER
;
376 /* check if there're enough room for ofs and size */
377 if (smb2_oob(buf
, ptr
, 6)) {
378 return NT_STATUS_INVALID_PARAMETER
;
381 if (blob
.data
== NULL
) {
382 if (blob
.length
!= 0) {
383 return NT_STATUS_INTERNAL_ERROR
;
390 offset
= buf
->dynamic
- buf
->hdr
;
391 padding_length
= smb2_padding_size(offset
, 2);
392 offset
+= padding_length
;
393 padding_fix
= smb2_padding_fix(buf
);
395 SSVAL(ptr
, 0, offset
);
396 SIVAL(ptr
, 2, blob
.length
);
398 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
399 NT_STATUS_NOT_OK_RETURN(status
);
401 memset(buf
->dynamic
, 0, padding_length
);
402 buf
->dynamic
+= padding_length
;
404 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
405 buf
->dynamic
+= blob
.length
;
407 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
408 buf
->body_size
+= blob
.length
+ padding_length
;
415 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
416 the ofs points to the start of the offset/length pair, and is relative
419 NTSTATUS
smb2_push_o32s32_blob(struct smb2_request_buffer
*buf
,
420 uint32_t ofs
, DATA_BLOB blob
)
424 size_t padding_length
;
426 uint8_t *ptr
= buf
->body
+ofs
;
428 if (buf
->dynamic
== NULL
) {
429 return NT_STATUS_INVALID_PARAMETER
;
432 /* check if there're enough room for ofs and size */
433 if (smb2_oob(buf
, ptr
, 8)) {
434 return NT_STATUS_INVALID_PARAMETER
;
437 if (blob
.data
== NULL
) {
438 if (blob
.length
!= 0) {
439 return NT_STATUS_INTERNAL_ERROR
;
446 offset
= buf
->dynamic
- buf
->hdr
;
447 padding_length
= smb2_padding_size(offset
, 8);
448 offset
+= padding_length
;
449 padding_fix
= smb2_padding_fix(buf
);
451 SIVAL(ptr
, 0, offset
);
452 SIVAL(ptr
, 4, blob
.length
);
454 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
455 NT_STATUS_NOT_OK_RETURN(status
);
457 memset(buf
->dynamic
, 0, padding_length
);
458 buf
->dynamic
+= padding_length
;
460 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
461 buf
->dynamic
+= blob
.length
;
463 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
464 buf
->body_size
+= blob
.length
+ padding_length
;
471 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
472 the ofs points to the start of the length/offset pair, and is relative
475 NTSTATUS
smb2_push_s32o32_blob(struct smb2_request_buffer
*buf
,
476 uint32_t ofs
, DATA_BLOB blob
)
480 size_t padding_length
;
482 uint8_t *ptr
= buf
->body
+ofs
;
484 if (buf
->dynamic
== NULL
) {
485 return NT_STATUS_INVALID_PARAMETER
;
488 /* check if there're enough room for ofs and size */
489 if (smb2_oob(buf
, ptr
, 8)) {
490 return NT_STATUS_INVALID_PARAMETER
;
493 if (blob
.data
== NULL
) {
494 if (blob
.length
!= 0) {
495 return NT_STATUS_INTERNAL_ERROR
;
502 offset
= buf
->dynamic
- buf
->hdr
;
503 padding_length
= smb2_padding_size(offset
, 8);
504 offset
+= padding_length
;
505 padding_fix
= smb2_padding_fix(buf
);
507 SIVAL(ptr
, 0, blob
.length
);
508 SIVAL(ptr
, 4, offset
);
510 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
511 NT_STATUS_NOT_OK_RETURN(status
);
513 memset(buf
->dynamic
, 0, padding_length
);
514 buf
->dynamic
+= padding_length
;
516 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
517 buf
->dynamic
+= blob
.length
;
519 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
520 buf
->body_size
+= blob
.length
+ padding_length
;
526 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
527 the ptr points to the start of the offset/length pair
529 NTSTATUS
smb2_pull_o16s32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
534 if (smb2_oob(buf
, ptr
, 6)) {
535 return NT_STATUS_INVALID_PARAMETER
;
540 *blob
= data_blob(NULL
, 0);
543 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
544 return NT_STATUS_INVALID_PARAMETER
;
546 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
547 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
552 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
553 the ptr points to the start of the offset/length pair
555 NTSTATUS
smb2_pull_o32s32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
558 if (smb2_oob(buf
, ptr
, 8)) {
559 return NT_STATUS_INVALID_PARAMETER
;
564 *blob
= data_blob(NULL
, 0);
567 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
568 return NT_STATUS_INVALID_PARAMETER
;
570 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
571 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
576 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
577 the ptr points to the start of the offset/length pair
579 In this varient the uint16_t is padded by an extra 2 bytes, making
580 the size aligned on 4 byte boundary
582 NTSTATUS
smb2_pull_o16As32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
585 if (smb2_oob(buf
, ptr
, 8)) {
586 return NT_STATUS_INVALID_PARAMETER
;
591 *blob
= data_blob(NULL
, 0);
594 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
595 return NT_STATUS_INVALID_PARAMETER
;
597 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
598 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
603 pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
604 the ptr points to the start of the offset/length pair
606 NTSTATUS
smb2_pull_s32o32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
609 if (smb2_oob(buf
, ptr
, 8)) {
610 return NT_STATUS_INVALID_PARAMETER
;
615 *blob
= data_blob(NULL
, 0);
618 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
619 return NT_STATUS_INVALID_PARAMETER
;
621 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
622 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
627 pull a uint32_t length/ uint16_t ofs/blob triple from a data blob
628 the ptr points to the start of the offset/length pair
630 NTSTATUS
smb2_pull_s32o16_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
633 if (smb2_oob(buf
, ptr
, 8)) {
634 return NT_STATUS_INVALID_PARAMETER
;
639 *blob
= data_blob(NULL
, 0);
642 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
643 return NT_STATUS_INVALID_PARAMETER
;
645 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
646 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
651 pull a string in a uint16_t ofs/ uint16_t length/blob format
652 UTF-16 without termination
654 NTSTATUS
smb2_pull_o16s16_string(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
,
655 uint8_t *ptr
, const char **str
)
662 status
= smb2_pull_o16s16_blob(buf
, mem_ctx
, ptr
, &blob
);
663 NT_STATUS_NOT_OK_RETURN(status
);
665 if (blob
.data
== NULL
) {
670 if (blob
.length
== 0) {
672 s
= talloc_strdup(mem_ctx
, "");
673 NT_STATUS_HAVE_NO_MEMORY(s
);
678 size
= convert_string_talloc(mem_ctx
, CH_UTF16
, CH_UNIX
,
679 blob
.data
, blob
.length
, &vstr
, false);
680 data_blob_free(&blob
);
681 (*str
) = (char *)vstr
;
683 return NT_STATUS_ILLEGAL_CHARACTER
;
689 push a string in a uint16_t ofs/ uint16_t length/blob format
690 UTF-16 without termination
692 NTSTATUS
smb2_push_o16s16_string(struct smb2_request_buffer
*buf
,
693 uint16_t ofs
, const char *str
)
700 return smb2_push_o16s16_blob(buf
, ofs
, data_blob(NULL
, 0));
704 blob
.data
= discard_const_p(uint8_t, str
);
706 return smb2_push_o16s16_blob(buf
, ofs
, blob
);
709 size
= convert_string_talloc(buf
->buffer
, CH_UNIX
, CH_UTF16
,
710 str
, strlen(str
), (void **)&blob
.data
, false);
712 return NT_STATUS_ILLEGAL_CHARACTER
;
716 status
= smb2_push_o16s16_blob(buf
, ofs
, blob
);
717 data_blob_free(&blob
);
722 push a file handle into a buffer
724 void smb2_push_handle(uint8_t *data
, struct smb2_handle
*h
)
726 SBVAL(data
, 0, h
->data
[0]);
727 SBVAL(data
, 8, h
->data
[1]);
731 pull a file handle from a buffer
733 void smb2_pull_handle(uint8_t *ptr
, struct smb2_handle
*h
)
735 h
->data
[0] = BVAL(ptr
, 0);
736 h
->data
[1] = BVAL(ptr
, 8);