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