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 "libcli/smb2/smb2_calls.h"
28 #include "include/dlinklist.h"
29 #include "lib/events/events.h"
32 initialise a smb2 request
34 struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
35 uint16_t body_fixed_size, uint32_t body_dynamic_size)
37 struct smb2_request *req;
39 req = talloc(transport, struct smb2_request);
40 if (req == NULL) return NULL;
42 req->state = SMB2_REQUEST_INIT;
43 req->transport = transport;
46 req->seqnum = transport->seqnum++;
47 req->status = NT_STATUS_OK;
49 req->next = req->prev = NULL;
53 req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
55 req->out.allocated = req->out.size + body_dynamic_size;
56 req->out.buffer = talloc_size(req, req->out.allocated);
57 if (req->out.buffer == NULL) {
62 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
63 req->out.body = req->out.hdr + SMB2_HDR_BODY;
64 req->out.body_size = body_fixed_size;
65 req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
67 SIVAL(req->out.hdr, 0, SMB2_MAGIC);
68 SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
69 SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
70 SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
71 SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
72 SSVAL(req->out.hdr, SMB2_HDR_PAD2, 0);
73 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
74 SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN, 0);
75 SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
76 SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
77 SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
78 SBVAL(req->out.hdr, SMB2_HDR_UID, 0);
79 memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
81 /* set the length of the fixed body part and +1 if there's a dynamic part also */
82 SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
85 * if we have a dynamic part, make sure the first byte
86 * which is always be part of the packet is initialized
88 if (body_dynamic_size) {
89 SCVAL(req->out.dynamic, 0, 0);
96 initialise a smb2 request for tree operations
98 struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
99 uint16_t body_fixed_size, uint32_t body_dynamic_size)
101 struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
102 body_fixed_size, body_dynamic_size);
103 if (req == NULL) return NULL;
105 SBVAL(req->out.hdr, SMB2_HDR_UID, tree->session->uid);
106 SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid);
107 req->session = tree->session;
113 /* destroy a request structure and return final status */
114 NTSTATUS smb2_request_destroy(struct smb2_request *req)
118 /* this is the error code we give the application for when a
119 _send() call fails completely */
120 if (!req) return NT_STATUS_UNSUCCESSFUL;
122 if (req->transport) {
123 /* remove it from the list of pending requests (a null op if
124 its not in the list) */
125 DLIST_REMOVE(req->transport->pending_recv, req);
128 if (req->state == SMBCLI_REQUEST_ERROR &&
129 NT_STATUS_IS_OK(req->status)) {
130 req->status = NT_STATUS_INTERNAL_ERROR;
133 status = req->status;
139 receive a response to a packet
141 BOOL smb2_request_receive(struct smb2_request *req)
143 /* req can be NULL when a send has failed. This eliminates lots of NULL
144 checks in each module */
145 if (!req) return False;
147 /* keep receiving packets until this one is replied to */
148 while (req->state <= SMB2_REQUEST_RECV) {
149 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
154 return req->state == SMB2_REQUEST_DONE;
157 /* Return true if the last packet was in error */
158 BOOL smb2_request_is_error(struct smb2_request *req)
160 return NT_STATUS_IS_ERR(req->status);
163 /* Return true if the last packet was OK */
164 BOOL smb2_request_is_ok(struct smb2_request *req)
166 return NT_STATUS_IS_OK(req->status);
170 check if a range in the reply body is out of bounds
172 BOOL smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, uint_t size)
174 /* be careful with wraparound! */
175 if (ptr < buf->body ||
176 ptr >= buf->body + buf->body_size ||
177 size > buf->body_size ||
178 ptr + size > buf->body + buf->body_size) {
184 static size_t smb2_padding_size(uint32_t offset, size_t n)
186 if ((offset & (n-1)) == 0) return 0;
187 return n - (offset & (n-1));
191 grow a SMB2 buffer by the specified amount
193 static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
197 uint32_t newsize = buf->size + increase;
199 /* a packet size should be limited a bit */
200 if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
202 if (newsize <= buf->allocated) return NT_STATUS_OK;
204 dynamic_ofs = buf->dynamic - buf->buffer;
206 buffer_ptr = talloc_realloc_size(buf, buf->buffer, newsize);
207 NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
209 buf->buffer = buffer_ptr;
210 buf->hdr = buf->buffer + NBT_HDR_SIZE;
211 buf->body = buf->hdr + SMB2_HDR_BODY;
212 buf->dynamic = buf->buffer + dynamic_ofs;
213 buf->allocated = newsize;
219 pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
220 the ptr points to the start of the offset/length pair
222 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
225 if (smb2_oob(buf, ptr, 4)) {
226 return NT_STATUS_BUFFER_TOO_SMALL;
230 if (ofs == 0 || size == 0) {
231 *blob = data_blob(NULL, 0);
234 if (smb2_oob(buf, buf->hdr + ofs, size)) {
235 return NT_STATUS_BUFFER_TOO_SMALL;
237 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
238 NT_STATUS_HAVE_NO_MEMORY(blob->data);
243 push a uint16_t ofs/ uint16_t length/blob triple into a data blob
244 the ofs points to the start of the offset/length pair, and is relative
247 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
248 uint16_t ofs, DATA_BLOB blob)
252 size_t padding_length;
253 uint8_t *ptr = buf->body+ofs;
255 if (buf->dynamic == NULL) {
256 return NT_STATUS_INVALID_PARAMETER;
259 /* we have only 16 bit for the size */
260 if (blob.length > 0xFFFF) {
261 return NT_STATUS_BUFFER_TOO_SMALL;
264 /* check if there're enough room for ofs and size */
265 if (smb2_oob(buf, ptr, 4)) {
266 return NT_STATUS_BUFFER_TOO_SMALL;
269 if (blob.length == 0) {
275 offset = buf->dynamic - buf->hdr;
276 padding_length = smb2_padding_size(offset, 2);
277 offset += padding_length;
279 SSVAL(ptr, 0, offset);
280 SSVAL(ptr, 2, blob.length);
282 status = smb2_grow_buffer(buf, padding_length + blob.length);
283 NT_STATUS_NOT_OK_RETURN(status);
285 memset(buf->dynamic, 0, padding_length);
286 buf->dynamic += padding_length;
288 memcpy(buf->dynamic, blob.data, blob.length);
289 buf->dynamic += blob.length;
291 buf->size += blob.length + padding_length;
292 buf->body_size += blob.length + padding_length;
299 push a uint16_t ofs/ uint32_t length/blob triple into a data blob
300 the ofs points to the start of the offset/length pair, and is relative
303 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
304 uint16_t ofs, DATA_BLOB blob)
308 size_t padding_length;
309 uint8_t *ptr = buf->body+ofs;
311 if (buf->dynamic == NULL) {
312 return NT_STATUS_INVALID_PARAMETER;
315 /* check if there're enough room for ofs and size */
316 if (smb2_oob(buf, ptr, 6)) {
317 return NT_STATUS_BUFFER_TOO_SMALL;
320 if (blob.length == 0) {
326 offset = buf->dynamic - buf->hdr;
327 padding_length = smb2_padding_size(offset, 2);
328 offset += padding_length;
330 SSVAL(ptr, 0, offset);
331 SIVAL(ptr, 2, blob.length);
333 status = smb2_grow_buffer(buf, padding_length + blob.length);
334 NT_STATUS_NOT_OK_RETURN(status);
336 memset(buf->dynamic, 0, padding_length);
337 buf->dynamic += padding_length;
339 memcpy(buf->dynamic, blob.data, blob.length);
340 buf->dynamic += blob.length;
342 buf->size += blob.length + padding_length;
343 buf->body_size += blob.length + padding_length;
350 push a uint32_t ofs/ uint32_t length/blob triple into a data blob
351 the ofs points to the start of the offset/length pair, and is relative
354 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
355 uint32_t ofs, DATA_BLOB blob)
359 size_t padding_length;
360 uint8_t *ptr = buf->body+ofs;
362 if (buf->dynamic == NULL) {
363 return NT_STATUS_INVALID_PARAMETER;
366 /* check if there're enough room for ofs and size */
367 if (smb2_oob(buf, ptr, 8)) {
368 return NT_STATUS_BUFFER_TOO_SMALL;
371 if (blob.length == 0) {
377 offset = buf->dynamic - buf->hdr;
378 padding_length = smb2_padding_size(offset, 8);
379 offset += padding_length;
381 SIVAL(ptr, 0, offset);
382 SIVAL(ptr, 4, blob.length);
384 status = smb2_grow_buffer(buf, padding_length + blob.length);
385 NT_STATUS_NOT_OK_RETURN(status);
387 memset(buf->dynamic, 0, padding_length);
388 buf->dynamic += padding_length;
390 memcpy(buf->dynamic, blob.data, blob.length);
391 buf->dynamic += blob.length;
393 buf->size += blob.length + padding_length;
394 buf->body_size += blob.length + padding_length;
401 push a uint32_t length/ uint32_t ofs/blob triple into a data blob
402 the ofs points to the start of the length/offset pair, and is relative
405 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
406 uint32_t ofs, DATA_BLOB blob)
410 size_t padding_length;
411 uint8_t *ptr = buf->body+ofs;
413 if (buf->dynamic == NULL) {
414 return NT_STATUS_INVALID_PARAMETER;
417 /* check if there're enough room for ofs and size */
418 if (smb2_oob(buf, ptr, 8)) {
419 return NT_STATUS_BUFFER_TOO_SMALL;
422 if (blob.length == 0) {
428 offset = buf->dynamic - buf->hdr;
429 padding_length = smb2_padding_size(offset, 8);
430 offset += padding_length;
432 SIVAL(ptr, 0, blob.length);
433 SIVAL(ptr, 4, offset);
435 status = smb2_grow_buffer(buf, padding_length + blob.length);
436 NT_STATUS_NOT_OK_RETURN(status);
438 memset(buf->dynamic, 0, padding_length);
439 buf->dynamic += padding_length;
441 memcpy(buf->dynamic, blob.data, blob.length);
442 buf->dynamic += blob.length;
444 buf->size += blob.length + padding_length;
445 buf->body_size += blob.length + padding_length;
451 pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
452 the ptr points to the start of the offset/length pair
454 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
459 if (smb2_oob(buf, ptr, 6)) {
460 return NT_STATUS_BUFFER_TOO_SMALL;
464 if (ofs == 0 || size == 0) {
465 *blob = data_blob(NULL, 0);
468 if (smb2_oob(buf, buf->hdr + ofs, size)) {
469 return NT_STATUS_BUFFER_TOO_SMALL;
471 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
472 NT_STATUS_HAVE_NO_MEMORY(blob->data);
477 pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
478 the ptr points to the start of the offset/length pair
480 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
483 if (smb2_oob(buf, ptr, 8)) {
484 return NT_STATUS_BUFFER_TOO_SMALL;
488 if (ofs == 0 || size == 0) {
489 *blob = data_blob(NULL, 0);
492 if (smb2_oob(buf, buf->hdr + ofs, size)) {
493 return NT_STATUS_BUFFER_TOO_SMALL;
495 *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
496 NT_STATUS_HAVE_NO_MEMORY(blob->data);
501 pull a string in a uint16_t ofs/ uint16_t length/blob format
502 UTF-16 without termination
504 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
505 uint8_t *ptr, const char **str)
512 status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
513 NT_STATUS_NOT_OK_RETURN(status);
515 size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
516 blob.data, blob.length, &vstr);
517 data_blob_free(&blob);
520 return NT_STATUS_ILLEGAL_CHARACTER;
526 push a string in a uint16_t ofs/ uint16_t length/blob format
527 UTF-16 without termination
529 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
530 uint16_t ofs, const char *str)
536 if (strcmp("", str) == 0) {
537 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
540 size = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16,
541 str, strlen(str), (void **)&blob.data);
543 return NT_STATUS_ILLEGAL_CHARACTER;
547 status = smb2_push_o16s16_blob(buf, ofs, blob);
548 data_blob_free(&blob);
553 push a file handle into a buffer
555 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
557 SBVAL(data, 0, h->data[0]);
558 SBVAL(data, 8, h->data[1]);
562 pull a file handle from a buffer
564 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
566 h->data[0] = BVAL(ptr, 0);
567 h->data[1] = BVAL(ptr, 8);