r6690: added ndr_pull_struct_blob_all(), which is like ndr_pull_struct_blob() but...
[samba.git] / source / librpc / ndr / ndr.c
index 2e350aa0da7e72a880ecc17c2d63f40fa77d5c3f..79af5967c754e7ac56186b6e04dfbc82e6f18234 100644 (file)
@@ -315,7 +315,7 @@ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
 {
        struct ndr_print *ndr;
 
-       ndr = talloc(NULL, struct ndr_print);
+       ndr = talloc_zero(NULL, struct ndr_print);
        if (!ndr) return;
        ndr->print = ndr_print_debug_helper;
        ndr->depth = 1;
@@ -324,23 +324,6 @@ void ndr_print_debug(ndr_print_fn_t fn, const char *name, void *ptr)
        talloc_free(ndr);
 }
 
-
-/*
-  a useful helper function for printing idl unions via DEBUG()
-*/
-void ndr_print_union_debug(ndr_print_union_fn_t fn, const char *name, uint32_t level, void *ptr)
-{
-       struct ndr_print *ndr;
-
-       ndr = talloc(NULL, struct ndr_print);
-       if (!ndr) return;
-       ndr->print = ndr_print_debug_helper;
-       ndr->depth = 1;
-       ndr->flags = 0;
-       fn(ndr, name, level, ptr);
-       talloc_free(ndr);
-}
-
 /*
   a useful helper function for printing idl function calls via DEBUG()
 */
@@ -348,7 +331,7 @@ void ndr_print_function_debug(ndr_print_function_t fn, const char *name, int fla
 {
        struct ndr_print *ndr;
 
-       ndr = talloc(NULL, struct ndr_print);
+       ndr = talloc_zero(NULL, struct ndr_print);
        if (!ndr) return;
        ndr->print = ndr_print_debug_helper;
        ndr->depth = 1;
@@ -433,34 +416,46 @@ NTSTATUS ndr_push_error(struct ndr_push *ndr, enum ndr_err_code err, const char
   we use magic in pidl to make them easier to cope with
 */
 NTSTATUS ndr_pull_subcontext_header(struct ndr_pull *ndr, 
-                                          size_t sub_size,
+                                          size_t header_size,
+                                          ssize_t size_is,
                                           struct ndr_pull *ndr2)
 {
        ndr2->flags = ndr->flags;
 
-       switch (sub_size) {
+       switch (header_size) {
        case 0: {
-               uint32_t size = ndr->data_size - ndr->offset;
-               NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
+               uint32_t content_size = ndr->data_size - ndr->offset;
+               if (size_is >= 0) {
+                       content_size = size_is;
+               }
+               NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, content_size));
                break;
        }
 
        case 2: {
-               uint16_t size;
-               NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &size));
-               NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
+               uint16_t content_size;
+               NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &content_size));
+               if (size_is >= 0 && size_is != content_size) {
+                       return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", 
+                                               size_is, content_size);
+               }
+               NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, content_size));
                break;
        }
 
        case 4: {
-               uint32_t size;
-               NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &size));
-               NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, size));
+               uint32_t content_size;
+               NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &content_size));
+               if (size_is >= 0 && size_is != content_size) {
+                       return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) size_is(%d) mismatch content_size %d", 
+                                               size_is, content_size);
+               }
+               NDR_CHECK(ndr_pull_subcontext(ndr, ndr2, content_size));
                break;
        }
        default:
-               return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d", 
-                                     sub_size);
+               return ndr_pull_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PULL) header_size %d", 
+                                     header_size);
        }
        return NT_STATUS_OK;
 }
@@ -469,10 +464,21 @@ NTSTATUS ndr_pull_subcontext_header(struct ndr_pull *ndr,
   push a subcontext header 
 */
 NTSTATUS ndr_push_subcontext_header(struct ndr_push *ndr, 
-                                          size_t sub_size,
+                                          size_t header_size,
+                                          ssize_t size_is,
                                           struct ndr_push *ndr2)
 {
-       switch (sub_size) {
+       if (size_is >= 0) {
+               ssize_t padding_len = size_is - ndr2->offset;
+               if (padding_len > 0) {
+                       NDR_CHECK(ndr_push_zero(ndr2, padding_len));
+               } else if (padding_len < 0) {
+                       return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext (PUSH) content_size %d is larger than size_is(%d)",
+                                             ndr2->offset, size_is);
+               }
+       }
+
+       switch (header_size) {
        case 0: 
                break;
 
@@ -485,8 +491,8 @@ NTSTATUS ndr_push_subcontext_header(struct ndr_push *ndr,
                break;
 
        default:
-               return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d", 
-                                     sub_size);
+               return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext header size %d", 
+                                     header_size);
        }
        return NT_STATUS_OK;
 }
@@ -644,12 +650,17 @@ NTSTATUS ndr_check_array_length(struct ndr_pull *ndr, void *p, uint32_t length)
 /*
   store a switch value
  */
-NTSTATUS ndr_push_set_switch_value(struct ndr_push *ndr, void *p, uint32_t val)
+NTSTATUS ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val)
+{
+       return ndr_token_store(ndr, &ndr->switch_list, p, val);
+}
+
+NTSTATUS ndr_pull_set_switch_value(struct ndr_pull *ndr, const void *p, uint32_t val)
 {
        return ndr_token_store(ndr, &ndr->switch_list, p, val);
 }
 
-NTSTATUS ndr_pull_set_switch_value(struct ndr_pull *ndr, void *p, uint32_t val)
+NTSTATUS ndr_print_set_switch_value(struct ndr_print *ndr, const void *p, uint32_t val)
 {
        return ndr_token_store(ndr, &ndr->switch_list, p, val);
 }
@@ -657,12 +668,17 @@ NTSTATUS ndr_pull_set_switch_value(struct ndr_pull *ndr, void *p, uint32_t val)
 /*
   retrieve a switch value
  */
-uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, void *p)
+uint32_t ndr_push_get_switch_value(struct ndr_push *ndr, const void *p)
+{
+       return ndr_token_peek(&ndr->switch_list, p);
+}
+
+uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, const void *p)
 {
        return ndr_token_peek(&ndr->switch_list, p);
 }
 
-uint32_t ndr_pull_get_switch_value(struct ndr_pull *ndr, void *p)
+uint32_t ndr_print_get_switch_value(struct ndr_print *ndr, const void *p)
 {
        return ndr_token_peek(&ndr->switch_list, p);
 }
@@ -729,33 +745,39 @@ NTSTATUS ndr_push_relative_ptr2(struct ndr_push *ndr, const void *p)
        return NT_STATUS_OK;
 }
 
-
 /*
-  pull a union from a blob using NDR
+  pull a struct from a blob using NDR
 */
-NTSTATUS ndr_pull_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, uint32_t level, void *p,
-                            ndr_pull_union_fn_t fn)
+NTSTATUS ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+                             ndr_pull_flags_fn_t fn)
 {
        struct ndr_pull *ndr;
        ndr = ndr_pull_init_blob(blob, mem_ctx);
        if (!ndr) {
                return NT_STATUS_NO_MEMORY;
        }
-       return fn(ndr, NDR_SCALARS|NDR_BUFFERS, level, p);
+       return fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
 }
 
 /*
-  pull a struct from a blob using NDR
+  pull a struct from a blob using NDR - failing if all bytes are not consumed
 */
-NTSTATUS ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
-                             ndr_pull_flags_fn_t fn)
+NTSTATUS ndr_pull_struct_blob_all(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+                                 ndr_pull_flags_fn_t fn)
 {
        struct ndr_pull *ndr;
+       NTSTATUS status;
+
        ndr = ndr_pull_init_blob(blob, mem_ctx);
        if (!ndr) {
                return NT_STATUS_NO_MEMORY;
        }
-       return fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
+       status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
+       if (!NT_STATUS_IS_OK(status)) return status;
+       if (ndr->offset != ndr->data_size) {
+               return NT_STATUS_BUFFER_TOO_SMALL;
+       }
+       return status;
 }
 
 /*
@@ -789,9 +811,12 @@ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
        NTSTATUS status;
        size_t ret;
 
+       /* avoid recursion */
+       if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
+
        ndr = ndr_push_init_ctx(NULL);
        if (!ndr) return 0;
-       ndr->flags |= flags;
+       ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
        status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
        if (!NT_STATUS_IS_OK(status)) {
                return 0;
@@ -804,16 +829,20 @@ size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push)
 /*
   generic ndr_size_*() handler for unions
 */
-size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_union_fn_t push)
+size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push)
 {
        struct ndr_push *ndr;
        NTSTATUS status;
        size_t ret;
 
+       /* avoid recursion */
+       if (flags & LIBNDR_FLAG_NO_NDR_SIZE) return 0;
+
        ndr = ndr_push_init_ctx(NULL);
        if (!ndr) return 0;
-       ndr->flags |= flags;
-       status = push(ndr, NDR_SCALARS|NDR_BUFFERS, level, discard_const(p));
+       ndr->flags |= flags | LIBNDR_FLAG_NO_NDR_SIZE;
+       ndr_push_set_switch_value(ndr, p, level);
+       status = push(ndr, NDR_SCALARS|NDR_BUFFERS, discard_const(p));
        if (!NT_STATUS_IS_OK(status)) {
                return 0;
        }