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)
209 /* be careful with wraparound! */
210 if (ptr < buf->body ||
211 ptr >= buf->body + buf->body_size ||
212 size > buf->body_size ||
213 ptr + size > buf->body + buf->body_size) {
219 size_t smb2_padding_size(uint32_t offset, size_t n)
221 if ((offset & (n-1)) == 0) return 0;
222 return n - (offset & (n-1));
225 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
227 if (buf->dynamic == (buf->body + buf->body_fixed)) {
234 grow a SMB2 buffer by the specified amount
236 static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
240 uint32_t newsize = buf->size + increase;
242 /* a packet size should be limited a bit */
243 if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
245 if (newsize <= buf->allocated) return NT_STATUS_OK;
247 dynamic_ofs = buf->dynamic - buf->buffer;
249 buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
250 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
252 buf->buffer = buffer_ptr;
253 buf->hdr = buf->buffer + NBT_HDR_SIZE;
254 buf->body = buf->hdr + SMB2_HDR_BODY;
255 buf->dynamic = buf->buffer + dynamic_ofs;
256 buf->allocated = newsize;
262 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
263 the ptr points to the start of the offset/length pair
265 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
268 if (smb2_oob(buf, ptr, 4)) {
269 return NT_STATUS_BUFFER_TOO_SMALL;
273 if (ofs == 0 || size == 0) {
274 *blob = data_blob(NULL, 0);
277 if (smb2_oob(buf, buf->hdr + ofs, size)) {
278 return NT_STATUS_BUFFER_TOO_SMALL;
280 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
281 NT_STATUS_HAVE_NO_MEMORY(blob->data);
286 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
287 the ofs points to the start of the offset/length pair, and is relative
290 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
291 uint16_t ofs, DATA_BLOB blob)
295 size_t padding_length;
297 uint8_t *ptr = buf->body+ofs;
299 if (buf->dynamic == NULL) {
300 return NT_STATUS_INVALID_PARAMETER;
303 /* we have only 16 bit for the size */
304 if (blob.length > 0xFFFF) {
305 return NT_STATUS_BUFFER_TOO_SMALL;
308 /* check if there're enough room for ofs and size */
309 if (smb2_oob(buf, ptr, 4)) {
310 return NT_STATUS_BUFFER_TOO_SMALL;
313 if (blob.length == 0) {
319 offset = buf->dynamic - buf->hdr;
320 padding_length = smb2_padding_size(offset, 2);
321 offset += padding_length;
322 padding_fix = smb2_padding_fix(buf);
324 SSVAL(ptr, 0, offset);
325 SSVAL(ptr, 2, blob.length);
327 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
328 NT_STATUS_NOT_OK_RETURN(status);
330 memset(buf->dynamic, 0, padding_length);
331 buf->dynamic += padding_length;
333 memcpy(buf->dynamic, blob.data, blob.length);
334 buf->dynamic += blob.length;
336 buf->size += blob.length + padding_length - padding_fix;
337 buf->body_size += blob.length + padding_length;
344 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
345 the ofs points to the start of the offset/length pair, and is relative
348 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
349 uint16_t ofs, DATA_BLOB blob)
353 size_t padding_length;
355 uint8_t *ptr = buf->body+ofs;
357 if (buf->dynamic == NULL) {
358 return NT_STATUS_INVALID_PARAMETER;
361 /* check if there're enough room for ofs and size */
362 if (smb2_oob(buf, ptr, 6)) {
363 return NT_STATUS_BUFFER_TOO_SMALL;
366 if (blob.length == 0) {
372 offset = buf->dynamic - buf->hdr;
373 padding_length = smb2_padding_size(offset, 2);
374 offset += padding_length;
375 padding_fix = smb2_padding_fix(buf);
377 SSVAL(ptr, 0, offset);
378 SIVAL(ptr, 2, blob.length);
380 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
381 NT_STATUS_NOT_OK_RETURN(status);
383 memset(buf->dynamic, 0, padding_length);
384 buf->dynamic += padding_length;
386 memcpy(buf->dynamic, blob.data, blob.length);
387 buf->dynamic += blob.length;
389 buf->size += blob.length + padding_length - padding_fix;
390 buf->body_size += blob.length + padding_length;
397 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
398 the ofs points to the start of the offset/length pair, and is relative
401 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
402 uint32_t ofs, DATA_BLOB blob)
406 size_t padding_length;
408 uint8_t *ptr = buf->body+ofs;
410 if (buf->dynamic == NULL) {
411 return NT_STATUS_INVALID_PARAMETER;
414 /* check if there're enough room for ofs and size */
415 if (smb2_oob(buf, ptr, 8)) {
416 return NT_STATUS_BUFFER_TOO_SMALL;
419 if (blob.length == 0) {
425 offset = buf->dynamic - buf->hdr;
426 padding_length = smb2_padding_size(offset, 8);
427 offset += padding_length;
428 padding_fix = smb2_padding_fix(buf);
430 SIVAL(ptr, 0, offset);
431 SIVAL(ptr, 4, blob.length);
433 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
434 NT_STATUS_NOT_OK_RETURN(status);
436 memset(buf->dynamic, 0, padding_length);
437 buf->dynamic += padding_length;
439 memcpy(buf->dynamic, blob.data, blob.length);
440 buf->dynamic += blob.length;
442 buf->size += blob.length + padding_length - padding_fix;
443 buf->body_size += blob.length + padding_length;
450 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
451 the ofs points to the start of the length/offset pair, and is relative
454 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
455 uint32_t ofs, DATA_BLOB blob)
459 size_t padding_length;
461 uint8_t *ptr = buf->body+ofs;
463 if (buf->dynamic == NULL) {
464 return NT_STATUS_INVALID_PARAMETER;
467 /* check if there're enough room for ofs and size */
468 if (smb2_oob(buf, ptr, 8)) {
469 return NT_STATUS_BUFFER_TOO_SMALL;
472 if (blob.length == 0) {
478 offset = buf->dynamic - buf->hdr;
479 padding_length = smb2_padding_size(offset, 8);
480 offset += padding_length;
481 padding_fix = smb2_padding_fix(buf);
483 SIVAL(ptr, 0, blob.length);
484 SIVAL(ptr, 4, offset);
486 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
487 NT_STATUS_NOT_OK_RETURN(status);
489 memset(buf->dynamic, 0, padding_length);
490 buf->dynamic += padding_length;
492 memcpy(buf->dynamic, blob.data, blob.length);
493 buf->dynamic += blob.length;
495 buf->size += blob.length + padding_length - padding_fix;
496 buf->body_size += blob.length + padding_length;
502 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
503 the ptr points to the start of the offset/length pair
505 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
510 if (smb2_oob(buf, ptr, 6)) {
511 return NT_STATUS_BUFFER_TOO_SMALL;
515 if (ofs == 0 || size == 0) {
516 *blob = data_blob(NULL, 0);
519 if (smb2_oob(buf, buf->hdr + ofs, size)) {
520 return NT_STATUS_BUFFER_TOO_SMALL;
522 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
523 NT_STATUS_HAVE_NO_MEMORY(blob->data);
528 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
529 the ptr points to the start of the offset/length pair
531 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
534 if (smb2_oob(buf, ptr, 8)) {
535 return NT_STATUS_BUFFER_TOO_SMALL;
539 if (ofs == 0 || size == 0) {
540 *blob = data_blob(NULL, 0);
543 if (smb2_oob(buf, buf->hdr + ofs, size)) {
544 return NT_STATUS_BUFFER_TOO_SMALL;
546 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
547 NT_STATUS_HAVE_NO_MEMORY(blob->data);
552 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
553 the ptr points to the start of the offset/length pair
555 In this varient the uint16_t is padded by an extra 2 bytes, making
556 the size aligned on 4 byte boundary
558 NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
561 if (smb2_oob(buf, ptr, 8)) {
562 return NT_STATUS_BUFFER_TOO_SMALL;
566 if (ofs == 0 || size == 0) {
567 *blob = data_blob(NULL, 0);
570 if (smb2_oob(buf, buf->hdr + ofs, size)) {
571 return NT_STATUS_BUFFER_TOO_SMALL;
573 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
574 NT_STATUS_HAVE_NO_MEMORY(blob->data);
579 pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
580 the ptr points to the start of the offset/length pair
582 NTSTATUS smb2_pull_s32o32_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_BUFFER_TOO_SMALL;
590 if (ofs == 0 || size == 0) {
591 *blob = data_blob(NULL, 0);
594 if (smb2_oob(buf, buf->hdr + ofs, size)) {
595 return NT_STATUS_BUFFER_TOO_SMALL;
597 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
598 NT_STATUS_HAVE_NO_MEMORY(blob->data);
603 pull a string in a uint16_t ofs/ uint16_t length/blob format
604 UTF-16 without termination
606 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
607 uint8_t *ptr, const char **str)
614 status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
615 NT_STATUS_NOT_OK_RETURN(status);
617 if (blob.length == 0) {
619 s = talloc_strdup(mem_ctx, "");
620 NT_STATUS_HAVE_NO_MEMORY(s);
625 size = convert_string_talloc(mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX,
626 blob.data, blob.length, &vstr);
627 data_blob_free(&blob);
628 (*str) = (char *)vstr;
630 return NT_STATUS_ILLEGAL_CHARACTER;
636 push a string in a uint16_t ofs/ uint16_t length/blob format
637 UTF-16 without termination
639 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
640 uint16_t ofs, const char *str)
646 if (strcmp("", str) == 0) {
647 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
650 size = convert_string_talloc(buf->buffer, lp_iconv_convenience(global_loadparm), CH_UNIX, CH_UTF16,
651 str, strlen(str), (void **)&blob.data);
653 return NT_STATUS_ILLEGAL_CHARACTER;
657 status = smb2_push_o16s16_blob(buf, ofs, blob);
658 data_blob_free(&blob);
663 push a file handle into a buffer
665 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
667 SBVAL(data, 0, h->data[0]);
668 SBVAL(data, 8, h->data[1]);
672 pull a file handle from a buffer
674 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
676 h->data[0] = BVAL(ptr, 0);
677 h->data[1] = BVAL(ptr, 8);