diff options
author | Stefan Metzmacher <metze@samba.org> | 2013-09-21 02:28:33 +0200 |
---|---|---|
committer | Günther Deschner <gd@samba.org> | 2014-02-11 16:02:14 +0100 |
commit | 7b5717058a7d7a93cda712efc7622a87d3980e48 (patch) | |
tree | ea4513ddd3e01089168bea938ff65bbc691095ad /librpc | |
parent | 53e0ceddff7a4e668242a2db53764fa962c71163 (diff) | |
download | samba-7b5717058a7d7a93cda712efc7622a87d3980e48.tar.gz |
librpc/ndr: add ndr_pull_append/pop()
They can be used to parse a fragmented NDR byte stream.
ndr_pull_append() appends more data that can be processed
and ndr_pull_pop() removed already processed data.
This will be used to implement dcerpc pipes, where we can get
a verify large amount of pipe chunks, once we processed a chunk
we can forget about the related data, but we may need to keep some
bytes in order to get the alignment right.
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
Diffstat (limited to 'librpc')
-rw-r--r-- | librpc/ndr/libndr.h | 2 | ||||
-rw-r--r-- | librpc/ndr/ndr.c | 105 |
2 files changed, 107 insertions, 0 deletions
diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h index f52038eb3b8..79de7a0f379 100644 --- a/librpc/ndr/libndr.h +++ b/librpc/ndr/libndr.h @@ -480,6 +480,8 @@ enum ndr_err_code ndr_pull_relative_ptr2(struct ndr_pull *ndr, const void *p); enum ndr_err_code ndr_pull_relative_ptr_short(struct ndr_pull *ndr, uint16_t *v); size_t ndr_align_size(uint32_t offset, size_t n); struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx); +enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob); +enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr); enum ndr_err_code ndr_pull_advance(struct ndr_pull *ndr, uint32_t size); struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx); DATA_BLOB ndr_push_blob(struct ndr_push *ndr); diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c index 367a9cde937..76073ed0b72 100644 --- a/librpc/ndr/ndr.c +++ b/librpc/ndr/ndr.c @@ -75,6 +75,111 @@ _PUBLIC_ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX * return ndr; } +_PUBLIC_ enum ndr_err_code ndr_pull_append(struct ndr_pull *ndr, DATA_BLOB *blob) +{ + enum ndr_err_code ndr_err; + DATA_BLOB b; + uint32_t append = 0; + bool ok; + + if (blob->length == 0) { + return NDR_ERR_SUCCESS; + } + + ndr_err = ndr_token_retrieve(&ndr->array_size_list, ndr, &append); + if (ndr_err == NDR_ERR_TOKEN) { + append = 0; + ndr_err = NDR_ERR_SUCCESS; + } + NDR_CHECK(ndr_err); + + if (ndr->data_size == 0) { + ndr->data = NULL; + append = UINT32_MAX; + } + + if (append == UINT32_MAX) { + /* + * append == UINT32_MAX means that + * ndr->data is either NULL or a valid + * talloc child of ndr, which means + * we can use data_blob_append() without + * data_blob_talloc() of the existing callers data + */ + b = data_blob_const(ndr->data, ndr->data_size); + } else { + b = data_blob_talloc(ndr, ndr->data, ndr->data_size); + if (b.data == NULL) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__); + } + } + + ok = data_blob_append(ndr, &b, blob->data, blob->length); + if (!ok) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__); + } + + ndr->data = b.data; + ndr->data_size = b.length; + + return ndr_token_store(ndr, &ndr->array_size_list, ndr, UINT32_MAX); +} + +_PUBLIC_ enum ndr_err_code ndr_pull_pop(struct ndr_pull *ndr) +{ + uint32_t skip = 0; + uint32_t append = 0; + + if (ndr->relative_base_offset != 0) { + return ndr_pull_error(ndr, NDR_ERR_RELATIVE, + "%s", __location__); + } + if (ndr->relative_highest_offset != 0) { + return ndr_pull_error(ndr, NDR_ERR_RELATIVE, + "%s", __location__); + } + if (ndr->relative_list != NULL) { + return ndr_pull_error(ndr, NDR_ERR_RELATIVE, + "%s", __location__); + } + if (ndr->relative_base_list != NULL) { + return ndr_pull_error(ndr, NDR_ERR_RELATIVE, + "%s", __location__); + } + + /* + * we need to keep up to 7 bytes + * in order to get the aligment right. + */ + skip = ndr->offset & 0xFFFFFFF8; + + if (skip == 0) { + return NDR_ERR_SUCCESS; + } + + ndr->offset -= skip; + ndr->data_size -= skip; + + append = ndr_token_peek(&ndr->array_size_list, ndr); + if (append != UINT32_MAX) { + /* + * here we assume, that ndr->data is not a + * talloc child of ndr. + */ + ndr->data += skip; + return NDR_ERR_SUCCESS; + } + + memmove(ndr->data, ndr->data + skip, ndr->data_size); + + ndr->data = talloc_realloc(ndr, ndr->data, uint8_t, ndr->data_size); + if (ndr->data_size != 0 && ndr->data == NULL) { + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "%s", __location__); + } + + return NDR_ERR_SUCCESS; +} + /* advance by 'size' bytes */ |