summaryrefslogtreecommitdiff
path: root/source4/librpc/ndr/ndr.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/librpc/ndr/ndr.c')
-rw-r--r--source4/librpc/ndr/ndr.c163
1 files changed, 144 insertions, 19 deletions
diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c
index b67fb25b1e..7deee6be3b 100644
--- a/source4/librpc/ndr/ndr.c
+++ b/source4/librpc/ndr/ndr.c
@@ -81,7 +81,9 @@ NTSTATUS ndr_pull_limit_size(struct ndr_pull *ndr, uint32 size, uint32 ofs)
new_size = ndr->offset + size - ofs;
if (new_size > ndr->data_size) {
- return NT_STATUS_BUFFER_TOO_SMALL;
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_limit_size %s %u failed",
+ size, ofs);
}
ndr->data_size = new_size;
@@ -96,7 +98,9 @@ NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32 size)
{
ndr->offset += size;
if (ndr->offset > ndr->data_size) {
- return NT_STATUS_BUFFER_TOO_SMALL;
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_advance by %u failed",
+ size);
}
return NT_STATUS_OK;
}
@@ -108,7 +112,9 @@ NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32 ofs)
{
ndr->offset = ofs;
if (ndr->offset > ndr->data_size) {
- return NT_STATUS_BUFFER_TOO_SMALL;
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_set_offset %u failed",
+ ofs);
}
return NT_STATUS_OK;
}
@@ -128,18 +134,13 @@ void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save)
}
-
-
/* create a ndr_push structure, ready for some marshalling */
-struct ndr_push *ndr_push_init(void)
+struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
{
struct ndr_push *ndr;
- TALLOC_CTX *mem_ctx = talloc_init("ndr_push_init");
- if (!mem_ctx) return NULL;
ndr = talloc(mem_ctx, sizeof(*ndr));
if (!ndr) {
- talloc_destroy(mem_ctx);
return NULL;
}
@@ -148,15 +149,30 @@ struct ndr_push *ndr_push_init(void)
ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
ndr->data = talloc(ndr->mem_ctx, ndr->alloc_size);
if (!ndr->data) {
- ndr_push_free(ndr);
return NULL;
}
ndr->offset = 0;
ndr->ptr_count = 0;
+ ndr->relative_list = NULL;
+ ndr->relative_list_end = NULL;
return ndr;
}
+
+/* create a ndr_push structure, ready for some marshalling */
+struct ndr_push *ndr_push_init(void)
+{
+ struct ndr_push *ndr;
+ TALLOC_CTX *mem_ctx = talloc_init("ndr_push_init");
+ if (!mem_ctx) return NULL;
+ ndr = ndr_push_init_ctx(mem_ctx);
+ if (!ndr) {
+ talloc_destroy(mem_ctx);
+ }
+ return ndr;
+}
+
/* free a ndr_push structure */
void ndr_push_free(struct ndr_push *ndr)
{
@@ -189,7 +205,8 @@ NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32 size)
}
ndr->data = talloc_realloc(ndr->mem_ctx, ndr->data, ndr->alloc_size);
if (!ndr->data) {
- return NT_STATUS_NO_MEMORY;
+ return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
+ ndr->alloc_size);
}
return NT_STATUS_OK;
@@ -358,6 +375,20 @@ void ndr_print_function_debug(void (*fn)(struct ndr_print *, const char *, int ,
talloc_destroy(ndr.mem_ctx);
}
+
+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_ALLOC:
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* we should all error codes to different status codes */
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
/*
return and possibly log an NDR error
*/
@@ -373,8 +404,8 @@ NTSTATUS ndr_pull_error(struct ndr_pull *ndr, enum ndr_err_code err, const char
DEBUG(3,("ndr_pull_error(%u): %s\n", err, s));
free(s);
- /* we should map to different status codes */
- return NT_STATUS_INVALID_PARAMETER;
+
+ return ndr_map_error(err);
}
/*
@@ -392,8 +423,8 @@ NTSTATUS ndr_push_error(struct ndr_push *ndr, enum ndr_err_code err, const char
DEBUG(3,("ndr_push_error(%u): %s\n", err, s));
free(s);
- /* we should map to different status codes */
- return NT_STATUS_INVALID_PARAMETER;
+
+ return ndr_map_error(err);
}
@@ -494,6 +525,92 @@ NTSTATUS ndr_pull_subcontext_union_fn(struct ndr_pull *ndr,
/*
+ push a subcontext header
+*/
+static NTSTATUS ndr_push_subcontext_header(struct ndr_push *ndr,
+ size_t sub_size,
+ struct ndr_push *ndr2)
+{
+ switch (sub_size) {
+ case 0:
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_uint16(ndr, ndr2->offset));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_push_uint32(ndr, ndr2->offset));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d",
+ sub_size);
+ }
+ return NT_STATUS_OK;
+}
+
+/*
+ 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_push_subcontext_fn(struct ndr_push *ndr,
+ size_t sub_size,
+ void *base,
+ NTSTATUS (*fn)(struct ndr_push *, void *))
+{
+ struct ndr_push *ndr2;
+
+ ndr2 = ndr_push_init_ctx(ndr->mem_ctx);
+ if (!ndr2) return NT_STATUS_NO_MEMORY;
+
+ NDR_CHECK(fn(ndr2, base));
+ NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
+ NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
+ return NT_STATUS_OK;
+}
+
+/*
+ handle subcontext buffers for function that take a flags arg
+*/
+NTSTATUS ndr_push_subcontext_flags_fn(struct ndr_push *ndr,
+ size_t sub_size,
+ void *base,
+ NTSTATUS (*fn)(struct ndr_push *, int, void *))
+{
+ struct ndr_push *ndr2;
+
+ ndr2 = ndr_push_init_ctx(ndr->mem_ctx);
+ if (!ndr2) return NT_STATUS_NO_MEMORY;
+
+ NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, base));
+ NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
+ NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
+ return NT_STATUS_OK;
+}
+
+/*
+ handle subcontext buffers for function that take a union
+*/
+NTSTATUS ndr_push_subcontext_union_fn(struct ndr_push *ndr,
+ size_t sub_size,
+ uint32 level,
+ void *base,
+ NTSTATUS (*fn)(struct ndr_push *, int, uint32, void *))
+{
+ struct ndr_push *ndr2;
+
+ ndr2 = ndr_push_init_ctx(ndr->mem_ctx);
+ if (!ndr2) return NT_STATUS_NO_MEMORY;
+
+ NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, level, base));
+ NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
+ NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
+ return NT_STATUS_OK;
+}
+
+
+/*
mark the start of a structure
*/
NTSTATUS ndr_pull_struct_start(struct ndr_pull *ndr)
@@ -520,7 +637,7 @@ void ndr_pull_struct_end(struct ndr_pull *ndr)
NTSTATUS ndr_push_struct_start(struct ndr_push *ndr)
{
struct ndr_ofs_list *ofs;
- NDR_ALLOC(ndr, ofs);
+ NDR_PUSH_ALLOC(ndr, ofs);
ofs->offset = ndr->offset;
ofs->next = ndr->ofs_list;
ndr->ofs_list = ofs;
@@ -579,12 +696,17 @@ NTSTATUS ndr_push_relative(struct ndr_push *ndr, int ndr_flags, const void *p,
NDR_CHECK(ndr_push_uint32(ndr, 0));
return NT_STATUS_OK;
}
- NDR_ALLOC(ndr, ofs);
+ NDR_PUSH_ALLOC(ndr, ofs);
NDR_CHECK(ndr_push_align(ndr, 4));
ofs->offset = ndr->offset;
NDR_CHECK(ndr_push_uint32(ndr, 0xFFFFFFFF));
- ofs->next = ndr->relative_list;
- ndr->relative_list = ofs;
+ ofs->next = NULL;
+ if (ndr->relative_list_end) {
+ ndr->relative_list_end->next = ofs;
+ } else {
+ ndr->relative_list = ofs;
+ }
+ ndr->relative_list_end = ofs;
}
if (ndr_flags & NDR_BUFFERS) {
struct ndr_push_save save;
@@ -596,6 +718,9 @@ NTSTATUS ndr_push_relative(struct ndr_push *ndr, int ndr_flags, const void *p,
return ndr_push_error(ndr, NDR_ERR_RELATIVE, "Empty relative stack");
}
ndr->relative_list = ndr->relative_list->next;
+ if (ndr->relative_list == NULL) {
+ ndr->relative_list_end = NULL;
+ }
NDR_CHECK(ndr_push_align(ndr, 8));
ndr_push_save(ndr, &save);
ndr->offset = ofs->offset;