1/* $OpenBSD: xform_ipcomp.c,v 1.8 2019/01/09 12:11:38 mpi Exp $ */
2
3/*
4 * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj@wabbitt.org)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *   notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *   derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * This file contains a wrapper around the deflate algo compression
32 * functions using the zlib library
33 */
34
35#include <sys/param.h>
36#include <sys/malloc.h>
37#include <sys/systm.h>
38#include <lib/libz/zutil.h>
39
40#define Z_METHOD	8
41#define Z_MEMLEVEL	8
42#define ZBUF		10
43
44u_int32_t deflate_global(u_int8_t *, u_int32_t, int, u_int8_t **);
45
46struct deflate_buf {
47	u_int8_t *out;
48	u_int32_t size;
49	int flag;
50};
51
52int window_inflate = -1 * MAX_WBITS;
53int window_deflate = -12;
54
55/*
56 * This function takes a block of data and (de)compress it using the deflate
57 * algorithm
58 */
59
60u_int32_t
61deflate_global(u_int8_t *data, u_int32_t size, int decomp, u_int8_t **out)
62{
63	z_stream zbuf;
64	u_int8_t *output;
65	u_int32_t count, result;
66	int error, i = 0, j;
67	struct deflate_buf buf[ZBUF];
68
69	bzero(&zbuf, sizeof(z_stream));
70	for (j = 0; j < ZBUF; j++)
71		buf[j].flag = 0;
72
73	zbuf.next_in = data;	/* data that is going to be processed */
74	zbuf.zalloc = zcalloc;
75	zbuf.zfree = zcfree;
76	zbuf.opaque = Z_NULL;
77	zbuf.avail_in = size;	/* Total length of data to be processed */
78
79	if (decomp) {
80		/*
81	 	 * Choose a buffer with 4x the size of the input buffer
82	 	 * for the size of the output buffer in the case of
83	 	 * decompression. If it's not sufficient, it will need to be
84	 	 * updated while the decompression is going on
85	 	 */
86		if (size < 32 * 1024)
87			size *= 4;
88	}
89	buf[i].out = malloc((u_long)size, M_CRYPTO_DATA, M_NOWAIT);
90	if (buf[i].out == NULL)
91		goto bad;
92	buf[i].size = size;
93	buf[i].flag = 1;
94	i++;
95
96	zbuf.next_out = buf[0].out;
97	zbuf.avail_out = buf[0].size;
98
99	error = decomp ?
100	    inflateInit2(&zbuf, window_inflate) :
101	    deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD,
102	    window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY);
103
104	if (error != Z_OK)
105		goto bad;
106	for (;;) {
107		error = decomp ?
108		    inflate(&zbuf, Z_PARTIAL_FLUSH) :
109		    deflate(&zbuf, Z_FINISH);
110		if (error == Z_STREAM_END)
111			break;
112		if (error != Z_OK)
113			goto bad;
114		if (zbuf.avail_out == 0 && i < (ZBUF - 1)) {
115			/* we need more output space, allocate size */
116			if (size < 32 * 1024)
117				size *= 2;
118			buf[i].out = malloc((u_long)size, M_CRYPTO_DATA,
119			    M_NOWAIT);
120			if (buf[i].out == NULL)
121				goto bad;
122			zbuf.next_out = buf[i].out;
123			buf[i].size = size;
124			buf[i].flag = 1;
125			zbuf.avail_out = buf[i].size;
126			i++;
127		} else
128			goto bad;	/* out of buffers */
129	}
130	result = count = zbuf.total_out;
131
132	*out = malloc((u_long)result, M_CRYPTO_DATA, M_NOWAIT);
133	if (*out == NULL)
134		goto bad;
135	if (decomp)
136		inflateEnd(&zbuf);
137	else
138		deflateEnd(&zbuf);
139	output = *out;
140	for (j = 0; buf[j].flag != 0; j++) {
141		if (count > buf[j].size) {
142			bcopy(buf[j].out, *out, buf[j].size);
143			*out += buf[j].size;
144			free(buf[j].out, M_CRYPTO_DATA, buf[j].size);
145			count -= buf[j].size;
146		} else {
147			/* it should be the last buffer */
148			bcopy(buf[j].out, *out, count);
149			*out += count;
150			free(buf[j].out, M_CRYPTO_DATA, buf[j].size);
151			count = 0;
152		}
153	}
154	*out = output;
155	return result;
156
157bad:
158	*out = NULL;
159	for (j = 0; buf[j].flag != 0; j++)
160		free(buf[j].out, M_CRYPTO_DATA, buf[j].size);
161	if (decomp)
162		inflateEnd(&zbuf);
163	else
164		deflateEnd(&zbuf);
165	return 0;
166}
167