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
;
68 bool compound
= false;
70 if (body_dynamic_present
) {
71 if (body_dynamic_size
== 0) {
72 body_dynamic_size
= 1;
75 body_dynamic_size
= 0;
78 req
= talloc(transport
, struct smb2_request
);
79 if (req
== NULL
) return NULL
;
81 seqnum
= transport
->seqnum
;
82 if (transport
->credits
.charge
> 0) {
83 transport
->seqnum
+= transport
->credits
.charge
;
85 transport
->seqnum
+= 1;
88 req
->state
= SMB2_REQUEST_INIT
;
89 req
->transport
= transport
;
93 req
->status
= NT_STATUS_OK
;
95 req
->next
= req
->prev
= NULL
;
97 ZERO_STRUCT(req
->cancel
);
100 if (transport
->compound
.missing
> 0) {
102 transport
->compound
.missing
-= 1;
103 req
->out
= transport
->compound
.buffer
;
104 ZERO_STRUCT(transport
->compound
.buffer
);
105 if (transport
->compound
.related
) {
106 flags
|= SMB2_HDR_FLAG_CHAINED
;
109 ZERO_STRUCT(req
->out
);
112 if (req
->out
.size
> 0) {
113 hdr_offset
= req
->out
.size
;
115 hdr_offset
= NBT_HDR_SIZE
;
118 req
->out
.size
= hdr_offset
+ SMB2_HDR_BODY
+ body_fixed_size
;
119 req
->out
.allocated
= req
->out
.size
+ body_dynamic_size
;
121 req
->out
.buffer
= talloc_realloc(req
, req
->out
.buffer
,
122 uint8_t, req
->out
.allocated
);
123 if (req
->out
.buffer
== NULL
) {
128 req
->out
.hdr
= req
->out
.buffer
+ hdr_offset
;
129 req
->out
.body
= req
->out
.hdr
+ SMB2_HDR_BODY
;
130 req
->out
.body_fixed
= body_fixed_size
;
131 req
->out
.body_size
= body_fixed_size
;
132 req
->out
.dynamic
= (body_dynamic_size
? req
->out
.body
+ body_fixed_size
: NULL
);
134 SIVAL(req
->out
.hdr
, 0, SMB2_MAGIC
);
135 SSVAL(req
->out
.hdr
, SMB2_HDR_LENGTH
, SMB2_HDR_BODY
);
136 SSVAL(req
->out
.hdr
, SMB2_HDR_EPOCH
, transport
->credits
.charge
);
137 SIVAL(req
->out
.hdr
, SMB2_HDR_STATUS
, 0);
138 SSVAL(req
->out
.hdr
, SMB2_HDR_OPCODE
, opcode
);
139 SSVAL(req
->out
.hdr
, SMB2_HDR_CREDIT
, transport
->credits
.ask_num
);
140 SIVAL(req
->out
.hdr
, SMB2_HDR_FLAGS
, flags
);
141 SIVAL(req
->out
.hdr
, SMB2_HDR_NEXT_COMMAND
, 0);
142 SBVAL(req
->out
.hdr
, SMB2_HDR_MESSAGE_ID
, req
->seqnum
);
143 SIVAL(req
->out
.hdr
, SMB2_HDR_PID
, 0);
144 SIVAL(req
->out
.hdr
, SMB2_HDR_TID
, 0);
145 SBVAL(req
->out
.hdr
, SMB2_HDR_SESSION_ID
, 0);
146 memset(req
->out
.hdr
+SMB2_HDR_SIGNATURE
, 0, 16);
148 /* set the length of the fixed body part and +1 if there's a dynamic part also */
149 SSVAL(req
->out
.body
, 0, body_fixed_size
+ (body_dynamic_size
?1:0));
152 * if we have a dynamic part, make sure the first byte
153 * which is always be part of the packet is initialized
155 if (body_dynamic_size
&& !compound
) {
157 SCVAL(req
->out
.dynamic
, 0, 0);
160 talloc_set_destructor(req
, smb2_request_destructor
);
166 initialise a smb2 request for tree operations
168 struct smb2_request
*smb2_request_init_tree(struct smb2_tree
*tree
, uint16_t opcode
,
169 uint16_t body_fixed_size
, bool body_dynamic_present
,
170 uint32_t body_dynamic_size
)
172 struct smb2_request
*req
= smb2_request_init(tree
->session
->transport
, opcode
,
173 body_fixed_size
, body_dynamic_present
,
175 if (req
== NULL
) return NULL
;
177 SBVAL(req
->out
.hdr
, SMB2_HDR_SESSION_ID
, tree
->session
->uid
);
178 SIVAL(req
->out
.hdr
, SMB2_HDR_TID
, tree
->tid
);
179 req
->session
= tree
->session
;
185 /* destroy a request structure and return final status */
186 NTSTATUS
smb2_request_destroy(struct smb2_request
*req
)
190 /* this is the error code we give the application for when a
191 _send() call fails completely */
192 if (!req
) return NT_STATUS_UNSUCCESSFUL
;
194 if (req
->state
== SMB2_REQUEST_ERROR
&&
195 NT_STATUS_IS_OK(req
->status
)) {
196 status
= NT_STATUS_INTERNAL_ERROR
;
198 status
= req
->status
;
206 receive a response to a packet
208 bool smb2_request_receive(struct smb2_request
*req
)
210 /* req can be NULL when a send has failed. This eliminates lots of NULL
211 checks in each module */
212 if (!req
) return false;
214 /* keep receiving packets until this one is replied to */
215 while (req
->state
<= SMB2_REQUEST_RECV
) {
216 if (event_loop_once(req
->transport
->socket
->event
.ctx
) != 0) {
221 return req
->state
== SMB2_REQUEST_DONE
;
224 /* Return true if the last packet was in error */
225 bool smb2_request_is_error(struct smb2_request
*req
)
227 return NT_STATUS_IS_ERR(req
->status
);
230 /* Return true if the last packet was OK */
231 bool smb2_request_is_ok(struct smb2_request
*req
)
233 return NT_STATUS_IS_OK(req
->status
);
237 check if a range in the reply body is out of bounds
239 bool smb2_oob(struct smb2_request_buffer
*buf
, const uint8_t *ptr
, size_t size
)
242 /* zero bytes is never out of range */
245 /* be careful with wraparound! */
246 if ((uintptr_t)ptr
< (uintptr_t)buf
->body
||
247 (uintptr_t)ptr
>= (uintptr_t)buf
->body
+ buf
->body_size
||
248 size
> buf
->body_size
||
249 (uintptr_t)ptr
+ size
> (uintptr_t)buf
->body
+ buf
->body_size
) {
255 size_t smb2_padding_size(uint32_t offset
, size_t n
)
257 if ((offset
& (n
-1)) == 0) return 0;
258 return n
- (offset
& (n
-1));
261 static size_t smb2_padding_fix(struct smb2_request_buffer
*buf
)
263 if (buf
->dynamic
== (buf
->body
+ buf
->body_fixed
)) {
264 if (buf
->dynamic
!= (buf
->buffer
+ buf
->size
)) {
272 grow a SMB2 buffer by the specified amount
274 NTSTATUS
smb2_grow_buffer(struct smb2_request_buffer
*buf
, size_t increase
)
279 uint32_t newsize
= buf
->size
+ increase
;
281 /* a packet size should be limited a bit */
282 if (newsize
>= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW
;
284 if (newsize
<= buf
->allocated
) return NT_STATUS_OK
;
286 hdr_ofs
= buf
->hdr
- buf
->buffer
;
287 dynamic_ofs
= buf
->dynamic
- buf
->buffer
;
289 buffer_ptr
= talloc_realloc(buf
, buf
->buffer
, uint8_t, newsize
);
290 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr
);
292 buf
->buffer
= buffer_ptr
;
293 buf
->hdr
= buf
->buffer
+ hdr_ofs
;
294 buf
->body
= buf
->hdr
+ SMB2_HDR_BODY
;
295 buf
->dynamic
= buf
->buffer
+ dynamic_ofs
;
296 buf
->allocated
= newsize
;
302 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
303 the ptr points to the start of the offset/length pair
305 NTSTATUS
smb2_pull_o16s16_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
308 if (smb2_oob(buf
, ptr
, 4)) {
309 return NT_STATUS_INVALID_PARAMETER
;
314 *blob
= data_blob(NULL
, 0);
317 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
318 return NT_STATUS_INVALID_PARAMETER
;
320 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
321 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
326 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
327 the ofs points to the start of the offset/length pair, and is relative
330 NTSTATUS
smb2_push_o16s16_blob(struct smb2_request_buffer
*buf
,
331 uint16_t ofs
, DATA_BLOB blob
)
335 size_t padding_length
;
337 uint8_t *ptr
= buf
->body
+ofs
;
339 if (buf
->dynamic
== NULL
) {
340 return NT_STATUS_INVALID_PARAMETER
;
343 /* we have only 16 bit for the size */
344 if (blob
.length
> 0xFFFF) {
345 return NT_STATUS_INVALID_PARAMETER
;
348 /* check if there're enough room for ofs and size */
349 if (smb2_oob(buf
, ptr
, 4)) {
350 return NT_STATUS_INVALID_PARAMETER
;
353 if (blob
.data
== NULL
) {
354 if (blob
.length
!= 0) {
355 return NT_STATUS_INTERNAL_ERROR
;
362 offset
= buf
->dynamic
- buf
->hdr
;
363 padding_length
= smb2_padding_size(offset
, 2);
364 offset
+= padding_length
;
365 padding_fix
= smb2_padding_fix(buf
);
367 SSVAL(ptr
, 0, offset
);
368 SSVAL(ptr
, 2, blob
.length
);
370 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
371 NT_STATUS_NOT_OK_RETURN(status
);
373 memset(buf
->dynamic
, 0, padding_length
);
374 buf
->dynamic
+= padding_length
;
376 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
377 buf
->dynamic
+= blob
.length
;
379 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
380 buf
->body_size
+= blob
.length
+ padding_length
;
387 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
388 the ofs points to the start of the offset/length pair, and is relative
391 NTSTATUS
smb2_push_o16s32_blob(struct smb2_request_buffer
*buf
,
392 uint16_t ofs
, DATA_BLOB blob
)
396 size_t padding_length
;
398 uint8_t *ptr
= buf
->body
+ofs
;
400 if (buf
->dynamic
== NULL
) {
401 return NT_STATUS_INVALID_PARAMETER
;
404 /* check if there're enough room for ofs and size */
405 if (smb2_oob(buf
, ptr
, 6)) {
406 return NT_STATUS_INVALID_PARAMETER
;
409 if (blob
.data
== NULL
) {
410 if (blob
.length
!= 0) {
411 return NT_STATUS_INTERNAL_ERROR
;
418 offset
= buf
->dynamic
- buf
->hdr
;
419 padding_length
= smb2_padding_size(offset
, 2);
420 offset
+= padding_length
;
421 padding_fix
= smb2_padding_fix(buf
);
423 SSVAL(ptr
, 0, offset
);
424 SIVAL(ptr
, 2, blob
.length
);
426 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
427 NT_STATUS_NOT_OK_RETURN(status
);
429 memset(buf
->dynamic
, 0, padding_length
);
430 buf
->dynamic
+= padding_length
;
432 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
433 buf
->dynamic
+= blob
.length
;
435 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
436 buf
->body_size
+= blob
.length
+ padding_length
;
443 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
444 the ofs points to the start of the offset/length pair, and is relative
447 NTSTATUS
smb2_push_o32s32_blob(struct smb2_request_buffer
*buf
,
448 uint32_t ofs
, DATA_BLOB blob
)
452 size_t padding_length
;
454 uint8_t *ptr
= buf
->body
+ofs
;
456 if (buf
->dynamic
== NULL
) {
457 return NT_STATUS_INVALID_PARAMETER
;
460 /* check if there're enough room for ofs and size */
461 if (smb2_oob(buf
, ptr
, 8)) {
462 return NT_STATUS_INVALID_PARAMETER
;
465 if (blob
.data
== NULL
) {
466 if (blob
.length
!= 0) {
467 return NT_STATUS_INTERNAL_ERROR
;
474 offset
= buf
->dynamic
- buf
->hdr
;
475 padding_length
= smb2_padding_size(offset
, 8);
476 offset
+= padding_length
;
477 padding_fix
= smb2_padding_fix(buf
);
479 SIVAL(ptr
, 0, offset
);
480 SIVAL(ptr
, 4, blob
.length
);
482 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
483 NT_STATUS_NOT_OK_RETURN(status
);
485 memset(buf
->dynamic
, 0, padding_length
);
486 buf
->dynamic
+= padding_length
;
488 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
489 buf
->dynamic
+= blob
.length
;
491 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
492 buf
->body_size
+= blob
.length
+ padding_length
;
499 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
500 the ofs points to the start of the length/offset pair, and is relative
503 NTSTATUS
smb2_push_s32o32_blob(struct smb2_request_buffer
*buf
,
504 uint32_t ofs
, DATA_BLOB blob
)
508 size_t padding_length
;
510 uint8_t *ptr
= buf
->body
+ofs
;
512 if (buf
->dynamic
== NULL
) {
513 return NT_STATUS_INVALID_PARAMETER
;
516 /* check if there're enough room for ofs and size */
517 if (smb2_oob(buf
, ptr
, 8)) {
518 return NT_STATUS_INVALID_PARAMETER
;
521 if (blob
.data
== NULL
) {
522 if (blob
.length
!= 0) {
523 return NT_STATUS_INTERNAL_ERROR
;
530 offset
= buf
->dynamic
- buf
->hdr
;
531 padding_length
= smb2_padding_size(offset
, 8);
532 offset
+= padding_length
;
533 padding_fix
= smb2_padding_fix(buf
);
535 SIVAL(ptr
, 0, blob
.length
);
536 SIVAL(ptr
, 4, offset
);
538 status
= smb2_grow_buffer(buf
, blob
.length
+ padding_length
- padding_fix
);
539 NT_STATUS_NOT_OK_RETURN(status
);
541 memset(buf
->dynamic
, 0, padding_length
);
542 buf
->dynamic
+= padding_length
;
544 memcpy(buf
->dynamic
, blob
.data
, blob
.length
);
545 buf
->dynamic
+= blob
.length
;
547 buf
->size
+= blob
.length
+ padding_length
- padding_fix
;
548 buf
->body_size
+= blob
.length
+ padding_length
;
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
557 NTSTATUS
smb2_pull_o16s32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
562 if (smb2_oob(buf
, ptr
, 6)) {
563 return NT_STATUS_INVALID_PARAMETER
;
568 *blob
= data_blob(NULL
, 0);
571 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
572 return NT_STATUS_INVALID_PARAMETER
;
574 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
575 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
580 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
581 the ptr points to the start of the offset/length pair
583 NTSTATUS
smb2_pull_o32s32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
586 if (smb2_oob(buf
, ptr
, 8)) {
587 return NT_STATUS_INVALID_PARAMETER
;
592 *blob
= data_blob(NULL
, 0);
595 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
596 return NT_STATUS_INVALID_PARAMETER
;
598 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
599 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
604 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
605 the ptr points to the start of the offset/length pair
607 In this varient the uint16_t is padded by an extra 2 bytes, making
608 the size aligned on 4 byte boundary
610 NTSTATUS
smb2_pull_o16As32_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 uint32_t length/ uint32_t ofs/blob triple from a data blob
632 the ptr points to the start of the offset/length pair
634 NTSTATUS
smb2_pull_s32o32_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
637 if (smb2_oob(buf
, ptr
, 8)) {
638 return NT_STATUS_INVALID_PARAMETER
;
643 *blob
= data_blob(NULL
, 0);
646 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
647 return NT_STATUS_INVALID_PARAMETER
;
649 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
650 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
655 pull a uint32_t length/ uint16_t ofs/blob triple from a data blob
656 the ptr points to the start of the offset/length pair
658 NTSTATUS
smb2_pull_s32o16_blob(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
, uint8_t *ptr
, DATA_BLOB
*blob
)
661 if (smb2_oob(buf
, ptr
, 8)) {
662 return NT_STATUS_INVALID_PARAMETER
;
667 *blob
= data_blob(NULL
, 0);
670 if (smb2_oob(buf
, buf
->hdr
+ ofs
, size
)) {
671 return NT_STATUS_INVALID_PARAMETER
;
673 *blob
= data_blob_talloc(mem_ctx
, buf
->hdr
+ ofs
, size
);
674 NT_STATUS_HAVE_NO_MEMORY(blob
->data
);
679 pull a string in a uint16_t ofs/ uint16_t length/blob format
680 UTF-16 without termination
682 NTSTATUS
smb2_pull_o16s16_string(struct smb2_request_buffer
*buf
, TALLOC_CTX
*mem_ctx
,
683 uint8_t *ptr
, const char **str
)
690 status
= smb2_pull_o16s16_blob(buf
, mem_ctx
, ptr
, &blob
);
691 NT_STATUS_NOT_OK_RETURN(status
);
693 if (blob
.data
== NULL
) {
698 if (blob
.length
== 0) {
700 s
= talloc_strdup(mem_ctx
, "");
701 NT_STATUS_HAVE_NO_MEMORY(s
);
706 ret
= convert_string_talloc(mem_ctx
, CH_UTF16
, CH_UNIX
,
707 blob
.data
, blob
.length
, &vstr
, NULL
, false);
708 data_blob_free(&blob
);
709 (*str
) = (char *)vstr
;
711 return NT_STATUS_ILLEGAL_CHARACTER
;
717 push a string in a uint16_t ofs/ uint16_t length/blob format
718 UTF-16 without termination
720 NTSTATUS
smb2_push_o16s16_string(struct smb2_request_buffer
*buf
,
721 uint16_t ofs
, const char *str
)
728 return smb2_push_o16s16_blob(buf
, ofs
, data_blob(NULL
, 0));
732 blob
.data
= discard_const_p(uint8_t, str
);
734 return smb2_push_o16s16_blob(buf
, ofs
, blob
);
737 ret
= convert_string_talloc(buf
->buffer
, CH_UNIX
, CH_UTF16
,
738 str
, strlen(str
), (void **)&blob
.data
, &blob
.length
,
741 return NT_STATUS_ILLEGAL_CHARACTER
;
744 status
= smb2_push_o16s16_blob(buf
, ofs
, blob
);
745 data_blob_free(&blob
);
750 push a file handle into a buffer
752 void smb2_push_handle(uint8_t *data
, struct smb2_handle
*h
)
754 SBVAL(data
, 0, h
->data
[0]);
755 SBVAL(data
, 8, h
->data
[1]);
759 pull a file handle from a buffer
761 void smb2_pull_handle(uint8_t *ptr
, struct smb2_handle
*h
)
763 h
->data
[0] = BVAL(ptr
, 0);
764 h
->data
[1] = BVAL(ptr
, 8);