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"
29 #include "param/param.h"
31 /* fill in the bufinfo */
32 void smb2_setup_bufinfo(struct smb2_request *req)
34 req->in.bufinfo.mem_ctx = req;
35 req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
36 req->in.bufinfo.align_base = req->in.buffer;
37 if (req->in.dynamic) {
38 req->in.bufinfo.data = req->in.dynamic;
39 req->in.bufinfo.data_size = req->in.body_size - req->in.body_fixed;
41 req->in.bufinfo.data = NULL;
42 req->in.bufinfo.data_size = 0;
47 /* destroy a request structure */
48 static int smb2_request_destructor(struct smb2_request *req)
51 /* remove it from the list of pending requests (a null op if
52 its not in the list) */
53 DLIST_REMOVE(req->transport->pending_recv, req);
59 initialise a smb2 request
61 struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
62 uint16_t body_fixed_size, bool body_dynamic_present,
63 uint32_t body_dynamic_size)
65 struct smb2_request *req;
68 if (body_dynamic_present) {
69 if (body_dynamic_size == 0) {
70 body_dynamic_size = 1;
73 body_dynamic_size = 0;
76 req = talloc(transport, struct smb2_request);
77 if (req == NULL) return NULL;
79 seqnum = transport->seqnum++;
80 if (seqnum == UINT64_MAX) {
81 seqnum = transport->seqnum++;
84 req->state = SMB2_REQUEST_INIT;
85 req->transport = transport;
89 req->status = NT_STATUS_OK;
91 req->next = req->prev = NULL;
93 ZERO_STRUCT(req->cancel);
96 req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
98 req->out.allocated = req->out.size + body_dynamic_size;
99 req->out.buffer = talloc_array(req, uint8_t, req->out.allocated);
100 if (req->out.buffer == NULL) {
105 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
106 req->out.body = req->out.hdr + SMB2_HDR_BODY;
107 req->out.body_fixed= body_fixed_size;
108 req->out.body_size = body_fixed_size;
109 req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
111 SIVAL(req->out.hdr, 0, SMB2_MAGIC);
112 SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
113 SSVAL(req->out.hdr, SMB2_HDR_EPOCH, 0);
114 SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
115 SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
116 SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0);
117 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
118 SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0);
119 SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, req->seqnum);
120 SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
121 SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
122 SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, 0);
123 memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16);
125 /* set the length of the fixed body part and +1 if there's a dynamic part also */
126 SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
129 * if we have a dynamic part, make sure the first byte
130 * which is always be part of the packet is initialized
132 if (body_dynamic_size) {
134 SCVAL(req->out.dynamic, 0, 0);
137 talloc_set_destructor(req, smb2_request_destructor);
143 initialise a smb2 request for tree operations
145 struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
146 uint16_t body_fixed_size, bool body_dynamic_present,
147 uint32_t body_dynamic_size)
149 struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
150 body_fixed_size, body_dynamic_present,
152 if (req == NULL) return NULL;
154 SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, tree->session->uid);
155 SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid);
156 req->session = tree->session;
162 /* destroy a request structure and return final status */
163 NTSTATUS smb2_request_destroy(struct smb2_request *req)
167 /* this is the error code we give the application for when a
168 _send() call fails completely */
169 if (!req) return NT_STATUS_UNSUCCESSFUL;
171 if (req->state == SMB2_REQUEST_ERROR &&
172 NT_STATUS_IS_OK(req->status)) {
173 status = NT_STATUS_INTERNAL_ERROR;
175 status = req->status;
183 receive a response to a packet
185 bool smb2_request_receive(struct smb2_request *req)
187 /* req can be NULL when a send has failed. This eliminates lots of NULL
188 checks in each module */
189 if (!req) return false;
191 /* keep receiving packets until this one is replied to */
192 while (req->state <= SMB2_REQUEST_RECV) {
193 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
198 return req->state == SMB2_REQUEST_DONE;
201 /* Return true if the last packet was in error */
202 bool smb2_request_is_error(struct smb2_request *req)
204 return NT_STATUS_IS_ERR(req->status);
207 /* Return true if the last packet was OK */
208 bool smb2_request_is_ok(struct smb2_request *req)
210 return NT_STATUS_IS_OK(req->status);
214 check if a range in the reply body is out of bounds
216 bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
219 /* zero bytes is never out of range */
222 /* be careful with wraparound! */
223 if ((uintptr_t)ptr < (uintptr_t)buf->body ||
224 (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size ||
225 size > buf->body_size ||
226 (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) {
232 size_t smb2_padding_size(uint32_t offset, size_t n)
234 if ((offset & (n-1)) == 0) return 0;
235 return n - (offset & (n-1));
238 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
240 if (buf->dynamic == (buf->body + buf->body_fixed)) {
247 grow a SMB2 buffer by the specified amount
249 static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
253 uint32_t newsize = buf->size + increase;
255 /* a packet size should be limited a bit */
256 if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
258 if (newsize <= buf->allocated) return NT_STATUS_OK;
260 dynamic_ofs = buf->dynamic - buf->buffer;
262 buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
263 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
265 buf->buffer = buffer_ptr;
266 buf->hdr = buf->buffer + NBT_HDR_SIZE;
267 buf->body = buf->hdr + SMB2_HDR_BODY;
268 buf->dynamic = buf->buffer + dynamic_ofs;
269 buf->allocated = newsize;
275 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
276 the ptr points to the start of the offset/length pair
278 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
281 if (smb2_oob(buf, ptr, 4)) {
282 return NT_STATUS_BUFFER_TOO_SMALL;
287 *blob = data_blob(NULL, 0);
290 if (smb2_oob(buf, buf->hdr + ofs, size)) {
291 return NT_STATUS_BUFFER_TOO_SMALL;
293 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
294 NT_STATUS_HAVE_NO_MEMORY(blob->data);
299 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
300 the ofs points to the start of the offset/length pair, and is relative
303 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
304 uint16_t ofs, DATA_BLOB blob)
308 size_t padding_length;
310 uint8_t *ptr = buf->body+ofs;
312 if (buf->dynamic == NULL) {
313 return NT_STATUS_INVALID_PARAMETER;
316 /* we have only 16 bit for the size */
317 if (blob.length > 0xFFFF) {
318 return NT_STATUS_BUFFER_TOO_SMALL;
321 /* check if there're enough room for ofs and size */
322 if (smb2_oob(buf, ptr, 4)) {
323 return NT_STATUS_BUFFER_TOO_SMALL;
326 if (blob.data == NULL) {
327 if (blob.length != 0) {
328 return NT_STATUS_INTERNAL_ERROR;
335 offset = buf->dynamic - buf->hdr;
336 padding_length = smb2_padding_size(offset, 2);
337 offset += padding_length;
338 padding_fix = smb2_padding_fix(buf);
340 SSVAL(ptr, 0, offset);
341 SSVAL(ptr, 2, blob.length);
343 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
344 NT_STATUS_NOT_OK_RETURN(status);
346 memset(buf->dynamic, 0, padding_length);
347 buf->dynamic += padding_length;
349 memcpy(buf->dynamic, blob.data, blob.length);
350 buf->dynamic += blob.length;
352 buf->size += blob.length + padding_length - padding_fix;
353 buf->body_size += blob.length + padding_length;
360 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
361 the ofs points to the start of the offset/length pair, and is relative
364 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
365 uint16_t ofs, DATA_BLOB blob)
369 size_t padding_length;
371 uint8_t *ptr = buf->body+ofs;
373 if (buf->dynamic == NULL) {
374 return NT_STATUS_INVALID_PARAMETER;
377 /* check if there're enough room for ofs and size */
378 if (smb2_oob(buf, ptr, 6)) {
379 return NT_STATUS_BUFFER_TOO_SMALL;
382 if (blob.data == NULL) {
383 if (blob.length != 0) {
384 return NT_STATUS_INTERNAL_ERROR;
391 offset = buf->dynamic - buf->hdr;
392 padding_length = smb2_padding_size(offset, 2);
393 offset += padding_length;
394 padding_fix = smb2_padding_fix(buf);
396 SSVAL(ptr, 0, offset);
397 SIVAL(ptr, 2, blob.length);
399 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
400 NT_STATUS_NOT_OK_RETURN(status);
402 memset(buf->dynamic, 0, padding_length);
403 buf->dynamic += padding_length;
405 memcpy(buf->dynamic, blob.data, blob.length);
406 buf->dynamic += blob.length;
408 buf->size += blob.length + padding_length - padding_fix;
409 buf->body_size += blob.length + padding_length;
416 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
417 the ofs points to the start of the offset/length pair, and is relative
420 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
421 uint32_t ofs, DATA_BLOB blob)
425 size_t padding_length;
427 uint8_t *ptr = buf->body+ofs;
429 if (buf->dynamic == NULL) {
430 return NT_STATUS_INVALID_PARAMETER;
433 /* check if there're enough room for ofs and size */
434 if (smb2_oob(buf, ptr, 8)) {
435 return NT_STATUS_BUFFER_TOO_SMALL;
438 if (blob.data == NULL) {
439 if (blob.length != 0) {
440 return NT_STATUS_INTERNAL_ERROR;
447 offset = buf->dynamic - buf->hdr;
448 padding_length = smb2_padding_size(offset, 8);
449 offset += padding_length;
450 padding_fix = smb2_padding_fix(buf);
452 SIVAL(ptr, 0, offset);
453 SIVAL(ptr, 4, blob.length);
455 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
456 NT_STATUS_NOT_OK_RETURN(status);
458 memset(buf->dynamic, 0, padding_length);
459 buf->dynamic += padding_length;
461 memcpy(buf->dynamic, blob.data, blob.length);
462 buf->dynamic += blob.length;
464 buf->size += blob.length + padding_length - padding_fix;
465 buf->body_size += blob.length + padding_length;
472 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
473 the ofs points to the start of the length/offset pair, and is relative
476 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
477 uint32_t ofs, DATA_BLOB blob)
481 size_t padding_length;
483 uint8_t *ptr = buf->body+ofs;
485 if (buf->dynamic == NULL) {
486 return NT_STATUS_INVALID_PARAMETER;
489 /* check if there're enough room for ofs and size */
490 if (smb2_oob(buf, ptr, 8)) {
491 return NT_STATUS_BUFFER_TOO_SMALL;
494 if (blob.data == NULL) {
495 if (blob.length != 0) {
496 return NT_STATUS_INTERNAL_ERROR;
503 offset = buf->dynamic - buf->hdr;
504 padding_length = smb2_padding_size(offset, 8);
505 offset += padding_length;
506 padding_fix = smb2_padding_fix(buf);
508 SIVAL(ptr, 0, blob.length);
509 SIVAL(ptr, 4, offset);
511 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
512 NT_STATUS_NOT_OK_RETURN(status);
514 memset(buf->dynamic, 0, padding_length);
515 buf->dynamic += padding_length;
517 memcpy(buf->dynamic, blob.data, blob.length);
518 buf->dynamic += blob.length;
520 buf->size += blob.length + padding_length - padding_fix;
521 buf->body_size += blob.length + padding_length;
527 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
528 the ptr points to the start of the offset/length pair
530 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
535 if (smb2_oob(buf, ptr, 6)) {
536 return NT_STATUS_BUFFER_TOO_SMALL;
541 *blob = data_blob(NULL, 0);
544 if (smb2_oob(buf, buf->hdr + ofs, size)) {
545 return NT_STATUS_BUFFER_TOO_SMALL;
547 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
548 NT_STATUS_HAVE_NO_MEMORY(blob->data);
553 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
554 the ptr points to the start of the offset/length pair
556 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
559 if (smb2_oob(buf, ptr, 8)) {
560 return NT_STATUS_BUFFER_TOO_SMALL;
565 *blob = data_blob(NULL, 0);
568 if (smb2_oob(buf, buf->hdr + ofs, size)) {
569 return NT_STATUS_BUFFER_TOO_SMALL;
571 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
572 NT_STATUS_HAVE_NO_MEMORY(blob->data);
577 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
578 the ptr points to the start of the offset/length pair
580 In this varient the uint16_t is padded by an extra 2 bytes, making
581 the size aligned on 4 byte boundary
583 NTSTATUS smb2_pull_o16As32_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_BUFFER_TOO_SMALL;
592 *blob = data_blob(NULL, 0);
595 if (smb2_oob(buf, buf->hdr + ofs, size)) {
596 return NT_STATUS_BUFFER_TOO_SMALL;
598 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
599 NT_STATUS_HAVE_NO_MEMORY(blob->data);
604 pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
605 the ptr points to the start of the offset/length pair
607 NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
610 if (smb2_oob(buf, ptr, 8)) {
611 return NT_STATUS_BUFFER_TOO_SMALL;
616 *blob = data_blob(NULL, 0);
619 if (smb2_oob(buf, buf->hdr + ofs, size)) {
620 return NT_STATUS_BUFFER_TOO_SMALL;
622 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
623 NT_STATUS_HAVE_NO_MEMORY(blob->data);
628 pull a string in a uint16_t ofs/ uint16_t length/blob format
629 UTF-16 without termination
631 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
632 uint8_t *ptr, const char **str)
639 status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
640 NT_STATUS_NOT_OK_RETURN(status);
642 if (blob.data == NULL) {
647 if (blob.length == 0) {
649 s = talloc_strdup(mem_ctx, "");
650 NT_STATUS_HAVE_NO_MEMORY(s);
655 size = convert_string_talloc(mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX,
656 blob.data, blob.length, &vstr);
657 data_blob_free(&blob);
658 (*str) = (char *)vstr;
660 return NT_STATUS_ILLEGAL_CHARACTER;
666 push a string in a uint16_t ofs/ uint16_t length/blob format
667 UTF-16 without termination
669 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
670 uint16_t ofs, const char *str)
677 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
681 blob.data = discard_const(str);
683 return smb2_push_o16s16_blob(buf, ofs, blob);
686 size = convert_string_talloc(buf->buffer, lp_iconv_convenience(global_loadparm), CH_UNIX, CH_UTF16,
687 str, strlen(str), (void **)&blob.data);
689 return NT_STATUS_ILLEGAL_CHARACTER;
693 status = smb2_push_o16s16_blob(buf, ofs, blob);
694 data_blob_free(&blob);
699 push a file handle into a buffer
701 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
703 SBVAL(data, 0, h->data[0]);
704 SBVAL(data, 8, h->data[1]);
708 pull a file handle from a buffer
710 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
712 h->data[0] = BVAL(ptr, 0);
713 h->data[1] = BVAL(ptr, 8);