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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/smb2/smb2.h"
27 #include "include/dlinklist.h"
28 #include "lib/events/events.h"
31 initialise a smb2 request
33 struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
34 uint16_t body_fixed_size, BOOL body_dynamic_present,
35 uint32_t body_dynamic_size)
37 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 req->state = SMB2_REQUEST_INIT;
51 req->transport = transport;
54 req->seqnum = transport->seqnum++;
55 req->status = NT_STATUS_OK;
57 req->next = req->prev = NULL;
61 req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
63 req->out.allocated = req->out.size + body_dynamic_size;
64 req->out.buffer = talloc_size(req, req->out.allocated);
65 if (req->out.buffer == NULL) {
70 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
71 req->out.body = req->out.hdr + SMB2_HDR_BODY;
72 req->out.body_fixed= body_fixed_size;
73 req->out.body_size = body_fixed_size;
74 req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
76 SIVAL(req->out.hdr, 0, SMB2_MAGIC);
77 SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
78 SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
79 SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
80 SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
81 SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0);
82 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
83 SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0);
84 SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
85 SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
86 SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
87 SBVAL(req->out.hdr, SMB2_HDR_UID, 0);
88 memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
90 /* set the length of the fixed body part and +1 if there's a dynamic part also */
91 SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
94 * if we have a dynamic part, make sure the first byte
95 * which is always be part of the packet is initialized
97 if (body_dynamic_size) {
99 SCVAL(req->out.dynamic, 0, 0);
106 initialise a smb2 request for tree operations
108 struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
109 uint16_t body_fixed_size, BOOL body_dynamic_present,
110 uint32_t body_dynamic_size)
112 struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
113 body_fixed_size, body_dynamic_present,
115 if (req == NULL) return NULL;
117 SBVAL(req->out.hdr, SMB2_HDR_UID, tree->session->uid);
118 SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid);
119 req->session = tree->session;
125 /* destroy a request structure and return final status */
126 NTSTATUS smb2_request_destroy(struct smb2_request *req)
130 /* this is the error code we give the application for when a
131 _send() call fails completely */
132 if (!req) return NT_STATUS_UNSUCCESSFUL;
134 if (req->transport) {
135 /* remove it from the list of pending requests (a null op if
136 its not in the list) */
137 DLIST_REMOVE(req->transport->pending_recv, req);
140 if (req->state == SMB2_REQUEST_ERROR &&
141 NT_STATUS_IS_OK(req->status)) {
142 req->status = NT_STATUS_INTERNAL_ERROR;
145 status = req->status;
151 receive a response to a packet
153 BOOL smb2_request_receive(struct smb2_request *req)
155 /* req can be NULL when a send has failed. This eliminates lots of NULL
156 checks in each module */
157 if (!req) return False;
159 /* keep receiving packets until this one is replied to */
160 while (req->state <= SMB2_REQUEST_RECV) {
161 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
166 return req->state == SMB2_REQUEST_DONE;
169 /* Return true if the last packet was in error */
170 BOOL smb2_request_is_error(struct smb2_request *req)
172 return NT_STATUS_IS_ERR(req->status);
175 /* Return true if the last packet was OK */
176 BOOL smb2_request_is_ok(struct smb2_request *req)
178 return NT_STATUS_IS_OK(req->status);
182 check if a range in the reply body is out of bounds
184 BOOL smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
186 /* be careful with wraparound! */
187 if (ptr < buf->body ||
188 ptr >= buf->body + buf->body_size ||
189 size > buf->body_size ||
190 ptr + size > buf->body + buf->body_size) {
196 size_t smb2_padding_size(uint32_t offset, size_t n)
198 if ((offset & (n-1)) == 0) return 0;
199 return n - (offset & (n-1));
202 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
204 if (buf->dynamic == (buf->body + buf->body_fixed)) {
211 grow a SMB2 buffer by the specified amount
213 static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
217 uint32_t newsize = buf->size + increase;
219 /* a packet size should be limited a bit */
220 if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
222 if (newsize <= buf->allocated) return NT_STATUS_OK;
224 dynamic_ofs = buf->dynamic - buf->buffer;
226 buffer_ptr = talloc_realloc_size(buf, buf->buffer, newsize);
227 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
229 buf->buffer = buffer_ptr;
230 buf->hdr = buf->buffer + NBT_HDR_SIZE;
231 buf->body = buf->hdr + SMB2_HDR_BODY;
232 buf->dynamic = buf->buffer + dynamic_ofs;
233 buf->allocated = newsize;
239 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
240 the ptr points to the start of the offset/length pair
242 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
245 if (smb2_oob(buf, ptr, 4)) {
246 return NT_STATUS_BUFFER_TOO_SMALL;
250 if (ofs == 0 || size == 0) {
251 *blob = data_blob(NULL, 0);
254 if (smb2_oob(buf, buf->hdr + ofs, size)) {
255 return NT_STATUS_BUFFER_TOO_SMALL;
257 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
258 NT_STATUS_HAVE_NO_MEMORY(blob->data);
263 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
264 the ofs points to the start of the offset/length pair, and is relative
267 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
268 uint16_t ofs, DATA_BLOB blob)
272 size_t padding_length;
274 uint8_t *ptr = buf->body+ofs;
276 if (buf->dynamic == NULL) {
277 return NT_STATUS_INVALID_PARAMETER;
280 /* we have only 16 bit for the size */
281 if (blob.length > 0xFFFF) {
282 return NT_STATUS_BUFFER_TOO_SMALL;
285 /* check if there're enough room for ofs and size */
286 if (smb2_oob(buf, ptr, 4)) {
287 return NT_STATUS_BUFFER_TOO_SMALL;
290 if (blob.length == 0) {
296 offset = buf->dynamic - buf->hdr;
297 padding_length = smb2_padding_size(offset, 2);
298 offset += padding_length;
299 padding_fix = smb2_padding_fix(buf);
301 SSVAL(ptr, 0, offset);
302 SSVAL(ptr, 2, blob.length);
304 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
305 NT_STATUS_NOT_OK_RETURN(status);
307 memset(buf->dynamic, 0, padding_length);
308 buf->dynamic += padding_length;
310 memcpy(buf->dynamic, blob.data, blob.length);
311 buf->dynamic += blob.length;
313 buf->size += blob.length + padding_length - padding_fix;
314 buf->body_size += blob.length + padding_length;
321 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
322 the ofs points to the start of the offset/length pair, and is relative
325 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
326 uint16_t ofs, DATA_BLOB blob)
330 size_t padding_length;
332 uint8_t *ptr = buf->body+ofs;
334 if (buf->dynamic == NULL) {
335 return NT_STATUS_INVALID_PARAMETER;
338 /* check if there're enough room for ofs and size */
339 if (smb2_oob(buf, ptr, 6)) {
340 return NT_STATUS_BUFFER_TOO_SMALL;
343 if (blob.length == 0) {
349 offset = buf->dynamic - buf->hdr;
350 padding_length = smb2_padding_size(offset, 2);
351 offset += padding_length;
352 padding_fix = smb2_padding_fix(buf);
354 SSVAL(ptr, 0, offset);
355 SIVAL(ptr, 2, blob.length);
357 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
358 NT_STATUS_NOT_OK_RETURN(status);
360 memset(buf->dynamic, 0, padding_length);
361 buf->dynamic += padding_length;
363 memcpy(buf->dynamic, blob.data, blob.length);
364 buf->dynamic += blob.length;
366 buf->size += blob.length + padding_length - padding_fix;
367 buf->body_size += blob.length + padding_length;
374 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
375 the ofs points to the start of the offset/length pair, and is relative
378 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
379 uint32_t ofs, DATA_BLOB blob)
383 size_t padding_length;
385 uint8_t *ptr = buf->body+ofs;
387 if (buf->dynamic == NULL) {
388 return NT_STATUS_INVALID_PARAMETER;
391 /* check if there're enough room for ofs and size */
392 if (smb2_oob(buf, ptr, 8)) {
393 return NT_STATUS_BUFFER_TOO_SMALL;
396 if (blob.length == 0) {
402 offset = buf->dynamic - buf->hdr;
403 padding_length = smb2_padding_size(offset, 8);
404 offset += padding_length;
405 padding_fix = smb2_padding_fix(buf);
407 SIVAL(ptr, 0, offset);
408 SIVAL(ptr, 4, blob.length);
410 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
411 NT_STATUS_NOT_OK_RETURN(status);
413 memset(buf->dynamic, 0, padding_length);
414 buf->dynamic += padding_length;
416 memcpy(buf->dynamic, blob.data, blob.length);
417 buf->dynamic += blob.length;
419 buf->size += blob.length + padding_length - padding_fix;
420 buf->body_size += blob.length + padding_length;
427 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
428 the ofs points to the start of the length/offset pair, and is relative
431 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
432 uint32_t ofs, DATA_BLOB blob)
436 size_t padding_length;
438 uint8_t *ptr = buf->body+ofs;
440 if (buf->dynamic == NULL) {
441 return NT_STATUS_INVALID_PARAMETER;
444 /* check if there're enough room for ofs and size */
445 if (smb2_oob(buf, ptr, 8)) {
446 return NT_STATUS_BUFFER_TOO_SMALL;
449 if (blob.length == 0) {
455 offset = buf->dynamic - buf->hdr;
456 padding_length = smb2_padding_size(offset, 8);
457 offset += padding_length;
458 padding_fix = smb2_padding_fix(buf);
460 SIVAL(ptr, 0, blob.length);
461 SIVAL(ptr, 4, offset);
463 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
464 NT_STATUS_NOT_OK_RETURN(status);
466 memset(buf->dynamic, 0, padding_length);
467 buf->dynamic += padding_length;
469 memcpy(buf->dynamic, blob.data, blob.length);
470 buf->dynamic += blob.length;
472 buf->size += blob.length + padding_length - padding_fix;
473 buf->body_size += blob.length + padding_length;
479 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
480 the ptr points to the start of the offset/length pair
482 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
487 if (smb2_oob(buf, ptr, 6)) {
488 return NT_STATUS_BUFFER_TOO_SMALL;
492 if (ofs == 0 || size == 0) {
493 *blob = data_blob(NULL, 0);
496 if (smb2_oob(buf, buf->hdr + ofs, size)) {
497 return NT_STATUS_BUFFER_TOO_SMALL;
499 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
500 NT_STATUS_HAVE_NO_MEMORY(blob->data);
505 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
506 the ptr points to the start of the offset/length pair
508 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
511 if (smb2_oob(buf, ptr, 8)) {
512 return NT_STATUS_BUFFER_TOO_SMALL;
516 if (ofs == 0 || size == 0) {
517 *blob = data_blob(NULL, 0);
520 if (smb2_oob(buf, buf->hdr + ofs, size)) {
521 return NT_STATUS_BUFFER_TOO_SMALL;
523 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
524 NT_STATUS_HAVE_NO_MEMORY(blob->data);
529 pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
530 the ptr points to the start of the offset/length pair
532 NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
535 if (smb2_oob(buf, ptr, 8)) {
536 return NT_STATUS_BUFFER_TOO_SMALL;
540 if (ofs == 0 || size == 0) {
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 string in a uint16_t ofs/ uint16_t length/blob format
554 UTF-16 without termination
556 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
557 uint8_t *ptr, const char **str)
564 status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
565 NT_STATUS_NOT_OK_RETURN(status);
567 if (blob.length == 0) {
569 s = talloc_strdup(mem_ctx, "");
570 NT_STATUS_HAVE_NO_MEMORY(s);
575 size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
576 blob.data, blob.length, &vstr);
577 data_blob_free(&blob);
580 return NT_STATUS_ILLEGAL_CHARACTER;
586 push a string in a uint16_t ofs/ uint16_t length/blob format
587 UTF-16 without termination
589 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
590 uint16_t ofs, const char *str)
596 if (strcmp("", str) == 0) {
597 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
600 size = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16,
601 str, strlen(str), (void **)&blob.data);
603 return NT_STATUS_ILLEGAL_CHARACTER;
607 status = smb2_push_o16s16_blob(buf, ofs, blob);
608 data_blob_free(&blob);
613 push a file handle into a buffer
615 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
617 SBVAL(data, 0, h->data[0]);
618 SBVAL(data, 8, h->data[1]);
622 pull a file handle from a buffer
624 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
626 h->data[0] = BVAL(ptr, 0);
627 h->data[1] = BVAL(ptr, 8);