This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
*/
#include "includes.h"
-#include "dlinklist.h"
+#include "librpc/ndr/libndr.h"
+#include "../lib/util/dlinklist.h"
+#include "librpc/gen_ndr/dcerpc.h"
+#include "param/param.h"
#define NDR_BASE_MARSHALL_SIZE 1024
+/* this guid indicates NDR encoding in a protocol tower */
+const struct ndr_syntax_id ndr_transfer_syntax = {
+ { 0x8a885d04, 0x1ceb, 0x11c9, {0x9f, 0xe8}, {0x08,0x00,0x2b,0x10,0x48,0x60} },
+ 2
+};
+
+const struct ndr_syntax_id ndr64_transfer_syntax = {
+ { 0x71710533, 0xbeba, 0x4937, {0x83, 0x19}, {0xb5,0xdb,0xef,0x9c,0xcc,0x36} },
+ 1
+};
+
/*
work out the number of bytes needed to align on a n byte boundary
*/
-size_t ndr_align_size(uint32_t offset, size_t n)
+_PUBLIC_ size_t ndr_align_size(uint32_t offset, size_t n)
{
if ((offset & (n-1)) == 0) return 0;
return n - (offset & (n-1));
/*
initialise a ndr parse structure from a data blob
*/
-struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
+_PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
{
struct ndr_pull *ndr;
ndr = talloc_zero(mem_ctx, struct ndr_pull);
if (!ndr) return NULL;
+ ndr->current_mem_ctx = mem_ctx;
ndr->data = blob->data;
ndr->data_size = blob->length;
+ ndr->iconv_convenience = talloc_reference(ndr, iconv_convenience);
return ndr;
}
-/*
- create an ndr sub-context based on an existing context. The new context starts
- at the current offset, with the given size limit
-*/
-NTSTATUS ndr_pull_subcontext(struct ndr_pull *ndr, struct ndr_pull *ndr2, uint32_t size)
-{
- NDR_PULL_NEED_BYTES(ndr, size);
- *ndr2 = *ndr;
- ndr2->data += ndr2->offset;
- ndr2->offset = 0;
- ndr2->data_size = size;
- ndr2->flags = ndr->flags;
- return NT_STATUS_OK;
-}
-
-
/*
advance by 'size' bytes
*/
-NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
+_PUBLIC_ enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size)
{
ndr->offset += size;
if (ndr->offset > ndr->data_size) {
"ndr_pull_advance by %u failed",
size);
}
- return NT_STATUS_OK;
+ return NDR_ERR_SUCCESS;
}
/*
set the parse offset to 'ofs'
*/
-NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
+static enum ndr_err_code ndr_pull_set_offset(struct ndr_pull *ndr, uint32_t ofs)
{
ndr->offset = ofs;
if (ndr->offset > ndr->data_size) {
"ndr_pull_set_offset %u failed",
ofs);
}
- return NT_STATUS_OK;
-}
-
-/* save the offset/size of the current ndr state */
-void ndr_pull_save(struct ndr_pull *ndr, struct ndr_pull_save *save)
-{
- save->offset = ndr->offset;
- save->data_size = ndr->data_size;
+ return NDR_ERR_SUCCESS;
}
-/* restore the size/offset of a ndr structure */
-void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save)
-{
- ndr->offset = save->offset;
- ndr->data_size = save->data_size;
-}
-
-
/* create a ndr_push structure, ready for some marshalling */
-struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
+_PUBLIC_ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx, struct smb_iconv_convenience *iconv_convenience)
{
struct ndr_push *ndr;
if (!ndr->data) {
return NULL;
}
+ ndr->iconv_convenience = talloc_reference(ndr, iconv_convenience);
return ndr;
}
-
-/* create a ndr_push structure, ready for some marshalling */
-struct ndr_push *ndr_push_init(void)
-{
- return ndr_push_init_ctx(NULL);
-}
-
-/* free a ndr_push structure */
-void ndr_push_free(struct ndr_push *ndr)
-{
- talloc_free(ndr);
-}
-
-
/* return a DATA_BLOB structure for the current ndr_push marshalled data */
-DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
+_PUBLIC_ DATA_BLOB ndr_push_blob(struct ndr_push *ndr)
{
DATA_BLOB blob;
- blob.data = ndr->data;
- blob.length = ndr->offset;
+ blob = data_blob_const(ndr->data, ndr->offset);
+ if (ndr->alloc_size > ndr->offset) {
+ ndr->data[ndr->offset] = 0;
+ }
return blob;
}
/*
- expand the available space in the buffer to 'size'
+ expand the available space in the buffer to ndr->offset + extra_size
*/
-NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32_t size)
+_PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_size)
{
- if (ndr->alloc_size >= size) {
- return NT_STATUS_OK;
+ uint32_t size = extra_size + ndr->offset;
+
+ if (size < ndr->offset) {
+ /* extra_size overflowed the offset */
+ return ndr_push_error(ndr, NDR_ERR_BUFSIZE, "Overflow in push_expand to %u",
+ size);
+ }
+
+ if (ndr->alloc_size > size) {
+ return NDR_ERR_SUCCESS;
}
ndr->alloc_size += NDR_BASE_MARSHALL_SIZE;
- if (size > ndr->alloc_size) {
- ndr->alloc_size = size;
+ if (size+1 > ndr->alloc_size) {
+ ndr->alloc_size = size+1;
}
ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->alloc_size);
if (!ndr->data) {
ndr->alloc_size);
}
- return NT_STATUS_OK;
+ return NDR_ERR_SUCCESS;
}
-/*
- set the push offset to 'ofs'
-*/
-NTSTATUS ndr_push_set_offset(struct ndr_push *ndr, uint32_t ofs)
+_PUBLIC_ void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...)
{
- NDR_CHECK(ndr_push_expand(ndr, ofs));
- ndr->offset = ofs;
- return NT_STATUS_OK;
-}
+ va_list ap;
+ char *s = NULL;
+ int i, ret;
-/*
- push a generic array
-*/
-NTSTATUS ndr_push_array(struct ndr_push *ndr, int ndr_flags, void *base,
- size_t elsize, uint32_t count,
- NTSTATUS (*push_fn)(struct ndr_push *, int, void *))
-{
- int i;
- char *p = base;
- if (!(ndr_flags & NDR_SCALARS)) goto buffers;
- for (i=0;i<count;i++) {
- NDR_CHECK(push_fn(ndr, NDR_SCALARS, p));
- p += elsize;
- }
- if (!(ndr_flags & NDR_BUFFERS)) goto done;
-buffers:
- p = base;
- for (i=0;i<count;i++) {
- NDR_CHECK(push_fn(ndr, NDR_BUFFERS, p));
- p += elsize;
- }
-done:
- return NT_STATUS_OK;
-}
+ va_start(ap, format);
+ ret = vasprintf(&s, format, ap);
+ va_end(ap);
-/*
- pull a constant sized array
-*/
-NTSTATUS ndr_pull_array(struct ndr_pull *ndr, int ndr_flags, void *base,
- size_t elsize, uint32_t count,
- NTSTATUS (*pull_fn)(struct ndr_pull *, int, void *))
-{
- int i;
- char *p;
- p = base;
- if (!(ndr_flags & NDR_SCALARS)) goto buffers;
- for (i=0;i<count;i++) {
- NDR_CHECK(pull_fn(ndr, NDR_SCALARS, p));
- p += elsize;
- }
- if (!(ndr_flags & NDR_BUFFERS)) goto done;
-buffers:
- p = base;
- for (i=0;i<count;i++) {
- NDR_CHECK(pull_fn(ndr, NDR_BUFFERS, p));
- p += elsize;
+ if (ret == -1) {
+ return;
}
-done:
- return NT_STATUS_OK;
-}
-
-/*
- pull a constant size array of structures
-*/
-NTSTATUS ndr_pull_struct_array(struct ndr_pull *ndr, uint32_t count,
- size_t elsize, void **info,
- NTSTATUS (*pull_fn)(struct ndr_pull *, int, void *))
-{
- int i;
- char *base;
-
- NDR_ALLOC_N_SIZE(ndr, *info, count, elsize);
- base = (char *)*info;
- for (i = 0; i < count; i++) {
- ndr->data += ndr->offset;
- ndr->offset = 0;
- NDR_CHECK(pull_fn(ndr, NDR_SCALARS|NDR_BUFFERS, &base[count * elsize]));
+ for (i=0;i<ndr->depth;i++) {
+ DEBUGADD(0,(" "));
}
- return NT_STATUS_OK;
-}
-
-/*
- print a generic array
-*/
-void ndr_print_array(struct ndr_print *ndr, const char *name, void *base,
- size_t elsize, uint32_t count,
- void (*print_fn)(struct ndr_print *, const char *, void *))
-{
- int i;
- char *p = base;
- ndr->print(ndr, "%s: ARRAY(%d)", name, count);
- ndr->depth++;
- for (i=0;i<count;i++) {
- char *idx=NULL;
- asprintf(&idx, "[%d]", i);
- if (idx) {
- print_fn(ndr, idx, p);
- free(idx);
- }
- p += elsize;
- }
- ndr->depth--;
+ DEBUGADD(0,("%s\n", s));
+ free(s);
}
-
-
-void ndr_print_debug_helper(struct ndr_print *ndr, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
+_PUBLIC_ void ndr_print_string_helper(struct ndr_print *ndr, const char *format, ...)
{
va_list ap;
- char *s = NULL;
int i;
- va_start(ap, format);
- vasprintf(&s, format, ap);
- va_end(ap);
-
for (i=0;i<ndr->depth;i++) {
- DEBUG(0,(" "));
+ ndr->private_data = talloc_asprintf_append_buffer(
+ (char *)ndr->private_data, " ");
}
- DEBUG(0,("%s\n", s));
- free(s);
+ va_start(ap, format);
+ ndr->private_data = talloc_vasprintf_append_buffer((char *)ndr->private_data,
+ format, ap);
+ va_end(ap);
+ ndr->private_data = talloc_asprintf_append_buffer((char *)ndr->private_data,
+ "\n");
}
/*
a useful helper function for printing idl structures via DEBUG()
*/
-void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
+_PUBLIC_ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
{
struct ndr_print *ndr;
- ndr = talloc(NULL, struct ndr_print);
+ ndr = talloc_zero(NULL, struct ndr_print);
if (!ndr) return;
ndr->print = ndr_print_debug_helper;
ndr->depth = 1;
talloc_free(ndr);
}
-
/*
a useful helper function for printing idl unions via DEBUG()
*/
-void ndr_print_union_debug(ndr_print_union_fn_t fn, const char *name, uint32_t level, void *ptr)
+_PUBLIC_ void ndr_print_union_debug(ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
{
struct ndr_print *ndr;
- ndr = talloc(NULL, struct ndr_print);
+ 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, level, ptr);
+ ndr_print_set_switch_value(ndr, ptr, level);
+ fn(ndr, name, ptr);
talloc_free(ndr);
}
/*
a useful helper function for printing idl function calls via DEBUG()
*/
-void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
+_PUBLIC_ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int flags, void *ptr)
{
struct ndr_print *ndr;
- ndr = talloc(NULL, struct ndr_print);
+ ndr = talloc_zero(NULL, struct ndr_print);
if (!ndr) return;
ndr->print = ndr_print_debug_helper;
ndr->depth = 1;
talloc_free(ndr);
}
-void ndr_set_flags(uint32_t *pflags, uint32_t new_flags)
+/*
+ a useful helper function for printing idl structures to a string
+*/
+_PUBLIC_ char *ndr_print_struct_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, void *ptr)
+{
+ struct ndr_print *ndr;
+ char *ret = NULL;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_print);
+ if (!ndr) return NULL;
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (!ndr->private_data) {
+ goto failed;
+ }
+ 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:
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ a useful helper function for printing idl unions to a string
+*/
+_PUBLIC_ char *ndr_print_union_string(TALLOC_CTX *mem_ctx, ndr_print_fn_t fn, const char *name, uint32_t level, void *ptr)
+{
+ struct ndr_print *ndr;
+ char *ret = NULL;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_print);
+ if (!ndr) return NULL;
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (!ndr->private_data) {
+ goto failed;
+ }
+ ndr->print = ndr_print_string_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ ndr_print_set_switch_value(ndr, ptr, level);
+ fn(ndr, name, ptr);
+ ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
+failed:
+ talloc_free(ndr);
+ return ret;
+}
+
+/*
+ a useful helper function for printing idl function calls to a string
+*/
+_PUBLIC_ char *ndr_print_function_string(TALLOC_CTX *mem_ctx,
+ ndr_print_function_t fn, const char *name,
+ int flags, void *ptr)
+{
+ struct ndr_print *ndr;
+ char *ret = NULL;
+
+ ndr = talloc_zero(mem_ctx, struct ndr_print);
+ if (!ndr) return NULL;
+ ndr->private_data = talloc_strdup(ndr, "");
+ if (!ndr->private_data) {
+ goto failed;
+ }
+ ndr->print = ndr_print_string_helper;
+ ndr->depth = 1;
+ ndr->flags = 0;
+ fn(ndr, name, flags, ptr);
+ ret = talloc_steal(mem_ctx, (char *)ndr->private_data);
+failed:
+ talloc_free(ndr);
+ return ret;
+}
+
+_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) {
if (new_flags & LIBNDR_FLAG_BIGENDIAN) {
(*pflags) &= ~LIBNDR_FLAG_LITTLE_ENDIAN;
}
- (*pflags) |= new_flags;
-}
-
-static NTSTATUS ndr_map_error(enum ndr_err_code err)
-{
- switch (err) {
- case NDR_ERR_BUFSIZE:
- return NT_STATUS_BUFFER_TOO_SMALL;
- case NDR_ERR_TOKEN:
- return NT_STATUS_INTERNAL_ERROR;
- case NDR_ERR_ALLOC:
- return NT_STATUS_NO_MEMORY;
- case NDR_ERR_ARRAY_SIZE:
- return NT_STATUS_ARRAY_BOUNDS_EXCEEDED;
- default:
- break;
+ if (new_flags & LIBNDR_FLAG_REMAINING) {
+ (*pflags) &= ~LIBNDR_ALIGN_FLAGS;
}
-
- /* we should all error codes to different status codes */
- return NT_STATUS_INVALID_PARAMETER;
+ if (new_flags & LIBNDR_ALIGN_FLAGS) {
+ (*pflags) &= ~LIBNDR_FLAG_REMAINING;
+ }
+ (*pflags) |= new_flags;
}
/*
return and possibly log an NDR error
*/
-NTSTATUS ndr_pull_error(struct ndr_pull *ndr,
- enum ndr_err_code err, const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
+_PUBLIC_ enum ndr_err_code ndr_pull_error(struct ndr_pull *ndr,
+ enum ndr_err_code ndr_err,
+ const char *format, ...)
{
char *s=NULL;
va_list ap;
+ int ret;
va_start(ap, format);
- vasprintf(&s, format, ap);
+ ret = vasprintf(&s, format, ap);
va_end(ap);
- DEBUG(3,("ndr_pull_error(%u): %s\n", err, s));
+ if (ret == -1) {
+ return NDR_ERR_ALLOC;
+ }
+
+ DEBUG(1,("ndr_pull_error(%u): %s\n", ndr_err, s));
free(s);
- return ndr_map_error(err);
+ return ndr_err;
}
/*
return and possibly log an NDR error
*/
-NTSTATUS ndr_push_error(struct ndr_push *ndr, enum ndr_err_code err, const char *format, ...) _PRINTF_ATTRIBUTE(3,4)
+_PUBLIC_ enum ndr_err_code ndr_push_error(struct ndr_push *ndr,
+ enum ndr_err_code ndr_err,
+ const char *format, ...)
{
char *s=NULL;
va_list ap;
+ int ret;
va_start(ap, format);
- vasprintf(&s, format, ap);
+ ret = vasprintf(&s, format, ap);
va_end(ap);
- DEBUG(3,("ndr_push_error(%u): %s\n", err, s));
+ if (ret == -1) {
+ return NDR_ERR_ALLOC;
+ }
+
+ DEBUG(1,("ndr_push_error(%u): %s\n", ndr_err, s));
free(s);
- return ndr_map_error(err);
+ return ndr_err;
}
-
/*
handle subcontext buffers, which in midl land are user-marshalled, but
we use magic in pidl to make them easier to cope with
*/
-NTSTATUS ndr_pull_subcontext_header(struct ndr_pull *ndr,
- size_t sub_size,
- struct ndr_pull *ndr2)
+_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_start(struct ndr_pull *ndr,
+ struct ndr_pull **_subndr,
+ size_t header_size,
+ ssize_t size_is)
{
- ndr2->flags = ndr->flags;
+ struct ndr_pull *subndr;
+ uint32_t r_content_size;
+ bool force_le = false;
+ bool force_be = false;
- switch (sub_size) {
+ switch (header_size) {
case 0: {
- uint32_t size = ndr->data_size - ndr->offset;
- NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
+ uint32_t content_size = ndr->data_size - ndr->offset;
+ if (size_is >= 0) {
+ content_size = size_is;
+ }
+ r_content_size = content_size;
break;
}
case 2: {
- uint16_t size;
- NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &size));
- NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
+ uint16_t content_size;
+ NDR_CHECK(ndr_pull_uint16(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);
+ }
+ r_content_size = content_size;
break;
}
case 4: {
- uint32_t size;
- NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size));
- NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
+ uint32_t content_size;
+ NDR_CHECK(ndr_pull_uint32(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);
+ }
+ r_content_size = content_size;
+ break;
+ }
+ case 0xFFFFFC01: {
+ /*
+ * Common Type Header for the Serialization Stream
+ * See [MS-RPCE] 2.2.6 Type Serialization Version 1
+ */
+ uint8_t version;
+ uint8_t drep;
+ uint16_t hdrlen;
+ uint32_t filler;
+ uint32_t content_size;
+ uint32_t reserved;
+
+ /* version */
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &version));
+
+ if (version != 1) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
+ "Bad subcontext (PULL) Common Type Header version %d != 1",
+ (int)version);
+ }
+
+ /*
+ * 0x10 little endian
+ * 0x00 big endian
+ */
+ NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &drep));
+ if (drep == 0x10) {
+ force_le = true;
+ } else if (drep == 0x00) {
+ force_be = true;
+ } else {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
+ "Bad subcontext (PULL) Common Type Header invalid drep 0x%02X",
+ (unsigned int)drep);
+ }
+
+ /* length of the "Private Header for Constructed Type" */
+ NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &hdrlen));
+ if (hdrlen != 8) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
+ "Bad subcontext (PULL) Common Type Header length %d != 8",
+ (int)hdrlen);
+ }
+
+ /* filler should be ignored */
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &filler));
+
+ /*
+ * Private Header for Constructed Type
+ */
+ /* length - will be updated latter */
+ NDR_CHECK(ndr_pull_uint32(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);
+ }
+ /* the content size must be a multiple of 8 */
+ if ((content_size % 8) != 0) {
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT,
+ "Bad subcontext (PULL) size_is(%d) not padded to 8 content_size %d",
+ (int)size_is, (int)content_size);
+ }
+ r_content_size = content_size;
+
+ /* reserved */
+ NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &reserved));
break;
}
default:
- return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d",
- sub_size);
+ return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d",
+ (int)header_size);
}
- return NT_STATUS_OK;
+
+ NDR_PULL_NEED_BYTES(ndr, r_content_size);
+
+ subndr = talloc_zero(ndr, struct ndr_pull);
+ NDR_ERR_HAVE_NO_MEMORY(subndr);
+ subndr->flags = ndr->flags;
+ 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);
+ } else if (force_be) {
+ ndr_set_flags(&ndr->flags, LIBNDR_FLAG_BIGENDIAN);
+ }
+
+ *_subndr = subndr;
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_subcontext_end(struct ndr_pull *ndr,
+ struct ndr_pull *subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ uint32_t advance;
+ if (size_is >= 0) {
+ advance = size_is;
+ } else if (header_size > 0) {
+ advance = subndr->data_size;
+ } else {
+ advance = subndr->offset;
+ }
+ NDR_CHECK(ndr_pull_advance(ndr, advance));
+ return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_push_subcontext_start(struct ndr_push *ndr,
+ struct ndr_push **_subndr,
+ size_t header_size,
+ ssize_t size_is)
+{
+ struct ndr_push *subndr;
+
+ subndr = ndr_push_init_ctx(ndr, ndr->iconv_convenience);
+ NDR_ERR_HAVE_NO_MEMORY(subndr);
+ subndr->flags = ndr->flags;
+
+ *_subndr = subndr;
+ return NDR_ERR_SUCCESS;
}
/*
push a subcontext header
*/
-NTSTATUS ndr_push_subcontext_header(struct ndr_push *ndr,
- size_t sub_size,
- struct ndr_push *ndr2)
+_PUBLIC_ enum ndr_err_code ndr_push_subcontext_end(struct ndr_push *ndr,
+ struct ndr_push *subndr,
+ size_t header_size,
+ ssize_t size_is)
{
- switch (sub_size) {
+ ssize_t padding_len;
+
+ 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) {
+ 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);
+ }
+ }
+
+ switch (header_size) {
case 0:
break;
case 2:
- NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, ndr2->offset));
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, subndr->offset));
break;
case 4:
- NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, ndr2->offset));
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
break;
- default:
- return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d",
- sub_size);
- }
- return NT_STATUS_OK;
-}
+ case 0xFFFFFC01:
+ /*
+ * Common Type Header for the Serialization Stream
+ * See [MS-RPCE] 2.2.6 Type Serialization Version 1
+ */
+ padding_len = NDR_ROUND(subndr->offset, 8) - subndr->offset;
+ if (padding_len > 0) {
+ NDR_CHECK(ndr_push_zero(subndr, padding_len));
+ }
-/*
- mark the start of a structure
-*/
-NTSTATUS ndr_pull_struct_start(struct ndr_pull *ndr)
-{
- return NT_STATUS_OK;
-}
+ /* version */
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, 1));
-/*
- mark the end of a structure
-*/
-void ndr_pull_struct_end(struct ndr_pull *ndr)
-{
-}
+ /*
+ * 0x10 little endian
+ * 0x00 big endian
+ */
+ NDR_CHECK(ndr_push_uint8(ndr, NDR_SCALARS, NDR_BE(ndr)?0x00:0x10));
-/*
- mark the start of a structure
-*/
-NTSTATUS ndr_push_struct_start(struct ndr_push *ndr)
-{
- return NT_STATUS_OK;
-}
+ /* length of the "Private Header for Constructed Type" */
+ NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, 8));
-/*
- mark the end of a structure
-*/
-void ndr_push_struct_end(struct ndr_push *ndr)
-{
+ /* filler */
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0xCCCCCCCC));
+
+ /*
+ * Private Header for Constructed Type
+ */
+ /* length - will be updated latter */
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, subndr->offset));
+
+ /* reserved */
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d",
+ (int)header_size);
+ }
+
+ NDR_CHECK(ndr_push_bytes(ndr, subndr->data, subndr->offset));
+ return NDR_ERR_SUCCESS;
}
/*
store a token in the ndr context, for later retrieval
*/
-static NTSTATUS ndr_token_store(TALLOC_CTX *mem_ctx,
- struct ndr_token_list **list,
- const void *key,
- uint32_t value)
+_PUBLIC_ enum ndr_err_code ndr_token_store(TALLOC_CTX *mem_ctx,
+ struct ndr_token_list **list,
+ const void *key,
+ uint32_t value)
{
struct ndr_token_list *tok;
tok = talloc(mem_ctx, struct ndr_token_list);
- if (tok == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
+ NDR_ERR_HAVE_NO_MEMORY(tok);
tok->key = key;
tok->value = value;
DLIST_ADD((*list), tok);
- return NT_STATUS_OK;
+ return NDR_ERR_SUCCESS;
}
/*
- retrieve a token from a ndr context
+ retrieve a token from a ndr context, using cmp_fn to match the tokens
*/
-static NTSTATUS ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v)
+_PUBLIC_ enum ndr_err_code ndr_token_retrieve_cmp_fn(struct ndr_token_list **list, const void *key, uint32_t *v,
+ comparison_fn_t _cmp_fn, bool _remove_tok)
{
struct ndr_token_list *tok;
for (tok=*list;tok;tok=tok->next) {
- if (tok->key == key) {
- DLIST_REMOVE((*list), tok);
- *v = tok->value;
- return NT_STATUS_OK;
- }
+ if (_cmp_fn && _cmp_fn(tok->key,key)==0) goto found;
+ else if (!_cmp_fn && tok->key == key) goto found;
}
- return ndr_map_error(NDR_ERR_TOKEN);
+ return NDR_ERR_TOKEN;
+found:
+ *v = tok->value;
+ if (_remove_tok) {
+ DLIST_REMOVE((*list), tok);
+ talloc_free(tok);
+ }
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ retrieve a token from a ndr context
+*/
+_PUBLIC_ enum ndr_err_code ndr_token_retrieve(struct ndr_token_list **list, const void *key, uint32_t *v)
+{
+ return ndr_token_retrieve_cmp_fn(list, key, v, NULL, true);
}
/*
peek at but don't removed a token from a ndr context
*/
-static uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
+_PUBLIC_ uint32_t ndr_token_peek(struct ndr_token_list **list, const void *key)
{
- struct ndr_token_list *tok;
- for (tok=*list;tok;tok=tok->next) {
- if (tok->key == key) {
- return tok->value;
- }
+ enum ndr_err_code status;
+ uint32_t v;
+
+ status = ndr_token_retrieve_cmp_fn(list, key, &v, NULL, false);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ return 0;
}
- return 0;
+
+ return v;
}
/*
pull an array size field and add it to the array_size_list token list
*/
-NTSTATUS ndr_pull_array_size(struct ndr_pull *ndr, const void *p)
+_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));
/*
get the stored array size field
*/
-uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
+_PUBLIC_ uint32_t ndr_get_array_size(struct ndr_pull *ndr, const void *p)
{
return ndr_token_peek(&ndr->array_size_list, p);
}
/*
check the stored array size field
*/
-NTSTATUS ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
+_PUBLIC_ enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, void *p, uint32_t size)
{
uint32_t stored;
- NDR_CHECK(ndr_token_retrieve(&ndr->array_size_list, p, &stored));
+ stored = ndr_token_peek(&ndr->array_size_list, p);
if (stored != size) {
return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
"Bad array size - got %u expected %u\n",
stored, size);
}
- return NT_STATUS_OK;
+ return NDR_ERR_SUCCESS;
}
/*
pull an array length field and add it to the array_length_list token list
*/
-NTSTATUS ndr_pull_array_length(struct ndr_pull *ndr, const void *p)
+_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));
/*
get the stored array length field
*/
-uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
+_PUBLIC_ uint32_t ndr_get_array_length(struct ndr_pull *ndr, const void *p)
{
return ndr_token_peek(&ndr->array_length_list, p);
}
/*
check the stored array length field
*/
-NTSTATUS ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
+_PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
{
uint32_t stored;
- NDR_CHECK(ndr_token_retrieve(&ndr->array_length_list, p, &stored));
+ stored = ndr_token_peek(&ndr->array_length_list, p);
if (stored != length) {
return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
"Bad array length - got %u expected %u\n",
stored, length);
}
- return NT_STATUS_OK;
+ return NDR_ERR_SUCCESS;
}
/*
store a switch value
*/
-NTSTATUS ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
+_PUBLIC_ enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
+{
+ return ndr_token_store(ndr, &ndr->switch_list, p, val);
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
{
return ndr_token_store(ndr, &ndr->switch_list, p, val);
}
-NTSTATUS ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
+_PUBLIC_ enum ndr_err_code ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
{
return ndr_token_store(ndr, &ndr->switch_list, p, val);
}
/*
retrieve a switch value
*/
-uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
+_PUBLIC_ uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
{
return ndr_token_peek(&ndr->switch_list, p);
}
-uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
+_PUBLIC_ uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
{
return ndr_token_peek(&ndr->switch_list, p);
}
-/*
- pull a relative object - stage1
- called during SCALARS processing
-*/
-NTSTATUS ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
+_PUBLIC_ uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
{
- if (ndr->flags & LIBNDR_FLAG_RELATIVE_CURRENT) {
- return ndr_token_store(ndr, &ndr->relative_list, p,
- rel_offset + ndr->offset - 4);
- } else {
- return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
- }
+ return ndr_token_peek(&ndr->switch_list, p);
}
/*
- pull a relative object - stage2
- called during BUFFERS processing
+ pull a struct from a blob using NDR
*/
-NTSTATUS ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
+_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,
+ ndr_pull_flags_fn_t fn)
{
- uint32_t rel_offset;
- NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
- return ndr_pull_set_offset(ndr, rel_offset);
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+ NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+ return NDR_ERR_SUCCESS;
}
/*
- push a relative object - stage1
- this is called during SCALARS processing
+ pull a struct from a blob using NDR - failing if all bytes are not consumed
*/
-NTSTATUS ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
+_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)
{
- if (p == NULL) {
- NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
- return NT_STATUS_OK;
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
+ 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(ndr_push_align(ndr, 4));
- NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
- return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
+ return NDR_ERR_SUCCESS;
}
/*
- push a relative object - stage2
- this is called during buffers processing
+ pull a union from a blob using NDR, given the union discriminator
*/
-NTSTATUS ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
+_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,
+ uint32_t level, ndr_pull_flags_fn_t fn)
{
- struct ndr_push_save save;
- if (p == NULL) {
- return NT_STATUS_OK;
- }
- NDR_CHECK(ndr_push_align(ndr, 4));
- ndr_push_save(ndr, &save);
- NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ndr->offset));
- if (ndr->flags & LIBNDR_FLAG_RELATIVE_CURRENT) {
- NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save.offset - ndr->offset));
- } else {
- NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, save.offset));
- }
- ndr_push_restore(ndr, &save);
- return NT_STATUS_OK;
+ struct ndr_pull *ndr;
+ ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
+ 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));
+ return NDR_ERR_SUCCESS;
}
/*
- pull a struct from a blob using NDR
+ pull a union from a blob using NDR, given the union discriminator,
+ failing if all bytes are not consumed
*/
-NTSTATUS ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
- ndr_pull_flags_fn_t fn)
+_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,
+ uint32_t level, ndr_pull_flags_fn_t fn)
{
struct ndr_pull *ndr;
- ndr = ndr_pull_init_blob(blob, mem_ctx);
- if (!ndr) {
- return NT_STATUS_NO_MEMORY;
+ ndr = ndr_pull_init_blob(blob, mem_ctx, iconv_convenience);
+ 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);
}
- return fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
+ return NDR_ERR_SUCCESS;
}
/*
push a struct to a blob using NDR
*/
-NTSTATUS ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
- ndr_push_flags_fn_t fn)
+_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)
{
- NTSTATUS status;
struct ndr_push *ndr;
- ndr = ndr_push_init_ctx(mem_ctx);
- if (!ndr) {
- return NT_STATUS_NO_MEMORY;
- }
- status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+
+ NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
*blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob->data);
+ talloc_free(ndr);
- return NT_STATUS_OK;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ 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,
+ uint32_t level, ndr_push_flags_fn_t fn)
+{
+ struct ndr_push *ndr;
+ ndr = ndr_push_init_ctx(mem_ctx, iconv_convenience);
+ NDR_ERR_HAVE_NO_MEMORY(ndr);
+
+ NDR_CHECK(ndr_push_set_switch_value(ndr, p, level));
+ NDR_CHECK(fn(ndr, NDR_SCALARS|NDR_BUFFERS, p));
+
+ *blob = ndr_push_blob(ndr);
+ talloc_steal(mem_ctx, blob->data);
+ talloc_free(ndr);
+
+ return NDR_ERR_SUCCESS;
}
/*
generic ndr_size_*() handler for structures
*/
-size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
+_PUBLIC_ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
{
struct ndr_push *ndr;
- NTSTATUS status;
+ enum ndr_err_code status;
size_t ret;
/* avoid recursion */
if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
- ndr = ndr_push_init_ctx(NULL);
+ ndr = ndr_push_init_ctx(NULL, lp_iconv_convenience(global_loadparm));
if (!ndr) return 0;
ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
- if (!NT_STATUS_IS_OK(status)) {
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(ndr);
return 0;
}
ret = ndr->offset;
/*
generic ndr_size_*() handler for unions
*/
-size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
+_PUBLIC_ size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
{
struct ndr_push *ndr;
- NTSTATUS status;
+ enum ndr_err_code status;
size_t ret;
/* avoid recursion */
if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
- ndr = ndr_push_init_ctx(NULL);
+ ndr = ndr_push_init_ctx(NULL, lp_iconv_convenience(global_loadparm));
if (!ndr) return 0;
ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
- ndr_push_set_switch_value(ndr, p, level);
- status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
- if (!NT_STATUS_IS_OK(status)) {
+
+ status = ndr_push_set_switch_value(ndr, p, level);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(ndr);
+ return 0;
+ }
+ status = push(ndr, NDR_SCALARS|NDR_BUFFERS, p);
+ if (!NDR_ERR_CODE_IS_SUCCESS(status)) {
+ talloc_free(ndr);
return 0;
}
ret = ndr->offset;
talloc_free(ndr);
return ret;
}
+
+/*
+ get the current base for relative pointers for the push
+*/
+_PUBLIC_ uint32_t ndr_push_get_relative_base_offset(struct ndr_push *ndr)
+{
+ return ndr->relative_base_offset;
+}
+
+/*
+ restore the old base for relative pointers for the push
+*/
+_PUBLIC_ void ndr_push_restore_relative_base_offset(struct ndr_push *ndr, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+}
+
+/*
+ setup the current base for relative pointers for the push
+ called in the NDR_SCALAR stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset1(struct ndr_push *ndr, const void *p, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+ return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
+}
+
+/*
+ setup the current base for relative pointers for the push
+ called in the NDR_BUFFERS stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_setup_relative_base_offset2(struct ndr_push *ndr, const void *p)
+{
+ return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
+}
+
+/*
+ push a relative object - stage1
+ this is called during SCALARS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_relative_ptr1(struct ndr_push *ndr, const void *p)
+{
+ if (p == NULL) {
+ NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, 0));
+ return NDR_ERR_SUCCESS;
+ }
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_token_store(ndr, &ndr->relative_list, p, ndr->offset));
+ return ndr_push_uint32(ndr, NDR_SCALARS, 0xFFFFFFFF);
+}
+
+/*
+ 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)
+{
+ uint32_t save_offset;
+ uint32_t ptr_offset = 0xFFFFFFFF;
+ 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_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_uint32(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
+ ndr->offset = save_offset;
+ return NDR_ERR_SUCCESS;
+}
+
+/*
+ get the current base for relative pointers for the pull
+*/
+_PUBLIC_ uint32_t ndr_pull_get_relative_base_offset(struct ndr_pull *ndr)
+{
+ return ndr->relative_base_offset;
+}
+
+/*
+ restore the old base for relative pointers for the pull
+*/
+_PUBLIC_ void ndr_pull_restore_relative_base_offset(struct ndr_pull *ndr, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+}
+
+/*
+ setup the current base for relative pointers for the pull
+ called in the NDR_SCALAR stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset1(struct ndr_pull *ndr, const void *p, uint32_t offset)
+{
+ ndr->relative_base_offset = offset;
+ return ndr_token_store(ndr, &ndr->relative_base_list, p, offset);
+}
+
+/*
+ setup the current base for relative pointers for the pull
+ called in the NDR_BUFFERS stage
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_setup_relative_base_offset2(struct ndr_pull *ndr, const void *p)
+{
+ return ndr_token_retrieve(&ndr->relative_base_list, p, &ndr->relative_base_offset);
+}
+
+/*
+ pull a relative object - stage1
+ called during SCALARS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
+{
+ rel_offset += ndr->relative_base_offset;
+ if (rel_offset > ndr->data_size) {
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_relative_ptr1 rel_offset(%u) > ndr->data_size(%u)",
+ rel_offset, ndr->data_size);
+ }
+ return ndr_token_store(ndr, &ndr->relative_list, p, rel_offset);
+}
+
+/*
+ pull a relative object - stage2
+ called during BUFFERS processing
+*/
+_PUBLIC_ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p)
+{
+ uint32_t rel_offset;
+ NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &rel_offset));
+ return ndr_pull_set_offset(ndr, rel_offset);
+}