Finish removal of iconv_convenience in public API's.
[bbaumbach/samba-autobuild/.git] / librpc / ndr / ndr.c
index 2341f51faa03315032ea03c8c81fecdbc090e164..1600d51c1c0791b07be13d536fbd493192e22eb5 100644 (file)
@@ -58,7 +58,7 @@ _PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
 /*
   initialise a ndr parse structure from a data blob
 */
-_PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
+_PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
 {
        struct ndr_pull *ndr;
 
@@ -68,7 +68,6 @@ _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *
 
        ndr->data = blob->data;
        ndr->data_size = blob->length;
-       ndr->iconv_convenience = talloc_reference(ndr, iconv_convenience);
 
        return ndr;
 }
@@ -102,7 +101,7 @@ static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
 }
 
 /* create a ndr_push structure, ready for some marshalling */
-_PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
+_PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
 {
        struct ndr_push *ndr;
 
@@ -117,7 +116,6 @@ _PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx, struct smb_icon
        if (!ndr->data) {
                return NULL;
        }
-       ndr->iconv_convenience = talloc_reference(ndr, iconv_convenience);
 
        return ndr;
 }
@@ -179,10 +177,10 @@ _PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format,
        }
 
        for (i=0;i<ndr->depth;i++) {
-               DEBUGADD(0,("    "));
+               DEBUGADD(1,("    "));
        }
 
-       DEBUGADD(0,("%s\n", s));
+       DEBUGADD(1,("%s\n", s));
        free(s);
 }
 
@@ -211,7 +209,7 @@ _PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
 {
        struct ndr_print *ndr;
 
-       DEBUG(0,(" "));
+       DEBUG(1,(" "));
 
        ndr = talloc_zero(NULL, struct ndr_print);
        if (!ndr) return;
@@ -229,7 +227,7 @@ _PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_
 {
        struct ndr_print *ndr;
 
-       DEBUG(0,(" "));
+       DEBUG(1,(" "));
 
        ndr = talloc_zero(NULL, struct ndr_print);
        if (!ndr) return;
@@ -248,13 +246,14 @@ _PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name
 {
        struct ndr_print *ndr;
 
-       DEBUG(0,(" "));
+       DEBUG(1,(" "));
 
        ndr = talloc_zero(NULL, struct ndr_print);
        if (!ndr) return;
        ndr->print = ndr_print_debug_helper;
        ndr->depth = 1;
        ndr->flags = 0;
+
        fn(ndr, name, flags, ptr);
        talloc_free(ndr);
 }
@@ -276,6 +275,7 @@ _PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, c
        ndr->print = ndr_print_string_helper;
        ndr->depth = 1;
        ndr->flags = 0;
+
        fn(ndr, name, ptr);
        ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
 failed:
@@ -339,9 +339,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;
@@ -349,6 +351,9 @@ _PUBLIC_ void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
        if (new_flags & LIBNDR_ALIGN_FLAGS) {
                (*pflags) &= ~LIBNDR_FLAG_REMAINING;
        }
+       if (new_flags & LIBNDR_FLAG_NO_RELATIVE_REVERSE) {
+               (*pflags) &= ~LIBNDR_FLAG_RELATIVE_REVERSE;
+       }
        (*pflags) |= new_flags;
 }
 
@@ -441,7 +446,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);
@@ -526,13 +531,12 @@ _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;
        subndr->offset = 0;
        subndr->data_size = r_content_size;
-       subndr->iconv_convenience = talloc_reference(subndr, ndr->iconv_convenience);
 
        if (force_le) {
                ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN);
@@ -568,9 +572,15 @@ _PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
 {
        struct ndr_push *subndr;
 
-       subndr = ndr_push_init_ctx(ndr, ndr->iconv_convenience);
+       subndr = ndr_push_init_ctx(ndr);
        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->relative_end_offset = size_is;
+       }
 
        *_subndr = subndr;
        return NDR_ERR_SUCCESS;
@@ -588,12 +598,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) {
@@ -605,7 +614,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:
@@ -720,7 +729,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);
 }
 
@@ -753,12 +762,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);
 }
 
@@ -824,13 +833,14 @@ _PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *
 /*
   pull a struct from a blob using NDR
 */
-_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, void *p,
+_PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
                              ndr_pull_flags_fn_t fn)
 {
        struct ndr_pull *ndr;
-       ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
+       ndr = ndr_pull_init_blob(blob, mem_ctx);
        NDR_ERR_HAVE_NO_MEMORY(ndr);
-       NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+       NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+       talloc_free(ndr);
        return NDR_ERR_SUCCESS;
 }
 
@@ -838,18 +848,27 @@ _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CT
   pull a struct from a blob using NDR - failing if all bytes are not consumed
 */
 _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
-                                                   struct smb_iconv_convenience *iconv_convenience,
                                                    void *p, ndr_pull_flags_fn_t fn)
 {
        struct ndr_pull *ndr;
-       ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
+       uint32_t highest_ofs;
+       ndr = ndr_pull_init_blob(blob, mem_ctx);
        NDR_ERR_HAVE_NO_MEMORY(ndr);
-       NDR_CHECK(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);
+       NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+       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;
 }
 
@@ -857,14 +876,15 @@ _PUBLIC_ enum ndr_err_code ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLO
   pull a union from a blob using NDR, given the union discriminator
 */
 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
-                                              struct smb_iconv_convenience *iconv_convenience, void *p,
+                                              void *p,
                             uint32_t level, ndr_pull_flags_fn_t fn)
 {
        struct ndr_pull *ndr;
-       ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
+       ndr = ndr_pull_init_blob(blob, mem_ctx);
        NDR_ERR_HAVE_NO_MEMORY(ndr);
-       NDR_CHECK(ndr_pull_set_switch_value(ndr, p, level));
-       NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+       NDR_CHECK_FREE(ndr_pull_set_switch_value(ndr, p, level));
+       NDR_CHECK_FREE(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+       talloc_free(ndr);
        return NDR_ERR_SUCCESS;
 }
 
@@ -873,29 +893,39 @@ _PUBLIC_ enum ndr_err_code ndr_pull_union_blob(const DATA_BLOB *blob, TALLOC_CTX
   failing if all bytes are not consumed
 */
 _PUBLIC_ enum ndr_err_code ndr_pull_union_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
-                                                  struct smb_iconv_convenience *iconv_convenience, void *p,
+                                                  void *p,
                             uint32_t level, ndr_pull_flags_fn_t fn)
 {
        struct ndr_pull *ndr;
-       ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
+       uint32_t highest_ofs;
+       ndr = ndr_pull_init_blob(blob, mem_ctx);
        NDR_ERR_HAVE_NO_MEMORY(ndr);
-       NDR_CHECK(ndr_pull_set_switch_value(ndr, p, level));
-       NDR_CHECK(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);
+       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->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;
 }
 
 /*
   push a struct to a blob using NDR
 */
-_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, const void *p, ndr_push_flags_fn_t fn)
+_PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, ndr_push_flags_fn_t fn)
 {
        struct ndr_push *ndr;
-       ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience);
+       ndr = ndr_push_init_ctx(mem_ctx);
        NDR_ERR_HAVE_NO_MEMORY(ndr);
 
        NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
@@ -910,11 +940,11 @@ _PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem
 /*
   push a union to a blob using NDR
 */
-_PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience, void *p,
+_PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
                             uint32_t level, ndr_push_flags_fn_t fn)
 {
        struct ndr_push *ndr;
-       ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience);
+       ndr = ndr_push_init_ctx(mem_ctx);
        NDR_ERR_HAVE_NO_MEMORY(ndr);
 
        NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
@@ -930,7 +960,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_
 /*
   generic ndr_size_*() handler for structures
 */
-_PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push, struct smb_iconv_convenience *iconv_convenience)
+_PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
 {
        struct ndr_push *ndr;
        enum ndr_err_code status;
@@ -939,7 +969,7 @@ _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t pu
        /* avoid recursion */
        if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
 
-       ndr = ndr_push_init_ctx(NULL, iconv_convenience);
+       ndr = ndr_push_init_ctx(NULL);
        if (!ndr) return 0;
        ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
        status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
@@ -955,7 +985,7 @@ _PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t pu
 /*
   generic ndr_size_*() handler for unions
 */
-_PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push, struct smb_iconv_convenience *iconv_convenience)
+_PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
 {
        struct ndr_push *ndr;
        enum ndr_err_code status;
@@ -964,7 +994,7 @@ _PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_pus
        /* avoid recursion */
        if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
 
-       ndr = ndr_push_init_ctx(NULL, iconv_convenience);
+       ndr = ndr_push_init_ctx(NULL);
        if (!ndr) return 0;
        ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
 
@@ -1033,11 +1063,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;
@@ -1061,6 +1105,161 @@ _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;
+       }
+       if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
+               return ndr_push_relative_ptr2(ndr, p);
+       }
+       if (ndr->relative_end_offset == -1) {
+               return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+                             "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d",
+                             ndr->relative_end_offset);
+       }
+       NDR_CHECK(ndr_token_store(ndr, &ndr->relative_begin_list, p, ndr->offset));
+       return NDR_ERR_SUCCESS;
+}
+
+/*
+  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)
+{
+       uint32_t begin_offset = 0xFFFFFFFF;
+       ssize_t len;
+       uint32_t correct_offset = 0;
+       uint32_t align = 1;
+       uint32_t pad = 0;
+
+       if (p == NULL) {
+               return NDR_ERR_SUCCESS;
+       }
+
+       if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) {
+               return NDR_ERR_SUCCESS;
+       }
+
+       if (ndr->flags & LIBNDR_FLAG_NO_NDR_SIZE) {
+               /* better say more than calculation a too small buffer */
+               NDR_PUSH_ALIGN(ndr, 8);
+               return NDR_ERR_SUCCESS;
+       }
+
+       if (ndr->relative_end_offset < ndr->offset) {
+               return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+                                     "ndr_push_relative_ptr2_end:"
+                                     "relative_end_offset %u < offset %u",
+                                     ndr->relative_end_offset, ndr->offset);
+       }
+
+       NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset));
+
+       /* we have marshalled a buffer, see how long it was */
+       len = ndr->offset - begin_offset;
+
+       if (len < 0) {
+               return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+                                     "ndr_push_relative_ptr2_end:"
+                                     "offset %u - begin_offset %u < 0",
+                                     ndr->offset, begin_offset);
+       }
+
+       if (ndr->relative_end_offset < len) {
+               return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+                                     "ndr_push_relative_ptr2_end:"
+                                     "relative_end_offset %u < len %lld",
+                                     ndr->offset, (long long)len);
+       }
+
+       /* the reversed offset is at the end of the main buffer */
+       correct_offset = ndr->relative_end_offset - len;
+
+       /* TODO: remove this hack and let the idl use FLAG_ALIGN2 explicit */
+       align = 2;
+
+       if (ndr->flags & LIBNDR_FLAG_ALIGN2) {
+               align = 2;
+       } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) {
+               align = 4;
+       } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) {
+               align = 8;
+       }
+
+       pad = ndr_align_size(correct_offset, align);
+       if (pad) {
+               correct_offset += pad;
+               correct_offset -= align;
+       }
+
+       if (correct_offset < begin_offset) {
+               return ndr_push_error(ndr, NDR_ERR_RELATIVE,
+                                     "ndr_push_relative_ptr2_end: "
+                                     "correct_offset %u < begin_offset %u",
+                                     correct_offset, begin_offset);
+       }
+
+       if (len > 0) {
+               uint32_t clear_size = correct_offset - begin_offset;
+
+               clear_size = MIN(clear_size, len);
+
+               /* now move the marshalled buffer to the end of the main buffer */
+               memmove(ndr->data + correct_offset, ndr->data + begin_offset, len);
+
+               if (clear_size) {
+                       /* and wipe out old buffer within the main buffer */
+                       memset(ndr->data + begin_offset, '\0', clear_size);
+               }
+       }
+
+       /* and set the end offset for the next buffer */
+       ndr->relative_end_offset = correct_offset;
+
+       /* finally write the offset to the main buffer */
+       ndr->offset = correct_offset;
+       NDR_CHECK(ndr_push_relative_ptr2(ndr, p));
+
+       /* restore to where we were in the main buffer */
+       ndr->offset = begin_offset;
+
+       return NDR_ERR_SUCCESS;
+}
 
 /*
   get the current base for relative pointers for the pull
@@ -1145,6 +1344,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 }
 };