libndr: change subcontext buffer allocation to allocate on subcontext_start.
[abartlet/samba.git/.git] / librpc / ndr / ndr.c
index 2b3493b2e3423ffc66ea4bb42fc686a7685c7a65..80025d71f07d0f1022e4a1bf5b27095de3a2183c 100644 (file)
@@ -355,9 +355,11 @@ _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
        /* the big/little endian flags are inter-dependent */
        if (new_flags & LIBNDR_FLAG_LITTLE_ENDIAN) {
                (*pflags) &= ~LIBNDR_FLAG_BIGENDIAN;
+               (*pflags) &= ~LIBNDR_FLAG_NDR64;
        }
        if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
                (*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
+               (*pflags) &= ~LIBNDR_FLAG_NDR64;
        }
        if (new_flags & LIBNDR_FLAG_REMAINING) {
                (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
@@ -457,7 +459,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
 
        case 4: {
                uint32_t content_size;
-               NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
+               NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &content_size));
                if (size_is >= 0 && size_is != content_size) {
                        return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", 
                                                (int)size_is, (int)content_size);
@@ -542,7 +544,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
 
        subndr = talloc_zero(ndr, struct ndr_pull);
        NDR_ERR_HAVE_NO_MEMORY(subndr);
-       subndr->flags           = ndr->flags;
+       subndr->flags           = ndr->flags & ~LIBNDR_FLAG_NDR64;
        subndr->current_mem_ctx = ndr->current_mem_ctx;
 
        subndr->data = ndr->data + ndr->offset;
@@ -586,7 +588,12 @@ _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
 
        subndr = ndr_push_init_ctx(ndr, ndr->iconv_convenience);
        NDR_ERR_HAVE_NO_MEMORY(subndr);
-       subndr->flags   = ndr->flags;
+       subndr->flags   = ndr->flags & ~LIBNDR_FLAG_NDR64;
+
+       if (size_is > 0) {
+               NDR_CHECK(ndr_push_zero(subndr, size_is));
+               subndr->offset = 0;
+       }
 
        *_subndr = subndr;
        return NDR_ERR_SUCCESS;
@@ -604,12 +611,11 @@ _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
 
        if (size_is >= 0) {
                padding_len = size_is - subndr->offset;
-               if (padding_len > 0) {
-                       NDR_CHECK(ndr_push_zero(subndr, padding_len));
-               } else if (padding_len < 0) {
+               if (padding_len < 0) {
                        return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
                                              (int)subndr->offset, (int)size_is);
                }
+               subndr->offset = size_is;
        }
 
        switch (header_size) {
@@ -621,7 +627,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
                break;
 
        case 4: 
-               NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
+               NDR_CHECK(ndr_push_uint3264(ndr, NDR_SCALARS, subndr->offset));
                break;
 
        case 0xFFFFFC01:
@@ -736,7 +742,7 @@ _PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
 _PUBLIC_ enum ndr_err_code ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
 {
        uint32_t size;
-       NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size));
+       NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &size));
        return ndr_token_store(ndr, &ndr->array_size_list, p, size);
 }
 
@@ -769,12 +775,12 @@ _PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, u
 _PUBLIC_ enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
 {
        uint32_t length, offset;
-       NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &offset));
+       NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &offset));
        if (offset != 0) {
                return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, 
                                      "non-zero array offset %u\n", offset);
        }
-       NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &length));
+       NDR_CHECK(ndr_pull_uint3264(ndr, NDR_SCALARS, &length));
        return ndr_token_store(ndr, &ndr->array_length_list, p, length);
 }
 
@@ -859,13 +865,22 @@ _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLO
                                                    void *p, ndr_pull_flags_fn_t fn)
 {
        struct ndr_pull *ndr;
+       uint32_t highest_ofs;
        ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
        NDR_ERR_HAVE_NO_MEMORY(ndr);
        NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
-       if (ndr->offset < ndr->data_size) {
-               return ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
-                                     "not all bytes consumed ofs[%u] size[%u]",
-                                     ndr->offset, ndr->data_size);
+       if (ndr->offset > ndr->relative_highest_offset) {
+               highest_ofs = ndr->offset;
+       } else {
+               highest_ofs = ndr->relative_highest_offset;
+       }
+       if (highest_ofs < ndr->data_size) {
+               enum ndr_err_code ret;
+               ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
+                                    "not all bytes consumed ofs[%u] size[%u]",
+                                    highest_ofs, ndr->data_size);
+               talloc_free(ndr);
+               return ret;
        }
        talloc_free(ndr);
        return NDR_ERR_SUCCESS;
@@ -896,15 +911,21 @@ _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC
                             uint32_t level, ndr_pull_flags_fn_t fn)
 {
        struct ndr_pull *ndr;
+       uint32_t highest_ofs;
        ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
        NDR_ERR_HAVE_NO_MEMORY(ndr);
        NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
        NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
-       if (ndr->offset < ndr->data_size) {
+       if (ndr->offset > ndr->relative_highest_offset) {
+               highest_ofs = ndr->offset;
+       } else {
+               highest_ofs = ndr->relative_highest_offset;
+       }
+       if (highest_ofs < ndr->data_size) {
                enum ndr_err_code ret;
                ret = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
                                     "not all bytes consumed ofs[%u] size[%u]",
-                                    ndr->offset, ndr->data_size);
+                                    highest_ofs, ndr->data_size);
                talloc_free(ndr);
                return ret;
        }
@@ -1056,11 +1077,25 @@ _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const vo
        return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
 }
 
+/*
+  push a short relative object - stage1
+  this is called during SCALARS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr1(struct ndr_push *ndr, const void *p)
+{
+       if (p == NULL) {
+               NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 0));
+               return NDR_ERR_SUCCESS;
+       }
+       NDR_CHECK(ndr_push_align(ndr, 2));
+       NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
+       return ndr_push_uint16(ndr, NDR_SCALARS, 0xFFFF);
+}
 /*
   push a relative object - stage2
   this is called during buffers processing
 */
-_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
+static enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
 {
        uint32_t save_offset;
        uint32_t ptr_offset = 0xFFFFFFFF;
@@ -1084,6 +1119,58 @@ _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2(struct ndr_push *ndr, const vo
        ndr->offset = save_offset;
        return NDR_ERR_SUCCESS;
 }
+/*
+  push a short relative object - stage2
+  this is called during buffers processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, const void *p)
+{
+       uint32_t save_offset;
+       uint32_t ptr_offset = 0xFFFF;
+       if (p == NULL) {
+               return NDR_ERR_SUCCESS;
+       }
+       save_offset = ndr->offset;
+       NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
+       if (ptr_offset > ndr->offset) {
+               return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+                                     "ndr_push_short_relative_ptr2 ptr_offset(%u) > ndr->offset(%u)",
+                                     ptr_offset, ndr->offset);
+       }
+       ndr->offset = ptr_offset;
+       if (save_offset < ndr->relative_base_offset) {
+               return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+                                     "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
+                                     save_offset, ndr->relative_base_offset);
+       }
+       NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
+       ndr->offset = save_offset;
+       return NDR_ERR_SUCCESS;
+}
+
+/*
+  push a relative object - stage2 start
+  this is called during buffers processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, const void *p)
+{
+       if (p == NULL) {
+               return NDR_ERR_SUCCESS;
+       }
+       return ndr_push_relative_ptr2(ndr, p);
+}
+
+/*
+  push a relative object - stage2 end
+  this is called during buffers processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p)
+{
+       if (p == NULL) {
+               return NDR_ERR_SUCCESS;
+       }
+       return NDR_ERR_SUCCESS;
+}
 
 /*
   get the current base for relative pointers for the pull
@@ -1168,6 +1255,7 @@ const static struct {
        { NDR_ERR_IPV4ADDRESS, "IPv4 Address Error" },
        { NDR_ERR_INVALID_POINTER, "Invalid Pointer" },
        { NDR_ERR_UNREAD_BYTES, "Unread Bytes" },
+       { NDR_ERR_NDR64, "NDR64 assertion error" },
        { 0, NULL }
 };