LCOV - code coverage report
Current view: top level - librpc/ndr - ndr_compression.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 384 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 18 0.0 %

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

Generated by: LCOV version 1.13