xref: /freebsd/crypto/openssl/crypto/comp/c_zlib.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 1998-2026 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <openssl/objects.h>
14 #include "internal/comp.h"
15 #include <openssl/err.h>
16 #include "crypto/cryptlib.h"
17 #include "internal/bio.h"
18 #include "internal/thread_once.h"
19 #include "comp_local.h"
20 
21 COMP_METHOD *COMP_zlib(void);
22 
23 #ifdef OPENSSL_NO_ZLIB
24 #undef ZLIB_SHARED
25 #else
26 
27 #include <zlib.h>
28 
29 static int zlib_stateful_init(COMP_CTX *ctx);
30 static void zlib_stateful_finish(COMP_CTX *ctx);
31 static ossl_ssize_t zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
32     size_t olen, unsigned char *in,
33     size_t ilen);
34 static ossl_ssize_t zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
35     size_t olen, unsigned char *in,
36     size_t ilen);
37 
38 /* memory allocations functions for zlib initialisation */
zlib_zalloc(void * opaque,unsigned int no,unsigned int size)39 static void *zlib_zalloc(void *opaque, unsigned int no, unsigned int size)
40 {
41     void *p;
42 
43     p = OPENSSL_zalloc(no * size);
44     return p;
45 }
46 
zlib_zfree(void * opaque,void * address)47 static void zlib_zfree(void *opaque, void *address)
48 {
49     OPENSSL_free(address);
50 }
51 
52 static COMP_METHOD zlib_stateful_method = {
53     NID_zlib_compression,
54     LN_zlib_compression,
55     zlib_stateful_init,
56     zlib_stateful_finish,
57     zlib_stateful_compress_block,
58     zlib_stateful_expand_block
59 };
60 
61 /*
62  * When OpenSSL is built on Windows, we do not want to require that
63  * the ZLIB.DLL be available in order for the OpenSSL DLLs to
64  * work.  Therefore, all ZLIB routines are loaded at run time
65  * and we do not link to a .LIB file when ZLIB_SHARED is set.
66  */
67 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
68 #include <windows.h>
69 #endif /* !(OPENSSL_SYS_WINDOWS || \
70         * OPENSSL_SYS_WIN32) */
71 
72 #ifdef ZLIB_SHARED
73 #include "internal/dso.h"
74 
75 /* Function pointers */
76 typedef int (*compress_ft)(Bytef *dest, uLongf *destLen,
77     const Bytef *source, uLong sourceLen);
78 typedef int (*uncompress_ft)(Bytef *dest, uLongf *destLen,
79     const Bytef *source, uLong sourceLen);
80 typedef int (*inflateEnd_ft)(z_streamp strm);
81 typedef int (*inflate_ft)(z_streamp strm, int flush);
82 typedef int (*inflateInit__ft)(z_streamp strm,
83     const char *version, int stream_size);
84 typedef int (*deflateEnd_ft)(z_streamp strm);
85 typedef int (*deflate_ft)(z_streamp strm, int flush);
86 typedef int (*deflateInit__ft)(z_streamp strm, int level,
87     const char *version, int stream_size);
88 typedef const char *(*zError__ft)(int err);
89 static compress_ft p_compress = NULL;
90 static uncompress_ft p_uncompress = NULL;
91 static inflateEnd_ft p_inflateEnd = NULL;
92 static inflate_ft p_inflate = NULL;
93 static inflateInit__ft p_inflateInit_ = NULL;
94 static deflateEnd_ft p_deflateEnd = NULL;
95 static deflate_ft p_deflate = NULL;
96 static deflateInit__ft p_deflateInit_ = NULL;
97 static zError__ft p_zError = NULL;
98 
99 static DSO *zlib_dso = NULL;
100 
101 #define compress p_compress
102 #define uncompress p_uncompress
103 #define inflateEnd p_inflateEnd
104 #define inflate p_inflate
105 #define inflateInit_ p_inflateInit_
106 #define deflateEnd p_deflateEnd
107 #define deflate p_deflate
108 #define deflateInit_ p_deflateInit_
109 #define zError p_zError
110 #endif /* ZLIB_SHARED */
111 
112 struct zlib_state {
113     z_stream istream;
114     z_stream ostream;
115 };
116 
zlib_stateful_init(COMP_CTX * ctx)117 static int zlib_stateful_init(COMP_CTX *ctx)
118 {
119     int err;
120     struct zlib_state *state = OPENSSL_zalloc(sizeof(*state));
121 
122     if (state == NULL)
123         goto err;
124 
125     state->istream.zalloc = zlib_zalloc;
126     state->istream.zfree = zlib_zfree;
127     state->istream.opaque = Z_NULL;
128     state->istream.next_in = Z_NULL;
129     state->istream.next_out = Z_NULL;
130     err = inflateInit_(&state->istream, ZLIB_VERSION, sizeof(z_stream));
131     if (err != Z_OK)
132         goto err;
133 
134     state->ostream.zalloc = zlib_zalloc;
135     state->ostream.zfree = zlib_zfree;
136     state->ostream.opaque = Z_NULL;
137     state->ostream.next_in = Z_NULL;
138     state->ostream.next_out = Z_NULL;
139     err = deflateInit_(&state->ostream, Z_DEFAULT_COMPRESSION,
140         ZLIB_VERSION, sizeof(z_stream));
141     if (err != Z_OK)
142         goto err;
143 
144     ctx->data = state;
145     return 1;
146 err:
147     OPENSSL_free(state);
148     return 0;
149 }
150 
zlib_stateful_finish(COMP_CTX * ctx)151 static void zlib_stateful_finish(COMP_CTX *ctx)
152 {
153     struct zlib_state *state = ctx->data;
154     inflateEnd(&state->istream);
155     deflateEnd(&state->ostream);
156     OPENSSL_free(state);
157 }
158 
zlib_stateful_compress_block(COMP_CTX * ctx,unsigned char * out,size_t olen,unsigned char * in,size_t ilen)159 static ossl_ssize_t zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
160     size_t olen, unsigned char *in,
161     size_t ilen)
162 {
163     int err = Z_OK;
164     struct zlib_state *state = ctx->data;
165 
166     if (state == NULL)
167         return -1;
168 
169     state->ostream.next_in = in;
170     state->ostream.avail_in = ilen;
171     state->ostream.next_out = out;
172     state->ostream.avail_out = olen;
173     if (ilen > 0)
174         err = deflate(&state->ostream, Z_SYNC_FLUSH);
175     if (err != Z_OK)
176         return -1;
177     if (state->ostream.avail_out > olen)
178         return -1;
179     return (ossl_ssize_t)(olen - state->ostream.avail_out);
180 }
181 
zlib_stateful_expand_block(COMP_CTX * ctx,unsigned char * out,size_t olen,unsigned char * in,size_t ilen)182 static ossl_ssize_t zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
183     size_t olen, unsigned char *in,
184     size_t ilen)
185 {
186     int err = Z_OK;
187     struct zlib_state *state = ctx->data;
188 
189     if (state == NULL)
190         return 0;
191 
192     state->istream.next_in = in;
193     state->istream.avail_in = ilen;
194     state->istream.next_out = out;
195     state->istream.avail_out = olen;
196     if (ilen > 0)
197         err = inflate(&state->istream, Z_SYNC_FLUSH);
198     if (err != Z_OK)
199         return -1;
200     if (state->istream.avail_out > olen)
201         return -1;
202     return (ossl_ssize_t)(olen - state->istream.avail_out);
203 }
204 
205 /* ONESHOT COMPRESSION/DECOMPRESSION */
206 
zlib_oneshot_init(COMP_CTX * ctx)207 static int zlib_oneshot_init(COMP_CTX *ctx)
208 {
209     return 1;
210 }
211 
zlib_oneshot_finish(COMP_CTX * ctx)212 static void zlib_oneshot_finish(COMP_CTX *ctx)
213 {
214 }
215 
zlib_oneshot_compress_block(COMP_CTX * ctx,unsigned char * out,size_t olen,unsigned char * in,size_t ilen)216 static ossl_ssize_t zlib_oneshot_compress_block(COMP_CTX *ctx, unsigned char *out,
217     size_t olen, unsigned char *in,
218     size_t ilen)
219 {
220     uLongf out_size;
221 
222     if (ilen == 0)
223         return 0;
224 
225     /* zlib's uLongf defined as unsigned long FAR */
226     if (olen > ULONG_MAX)
227         return -1;
228     out_size = (uLongf)olen;
229 
230     if (compress(out, &out_size, in, ilen) != Z_OK)
231         return -1;
232 
233     if (out_size > OSSL_SSIZE_MAX)
234         return -1;
235     return (ossl_ssize_t)out_size;
236 }
237 
zlib_oneshot_expand_block(COMP_CTX * ctx,unsigned char * out,size_t olen,unsigned char * in,size_t ilen)238 static ossl_ssize_t zlib_oneshot_expand_block(COMP_CTX *ctx, unsigned char *out,
239     size_t olen, unsigned char *in,
240     size_t ilen)
241 {
242     uLongf out_size;
243 
244     if (ilen == 0)
245         return 0;
246 
247     /* zlib's uLongf defined as unsigned long FAR */
248     if (olen > ULONG_MAX)
249         return -1;
250     out_size = (uLongf)olen;
251 
252     if (uncompress(out, &out_size, in, ilen) != Z_OK)
253         return -1;
254 
255     if (out_size > OSSL_SSIZE_MAX)
256         return -1;
257     return (ossl_ssize_t)out_size;
258 }
259 
260 static COMP_METHOD zlib_oneshot_method = {
261     NID_zlib_compression,
262     LN_zlib_compression,
263     zlib_oneshot_init,
264     zlib_oneshot_finish,
265     zlib_oneshot_compress_block,
266     zlib_oneshot_expand_block
267 };
268 
269 static CRYPTO_ONCE zlib_once = CRYPTO_ONCE_STATIC_INIT;
DEFINE_RUN_ONCE_STATIC(ossl_comp_zlib_init)270 DEFINE_RUN_ONCE_STATIC(ossl_comp_zlib_init)
271 {
272 #ifdef ZLIB_SHARED
273     /* LIBZ may be externally defined, and we should respect that value */
274 #ifndef LIBZ
275 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
276 #define LIBZ "ZLIB1"
277 #elif defined(OPENSSL_SYS_VMS)
278 #define LIBZ "LIBZ"
279 #else
280 #define LIBZ "z"
281 #endif
282 #endif
283 
284     zlib_dso = DSO_load(NULL, LIBZ, NULL, 0);
285     if (zlib_dso != NULL) {
286         p_compress = (compress_ft)DSO_bind_func(zlib_dso, "compress");
287         p_uncompress = (uncompress_ft)DSO_bind_func(zlib_dso, "uncompress");
288         p_inflateEnd = (inflateEnd_ft)DSO_bind_func(zlib_dso, "inflateEnd");
289         p_inflate = (inflate_ft)DSO_bind_func(zlib_dso, "inflate");
290         p_inflateInit_ = (inflateInit__ft)DSO_bind_func(zlib_dso, "inflateInit_");
291         p_deflateEnd = (deflateEnd_ft)DSO_bind_func(zlib_dso, "deflateEnd");
292         p_deflate = (deflate_ft)DSO_bind_func(zlib_dso, "deflate");
293         p_deflateInit_ = (deflateInit__ft)DSO_bind_func(zlib_dso, "deflateInit_");
294         p_zError = (zError__ft)DSO_bind_func(zlib_dso, "zError");
295     }
296 
297     if (p_compress == NULL || p_uncompress == NULL || p_inflateEnd == NULL
298         || p_inflate == NULL || p_inflateInit_ == NULL
299         || p_deflateEnd == NULL || p_deflate == NULL
300         || p_deflateInit_ == NULL || p_zError == NULL) {
301         ossl_comp_zlib_cleanup();
302         return 0;
303     }
304 #endif
305     return 1;
306 }
307 #endif
308 
COMP_zlib(void)309 COMP_METHOD *COMP_zlib(void)
310 {
311     COMP_METHOD *meth = NULL;
312 
313 #ifndef OPENSSL_NO_ZLIB
314     if (RUN_ONCE(&zlib_once, ossl_comp_zlib_init))
315         meth = &zlib_stateful_method;
316 #endif
317 
318     return meth;
319 }
320 
COMP_zlib_oneshot(void)321 COMP_METHOD *COMP_zlib_oneshot(void)
322 {
323     COMP_METHOD *meth = NULL;
324 
325 #ifndef OPENSSL_NO_ZLIB
326     if (RUN_ONCE(&zlib_once, ossl_comp_zlib_init))
327         meth = &zlib_oneshot_method;
328 #endif
329 
330     return meth;
331 }
332 
333 /* Also called from OPENSSL_cleanup() */
ossl_comp_zlib_cleanup(void)334 void ossl_comp_zlib_cleanup(void)
335 {
336 #ifdef ZLIB_SHARED
337     DSO_free(zlib_dso);
338     zlib_dso = NULL;
339 #endif
340 }
341 
342 #ifndef OPENSSL_NO_ZLIB
343 
344 /* Zlib based compression/decompression filter BIO */
345 
346 typedef struct {
347     unsigned char *ibuf; /* Input buffer */
348     int ibufsize; /* Buffer size */
349     z_stream zin; /* Input decompress context */
350     unsigned char *obuf; /* Output buffer */
351     int obufsize; /* Output buffer size */
352     unsigned char *optr; /* Position in output buffer */
353     int ocount; /* Amount of data in output buffer */
354     int odone; /* deflate EOF */
355     int comp_level; /* Compression level to use */
356     z_stream zout; /* Output compression context */
357 } BIO_ZLIB_CTX;
358 
359 #define ZLIB_DEFAULT_BUFSIZE 1024
360 
361 static int bio_zlib_new(BIO *bi);
362 static int bio_zlib_free(BIO *bi);
363 static int bio_zlib_read(BIO *b, char *out, int outl);
364 static int bio_zlib_write(BIO *b, const char *in, int inl);
365 static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr);
366 static long bio_zlib_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);
367 
368 static const BIO_METHOD bio_meth_zlib = {
369     BIO_TYPE_COMP,
370     "zlib",
371     bwrite_conv,
372     bio_zlib_write,
373     bread_conv,
374     bio_zlib_read,
375     NULL, /* bio_zlib_puts, */
376     NULL, /* bio_zlib_gets, */
377     bio_zlib_ctrl,
378     bio_zlib_new,
379     bio_zlib_free,
380     bio_zlib_callback_ctrl
381 };
382 #endif
383 
BIO_f_zlib(void)384 const BIO_METHOD *BIO_f_zlib(void)
385 {
386 #ifndef OPENSSL_NO_ZLIB
387     if (RUN_ONCE(&zlib_once, ossl_comp_zlib_init))
388         return &bio_meth_zlib;
389 #endif
390     return NULL;
391 }
392 
393 #ifndef OPENSSL_NO_ZLIB
bio_zlib_new(BIO * bi)394 static int bio_zlib_new(BIO *bi)
395 {
396     BIO_ZLIB_CTX *ctx;
397 
398 #ifdef ZLIB_SHARED
399     if (!RUN_ONCE(&zlib_once, ossl_comp_zlib_init)) {
400         ERR_raise(ERR_LIB_COMP, COMP_R_ZLIB_NOT_SUPPORTED);
401         return 0;
402     }
403 #endif
404     ctx = OPENSSL_zalloc(sizeof(*ctx));
405     if (ctx == NULL)
406         return 0;
407     ctx->ibufsize = ZLIB_DEFAULT_BUFSIZE;
408     ctx->obufsize = ZLIB_DEFAULT_BUFSIZE;
409     ctx->zin.zalloc = Z_NULL;
410     ctx->zin.zfree = Z_NULL;
411     ctx->zout.zalloc = Z_NULL;
412     ctx->zout.zfree = Z_NULL;
413     ctx->comp_level = Z_DEFAULT_COMPRESSION;
414     BIO_set_init(bi, 1);
415     BIO_set_data(bi, ctx);
416 
417     return 1;
418 }
419 
bio_zlib_free(BIO * bi)420 static int bio_zlib_free(BIO *bi)
421 {
422     BIO_ZLIB_CTX *ctx;
423 
424     if (!bi)
425         return 0;
426     ctx = BIO_get_data(bi);
427     if (ctx->ibuf) {
428         /* Destroy decompress context */
429         inflateEnd(&ctx->zin);
430         OPENSSL_free(ctx->ibuf);
431     }
432     if (ctx->obuf) {
433         /* Destroy compress context */
434         deflateEnd(&ctx->zout);
435         OPENSSL_free(ctx->obuf);
436     }
437     OPENSSL_free(ctx);
438     BIO_set_data(bi, NULL);
439     BIO_set_init(bi, 0);
440 
441     return 1;
442 }
443 
bio_zlib_read(BIO * b,char * out,int outl)444 static int bio_zlib_read(BIO *b, char *out, int outl)
445 {
446     BIO_ZLIB_CTX *ctx;
447     int ret;
448     z_stream *zin;
449     BIO *next = BIO_next(b);
450 
451     if (!out || !outl)
452         return 0;
453     ctx = BIO_get_data(b);
454     zin = &ctx->zin;
455     BIO_clear_retry_flags(b);
456     if (!ctx->ibuf) {
457         ctx->ibuf = OPENSSL_malloc(ctx->ibufsize);
458         if (ctx->ibuf == NULL)
459             return 0;
460         if ((ret = inflateInit(zin)) != Z_OK) {
461             ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_INFLATE_ERROR,
462                 "zlib error: %s", zError(ret));
463             return 0;
464         }
465         zin->next_in = ctx->ibuf;
466         zin->avail_in = 0;
467     }
468 
469     /* Copy output data directly to supplied buffer */
470     zin->next_out = (unsigned char *)out;
471     zin->avail_out = (unsigned int)outl;
472     for (;;) {
473         /* Decompress while data available */
474         while (zin->avail_in) {
475             ret = inflate(zin, 0);
476             if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
477                 ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_INFLATE_ERROR,
478                     "zlib error: %s", zError(ret));
479                 return 0;
480             }
481             /* If EOF or we've read everything then return */
482             if ((ret == Z_STREAM_END) || !zin->avail_out)
483                 return outl - zin->avail_out;
484         }
485 
486         /*
487          * No data in input buffer try to read some in, if an error then
488          * return the total data read.
489          */
490         ret = BIO_read(next, ctx->ibuf, ctx->ibufsize);
491         if (ret <= 0) {
492             /* Total data read */
493             int tot = outl - zin->avail_out;
494             BIO_copy_next_retry(b);
495             if (ret < 0)
496                 return (tot > 0) ? tot : ret;
497             return tot;
498         }
499         zin->avail_in = ret;
500         zin->next_in = ctx->ibuf;
501     }
502 }
503 
bio_zlib_write(BIO * b,const char * in,int inl)504 static int bio_zlib_write(BIO *b, const char *in, int inl)
505 {
506     BIO_ZLIB_CTX *ctx;
507     int ret;
508     z_stream *zout;
509     BIO *next = BIO_next(b);
510 
511     if (!in || !inl)
512         return 0;
513     ctx = BIO_get_data(b);
514     if (ctx->odone)
515         return 0;
516     zout = &ctx->zout;
517     BIO_clear_retry_flags(b);
518     if (!ctx->obuf) {
519         ctx->obuf = OPENSSL_malloc(ctx->obufsize);
520         /* Need error here */
521         if (ctx->obuf == NULL)
522             return 0;
523         ctx->optr = ctx->obuf;
524         ctx->ocount = 0;
525         if ((ret = deflateInit(zout, ctx->comp_level)) != Z_OK) {
526             ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR,
527                 "zlib error: %s", zError(ret));
528             return 0;
529         }
530         zout->next_out = ctx->obuf;
531         zout->avail_out = ctx->obufsize;
532     }
533     /* Obtain input data directly from supplied buffer */
534     zout->next_in = (void *)in;
535     zout->avail_in = inl;
536     for (;;) {
537         /* If data in output buffer write it first */
538         while (ctx->ocount) {
539             ret = BIO_write(next, ctx->optr, ctx->ocount);
540             if (ret <= 0) {
541                 /* Total data written */
542                 int tot = inl - zout->avail_in;
543                 BIO_copy_next_retry(b);
544                 if (ret < 0)
545                     return (tot > 0) ? tot : ret;
546                 return tot;
547             }
548             ctx->optr += ret;
549             ctx->ocount -= ret;
550         }
551 
552         /* Have we consumed all supplied data? */
553         if (!zout->avail_in)
554             return inl;
555 
556         /* Compress some more */
557 
558         /* Reset buffer */
559         ctx->optr = ctx->obuf;
560         zout->next_out = ctx->obuf;
561         zout->avail_out = ctx->obufsize;
562         /* Compress some more */
563         ret = deflate(zout, 0);
564         if (ret != Z_OK) {
565             ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR,
566                 "zlib error: %s", zError(ret));
567             return 0;
568         }
569         ctx->ocount = ctx->obufsize - zout->avail_out;
570     }
571 }
572 
bio_zlib_flush(BIO * b)573 static int bio_zlib_flush(BIO *b)
574 {
575     BIO_ZLIB_CTX *ctx;
576     int ret;
577     z_stream *zout;
578     BIO *next = BIO_next(b);
579 
580     ctx = BIO_get_data(b);
581     /* If no data written or already flush show success */
582     if (!ctx->obuf || (ctx->odone && !ctx->ocount))
583         return 1;
584     zout = &ctx->zout;
585     BIO_clear_retry_flags(b);
586     /* No more input data */
587     zout->next_in = NULL;
588     zout->avail_in = 0;
589     for (;;) {
590         /* If data in output buffer write it first */
591         while (ctx->ocount) {
592             ret = BIO_write(next, ctx->optr, ctx->ocount);
593             if (ret <= 0) {
594                 BIO_copy_next_retry(b);
595                 return ret;
596             }
597             ctx->optr += ret;
598             ctx->ocount -= ret;
599         }
600         if (ctx->odone)
601             return 1;
602 
603         /* Compress some more */
604 
605         /* Reset buffer */
606         ctx->optr = ctx->obuf;
607         zout->next_out = ctx->obuf;
608         zout->avail_out = ctx->obufsize;
609         /* Compress some more */
610         ret = deflate(zout, Z_FINISH);
611         if (ret == Z_STREAM_END)
612             ctx->odone = 1;
613         else if (ret != Z_OK) {
614             ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR,
615                 "zlib error: %s", zError(ret));
616             return 0;
617         }
618         ctx->ocount = ctx->obufsize - zout->avail_out;
619     }
620 }
621 
bio_zlib_ctrl(BIO * b,int cmd,long num,void * ptr)622 static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr)
623 {
624     BIO_ZLIB_CTX *ctx;
625     int ret, *ip;
626     int ibs, obs;
627     BIO *next = BIO_next(b);
628 
629     if (next == NULL)
630         return 0;
631     ctx = BIO_get_data(b);
632     switch (cmd) {
633 
634     case BIO_CTRL_RESET:
635         ctx->ocount = 0;
636         ctx->odone = 0;
637         ret = 1;
638         break;
639 
640     case BIO_CTRL_FLUSH:
641         ret = bio_zlib_flush(b);
642         if (ret > 0) {
643             ret = BIO_flush(next);
644             BIO_copy_next_retry(b);
645         }
646         break;
647 
648     case BIO_C_SET_BUFF_SIZE:
649         ibs = -1;
650         obs = -1;
651         if (ptr != NULL) {
652             ip = ptr;
653             if (*ip == 0)
654                 ibs = (int)num;
655             else
656                 obs = (int)num;
657         } else {
658             ibs = (int)num;
659             obs = ibs;
660         }
661 
662         if (ibs != -1) {
663             OPENSSL_free(ctx->ibuf);
664             ctx->ibuf = NULL;
665             ctx->ibufsize = ibs;
666         }
667 
668         if (obs != -1) {
669             OPENSSL_free(ctx->obuf);
670             ctx->obuf = NULL;
671             ctx->obufsize = obs;
672         }
673         ret = 1;
674         break;
675 
676     case BIO_C_DO_STATE_MACHINE:
677         BIO_clear_retry_flags(b);
678         ret = BIO_ctrl(next, cmd, num, ptr);
679         BIO_copy_next_retry(b);
680         break;
681 
682     case BIO_CTRL_WPENDING:
683         if (ctx->obuf == NULL)
684             return 0;
685 
686         if (ctx->odone) {
687             ret = ctx->ocount;
688         } else {
689             ret = ctx->ocount;
690             if (ret == 0)
691                 /* Unknown amount pending but we are not finished */
692                 ret = 1;
693         }
694         if (ret == 0)
695             ret = BIO_ctrl(next, cmd, num, ptr);
696         break;
697 
698     case BIO_CTRL_PENDING:
699         ret = ctx->zin.avail_in;
700         if (ret == 0)
701             ret = BIO_ctrl(next, cmd, num, ptr);
702         break;
703 
704     default:
705         ret = BIO_ctrl(next, cmd, num, ptr);
706         break;
707     }
708 
709     return ret;
710 }
711 
bio_zlib_callback_ctrl(BIO * b,int cmd,BIO_info_cb * fp)712 static long bio_zlib_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
713 {
714     BIO *next = BIO_next(b);
715 
716     if (next == NULL)
717         return 0;
718     return BIO_callback_ctrl(next, cmd, fp);
719 }
720 
721 #endif
722