diff options
Diffstat (limited to 'source4/librpc/ndr')
-rw-r--r-- | source4/librpc/ndr/ndr_compression.c | 111 |
1 files changed, 73 insertions, 38 deletions
diff --git a/source4/librpc/ndr/ndr_compression.c b/source4/librpc/ndr/ndr_compression.c index bcbe8e5650..ec29b1cd30 100644 --- a/source4/librpc/ndr/ndr_compression.c +++ b/source4/librpc/ndr/ndr_compression.c @@ -25,67 +25,102 @@ #ifdef HAVE_ZLIB #include <zlib.h> -static NTSTATUS ndr_pull_compression_zlib(struct ndr_pull *subndr, - struct ndr_pull *comndr, - ssize_t decompressed_len) +static NTSTATUS ndr_pull_compression_zlib_chunk(struct ndr_pull *ndrpull, + struct ndr_push *ndrpush, + struct z_stream_s *zs, int i) { - DATA_BLOB inbuf; - DATA_BLOB outbuf = data_blob_talloc(comndr, NULL, decompressed_len); - uint32_t outbuf_len = outbuf.length; - struct z_stream_s zs; + uint8_t *comp_chunk; + uint32_t comp_chunk_offset; + uint32_t comp_chunk_size; + uint8_t *plain_chunk; + uint32_t plain_chunk_offset; + uint32_t plain_chunk_size; + uint16_t unknown_marker; int ret; - ZERO_STRUCT(zs); + /* I don't know why, this is needed... --metze */ + if (i == 5) ndrpull->offset -=4; - if (subndr->data_size < 10) { - return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB compressed header (PULL) subcontext size %d", - subndr->data_size); + NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size)); + if (plain_chunk_size > 0x00008000) { + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad ZLIB plain chunk size %08X > 0x00008000 (PULL)", + plain_chunk_size); } - inbuf.data = subndr->data+10; - inbuf.length = subndr->data_size-10; + NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size)); - zs.avail_in = inbuf.length; - zs.next_in = inbuf.data; - zs.next_out = outbuf.data; - zs.avail_out = outbuf.length; + NDR_CHECK(ndr_pull_uint16(ndrpull, NDR_SCALARS, &unknown_marker)); - ret = inflateInit2(&zs, -15); - if (ret != Z_OK) { - return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB (PULL) inflateInit2 error %d", - ret); - } + DEBUG(10,("plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u) unknown_marker: %04X (%u)\n", + plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size, unknown_marker, unknown_marker)); + + comp_chunk_offset = ndrpull->offset; + NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size)); + comp_chunk = ndrpull->data + comp_chunk_offset; - while(1) { - ret = inflate(&zs, Z_SYNC_FLUSH); + plain_chunk_offset = ndrpush->offset; + NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size)); + plain_chunk = ndrpush->data + plain_chunk_offset; + + zs->avail_in = comp_chunk_size; + zs->next_in = comp_chunk; + zs->next_out = plain_chunk; + zs->avail_out = plain_chunk_size; + + while (True) { + ret = inflate(zs, Z_BLOCK); if (ret == Z_STREAM_END) { - - DEBUG(0,("inbuf.length: %d avail_in: %d, avail_out: %d\n", inbuf.length, zs.avail_in, zs.avail_out)); + DEBUG(0,("comp_chunk_size: %u avail_in: %d, plain_chunk_size: %u, avail_out: %d\n", + comp_chunk_size, zs->avail_in, plain_chunk_size, zs->avail_out)); break; } if (ret != Z_OK) { - return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB (PULL) inflate error %d", + return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad ZLIB (PULL) inflate error %d", ret); } } - inflateEnd(&zs); + if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) { + /* this is the last chunk */ + return NT_STATUS_OK; + } - /* TODO: check if the decompressed_len == outbuf_len */ - outbuf.length = outbuf_len - zs.avail_out; + return NT_STATUS_MORE_PROCESSING_REQUIRED; +} + +static NTSTATUS ndr_pull_compression_zlib(struct ndr_pull *subndr, + struct ndr_pull *comndr, + ssize_t decompressed_len) +{ + NTSTATUS status = NT_STATUS_MORE_PROCESSING_REQUIRED; + struct ndr_push *ndrpush; + DATA_BLOB uncompressed; + struct z_stream_s zs; + int ret; + int i = 0; + + ZERO_STRUCT(zs); + + ndrpush = ndr_push_init_ctx(subndr); + NT_STATUS_HAVE_NO_MEMORY(ndrpush); - if (outbuf.length < 16) { - return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB uncompressed header (PULL) uncompressed size %d", - outbuf.length); + ret = inflateInit2(&zs, -15); + if (ret != Z_OK) { + return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB (PULL) inflateInit2 error %d", + ret); + } + + while (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) { + status = ndr_pull_compression_zlib_chunk(subndr, ndrpush, &zs, i++); } + inflateEnd(&zs); + NT_STATUS_NOT_OK_RETURN(status); - outbuf.data += 16; - outbuf.length -= 16; + uncompressed = ndr_push_blob(ndrpush); - /* TODO: really decompress the data here */ *comndr = *subndr; - comndr->data = outbuf.data; - comndr->data_size = outbuf.length; + comndr->data = uncompressed.data; + comndr->data_size = uncompressed.length; comndr->offset = 0; return NT_STATUS_OK; |