librpc: Add autogenerated total cabinet size for Cabinet files
[kai/samba-autobuild/.git] / librpc / ndr / ndr.c
index f66029ab2cba174310794eb0e7d6206bff89dced..22c4d763d09f719b9c8fedd440ad85e2b0f594c4 100644 (file)
@@ -254,6 +254,17 @@ _PUBLIC_ enum ndr_err_code ndr_push_expand(struct ndr_push *ndr, uint32_t extra_
                                      size);
        }
 
+       if (ndr->fixed_buf_size) {
+               if (ndr->alloc_size >= size) {
+                       return NDR_ERR_SUCCESS;
+               }
+               return ndr_push_error(ndr,
+                                     NDR_ERR_BUFSIZE,
+                                     "Overflow of fixed buffer in "
+                                     "push_expand to %u",
+                                     size);
+       }
+       
        if (ndr->alloc_size > size) {
                return NDR_ERR_SUCCESS;
        }
@@ -1264,6 +1275,35 @@ _PUBLIC_ enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem
        return NDR_ERR_SUCCESS;
 }
 
+/* 
+  push a struct into a provided blob using NDR. 
+  We error because we want to have the performance issue (extra
+  talloc() calls) show up as an error, not just slower code.  This is
+  used for things like GUIDs, which we expect to be a fixed size, and
+  SIDs that we can pre-calculate the size for.
+*/
+_PUBLIC_ enum ndr_err_code ndr_push_struct_into_fixed_blob(
+       DATA_BLOB *blob, const void *p, ndr_push_flags_fn_t fn)
+{
+       struct ndr_push ndr = {
+               .data = blob->data,
+               .alloc_size = blob->length,
+               .fixed_buf_size = true
+       };
+
+       NDR_CHECK(fn(&ndr, NDR_SCALARS|NDR_BUFFERS, p));
+
+       if (ndr.offset != blob->length) {
+               return ndr_push_error(&ndr, NDR_ERR_BUFSIZE,
+                                     "buffer was either to large or small "
+                                     "ofs[%u] size[%zu]",
+                                     ndr.offset, blob->length);
+       }
+
+       return NDR_ERR_SUCCESS;
+}
+
 /*
   push a union to a blob using NDR
 */
@@ -1440,9 +1480,44 @@ _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, co
 {
        uint32_t save_offset;
        uint32_t ptr_offset = 0xFFFF;
+       uint32_t relative_offset;
+       size_t pad;
+       size_t align = 1;
+
        if (p == NULL) {
                return NDR_ERR_SUCCESS;
        }
+
+       if (ndr->offset < ndr->relative_base_offset) {
+               return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+                                     "ndr_push_relative_ptr2 ndr->offset(%u) < ndr->relative_base_offset(%u)",
+                                     ndr->offset, ndr->relative_base_offset);
+       }
+
+       relative_offset = ndr->offset - ndr->relative_base_offset;
+
+       if (ndr->flags & LIBNDR_FLAG_NOALIGN) {
+               align = 1;
+       } else 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(relative_offset, align);
+       if (pad != 0) {
+               NDR_CHECK(ndr_push_zero(ndr, pad));
+       }
+
+       relative_offset = ndr->offset - ndr->relative_base_offset;
+       if (relative_offset > UINT16_MAX) {
+               return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
+                                     "ndr_push_relative_ptr2 relative_offset(%u) > UINT16_MAX",
+                                     relative_offset);
+       }
+
        save_offset = ndr->offset;
        NDR_CHECK(ndr_token_retrieve(&ndr->relative_list, p, &ptr_offset));
        if (ptr_offset > ndr->offset) {
@@ -1451,12 +1526,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_short_relative_ptr2(struct ndr_push *ndr, co
                                      ptr_offset, ndr->offset);
        }
        ndr->offset = ptr_offset;
-       if (save_offset < ndr->relative_base_offset) {
-               return ndr_push_error(ndr, NDR_ERR_BUFSIZE,
-                                     "ndr_push_relative_ptr2 save_offset(%u) < ndr->relative_base_offset(%u)",
-                                     save_offset, ndr->relative_base_offset);
-       }
-       NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, save_offset - ndr->relative_base_offset));
+       NDR_CHECK(ndr_push_uint16(ndr, NDR_SCALARS, relative_offset));
        ndr->offset = save_offset;
        return NDR_ERR_SUCCESS;
 }