1221420Sdes/* $OpenBSD: compress.c,v 1.26 2010/09/08 04:13:31 deraadt Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 657429Smarkm * Interface to packet compression for ssh. 760573Skris * 865668Skris * As far as I am concerned, the code I have written for this software 965668Skris * can be used freely for any purpose. Any derived versions of this 1065668Skris * software must be clearly marked as such, and if the derived work is 1165668Skris * incompatible with the protocol description in the RFC file, it must be 1265668Skris * called by a name other than "ssh" or "Secure Shell". 1357429Smarkm */ 1457429Smarkm 1557429Smarkm#include "includes.h" 1657429Smarkm 17162852Sdes#include <sys/types.h> 18162852Sdes 19162852Sdes#include <stdarg.h> 20162852Sdes 2176259Sgreen#include "log.h" 2257429Smarkm#include "buffer.h" 2376259Sgreen#include "compress.h" 2457429Smarkm 25221420Sdes#include <zlib.h> 26221420Sdes 2798675Sdesz_stream incoming_stream; 2898675Sdesz_stream outgoing_stream; 2976259Sgreenstatic int compress_init_send_called = 0; 3076259Sgreenstatic int compress_init_recv_called = 0; 3198675Sdesstatic int inflate_failed = 0; 3298675Sdesstatic int deflate_failed = 0; 3357429Smarkm 3457429Smarkm/* 3557429Smarkm * Initializes compression; level is compression level from 1 to 9 3657429Smarkm * (as in gzip). 3757429Smarkm */ 3857429Smarkm 3960573Skrisvoid 4076259Sgreenbuffer_compress_init_send(int level) 4157429Smarkm{ 4276259Sgreen if (compress_init_send_called == 1) 4392555Sdes deflateEnd(&outgoing_stream); 4476259Sgreen compress_init_send_called = 1; 4557429Smarkm debug("Enabling compression at level %d.", level); 4657429Smarkm if (level < 1 || level > 9) 4757429Smarkm fatal("Bad compression level %d.", level); 4857429Smarkm deflateInit(&outgoing_stream, level); 4957429Smarkm} 5076259Sgreenvoid 5176259Sgreenbuffer_compress_init_recv(void) 5276259Sgreen{ 5376259Sgreen if (compress_init_recv_called == 1) 5476259Sgreen inflateEnd(&incoming_stream); 5576259Sgreen compress_init_recv_called = 1; 5676259Sgreen inflateInit(&incoming_stream); 5776259Sgreen} 5857429Smarkm 5957429Smarkm/* Frees any data structures allocated for compression. */ 6057429Smarkm 6160573Skrisvoid 6276259Sgreenbuffer_compress_uninit(void) 6357429Smarkm{ 64126274Sdes debug("compress outgoing: raw data %llu, compressed %llu, factor %.2f", 65126274Sdes (unsigned long long)outgoing_stream.total_in, 66126274Sdes (unsigned long long)outgoing_stream.total_out, 6792555Sdes outgoing_stream.total_in == 0 ? 0.0 : 6892555Sdes (double) outgoing_stream.total_out / outgoing_stream.total_in); 69126274Sdes debug("compress incoming: raw data %llu, compressed %llu, factor %.2f", 70126274Sdes (unsigned long long)incoming_stream.total_out, 71126274Sdes (unsigned long long)incoming_stream.total_in, 7292555Sdes incoming_stream.total_out == 0 ? 0.0 : 7392555Sdes (double) incoming_stream.total_in / incoming_stream.total_out); 7498675Sdes if (compress_init_recv_called == 1 && inflate_failed == 0) 7576259Sgreen inflateEnd(&incoming_stream); 7698675Sdes if (compress_init_send_called == 1 && deflate_failed == 0) 7776259Sgreen deflateEnd(&outgoing_stream); 7857429Smarkm} 7957429Smarkm 8057429Smarkm/* 8157429Smarkm * Compresses the contents of input_buffer into output_buffer. All packets 8257429Smarkm * compressed using this function will form a single compressed data stream; 8357429Smarkm * however, data will be flushed at the end of every call so that each 8457429Smarkm * output_buffer can be decompressed independently (but in the appropriate 8557429Smarkm * order since they together form a single compression stream) by the 8657429Smarkm * receiver. This appends the compressed data to the output buffer. 8757429Smarkm */ 8857429Smarkm 8960573Skrisvoid 9057429Smarkmbuffer_compress(Buffer * input_buffer, Buffer * output_buffer) 9157429Smarkm{ 9292555Sdes u_char buf[4096]; 9357429Smarkm int status; 9457429Smarkm 9557429Smarkm /* This case is not handled below. */ 9657429Smarkm if (buffer_len(input_buffer) == 0) 9757429Smarkm return; 9857429Smarkm 9957429Smarkm /* Input is the contents of the input buffer. */ 10092555Sdes outgoing_stream.next_in = buffer_ptr(input_buffer); 10157429Smarkm outgoing_stream.avail_in = buffer_len(input_buffer); 10257429Smarkm 10357429Smarkm /* Loop compressing until deflate() returns with avail_out != 0. */ 10457429Smarkm do { 10557429Smarkm /* Set up fixed-size output buffer. */ 10692555Sdes outgoing_stream.next_out = buf; 10757429Smarkm outgoing_stream.avail_out = sizeof(buf); 10857429Smarkm 10957429Smarkm /* Compress as much data into the buffer as possible. */ 11057429Smarkm status = deflate(&outgoing_stream, Z_PARTIAL_FLUSH); 11157429Smarkm switch (status) { 11257429Smarkm case Z_OK: 11357429Smarkm /* Append compressed data to output_buffer. */ 11457429Smarkm buffer_append(output_buffer, buf, 11560573Skris sizeof(buf) - outgoing_stream.avail_out); 11657429Smarkm break; 11757429Smarkm default: 11898675Sdes deflate_failed = 1; 11957429Smarkm fatal("buffer_compress: deflate returned %d", status); 12057429Smarkm /* NOTREACHED */ 12157429Smarkm } 12260573Skris } while (outgoing_stream.avail_out == 0); 12357429Smarkm} 12457429Smarkm 12557429Smarkm/* 12657429Smarkm * Uncompresses the contents of input_buffer into output_buffer. All packets 12757429Smarkm * uncompressed using this function will form a single compressed data 12857429Smarkm * stream; however, data will be flushed at the end of every call so that 12957429Smarkm * each output_buffer. This must be called for the same size units that the 13057429Smarkm * buffer_compress was called, and in the same order that buffers compressed 13157429Smarkm * with that. This appends the uncompressed data to the output buffer. 13257429Smarkm */ 13357429Smarkm 13460573Skrisvoid 13557429Smarkmbuffer_uncompress(Buffer * input_buffer, Buffer * output_buffer) 13657429Smarkm{ 13792555Sdes u_char buf[4096]; 13857429Smarkm int status; 13957429Smarkm 14092555Sdes incoming_stream.next_in = buffer_ptr(input_buffer); 14157429Smarkm incoming_stream.avail_in = buffer_len(input_buffer); 14257429Smarkm 14360573Skris for (;;) { 14460573Skris /* Set up fixed-size output buffer. */ 14592555Sdes incoming_stream.next_out = buf; 14660573Skris incoming_stream.avail_out = sizeof(buf); 14757429Smarkm 14857429Smarkm status = inflate(&incoming_stream, Z_PARTIAL_FLUSH); 14957429Smarkm switch (status) { 15057429Smarkm case Z_OK: 15157429Smarkm buffer_append(output_buffer, buf, 15260573Skris sizeof(buf) - incoming_stream.avail_out); 15357429Smarkm break; 15457429Smarkm case Z_BUF_ERROR: 15557429Smarkm /* 15657429Smarkm * Comments in zlib.h say that we should keep calling 15757429Smarkm * inflate() until we get an error. This appears to 15857429Smarkm * be the error that we get. 15957429Smarkm */ 16057429Smarkm return; 16157429Smarkm default: 16298675Sdes inflate_failed = 1; 16357429Smarkm fatal("buffer_uncompress: inflate returned %d", status); 16460573Skris /* NOTREACHED */ 16557429Smarkm } 16657429Smarkm } 16757429Smarkm} 168