LCOV - code coverage report
Current view: top level - librpc/ndr - ndr_compression.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 211 510 41.4 %
Date: 2024-02-28 12:06:22 Functions: 13 19 68.4 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    libndr compression support
       5             : 
       6             :    Copyright (C) Stefan Metzmacher 2005
       7             :    Copyright (C) Matthieu Suiche 2008
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "../lib/compression/lzxpress.h"
      25             : #include "../lib/compression/lzxpress_huffman.h"
      26             : #include "librpc/ndr/libndr.h"
      27             : #include "../librpc/ndr/ndr_compression.h"
      28             : #include <zlib.h>
      29             : 
      30             : struct ndr_compression_state {
      31             :         enum ndr_compression_alg type;
      32             :         union {
      33             :                 struct {
      34             :                         struct z_stream_s *z;
      35             :                         uint8_t *dict;
      36             :                         size_t dict_size;
      37             :                 } mszip;
      38             :                 struct {
      39             :                         struct lzxhuff_compressor_mem *mem;
      40             :                 } lzxpress_huffman;
      41             :         } alg;
      42             : };
      43             : 
      44           2 : static voidpf ndr_zlib_alloc(voidpf opaque, uInt items, uInt size)
      45             : {
      46           2 :         return talloc_zero_size(opaque, items * size);
      47             : }
      48             : 
      49           0 : static void  ndr_zlib_free(voidpf opaque, voidpf address)
      50             : {
      51           0 :         talloc_free(address);
      52           0 : }
      53             : 
      54           2 : static enum ndr_err_code ndr_pull_compression_mszip_cab_chunk(struct ndr_pull *ndrpull,
      55             :                                                               struct ndr_push *ndrpush,
      56             :                                                               struct ndr_compression_state *state,
      57             :                                                               ssize_t decompressed_len,
      58             :                                                               ssize_t compressed_len)
      59             : {
      60           2 :         DATA_BLOB comp_chunk;
      61           2 :         uint32_t comp_chunk_offset;
      62           2 :         uint32_t comp_chunk_size;
      63           2 :         DATA_BLOB plain_chunk;
      64           2 :         uint32_t plain_chunk_offset;
      65           2 :         uint32_t plain_chunk_size;
      66           2 :         z_stream *z = state->alg.mszip.z;
      67           2 :         int z_ret;
      68             : 
      69           2 :         plain_chunk_size = decompressed_len;
      70             : 
      71           2 :         if (plain_chunk_size > 0x00008000) {
      72           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
      73             :                                       "Bad MSZIP CAB plain chunk size %08"PRIX32" > 0x00008000 (PULL)",
      74             :                                       plain_chunk_size);
      75             :         }
      76             : 
      77             : 
      78           2 :         comp_chunk_size = compressed_len;
      79             : 
      80           2 :         DEBUG(9,("MSZIP CAB plain_chunk_size: %08"PRIX32" (%"PRIu32") comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
      81             :                  plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
      82             : 
      83           2 :         comp_chunk_offset = ndrpull->offset;
      84           2 :         NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
      85           2 :         comp_chunk.length = comp_chunk_size;
      86           2 :         comp_chunk.data = ndrpull->data + comp_chunk_offset;
      87             : 
      88           2 :         plain_chunk_offset = ndrpush->offset;
      89           2 :         NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
      90           2 :         plain_chunk.length = plain_chunk_size;
      91           2 :         plain_chunk.data = ndrpush->data + plain_chunk_offset;
      92             : 
      93           2 :         if (comp_chunk.length < 2) {
      94           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
      95             :                                       "Bad MSZIP CAB comp chunk size %zu < 2 (PULL)",
      96             :                                       comp_chunk.length);
      97             :         }
      98             :         /* CK = Chris Kirmse, official Microsoft purloiner */
      99           2 :         if (comp_chunk.data[0] != 'C' ||
     100           2 :             comp_chunk.data[1] != 'K') {
     101           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     102             :                                       "Bad MSZIP CAB invalid prefix [%c%c] != [CK]",
     103             :                                       comp_chunk.data[0], comp_chunk.data[1]);
     104             :         }
     105             : 
     106             :         /*
     107             :          * This is a MSZIP block. It is actually using the deflate
     108             :          * algorithm which can be decompressed by zlib. zlib will try
     109             :          * to decompress as much as it can in each run. If we provide
     110             :          * all the input and enough room for the uncompressed output,
     111             :          * one call is enough. It will loop over all the sub-blocks
     112             :          * that make up a deflate block.
     113             :          *
     114             :          * See corresponding push function for more info.
     115             :          */
     116             : 
     117           2 :         z->next_in = comp_chunk.data + 2;
     118           2 :         z->avail_in = comp_chunk.length - 2;
     119           2 :         z->next_out = plain_chunk.data;
     120           2 :         z->avail_out = plain_chunk.length;
     121             : 
     122             :         /*
     123             :          * Each MSZIP CDATA contains a complete deflate stream
     124             :          * i.e. the stream starts and ends in the CFDATA but the
     125             :          * _dictionary_ is shared between all CFDATA of a CFFOLDER.
     126             :          *
     127             :          * When decompressing, the initial dictionary of the first
     128             :          * CDATA is empty. All other CFDATA use the previous CFDATA
     129             :          * uncompressed output as dictionary.
     130             :          */
     131             : 
     132           2 :         if (state->alg.mszip.dict_size) {
     133           0 :                 z_ret = inflateSetDictionary(z, state->alg.mszip.dict, state->alg.mszip.dict_size);
     134           0 :                 if (z_ret != Z_OK) {
     135           0 :                         return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     136             :                                               "zlib inflateSetDictionary error %s (%d) %s (PULL)",
     137             :                                               zError(z_ret), z_ret, z->msg);
     138             :                 }
     139             :         }
     140             : 
     141           2 :         z_ret = inflate(z, Z_FINISH);
     142           2 :         if (z_ret == Z_OK) {
     143             :                 /*
     144             :                  * Z_OK here means there was no error but the stream
     145             :                  * hasn't been fully decompressed because there was
     146             :                  * not enough room for the output, which should not
     147             :                  * happen
     148             :                  */
     149           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     150             :                                       "zlib inflate error not enough space for output (PULL)");
     151             :         }
     152           2 :         if (z_ret != Z_STREAM_END) {
     153           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     154             :                                       "zlib inflate error %s (%d) %s (PULL)", zError(z_ret), z_ret, z->msg);
     155             :         }
     156             : 
     157           2 :         if (z->total_out < plain_chunk.length) {
     158           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     159             :                                       "zlib uncompressed output is smaller than expected (%lu < %zu) (PULL)",
     160             :                                       z->total_out, plain_chunk.length);
     161             :         }
     162             : 
     163             :         /*
     164             :          * Keep a copy of the output to set as dictionary for the
     165             :          * next decompression call.
     166             :          *
     167             :          * The input pointer seems to be still valid between calls, so
     168             :          * we can just store that instead of copying the memory over
     169             :          * the dict temp buffer.
     170             :          */
     171           2 :         state->alg.mszip.dict = plain_chunk.data;
     172           2 :         state->alg.mszip.dict_size = plain_chunk.length;
     173             : 
     174           2 :         z_ret = inflateReset(z);
     175           2 :         if (z_ret != Z_OK) {
     176           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     177             :                                       "zlib inflateReset error %s (%d) %s (PULL)",
     178             :                                       zError(z_ret), z_ret, z->msg);
     179             :         }
     180             : 
     181           0 :         return NDR_ERR_SUCCESS;
     182             : }
     183             : 
     184           0 : static enum ndr_err_code ndr_push_compression_mszip_cab_chunk(struct ndr_push *ndrpush,
     185             :                                                               struct ndr_pull *ndrpull,
     186             :                                                               struct ndr_compression_state *state)
     187             : {
     188           0 :         DATA_BLOB comp_chunk;
     189           0 :         uint32_t comp_chunk_size;
     190           0 :         DATA_BLOB plain_chunk;
     191           0 :         uint32_t plain_chunk_size;
     192           0 :         uint32_t plain_chunk_offset;
     193           0 :         uint32_t max_plain_size = 0x00008000;
     194             :         /*
     195             :          * The maximum compressed size of each MSZIP block is 32k + 12 bytes
     196             :          * header size.
     197             :          */
     198           0 :         uint32_t max_comp_size = 0x00008000 + 12;
     199           0 :         int z_ret;
     200           0 :         z_stream *z;
     201             : 
     202           0 :         if (ndrpull->data_size <= ndrpull->offset) {
     203           0 :                 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
     204             :                                       "strange NDR pull size and offset (integer overflow?)");
     205             : 
     206             :         }
     207             : 
     208           0 :         plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
     209           0 :         plain_chunk_offset = ndrpull->offset;
     210           0 :         NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
     211             : 
     212           0 :         plain_chunk.data = ndrpull->data + plain_chunk_offset;
     213           0 :         plain_chunk.length = plain_chunk_size;
     214             : 
     215           0 :         NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
     216             : 
     217           0 :         comp_chunk.data = ndrpush->data + ndrpush->offset;
     218           0 :         comp_chunk.length = max_comp_size;
     219             : 
     220             :         /* CK = Chris Kirmse, official Microsoft purloiner */
     221           0 :         comp_chunk.data[0] = 'C';
     222           0 :         comp_chunk.data[1] = 'K';
     223             : 
     224           0 :         z = state->alg.mszip.z;
     225           0 :         z->next_in   = plain_chunk.data;
     226           0 :         z->avail_in  = plain_chunk.length;
     227           0 :         z->total_in  = 0;
     228             : 
     229           0 :         z->next_out  = comp_chunk.data + 2;
     230           0 :         z->avail_out = comp_chunk.length;
     231           0 :         z->total_out = 0;
     232             : 
     233             :         /*
     234             :          * See pull function for explanations of the MSZIP format.
     235             :          *
     236             :          * The CFDATA block contains a full deflate stream. Each stream
     237             :          * uses the uncompressed input of the previous CFDATA in the
     238             :          * same CFFOLDER as a dictionary for the compression.
     239             :          */
     240             : 
     241           0 :         if (state->alg.mszip.dict_size) {
     242           0 :                 z_ret = deflateSetDictionary(z, state->alg.mszip.dict, state->alg.mszip.dict_size);
     243           0 :                 if (z_ret != Z_OK) {
     244           0 :                         return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     245             :                                               "zlib deflateSetDictionary error %s (%d) %s (PUSH)",
     246             :                                               zError(z_ret), z_ret, z->msg);
     247             :                 }
     248             :         }
     249             : 
     250             :         /*
     251             :          * Z_FINISH should make deflate process all of the input in
     252             :          * one call. If the stream is not finished there was an error
     253             :          * e.g. not enough room to store the compressed output.
     254             :          */
     255           0 :         z_ret = deflate(z, Z_FINISH);
     256           0 :         if (z_ret != Z_STREAM_END) {
     257           0 :                 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
     258             :                                       "zlib deflate error %s (%d) %s (PUSH)",
     259             :                                       zError(z_ret), z_ret, z->msg);
     260             :         }
     261             : 
     262           0 :         if (z->avail_in) {
     263           0 :                 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
     264             :                                       "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
     265             :                                       z->avail_in);
     266             :         }
     267             : 
     268           0 :         comp_chunk_size = 2 + z->total_out;
     269           0 :         if (comp_chunk_size < z->total_out) {
     270           0 :                 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
     271             :                                       "strange NDR push compressed size (integer overflow?)");
     272             :         }
     273             : 
     274           0 :         z_ret = deflateReset(z);
     275           0 :         if (z_ret != Z_OK) {
     276           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     277             :                                       "zlib deflateReset error %s (%d) %s (PUSH)",
     278             :                                       zError(z_ret), z_ret, z->msg);
     279             :         }
     280             : 
     281           0 :         if (plain_chunk.length > talloc_array_length(state->alg.mszip.dict)) {
     282           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     283             :                                       "zlib dict buffer is too big (PUSH)");
     284             :         }
     285             : 
     286             :         /*
     287             :          * Keep a copy of the input to set as dictionary for the next
     288             :          * compression call.
     289             :          *
     290             :          * Ideally we would just store the input pointer and length
     291             :          * without copying but the memory gets invalidated between the
     292             :          * calls, so we just copy to a dedicated buffer we know is
     293             :          * still going to be valid for the lifetime of the
     294             :          * compressions state object.
     295             :          */
     296           0 :         memcpy(state->alg.mszip.dict, plain_chunk.data, plain_chunk.length);
     297           0 :         state->alg.mszip.dict_size = plain_chunk.length;
     298             : 
     299           0 :         DEBUG(9,("MSZIP comp plain_chunk_size: %08zX (%zu) comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
     300             :                  plain_chunk.length,
     301             :                  plain_chunk.length,
     302             :                  comp_chunk_size, comp_chunk_size));
     303             : 
     304           0 :         ndrpush->offset += comp_chunk_size;
     305           0 :         return NDR_ERR_SUCCESS;
     306             : }
     307             : 
     308             : 
     309           0 : static enum ndr_err_code ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull,
     310             :                                                  struct ndr_push *ndrpush,
     311             :                                                  z_stream *z,
     312             :                                                  bool *last)
     313             : {
     314           0 :         DATA_BLOB comp_chunk;
     315           0 :         uint32_t comp_chunk_offset;
     316           0 :         uint32_t comp_chunk_size;
     317           0 :         DATA_BLOB plain_chunk;
     318           0 :         uint32_t plain_chunk_offset;
     319           0 :         uint32_t plain_chunk_size;
     320           0 :         int z_ret;
     321             : 
     322           0 :         NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
     323           0 :         if (plain_chunk_size > 0x00008000) {
     324           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad MSZIP plain chunk size %08"PRIX32" > 0x00008000 (PULL)",
     325             :                                       plain_chunk_size);
     326             :         }
     327             : 
     328           0 :         NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
     329             : 
     330           0 :         DEBUG(9,("MSZIP plain_chunk_size: %08"PRIX32" (%"PRIu32") comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
     331             :                  plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
     332             : 
     333           0 :         comp_chunk_offset = ndrpull->offset;
     334           0 :         NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
     335           0 :         comp_chunk.length = comp_chunk_size;
     336           0 :         comp_chunk.data = ndrpull->data + comp_chunk_offset;
     337             : 
     338           0 :         plain_chunk_offset = ndrpush->offset;
     339           0 :         NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
     340           0 :         plain_chunk.length = plain_chunk_size;
     341           0 :         plain_chunk.data = ndrpush->data + plain_chunk_offset;
     342             : 
     343           0 :         if (comp_chunk.length < 2) {
     344           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     345             :                                       "Bad MSZIP comp chunk size %zu < 2 (PULL)",
     346             :                                       comp_chunk.length);
     347             :         }
     348             :         /* CK = Chris Kirmse, official Microsoft purloiner */
     349           0 :         if (comp_chunk.data[0] != 'C' ||
     350           0 :             comp_chunk.data[1] != 'K') {
     351           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     352             :                                       "Bad MSZIP invalid prefix [%c%c] != [CK]",
     353             :                                       comp_chunk.data[0], comp_chunk.data[1]);
     354             :         }
     355             : 
     356           0 :         z->next_in   = comp_chunk.data + 2;
     357           0 :         z->avail_in  = comp_chunk.length -2;
     358           0 :         z->total_in  = 0;
     359             : 
     360           0 :         z->next_out  = plain_chunk.data;
     361           0 :         z->avail_out = plain_chunk.length;
     362           0 :         z->total_out = 0;
     363             : 
     364           0 :         if (!z->opaque) {
     365             :                 /* the first time we need to initialize completely */
     366           0 :                 z->zalloc    = ndr_zlib_alloc;
     367           0 :                 z->zfree     = ndr_zlib_free;
     368           0 :                 z->opaque    = ndrpull;
     369             : 
     370           0 :                 z_ret = inflateInit2(z, -MAX_WBITS);
     371           0 :                 if (z_ret != Z_OK) {
     372           0 :                         return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     373             :                                               "Bad inflateInit2 error %s(%d) (PULL)",
     374             :                                               zError(z_ret), z_ret);
     375             : 
     376             :                 }
     377             :         }
     378             : 
     379             :         /* call inflate until we get Z_STREAM_END or an error */
     380           0 :         while (true) {
     381           0 :                 z_ret = inflate(z, Z_BLOCK);
     382           0 :                 if (z_ret != Z_OK) break;
     383             :         }
     384             : 
     385           0 :         if (z_ret != Z_STREAM_END) {
     386           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     387             :                                       "Bad inflate(Z_BLOCK) error %s(%d) (PULL)",
     388             :                                       zError(z_ret), z_ret);
     389             :         }
     390             : 
     391           0 :         if (z->avail_in) {
     392           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     393             :                                       "MSZIP not all avail_in[%u] bytes consumed (PULL)",
     394             :                                       z->avail_in);
     395             :         }
     396             : 
     397           0 :         if (z->avail_out) {
     398           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     399             :                                       "MSZIP not all avail_out[%u] bytes consumed (PULL)",
     400             :                                       z->avail_out);
     401             :         }
     402             : 
     403           0 :         if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
     404             :                 /* this is the last chunk */
     405           0 :                 *last = true;
     406             :         }
     407             : 
     408           0 :         z_ret = inflateReset(z);
     409           0 :         if (z_ret != Z_OK) {
     410           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     411             :                                       "Bad inflateReset error %s(%d) (PULL)",
     412             :                                       zError(z_ret), z_ret);
     413             :         }
     414             : 
     415           0 :         z_ret = inflateSetDictionary(z, plain_chunk.data, plain_chunk.length);
     416           0 :         if (z_ret != Z_OK) {
     417           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     418             :                                       "Bad inflateSetDictionary error %s(%d) (PULL)",
     419             :                                       zError(z_ret), z_ret);
     420             :         }
     421             : 
     422           0 :         return NDR_ERR_SUCCESS;
     423             : }
     424             : 
     425           0 : static enum ndr_err_code ndr_push_compression_mszip_chunk(struct ndr_push *ndrpush,
     426             :                                                           struct ndr_pull *ndrpull,
     427             :                                                           z_stream *z,
     428             :                                                           bool *last)
     429             : {
     430           0 :         DATA_BLOB comp_chunk;
     431           0 :         uint32_t comp_chunk_size;
     432           0 :         uint32_t comp_chunk_size_offset;
     433           0 :         DATA_BLOB plain_chunk;
     434           0 :         uint32_t plain_chunk_size;
     435           0 :         uint32_t plain_chunk_offset;
     436           0 :         uint32_t max_plain_size = 0x00008000;
     437             :         /*
     438             :          * The maximum compressed size of each MSZIP block is 32k + 12 bytes
     439             :          * header size.
     440             :          */
     441           0 :         uint32_t max_comp_size = 0x00008000 + 12;
     442           0 :         uint32_t tmp_offset;
     443           0 :         int z_ret;
     444             : 
     445           0 :         plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
     446           0 :         plain_chunk_offset = ndrpull->offset;
     447           0 :         NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
     448             : 
     449           0 :         plain_chunk.data = ndrpull->data + plain_chunk_offset;
     450           0 :         plain_chunk.length = plain_chunk_size;
     451             : 
     452           0 :         if (plain_chunk_size < max_plain_size) {
     453           0 :                 *last = true;
     454             :         }
     455             : 
     456           0 :         NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size));
     457           0 :         comp_chunk_size_offset = ndrpush->offset;
     458           0 :         NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE));
     459             : 
     460           0 :         NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
     461             : 
     462           0 :         comp_chunk.data = ndrpush->data + ndrpush->offset;
     463           0 :         comp_chunk.length = max_comp_size;
     464             : 
     465             :         /* CK = Chris Kirmse, official Microsoft purloiner */
     466           0 :         comp_chunk.data[0] = 'C';
     467           0 :         comp_chunk.data[1] = 'K';
     468             : 
     469           0 :         z->next_in   = plain_chunk.data;
     470           0 :         z->avail_in  = plain_chunk.length;
     471           0 :         z->total_in  = 0;
     472             : 
     473           0 :         z->next_out  = comp_chunk.data + 2;
     474           0 :         z->avail_out = comp_chunk.length;
     475           0 :         z->total_out = 0;
     476             : 
     477           0 :         if (!z->opaque) {
     478             :                 /* the first time we need to initialize completely */
     479           0 :                 z->zalloc    = ndr_zlib_alloc;
     480           0 :                 z->zfree     = ndr_zlib_free;
     481           0 :                 z->opaque    = ndrpull;
     482             : 
     483             :                 /* TODO: find how to trigger the same parameters windows uses */
     484           0 :                 z_ret = deflateInit2(z,
     485             :                                      Z_DEFAULT_COMPRESSION,
     486             :                                      Z_DEFLATED,
     487             :                                      -MAX_WBITS,
     488             :                                      8, /* memLevel */
     489             :                                      Z_DEFAULT_STRATEGY);
     490           0 :                 if (z_ret != Z_OK) {
     491           0 :                         return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
     492             :                                               "Bad deflateInit2 error %s(%d) (PUSH)",
     493             :                                               zError(z_ret), z_ret);
     494             : 
     495             :                 }
     496             :         }
     497             : 
     498             :         /* call deflate until we get Z_STREAM_END or an error */
     499           0 :         while (true) {
     500           0 :                 z_ret = deflate(z, Z_FINISH);
     501           0 :                 if (z_ret != Z_OK) break;
     502             :         }
     503           0 :         if (z_ret != Z_STREAM_END) {
     504           0 :                 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
     505             :                                       "Bad deflate(Z_BLOCK) error %s(%d) (PUSH)",
     506             :                                       zError(z_ret), z_ret);
     507             :         }
     508             : 
     509           0 :         if (z->avail_in) {
     510           0 :                 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
     511             :                                       "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
     512             :                                       z->avail_in);
     513             :         }
     514             : 
     515           0 :         comp_chunk_size = 2 + z->total_out;
     516             : 
     517           0 :         z_ret = deflateReset(z);
     518           0 :         if (z_ret != Z_OK) {
     519           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     520             :                                       "Bad deflateReset error %s(%d) (PULL)",
     521             :                                       zError(z_ret), z_ret);
     522             :         }
     523             : 
     524           0 :         z_ret = deflateSetDictionary(z, plain_chunk.data, plain_chunk.length);
     525           0 :         if (z_ret != Z_OK) {
     526           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     527             :                                       "Bad deflateSetDictionary error %s(%d) (PULL)",
     528             :                                       zError(z_ret), z_ret);
     529             :         }
     530             : 
     531           0 :         tmp_offset = ndrpush->offset;
     532           0 :         ndrpush->offset = comp_chunk_size_offset;
     533           0 :         NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk_size));
     534           0 :         ndrpush->offset = tmp_offset;
     535             : 
     536           0 :         DEBUG(9,("MSZIP comp plain_chunk_size: %08zX (%zu) comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
     537             :                  plain_chunk.length,
     538             :                  plain_chunk.length,
     539             :                  comp_chunk_size, comp_chunk_size));
     540             : 
     541           0 :         ndrpush->offset += comp_chunk_size;
     542           0 :         return NDR_ERR_SUCCESS;
     543             : }
     544             : 
     545           0 : static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull,
     546             :                                                   struct ndr_push *ndrpush,
     547             :                                                   bool *last)
     548             : {
     549           0 :         DATA_BLOB comp_chunk;
     550           0 :         DATA_BLOB plain_chunk;
     551           0 :         uint32_t comp_chunk_offset;
     552           0 :         uint32_t plain_chunk_offset;
     553           0 :         uint32_t comp_chunk_size;
     554           0 :         uint32_t plain_chunk_size;
     555           0 :         ssize_t ret;
     556             : 
     557           0 :         NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
     558           0 :         if (plain_chunk_size > 0x00010000) {
     559           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad XPRESS plain chunk size %08"PRIX32" > 0x00010000 (PULL)",
     560             :                                       plain_chunk_size);
     561             :         }
     562             : 
     563           0 :         NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
     564             : 
     565           0 :         comp_chunk_offset = ndrpull->offset;
     566           0 :         NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
     567           0 :         comp_chunk.length = comp_chunk_size;
     568           0 :         comp_chunk.data = ndrpull->data + comp_chunk_offset;
     569             : 
     570           0 :         plain_chunk_offset = ndrpush->offset;
     571           0 :         NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
     572           0 :         plain_chunk.length = plain_chunk_size;
     573           0 :         plain_chunk.data = ndrpush->data + plain_chunk_offset;
     574             : 
     575           0 :         DEBUG(9,("XPRESS plain_chunk_size: %08"PRIX32" (%"PRIu32") comp_chunk_size: %08"PRIX32" (%"PRIu32")\n",
     576             :                  plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
     577             : 
     578             :         /* Uncompressing the buffer using LZ Xpress algorithm */
     579           0 :         ret = lzxpress_decompress(comp_chunk.data,
     580           0 :                                   comp_chunk.length,
     581             :                                   plain_chunk.data,
     582           0 :                                   plain_chunk.length);
     583           0 :         if (ret < 0) {
     584           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     585             :                                       "XPRESS lzxpress_decompress() returned %zd\n",
     586             :                                       ret);
     587             :         }
     588           0 :         plain_chunk.length = ret;
     589             : 
     590           0 :         if ((plain_chunk_size < 0x00010000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
     591             :                 /* this is the last chunk */
     592           0 :                 *last = true;
     593             :         }
     594             : 
     595           0 :         return NDR_ERR_SUCCESS;
     596             : }
     597             : 
     598           0 : static enum ndr_err_code ndr_push_compression_xpress_chunk(struct ndr_push *ndrpush,
     599             :                                                            struct ndr_pull *ndrpull,
     600             :                                                            bool *last)
     601             : {
     602           0 :         DATA_BLOB comp_chunk;
     603           0 :         uint32_t comp_chunk_size_offset;
     604           0 :         DATA_BLOB plain_chunk;
     605           0 :         uint32_t plain_chunk_size;
     606           0 :         uint32_t plain_chunk_offset;
     607           0 :         uint32_t max_plain_size = 0x00010000;
     608           0 :         uint32_t max_comp_size = 0x00020000 + 2; /* TODO: use the correct value here */
     609           0 :         uint32_t tmp_offset;
     610           0 :         ssize_t ret;
     611             : 
     612           0 :         plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
     613           0 :         plain_chunk_offset = ndrpull->offset;
     614           0 :         NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
     615             : 
     616           0 :         plain_chunk.data = ndrpull->data + plain_chunk_offset;
     617           0 :         plain_chunk.length = plain_chunk_size;
     618             : 
     619           0 :         if (plain_chunk_size < max_plain_size) {
     620           0 :                 *last = true;
     621             :         }
     622             : 
     623           0 :         NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size));
     624           0 :         comp_chunk_size_offset = ndrpush->offset;
     625           0 :         NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE));
     626             : 
     627           0 :         NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
     628             : 
     629           0 :         comp_chunk.data = ndrpush->data + ndrpush->offset;
     630           0 :         comp_chunk.length = max_comp_size;
     631             : 
     632             :         /* Compressing the buffer using LZ Xpress algorithm */
     633           0 :         ret = lzxpress_compress(plain_chunk.data,
     634           0 :                                 plain_chunk.length,
     635             :                                 comp_chunk.data,
     636           0 :                                 comp_chunk.length);
     637           0 :         if (ret < 0) {
     638           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     639             :                                       "XPRESS lzxpress_compress() returned %zd\n",
     640             :                                       ret);
     641             :         }
     642           0 :         comp_chunk.length = ret;
     643             : 
     644           0 :         tmp_offset = ndrpush->offset;
     645           0 :         ndrpush->offset = comp_chunk_size_offset;
     646           0 :         NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk.length));
     647           0 :         ndrpush->offset = tmp_offset;
     648             : 
     649           0 :         ndrpush->offset += comp_chunk.length;
     650           0 :         return NDR_ERR_SUCCESS;
     651             : }
     652             : 
     653         374 : static enum ndr_err_code ndr_pull_compression_none(struct ndr_pull *ndrpull,
     654             :                                                    struct ndr_push *ndrpush,
     655             :                                                    ssize_t decompressed_len,
     656             :                                                    ssize_t compressed_len)
     657             : {
     658          10 :         DATA_BLOB comp_chunk;
     659         374 :         uint32_t comp_chunk_size = compressed_len;
     660          10 :         uint32_t comp_chunk_offset;
     661             : 
     662         374 :         if (decompressed_len != compressed_len) {
     663           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     664             :                                       "decompressed len %zd != compressed_len %zd in 'NONE' compression!",
     665             :                                       decompressed_len,
     666             :                                       compressed_len);
     667             :         }
     668             : 
     669         374 :         if (comp_chunk_size != compressed_len) {
     670           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     671             :                                       "compressed_len %zd overflows uint32_t in 'NONE' compression!",
     672             :                                       compressed_len);
     673             :         }
     674             : 
     675         374 :         comp_chunk_offset = ndrpull->offset;
     676         374 :         NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
     677         374 :         comp_chunk.length = comp_chunk_size;
     678         374 :         comp_chunk.data = ndrpull->data + comp_chunk_offset;
     679             : 
     680         374 :         NDR_CHECK(ndr_push_array_uint8(ndrpush,
     681             :                                        NDR_SCALARS,
     682             :                                        comp_chunk.data,
     683             :                                        comp_chunk.length));
     684             : 
     685         364 :         return NDR_ERR_SUCCESS;
     686             : }
     687             : 
     688         594 : static enum ndr_err_code ndr_push_compression_none(struct ndr_push *ndrpush,
     689             :                                                    struct ndr_pull *ndrpull)
     690             : {
     691           9 :         DATA_BLOB plain_chunk;
     692           9 :         uint32_t plain_chunk_size;
     693           9 :         uint32_t plain_chunk_offset;
     694             : 
     695         594 :         plain_chunk_size = ndrpull->data_size - ndrpull->offset;
     696         594 :         plain_chunk_offset = ndrpull->offset;
     697         594 :         NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
     698             : 
     699         594 :         plain_chunk.data = ndrpull->data + plain_chunk_offset;
     700         594 :         plain_chunk.length = plain_chunk_size;
     701             : 
     702         594 :         NDR_CHECK(ndr_push_array_uint8(ndrpush,
     703             :                                        NDR_SCALARS,
     704             :                                        plain_chunk.data,
     705             :                                        plain_chunk.length));
     706         585 :         return NDR_ERR_SUCCESS;
     707             : }
     708             : 
     709         256 : static enum ndr_err_code ndr_pull_compression_xpress_huff_raw_chunk(struct ndr_pull *ndrpull,
     710             :                                                                     struct ndr_push *ndrpush,
     711             :                                                                     ssize_t decompressed_len,
     712             :                                                                     ssize_t compressed_len)
     713             : {
     714           7 :         DATA_BLOB comp_chunk;
     715           7 :         uint32_t comp_chunk_offset;
     716           7 :         uint32_t comp_chunk_size;
     717           7 :         DATA_BLOB plain_chunk;
     718           7 :         uint32_t plain_chunk_offset;
     719           7 :         uint32_t plain_chunk_size;
     720           7 :         ssize_t ret;
     721             : 
     722         256 :         plain_chunk_size = decompressed_len;
     723         256 :         comp_chunk_size = compressed_len;
     724             : 
     725         256 :         DEBUG(9,("XPRESS_HUFF plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
     726             :                  plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
     727             : 
     728         256 :         comp_chunk_offset = ndrpull->offset;
     729         256 :         NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
     730         256 :         comp_chunk.length = comp_chunk_size;
     731         256 :         comp_chunk.data = ndrpull->data + comp_chunk_offset;
     732             : 
     733         256 :         plain_chunk_offset = ndrpush->offset;
     734         256 :         NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
     735         256 :         plain_chunk.length = plain_chunk_size;
     736         256 :         plain_chunk.data = ndrpush->data + plain_chunk_offset;
     737             : 
     738             :         /* Decompressing the buffer using LZ Xpress w/ Huffman algorithm */
     739         256 :         ret = lzxpress_huffman_decompress(comp_chunk.data,
     740             :                                           comp_chunk.length,
     741             :                                           plain_chunk.data,
     742             :                                           plain_chunk.length);
     743         256 :         if (ret < 0) {
     744           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     745             :                                       "XPRESS HUFF lzxpress_huffman_decompress() returned %zd\n",
     746             :                                       ret);
     747             :         }
     748             : 
     749         256 :         if (plain_chunk.length != ret) {
     750           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     751             :                                       "XPRESS HUFF lzxpress_huffman_decompress() output is not as expected (%zd != %zu) (PULL)",
     752             :                                       ret, plain_chunk.length);
     753             :         }
     754             : 
     755         249 :         return NDR_ERR_SUCCESS;
     756             : }
     757             : 
     758         123 : static enum ndr_err_code ndr_push_compression_xpress_huff_raw_chunk(struct ndr_push *ndrpush,
     759             :                                                                     struct ndr_pull *ndrpull,
     760             :                                                                     struct ndr_compression_state *state)
     761             : {
     762           4 :         DATA_BLOB comp_chunk;
     763           4 :         DATA_BLOB plain_chunk;
     764           4 :         uint32_t plain_chunk_size;
     765           4 :         uint32_t plain_chunk_offset;
     766           4 :         ssize_t ret;
     767             : 
     768         123 :         struct lzxhuff_compressor_mem *mem = state->alg.lzxpress_huffman.mem;
     769             : 
     770         123 :         if (ndrpull->data_size <= ndrpull->offset) {
     771           0 :                 return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
     772             :                                       "strange NDR pull size and offset (integer overflow?)");
     773             : 
     774             :         }
     775             : 
     776         123 :         plain_chunk_size = ndrpull->data_size - ndrpull->offset;
     777         123 :         plain_chunk_offset = ndrpull->offset;
     778         123 :         NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
     779             : 
     780         123 :         plain_chunk.data = ndrpull->data + plain_chunk_offset;
     781         123 :         plain_chunk.length = plain_chunk_size;
     782             : 
     783         123 :         comp_chunk.length = lzxpress_huffman_max_compressed_size(plain_chunk_size);
     784         123 :         NDR_CHECK(ndr_push_expand(ndrpush, comp_chunk.length));
     785             : 
     786         123 :         comp_chunk.data = ndrpush->data + ndrpush->offset;
     787             : 
     788             : 
     789             :         /* Compressing the buffer using LZ Xpress w/ Huffman algorithm */
     790         123 :         ret = lzxpress_huffman_compress(mem,
     791         119 :                                         plain_chunk.data,
     792             :                                         plain_chunk.length,
     793             :                                         comp_chunk.data,
     794             :                                         comp_chunk.length);
     795         123 :         if (ret < 0) {
     796           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     797             :                                       "XPRESS HUFF lzxpress_huffman_compress() returned %zd\n",
     798             :                                       ret);
     799             :         }
     800             : 
     801         123 :         if (ret > comp_chunk.length) {
     802           0 :                 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION,
     803             :                                       "XPRESS HUFF lzxpress_huffman_compress() output is not as expected (%zd > %zu) (PULL)",
     804             :                                       ret, comp_chunk.length);
     805             :         }
     806             : 
     807         123 :         ndrpush->offset += ret;
     808         123 :         return NDR_ERR_SUCCESS;
     809             : }
     810             : 
     811             : 
     812             : /*
     813             :   handle compressed subcontext buffers, which in midl land are user-marshalled, but
     814             :   we use magic in pidl to make them easier to cope with
     815             : */
     816         633 : enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr,
     817             :                                     struct ndr_pull **_comndr,
     818             :                                     enum ndr_compression_alg compression_alg,
     819             :                                     ssize_t decompressed_len,
     820             :                                     ssize_t compressed_len)
     821             : {
     822          20 :         struct ndr_push *ndrpush;
     823          20 :         struct ndr_pull *comndr;
     824          20 :         DATA_BLOB uncompressed;
     825         633 :         bool last = false;
     826          20 :         z_stream z;
     827             : 
     828         633 :         ndrpush = ndr_push_init_ctx(subndr);
     829         633 :         NDR_ERR_HAVE_NO_MEMORY(ndrpush);
     830             : 
     831         633 :         switch (compression_alg) {
     832         374 :         case NDR_COMPRESSION_NONE:
     833         374 :                 NDR_CHECK(ndr_pull_compression_none(subndr, ndrpush,
     834             :                                                     decompressed_len,
     835             :                                                     compressed_len));
     836         364 :                 break;
     837           2 :         case NDR_COMPRESSION_MSZIP_CAB:
     838           2 :                 NDR_CHECK(ndr_pull_compression_mszip_cab_chunk(subndr, ndrpush,
     839             :                                                                subndr->cstate,
     840             :                                                                decompressed_len,
     841             :                                                                compressed_len));
     842           0 :                 break;
     843           0 :         case NDR_COMPRESSION_MSZIP:
     844           0 :                 ZERO_STRUCT(z);
     845           0 :                 while (!last) {
     846           0 :                         NDR_CHECK(ndr_pull_compression_mszip_chunk(subndr, ndrpush, &z, &last));
     847             :                 }
     848           0 :                 break;
     849             : 
     850           0 :         case NDR_COMPRESSION_XPRESS:
     851           0 :                 while (!last) {
     852           0 :                         NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr, ndrpush, &last));
     853             :                 }
     854           0 :                 break;
     855             : 
     856         256 :         case NDR_COMPRESSION_XPRESS_HUFF_RAW:
     857         256 :                 NDR_CHECK(ndr_pull_compression_xpress_huff_raw_chunk(subndr, ndrpush,
     858             :                                                                      decompressed_len,
     859             :                                                                      compressed_len));
     860         249 :                 break;
     861             : 
     862           1 :         default:
     863           1 :                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)",
     864             :                                       compression_alg);
     865             :         }
     866             : 
     867         632 :         uncompressed = ndr_push_blob(ndrpush);
     868         632 :         if (uncompressed.length != decompressed_len) {
     869           0 :                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION,
     870             :                                       "Bad uncompressed_len [%zu] != [%zd](0x%08zX) (PULL)",
     871             :                                       uncompressed.length,
     872             :                                       decompressed_len,
     873             :                                       decompressed_len);
     874             :         }
     875             : 
     876         632 :         comndr = talloc_zero(subndr, struct ndr_pull);
     877         632 :         NDR_ERR_HAVE_NO_MEMORY(comndr);
     878         632 :         comndr->flags                = subndr->flags;
     879         632 :         comndr->current_mem_ctx      = subndr->current_mem_ctx;
     880             : 
     881         632 :         comndr->data         = uncompressed.data;
     882         632 :         comndr->data_size    = uncompressed.length;
     883         632 :         comndr->offset               = 0;
     884             : 
     885         632 :         *_comndr = comndr;
     886         632 :         return NDR_ERR_SUCCESS;
     887             : }
     888             : 
     889         632 : enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr,
     890             :                                   struct ndr_pull *comndr,
     891             :                                   enum ndr_compression_alg compression_alg,
     892             :                                   ssize_t decompressed_len)
     893             : {
     894         632 :         return NDR_ERR_SUCCESS;
     895             : }
     896             : 
     897             : /*
     898             :   push a compressed subcontext
     899             : */
     900         717 : enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr,
     901             :                                     struct ndr_push **_uncomndr)
     902             : {
     903          13 :         struct ndr_push *uncomndr;
     904         717 :         enum ndr_compression_alg compression_alg = subndr->cstate->type;
     905             : 
     906         717 :         switch (compression_alg) {
     907         704 :         case NDR_COMPRESSION_NONE:
     908             :         case NDR_COMPRESSION_MSZIP_CAB:
     909             :         case NDR_COMPRESSION_MSZIP:
     910             :         case NDR_COMPRESSION_XPRESS:
     911             :         case NDR_COMPRESSION_XPRESS_HUFF_RAW:
     912         717 :                 break;
     913           0 :         default:
     914           0 :                 return ndr_push_error(subndr, NDR_ERR_COMPRESSION,
     915             :                                       "Bad compression algorithm %d (PUSH)",
     916             :                                       compression_alg);
     917             :         }
     918             : 
     919         717 :         uncomndr = ndr_push_init_ctx(subndr);
     920         717 :         NDR_ERR_HAVE_NO_MEMORY(uncomndr);
     921         717 :         uncomndr->flags      = subndr->flags;
     922             : 
     923         717 :         *_uncomndr = uncomndr;
     924         717 :         return NDR_ERR_SUCCESS;
     925             : }
     926             : 
     927             : /*
     928             :   push a compressed subcontext
     929             : */
     930         717 : enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr,
     931             :                                   struct ndr_push *uncomndr)
     932             : {
     933          13 :         struct ndr_pull *ndrpull;
     934         717 :         bool last = false;
     935          13 :         z_stream z;
     936             : 
     937         717 :         enum ndr_compression_alg compression_alg = subndr->cstate->type;
     938             : 
     939         717 :         ndrpull = talloc_zero(uncomndr, struct ndr_pull);
     940         717 :         NDR_ERR_HAVE_NO_MEMORY(ndrpull);
     941         717 :         ndrpull->flags               = uncomndr->flags;
     942         717 :         ndrpull->data                = uncomndr->data;
     943         717 :         ndrpull->data_size   = uncomndr->offset;
     944         717 :         ndrpull->offset              = 0;
     945             : 
     946         717 :         switch (compression_alg) {
     947         594 :         case NDR_COMPRESSION_NONE:
     948         594 :                 NDR_CHECK(ndr_push_compression_none(subndr, ndrpull));
     949         585 :                 break;
     950             : 
     951           0 :         case NDR_COMPRESSION_MSZIP_CAB:
     952           0 :                 NDR_CHECK(ndr_push_compression_mszip_cab_chunk(subndr, ndrpull, subndr->cstate));
     953           0 :                 break;
     954             : 
     955           0 :         case NDR_COMPRESSION_MSZIP:
     956           0 :                 ZERO_STRUCT(z);
     957           0 :                 while (!last) {
     958           0 :                         NDR_CHECK(ndr_push_compression_mszip_chunk(subndr, ndrpull, &z, &last));
     959             :                 }
     960           0 :                 break;
     961             : 
     962           0 :         case NDR_COMPRESSION_XPRESS:
     963           0 :                 while (!last) {
     964           0 :                         NDR_CHECK(ndr_push_compression_xpress_chunk(subndr, ndrpull, &last));
     965             :                 }
     966           0 :                 break;
     967             : 
     968         123 :         case NDR_COMPRESSION_XPRESS_HUFF_RAW:
     969         123 :                 NDR_CHECK(ndr_push_compression_xpress_huff_raw_chunk(subndr, ndrpull, subndr->cstate));
     970         119 :                 break;
     971             : 
     972           0 :         default:
     973           0 :                 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)",
     974             :                                       compression_alg);
     975             :         }
     976             : 
     977         717 :         talloc_free(uncomndr);
     978         717 :         return NDR_ERR_SUCCESS;
     979             : }
     980             : 
     981           2 : static enum ndr_err_code generic_mszip_init(struct ndr_compression_state *state)
     982             : {
     983           2 :         z_stream *z = talloc_zero(state, z_stream);
     984           2 :         NDR_ERR_HAVE_NO_MEMORY(z);
     985             : 
     986           2 :         z->zalloc = ndr_zlib_alloc;
     987           2 :         z->zfree  = ndr_zlib_free;
     988           2 :         z->opaque = state;
     989             : 
     990           2 :         state->alg.mszip.z = z;
     991           2 :         state->alg.mszip.dict_size = 0;
     992             :         /* pre-alloc dictionary */
     993           2 :         state->alg.mszip.dict = talloc_array(state, uint8_t, 0x8000);
     994           2 :         NDR_ERR_HAVE_NO_MEMORY(state->alg.mszip.dict);
     995             : 
     996           0 :         return NDR_ERR_SUCCESS;
     997             : }
     998             : 
     999           2 : enum ndr_err_code ndr_pull_compression_state_init(struct ndr_pull *ndr,
    1000             :                                                   enum ndr_compression_alg compression_alg,
    1001             :                                                   struct ndr_compression_state **state)
    1002             : {
    1003           2 :         struct ndr_compression_state *s;
    1004           2 :         int z_ret;
    1005             : 
    1006           2 :         s = talloc_zero(ndr, struct ndr_compression_state);
    1007           2 :         NDR_ERR_HAVE_NO_MEMORY(s);
    1008           2 :         s->type = compression_alg;
    1009             : 
    1010           2 :         switch (compression_alg) {
    1011           0 :         case NDR_COMPRESSION_NONE:
    1012             :         case NDR_COMPRESSION_MSZIP:
    1013             :         case NDR_COMPRESSION_XPRESS:
    1014             :         case NDR_COMPRESSION_XPRESS_HUFF_RAW:
    1015           0 :                 break;
    1016           2 :         case NDR_COMPRESSION_MSZIP_CAB:
    1017           2 :                 NDR_CHECK(generic_mszip_init(s));
    1018           2 :                 z_ret = inflateInit2(s->alg.mszip.z, -MAX_WBITS);
    1019           2 :                 if (z_ret != Z_OK) {
    1020           0 :                         return ndr_pull_error(ndr, NDR_ERR_COMPRESSION,
    1021             :                                               "zlib inflateinit2 error %s (%d) %s (PULL)",
    1022             :                                               zError(z_ret), z_ret, s->alg.mszip.z->msg);
    1023             :                 }
    1024           0 :                 break;
    1025           0 :         default:
    1026           0 :                 return ndr_pull_error(ndr, NDR_ERR_COMPRESSION,
    1027             :                                       "Bad compression algorithm %d (PULL)",
    1028             :                                       compression_alg);
    1029           2 :                 break;
    1030             :         }
    1031             : 
    1032           2 :         *state = s;
    1033             : 
    1034           2 :         return NDR_ERR_SUCCESS;
    1035             : }
    1036             : 
    1037         717 : enum ndr_err_code ndr_push_compression_state_init(struct ndr_push *ndr,
    1038             :                                                   enum ndr_compression_alg compression_alg)
    1039             : {
    1040          13 :         struct ndr_compression_state *s;
    1041          13 :         int z_ret;
    1042             : 
    1043             :         /*
    1044             :          * Avoid confusion, NULL out ndr->cstate at the start of the
    1045             :          * compression block
    1046             :          */
    1047         717 :         ndr->cstate = NULL;
    1048             : 
    1049         717 :         s = talloc_zero(ndr, struct ndr_compression_state);
    1050         717 :         NDR_ERR_HAVE_NO_MEMORY(s);
    1051         717 :         s->type = compression_alg;
    1052             : 
    1053         717 :         switch (compression_alg) {
    1054         585 :         case NDR_COMPRESSION_NONE:
    1055             :         case NDR_COMPRESSION_XPRESS:
    1056         585 :                 break;
    1057             : 
    1058         123 :         case NDR_COMPRESSION_XPRESS_HUFF_RAW:
    1059         123 :                 s->alg.lzxpress_huffman.mem = talloc(s, struct lzxhuff_compressor_mem);
    1060         123 :                 if (s->alg.lzxpress_huffman.mem == NULL) {
    1061           0 :                         return NDR_ERR_ALLOC;
    1062             :                 }
    1063         119 :                 break;
    1064             : 
    1065           0 :         case NDR_COMPRESSION_MSZIP:
    1066           0 :                 break;
    1067           0 :         case NDR_COMPRESSION_MSZIP_CAB:
    1068           0 :                 NDR_CHECK(generic_mszip_init(s));
    1069           0 :                 z_ret = deflateInit2(s->alg.mszip.z,
    1070             :                                      Z_DEFAULT_COMPRESSION,
    1071             :                                      Z_DEFLATED,
    1072             :                                      -MAX_WBITS,
    1073             :                                      8, /* memLevel */
    1074             :                                      Z_DEFAULT_STRATEGY);
    1075           0 :                 if (z_ret != Z_OK) {
    1076           0 :                         return ndr_push_error(ndr, NDR_ERR_COMPRESSION,
    1077             :                                               "zlib inflateinit2 error %s (%d) %s (PUSH)",
    1078             :                                               zError(z_ret), z_ret, s->alg.mszip.z->msg);
    1079             :                 }
    1080           0 :                 break;
    1081           0 :         default:
    1082           0 :                 return ndr_push_error(ndr, NDR_ERR_COMPRESSION,
    1083             :                                       "Bad compression algorithm %d (PUSH)",
    1084             :                                       compression_alg);
    1085          13 :                 break;
    1086             :         }
    1087             : 
    1088         717 :         ndr->cstate = s;
    1089             : 
    1090         717 :         return NDR_ERR_SUCCESS;
    1091             : }
    1092             : 

Generated by: LCOV version 1.14