Coverage Report

Created: 2026-01-10 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/g10/compress.c
Line
Count
Source
1
/* compress.c - compress filter
2
 * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3
 *               2003, 2006, 2010 Free Software Foundation, Inc.
4
 *
5
 * This file is part of GnuPG.
6
 *
7
 * GnuPG is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * GnuPG is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
/* Note that the code in compress-bz2.c is nearly identical to the
22
   code here, so if you fix a bug here, look there to see if a
23
   matching bug needs to be fixed.  I tried to have one set of
24
   functions that could do ZIP, ZLIB, and BZIP2, but it became
25
   dangerously unreadable with #ifdefs and if(algo) -dshaw */
26
27
#include <config.h>
28
#include <stdio.h>
29
#include <stdlib.h>
30
#include <string.h>
31
#include <unistd.h>
32
#include <errno.h>
33
#ifdef HAVE_ZIP
34
# include <zlib.h>
35
#endif
36
37
#include "gpg.h"
38
#include "../common/util.h"
39
#include "packet.h"
40
#include "filter.h"
41
#include "main.h"
42
#include "options.h"
43
44
45
#ifdef __riscos__
46
#define BYTEF_CAST(a) ((Bytef *)(a))
47
#else
48
#define BYTEF_CAST(a) (a)
49
#endif
50
51
52
53
int compress_filter_bz2( void *opaque, int control,
54
       IOBUF a, byte *buf, size_t *ret_len);
55
56
#ifdef HAVE_ZIP
57
static void
58
init_compress( compress_filter_context_t *zfx, z_stream *zs )
59
{
60
    int rc;
61
    int level;
62
63
    if( opt.compress_level >= 1 && opt.compress_level <= 9 )
64
  level = opt.compress_level;
65
    else if( opt.compress_level == -1 )
66
  level = Z_DEFAULT_COMPRESSION;
67
    else {
68
  log_error("invalid compression level; using default level\n");
69
  level = Z_DEFAULT_COMPRESSION;
70
    }
71
72
    if( (rc = zfx->algo == 1? deflateInit2( zs, level, Z_DEFLATED,
73
              -13, 8, Z_DEFAULT_STRATEGY)
74
          : deflateInit( zs, level )
75
          ) != Z_OK ) {
76
  log_error ("zlib problem: %s\n", zs->msg? zs->msg :
77
             rc == Z_MEM_ERROR ? "out of core" :
78
             rc == Z_VERSION_ERROR ? "invalid lib version" :
79
                   "unknown error" );
80
        write_status_error ("zlib.init", gpg_error (GPG_ERR_INTERNAL));
81
        g10_exit (2);
82
    }
83
84
    zfx->outbufsize = 65536;
85
    zfx->outbuf = xmalloc( zfx->outbufsize );
86
}
87
88
static int
89
do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a )
90
{
91
    int rc;
92
    int zrc;
93
    unsigned n;
94
95
    if (flush == Z_NO_FLUSH && zs->avail_in == 0)
96
      return 0;
97
98
    do {
99
  zs->next_out = BYTEF_CAST (zfx->outbuf);
100
  zs->avail_out = zfx->outbufsize;
101
  if( DBG_FILTER )
102
      log_debug("enter deflate: avail_in=%u, avail_out=%u, flush=%d\n",
103
        (unsigned)zs->avail_in, (unsigned)zs->avail_out, flush );
104
  zrc = deflate( zs, flush );
105
  if( zrc == Z_STREAM_END && flush == Z_FINISH )
106
      ;
107
  else if( zrc != Z_OK ) {
108
      if( zs->msg )
109
    log_error ("zlib deflate problem: %s\n", zs->msg );
110
      else
111
    log_error ("zlib deflate problem: rc=%d\n", zrc );
112
            write_status_error ("zlib.deflate", gpg_error (GPG_ERR_INTERNAL));
113
            g10_exit (2);
114
  }
115
  n = zfx->outbufsize - zs->avail_out;
116
  if( DBG_FILTER )
117
      log_debug("leave deflate: "
118
          "avail_in=%u, avail_out=%u, n=%u, zrc=%d\n",
119
    (unsigned)zs->avail_in, (unsigned)zs->avail_out,
120
                 (unsigned)n, zrc );
121
122
  if( (rc=iobuf_write( a, zfx->outbuf, n )) ) {
123
      log_error ("deflate: iobuf_write failed\n");
124
      return rc;
125
  }
126
    } while( zs->avail_in || (flush == Z_FINISH && zrc != Z_STREAM_END) );
127
    return 0;
128
}
129
130
static void
131
init_uncompress( compress_filter_context_t *zfx, z_stream *zs )
132
{
133
    int rc;
134
135
    /****************
136
     * PGP uses a windowsize of 13 bits. Using a negative value for
137
     * it forces zlib not to expect a zlib header.  This is a
138
     * undocumented feature Peter Gutmann told me about.
139
     *
140
     * We must use 15 bits for the inflator because CryptoEx uses 15
141
     * bits thus the output would get scrambled w/o error indication
142
     * if we would use 13 bits.  For the uncompressing this does not
143
     * matter at all.
144
     */
145
    if( (rc = zfx->algo == 1? inflateInit2( zs, -15)
146
          : inflateInit( zs )) != Z_OK ) {
147
  log_error ("zlib problem: %s\n", zs->msg? zs->msg :
148
                   rc == Z_MEM_ERROR ? "out of core" :
149
                   rc == Z_VERSION_ERROR ? "invalid lib version" :
150
                                            "unknown error" );
151
        write_status_error ("zlib.init.un", gpg_error (GPG_ERR_INTERNAL));
152
        g10_exit (2);
153
    }
154
155
    zfx->inbufsize = 2048;
156
    zfx->inbuf = xmalloc( zfx->inbufsize );
157
    zs->avail_in = 0;
158
}
159
160
static int
161
do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
162
         IOBUF a, size_t *ret_len )
163
{
164
    int zrc;
165
    int rc = 0;
166
    int leave = 0;
167
    size_t n;
168
    int nread, count;
169
    int refill = !zs->avail_in;
170
171
    if( DBG_FILTER )
172
  log_debug("begin inflate: avail_in=%u, avail_out=%u, inbuf=%u\n",
173
    (unsigned)zs->avail_in, (unsigned)zs->avail_out,
174
    (unsigned)zfx->inbufsize );
175
    do {
176
  if( zs->avail_in < zfx->inbufsize && refill ) {
177
      n = zs->avail_in;
178
      if( !n )
179
            zs->next_in = BYTEF_CAST (zfx->inbuf);
180
      count = zfx->inbufsize - n;
181
      nread = iobuf_read( a, zfx->inbuf + n, count );
182
      if( nread == -1 ) nread = 0;
183
      n += nread;
184
      /* Algo 1 has no zlib header which requires us to give
185
       * inflate an extra dummy byte to read. To be on the safe
186
       * side we allow for up to 4 ff bytes.  */
187
      if( nread < count && zfx->algo == 1 && zfx->algo1hack < 4) {
188
    *(zfx->inbuf + n) = 0xFF;
189
    zfx->algo1hack++;
190
    n++;
191
                leave = 1;
192
      }
193
      zs->avail_in = n;
194
  }
195
  refill = 1;
196
  if( DBG_FILTER )
197
      log_debug("enter inflate: avail_in=%u, avail_out=%u\n",
198
        (unsigned)zs->avail_in, (unsigned)zs->avail_out);
199
  zrc = inflate ( zs, Z_SYNC_FLUSH );
200
  if( DBG_FILTER )
201
      log_debug("leave inflate: avail_in=%u, avail_out=%u, zrc=%d\n",
202
       (unsigned)zs->avail_in, (unsigned)zs->avail_out, zrc);
203
  if( zrc == Z_STREAM_END )
204
      rc = -1; /* eof */
205
  else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) {
206
      if( zs->msg )
207
    log_error ("zlib inflate problem: %s\n", zs->msg );
208
      else
209
    log_error ("zlib inflate problem: rc=%d\n", zrc );
210
            write_status_error ("zlib.inflate", gpg_error (GPG_ERR_BAD_DATA));
211
            g10_exit (2);
212
  }
213
    } while (zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR
214
             && !leave);
215
216
    *ret_len = zfx->outbufsize - zs->avail_out;
217
    if( DBG_FILTER )
218
  log_debug("do_uncompress: returning %u bytes (%u ignored)\n",
219
                  (unsigned int)*ret_len, (unsigned int)zs->avail_in );
220
    return rc;
221
}
222
223
static int
224
compress_filter( void *opaque, int control,
225
     IOBUF a, byte *buf, size_t *ret_len)
226
{
227
    size_t size = *ret_len;
228
    compress_filter_context_t *zfx = opaque;
229
    z_stream *zs = zfx->opaque;
230
    int rc=0;
231
232
    if( control == IOBUFCTRL_UNDERFLOW ) {
233
  if( !zfx->status ) {
234
      zs = zfx->opaque = xmalloc_clear( sizeof *zs );
235
      init_uncompress( zfx, zs );
236
      zfx->status = 1;
237
  }
238
239
  zs->next_out = BYTEF_CAST (buf);
240
  zs->avail_out = size;
241
  zfx->outbufsize = size; /* needed only for calculation */
242
  rc = do_uncompress( zfx, zs, a, ret_len );
243
    }
244
    else if( control == IOBUFCTRL_FLUSH ) {
245
  if( !zfx->status ) {
246
      PACKET pkt;
247
      PKT_compressed cd;
248
      if(zfx->algo != COMPRESS_ALGO_ZIP
249
         && zfx->algo != COMPRESS_ALGO_ZLIB)
250
        BUG();
251
      memset( &cd, 0, sizeof cd );
252
      cd.len = 0;
253
      cd.algorithm = zfx->algo;
254
            /* Fixme: We should force a new CTB here:
255
               cd.new_ctb = zfx->new_ctb;
256
            */
257
      init_packet( &pkt );
258
      pkt.pkttype = PKT_COMPRESSED;
259
      pkt.pkt.compressed = &cd;
260
      if( build_packet( a, &pkt ))
261
    log_bug("build_packet(PKT_COMPRESSED) failed\n");
262
      zs = zfx->opaque = xmalloc_clear( sizeof *zs );
263
      init_compress( zfx, zs );
264
      zfx->status = 2;
265
  }
266
267
  zs->next_in = BYTEF_CAST (buf);
268
  zs->avail_in = size;
269
  rc = do_compress( zfx, zs, Z_NO_FLUSH, a );
270
    }
271
    else if( control == IOBUFCTRL_FREE ) {
272
  if( zfx->status == 1 ) {
273
      inflateEnd(zs);
274
      xfree(zs);
275
      zfx->opaque = NULL;
276
      xfree(zfx->outbuf); zfx->outbuf = NULL;
277
  }
278
  else if( zfx->status == 2 ) {
279
      zs->next_in = BYTEF_CAST (buf);
280
      zs->avail_in = 0;
281
      do_compress( zfx, zs, Z_FINISH, a );
282
      deflateEnd(zs);
283
      xfree(zs);
284
      zfx->opaque = NULL;
285
      xfree(zfx->outbuf); zfx->outbuf = NULL;
286
  }
287
        if (zfx->release)
288
          zfx->release (zfx);
289
    }
290
    else if( control == IOBUFCTRL_DESC )
291
        mem2str (buf, "compress_filter", *ret_len);
292
    return rc;
293
}
294
#endif /*HAVE_ZIP*/
295
296
static void
297
release_context (compress_filter_context_t *ctx)
298
0
{
299
0
  xfree(ctx->inbuf);
300
0
  ctx->inbuf = NULL;
301
0
  xfree(ctx->outbuf);
302
0
  ctx->outbuf = NULL;
303
0
  xfree (ctx);
304
0
}
305
306
/****************
307
 * Handle a compressed packet
308
 */
309
int
310
handle_compressed (ctrl_t ctrl, void *procctx, PKT_compressed *cd,
311
       int (*callback)(IOBUF, void *), void *passthru )
312
14.0k
{
313
14.0k
    int rc;
314
315
14.0k
    if(check_compress_algo(cd->algorithm))
316
47
      return GPG_ERR_COMPR_ALGO;
317
13.9k
    if(cd->algorithm) {
318
0
        compress_filter_context_t *cfx;
319
320
0
        cfx = xmalloc_clear (sizeof *cfx);
321
0
        cfx->release = release_context;
322
0
        cfx->algo = cd->algorithm;
323
0
        if (push_compress_filter(cd->buf, cfx, cd->algorithm))
324
0
          xfree (cfx);
325
0
    }
326
13.9k
    if( callback )
327
0
  rc = callback(cd->buf, passthru );
328
13.9k
    else
329
13.9k
      rc = proc_packets (ctrl,procctx, cd->buf);
330
13.9k
    cd->buf = NULL;
331
13.9k
    return rc;
332
14.0k
}
333
334
gpg_error_t
335
push_compress_filter(IOBUF out,compress_filter_context_t *zfx,int algo)
336
0
{
337
0
  return push_compress_filter2(out,zfx,algo,0);
338
0
}
339
340
341
/* Push a compress filter and return 0 if that succeeded.  */
342
gpg_error_t
343
push_compress_filter2(IOBUF out,compress_filter_context_t *zfx,
344
          int algo,int rel)
345
0
{
346
0
  gpg_error_t err = gpg_error (GPG_ERR_FALSE);
347
348
0
  if(algo>=0)
349
0
    zfx->algo=algo;
350
0
  else
351
0
    zfx->algo=DEFAULT_COMPRESS_ALGO;
352
353
0
  switch(zfx->algo)
354
0
    {
355
0
    case COMPRESS_ALGO_NONE:
356
0
      break;
357
358
#ifdef HAVE_ZIP
359
    case COMPRESS_ALGO_ZIP:
360
    case COMPRESS_ALGO_ZLIB:
361
      iobuf_push_filter2(out,compress_filter,zfx,rel);
362
      err = 0;
363
      break;
364
#endif
365
366
#ifdef HAVE_BZIP2
367
    case COMPRESS_ALGO_BZIP2:
368
      iobuf_push_filter2(out,compress_filter_bz2,zfx,rel);
369
      err = 0;
370
      break;
371
#endif
372
373
0
    default:
374
0
      BUG();
375
0
    }
376
377
0
  return err;
378
0
}