diff options
Diffstat (limited to 'source4/librpc')
-rw-r--r-- | source4/librpc/idl/samr.idl | 10 | ||||
-rw-r--r-- | source4/librpc/ndr/libndr.h | 35 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr.c | 163 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr_basic.c | 24 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr_sec.c | 50 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.c | 160 | ||||
-rw-r--r-- | source4/librpc/rpc/dcerpc.h | 6 |
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. */ |