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