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#if 0
35static int zlib_compress_block(COMP_CTX *ctx, unsigned char *out,
36	unsigned int olen, unsigned char *in, unsigned int ilen);
37static int zlib_expand_block(COMP_CTX *ctx, unsigned char *out,
38	unsigned int olen, unsigned char *in, unsigned int ilen);
39
40static int zz_uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
41	uLong sourceLen);
42
43static COMP_METHOD zlib_stateless_method={
44	NID_zlib_compression,
45	LN_zlib_compression,
46	NULL,
47	NULL,
48	zlib_compress_block,
49	zlib_expand_block,
50	NULL,
51	NULL,
52	};
53#endif
54
55static COMP_METHOD zlib_stateful_method={
56	NID_zlib_compression,
57	LN_zlib_compression,
58	zlib_stateful_init,
59	zlib_stateful_finish,
60	zlib_stateful_compress_block,
61	zlib_stateful_expand_block,
62	NULL,
63	NULL,
64	};
65
66/*
67 * When OpenSSL is built on Windows, we do not want to require that
68 * the ZLIB.DLL be available in order for the OpenSSL DLLs to
69 * work.  Therefore, all ZLIB routines are loaded at run time
70 * and we do not link to a .LIB file.
71 */
72#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
73# include <windows.h>
74
75# define Z_CALLCONV _stdcall
76# ifndef ZLIB_SHARED
77#  define ZLIB_SHARED
78# endif
79#else
80# define Z_CALLCONV
81#endif /* !(OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32) */
82
83#ifdef ZLIB_SHARED
84#include <openssl/dso.h>
85
86/* Prototypes for built in stubs */
87#if 0
88static int stub_compress(Bytef *dest,uLongf *destLen,
89	const Bytef *source, uLong sourceLen);
90#endif
91static int stub_inflateEnd(z_streamp strm);
92static int stub_inflate(z_streamp strm, int flush);
93static int stub_inflateInit_(z_streamp strm, const char * version,
94	int stream_size);
95static int stub_deflateEnd(z_streamp strm);
96static int stub_deflate(z_streamp strm, int flush);
97static int stub_deflateInit_(z_streamp strm, int level,
98	const char * version, int stream_size);
99
100/* Function pointers */
101typedef int (Z_CALLCONV *compress_ft)(Bytef *dest,uLongf *destLen,
102	const Bytef *source, uLong sourceLen);
103typedef int (Z_CALLCONV *inflateEnd_ft)(z_streamp strm);
104typedef int (Z_CALLCONV *inflate_ft)(z_streamp strm, int flush);
105typedef int (Z_CALLCONV *inflateInit__ft)(z_streamp strm,
106	const char * version, int stream_size);
107typedef int (Z_CALLCONV *deflateEnd_ft)(z_streamp strm);
108typedef int (Z_CALLCONV *deflate_ft)(z_streamp strm, int flush);
109typedef int (Z_CALLCONV *deflateInit__ft)(z_streamp strm, int level,
110	const char * version, int stream_size);
111static compress_ft	p_compress=NULL;
112static inflateEnd_ft	p_inflateEnd=NULL;
113static inflate_ft	p_inflate=NULL;
114static inflateInit__ft	p_inflateInit_=NULL;
115static deflateEnd_ft	p_deflateEnd=NULL;
116static deflate_ft	p_deflate=NULL;
117static deflateInit__ft	p_deflateInit_=NULL;
118
119static int zlib_loaded = 0;     /* only attempt to init func pts once */
120static DSO *zlib_dso = NULL;
121
122#define compress                stub_compress
123#define inflateEnd              stub_inflateEnd
124#define inflate                 stub_inflate
125#define inflateInit_            stub_inflateInit_
126#define deflateEnd              stub_deflateEnd
127#define deflate                 stub_deflate
128#define deflateInit_            stub_deflateInit_
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 void zlib_stateful_free_ex_data(void *obj, void *item,
140	CRYPTO_EX_DATA *ad, int ind,long argl, void *argp)
141	{
142	struct zlib_state *state = (struct zlib_state *)item;
143	inflateEnd(&state->istream);
144	deflateEnd(&state->ostream);
145	OPENSSL_free(state);
146	}
147
148static int zlib_stateful_init(COMP_CTX *ctx)
149	{
150	int err;
151	struct zlib_state *state =
152		(struct zlib_state *)OPENSSL_malloc(sizeof(struct zlib_state));
153
154	if (state == NULL)
155		goto err;
156
157	state->istream.zalloc = Z_NULL;
158	state->istream.zfree = Z_NULL;
159	state->istream.opaque = Z_NULL;
160	state->istream.next_in = Z_NULL;
161	state->istream.next_out = Z_NULL;
162	state->istream.avail_in = 0;
163	state->istream.avail_out = 0;
164	err = inflateInit_(&state->istream,
165		ZLIB_VERSION, sizeof(z_stream));
166	if (err != Z_OK)
167		goto err;
168
169	state->ostream.zalloc = Z_NULL;
170	state->ostream.zfree = Z_NULL;
171	state->ostream.opaque = Z_NULL;
172	state->ostream.next_in = Z_NULL;
173	state->ostream.next_out = Z_NULL;
174	state->ostream.avail_in = 0;
175	state->ostream.avail_out = 0;
176	err = deflateInit_(&state->ostream,Z_DEFAULT_COMPRESSION,
177		ZLIB_VERSION, sizeof(z_stream));
178	if (err != Z_OK)
179		goto err;
180
181	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
182	if (zlib_stateful_ex_idx == -1)
183		{
184		CRYPTO_w_lock(CRYPTO_LOCK_COMP);
185		if (zlib_stateful_ex_idx == -1)
186			zlib_stateful_ex_idx =
187				CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_COMP,
188					0,NULL,NULL,NULL,zlib_stateful_free_ex_data);
189		CRYPTO_w_unlock(CRYPTO_LOCK_COMP);
190		if (zlib_stateful_ex_idx == -1)
191			goto err;
192		}
193	CRYPTO_set_ex_data(&ctx->ex_data,zlib_stateful_ex_idx,state);
194	return 1;
195 err:
196	if (state) OPENSSL_free(state);
197	return 0;
198	}
199
200static void zlib_stateful_finish(COMP_CTX *ctx)
201	{
202	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
203	}
204
205static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
206	unsigned int olen, unsigned char *in, unsigned int ilen)
207	{
208	int err = Z_OK;
209	struct zlib_state *state =
210		(struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
211			zlib_stateful_ex_idx);
212
213	if (state == NULL)
214		return -1;
215
216	state->ostream.next_in = in;
217	state->ostream.avail_in = ilen;
218	state->ostream.next_out = out;
219	state->ostream.avail_out = olen;
220	if (ilen > 0)
221		err = deflate(&state->ostream, Z_SYNC_FLUSH);
222	if (err != Z_OK)
223		return -1;
224#ifdef DEBUG_ZLIB
225	fprintf(stderr,"compress(%4d)->%4d %s\n",
226		ilen,olen - state->ostream.avail_out,
227		(ilen != olen - state->ostream.avail_out)?"zlib":"clear");
228#endif
229	return olen - state->ostream.avail_out;
230	}
231
232static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
233	unsigned int olen, unsigned char *in, unsigned int ilen)
234	{
235	int err = Z_OK;
236
237	struct zlib_state *state =
238		(struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
239			zlib_stateful_ex_idx);
240
241	if (state == NULL)
242		return 0;
243
244	state->istream.next_in = in;
245	state->istream.avail_in = ilen;
246	state->istream.next_out = out;
247	state->istream.avail_out = olen;
248	if (ilen > 0)
249		err = inflate(&state->istream, Z_SYNC_FLUSH);
250	if (err != Z_OK)
251		return -1;
252#ifdef DEBUG_ZLIB
253	fprintf(stderr,"expand(%4d)->%4d %s\n",
254		ilen,olen - state->istream.avail_out,
255		(ilen != olen - state->istream.avail_out)?"zlib":"clear");
256#endif
257	return olen - state->istream.avail_out;
258	}
259
260#if 0
261static int zlib_compress_block(COMP_CTX *ctx, unsigned char *out,
262	unsigned int olen, unsigned char *in, unsigned int ilen)
263	{
264	unsigned long l;
265	int i;
266	int clear=1;
267
268	if (ilen > 128)
269		{
270		out[0]=1;
271		l=olen-1;
272		i=compress(&(out[1]),&l,in,(unsigned long)ilen);
273		if (i != Z_OK)
274			return(-1);
275		if (ilen > l)
276			{
277			clear=0;
278			l++;
279			}
280		}
281	if (clear)
282		{
283		out[0]=0;
284		memcpy(&(out[1]),in,ilen);
285		l=ilen+1;
286		}
287#ifdef DEBUG_ZLIB
288	fprintf(stderr,"compress(%4d)->%4d %s\n",
289		ilen,(int)l,(clear)?"clear":"zlib");
290#endif
291	return((int)l);
292	}
293
294static int zlib_expand_block(COMP_CTX *ctx, unsigned char *out,
295	unsigned int olen, unsigned char *in, unsigned int ilen)
296	{
297	unsigned long l;
298	int i;
299
300	if (in[0])
301		{
302		l=olen;
303		i=zz_uncompress(out,&l,&(in[1]),(unsigned long)ilen-1);
304		if (i != Z_OK)
305			return(-1);
306		}
307	else
308		{
309		memcpy(out,&(in[1]),ilen-1);
310		l=ilen-1;
311		}
312#ifdef DEBUG_ZLIB
313        fprintf(stderr,"expand  (%4d)->%4d %s\n",
314		ilen,(int)l,in[0]?"zlib":"clear");
315#endif
316	return((int)l);
317	}
318
319static int zz_uncompress (Bytef *dest, uLongf *destLen, const Bytef *source,
320	     uLong sourceLen)
321{
322    z_stream stream;
323    int err;
324
325    stream.next_in = (Bytef*)source;
326    stream.avail_in = (uInt)sourceLen;
327    /* Check for source > 64K on 16-bit machine: */
328    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
329
330    stream.next_out = dest;
331    stream.avail_out = (uInt)*destLen;
332    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
333
334    stream.zalloc = (alloc_func)0;
335    stream.zfree = (free_func)0;
336
337    err = inflateInit_(&stream,
338	    ZLIB_VERSION, sizeof(z_stream));
339    if (err != Z_OK) return err;
340
341    err = inflate(&stream, Z_FINISH);
342    if (err != Z_STREAM_END) {
343        inflateEnd(&stream);
344        return err;
345    }
346    *destLen = stream.total_out;
347
348    err = inflateEnd(&stream);
349    return err;
350}
351#endif
352
353#endif
354
355COMP_METHOD *COMP_zlib(void)
356	{
357	COMP_METHOD *meth = &zlib_method_nozlib;
358
359#ifdef ZLIB_SHARED
360	if (!zlib_loaded)
361		{
362#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
363		zlib_dso = DSO_load(NULL, "ZLIB1", NULL, 0);
364		if (!zlib_dso)
365			{
366			zlib_dso = DSO_load(NULL, "ZLIB", NULL, 0);
367			if (zlib_dso)
368				{
369				/* Clear the errors from the first failed
370				   DSO_load() */
371				ERR_clear_error();
372				}
373			}
374#else
375		zlib_dso = DSO_load(NULL, "z", NULL, 0);
376#endif
377		if (zlib_dso != NULL)
378			{
379			p_compress
380				= (compress_ft) DSO_bind_func(zlib_dso,
381					"compress");
382			p_inflateEnd
383				= (inflateEnd_ft) DSO_bind_func(zlib_dso,
384					"inflateEnd");
385			p_inflate
386				= (inflate_ft) DSO_bind_func(zlib_dso,
387					"inflate");
388			p_inflateInit_
389				= (inflateInit__ft) DSO_bind_func(zlib_dso,
390					"inflateInit_");
391			p_deflateEnd
392				= (deflateEnd_ft) DSO_bind_func(zlib_dso,
393					"deflateEnd");
394			p_deflate
395				= (deflate_ft) DSO_bind_func(zlib_dso,
396					"deflate");
397			p_deflateInit_
398				= (deflateInit__ft) DSO_bind_func(zlib_dso,
399					"deflateInit_");
400			zlib_loaded++;
401			}
402		}
403
404#endif
405#if defined(ZLIB) || defined(ZLIB_SHARED)
406	meth = &zlib_stateful_method;
407#endif
408
409	return(meth);
410	}
411
412#ifdef ZLIB_SHARED
413#if 0
414/* Stubs for each function to be dynamicly loaded */
415static int
416stub_compress(Bytef *dest,uLongf *destLen,const Bytef *source, uLong sourceLen)
417	{
418	if (p_compress)
419		return(p_compress(dest,destLen,source,sourceLen));
420	else
421		return(Z_MEM_ERROR);
422	}
423#endif
424
425static int
426stub_inflateEnd(z_streamp strm)
427	{
428	if ( p_inflateEnd )
429		return(p_inflateEnd(strm));
430	else
431		return(Z_MEM_ERROR);
432	}
433
434static int
435stub_inflate(z_streamp strm, int flush)
436	{
437	if ( p_inflate )
438		return(p_inflate(strm,flush));
439	else
440		return(Z_MEM_ERROR);
441	}
442
443static int
444stub_inflateInit_(z_streamp strm, const char * version, int stream_size)
445	{
446	if ( p_inflateInit_ )
447		return(p_inflateInit_(strm,version,stream_size));
448	else
449		return(Z_MEM_ERROR);
450	}
451
452static int
453stub_deflateEnd(z_streamp strm)
454	{
455	if ( p_deflateEnd )
456		return(p_deflateEnd(strm));
457	else
458		return(Z_MEM_ERROR);
459	}
460
461static int
462stub_deflate(z_streamp strm, int flush)
463	{
464	if ( p_deflate )
465		return(p_deflate(strm,flush));
466	else
467		return(Z_MEM_ERROR);
468	}
469
470static int
471stub_deflateInit_(z_streamp strm, int level,
472	const char * version, int stream_size)
473	{
474	if ( p_deflateInit_ )
475		return(p_deflateInit_(strm,level,version,stream_size));
476	else
477		return(Z_MEM_ERROR);
478	}
479
480#endif /* ZLIB_SHARED */
481