155714Skris/* crypto/bio/bf_buff.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 855714Skris * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 1555714Skris * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 2255714Skris * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 3755714Skris * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 4055714Skris * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 5255714Skris * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 5955714Skris#include <stdio.h> 6055714Skris#include <errno.h> 6155714Skris#include "cryptlib.h" 6255714Skris#include <openssl/bio.h> 6355714Skris 6468651Skrisstatic int buffer_write(BIO *h, const char *buf,int num); 6568651Skrisstatic int buffer_read(BIO *h, char *buf, int size); 6668651Skrisstatic int buffer_puts(BIO *h, const char *str); 6768651Skrisstatic int buffer_gets(BIO *h, char *str, int size); 6868651Skrisstatic long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 6955714Skrisstatic int buffer_new(BIO *h); 7055714Skrisstatic int buffer_free(BIO *data); 7168651Skrisstatic long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 7279998Skris#define DEFAULT_BUFFER_SIZE 4096 7355714Skris 7455714Skrisstatic BIO_METHOD methods_buffer= 7555714Skris { 7655714Skris BIO_TYPE_BUFFER, 7755714Skris "buffer", 7855714Skris buffer_write, 7955714Skris buffer_read, 8055714Skris buffer_puts, 8155714Skris buffer_gets, 8255714Skris buffer_ctrl, 8355714Skris buffer_new, 8455714Skris buffer_free, 8559191Skris buffer_callback_ctrl, 8655714Skris }; 8755714Skris 8855714SkrisBIO_METHOD *BIO_f_buffer(void) 8955714Skris { 9055714Skris return(&methods_buffer); 9155714Skris } 9255714Skris 9355714Skrisstatic int buffer_new(BIO *bi) 9455714Skris { 9555714Skris BIO_F_BUFFER_CTX *ctx; 9655714Skris 9768651Skris ctx=(BIO_F_BUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX)); 9855714Skris if (ctx == NULL) return(0); 9968651Skris ctx->ibuf=(char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 10068651Skris if (ctx->ibuf == NULL) { OPENSSL_free(ctx); return(0); } 10168651Skris ctx->obuf=(char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 10268651Skris if (ctx->obuf == NULL) { OPENSSL_free(ctx->ibuf); OPENSSL_free(ctx); return(0); } 10355714Skris ctx->ibuf_size=DEFAULT_BUFFER_SIZE; 10455714Skris ctx->obuf_size=DEFAULT_BUFFER_SIZE; 10555714Skris ctx->ibuf_len=0; 10655714Skris ctx->ibuf_off=0; 10755714Skris ctx->obuf_len=0; 10855714Skris ctx->obuf_off=0; 10955714Skris 11055714Skris bi->init=1; 11155714Skris bi->ptr=(char *)ctx; 11255714Skris bi->flags=0; 11355714Skris return(1); 11455714Skris } 11555714Skris 11655714Skrisstatic int buffer_free(BIO *a) 11755714Skris { 11855714Skris BIO_F_BUFFER_CTX *b; 11955714Skris 12055714Skris if (a == NULL) return(0); 12155714Skris b=(BIO_F_BUFFER_CTX *)a->ptr; 12268651Skris if (b->ibuf != NULL) OPENSSL_free(b->ibuf); 12368651Skris if (b->obuf != NULL) OPENSSL_free(b->obuf); 12468651Skris OPENSSL_free(a->ptr); 12555714Skris a->ptr=NULL; 12655714Skris a->init=0; 12755714Skris a->flags=0; 12855714Skris return(1); 12955714Skris } 13055714Skris 13155714Skrisstatic int buffer_read(BIO *b, char *out, int outl) 13255714Skris { 13355714Skris int i,num=0; 13455714Skris BIO_F_BUFFER_CTX *ctx; 13555714Skris 13655714Skris if (out == NULL) return(0); 13755714Skris ctx=(BIO_F_BUFFER_CTX *)b->ptr; 13855714Skris 13955714Skris if ((ctx == NULL) || (b->next_bio == NULL)) return(0); 14055714Skris num=0; 14155714Skris BIO_clear_retry_flags(b); 14255714Skris 14355714Skrisstart: 14455714Skris i=ctx->ibuf_len; 14555714Skris /* If there is stuff left over, grab it */ 14655714Skris if (i != 0) 14755714Skris { 14855714Skris if (i > outl) i=outl; 14955714Skris memcpy(out,&(ctx->ibuf[ctx->ibuf_off]),i); 15055714Skris ctx->ibuf_off+=i; 15155714Skris ctx->ibuf_len-=i; 15255714Skris num+=i; 15355714Skris if (outl == i) return(num); 15455714Skris outl-=i; 15555714Skris out+=i; 15655714Skris } 15755714Skris 15855714Skris /* We may have done a partial read. try to do more. 15955714Skris * We have nothing in the buffer. 16055714Skris * If we get an error and have read some data, just return it 16155714Skris * and let them retry to get the error again. 16255714Skris * copy direct to parent address space */ 16355714Skris if (outl > ctx->ibuf_size) 16455714Skris { 16555714Skris for (;;) 16655714Skris { 16755714Skris i=BIO_read(b->next_bio,out,outl); 16855714Skris if (i <= 0) 16955714Skris { 17055714Skris BIO_copy_next_retry(b); 17155714Skris if (i < 0) return((num > 0)?num:i); 17255714Skris if (i == 0) return(num); 17355714Skris } 17455714Skris num+=i; 17555714Skris if (outl == i) return(num); 17655714Skris out+=i; 17755714Skris outl-=i; 17855714Skris } 17955714Skris } 18055714Skris /* else */ 18155714Skris 18255714Skris /* we are going to be doing some buffering */ 18355714Skris i=BIO_read(b->next_bio,ctx->ibuf,ctx->ibuf_size); 18455714Skris if (i <= 0) 18555714Skris { 18655714Skris BIO_copy_next_retry(b); 18755714Skris if (i < 0) return((num > 0)?num:i); 18855714Skris if (i == 0) return(num); 18955714Skris } 19055714Skris ctx->ibuf_off=0; 19155714Skris ctx->ibuf_len=i; 19255714Skris 19355714Skris /* Lets re-read using ourselves :-) */ 19455714Skris goto start; 19555714Skris } 19655714Skris 19768651Skrisstatic int buffer_write(BIO *b, const char *in, int inl) 19855714Skris { 19955714Skris int i,num=0; 20055714Skris BIO_F_BUFFER_CTX *ctx; 20155714Skris 20255714Skris if ((in == NULL) || (inl <= 0)) return(0); 20355714Skris ctx=(BIO_F_BUFFER_CTX *)b->ptr; 20455714Skris if ((ctx == NULL) || (b->next_bio == NULL)) return(0); 20555714Skris 20655714Skris BIO_clear_retry_flags(b); 20755714Skrisstart: 20855714Skris i=ctx->obuf_size-(ctx->obuf_len+ctx->obuf_off); 20955714Skris /* add to buffer and return */ 21055714Skris if (i >= inl) 21155714Skris { 212237657Sjkim memcpy(&(ctx->obuf[ctx->obuf_off+ctx->obuf_len]),in,inl); 21355714Skris ctx->obuf_len+=inl; 21455714Skris return(num+inl); 21555714Skris } 21655714Skris /* else */ 21755714Skris /* stuff already in buffer, so add to it first, then flush */ 21855714Skris if (ctx->obuf_len != 0) 21955714Skris { 22055714Skris if (i > 0) /* lets fill it up if we can */ 22155714Skris { 222237657Sjkim memcpy(&(ctx->obuf[ctx->obuf_off+ctx->obuf_len]),in,i); 22355714Skris in+=i; 22455714Skris inl-=i; 22555714Skris num+=i; 22655714Skris ctx->obuf_len+=i; 22755714Skris } 22855714Skris /* we now have a full buffer needing flushing */ 22955714Skris for (;;) 23055714Skris { 23155714Skris i=BIO_write(b->next_bio,&(ctx->obuf[ctx->obuf_off]), 23255714Skris ctx->obuf_len); 23355714Skris if (i <= 0) 23455714Skris { 23555714Skris BIO_copy_next_retry(b); 23655714Skris 23755714Skris if (i < 0) return((num > 0)?num:i); 23855714Skris if (i == 0) return(num); 23955714Skris } 24055714Skris ctx->obuf_off+=i; 24155714Skris ctx->obuf_len-=i; 24255714Skris if (ctx->obuf_len == 0) break; 24355714Skris } 24455714Skris } 24555714Skris /* we only get here if the buffer has been flushed and we 24655714Skris * still have stuff to write */ 24755714Skris ctx->obuf_off=0; 24855714Skris 24955714Skris /* we now have inl bytes to write */ 25055714Skris while (inl >= ctx->obuf_size) 25155714Skris { 25255714Skris i=BIO_write(b->next_bio,in,inl); 25355714Skris if (i <= 0) 25455714Skris { 25555714Skris BIO_copy_next_retry(b); 25655714Skris if (i < 0) return((num > 0)?num:i); 25755714Skris if (i == 0) return(num); 25855714Skris } 25955714Skris num+=i; 26055714Skris in+=i; 26155714Skris inl-=i; 26255714Skris if (inl == 0) return(num); 26355714Skris } 26455714Skris 26555714Skris /* copy the rest into the buffer since we have only a small 26655714Skris * amount left */ 26755714Skris goto start; 26855714Skris } 26955714Skris 27068651Skrisstatic long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) 27155714Skris { 27255714Skris BIO *dbio; 27355714Skris BIO_F_BUFFER_CTX *ctx; 27455714Skris long ret=1; 27555714Skris char *p1,*p2; 27655714Skris int r,i,*ip; 27755714Skris int ibs,obs; 27855714Skris 27955714Skris ctx=(BIO_F_BUFFER_CTX *)b->ptr; 28055714Skris 28155714Skris switch (cmd) 28255714Skris { 28355714Skris case BIO_CTRL_RESET: 28455714Skris ctx->ibuf_off=0; 28555714Skris ctx->ibuf_len=0; 28655714Skris ctx->obuf_off=0; 28755714Skris ctx->obuf_len=0; 28859191Skris if (b->next_bio == NULL) return(0); 28955714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 29055714Skris break; 29155714Skris case BIO_CTRL_INFO: 29255714Skris ret=(long)ctx->obuf_len; 29355714Skris break; 29455714Skris case BIO_C_GET_BUFF_NUM_LINES: 29555714Skris ret=0; 29655714Skris p1=ctx->ibuf; 297237657Sjkim for (i=0; i<ctx->ibuf_len; i++) 29855714Skris { 299237657Sjkim if (p1[ctx->ibuf_off + i] == '\n') ret++; 30055714Skris } 30155714Skris break; 30255714Skris case BIO_CTRL_WPENDING: 30355714Skris ret=(long)ctx->obuf_len; 30455714Skris if (ret == 0) 30559191Skris { 30659191Skris if (b->next_bio == NULL) return(0); 30755714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 30859191Skris } 30955714Skris break; 31055714Skris case BIO_CTRL_PENDING: 31155714Skris ret=(long)ctx->ibuf_len; 31255714Skris if (ret == 0) 31359191Skris { 31459191Skris if (b->next_bio == NULL) return(0); 31555714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 31659191Skris } 31755714Skris break; 31855714Skris case BIO_C_SET_BUFF_READ_DATA: 31955714Skris if (num > ctx->ibuf_size) 32055714Skris { 32168651Skris p1=OPENSSL_malloc((int)num); 32255714Skris if (p1 == NULL) goto malloc_error; 32368651Skris if (ctx->ibuf != NULL) OPENSSL_free(ctx->ibuf); 32455714Skris ctx->ibuf=p1; 32555714Skris } 32655714Skris ctx->ibuf_off=0; 32755714Skris ctx->ibuf_len=(int)num; 32855714Skris memcpy(ctx->ibuf,ptr,(int)num); 32955714Skris ret=1; 33055714Skris break; 33155714Skris case BIO_C_SET_BUFF_SIZE: 33255714Skris if (ptr != NULL) 33355714Skris { 33455714Skris ip=(int *)ptr; 33555714Skris if (*ip == 0) 33655714Skris { 33755714Skris ibs=(int)num; 33855714Skris obs=ctx->obuf_size; 33955714Skris } 34055714Skris else /* if (*ip == 1) */ 34155714Skris { 34255714Skris ibs=ctx->ibuf_size; 34355714Skris obs=(int)num; 34455714Skris } 34555714Skris } 34655714Skris else 34755714Skris { 34855714Skris ibs=(int)num; 34955714Skris obs=(int)num; 35055714Skris } 35155714Skris p1=ctx->ibuf; 35255714Skris p2=ctx->obuf; 35355714Skris if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) 35455714Skris { 35568651Skris p1=(char *)OPENSSL_malloc((int)num); 35655714Skris if (p1 == NULL) goto malloc_error; 35755714Skris } 35855714Skris if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) 35955714Skris { 36068651Skris p2=(char *)OPENSSL_malloc((int)num); 36155714Skris if (p2 == NULL) 36255714Skris { 36368651Skris if (p1 != ctx->ibuf) OPENSSL_free(p1); 36455714Skris goto malloc_error; 36555714Skris } 36655714Skris } 36755714Skris if (ctx->ibuf != p1) 36855714Skris { 36968651Skris OPENSSL_free(ctx->ibuf); 37055714Skris ctx->ibuf=p1; 37155714Skris ctx->ibuf_off=0; 37255714Skris ctx->ibuf_len=0; 37355714Skris ctx->ibuf_size=ibs; 37455714Skris } 37555714Skris if (ctx->obuf != p2) 37655714Skris { 37768651Skris OPENSSL_free(ctx->obuf); 37855714Skris ctx->obuf=p2; 37955714Skris ctx->obuf_off=0; 38055714Skris ctx->obuf_len=0; 38155714Skris ctx->obuf_size=obs; 38255714Skris } 38355714Skris break; 38455714Skris case BIO_C_DO_STATE_MACHINE: 38559191Skris if (b->next_bio == NULL) return(0); 38655714Skris BIO_clear_retry_flags(b); 38755714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 38855714Skris BIO_copy_next_retry(b); 38955714Skris break; 39055714Skris 39155714Skris case BIO_CTRL_FLUSH: 39259191Skris if (b->next_bio == NULL) return(0); 39355714Skris if (ctx->obuf_len <= 0) 39455714Skris { 39555714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 39655714Skris break; 39755714Skris } 39855714Skris 39955714Skris for (;;) 40055714Skris { 40155714Skris BIO_clear_retry_flags(b); 402237657Sjkim if (ctx->obuf_len > 0) 40355714Skris { 40455714Skris r=BIO_write(b->next_bio, 40555714Skris &(ctx->obuf[ctx->obuf_off]), 406237657Sjkim ctx->obuf_len); 40755714Skris#if 0 408237657Sjkimfprintf(stderr,"FLUSH [%3d] %3d -> %3d\n",ctx->obuf_off,ctx->obuf_len,r); 40955714Skris#endif 41055714Skris BIO_copy_next_retry(b); 41155714Skris if (r <= 0) return((long)r); 41255714Skris ctx->obuf_off+=r; 413237657Sjkim ctx->obuf_len-=r; 41455714Skris } 41555714Skris else 41655714Skris { 41755714Skris ctx->obuf_len=0; 41855714Skris ctx->obuf_off=0; 41955714Skris ret=1; 42055714Skris break; 42155714Skris } 42255714Skris } 42355714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 42455714Skris break; 42555714Skris case BIO_CTRL_DUP: 42655714Skris dbio=(BIO *)ptr; 42755714Skris if ( !BIO_set_read_buffer_size(dbio,ctx->ibuf_size) || 42855714Skris !BIO_set_write_buffer_size(dbio,ctx->obuf_size)) 42955714Skris ret=0; 43055714Skris break; 43155714Skris default: 43259191Skris if (b->next_bio == NULL) return(0); 43355714Skris ret=BIO_ctrl(b->next_bio,cmd,num,ptr); 43455714Skris break; 43555714Skris } 43655714Skris return(ret); 43755714Skrismalloc_error: 43855714Skris BIOerr(BIO_F_BUFFER_CTRL,ERR_R_MALLOC_FAILURE); 43955714Skris return(0); 44055714Skris } 44155714Skris 44268651Skrisstatic long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 44359191Skris { 44459191Skris long ret=1; 44559191Skris 44659191Skris if (b->next_bio == NULL) return(0); 44759191Skris switch (cmd) 44859191Skris { 44959191Skris default: 45059191Skris ret=BIO_callback_ctrl(b->next_bio,cmd,fp); 45159191Skris break; 45259191Skris } 45359191Skris return(ret); 45459191Skris } 45559191Skris 45655714Skrisstatic int buffer_gets(BIO *b, char *buf, int size) 45755714Skris { 45855714Skris BIO_F_BUFFER_CTX *ctx; 45955714Skris int num=0,i,flag; 46055714Skris char *p; 46155714Skris 46255714Skris ctx=(BIO_F_BUFFER_CTX *)b->ptr; 46355714Skris size--; /* reserve space for a '\0' */ 46455714Skris BIO_clear_retry_flags(b); 46555714Skris 46655714Skris for (;;) 46755714Skris { 46855714Skris if (ctx->ibuf_len > 0) 46955714Skris { 47055714Skris p= &(ctx->ibuf[ctx->ibuf_off]); 47155714Skris flag=0; 47255714Skris for (i=0; (i<ctx->ibuf_len) && (i<size); i++) 47355714Skris { 47455714Skris *(buf++)=p[i]; 47555714Skris if (p[i] == '\n') 47655714Skris { 47755714Skris flag=1; 47855714Skris i++; 47955714Skris break; 48055714Skris } 48155714Skris } 48255714Skris num+=i; 48355714Skris size-=i; 48455714Skris ctx->ibuf_len-=i; 48555714Skris ctx->ibuf_off+=i; 486109998Smarkm if (flag || size == 0) 48755714Skris { 48855714Skris *buf='\0'; 48955714Skris return(num); 49055714Skris } 49155714Skris } 49255714Skris else /* read another chunk */ 49355714Skris { 49455714Skris i=BIO_read(b->next_bio,ctx->ibuf,ctx->ibuf_size); 49555714Skris if (i <= 0) 49655714Skris { 49755714Skris BIO_copy_next_retry(b); 498120631Snectar *buf='\0'; 49955714Skris if (i < 0) return((num > 0)?num:i); 50055714Skris if (i == 0) return(num); 50155714Skris } 50255714Skris ctx->ibuf_len=i; 50355714Skris ctx->ibuf_off=0; 50455714Skris } 50555714Skris } 50655714Skris } 50755714Skris 50868651Skrisstatic int buffer_puts(BIO *b, const char *str) 50955714Skris { 51068651Skris return(buffer_write(b,str,strlen(str))); 51155714Skris } 51255714Skris 513