diff options
author | Stefan Metzmacher <metze@samba.org> | 2010-02-17 21:24:40 +0100 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2010-02-19 14:32:31 +0100 |
commit | 8423dc74341d7b153131d0002aee8585af16582f (patch) | |
tree | 38115b03d7c9c1bfbf0051ecb772a2423f79ffea | |
parent | df1d697ac9070c4cb5a08452c271035dd3daa89f (diff) | |
download | samba-8423dc74341d7b153131d0002aee8585af16582f.tar.gz samba-8423dc74341d7b153131d0002aee8585af16582f.tar.xz samba-8423dc74341d7b153131d0002aee8585af16582f.zip |
libndr: implement LIBNDR_RELATIVE_REVERSE handling
This is based on Guenther's initial code.
metze
(cherry picked from commit 31c7780c16651b284009874cf3da04587dc36d19)
(cherry picked from commit 148460b4ed9dd1ecf83acace0641bab6d22f7296)
-rw-r--r-- | librpc/ndr/libndr.h | 1 | ||||
-rw-r--r-- | librpc/ndr/ndr.c | 89 |
2 files changed, 87 insertions, 3 deletions
diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h index ca920ec068b..ff7c9125d63 100644 --- a/librpc/ndr/libndr.h +++ b/librpc/ndr/libndr.h @@ -90,6 +90,7 @@ struct ndr_push { struct ndr_token_list *switch_list; struct ndr_token_list *relative_list; + struct ndr_token_list *relative_begin_list; struct ndr_token_list *nbt_string_list; struct ndr_token_list *full_ptr_list; diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c index 19620acc56f..c5c6804afc2 100644 --- a/librpc/ndr/ndr.c +++ b/librpc/ndr/ndr.c @@ -1107,9 +1107,13 @@ _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, co if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) { return ndr_push_relative_ptr2(ndr, p); } - - return ndr_push_error(ndr, NDR_ERR_RELATIVE, - "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set, but not supported"); + if (ndr->relative_end_offset == -1) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_start RELATIVE_REVERSE flag set and relative_end_offset %d", + ndr->relative_end_offset); + } + NDR_CHECK(ndr_token_store(ndr, &ndr->relative_begin_list, p, ndr->offset)); + return NDR_ERR_SUCCESS; } /* @@ -1118,9 +1122,88 @@ _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_start(struct ndr_push *ndr, co */ _PUBLIC_ enum ndr_err_code ndr_push_relative_ptr2_end(struct ndr_push *ndr, const void *p) { + uint32_t begin_offset = 0xFFFFFFFF; + ssize_t len; + uint32_t correct_offset = 0; + uint32_t align = 1; + uint32_t pad = 0; + if (p == NULL) { return NDR_ERR_SUCCESS; } + + if (!(ndr->flags & LIBNDR_FLAG_RELATIVE_REVERSE)) { + return NDR_ERR_SUCCESS; + } + + if (ndr->relative_end_offset < ndr->offset) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end:" + "relative_end_offset %u < offset %u", + ndr->relative_end_offset, ndr->offset); + } + + NDR_CHECK(ndr_token_retrieve(&ndr->relative_begin_list, p, &begin_offset)); + + /* we have marshalled a buffer, see how long it was */ + len = ndr->offset - begin_offset; + + if (len < 0) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end:" + "offset %u - begin_offset %u < 0", + ndr->offset, begin_offset); + } + + if (ndr->relative_end_offset < len) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end:" + "relative_end_offset %u < len %lld", + ndr->offset, (long long)len); + } + + /* the reversed offset is at the end of the main buffer */ + correct_offset = ndr->relative_end_offset - len; + + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + align = 2; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + align = 4; + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + align = 8; + } + + pad = ndr_align_size(correct_offset, align); + if (pad) { + correct_offset += pad; + correct_offset -= align; + } + + if (correct_offset < begin_offset) { + return ndr_push_error(ndr, NDR_ERR_RELATIVE, + "ndr_push_relative_ptr2_end: " + "correct_offset %u < begin_offset %u", + correct_offset, begin_offset); + } + + if (len > 0) { + /* now move the marshalled buffer to the end of the main buffer */ + memmove(ndr->data + correct_offset, ndr->data + begin_offset, len); + + /* and wipe out old buffer within the main buffer */ + memset(ndr->data + begin_offset, '\0', len); + } + + /* and set the end offset for the next buffer */ + ndr->relative_end_offset = correct_offset; + + /* finally write the offset to the main buffer */ + ndr->offset = correct_offset; + NDR_CHECK(ndr_push_relative_ptr2(ndr, p)); + + /* restore to where we were in the main buffer */ + ndr->offset = begin_offset; + return NDR_ERR_SUCCESS; } |