summaryrefslogtreecommitdiff
path: root/source4/librpc
diff options
context:
space:
mode:
Diffstat (limited to 'source4/librpc')
-rw-r--r--source4/librpc/idl/samr.idl10
-rw-r--r--source4/librpc/ndr/libndr.h35
-rw-r--r--source4/librpc/ndr/ndr.c163
-rw-r--r--source4/librpc/ndr/ndr_basic.c24
-rw-r--r--source4/librpc/ndr/ndr_sec.c50
-rw-r--r--source4/librpc/rpc/dcerpc.c160
-rw-r--r--source4/librpc/rpc/dcerpc.h6
7 files changed, 409 insertions, 39 deletions
diff --git a/source4/librpc/idl/samr.idl b/source4/librpc/idl/samr.idl
index bb0e85b7de..f73ad9a8ea 100644
--- a/source4/librpc/idl/samr.idl
+++ b/source4/librpc/idl/samr.idl
@@ -44,7 +44,7 @@
/* Function: 0x03 */
typedef struct {
- uint32 sd_size;
+ [value(ndr_size_security_descriptor(r->sd))] uint32 sd_size;
[subcontext(4)] security_descriptor *sd;
} samr_SdBuf;
@@ -91,7 +91,7 @@
[in,out,ref] uint32 *resume_handle,
[in] uint32 buf_size,
[out] samr_SamArray *sam,
- [out,ref] uint32 *num_entries
+ [out] uint32 num_entries
);
@@ -224,7 +224,7 @@
[in,out,ref] uint32 *resume_handle,
[in] uint32 max_size,
[out] samr_SamArray *sam,
- [out,ref] uint32 num_entries
+ [out] uint32 num_entries
);
/************************/
@@ -245,7 +245,7 @@
[in] uint32 acct_flags,
[in] uint32 max_size,
[out] samr_SamArray *sam,
- [out,ref] uint32 num_entries
+ [out] uint32 num_entries
);
/************************/
@@ -259,7 +259,7 @@
[in,out,ref] uint32 *resume_handle,
[in] uint32 max_size,
[out] samr_SamArray *sam,
- [out,ref] uint32 num_entries
+ [out] uint32 num_entries
);
/************************/
diff --git a/source4/librpc/ndr/libndr.h b/source4/librpc/ndr/libndr.h
index 5c771ff2d2..3c77646239 100644
--- a/source4/librpc/ndr/libndr.h
+++ b/source4/librpc/ndr/libndr.h
@@ -73,7 +73,7 @@ struct ndr_push {
struct ndr_ofs_list *ofs_list;
/* this list is used by the [relative] code to find the offsets */
- struct ndr_ofs_list *relative_list;
+ struct ndr_ofs_list *relative_list, *relative_list_end;
};
struct ndr_push_save {
@@ -101,6 +101,8 @@ struct ndr_print {
#define LIBNDR_FLAG_STR_NULLTERM (1<<6)
#define LIBNDR_STRING_FLAGS (0x7C)
+#define LIBNDR_FLAG_REF_ALLOC (1<<10)
+
/* useful macro for debugging */
#define NDR_PRINT_DEBUG(type, p) ndr_print_debug((ndr_print_fn_t)ndr_print_ ##type, #p, p)
#define NDR_PRINT_UNION_DEBUG(type, level, p) ndr_print_union_debug((ndr_print_union_fn_t)ndr_print_ ##type, #p, level, p)
@@ -119,7 +121,10 @@ enum ndr_err_code {
NDR_ERR_CHARCNV,
NDR_ERR_LENGTH,
NDR_ERR_SUBCONTEXT,
- NDR_ERR_STRING
+ NDR_ERR_STRING,
+ NDR_ERR_VALIDATE,
+ NDR_ERR_BUFSIZE,
+ NDR_ERR_ALLOC
};
/*
@@ -137,7 +142,7 @@ enum ndr_err_code {
#define NDR_PULL_NEED_BYTES(ndr, n) do { \
if ((n) > ndr->data_size || ndr->offset + (n) > ndr->data_size) { \
- return NT_STATUS_BUFFER_TOO_SMALL; \
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull bytes %u", n); \
} \
} while(0)
@@ -146,7 +151,7 @@ enum ndr_err_code {
ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \
} \
if (ndr->offset >= ndr->data_size) { \
- return NT_STATUS_BUFFER_TOO_SMALL; \
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, "Pull align %u", n); \
} \
} while(0)
@@ -154,7 +159,7 @@ enum ndr_err_code {
#define NDR_PUSH_ALIGN(ndr, n) do { \
if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \
- uint32 _pad = (ndr->offset & (n-1)); \
+ uint32 _pad = ((ndr->offset + (n-1)) & ~(n-1)) - ndr->offset; \
while (_pad--) NDR_CHECK(ndr_push_uint8(ndr, 0)); \
} \
} while(0)
@@ -171,7 +176,9 @@ enum ndr_err_code {
#define NDR_ALLOC_SIZE(ndr, s, size) do { \
(s) = talloc(ndr->mem_ctx, size); \
- if (!(s)) return NT_STATUS_NO_MEMORY; \
+ if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, \
+ "Alloc %u failed\n", \
+ size); \
} while (0)
#define NDR_ALLOC(ndr, s) NDR_ALLOC_SIZE(ndr, s, sizeof(*(s)))
@@ -182,12 +189,26 @@ enum ndr_err_code {
(s) = NULL; \
} else { \
(s) = talloc(ndr->mem_ctx, (n) * elsize); \
- if (!(s)) return NT_STATUS_NO_MEMORY; \
+ if (!(s)) return ndr_pull_error(ndr, \
+ NDR_ERR_ALLOC, \
+ "Alloc %u * %u failed\n", \
+ n, elsize); \
} \
} while (0)
#define NDR_ALLOC_N(ndr, s, n) NDR_ALLOC_N_SIZE(ndr, s, n, sizeof(*(s)))
+
+#define NDR_PUSH_ALLOC_SIZE(ndr, s, size) do { \
+ (s) = talloc(ndr->mem_ctx, size); \
+ if (!(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, \
+ "push alloc %u failed\n",\
+ size); \
+ } while (0)
+
+#define NDR_PUSH_ALLOC(ndr, s) NDR_PUSH_ALLOC_SIZE(ndr, s, sizeof(*(s)))
+
+
/* these are used when generic fn pointers are needed for ndr push/pull fns */
typedef NTSTATUS (*ndr_push_fn_t)(struct ndr_push *, void *);
typedef NTSTATUS (*ndr_pull_fn_t)(struct ndr_pull *, void *);
diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c
index b67fb25b1e..7deee6be3b 100644
--- a/source4/librpc/ndr/ndr.c
+++ b/source4/librpc/ndr/ndr.c
@@ -81,7 +81,9 @@ NTSTATUS ndr_pull_limit_size(struct ndr_pull *ndr, uint32 size, uint32 ofs)
new_size = ndr->offset + size - ofs;
if (new_size > ndr->data_size) {
- return NT_STATUS_BUFFER_TOO_SMALL;
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_limit_size %s %u failed",
+ size, ofs);
}
ndr->data_size = new_size;
@@ -96,7 +98,9 @@ NTSTATUS ndr_pull_advance(struct ndr_pull *ndr, uint32 size)
{
ndr->offset += size;
if (ndr->offset > ndr->data_size) {
- return NT_STATUS_BUFFER_TOO_SMALL;
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_advance by %u failed",
+ size);
}
return NT_STATUS_OK;
}
@@ -108,7 +112,9 @@ NTSTATUS ndr_pull_set_offset(struct ndr_pull *ndr, uint32 ofs)
{
ndr->offset = ofs;
if (ndr->offset > ndr->data_size) {
- return NT_STATUS_BUFFER_TOO_SMALL;
+ return ndr_pull_error(ndr, NDR_ERR_BUFSIZE,
+ "ndr_pull_set_offset %u failed",
+ ofs);
}
return NT_STATUS_OK;
}
@@ -128,18 +134,13 @@ void ndr_pull_restore(struct ndr_pull *ndr, struct ndr_pull_save *save)
}
-
-
/* create a ndr_push structure, ready for some marshalling */
-struct ndr_push *ndr_push_init(void)
+struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx)
{
struct ndr_push *ndr;
- TALLOC_CTX *mem_ctx = talloc_init("ndr_push_init");
- if (!mem_ctx) return NULL;
ndr = talloc(mem_ctx, sizeof(*ndr));
if (!ndr) {
- talloc_destroy(mem_ctx);
return NULL;
}
@@ -148,15 +149,30 @@ struct ndr_push *ndr_push_init(void)
ndr->alloc_size = NDR_BASE_MARSHALL_SIZE;
ndr->data = talloc(ndr->mem_ctx, ndr->alloc_size);
if (!ndr->data) {
- ndr_push_free(ndr);
return NULL;
}
ndr->offset = 0;
ndr->ptr_count = 0;
+ ndr->relative_list = NULL;
+ ndr->relative_list_end = NULL;
return ndr;
}
+
+/* create a ndr_push structure, ready for some marshalling */
+struct ndr_push *ndr_push_init(void)
+{
+ struct ndr_push *ndr;
+ TALLOC_CTX *mem_ctx = talloc_init("ndr_push_init");
+ if (!mem_ctx) return NULL;
+ ndr = ndr_push_init_ctx(mem_ctx);
+ if (!ndr) {
+ talloc_destroy(mem_ctx);
+ }
+ return ndr;
+}
+
/* free a ndr_push structure */
void ndr_push_free(struct ndr_push *ndr)
{
@@ -189,7 +205,8 @@ NTSTATUS ndr_push_expand(struct ndr_push *ndr, uint32 size)
}
ndr->data = talloc_realloc(ndr->mem_ctx, ndr->data, ndr->alloc_size);
if (!ndr->data) {
- return NT_STATUS_NO_MEMORY;
+ return ndr_push_error(ndr, NDR_ERR_ALLOC, "Failed to push_expand to %u",
+ ndr->alloc_size);
}
return NT_STATUS_OK;
@@ -358,6 +375,20 @@ void ndr_print_function_debug(void (*fn)(struct ndr_print *, const char *, int ,
talloc_destroy(ndr.mem_ctx);
}
+
+static NTSTATUS ndr_map_error(enum ndr_err_code err)
+{
+ switch (err) {
+ case NDR_ERR_BUFSIZE:
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ case NDR_ERR_ALLOC:
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* we should all error codes to different status codes */
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
/*
return and possibly log an NDR error
*/
@@ -373,8 +404,8 @@ NTSTATUS ndr_pull_error(struct ndr_pull *ndr, enum ndr_err_code err, const char
DEBUG(3,("ndr_pull_error(%u): %s\n", err, s));
free(s);
- /* we should map to different status codes */
- return NT_STATUS_INVALID_PARAMETER;
+
+ return ndr_map_error(err);
}
/*
@@ -392,8 +423,8 @@ NTSTATUS ndr_push_error(struct ndr_push *ndr, enum ndr_err_code err, const char
DEBUG(3,("ndr_push_error(%u): %s\n", err, s));
free(s);
- /* we should map to different status codes */
- return NT_STATUS_INVALID_PARAMETER;
+
+ return ndr_map_error(err);
}
@@ -494,6 +525,92 @@ NTSTATUS ndr_pull_subcontext_union_fn(struct ndr_pull *ndr,
/*
+ push a subcontext header
+*/
+static NTSTATUS ndr_push_subcontext_header(struct ndr_push *ndr,
+ size_t sub_size,
+ struct ndr_push *ndr2)
+{
+ switch (sub_size) {
+ case 0:
+ break;
+
+ case 2:
+ NDR_CHECK(ndr_push_uint16(ndr, ndr2->offset));
+ break;
+
+ case 4:
+ NDR_CHECK(ndr_push_uint32(ndr, ndr2->offset));
+ break;
+
+ default:
+ return ndr_push_error(ndr, NDR_ERR_SUBCONTEXT, "Bad subcontext size %d",
+ sub_size);
+ }
+ return NT_STATUS_OK;
+}
+
+/*
+ handle subcontext buffers, which in midl land are user-marshalled, but
+ we use magic in pidl to make them easier to cope with
+*/
+NTSTATUS ndr_push_subcontext_fn(struct ndr_push *ndr,
+ size_t sub_size,
+ void *base,
+ NTSTATUS (*fn)(struct ndr_push *, void *))
+{
+ struct ndr_push *ndr2;
+
+ ndr2 = ndr_push_init_ctx(ndr->mem_ctx);
+ if (!ndr2) return NT_STATUS_NO_MEMORY;
+
+ NDR_CHECK(fn(ndr2, base));
+ NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
+ NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
+ return NT_STATUS_OK;
+}
+
+/*
+ handle subcontext buffers for function that take a flags arg
+*/
+NTSTATUS ndr_push_subcontext_flags_fn(struct ndr_push *ndr,
+ size_t sub_size,
+ void *base,
+ NTSTATUS (*fn)(struct ndr_push *, int, void *))
+{
+ struct ndr_push *ndr2;
+
+ ndr2 = ndr_push_init_ctx(ndr->mem_ctx);
+ if (!ndr2) return NT_STATUS_NO_MEMORY;
+
+ NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, base));
+ NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
+ NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
+ return NT_STATUS_OK;
+}
+
+/*
+ handle subcontext buffers for function that take a union
+*/
+NTSTATUS ndr_push_subcontext_union_fn(struct ndr_push *ndr,
+ size_t sub_size,
+ uint32 level,
+ void *base,
+ NTSTATUS (*fn)(struct ndr_push *, int, uint32, void *))
+{
+ struct ndr_push *ndr2;
+
+ ndr2 = ndr_push_init_ctx(ndr->mem_ctx);
+ if (!ndr2) return NT_STATUS_NO_MEMORY;
+
+ NDR_CHECK(fn(ndr2, NDR_SCALARS|NDR_BUFFERS, level, base));
+ NDR_CHECK(ndr_push_subcontext_header(ndr, sub_size, ndr2));
+ NDR_CHECK(ndr_push_bytes(ndr, ndr2->data, ndr2->offset));
+ return NT_STATUS_OK;
+}
+
+
+/*
mark the start of a structure
*/
NTSTATUS ndr_pull_struct_start(struct ndr_pull *ndr)
@@ -520,7 +637,7 @@ void ndr_pull_struct_end(struct ndr_pull *ndr)
NTSTATUS ndr_push_struct_start(struct ndr_push *ndr)
{
struct ndr_ofs_list *ofs;
- NDR_ALLOC(ndr, ofs);
+ NDR_PUSH_ALLOC(ndr, ofs);
ofs->offset = ndr->offset;
ofs->next = ndr->ofs_list;
ndr->ofs_list = ofs;
@@ -579,12 +696,17 @@ NTSTATUS ndr_push_relative(struct ndr_push *ndr, int ndr_flags, const void *p,
NDR_CHECK(ndr_push_uint32(ndr, 0));
return NT_STATUS_OK;
}
- NDR_ALLOC(ndr, ofs);
+ NDR_PUSH_ALLOC(ndr, ofs);
NDR_CHECK(ndr_push_align(ndr, 4));
ofs->offset = ndr->offset;
NDR_CHECK(ndr_push_uint32(ndr, 0xFFFFFFFF));
- ofs->next = ndr->relative_list;
- ndr->relative_list = ofs;
+ ofs->next = NULL;
+ if (ndr->relative_list_end) {
+ ndr->relative_list_end->next = ofs;
+ } else {
+ ndr->relative_list = ofs;
+ }
+ ndr->relative_list_end = ofs;
}
if (ndr_flags & NDR_BUFFERS) {
struct ndr_push_save save;
@@ -596,6 +718,9 @@ NTSTATUS ndr_push_relative(struct ndr_push *ndr, int ndr_flags, const void *p,
return ndr_push_error(ndr, NDR_ERR_RELATIVE, "Empty relative stack");
}
ndr->relative_list = ndr->relative_list->next;
+ if (ndr->relative_list == NULL) {
+ ndr->relative_list_end = NULL;
+ }
NDR_CHECK(ndr_push_align(ndr, 8));
ndr_push_save(ndr, &save);
ndr->offset = ofs->offset;
diff --git a/source4/librpc/ndr/ndr_basic.c b/source4/librpc/ndr/ndr_basic.c
index 56c0ab231e..a3c4bc0aec 100644
--- a/source4/librpc/ndr/ndr_basic.c
+++ b/source4/librpc/ndr/ndr_basic.c
@@ -83,6 +83,14 @@ NTSTATUS ndr_pull_NTSTATUS(struct ndr_pull *ndr, NTSTATUS *status)
return NT_STATUS_OK;
}
+/*
+ push a NTSTATUS
+*/
+NTSTATUS ndr_push_NTSTATUS(struct ndr_push *ndr, NTSTATUS status)
+{
+ return ndr_push_uint32(ndr, NT_STATUS_V(status));
+}
+
void ndr_print_NTSTATUS(struct ndr_print *ndr, const char *name, NTSTATUS *r)
{
ndr->print(ndr, "%-25s: %s", name, nt_errstr(*r));
@@ -99,6 +107,14 @@ NTSTATUS ndr_pull_WERROR(struct ndr_pull *ndr, WERROR *status)
return NT_STATUS_OK;
}
+/*
+ push a WERROR
+*/
+NTSTATUS ndr_push_WERROR(struct ndr_push *ndr, WERROR status)
+{
+ return ndr_push_uint32(ndr, W_ERROR_V(status));
+}
+
void ndr_print_WERROR(struct ndr_print *ndr, const char *name, WERROR *r)
{
ndr->print(ndr, "%-25s: %s", name, win_errstr(*r));
@@ -340,7 +356,9 @@ NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
NDR_CHECK(ndr_pull_uint32(ndr, &ofs));
NDR_CHECK(ndr_pull_uint32(ndr, &len2));
if (len2 > len1) {
- return NT_STATUS_INVALID_PARAMETER;
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "Bad string lengths len1=%u ofs=%u len2=%u\n",
+ len1, ofs, len2);
}
if (len2 == 0) {
*s = talloc_strdup(ndr->mem_ctx, "");
@@ -395,7 +413,9 @@ NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s)
NDR_CHECK(ndr_pull_uint32(ndr, &ofs));
NDR_CHECK(ndr_pull_uint32(ndr, &len2));
if (len2 > len1) {
- return NT_STATUS_INVALID_PARAMETER;
+ return ndr_pull_error(ndr, NDR_ERR_STRING,
+ "Bad ascii string lengths len1=%u ofs=%u len2=%u\n",
+ len1, ofs, len2);
}
NDR_ALLOC_N(ndr, as, (len2+1));
NDR_CHECK(ndr_pull_bytes(ndr, as, len2));
diff --git a/source4/librpc/ndr/ndr_sec.c b/source4/librpc/ndr/ndr_sec.c
index 5a959b9b47..1a8d355149 100644
--- a/source4/librpc/ndr/ndr_sec.c
+++ b/source4/librpc/ndr/ndr_sec.c
@@ -88,3 +88,53 @@ void ndr_print_dom_sid2(struct ndr_print *ndr, const char *name, struct dom_sid2
ndr_print_dom_sid(ndr, name, sid);
}
+
+/*
+ return the wire size of a security_ace
+*/
+size_t ndr_size_security_ace(struct security_ace *ace)
+{
+ if (!ace) return 0;
+ return 8 + ndr_size_dom_sid(&ace->trustee);
+}
+
+
+/*
+ return the wire size of a security_acl
+*/
+size_t ndr_size_security_acl(struct security_acl *acl)
+{
+ size_t ret;
+ int i;
+ if (!acl) return 0;
+ ret = 8;
+ for (i=0;i<acl->num_aces;i++) {
+ ret += ndr_size_security_ace(&acl->aces[i]);
+ }
+ return ret;
+}
+
+/*
+ return the wire size of a dom_sid
+*/
+size_t ndr_size_dom_sid(struct dom_sid *sid)
+{
+ if (!sid) return 0;
+ return 8 + 4*sid->num_auths;
+}
+
+/*
+ return the wire size of a security descriptor
+*/
+size_t ndr_size_security_descriptor(struct security_descriptor *sd)
+{
+ size_t ret;
+ if (!sd) return 0;
+
+ ret = 20;
+ ret += ndr_size_dom_sid(sd->owner_sid);
+ ret += ndr_size_dom_sid(sd->group_sid);
+ ret += ndr_size_security_acl(sd->dacl);
+ ret += ndr_size_security_acl(sd->sacl);
+ return ret;
+}
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 7fa24bb171..cb03ff8970 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -731,6 +731,139 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
/*
+ this is a paranoid NDR validator. For every packet we push onto the wire
+ we pull it back again, then push it again. Then we compare the raw NDR data
+ for that to the NDR we initially generated. If they don't match then we know
+ we must have a bug in either the pull or push side of our code
+*/
+static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
+ DATA_BLOB blob,
+ size_t struct_size,
+ NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
+ NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
+{
+ void *st;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ NTSTATUS status;
+ DATA_BLOB blob2;
+
+ st = talloc(mem_ctx, struct_size);
+ if (!st) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pull = ndr_pull_init_blob(&blob, mem_ctx);
+ if (!pull) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ndr_pull(pull, NDR_IN, st);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ndr_pull_error(pull, NDR_ERR_VALIDATE,
+ "Error in input validation pull - %s",
+ nt_errstr(status));
+ }
+
+ push = ndr_push_init_ctx(mem_ctx);
+ if (!push) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ndr_push(push, NDR_IN, st);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ndr_push_error(push, NDR_ERR_VALIDATE,
+ "Error in input validation push - %s",
+ nt_errstr(status));
+ }
+
+ blob2 = ndr_push_blob(push);
+
+ if (!data_blob_equal(&blob, &blob2)) {
+ return ndr_push_error(push, NDR_ERR_VALIDATE,
+ "Error in input validation data - %s",
+ nt_errstr(status));
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
+ this is a paranoid NDR input validator. For every packet we pull
+ from the wire we push it back again then pull and push it
+ again. Then we compare the raw NDR data for that to the NDR we
+ initially generated. If they don't match then we know we must have a
+ bug in either the pull or push side of our code
+*/
+static NTSTATUS dcerpc_ndr_validate_out(TALLOC_CTX *mem_ctx,
+ void *struct_ptr,
+ size_t struct_size,
+ NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
+ NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
+{
+ void *st;
+ struct ndr_pull *pull;
+ struct ndr_push *push;
+ NTSTATUS status;
+ DATA_BLOB blob, blob2;
+
+ st = talloc(mem_ctx, struct_size);
+ if (!st) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ memcpy(st, struct_ptr, struct_size);
+
+ push = ndr_push_init_ctx(mem_ctx);
+ if (!push) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ndr_push(push, NDR_OUT, struct_ptr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ndr_push_error(push, NDR_ERR_VALIDATE,
+ "Error in output validation push - %s",
+ nt_errstr(status));
+ }
+
+ blob = ndr_push_blob(push);
+
+ pull = ndr_pull_init_blob(&blob, mem_ctx);
+ if (!pull) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ status = ndr_pull(pull, NDR_OUT, st);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ndr_pull_error(pull, NDR_ERR_VALIDATE,
+ "Error in output validation pull - %s",
+ nt_errstr(status));
+ }
+
+ push = ndr_push_init_ctx(mem_ctx);
+ if (!push) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ status = ndr_push(push, NDR_OUT, st);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ndr_push_error(push, NDR_ERR_VALIDATE,
+ "Error in output validation push2 - %s",
+ nt_errstr(status));
+ }
+
+ blob2 = ndr_push_blob(push);
+
+ if (!data_blob_equal(&blob, &blob2)) {
+ return ndr_push_error(push, NDR_ERR_VALIDATE,
+ "Error in output validation data - %s",
+ nt_errstr(status));
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*
a useful helper function for synchronous rpc requests
this can be used when you have ndr push/pull functions in the
@@ -739,9 +872,10 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
uint32 opnum,
TALLOC_CTX *mem_ctx,
- NTSTATUS (*ndr_push)(struct ndr_push *, void *),
- NTSTATUS (*ndr_pull)(struct ndr_pull *, void *),
- void *struct_ptr)
+ NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
+ NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
+ void *struct_ptr,
+ size_t struct_size)
{
struct ndr_push *push;
struct ndr_pull *pull;
@@ -756,7 +890,7 @@ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
}
/* push the structure into a blob */
- status = ndr_push(push, struct_ptr);
+ status = ndr_push(push, NDR_IN, struct_ptr);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
@@ -764,6 +898,14 @@ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
/* retrieve the blob */
request = ndr_push_blob(push);
+ if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
+ status = dcerpc_ndr_validate_in(mem_ctx, request, struct_size,
+ ndr_push, ndr_pull);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+ }
+
DEBUG(10,("rpc request data:\n"));
dump_data(10, request.data, request.length);
@@ -783,11 +925,19 @@ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
dump_data(10, pull->data, pull->data_size);
/* pull the structure from the blob */
- status = ndr_pull(pull, struct_ptr);
+ status = ndr_pull(pull, NDR_OUT, struct_ptr);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
+ if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
+ status = dcerpc_ndr_validate_out(mem_ctx, struct_ptr, struct_size,
+ ndr_push, ndr_pull);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
+ }
+ }
+
if (pull->offset != pull->data_size) {
DEBUG(0,("Warning! %d unread bytes\n", pull->data_size - pull->offset));
status = NT_STATUS_INFO_LENGTH_MISMATCH;
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index 3f9241e9a3..65566878e3 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -53,10 +53,14 @@ struct dcerpc_pipe {
#define DCERPC_PFC_FLAG_NOCALL 0x20
/* dcerpc pipe flags */
-#define DCERPC_DEBUG_PRINT_IN 1
+#define DCERPC_DEBUG_PRINT_IN 1
#define DCERPC_DEBUG_PRINT_OUT 2
#define DCERPC_DEBUG_PRINT_BOTH (DCERPC_DEBUG_PRINT_IN | DCERPC_DEBUG_PRINT_OUT)
+#define DCERPC_DEBUG_VALIDATE_IN 4
+#define DCERPC_DEBUG_VALIDATE_OUT 8
+#define DCERPC_DEBUG_VALIDATE_BOTH (DCERPC_DEBUG_VALIDATE_IN | DCERPC_DEBUG_VALIDATE_OUT)
+
/*
all dcerpc packets use this structure.
*/