1*acf64401Sbeck /* $OpenBSD: bf_buff.c,v 1.28 2023/07/05 21:23:37 beck Exp $ */
25b37fcf3Sryker /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
35b37fcf3Sryker * All rights reserved.
45b37fcf3Sryker *
55b37fcf3Sryker * This package is an SSL implementation written
65b37fcf3Sryker * by Eric Young (eay@cryptsoft.com).
75b37fcf3Sryker * The implementation was written so as to conform with Netscapes SSL.
85b37fcf3Sryker *
95b37fcf3Sryker * This library is free for commercial and non-commercial use as long as
105b37fcf3Sryker * the following conditions are aheared to. The following conditions
115b37fcf3Sryker * apply to all code found in this distribution, be it the RC4, RSA,
125b37fcf3Sryker * lhash, DES, etc., code; not just the SSL code. The SSL documentation
135b37fcf3Sryker * included with this distribution is covered by the same copyright terms
145b37fcf3Sryker * except that the holder is Tim Hudson (tjh@cryptsoft.com).
155b37fcf3Sryker *
165b37fcf3Sryker * Copyright remains Eric Young's, and as such any Copyright notices in
175b37fcf3Sryker * the code are not to be removed.
185b37fcf3Sryker * If this package is used in a product, Eric Young should be given attribution
195b37fcf3Sryker * as the author of the parts of the library used.
205b37fcf3Sryker * This can be in the form of a textual message at program startup or
215b37fcf3Sryker * in documentation (online or textual) provided with the package.
225b37fcf3Sryker *
235b37fcf3Sryker * Redistribution and use in source and binary forms, with or without
245b37fcf3Sryker * modification, are permitted provided that the following conditions
255b37fcf3Sryker * are met:
265b37fcf3Sryker * 1. Redistributions of source code must retain the copyright
275b37fcf3Sryker * notice, this list of conditions and the following disclaimer.
285b37fcf3Sryker * 2. Redistributions in binary form must reproduce the above copyright
295b37fcf3Sryker * notice, this list of conditions and the following disclaimer in the
305b37fcf3Sryker * documentation and/or other materials provided with the distribution.
315b37fcf3Sryker * 3. All advertising materials mentioning features or use of this software
325b37fcf3Sryker * must display the following acknowledgement:
335b37fcf3Sryker * "This product includes cryptographic software written by
345b37fcf3Sryker * Eric Young (eay@cryptsoft.com)"
355b37fcf3Sryker * The word 'cryptographic' can be left out if the rouines from the library
365b37fcf3Sryker * being used are not cryptographic related :-).
375b37fcf3Sryker * 4. If you include any Windows specific code (or a derivative thereof) from
385b37fcf3Sryker * the apps directory (application code) you must include an acknowledgement:
395b37fcf3Sryker * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
405b37fcf3Sryker *
415b37fcf3Sryker * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
425b37fcf3Sryker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
435b37fcf3Sryker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
445b37fcf3Sryker * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
455b37fcf3Sryker * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
465b37fcf3Sryker * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
475b37fcf3Sryker * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
485b37fcf3Sryker * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
495b37fcf3Sryker * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
505b37fcf3Sryker * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
515b37fcf3Sryker * SUCH DAMAGE.
525b37fcf3Sryker *
535b37fcf3Sryker * The licence and distribution terms for any publically available version or
545b37fcf3Sryker * derivative of this code cannot be changed. i.e. this code cannot simply be
555b37fcf3Sryker * copied and put under another distribution licence
565b37fcf3Sryker * [including the GNU Public Licence.]
575b37fcf3Sryker */
585b37fcf3Sryker
595b37fcf3Sryker #include <errno.h>
60a8913c44Sjsing #include <stdio.h>
61a8913c44Sjsing #include <string.h>
62a8913c44Sjsing
63913ec974Sbeck #include <openssl/bio.h>
64b6ab114eSjsing #include <openssl/err.h>
655b37fcf3Sryker
6694b1984eStb #include "bio_local.h"
6794b1984eStb
68c109e398Sbeck static int buffer_write(BIO *h, const char *buf, int num);
695b37fcf3Sryker static int buffer_read(BIO *h, char *buf, int size);
70c109e398Sbeck static int buffer_puts(BIO *h, const char *str);
715b37fcf3Sryker static int buffer_gets(BIO *h, char *str, int size);
72c109e398Sbeck static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
735b37fcf3Sryker static int buffer_new(BIO *h);
745b37fcf3Sryker static int buffer_free(BIO *data);
75818427c5Stb static long buffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
76200c0290Sbeck #define DEFAULT_BUFFER_SIZE 4096
775b37fcf3Sryker
786dc76777Stb static const BIO_METHOD methods_buffer = {
79e402ce74Smiod .type = BIO_TYPE_BUFFER,
80e402ce74Smiod .name = "buffer",
81e402ce74Smiod .bwrite = buffer_write,
82e402ce74Smiod .bread = buffer_read,
83e402ce74Smiod .bputs = buffer_puts,
84e402ce74Smiod .bgets = buffer_gets,
85e402ce74Smiod .ctrl = buffer_ctrl,
86e402ce74Smiod .create = buffer_new,
87e402ce74Smiod .destroy = buffer_free,
88e402ce74Smiod .callback_ctrl = buffer_callback_ctrl
895b37fcf3Sryker };
905b37fcf3Sryker
916dc76777Stb const BIO_METHOD *
BIO_f_buffer(void)92ae7f143bSderaadt BIO_f_buffer(void)
935b37fcf3Sryker {
945b37fcf3Sryker return (&methods_buffer);
955b37fcf3Sryker }
96*acf64401Sbeck LCRYPTO_ALIAS(BIO_f_buffer);
975b37fcf3Sryker
98c3d505beSjsing static int
buffer_new(BIO * bi)99c3d505beSjsing buffer_new(BIO *bi)
1005b37fcf3Sryker {
1015b37fcf3Sryker BIO_F_BUFFER_CTX *ctx;
1025b37fcf3Sryker
1033c6fe066Sderaadt ctx = malloc(sizeof(BIO_F_BUFFER_CTX));
104c3d505beSjsing if (ctx == NULL)
105c3d505beSjsing return (0);
1063c6fe066Sderaadt ctx->ibuf = malloc(DEFAULT_BUFFER_SIZE);
107c3d505beSjsing if (ctx->ibuf == NULL) {
1086f3a6cb1Sbeck free(ctx);
109c3d505beSjsing return (0);
110c3d505beSjsing }
1113c6fe066Sderaadt ctx->obuf = malloc(DEFAULT_BUFFER_SIZE);
112c3d505beSjsing if (ctx->obuf == NULL) {
1136f3a6cb1Sbeck free(ctx->ibuf);
1146f3a6cb1Sbeck free(ctx);
115c3d505beSjsing return (0);
116c3d505beSjsing }
1175b37fcf3Sryker ctx->ibuf_size = DEFAULT_BUFFER_SIZE;
1185b37fcf3Sryker ctx->obuf_size = DEFAULT_BUFFER_SIZE;
1195b37fcf3Sryker ctx->ibuf_len = 0;
1205b37fcf3Sryker ctx->ibuf_off = 0;
1215b37fcf3Sryker ctx->obuf_len = 0;
1225b37fcf3Sryker ctx->obuf_off = 0;
1235b37fcf3Sryker
1245b37fcf3Sryker bi->init = 1;
1255b37fcf3Sryker bi->ptr = (char *)ctx;
1265b37fcf3Sryker bi->flags = 0;
1275b37fcf3Sryker return (1);
1285b37fcf3Sryker }
1295b37fcf3Sryker
130c3d505beSjsing static int
buffer_free(BIO * a)131c3d505beSjsing buffer_free(BIO *a)
1325b37fcf3Sryker {
1335b37fcf3Sryker BIO_F_BUFFER_CTX *b;
1345b37fcf3Sryker
135c3d505beSjsing if (a == NULL)
136c3d505beSjsing return (0);
1375b37fcf3Sryker b = (BIO_F_BUFFER_CTX *)a->ptr;
1386f3a6cb1Sbeck free(b->ibuf);
1396f3a6cb1Sbeck free(b->obuf);
1406f3a6cb1Sbeck free(a->ptr);
1415b37fcf3Sryker a->ptr = NULL;
1425b37fcf3Sryker a->init = 0;
1435b37fcf3Sryker a->flags = 0;
1445b37fcf3Sryker return (1);
1455b37fcf3Sryker }
1465b37fcf3Sryker
147c3d505beSjsing static int
buffer_read(BIO * b,char * out,int outl)148c3d505beSjsing buffer_read(BIO *b, char *out, int outl)
1495b37fcf3Sryker {
1505b37fcf3Sryker int i, num = 0;
1515b37fcf3Sryker BIO_F_BUFFER_CTX *ctx;
1525b37fcf3Sryker
153c3d505beSjsing if (out == NULL)
154c3d505beSjsing return (0);
1555b37fcf3Sryker ctx = (BIO_F_BUFFER_CTX *)b->ptr;
1565b37fcf3Sryker
157c3d505beSjsing if ((ctx == NULL) || (b->next_bio == NULL))
158c3d505beSjsing return (0);
1595b37fcf3Sryker num = 0;
1605b37fcf3Sryker BIO_clear_retry_flags(b);
1615b37fcf3Sryker
1625b37fcf3Sryker start:
1635b37fcf3Sryker i = ctx->ibuf_len;
1645b37fcf3Sryker /* If there is stuff left over, grab it */
165c3d505beSjsing if (i != 0) {
166c3d505beSjsing if (i > outl)
167c3d505beSjsing i = outl;
1685b37fcf3Sryker memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i);
1695b37fcf3Sryker ctx->ibuf_off += i;
1705b37fcf3Sryker ctx->ibuf_len -= i;
1715b37fcf3Sryker num += i;
172c3d505beSjsing if (outl == i)
173c3d505beSjsing return (num);
1745b37fcf3Sryker outl -= i;
1755b37fcf3Sryker out += i;
1765b37fcf3Sryker }
1775b37fcf3Sryker
1785b37fcf3Sryker /* We may have done a partial read. try to do more.
1795b37fcf3Sryker * We have nothing in the buffer.
1805b37fcf3Sryker * If we get an error and have read some data, just return it
1815b37fcf3Sryker * and let them retry to get the error again.
1825b37fcf3Sryker * copy direct to parent address space */
183c3d505beSjsing if (outl > ctx->ibuf_size) {
184c3d505beSjsing for (;;) {
1855b37fcf3Sryker i = BIO_read(b->next_bio, out, outl);
186c3d505beSjsing if (i <= 0) {
1875b37fcf3Sryker BIO_copy_next_retry(b);
188c3d505beSjsing if (i < 0)
189c3d505beSjsing return ((num > 0) ? num : i);
190c3d505beSjsing if (i == 0)
191c3d505beSjsing return (num);
1925b37fcf3Sryker }
1935b37fcf3Sryker num += i;
194c3d505beSjsing if (outl == i)
195c3d505beSjsing return (num);
1965b37fcf3Sryker out += i;
1975b37fcf3Sryker outl -= i;
1985b37fcf3Sryker }
1995b37fcf3Sryker }
2005b37fcf3Sryker /* else */
2015b37fcf3Sryker
2025b37fcf3Sryker /* we are going to be doing some buffering */
2035b37fcf3Sryker i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
204c3d505beSjsing if (i <= 0) {
2055b37fcf3Sryker BIO_copy_next_retry(b);
206c3d505beSjsing if (i < 0)
207c3d505beSjsing return ((num > 0) ? num : i);
208c3d505beSjsing if (i == 0)
209c3d505beSjsing return (num);
2105b37fcf3Sryker }
2115b37fcf3Sryker ctx->ibuf_off = 0;
2125b37fcf3Sryker ctx->ibuf_len = i;
2135b37fcf3Sryker
2145b37fcf3Sryker /* Lets re-read using ourselves :-) */
2155b37fcf3Sryker goto start;
2165b37fcf3Sryker }
2175b37fcf3Sryker
218c3d505beSjsing static int
buffer_write(BIO * b,const char * in,int inl)219c3d505beSjsing buffer_write(BIO *b, const char *in, int inl)
2205b37fcf3Sryker {
2215b37fcf3Sryker int i, num = 0;
2225b37fcf3Sryker BIO_F_BUFFER_CTX *ctx;
2235b37fcf3Sryker
224c3d505beSjsing if ((in == NULL) || (inl <= 0))
225c3d505beSjsing return (0);
2265b37fcf3Sryker ctx = (BIO_F_BUFFER_CTX *)b->ptr;
227c3d505beSjsing if ((ctx == NULL) || (b->next_bio == NULL))
228c3d505beSjsing return (0);
2295b37fcf3Sryker
2305b37fcf3Sryker BIO_clear_retry_flags(b);
2315b37fcf3Sryker start:
2325b37fcf3Sryker i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off);
2335b37fcf3Sryker /* add to buffer and return */
234c3d505beSjsing if (i >= inl) {
23517150393Sdjm memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl);
2365b37fcf3Sryker ctx->obuf_len += inl;
2375b37fcf3Sryker return (num + inl);
2385b37fcf3Sryker }
2395b37fcf3Sryker /* else */
2405b37fcf3Sryker /* stuff already in buffer, so add to it first, then flush */
241c3d505beSjsing if (ctx->obuf_len != 0) {
2425b37fcf3Sryker if (i > 0) /* lets fill it up if we can */
2435b37fcf3Sryker {
24417150393Sdjm memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i);
2455b37fcf3Sryker in += i;
2465b37fcf3Sryker inl -= i;
2475b37fcf3Sryker num += i;
2485b37fcf3Sryker ctx->obuf_len += i;
2495b37fcf3Sryker }
2505b37fcf3Sryker /* we now have a full buffer needing flushing */
251c3d505beSjsing for (;;) {
2525b37fcf3Sryker i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]),
2535b37fcf3Sryker ctx->obuf_len);
254c3d505beSjsing if (i <= 0) {
2555b37fcf3Sryker BIO_copy_next_retry(b);
2565b37fcf3Sryker
257c3d505beSjsing if (i < 0)
258c3d505beSjsing return ((num > 0) ? num : i);
259c3d505beSjsing if (i == 0)
260c3d505beSjsing return (num);
2615b37fcf3Sryker }
2625b37fcf3Sryker ctx->obuf_off += i;
2635b37fcf3Sryker ctx->obuf_len -= i;
264c3d505beSjsing if (ctx->obuf_len == 0)
265c3d505beSjsing break;
2665b37fcf3Sryker }
2675b37fcf3Sryker }
2685b37fcf3Sryker /* we only get here if the buffer has been flushed and we
2695b37fcf3Sryker * still have stuff to write */
2705b37fcf3Sryker ctx->obuf_off = 0;
2715b37fcf3Sryker
2725b37fcf3Sryker /* we now have inl bytes to write */
273c3d505beSjsing while (inl >= ctx->obuf_size) {
2745b37fcf3Sryker i = BIO_write(b->next_bio, in, inl);
275c3d505beSjsing if (i <= 0) {
2765b37fcf3Sryker BIO_copy_next_retry(b);
277c3d505beSjsing if (i < 0)
278c3d505beSjsing return ((num > 0) ? num : i);
279c3d505beSjsing if (i == 0)
280c3d505beSjsing return (num);
2815b37fcf3Sryker }
2825b37fcf3Sryker num += i;
2835b37fcf3Sryker in += i;
2845b37fcf3Sryker inl -= i;
285c3d505beSjsing if (inl == 0)
286c3d505beSjsing return (num);
2875b37fcf3Sryker }
2885b37fcf3Sryker
2895b37fcf3Sryker /* copy the rest into the buffer since we have only a small
2905b37fcf3Sryker * amount left */
2915b37fcf3Sryker goto start;
2925b37fcf3Sryker }
2935b37fcf3Sryker
294c3d505beSjsing static long
buffer_ctrl(BIO * b,int cmd,long num,void * ptr)295c3d505beSjsing buffer_ctrl(BIO *b, int cmd, long num, void *ptr)
2965b37fcf3Sryker {
2975b37fcf3Sryker BIO *dbio;
2985b37fcf3Sryker BIO_F_BUFFER_CTX *ctx;
2995b37fcf3Sryker long ret = 1;
3005b37fcf3Sryker char *p1, *p2;
3015b37fcf3Sryker int r, i, *ip;
3025b37fcf3Sryker int ibs, obs;
3035b37fcf3Sryker
3045b37fcf3Sryker ctx = (BIO_F_BUFFER_CTX *)b->ptr;
3055b37fcf3Sryker
306c3d505beSjsing switch (cmd) {
3075b37fcf3Sryker case BIO_CTRL_RESET:
3085b37fcf3Sryker ctx->ibuf_off = 0;
3095b37fcf3Sryker ctx->ibuf_len = 0;
3105b37fcf3Sryker ctx->obuf_off = 0;
3115b37fcf3Sryker ctx->obuf_len = 0;
312c3d505beSjsing if (b->next_bio == NULL)
313c3d505beSjsing return (0);
3145b37fcf3Sryker ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
3155b37fcf3Sryker break;
3165b37fcf3Sryker case BIO_CTRL_INFO:
3175b37fcf3Sryker ret = (long)ctx->obuf_len;
3185b37fcf3Sryker break;
3195b37fcf3Sryker case BIO_C_GET_BUFF_NUM_LINES:
3205b37fcf3Sryker ret = 0;
3215b37fcf3Sryker p1 = ctx->ibuf;
322c3d505beSjsing for (i = 0; i < ctx->ibuf_len; i++) {
323c3d505beSjsing if (p1[ctx->ibuf_off + i] == '\n')
324c3d505beSjsing ret++;
3255b37fcf3Sryker }
3265b37fcf3Sryker break;
3275b37fcf3Sryker case BIO_CTRL_WPENDING:
3285b37fcf3Sryker ret = (long)ctx->obuf_len;
329c3d505beSjsing if (ret == 0) {
330c3d505beSjsing if (b->next_bio == NULL)
331c3d505beSjsing return (0);
3325b37fcf3Sryker ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
333ba5406e9Sbeck }
3345b37fcf3Sryker break;
3355b37fcf3Sryker case BIO_CTRL_PENDING:
3365b37fcf3Sryker ret = (long)ctx->ibuf_len;
337c3d505beSjsing if (ret == 0) {
338c3d505beSjsing if (b->next_bio == NULL)
339c3d505beSjsing return (0);
3405b37fcf3Sryker ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
341ba5406e9Sbeck }
3425b37fcf3Sryker break;
3435b37fcf3Sryker case BIO_C_SET_BUFF_READ_DATA:
344c3d505beSjsing if (num > ctx->ibuf_size) {
345cdab2a2eSmiod p1 = malloc(num);
346c3d505beSjsing if (p1 == NULL)
347c3d505beSjsing goto malloc_error;
3486f3a6cb1Sbeck free(ctx->ibuf);
3495b37fcf3Sryker ctx->ibuf = p1;
3505b37fcf3Sryker }
3515b37fcf3Sryker ctx->ibuf_off = 0;
3525b37fcf3Sryker ctx->ibuf_len = (int)num;
3533372276cStedu memcpy(ctx->ibuf, ptr, num);
3545b37fcf3Sryker ret = 1;
3555b37fcf3Sryker break;
3565b37fcf3Sryker case BIO_C_SET_BUFF_SIZE:
357c3d505beSjsing if (ptr != NULL) {
3585b37fcf3Sryker ip = (int *)ptr;
359c3d505beSjsing if (*ip == 0) {
3605b37fcf3Sryker ibs = (int)num;
3615b37fcf3Sryker obs = ctx->obuf_size;
3625b37fcf3Sryker }
3635b37fcf3Sryker else /* if (*ip == 1) */
3645b37fcf3Sryker {
3655b37fcf3Sryker ibs = ctx->ibuf_size;
3665b37fcf3Sryker obs = (int)num;
3675b37fcf3Sryker }
368c3d505beSjsing } else {
3695b37fcf3Sryker ibs = (int)num;
3705b37fcf3Sryker obs = (int)num;
3715b37fcf3Sryker }
3725b37fcf3Sryker p1 = ctx->ibuf;
3735b37fcf3Sryker p2 = ctx->obuf;
374c3d505beSjsing if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) {
375cdab2a2eSmiod p1 = malloc(num);
376c3d505beSjsing if (p1 == NULL)
377c3d505beSjsing goto malloc_error;
3785b37fcf3Sryker }
379c3d505beSjsing if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) {
380cdab2a2eSmiod p2 = malloc(num);
381c3d505beSjsing if (p2 == NULL) {
382c3d505beSjsing if (p1 != ctx->ibuf)
3836f3a6cb1Sbeck free(p1);
3845b37fcf3Sryker goto malloc_error;
3855b37fcf3Sryker }
3865b37fcf3Sryker }
387c3d505beSjsing if (ctx->ibuf != p1) {
3886f3a6cb1Sbeck free(ctx->ibuf);
3895b37fcf3Sryker ctx->ibuf = p1;
3905b37fcf3Sryker ctx->ibuf_off = 0;
3915b37fcf3Sryker ctx->ibuf_len = 0;
3925b37fcf3Sryker ctx->ibuf_size = ibs;
3935b37fcf3Sryker }
394c3d505beSjsing if (ctx->obuf != p2) {
3956f3a6cb1Sbeck free(ctx->obuf);
3965b37fcf3Sryker ctx->obuf = p2;
3975b37fcf3Sryker ctx->obuf_off = 0;
3985b37fcf3Sryker ctx->obuf_len = 0;
3995b37fcf3Sryker ctx->obuf_size = obs;
4005b37fcf3Sryker }
4015b37fcf3Sryker break;
4025b37fcf3Sryker case BIO_C_DO_STATE_MACHINE:
403c3d505beSjsing if (b->next_bio == NULL)
404c3d505beSjsing return (0);
4055b37fcf3Sryker BIO_clear_retry_flags(b);
4065b37fcf3Sryker ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
4075b37fcf3Sryker BIO_copy_next_retry(b);
4085b37fcf3Sryker break;
4095b37fcf3Sryker
4105b37fcf3Sryker case BIO_CTRL_FLUSH:
411c3d505beSjsing if (b->next_bio == NULL)
412c3d505beSjsing return (0);
413c3d505beSjsing if (ctx->obuf_len <= 0) {
4145b37fcf3Sryker ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
4155b37fcf3Sryker break;
4165b37fcf3Sryker }
4175b37fcf3Sryker
418c3d505beSjsing for (;;) {
4195b37fcf3Sryker BIO_clear_retry_flags(b);
420c3d505beSjsing if (ctx->obuf_len > 0) {
4215b37fcf3Sryker r = BIO_write(b->next_bio,
4225b37fcf3Sryker &(ctx->obuf[ctx->obuf_off]),
42317150393Sdjm ctx->obuf_len);
4245b37fcf3Sryker BIO_copy_next_retry(b);
425c3d505beSjsing if (r <= 0)
426c3d505beSjsing return ((long)r);
4275b37fcf3Sryker ctx->obuf_off += r;
42817150393Sdjm ctx->obuf_len -= r;
429c3d505beSjsing } else {
4305b37fcf3Sryker ctx->obuf_len = 0;
4315b37fcf3Sryker ctx->obuf_off = 0;
4325b37fcf3Sryker break;
4335b37fcf3Sryker }
4345b37fcf3Sryker }
435913ec974Sbeck ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
4365b37fcf3Sryker break;
4375b37fcf3Sryker case BIO_CTRL_DUP:
4385b37fcf3Sryker dbio = (BIO *)ptr;
4395b37fcf3Sryker if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) ||
4405b37fcf3Sryker !BIO_set_write_buffer_size(dbio, ctx->obuf_size))
4415b37fcf3Sryker ret = 0;
4425b37fcf3Sryker break;
4435b37fcf3Sryker default:
444c3d505beSjsing if (b->next_bio == NULL)
445c3d505beSjsing return (0);
4465b37fcf3Sryker ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
4475b37fcf3Sryker break;
4485b37fcf3Sryker }
4495b37fcf3Sryker return (ret);
4505b37fcf3Sryker malloc_error:
4515067ae9fSbeck BIOerror(ERR_R_MALLOC_FAILURE);
4525b37fcf3Sryker return (0);
4535b37fcf3Sryker }
4545b37fcf3Sryker
455c3d505beSjsing static long
buffer_callback_ctrl(BIO * b,int cmd,BIO_info_cb * fp)456818427c5Stb buffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
457ba5406e9Sbeck {
458ba5406e9Sbeck long ret = 1;
459ba5406e9Sbeck
460c3d505beSjsing if (b->next_bio == NULL)
461c3d505beSjsing return (0);
462c3d505beSjsing switch (cmd) {
463ba5406e9Sbeck default:
464ba5406e9Sbeck ret = BIO_callback_ctrl(b->next_bio, cmd, fp);
465ba5406e9Sbeck break;
466ba5406e9Sbeck }
467ba5406e9Sbeck return (ret);
468ba5406e9Sbeck }
469ba5406e9Sbeck
470c3d505beSjsing static int
buffer_gets(BIO * b,char * buf,int size)471c3d505beSjsing buffer_gets(BIO *b, char *buf, int size)
4725b37fcf3Sryker {
4735b37fcf3Sryker BIO_F_BUFFER_CTX *ctx;
4745b37fcf3Sryker int num = 0, i, flag;
4755b37fcf3Sryker char *p;
4765b37fcf3Sryker
4775b37fcf3Sryker ctx = (BIO_F_BUFFER_CTX *)b->ptr;
4785b37fcf3Sryker size--; /* reserve space for a '\0' */
4795b37fcf3Sryker BIO_clear_retry_flags(b);
4805b37fcf3Sryker
481c3d505beSjsing for (;;) {
482c3d505beSjsing if (ctx->ibuf_len > 0) {
4835b37fcf3Sryker p = &(ctx->ibuf[ctx->ibuf_off]);
4845b37fcf3Sryker flag = 0;
485c3d505beSjsing for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) {
4865b37fcf3Sryker *(buf++) = p[i];
487c3d505beSjsing if (p[i] == '\n') {
4885b37fcf3Sryker flag = 1;
4895b37fcf3Sryker i++;
4905b37fcf3Sryker break;
4915b37fcf3Sryker }
4925b37fcf3Sryker }
4935b37fcf3Sryker num += i;
4945b37fcf3Sryker size -= i;
4955b37fcf3Sryker ctx->ibuf_len -= i;
4965b37fcf3Sryker ctx->ibuf_off += i;
497c3d505beSjsing if (flag || size == 0) {
4985b37fcf3Sryker *buf = '\0';
4995b37fcf3Sryker return (num);
5005b37fcf3Sryker }
5015b37fcf3Sryker }
5025b37fcf3Sryker else /* read another chunk */
5035b37fcf3Sryker {
5045b37fcf3Sryker i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size);
505c3d505beSjsing if (i <= 0) {
5065b37fcf3Sryker BIO_copy_next_retry(b);
507cdc51833Smarkus *buf = '\0';
508c3d505beSjsing if (i < 0)
509c3d505beSjsing return ((num > 0) ? num : i);
510c3d505beSjsing if (i == 0)
511c3d505beSjsing return (num);
5125b37fcf3Sryker }
5135b37fcf3Sryker ctx->ibuf_len = i;
5145b37fcf3Sryker ctx->ibuf_off = 0;
5155b37fcf3Sryker }
5165b37fcf3Sryker }
5175b37fcf3Sryker }
5185b37fcf3Sryker
519c3d505beSjsing static int
buffer_puts(BIO * b,const char * str)520c3d505beSjsing buffer_puts(BIO *b, const char *str)
5215b37fcf3Sryker {
522c109e398Sbeck return (buffer_write(b, str, strlen(str)));
5235b37fcf3Sryker }
524