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);
108static compress_ft	p_compress=NULL;
109static inflateEnd_ft	p_inflateEnd=NULL;
110static inflate_ft	p_inflate=NULL;
111static inflateInit__ft	p_inflateInit_=NULL;
112static deflateEnd_ft	p_deflateEnd=NULL;
113static deflate_ft	p_deflate=NULL;
114static deflateInit__ft	p_deflateInit_=NULL;
115
116static int zlib_loaded = 0;     /* only attempt to init func pts once */
117static DSO *zlib_dso = NULL;
118
119#define compress                p_compress
120#define inflateEnd              p_inflateEnd
121#define inflate                 p_inflate
122#define inflateInit_            p_inflateInit_
123#define deflateEnd              p_deflateEnd
124#define deflate                 p_deflate
125#define deflateInit_            p_deflateInit_
126#endif /* ZLIB_SHARED */
127
128struct zlib_state
129	{
130	z_stream istream;
131	z_stream ostream;
132	};
133
134static int zlib_stateful_ex_idx = -1;
135
136static void zlib_stateful_free_ex_data(void *obj, void *item,
137	CRYPTO_EX_DATA *ad, int ind,long argl, void *argp)
138	{
139	struct zlib_state *state = (struct zlib_state *)item;
140	inflateEnd(&state->istream);
141	deflateEnd(&state->ostream);
142	OPENSSL_free(state);
143	}
144
145static int zlib_stateful_init(COMP_CTX *ctx)
146	{
147	int err;
148	struct zlib_state *state =
149		(struct zlib_state *)OPENSSL_malloc(sizeof(struct zlib_state));
150
151	if (state == NULL)
152		goto err;
153
154	state->istream.zalloc = zlib_zalloc;
155	state->istream.zfree = zlib_zfree;
156	state->istream.opaque = Z_NULL;
157	state->istream.next_in = Z_NULL;
158	state->istream.next_out = Z_NULL;
159	state->istream.avail_in = 0;
160	state->istream.avail_out = 0;
161	err = inflateInit_(&state->istream,
162		ZLIB_VERSION, sizeof(z_stream));
163	if (err != Z_OK)
164		goto err;
165
166	state->ostream.zalloc = zlib_zalloc;
167	state->ostream.zfree = zlib_zfree;
168	state->ostream.opaque = Z_NULL;
169	state->ostream.next_in = Z_NULL;
170	state->ostream.next_out = Z_NULL;
171	state->ostream.avail_in = 0;
172	state->ostream.avail_out = 0;
173	err = deflateInit_(&state->ostream,Z_DEFAULT_COMPRESSION,
174		ZLIB_VERSION, sizeof(z_stream));
175	if (err != Z_OK)
176		goto err;
177
178	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
179	CRYPTO_set_ex_data(&ctx->ex_data,zlib_stateful_ex_idx,state);
180	return 1;
181 err:
182	if (state) OPENSSL_free(state);
183	return 0;
184	}
185
186static void zlib_stateful_finish(COMP_CTX *ctx)
187	{
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
377			if (p_compress && p_inflateEnd && p_inflate
378				&& p_inflateInit_ && p_deflateEnd
379				&& p_deflate && p_deflateInit_)
380				zlib_loaded++;
381			}
382		}
383
384#endif
385#ifdef ZLIB_SHARED
386	if (zlib_loaded)
387#endif
388#if defined(ZLIB) || defined(ZLIB_SHARED)
389		{
390		/* init zlib_stateful_ex_idx here so that in a multi-process
391		 * application it's enough to intialize openssl before forking
392		 * (idx will be inherited in all the children) */
393		if (zlib_stateful_ex_idx == -1)
394			{
395			CRYPTO_w_lock(CRYPTO_LOCK_COMP);
396			if (zlib_stateful_ex_idx == -1)
397				zlib_stateful_ex_idx =
398					CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_COMP,
399						0,NULL,NULL,NULL,zlib_stateful_free_ex_data);
400			CRYPTO_w_unlock(CRYPTO_LOCK_COMP);
401			if (zlib_stateful_ex_idx == -1)
402				goto err;
403			}
404
405		meth = &zlib_stateful_method;
406		}
407err:
408#endif
409
410	return(meth);
411	}
412
413