bf_lbuf.c revision 280304
1223328Sgavin/* crypto/bio/bf_buff.c */ 2223328Sgavin/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 379971Sobrien * All rights reserved. 479971Sobrien * 5223328Sgavin * This package is an SSL implementation written 679971Sobrien * by Eric Young (eay@cryptsoft.com). 779971Sobrien * The implementation was written so as to conform with Netscapes SSL. 879971Sobrien * 979971Sobrien * This library is free for commercial and non-commercial use as long as 1079971Sobrien * the following conditions are aheared to. The following conditions 1179971Sobrien * apply to all code found in this distribution, be it the RC4, RSA, 1279971Sobrien * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1379971Sobrien * included with this distribution is covered by the same copyright terms 1479971Sobrien * except that the holder is Tim Hudson (tjh@cryptsoft.com). 1579971Sobrien * 1679971Sobrien * Copyright remains Eric Young's, and as such any Copyright notices in 1779971Sobrien * the code are not to be removed. 1879971Sobrien * If this package is used in a product, Eric Young should be given attribution 1979971Sobrien * as the author of the parts of the library used. 2079971Sobrien * This can be in the form of a textual message at program startup or 2179971Sobrien * in documentation (online or textual) provided with the package. 2279971Sobrien * 2379971Sobrien * Redistribution and use in source and binary forms, with or without 2479971Sobrien * modification, are permitted provided that the following conditions 2579971Sobrien * are met: 2679971Sobrien * 1. Redistributions of source code must retain the copyright 2779971Sobrien * notice, this list of conditions and the following disclaimer. 2879971Sobrien * 2. Redistributions in binary form must reproduce the above copyright 2979971Sobrien * notice, this list of conditions and the following disclaimer in the 3079971Sobrien * documentation and/or other materials provided with the distribution. 3179971Sobrien * 3. All advertising materials mentioning features or use of this software 3279971Sobrien * must display the following acknowledgement: 3379971Sobrien * "This product includes cryptographic software written by 3479971Sobrien * Eric Young (eay@cryptsoft.com)" 3579971Sobrien * The word 'cryptographic' can be left out if the rouines from the library 3679971Sobrien * being used are not cryptographic related :-). 3779971Sobrien * 4. If you include any Windows specific code (or a derivative thereof) from 3879971Sobrien * the apps directory (application code) you must include an acknowledgement: 3979971Sobrien * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 4079971Sobrien * 4179971Sobrien * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4279971Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4379971Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4479971Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45121966Smikeh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4679971Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4779971Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4879971Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4979971Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5079971Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5179971Sobrien * SUCH DAMAGE. 5279971Sobrien * 5379971Sobrien * The licence and distribution terms for any publically available version or 5479971Sobrien * derivative of this code cannot be changed. i.e. this code cannot simply be 5579971Sobrien * copied and put under another distribution licence 5679971Sobrien * [including the GNU Public Licence.] 5779971Sobrien */ 5879971Sobrien 5979971Sobrien#include <stdio.h> 6079971Sobrien#include <errno.h> 6179971Sobrien#include "cryptlib.h" 6279971Sobrien#include <openssl/bio.h> 6379971Sobrien#include <openssl/evp.h> 6479971Sobrien 65146309Smikehstatic int linebuffer_write(BIO *h, const char *buf, int num); 6679971Sobrienstatic int linebuffer_read(BIO *h, char *buf, int size); 6779971Sobrienstatic int linebuffer_puts(BIO *h, const char *str); 6879971Sobrienstatic int linebuffer_gets(BIO *h, char *str, int size); 6979971Sobrienstatic long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 7079971Sobrienstatic int linebuffer_new(BIO *h); 7179971Sobrienstatic int linebuffer_free(BIO *data); 7279971Sobrienstatic long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 7379971Sobrien 7479971Sobrien/* A 10k maximum should be enough for most purposes */ 7579971Sobrien#define DEFAULT_LINEBUFFER_SIZE 1024*10 7679971Sobrien 77146309Smikeh/* #define DEBUG */ 7879971Sobrien 7979971Sobrienstatic BIO_METHOD methods_linebuffer = { 8079971Sobrien BIO_TYPE_LINEBUFFER, 8179971Sobrien "linebuffer", 8279971Sobrien linebuffer_write, 8379971Sobrien linebuffer_read, 8479971Sobrien linebuffer_puts, 8579971Sobrien linebuffer_gets, 8679971Sobrien linebuffer_ctrl, 8779971Sobrien linebuffer_new, 8879971Sobrien linebuffer_free, 8979971Sobrien linebuffer_callback_ctrl, 9079971Sobrien}; 91223328Sgavin 92223328SgavinBIO_METHOD *BIO_f_linebuffer(void) 93223328Sgavin{ 94223328Sgavin return (&methods_linebuffer); 95116424Smikeh} 96116424Smikeh 97223328Sgavintypedef struct bio_linebuffer_ctx_struct { 98223328Sgavin char *obuf; /* the output char array */ 99223328Sgavin int obuf_size; /* how big is the output buffer */ 100116424Smikeh int obuf_len; /* how many bytes are in it */ 101116424Smikeh} BIO_LINEBUFFER_CTX; 102116424Smikeh 103116424Smikehstatic int linebuffer_new(BIO *bi) 104116424Smikeh{ 105116424Smikeh BIO_LINEBUFFER_CTX *ctx; 106223328Sgavin 107116424Smikeh ctx = (BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX)); 108116424Smikeh if (ctx == NULL) 109116424Smikeh return (0); 11079971Sobrien ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 11179971Sobrien if (ctx->obuf == NULL) { 11279971Sobrien OPENSSL_free(ctx); 113116424Smikeh return (0); 114116424Smikeh } 11579971Sobrien ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; 116116424Smikeh ctx->obuf_len = 0; 117116424Smikeh 118116424Smikeh bi->init = 1; 119116424Smikeh bi->ptr = (char *)ctx; 120116424Smikeh bi->flags = 0; 121142129Smikeh return (1); 122116424Smikeh} 123116424Smikeh 124116424Smikehstatic int linebuffer_free(BIO *a) 125223328Sgavin{ 126116424Smikeh BIO_LINEBUFFER_CTX *b; 127116424Smikeh 12879971Sobrien if (a == NULL) 129223328Sgavin return (0); 130223328Sgavin b = (BIO_LINEBUFFER_CTX *)a->ptr; 13179971Sobrien if (b->obuf != NULL) 13279971Sobrien OPENSSL_free(b->obuf); 13379971Sobrien OPENSSL_free(a->ptr); 13479971Sobrien a->ptr = NULL; 13579971Sobrien a->init = 0; 13679971Sobrien a->flags = 0; 13779971Sobrien return (1); 13879971Sobrien} 139223328Sgavin 14079971Sobrienstatic int linebuffer_read(BIO *b, char *out, int outl) 14179971Sobrien{ 14279971Sobrien int ret = 0; 143223328Sgavin 14479971Sobrien if (out == NULL) 14579971Sobrien return (0); 14698247Smikeh if (b->next_bio == NULL) 147223328Sgavin return (0); 148223328Sgavin ret = BIO_read(b->next_bio, out, outl); 149232779Sgavin BIO_clear_retry_flags(b); 150223328Sgavin BIO_copy_next_retry(b); 15179971Sobrien return (ret); 152223328Sgavin} 153223328Sgavin 15498247Smikehstatic int linebuffer_write(BIO *b, const char *in, int inl) 155223328Sgavin{ 15698247Smikeh int i, num = 0, foundnl; 15779971Sobrien BIO_LINEBUFFER_CTX *ctx; 158142129Smikeh 159142129Smikeh if ((in == NULL) || (inl <= 0)) 16079971Sobrien return (0); 16179971Sobrien ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 16279971Sobrien if ((ctx == NULL) || (b->next_bio == NULL)) 16379971Sobrien return (0); 16479971Sobrien 16579971Sobrien BIO_clear_retry_flags(b); 16679971Sobrien 16779971Sobrien do { 16879971Sobrien const char *p; 16979971Sobrien 17079971Sobrien for (p = in; p < in + inl && *p != '\n'; p++) ; 17179971Sobrien if (*p == '\n') { 17279971Sobrien p++; 17379971Sobrien foundnl = 1; 17479971Sobrien } else 17579971Sobrien foundnl = 0; 17679971Sobrien 17779971Sobrien /* 17879971Sobrien * If a NL was found and we already have text in the save buffer, 17979971Sobrien * concatenate them and write 18079971Sobrien */ 18179971Sobrien while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 18279971Sobrien && ctx->obuf_len > 0) { 18379971Sobrien int orig_olen = ctx->obuf_len; 18479971Sobrien 18579971Sobrien i = ctx->obuf_size - ctx->obuf_len; 18679971Sobrien if (p - in > 0) { 18779971Sobrien if (i >= p - in) { 18879971Sobrien memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); 18979971Sobrien ctx->obuf_len += p - in; 19079971Sobrien inl -= p - in; 19179971Sobrien num += p - in; 19279971Sobrien in = p; 193223328Sgavin } else { 19479971Sobrien memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); 19579971Sobrien ctx->obuf_len += i; 196223328Sgavin inl -= i; 19779971Sobrien in += i; 19879971Sobrien num += i; 199223328Sgavin } 200223328Sgavin } 20179971Sobrien#if 0 20279971Sobrien BIO_write(b->next_bio, "<*<", 3); 20379971Sobrien#endif 204223328Sgavin i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 20595504Smikeh if (i <= 0) { 206223328Sgavin ctx->obuf_len = orig_olen; 207223328Sgavin BIO_copy_next_retry(b); 208223328Sgavin 20979971Sobrien#if 0 21098247Smikeh BIO_write(b->next_bio, ">*>", 3); 21198247Smikeh#endif 21298247Smikeh if (i < 0) 21398247Smikeh return ((num > 0) ? num : i); 21498247Smikeh if (i == 0) 215223328Sgavin return (num); 21679971Sobrien } 21779971Sobrien#if 0 21879971Sobrien BIO_write(b->next_bio, ">*>", 3); 21979971Sobrien#endif 22079971Sobrien if (i < ctx->obuf_len) 22179971Sobrien memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); 22279971Sobrien ctx->obuf_len -= i; 22379971Sobrien } 22479971Sobrien 22579971Sobrien /* 22679971Sobrien * Now that the save buffer is emptied, let's write the input buffer 22779971Sobrien * if a NL was found and there is anything to write. 22879971Sobrien */ 22979971Sobrien if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { 23079971Sobrien#if 0 23179971Sobrien BIO_write(b->next_bio, "<*<", 3); 23279971Sobrien#endif 233223328Sgavin i = BIO_write(b->next_bio, in, p - in); 23479971Sobrien if (i <= 0) { 23579971Sobrien BIO_copy_next_retry(b); 23698247Smikeh#if 0 23779971Sobrien BIO_write(b->next_bio, ">*>", 3); 23879971Sobrien#endif 23998247Smikeh if (i < 0) 24079971Sobrien return ((num > 0) ? num : i); 24179971Sobrien if (i == 0) 24279971Sobrien return (num); 24379971Sobrien } 24479971Sobrien#if 0 24579971Sobrien BIO_write(b->next_bio, ">*>", 3); 24679971Sobrien#endif 24779971Sobrien num += i; 24879971Sobrien in += i; 24979971Sobrien inl -= i; 25079971Sobrien } 25179971Sobrien } 25279971Sobrien while (foundnl && inl > 0); 25379971Sobrien /* 25479971Sobrien * We've written as much as we can. The rest of the input buffer, if 25579971Sobrien * any, is text that doesn't and with a NL and therefore needs to be 25679971Sobrien * saved for the next trip. 25779971Sobrien */ 25879971Sobrien if (inl > 0) { 25979971Sobrien memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 26079971Sobrien ctx->obuf_len += inl; 26179971Sobrien num += inl; 26279971Sobrien } 26379971Sobrien return num; 26479971Sobrien} 26579971Sobrien 26679971Sobrienstatic long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 26779971Sobrien{ 26879971Sobrien BIO *dbio; 26979971Sobrien BIO_LINEBUFFER_CTX *ctx; 27079971Sobrien long ret = 1; 27179971Sobrien char *p; 27279971Sobrien int r; 27379971Sobrien int obs; 274223328Sgavin 27579971Sobrien ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 27695504Smikeh 27795504Smikeh switch (cmd) { 27895504Smikeh case BIO_CTRL_RESET: 27995504Smikeh ctx->obuf_len = 0; 28095504Smikeh if (b->next_bio == NULL) 28198247Smikeh return (0); 28295504Smikeh ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 28398247Smikeh break; 28498247Smikeh case BIO_CTRL_INFO: 28598247Smikeh ret = (long)ctx->obuf_len; 28695504Smikeh break; 28795504Smikeh case BIO_CTRL_WPENDING: 28879971Sobrien ret = (long)ctx->obuf_len; 28979971Sobrien if (ret == 0) { 29079971Sobrien if (b->next_bio == NULL) 29179971Sobrien return (0); 29279971Sobrien ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 29379971Sobrien } 29479971Sobrien break; 29579971Sobrien case BIO_C_SET_BUFF_SIZE: 29679971Sobrien obs = (int)num; 29779971Sobrien p = ctx->obuf; 29879971Sobrien if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { 299223328Sgavin p = (char *)OPENSSL_malloc((int)num); 30079971Sobrien if (p == NULL) 30179971Sobrien goto malloc_error; 30279971Sobrien } 30379971Sobrien if (ctx->obuf != p) { 30479971Sobrien if (ctx->obuf_len > obs) { 30579971Sobrien ctx->obuf_len = obs; 30679971Sobrien } 30779971Sobrien memcpy(p, ctx->obuf, ctx->obuf_len); 30879971Sobrien OPENSSL_free(ctx->obuf); 30979971Sobrien ctx->obuf = p; 31079971Sobrien ctx->obuf_size = obs; 31179971Sobrien } 31279971Sobrien break; 31379971Sobrien case BIO_C_DO_STATE_MACHINE: 31479971Sobrien if (b->next_bio == NULL) 31579971Sobrien return (0); 31679971Sobrien BIO_clear_retry_flags(b); 31779971Sobrien ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 31879971Sobrien BIO_copy_next_retry(b); 31979971Sobrien break; 32079971Sobrien 32179971Sobrien case BIO_CTRL_FLUSH: 32279971Sobrien if (b->next_bio == NULL) 32379971Sobrien return (0); 32498247Smikeh if (ctx->obuf_len <= 0) { 32598247Smikeh ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 32698247Smikeh break; 32798247Smikeh } 32898247Smikeh 32998247Smikeh for (;;) { 33098247Smikeh BIO_clear_retry_flags(b); 33179971Sobrien if (ctx->obuf_len > 0) { 33279971Sobrien r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 33379971Sobrien#if 0 33479971Sobrien fprintf(stderr, "FLUSH %3d -> %3d\n", ctx->obuf_len, r); 33579971Sobrien#endif 33679971Sobrien BIO_copy_next_retry(b); 33779971Sobrien if (r <= 0) 33879971Sobrien return ((long)r); 33979971Sobrien if (r < ctx->obuf_len) 34079971Sobrien memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); 34179971Sobrien ctx->obuf_len -= r; 34279971Sobrien } else { 34379971Sobrien ctx->obuf_len = 0; 34479971Sobrien ret = 1; 34579971Sobrien break; 346116424Smikeh } 347116424Smikeh } 348116424Smikeh ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 349223328Sgavin break; 350116424Smikeh case BIO_CTRL_DUP: 351116424Smikeh dbio = (BIO *)ptr; 35279971Sobrien if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) 35379971Sobrien ret = 0; 35479971Sobrien break; 355223328Sgavin default: 35679971Sobrien if (b->next_bio == NULL) 35779971Sobrien return (0); 35879971Sobrien ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 35979971Sobrien break; 36079971Sobrien } 36179971Sobrien return (ret); 362223328Sgavin malloc_error: 363223328Sgavin BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE); 364223328Sgavin return (0); 365223328Sgavin} 36679971Sobrien 36779971Sobrienstatic long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 36879971Sobrien{ 36979971Sobrien long ret = 1; 37079971Sobrien 37179971Sobrien if (b->next_bio == NULL) 37279971Sobrien return (0); 37379971Sobrien switch (cmd) { 374223328Sgavin default: 37579971Sobrien ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 37679971Sobrien break; 37779971Sobrien } 378223328Sgavin return (ret); 379223328Sgavin} 380223328Sgavin 38179971Sobrienstatic int linebuffer_gets(BIO *b, char *buf, int size) 38279971Sobrien{ 38379971Sobrien if (b->next_bio == NULL) 384223328Sgavin return (0); 385223328Sgavin return (BIO_gets(b->next_bio, buf, size)); 38679971Sobrien} 38779971Sobrien 38879971Sobrienstatic int linebuffer_puts(BIO *b, const char *str) 38979971Sobrien{ 39079971Sobrien return (linebuffer_write(b, str, strlen(str))); 39179971Sobrien} 39279971Sobrien