xref: /dflybsd-src/crypto/libressl/crypto/bio/bf_buff.c (revision f5b1c8a1e6dbe9333aed363dba27c2ff58be6174)
1*f5b1c8a1SJohn Marino /* $OpenBSD: bf_buff.c,v 1.22 2015/07/19 01:18:17 beck Exp $ */
2*f5b1c8a1SJohn Marino /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3*f5b1c8a1SJohn Marino  * All rights reserved.
4*f5b1c8a1SJohn Marino  *
5*f5b1c8a1SJohn Marino  * This package is an SSL implementation written
6*f5b1c8a1SJohn Marino  * by Eric Young (eay@cryptsoft.com).
7*f5b1c8a1SJohn Marino  * The implementation was written so as to conform with Netscapes SSL.
8*f5b1c8a1SJohn Marino  *
9*f5b1c8a1SJohn Marino  * This library is free for commercial and non-commercial use as long as
10*f5b1c8a1SJohn Marino  * the following conditions are aheared to.  The following conditions
11*f5b1c8a1SJohn Marino  * apply to all code found in this distribution, be it the RC4, RSA,
12*f5b1c8a1SJohn Marino  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13*f5b1c8a1SJohn Marino  * included with this distribution is covered by the same copyright terms
14*f5b1c8a1SJohn Marino  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15*f5b1c8a1SJohn Marino  *
16*f5b1c8a1SJohn Marino  * Copyright remains Eric Young's, and as such any Copyright notices in
17*f5b1c8a1SJohn Marino  * the code are not to be removed.
18*f5b1c8a1SJohn Marino  * If this package is used in a product, Eric Young should be given attribution
19*f5b1c8a1SJohn Marino  * as the author of the parts of the library used.
20*f5b1c8a1SJohn Marino  * This can be in the form of a textual message at program startup or
21*f5b1c8a1SJohn Marino  * in documentation (online or textual) provided with the package.
22*f5b1c8a1SJohn Marino  *
23*f5b1c8a1SJohn Marino  * Redistribution and use in source and binary forms, with or without
24*f5b1c8a1SJohn Marino  * modification, are permitted provided that the following conditions
25*f5b1c8a1SJohn Marino  * are met:
26*f5b1c8a1SJohn Marino  * 1. Redistributions of source code must retain the copyright
27*f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer.
28*f5b1c8a1SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
29*f5b1c8a1SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
30*f5b1c8a1SJohn Marino  *    documentation and/or other materials provided with the distribution.
31*f5b1c8a1SJohn Marino  * 3. All advertising materials mentioning features or use of this software
32*f5b1c8a1SJohn Marino  *    must display the following acknowledgement:
33*f5b1c8a1SJohn Marino  *    "This product includes cryptographic software written by
34*f5b1c8a1SJohn Marino  *     Eric Young (eay@cryptsoft.com)"
35*f5b1c8a1SJohn Marino  *    The word 'cryptographic' can be left out if the rouines from the library
36*f5b1c8a1SJohn Marino  *    being used are not cryptographic related :-).
37*f5b1c8a1SJohn Marino  * 4. If you include any Windows specific code (or a derivative thereof) from
38*f5b1c8a1SJohn Marino  *    the apps directory (application code) you must include an acknowledgement:
39*f5b1c8a1SJohn Marino  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40*f5b1c8a1SJohn Marino  *
41*f5b1c8a1SJohn Marino  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42*f5b1c8a1SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43*f5b1c8a1SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44*f5b1c8a1SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45*f5b1c8a1SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46*f5b1c8a1SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47*f5b1c8a1SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48*f5b1c8a1SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49*f5b1c8a1SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50*f5b1c8a1SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51*f5b1c8a1SJohn Marino  * SUCH DAMAGE.
52*f5b1c8a1SJohn Marino  *
53*f5b1c8a1SJohn Marino  * The licence and distribution terms for any publically available version or
54*f5b1c8a1SJohn Marino  * derivative of this code cannot be changed.  i.e. this code cannot simply be
55*f5b1c8a1SJohn Marino  * copied and put under another distribution licence
56*f5b1c8a1SJohn Marino  * [including the GNU Public Licence.]
57*f5b1c8a1SJohn Marino  */
58*f5b1c8a1SJohn Marino 
59*f5b1c8a1SJohn Marino #include <errno.h>
60*f5b1c8a1SJohn Marino #include <stdio.h>
61*f5b1c8a1SJohn Marino #include <string.h>
62*f5b1c8a1SJohn Marino 
63*f5b1c8a1SJohn Marino #include <openssl/bio.h>
64*f5b1c8a1SJohn Marino #include <openssl/err.h>
65*f5b1c8a1SJohn Marino 
66*f5b1c8a1SJohn Marino static int buffer_write(BIO *h, const char *buf, int num);
67*f5b1c8a1SJohn Marino static int buffer_read(BIO *h, char *buf, int size);
68*f5b1c8a1SJohn Marino static int buffer_puts(BIO *h, const char *str);
69*f5b1c8a1SJohn Marino static int buffer_gets(BIO *h, char *str, int size);
70*f5b1c8a1SJohn Marino static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
71*f5b1c8a1SJohn Marino static int buffer_new(BIO *h);
72*f5b1c8a1SJohn Marino static int buffer_free(BIO *data);
73*f5b1c8a1SJohn Marino static long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
74*f5b1c8a1SJohn Marino #define DEFAULT_BUFFER_SIZE	4096
75*f5b1c8a1SJohn Marino 
76*f5b1c8a1SJohn Marino static BIO_METHOD methods_buffer = {
77*f5b1c8a1SJohn Marino 	.type = BIO_TYPE_BUFFER,
78*f5b1c8a1SJohn Marino 	.name = "buffer",
79*f5b1c8a1SJohn Marino 	.bwrite = buffer_write,
80*f5b1c8a1SJohn Marino 	.bread = buffer_read,
81*f5b1c8a1SJohn Marino 	.bputs = buffer_puts,
82*f5b1c8a1SJohn Marino 	.bgets = buffer_gets,
83*f5b1c8a1SJohn Marino 	.ctrl = buffer_ctrl,
84*f5b1c8a1SJohn Marino 	.create = buffer_new,
85*f5b1c8a1SJohn Marino 	.destroy = buffer_free,
86*f5b1c8a1SJohn Marino 	.callback_ctrl = buffer_callback_ctrl
87*f5b1c8a1SJohn Marino };
88*f5b1c8a1SJohn Marino 
89*f5b1c8a1SJohn Marino BIO_METHOD *
90*f5b1c8a1SJohn Marino BIO_f_buffer(void)
91*f5b1c8a1SJohn Marino {
92*f5b1c8a1SJohn Marino 	return (&methods_buffer);
93*f5b1c8a1SJohn Marino }
94*f5b1c8a1SJohn Marino 
95*f5b1c8a1SJohn Marino static int
96*f5b1c8a1SJohn Marino buffer_new(BIO *bi)
97*f5b1c8a1SJohn Marino {
98*f5b1c8a1SJohn Marino 	BIO_F_BUFFER_CTX *ctx;
99*f5b1c8a1SJohn Marino 
100*f5b1c8a1SJohn Marino 	ctx = malloc(sizeof(BIO_F_BUFFER_CTX));
101*f5b1c8a1SJohn Marino 	if (ctx == NULL)
102*f5b1c8a1SJohn Marino 		return (0);
103*f5b1c8a1SJohn Marino 	ctx->ibuf = malloc(DEFAULT_BUFFER_SIZE);
104*f5b1c8a1SJohn Marino 	if (ctx->ibuf == NULL) {
105*f5b1c8a1SJohn Marino 		free(ctx);
106*f5b1c8a1SJohn Marino 		return (0);
107*f5b1c8a1SJohn Marino 	}
108*f5b1c8a1SJohn Marino 	ctx->obuf = malloc(DEFAULT_BUFFER_SIZE);
109*f5b1c8a1SJohn Marino 	if (ctx->obuf == NULL) {
110*f5b1c8a1SJohn Marino 		free(ctx->ibuf);
111*f5b1c8a1SJohn Marino 		free(ctx);
112*f5b1c8a1SJohn Marino 		return (0);
113*f5b1c8a1SJohn Marino 	}
114*f5b1c8a1SJohn Marino 	ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
115*f5b1c8a1SJohn Marino 	ctx->obuf_size = DEFAULT_BUFFER_SIZE;
116*f5b1c8a1SJohn Marino 	ctx->ibuf_len = 0;
117*f5b1c8a1SJohn Marino 	ctx->ibuf_off = 0;
118*f5b1c8a1SJohn Marino 	ctx->obuf_len = 0;
119*f5b1c8a1SJohn Marino 	ctx->obuf_off = 0;
120*f5b1c8a1SJohn Marino 
121*f5b1c8a1SJohn Marino 	bi->init = 1;
122*f5b1c8a1SJohn Marino 	bi->ptr = (char *)ctx;
123*f5b1c8a1SJohn Marino 	bi->flags = 0;
124*f5b1c8a1SJohn Marino 	return (1);
125*f5b1c8a1SJohn Marino }
126*f5b1c8a1SJohn Marino 
127*f5b1c8a1SJohn Marino static int
128*f5b1c8a1SJohn Marino buffer_free(BIO *a)
129*f5b1c8a1SJohn Marino {
130*f5b1c8a1SJohn Marino 	BIO_F_BUFFER_CTX *b;
131*f5b1c8a1SJohn Marino 
132*f5b1c8a1SJohn Marino 	if (a == NULL)
133*f5b1c8a1SJohn Marino 		return (0);
134*f5b1c8a1SJohn Marino 	b = (BIO_F_BUFFER_CTX *)a->ptr;
135*f5b1c8a1SJohn Marino 	free(b->ibuf);
136*f5b1c8a1SJohn Marino 	free(b->obuf);
137*f5b1c8a1SJohn Marino 	free(a->ptr);
138*f5b1c8a1SJohn Marino 	a->ptr = NULL;
139*f5b1c8a1SJohn Marino 	a->init = 0;
140*f5b1c8a1SJohn Marino 	a->flags = 0;
141*f5b1c8a1SJohn Marino 	return (1);
142*f5b1c8a1SJohn Marino }
143*f5b1c8a1SJohn Marino 
144*f5b1c8a1SJohn Marino static int
145*f5b1c8a1SJohn Marino buffer_read(BIO *b, char *out, int outl)
146*f5b1c8a1SJohn Marino {
147*f5b1c8a1SJohn Marino 	int i, num = 0;
148*f5b1c8a1SJohn Marino 	BIO_F_BUFFER_CTX *ctx;
149*f5b1c8a1SJohn Marino 
150*f5b1c8a1SJohn Marino 	if (out == NULL)
151*f5b1c8a1SJohn Marino 		return (0);
152*f5b1c8a1SJohn Marino 	ctx = (BIO_F_BUFFER_CTX *)b->ptr;
153*f5b1c8a1SJohn Marino 
154*f5b1c8a1SJohn Marino 	if ((ctx == NULL) || (b->next_bio == NULL))
155*f5b1c8a1SJohn Marino 		return (0);
156*f5b1c8a1SJohn Marino 	num = 0;
157*f5b1c8a1SJohn Marino 	BIO_clear_retry_flags(b);
158*f5b1c8a1SJohn Marino 
159*f5b1c8a1SJohn Marino start:
160*f5b1c8a1SJohn Marino 	i = ctx->ibuf_len;
161*f5b1c8a1SJohn Marino 	/* If there is stuff left over, grab it */
162*f5b1c8a1SJohn Marino 	if (i != 0) {
163*f5b1c8a1SJohn Marino 		if (i > outl)
164*f5b1c8a1SJohn Marino 			i = outl;
165*f5b1c8a1SJohn Marino 		memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i);
166*f5b1c8a1SJohn Marino 		ctx->ibuf_off += i;
167*f5b1c8a1SJohn Marino 		ctx->ibuf_len -= i;
168*f5b1c8a1SJohn Marino 		num += i;
169*f5b1c8a1SJohn Marino 		if (outl == i)
170*f5b1c8a1SJohn Marino 			return (num);
171*f5b1c8a1SJohn Marino 		outl -= i;
172*f5b1c8a1SJohn Marino 		out += i;
173*f5b1c8a1SJohn Marino 	}
174*f5b1c8a1SJohn Marino 
175*f5b1c8a1SJohn Marino 	/* We may have done a partial read. try to do more.
176*f5b1c8a1SJohn Marino 	 * We have nothing in the buffer.
177*f5b1c8a1SJohn Marino 	 * If we get an error and have read some data, just return it
178*f5b1c8a1SJohn Marino 	 * and let them retry to get the error again.
179*f5b1c8a1SJohn Marino 	 * copy direct to parent address space */
180*f5b1c8a1SJohn Marino 	if (outl > ctx->ibuf_size) {
181*f5b1c8a1SJohn Marino 		for (;;) {
182*f5b1c8a1SJohn Marino 			i = BIO_read(b->next_bio, out, outl);
183*f5b1c8a1SJohn Marino 			if (i <= 0) {
184*f5b1c8a1SJohn Marino 				BIO_copy_next_retry(b);
185*f5b1c8a1SJohn Marino 				if (i < 0)
186*f5b1c8a1SJohn Marino 					return ((num > 0) ? num : i);
187*f5b1c8a1SJohn Marino 				if (i == 0)
188*f5b1c8a1SJohn Marino 					return (num);
189*f5b1c8a1SJohn Marino 			}
190*f5b1c8a1SJohn Marino 			num += i;
191*f5b1c8a1SJohn Marino 			if (outl == i)
192*f5b1c8a1SJohn Marino 				return (num);
193*f5b1c8a1SJohn Marino 			out += i;
194*f5b1c8a1SJohn Marino 			outl -= i;
195*f5b1c8a1SJohn Marino 		}
196*f5b1c8a1SJohn Marino 	}
197*f5b1c8a1SJohn Marino 	/* else */
198*f5b1c8a1SJohn Marino 
199*f5b1c8a1SJohn Marino 	/* we are going to be doing some buffering */
200*f5b1c8a1SJohn Marino 	i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
201*f5b1c8a1SJohn Marino 	if (i <= 0) {
202*f5b1c8a1SJohn Marino 		BIO_copy_next_retry(b);
203*f5b1c8a1SJohn Marino 		if (i < 0)
204*f5b1c8a1SJohn Marino 			return ((num > 0) ? num : i);
205*f5b1c8a1SJohn Marino 		if (i == 0)
206*f5b1c8a1SJohn Marino 			return (num);
207*f5b1c8a1SJohn Marino 	}
208*f5b1c8a1SJohn Marino 	ctx->ibuf_off = 0;
209*f5b1c8a1SJohn Marino 	ctx->ibuf_len = i;
210*f5b1c8a1SJohn Marino 
211*f5b1c8a1SJohn Marino 	/* Lets re-read using ourselves :-) */
212*f5b1c8a1SJohn Marino 	goto start;
213*f5b1c8a1SJohn Marino }
214*f5b1c8a1SJohn Marino 
215*f5b1c8a1SJohn Marino static int
216*f5b1c8a1SJohn Marino buffer_write(BIO *b, const char *in, int inl)
217*f5b1c8a1SJohn Marino {
218*f5b1c8a1SJohn Marino 	int i, num = 0;
219*f5b1c8a1SJohn Marino 	BIO_F_BUFFER_CTX *ctx;
220*f5b1c8a1SJohn Marino 
221*f5b1c8a1SJohn Marino 	if ((in == NULL) || (inl <= 0))
222*f5b1c8a1SJohn Marino 		return (0);
223*f5b1c8a1SJohn Marino 	ctx = (BIO_F_BUFFER_CTX *)b->ptr;
224*f5b1c8a1SJohn Marino 	if ((ctx == NULL) || (b->next_bio == NULL))
225*f5b1c8a1SJohn Marino 		return (0);
226*f5b1c8a1SJohn Marino 
227*f5b1c8a1SJohn Marino 	BIO_clear_retry_flags(b);
228*f5b1c8a1SJohn Marino start:
229*f5b1c8a1SJohn Marino 	i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off);
230*f5b1c8a1SJohn Marino 	/* add to buffer and return */
231*f5b1c8a1SJohn Marino 	if (i >= inl) {
232*f5b1c8a1SJohn Marino 		memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl);
233*f5b1c8a1SJohn Marino 		ctx->obuf_len += inl;
234*f5b1c8a1SJohn Marino 		return (num + inl);
235*f5b1c8a1SJohn Marino 	}
236*f5b1c8a1SJohn Marino 	/* else */
237*f5b1c8a1SJohn Marino 	/* stuff already in buffer, so add to it first, then flush */
238*f5b1c8a1SJohn Marino 	if (ctx->obuf_len != 0) {
239*f5b1c8a1SJohn Marino 		if (i > 0) /* lets fill it up if we can */
240*f5b1c8a1SJohn Marino 		{
241*f5b1c8a1SJohn Marino 			memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i);
242*f5b1c8a1SJohn Marino 			in += i;
243*f5b1c8a1SJohn Marino 			inl -= i;
244*f5b1c8a1SJohn Marino 			num += i;
245*f5b1c8a1SJohn Marino 			ctx->obuf_len += i;
246*f5b1c8a1SJohn Marino 		}
247*f5b1c8a1SJohn Marino 		/* we now have a full buffer needing flushing */
248*f5b1c8a1SJohn Marino 		for (;;) {
249*f5b1c8a1SJohn Marino 			i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
250*f5b1c8a1SJohn Marino 			    ctx->obuf_len);
251*f5b1c8a1SJohn Marino 			if (i <= 0) {
252*f5b1c8a1SJohn Marino 				BIO_copy_next_retry(b);
253*f5b1c8a1SJohn Marino 
254*f5b1c8a1SJohn Marino 				if (i < 0)
255*f5b1c8a1SJohn Marino 					return ((num > 0) ? num : i);
256*f5b1c8a1SJohn Marino 				if (i == 0)
257*f5b1c8a1SJohn Marino 					return (num);
258*f5b1c8a1SJohn Marino 			}
259*f5b1c8a1SJohn Marino 			ctx->obuf_off += i;
260*f5b1c8a1SJohn Marino 			ctx->obuf_len -= i;
261*f5b1c8a1SJohn Marino 			if (ctx->obuf_len == 0)
262*f5b1c8a1SJohn Marino 				break;
263*f5b1c8a1SJohn Marino 		}
264*f5b1c8a1SJohn Marino 	}
265*f5b1c8a1SJohn Marino 	/* we only get here if the buffer has been flushed and we
266*f5b1c8a1SJohn Marino 	 * still have stuff to write */
267*f5b1c8a1SJohn Marino 	ctx->obuf_off = 0;
268*f5b1c8a1SJohn Marino 
269*f5b1c8a1SJohn Marino 	/* we now have inl bytes to write */
270*f5b1c8a1SJohn Marino 	while (inl >= ctx->obuf_size) {
271*f5b1c8a1SJohn Marino 		i = BIO_write(b->next_bio, in, inl);
272*f5b1c8a1SJohn Marino 		if (i <= 0) {
273*f5b1c8a1SJohn Marino 			BIO_copy_next_retry(b);
274*f5b1c8a1SJohn Marino 			if (i < 0)
275*f5b1c8a1SJohn Marino 				return ((num > 0) ? num : i);
276*f5b1c8a1SJohn Marino 			if (i == 0)
277*f5b1c8a1SJohn Marino 				return (num);
278*f5b1c8a1SJohn Marino 		}
279*f5b1c8a1SJohn Marino 		num += i;
280*f5b1c8a1SJohn Marino 		in += i;
281*f5b1c8a1SJohn Marino 		inl -= i;
282*f5b1c8a1SJohn Marino 		if (inl == 0)
283*f5b1c8a1SJohn Marino 			return (num);
284*f5b1c8a1SJohn Marino 	}
285*f5b1c8a1SJohn Marino 
286*f5b1c8a1SJohn Marino 	/* copy the rest into the buffer since we have only a small
287*f5b1c8a1SJohn Marino 	 * amount left */
288*f5b1c8a1SJohn Marino 	goto start;
289*f5b1c8a1SJohn Marino }
290*f5b1c8a1SJohn Marino 
291*f5b1c8a1SJohn Marino static long
292*f5b1c8a1SJohn Marino buffer_ctrl(BIO *b, int cmd, long num, void *ptr)
293*f5b1c8a1SJohn Marino {
294*f5b1c8a1SJohn Marino 	BIO *dbio;
295*f5b1c8a1SJohn Marino 	BIO_F_BUFFER_CTX *ctx;
296*f5b1c8a1SJohn Marino 	long ret = 1;
297*f5b1c8a1SJohn Marino 	char *p1, *p2;
298*f5b1c8a1SJohn Marino 	int r, i, *ip;
299*f5b1c8a1SJohn Marino 	int ibs, obs;
300*f5b1c8a1SJohn Marino 
301*f5b1c8a1SJohn Marino 	ctx = (BIO_F_BUFFER_CTX *)b->ptr;
302*f5b1c8a1SJohn Marino 
303*f5b1c8a1SJohn Marino 	switch (cmd) {
304*f5b1c8a1SJohn Marino 	case BIO_CTRL_RESET:
305*f5b1c8a1SJohn Marino 		ctx->ibuf_off = 0;
306*f5b1c8a1SJohn Marino 		ctx->ibuf_len = 0;
307*f5b1c8a1SJohn Marino 		ctx->obuf_off = 0;
308*f5b1c8a1SJohn Marino 		ctx->obuf_len = 0;
309*f5b1c8a1SJohn Marino 		if (b->next_bio == NULL)
310*f5b1c8a1SJohn Marino 			return (0);
311*f5b1c8a1SJohn Marino 		ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
312*f5b1c8a1SJohn Marino 		break;
313*f5b1c8a1SJohn Marino 	case BIO_CTRL_INFO:
314*f5b1c8a1SJohn Marino 		ret = (long)ctx->obuf_len;
315*f5b1c8a1SJohn Marino 		break;
316*f5b1c8a1SJohn Marino 	case BIO_C_GET_BUFF_NUM_LINES:
317*f5b1c8a1SJohn Marino 		ret = 0;
318*f5b1c8a1SJohn Marino 		p1 = ctx->ibuf;
319*f5b1c8a1SJohn Marino 		for (i = 0; i < ctx->ibuf_len; i++) {
320*f5b1c8a1SJohn Marino 			if (p1[ctx->ibuf_off + i] == '\n')
321*f5b1c8a1SJohn Marino 				ret++;
322*f5b1c8a1SJohn Marino 		}
323*f5b1c8a1SJohn Marino 		break;
324*f5b1c8a1SJohn Marino 	case BIO_CTRL_WPENDING:
325*f5b1c8a1SJohn Marino 		ret = (long)ctx->obuf_len;
326*f5b1c8a1SJohn Marino 		if (ret == 0) {
327*f5b1c8a1SJohn Marino 			if (b->next_bio == NULL)
328*f5b1c8a1SJohn Marino 				return (0);
329*f5b1c8a1SJohn Marino 			ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
330*f5b1c8a1SJohn Marino 		}
331*f5b1c8a1SJohn Marino 		break;
332*f5b1c8a1SJohn Marino 	case BIO_CTRL_PENDING:
333*f5b1c8a1SJohn Marino 		ret = (long)ctx->ibuf_len;
334*f5b1c8a1SJohn Marino 		if (ret == 0) {
335*f5b1c8a1SJohn Marino 			if (b->next_bio == NULL)
336*f5b1c8a1SJohn Marino 				return (0);
337*f5b1c8a1SJohn Marino 			ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
338*f5b1c8a1SJohn Marino 		}
339*f5b1c8a1SJohn Marino 		break;
340*f5b1c8a1SJohn Marino 	case BIO_C_SET_BUFF_READ_DATA:
341*f5b1c8a1SJohn Marino 		if (num > ctx->ibuf_size) {
342*f5b1c8a1SJohn Marino 			p1 = malloc(num);
343*f5b1c8a1SJohn Marino 			if (p1 == NULL)
344*f5b1c8a1SJohn Marino 				goto malloc_error;
345*f5b1c8a1SJohn Marino 			free(ctx->ibuf);
346*f5b1c8a1SJohn Marino 			ctx->ibuf = p1;
347*f5b1c8a1SJohn Marino 		}
348*f5b1c8a1SJohn Marino 		ctx->ibuf_off = 0;
349*f5b1c8a1SJohn Marino 		ctx->ibuf_len = (int)num;
350*f5b1c8a1SJohn Marino 		memcpy(ctx->ibuf, ptr, num);
351*f5b1c8a1SJohn Marino 		ret = 1;
352*f5b1c8a1SJohn Marino 		break;
353*f5b1c8a1SJohn Marino 	case BIO_C_SET_BUFF_SIZE:
354*f5b1c8a1SJohn Marino 		if (ptr != NULL) {
355*f5b1c8a1SJohn Marino 			ip = (int *)ptr;
356*f5b1c8a1SJohn Marino 			if (*ip == 0) {
357*f5b1c8a1SJohn Marino 				ibs = (int)num;
358*f5b1c8a1SJohn Marino 				obs = ctx->obuf_size;
359*f5b1c8a1SJohn Marino 			}
360*f5b1c8a1SJohn Marino 			else /* if (*ip == 1) */
361*f5b1c8a1SJohn Marino 			{
362*f5b1c8a1SJohn Marino 				ibs = ctx->ibuf_size;
363*f5b1c8a1SJohn Marino 				obs = (int)num;
364*f5b1c8a1SJohn Marino 			}
365*f5b1c8a1SJohn Marino 		} else {
366*f5b1c8a1SJohn Marino 			ibs = (int)num;
367*f5b1c8a1SJohn Marino 			obs = (int)num;
368*f5b1c8a1SJohn Marino 		}
369*f5b1c8a1SJohn Marino 		p1 = ctx->ibuf;
370*f5b1c8a1SJohn Marino 		p2 = ctx->obuf;
371*f5b1c8a1SJohn Marino 		if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) {
372*f5b1c8a1SJohn Marino 			p1 = malloc(num);
373*f5b1c8a1SJohn Marino 			if (p1 == NULL)
374*f5b1c8a1SJohn Marino 				goto malloc_error;
375*f5b1c8a1SJohn Marino 		}
376*f5b1c8a1SJohn Marino 		if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) {
377*f5b1c8a1SJohn Marino 			p2 = malloc(num);
378*f5b1c8a1SJohn Marino 			if (p2 == NULL) {
379*f5b1c8a1SJohn Marino 				if (p1 != ctx->ibuf)
380*f5b1c8a1SJohn Marino 					free(p1);
381*f5b1c8a1SJohn Marino 				goto malloc_error;
382*f5b1c8a1SJohn Marino 			}
383*f5b1c8a1SJohn Marino 		}
384*f5b1c8a1SJohn Marino 		if (ctx->ibuf != p1) {
385*f5b1c8a1SJohn Marino 			free(ctx->ibuf);
386*f5b1c8a1SJohn Marino 			ctx->ibuf = p1;
387*f5b1c8a1SJohn Marino 			ctx->ibuf_off = 0;
388*f5b1c8a1SJohn Marino 			ctx->ibuf_len = 0;
389*f5b1c8a1SJohn Marino 			ctx->ibuf_size = ibs;
390*f5b1c8a1SJohn Marino 		}
391*f5b1c8a1SJohn Marino 		if (ctx->obuf != p2) {
392*f5b1c8a1SJohn Marino 			free(ctx->obuf);
393*f5b1c8a1SJohn Marino 			ctx->obuf = p2;
394*f5b1c8a1SJohn Marino 			ctx->obuf_off = 0;
395*f5b1c8a1SJohn Marino 			ctx->obuf_len = 0;
396*f5b1c8a1SJohn Marino 			ctx->obuf_size = obs;
397*f5b1c8a1SJohn Marino 		}
398*f5b1c8a1SJohn Marino 		break;
399*f5b1c8a1SJohn Marino 	case BIO_C_DO_STATE_MACHINE:
400*f5b1c8a1SJohn Marino 		if (b->next_bio == NULL)
401*f5b1c8a1SJohn Marino 			return (0);
402*f5b1c8a1SJohn Marino 		BIO_clear_retry_flags(b);
403*f5b1c8a1SJohn Marino 		ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
404*f5b1c8a1SJohn Marino 		BIO_copy_next_retry(b);
405*f5b1c8a1SJohn Marino 		break;
406*f5b1c8a1SJohn Marino 
407*f5b1c8a1SJohn Marino 	case BIO_CTRL_FLUSH:
408*f5b1c8a1SJohn Marino 		if (b->next_bio == NULL)
409*f5b1c8a1SJohn Marino 			return (0);
410*f5b1c8a1SJohn Marino 		if (ctx->obuf_len <= 0) {
411*f5b1c8a1SJohn Marino 			ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
412*f5b1c8a1SJohn Marino 			break;
413*f5b1c8a1SJohn Marino 		}
414*f5b1c8a1SJohn Marino 
415*f5b1c8a1SJohn Marino 		for (;;) {
416*f5b1c8a1SJohn Marino 			BIO_clear_retry_flags(b);
417*f5b1c8a1SJohn Marino 			if (ctx->obuf_len > 0) {
418*f5b1c8a1SJohn Marino 				r = BIO_write(b->next_bio,
419*f5b1c8a1SJohn Marino 				    &(ctx->obuf[ctx->obuf_off]),
420*f5b1c8a1SJohn Marino 				    ctx->obuf_len);
421*f5b1c8a1SJohn Marino 				BIO_copy_next_retry(b);
422*f5b1c8a1SJohn Marino 				if (r <= 0)
423*f5b1c8a1SJohn Marino 					return ((long)r);
424*f5b1c8a1SJohn Marino 				ctx->obuf_off += r;
425*f5b1c8a1SJohn Marino 				ctx->obuf_len -= r;
426*f5b1c8a1SJohn Marino 			} else {
427*f5b1c8a1SJohn Marino 				ctx->obuf_len = 0;
428*f5b1c8a1SJohn Marino 				ctx->obuf_off = 0;
429*f5b1c8a1SJohn Marino 				break;
430*f5b1c8a1SJohn Marino 			}
431*f5b1c8a1SJohn Marino 		}
432*f5b1c8a1SJohn Marino 		ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
433*f5b1c8a1SJohn Marino 		break;
434*f5b1c8a1SJohn Marino 	case BIO_CTRL_DUP:
435*f5b1c8a1SJohn Marino 		dbio = (BIO *)ptr;
436*f5b1c8a1SJohn Marino 		if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) ||
437*f5b1c8a1SJohn Marino 		    !BIO_set_write_buffer_size(dbio, ctx->obuf_size))
438*f5b1c8a1SJohn Marino 			ret = 0;
439*f5b1c8a1SJohn Marino 		break;
440*f5b1c8a1SJohn Marino 	default:
441*f5b1c8a1SJohn Marino 		if (b->next_bio == NULL)
442*f5b1c8a1SJohn Marino 			return (0);
443*f5b1c8a1SJohn Marino 		ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
444*f5b1c8a1SJohn Marino 		break;
445*f5b1c8a1SJohn Marino 	}
446*f5b1c8a1SJohn Marino 	return (ret);
447*f5b1c8a1SJohn Marino malloc_error:
448*f5b1c8a1SJohn Marino 	BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE);
449*f5b1c8a1SJohn Marino 	return (0);
450*f5b1c8a1SJohn Marino }
451*f5b1c8a1SJohn Marino 
452*f5b1c8a1SJohn Marino static long
453*f5b1c8a1SJohn Marino buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
454*f5b1c8a1SJohn Marino {
455*f5b1c8a1SJohn Marino 	long ret = 1;
456*f5b1c8a1SJohn Marino 
457*f5b1c8a1SJohn Marino 	if (b->next_bio == NULL)
458*f5b1c8a1SJohn Marino 		return (0);
459*f5b1c8a1SJohn Marino 	switch (cmd) {
460*f5b1c8a1SJohn Marino 	default:
461*f5b1c8a1SJohn Marino 		ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
462*f5b1c8a1SJohn Marino 		break;
463*f5b1c8a1SJohn Marino 	}
464*f5b1c8a1SJohn Marino 	return (ret);
465*f5b1c8a1SJohn Marino }
466*f5b1c8a1SJohn Marino 
467*f5b1c8a1SJohn Marino static int
468*f5b1c8a1SJohn Marino buffer_gets(BIO *b, char *buf, int size)
469*f5b1c8a1SJohn Marino {
470*f5b1c8a1SJohn Marino 	BIO_F_BUFFER_CTX *ctx;
471*f5b1c8a1SJohn Marino 	int num = 0, i, flag;
472*f5b1c8a1SJohn Marino 	char *p;
473*f5b1c8a1SJohn Marino 
474*f5b1c8a1SJohn Marino 	ctx = (BIO_F_BUFFER_CTX *)b->ptr;
475*f5b1c8a1SJohn Marino 	size--; /* reserve space for a '\0' */
476*f5b1c8a1SJohn Marino 	BIO_clear_retry_flags(b);
477*f5b1c8a1SJohn Marino 
478*f5b1c8a1SJohn Marino 	for (;;) {
479*f5b1c8a1SJohn Marino 		if (ctx->ibuf_len > 0) {
480*f5b1c8a1SJohn Marino 			p = &(ctx->ibuf[ctx->ibuf_off]);
481*f5b1c8a1SJohn Marino 			flag = 0;
482*f5b1c8a1SJohn Marino 			for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
483*f5b1c8a1SJohn Marino 				*(buf++) = p[i];
484*f5b1c8a1SJohn Marino 				if (p[i] == '\n') {
485*f5b1c8a1SJohn Marino 					flag = 1;
486*f5b1c8a1SJohn Marino 					i++;
487*f5b1c8a1SJohn Marino 					break;
488*f5b1c8a1SJohn Marino 				}
489*f5b1c8a1SJohn Marino 			}
490*f5b1c8a1SJohn Marino 			num += i;
491*f5b1c8a1SJohn Marino 			size -= i;
492*f5b1c8a1SJohn Marino 			ctx->ibuf_len -= i;
493*f5b1c8a1SJohn Marino 			ctx->ibuf_off += i;
494*f5b1c8a1SJohn Marino 			if (flag || size == 0) {
495*f5b1c8a1SJohn Marino 				*buf = '\0';
496*f5b1c8a1SJohn Marino 				return (num);
497*f5b1c8a1SJohn Marino 			}
498*f5b1c8a1SJohn Marino 		}
499*f5b1c8a1SJohn Marino 		else	/* read another chunk */
500*f5b1c8a1SJohn Marino 		{
501*f5b1c8a1SJohn Marino 			i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
502*f5b1c8a1SJohn Marino 			if (i <= 0) {
503*f5b1c8a1SJohn Marino 				BIO_copy_next_retry(b);
504*f5b1c8a1SJohn Marino 				*buf = '\0';
505*f5b1c8a1SJohn Marino 				if (i < 0)
506*f5b1c8a1SJohn Marino 					return ((num > 0) ? num : i);
507*f5b1c8a1SJohn Marino 				if (i == 0)
508*f5b1c8a1SJohn Marino 					return (num);
509*f5b1c8a1SJohn Marino 			}
510*f5b1c8a1SJohn Marino 			ctx->ibuf_len = i;
511*f5b1c8a1SJohn Marino 			ctx->ibuf_off = 0;
512*f5b1c8a1SJohn Marino 		}
513*f5b1c8a1SJohn Marino 	}
514*f5b1c8a1SJohn Marino }
515*f5b1c8a1SJohn Marino 
516*f5b1c8a1SJohn Marino static int
517*f5b1c8a1SJohn Marino buffer_puts(BIO *b, const char *str)
518*f5b1c8a1SJohn Marino {
519*f5b1c8a1SJohn Marino 	return (buffer_write(b, str, strlen(str)));
520*f5b1c8a1SJohn Marino }
521