1327Sjkh/* crypto/bio/bf_buff.c */ 230221Scharnier/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 350479Speter * All rights reserved. 4327Sjkh * 5327Sjkh * This package is an SSL implementation written 6327Sjkh * by Eric Young (eay@cryptsoft.com). 7327Sjkh * The implementation was written so as to conform with Netscapes SSL. 8327Sjkh * 9327Sjkh * This library is free for commercial and non-commercial use as long as 10327Sjkh * the following conditions are aheared to. The following conditions 11327Sjkh * apply to all code found in this distribution, be it the RC4, RSA, 12327Sjkh * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13327Sjkh * included with this distribution is covered by the same copyright terms 14327Sjkh * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15327Sjkh * 16327Sjkh * Copyright remains Eric Young's, and as such any Copyright notices in 17327Sjkh * the code are not to be removed. 18327Sjkh * If this package is used in a product, Eric Young should be given attribution 19327Sjkh * as the author of the parts of the library used. 20327Sjkh * This can be in the form of a textual message at program startup or 21327Sjkh * in documentation (online or textual) provided with the package. 22327Sjkh * 23327Sjkh * Redistribution and use in source and binary forms, with or without 24327Sjkh * modification, are permitted provided that the following conditions 25327Sjkh * are met: 26327Sjkh * 1. Redistributions of source code must retain the copyright 27327Sjkh * notice, this list of conditions and the following disclaimer. 28327Sjkh * 2. Redistributions in binary form must reproduce the above copyright 2972174Ssobomax * notice, this list of conditions and the following disclaimer in the 3072174Ssobomax * documentation and/or other materials provided with the distribution. 3172174Ssobomax * 3. All advertising materials mentioning features or use of this software 3249300Sjdp * must display the following acknowledgement: 3372174Ssobomax * "This product includes cryptographic software written by 34327Sjkh * Eric Young (eay@cryptsoft.com)" 35327Sjkh * The word 'cryptographic' can be left out if the rouines from the library 3649300Sjdp * being used are not cryptographic related :-). 37327Sjkh * 4. If you include any Windows specific code (or a derivative thereof) from 3872174Ssobomax * the apps directory (application code) you must include an acknowledgement: 39327Sjkh * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40327Sjkh * 41327Sjkh * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42327Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43327Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 447937Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45327Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46327Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47327Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 487937Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 497937Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 507937Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51327Sjkh * SUCH DAMAGE. 5216404Sjkh * 5316404Sjkh * The licence and distribution terms for any publically available version or 54327Sjkh * derivative of this code cannot be changed. i.e. this code cannot simply be 5516404Sjkh * copied and put under another distribution licence 5616404Sjkh * [including the GNU Public Licence.] 5772174Ssobomax */ 5816404Sjkh 598857Srgrimes#include <stdio.h> 6072174Ssobomax#include <errno.h> 6172174Ssobomax#include "cryptlib.h" 6272174Ssobomax#include <openssl/bio.h> 6372174Ssobomax 6472174Ssobomaxstatic int buffer_write(BIO *h, const char *buf, int num); 6572174Ssobomaxstatic int buffer_read(BIO *h, char *buf, int size); 6672174Ssobomaxstatic int buffer_puts(BIO *h, const char *str); 6772174Ssobomaxstatic int buffer_gets(BIO *h, char *str, int size); 6872174Ssobomaxstatic long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 6972174Ssobomaxstatic int buffer_new(BIO *h); 7072174Ssobomaxstatic int buffer_free(BIO *data); 7172174Ssobomaxstatic long buffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 7272174Ssobomax#define DEFAULT_BUFFER_SIZE 4096 7372174Ssobomax 7472174Ssobomaxstatic BIO_METHOD methods_buffer = { 7572174Ssobomax BIO_TYPE_BUFFER, 7672174Ssobomax "buffer", 7772174Ssobomax buffer_write, 7872174Ssobomax buffer_read, 7972174Ssobomax buffer_puts, 8072174Ssobomax buffer_gets, 8172174Ssobomax buffer_ctrl, 8272174Ssobomax buffer_new, 8372174Ssobomax buffer_free, 8472174Ssobomax buffer_callback_ctrl, 8572174Ssobomax}; 8672174Ssobomax 8772174SsobomaxBIO_METHOD *BIO_f_buffer(void) 8872174Ssobomax{ 8972174Ssobomax return (&methods_buffer); 9049300Sjdp} 9172174Ssobomax 9249300Sjdpstatic int buffer_new(BIO *bi) 9316404Sjkh{ 9472174Ssobomax BIO_F_BUFFER_CTX *ctx; 9572174Ssobomax 9672174Ssobomax ctx = (BIO_F_BUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX)); 9772174Ssobomax if (ctx == NULL) 9872174Ssobomax return (0); 9972174Ssobomax ctx->ibuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 10072174Ssobomax if (ctx->ibuf == NULL) { 10172174Ssobomax OPENSSL_free(ctx); 10272174Ssobomax return (0); 10372174Ssobomax } 10472174Ssobomax ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 10572174Ssobomax if (ctx->obuf == NULL) { 10672174Ssobomax OPENSSL_free(ctx->ibuf); 10772174Ssobomax OPENSSL_free(ctx); 10872174Ssobomax return (0); 10972174Ssobomax } 11072174Ssobomax ctx->ibuf_size = DEFAULT_BUFFER_SIZE; 11172174Ssobomax ctx->obuf_size = DEFAULT_BUFFER_SIZE; 11272174Ssobomax ctx->ibuf_len = 0; 11372174Ssobomax ctx->ibuf_off = 0; 11472174Ssobomax ctx->obuf_len = 0; 11572174Ssobomax ctx->obuf_off = 0; 11672174Ssobomax 11772174Ssobomax bi->init = 1; 11872174Ssobomax bi->ptr = (char *)ctx; 11972174Ssobomax bi->flags = 0; 12072174Ssobomax return (1); 12172174Ssobomax} 12272174Ssobomax 12372174Ssobomaxstatic int buffer_free(BIO *a) 12472174Ssobomax{ 12572174Ssobomax BIO_F_BUFFER_CTX *b; 12672174Ssobomax 12772174Ssobomax if (a == NULL) 12872174Ssobomax return (0); 12972174Ssobomax b = (BIO_F_BUFFER_CTX *)a->ptr; 13072174Ssobomax if (b->ibuf != NULL) 13172174Ssobomax OPENSSL_free(b->ibuf); 13272174Ssobomax if (b->obuf != NULL) 13372174Ssobomax OPENSSL_free(b->obuf); 13472174Ssobomax OPENSSL_free(a->ptr); 13572174Ssobomax a->ptr = NULL; 13672174Ssobomax a->init = 0; 13772174Ssobomax a->flags = 0; 13872174Ssobomax return (1); 13916404Sjkh} 14016404Sjkh 14172174Ssobomaxstatic int buffer_read(BIO *b, char *out, int outl) 14272174Ssobomax{ 14372174Ssobomax int i, num = 0; 144327Sjkh BIO_F_BUFFER_CTX *ctx; 145327Sjkh 146327Sjkh if (out == NULL) 14711780Sjkh return (0); 14811780Sjkh ctx = (BIO_F_BUFFER_CTX *)b->ptr; 149327Sjkh 150327Sjkh if ((ctx == NULL) || (b->next_bio == NULL)) 151327Sjkh return (0); 1528086Sjkh num = 0; 153327Sjkh BIO_clear_retry_flags(b); 1548086Sjkh 155327Sjkh start: 156327Sjkh i = ctx->ibuf_len; 1578086Sjkh /* If there is stuff left over, grab it */ 1588142Sjkh if (i != 0) { 1598086Sjkh if (i > outl) 160327Sjkh i = outl; 1618086Sjkh memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i); 16211780Sjkh ctx->ibuf_off += i; 1638086Sjkh ctx->ibuf_len -= i; 1648086Sjkh num += i; 1658086Sjkh if (outl == i) 1668086Sjkh return (num); 1679782Sache outl -= i; 1688086Sjkh out += i; 169327Sjkh } 1708423Sjkh 1718423Sjkh /* 1728423Sjkh * We may have done a partial read. try to do more. We have nothing in 1738423Sjkh * the buffer. If we get an error and have read some data, just return it 1748423Sjkh * and let them retry to get the error again. copy direct to parent 1758423Sjkh * address space 1768423Sjkh */ 1778423Sjkh if (outl > ctx->ibuf_size) { 1788086Sjkh for (;;) { 1798086Sjkh i = BIO_read(b->next_bio, out, outl); 1808086Sjkh if (i <= 0) { 18111780Sjkh BIO_copy_next_retry(b); 1828086Sjkh if (i < 0) 1838086Sjkh return ((num > 0) ? num : i); 1848086Sjkh if (i == 0) 1853364Sjkh return (num); 1863364Sjkh } 1873364Sjkh num += i; 1883577Sjkh if (outl == i) 1893577Sjkh return (num); 1903364Sjkh out += i; 1913364Sjkh outl -= i; 19230221Scharnier } 1938086Sjkh } 1948086Sjkh /* else */ 1953364Sjkh 19611780Sjkh /* we are going to be doing some buffering */ 197327Sjkh i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); 19830221Scharnier if (i <= 0) { 1998086Sjkh BIO_copy_next_retry(b); 2008086Sjkh if (i < 0) 201327Sjkh return ((num > 0) ? num : i); 202327Sjkh if (i == 0) 2038086Sjkh return (num); 204327Sjkh } 2057937Sjkh ctx->ibuf_off = 0; 2067937Sjkh ctx->ibuf_len = i; 2077937Sjkh 2087937Sjkh /* Lets re-read using ourselves :-) */ 209327Sjkh goto start; 21030221Scharnier} 211327Sjkh 212327Sjkhstatic int buffer_write(BIO *b, const char *in, int inl) 213327Sjkh{ 21430221Scharnier int i, num = 0; 215327Sjkh BIO_F_BUFFER_CTX *ctx; 216327Sjkh 217327Sjkh if ((in == NULL) || (inl <= 0)) 218327Sjkh return (0); 219327Sjkh ctx = (BIO_F_BUFFER_CTX *)b->ptr; 220327Sjkh if ((ctx == NULL) || (b->next_bio == NULL)) 221327Sjkh return (0); 222327Sjkh 223327Sjkh BIO_clear_retry_flags(b); 22430221Scharnier start: 2258086Sjkh i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off); 2268086Sjkh /* add to buffer and return */ 227327Sjkh if (i >= inl) { 228327Sjkh memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl); 229327Sjkh ctx->obuf_len += inl; 230327Sjkh return (num + inl); 231327Sjkh } 232327Sjkh /* else */ 233327Sjkh /* stuff already in buffer, so add to it first, then flush */ 234327Sjkh if (ctx->obuf_len != 0) { 235327Sjkh if (i > 0) { /* lets fill it up if we can */ 236327Sjkh memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i); 2378086Sjkh in += i; 238327Sjkh inl -= i; 2398086Sjkh num += i; 2408086Sjkh ctx->obuf_len += i; 241327Sjkh } 242327Sjkh /* we now have a full buffer needing flushing */ 243327Sjkh for (;;) { 244411Sjkh i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), 245411Sjkh ctx->obuf_len); 246327Sjkh if (i <= 0) { 247379Sjkh BIO_copy_next_retry(b); 24866339Smarko 24966339Smarko if (i < 0) 2504996Sjkh return ((num > 0) ? num : i); 2514996Sjkh if (i == 0) 252327Sjkh return (num); 253379Sjkh } 2544996Sjkh ctx->obuf_off += i; 2554996Sjkh ctx->obuf_len -= i; 256327Sjkh if (ctx->obuf_len == 0) 257379Sjkh break; 258327Sjkh } 259379Sjkh } 26041866Sjkh /* 26141866Sjkh * we only get here if the buffer has been flushed and we still have 262327Sjkh * stuff to write 263379Sjkh */ 26441866Sjkh ctx->obuf_off = 0; 26541866Sjkh 2664996Sjkh /* we now have inl bytes to write */ 2674996Sjkh while (inl >= ctx->obuf_size) { 268327Sjkh i = BIO_write(b->next_bio, in, inl); 269379Sjkh if (i <= 0) { 270411Sjkh BIO_copy_next_retry(b); 271411Sjkh if (i < 0) 27262775Ssobomax return ((num > 0) ? num : i); 27362775Ssobomax if (i == 0) 27471965Sjkh return (num); 27571965Sjkh } 27667454Ssobomax num += i; 27767454Ssobomax in += i; 278411Sjkh inl -= i; 279411Sjkh if (inl == 0) 280327Sjkh return (num); 281327Sjkh } 2828086Sjkh 28333427Sjkh /* 2848086Sjkh * copy the rest into the buffer since we have only a small amount left 2858086Sjkh */ 2868086Sjkh goto start; 287327Sjkh} 288327Sjkh 289327Sjkhstatic long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) 290327Sjkh{ 291327Sjkh BIO *dbio; 29233427Sjkh BIO_F_BUFFER_CTX *ctx; 29333427Sjkh long ret = 1; 29433427Sjkh char *p1, *p2; 29533427Sjkh int r, i, *ip; 29672174Ssobomax int ibs, obs; 29733427Sjkh 29839068Sjkh ctx = (BIO_F_BUFFER_CTX *)b->ptr; 29939068Sjkh 300327Sjkh switch (cmd) { 30149300Sjdp case BIO_CTRL_RESET: 30249300Sjdp ctx->ibuf_off = 0; 30349300Sjdp ctx->ibuf_len = 0; 30449300Sjdp ctx->obuf_off = 0; 30549300Sjdp ctx->obuf_len = 0; 30649300Sjdp if (b->next_bio == NULL) 30772174Ssobomax return (0); 30872174Ssobomax ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 30972174Ssobomax break; 31072174Ssobomax case BIO_CTRL_INFO: 31172174Ssobomax ret = (long)ctx->obuf_len; 31272174Ssobomax break; 31372174Ssobomax case BIO_C_GET_BUFF_NUM_LINES: 31472174Ssobomax ret = 0; 31572174Ssobomax p1 = ctx->ibuf; 31672174Ssobomax for (i = 0; i < ctx->ibuf_len; i++) { 31772174Ssobomax if (p1[ctx->ibuf_off + i] == '\n') 31872174Ssobomax ret++; 31972174Ssobomax } 32072174Ssobomax break; 32172174Ssobomax case BIO_CTRL_WPENDING: 32272174Ssobomax ret = (long)ctx->obuf_len; 32372174Ssobomax if (ret == 0) { 32472174Ssobomax if (b->next_bio == NULL) 32572174Ssobomax return (0); 32672174Ssobomax ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 32772174Ssobomax } 32872174Ssobomax break; 32972174Ssobomax case BIO_CTRL_PENDING: 33072174Ssobomax ret = (long)ctx->ibuf_len; 33172174Ssobomax if (ret == 0) { 33272174Ssobomax if (b->next_bio == NULL) 33372174Ssobomax return (0); 33472174Ssobomax ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 33572174Ssobomax } 33672174Ssobomax break; 33772174Ssobomax case BIO_C_SET_BUFF_READ_DATA: 33872174Ssobomax if (num > ctx->ibuf_size) { 33972174Ssobomax p1 = OPENSSL_malloc((int)num); 34072174Ssobomax if (p1 == NULL) 34172174Ssobomax goto malloc_error; 34272174Ssobomax if (ctx->ibuf != NULL) 34372174Ssobomax OPENSSL_free(ctx->ibuf); 34472174Ssobomax ctx->ibuf = p1; 34572174Ssobomax } 34672174Ssobomax ctx->ibuf_off = 0; 34772174Ssobomax ctx->ibuf_len = (int)num; 34872174Ssobomax memcpy(ctx->ibuf, ptr, (int)num); 34972174Ssobomax ret = 1; 35072174Ssobomax break; 35172174Ssobomax case BIO_C_SET_BUFF_SIZE: 35272174Ssobomax if (ptr != NULL) { 35372174Ssobomax ip = (int *)ptr; 35472174Ssobomax if (*ip == 0) { 35572174Ssobomax ibs = (int)num; 356 obs = ctx->obuf_size; 357 } else { /* if (*ip == 1) */ 358 359 ibs = ctx->ibuf_size; 360 obs = (int)num; 361 } 362 } else { 363 ibs = (int)num; 364 obs = (int)num; 365 } 366 p1 = ctx->ibuf; 367 p2 = ctx->obuf; 368 if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) { 369 p1 = (char *)OPENSSL_malloc((int)num); 370 if (p1 == NULL) 371 goto malloc_error; 372 } 373 if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) { 374 p2 = (char *)OPENSSL_malloc((int)num); 375 if (p2 == NULL) { 376 if (p1 != ctx->ibuf) 377 OPENSSL_free(p1); 378 goto malloc_error; 379 } 380 } 381 if (ctx->ibuf != p1) { 382 OPENSSL_free(ctx->ibuf); 383 ctx->ibuf = p1; 384 ctx->ibuf_off = 0; 385 ctx->ibuf_len = 0; 386 ctx->ibuf_size = ibs; 387 } 388 if (ctx->obuf != p2) { 389 OPENSSL_free(ctx->obuf); 390 ctx->obuf = p2; 391 ctx->obuf_off = 0; 392 ctx->obuf_len = 0; 393 ctx->obuf_size = obs; 394 } 395 break; 396 case BIO_C_DO_STATE_MACHINE: 397 if (b->next_bio == NULL) 398 return (0); 399 BIO_clear_retry_flags(b); 400 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 401 BIO_copy_next_retry(b); 402 break; 403 404 case BIO_CTRL_FLUSH: 405 if (b->next_bio == NULL) 406 return (0); 407 if (ctx->obuf_len <= 0) { 408 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 409 break; 410 } 411 412 for (;;) { 413 BIO_clear_retry_flags(b); 414 if (ctx->obuf_len > 0) { 415 r = BIO_write(b->next_bio, 416 &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len); 417#if 0 418 fprintf(stderr, "FLUSH [%3d] %3d -> %3d\n", ctx->obuf_off, 419 ctx->obuf_len, r); 420#endif 421 BIO_copy_next_retry(b); 422 if (r <= 0) 423 return ((long)r); 424 ctx->obuf_off += r; 425 ctx->obuf_len -= r; 426 } else { 427 ctx->obuf_len = 0; 428 ctx->obuf_off = 0; 429 ret = 1; 430 break; 431 } 432 } 433 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 434 break; 435 case BIO_CTRL_DUP: 436 dbio = (BIO *)ptr; 437 if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) || 438 !BIO_set_write_buffer_size(dbio, ctx->obuf_size)) 439 ret = 0; 440 break; 441 default: 442 if (b->next_bio == NULL) 443 return (0); 444 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 445 break; 446 } 447 return (ret); 448 malloc_error: 449 BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE); 450 return (0); 451} 452 453static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 454{ 455 long ret = 1; 456 457 if (b->next_bio == NULL) 458 return (0); 459 switch (cmd) { 460 default: 461 ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 462 break; 463 } 464 return (ret); 465} 466 467static int buffer_gets(BIO *b, char *buf, int size) 468{ 469 BIO_F_BUFFER_CTX *ctx; 470 int num = 0, i, flag; 471 char *p; 472 473 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 474 size--; /* reserve space for a '\0' */ 475 BIO_clear_retry_flags(b); 476 477 for (;;) { 478 if (ctx->ibuf_len > 0) { 479 p = &(ctx->ibuf[ctx->ibuf_off]); 480 flag = 0; 481 for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { 482 *(buf++) = p[i]; 483 if (p[i] == '\n') { 484 flag = 1; 485 i++; 486 break; 487 } 488 } 489 num += i; 490 size -= i; 491 ctx->ibuf_len -= i; 492 ctx->ibuf_off += i; 493 if (flag || size == 0) { 494 *buf = '\0'; 495 return (num); 496 } 497 } else { /* read another chunk */ 498 499 i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); 500 if (i <= 0) { 501 BIO_copy_next_retry(b); 502 *buf = '\0'; 503 if (i < 0) 504 return ((num > 0) ? num : i); 505 if (i == 0) 506 return (num); 507 } 508 ctx->ibuf_len = i; 509 ctx->ibuf_off = 0; 510 } 511 } 512} 513 514static int buffer_puts(BIO *b, const char *str) 515{ 516 return (buffer_write(b, str, strlen(str))); 517} 518