Home | History | Annotate | Download | only in bio
      1 /* crypto/bio/bf_buff.c */
      2 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      3  * All rights reserved.
      4  *
      5  * This package is an SSL implementation written
      6  * by Eric Young (eay (at) cryptsoft.com).
      7  * The implementation was written so as to conform with Netscapes SSL.
      8  *
      9  * This library is free for commercial and non-commercial use as long as
     10  * the following conditions are aheared to.  The following conditions
     11  * apply to all code found in this distribution, be it the RC4, RSA,
     12  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
     13  * included with this distribution is covered by the same copyright terms
     14  * except that the holder is Tim Hudson (tjh (at) cryptsoft.com).
     15  *
     16  * Copyright remains Eric Young's, and as such any Copyright notices in
     17  * the code are not to be removed.
     18  * If this package is used in a product, Eric Young should be given attribution
     19  * as the author of the parts of the library used.
     20  * This can be in the form of a textual message at program startup or
     21  * in documentation (online or textual) provided with the package.
     22  *
     23  * Redistribution and use in source and binary forms, with or without
     24  * modification, are permitted provided that the following conditions
     25  * are met:
     26  * 1. Redistributions of source code must retain the copyright
     27  *    notice, this list of conditions and the following disclaimer.
     28  * 2. Redistributions in binary form must reproduce the above copyright
     29  *    notice, this list of conditions and the following disclaimer in the
     30  *    documentation and/or other materials provided with the distribution.
     31  * 3. All advertising materials mentioning features or use of this software
     32  *    must display the following acknowledgement:
     33  *    "This product includes cryptographic software written by
     34  *     Eric Young (eay (at) cryptsoft.com)"
     35  *    The word 'cryptographic' can be left out if the rouines from the library
     36  *    being used are not cryptographic related :-).
     37  * 4. If you include any Windows specific code (or a derivative thereof) from
     38  *    the apps directory (application code) you must include an acknowledgement:
     39  *    "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)"
     40  *
     41  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
     42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     51  * SUCH DAMAGE.
     52  *
     53  * The licence and distribution terms for any publically available version or
     54  * derivative of this code cannot be changed.  i.e. this code cannot simply be
     55  * copied and put under another distribution licence
     56  * [including the GNU Public Licence.]
     57  */
     58 
     59 #include <stdio.h>
     60 #include <errno.h>
     61 #include "cryptlib.h"
     62 #include <openssl/bio.h>
     63 #include <openssl/evp.h>
     64 
     65 static int linebuffer_write(BIO *h, const char *buf,int num);
     66 static int linebuffer_read(BIO *h, char *buf, int size);
     67 static int linebuffer_puts(BIO *h, const char *str);
     68 static int linebuffer_gets(BIO *h, char *str, int size);
     69 static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2);
     70 static int linebuffer_new(BIO *h);
     71 static int linebuffer_free(BIO *data);
     72 static long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
     73 
     74 /* A 10k maximum should be enough for most purposes */
     75 #define DEFAULT_LINEBUFFER_SIZE	1024*10
     76 
     77 /* #define DEBUG */
     78 
     79 static BIO_METHOD methods_linebuffer=
     80 	{
     81 	BIO_TYPE_LINEBUFFER,
     82 	"linebuffer",
     83 	linebuffer_write,
     84 	linebuffer_read,
     85 	linebuffer_puts,
     86 	linebuffer_gets,
     87 	linebuffer_ctrl,
     88 	linebuffer_new,
     89 	linebuffer_free,
     90 	linebuffer_callback_ctrl,
     91 	};
     92 
     93 BIO_METHOD *BIO_f_linebuffer(void)
     94 	{
     95 	return(&methods_linebuffer);
     96 	}
     97 
     98 typedef struct bio_linebuffer_ctx_struct
     99 	{
    100 	char *obuf;		/* the output char array */
    101 	int obuf_size;		/* how big is the output buffer */
    102 	int obuf_len;		/* how many bytes are in it */
    103 	} BIO_LINEBUFFER_CTX;
    104 
    105 static int linebuffer_new(BIO *bi)
    106 	{
    107 	BIO_LINEBUFFER_CTX *ctx;
    108 
    109 	ctx=(BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX));
    110 	if (ctx == NULL) return(0);
    111 	ctx->obuf=(char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE);
    112 	if (ctx->obuf == NULL) { OPENSSL_free(ctx); return(0); }
    113 	ctx->obuf_size=DEFAULT_LINEBUFFER_SIZE;
    114 	ctx->obuf_len=0;
    115 
    116 	bi->init=1;
    117 	bi->ptr=(char *)ctx;
    118 	bi->flags=0;
    119 	return(1);
    120 	}
    121 
    122 static int linebuffer_free(BIO *a)
    123 	{
    124 	BIO_LINEBUFFER_CTX *b;
    125 
    126 	if (a == NULL) return(0);
    127 	b=(BIO_LINEBUFFER_CTX *)a->ptr;
    128 	if (b->obuf != NULL) OPENSSL_free(b->obuf);
    129 	OPENSSL_free(a->ptr);
    130 	a->ptr=NULL;
    131 	a->init=0;
    132 	a->flags=0;
    133 	return(1);
    134 	}
    135 
    136 static int linebuffer_read(BIO *b, char *out, int outl)
    137 	{
    138 	int ret=0;
    139 
    140 	if (out == NULL) return(0);
    141 	if (b->next_bio == NULL) return(0);
    142 	ret=BIO_read(b->next_bio,out,outl);
    143 	BIO_clear_retry_flags(b);
    144 	BIO_copy_next_retry(b);
    145 	return(ret);
    146 	}
    147 
    148 static int linebuffer_write(BIO *b, const char *in, int inl)
    149 	{
    150 	int i,num=0,foundnl;
    151 	BIO_LINEBUFFER_CTX *ctx;
    152 
    153 	if ((in == NULL) || (inl <= 0)) return(0);
    154 	ctx=(BIO_LINEBUFFER_CTX *)b->ptr;
    155 	if ((ctx == NULL) || (b->next_bio == NULL)) return(0);
    156 
    157 	BIO_clear_retry_flags(b);
    158 
    159 	do
    160 		{
    161 		const char *p;
    162 
    163 		for(p = in; p < in + inl && *p != '\n'; p++)
    164 			;
    165 		if (*p == '\n')
    166 			{
    167 			p++;
    168 			foundnl = 1;
    169 			}
    170 		else
    171 			foundnl = 0;
    172 
    173 		/* If a NL was found and we already have text in the save
    174 		   buffer, concatenate them and write */
    175 		while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len)
    176 			&& ctx->obuf_len > 0)
    177 			{
    178 			int orig_olen = ctx->obuf_len;
    179 
    180 			i = ctx->obuf_size - ctx->obuf_len;
    181 			if (p - in > 0)
    182 				{
    183 				if (i >= p - in)
    184 					{
    185 					memcpy(&(ctx->obuf[ctx->obuf_len]),
    186 						in,p - in);
    187 					ctx->obuf_len += p - in;
    188 					inl -= p - in;
    189 					num += p - in;
    190 					in = p;
    191 					}
    192 				else
    193 					{
    194 					memcpy(&(ctx->obuf[ctx->obuf_len]),
    195 						in,i);
    196 					ctx->obuf_len += i;
    197 					inl -= i;
    198 					in += i;
    199 					num += i;
    200 					}
    201 				}
    202 
    203 #if 0
    204 BIO_write(b->next_bio, "<*<", 3);
    205 #endif
    206 			i=BIO_write(b->next_bio,
    207 				ctx->obuf, ctx->obuf_len);
    208 			if (i <= 0)
    209 				{
    210 				ctx->obuf_len = orig_olen;
    211 				BIO_copy_next_retry(b);
    212 
    213 #if 0
    214 BIO_write(b->next_bio, ">*>", 3);
    215 #endif
    216 				if (i < 0) return((num > 0)?num:i);
    217 				if (i == 0) return(num);
    218 				}
    219 #if 0
    220 BIO_write(b->next_bio, ">*>", 3);
    221 #endif
    222 			if (i < ctx->obuf_len)
    223 				memmove(ctx->obuf, ctx->obuf + i,
    224 					ctx->obuf_len - i);
    225 			ctx->obuf_len-=i;
    226 			}
    227 
    228 		/* Now that the save buffer is emptied, let's write the input
    229 		   buffer if a NL was found and there is anything to write. */
    230 		if ((foundnl || p - in > ctx->obuf_size) && p - in > 0)
    231 			{
    232 #if 0
    233 BIO_write(b->next_bio, "<*<", 3);
    234 #endif
    235 			i=BIO_write(b->next_bio,in,p - in);
    236 			if (i <= 0)
    237 				{
    238 				BIO_copy_next_retry(b);
    239 #if 0
    240 BIO_write(b->next_bio, ">*>", 3);
    241 #endif
    242 				if (i < 0) return((num > 0)?num:i);
    243 				if (i == 0) return(num);
    244 				}
    245 #if 0
    246 BIO_write(b->next_bio, ">*>", 3);
    247 #endif
    248 			num+=i;
    249 			in+=i;
    250 			inl-=i;
    251 			}
    252 		}
    253 	while(foundnl && inl > 0);
    254 	/* We've written as much as we can.  The rest of the input buffer, if
    255 	   any, is text that doesn't and with a NL and therefore needs to be
    256 	   saved for the next trip. */
    257 	if (inl > 0)
    258 		{
    259 		memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl);
    260 		ctx->obuf_len += inl;
    261 		num += inl;
    262 		}
    263 	return num;
    264 	}
    265 
    266 static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr)
    267 	{
    268 	BIO *dbio;
    269 	BIO_LINEBUFFER_CTX *ctx;
    270 	long ret=1;
    271 	char *p;
    272 	int r;
    273 	int obs;
    274 
    275 	ctx=(BIO_LINEBUFFER_CTX *)b->ptr;
    276 
    277 	switch (cmd)
    278 		{
    279 	case BIO_CTRL_RESET:
    280 		ctx->obuf_len=0;
    281 		if (b->next_bio == NULL) return(0);
    282 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
    283 		break;
    284 	case BIO_CTRL_INFO:
    285 		ret=(long)ctx->obuf_len;
    286 		break;
    287 	case BIO_CTRL_WPENDING:
    288 		ret=(long)ctx->obuf_len;
    289 		if (ret == 0)
    290 			{
    291 			if (b->next_bio == NULL) return(0);
    292 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
    293 			}
    294 		break;
    295 	case BIO_C_SET_BUFF_SIZE:
    296 		obs=(int)num;
    297 		p=ctx->obuf;
    298 		if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size))
    299 			{
    300 			p=(char *)OPENSSL_malloc((int)num);
    301 			if (p == NULL)
    302 				goto malloc_error;
    303 			}
    304 		if (ctx->obuf != p)
    305 			{
    306 			if (ctx->obuf_len > obs)
    307 				{
    308 				ctx->obuf_len = obs;
    309 				}
    310 			memcpy(p, ctx->obuf, ctx->obuf_len);
    311 			OPENSSL_free(ctx->obuf);
    312 			ctx->obuf=p;
    313 			ctx->obuf_size=obs;
    314 			}
    315 		break;
    316 	case BIO_C_DO_STATE_MACHINE:
    317 		if (b->next_bio == NULL) return(0);
    318 		BIO_clear_retry_flags(b);
    319 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
    320 		BIO_copy_next_retry(b);
    321 		break;
    322 
    323 	case BIO_CTRL_FLUSH:
    324 		if (b->next_bio == NULL) return(0);
    325 		if (ctx->obuf_len <= 0)
    326 			{
    327 			ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
    328 			break;
    329 			}
    330 
    331 		for (;;)
    332 			{
    333 			BIO_clear_retry_flags(b);
    334 			if (ctx->obuf_len > 0)
    335 				{
    336 				r=BIO_write(b->next_bio,
    337 					ctx->obuf, ctx->obuf_len);
    338 #if 0
    339 fprintf(stderr,"FLUSH %3d -> %3d\n",ctx->obuf_len,r);
    340 #endif
    341 				BIO_copy_next_retry(b);
    342 				if (r <= 0) return((long)r);
    343 				if (r < ctx->obuf_len)
    344 					memmove(ctx->obuf, ctx->obuf + r,
    345 						ctx->obuf_len - r);
    346 				ctx->obuf_len-=r;
    347 				}
    348 			else
    349 				{
    350 				ctx->obuf_len=0;
    351 				ret=1;
    352 				break;
    353 				}
    354 			}
    355 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
    356 		break;
    357 	case BIO_CTRL_DUP:
    358 		dbio=(BIO *)ptr;
    359 		if (	!BIO_set_write_buffer_size(dbio,ctx->obuf_size))
    360 			ret=0;
    361 		break;
    362 	default:
    363 		if (b->next_bio == NULL) return(0);
    364 		ret=BIO_ctrl(b->next_bio,cmd,num,ptr);
    365 		break;
    366 		}
    367 	return(ret);
    368 malloc_error:
    369 	BIOerr(BIO_F_LINEBUFFER_CTRL,ERR_R_MALLOC_FAILURE);
    370 	return(0);
    371 	}
    372 
    373 static long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
    374 	{
    375 	long ret=1;
    376 
    377 	if (b->next_bio == NULL) return(0);
    378 	switch (cmd)
    379 		{
    380 	default:
    381 		ret=BIO_callback_ctrl(b->next_bio,cmd,fp);
    382 		break;
    383 		}
    384 	return(ret);
    385 	}
    386 
    387 static int linebuffer_gets(BIO *b, char *buf, int size)
    388 	{
    389 	if (b->next_bio == NULL) return(0);
    390 	return(BIO_gets(b->next_bio,buf,size));
    391 	}
    392 
    393 static int linebuffer_puts(BIO *b, const char *str)
    394 	{
    395 	return(linebuffer_write(b,str,strlen(str)));
    396 	}
    397 
    398