summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-08-12 05:15:41 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:57:54 -0500
commite2357c67f5afbfeacafab6997b57ea262cd3c05a (patch)
treef003a9ce63846a5ce8340b366df502d8bf49c381
parentfa8d37adae70a5f479262b722e47aa7fc21aaf5c (diff)
downloadsamba-e2357c67f5afbfeacafab6997b57ea262cd3c05a.tar.gz
samba-e2357c67f5afbfeacafab6997b57ea262cd3c05a.tar.bz2
samba-e2357c67f5afbfeacafab6997b57ea262cd3c05a.zip
r1757: much simpler (and smaller, faster etc) way of doing relative pointers
in pidl. This mechanism should be much easier to extend to the "retrospective subcontexts" that jelmer needs. also produced more standards complient full-pointer offsets. This keeps ethereal happy with decoding our epmapper frames. (This used to be commit ecb7378bbcd86727aedfa04a9e302e06b0a2ccd9)
-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;
}