168651Skris/* crypto/bio/bf_buff.c */ 268651Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 368651Skris * All rights reserved. 468651Skris * 568651Skris * This package is an SSL implementation written 668651Skris * by Eric Young (eay@cryptsoft.com). 768651Skris * The implementation was written so as to conform with Netscapes SSL. 8280304Sjkim * 968651Skris * This library is free for commercial and non-commercial use as long as 1068651Skris * the following conditions are aheared to. The following conditions 1168651Skris * apply to all code found in this distribution, be it the RC4, RSA, 1268651Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1368651Skris * included with this distribution is covered by the same copyright terms 1468651Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15280304Sjkim * 1668651Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1768651Skris * the code are not to be removed. 1868651Skris * If this package is used in a product, Eric Young should be given attribution 1968651Skris * as the author of the parts of the library used. 2068651Skris * This can be in the form of a textual message at program startup or 2168651Skris * in documentation (online or textual) provided with the package. 22280304Sjkim * 2368651Skris * Redistribution and use in source and binary forms, with or without 2468651Skris * modification, are permitted provided that the following conditions 2568651Skris * are met: 2668651Skris * 1. Redistributions of source code must retain the copyright 2768651Skris * notice, this list of conditions and the following disclaimer. 2868651Skris * 2. Redistributions in binary form must reproduce the above copyright 2968651Skris * notice, this list of conditions and the following disclaimer in the 3068651Skris * documentation and/or other materials provided with the distribution. 3168651Skris * 3. All advertising materials mentioning features or use of this software 3268651Skris * must display the following acknowledgement: 3368651Skris * "This product includes cryptographic software written by 3468651Skris * Eric Young (eay@cryptsoft.com)" 3568651Skris * The word 'cryptographic' can be left out if the rouines from the library 3668651Skris * being used are not cryptographic related :-). 37280304Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from 3868651Skris * the apps directory (application code) you must include an acknowledgement: 3968651Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40280304Sjkim * 4168651Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4268651Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4368651Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4468651Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4568651Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4668651Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4768651Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4868651Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4968651Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5068651Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5168651Skris * SUCH DAMAGE. 52280304Sjkim * 5368651Skris * The licence and distribution terms for any publically available version or 5468651Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5568651Skris * copied and put under another distribution licence 5668651Skris * [including the GNU Public Licence.] 5768651Skris */ 5868651Skris 5968651Skris#include <stdio.h> 6068651Skris#include <errno.h> 6168651Skris#include "cryptlib.h" 6268651Skris#include <openssl/bio.h> 6368651Skris#include <openssl/evp.h> 6468651Skris 65280304Sjkimstatic int linebuffer_write(BIO *h, const char *buf, int num); 6668651Skrisstatic int linebuffer_read(BIO *h, char *buf, int size); 6768651Skrisstatic int linebuffer_puts(BIO *h, const char *str); 6868651Skrisstatic int linebuffer_gets(BIO *h, char *str, int size); 6968651Skrisstatic long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 7068651Skrisstatic int linebuffer_new(BIO *h); 7168651Skrisstatic int linebuffer_free(BIO *data); 7268651Skrisstatic long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 7368651Skris 7468651Skris/* A 10k maximum should be enough for most purposes */ 75280304Sjkim#define DEFAULT_LINEBUFFER_SIZE 1024*10 7668651Skris 7768651Skris/* #define DEBUG */ 7868651Skris 79280304Sjkimstatic BIO_METHOD methods_linebuffer = { 80280304Sjkim BIO_TYPE_LINEBUFFER, 81280304Sjkim "linebuffer", 82280304Sjkim linebuffer_write, 83280304Sjkim linebuffer_read, 84280304Sjkim linebuffer_puts, 85280304Sjkim linebuffer_gets, 86280304Sjkim linebuffer_ctrl, 87280304Sjkim linebuffer_new, 88280304Sjkim linebuffer_free, 89280304Sjkim linebuffer_callback_ctrl, 90280304Sjkim}; 9168651Skris 9268651SkrisBIO_METHOD *BIO_f_linebuffer(void) 93280304Sjkim{ 94280304Sjkim return (&methods_linebuffer); 95280304Sjkim} 9668651Skris 97280304Sjkimtypedef struct bio_linebuffer_ctx_struct { 98280304Sjkim char *obuf; /* the output char array */ 99280304Sjkim int obuf_size; /* how big is the output buffer */ 100280304Sjkim int obuf_len; /* how many bytes are in it */ 101280304Sjkim} BIO_LINEBUFFER_CTX; 10268651Skris 10368651Skrisstatic int linebuffer_new(BIO *bi) 104280304Sjkim{ 105280304Sjkim BIO_LINEBUFFER_CTX *ctx; 10668651Skris 107280304Sjkim ctx = (BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX)); 108280304Sjkim if (ctx == NULL) 109280304Sjkim return (0); 110280304Sjkim ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 111280304Sjkim if (ctx->obuf == NULL) { 112280304Sjkim OPENSSL_free(ctx); 113280304Sjkim return (0); 114280304Sjkim } 115280304Sjkim ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; 116280304Sjkim ctx->obuf_len = 0; 11768651Skris 118280304Sjkim bi->init = 1; 119280304Sjkim bi->ptr = (char *)ctx; 120280304Sjkim bi->flags = 0; 121280304Sjkim return (1); 122280304Sjkim} 12368651Skris 12468651Skrisstatic int linebuffer_free(BIO *a) 125280304Sjkim{ 126280304Sjkim BIO_LINEBUFFER_CTX *b; 12768651Skris 128280304Sjkim if (a == NULL) 129280304Sjkim return (0); 130280304Sjkim b = (BIO_LINEBUFFER_CTX *)a->ptr; 131280304Sjkim if (b->obuf != NULL) 132280304Sjkim OPENSSL_free(b->obuf); 133280304Sjkim OPENSSL_free(a->ptr); 134280304Sjkim a->ptr = NULL; 135280304Sjkim a->init = 0; 136280304Sjkim a->flags = 0; 137280304Sjkim return (1); 138280304Sjkim} 139280304Sjkim 14068651Skrisstatic int linebuffer_read(BIO *b, char *out, int outl) 141280304Sjkim{ 142280304Sjkim int ret = 0; 14368651Skris 144280304Sjkim if (out == NULL) 145280304Sjkim return (0); 146280304Sjkim if (b->next_bio == NULL) 147280304Sjkim return (0); 148280304Sjkim ret = BIO_read(b->next_bio, out, outl); 149280304Sjkim BIO_clear_retry_flags(b); 150280304Sjkim BIO_copy_next_retry(b); 151280304Sjkim return (ret); 152280304Sjkim} 153280304Sjkim 15468651Skrisstatic int linebuffer_write(BIO *b, const char *in, int inl) 155280304Sjkim{ 156280304Sjkim int i, num = 0, foundnl; 157280304Sjkim BIO_LINEBUFFER_CTX *ctx; 15868651Skris 159280304Sjkim if ((in == NULL) || (inl <= 0)) 160280304Sjkim return (0); 161280304Sjkim ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 162280304Sjkim if ((ctx == NULL) || (b->next_bio == NULL)) 163280304Sjkim return (0); 16468651Skris 165280304Sjkim BIO_clear_retry_flags(b); 16668651Skris 167280304Sjkim do { 168280304Sjkim const char *p; 16968651Skris 170280304Sjkim for (p = in; p < in + inl && *p != '\n'; p++) ; 171280304Sjkim if (*p == '\n') { 172280304Sjkim p++; 173280304Sjkim foundnl = 1; 174280304Sjkim } else 175280304Sjkim foundnl = 0; 17668651Skris 177280304Sjkim /* 178280304Sjkim * If a NL was found and we already have text in the save buffer, 179280304Sjkim * concatenate them and write 180280304Sjkim */ 181280304Sjkim while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 182280304Sjkim && ctx->obuf_len > 0) { 183280304Sjkim int orig_olen = ctx->obuf_len; 18468651Skris 185280304Sjkim i = ctx->obuf_size - ctx->obuf_len; 186280304Sjkim if (p - in > 0) { 187280304Sjkim if (i >= p - in) { 188280304Sjkim memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); 189280304Sjkim ctx->obuf_len += p - in; 190280304Sjkim inl -= p - in; 191280304Sjkim num += p - in; 192280304Sjkim in = p; 193280304Sjkim } else { 194280304Sjkim memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); 195280304Sjkim ctx->obuf_len += i; 196280304Sjkim inl -= i; 197280304Sjkim in += i; 198280304Sjkim num += i; 199280304Sjkim } 200280304Sjkim } 201100928Snectar#if 0 202280304Sjkim BIO_write(b->next_bio, "<*<", 3); 20368651Skris#endif 204280304Sjkim i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 205280304Sjkim if (i <= 0) { 206280304Sjkim ctx->obuf_len = orig_olen; 207280304Sjkim BIO_copy_next_retry(b); 20868651Skris 209100928Snectar#if 0 210280304Sjkim BIO_write(b->next_bio, ">*>", 3); 21168651Skris#endif 212280304Sjkim if (i < 0) 213280304Sjkim return ((num > 0) ? num : i); 214280304Sjkim if (i == 0) 215280304Sjkim return (num); 216280304Sjkim } 217100928Snectar#if 0 218280304Sjkim BIO_write(b->next_bio, ">*>", 3); 21968651Skris#endif 220280304Sjkim if (i < ctx->obuf_len) 221280304Sjkim memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); 222280304Sjkim ctx->obuf_len -= i; 223280304Sjkim } 22468651Skris 225280304Sjkim /* 226280304Sjkim * Now that the save buffer is emptied, let's write the input buffer 227280304Sjkim * if a NL was found and there is anything to write. 228280304Sjkim */ 229280304Sjkim if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { 230100928Snectar#if 0 231280304Sjkim BIO_write(b->next_bio, "<*<", 3); 23268651Skris#endif 233280304Sjkim i = BIO_write(b->next_bio, in, p - in); 234280304Sjkim if (i <= 0) { 235280304Sjkim BIO_copy_next_retry(b); 236100928Snectar#if 0 237280304Sjkim BIO_write(b->next_bio, ">*>", 3); 23868651Skris#endif 239280304Sjkim if (i < 0) 240280304Sjkim return ((num > 0) ? num : i); 241280304Sjkim if (i == 0) 242280304Sjkim return (num); 243280304Sjkim } 244100928Snectar#if 0 245280304Sjkim BIO_write(b->next_bio, ">*>", 3); 24668651Skris#endif 247280304Sjkim num += i; 248280304Sjkim in += i; 249280304Sjkim inl -= i; 250280304Sjkim } 251280304Sjkim } 252280304Sjkim while (foundnl && inl > 0); 253280304Sjkim /* 254280304Sjkim * We've written as much as we can. The rest of the input buffer, if 255280304Sjkim * any, is text that doesn't and with a NL and therefore needs to be 256280304Sjkim * saved for the next trip. 257280304Sjkim */ 258280304Sjkim if (inl > 0) { 259280304Sjkim memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 260280304Sjkim ctx->obuf_len += inl; 261280304Sjkim num += inl; 262280304Sjkim } 263280304Sjkim return num; 264280304Sjkim} 26568651Skris 26668651Skrisstatic long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 267280304Sjkim{ 268280304Sjkim BIO *dbio; 269280304Sjkim BIO_LINEBUFFER_CTX *ctx; 270280304Sjkim long ret = 1; 271280304Sjkim char *p; 272280304Sjkim int r; 273280304Sjkim int obs; 27468651Skris 275280304Sjkim ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 27668651Skris 277280304Sjkim switch (cmd) { 278280304Sjkim case BIO_CTRL_RESET: 279280304Sjkim ctx->obuf_len = 0; 280280304Sjkim if (b->next_bio == NULL) 281280304Sjkim return (0); 282280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 283280304Sjkim break; 284280304Sjkim case BIO_CTRL_INFO: 285280304Sjkim ret = (long)ctx->obuf_len; 286280304Sjkim break; 287280304Sjkim case BIO_CTRL_WPENDING: 288280304Sjkim ret = (long)ctx->obuf_len; 289280304Sjkim if (ret == 0) { 290280304Sjkim if (b->next_bio == NULL) 291280304Sjkim return (0); 292280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 293280304Sjkim } 294280304Sjkim break; 295280304Sjkim case BIO_C_SET_BUFF_SIZE: 296280304Sjkim obs = (int)num; 297280304Sjkim p = ctx->obuf; 298280304Sjkim if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { 299280304Sjkim p = (char *)OPENSSL_malloc((int)num); 300280304Sjkim if (p == NULL) 301280304Sjkim goto malloc_error; 302280304Sjkim } 303280304Sjkim if (ctx->obuf != p) { 304280304Sjkim if (ctx->obuf_len > obs) { 305280304Sjkim ctx->obuf_len = obs; 306280304Sjkim } 307280304Sjkim memcpy(p, ctx->obuf, ctx->obuf_len); 308280304Sjkim OPENSSL_free(ctx->obuf); 309280304Sjkim ctx->obuf = p; 310280304Sjkim ctx->obuf_size = obs; 311280304Sjkim } 312280304Sjkim break; 313280304Sjkim case BIO_C_DO_STATE_MACHINE: 314280304Sjkim if (b->next_bio == NULL) 315280304Sjkim return (0); 316280304Sjkim BIO_clear_retry_flags(b); 317280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 318280304Sjkim BIO_copy_next_retry(b); 319280304Sjkim break; 32068651Skris 321280304Sjkim case BIO_CTRL_FLUSH: 322280304Sjkim if (b->next_bio == NULL) 323280304Sjkim return (0); 324280304Sjkim if (ctx->obuf_len <= 0) { 325280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 326280304Sjkim break; 327280304Sjkim } 32868651Skris 329280304Sjkim for (;;) { 330280304Sjkim BIO_clear_retry_flags(b); 331280304Sjkim if (ctx->obuf_len > 0) { 332280304Sjkim r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 33368651Skris#if 0 334280304Sjkim fprintf(stderr, "FLUSH %3d -> %3d\n", ctx->obuf_len, r); 33568651Skris#endif 336280304Sjkim BIO_copy_next_retry(b); 337280304Sjkim if (r <= 0) 338280304Sjkim return ((long)r); 339280304Sjkim if (r < ctx->obuf_len) 340280304Sjkim memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); 341280304Sjkim ctx->obuf_len -= r; 342280304Sjkim } else { 343280304Sjkim ctx->obuf_len = 0; 344280304Sjkim ret = 1; 345280304Sjkim break; 346280304Sjkim } 347280304Sjkim } 348280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 349280304Sjkim break; 350280304Sjkim case BIO_CTRL_DUP: 351280304Sjkim dbio = (BIO *)ptr; 352280304Sjkim if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) 353280304Sjkim ret = 0; 354280304Sjkim break; 355280304Sjkim default: 356280304Sjkim if (b->next_bio == NULL) 357280304Sjkim return (0); 358280304Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 359280304Sjkim break; 360280304Sjkim } 361280304Sjkim return (ret); 362280304Sjkim malloc_error: 363280304Sjkim BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE); 364280304Sjkim return (0); 365280304Sjkim} 36668651Skris 36768651Skrisstatic long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 368280304Sjkim{ 369280304Sjkim long ret = 1; 37068651Skris 371280304Sjkim if (b->next_bio == NULL) 372280304Sjkim return (0); 373280304Sjkim switch (cmd) { 374280304Sjkim default: 375280304Sjkim ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 376280304Sjkim break; 377280304Sjkim } 378280304Sjkim return (ret); 379280304Sjkim} 38068651Skris 38168651Skrisstatic int linebuffer_gets(BIO *b, char *buf, int size) 382280304Sjkim{ 383280304Sjkim if (b->next_bio == NULL) 384280304Sjkim return (0); 385280304Sjkim return (BIO_gets(b->next_bio, buf, size)); 386280304Sjkim} 38768651Skris 38868651Skrisstatic int linebuffer_puts(BIO *b, const char *str) 389280304Sjkim{ 390280304Sjkim return (linebuffer_write(b, str, strlen(str))); 391280304Sjkim} 392