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"
30 initialise a smb2 request
32 struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
33 uint16_t body_fixed_size, BOOL body_dynamic_present,
34 uint32_t body_dynamic_size)
36 struct smb2_request *req;
39 if (body_dynamic_present) {
40 if (body_dynamic_size == 0) {
41 body_dynamic_size = 1;
44 body_dynamic_size = 0;
47 req = talloc(transport, struct smb2_request);
48 if (req == NULL) return NULL;
50 seqnum = transport->seqnum++;
51 if (seqnum == UINT64_MAX) {
52 seqnum = transport->seqnum++;
55 req->state = SMB2_REQUEST_INIT;
56 req->transport = transport;
60 req->status = NT_STATUS_OK;
62 req->next = req->prev = NULL;
64 ZERO_STRUCT(req->cancel);
67 req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
69 req->out.allocated = req->out.size + body_dynamic_size;
70 req->out.buffer = talloc_size(req, req->out.allocated);
71 if (req->out.buffer == NULL) {
76 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
77 req->out.body = req->out.hdr + SMB2_HDR_BODY;
78 req->out.body_fixed= body_fixed_size;
79 req->out.body_size = body_fixed_size;
80 req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
82 SIVAL(req->out.hdr, 0, SMB2_MAGIC);
83 SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
84 SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
85 SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
86 SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
87 SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0);
88 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
89 SIVAL(req->out.hdr, SMB2_HDR_CHAIN_OFFSET, 0);
90 SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
91 SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
92 SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
93 SBVAL(req->out.hdr, SMB2_HDR_UID, 0);
94 memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
96 /* set the length of the fixed body part and +1 if there's a dynamic part also */
97 SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
100 * if we have a dynamic part, make sure the first byte
101 * which is always be part of the packet is initialized
103 if (body_dynamic_size) {
105 SCVAL(req->out.dynamic, 0, 0);
112 initialise a smb2 request for tree operations
114 struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
115 uint16_t body_fixed_size, BOOL body_dynamic_present,
116 uint32_t body_dynamic_size)
118 struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
119 body_fixed_size, body_dynamic_present,
121 if (req == NULL) return NULL;
123 SBVAL(req->out.hdr, SMB2_HDR_UID, tree->session->uid);
124 SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid);
125 req->session = tree->session;
131 /* destroy a request structure and return final status */
132 NTSTATUS smb2_request_destroy(struct smb2_request *req)
136 /* this is the error code we give the application for when a
137 _send() call fails completely */
138 if (!req) return NT_STATUS_UNSUCCESSFUL;
140 if (req->transport) {
141 /* remove it from the list of pending requests (a null op if
142 its not in the list) */
143 DLIST_REMOVE(req->transport->pending_recv, req);
146 if (req->state == SMB2_REQUEST_ERROR &&
147 NT_STATUS_IS_OK(req->status)) {
148 req->status = NT_STATUS_INTERNAL_ERROR;
151 status = req->status;
157 receive a response to a packet
159 BOOL smb2_request_receive(struct smb2_request *req)
161 /* req can be NULL when a send has failed. This eliminates lots of NULL
162 checks in each module */
163 if (!req) return False;
165 /* keep receiving packets until this one is replied to */
166 while (req->state <= SMB2_REQUEST_RECV) {
167 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
172 return req->state == SMB2_REQUEST_DONE;
175 /* Return true if the last packet was in error */
176 BOOL smb2_request_is_error(struct smb2_request *req)
178 return NT_STATUS_IS_ERR(req->status);
181 /* Return true if the last packet was OK */
182 BOOL smb2_request_is_ok(struct smb2_request *req)
184 return NT_STATUS_IS_OK(req->status);
188 check if a range in the reply body is out of bounds
190 BOOL smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
192 /* be careful with wraparound! */
193 if (ptr < buf->body ||
194 ptr >= buf->body + buf->body_size ||
195 size > buf->body_size ||
196 ptr + size > buf->body + buf->body_size) {
202 size_t smb2_padding_size(uint32_t offset, size_t n)
204 if ((offset & (n-1)) == 0) return 0;
205 return n - (offset & (n-1));
208 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
210 if (buf->dynamic == (buf->body + buf->body_fixed)) {
217 grow a SMB2 buffer by the specified amount
219 static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
223 uint32_t newsize = buf->size + increase;
225 /* a packet size should be limited a bit */
226 if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
228 if (newsize <= buf->allocated) return NT_STATUS_OK;
230 dynamic_ofs = buf->dynamic - buf->buffer;
232 buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
233 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
235 buf->buffer = buffer_ptr;
236 buf->hdr = buf->buffer + NBT_HDR_SIZE;
237 buf->body = buf->hdr + SMB2_HDR_BODY;
238 buf->dynamic = buf->buffer + dynamic_ofs;
239 buf->allocated = newsize;
245 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
246 the ptr points to the start of the offset/length pair
248 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
251 if (smb2_oob(buf, ptr, 4)) {
252 return NT_STATUS_BUFFER_TOO_SMALL;
256 if (ofs == 0 || size == 0) {
257 *blob = data_blob(NULL, 0);
260 if (smb2_oob(buf, buf->hdr + ofs, size)) {
261 return NT_STATUS_BUFFER_TOO_SMALL;
263 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
264 NT_STATUS_HAVE_NO_MEMORY(blob->data);
269 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
270 the ofs points to the start of the offset/length pair, and is relative
273 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
274 uint16_t ofs, DATA_BLOB blob)
278 size_t padding_length;
280 uint8_t *ptr = buf->body+ofs;
282 if (buf->dynamic == NULL) {
283 return NT_STATUS_INVALID_PARAMETER;
286 /* we have only 16 bit for the size */
287 if (blob.length > 0xFFFF) {
288 return NT_STATUS_BUFFER_TOO_SMALL;
291 /* check if there're enough room for ofs and size */
292 if (smb2_oob(buf, ptr, 4)) {
293 return NT_STATUS_BUFFER_TOO_SMALL;
296 if (blob.length == 0) {
302 offset = buf->dynamic - buf->hdr;
303 padding_length = smb2_padding_size(offset, 2);
304 offset += padding_length;
305 padding_fix = smb2_padding_fix(buf);
307 SSVAL(ptr, 0, offset);
308 SSVAL(ptr, 2, blob.length);
310 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
311 NT_STATUS_NOT_OK_RETURN(status);
313 memset(buf->dynamic, 0, padding_length);
314 buf->dynamic += padding_length;
316 memcpy(buf->dynamic, blob.data, blob.length);
317 buf->dynamic += blob.length;
319 buf->size += blob.length + padding_length - padding_fix;
320 buf->body_size += blob.length + padding_length;
327 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
328 the ofs points to the start of the offset/length pair, and is relative
331 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
332 uint16_t ofs, DATA_BLOB blob)
336 size_t padding_length;
338 uint8_t *ptr = buf->body+ofs;
340 if (buf->dynamic == NULL) {
341 return NT_STATUS_INVALID_PARAMETER;
344 /* check if there're enough room for ofs and size */
345 if (smb2_oob(buf, ptr, 6)) {
346 return NT_STATUS_BUFFER_TOO_SMALL;
349 if (blob.length == 0) {
355 offset = buf->dynamic - buf->hdr;
356 padding_length = smb2_padding_size(offset, 2);
357 offset += padding_length;
358 padding_fix = smb2_padding_fix(buf);
360 SSVAL(ptr, 0, offset);
361 SIVAL(ptr, 2, blob.length);
363 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
364 NT_STATUS_NOT_OK_RETURN(status);
366 memset(buf->dynamic, 0, padding_length);
367 buf->dynamic += padding_length;
369 memcpy(buf->dynamic, blob.data, blob.length);
370 buf->dynamic += blob.length;
372 buf->size += blob.length + padding_length - padding_fix;
373 buf->body_size += blob.length + padding_length;
380 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
381 the ofs points to the start of the offset/length pair, and is relative
384 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
385 uint32_t ofs, DATA_BLOB blob)
389 size_t padding_length;
391 uint8_t *ptr = buf->body+ofs;
393 if (buf->dynamic == NULL) {
394 return NT_STATUS_INVALID_PARAMETER;
397 /* check if there're enough room for ofs and size */
398 if (smb2_oob(buf, ptr, 8)) {
399 return NT_STATUS_BUFFER_TOO_SMALL;
402 if (blob.length == 0) {
408 offset = buf->dynamic - buf->hdr;
409 padding_length = smb2_padding_size(offset, 8);
410 offset += padding_length;
411 padding_fix = smb2_padding_fix(buf);
413 SIVAL(ptr, 0, offset);
414 SIVAL(ptr, 4, blob.length);
416 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
417 NT_STATUS_NOT_OK_RETURN(status);
419 memset(buf->dynamic, 0, padding_length);
420 buf->dynamic += padding_length;
422 memcpy(buf->dynamic, blob.data, blob.length);
423 buf->dynamic += blob.length;
425 buf->size += blob.length + padding_length - padding_fix;
426 buf->body_size += blob.length + padding_length;
433 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
434 the ofs points to the start of the length/offset pair, and is relative
437 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
438 uint32_t ofs, DATA_BLOB blob)
442 size_t padding_length;
444 uint8_t *ptr = buf->body+ofs;
446 if (buf->dynamic == NULL) {
447 return NT_STATUS_INVALID_PARAMETER;
450 /* check if there're enough room for ofs and size */
451 if (smb2_oob(buf, ptr, 8)) {
452 return NT_STATUS_BUFFER_TOO_SMALL;
455 if (blob.length == 0) {
461 offset = buf->dynamic - buf->hdr;
462 padding_length = smb2_padding_size(offset, 8);
463 offset += padding_length;
464 padding_fix = smb2_padding_fix(buf);
466 SIVAL(ptr, 0, blob.length);
467 SIVAL(ptr, 4, offset);
469 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
470 NT_STATUS_NOT_OK_RETURN(status);
472 memset(buf->dynamic, 0, padding_length);
473 buf->dynamic += padding_length;
475 memcpy(buf->dynamic, blob.data, blob.length);
476 buf->dynamic += blob.length;
478 buf->size += blob.length + padding_length - padding_fix;
479 buf->body_size += blob.length + padding_length;
485 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
486 the ptr points to the start of the offset/length pair
488 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
493 if (smb2_oob(buf, ptr, 6)) {
494 return NT_STATUS_BUFFER_TOO_SMALL;
498 if (ofs == 0 || size == 0) {
499 *blob = data_blob(NULL, 0);
502 if (smb2_oob(buf, buf->hdr + ofs, size)) {
503 return NT_STATUS_BUFFER_TOO_SMALL;
505 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
506 NT_STATUS_HAVE_NO_MEMORY(blob->data);
511 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
512 the ptr points to the start of the offset/length pair
514 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
517 if (smb2_oob(buf, ptr, 8)) {
518 return NT_STATUS_BUFFER_TOO_SMALL;
522 if (ofs == 0 || size == 0) {
523 *blob = data_blob(NULL, 0);
526 if (smb2_oob(buf, buf->hdr + ofs, size)) {
527 return NT_STATUS_BUFFER_TOO_SMALL;
529 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
530 NT_STATUS_HAVE_NO_MEMORY(blob->data);
535 pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
536 the ptr points to the start of the offset/length pair
538 NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
541 if (smb2_oob(buf, ptr, 8)) {
542 return NT_STATUS_BUFFER_TOO_SMALL;
546 if (ofs == 0 || size == 0) {
547 *blob = data_blob(NULL, 0);
550 if (smb2_oob(buf, buf->hdr + ofs, size)) {
551 return NT_STATUS_BUFFER_TOO_SMALL;
553 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
554 NT_STATUS_HAVE_NO_MEMORY(blob->data);
559 pull a string in a uint16_t ofs/ uint16_t length/blob format
560 UTF-16 without termination
562 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
563 uint8_t *ptr, const char **str)
570 status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
571 NT_STATUS_NOT_OK_RETURN(status);
573 if (blob.length == 0) {
575 s = talloc_strdup(mem_ctx, "");
576 NT_STATUS_HAVE_NO_MEMORY(s);
581 size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
582 blob.data, blob.length, &vstr);
583 data_blob_free(&blob);
586 return NT_STATUS_ILLEGAL_CHARACTER;
592 push a string in a uint16_t ofs/ uint16_t length/blob format
593 UTF-16 without termination
595 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
596 uint16_t ofs, const char *str)
602 if (strcmp("", str) == 0) {
603 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
606 size = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16,
607 str, strlen(str), (void **)&blob.data);
609 return NT_STATUS_ILLEGAL_CHARACTER;
613 status = smb2_push_o16s16_blob(buf, ofs, blob);
614 data_blob_free(&blob);
619 push a file handle into a buffer
621 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
623 SBVAL(data, 0, h->data[0]);
624 SBVAL(data, 8, h->data[1]);
628 pull a file handle from a buffer
630 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
632 h->data[0] = BVAL(ptr, 0);
633 h->data[1] = BVAL(ptr, 8);