1/* crypto/bio/bf_buff.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59#include <stdio.h> 60#include <errno.h> 61#include "cryptlib.h" 62#include <openssl/bio.h> 63#include <openssl/evp.h> 64 65static int linebuffer_write(BIO *h, const char *buf, int num); 66static int linebuffer_read(BIO *h, char *buf, int size); 67static int linebuffer_puts(BIO *h, const char *str); 68static int linebuffer_gets(BIO *h, char *str, int size); 69static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 70static int linebuffer_new(BIO *h); 71static int linebuffer_free(BIO *data); 72static long linebuffer_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 73 74/* A 10k maximum should be enough for most purposes */ 75#define DEFAULT_LINEBUFFER_SIZE 1024*10 76 77/* #define DEBUG */ 78 79static BIO_METHOD methods_linebuffer = { 80 BIO_TYPE_LINEBUFFER, 81 "linebuffer", 82 linebuffer_write, 83 linebuffer_read, 84 linebuffer_puts, 85 linebuffer_gets, 86 linebuffer_ctrl, 87 linebuffer_new, 88 linebuffer_free, 89 linebuffer_callback_ctrl, 90}; 91 92BIO_METHOD *BIO_f_linebuffer(void) 93{ 94 return (&methods_linebuffer); 95} 96 97typedef struct bio_linebuffer_ctx_struct { 98 char *obuf; /* the output char array */ 99 int obuf_size; /* how big is the output buffer */ 100 int obuf_len; /* how many bytes are in it */ 101} BIO_LINEBUFFER_CTX; 102 103static int linebuffer_new(BIO *bi) 104{ 105 BIO_LINEBUFFER_CTX *ctx; 106 107 ctx = (BIO_LINEBUFFER_CTX *)OPENSSL_malloc(sizeof(BIO_LINEBUFFER_CTX)); 108 if (ctx == NULL) 109 return (0); 110 ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); 111 if (ctx->obuf == NULL) { 112 OPENSSL_free(ctx); 113 return (0); 114 } 115 ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; 116 ctx->obuf_len = 0; 117 118 bi->init = 1; 119 bi->ptr = (char *)ctx; 120 bi->flags = 0; 121 return (1); 122} 123 124static int linebuffer_free(BIO *a) 125{ 126 BIO_LINEBUFFER_CTX *b; 127 128 if (a == NULL) 129 return (0); 130 b = (BIO_LINEBUFFER_CTX *)a->ptr; 131 if (b->obuf != NULL) 132 OPENSSL_free(b->obuf); 133 OPENSSL_free(a->ptr); 134 a->ptr = NULL; 135 a->init = 0; 136 a->flags = 0; 137 return (1); 138} 139 140static int linebuffer_read(BIO *b, char *out, int outl) 141{ 142 int ret = 0; 143 144 if (out == NULL) 145 return (0); 146 if (b->next_bio == NULL) 147 return (0); 148 ret = BIO_read(b->next_bio, out, outl); 149 BIO_clear_retry_flags(b); 150 BIO_copy_next_retry(b); 151 return (ret); 152} 153 154static int linebuffer_write(BIO *b, const char *in, int inl) 155{ 156 int i, num = 0, foundnl; 157 BIO_LINEBUFFER_CTX *ctx; 158 159 if ((in == NULL) || (inl <= 0)) 160 return (0); 161 ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 162 if ((ctx == NULL) || (b->next_bio == NULL)) 163 return (0); 164 165 BIO_clear_retry_flags(b); 166 167 do { 168 const char *p; 169 170 for (p = in; p < in + inl && *p != '\n'; p++) ; 171 if (*p == '\n') { 172 p++; 173 foundnl = 1; 174 } else 175 foundnl = 0; 176 177 /* 178 * If a NL was found and we already have text in the save buffer, 179 * concatenate them and write 180 */ 181 while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) 182 && ctx->obuf_len > 0) { 183 int orig_olen = ctx->obuf_len; 184 185 i = ctx->obuf_size - ctx->obuf_len; 186 if (p - in > 0) { 187 if (i >= p - in) { 188 memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); 189 ctx->obuf_len += p - in; 190 inl -= p - in; 191 num += p - in; 192 in = p; 193 } else { 194 memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); 195 ctx->obuf_len += i; 196 inl -= i; 197 in += i; 198 num += i; 199 } 200 } 201#if 0 202 BIO_write(b->next_bio, "<*<", 3); 203#endif 204 i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 205 if (i <= 0) { 206 ctx->obuf_len = orig_olen; 207 BIO_copy_next_retry(b); 208 209#if 0 210 BIO_write(b->next_bio, ">*>", 3); 211#endif 212 if (i < 0) 213 return ((num > 0) ? num : i); 214 if (i == 0) 215 return (num); 216 } 217#if 0 218 BIO_write(b->next_bio, ">*>", 3); 219#endif 220 if (i < ctx->obuf_len) 221 memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); 222 ctx->obuf_len -= i; 223 } 224 225 /* 226 * Now that the save buffer is emptied, let's write the input buffer 227 * if a NL was found and there is anything to write. 228 */ 229 if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { 230#if 0 231 BIO_write(b->next_bio, "<*<", 3); 232#endif 233 i = BIO_write(b->next_bio, in, p - in); 234 if (i <= 0) { 235 BIO_copy_next_retry(b); 236#if 0 237 BIO_write(b->next_bio, ">*>", 3); 238#endif 239 if (i < 0) 240 return ((num > 0) ? num : i); 241 if (i == 0) 242 return (num); 243 } 244#if 0 245 BIO_write(b->next_bio, ">*>", 3); 246#endif 247 num += i; 248 in += i; 249 inl -= i; 250 } 251 } 252 while (foundnl && inl > 0); 253 /* 254 * We've written as much as we can. The rest of the input buffer, if 255 * any, is text that doesn't and with a NL and therefore needs to be 256 * saved for the next trip. 257 */ 258 if (inl > 0) { 259 memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); 260 ctx->obuf_len += inl; 261 num += inl; 262 } 263 return num; 264} 265 266static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) 267{ 268 BIO *dbio; 269 BIO_LINEBUFFER_CTX *ctx; 270 long ret = 1; 271 char *p; 272 int r; 273 int obs; 274 275 ctx = (BIO_LINEBUFFER_CTX *)b->ptr; 276 277 switch (cmd) { 278 case BIO_CTRL_RESET: 279 ctx->obuf_len = 0; 280 if (b->next_bio == NULL) 281 return (0); 282 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 283 break; 284 case BIO_CTRL_INFO: 285 ret = (long)ctx->obuf_len; 286 break; 287 case BIO_CTRL_WPENDING: 288 ret = (long)ctx->obuf_len; 289 if (ret == 0) { 290 if (b->next_bio == NULL) 291 return (0); 292 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 293 } 294 break; 295 case BIO_C_SET_BUFF_SIZE: 296 obs = (int)num; 297 p = ctx->obuf; 298 if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { 299 p = (char *)OPENSSL_malloc((int)num); 300 if (p == NULL) 301 goto malloc_error; 302 } 303 if (ctx->obuf != p) { 304 if (ctx->obuf_len > obs) { 305 ctx->obuf_len = obs; 306 } 307 memcpy(p, ctx->obuf, ctx->obuf_len); 308 OPENSSL_free(ctx->obuf); 309 ctx->obuf = p; 310 ctx->obuf_size = obs; 311 } 312 break; 313 case BIO_C_DO_STATE_MACHINE: 314 if (b->next_bio == NULL) 315 return (0); 316 BIO_clear_retry_flags(b); 317 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 318 BIO_copy_next_retry(b); 319 break; 320 321 case BIO_CTRL_FLUSH: 322 if (b->next_bio == NULL) 323 return (0); 324 if (ctx->obuf_len <= 0) { 325 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 326 break; 327 } 328 329 for (;;) { 330 BIO_clear_retry_flags(b); 331 if (ctx->obuf_len > 0) { 332 r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); 333#if 0 334 fprintf(stderr, "FLUSH %3d -> %3d\n", ctx->obuf_len, r); 335#endif 336 BIO_copy_next_retry(b); 337 if (r <= 0) 338 return ((long)r); 339 if (r < ctx->obuf_len) 340 memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); 341 ctx->obuf_len -= r; 342 } else { 343 ctx->obuf_len = 0; 344 ret = 1; 345 break; 346 } 347 } 348 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 349 break; 350 case BIO_CTRL_DUP: 351 dbio = (BIO *)ptr; 352 if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) 353 ret = 0; 354 break; 355 default: 356 if (b->next_bio == NULL) 357 return (0); 358 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 359 break; 360 } 361 return (ret); 362 malloc_error: 363 BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE); 364 return (0); 365} 366 367static long linebuffer_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 368{ 369 long ret = 1; 370 371 if (b->next_bio == NULL) 372 return (0); 373 switch (cmd) { 374 default: 375 ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 376 break; 377 } 378 return (ret); 379} 380 381static int linebuffer_gets(BIO *b, char *buf, int size) 382{ 383 if (b->next_bio == NULL) 384 return (0); 385 return (BIO_gets(b->next_bio, buf, size)); 386} 387 388static int linebuffer_puts(BIO *b, const char *str) 389{ 390 return (linebuffer_write(b, str, strlen(str))); 391} 392