1 /* crypto/err/err_def.c */ 2 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay (at) 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 (at) 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 (at) 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 (at) 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 * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. 60 * 61 * Redistribution and use in source and binary forms, with or without 62 * modification, are permitted provided that the following conditions 63 * are met: 64 * 65 * 1. Redistributions of source code must retain the above copyright 66 * notice, this list of conditions and the following disclaimer. 67 * 68 * 2. Redistributions in binary form must reproduce the above copyright 69 * notice, this list of conditions and the following disclaimer in 70 * the documentation and/or other materials provided with the 71 * distribution. 72 * 73 * 3. All advertising materials mentioning features or use of this 74 * software must display the following acknowledgment: 75 * "This product includes software developed by the OpenSSL Project 76 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 77 * 78 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 79 * endorse or promote products derived from this software without 80 * prior written permission. For written permission, please contact 81 * openssl-core (at) openssl.org. 82 * 83 * 5. Products derived from this software may not be called "OpenSSL" 84 * nor may "OpenSSL" appear in their names without prior written 85 * permission of the OpenSSL Project. 86 * 87 * 6. Redistributions of any form whatsoever must retain the following 88 * acknowledgment: 89 * "This product includes software developed by the OpenSSL Project 90 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 91 * 92 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 93 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 95 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 96 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 97 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 98 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 99 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 101 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 102 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 103 * OF THE POSSIBILITY OF SUCH DAMAGE. 104 * ==================================================================== 105 * 106 * This product includes cryptographic software written by Eric Young 107 * (eay (at) cryptsoft.com). This product includes software written by Tim 108 * Hudson (tjh (at) cryptsoft.com). 109 * 110 */ 111 112 #include <stdio.h> 113 #include <stdarg.h> 114 #include <string.h> 115 #include "cryptlib.h" 116 #include <openssl/lhash.h> 117 #include <openssl/crypto.h> 118 #include <openssl/buffer.h> 119 #include <openssl/bio.h> 120 #include <openssl/err.h> 121 122 #define err_clear_data(p,i) \ 123 do { \ 124 if (((p)->err_data[i] != NULL) && \ 125 (p)->err_data_flags[i] & ERR_TXT_MALLOCED) \ 126 { \ 127 OPENSSL_free((p)->err_data[i]); \ 128 (p)->err_data[i]=NULL; \ 129 } \ 130 (p)->err_data_flags[i]=0; \ 131 } while(0) 132 133 #define err_clear(p,i) \ 134 do { \ 135 (p)->err_flags[i]=0; \ 136 (p)->err_buffer[i]=0; \ 137 err_clear_data(p,i); \ 138 (p)->err_file[i]=NULL; \ 139 (p)->err_line[i]= -1; \ 140 } while(0) 141 142 static void err_load_strings(int lib, ERR_STRING_DATA *str); 143 144 static void ERR_STATE_free(ERR_STATE *s); 145 146 /* Define the predeclared (but externally opaque) "ERR_FNS" type */ 147 struct st_ERR_FNS 148 { 149 /* Works on the "error_hash" string table */ 150 LHASH *(*cb_err_get)(int create); 151 void (*cb_err_del)(void); 152 ERR_STRING_DATA *(*cb_err_get_item)(const ERR_STRING_DATA *); 153 ERR_STRING_DATA *(*cb_err_set_item)(ERR_STRING_DATA *); 154 ERR_STRING_DATA *(*cb_err_del_item)(ERR_STRING_DATA *); 155 /* Works on the "thread_hash" error-state table */ 156 LHASH *(*cb_thread_get)(int create); 157 void (*cb_thread_release)(LHASH **hash); 158 ERR_STATE *(*cb_thread_get_item)(const ERR_STATE *); 159 ERR_STATE *(*cb_thread_set_item)(ERR_STATE *); 160 void (*cb_thread_del_item)(const ERR_STATE *); 161 /* Returns the next available error "library" numbers */ 162 int (*cb_get_next_lib)(void); 163 }; 164 165 /* Predeclarations of the "err_defaults" functions */ 166 static LHASH *int_err_get(int create); 167 static void int_err_del(void); 168 static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *); 169 static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *); 170 static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *); 171 static LHASH *int_thread_get(int create); 172 static void int_thread_release(LHASH **hash); 173 static ERR_STATE *int_thread_get_item(const ERR_STATE *); 174 static ERR_STATE *int_thread_set_item(ERR_STATE *); 175 static void int_thread_del_item(const ERR_STATE *); 176 static int int_err_get_next_lib(void); 177 /* The static ERR_FNS table using these defaults functions */ 178 static const ERR_FNS err_defaults = 179 { 180 int_err_get, 181 int_err_del, 182 int_err_get_item, 183 int_err_set_item, 184 int_err_del_item, 185 int_thread_get, 186 int_thread_release, 187 int_thread_get_item, 188 int_thread_set_item, 189 int_thread_del_item, 190 int_err_get_next_lib 191 }; 192 193 /* The replacable table of ERR_FNS functions we use at run-time */ 194 static const ERR_FNS *err_fns = NULL; 195 196 /* Eg. rather than using "err_get()", use "ERRFN(err_get)()". */ 197 #define ERRFN(a) err_fns->cb_##a 198 199 /* The internal state used by "err_defaults" - as such, the setting, reading, 200 * creating, and deleting of this data should only be permitted via the 201 * "err_defaults" functions. This way, a linked module can completely defer all 202 * ERR state operation (together with requisite locking) to the implementations 203 * and state in the loading application. */ 204 static LHASH *int_error_hash = NULL; 205 static LHASH *int_thread_hash = NULL; 206 static int int_thread_hash_references = 0; 207 static int int_err_library_number= ERR_LIB_USER; 208 209 /* Internal function that checks whether "err_fns" is set and if not, sets it to 210 * the defaults. */ 211 static void err_fns_check(void) 212 { 213 if (err_fns) return; 214 215 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 216 if (!err_fns) 217 err_fns = &err_defaults; 218 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 219 } 220 221 /* API functions to get or set the underlying ERR functions. */ 222 223 const ERR_FNS *ERR_get_implementation(void) 224 { 225 err_fns_check(); 226 return err_fns; 227 } 228 229 int ERR_set_implementation(const ERR_FNS *fns) 230 { 231 int ret = 0; 232 233 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 234 /* It's too late if 'err_fns' is non-NULL. BTW: not much point setting 235 * an error is there?! */ 236 if (!err_fns) 237 { 238 err_fns = fns; 239 ret = 1; 240 } 241 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 242 return ret; 243 } 244 245 /* These are the callbacks provided to "lh_new()" when creating the LHASH tables 246 * internal to the "err_defaults" implementation. */ 247 248 /* static unsigned long err_hash(ERR_STRING_DATA *a); */ 249 static unsigned long err_hash(const void *a_void); 250 /* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b); */ 251 static int err_cmp(const void *a_void, const void *b_void); 252 /* static unsigned long pid_hash(ERR_STATE *pid); */ 253 static unsigned long pid_hash(const void *pid_void); 254 /* static int pid_cmp(ERR_STATE *a,ERR_STATE *pid); */ 255 static int pid_cmp(const void *a_void,const void *pid_void); 256 257 /* The internal functions used in the "err_defaults" implementation */ 258 259 static LHASH *int_err_get(int create) 260 { 261 LHASH *ret = NULL; 262 263 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 264 if (!int_error_hash && create) 265 { 266 CRYPTO_push_info("int_err_get (err.c)"); 267 int_error_hash = lh_new(err_hash, err_cmp); 268 CRYPTO_pop_info(); 269 } 270 if (int_error_hash) 271 ret = int_error_hash; 272 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 273 274 return ret; 275 } 276 277 static void int_err_del(void) 278 { 279 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 280 if (int_error_hash) 281 { 282 lh_free(int_error_hash); 283 int_error_hash = NULL; 284 } 285 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 286 } 287 288 static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d) 289 { 290 ERR_STRING_DATA *p; 291 LHASH *hash; 292 293 err_fns_check(); 294 hash = ERRFN(err_get)(0); 295 if (!hash) 296 return NULL; 297 298 CRYPTO_r_lock(CRYPTO_LOCK_ERR); 299 p = (ERR_STRING_DATA *)lh_retrieve(hash, d); 300 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); 301 302 return p; 303 } 304 305 static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *d) 306 { 307 ERR_STRING_DATA *p; 308 LHASH *hash; 309 310 err_fns_check(); 311 hash = ERRFN(err_get)(1); 312 if (!hash) 313 return NULL; 314 315 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 316 p = (ERR_STRING_DATA *)lh_insert(hash, d); 317 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 318 319 return p; 320 } 321 322 static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d) 323 { 324 ERR_STRING_DATA *p; 325 LHASH *hash; 326 327 err_fns_check(); 328 hash = ERRFN(err_get)(0); 329 if (!hash) 330 return NULL; 331 332 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 333 p = (ERR_STRING_DATA *)lh_delete(hash, d); 334 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 335 336 return p; 337 } 338 339 static LHASH *int_thread_get(int create) 340 { 341 LHASH *ret = NULL; 342 343 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 344 if (!int_thread_hash && create) 345 { 346 CRYPTO_push_info("int_thread_get (err.c)"); 347 int_thread_hash = lh_new(pid_hash, pid_cmp); 348 CRYPTO_pop_info(); 349 } 350 if (int_thread_hash) 351 { 352 int_thread_hash_references++; 353 ret = int_thread_hash; 354 } 355 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 356 return ret; 357 } 358 359 static void int_thread_release(LHASH **hash) 360 { 361 int i; 362 363 if (hash == NULL || *hash == NULL) 364 return; 365 366 i = CRYPTO_add(&int_thread_hash_references, -1, CRYPTO_LOCK_ERR); 367 368 #ifdef REF_PRINT 369 fprintf(stderr,"%4d:%s\n",int_thread_hash_references,"ERR"); 370 #endif 371 if (i > 0) return; 372 #ifdef REF_CHECK 373 if (i < 0) 374 { 375 fprintf(stderr,"int_thread_release, bad reference count\n"); 376 abort(); /* ok */ 377 } 378 #endif 379 *hash = NULL; 380 } 381 382 static ERR_STATE *int_thread_get_item(const ERR_STATE *d) 383 { 384 ERR_STATE *p; 385 LHASH *hash; 386 387 err_fns_check(); 388 hash = ERRFN(thread_get)(0); 389 if (!hash) 390 return NULL; 391 392 CRYPTO_r_lock(CRYPTO_LOCK_ERR); 393 p = (ERR_STATE *)lh_retrieve(hash, d); 394 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); 395 396 ERRFN(thread_release)(&hash); 397 return p; 398 } 399 400 static ERR_STATE *int_thread_set_item(ERR_STATE *d) 401 { 402 ERR_STATE *p; 403 LHASH *hash; 404 405 err_fns_check(); 406 hash = ERRFN(thread_get)(1); 407 if (!hash) 408 return NULL; 409 410 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 411 p = (ERR_STATE *)lh_insert(hash, d); 412 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 413 414 ERRFN(thread_release)(&hash); 415 return p; 416 } 417 418 static void int_thread_del_item(const ERR_STATE *d) 419 { 420 ERR_STATE *p; 421 LHASH *hash; 422 423 err_fns_check(); 424 hash = ERRFN(thread_get)(0); 425 if (!hash) 426 return; 427 428 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 429 p = (ERR_STATE *)lh_delete(hash, d); 430 /* make sure we don't leak memory */ 431 if (int_thread_hash_references == 1 432 && int_thread_hash && (lh_num_items(int_thread_hash) == 0)) 433 { 434 lh_free(int_thread_hash); 435 int_thread_hash = NULL; 436 } 437 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 438 439 ERRFN(thread_release)(&hash); 440 if (p) 441 ERR_STATE_free(p); 442 } 443 444 static int int_err_get_next_lib(void) 445 { 446 int ret; 447 448 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 449 ret = int_err_library_number++; 450 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 451 452 return ret; 453 } 454 455 static void ERR_STATE_free(ERR_STATE *s) 456 { 457 int i; 458 459 if (s == NULL) 460 return; 461 462 for (i=0; i<ERR_NUM_ERRORS; i++) 463 { 464 err_clear_data(s,i); 465 } 466 OPENSSL_free(s); 467 } 468 469 static void err_load_strings(int lib, ERR_STRING_DATA *str) 470 { 471 while (str->error) 472 { 473 if (lib) 474 str->error|=ERR_PACK(lib,0,0); 475 ERRFN(err_set_item)(str); 476 str++; 477 } 478 } 479 480 void ERR_load_strings(int lib, ERR_STRING_DATA *str) 481 { 482 err_fns_check(); 483 err_load_strings(lib, str); 484 } 485 486 void ERR_unload_strings(int lib, ERR_STRING_DATA *str) 487 { 488 while (str->error) 489 { 490 if (lib) 491 str->error|=ERR_PACK(lib,0,0); 492 ERRFN(err_del_item)(str); 493 str++; 494 } 495 } 496 497 void ERR_free_strings(void) 498 { 499 err_fns_check(); 500 ERRFN(err_del)(); 501 } 502 503 LHASH *ERR_get_string_table(void) 504 { 505 err_fns_check(); 506 return ERRFN(err_get)(0); 507 } 508 509 LHASH *ERR_get_err_state_table(void) 510 { 511 err_fns_check(); 512 return ERRFN(thread_get)(0); 513 } 514 515 void ERR_release_err_state_table(LHASH **hash) 516 { 517 err_fns_check(); 518 ERRFN(thread_release)(hash); 519 } 520 521 const char *ERR_lib_error_string(unsigned long e) 522 { 523 ERR_STRING_DATA d,*p; 524 unsigned long l; 525 526 err_fns_check(); 527 l=ERR_GET_LIB(e); 528 d.error=ERR_PACK(l,0,0); 529 p=ERRFN(err_get_item)(&d); 530 return((p == NULL)?NULL:p->string); 531 } 532 533 const char *ERR_func_error_string(unsigned long e) 534 { 535 ERR_STRING_DATA d,*p; 536 unsigned long l,f; 537 538 err_fns_check(); 539 l=ERR_GET_LIB(e); 540 f=ERR_GET_FUNC(e); 541 d.error=ERR_PACK(l,f,0); 542 p=ERRFN(err_get_item)(&d); 543 return((p == NULL)?NULL:p->string); 544 } 545 546 const char *ERR_reason_error_string(unsigned long e) 547 { 548 ERR_STRING_DATA d,*p=NULL; 549 unsigned long l,r; 550 551 err_fns_check(); 552 l=ERR_GET_LIB(e); 553 r=ERR_GET_REASON(e); 554 d.error=ERR_PACK(l,0,r); 555 p=ERRFN(err_get_item)(&d); 556 if (!p) 557 { 558 d.error=ERR_PACK(0,0,r); 559 p=ERRFN(err_get_item)(&d); 560 } 561 return((p == NULL)?NULL:p->string); 562 } 563 564 /* static unsigned long err_hash(ERR_STRING_DATA *a) */ 565 static unsigned long err_hash(const void *a_void) 566 { 567 unsigned long ret,l; 568 569 l=((const ERR_STRING_DATA *)a_void)->error; 570 ret=l^ERR_GET_LIB(l)^ERR_GET_FUNC(l); 571 return(ret^ret%19*13); 572 } 573 574 /* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b) */ 575 static int err_cmp(const void *a_void, const void *b_void) 576 { 577 return((int)(((const ERR_STRING_DATA *)a_void)->error - 578 ((const ERR_STRING_DATA *)b_void)->error)); 579 } 580 581 /* static unsigned long pid_hash(ERR_STATE *a) */ 582 static unsigned long pid_hash(const void *a_void) 583 { 584 return(((const ERR_STATE *)a_void)->pid*13); 585 } 586 587 /* static int pid_cmp(ERR_STATE *a, ERR_STATE *b) */ 588 static int pid_cmp(const void *a_void, const void *b_void) 589 { 590 return((int)((long)((const ERR_STATE *)a_void)->pid - 591 (long)((const ERR_STATE *)b_void)->pid)); 592 } 593 #ifdef OPENSSL_FIPS 594 static void int_err_remove_state(unsigned long pid) 595 #else 596 void ERR_remove_state(unsigned long pid) 597 #endif 598 { 599 ERR_STATE tmp; 600 601 err_fns_check(); 602 if (pid == 0) 603 pid=(unsigned long)CRYPTO_thread_id(); 604 tmp.pid=pid; 605 /* thread_del_item automatically destroys the LHASH if the number of 606 * items reaches zero. */ 607 ERRFN(thread_del_item)(&tmp); 608 } 609 610 #ifdef OPENSSL_FIPS 611 static ERR_STATE *int_err_get_state(void) 612 #else 613 ERR_STATE *ERR_get_state(void) 614 #endif 615 { 616 static ERR_STATE fallback; 617 ERR_STATE *ret,tmp,*tmpp=NULL; 618 int i; 619 unsigned long pid; 620 621 err_fns_check(); 622 pid=(unsigned long)CRYPTO_thread_id(); 623 tmp.pid=pid; 624 ret=ERRFN(thread_get_item)(&tmp); 625 626 /* ret == the error state, if NULL, make a new one */ 627 if (ret == NULL) 628 { 629 ret=(ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE)); 630 if (ret == NULL) return(&fallback); 631 ret->pid=pid; 632 ret->top=0; 633 ret->bottom=0; 634 for (i=0; i<ERR_NUM_ERRORS; i++) 635 { 636 ret->err_data[i]=NULL; 637 ret->err_data_flags[i]=0; 638 } 639 tmpp = ERRFN(thread_set_item)(ret); 640 /* To check if insertion failed, do a get. */ 641 if (ERRFN(thread_get_item)(ret) != ret) 642 { 643 ERR_STATE_free(ret); /* could not insert it */ 644 return(&fallback); 645 } 646 /* If a race occured in this function and we came second, tmpp 647 * is the first one that we just replaced. */ 648 if (tmpp) 649 ERR_STATE_free(tmpp); 650 } 651 return ret; 652 } 653 654 #ifdef OPENSSL_FIPS 655 void int_ERR_lib_init(void) 656 { 657 int_ERR_set_state_func(int_err_get_state, int_err_remove_state); 658 } 659 #endif 660 661 int ERR_get_next_error_library(void) 662 { 663 err_fns_check(); 664 return ERRFN(get_next_lib)(); 665 } 666