summaryrefslogtreecommitdiffstats
path: root/librpc
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2010-02-17 21:24:40 +0100
committerKarolin Seeger <kseeger@samba.org>2010-02-19 14:32:31 +0100
commit8423dc74341d7b153131d0002aee8585af16582f (patch)
tree38115b03d7c9c1bfbf0051ecb772a2423f79ffea /librpc
parentdf1d697ac9070c4cb5a08452c271035dd3daa89f (diff)
downloadsamba-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)
Diffstat (limited to 'librpc')
-rw-r--r--librpc/ndr/libndr.h1
-rw-r--r--librpc/ndr/ndr.c89
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;
}