r15191: Avoid uint_t as it's not standard.
[ab/samba.git/.git] / source4 / libcli / smb2 / request.c
index bb8ff06e2d3d3e00bd8ebb95aaa619cadfa6c282..2476270d49a2e151254fe922a4071cd2c85eb8b5 100644 (file)
@@ -24,7 +24,6 @@
 #include "includes.h"
 #include "libcli/raw/libcliraw.h"
 #include "libcli/smb2/smb2.h"
-#include "libcli/smb2/smb2_calls.h"
 #include "include/dlinklist.h"
 #include "lib/events/events.h"
 
@@ -50,14 +49,15 @@ struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_
 
        ZERO_STRUCT(req->in);
        
-       req->out.allocated = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size+body_dynamic_size;
+       req->out.size      = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
+
+       req->out.allocated = req->out.size + body_dynamic_size;
        req->out.buffer    = talloc_size(req, req->out.allocated);
        if (req->out.buffer == NULL) {
                talloc_free(req);
                return NULL;
        }
 
-       req->out.size      = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size+(body_dynamic_size?1:0);
        req->out.hdr       = req->out.buffer + NBT_HDR_SIZE;
        req->out.body      = req->out.hdr + SMB2_HDR_BODY;
        req->out.body_size = body_fixed_size;
@@ -124,7 +124,7 @@ NTSTATUS smb2_request_destroy(struct smb2_request *req)
                DLIST_REMOVE(req->transport->pending_recv, req);
        }
 
-       if (req->state == SMBCLI_REQUEST_ERROR &&
+       if (req->state == SMB2_REQUEST_ERROR &&
            NT_STATUS_IS_OK(req->status)) {
                req->status = NT_STATUS_INTERNAL_ERROR;
        }
@@ -159,10 +159,16 @@ BOOL smb2_request_is_error(struct smb2_request *req)
        return NT_STATUS_IS_ERR(req->status);
 }
 
+/* Return true if the last packet was OK */
+BOOL smb2_request_is_ok(struct smb2_request *req)
+{
+       return NT_STATUS_IS_OK(req->status);
+}
+
 /*
   check if a range in the reply body is out of bounds
 */
-BOOL smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, uint_t size)
+BOOL smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
 {
        /* be careful with wraparound! */
        if (ptr < buf->body ||
@@ -174,32 +180,36 @@ BOOL smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, uint_t size)
        return False;
 }
 
-static size_t smb2_padding_size(uint32_t offset, size_t n)
+size_t smb2_padding_size(uint32_t offset, size_t n)
 {
        if ((offset & (n-1)) == 0) return 0;
        return n - (offset & (n-1));
 }
 
-static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t n)
+/*
+  grow a SMB2 buffer by the specified amount
+*/
+static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
 {
        size_t dynamic_ofs;
        uint8_t *buffer_ptr;
+       uint32_t newsize = buf->size + increase;
 
        /* a packet size should be limited a bit */
-       if (n >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
+       if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
 
-       if (n <= buf->allocated) return NT_STATUS_OK;
+       if (newsize <= buf->allocated) return NT_STATUS_OK;
 
        dynamic_ofs = buf->dynamic - buf->buffer;
 
-       buffer_ptr = talloc_realloc_size(buf, buf->buffer, n);
+       buffer_ptr = talloc_realloc_size(buf, buf->buffer, newsize);
        NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
 
        buf->buffer     = buffer_ptr;
        buf->hdr        = buf->buffer + NBT_HDR_SIZE;
        buf->body       = buf->hdr    + SMB2_HDR_BODY;
        buf->dynamic    = buf->buffer + dynamic_ofs;
-       buf->allocated  = n;
+       buf->allocated  = newsize;
 
        return NT_STATUS_OK;
 }
@@ -230,15 +240,18 @@ NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_
 
 /*
   push a uint16_t ofs/ uint16_t length/blob triple into a data blob
-  the ptr points to the start of the offset/length pair
+  the ofs points to the start of the offset/length pair, and is relative
+  to the body start
 */
-NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DATA_BLOB blob)
+NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, 
+                              uint16_t ofs, DATA_BLOB blob)
 {
        NTSTATUS status;
        size_t offset;
        size_t padding_length;
+       uint8_t *ptr = buf->body+ofs;
 
-       if (!buf->dynamic) {
+       if (buf->dynamic == NULL) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -252,6 +265,12 @@ NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DA
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
+       if (blob.length == 0) {
+               SSVAL(ptr, 0, 0);
+               SSVAL(ptr, 2, 0);
+               return NT_STATUS_OK;
+       }
+
        offset = buf->dynamic - buf->hdr;
        padding_length = smb2_padding_size(offset, 2);
        offset += padding_length;
@@ -259,7 +278,7 @@ NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DA
        SSVAL(ptr, 0, offset);
        SSVAL(ptr, 2, blob.length);
 
-       status = smb2_grow_buffer(buf, NBT_HDR_SIZE + offset + blob.length);
+       status = smb2_grow_buffer(buf, padding_length + blob.length);
        NT_STATUS_NOT_OK_RETURN(status);
 
        memset(buf->dynamic, 0, padding_length);
@@ -268,48 +287,27 @@ NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DA
        memcpy(buf->dynamic, blob.data, blob.length);
        buf->dynamic += blob.length;
 
-       buf->size = buf->dynamic - buf->buffer;
+       buf->size += blob.length + padding_length;
+       buf->body_size += blob.length + padding_length;
 
        return NT_STATUS_OK;
 }
 
-/*
-  pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
-  the ptr points to the start of the offset/length pair
-*/
-NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
-{
-       uint16_t ofs;
-       uint32_t size;
-
-       if (smb2_oob(buf, ptr, 6)) {
-               return NT_STATUS_BUFFER_TOO_SMALL;
-       }
-       ofs  = SVAL(ptr, 0);
-       size = IVAL(ptr, 2);
-       if (ofs == 0 || size == 0) {
-               *blob = data_blob(NULL, 0);
-               return NT_STATUS_OK;
-       }
-       if (smb2_oob(buf, buf->hdr + ofs, size)) {
-               return NT_STATUS_BUFFER_TOO_SMALL;
-       }
-       *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
-       NT_STATUS_HAVE_NO_MEMORY(blob->data);
-       return NT_STATUS_OK;
-}
 
 /*
   push a uint16_t ofs/ uint32_t length/blob triple into a data blob
-  the ptr points to the start of the offset/length pair
+  the ofs points to the start of the offset/length pair, and is relative
+  to the body start
 */
-NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DATA_BLOB blob)
+NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, 
+                              uint16_t ofs, DATA_BLOB blob)
 {
        NTSTATUS status;
        size_t offset;
        size_t padding_length;
+       uint8_t *ptr = buf->body+ofs;
 
-       if (!buf->dynamic) {
+       if (buf->dynamic == NULL) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -318,6 +316,12 @@ NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DA
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
+       if (blob.length == 0) {
+               SSVAL(ptr, 0, 0);
+               SIVAL(ptr, 2, 0);
+               return NT_STATUS_OK;
+       }
+
        offset = buf->dynamic - buf->hdr;
        padding_length = smb2_padding_size(offset, 2);
        offset += padding_length;
@@ -325,7 +329,7 @@ NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DA
        SSVAL(ptr, 0, offset);
        SIVAL(ptr, 2, blob.length);
 
-       status = smb2_grow_buffer(buf, NBT_HDR_SIZE + offset + blob.length);
+       status = smb2_grow_buffer(buf, padding_length + blob.length);
        NT_STATUS_NOT_OK_RETURN(status);
 
        memset(buf->dynamic, 0, padding_length);
@@ -334,46 +338,78 @@ NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DA
        memcpy(buf->dynamic, blob.data, blob.length);
        buf->dynamic += blob.length;
 
-       buf->size = buf->dynamic - buf->buffer;
+       buf->size += blob.length + padding_length;
+       buf->body_size += blob.length + padding_length;
 
        return NT_STATUS_OK;
 }
 
+
 /*
-  pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
-  the ptr points to the start of the offset/length pair
+  push a uint32_t ofs/ uint32_t length/blob triple into a data blob
+  the ofs points to the start of the offset/length pair, and is relative
+  to the body start
 */
-NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
+NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, 
+                              uint32_t ofs, DATA_BLOB blob)
 {
-       uint32_t ofs, size;
+       NTSTATUS status;
+       size_t offset;
+       size_t padding_length;
+       uint8_t *ptr = buf->body+ofs;
+
+       if (buf->dynamic == NULL) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       /* check if there're enough room for ofs and size */
        if (smb2_oob(buf, ptr, 8)) {
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
-       ofs  = IVAL(ptr, 0);
-       size = IVAL(ptr, 4);
-       if (ofs == 0 || size == 0) {
-               *blob = data_blob(NULL, 0);
+
+       if (blob.length == 0) {
+               SIVAL(ptr, 0, 0);
+               SIVAL(ptr, 4, 0);
                return NT_STATUS_OK;
        }
-       if (smb2_oob(buf, buf->hdr + ofs, size)) {
-               return NT_STATUS_BUFFER_TOO_SMALL;
-       }
-       *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
-       NT_STATUS_HAVE_NO_MEMORY(blob->data);
+
+       offset = buf->dynamic - buf->hdr;
+       padding_length = smb2_padding_size(offset, 8);
+       offset += padding_length;
+
+       SIVAL(ptr, 0, offset);
+       SIVAL(ptr, 4, blob.length);
+
+       status = smb2_grow_buffer(buf, padding_length + blob.length);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       memset(buf->dynamic, 0, padding_length);
+       buf->dynamic += padding_length;
+
+       memcpy(buf->dynamic, blob.data, blob.length);
+       buf->dynamic += blob.length;
+
+       buf->size += blob.length + padding_length;
+       buf->body_size += blob.length + padding_length;
+
        return NT_STATUS_OK;
 }
 
+
 /*
-  push a uint32_t ofs/ uint32_t length/blob triple into a data blob
-  the ptr points to the start of the offset/length pair
+  push a uint32_t length/ uint32_t ofs/blob triple into a data blob
+  the ofs points to the start of the length/offset pair, and is relative
+  to the body start
 */
-NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DATA_BLOB blob)
+NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf, 
+                              uint32_t ofs, DATA_BLOB blob)
 {
        NTSTATUS status;
        size_t offset;
        size_t padding_length;
+       uint8_t *ptr = buf->body+ofs;
 
-       if (!buf->dynamic) {
+       if (buf->dynamic == NULL) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
@@ -382,14 +418,20 @@ NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DA
                return NT_STATUS_BUFFER_TOO_SMALL;
        }
 
+       if (blob.length == 0) {
+               SIVAL(ptr, 0, 0);
+               SIVAL(ptr, 4, 0);
+               return NT_STATUS_OK;
+       }
+
        offset = buf->dynamic - buf->hdr;
        padding_length = smb2_padding_size(offset, 8);
        offset += padding_length;
 
-       SIVAL(ptr, 0, offset);
-       SIVAL(ptr, 4, blob.length);
+       SIVAL(ptr, 0, blob.length);
+       SIVAL(ptr, 4, offset);
 
-       status = smb2_grow_buffer(buf, NBT_HDR_SIZE + offset + blob.length);
+       status = smb2_grow_buffer(buf, padding_length + blob.length);
        NT_STATUS_NOT_OK_RETURN(status);
 
        memset(buf->dynamic, 0, padding_length);
@@ -398,8 +440,59 @@ NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, uint8_t *ptr, DA
        memcpy(buf->dynamic, blob.data, blob.length);
        buf->dynamic += blob.length;
 
-       buf->size = buf->dynamic - buf->buffer;
+       buf->size += blob.length + padding_length;
+       buf->body_size += blob.length + padding_length;
+
+       return NT_STATUS_OK;
+}
+
+/*
+  pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
+  the ptr points to the start of the offset/length pair
+*/
+NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
+{
+       uint16_t ofs;
+       uint32_t size;
+
+       if (smb2_oob(buf, ptr, 6)) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+       ofs  = SVAL(ptr, 0);
+       size = IVAL(ptr, 2);
+       if (ofs == 0 || size == 0) {
+               *blob = data_blob(NULL, 0);
+               return NT_STATUS_OK;
+       }
+       if (smb2_oob(buf, buf->hdr + ofs, size)) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+       *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
+       NT_STATUS_HAVE_NO_MEMORY(blob->data);
+       return NT_STATUS_OK;
+}
 
+/*
+  pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
+  the ptr points to the start of the offset/length pair
+*/
+NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
+{
+       uint32_t ofs, size;
+       if (smb2_oob(buf, ptr, 8)) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+       ofs  = IVAL(ptr, 0);
+       size = IVAL(ptr, 4);
+       if (ofs == 0 || size == 0) {
+               *blob = data_blob(NULL, 0);
+               return NT_STATUS_OK;
+       }
+       if (smb2_oob(buf, buf->hdr + ofs, size)) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+       *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
+       NT_STATUS_HAVE_NO_MEMORY(blob->data);
        return NT_STATUS_OK;
 }
 
@@ -433,12 +526,16 @@ NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *me
   UTF-16 without termination
 */
 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
-                                uint8_t *ptr, const char *str)
+                                uint16_t ofs, const char *str)
 {
        DATA_BLOB blob;
        NTSTATUS status;
        ssize_t size;
 
+       if (strcmp("", str) == 0) {
+               return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
+       }
+
        size = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16, 
                                     str, strlen(str), (void **)&blob.data);
        if (size == -1) {
@@ -446,11 +543,9 @@ NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
        }
        blob.length = size;
 
-       status = smb2_push_o16s16_blob(buf, ptr, blob);
+       status = smb2_push_o16s16_blob(buf, ofs, blob);
        data_blob_free(&blob);
-       NT_STATUS_NOT_OK_RETURN(status);
-
-       return NT_STATUS_OK;
+       return status;
 }
 
 /*