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 "lib/util/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;
40 if (body_dynamic_present) {
41 if (body_dynamic_size == 0) {
42 body_dynamic_size = 1;
45 body_dynamic_size = 0;
48 req = talloc(transport, struct smb2_request);
49 if (req == NULL) return NULL;
51 seqnum = transport->seqnum++;
52 if (seqnum == UINT64_MAX) {
53 seqnum = transport->seqnum++;
56 req->state = SMB2_REQUEST_INIT;
57 req->transport = transport;
61 req->status = NT_STATUS_OK;
63 req->next = req->prev = NULL;
65 ZERO_STRUCT(req->cancel);
68 req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
70 req->out.allocated = req->out.size + body_dynamic_size;
71 req->out.buffer = talloc_size(req, req->out.allocated);
72 if (req->out.buffer == NULL) {
77 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
78 req->out.body = req->out.hdr + SMB2_HDR_BODY;
79 req->out.body_fixed= body_fixed_size;
80 req->out.body_size = body_fixed_size;
81 req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
83 SIVAL(req->out.hdr, 0, SMB2_MAGIC);
84 SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
85 SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
86 SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
87 SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
88 SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0);
89 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
90 SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0);
91 SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
92 SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
93 SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
94 SBVAL(req->out.hdr, SMB2_HDR_UID, 0);
95 memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
97 /* set the length of the fixed body part and +1 if there's a dynamic part also */
98 SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
101 * if we have a dynamic part, make sure the first byte
102 * which is always be part of the packet is initialized
104 if (body_dynamic_size) {
106 SCVAL(req->out.dynamic, 0, 0);
113 initialise a smb2 request for tree operations
115 struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
116 uint16_t body_fixed_size, BOOL body_dynamic_present,
117 uint32_t body_dynamic_size)
119 struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
120 body_fixed_size, body_dynamic_present,
122 if (req == NULL) return NULL;
124 SBVAL(req->out.hdr, SMB2_HDR_UID, tree->session->uid);
125 SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid);
126 req->session = tree->session;
132 /* destroy a request structure and return final status */
133 NTSTATUS smb2_request_destroy(struct smb2_request *req)
137 /* this is the error code we give the application for when a
138 _send() call fails completely */
139 if (!req) return NT_STATUS_UNSUCCESSFUL;
141 if (req->transport) {
142 /* remove it from the list of pending requests (a null op if
143 its not in the list) */
144 DLIST_REMOVE(req->transport->pending_recv, req);
147 if (req->state == SMB2_REQUEST_ERROR &&
148 NT_STATUS_IS_OK(req->status)) {
149 req->status = NT_STATUS_INTERNAL_ERROR;
152 status = req->status;
158 receive a response to a packet
160 BOOL smb2_request_receive(struct smb2_request *req)
162 /* req can be NULL when a send has failed. This eliminates lots of NULL
163 checks in each module */
164 if (!req) return False;
166 /* keep receiving packets until this one is replied to */
167 while (req->state <= SMB2_REQUEST_RECV) {
168 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
173 return req->state == SMB2_REQUEST_DONE;
176 /* Return true if the last packet was in error */
177 BOOL smb2_request_is_error(struct smb2_request *req)
179 return NT_STATUS_IS_ERR(req->status);
182 /* Return true if the last packet was OK */
183 BOOL smb2_request_is_ok(struct smb2_request *req)
185 return NT_STATUS_IS_OK(req->status);
189 check if a range in the reply body is out of bounds
191 BOOL smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
193 /* be careful with wraparound! */
194 if (ptr < buf->body ||
195 ptr >= buf->body + buf->body_size ||
196 size > buf->body_size ||
197 ptr + size > buf->body + buf->body_size) {
203 size_t smb2_padding_size(uint32_t offset, size_t n)
205 if ((offset & (n-1)) == 0) return 0;
206 return n - (offset & (n-1));
209 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
211 if (buf->dynamic == (buf->body + buf->body_fixed)) {
218 grow a SMB2 buffer by the specified amount
220 static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
224 uint32_t newsize = buf->size + increase;
226 /* a packet size should be limited a bit */
227 if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
229 if (newsize <= buf->allocated) return NT_STATUS_OK;
231 dynamic_ofs = buf->dynamic - buf->buffer;
233 buffer_ptr = talloc_realloc_size(buf, buf->buffer, newsize);
234 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
236 buf->buffer = buffer_ptr;
237 buf->hdr = buf->buffer + NBT_HDR_SIZE;
238 buf->body = buf->hdr + SMB2_HDR_BODY;
239 buf->dynamic = buf->buffer + dynamic_ofs;
240 buf->allocated = newsize;
246 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
247 the ptr points to the start of the offset/length pair
249 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
252 if (smb2_oob(buf, ptr, 4)) {
253 return NT_STATUS_BUFFER_TOO_SMALL;
257 if (ofs == 0 || size == 0) {
258 *blob = data_blob(NULL, 0);
261 if (smb2_oob(buf, buf->hdr + ofs, size)) {
262 return NT_STATUS_BUFFER_TOO_SMALL;
264 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
265 NT_STATUS_HAVE_NO_MEMORY(blob->data);
270 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
271 the ofs points to the start of the offset/length pair, and is relative
274 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
275 uint16_t ofs, DATA_BLOB blob)
279 size_t padding_length;
281 uint8_t *ptr = buf->body+ofs;
283 if (buf->dynamic == NULL) {
284 return NT_STATUS_INVALID_PARAMETER;
287 /* we have only 16 bit for the size */
288 if (blob.length > 0xFFFF) {
289 return NT_STATUS_BUFFER_TOO_SMALL;
292 /* check if there're enough room for ofs and size */
293 if (smb2_oob(buf, ptr, 4)) {
294 return NT_STATUS_BUFFER_TOO_SMALL;
297 if (blob.length == 0) {
303 offset = buf->dynamic - buf->hdr;
304 padding_length = smb2_padding_size(offset, 2);
305 offset += padding_length;
306 padding_fix = smb2_padding_fix(buf);
308 SSVAL(ptr, 0, offset);
309 SSVAL(ptr, 2, blob.length);
311 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
312 NT_STATUS_NOT_OK_RETURN(status);
314 memset(buf->dynamic, 0, padding_length);
315 buf->dynamic += padding_length;
317 memcpy(buf->dynamic, blob.data, blob.length);
318 buf->dynamic += blob.length;
320 buf->size += blob.length + padding_length - padding_fix;
321 buf->body_size += blob.length + padding_length;
328 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
329 the ofs points to the start of the offset/length pair, and is relative
332 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
333 uint16_t ofs, DATA_BLOB blob)
337 size_t padding_length;
339 uint8_t *ptr = buf->body+ofs;
341 if (buf->dynamic == NULL) {
342 return NT_STATUS_INVALID_PARAMETER;
345 /* check if there're enough room for ofs and size */
346 if (smb2_oob(buf, ptr, 6)) {
347 return NT_STATUS_BUFFER_TOO_SMALL;
350 if (blob.length == 0) {
356 offset = buf->dynamic - buf->hdr;
357 padding_length = smb2_padding_size(offset, 2);
358 offset += padding_length;
359 padding_fix = smb2_padding_fix(buf);
361 SSVAL(ptr, 0, offset);
362 SIVAL(ptr, 2, blob.length);
364 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
365 NT_STATUS_NOT_OK_RETURN(status);
367 memset(buf->dynamic, 0, padding_length);
368 buf->dynamic += padding_length;
370 memcpy(buf->dynamic, blob.data, blob.length);
371 buf->dynamic += blob.length;
373 buf->size += blob.length + padding_length - padding_fix;
374 buf->body_size += blob.length + padding_length;
381 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
382 the ofs points to the start of the offset/length pair, and is relative
385 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
386 uint32_t ofs, DATA_BLOB blob)
390 size_t padding_length;
392 uint8_t *ptr = buf->body+ofs;
394 if (buf->dynamic == NULL) {
395 return NT_STATUS_INVALID_PARAMETER;
398 /* check if there're enough room for ofs and size */
399 if (smb2_oob(buf, ptr, 8)) {
400 return NT_STATUS_BUFFER_TOO_SMALL;
403 if (blob.length == 0) {
409 offset = buf->dynamic - buf->hdr;
410 padding_length = smb2_padding_size(offset, 8);
411 offset += padding_length;
412 padding_fix = smb2_padding_fix(buf);
414 SIVAL(ptr, 0, offset);
415 SIVAL(ptr, 4, blob.length);
417 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
418 NT_STATUS_NOT_OK_RETURN(status);
420 memset(buf->dynamic, 0, padding_length);
421 buf->dynamic += padding_length;
423 memcpy(buf->dynamic, blob.data, blob.length);
424 buf->dynamic += blob.length;
426 buf->size += blob.length + padding_length - padding_fix;
427 buf->body_size += blob.length + padding_length;
434 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
435 the ofs points to the start of the length/offset pair, and is relative
438 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
439 uint32_t ofs, DATA_BLOB blob)
443 size_t padding_length;
445 uint8_t *ptr = buf->body+ofs;
447 if (buf->dynamic == NULL) {
448 return NT_STATUS_INVALID_PARAMETER;
451 /* check if there're enough room for ofs and size */
452 if (smb2_oob(buf, ptr, 8)) {
453 return NT_STATUS_BUFFER_TOO_SMALL;
456 if (blob.length == 0) {
462 offset = buf->dynamic - buf->hdr;
463 padding_length = smb2_padding_size(offset, 8);
464 offset += padding_length;
465 padding_fix = smb2_padding_fix(buf);
467 SIVAL(ptr, 0, blob.length);
468 SIVAL(ptr, 4, offset);
470 status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
471 NT_STATUS_NOT_OK_RETURN(status);
473 memset(buf->dynamic, 0, padding_length);
474 buf->dynamic += padding_length;
476 memcpy(buf->dynamic, blob.data, blob.length);
477 buf->dynamic += blob.length;
479 buf->size += blob.length + padding_length - padding_fix;
480 buf->body_size += blob.length + padding_length;
486 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
487 the ptr points to the start of the offset/length pair
489 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
494 if (smb2_oob(buf, ptr, 6)) {
495 return NT_STATUS_BUFFER_TOO_SMALL;
499 if (ofs == 0 || size == 0) {
500 *blob = data_blob(NULL, 0);
503 if (smb2_oob(buf, buf->hdr + ofs, size)) {
504 return NT_STATUS_BUFFER_TOO_SMALL;
506 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
507 NT_STATUS_HAVE_NO_MEMORY(blob->data);
512 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
513 the ptr points to the start of the offset/length pair
515 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
518 if (smb2_oob(buf, ptr, 8)) {
519 return NT_STATUS_BUFFER_TOO_SMALL;
523 if (ofs == 0 || size == 0) {
524 *blob = data_blob(NULL, 0);
527 if (smb2_oob(buf, buf->hdr + ofs, size)) {
528 return NT_STATUS_BUFFER_TOO_SMALL;
530 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
531 NT_STATUS_HAVE_NO_MEMORY(blob->data);
536 pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
537 the ptr points to the start of the offset/length pair
539 NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
542 if (smb2_oob(buf, ptr, 8)) {
543 return NT_STATUS_BUFFER_TOO_SMALL;
547 if (ofs == 0 || size == 0) {
548 *blob = data_blob(NULL, 0);
551 if (smb2_oob(buf, buf->hdr + ofs, size)) {
552 return NT_STATUS_BUFFER_TOO_SMALL;
554 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
555 NT_STATUS_HAVE_NO_MEMORY(blob->data);
560 pull a string in a uint16_t ofs/ uint16_t length/blob format
561 UTF-16 without termination
563 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
564 uint8_t *ptr, const char **str)
571 status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
572 NT_STATUS_NOT_OK_RETURN(status);
574 if (blob.length == 0) {
576 s = talloc_strdup(mem_ctx, "");
577 NT_STATUS_HAVE_NO_MEMORY(s);
582 size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
583 blob.data, blob.length, &vstr);
584 data_blob_free(&blob);
587 return NT_STATUS_ILLEGAL_CHARACTER;
593 push a string in a uint16_t ofs/ uint16_t length/blob format
594 UTF-16 without termination
596 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
597 uint16_t ofs, const char *str)
603 if (strcmp("", str) == 0) {
604 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
607 size = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16,
608 str, strlen(str), (void **)&blob.data);
610 return NT_STATUS_ILLEGAL_CHARACTER;
614 status = smb2_push_o16s16_blob(buf, ofs, blob);
615 data_blob_free(&blob);
620 push a file handle into a buffer
622 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
624 SBVAL(data, 0, h->data[0]);
625 SBVAL(data, 8, h->data[1]);
629 pull a file handle from a buffer
631 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
633 h->data[0] = BVAL(ptr, 0);
634 h->data[1] = BVAL(ptr, 8);