The Zlib module now uses dynamically allocated contexts. I think
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 25 Oct 2002 13:26:33 +0000 (13:26 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Fri, 25 Oct 2002 13:26:33 +0000 (13:26 +0000)
that completes the static-removal in the crypto library. Ooh.

git-svn-id: svn://svn.tartarus.org/sgt/putty@2136 cda61777-01e9-0310-a592-d414129be87e

ssh.c
ssh.h
sshzlib.c

diff --git a/ssh.c b/ssh.c
index c936060..072a1b3 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -401,23 +401,27 @@ const static struct ssh_mac *buggymacs[] = {
     &ssh_sha1_buggy, &ssh_md5, &ssh_mac_none
 };
 
-static void ssh_comp_none_init(void)
+static void *ssh_comp_none_init(void)
+{
+    return NULL;
+}
+static void ssh_comp_none_cleanup(void *handle)
 {
 }
-static int ssh_comp_none_block(unsigned char *block, int len,
+static int ssh_comp_none_block(void *handle, unsigned char *block, int len,
                               unsigned char **outblock, int *outlen)
 {
     return 0;
 }
-static int ssh_comp_none_disable(void)
+static int ssh_comp_none_disable(void *handle)
 {
     return 0;
 }
 const static struct ssh_compress ssh_comp_none = {
     "none",
-    ssh_comp_none_init, ssh_comp_none_block,
-    ssh_comp_none_init, ssh_comp_none_block,
-    ssh_comp_none_disable
+    ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,
+    ssh_comp_none_init, ssh_comp_none_cleanup, ssh_comp_none_block,
+    ssh_comp_none_disable, NULL
 };
 extern const struct ssh_compress ssh_zlib;
 const static struct ssh_compress *compressions[] = {
@@ -566,6 +570,7 @@ struct ssh_tag {
     const struct ssh_mac *csmac, *scmac;
     void *cs_mac_ctx, *sc_mac_ctx;
     const struct ssh_compress *cscomp, *sccomp;
+    void *cs_comp_ctx, *sc_comp_ctx;
     const struct ssh_kex *kex;
     const struct ssh_signkey *hostkey;
     unsigned char v2_session_id[20];
@@ -832,7 +837,8 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
     if (ssh->v1_compressing) {
        unsigned char *decompblk;
        int decomplen;
-       zlib_decompress_block(ssh->pktin.body - 1, ssh->pktin.length + 1,
+       zlib_decompress_block(ssh->sc_comp_ctx,
+                             ssh->pktin.body - 1, ssh->pktin.length + 1,
                              &decompblk, &decomplen);
 
        if (ssh->pktin.maxlen < st->pad + decomplen) {
@@ -1006,7 +1012,8 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
        unsigned char *newpayload;
        int newlen;
        if (ssh->sccomp &&
-           ssh->sccomp->decompress(ssh->pktin.data + 5, ssh->pktin.length - 5,
+           ssh->sccomp->decompress(ssh->sc_comp_ctx,
+                                   ssh->pktin.data + 5, ssh->pktin.length - 5,
                                    &newpayload, &newlen)) {
            if (ssh->pktin.maxlen < newlen + 5) {
                ssh->pktin.maxlen = newlen + 5;
@@ -1171,7 +1178,8 @@ static int s_wrpkt_prepare(Ssh ssh)
     if (ssh->v1_compressing) {
        unsigned char *compblk;
        int complen;
-       zlib_compress_block(ssh->pktout.body - 1, ssh->pktout.length + 1,
+       zlib_compress_block(ssh->cs_comp_ctx,
+                           ssh->pktout.body - 1, ssh->pktout.length + 1,
                            &compblk, &complen);
        ssh1_pktout_size(ssh, complen - 1);
        memcpy(ssh->pktout.body - 1, compblk, complen);
@@ -1457,7 +1465,8 @@ static int ssh2_pkt_construct(Ssh ssh)
        unsigned char *newpayload;
        int newlen;
        if (ssh->cscomp &&
-           ssh->cscomp->compress(ssh->pktout.data + 5, ssh->pktout.length - 5,
+           ssh->cscomp->compress(ssh->cs_comp_ctx, ssh->pktout.data + 5,
+                                 ssh->pktout.length - 5,
                                  &newpayload, &newlen)) {
            ssh->pktout.length = 5;
            ssh2_pkt_adddata(ssh, newpayload, newlen);
@@ -3191,8 +3200,10 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
        }
        logevent("Started compression");
        ssh->v1_compressing = TRUE;
-       zlib_compress_init();
-       zlib_decompress_init();
+       ssh->cs_comp_ctx = zlib_compress_init();
+       logevent("Initialised zlib (RFC1950) compression");
+       ssh->sc_comp_ctx = zlib_decompress_init();
+       logevent("Initialised zlib (RFC1950) decompression");
     }
 
     /*
@@ -4064,10 +4075,16 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt)
     ssh->scmac = s->scmac_tobe;
     ssh->sc_mac_ctx = ssh->scmac->make_context();
 
+    if (ssh->cs_comp_ctx)
+       ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx);
     ssh->cscomp = s->cscomp_tobe;
+    ssh->cs_comp_ctx = ssh->cscomp->compress_init();
+
+    if (ssh->sc_comp_ctx)
+       ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx);
     ssh->sccomp = s->sccomp_tobe;
-    ssh->cscomp->compress_init();
-    ssh->sccomp->decompress_init();
+    ssh->sc_comp_ctx = ssh->sccomp->decompress_init();
+
     /*
      * Set IVs after keys. Here we use the exchange hash from the
      * _first_ key exchange.
@@ -4098,6 +4115,16 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt)
        sprintf(buf, "Initialised %.200s server->client encryption",
                ssh->sccipher->text_name);
        logevent(buf);
+       if (ssh->cscomp->text_name) {
+           sprintf(buf, "Initialised %.200s compression",
+                   ssh->cscomp->text_name);
+           logevent(buf);
+       }
+       if (ssh->sccomp->text_name) {
+           sprintf(buf, "Initialised %.200s decompression",
+                   ssh->sccomp->text_name);
+           logevent(buf);
+       }
     }
 
 
@@ -4926,7 +4953,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                         * bytes we should adjust our string length
                         * by.
                         */
-                       stringlen -= ssh->cscomp->disable_compression();
+                       stringlen -= 
+                           ssh->cscomp->disable_compression(ssh->cs_comp_ctx);
                    }
                    ssh2_pkt_init(ssh, SSH2_MSG_IGNORE);
                    ssh2_pkt_addstring_start(ssh);
@@ -5817,7 +5845,9 @@ static char *ssh_init(void *frontend_handle, void **backend_handle,
     ssh->scmac = NULL;
     ssh->sc_mac_ctx = NULL;
     ssh->cscomp = NULL;
+    ssh->cs_comp_ctx = NULL;
     ssh->sccomp = NULL;
+    ssh->sc_comp_ctx = NULL;
     ssh->kex = NULL;
     ssh->hostkey = NULL;
     ssh->exitcode = -1;
diff --git a/ssh.h b/ssh.h
index 9f9f1e6..ce58435 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -195,13 +195,16 @@ struct ssh_signkey {
 
 struct ssh_compress {
     char *name;
-    void (*compress_init) (void);
-    int (*compress) (unsigned char *block, int len,
+    void *(*compress_init) (void);
+    void (*compress_cleanup) (void *);
+    int (*compress) (void *, unsigned char *block, int len,
                     unsigned char **outblock, int *outlen);
-    void (*decompress_init) (void);
-    int (*decompress) (unsigned char *block, int len,
+    void *(*decompress_init) (void);
+    void (*decompress_cleanup) (void *);
+    int (*decompress) (void *, unsigned char *block, int len,
                       unsigned char **outblock, int *outlen);
-    int (*disable_compression) (void);
+    int (*disable_compression) (void *);
+    char *text_name;
 };
 
 struct ssh2_userkey {
@@ -359,11 +362,13 @@ Bignum primegen(int bits, int modulus, int residue, Bignum factor,
 /*
  * zlib compression.
  */
-void zlib_compress_init(void);
-void zlib_decompress_init(void);
-int zlib_compress_block(unsigned char *block, int len,
+void *zlib_compress_init(void);
+void zlib_compress_cleanup(void *);
+void *zlib_decompress_init(void);
+void zlib_decompress_cleanup(void *);
+int zlib_compress_block(void *, unsigned char *block, int len,
                        unsigned char **outblock, int *outlen);
-int zlib_decompress_block(unsigned char *block, int len,
+int zlib_decompress_block(void *, unsigned char *block, int len,
                          unsigned char **outblock, int *outlen);
 
 /*
index 91b29a0..ae60bb1 100644 (file)
--- a/sshzlib.c
+++ b/sshzlib.c
@@ -337,8 +337,6 @@ static void lz77_compress(struct LZ77Context *ctx,
  * having to transmit the trees.
  */
 
-static struct LZ77Context ectx;
-
 struct Outbuf {
     unsigned char *outbuf;
     int outlen, outsize;
@@ -582,21 +580,28 @@ static void zlib_match(struct LZ77Context *ectx, int distance, int len)
     }
 }
 
-void zlib_compress_init(void)
+void *zlib_compress_init(void)
 {
     struct Outbuf *out;
+    struct LZ77Context *ectx = smalloc(sizeof(struct LZ77Context));
 
-    lz77_init(&ectx);
-    ectx.literal = zlib_literal;
-    ectx.match = zlib_match;
+    lz77_init(ectx);
+    ectx->literal = zlib_literal;
+    ectx->match = zlib_match;
 
     out = smalloc(sizeof(struct Outbuf));
     out->outbits = out->noutbits = 0;
     out->firstblock = 1;
     out->comp_disabled = FALSE;
-    ectx.userdata = out;
+    ectx->userdata = out;
+
+    return ectx;
+}
 
-    logevent("Initialised zlib (RFC1950) compression");
+void zlib_compress_cleanup(void *handle)
+{
+    struct LZ77Context *ectx = (struct LZ77Context *)handle;
+    sfree(ectx->userdata);
 }
 
 /*
@@ -605,9 +610,10 @@ void zlib_compress_init(void)
  * length adjustment (which is only valid for packets < 65536
  * bytes, but that seems reasonable enough).
  */
-int zlib_disable_compression(void)
+int zlib_disable_compression(void *handle)
 {
-    struct Outbuf *out = (struct Outbuf *) ectx.userdata;
+    struct LZ77Context *ectx = (struct LZ77Context *)handle;
+    struct Outbuf *out = (struct Outbuf *) ectx->userdata;
     int n;
 
     out->comp_disabled = TRUE;
@@ -640,10 +646,11 @@ int zlib_disable_compression(void)
     return n;
 }
 
-int zlib_compress_block(unsigned char *block, int len,
+int zlib_compress_block(void *handle, unsigned char *block, int len,
                        unsigned char **outblock, int *outlen)
 {
-    struct Outbuf *out = (struct Outbuf *) ectx.userdata;
+    struct LZ77Context *ectx = (struct LZ77Context *)handle;
+    struct Outbuf *out = (struct Outbuf *) ectx->userdata;
     int in_block;
 
     out->outbuf = NULL;
@@ -702,7 +709,7 @@ int zlib_compress_block(unsigned char *block, int len,
             * zlib_literal which will spot out->comp_disabled and
             * emit in the uncompressed format.
             */
-           lz77_compress(&ectx, block, blen, FALSE);
+           lz77_compress(ectx, block, blen, FALSE);
 
            len -= blen;
            block += blen;
@@ -722,7 +729,7 @@ int zlib_compress_block(unsigned char *block, int len,
        /*
         * Do the compression.
         */
-       lz77_compress(&ectx, block, len, TRUE);
+       lz77_compress(ectx, block, len, TRUE);
 
        /*
         * End the block (by transmitting code 256, which is
@@ -910,7 +917,7 @@ static int zlib_freetable(struct zlib_table **ztab)
     return (0);
 }
 
-static struct zlib_decompress_ctx {
+struct zlib_decompress_ctx {
     struct zlib_table *staticlentable, *staticdisttable;
     struct zlib_table *currlentable, *currdisttable, *lenlentable;
     enum {
@@ -930,23 +937,40 @@ static struct zlib_decompress_ctx {
     int winpos;
     unsigned char *outblk;
     int outlen, outsize;
-} dctx;
+};
 
-void zlib_decompress_init(void)
+void *zlib_decompress_init(void)
 {
+    struct zlib_decompress_ctx *dctx =
+       smalloc(sizeof(struct zlib_decompress_ctx));
     unsigned char lengths[288];
+
     memset(lengths, 8, 144);
     memset(lengths + 144, 9, 256 - 144);
     memset(lengths + 256, 7, 280 - 256);
     memset(lengths + 280, 8, 288 - 280);
-    dctx.staticlentable = zlib_mktable(lengths, 288);
+    dctx->staticlentable = zlib_mktable(lengths, 288);
     memset(lengths, 5, 32);
-    dctx.staticdisttable = zlib_mktable(lengths, 32);
-    dctx.state = START;                       /* even before header */
-    dctx.currlentable = dctx.currdisttable = dctx.lenlentable = NULL;
-    dctx.bits = 0;
-    dctx.nbits = 0;
-    logevent("Initialised zlib (RFC1950) decompression");
+    dctx->staticdisttable = zlib_mktable(lengths, 32);
+    dctx->state = START;                      /* even before header */
+    dctx->currlentable = dctx->currdisttable = dctx->lenlentable = NULL;
+    dctx->bits = 0;
+    dctx->nbits = 0;
+
+    return dctx;
+}
+
+void zlib_decompress_cleanup(void *handle)
+{
+    struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle;
+    
+    if (dctx->currlentable && dctx->currlentable != dctx->staticlentable)
+       zlib_freetable(&dctx->currlentable);
+    if (dctx->currdisttable && dctx->currdisttable != dctx->staticdisttable)
+       zlib_freetable(&dctx->currdisttable);
+    if (dctx->lenlentable)
+       zlib_freetable(&dctx->lenlentable);
+    sfree(dctx);
 }
 
 int zlib_huflookup(unsigned long *bitsp, int *nbitsp,
@@ -971,62 +995,63 @@ int zlib_huflookup(unsigned long *bitsp, int *nbitsp,
     }
 }
 
-static void zlib_emit_char(int c)
+static void zlib_emit_char(struct zlib_decompress_ctx *dctx, int c)
 {
-    dctx.window[dctx.winpos] = c;
-    dctx.winpos = (dctx.winpos + 1) & (WINSIZE - 1);
-    if (dctx.outlen >= dctx.outsize) {
-       dctx.outsize = dctx.outlen + 512;
-       dctx.outblk = srealloc(dctx.outblk, dctx.outsize);
+    dctx->window[dctx->winpos] = c;
+    dctx->winpos = (dctx->winpos + 1) & (WINSIZE - 1);
+    if (dctx->outlen >= dctx->outsize) {
+       dctx->outsize = dctx->outlen + 512;
+       dctx->outblk = srealloc(dctx->outblk, dctx->outsize);
     }
-    dctx.outblk[dctx.outlen++] = c;
+    dctx->outblk[dctx->outlen++] = c;
 }
 
-#define EATBITS(n) ( dctx.nbits -= (n), dctx.bits >>= (n) )
+#define EATBITS(n) ( dctx->nbits -= (n), dctx->bits >>= (n) )
 
-int zlib_decompress_block(unsigned char *block, int len,
+int zlib_decompress_block(void *handle, unsigned char *block, int len,
                          unsigned char **outblock, int *outlen)
 {
+    struct zlib_decompress_ctx *dctx = (struct zlib_decompress_ctx *)handle;
     const coderecord *rec;
     int code, blktype, rep, dist, nlen;
     static const unsigned char lenlenmap[] = {
        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
     };
 
-    dctx.outblk = NULL;
-    dctx.outsize = dctx.outlen = 0;
+    dctx->outblk = NULL;
+    dctx->outsize = dctx->outlen = 0;
 
-    while (len > 0 || dctx.nbits > 0) {
-       while (dctx.nbits < 24 && len > 0) {
-           dctx.bits |= (*block++) << dctx.nbits;
-           dctx.nbits += 8;
+    while (len > 0 || dctx->nbits > 0) {
+       while (dctx->nbits < 24 && len > 0) {
+           dctx->bits |= (*block++) << dctx->nbits;
+           dctx->nbits += 8;
            len--;
        }
-       switch (dctx.state) {
+       switch (dctx->state) {
          case START:
            /* Expect 16-bit zlib header, which we'll dishonourably ignore. */
-           if (dctx.nbits < 16)
+           if (dctx->nbits < 16)
                goto finished;         /* done all we can */
            EATBITS(16);
-           dctx.state = OUTSIDEBLK;
+           dctx->state = OUTSIDEBLK;
            break;
          case OUTSIDEBLK:
            /* Expect 3-bit block header. */
-           if (dctx.nbits < 3)
+           if (dctx->nbits < 3)
                goto finished;         /* done all we can */
            EATBITS(1);
-           blktype = dctx.bits & 3;
+           blktype = dctx->bits & 3;
            EATBITS(2);
            if (blktype == 0) {
-               int to_eat = dctx.nbits & 7;
-               dctx.state = UNCOMP_LEN;
+               int to_eat = dctx->nbits & 7;
+               dctx->state = UNCOMP_LEN;
                EATBITS(to_eat);       /* align to byte boundary */
            } else if (blktype == 1) {
-               dctx.currlentable = dctx.staticlentable;
-               dctx.currdisttable = dctx.staticdisttable;
-               dctx.state = INBLK;
+               dctx->currlentable = dctx->staticlentable;
+               dctx->currdisttable = dctx->staticdisttable;
+               dctx->state = INBLK;
            } else if (blktype == 2) {
-               dctx.state = TREES_HDR;
+               dctx->state = TREES_HDR;
            }
            break;
          case TREES_HDR:
@@ -1034,125 +1059,130 @@ int zlib_decompress_block(unsigned char *block, int len,
             * Dynamic block header. Five bits of HLIT, five of
             * HDIST, four of HCLEN.
             */
-           if (dctx.nbits < 5 + 5 + 4)
+           if (dctx->nbits < 5 + 5 + 4)
                goto finished;         /* done all we can */
-           dctx.hlit = 257 + (dctx.bits & 31);
+           dctx->hlit = 257 + (dctx->bits & 31);
            EATBITS(5);
-           dctx.hdist = 1 + (dctx.bits & 31);
+           dctx->hdist = 1 + (dctx->bits & 31);
            EATBITS(5);
-           dctx.hclen = 4 + (dctx.bits & 15);
+           dctx->hclen = 4 + (dctx->bits & 15);
            EATBITS(4);
-           dctx.lenptr = 0;
-           dctx.state = TREES_LENLEN;
-           memset(dctx.lenlen, 0, sizeof(dctx.lenlen));
+           dctx->lenptr = 0;
+           dctx->state = TREES_LENLEN;
+           memset(dctx->lenlen, 0, sizeof(dctx->lenlen));
            break;
          case TREES_LENLEN:
-           if (dctx.nbits < 3)
+           if (dctx->nbits < 3)
                goto finished;
-           while (dctx.lenptr < dctx.hclen && dctx.nbits >= 3) {
-               dctx.lenlen[lenlenmap[dctx.lenptr++]] =
-                   (unsigned char) (dctx.bits & 7);
+           while (dctx->lenptr < dctx->hclen && dctx->nbits >= 3) {
+               dctx->lenlen[lenlenmap[dctx->lenptr++]] =
+                   (unsigned char) (dctx->bits & 7);
                EATBITS(3);
            }
-           if (dctx.lenptr == dctx.hclen) {
-               dctx.lenlentable = zlib_mktable(dctx.lenlen, 19);
-               dctx.state = TREES_LEN;
-               dctx.lenptr = 0;
+           if (dctx->lenptr == dctx->hclen) {
+               dctx->lenlentable = zlib_mktable(dctx->lenlen, 19);
+               dctx->state = TREES_LEN;
+               dctx->lenptr = 0;
            }
            break;
          case TREES_LEN:
-           if (dctx.lenptr >= dctx.hlit + dctx.hdist) {
-               dctx.currlentable = zlib_mktable(dctx.lengths, dctx.hlit);
-               dctx.currdisttable = zlib_mktable(dctx.lengths + dctx.hlit,
-                                                 dctx.hdist);
-               zlib_freetable(&dctx.lenlentable);
-               dctx.state = INBLK;
+           if (dctx->lenptr >= dctx->hlit + dctx->hdist) {
+               dctx->currlentable = zlib_mktable(dctx->lengths, dctx->hlit);
+               dctx->currdisttable = zlib_mktable(dctx->lengths + dctx->hlit,
+                                                 dctx->hdist);
+               zlib_freetable(&dctx->lenlentable);
+               dctx->lenlentable = NULL;
+               dctx->state = INBLK;
                break;
            }
            code =
-               zlib_huflookup(&dctx.bits, &dctx.nbits, dctx.lenlentable);
+               zlib_huflookup(&dctx->bits, &dctx->nbits, dctx->lenlentable);
            if (code == -1)
                goto finished;
            if (code < 16)
-               dctx.lengths[dctx.lenptr++] = code;
+               dctx->lengths[dctx->lenptr++] = code;
            else {
-               dctx.lenextrabits = (code == 16 ? 2 : code == 17 ? 3 : 7);
-               dctx.lenaddon = (code == 18 ? 11 : 3);
-               dctx.lenrep = (code == 16 && dctx.lenptr > 0 ?
-                              dctx.lengths[dctx.lenptr - 1] : 0);
-               dctx.state = TREES_LENREP;
+               dctx->lenextrabits = (code == 16 ? 2 : code == 17 ? 3 : 7);
+               dctx->lenaddon = (code == 18 ? 11 : 3);
+               dctx->lenrep = (code == 16 && dctx->lenptr > 0 ?
+                              dctx->lengths[dctx->lenptr - 1] : 0);
+               dctx->state = TREES_LENREP;
            }
            break;
          case TREES_LENREP:
-           if (dctx.nbits < dctx.lenextrabits)
+           if (dctx->nbits < dctx->lenextrabits)
                goto finished;
            rep =
-               dctx.lenaddon +
-               (dctx.bits & ((1 << dctx.lenextrabits) - 1));
-           EATBITS(dctx.lenextrabits);
-           while (rep > 0 && dctx.lenptr < dctx.hlit + dctx.hdist) {
-               dctx.lengths[dctx.lenptr] = dctx.lenrep;
-               dctx.lenptr++;
+               dctx->lenaddon +
+               (dctx->bits & ((1 << dctx->lenextrabits) - 1));
+           EATBITS(dctx->lenextrabits);
+           while (rep > 0 && dctx->lenptr < dctx->hlit + dctx->hdist) {
+               dctx->lengths[dctx->lenptr] = dctx->lenrep;
+               dctx->lenptr++;
                rep--;
            }
-           dctx.state = TREES_LEN;
+           dctx->state = TREES_LEN;
            break;
          case INBLK:
            code =
-               zlib_huflookup(&dctx.bits, &dctx.nbits, dctx.currlentable);
+               zlib_huflookup(&dctx->bits, &dctx->nbits, dctx->currlentable);
            if (code == -1)
                goto finished;
            if (code < 256)
-               zlib_emit_char(code);
+               zlib_emit_char(dctx, code);
            else if (code == 256) {
-               dctx.state = OUTSIDEBLK;
-               if (dctx.currlentable != dctx.staticlentable)
-                   zlib_freetable(&dctx.currlentable);
-               if (dctx.currdisttable != dctx.staticdisttable)
-                   zlib_freetable(&dctx.currdisttable);
+               dctx->state = OUTSIDEBLK;
+               if (dctx->currlentable != dctx->staticlentable) {
+                   zlib_freetable(&dctx->currlentable);
+                   dctx->currlentable = NULL;
+               }
+               if (dctx->currdisttable != dctx->staticdisttable) {
+                   zlib_freetable(&dctx->currdisttable);
+                   dctx->currdisttable = NULL;
+               }
            } else if (code < 286) {   /* static tree can give >285; ignore */
-               dctx.state = GOTLENSYM;
-               dctx.sym = code;
+               dctx->state = GOTLENSYM;
+               dctx->sym = code;
            }
            break;
          case GOTLENSYM:
-           rec = &lencodes[dctx.sym - 257];
-           if (dctx.nbits < rec->extrabits)
+           rec = &lencodes[dctx->sym - 257];
+           if (dctx->nbits < rec->extrabits)
                goto finished;
-           dctx.len =
-               rec->min + (dctx.bits & ((1 << rec->extrabits) - 1));
+           dctx->len =
+               rec->min + (dctx->bits & ((1 << rec->extrabits) - 1));
            EATBITS(rec->extrabits);
-           dctx.state = GOTLEN;
+           dctx->state = GOTLEN;
            break;
          case GOTLEN:
            code =
-               zlib_huflookup(&dctx.bits, &dctx.nbits,
-                              dctx.currdisttable);
+               zlib_huflookup(&dctx->bits, &dctx->nbits,
+                              dctx->currdisttable);
            if (code == -1)
                goto finished;
-           dctx.state = GOTDISTSYM;
-           dctx.sym = code;
+           dctx->state = GOTDISTSYM;
+           dctx->sym = code;
            break;
          case GOTDISTSYM:
-           rec = &distcodes[dctx.sym];
-           if (dctx.nbits < rec->extrabits)
+           rec = &distcodes[dctx->sym];
+           if (dctx->nbits < rec->extrabits)
                goto finished;
-           dist = rec->min + (dctx.bits & ((1 << rec->extrabits) - 1));
+           dist = rec->min + (dctx->bits & ((1 << rec->extrabits) - 1));
            EATBITS(rec->extrabits);
-           dctx.state = INBLK;
-           while (dctx.len--)
-               zlib_emit_char(dctx.window[(dctx.winpos - dist) &
-                                          (WINSIZE - 1)]);
+           dctx->state = INBLK;
+           while (dctx->len--)
+               zlib_emit_char(dctx, dctx->window[(dctx->winpos - dist) &
+                                                 (WINSIZE - 1)]);
            break;
          case UNCOMP_LEN:
            /*
             * Uncompressed block. We expect to see a 16-bit LEN.
             */
-           if (dctx.nbits < 16)
+           if (dctx->nbits < 16)
                goto finished;
-           dctx.uncomplen = dctx.bits & 0xFFFF;
+           dctx->uncomplen = dctx->bits & 0xFFFF;
            EATBITS(16);
-           dctx.state = UNCOMP_NLEN;
+           dctx->state = UNCOMP_NLEN;
            break;
          case UNCOMP_NLEN:
            /*
@@ -1160,29 +1190,29 @@ int zlib_decompress_block(unsigned char *block, int len,
             * which should be the one's complement of the previous
             * LEN.
             */
-           if (dctx.nbits < 16)
+           if (dctx->nbits < 16)
                goto finished;
-           nlen = dctx.bits & 0xFFFF;
+           nlen = dctx->bits & 0xFFFF;
            EATBITS(16);
-           if (dctx.uncomplen == 0)
-               dctx.state = OUTSIDEBLK;        /* block is empty */
+           if (dctx->uncomplen == 0)
+               dctx->state = OUTSIDEBLK;       /* block is empty */
            else
-               dctx.state = UNCOMP_DATA;
+               dctx->state = UNCOMP_DATA;
            break;
          case UNCOMP_DATA:
-           if (dctx.nbits < 8)
+           if (dctx->nbits < 8)
                goto finished;
-           zlib_emit_char(dctx.bits & 0xFF);
+           zlib_emit_char(dctx, dctx->bits & 0xFF);
            EATBITS(8);
-           if (--dctx.uncomplen == 0)
-               dctx.state = OUTSIDEBLK;        /* end of uncompressed block */
+           if (--dctx->uncomplen == 0)
+               dctx->state = OUTSIDEBLK;       /* end of uncompressed block */
            break;
        }
     }
 
   finished:
-    *outblock = dctx.outblk;
-    *outlen = dctx.outlen;
+    *outblock = dctx->outblk;
+    *outlen = dctx->outlen;
 
     return 1;
 }
@@ -1190,8 +1220,11 @@ int zlib_decompress_block(unsigned char *block, int len,
 const struct ssh_compress ssh_zlib = {
     "zlib",
     zlib_compress_init,
+    zlib_compress_cleanup,
     zlib_compress_block,
     zlib_decompress_init,
+    zlib_decompress_cleanup,
     zlib_decompress_block,
-    zlib_disable_compression
+    zlib_disable_compression,
+    "zlib (RFC1950)"
 };