1/* 2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19/* crypto/err/err.c */ 20/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 21 * All rights reserved. 22 * 23 * This package is an SSL implementation written 24 * by Eric Young (eay@cryptsoft.com). 25 * The implementation was written so as to conform with Netscapes SSL. 26 * 27 * This library is free for commercial and non-commercial use as long as 28 * the following conditions are aheared to. The following conditions 29 * apply to all code found in this distribution, be it the RC4, RSA, 30 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 31 * included with this distribution is covered by the same copyright terms 32 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 33 * 34 * Copyright remains Eric Young's, and as such any Copyright notices in 35 * the code are not to be removed. 36 * If this package is used in a product, Eric Young should be given attribution 37 * as the author of the parts of the library used. 38 * This can be in the form of a textual message at program startup or 39 * in documentation (online or textual) provided with the package. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * "This product includes cryptographic software written by 52 * Eric Young (eay@cryptsoft.com)" 53 * The word 'cryptographic' can be left out if the rouines from the library 54 * being used are not cryptographic related :-). 55 * 4. If you include any Windows specific code (or a derivative thereof) from 56 * the apps directory (application code) you must include an acknowledgement: 57 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 58 * 59 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * The licence and distribution terms for any publically available version or 72 * derivative of this code cannot be changed. i.e. this code cannot simply be 73 * copied and put under another distribution licence 74 * [including the GNU Public Licence.] 75 */ 76/* ==================================================================== 77 * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. 78 * 79 * Redistribution and use in source and binary forms, with or without 80 * modification, are permitted provided that the following conditions 81 * are met: 82 * 83 * 1. Redistributions of source code must retain the above copyright 84 * notice, this list of conditions and the following disclaimer. 85 * 86 * 2. Redistributions in binary form must reproduce the above copyright 87 * notice, this list of conditions and the following disclaimer in 88 * the documentation and/or other materials provided with the 89 * distribution. 90 * 91 * 3. All advertising materials mentioning features or use of this 92 * software must display the following acknowledgment: 93 * "This product includes software developed by the OpenSSL Project 94 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 95 * 96 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 97 * endorse or promote products derived from this software without 98 * prior written permission. For written permission, please contact 99 * openssl-core@openssl.org. 100 * 101 * 5. Products derived from this software may not be called "OpenSSL" 102 * nor may "OpenSSL" appear in their names without prior written 103 * permission of the OpenSSL Project. 104 * 105 * 6. Redistributions of any form whatsoever must retain the following 106 * acknowledgment: 107 * "This product includes software developed by the OpenSSL Project 108 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 109 * 110 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 111 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 112 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 113 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 114 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 115 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 116 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 117 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 118 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 119 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 120 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 121 * OF THE POSSIBILITY OF SUCH DAMAGE. 122 * ==================================================================== 123 * 124 * This product includes cryptographic software written by Eric Young 125 * (eay@cryptsoft.com). This product includes software written by Tim 126 * Hudson (tjh@cryptsoft.com). 127 * 128 */ 129 130#include <stdio.h> 131#include <stdarg.h> 132#include <string.h> 133#include <openssl/opensslconf.h> 134#include <openssl/lhash.h> 135#include <openssl/crypto.h> 136#include "cryptlib.h" 137#include <openssl/buffer.h> 138#include <openssl/err.h> 139#include <openssl/crypto.h> 140 141 142static LHASH *error_hash=NULL; 143static LHASH *thread_hash=NULL; 144 145static unsigned long err_hash(ERR_STRING_DATA *a); 146static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b); 147static unsigned long pid_hash(ERR_STATE *pid); 148static int pid_cmp(ERR_STATE *a,ERR_STATE *pid); 149static unsigned long get_error_values(int inc,const char **file,int *line, 150 const char **data,int *flags); 151static void ERR_STATE_free(ERR_STATE *s); 152#ifndef NO_ERR 153static ERR_STRING_DATA ERR_str_libraries[]= 154 { 155{ERR_PACK(ERR_LIB_NONE,0,0) ,"unknown library"}, 156{ERR_PACK(ERR_LIB_SYS,0,0) ,"system library"}, 157{ERR_PACK(ERR_LIB_BN,0,0) ,"bignum routines"}, 158{ERR_PACK(ERR_LIB_RSA,0,0) ,"rsa routines"}, 159{ERR_PACK(ERR_LIB_DH,0,0) ,"Diffie-Hellman routines"}, 160{ERR_PACK(ERR_LIB_EVP,0,0) ,"digital envelope routines"}, 161{ERR_PACK(ERR_LIB_BUF,0,0) ,"memory buffer routines"}, 162{ERR_PACK(ERR_LIB_BIO,0,0) ,"BIO routines"}, 163{ERR_PACK(ERR_LIB_OBJ,0,0) ,"object identifier routines"}, 164{ERR_PACK(ERR_LIB_PEM,0,0) ,"PEM routines"}, 165{ERR_PACK(ERR_LIB_ASN1,0,0) ,"asn1 encoding routines"}, 166{ERR_PACK(ERR_LIB_X509,0,0) ,"x509 certificate routines"}, 167{ERR_PACK(ERR_LIB_CONF,0,0) ,"configuration file routines"}, 168{ERR_PACK(ERR_LIB_METH,0,0) ,"X509 lookup 'method' routines"}, 169{ERR_PACK(ERR_LIB_SSL,0,0) ,"SSL routines"}, 170{ERR_PACK(ERR_LIB_RSAREF,0,0) ,"RSAref routines"}, 171{ERR_PACK(ERR_LIB_PROXY,0,0) ,"Proxy routines"}, 172{ERR_PACK(ERR_LIB_BIO,0,0) ,"BIO routines"}, 173{ERR_PACK(ERR_LIB_PKCS7,0,0) ,"PKCS7 routines"}, 174{ERR_PACK(ERR_LIB_X509V3,0,0) ,"X509 V3 routines"}, 175{ERR_PACK(ERR_LIB_PKCS12,0,0) ,"PKCS12 routines"}, 176{ERR_PACK(ERR_LIB_RAND,0,0) ,"random number generator"}, 177{0,NULL}, 178 }; 179 180static ERR_STRING_DATA ERR_str_functs[]= 181 { 182 {ERR_PACK(0,SYS_F_FOPEN,0), "fopen"}, 183 {ERR_PACK(0,SYS_F_CONNECT,0), "connect"}, 184 {ERR_PACK(0,SYS_F_GETSERVBYNAME,0), "getservbyname"}, 185 {ERR_PACK(0,SYS_F_SOCKET,0), "socket"}, 186 {ERR_PACK(0,SYS_F_IOCTLSOCKET,0), "ioctlsocket"}, 187 {ERR_PACK(0,SYS_F_BIND,0), "bind"}, 188 {ERR_PACK(0,SYS_F_LISTEN,0), "listen"}, 189 {ERR_PACK(0,SYS_F_ACCEPT,0), "accept"}, 190#ifdef WINDOWS 191 {ERR_PACK(0,SYS_F_WSASTARTUP,0), "WSAstartup"}, 192#endif 193 {ERR_PACK(0,SYS_F_OPENDIR,0), "opendir"}, 194 {0,NULL}, 195 }; 196 197static ERR_STRING_DATA ERR_str_reasons[]= 198 { 199{ERR_R_FATAL ,"fatal"}, 200{ERR_R_SYS_LIB ,"system lib"}, 201{ERR_R_BN_LIB ,"BN lib"}, 202{ERR_R_RSA_LIB ,"RSA lib"}, 203{ERR_R_DH_LIB ,"DH lib"}, 204{ERR_R_EVP_LIB ,"EVP lib"}, 205{ERR_R_BUF_LIB ,"BUF lib"}, 206{ERR_R_BIO_LIB ,"BIO lib"}, 207{ERR_R_OBJ_LIB ,"OBJ lib"}, 208{ERR_R_PEM_LIB ,"PEM lib"}, 209{ERR_R_X509_LIB ,"X509 lib"}, 210{ERR_R_METH_LIB ,"METH lib"}, 211{ERR_R_ASN1_LIB ,"ASN1 lib"}, 212{ERR_R_CONF_LIB ,"CONF lib"}, 213{ERR_R_SSL_LIB ,"SSL lib"}, 214{ERR_R_PROXY_LIB ,"PROXY lib"}, 215{ERR_R_BIO_LIB ,"BIO lib"}, 216{ERR_R_PKCS7_LIB ,"PKCS7 lib"}, 217{ERR_R_PKCS12_LIB ,"PKCS12 lib"}, 218{ERR_R_MALLOC_FAILURE ,"Malloc failure"}, 219{ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED ,"called a function you should not call"}, 220{ERR_R_PASSED_NULL_PARAMETER ,"passed a null parameter"}, 221{ERR_R_NESTED_ASN1_ERROR ,"nested asn1 error"}, 222{ERR_R_BAD_ASN1_OBJECT_HEADER ,"bad asn1 object header"}, 223{ERR_R_BAD_GET_ASN1_OBJECT_CALL ,"bad get asn1 object call"}, 224{ERR_R_EXPECTING_AN_ASN1_SEQUENCE ,"expecting an asn1 sequence"}, 225{ERR_R_ASN1_LENGTH_MISMATCH ,"asn1 length mismatch"}, 226{ERR_R_MISSING_ASN1_EOS ,"missing asn1 eos"}, 227 228{0,NULL}, 229 }; 230 231 232#define NUM_SYS_STR_REASONS 127 233#define LEN_SYS_STR_REASON 32 234 235static ERR_STRING_DATA SYS_str_reasons[NUM_SYS_STR_REASONS + 1]; 236/* SYS_str_reasons is filled with copies of strerror() results at 237 * initialization. 238 * 'errno' values up to 127 should cover all usual errors, 239 * others will be displayed numerically by ERR_error_string. 240 * It is crucial that we have something for each reason code 241 * that occurs in ERR_str_reasons, or bogus reason strings 242 * will be returned for SYSerr(), which always gets an errno 243 * value and never one of those 'standard' reason codes. */ 244 245static void build_SYS_str_reasons() 246 { 247 /* Malloc cannot be used here, use static storage instead */ 248 static char strerror_tab[NUM_SYS_STR_REASONS][LEN_SYS_STR_REASON]; 249 int i; 250 251 CRYPTO_w_lock(CRYPTO_LOCK_ERR_HASH); 252 253 for (i = 1; i <= NUM_SYS_STR_REASONS; i++) 254 { 255 ERR_STRING_DATA *str = &SYS_str_reasons[i - 1]; 256 257 str->error = (unsigned long)i; 258 if (str->string == NULL) 259 { 260 char (*dest)[LEN_SYS_STR_REASON] = &(strerror_tab[i - 1]); 261 char *src = strerror(i); 262 if (src != NULL) 263 { 264 strncpy(*dest, src, sizeof *dest); 265 (*dest)[sizeof *dest - 1] = '\0'; 266 str->string = *dest; 267 } 268 } 269 if (str->string == NULL) 270 str->string = "unknown"; 271 } 272 273 /* Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL}, 274 * as required by ERR_load_strings. */ 275 276 CRYPTO_w_unlock(CRYPTO_LOCK_ERR_HASH); 277 } 278#endif 279 280#define err_clear_data(p,i) \ 281 if (((p)->err_data[i] != NULL) && \ 282 (p)->err_data_flags[i] & ERR_TXT_MALLOCED) \ 283 { \ 284 Free((p)->err_data[i]); \ 285 (p)->err_data[i]=NULL; \ 286 } \ 287 (p)->err_data_flags[i]=0; 288 289static void ERR_STATE_free(ERR_STATE *s) 290 { 291 int i; 292 293 if(s == NULL) 294 return; 295 296 for (i=0; i<ERR_NUM_ERRORS; i++) 297 { 298 err_clear_data(s,i); 299 } 300 Free(s); 301 } 302 303void ERR_load_ERR_strings(void) 304 { 305 static int init=1; 306 307 if (init) 308 { 309 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 310 if (init == 0) 311 { 312 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 313 return; 314 } 315 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 316 317#ifndef NO_ERR 318 ERR_load_strings(0,ERR_str_libraries); 319 ERR_load_strings(0,ERR_str_reasons); 320 ERR_load_strings(ERR_LIB_SYS,ERR_str_functs); 321 build_SYS_str_reasons(); 322 ERR_load_strings(ERR_LIB_SYS,SYS_str_reasons); 323#endif 324 init=0; 325 } 326 } 327 328void ERR_load_strings(int lib, ERR_STRING_DATA *str) 329 { 330 if (error_hash == NULL) 331 { 332 CRYPTO_w_lock(CRYPTO_LOCK_ERR_HASH); 333 error_hash=lh_new(err_hash,err_cmp); 334 if (error_hash == NULL) 335 { 336 CRYPTO_w_unlock(CRYPTO_LOCK_ERR_HASH); 337 return; 338 } 339 CRYPTO_w_unlock(CRYPTO_LOCK_ERR_HASH); 340 341 ERR_load_ERR_strings(); 342 } 343 344 CRYPTO_w_lock(CRYPTO_LOCK_ERR_HASH); 345 while (str->error) 346 { 347 str->error|=ERR_PACK(lib,0,0); 348 lh_insert(error_hash,str); 349 str++; 350 } 351 CRYPTO_w_unlock(CRYPTO_LOCK_ERR_HASH); 352 } 353 354void ERR_free_strings(void) 355 { 356 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 357 358 if (error_hash != NULL) 359 { 360 lh_free(error_hash); 361 error_hash=NULL; 362 } 363 364 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 365 } 366 367/********************************************************/ 368 369void ERR_put_error(int lib, int func, int reason, const char *file, 370 int line) 371 { 372 ERR_STATE *es; 373 374#ifdef _OSD_POSIX 375 /* In the BS2000-OSD POSIX subsystem, the compiler generates 376 * path names in the form "*POSIX(/etc/passwd)". 377 * This dirty hack strips them to something sensible. 378 * @@@ We shouldn't modify a const string, though. 379 */ 380 if (strncmp(file,"*POSIX(", sizeof("*POSIX(")-1) == 0) { 381 char *end; 382 383 /* Skip the "*POSIX(" prefix */ 384 file += sizeof("*POSIX(")-1; 385 end = &file[strlen(file)-1]; 386 if (*end == ')') 387 *end = '\0'; 388 /* Optional: use the basename of the path only. */ 389 if ((end = strrchr(file, '/')) != NULL) 390 file = &end[1]; 391 } 392#endif 393 es=ERR_get_state(); 394 395 es->top=(es->top+1)%ERR_NUM_ERRORS; 396 if (es->top == es->bottom) 397 es->bottom=(es->bottom+1)%ERR_NUM_ERRORS; 398 es->err_buffer[es->top]=ERR_PACK(lib,func,reason); 399 es->err_file[es->top]=file; 400 es->err_line[es->top]=line; 401 err_clear_data(es,es->top); 402 } 403 404void ERR_clear_error(void) 405 { 406 ERR_STATE *es; 407 408 es=ERR_get_state(); 409 410#if 0 411 /* hmm... is this needed */ 412 for (i=0; i<ERR_NUM_ERRORS; i++) 413 { 414 es->err_buffer[i]=0; 415 es->err_file[i]=NULL; 416 es->err_line[i]= -1; 417 err_clear_data(es,i); 418 } 419#endif 420 es->top=es->bottom=0; 421 } 422 423 424unsigned long ERR_get_error(void) 425 { return(get_error_values(1,NULL,NULL,NULL,NULL)); } 426 427unsigned long ERR_get_error_line(const char **file, 428 int *line) 429 { return(get_error_values(1,file,line,NULL,NULL)); } 430 431unsigned long ERR_get_error_line_data(const char **file, int *line, 432 const char **data, int *flags) 433 { return(get_error_values(1,file,line, 434 data,flags)); } 435 436unsigned long ERR_peek_error(void) 437 { return(get_error_values(0,NULL,NULL,NULL,NULL)); } 438 439unsigned long ERR_peek_error_line(const char **file, 440 int *line) 441 { return(get_error_values(0,file,line,NULL,NULL)); } 442 443unsigned long ERR_peek_error_line_data(const char **file, int *line, 444 const char **data, int *flags) 445 { return(get_error_values(0,file,line, 446 data,flags)); } 447 448static unsigned long get_error_values(int inc, const char **file, int *line, 449 const char **data, int *flags) 450 { 451 int i=0; 452 ERR_STATE *es; 453 unsigned long ret; 454 455 es=ERR_get_state(); 456 457 if (es->bottom == es->top) return(0); 458 i=(es->bottom+1)%ERR_NUM_ERRORS; 459 460 ret=es->err_buffer[i]; 461 if (inc) 462 { 463 es->bottom=i; 464 es->err_buffer[i]=0; 465 } 466 467 if ((file != NULL) && (line != NULL)) 468 { 469 if (es->err_file[i] == NULL) 470 { 471 *file="NA"; 472 if (line != NULL) *line=0; 473 } 474 else 475 { 476 *file=es->err_file[i]; 477 if (line != NULL) *line=es->err_line[i]; 478 } 479 } 480 481 if (data != NULL) 482 { 483 if (es->err_data[i] == NULL) 484 { 485 *data=""; 486 if (flags != NULL) *flags=0; 487 } 488 else 489 { 490 *data=es->err_data[i]; 491 if (flags != NULL) *flags=es->err_data_flags[i]; 492 } 493 } 494 return(ret); 495 } 496 497/* BAD for multi-threaded, uses a local buffer if ret == NULL */ 498char *ERR_error_string(unsigned long e, char *ret) 499 { 500 #ifdef NO_ERR 501 if(ret != NULL) { 502 strcpy(ret, "No Error String Info."); 503 } 504 return "No Error String info."; 505 #else 506 static char buf[256]; 507 const char *ls,*fs,*rs; 508 unsigned long l,f,r; 509 size_t i; 510 511 l=ERR_GET_LIB(e); 512 f=ERR_GET_FUNC(e); 513 r=ERR_GET_REASON(e); 514 515 ls=ERR_lib_error_string(e); 516 fs=ERR_func_error_string(e); 517 rs=ERR_reason_error_string(e); 518 519 if (ret == NULL) ret=buf; 520 521 sprintf(&(ret[0]),"error:%08lX:",e); 522 i=strlen(ret); 523 if (ls == NULL) 524 sprintf(&(ret[i]),":lib(%lu) ",l); 525 else sprintf(&(ret[i]),"%s",ls); 526 i=strlen(ret); 527 if (fs == NULL) 528 sprintf(&(ret[i]),":func(%lu) ",f); 529 else sprintf(&(ret[i]),":%s",fs); 530 i=strlen(ret); 531 if (rs == NULL) 532 sprintf(&(ret[i]),":reason(%lu)",r); 533 else sprintf(&(ret[i]),":%s",rs); 534 535 return(ret); 536 #endif 537 } 538 539LHASH *ERR_get_string_table(void) 540 { 541 return(error_hash); 542 } 543 544LHASH *ERR_get_err_state_table(void) 545 { 546 return(thread_hash); 547 } 548 549const char *ERR_lib_error_string(unsigned long e) 550 { 551 ERR_STRING_DATA d,*p=NULL; 552 unsigned long l; 553 554 l=ERR_GET_LIB(e); 555 556 CRYPTO_r_lock(CRYPTO_LOCK_ERR_HASH); 557 558 if (error_hash != NULL) 559 { 560 d.error=ERR_PACK(l,0,0); 561 p=(ERR_STRING_DATA *)lh_retrieve(error_hash,&d); 562 } 563 564 CRYPTO_r_unlock(CRYPTO_LOCK_ERR_HASH); 565 566 return((p == NULL)?NULL:p->string); 567 } 568 569const char *ERR_func_error_string(unsigned long e) 570 { 571 ERR_STRING_DATA d,*p=NULL; 572 unsigned long l,f; 573 574 l=ERR_GET_LIB(e); 575 f=ERR_GET_FUNC(e); 576 577 CRYPTO_r_lock(CRYPTO_LOCK_ERR_HASH); 578 579 if (error_hash != NULL) 580 { 581 d.error=ERR_PACK(l,f,0); 582 p=(ERR_STRING_DATA *)lh_retrieve(error_hash,&d); 583 } 584 585 CRYPTO_r_unlock(CRYPTO_LOCK_ERR_HASH); 586 587 return((p == NULL)?NULL:p->string); 588 } 589 590const char *ERR_reason_error_string(unsigned long e) 591 { 592 ERR_STRING_DATA d,*p=NULL; 593 unsigned long l,r; 594 595 l=ERR_GET_LIB(e); 596 r=ERR_GET_REASON(e); 597 598 CRYPTO_r_lock(CRYPTO_LOCK_ERR_HASH); 599 600 if (error_hash != NULL) 601 { 602 d.error=ERR_PACK(l,0,r); 603 p=(ERR_STRING_DATA *)lh_retrieve(error_hash,&d); 604 if (p == NULL) 605 { 606 d.error=ERR_PACK(0,0,r); 607 p=(ERR_STRING_DATA *)lh_retrieve(error_hash,&d); 608 } 609 } 610 611 CRYPTO_r_unlock(CRYPTO_LOCK_ERR_HASH); 612 613 return((p == NULL)?NULL:p->string); 614 } 615 616static unsigned long err_hash(ERR_STRING_DATA *a) 617 { 618 unsigned long ret,l; 619 620 l=a->error; 621 ret=l^ERR_GET_LIB(l)^ERR_GET_FUNC(l); 622 return(ret^ret%19*13); 623 } 624 625static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b) 626 { 627 return((int)(a->error-b->error)); 628 } 629 630static unsigned long pid_hash(ERR_STATE *a) 631 { 632 return(a->pid*13); 633 } 634 635static int pid_cmp(ERR_STATE *a, ERR_STATE *b) 636 { 637 return((int)((long)a->pid - (long)b->pid)); 638 } 639 640void ERR_remove_state(unsigned long pid) 641 { 642 ERR_STATE *p,tmp; 643 644 if (thread_hash == NULL) 645 return; 646 if (pid == 0) 647 pid=(unsigned long)CRYPTO_thread_id(); 648 tmp.pid=pid; 649 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 650 p=(ERR_STATE *)lh_delete(thread_hash,&tmp); 651 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 652 653 if (p != NULL) ERR_STATE_free(p); 654 } 655 656static ERR_STATE *fallback = NULL; 657static ERR_STATE *getFallback() 658{ 659 if(fallback == NULL) { 660 fallback = (ERR_STATE *)Malloc(sizeof(ERR_STATE)); 661 } 662 return fallback; 663} 664 665ERR_STATE *ERR_get_state(void) 666 { 667 ERR_STATE *ret=NULL,tmp,*tmpp; 668 int i; 669 unsigned long pid; 670 671 pid=(unsigned long)CRYPTO_thread_id(); 672 673 CRYPTO_r_lock(CRYPTO_LOCK_ERR); 674 if (thread_hash == NULL) 675 { 676 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); 677 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 678 if (thread_hash == NULL) 679 { 680 MemCheck_off(); 681 thread_hash=lh_new(pid_hash,pid_cmp); 682 MemCheck_on(); 683 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 684 if (thread_hash == NULL) return(getFallback()); 685 } 686 else 687 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 688 } 689 else 690 { 691 tmp.pid=pid; 692 ret=(ERR_STATE *)lh_retrieve(thread_hash,&tmp); 693 CRYPTO_r_unlock(CRYPTO_LOCK_ERR); 694 } 695 696 /* ret == the error state, if NULL, make a new one */ 697 if (ret == NULL) 698 { 699 ret=(ERR_STATE *)Malloc(sizeof(ERR_STATE)); 700 if (ret == NULL) return(getFallback()); 701 ret->pid=pid; 702 ret->top=0; 703 ret->bottom=0; 704 for (i=0; i<ERR_NUM_ERRORS; i++) 705 { 706 ret->err_data[i]=NULL; 707 ret->err_data_flags[i]=0; 708 } 709 CRYPTO_w_lock(CRYPTO_LOCK_ERR); 710 tmpp=(ERR_STATE *)lh_insert(thread_hash,ret); 711 CRYPTO_w_unlock(CRYPTO_LOCK_ERR); 712 if (tmpp != NULL) /* old entry - should not happen */ 713 { 714 ERR_STATE_free(tmpp); 715 } 716 } 717 return(ret); 718 } 719 720int ERR_get_next_error_library(void) 721 { 722 static int value=ERR_LIB_USER; 723 724 return(value++); 725 } 726 727void ERR_set_error_data(char *data, int flags) 728 { 729 ERR_STATE *es; 730 int i; 731 732 es=ERR_get_state(); 733 734 i=es->top; 735 if (i == 0) 736 i=ERR_NUM_ERRORS-1; 737 738 es->err_data[i]=data; 739 es->err_data_flags[es->top]=flags; 740 } 741 742void ERR_add_error_data(int num, ...) 743 { 744 va_list args; 745 int i,n,s; 746 char *str,*p,*a; 747 748 s=64; 749 str=Malloc(s+1); 750 if (str == NULL) return; 751 str[0]='\0'; 752 753 va_start(args, num); 754 n=0; 755 for (i=0; i<num; i++) 756 { 757 a=va_arg(args, char*); 758 /* ignore NULLs, thanks to Bob Beck <beck@obtuse.com> */ 759 if (a != NULL) 760 { 761 n+=strlen(a); 762 if (n > s) 763 { 764 s=n+20; 765 p=Realloc(str,s+1); 766 if (p == NULL) 767 { 768 Free(str); 769 return; 770 } 771 else 772 str=p; 773 } 774 strcat(str,a); 775 } 776 } 777 ERR_set_error_data(str,ERR_TXT_MALLOCED|ERR_TXT_STRING); 778 779 va_end(args); 780 } 781 782