1 /* $OpenBSD: bio_lib.c,v 1.43 2022/12/16 13:41:55 schwarze Exp $ */ 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 <errno.h> 60 #include <limits.h> 61 #include <stdio.h> 62 63 #include <openssl/bio.h> 64 #include <openssl/crypto.h> 65 #include <openssl/err.h> 66 #include <openssl/stack.h> 67 68 #include "bio_local.h" 69 70 /* 71 * Helper function to work out whether to call the new style callback or the old 72 * one, and translate between the two. 73 * 74 * This has a long return type for consistency with the old callback. Similarly 75 * for the "long" used for "inret" 76 */ 77 static long 78 bio_call_callback(BIO *b, int oper, const char *argp, size_t len, int argi, 79 long argl, long inret, size_t *processed) 80 { 81 long ret; 82 int bareoper; 83 84 if (b->callback_ex != NULL) 85 return b->callback_ex(b, oper, argp, len, argi, argl, inret, 86 processed); 87 88 /* 89 * We have an old style callback, so we will have to do nasty casts and 90 * check for overflows. 91 */ 92 93 bareoper = oper & ~BIO_CB_RETURN; 94 95 if (bareoper == BIO_CB_READ || bareoper == BIO_CB_WRITE || 96 bareoper == BIO_CB_GETS) { 97 /* In this case len is set and should be used instead of argi. */ 98 if (len > INT_MAX) 99 return -1; 100 argi = (int)len; 101 } 102 103 if (inret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { 104 if (*processed > INT_MAX) 105 return -1; 106 inret = *processed; 107 } 108 109 ret = b->callback(b, oper, argp, argi, argl, inret); 110 111 if (ret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { 112 *processed = (size_t)ret; 113 ret = 1; 114 } 115 116 return ret; 117 } 118 119 int 120 BIO_get_new_index(void) 121 { 122 static int bio_type_index = BIO_TYPE_START; 123 int index; 124 125 /* The index will collide with the BIO flag bits if it exceeds 255. */ 126 index = CRYPTO_add(&bio_type_index, 1, CRYPTO_LOCK_BIO); 127 if (index > 255) 128 return -1; 129 130 return index; 131 } 132 133 BIO * 134 BIO_new(const BIO_METHOD *method) 135 { 136 BIO *ret = NULL; 137 138 /* XXX calloc */ 139 ret = malloc(sizeof(BIO)); 140 if (ret == NULL) { 141 BIOerror(ERR_R_MALLOC_FAILURE); 142 return (NULL); 143 } 144 if (!BIO_set(ret, method)) { 145 free(ret); 146 ret = NULL; 147 } 148 return (ret); 149 } 150 151 int 152 BIO_set(BIO *bio, const BIO_METHOD *method) 153 { 154 bio->method = method; 155 bio->callback = NULL; 156 bio->callback_ex = NULL; 157 bio->cb_arg = NULL; 158 bio->init = 0; 159 bio->shutdown = 1; 160 bio->flags = 0; 161 bio->retry_reason = 0; 162 bio->num = 0; 163 bio->ptr = NULL; 164 bio->prev_bio = NULL; 165 bio->next_bio = NULL; 166 bio->references = 1; 167 bio->num_read = 0L; 168 bio->num_write = 0L; 169 CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); 170 if (method->create != NULL) { 171 if (!method->create(bio)) { 172 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, 173 &bio->ex_data); 174 return (0); 175 } 176 } 177 return (1); 178 } 179 180 int 181 BIO_free(BIO *a) 182 { 183 int ret; 184 185 if (a == NULL) 186 return (0); 187 188 if (CRYPTO_add(&a->references, -1, CRYPTO_LOCK_BIO) > 0) 189 return (1); 190 191 if (a->callback != NULL || a->callback_ex != NULL) { 192 if ((ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 193 0L, 1L, NULL)) <= 0) 194 return (ret); 195 } 196 197 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, a, &a->ex_data); 198 199 if (a->method != NULL && a->method->destroy != NULL) 200 a->method->destroy(a); 201 free(a); 202 return (1); 203 } 204 205 void 206 BIO_vfree(BIO *a) 207 { 208 BIO_free(a); 209 } 210 211 int 212 BIO_up_ref(BIO *bio) 213 { 214 int refs = CRYPTO_add(&bio->references, 1, CRYPTO_LOCK_BIO); 215 return (refs > 1) ? 1 : 0; 216 } 217 218 void * 219 BIO_get_data(BIO *a) 220 { 221 return (a->ptr); 222 } 223 224 void 225 BIO_set_data(BIO *a, void *ptr) 226 { 227 a->ptr = ptr; 228 } 229 230 int 231 BIO_get_init(BIO *a) 232 { 233 return a->init; 234 } 235 236 void 237 BIO_set_init(BIO *a, int init) 238 { 239 a->init = init; 240 } 241 242 int 243 BIO_get_shutdown(BIO *a) 244 { 245 return (a->shutdown); 246 } 247 248 void 249 BIO_set_shutdown(BIO *a, int shut) 250 { 251 a->shutdown = shut; 252 } 253 254 void 255 BIO_clear_flags(BIO *b, int flags) 256 { 257 b->flags &= ~flags; 258 } 259 260 int 261 BIO_test_flags(const BIO *b, int flags) 262 { 263 return (b->flags & flags); 264 } 265 266 void 267 BIO_set_flags(BIO *b, int flags) 268 { 269 b->flags |= flags; 270 } 271 272 BIO_callback_fn 273 BIO_get_callback(const BIO *b) 274 { 275 return b->callback; 276 } 277 278 void 279 BIO_set_callback(BIO *b, BIO_callback_fn cb) 280 { 281 b->callback = cb; 282 } 283 284 BIO_callback_fn_ex 285 BIO_get_callback_ex(const BIO *b) 286 { 287 return b->callback_ex; 288 } 289 290 void 291 BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex cb) 292 { 293 b->callback_ex = cb; 294 } 295 296 void 297 BIO_set_callback_arg(BIO *b, char *arg) 298 { 299 b->cb_arg = arg; 300 } 301 302 char * 303 BIO_get_callback_arg(const BIO *b) 304 { 305 return b->cb_arg; 306 } 307 308 const char * 309 BIO_method_name(const BIO *b) 310 { 311 return b->method->name; 312 } 313 314 int 315 BIO_method_type(const BIO *b) 316 { 317 return b->method->type; 318 } 319 320 int 321 BIO_read(BIO *b, void *out, int outl) 322 { 323 size_t readbytes = 0; 324 int ret; 325 326 if (b == NULL) { 327 BIOerror(ERR_R_PASSED_NULL_PARAMETER); 328 return (-1); 329 } 330 331 if (outl <= 0) 332 return (0); 333 334 if (out == NULL) { 335 BIOerror(ERR_R_PASSED_NULL_PARAMETER); 336 return (-1); 337 } 338 339 if (b->method == NULL || b->method->bread == NULL) { 340 BIOerror(BIO_R_UNSUPPORTED_METHOD); 341 return (-2); 342 } 343 344 if (b->callback != NULL || b->callback_ex != NULL) { 345 if ((ret = (int)bio_call_callback(b, BIO_CB_READ, out, outl, 0, 346 0L, 1L, NULL)) <= 0) 347 return (ret); 348 } 349 350 if (!b->init) { 351 BIOerror(BIO_R_UNINITIALIZED); 352 return (-2); 353 } 354 355 if ((ret = b->method->bread(b, out, outl)) > 0) 356 readbytes = (size_t)ret; 357 358 b->num_read += readbytes; 359 360 if (b->callback != NULL || b->callback_ex != NULL) { 361 ret = (int)bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, 362 out, outl, 0, 0L, (ret > 0) ? 1 : ret, &readbytes); 363 } 364 365 if (ret > 0) { 366 if (readbytes > INT_MAX) { 367 BIOerror(BIO_R_LENGTH_TOO_LONG); 368 ret = -1; 369 } else { 370 ret = (int)readbytes; 371 } 372 } 373 374 return (ret); 375 } 376 377 int 378 BIO_write(BIO *b, const void *in, int inl) 379 { 380 size_t writebytes = 0; 381 int ret; 382 383 if (b == NULL) { 384 BIOerror(ERR_R_PASSED_NULL_PARAMETER); 385 return (-1); 386 } 387 388 if (inl <= 0) 389 return (0); 390 391 if (in == NULL) { 392 BIOerror(ERR_R_PASSED_NULL_PARAMETER); 393 return (-1); 394 } 395 396 if (b->method == NULL || b->method->bwrite == NULL) { 397 BIOerror(BIO_R_UNSUPPORTED_METHOD); 398 return (-2); 399 } 400 401 if (b->callback != NULL || b->callback_ex != NULL) { 402 if ((ret = (int)bio_call_callback(b, BIO_CB_WRITE, in, inl, 0, 403 0L, 1L, NULL)) <= 0) 404 return (ret); 405 } 406 407 if (!b->init) { 408 BIOerror(BIO_R_UNINITIALIZED); 409 return (-2); 410 } 411 412 if ((ret = b->method->bwrite(b, in, inl)) > 0) 413 writebytes = ret; 414 415 b->num_write += writebytes; 416 417 if (b->callback != NULL || b->callback_ex != NULL) { 418 ret = (int)bio_call_callback(b, BIO_CB_WRITE | BIO_CB_RETURN, 419 in, inl, 0, 0L, (ret > 0) ? 1 : ret, &writebytes); 420 } 421 422 if (ret > 0) { 423 if (writebytes > INT_MAX) { 424 BIOerror(BIO_R_LENGTH_TOO_LONG); 425 ret = -1; 426 } else { 427 ret = (int)writebytes; 428 } 429 } 430 431 return (ret); 432 } 433 434 int 435 BIO_puts(BIO *b, const char *in) 436 { 437 size_t writebytes = 0; 438 int ret; 439 440 if (b == NULL || b->method == NULL || b->method->bputs == NULL) { 441 BIOerror(BIO_R_UNSUPPORTED_METHOD); 442 return (-2); 443 } 444 445 if (b->callback != NULL || b->callback_ex != NULL) { 446 if ((ret = (int)bio_call_callback(b, BIO_CB_PUTS, in, 0, 0, 0L, 447 1L, NULL)) <= 0) 448 return (ret); 449 } 450 451 if (!b->init) { 452 BIOerror(BIO_R_UNINITIALIZED); 453 return (-2); 454 } 455 456 if ((ret = b->method->bputs(b, in)) > 0) 457 writebytes = ret; 458 459 b->num_write += writebytes; 460 461 if (b->callback != NULL || b->callback_ex != NULL) { 462 ret = (int)bio_call_callback(b, BIO_CB_PUTS | BIO_CB_RETURN, 463 in, 0, 0, 0L, (ret > 0) ? 1 : ret, &writebytes); 464 } 465 466 if (ret > 0) { 467 if (writebytes > INT_MAX) { 468 BIOerror(BIO_R_LENGTH_TOO_LONG); 469 ret = -1; 470 } else { 471 ret = (int)writebytes; 472 } 473 } 474 475 return (ret); 476 } 477 478 int 479 BIO_gets(BIO *b, char *in, int inl) 480 { 481 size_t readbytes = 0; 482 int ret; 483 484 if (b == NULL || b->method == NULL || b->method->bgets == NULL) { 485 BIOerror(BIO_R_UNSUPPORTED_METHOD); 486 return (-2); 487 } 488 489 if (b->callback != NULL || b->callback_ex != NULL) { 490 if ((ret = (int)bio_call_callback(b, BIO_CB_GETS, in, inl, 0, 0L, 491 1, NULL)) <= 0) 492 return (ret); 493 } 494 495 if (!b->init) { 496 BIOerror(BIO_R_UNINITIALIZED); 497 return (-2); 498 } 499 500 if ((ret = b->method->bgets(b, in, inl)) > 0) 501 readbytes = ret; 502 503 if (b->callback != NULL || b->callback_ex != NULL) { 504 ret = (int)bio_call_callback(b, BIO_CB_GETS | BIO_CB_RETURN, in, 505 inl, 0, 0L, (ret > 0) ? 1 : ret, &readbytes); 506 } 507 508 if (ret > 0) { 509 if (readbytes > INT_MAX) { 510 BIOerror(BIO_R_LENGTH_TOO_LONG); 511 ret = -1; 512 } else { 513 ret = (int)readbytes; 514 } 515 } 516 517 return (ret); 518 } 519 520 int 521 BIO_indent(BIO *b, int indent, int max) 522 { 523 if (indent > max) 524 indent = max; 525 if (indent < 0) 526 indent = 0; 527 while (indent--) 528 if (BIO_puts(b, " ") != 1) 529 return 0; 530 return 1; 531 } 532 533 long 534 BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) 535 { 536 int i; 537 538 i = iarg; 539 return (BIO_ctrl(b, cmd, larg, (char *)&i)); 540 } 541 542 char * 543 BIO_ptr_ctrl(BIO *b, int cmd, long larg) 544 { 545 char *p = NULL; 546 547 if (BIO_ctrl(b, cmd, larg, (char *)&p) <= 0) 548 return (NULL); 549 else 550 return (p); 551 } 552 553 long 554 BIO_ctrl(BIO *b, int cmd, long larg, void *parg) 555 { 556 long ret; 557 558 if (b == NULL) 559 return (0); 560 561 if (b->method == NULL || b->method->ctrl == NULL) { 562 BIOerror(BIO_R_UNSUPPORTED_METHOD); 563 return (-2); 564 } 565 566 if (b->callback != NULL || b->callback_ex != NULL) { 567 if ((ret = bio_call_callback(b, BIO_CB_CTRL, parg, 0, cmd, larg, 568 1L, NULL)) <= 0) 569 return (ret); 570 } 571 572 ret = b->method->ctrl(b, cmd, larg, parg); 573 574 if (b->callback != NULL || b->callback_ex != NULL) { 575 ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, 576 cmd, larg, ret, NULL); 577 } 578 579 return (ret); 580 } 581 582 long 583 BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 584 { 585 long ret; 586 587 if (b == NULL) 588 return (0); 589 590 if (b->method == NULL || b->method->callback_ctrl == NULL || 591 cmd != BIO_CTRL_SET_CALLBACK) { 592 BIOerror(BIO_R_UNSUPPORTED_METHOD); 593 return (-2); 594 } 595 596 if (b->callback != NULL || b->callback_ex != NULL) { 597 if ((ret = bio_call_callback(b, BIO_CB_CTRL, (void *)&fp, 0, 598 cmd, 0, 1L, NULL)) <= 0) 599 return (ret); 600 } 601 602 ret = b->method->callback_ctrl(b, cmd, fp); 603 604 if (b->callback != NULL || b->callback_ex != NULL) { 605 ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, 606 (void *)&fp, 0, cmd, 0, ret, NULL); 607 } 608 609 return (ret); 610 } 611 612 /* It is unfortunate to duplicate in functions what the BIO_(w)pending macros 613 * do; but those macros have inappropriate return type, and for interfacing 614 * from other programming languages, C macros aren't much of a help anyway. */ 615 size_t 616 BIO_ctrl_pending(BIO *bio) 617 { 618 return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL); 619 } 620 621 size_t 622 BIO_ctrl_wpending(BIO *bio) 623 { 624 return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL); 625 } 626 627 628 /* 629 * Append "bio" to the end of the chain containing "b": 630 * Two chains "b -> lb" and "oldhead -> bio" 631 * become two chains "b -> lb -> bio" and "oldhead". 632 */ 633 BIO * 634 BIO_push(BIO *b, BIO *bio) 635 { 636 BIO *lb; 637 638 if (b == NULL) 639 return (bio); 640 lb = b; 641 while (lb->next_bio != NULL) 642 lb = lb->next_bio; 643 lb->next_bio = bio; 644 if (bio != NULL) { 645 if (bio->prev_bio != NULL) 646 bio->prev_bio->next_bio = NULL; 647 bio->prev_bio = lb; 648 } 649 /* called to do internal processing */ 650 BIO_ctrl(b, BIO_CTRL_PUSH, 0, lb); 651 return (b); 652 } 653 654 /* Remove the first and return the rest */ 655 BIO * 656 BIO_pop(BIO *b) 657 { 658 BIO *ret; 659 660 if (b == NULL) 661 return (NULL); 662 ret = b->next_bio; 663 664 BIO_ctrl(b, BIO_CTRL_POP, 0, b); 665 666 if (b->prev_bio != NULL) 667 b->prev_bio->next_bio = b->next_bio; 668 if (b->next_bio != NULL) 669 b->next_bio->prev_bio = b->prev_bio; 670 671 b->next_bio = NULL; 672 b->prev_bio = NULL; 673 return (ret); 674 } 675 676 BIO * 677 BIO_get_retry_BIO(BIO *bio, int *reason) 678 { 679 BIO *b, *last; 680 681 b = last = bio; 682 for (;;) { 683 if (!BIO_should_retry(b)) 684 break; 685 last = b; 686 b = b->next_bio; 687 if (b == NULL) 688 break; 689 } 690 if (reason != NULL) 691 *reason = last->retry_reason; 692 return (last); 693 } 694 695 int 696 BIO_get_retry_reason(BIO *bio) 697 { 698 return (bio->retry_reason); 699 } 700 701 void 702 BIO_set_retry_reason(BIO *bio, int reason) 703 { 704 bio->retry_reason = reason; 705 } 706 707 BIO * 708 BIO_find_type(BIO *bio, int type) 709 { 710 int mt, mask; 711 712 if (!bio) 713 return NULL; 714 mask = type & 0xff; 715 do { 716 if (bio->method != NULL) { 717 mt = bio->method->type; 718 if (!mask) { 719 if (mt & type) 720 return (bio); 721 } else if (mt == type) 722 return (bio); 723 } 724 bio = bio->next_bio; 725 } while (bio != NULL); 726 return (NULL); 727 } 728 729 BIO * 730 BIO_next(BIO *b) 731 { 732 if (!b) 733 return NULL; 734 return b->next_bio; 735 } 736 737 /* 738 * Two chains "bio -> oldtail" and "oldhead -> next" become 739 * three chains "oldtail", "bio -> next", and "oldhead". 740 */ 741 void 742 BIO_set_next(BIO *bio, BIO *next) 743 { 744 /* Cut off the tail of the chain containing bio after bio. */ 745 if (bio->next_bio != NULL) 746 bio->next_bio->prev_bio = NULL; 747 748 /* Cut off the head of the chain containing next before next. */ 749 if (next != NULL && next->prev_bio != NULL) 750 next->prev_bio->next_bio = NULL; 751 752 /* Append the chain starting at next to the chain ending at bio. */ 753 bio->next_bio = next; 754 if (next != NULL) 755 next->prev_bio = bio; 756 } 757 758 void 759 BIO_free_all(BIO *bio) 760 { 761 BIO *b; 762 int ref; 763 764 while (bio != NULL) { 765 b = bio; 766 ref = b->references; 767 bio = bio->next_bio; 768 BIO_free(b); 769 /* Since ref count > 1, don't free anyone else. */ 770 if (ref > 1) 771 break; 772 } 773 } 774 775 BIO * 776 BIO_dup_chain(BIO *in) 777 { 778 BIO *ret = NULL, *eoc = NULL, *bio, *new_bio; 779 780 for (bio = in; bio != NULL; bio = bio->next_bio) { 781 if ((new_bio = BIO_new(bio->method)) == NULL) 782 goto err; 783 new_bio->callback = bio->callback; 784 new_bio->callback_ex = bio->callback_ex; 785 new_bio->cb_arg = bio->cb_arg; 786 new_bio->init = bio->init; 787 new_bio->shutdown = bio->shutdown; 788 new_bio->flags = bio->flags; 789 790 /* This will let SSL_s_sock() work with stdin/stdout */ 791 new_bio->num = bio->num; 792 793 if (!BIO_dup_state(bio, (char *)new_bio)) { 794 BIO_free(new_bio); 795 goto err; 796 } 797 798 /* copy app data */ 799 if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_BIO, 800 &new_bio->ex_data, &bio->ex_data)) 801 goto err; 802 803 if (ret == NULL) { 804 eoc = new_bio; 805 ret = eoc; 806 } else { 807 BIO_push(eoc, new_bio); 808 eoc = new_bio; 809 } 810 } 811 return (ret); 812 err: 813 BIO_free(ret); 814 return (NULL); 815 816 } 817 818 void 819 BIO_copy_next_retry(BIO *b) 820 { 821 BIO_set_flags(b, BIO_get_retry_flags(b->next_bio)); 822 b->retry_reason = b->next_bio->retry_reason; 823 } 824 825 int 826 BIO_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, 827 CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) 828 { 829 return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_BIO, argl, argp, 830 new_func, dup_func, free_func); 831 } 832 833 int 834 BIO_set_ex_data(BIO *bio, int idx, void *data) 835 { 836 return (CRYPTO_set_ex_data(&(bio->ex_data), idx, data)); 837 } 838 839 void * 840 BIO_get_ex_data(BIO *bio, int idx) 841 { 842 return (CRYPTO_get_ex_data(&(bio->ex_data), idx)); 843 } 844 845 unsigned long 846 BIO_number_read(BIO *bio) 847 { 848 if (bio) 849 return bio->num_read; 850 return 0; 851 } 852 853 unsigned long 854 BIO_number_written(BIO *bio) 855 { 856 if (bio) 857 return bio->num_write; 858 return 0; 859 } 860