From 800d3e0134b72135fa359fa5a239f1c68adf4ca1 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 23 Nov 2003 06:28:12 +0000 Subject: ooh, this is fun! I have recoded the core dcerpc packet structures (all the PDUs etc) in terms of IDL, which means we now use pidl to generate all the code for handling the most basic dcerpc packets. This is not normally possible as it isn't completely valid NDR, but pidl has a number of extensions that make it quite easy. This also means we get the server side dcerpc marshalling/unmarshalling code for free. (This used to be commit 92bcad02587c3c1b31b523ee9fa46658a6cef9ff) --- source4/librpc/ndr/libndr.h | 16 ++++++++++--- source4/librpc/ndr/ndr.c | 10 ++++++++ source4/librpc/ndr/ndr_basic.c | 54 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 5 deletions(-) (limited to 'source4/librpc/ndr') diff --git a/source4/librpc/ndr/libndr.h b/source4/librpc/ndr/libndr.h index 3c77646239..5c51113874 100644 --- a/source4/librpc/ndr/libndr.h +++ b/source4/librpc/ndr/libndr.h @@ -99,9 +99,16 @@ struct ndr_print { #define LIBNDR_FLAG_STR_SIZE4 (1<<4) #define LIBNDR_FLAG_STR_NOTERM (1<<5) #define LIBNDR_FLAG_STR_NULLTERM (1<<6) -#define LIBNDR_STRING_FLAGS (0x7C) +#define LIBNDR_FLAG_STR_SIZE2 (1<<7) +#define LIBNDR_STRING_FLAGS (0xFC) #define LIBNDR_FLAG_REF_ALLOC (1<<10) +#define LIBNDR_FLAG_REMAINING (1<<11) +#define LIBNDR_FLAG_ALIGN2 (1<<12) +#define LIBNDR_FLAG_ALIGN4 (1<<13) +#define LIBNDR_FLAG_ALIGN8 (1<<14) + +#define LIBNDR_ALIGN_FLAGS (LIBNDR_FLAG_ALIGN2|LIBNDR_FLAG_ALIGN4|LIBNDR_FLAG_ALIGN8) /* useful macro for debugging */ #define NDR_PRINT_DEBUG(type, p) ndr_print_debug((ndr_print_fn_t)ndr_print_ ##type, #p, p) @@ -146,6 +153,8 @@ enum ndr_err_code { } \ } while(0) +#define NDR_ALIGN(ndr, n) ndr_align_size(ndr->offset, n) + #define NDR_PULL_ALIGN(ndr, n) do { \ if (!(ndr->flags & LIBNDR_FLAG_NOALIGN)) { \ ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \ @@ -176,7 +185,7 @@ enum ndr_err_code { #define NDR_ALLOC_SIZE(ndr, s, size) do { \ (s) = talloc(ndr->mem_ctx, size); \ - if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, \ + if ((size) && !(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, \ "Alloc %u failed\n", \ size); \ } while (0) @@ -201,7 +210,7 @@ enum ndr_err_code { #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, \ + if ((size) && !(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, \ "push alloc %u failed\n",\ size); \ } while (0) @@ -225,6 +234,7 @@ typedef void (*ndr_print_union_fn_t)(struct ndr_print *, const char *, uint32, v /* now pull in the individual parsers */ #include "librpc/ndr/ndr_basic.h" #include "librpc/ndr/ndr_sec.h" +#include "librpc/gen_ndr/ndr_dcerpc.h" #include "librpc/gen_ndr/ndr_misc.h" #include "librpc/gen_ndr/ndr_echo.h" #include "librpc/gen_ndr/ndr_lsa.h" diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c index 44472147fd..bce4759d8a 100644 --- a/source4/librpc/ndr/ndr.c +++ b/source4/librpc/ndr/ndr.c @@ -31,6 +31,16 @@ #define NDR_BASE_MARSHALL_SIZE 1024 + +/* + work out the number of bytes needed to align on a n byte boundary +*/ +size_t ndr_align_size(uint32 offset, size_t n) +{ + if ((offset & (n-1)) == 0) return 0; + return n - (offset & (n-1)); +} + /* initialise a ndr parse structure from a data blob */ diff --git a/source4/librpc/ndr/ndr_basic.c b/source4/librpc/ndr/ndr_basic.c index 4d0be44a89..081d9ff87a 100644 --- a/source4/librpc/ndr/ndr_basic.c +++ b/source4/librpc/ndr/ndr_basic.c @@ -343,6 +343,7 @@ NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s) { char *as=NULL; uint32 len1, ofs, len2; + uint16 len3; int ret; if (!(ndr_flags & NDR_SCALARS)) { @@ -437,6 +438,14 @@ NTSTATUS ndr_pull_string(struct ndr_pull *ndr, int ndr_flags, const char **s) (*s) = as; break; + case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_SIZE2: + NDR_CHECK(ndr_pull_uint16(ndr, &len3)); + NDR_ALLOC_N(ndr, as, (len3+1)); + NDR_CHECK(ndr_pull_bytes(ndr, as, len3)); + as[len3] = 0; + (*s) = as; + break; + default: return ndr_pull_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", ndr->flags & LIBNDR_STRING_FLAGS); @@ -546,6 +555,19 @@ NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s) ndr->offset += c_len + 1; break; + case LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_SIZE2: + NDR_CHECK(ndr_push_uint16(ndr, c_len+1)); + NDR_PUSH_NEED_BYTES(ndr, c_len + 1); + ret = convert_string(CH_UNIX, CH_DOS, + s, s_len + 1, + ndr->data+ndr->offset, c_len + 1); + if (ret == -1) { + return ndr_push_error(ndr, NDR_ERR_CHARCNV, + "Bad character conversion"); + } + ndr->offset += c_len + 1; + break; + default: return ndr_push_error(ndr, NDR_ERR_STRING, "Bad string flags 0x%x\n", ndr->flags & LIBNDR_STRING_FLAGS); @@ -729,7 +751,19 @@ void ndr_print_DATA_BLOB(struct ndr_print *ndr, const char *name, DATA_BLOB r) */ NTSTATUS ndr_push_DATA_BLOB(struct ndr_push *ndr, DATA_BLOB blob) { - NDR_CHECK(ndr_push_uint32(ndr, blob.length)); + if (ndr->flags & LIBNDR_ALIGN_FLAGS) { + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + blob.length = NDR_ALIGN(ndr, 2); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + blob.length = NDR_ALIGN(ndr, 4); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + blob.length = NDR_ALIGN(ndr, 8); + } + NDR_PUSH_ALLOC_SIZE(ndr, blob.data, blob.length); + data_blob_clear(&blob); + } else if (!(ndr->flags & LIBNDR_FLAG_REMAINING)) { + NDR_CHECK(ndr_push_uint32(ndr, blob.length)); + } NDR_CHECK(ndr_push_bytes(ndr, blob.data, blob.length)); return NT_STATUS_OK; } @@ -740,7 +774,23 @@ NTSTATUS ndr_push_DATA_BLOB(struct ndr_push *ndr, DATA_BLOB blob) NTSTATUS ndr_pull_DATA_BLOB(struct ndr_pull *ndr, DATA_BLOB *blob) { uint32 length; - NDR_CHECK(ndr_pull_uint32(ndr, &length)); + + if (ndr->flags & LIBNDR_ALIGN_FLAGS) { + if (ndr->flags & LIBNDR_FLAG_ALIGN2) { + length = NDR_ALIGN(ndr, 2); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN4) { + length = NDR_ALIGN(ndr, 4); + } else if (ndr->flags & LIBNDR_FLAG_ALIGN8) { + length = NDR_ALIGN(ndr, 8); + } + if (ndr->data_size - ndr->offset < length) { + length = ndr->data_size - ndr->offset; + } + } else if (ndr->flags & LIBNDR_FLAG_REMAINING) { + length = ndr->data_size - ndr->offset; + } else { + NDR_CHECK(ndr_pull_uint32(ndr, &length)); + } NDR_PULL_NEED_BYTES(ndr, length); *blob = data_blob_talloc(ndr->mem_ctx, ndr->data+ndr->offset, length); ndr->offset += length; -- cgit