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. 8296465Sdelphij * 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). 15296465Sdelphij * 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. 22296465Sdelphij * 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 :-). 37296465Sdelphij * 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)" 40296465Sdelphij * 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. 52296465Sdelphij * 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 65296465Sdelphijstatic 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 */ 75296465Sdelphij#define DEFAULT_LINEBUFFER_SIZE 1024*10 7668651Skris 7768651Skris/* #define DEBUG */ 7868651Skris 79296465Sdelphijstatic BIO_METHOD methods_linebuffer = { 80296465Sdelphij BIO_TYPE_LINEBUFFER, 81296465Sdelphij "linebuffer", 82296465Sdelphij linebuffer_write, 83296465Sdelphij linebuffer_read, 84296465Sdelphij linebuffer_puts, 85296465Sdelphij linebuffer_gets, 86296465Sdelphij linebuffer_ctrl, 87296465Sdelphij linebuffer_new, 88296465Sdelphij linebuffer_free, 89296465Sdelphij linebuffer_callback_ctrl, 90296465Sdelphij}; 9168651Skris 9268651SkrisBIO_METHOD *BIO_f_linebuffer(void) 93296465Sdelphij{ 94296465Sdelphij return (&methods_linebuffer); 95296465Sdelphij} 9668651Skris 97296465Sdelphijtypedef struct bio_linebuffer_ctx_struct { 98296465Sdelphij char *obuf; /* the output char array */ 99296465Sdelphij int obuf_size; /* how big is the output buffer */ 100296465Sdelphij int obuf_len; /* how many bytes are in it */ 101296465Sdelphij} BIO_LINEBUFFER_CTX; 10268651Skris 10368651Skrisstatic int linebuffer_new(BIO *bi) 104296465Sdelphij{ 105296465Sdelphij BIO_LINEBUFFER_CTX *ctx; 10668651Skris 107296465Sdelphij ctx = (BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX)); 108296465Sdelphij if (ctx == NULL) 109296465Sdelphij return (0); 110296465Sdelphij ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 111296465Sdelphij if (ctx->obuf == NULL) { 112296465Sdelphij OPENSSL_free(ctx); 113296465Sdelphij return (0); 114296465Sdelphij } 115296465Sdelphij ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; 116296465Sdelphij ctx->obuf_len = 0; 11768651Skris 118296465Sdelphij bi->init = 1; 119296465Sdelphij bi->ptr = (char *)ctx; 120296465Sdelphij bi->flags = 0; 121296465Sdelphij return (1); 122296465Sdelphij} 12368651Skris 12468651Skrisstatic int linebuffer_free(BIO *a) 125296465Sdelphij{ 126296465Sdelphij BIO_LINEBUFFER_CTX *b; 12768651Skris 128296465Sdelphij if (a == NULL) 129296465Sdelphij return (0); 130296465Sdelphij b = (BIO_LINEBUFFER_CTX *)a->ptr; 131296465Sdelphij if (b->obuf != NULL) 132296465Sdelphij OPENSSL_free(b->obuf); 133296465Sdelphij OPENSSL_free(a->ptr); 134296465Sdelphij a->ptr = NULL; 135296465Sdelphij a->init = 0; 136296465Sdelphij a->flags = 0; 137296465Sdelphij return (1); 138296465Sdelphij} 139296465Sdelphij 14068651Skrisstatic int linebuffer_read(BIO *b, char *out, int outl) 141296465Sdelphij{ 142296465Sdelphij int ret = 0; 14368651Skris 144296465Sdelphij if (out == NULL) 145296465Sdelphij return (0); 146296465Sdelphij if (b->next_bio == NULL) 147296465Sdelphij return (0); 148296465Sdelphij ret = BIO_read(b->next_bio, out, outl); 149296465Sdelphij BIO_clear_retry_flags(b); 150296465Sdelphij BIO_copy_next_retry(b); 151296465Sdelphij return (ret); 152296465Sdelphij} 153296465Sdelphij 15468651Skrisstatic int linebuffer_write(BIO *b, const char *in, int inl) 155296465Sdelphij{ 156296465Sdelphij int i, num = 0, foundnl; 157296465Sdelphij BIO_LINEBUFFER_CTX *ctx; 15868651Skris 159296465Sdelphij if ((in == NULL) || (inl <= 0)) 160296465Sdelphij return (0); 161296465Sdelphij ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 162296465Sdelphij if ((ctx == NULL) || (b->next_bio == NULL)) 163296465Sdelphij return (0); 16468651Skris 165296465Sdelphij BIO_clear_retry_flags(b); 16668651Skris 167296465Sdelphij do { 168296465Sdelphij const char *p; 16968651Skris 170296465Sdelphij for (p = in; p < in + inl && *p != '\n'; p++) ; 171296465Sdelphij if (*p == '\n') { 172296465Sdelphij p++; 173296465Sdelphij foundnl = 1; 174296465Sdelphij } else 175296465Sdelphij foundnl = 0; 17668651Skris 177296465Sdelphij /* 178296465Sdelphij * If a NL was found and we already have text in the save buffer, 179296465Sdelphij * concatenate them and write 180296465Sdelphij */ 181296465Sdelphij while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 182296465Sdelphij && ctx->obuf_len > 0) { 183296465Sdelphij int orig_olen = ctx->obuf_len; 18468651Skris 185296465Sdelphij i = ctx->obuf_size - ctx->obuf_len; 186296465Sdelphij if (p - in > 0) { 187296465Sdelphij if (i >= p - in) { 188296465Sdelphij memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); 189296465Sdelphij ctx->obuf_len += p - in; 190296465Sdelphij inl -= p - in; 191296465Sdelphij num += p - in; 192296465Sdelphij in = p; 193296465Sdelphij } else { 194296465Sdelphij memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); 195296465Sdelphij ctx->obuf_len += i; 196296465Sdelphij inl -= i; 197296465Sdelphij in += i; 198296465Sdelphij num += i; 199296465Sdelphij } 200296465Sdelphij } 201100928Snectar#if 0 202296465Sdelphij BIO_write(b->next_bio, "<*<", 3); 20368651Skris#endif 204296465Sdelphij i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 205296465Sdelphij if (i <= 0) { 206296465Sdelphij ctx->obuf_len = orig_olen; 207296465Sdelphij BIO_copy_next_retry(b); 20868651Skris 209100928Snectar#if 0 210296465Sdelphij BIO_write(b->next_bio, ">*>", 3); 21168651Skris#endif 212296465Sdelphij if (i < 0) 213296465Sdelphij return ((num > 0) ? num : i); 214296465Sdelphij if (i == 0) 215296465Sdelphij return (num); 216296465Sdelphij } 217100928Snectar#if 0 218296465Sdelphij BIO_write(b->next_bio, ">*>", 3); 21968651Skris#endif 220296465Sdelphij if (i < ctx->obuf_len) 221296465Sdelphij memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); 222296465Sdelphij ctx->obuf_len -= i; 223296465Sdelphij } 22468651Skris 225296465Sdelphij /* 226296465Sdelphij * Now that the save buffer is emptied, let's write the input buffer 227296465Sdelphij * if a NL was found and there is anything to write. 228296465Sdelphij */ 229296465Sdelphij if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { 230100928Snectar#if 0 231296465Sdelphij BIO_write(b->next_bio, "<*<", 3); 23268651Skris#endif 233296465Sdelphij i = BIO_write(b->next_bio, in, p - in); 234296465Sdelphij if (i <= 0) { 235296465Sdelphij BIO_copy_next_retry(b); 236100928Snectar#if 0 237296465Sdelphij BIO_write(b->next_bio, ">*>", 3); 23868651Skris#endif 239296465Sdelphij if (i < 0) 240296465Sdelphij return ((num > 0) ? num : i); 241296465Sdelphij if (i == 0) 242296465Sdelphij return (num); 243296465Sdelphij } 244100928Snectar#if 0 245296465Sdelphij BIO_write(b->next_bio, ">*>", 3); 24668651Skris#endif 247296465Sdelphij num += i; 248296465Sdelphij in += i; 249296465Sdelphij inl -= i; 250296465Sdelphij } 251296465Sdelphij } 252296465Sdelphij while (foundnl && inl > 0); 253296465Sdelphij /* 254296465Sdelphij * We've written as much as we can. The rest of the input buffer, if 255296465Sdelphij * any, is text that doesn't and with a NL and therefore needs to be 256296465Sdelphij * saved for the next trip. 257296465Sdelphij */ 258296465Sdelphij if (inl > 0) { 259296465Sdelphij memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 260296465Sdelphij ctx->obuf_len += inl; 261296465Sdelphij num += inl; 262296465Sdelphij } 263296465Sdelphij return num; 264296465Sdelphij} 26568651Skris 26668651Skrisstatic long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 267296465Sdelphij{ 268296465Sdelphij BIO *dbio; 269296465Sdelphij BIO_LINEBUFFER_CTX *ctx; 270296465Sdelphij long ret = 1; 271296465Sdelphij char *p; 272296465Sdelphij int r; 273296465Sdelphij int obs; 27468651Skris 275296465Sdelphij ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 27668651Skris 277296465Sdelphij switch (cmd) { 278296465Sdelphij case BIO_CTRL_RESET: 279296465Sdelphij ctx->obuf_len = 0; 280296465Sdelphij if (b->next_bio == NULL) 281296465Sdelphij return (0); 282296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 283296465Sdelphij break; 284296465Sdelphij case BIO_CTRL_INFO: 285296465Sdelphij ret = (long)ctx->obuf_len; 286296465Sdelphij break; 287296465Sdelphij case BIO_CTRL_WPENDING: 288296465Sdelphij ret = (long)ctx->obuf_len; 289296465Sdelphij if (ret == 0) { 290296465Sdelphij if (b->next_bio == NULL) 291296465Sdelphij return (0); 292296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 293296465Sdelphij } 294296465Sdelphij break; 295296465Sdelphij case BIO_C_SET_BUFF_SIZE: 296296465Sdelphij obs = (int)num; 297296465Sdelphij p = ctx->obuf; 298296465Sdelphij if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { 299296465Sdelphij p = (char *)OPENSSL_malloc((int)num); 300296465Sdelphij if (p == NULL) 301296465Sdelphij goto malloc_error; 302296465Sdelphij } 303296465Sdelphij if (ctx->obuf != p) { 304296465Sdelphij if (ctx->obuf_len > obs) { 305296465Sdelphij ctx->obuf_len = obs; 306296465Sdelphij } 307296465Sdelphij memcpy(p, ctx->obuf, ctx->obuf_len); 308296465Sdelphij OPENSSL_free(ctx->obuf); 309296465Sdelphij ctx->obuf = p; 310296465Sdelphij ctx->obuf_size = obs; 311296465Sdelphij } 312296465Sdelphij break; 313296465Sdelphij case BIO_C_DO_STATE_MACHINE: 314296465Sdelphij if (b->next_bio == NULL) 315296465Sdelphij return (0); 316296465Sdelphij BIO_clear_retry_flags(b); 317296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 318296465Sdelphij BIO_copy_next_retry(b); 319296465Sdelphij break; 32068651Skris 321296465Sdelphij case BIO_CTRL_FLUSH: 322296465Sdelphij if (b->next_bio == NULL) 323296465Sdelphij return (0); 324296465Sdelphij if (ctx->obuf_len <= 0) { 325296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 326296465Sdelphij break; 327296465Sdelphij } 32868651Skris 329296465Sdelphij for (;;) { 330296465Sdelphij BIO_clear_retry_flags(b); 331296465Sdelphij if (ctx->obuf_len > 0) { 332296465Sdelphij r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 33368651Skris#if 0 334296465Sdelphij fprintf(stderr, "FLUSH %3d -> %3d\n", ctx->obuf_len, r); 33568651Skris#endif 336296465Sdelphij BIO_copy_next_retry(b); 337296465Sdelphij if (r <= 0) 338296465Sdelphij return ((long)r); 339296465Sdelphij if (r < ctx->obuf_len) 340296465Sdelphij memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); 341296465Sdelphij ctx->obuf_len -= r; 342296465Sdelphij } else { 343296465Sdelphij ctx->obuf_len = 0; 344296465Sdelphij ret = 1; 345296465Sdelphij break; 346296465Sdelphij } 347296465Sdelphij } 348296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 349296465Sdelphij break; 350296465Sdelphij case BIO_CTRL_DUP: 351296465Sdelphij dbio = (BIO *)ptr; 352296465Sdelphij if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) 353296465Sdelphij ret = 0; 354296465Sdelphij break; 355296465Sdelphij default: 356296465Sdelphij if (b->next_bio == NULL) 357296465Sdelphij return (0); 358296465Sdelphij ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 359296465Sdelphij break; 360296465Sdelphij } 361296465Sdelphij return (ret); 362296465Sdelphij malloc_error: 363296465Sdelphij BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE); 364296465Sdelphij return (0); 365296465Sdelphij} 36668651Skris 36768651Skrisstatic long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 368296465Sdelphij{ 369296465Sdelphij long ret = 1; 37068651Skris 371296465Sdelphij if (b->next_bio == NULL) 372296465Sdelphij return (0); 373296465Sdelphij switch (cmd) { 374296465Sdelphij default: 375296465Sdelphij ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 376296465Sdelphij break; 377296465Sdelphij } 378296465Sdelphij return (ret); 379296465Sdelphij} 38068651Skris 38168651Skrisstatic int linebuffer_gets(BIO *b, char *buf, int size) 382296465Sdelphij{ 383296465Sdelphij if (b->next_bio == NULL) 384296465Sdelphij return (0); 385296465Sdelphij return (BIO_gets(b->next_bio, buf, size)); 386296465Sdelphij} 38768651Skris 38868651Skrisstatic int linebuffer_puts(BIO *b, const char *str) 389296465Sdelphij{ 390296465Sdelphij return (linebuffer_write(b, str, strlen(str))); 391296465Sdelphij} 392