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. 8280297Sjkim * 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). 15280297Sjkim * 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. 22280297Sjkim * 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 :-). 37280297Sjkim * 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)" 40280297Sjkim * 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. 52280297Sjkim * 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 65280297Sjkimstatic 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 */ 75280297Sjkim#define DEFAULT_LINEBUFFER_SIZE 1024*10 7668651Skris 7768651Skris/* #define DEBUG */ 7868651Skris 79280297Sjkimstatic BIO_METHOD methods_linebuffer = { 80280297Sjkim BIO_TYPE_LINEBUFFER, 81280297Sjkim "linebuffer", 82280297Sjkim linebuffer_write, 83280297Sjkim linebuffer_read, 84280297Sjkim linebuffer_puts, 85280297Sjkim linebuffer_gets, 86280297Sjkim linebuffer_ctrl, 87280297Sjkim linebuffer_new, 88280297Sjkim linebuffer_free, 89280297Sjkim linebuffer_callback_ctrl, 90280297Sjkim}; 9168651Skris 9268651SkrisBIO_METHOD *BIO_f_linebuffer(void) 93280297Sjkim{ 94280297Sjkim return (&methods_linebuffer); 95280297Sjkim} 9668651Skris 97280297Sjkimtypedef struct bio_linebuffer_ctx_struct { 98280297Sjkim char *obuf; /* the output char array */ 99280297Sjkim int obuf_size; /* how big is the output buffer */ 100280297Sjkim int obuf_len; /* how many bytes are in it */ 101280297Sjkim} BIO_LINEBUFFER_CTX; 10268651Skris 10368651Skrisstatic int linebuffer_new(BIO *bi) 104280297Sjkim{ 105280297Sjkim BIO_LINEBUFFER_CTX *ctx; 10668651Skris 107280297Sjkim ctx = (BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX)); 108280297Sjkim if (ctx == NULL) 109280297Sjkim return (0); 110280297Sjkim ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 111280297Sjkim if (ctx->obuf == NULL) { 112280297Sjkim OPENSSL_free(ctx); 113280297Sjkim return (0); 114280297Sjkim } 115280297Sjkim ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; 116280297Sjkim ctx->obuf_len = 0; 11768651Skris 118280297Sjkim bi->init = 1; 119280297Sjkim bi->ptr = (char *)ctx; 120280297Sjkim bi->flags = 0; 121280297Sjkim return (1); 122280297Sjkim} 12368651Skris 12468651Skrisstatic int linebuffer_free(BIO *a) 125280297Sjkim{ 126280297Sjkim BIO_LINEBUFFER_CTX *b; 12768651Skris 128280297Sjkim if (a == NULL) 129280297Sjkim return (0); 130280297Sjkim b = (BIO_LINEBUFFER_CTX *)a->ptr; 131280297Sjkim if (b->obuf != NULL) 132280297Sjkim OPENSSL_free(b->obuf); 133280297Sjkim OPENSSL_free(a->ptr); 134280297Sjkim a->ptr = NULL; 135280297Sjkim a->init = 0; 136280297Sjkim a->flags = 0; 137280297Sjkim return (1); 138280297Sjkim} 139280297Sjkim 14068651Skrisstatic int linebuffer_read(BIO *b, char *out, int outl) 141280297Sjkim{ 142280297Sjkim int ret = 0; 14368651Skris 144280297Sjkim if (out == NULL) 145280297Sjkim return (0); 146280297Sjkim if (b->next_bio == NULL) 147280297Sjkim return (0); 148280297Sjkim ret = BIO_read(b->next_bio, out, outl); 149280297Sjkim BIO_clear_retry_flags(b); 150280297Sjkim BIO_copy_next_retry(b); 151280297Sjkim return (ret); 152280297Sjkim} 153280297Sjkim 15468651Skrisstatic int linebuffer_write(BIO *b, const char *in, int inl) 155280297Sjkim{ 156280297Sjkim int i, num = 0, foundnl; 157280297Sjkim BIO_LINEBUFFER_CTX *ctx; 15868651Skris 159280297Sjkim if ((in == NULL) || (inl <= 0)) 160280297Sjkim return (0); 161280297Sjkim ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 162280297Sjkim if ((ctx == NULL) || (b->next_bio == NULL)) 163280297Sjkim return (0); 16468651Skris 165280297Sjkim BIO_clear_retry_flags(b); 16668651Skris 167280297Sjkim do { 168280297Sjkim const char *p; 16968651Skris 170280297Sjkim for (p = in; p < in + inl && *p != '\n'; p++) ; 171280297Sjkim if (*p == '\n') { 172280297Sjkim p++; 173280297Sjkim foundnl = 1; 174280297Sjkim } else 175280297Sjkim foundnl = 0; 17668651Skris 177280297Sjkim /* 178280297Sjkim * If a NL was found and we already have text in the save buffer, 179280297Sjkim * concatenate them and write 180280297Sjkim */ 181280297Sjkim while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 182280297Sjkim && ctx->obuf_len > 0) { 183280297Sjkim int orig_olen = ctx->obuf_len; 18468651Skris 185280297Sjkim i = ctx->obuf_size - ctx->obuf_len; 186280297Sjkim if (p - in > 0) { 187280297Sjkim if (i >= p - in) { 188280297Sjkim memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); 189280297Sjkim ctx->obuf_len += p - in; 190280297Sjkim inl -= p - in; 191280297Sjkim num += p - in; 192280297Sjkim in = p; 193280297Sjkim } else { 194280297Sjkim memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); 195280297Sjkim ctx->obuf_len += i; 196280297Sjkim inl -= i; 197280297Sjkim in += i; 198280297Sjkim num += i; 199280297Sjkim } 200280297Sjkim } 201100928Snectar#if 0 202280297Sjkim BIO_write(b->next_bio, "<*<", 3); 20368651Skris#endif 204280297Sjkim i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 205280297Sjkim if (i <= 0) { 206280297Sjkim ctx->obuf_len = orig_olen; 207280297Sjkim BIO_copy_next_retry(b); 20868651Skris 209100928Snectar#if 0 210280297Sjkim BIO_write(b->next_bio, ">*>", 3); 21168651Skris#endif 212280297Sjkim if (i < 0) 213280297Sjkim return ((num > 0) ? num : i); 214280297Sjkim if (i == 0) 215280297Sjkim return (num); 216280297Sjkim } 217100928Snectar#if 0 218280297Sjkim BIO_write(b->next_bio, ">*>", 3); 21968651Skris#endif 220280297Sjkim if (i < ctx->obuf_len) 221280297Sjkim memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); 222280297Sjkim ctx->obuf_len -= i; 223280297Sjkim } 22468651Skris 225280297Sjkim /* 226280297Sjkim * Now that the save buffer is emptied, let's write the input buffer 227280297Sjkim * if a NL was found and there is anything to write. 228280297Sjkim */ 229280297Sjkim if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { 230100928Snectar#if 0 231280297Sjkim BIO_write(b->next_bio, "<*<", 3); 23268651Skris#endif 233280297Sjkim i = BIO_write(b->next_bio, in, p - in); 234280297Sjkim if (i <= 0) { 235280297Sjkim BIO_copy_next_retry(b); 236100928Snectar#if 0 237280297Sjkim BIO_write(b->next_bio, ">*>", 3); 23868651Skris#endif 239280297Sjkim if (i < 0) 240280297Sjkim return ((num > 0) ? num : i); 241280297Sjkim if (i == 0) 242280297Sjkim return (num); 243280297Sjkim } 244100928Snectar#if 0 245280297Sjkim BIO_write(b->next_bio, ">*>", 3); 24668651Skris#endif 247280297Sjkim num += i; 248280297Sjkim in += i; 249280297Sjkim inl -= i; 250280297Sjkim } 251280297Sjkim } 252280297Sjkim while (foundnl && inl > 0); 253280297Sjkim /* 254280297Sjkim * We've written as much as we can. The rest of the input buffer, if 255280297Sjkim * any, is text that doesn't and with a NL and therefore needs to be 256280297Sjkim * saved for the next trip. 257280297Sjkim */ 258280297Sjkim if (inl > 0) { 259280297Sjkim memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 260280297Sjkim ctx->obuf_len += inl; 261280297Sjkim num += inl; 262280297Sjkim } 263280297Sjkim return num; 264280297Sjkim} 26568651Skris 26668651Skrisstatic long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 267280297Sjkim{ 268280297Sjkim BIO *dbio; 269280297Sjkim BIO_LINEBUFFER_CTX *ctx; 270280297Sjkim long ret = 1; 271280297Sjkim char *p; 272280297Sjkim int r; 273280297Sjkim int obs; 27468651Skris 275280297Sjkim ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 27668651Skris 277280297Sjkim switch (cmd) { 278280297Sjkim case BIO_CTRL_RESET: 279280297Sjkim ctx->obuf_len = 0; 280280297Sjkim if (b->next_bio == NULL) 281280297Sjkim return (0); 282280297Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 283280297Sjkim break; 284280297Sjkim case BIO_CTRL_INFO: 285280297Sjkim ret = (long)ctx->obuf_len; 286280297Sjkim break; 287280297Sjkim case BIO_CTRL_WPENDING: 288280297Sjkim ret = (long)ctx->obuf_len; 289280297Sjkim if (ret == 0) { 290280297Sjkim if (b->next_bio == NULL) 291280297Sjkim return (0); 292280297Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 293280297Sjkim } 294280297Sjkim break; 295280297Sjkim case BIO_C_SET_BUFF_SIZE: 296280297Sjkim obs = (int)num; 297280297Sjkim p = ctx->obuf; 298280297Sjkim if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { 299280297Sjkim p = (char *)OPENSSL_malloc((int)num); 300280297Sjkim if (p == NULL) 301280297Sjkim goto malloc_error; 302280297Sjkim } 303280297Sjkim if (ctx->obuf != p) { 304280297Sjkim if (ctx->obuf_len > obs) { 305280297Sjkim ctx->obuf_len = obs; 306280297Sjkim } 307280297Sjkim memcpy(p, ctx->obuf, ctx->obuf_len); 308280297Sjkim OPENSSL_free(ctx->obuf); 309280297Sjkim ctx->obuf = p; 310280297Sjkim ctx->obuf_size = obs; 311280297Sjkim } 312280297Sjkim break; 313280297Sjkim case BIO_C_DO_STATE_MACHINE: 314280297Sjkim if (b->next_bio == NULL) 315280297Sjkim return (0); 316280297Sjkim BIO_clear_retry_flags(b); 317280297Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 318280297Sjkim BIO_copy_next_retry(b); 319280297Sjkim break; 32068651Skris 321280297Sjkim case BIO_CTRL_FLUSH: 322280297Sjkim if (b->next_bio == NULL) 323280297Sjkim return (0); 324280297Sjkim if (ctx->obuf_len <= 0) { 325280297Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 326280297Sjkim break; 327280297Sjkim } 32868651Skris 329280297Sjkim for (;;) { 330280297Sjkim BIO_clear_retry_flags(b); 331280297Sjkim if (ctx->obuf_len > 0) { 332280297Sjkim r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 33368651Skris#if 0 334280297Sjkim fprintf(stderr, "FLUSH %3d -> %3d\n", ctx->obuf_len, r); 33568651Skris#endif 336280297Sjkim BIO_copy_next_retry(b); 337280297Sjkim if (r <= 0) 338280297Sjkim return ((long)r); 339280297Sjkim if (r < ctx->obuf_len) 340280297Sjkim memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); 341280297Sjkim ctx->obuf_len -= r; 342280297Sjkim } else { 343280297Sjkim ctx->obuf_len = 0; 344280297Sjkim ret = 1; 345280297Sjkim break; 346280297Sjkim } 347280297Sjkim } 348280297Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 349280297Sjkim break; 350280297Sjkim case BIO_CTRL_DUP: 351280297Sjkim dbio = (BIO *)ptr; 352280297Sjkim if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) 353280297Sjkim ret = 0; 354280297Sjkim break; 355280297Sjkim default: 356280297Sjkim if (b->next_bio == NULL) 357280297Sjkim return (0); 358280297Sjkim ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 359280297Sjkim break; 360280297Sjkim } 361280297Sjkim return (ret); 362280297Sjkim malloc_error: 363280297Sjkim BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE); 364280297Sjkim return (0); 365280297Sjkim} 36668651Skris 36768651Skrisstatic long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 368280297Sjkim{ 369280297Sjkim long ret = 1; 37068651Skris 371280297Sjkim if (b->next_bio == NULL) 372280297Sjkim return (0); 373280297Sjkim switch (cmd) { 374280297Sjkim default: 375280297Sjkim ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 376280297Sjkim break; 377280297Sjkim } 378280297Sjkim return (ret); 379280297Sjkim} 38068651Skris 38168651Skrisstatic int linebuffer_gets(BIO *b, char *buf, int size) 382280297Sjkim{ 383280297Sjkim if (b->next_bio == NULL) 384280297Sjkim return (0); 385280297Sjkim return (BIO_gets(b->next_bio, buf, size)); 386280297Sjkim} 38768651Skris 38868651Skrisstatic int linebuffer_puts(BIO *b, const char *str) 389280297Sjkim{ 390280297Sjkim return (linebuffer_write(b, str, strlen(str))); 391280297Sjkim} 392