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 initialise a smb2 request
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
)
52 struct smb2_request
*req
;
54 bool compound
= false;
56 if (body_dynamic_present
) {
57 if (body_dynamic_size
== 0) {
58 body_dynamic_size
= 1;
61 body_dynamic_size
= 0;
64 req
= talloc_zero(transport
, struct smb2_request
);
65 if (req
== NULL
) return NULL
;
67 req
->state
= SMB2_REQUEST_INIT
;
68 req
->transport
= transport
;
70 hdr_offset
= NBT_HDR_SIZE
;
72 req
->out
.size
= hdr_offset
+ SMB2_HDR_BODY
+ body_fixed_size
;
73 req
->out
.allocated
= req
->out
.size
+ body_dynamic_size
;
75 req
->out
.buffer
= talloc_realloc(req
, req
->out
.buffer
,
76 uint8_t, req
->out
.allocated
);
77 if (req
->out
.buffer
== NULL
) {
82 req
->out
.hdr
= req
->out
.buffer
+ hdr_offset
;
83 req
->out
.body
= req
->out
.hdr
+ SMB2_HDR_BODY
;
84 req
->out
.body_fixed
= body_fixed_size
;
85 req
->out
.body_size
= body_fixed_size
;
86 req
->out
.dynamic
= (body_dynamic_size
? req
->out
.body
+ body_fixed_size
: NULL
);
88 SIVAL(req
->out
.hdr
, 0, SMB2_MAGIC
);
89 SSVAL(req
->out
.hdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
90 SSVAL(req
->out
.hdr
, SMB2_HDR_CREDIT_CHARGE
, 0);
91 SIVAL(req
->out
.hdr
, SMB2_HDR_STATUS
, 0);
92 SSVAL(req
->out
.hdr
, SMB2_HDR_OPCODE
, opcode
);
93 SSVAL(req
->out
.hdr
, SMB2_HDR_CREDIT
, 0);
94 SIVAL(req
->out
.hdr
, SMB2_HDR_FLAGS
, 0);
95 SIVAL(req
->out
.hdr
, SMB2_HDR_NEXT_COMMAND
, 0);
96 SBVAL(req
->out
.hdr
, SMB2_HDR_MESSAGE_ID
, 0);
97 SIVAL(req
->out
.hdr
, SMB2_HDR_PID
, 0);
98 SIVAL(req
->out
.hdr
, SMB2_HDR_TID
, 0);
99 SBVAL(req
->out
.hdr
, SMB2_HDR_SESSION_ID
, 0);
100 memset(req
->out
.hdr
+SMB2_HDR_SIGNATURE
, 0, 16);
102 /* set the length of the fixed body part and +1 if there's a dynamic part also */
103 SSVAL(req
->out
.body
, 0, body_fixed_size
+ (body_dynamic_size
?1:0));
106 * if we have a dynamic part, make sure the first byte
107 * which is always be part of the packet is initialized
109 if (body_dynamic_size
&& !compound
) {
111 SCVAL(req
->out
.dynamic
, 0, 0);
118 initialise a smb2 request for tree operations
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
)
124 struct smb2_request
*req
= smb2_request_init(tree
->session
->transport
, opcode
,
125 body_fixed_size
, body_dynamic_present
,
127 if (req
== NULL
) return NULL
;
129 SIVAL(req
->out
.hdr
, SMB2_HDR_PID
, tree
->session
->pid
);
130 SIVAL(req
->out
.hdr
, SMB2_HDR_TID
, tree
->tid
);
131 req
->session
= tree
->session
;
137 /* destroy a request structure and return final status */
138 NTSTATUS
smb2_request_destroy(struct smb2_request
*req
)
142 /* this is the error code we give the application for when a
143 _send() call fails completely */
144 if (!req
) return NT_STATUS_UNSUCCESSFUL
;
146 if (req
->state
== SMB2_REQUEST_ERROR
&&
147 NT_STATUS_IS_OK(req
->status
)) {
148 status
= NT_STATUS_INTERNAL_ERROR
;
150 status
= req
->status
;
158 receive a response to a packet
160 bool smb2_request_receive(struct smb2_request
*req
)
162 /* req can be NULL when a send has failed. This eliminates lots of NULL
163 checks in each module */
164 if (!req
) return false;
166 /* keep receiving packets until this one is replied to */
167 while (req
->state
<= SMB2_REQUEST_RECV
) {
168 if (tevent_loop_once(req
->transport
->ev
) != 0) {
173 return req
->state
== SMB2_REQUEST_DONE
;
176 /* Return true if the last packet was in error */
177 bool smb2_request_is_error(struct smb2_request
*req
)
179 return NT_STATUS_IS_ERR(req
->status
);
182 /* Return true if the last packet was OK */
183 bool smb2_request_is_ok(struct smb2_request
*req
)
185 return NT_STATUS_IS_OK(req
->status
);
189 check if a range in the reply body is out of bounds
191 bool smb2_oob(struct smb2_request_buffer
*buf
, const uint8_t *ptr
, size_t size
)
194 /* zero bytes is never out of range */
197 /* be careful with wraparound! */
198 if ((uintptr_t)ptr
< (uintptr_t)buf
->body
||
199 (uintptr_t)ptr
>= (uintptr_t)buf
->body
+ buf
->body_size
||
200 size
> buf
->body_size
||
201 (uintptr_t)ptr
+ size
> (uintptr_t)buf
->body
+ buf
->body_size
) {
207 size_t smb2_padding_size(uint32_t offset
, size_t n
)
209 if ((offset
& (n
-1)) == 0) return 0;
210 return n
- (offset
& (n
-1));
213 static size_t smb2_padding_fix(struct smb2_request_buffer
*buf
)
215 if (buf
->dynamic
== (buf
->body
+ buf
->body_fixed
)) {
216 if (buf
->dynamic
!= (buf
->buffer
+ buf
->size
)) {
224 grow a SMB2 buffer by the specified amount
226 NTSTATUS
smb2_grow_buffer(struct smb2_request_buffer
*buf
, size_t increase
)
231 uint32_t newsize
= buf
->size
+ increase
;
233 /* a packet size should be limited a bit */
234 if (newsize
>= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW
;
236 if (newsize
<= buf
->allocated
) return NT_STATUS_OK
;
238 hdr_ofs
= buf
->hdr
- buf
->buffer
;
239 dynamic_ofs
= buf
->dynamic
- buf
->buffer
;
241 buffer_ptr
= talloc_realloc(buf
, buf
->buffer
, uint8_t, newsize
);
242 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr
);
244 buf
->buffer
= buffer_ptr
;
245 buf
->hdr
= buf
->buffer
+ hdr_ofs
;
246 buf
->body
= buf
->hdr
+ SMB2_HDR_BODY
;
247 buf
->dynamic
= buf
->buffer
+ dynamic_ofs
;
248 buf
->allocated
= newsize
;
254 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
255 the ptr points to the start of the offset/length pair
257 NTSTATUS
smb2_pull_o16s16_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
260 if (smb2_oob(buf
, ptr
, 4)) {
261 return NT_STATUS_INVALID_PARAMETER
;
266 *blob
= data_blob(NULL
, 0);
269 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
270 return NT_STATUS_INVALID_PARAMETER
;
272 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
273 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
278 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
279 the ofs points to the start of the offset/length pair, and is relative
282 NTSTATUS
smb2_push_o16s16_blob(struct smb2_request_buffer
*buf
,
283 uint16_t ofs
, DATA_BLOB blob
)
287 size_t padding_length
;
289 uint8_t *ptr
= buf
->body
+ofs
;
291 if (buf
->dynamic
== NULL
) {
292 return NT_STATUS_INVALID_PARAMETER
;
295 /* we have only 16 bit for the size */
296 if (blob
.length
> 0xFFFF) {
297 return NT_STATUS_INVALID_PARAMETER
;
300 /* check if there're enough room for ofs and size */
301 if (smb2_oob(buf
, ptr
, 4)) {
302 return NT_STATUS_INVALID_PARAMETER
;
305 if (blob
.data
== NULL
) {
306 if (blob
.length
!= 0) {
307 return NT_STATUS_INTERNAL_ERROR
;
314 offset
= buf
->dynamic
- buf
->hdr
;
315 padding_length
= smb2_padding_size(offset
, 2);
316 offset
+= padding_length
;
317 padding_fix
= smb2_padding_fix(buf
);
319 SSVAL(ptr
, 0, offset
);
320 SSVAL(ptr
, 2, blob
.length
);
322 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
323 NT_STATUS_NOT_OK_RETURN(status
);
325 memset(buf
->dynamic
, 0, padding_length
);
326 buf
->dynamic
+= padding_length
;
328 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
329 buf
->dynamic
+= blob
.length
;
331 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
332 buf
->body_size
+= blob
.length
+ padding_length
;
339 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
340 the ofs points to the start of the offset/length pair, and is relative
343 NTSTATUS
smb2_push_o16s32_blob(struct smb2_request_buffer
*buf
,
344 uint16_t ofs
, DATA_BLOB blob
)
348 size_t padding_length
;
350 uint8_t *ptr
= buf
->body
+ofs
;
352 if (buf
->dynamic
== NULL
) {
353 return NT_STATUS_INVALID_PARAMETER
;
356 /* check if there're enough room for ofs and size */
357 if (smb2_oob(buf
, ptr
, 6)) {
358 return NT_STATUS_INVALID_PARAMETER
;
361 if (blob
.data
== NULL
) {
362 if (blob
.length
!= 0) {
363 return NT_STATUS_INTERNAL_ERROR
;
370 offset
= buf
->dynamic
- buf
->hdr
;
371 padding_length
= smb2_padding_size(offset
, 2);
372 offset
+= padding_length
;
373 padding_fix
= smb2_padding_fix(buf
);
375 SSVAL(ptr
, 0, offset
);
376 SIVAL(ptr
, 2, blob
.length
);
378 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
379 NT_STATUS_NOT_OK_RETURN(status
);
381 memset(buf
->dynamic
, 0, padding_length
);
382 buf
->dynamic
+= padding_length
;
384 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
385 buf
->dynamic
+= blob
.length
;
387 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
388 buf
->body_size
+= blob
.length
+ padding_length
;
395 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
396 the ofs points to the start of the offset/length pair, and is relative
399 NTSTATUS
smb2_push_o32s32_blob(struct smb2_request_buffer
*buf
,
400 uint32_t ofs
, DATA_BLOB blob
)
404 size_t padding_length
;
406 uint8_t *ptr
= buf
->body
+ofs
;
408 if (buf
->dynamic
== NULL
) {
409 return NT_STATUS_INVALID_PARAMETER
;
412 /* check if there're enough room for ofs and size */
413 if (smb2_oob(buf
, ptr
, 8)) {
414 return NT_STATUS_INVALID_PARAMETER
;
417 if (blob
.data
== NULL
) {
418 if (blob
.length
!= 0) {
419 return NT_STATUS_INTERNAL_ERROR
;
426 offset
= buf
->dynamic
- buf
->hdr
;
427 padding_length
= smb2_padding_size(offset
, 8);
428 offset
+= padding_length
;
429 padding_fix
= smb2_padding_fix(buf
);
431 SIVAL(ptr
, 0, offset
);
432 SIVAL(ptr
, 4, blob
.length
);
434 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
435 NT_STATUS_NOT_OK_RETURN(status
);
437 memset(buf
->dynamic
, 0, padding_length
);
438 buf
->dynamic
+= padding_length
;
440 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
441 buf
->dynamic
+= blob
.length
;
443 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
444 buf
->body_size
+= blob
.length
+ padding_length
;
451 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
452 the ofs points to the start of the length/offset pair, and is relative
455 NTSTATUS
smb2_push_s32o32_blob(struct smb2_request_buffer
*buf
,
456 uint32_t ofs
, DATA_BLOB blob
)
460 size_t padding_length
;
462 uint8_t *ptr
= buf
->body
+ofs
;
464 if (buf
->dynamic
== NULL
) {
465 return NT_STATUS_INVALID_PARAMETER
;
468 /* check if there're enough room for ofs and size */
469 if (smb2_oob(buf
, ptr
, 8)) {
470 return NT_STATUS_INVALID_PARAMETER
;
473 if (blob
.data
== NULL
) {
474 if (blob
.length
!= 0) {
475 return NT_STATUS_INTERNAL_ERROR
;
482 offset
= buf
->dynamic
- buf
->hdr
;
483 padding_length
= smb2_padding_size(offset
, 8);
484 offset
+= padding_length
;
485 padding_fix
= smb2_padding_fix(buf
);
487 SIVAL(ptr
, 0, blob
.length
);
488 SIVAL(ptr
, 4, offset
);
490 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
491 NT_STATUS_NOT_OK_RETURN(status
);
493 memset(buf
->dynamic
, 0, padding_length
);
494 buf
->dynamic
+= padding_length
;
496 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
497 buf
->dynamic
+= blob
.length
;
499 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
500 buf
->body_size
+= blob
.length
+ padding_length
;
506 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
507 the ptr points to the start of the offset/length pair
509 NTSTATUS
smb2_pull_o16s32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
514 if (smb2_oob(buf
, ptr
, 6)) {
515 return NT_STATUS_INVALID_PARAMETER
;
520 *blob
= data_blob(NULL
, 0);
523 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
524 return NT_STATUS_INVALID_PARAMETER
;
526 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
527 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
532 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
533 the ptr points to the start of the offset/length pair
535 NTSTATUS
smb2_pull_o32s32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
538 if (smb2_oob(buf
, ptr
, 8)) {
539 return NT_STATUS_INVALID_PARAMETER
;
544 *blob
= data_blob(NULL
, 0);
547 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
548 return NT_STATUS_INVALID_PARAMETER
;
550 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
551 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
556 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
557 the ptr points to the start of the offset/length pair
559 In this varient the uint16_t is padded by an extra 2 bytes, making
560 the size aligned on 4 byte boundary
562 NTSTATUS
smb2_pull_o16As32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
565 if (smb2_oob(buf
, ptr
, 8)) {
566 return NT_STATUS_INVALID_PARAMETER
;
571 *blob
= data_blob(NULL
, 0);
574 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
575 return NT_STATUS_INVALID_PARAMETER
;
577 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
578 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
583 pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
584 the ptr points to the start of the offset/length pair
586 NTSTATUS
smb2_pull_s32o32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
589 if (smb2_oob(buf
, ptr
, 8)) {
590 return NT_STATUS_INVALID_PARAMETER
;
595 *blob
= data_blob(NULL
, 0);
598 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
599 return NT_STATUS_INVALID_PARAMETER
;
601 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
602 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
607 pull a uint32_t length/ uint16_t ofs/blob triple from a data blob
608 the ptr points to the start of the offset/length pair
610 NTSTATUS
smb2_pull_s32o16_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
613 if (smb2_oob(buf
, ptr
, 8)) {
614 return NT_STATUS_INVALID_PARAMETER
;
619 *blob
= data_blob(NULL
, 0);
622 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
623 return NT_STATUS_INVALID_PARAMETER
;
625 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
626 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
631 pull a string in a uint16_t ofs/ uint16_t length/blob format
632 UTF-16 without termination
634 NTSTATUS
smb2_pull_o16s16_string(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
,
635 uint8_t *ptr
, const char **str
)
640 size_t converted_size
= 0;
643 status
= smb2_pull_o16s16_blob(buf
, mem_ctx
, ptr
, &blob
);
644 NT_STATUS_NOT_OK_RETURN(status
);
646 if (blob
.data
== NULL
) {
651 if (blob
.length
== 0) {
653 s
= talloc_strdup(mem_ctx
, "");
654 NT_STATUS_HAVE_NO_MEMORY(s
);
659 ret
= convert_string_talloc(mem_ctx
, CH_UTF16
, CH_UNIX
,
660 blob
.data
, blob
.length
, &vstr
, &converted_size
);
661 data_blob_free(&blob
);
662 (*str
) = (char *)vstr
;
664 return NT_STATUS_ILLEGAL_CHARACTER
;
670 push a string in a uint16_t ofs/ uint16_t length/blob format
671 UTF-16 without termination
673 NTSTATUS
smb2_push_o16s16_string(struct smb2_request_buffer
*buf
,
674 uint16_t ofs
, const char *str
)
682 return smb2_push_o16s16_blob(buf
, ofs
, data_blob(NULL
, 0));
686 blob
.data
= discard_const_p(uint8_t, str
);
688 return smb2_push_o16s16_blob(buf
, ofs
, blob
);
691 ret
= convert_string_talloc(buf
->buffer
, CH_UNIX
, CH_UTF16
,
692 str
, strlen(str
), &ptr
, &blob
.length
);
694 return NT_STATUS_ILLEGAL_CHARACTER
;
696 blob
.data
= (uint8_t *)ptr
;
698 status
= smb2_push_o16s16_blob(buf
, ofs
, blob
);
699 data_blob_free(&blob
);
704 push a file handle into a buffer
706 void smb2_push_handle(uint8_t *data
, struct smb2_handle
*h
)
708 SBVAL(data
, 0, h
->data
[0]);
709 SBVAL(data
, 8, h
->data
[1]);
713 pull a file handle from a buffer
715 void smb2_pull_handle(uint8_t *ptr
, struct smb2_handle
*h
)
717 h
->data
[0] = BVAL(ptr
, 0);
718 h
->data
[1] = BVAL(ptr
, 8);