diff options
-rw-r--r-- | source4/librpc/idl/drsuapi.idl | 12 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr_compression.c | 164 | ||||
-rw-r--r-- | source4/librpc/ndr/ndr_drsuapi.c | 173 |
3 files changed, 328 insertions, 21 deletions
diff --git a/source4/librpc/idl/drsuapi.idl b/source4/librpc/idl/drsuapi.idl index b929bb0d58..cc76599be6 100644 --- a/source4/librpc/idl/drsuapi.idl +++ b/source4/librpc/idl/drsuapi.idl @@ -617,15 +617,15 @@ interface drsuapi WERROR drs_error; } drsuapi_DsGetNCChangesCtr6; - typedef struct { + typedef [public] struct { [subcontext(0xFFFFFC01)] drsuapi_DsGetNCChangesCtr1 ctr1; } drsuapi_DsGetNCChangesCtr1TS; - typedef struct { + typedef [public] struct { [subcontext(0xFFFFFC01)] drsuapi_DsGetNCChangesCtr6 ctr6; } drsuapi_DsGetNCChangesCtr6TS; - typedef struct { + typedef [nopush] struct { uint32 decompressed_length; uint32 compressed_length; [subcontext(4),subcontext_size(compressed_length), @@ -633,7 +633,7 @@ interface drsuapi drsuapi_DsGetNCChangesCtr1TS *ts; } drsuapi_DsGetNCChangesMSZIPCtr1; - typedef struct { + typedef [nopush] struct { uint32 decompressed_length; uint32 compressed_length; [subcontext(4),subcontext_size(compressed_length), @@ -641,7 +641,7 @@ interface drsuapi drsuapi_DsGetNCChangesCtr6TS *ts; } drsuapi_DsGetNCChangesMSZIPCtr6; - typedef struct { + typedef [nopush] struct { uint32 decompressed_length; uint32 compressed_length; [subcontext(4),subcontext_size(compressed_length), @@ -649,7 +649,7 @@ interface drsuapi drsuapi_DsGetNCChangesCtr1TS *ts; } drsuapi_DsGetNCChangesXPRESSCtr1; - typedef struct { + typedef [nopush] struct { uint32 decompressed_length; uint32 compressed_length; [subcontext(4),subcontext_size(compressed_length), diff --git a/source4/librpc/ndr/ndr_compression.c b/source4/librpc/ndr/ndr_compression.c index f6de0a1319..37f95bb1b6 100644 --- a/source4/librpc/ndr/ndr_compression.c +++ b/source4/librpc/ndr/ndr_compression.c @@ -145,10 +145,109 @@ static enum ndr_err_code ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpu return NDR_ERR_SUCCESS; } -static enum ndr_err_code ndr_push_compression_mszip(struct ndr_push *subndr, - struct ndr_push *comndr) +static enum ndr_err_code ndr_push_compression_mszip_chunk(struct ndr_push *ndrpush, + struct ndr_pull *ndrpull, + z_stream *z, + bool *last) { - return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Sorry MSZIP compression is not supported yet (PUSH)"); + DATA_BLOB comp_chunk; + uint32_t comp_chunk_size; + uint32_t comp_chunk_size_offset; + DATA_BLOB plain_chunk; + uint32_t plain_chunk_size; + uint32_t plain_chunk_offset; + uint32_t max_plain_size = 0x00008000; + uint32_t max_comp_size = 0x00008000 + 2 + 12 /*TODO: what value do we really need here?*/; + uint32_t tmp_offset; + int z_ret; + + plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset); + plain_chunk_offset = ndrpull->offset; + NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size)); + + plain_chunk.data = ndrpull->data + plain_chunk_offset; + plain_chunk.length = plain_chunk_size; + + if (plain_chunk_size < max_plain_size) { + *last = true; + } + + NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size)); + comp_chunk_size_offset = ndrpush->offset; + NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE)); + + NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size)); + + comp_chunk.data = ndrpush->data + ndrpush->offset; + comp_chunk.length = max_comp_size; + + /* CK = Chris Kirmse, official Microsoft purloiner */ + comp_chunk.data[0] = 'C'; + comp_chunk.data[1] = 'K'; + + z->next_in = plain_chunk.data; + z->avail_in = plain_chunk.length; + z->total_in = 0; + + z->next_out = comp_chunk.data + 2; + z->avail_out = comp_chunk.length - 2; + z->total_out = 0; + + if (!z->opaque) { + /* the first time we need to intialize completely */ + z->zalloc = ndr_zlib_alloc; + z->zfree = ndr_zlib_free; + z->opaque = ndrpull; + + /* TODO: find how to trigger the same parameters windows uses */ + z_ret = deflateInit2(z, + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + -15, + 9, + Z_DEFAULT_STRATEGY); + if (z_ret != Z_OK) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "Bad deflateInit2 error %s(%d) (PUSH)", + zError(z_ret), z_ret); + + } + } else { + /* TODO: keep the window */ + z_ret = deflateReset(z); + if (z_ret != Z_OK) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "Bad delateReset2 error %s(%d) (PUSH)", + zError(z_ret), z_ret); + } + } + + /* call deflate untill we get Z_STREAM_END or an error */ + while (true) { + z_ret = deflate(z, Z_FINISH); + if (z_ret != Z_OK) break; + } + if (z_ret != Z_STREAM_END) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "Bad delate(Z_BLOCK) error %s(%d) (PUSH)", + zError(z_ret), z_ret); + } + + if (z->avail_in) { + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, + "MSZIP not all avail_in[%u] bytes consumed (PUSH)", + z->avail_in); + } + + comp_chunk_size = 2 + z->total_out; + + tmp_offset = ndrpush->offset; + ndrpush->offset = comp_chunk_size_offset; + NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk_size)); + ndrpush->offset = tmp_offset; + + ndrpush->offset += comp_chunk_size; + return NDR_ERR_SUCCESS; } static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull, @@ -194,10 +293,11 @@ static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrp return NDR_ERR_SUCCESS; } -static enum ndr_err_code ndr_push_compression_xpress(struct ndr_push *subndr, - struct ndr_push *comndr) +static enum ndr_err_code ndr_push_compression_xpress_chunk(struct ndr_push *ndrpush, + struct ndr_pull *ndrpull, + bool *last) { - return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "XPRESS compression is not supported yet (PUSH)"); + return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, "XPRESS compression is not supported yet (PUSH)"); } /* @@ -273,17 +373,27 @@ enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr, push a compressed subcontext */ enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr, - struct ndr_push **_comndr, + struct ndr_push **_uncomndr, enum ndr_compression_alg compression_alg, ssize_t decompressed_len) { - struct ndr_push *comndr; + struct ndr_push *uncomndr; - comndr = ndr_push_init_ctx(subndr, subndr->iconv_convenience); - NDR_ERR_HAVE_NO_MEMORY(comndr); - comndr->flags = subndr->flags; + switch (compression_alg) { + case NDR_COMPRESSION_MSZIP: + case NDR_COMPRESSION_XPRESS: + break; + default: + return ndr_push_error(subndr, NDR_ERR_COMPRESSION, + "Bad compression algorithm %d (PUSH)", + compression_alg); + } - *_comndr = comndr; + uncomndr = ndr_push_init_ctx(subndr, subndr->iconv_convenience); + NDR_ERR_HAVE_NO_MEMORY(uncomndr); + uncomndr->flags = subndr->flags; + + *_uncomndr = uncomndr; return NDR_ERR_SUCCESS; } @@ -291,18 +401,42 @@ enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr, push a compressed subcontext */ enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr, - struct ndr_push *comndr, + struct ndr_push *uncomndr, enum ndr_compression_alg compression_alg, ssize_t decompressed_len) { + struct ndr_pull *ndrpull; + bool last = false; + z_stream z; + + ndrpull = talloc_zero(uncomndr, struct ndr_pull); + NDR_ERR_HAVE_NO_MEMORY(ndrpull); + ndrpull->flags = uncomndr->flags; + ndrpull->data = uncomndr->data; + ndrpull->data_size = uncomndr->offset; + ndrpull->offset = 0; + + ndrpull->iconv_convenience = talloc_reference(ndrpull, subndr->iconv_convenience); + switch (compression_alg) { case NDR_COMPRESSION_MSZIP: - return ndr_push_compression_mszip(subndr, comndr); + ZERO_STRUCT(z); + while (!last) { + NDR_CHECK(ndr_push_compression_mszip_chunk(subndr, ndrpull, &z, &last)); + } + break; + case NDR_COMPRESSION_XPRESS: - return ndr_push_compression_xpress(subndr, comndr); + while (!last) { + NDR_CHECK(ndr_push_compression_xpress_chunk(subndr, ndrpull, &last)); + } + break; + default: return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)", compression_alg); } + + talloc_free(uncomndr); return NDR_ERR_SUCCESS; } diff --git a/source4/librpc/ndr/ndr_drsuapi.c b/source4/librpc/ndr/ndr_drsuapi.c index 1b6be9ed8e..e77ab54071 100644 --- a/source4/librpc/ndr/ndr_drsuapi.c +++ b/source4/librpc/ndr/ndr_drsuapi.c @@ -24,6 +24,7 @@ #include "librpc/gen_ndr/ndr_drsuapi.h" #include "librpc/gen_ndr/ndr_misc.h" #include "lib/util/asn1.h" +#include "librpc/ndr/ndr_compression.h" void ndr_print_drsuapi_DsReplicaObjectListItem(struct ndr_print *ndr, const char *name, const struct drsuapi_DsReplicaObjectListItem *r) @@ -176,3 +177,175 @@ size_t ndr_size_drsuapi_DsReplicaOID_oid(const char *oid, int flags) data_blob_free(&_blob); return ret; } + +enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesMSZIPCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesMSZIPCtr1 *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t decompressed_length = 0; + uint32_t compressed_length = 0; + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed, NDR_COMPRESSION_MSZIP, -1)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + decompressed_length = _ndr_ts_compressed->offset; + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed, NDR_COMPRESSION_MSZIP, -1)); + } + compressed_length = _ndr_ts->offset; + talloc_free(_ndr_ts); + } + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length)); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed, NDR_COMPRESSION_MSZIP, -1)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed, NDR_COMPRESSION_MSZIP, -1)); + } + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1)); + } + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesMSZIPCtr6(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesMSZIPCtr6 *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t decompressed_length = 0; + uint32_t compressed_length = 0; + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed, NDR_COMPRESSION_MSZIP, -1)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + decompressed_length = _ndr_ts_compressed->offset; + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed, NDR_COMPRESSION_MSZIP, -1)); + } + compressed_length = _ndr_ts->offset; + talloc_free(_ndr_ts); + } + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length)); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed, NDR_COMPRESSION_MSZIP, -1)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed, NDR_COMPRESSION_MSZIP, -1)); + } + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1)); + } + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesXPRESSCtr1(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesXPRESSCtr1 *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t decompressed_length = 0; + uint32_t compressed_length = 0; + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed, NDR_COMPRESSION_XPRESS, -1)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + decompressed_length = _ndr_ts_compressed->offset; + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed, NDR_COMPRESSION_XPRESS, -1)); + } + compressed_length = _ndr_ts->offset; + talloc_free(_ndr_ts); + } + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length)); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed, NDR_COMPRESSION_XPRESS, -1)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr1TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed, NDR_COMPRESSION_XPRESS, -1)); + } + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1)); + } + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code ndr_push_drsuapi_DsGetNCChangesXPRESSCtr6(struct ndr_push *ndr, int ndr_flags, const struct drsuapi_DsGetNCChangesXPRESSCtr6 *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t decompressed_length = 0; + uint32_t compressed_length = 0; + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed, NDR_COMPRESSION_XPRESS, -1)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + decompressed_length = _ndr_ts_compressed->offset; + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed, NDR_COMPRESSION_XPRESS, -1)); + } + compressed_length = _ndr_ts->offset; + talloc_free(_ndr_ts); + } + } + NDR_CHECK(ndr_push_align(ndr, 4)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, decompressed_length)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, compressed_length)); + NDR_CHECK(ndr_push_unique_ptr(ndr, r->ts)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->ts) { + { + struct ndr_push *_ndr_ts; + NDR_CHECK(ndr_push_subcontext_start(ndr, &_ndr_ts, 4, -1)); + { + struct ndr_push *_ndr_ts_compressed; + NDR_CHECK(ndr_push_compression_start(_ndr_ts, &_ndr_ts_compressed, NDR_COMPRESSION_XPRESS, -1)); + NDR_CHECK(ndr_push_drsuapi_DsGetNCChangesCtr6TS(_ndr_ts_compressed, NDR_SCALARS|NDR_BUFFERS, r->ts)); + NDR_CHECK(ndr_push_compression_end(_ndr_ts, _ndr_ts_compressed, NDR_COMPRESSION_XPRESS, -1)); + } + NDR_CHECK(ndr_push_subcontext_end(ndr, _ndr_ts, 4, -1)); + } + } + } + return NDR_ERR_SUCCESS; +} |