diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/build/pidl/parser.pm | 13 | ||||
-rw-r--r-- | source4/librpc/ndr/libndr.h | 31 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr.c | 152 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr_basic.c | 3 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 5 |
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; } |