diff options
Diffstat (limited to 'source4/librpc')
-rw-r--r-- | source4/librpc/ndr/ndr_compression.c | 99 |
1 files changed, 98 insertions, 1 deletions
diff --git a/source4/librpc/ndr/ndr_compression.c b/source4/librpc/ndr/ndr_compression.c index 3b38c6b913..37f95bb1b6 100644 --- a/source4/librpc/ndr/ndr_compression.c +++ b/source4/librpc/ndr/ndr_compression.c @@ -150,7 +150,104 @@ static enum ndr_err_code ndr_push_compression_mszip_chunk(struct ndr_push *ndrpu z_stream *z, bool *last) { - return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, "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, |