bf_lbuf.c revision 296465
1193323Sed/* crypto/bio/bf_buff.c */ 2193323Sed/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3193323Sed * All rights reserved. 4193323Sed * 5193323Sed * This package is an SSL implementation written 6193323Sed * by Eric Young (eay@cryptsoft.com). 7193323Sed * The implementation was written so as to conform with Netscapes SSL. 8193323Sed * 9193323Sed * This library is free for commercial and non-commercial use as long as 10193323Sed * the following conditions are aheared to. The following conditions 11193323Sed * apply to all code found in this distribution, be it the RC4, RSA, 12193323Sed * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13193323Sed * included with this distribution is covered by the same copyright terms 14193323Sed * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15193323Sed * 16193323Sed * Copyright remains Eric Young's, and as such any Copyright notices in 17193323Sed * the code are not to be removed. 18193323Sed * If this package is used in a product, Eric Young should be given attribution 19193323Sed * as the author of the parts of the library used. 20193323Sed * This can be in the form of a textual message at program startup or 21193323Sed * in documentation (online or textual) provided with the package. 22193323Sed * 23193323Sed * Redistribution and use in source and binary forms, with or without 24193323Sed * modification, are permitted provided that the following conditions 25193323Sed * are met: 26193323Sed * 1. Redistributions of source code must retain the copyright 27193323Sed * notice, this list of conditions and the following disclaimer. 28193323Sed * 2. Redistributions in binary form must reproduce the above copyright 29193323Sed * notice, this list of conditions and the following disclaimer in the 30193323Sed * documentation and/or other materials provided with the distribution. 31193323Sed * 3. All advertising materials mentioning features or use of this software 32193323Sed * must display the following acknowledgement: 33193323Sed * "This product includes cryptographic software written by 34193323Sed * Eric Young (eay@cryptsoft.com)" 35193323Sed * The word 'cryptographic' can be left out if the rouines from the library 36193323Sed * being used are not cryptographic related :-). 37193323Sed * 4. If you include any Windows specific code (or a derivative thereof) from 38193323Sed * the apps directory (application code) you must include an acknowledgement: 39193323Sed * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40193323Sed * 41193323Sed * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51193323Sed * SUCH DAMAGE. 52193323Sed * 53193323Sed * The licence and distribution terms for any publically available version or 54193323Sed * derivative of this code cannot be changed. i.e. this code cannot simply be 55193323Sed * copied and put under another distribution licence 56193323Sed * [including the GNU Public Licence.] 57193323Sed */ 58193323Sed 59193323Sed#include <stdio.h> 60193323Sed#include <errno.h> 61193323Sed#include "cryptlib.h" 62193323Sed#include <openssl/bio.h> 63193323Sed#include <openssl/evp.h> 64193323Sed 65193323Sedstatic int linebuffer_write(BIO *h, const char *buf, int num); 66193323Sedstatic int linebuffer_read(BIO *h, char *buf, int size); 67193323Sedstatic int linebuffer_puts(BIO *h, const char *str); 68193323Sedstatic int linebuffer_gets(BIO *h, char *str, int size); 69193323Sedstatic long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 70193323Sedstatic int linebuffer_new(BIO *h); 71193323Sedstatic int linebuffer_free(BIO *data); 72193323Sedstatic long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 73193323Sed 74193323Sed/* A 10k maximum should be enough for most purposes */ 75193323Sed#define DEFAULT_LINEBUFFER_SIZE 1024*10 76193323Sed 77193323Sed/* #define DEBUG */ 78193323Sed 79193323Sedstatic BIO_METHOD methods_linebuffer = { 80193323Sed BIO_TYPE_LINEBUFFER, 81193323Sed "linebuffer", 82193323Sed linebuffer_write, 83193323Sed linebuffer_read, 84193323Sed linebuffer_puts, 85193323Sed linebuffer_gets, 86193323Sed linebuffer_ctrl, 87193323Sed linebuffer_new, 88193323Sed linebuffer_free, 89193323Sed linebuffer_callback_ctrl, 90193323Sed}; 91193323Sed 92193323SedBIO_METHOD *BIO_f_linebuffer(void) 93193323Sed{ 94193323Sed return (&methods_linebuffer); 95193323Sed} 96193323Sed 97193323Sedtypedef struct bio_linebuffer_ctx_struct { 98193323Sed char *obuf; /* the output char array */ 99193323Sed int obuf_size; /* how big is the output buffer */ 100193323Sed int obuf_len; /* how many bytes are in it */ 101193323Sed} BIO_LINEBUFFER_CTX; 102193323Sed 103193323Sedstatic int linebuffer_new(BIO *bi) 104193323Sed{ 105193323Sed BIO_LINEBUFFER_CTX *ctx; 106193323Sed 107193323Sed ctx = (BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX)); 108193323Sed if (ctx == NULL) 109193323Sed return (0); 110193323Sed ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 111193323Sed if (ctx->obuf == NULL) { 112193323Sed OPENSSL_free(ctx); 113193323Sed return (0); 114193323Sed } 115193323Sed ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; 116193323Sed ctx->obuf_len = 0; 117193323Sed 118193323Sed bi->init = 1; 119193323Sed bi->ptr = (char *)ctx; 120193323Sed bi->flags = 0; 121193323Sed return (1); 122193323Sed} 123193323Sed 124193323Sedstatic int linebuffer_free(BIO *a) 125193323Sed{ 126193323Sed BIO_LINEBUFFER_CTX *b; 127193323Sed 128193323Sed if (a == NULL) 129193323Sed return (0); 130193323Sed b = (BIO_LINEBUFFER_CTX *)a->ptr; 131193323Sed if (b->obuf != NULL) 132193323Sed OPENSSL_free(b->obuf); 133193323Sed OPENSSL_free(a->ptr); 134193323Sed a->ptr = NULL; 135193323Sed a->init = 0; 136193323Sed a->flags = 0; 137193323Sed return (1); 138193323Sed} 139193323Sed 140193323Sedstatic int linebuffer_read(BIO *b, char *out, int outl) 141193323Sed{ 142193323Sed int ret = 0; 143193323Sed 144193323Sed if (out == NULL) 145193323Sed return (0); 146193323Sed if (b->next_bio == NULL) 147193323Sed return (0); 148193323Sed ret = BIO_read(b->next_bio, out, outl); 149193323Sed BIO_clear_retry_flags(b); 150193323Sed BIO_copy_next_retry(b); 151193323Sed return (ret); 152193323Sed} 153193323Sed 154193323Sedstatic int linebuffer_write(BIO *b, const char *in, int inl) 155193323Sed{ 156193323Sed int i, num = 0, foundnl; 157193323Sed BIO_LINEBUFFER_CTX *ctx; 158193323Sed 159193323Sed if ((in == NULL) || (inl <= 0)) 160193323Sed return (0); 161193323Sed ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 162193323Sed if ((ctx == NULL) || (b->next_bio == NULL)) 163193323Sed return (0); 164193323Sed 165193323Sed BIO_clear_retry_flags(b); 166193323Sed 167193323Sed do { 168193323Sed const char *p; 169193323Sed 170193323Sed for (p = in; p < in + inl && *p != '\n'; p++) ; 171193323Sed if (*p == '\n') { 172193323Sed p++; 173193323Sed foundnl = 1; 174193323Sed } else 175193323Sed foundnl = 0; 176193323Sed 177193323Sed /* 178193323Sed * If a NL was found and we already have text in the save buffer, 179193323Sed * concatenate them and write 180193323Sed */ 181193323Sed while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 182193323Sed && ctx->obuf_len > 0) { 183193323Sed int orig_olen = ctx->obuf_len; 184193323Sed 185193323Sed i = ctx->obuf_size - ctx->obuf_len; 186193323Sed if (p - in > 0) { 187193323Sed if (i >= p - in) { 188193323Sed memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); 189193323Sed ctx->obuf_len += p - in; 190193323Sed inl -= p - in; 191193323Sed num += p - in; 192193323Sed in = p; 193193323Sed } else { 194193323Sed memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); 195193323Sed ctx->obuf_len += i; 196193323Sed inl -= i; 197193323Sed in += i; 198193323Sed num += i; 199193323Sed } 200193323Sed } 201193323Sed#if 0 202193323Sed BIO_write(b->next_bio, "<*<", 3); 203193323Sed#endif 204193323Sed i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 205193323Sed if (i <= 0) { 206193323Sed ctx->obuf_len = orig_olen; 207193323Sed BIO_copy_next_retry(b); 208193323Sed 209193323Sed#if 0 210193323Sed BIO_write(b->next_bio, ">*>", 3); 211193323Sed#endif 212193323Sed if (i < 0) 213193323Sed return ((num > 0) ? num : i); 214193323Sed if (i == 0) 215193323Sed return (num); 216193323Sed } 217193323Sed#if 0 218193323Sed BIO_write(b->next_bio, ">*>", 3); 219193323Sed#endif 220193323Sed if (i < ctx->obuf_len) 221193323Sed memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); 222193323Sed ctx->obuf_len -= i; 223193323Sed } 224193323Sed 225193323Sed /* 226193323Sed * Now that the save buffer is emptied, let's write the input buffer 227193323Sed * if a NL was found and there is anything to write. 228193323Sed */ 229193323Sed if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { 230193323Sed#if 0 231193323Sed BIO_write(b->next_bio, "<*<", 3); 232193323Sed#endif 233193323Sed i = BIO_write(b->next_bio, in, p - in); 234193323Sed if (i <= 0) { 235193323Sed BIO_copy_next_retry(b); 236193323Sed#if 0 237193323Sed BIO_write(b->next_bio, ">*>", 3); 238193323Sed#endif 239193323Sed if (i < 0) 240193323Sed return ((num > 0) ? num : i); 241193323Sed if (i == 0) 242193323Sed return (num); 243193323Sed } 244193323Sed#if 0 245193323Sed BIO_write(b->next_bio, ">*>", 3); 246193323Sed#endif 247193323Sed num += i; 248193323Sed in += i; 249193323Sed inl -= i; 250193323Sed } 251193323Sed } 252193323Sed while (foundnl && inl > 0); 253193323Sed /* 254193323Sed * We've written as much as we can. The rest of the input buffer, if 255193323Sed * any, is text that doesn't and with a NL and therefore needs to be 256193323Sed * saved for the next trip. 257193323Sed */ 258193323Sed if (inl > 0) { 259193323Sed memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 260193323Sed ctx->obuf_len += inl; 261193323Sed num += inl; 262193323Sed } 263193323Sed return num; 264193323Sed} 265193323Sed 266193323Sedstatic long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 267193323Sed{ 268193323Sed BIO *dbio; 269193323Sed BIO_LINEBUFFER_CTX *ctx; 270193323Sed long ret = 1; 271193323Sed char *p; 272193323Sed int r; 273193323Sed int obs; 274193323Sed 275193323Sed ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 276193323Sed 277193323Sed switch (cmd) { 278193323Sed case BIO_CTRL_RESET: 279193323Sed ctx->obuf_len = 0; 280193323Sed if (b->next_bio == NULL) 281193323Sed return (0); 282193323Sed ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 283193323Sed break; 284193323Sed case BIO_CTRL_INFO: 285193323Sed ret = (long)ctx->obuf_len; 286193323Sed break; 287193323Sed case BIO_CTRL_WPENDING: 288193323Sed ret = (long)ctx->obuf_len; 289193323Sed if (ret == 0) { 290193323Sed if (b->next_bio == NULL) 291193323Sed return (0); 292193323Sed ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 293193323Sed } 294193323Sed break; 295193323Sed case BIO_C_SET_BUFF_SIZE: 296193323Sed obs = (int)num; 297193323Sed p = ctx->obuf; 298193323Sed if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { 299193323Sed p = (char *)OPENSSL_malloc((int)num); 300193323Sed if (p == NULL) 301193323Sed goto malloc_error; 302193323Sed } 303193323Sed if (ctx->obuf != p) { 304193323Sed if (ctx->obuf_len > obs) { 305193323Sed ctx->obuf_len = obs; 306193323Sed } 307193323Sed memcpy(p, ctx->obuf, ctx->obuf_len); 308193323Sed OPENSSL_free(ctx->obuf); 309193323Sed ctx->obuf = p; 310193323Sed ctx->obuf_size = obs; 311193323Sed } 312193323Sed break; 313193323Sed case BIO_C_DO_STATE_MACHINE: 314193323Sed if (b->next_bio == NULL) 315193323Sed return (0); 316193323Sed BIO_clear_retry_flags(b); 317193323Sed ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 318193323Sed BIO_copy_next_retry(b); 319193323Sed break; 320193323Sed 321193323Sed case BIO_CTRL_FLUSH: 322193323Sed if (b->next_bio == NULL) 323193323Sed return (0); 324193323Sed if (ctx->obuf_len <= 0) { 325193323Sed ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 326193323Sed break; 327193323Sed } 328193323Sed 329193323Sed for (;;) { 330193323Sed BIO_clear_retry_flags(b); 331193323Sed if (ctx->obuf_len > 0) { 332193323Sed r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 333193323Sed#if 0 334193323Sed fprintf(stderr, "FLUSH %3d -> %3d\n", ctx->obuf_len, r); 335193323Sed#endif 336193323Sed BIO_copy_next_retry(b); 337193323Sed if (r <= 0) 338193323Sed return ((long)r); 339193323Sed if (r < ctx->obuf_len) 340193323Sed memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); 341193323Sed ctx->obuf_len -= r; 342193323Sed } else { 343193323Sed ctx->obuf_len = 0; 344193323Sed ret = 1; 345193323Sed break; 346193323Sed } 347193323Sed } 348193323Sed ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 349193323Sed break; 350193323Sed case BIO_CTRL_DUP: 351193323Sed dbio = (BIO *)ptr; 352193323Sed if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) 353193323Sed ret = 0; 354193323Sed break; 355193323Sed default: 356193323Sed if (b->next_bio == NULL) 357193323Sed return (0); 358193323Sed ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 359193323Sed break; 360193323Sed } 361193323Sed return (ret); 362193323Sed malloc_error: 363193323Sed BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE); 364193323Sed return (0); 365193323Sed} 366193323Sed 367193323Sedstatic long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 368193323Sed{ 369193323Sed long ret = 1; 370193323Sed 371193323Sed if (b->next_bio == NULL) 372193323Sed return (0); 373193323Sed switch (cmd) { 374193323Sed default: 375193323Sed ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 376193323Sed break; 377193323Sed } 378193323Sed return (ret); 379193323Sed} 380193323Sed 381193323Sedstatic int linebuffer_gets(BIO *b, char *buf, int size) 382193323Sed{ 383193323Sed if (b->next_bio == NULL) 384193323Sed return (0); 385193323Sed return (BIO_gets(b->next_bio, buf, size)); 386193323Sed} 387193323Sed 388193323Sedstatic int linebuffer_puts(BIO *b, const char *str) 389193323Sed{ 390193323Sed return (linebuffer_write(b, str, strlen(str))); 391193323Sed} 392193323Sed