summaryrefslogtreecommitdiffstats
path: root/librpc/ndr
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2013-09-21 02:28:33 +0200
committerGünther Deschner <gd@samba.org>2014-02-11 16:02:14 +0100
commit7b5717058a7d7a93cda712efc7622a87d3980e48 (patch)
treeea4513ddd3e01089168bea938ff65bbc691095ad /librpc/ndr
parent53e0ceddff7a4e668242a2db53764fa962c71163 (diff)
downloadsamba-7b5717058a7d7a93cda712efc7622a87d3980e48.tar.gz
samba-7b5717058a7d7a93cda712efc7622a87d3980e48.tar.xz
samba-7b5717058a7d7a93cda712efc7622a87d3980e48.zip
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/ndr')
-rw-r--r--librpc/ndr/libndr.h2
-rw-r--r--librpc/ndr/ndr.c105
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
*/