summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/build/pidl/parser.pm13
-rw-r--r--source4/librpc/ndr/libndr.h31
-rw-r--r--source4/librpc/ndr/ndr.c152
-rw-r--r--source4/librpc/ndr/ndr_basic.c3
-rw-r--r--source4/rpc_server/dcerpc_server.c5
5 files changed, 116 insertions, 88 deletions
diff --git a/source4/build/pidl/parser.pm b/source4/build/pidl/parser.pm
index 51d561d4b2..5b85337212 100644
--- a/source4/build/pidl/parser.pm
+++ b/source4/build/pidl/parser.pm
@@ -364,7 +364,7 @@ sub ParseElementPushScalar($$$)
}
if (util::has_property($e, "relative")) {
- pidl "\tNDR_CHECK(ndr_push_relative(ndr, NDR_SCALARS, $var_prefix$e->{NAME}));\n";
+ pidl "\tNDR_CHECK(ndr_push_relative1(ndr, $var_prefix$e->{NAME}));\n";
} elsif (util::is_inline_array($e)) {
ParseArrayPush($e, "r->", "NDR_SCALARS");
} elsif (util::need_wire_pointer($e)) {
@@ -521,11 +521,9 @@ sub ParseElementPullScalar($$$)
} elsif (util::need_wire_pointer($e)) {
pidl "\tNDR_CHECK(ndr_pull_ptr(ndr, &_ptr_$e->{NAME}));\n";
pidl "\tif (_ptr_$e->{NAME}) {\n";
+ pidl "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
if (util::has_property($e, "relative")) {
- # NOTE: this assumes a pointer can hold a uint32. Not legal C
- pidl "\t\t$var_prefix$e->{NAME} = (void *)_ptr_$e->{NAME};\n";
- } else {
- pidl "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
+ pidl "\t\tNDR_CHECK(ndr_pull_relative1(ndr, $var_prefix$e->{NAME}, _ptr_$e->{NAME}));";
}
pidl "\t} else {\n";
pidl "\t\t$var_prefix$e->{NAME} = NULL;\n";
@@ -568,7 +566,7 @@ sub ParseElementPushBuffer($$$)
if (util::need_wire_pointer($e)) {
pidl "\tif ($var_prefix$e->{NAME}) {\n";
if (util::has_property($e, "relative")) {
- pidl "\t\tNDR_CHECK(ndr_push_relative(ndr, NDR_BUFFERS, $var_prefix$e->{NAME}));\n";
+ pidl "\t\tNDR_CHECK(ndr_push_relative2(ndr, $var_prefix$e->{NAME}));\n";
}
}
@@ -652,8 +650,7 @@ sub ParseElementPullBuffer($$$)
if (util::has_property($e, "relative")) {
pidl "\t\tstruct ndr_pull_save _relative_save;\n";
pidl "\t\tndr_pull_save(ndr, &_relative_save);\n";
- pidl "\t\tNDR_CHECK(ndr_pull_set_offset(ndr, (uint32_t)$var_prefix$e->{NAME}));\n";
- pidl "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
+ pidl "\t\tNDR_CHECK(ndr_pull_relative2(ndr, $var_prefix$e->{NAME}));\n";
}
}
diff --git a/source4/librpc/ndr/libndr.h b/source4/librpc/ndr/libndr.h
index 57d9766811..7ab5de52fa 100644
--- a/source4/librpc/ndr/libndr.h
+++ b/source4/librpc/ndr/libndr.h
@@ -23,15 +23,15 @@
*/
-/* offset lists are used to allow a push/pull function to find the
- start of an encapsulating structure */
-struct ndr_ofs_list {
- uint32_t offset;
- uint32_t base;
- struct ndr_ofs_list *next;
+/*
+ this is used by the token store/retrieve code
+*/
+struct ndr_token_list {
+ struct ndr_token_list *next, *prev;
+ const void *key;
+ uint32_t value;
};
-
/* this is the base structure passed to routines that
parse MSRPC formatted data
@@ -47,9 +47,11 @@ struct ndr_pull {
uint32_t offset;
TALLOC_CTX *mem_ctx;
- /* this points at a list of offsets to the structures being processed.
- The first element in the list is the current structure */
- struct ndr_ofs_list *ofs_list;
+ struct ndr_token_list *relative_list;
+
+ /* this is used to ensure we generate unique reference IDs
+ between request and reply */
+ uint32_t ptr_count;
};
struct ndr_pull_save {
@@ -66,15 +68,10 @@ struct ndr_push {
uint32_t offset;
TALLOC_CTX *mem_ctx;
+ struct ndr_token_list *relative_list;
+
/* this is used to ensure we generate unique reference IDs */
uint32_t ptr_count;
-
- /* this points at a list of offsets to the structures being processed.
- The first element in the list is the current structure */
- struct ndr_ofs_list *ofs_list;
-
- /* this list is used by the [relative] code to find the offsets */
- struct ndr_ofs_list *relative_list, *relative_list_end;
};
struct ndr_push_save {
diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c
index 1d6b90f4bf..1d50d95afa 100644
--- a/source4/librpc/ndr/ndr.c
+++ b/source4/librpc/ndr/ndr.c
@@ -55,7 +55,8 @@ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
ndr->data_size = blob->length;
ndr->offset = 0;
ndr->mem_ctx = mem_ctx;
- ndr->ofs_list = NULL;
+ ndr->ptr_count = 0;
+ ndr->relative_list = NULL;
return ndr;
}
@@ -139,9 +140,7 @@ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
ndr->offset = 0;
ndr->ptr_count = 0;
ndr->relative_list = NULL;
- ndr->relative_list_end = NULL;
- ndr->ofs_list = NULL;
-
+
return ndr;
}
@@ -604,12 +603,6 @@ NTSTATUS ndr_push_subcontext_union_fn(struct ndr_push *ndr,
*/
NTSTATUS ndr_pull_struct_start(struct ndr_pull *ndr)
{
- struct ndr_ofs_list *ofs;
- NDR_ALLOC(ndr, ofs);
- ofs->offset = ndr->offset;
- ofs->next = ndr->ofs_list;
- ofs->base = 0;
- ndr->ofs_list = ofs;
return NT_STATUS_OK;
}
@@ -618,7 +611,6 @@ NTSTATUS ndr_pull_struct_start(struct ndr_pull *ndr)
*/
void ndr_pull_struct_end(struct ndr_pull *ndr)
{
- ndr->ofs_list = ndr->ofs_list->next;
}
/*
@@ -626,12 +618,6 @@ void ndr_pull_struct_end(struct ndr_pull *ndr)
*/
NTSTATUS ndr_push_struct_start(struct ndr_push *ndr)
{
- struct ndr_ofs_list *ofs;
- NDR_PUSH_ALLOC(ndr, ofs);
- ofs->offset = ndr->offset;
- ofs->next = ndr->ofs_list;
- ofs->base = 0;
- ndr->ofs_list = ofs;
return NT_STATUS_OK;
}
@@ -640,7 +626,6 @@ NTSTATUS ndr_push_struct_start(struct ndr_push *ndr)
*/
void ndr_push_struct_end(struct ndr_push *ndr)
{
- ndr->ofs_list = ndr->ofs_list->next;
}
@@ -665,11 +650,7 @@ NTSTATUS ndr_pull_relative(struct ndr_pull *ndr, const void **buf, size_t size,
wrong, and there doesn't seem to be anything relying on it,
but I am keeping the code around in case I missed a
critical use for it (tridge, august 2004) */
-#if OLD_RELATIVE_BEHAVIOUR
- NDR_CHECK(ndr_pull_set_offset(ndr, ofs + ndr->ofs_list->offset));
-#else
NDR_CHECK(ndr_pull_set_offset(ndr, ofs));
-#endif
NDR_CHECK(ndr_pull_subcontext(ndr, &ndr2, ndr->data_size - ndr->offset));
/* strings must be allocated by the backend functions */
if (ndr->flags & LIBNDR_STRING_FLAGS) {
@@ -683,53 +664,98 @@ NTSTATUS ndr_pull_relative(struct ndr_pull *ndr, const void **buf, size_t size,
return NT_STATUS_OK;
}
+
/*
- push a relative structure
+ store a token in the ndr context, for later retrieval
*/
-NTSTATUS ndr_push_relative(struct ndr_push *ndr, int ndr_flags, const void *p)
+static NTSTATUS ndr_token_store(TALLOC_CTX *mem_ctx,
+ struct ndr_token_list **list,
+ const void *key,
+ uint32_t value)
{
- struct ndr_ofs_list *ofs;
- if (ndr_flags & NDR_SCALARS) {
- if (!p) {
- NDR_CHECK(ndr_push_uint32(ndr, 0));
- return NT_STATUS_OK;
- }
- NDR_PUSH_ALLOC(ndr, ofs);
- NDR_CHECK(ndr_push_align(ndr, 4));
- ofs->offset = ndr->offset;
-#if OLD_RELATIVE_BEHAVIOUR
- ofs->base = ndr->ofs_list->offset;
-#else
- ofs->base = 0;
-#endif
- NDR_CHECK(ndr_push_uint32(ndr, 0xFFFFFFFF));
- ofs->next = NULL;
- if (ndr->relative_list_end) {
- ndr->relative_list_end->next = ofs;
- } else {
- ndr->relative_list = ofs;
- }
- ndr->relative_list_end = ofs;
+ struct ndr_token_list *tok;
+ tok = talloc_p(mem_ctx, struct ndr_token_list);
+ if (tok == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
- if (ndr_flags & NDR_BUFFERS) {
- struct ndr_push_save save;
- if (!p) {
- return NT_STATUS_OK;
- }
- ofs = ndr->relative_list;
- if (!ofs) {
- 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;
+ tok->key = key;
+ tok->value = value;
+ DLIST_ADD((*list), tok);
+ return NT_STATUS_OK;
+}
+
+/*
+ retrieve a token from a ndr context
+*/
+static uint32_t ndr_token_retrieve(struct ndr_token_list **list, const void *key)
+{
+ struct ndr_token_list *tok;
+ for (tok=*list;tok;tok=tok->next) {
+ if (tok->key == key) {
+ DLIST_REMOVE((*list), tok);
+ return tok->value;
}
- NDR_CHECK(ndr_push_align(ndr, 4));
- ndr_push_save(ndr, &save);
- ndr->offset = ofs->offset;
- NDR_CHECK(ndr_push_uint32(ndr, save.offset - ofs->base));
- ndr_push_restore(ndr, &save);
}
+ return 0;
+}
+
+
+/*
+ pull a relative object - stage1
+ called during SCALARS processing
+*/
+NTSTATUS ndr_pull_relative1(struct ndr_pull *ndr, const void *p, uint32_t rel_offset)
+{
+ return ndr_token_store(ndr->mem_ctx, &ndr->relative_list, p, rel_offset);
+}
+
+/*
+ pull a relative object - stage2
+ called during BUFFERS processing
+*/
+NTSTATUS ndr_pull_relative2(struct ndr_pull *ndr, const void *p)
+{
+ uint32_t rel_offset;
+ rel_offset = ndr_token_retrieve(&ndr->relative_list, p);
+ if (rel_offset == 0) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ return ndr_pull_set_offset(ndr, rel_offset);
+}
+
+/*
+ push a relative object - stage1
+ this is called during SCALARS processing
+*/
+NTSTATUS ndr_push_relative1(struct ndr_push *ndr, const void *p)
+{
+ if (p == NULL) {
+ NDR_CHECK(ndr_push_uint32(ndr, 0));
+ return NT_STATUS_OK;
+ }
+ NDR_CHECK(ndr_push_align(ndr, 4));
+ NDR_CHECK(ndr_token_store(ndr->mem_ctx, &ndr->relative_list, p, ndr->offset));
+ return ndr_push_uint32(ndr, 0xFFFFFFFF);
+}
+
+/*
+ push a relative object - stage2
+ this is called during buffers processing
+*/
+NTSTATUS ndr_push_relative2(struct ndr_push *ndr, const void *p)
+{
+ 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->offset = ndr_token_retrieve(&ndr->relative_list, p);
+ if (ndr->offset == 0) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+ NDR_CHECK(ndr_push_uint32(ndr, save.offset));
+ ndr_push_restore(ndr, &save);
return NT_STATUS_OK;
}
diff --git a/source4/librpc/ndr/ndr_basic.c b/source4/librpc/ndr/ndr_basic.c
index bf72e0ad8b..88a58e91fd 100644
--- a/source4/librpc/ndr/ndr_basic.c
+++ b/source4/librpc/ndr/ndr_basic.c
@@ -72,6 +72,9 @@ NTSTATUS ndr_pull_ptr(struct ndr_pull *ndr, uint32_t *v)
{
NTSTATUS status;
status = ndr_pull_uint32(ndr, v);
+ if (*v != 0) {
+ ndr->ptr_count++;
+ }
return status;
}
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index b04591cf3b..000dc27fad 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -614,6 +614,11 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
return NT_STATUS_NO_MEMORY;
}
+ /* carry over the pointer count to the reply in case we are
+ using full pointer. See NDR specification for full
+ pointers */
+ push->ptr_count = pull->ptr_count;
+
if (lp_rpc_big_endian()) {
push->flags |= LIBNDR_FLAG_BIGENDIAN;
}