1 /* 2 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <stdio.h> 11 #include <errno.h> 12 #include "bio_lcl.h" 13 #include "internal/cryptlib.h" 14 15 static int buffer_write(BIO *h, const char *buf, int num); 16 static int buffer_read(BIO *h, char *buf, int size); 17 static int buffer_puts(BIO *h, const char *str); 18 static int buffer_gets(BIO *h, char *str, int size); 19 static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); 20 static int buffer_new(BIO *h); 21 static int buffer_free(BIO *data); 22 static long buffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); 23 #define DEFAULT_BUFFER_SIZE 4096 24 25 static const BIO_METHOD methods_buffer = { 26 BIO_TYPE_BUFFER, 27 "buffer", 28 /* TODO: Convert to new style write function */ 29 bwrite_conv, 30 buffer_write, 31 /* TODO: Convert to new style read function */ 32 bread_conv, 33 buffer_read, 34 buffer_puts, 35 buffer_gets, 36 buffer_ctrl, 37 buffer_new, 38 buffer_free, 39 buffer_callback_ctrl, 40 }; 41 42 const BIO_METHOD *BIO_f_buffer(void) 43 { 44 return &methods_buffer; 45 } 46 47 static int buffer_new(BIO *bi) 48 { 49 BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); 50 51 if (ctx == NULL) 52 return 0; 53 ctx->ibuf_size = DEFAULT_BUFFER_SIZE; 54 ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 55 if (ctx->ibuf == NULL) { 56 OPENSSL_free(ctx); 57 return 0; 58 } 59 ctx->obuf_size = DEFAULT_BUFFER_SIZE; 60 ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); 61 if (ctx->obuf == NULL) { 62 OPENSSL_free(ctx->ibuf); 63 OPENSSL_free(ctx); 64 return 0; 65 } 66 67 bi->init = 1; 68 bi->ptr = (char *)ctx; 69 bi->flags = 0; 70 return 1; 71 } 72 73 static int buffer_free(BIO *a) 74 { 75 BIO_F_BUFFER_CTX *b; 76 77 if (a == NULL) 78 return 0; 79 b = (BIO_F_BUFFER_CTX *)a->ptr; 80 OPENSSL_free(b->ibuf); 81 OPENSSL_free(b->obuf); 82 OPENSSL_free(a->ptr); 83 a->ptr = NULL; 84 a->init = 0; 85 a->flags = 0; 86 return 1; 87 } 88 89 static int buffer_read(BIO *b, char *out, int outl) 90 { 91 int i, num = 0; 92 BIO_F_BUFFER_CTX *ctx; 93 94 if (out == NULL) 95 return 0; 96 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 97 98 if ((ctx == NULL) || (b->next_bio == NULL)) 99 return 0; 100 num = 0; 101 BIO_clear_retry_flags(b); 102 103 start: 104 i = ctx->ibuf_len; 105 /* If there is stuff left over, grab it */ 106 if (i != 0) { 107 if (i > outl) 108 i = outl; 109 memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i); 110 ctx->ibuf_off += i; 111 ctx->ibuf_len -= i; 112 num += i; 113 if (outl == i) 114 return num; 115 outl -= i; 116 out += i; 117 } 118 119 /* 120 * We may have done a partial read. try to do more. We have nothing in 121 * the buffer. If we get an error and have read some data, just return it 122 * and let them retry to get the error again. copy direct to parent 123 * address space 124 */ 125 if (outl > ctx->ibuf_size) { 126 for (;;) { 127 i = BIO_read(b->next_bio, out, outl); 128 if (i <= 0) { 129 BIO_copy_next_retry(b); 130 if (i < 0) 131 return ((num > 0) ? num : i); 132 if (i == 0) 133 return num; 134 } 135 num += i; 136 if (outl == i) 137 return num; 138 out += i; 139 outl -= i; 140 } 141 } 142 /* else */ 143 144 /* we are going to be doing some buffering */ 145 i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); 146 if (i <= 0) { 147 BIO_copy_next_retry(b); 148 if (i < 0) 149 return ((num > 0) ? num : i); 150 if (i == 0) 151 return num; 152 } 153 ctx->ibuf_off = 0; 154 ctx->ibuf_len = i; 155 156 /* Lets re-read using ourselves :-) */ 157 goto start; 158 } 159 160 static int buffer_write(BIO *b, const char *in, int inl) 161 { 162 int i, num = 0; 163 BIO_F_BUFFER_CTX *ctx; 164 165 if ((in == NULL) || (inl <= 0)) 166 return 0; 167 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 168 if ((ctx == NULL) || (b->next_bio == NULL)) 169 return 0; 170 171 BIO_clear_retry_flags(b); 172 start: 173 i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off); 174 /* add to buffer and return */ 175 if (i >= inl) { 176 memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl); 177 ctx->obuf_len += inl; 178 return (num + inl); 179 } 180 /* else */ 181 /* stuff already in buffer, so add to it first, then flush */ 182 if (ctx->obuf_len != 0) { 183 if (i > 0) { /* lets fill it up if we can */ 184 memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i); 185 in += i; 186 inl -= i; 187 num += i; 188 ctx->obuf_len += i; 189 } 190 /* we now have a full buffer needing flushing */ 191 for (;;) { 192 i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), 193 ctx->obuf_len); 194 if (i <= 0) { 195 BIO_copy_next_retry(b); 196 197 if (i < 0) 198 return ((num > 0) ? num : i); 199 if (i == 0) 200 return num; 201 } 202 ctx->obuf_off += i; 203 ctx->obuf_len -= i; 204 if (ctx->obuf_len == 0) 205 break; 206 } 207 } 208 /* 209 * we only get here if the buffer has been flushed and we still have 210 * stuff to write 211 */ 212 ctx->obuf_off = 0; 213 214 /* we now have inl bytes to write */ 215 while (inl >= ctx->obuf_size) { 216 i = BIO_write(b->next_bio, in, inl); 217 if (i <= 0) { 218 BIO_copy_next_retry(b); 219 if (i < 0) 220 return ((num > 0) ? num : i); 221 if (i == 0) 222 return num; 223 } 224 num += i; 225 in += i; 226 inl -= i; 227 if (inl == 0) 228 return num; 229 } 230 231 /* 232 * copy the rest into the buffer since we have only a small amount left 233 */ 234 goto start; 235 } 236 237 static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) 238 { 239 BIO *dbio; 240 BIO_F_BUFFER_CTX *ctx; 241 long ret = 1; 242 char *p1, *p2; 243 int r, i, *ip; 244 int ibs, obs; 245 246 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 247 248 switch (cmd) { 249 case BIO_CTRL_RESET: 250 ctx->ibuf_off = 0; 251 ctx->ibuf_len = 0; 252 ctx->obuf_off = 0; 253 ctx->obuf_len = 0; 254 if (b->next_bio == NULL) 255 return 0; 256 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 257 break; 258 case BIO_CTRL_EOF: 259 if (ctx->ibuf_len > 0) 260 return 0; 261 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 262 break; 263 case BIO_CTRL_INFO: 264 ret = (long)ctx->obuf_len; 265 break; 266 case BIO_C_GET_BUFF_NUM_LINES: 267 ret = 0; 268 p1 = ctx->ibuf; 269 for (i = 0; i < ctx->ibuf_len; i++) { 270 if (p1[ctx->ibuf_off + i] == '\n') 271 ret++; 272 } 273 break; 274 case BIO_CTRL_WPENDING: 275 ret = (long)ctx->obuf_len; 276 if (ret == 0) { 277 if (b->next_bio == NULL) 278 return 0; 279 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 280 } 281 break; 282 case BIO_CTRL_PENDING: 283 ret = (long)ctx->ibuf_len; 284 if (ret == 0) { 285 if (b->next_bio == NULL) 286 return 0; 287 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 288 } 289 break; 290 case BIO_C_SET_BUFF_READ_DATA: 291 if (num > ctx->ibuf_size) { 292 p1 = OPENSSL_malloc((int)num); 293 if (p1 == NULL) 294 goto malloc_error; 295 OPENSSL_free(ctx->ibuf); 296 ctx->ibuf = p1; 297 } 298 ctx->ibuf_off = 0; 299 ctx->ibuf_len = (int)num; 300 memcpy(ctx->ibuf, ptr, (int)num); 301 ret = 1; 302 break; 303 case BIO_C_SET_BUFF_SIZE: 304 if (ptr != NULL) { 305 ip = (int *)ptr; 306 if (*ip == 0) { 307 ibs = (int)num; 308 obs = ctx->obuf_size; 309 } else { /* if (*ip == 1) */ 310 311 ibs = ctx->ibuf_size; 312 obs = (int)num; 313 } 314 } else { 315 ibs = (int)num; 316 obs = (int)num; 317 } 318 p1 = ctx->ibuf; 319 p2 = ctx->obuf; 320 if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) { 321 p1 = OPENSSL_malloc((int)num); 322 if (p1 == NULL) 323 goto malloc_error; 324 } 325 if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) { 326 p2 = OPENSSL_malloc((int)num); 327 if (p2 == NULL) { 328 if (p1 != ctx->ibuf) 329 OPENSSL_free(p1); 330 goto malloc_error; 331 } 332 } 333 if (ctx->ibuf != p1) { 334 OPENSSL_free(ctx->ibuf); 335 ctx->ibuf = p1; 336 ctx->ibuf_off = 0; 337 ctx->ibuf_len = 0; 338 ctx->ibuf_size = ibs; 339 } 340 if (ctx->obuf != p2) { 341 OPENSSL_free(ctx->obuf); 342 ctx->obuf = p2; 343 ctx->obuf_off = 0; 344 ctx->obuf_len = 0; 345 ctx->obuf_size = obs; 346 } 347 break; 348 case BIO_C_DO_STATE_MACHINE: 349 if (b->next_bio == NULL) 350 return 0; 351 BIO_clear_retry_flags(b); 352 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 353 BIO_copy_next_retry(b); 354 break; 355 356 case BIO_CTRL_FLUSH: 357 if (b->next_bio == NULL) 358 return 0; 359 if (ctx->obuf_len <= 0) { 360 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 361 break; 362 } 363 364 for (;;) { 365 BIO_clear_retry_flags(b); 366 if (ctx->obuf_len > 0) { 367 r = BIO_write(b->next_bio, 368 &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len); 369 BIO_copy_next_retry(b); 370 if (r <= 0) 371 return (long)r; 372 ctx->obuf_off += r; 373 ctx->obuf_len -= r; 374 } else { 375 ctx->obuf_len = 0; 376 ctx->obuf_off = 0; 377 break; 378 } 379 } 380 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 381 break; 382 case BIO_CTRL_DUP: 383 dbio = (BIO *)ptr; 384 if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) || 385 !BIO_set_write_buffer_size(dbio, ctx->obuf_size)) 386 ret = 0; 387 break; 388 case BIO_CTRL_PEEK: 389 /* Ensure there's stuff in the input buffer */ 390 { 391 char fake_buf[1]; 392 (void)buffer_read(b, fake_buf, 0); 393 } 394 if (num > ctx->ibuf_len) 395 num = ctx->ibuf_len; 396 memcpy(ptr, &(ctx->ibuf[ctx->ibuf_off]), num); 397 ret = num; 398 break; 399 default: 400 if (b->next_bio == NULL) 401 return 0; 402 ret = BIO_ctrl(b->next_bio, cmd, num, ptr); 403 break; 404 } 405 return ret; 406 malloc_error: 407 BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE); 408 return 0; 409 } 410 411 static long buffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 412 { 413 long ret = 1; 414 415 if (b->next_bio == NULL) 416 return 0; 417 switch (cmd) { 418 default: 419 ret = BIO_callback_ctrl(b->next_bio, cmd, fp); 420 break; 421 } 422 return ret; 423 } 424 425 static int buffer_gets(BIO *b, char *buf, int size) 426 { 427 BIO_F_BUFFER_CTX *ctx; 428 int num = 0, i, flag; 429 char *p; 430 431 ctx = (BIO_F_BUFFER_CTX *)b->ptr; 432 size--; /* reserve space for a '\0' */ 433 BIO_clear_retry_flags(b); 434 435 for (;;) { 436 if (ctx->ibuf_len > 0) { 437 p = &(ctx->ibuf[ctx->ibuf_off]); 438 flag = 0; 439 for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { 440 *(buf++) = p[i]; 441 if (p[i] == '\n') { 442 flag = 1; 443 i++; 444 break; 445 } 446 } 447 num += i; 448 size -= i; 449 ctx->ibuf_len -= i; 450 ctx->ibuf_off += i; 451 if (flag || size == 0) { 452 *buf = '\0'; 453 return num; 454 } 455 } else { /* read another chunk */ 456 457 i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); 458 if (i <= 0) { 459 BIO_copy_next_retry(b); 460 *buf = '\0'; 461 if (i < 0) 462 return ((num > 0) ? num : i); 463 if (i == 0) 464 return num; 465 } 466 ctx->ibuf_len = i; 467 ctx->ibuf_off = 0; 468 } 469 } 470 } 471 472 static int buffer_puts(BIO *b, const char *str) 473 { 474 return buffer_write(b, str, strlen(str)); 475 } 476