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 initialise a smb2 request
49 struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
50 uint16_t body_fixed_size, bool body_dynamic_present,
51 uint32_t body_dynamic_size)
53 struct smb2_request *req;
56 if (body_dynamic_present) {
57 if (body_dynamic_size == 0) {
58 body_dynamic_size = 1;
61 body_dynamic_size = 0;
64 req = talloc(transport, struct smb2_request);
65 if (req == NULL) return NULL;
67 seqnum = transport->seqnum++;
68 if (seqnum == UINT64_MAX) {
69 seqnum = transport->seqnum++;
72 req->state = SMB2_REQUEST_INIT;
73 req->transport = transport;
77 req->status = NT_STATUS_OK;
79 req->next = req->prev = NULL;
81 ZERO_STRUCT(req->cancel);
84 req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
86 req->out.allocated = req->out.size + body_dynamic_size;
87 req->out.buffer = talloc_array(req, uint8_t, req->out.allocated);
88 if (req->out.buffer == NULL) {
93 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
94 req->out.body = req->out.hdr + SMB2_HDR_BODY;
95 req->out.body_fixed= body_fixed_size;
96 req->out.body_size = body_fixed_size;
97 req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
99 SIVAL(req->out.hdr, 0, SMB2_MAGIC);
100 SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
101 SSVAL(req->out.hdr, SMB2_HDR_EPOCH, 0);
102 SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
103 SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
104 SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0);
105 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
106 SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0);
107 SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, req->seqnum);
108 SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
109 SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
110 SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, 0);
111 memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16);
113 /* set the length of the fixed body part and +1 if there's a dynamic part also */
114 SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
117 * if we have a dynamic part, make sure the first byte
118 * which is always be part of the packet is initialized
120 if (body_dynamic_size) {
122 SCVAL(req->out.dynamic, 0, 0);
129 initialise a smb2 request for tree operations
131 struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
132 uint16_t body_fixed_size, bool body_dynamic_present,
133 uint32_t body_dynamic_size)
135 struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
136 body_fixed_size, body_dynamic_present,
138 if (req == NULL) return NULL;
140 SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, tree->session->uid);
141 SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid);
142 req->session = tree->session;
148 /* destroy a request structure and return final status */
149 NTSTATUS smb2_request_destroy(struct smb2_request *req)
153 /* this is the error code we give the application for when a
154 _send() call fails completely */
155 if (!req) return NT_STATUS_UNSUCCESSFUL;
157 if (req->transport) {
158 /* remove it from the list of pending requests (a null op if
159 its not in the list) */
160 DLIST_REMOVE(req->transport->pending_recv, req);
163 if (req->state == SMB2_REQUEST_ERROR &&
164 NT_STATUS_IS_OK(req->status)) {
165 req->status = NT_STATUS_INTERNAL_ERROR;
168 status = req->status;
174 receive a response to a packet
176 bool smb2_request_receive(struct smb2_request *req)
178 /* req can be NULL when a send has failed. This eliminates lots of NULL
179 checks in each module */
180 if (!req) return false;
182 /* keep receiving packets until this one is replied to */
183 while (req->state <= SMB2_REQUEST_RECV) {
184 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
189 return req->state == SMB2_REQUEST_DONE;
192 /* Return true if the last packet was in error */
193 bool smb2_request_is_error(struct smb2_request *req)
195 return NT_STATUS_IS_ERR(req->status);
198 /* Return true if the last packet was OK */
199 bool smb2_request_is_ok(struct smb2_request *req)
201 return NT_STATUS_IS_OK(req->status);
205 check if a range in the reply body is out of bounds
207 bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
210 /* zero bytes is never out of range */
213 /* be careful with wraparound! */
214 if ((uintptr_t)ptr < (uintptr_t)buf->body ||
215 (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size ||
216 size > buf->body_size ||
217 (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) {
223 size_t smb2_padding_size(uint32_t offset, size_t n)
225 if ((offset & (n-1)) == 0) return 0;
226 return n - (offset & (n-1));
229 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
231 if (buf->dynamic == (buf->body + buf->body_fixed)) {
238 grow a SMB2 buffer by the specified amount
240 static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
244 uint32_t newsize = buf->size + increase;
246 /* a packet size should be limited a bit */
247 if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
249 if (newsize <= buf->allocated) return NT_STATUS_OK;
251 dynamic_ofs = buf->dynamic - buf->buffer;
253 buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
254 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
256 buf->buffer = buffer_ptr;
257 buf->hdr = buf->buffer + NBT_HDR_SIZE;
258 buf->body = buf->hdr + SMB2_HDR_BODY;
259 buf->dynamic = buf->buffer + dynamic_ofs;
260 buf->allocated = newsize;
266 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
267 the ptr points to the start of the offset/length pair
269 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
272 if (smb2_oob(buf, ptr, 4)) {
273 return NT_STATUS_BUFFER_TOO_SMALL;
278 *blob = data_blob(NULL, 0);
281 if (smb2_oob(buf, buf->hdr + ofs, size)) {
282 return NT_STATUS_BUFFER_TOO_SMALL;
284 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
285 NT_STATUS_HAVE_NO_MEMORY(blob->data);
290 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
291 the ofs points to the start of the offset/length pair, and is relative
294 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
295 uint16_t ofs, DATA_BLOB blob)
299 size_t padding_length;
301 uint8_t *ptr = buf->body+ofs;
303 if (buf->dynamic == NULL) {
304 return NT_STATUS_INVALID_PARAMETER;
307 /* we have only 16 bit for the size */
308 if (blob.length > 0xFFFF) {
309 return NT_STATUS_BUFFER_TOO_SMALL;
312 /* check if there're enough room for ofs and size */
313 if (smb2_oob(buf, ptr, 4)) {
314 return NT_STATUS_BUFFER_TOO_SMALL;
317 if (blob.data == NULL) {
318 if (blob.length != 0) {
319 return NT_STATUS_INTERNAL_ERROR;
326 offset = buf->dynamic - buf->hdr;
327 padding_length = smb2_padding_size(offset, 2);
328 offset += padding_length;
329 padding_fix = smb2_padding_fix(buf);
331 SSVAL(ptr, 0, offset);
332 SSVAL(ptr, 2, blob.length);
334 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
335 NT_STATUS_NOT_OK_RETURN(status);
337 memset(buf->dynamic, 0, padding_length);
338 buf->dynamic += padding_length;
340 memcpy(buf->dynamic, blob.data, blob.length);
341 buf->dynamic += blob.length;
343 buf->size += blob.length + padding_length - padding_fix;
344 buf->body_size += blob.length + padding_length;
351 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
352 the ofs points to the start of the offset/length pair, and is relative
355 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
356 uint16_t ofs, DATA_BLOB blob)
360 size_t padding_length;
362 uint8_t *ptr = buf->body+ofs;
364 if (buf->dynamic == NULL) {
365 return NT_STATUS_INVALID_PARAMETER;
368 /* check if there're enough room for ofs and size */
369 if (smb2_oob(buf, ptr, 6)) {
370 return NT_STATUS_BUFFER_TOO_SMALL;
373 if (blob.data == NULL) {
374 if (blob.length != 0) {
375 return NT_STATUS_INTERNAL_ERROR;
382 offset = buf->dynamic - buf->hdr;
383 padding_length = smb2_padding_size(offset, 2);
384 offset += padding_length;
385 padding_fix = smb2_padding_fix(buf);
387 SSVAL(ptr, 0, offset);
388 SIVAL(ptr, 2, blob.length);
390 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
391 NT_STATUS_NOT_OK_RETURN(status);
393 memset(buf->dynamic, 0, padding_length);
394 buf->dynamic += padding_length;
396 memcpy(buf->dynamic, blob.data, blob.length);
397 buf->dynamic += blob.length;
399 buf->size += blob.length + padding_length - padding_fix;
400 buf->body_size += blob.length + padding_length;
407 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
408 the ofs points to the start of the offset/length pair, and is relative
411 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
412 uint32_t ofs, DATA_BLOB blob)
416 size_t padding_length;
418 uint8_t *ptr = buf->body+ofs;
420 if (buf->dynamic == NULL) {
421 return NT_STATUS_INVALID_PARAMETER;
424 /* check if there're enough room for ofs and size */
425 if (smb2_oob(buf, ptr, 8)) {
426 return NT_STATUS_BUFFER_TOO_SMALL;
429 if (blob.data == NULL) {
430 if (blob.length != 0) {
431 return NT_STATUS_INTERNAL_ERROR;
438 offset = buf->dynamic - buf->hdr;
439 padding_length = smb2_padding_size(offset, 8);
440 offset += padding_length;
441 padding_fix = smb2_padding_fix(buf);
443 SIVAL(ptr, 0, offset);
444 SIVAL(ptr, 4, blob.length);
446 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
447 NT_STATUS_NOT_OK_RETURN(status);
449 memset(buf->dynamic, 0, padding_length);
450 buf->dynamic += padding_length;
452 memcpy(buf->dynamic, blob.data, blob.length);
453 buf->dynamic += blob.length;
455 buf->size += blob.length + padding_length - padding_fix;
456 buf->body_size += blob.length + padding_length;
463 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
464 the ofs points to the start of the length/offset pair, and is relative
467 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
468 uint32_t ofs, DATA_BLOB blob)
472 size_t padding_length;
474 uint8_t *ptr = buf->body+ofs;
476 if (buf->dynamic == NULL) {
477 return NT_STATUS_INVALID_PARAMETER;
480 /* check if there're enough room for ofs and size */
481 if (smb2_oob(buf, ptr, 8)) {
482 return NT_STATUS_BUFFER_TOO_SMALL;
485 if (blob.data == NULL) {
486 if (blob.length != 0) {
487 return NT_STATUS_INTERNAL_ERROR;
494 offset = buf->dynamic - buf->hdr;
495 padding_length = smb2_padding_size(offset, 8);
496 offset += padding_length;
497 padding_fix = smb2_padding_fix(buf);
499 SIVAL(ptr, 0, blob.length);
500 SIVAL(ptr, 4, offset);
502 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
503 NT_STATUS_NOT_OK_RETURN(status);
505 memset(buf->dynamic, 0, padding_length);
506 buf->dynamic += padding_length;
508 memcpy(buf->dynamic, blob.data, blob.length);
509 buf->dynamic += blob.length;
511 buf->size += blob.length + padding_length - padding_fix;
512 buf->body_size += blob.length + padding_length;
518 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
519 the ptr points to the start of the offset/length pair
521 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
526 if (smb2_oob(buf, ptr, 6)) {
527 return NT_STATUS_BUFFER_TOO_SMALL;
532 *blob = data_blob(NULL, 0);
535 if (smb2_oob(buf, buf->hdr + ofs, size)) {
536 return NT_STATUS_BUFFER_TOO_SMALL;
538 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
539 NT_STATUS_HAVE_NO_MEMORY(blob->data);
544 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
545 the ptr points to the start of the offset/length pair
547 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
550 if (smb2_oob(buf, ptr, 8)) {
551 return NT_STATUS_BUFFER_TOO_SMALL;
556 *blob = data_blob(NULL, 0);
559 if (smb2_oob(buf, buf->hdr + ofs, size)) {
560 return NT_STATUS_BUFFER_TOO_SMALL;
562 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
563 NT_STATUS_HAVE_NO_MEMORY(blob->data);
568 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
569 the ptr points to the start of the offset/length pair
571 In this varient the uint16_t is padded by an extra 2 bytes, making
572 the size aligned on 4 byte boundary
574 NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
577 if (smb2_oob(buf, ptr, 8)) {
578 return NT_STATUS_BUFFER_TOO_SMALL;
583 *blob = data_blob(NULL, 0);
586 if (smb2_oob(buf, buf->hdr + ofs, size)) {
587 return NT_STATUS_BUFFER_TOO_SMALL;
589 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
590 NT_STATUS_HAVE_NO_MEMORY(blob->data);
595 pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
596 the ptr points to the start of the offset/length pair
598 NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
601 if (smb2_oob(buf, ptr, 8)) {
602 return NT_STATUS_BUFFER_TOO_SMALL;
607 *blob = data_blob(NULL, 0);
610 if (smb2_oob(buf, buf->hdr + ofs, size)) {
611 return NT_STATUS_BUFFER_TOO_SMALL;
613 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
614 NT_STATUS_HAVE_NO_MEMORY(blob->data);
619 pull a string in a uint16_t ofs/ uint16_t length/blob format
620 UTF-16 without termination
622 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
623 uint8_t *ptr, const char **str)
630 status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
631 NT_STATUS_NOT_OK_RETURN(status);
633 if (blob.data == NULL) {
638 if (blob.length == 0) {
640 s = talloc_strdup(mem_ctx, "");
641 NT_STATUS_HAVE_NO_MEMORY(s);
646 size = convert_string_talloc(mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX,
647 blob.data, blob.length, &vstr);
648 data_blob_free(&blob);
649 (*str) = (char *)vstr;
651 return NT_STATUS_ILLEGAL_CHARACTER;
657 push a string in a uint16_t ofs/ uint16_t length/blob format
658 UTF-16 without termination
660 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
661 uint16_t ofs, const char *str)
668 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
672 blob.data = discard_const(str);
674 return smb2_push_o16s16_blob(buf, ofs, blob);
677 size = convert_string_talloc(buf->buffer, lp_iconv_convenience(global_loadparm), CH_UNIX, CH_UTF16,
678 str, strlen(str), (void **)&blob.data);
680 return NT_STATUS_ILLEGAL_CHARACTER;
684 status = smb2_push_o16s16_blob(buf, ofs, blob);
685 data_blob_free(&blob);
690 push a file handle into a buffer
692 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
694 SBVAL(data, 0, h->data[0]);
695 SBVAL(data, 8, h->data[1]);
699 pull a file handle from a buffer
701 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
703 h->data[0] = BVAL(ptr, 0);
704 h->data[1] = BVAL(ptr, 8);