summaryrefslogtreecommitdiff
path: root/librpc/ndr
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2016-06-17 13:29:51 +1200
committerStefan Metzmacher <metze@samba.org>2016-07-28 10:06:12 +0200
commit1246904d41eebc3440636dd29a9dc9ba38b738f6 (patch)
tree642617b02dd9318c0ed4d2b14e880aa4a902e83d /librpc/ndr
parentc07504f40dea1b850aa84dab6af5216b097217cc (diff)
downloadsamba-1246904d41eebc3440636dd29a9dc9ba38b738f6.tar.gz
librpc: Add ndr_push_struct_into_fixed_blob() and use it in GUID_to_ndr_blob()
This allows us to allocate only the correct size, not a default of 1024 bytes per push. Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Diffstat (limited to 'librpc/ndr')
-rw-r--r--librpc/ndr/libndr.h6
-rw-r--r--librpc/ndr/ndr.c40
-rw-r--r--librpc/ndr/uuid.c8
3 files changed, 51 insertions, 3 deletions
diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h
index 6034229336e..0c3c55a9bf2 100644
--- a/librpc/ndr/libndr.h
+++ b/librpc/ndr/libndr.h
@@ -83,7 +83,8 @@ struct ndr_push {
uint8_t *data;
uint32_t alloc_size;
uint32_t offset;
-
+ bool fixed_buf_size;
+
uint32_t relative_base_offset;
uint32_t relative_end_offset;
struct ndr_token_list *relative_base_list;
@@ -466,6 +467,9 @@ bool ndr_syntax_id_equal(const struct ndr_syntax_id *i1, const struct ndr_syntax
char *ndr_syntax_id_to_string(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id *id);
bool ndr_syntax_id_from_string(const char *s, struct ndr_syntax_id *id);
enum ndr_err_code ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, const void *p, ndr_push_flags_fn_t fn);
+enum ndr_err_code ndr_push_struct_into_fixed_blob(DATA_BLOB *blob,
+ const void *p,
+ ndr_push_flags_fn_t fn);
enum ndr_err_code ndr_push_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p, uint32_t level, ndr_push_flags_fn_t fn);
size_t ndr_size_struct(const void *p, int flags, ndr_push_flags_fn_t push);
size_t ndr_size_union(const void *p, int flags, uint32_t level, ndr_push_flags_fn_t push);
diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c
index 78cde20f7d1..22c4d763d09 100644
--- a/librpc/ndr/ndr.c
+++ b/librpc/ndr/ndr.c
@@ -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
*/
diff --git a/librpc/ndr/uuid.c b/librpc/ndr/uuid.c
index fbd305e5401..a3f68d1d344 100644
--- a/librpc/ndr/uuid.c
+++ b/librpc/ndr/uuid.c
@@ -31,8 +31,12 @@
_PUBLIC_ NTSTATUS GUID_to_ndr_blob(const struct GUID *guid, TALLOC_CTX *mem_ctx, DATA_BLOB *b)
{
enum ndr_err_code ndr_err;
- ndr_err = ndr_push_struct_blob(b, mem_ctx, guid,
- (ndr_push_flags_fn_t)ndr_push_GUID);
+ *b = data_blob_talloc(mem_ctx, NULL, 16);
+ if (b->data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ ndr_err = ndr_push_struct_into_fixed_blob(
+ b, guid, (ndr_push_flags_fn_t)ndr_push_GUID);
return ndr_map_error2ntstatus(ndr_err);
}