sl@0: /* crypto/err/err.c */
sl@0: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
sl@0:  * All rights reserved.
sl@0:  *
sl@0:  * This package is an SSL implementation written
sl@0:  * by Eric Young (eay@cryptsoft.com).
sl@0:  * The implementation was written so as to conform with Netscapes SSL.
sl@0:  * 
sl@0:  * This library is free for commercial and non-commercial use as long as
sl@0:  * the following conditions are aheared to.  The following conditions
sl@0:  * apply to all code found in this distribution, be it the RC4, RSA,
sl@0:  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
sl@0:  * included with this distribution is covered by the same copyright terms
sl@0:  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
sl@0:  * 
sl@0:  * Copyright remains Eric Young's, and as such any Copyright notices in
sl@0:  * the code are not to be removed.
sl@0:  * If this package is used in a product, Eric Young should be given attribution
sl@0:  * as the author of the parts of the library used.
sl@0:  * This can be in the form of a textual message at program startup or
sl@0:  * in documentation (online or textual) provided with the package.
sl@0:  * 
sl@0:  * Redistribution and use in source and binary forms, with or without
sl@0:  * modification, are permitted provided that the following conditions
sl@0:  * are met:
sl@0:  * 1. Redistributions of source code must retain the copyright
sl@0:  *    notice, this list of conditions and the following disclaimer.
sl@0:  * 2. Redistributions in binary form must reproduce the above copyright
sl@0:  *    notice, this list of conditions and the following disclaimer in the
sl@0:  *    documentation and/or other materials provided with the distribution.
sl@0:  * 3. All advertising materials mentioning features or use of this software
sl@0:  *    must display the following acknowledgement:
sl@0:  *    "This product includes cryptographic software written by
sl@0:  *     Eric Young (eay@cryptsoft.com)"
sl@0:  *    The word 'cryptographic' can be left out if the rouines from the library
sl@0:  *    being used are not cryptographic related :-).
sl@0:  * 4. If you include any Windows specific code (or a derivative thereof) from 
sl@0:  *    the apps directory (application code) you must include an acknowledgement:
sl@0:  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
sl@0:  * 
sl@0:  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
sl@0:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
sl@0:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
sl@0:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
sl@0:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
sl@0:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
sl@0:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
sl@0:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
sl@0:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
sl@0:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
sl@0:  * SUCH DAMAGE.
sl@0:  * 
sl@0:  * The licence and distribution terms for any publically available version or
sl@0:  * derivative of this code cannot be changed.  i.e. this code cannot simply be
sl@0:  * copied and put under another distribution licence
sl@0:  * [including the GNU Public Licence.]
sl@0:  */
sl@0: /* ====================================================================
sl@0:  * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
sl@0:  *
sl@0:  * Redistribution and use in source and binary forms, with or without
sl@0:  * modification, are permitted provided that the following conditions
sl@0:  * are met:
sl@0:  *
sl@0:  * 1. Redistributions of source code must retain the above copyright
sl@0:  *    notice, this list of conditions and the following disclaimer. 
sl@0:  *
sl@0:  * 2. Redistributions in binary form must reproduce the above copyright
sl@0:  *    notice, this list of conditions and the following disclaimer in
sl@0:  *    the documentation and/or other materials provided with the
sl@0:  *    distribution.
sl@0:  *
sl@0:  * 3. All advertising materials mentioning features or use of this
sl@0:  *    software must display the following acknowledgment:
sl@0:  *    "This product includes software developed by the OpenSSL Project
sl@0:  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
sl@0:  *
sl@0:  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
sl@0:  *    endorse or promote products derived from this software without
sl@0:  *    prior written permission. For written permission, please contact
sl@0:  *    openssl-core@openssl.org.
sl@0:  *
sl@0:  * 5. Products derived from this software may not be called "OpenSSL"
sl@0:  *    nor may "OpenSSL" appear in their names without prior written
sl@0:  *    permission of the OpenSSL Project.
sl@0:  *
sl@0:  * 6. Redistributions of any form whatsoever must retain the following
sl@0:  *    acknowledgment:
sl@0:  *    "This product includes software developed by the OpenSSL Project
sl@0:  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
sl@0:  *
sl@0:  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
sl@0:  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
sl@0:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
sl@0:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
sl@0:  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
sl@0:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
sl@0:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
sl@0:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
sl@0:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
sl@0:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
sl@0:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
sl@0:  * OF THE POSSIBILITY OF SUCH DAMAGE.
sl@0:  * ====================================================================
sl@0:  *
sl@0:  * This product includes cryptographic software written by Eric Young
sl@0:  * (eay@cryptsoft.com).  This product includes software written by Tim
sl@0:  * Hudson (tjh@cryptsoft.com).
sl@0:  *
sl@0:  */
sl@0:  /*
sl@0:  © Portions copyright (c) 2006 Nokia Corporation.  All rights reserved.
sl@0:  */
sl@0: 
sl@0: 
sl@0: #include <stdio.h>
sl@0: #include <stdarg.h>
sl@0: #include <string.h>
sl@0: #include "cryptlib.h"
sl@0: #include <openssl/lhash.h>
sl@0: #include <openssl/crypto.h>
sl@0: #include <openssl/buffer.h>
sl@0: #include <openssl/bio.h>
sl@0: #include <openssl/err.h>
sl@0: #if (defined(SYMBIAN) && (defined(__WINSCW__) || defined(__WINS__)))
sl@0: #include "libcrypto_wsd_macros.h"
sl@0: #include "libcrypto_wsd.h"
sl@0: #endif
sl@0: 
sl@0: static void err_load_strings(int lib, ERR_STRING_DATA *str);
sl@0: static void ERR_STATE_free(ERR_STATE *s);
sl@0: #ifndef OPENSSL_NO_ERR
sl@0: #ifndef EMULATOR
sl@0: static ERR_STRING_DATA ERR_str_libraries[]=
sl@0: 	{
sl@0: {ERR_PACK(ERR_LIB_NONE,0,0)		,"unknown library"},
sl@0: {ERR_PACK(ERR_LIB_SYS,0,0)		,"system library"},
sl@0: {ERR_PACK(ERR_LIB_BN,0,0)		,"bignum routines"},
sl@0: {ERR_PACK(ERR_LIB_RSA,0,0)		,"rsa routines"},
sl@0: {ERR_PACK(ERR_LIB_DH,0,0)		,"Diffie-Hellman routines"},
sl@0: {ERR_PACK(ERR_LIB_EVP,0,0)		,"digital envelope routines"},
sl@0: {ERR_PACK(ERR_LIB_BUF,0,0)		,"memory buffer routines"},
sl@0: {ERR_PACK(ERR_LIB_OBJ,0,0)		,"object identifier routines"},
sl@0: {ERR_PACK(ERR_LIB_PEM,0,0)		,"PEM routines"},
sl@0: {ERR_PACK(ERR_LIB_DSA,0,0)		,"dsa routines"},
sl@0: {ERR_PACK(ERR_LIB_X509,0,0)		,"x509 certificate routines"},
sl@0: {ERR_PACK(ERR_LIB_ASN1,0,0)		,"asn1 encoding routines"},
sl@0: {ERR_PACK(ERR_LIB_CONF,0,0)		,"configuration file routines"},
sl@0: {ERR_PACK(ERR_LIB_CRYPTO,0,0)		,"common libcrypto routines"},
sl@0: {ERR_PACK(ERR_LIB_EC,0,0)		,"elliptic curve routines"},
sl@0: {ERR_PACK(ERR_LIB_SSL,0,0)		,"SSL routines"},
sl@0: {ERR_PACK(ERR_LIB_BIO,0,0)		,"BIO routines"},
sl@0: {ERR_PACK(ERR_LIB_PKCS7,0,0)		,"PKCS7 routines"},
sl@0: {ERR_PACK(ERR_LIB_X509V3,0,0)		,"X509 V3 routines"},
sl@0: {ERR_PACK(ERR_LIB_PKCS12,0,0)		,"PKCS12 routines"},
sl@0: {ERR_PACK(ERR_LIB_RAND,0,0)		,"random number generator"},
sl@0: {ERR_PACK(ERR_LIB_DSO,0,0)		,"DSO support routines"},
sl@0: {ERR_PACK(ERR_LIB_ENGINE,0,0)		,"engine routines"},
sl@0: {ERR_PACK(ERR_LIB_OCSP,0,0)		,"OCSP routines"},
sl@0: {0,NULL},
sl@0: 	};
sl@0: 
sl@0: static ERR_STRING_DATA ERR_str_functs[]=
sl@0: 	{
sl@0: 	{ERR_PACK(0,SYS_F_FOPEN,0),     	"fopen"},
sl@0: 	{ERR_PACK(0,SYS_F_CONNECT,0),		"connect"},
sl@0: 	{ERR_PACK(0,SYS_F_GETSERVBYNAME,0),	"getservbyname"},
sl@0: 	{ERR_PACK(0,SYS_F_SOCKET,0),		"socket"}, 
sl@0: 	{ERR_PACK(0,SYS_F_IOCTLSOCKET,0),	"ioctlsocket"},
sl@0: 	{ERR_PACK(0,SYS_F_BIND,0),		"bind"},
sl@0: 	{ERR_PACK(0,SYS_F_LISTEN,0),		"listen"},
sl@0: 	{ERR_PACK(0,SYS_F_ACCEPT,0),		"accept"},
sl@0: #ifdef OPENSSL_SYS_WINDOWS
sl@0: 	{ERR_PACK(0,SYS_F_WSASTARTUP,0),	"WSAstartup"},
sl@0: #endif
sl@0: 	{ERR_PACK(0,SYS_F_OPENDIR,0),		"opendir"},
sl@0: 	{ERR_PACK(0,SYS_F_FREAD,0),		"fread"},
sl@0: 	{0,NULL},
sl@0: 	};
sl@0: 
sl@0: static ERR_STRING_DATA ERR_str_reasons[]=
sl@0: 	{
sl@0: {ERR_R_SYS_LIB				,"system lib"},
sl@0: {ERR_R_BN_LIB				,"BN lib"},
sl@0: {ERR_R_RSA_LIB				,"RSA lib"},
sl@0: {ERR_R_DH_LIB				,"DH lib"},
sl@0: {ERR_R_EVP_LIB				,"EVP lib"},
sl@0: {ERR_R_BUF_LIB				,"BUF lib"},
sl@0: {ERR_R_OBJ_LIB				,"OBJ lib"},
sl@0: {ERR_R_PEM_LIB				,"PEM lib"},
sl@0: {ERR_R_DSA_LIB				,"DSA lib"},
sl@0: {ERR_R_X509_LIB				,"X509 lib"},
sl@0: {ERR_R_ASN1_LIB				,"ASN1 lib"},
sl@0: {ERR_R_CONF_LIB				,"CONF lib"},
sl@0: {ERR_R_CRYPTO_LIB			,"CRYPTO lib"},
sl@0: {ERR_R_EC_LIB				,"EC lib"},
sl@0: {ERR_R_SSL_LIB				,"SSL lib"},
sl@0: {ERR_R_BIO_LIB				,"BIO lib"},
sl@0: {ERR_R_PKCS7_LIB			,"PKCS7 lib"},
sl@0: {ERR_R_X509V3_LIB			,"X509V3 lib"},
sl@0: {ERR_R_PKCS12_LIB			,"PKCS12 lib"},
sl@0: {ERR_R_RAND_LIB				,"RAND lib"},
sl@0: {ERR_R_DSO_LIB				,"DSO lib"},
sl@0: {ERR_R_ENGINE_LIB			,"ENGINE lib"},
sl@0: {ERR_R_OCSP_LIB				,"OCSP lib"},
sl@0: 
sl@0: {ERR_R_NESTED_ASN1_ERROR		,"nested asn1 error"},
sl@0: {ERR_R_BAD_ASN1_OBJECT_HEADER		,"bad asn1 object header"},
sl@0: {ERR_R_BAD_GET_ASN1_OBJECT_CALL		,"bad get asn1 object call"},
sl@0: {ERR_R_EXPECTING_AN_ASN1_SEQUENCE	,"expecting an asn1 sequence"},
sl@0: {ERR_R_ASN1_LENGTH_MISMATCH		,"asn1 length mismatch"},
sl@0: {ERR_R_MISSING_ASN1_EOS			,"missing asn1 eos"},
sl@0: 
sl@0: {ERR_R_FATAL                            ,"fatal"},
sl@0: {ERR_R_MALLOC_FAILURE			,"malloc failure"},
sl@0: {ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED	,"called a function you should not call"},
sl@0: {ERR_R_PASSED_NULL_PARAMETER		,"passed a null parameter"},
sl@0: {ERR_R_INTERNAL_ERROR			,"internal error"},
sl@0: {ERR_R_DISABLED				,"called a function that was disabled at compile-time"},
sl@0: 
sl@0: {0,NULL},
sl@0: 	};
sl@0: #else //EMULATOR
sl@0: const ERR_STRING_DATA temp_ERR_str_libraries[]=
sl@0: 	{
sl@0: {ERR_PACK(ERR_LIB_NONE,0,0)		,"unknown library"},
sl@0: {ERR_PACK(ERR_LIB_SYS,0,0)		,"system library"},
sl@0: {ERR_PACK(ERR_LIB_BN,0,0)		,"bignum routines"},
sl@0: {ERR_PACK(ERR_LIB_RSA,0,0)		,"rsa routines"},
sl@0: {ERR_PACK(ERR_LIB_DH,0,0)		,"Diffie-Hellman routines"},
sl@0: {ERR_PACK(ERR_LIB_EVP,0,0)		,"digital envelope routines"},
sl@0: {ERR_PACK(ERR_LIB_BUF,0,0)		,"memory buffer routines"},
sl@0: {ERR_PACK(ERR_LIB_OBJ,0,0)		,"object identifier routines"},
sl@0: {ERR_PACK(ERR_LIB_PEM,0,0)		,"PEM routines"},
sl@0: {ERR_PACK(ERR_LIB_DSA,0,0)		,"dsa routines"},
sl@0: {ERR_PACK(ERR_LIB_X509,0,0)		,"x509 certificate routines"},
sl@0: {ERR_PACK(ERR_LIB_ASN1,0,0)		,"asn1 encoding routines"},
sl@0: {ERR_PACK(ERR_LIB_CONF,0,0)		,"configuration file routines"},
sl@0: {ERR_PACK(ERR_LIB_CRYPTO,0,0)		,"common libcrypto routines"},
sl@0: {ERR_PACK(ERR_LIB_EC,0,0)		,"elliptic curve routines"},
sl@0: {ERR_PACK(ERR_LIB_SSL,0,0)		,"SSL routines"},
sl@0: {ERR_PACK(ERR_LIB_BIO,0,0)		,"BIO routines"},
sl@0: {ERR_PACK(ERR_LIB_PKCS7,0,0)		,"PKCS7 routines"},
sl@0: {ERR_PACK(ERR_LIB_X509V3,0,0)		,"X509 V3 routines"},
sl@0: {ERR_PACK(ERR_LIB_PKCS12,0,0)		,"PKCS12 routines"},
sl@0: {ERR_PACK(ERR_LIB_RAND,0,0)		,"random number generator"},
sl@0: {ERR_PACK(ERR_LIB_DSO,0,0)		,"DSO support routines"},
sl@0: {ERR_PACK(ERR_LIB_ENGINE,0,0)		,"engine routines"},
sl@0: {ERR_PACK(ERR_LIB_OCSP,0,0)		,"OCSP routines"},
sl@0: {0,NULL},
sl@0: 	};
sl@0: 
sl@0: const ERR_STRING_DATA temp_ERR_str_functs[]=
sl@0: 	{
sl@0: 	{ERR_PACK(0,SYS_F_FOPEN,0),     	"fopen"},
sl@0: 	{ERR_PACK(0,SYS_F_CONNECT,0),		"connect"},
sl@0: 	{ERR_PACK(0,SYS_F_GETSERVBYNAME,0),	"getservbyname"},
sl@0: 	{ERR_PACK(0,SYS_F_SOCKET,0),		"socket"}, 
sl@0: 	{ERR_PACK(0,SYS_F_IOCTLSOCKET,0),	"ioctlsocket"},
sl@0: 	{ERR_PACK(0,SYS_F_BIND,0),		"bind"},
sl@0: 	{ERR_PACK(0,SYS_F_LISTEN,0),		"listen"},
sl@0: 	{ERR_PACK(0,SYS_F_ACCEPT,0),		"accept"},
sl@0: #ifdef OPENSSL_SYS_WINDOWS
sl@0: 	{ERR_PACK(0,SYS_F_WSASTARTUP,0),	"WSAstartup"},
sl@0: #endif
sl@0: 	{ERR_PACK(0,SYS_F_OPENDIR,0),		"opendir"},
sl@0: 	{ERR_PACK(0,SYS_F_FREAD,0),		"fread"},
sl@0: 	{0,NULL},
sl@0: 	};
sl@0: 
sl@0: const ERR_STRING_DATA temp_ERR_str_reasons[]=
sl@0: 	{
sl@0: {ERR_R_SYS_LIB				,"system lib"},
sl@0: {ERR_R_BN_LIB				,"BN lib"},
sl@0: {ERR_R_RSA_LIB				,"RSA lib"},
sl@0: {ERR_R_DH_LIB				,"DH lib"},
sl@0: {ERR_R_EVP_LIB				,"EVP lib"},
sl@0: {ERR_R_BUF_LIB				,"BUF lib"},
sl@0: {ERR_R_OBJ_LIB				,"OBJ lib"},
sl@0: {ERR_R_PEM_LIB				,"PEM lib"},
sl@0: {ERR_R_DSA_LIB				,"DSA lib"},
sl@0: {ERR_R_X509_LIB				,"X509 lib"},
sl@0: {ERR_R_ASN1_LIB				,"ASN1 lib"},
sl@0: {ERR_R_CONF_LIB				,"CONF lib"},
sl@0: {ERR_R_CRYPTO_LIB			,"CRYPTO lib"},
sl@0: {ERR_R_EC_LIB				,"EC lib"},
sl@0: {ERR_R_SSL_LIB				,"SSL lib"},
sl@0: {ERR_R_BIO_LIB				,"BIO lib"},
sl@0: {ERR_R_PKCS7_LIB			,"PKCS7 lib"},
sl@0: {ERR_R_X509V3_LIB			,"X509V3 lib"},
sl@0: {ERR_R_PKCS12_LIB			,"PKCS12 lib"},
sl@0: {ERR_R_RAND_LIB				,"RAND lib"},
sl@0: {ERR_R_DSO_LIB				,"DSO lib"},
sl@0: {ERR_R_ENGINE_LIB			,"ENGINE lib"},
sl@0: {ERR_R_OCSP_LIB				,"OCSP lib"},
sl@0: 
sl@0: {ERR_R_NESTED_ASN1_ERROR		,"nested asn1 error"},
sl@0: {ERR_R_BAD_ASN1_OBJECT_HEADER		,"bad asn1 object header"},
sl@0: {ERR_R_BAD_GET_ASN1_OBJECT_CALL		,"bad get asn1 object call"},
sl@0: {ERR_R_EXPECTING_AN_ASN1_SEQUENCE	,"expecting an asn1 sequence"},
sl@0: {ERR_R_ASN1_LENGTH_MISMATCH		,"asn1 length mismatch"},
sl@0: {ERR_R_MISSING_ASN1_EOS			,"missing asn1 eos"},
sl@0: 
sl@0: {ERR_R_FATAL                            ,"fatal"},
sl@0: {ERR_R_MALLOC_FAILURE			,"malloc failure"},
sl@0: {ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED	,"called a function you should not call"},
sl@0: {ERR_R_PASSED_NULL_PARAMETER		,"passed a null parameter"},
sl@0: {ERR_R_INTERNAL_ERROR			,"internal error"},
sl@0: {ERR_R_DISABLED				,"called a function that was disabled at compile-time"},
sl@0: 
sl@0: {0,NULL},
sl@0: 	};
sl@0:  GET_STATIC_ARRAY_FROM_TLS(ERR_str_functs,err_err,ERR_STRING_DATA)
sl@0:  GET_STATIC_ARRAY_FROM_TLS(ERR_str_reasons,err_err,ERR_STRING_DATA)
sl@0:  GET_STATIC_ARRAY_FROM_TLS(ERR_str_libraries,err_err,ERR_STRING_DATA)
sl@0:  #define ERR_str_functs (GET_WSD_VAR_NAME(ERR_str_functs,err_err, s)())
sl@0:  #define ERR_str_reasons (GET_WSD_VAR_NAME(ERR_str_reasons,err_err, s)())
sl@0:  #define ERR_str_libraries (GET_WSD_VAR_NAME(ERR_str_libraries,err_err, s)())
sl@0: #endif //EMULATOR
sl@0: #endif
sl@0: 
sl@0: #ifndef EMULATOR
sl@0: /* Define the predeclared (but externally opaque) "ERR_FNS" type */
sl@0: struct st_ERR_FNS
sl@0: 	{
sl@0: 	/* Works on the "error_hash" string table */
sl@0: 	LHASH *(*cb_err_get)(int create);
sl@0: 	void (*cb_err_del)(void);
sl@0: 	ERR_STRING_DATA *(*cb_err_get_item)(const ERR_STRING_DATA *);
sl@0: 	ERR_STRING_DATA *(*cb_err_set_item)(ERR_STRING_DATA *);
sl@0: 	ERR_STRING_DATA *(*cb_err_del_item)(ERR_STRING_DATA *);
sl@0: 	/* Works on the "thread_hash" error-state table */
sl@0: 	LHASH *(*cb_thread_get)(int create);
sl@0: 	void (*cb_thread_release)(LHASH **hash);
sl@0: 	ERR_STATE *(*cb_thread_get_item)(const ERR_STATE *);
sl@0: 	ERR_STATE *(*cb_thread_set_item)(ERR_STATE *);
sl@0: 	void (*cb_thread_del_item)(const ERR_STATE *);
sl@0: 	/* Returns the next available error "library" numbers */
sl@0: 	int (*cb_get_next_lib)(void);
sl@0: 	};
sl@0: #endif
sl@0: /* Predeclarations of the "err_defaults" functions */
sl@0: static LHASH *int_err_get(int create);
sl@0: static void int_err_del(void);
sl@0: static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *);
sl@0: static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *);
sl@0: static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *);
sl@0: static LHASH *int_thread_get(int create);
sl@0: static void int_thread_release(LHASH **hash);
sl@0: static ERR_STATE *int_thread_get_item(const ERR_STATE *);
sl@0: static ERR_STATE *int_thread_set_item(ERR_STATE *);
sl@0: static void int_thread_del_item(const ERR_STATE *);
sl@0: static int int_err_get_next_lib(void);
sl@0: /* The static ERR_FNS table using these defaults functions */
sl@0: static const ERR_FNS err_defaults =
sl@0: 	{
sl@0: 	int_err_get,
sl@0: 	int_err_del,
sl@0: 	int_err_get_item,
sl@0: 	int_err_set_item,
sl@0: 	int_err_del_item,
sl@0: 	int_thread_get,
sl@0: 	int_thread_release,
sl@0: 	int_thread_get_item,
sl@0: 	int_thread_set_item,
sl@0: 	int_thread_del_item,
sl@0: 	int_err_get_next_lib
sl@0: 	};
sl@0: 
sl@0: #ifndef EMULATOR
sl@0: /* The replacable table of ERR_FNS functions we use at run-time */
sl@0: static const ERR_FNS *err_fns = NULL;
sl@0: #else
sl@0: GET_STATIC_VAR_FROM_TLS(err_fns,err,const ERR_FNS *)
sl@0: #define err_fns (*GET_WSD_VAR_NAME(err_fns,err, s)())
sl@0: #endif
sl@0: 
sl@0: /* Eg. rather than using "err_get()", use "ERRFN(err_get)()". */
sl@0: #define ERRFN(a) err_fns->cb_##a
sl@0: 
sl@0: #ifndef EMULATOR
sl@0: /* The internal state used by "err_defaults" - as such, the setting, reading,
sl@0:  * creating, and deleting of this data should only be permitted via the
sl@0:  * "err_defaults" functions. This way, a linked module can completely defer all
sl@0:  * ERR state operation (together with requisite locking) to the implementations
sl@0:  * and state in the loading application. */
sl@0: static LHASH *int_error_hash = NULL;
sl@0: static LHASH *int_thread_hash = NULL;
sl@0: static int int_thread_hash_references = 0;
sl@0: static int int_err_library_number= ERR_LIB_USER;
sl@0: #else
sl@0: GET_STATIC_VAR_FROM_TLS(int_error_hash,err,LHASH *)
sl@0: #define int_error_hash (*GET_WSD_VAR_NAME(int_error_hash,err,s)())
sl@0: 
sl@0: GET_STATIC_VAR_FROM_TLS(int_thread_hash,err,LHASH *)
sl@0: #define int_thread_hash (*GET_WSD_VAR_NAME(int_thread_hash,err,s)())
sl@0: 
sl@0: GET_STATIC_VAR_FROM_TLS(int_thread_hash_references,err,int)
sl@0: #define int_thread_hash_references (*GET_WSD_VAR_NAME(int_thread_hash_references,err,s)())
sl@0: 
sl@0: GET_STATIC_VAR_FROM_TLS(int_err_library_number,err,int)
sl@0: #define int_err_library_number (*GET_WSD_VAR_NAME(int_err_library_number,err,s)())
sl@0: 
sl@0: #endif
sl@0: 
sl@0: /* Internal function that checks whether "err_fns" is set and if not, sets it to
sl@0:  * the defaults. */
sl@0: static void err_fns_check(void)
sl@0: 	{
sl@0: 	if (err_fns) return;
sl@0: 	
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	if (!err_fns)
sl@0: 		err_fns = &err_defaults;
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 	}
sl@0: 
sl@0: /* API functions to get or set the underlying ERR functions. */
sl@0: 
sl@0: EXPORT_C const ERR_FNS *ERR_get_implementation(void)
sl@0: 	{
sl@0: 	err_fns_check();
sl@0: 	return err_fns;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C int ERR_set_implementation(const ERR_FNS *fns)
sl@0: 	{
sl@0: 	int ret = 0;
sl@0: 
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	/* It's too late if 'err_fns' is non-NULL. BTW: not much point setting
sl@0: 	 * an error is there?! */
sl@0: 	if (!err_fns)
sl@0: 		{
sl@0: 		err_fns = fns;
sl@0: 		ret = 1;
sl@0: 		}
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: /* These are the callbacks provided to "lh_new()" when creating the LHASH tables
sl@0:  * internal to the "err_defaults" implementation. */
sl@0: 
sl@0: /* static unsigned long err_hash(ERR_STRING_DATA *a); */
sl@0: static unsigned long err_hash(const void *a_void);
sl@0: /* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b); */
sl@0: static int err_cmp(const void *a_void, const void *b_void);
sl@0: /* static unsigned long pid_hash(ERR_STATE *pid); */
sl@0: static unsigned long pid_hash(const void *pid_void);
sl@0: /* static int pid_cmp(ERR_STATE *a,ERR_STATE *pid); */
sl@0: static int pid_cmp(const void *a_void,const void *pid_void);
sl@0: static unsigned long get_error_values(int inc,int top,const char **file,int *line,
sl@0: 				      const char **data,int *flags);
sl@0: 
sl@0: /* The internal functions used in the "err_defaults" implementation */
sl@0: 
sl@0: static LHASH *int_err_get(int create)
sl@0: 	{
sl@0: 	LHASH *ret = NULL;
sl@0: 
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	if (!int_error_hash && create)
sl@0: 		{
sl@0: 		CRYPTO_push_info("int_err_get (err.c)");
sl@0: 		int_error_hash = lh_new(err_hash, err_cmp);
sl@0: 		CRYPTO_pop_info();
sl@0: 		}
sl@0: 	if (int_error_hash)
sl@0: 		ret = int_error_hash;
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: static void int_err_del(void)
sl@0: 	{
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	if (int_error_hash)
sl@0: 		{
sl@0: 		lh_free(int_error_hash);
sl@0: 		int_error_hash = NULL;
sl@0: 		}
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 	}
sl@0: 
sl@0: static ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d)
sl@0: 	{
sl@0: 	ERR_STRING_DATA *p;
sl@0: 	LHASH *hash;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	hash = ERRFN(err_get)(0);
sl@0: 	if (!hash)
sl@0: 		return NULL;
sl@0: 
sl@0: 	CRYPTO_r_lock(CRYPTO_LOCK_ERR);
sl@0: 	p = (ERR_STRING_DATA *)lh_retrieve(hash, d);
sl@0: 	CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
sl@0: 
sl@0: 	return p;
sl@0: 	}
sl@0: 
sl@0: static ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *d)
sl@0: 	{
sl@0: 	ERR_STRING_DATA *p;
sl@0: 	LHASH *hash;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	hash = ERRFN(err_get)(1);
sl@0: 	if (!hash)
sl@0: 		return NULL;
sl@0: 
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	p = (ERR_STRING_DATA *)lh_insert(hash, d);
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 
sl@0: 	return p;
sl@0: 	}
sl@0: 
sl@0: static ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d)
sl@0: 	{
sl@0: 	ERR_STRING_DATA *p;
sl@0: 	LHASH *hash;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	hash = ERRFN(err_get)(0);
sl@0: 	if (!hash)
sl@0: 		return NULL;
sl@0: 
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	p = (ERR_STRING_DATA *)lh_delete(hash, d);
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 
sl@0: 	return p;
sl@0: 	}
sl@0: 
sl@0: static LHASH *int_thread_get(int create)
sl@0: 	{
sl@0: 	LHASH *ret = NULL;
sl@0: 
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	if (!int_thread_hash && create)
sl@0: 		{
sl@0: 		CRYPTO_push_info("int_thread_get (err.c)");
sl@0: 		int_thread_hash = lh_new(pid_hash, pid_cmp);
sl@0: 		CRYPTO_pop_info();
sl@0: 		}
sl@0: 	if (int_thread_hash)
sl@0: 		{
sl@0: 		int_thread_hash_references++;
sl@0: 		ret = int_thread_hash;
sl@0: 		}
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: static void int_thread_release(LHASH **hash)
sl@0: 	{
sl@0: 	int i;
sl@0: 
sl@0: 	if (hash == NULL || *hash == NULL)
sl@0: 		return;
sl@0: 
sl@0: 	i = CRYPTO_add(&int_thread_hash_references, -1, CRYPTO_LOCK_ERR);
sl@0: 
sl@0: #ifdef REF_PRINT
sl@0: 	fprintf(stderr,"%4d:%s\n",int_thread_hash_references,"ERR");
sl@0: #endif
sl@0: 	if (i > 0) return;
sl@0: #ifdef REF_CHECK
sl@0: 	if (i < 0)
sl@0: 		{
sl@0: 		fprintf(stderr,"int_thread_release, bad reference count\n");
sl@0: 		abort(); /* ok */
sl@0: 		}
sl@0: #endif
sl@0: 	*hash = NULL;
sl@0: 	}
sl@0: 
sl@0: static ERR_STATE *int_thread_get_item(const ERR_STATE *d)
sl@0: 	{
sl@0: 	ERR_STATE *p;
sl@0: 	LHASH *hash;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	hash = ERRFN(thread_get)(0);
sl@0: 	if (!hash)
sl@0: 		return NULL;
sl@0: 
sl@0: 	CRYPTO_r_lock(CRYPTO_LOCK_ERR);
sl@0: 	p = (ERR_STATE *)lh_retrieve(hash, d);
sl@0: 	CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
sl@0: 
sl@0: 	ERRFN(thread_release)(&hash);
sl@0: 	return p;
sl@0: 	}
sl@0: 
sl@0: static ERR_STATE *int_thread_set_item(ERR_STATE *d)
sl@0: 	{
sl@0: 	ERR_STATE *p;
sl@0: 	LHASH *hash;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	hash = ERRFN(thread_get)(1);
sl@0: 	if (!hash)
sl@0: 		return NULL;
sl@0: 
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	p = (ERR_STATE *)lh_insert(hash, d);
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 
sl@0: 	ERRFN(thread_release)(&hash);
sl@0: 	return p;
sl@0: 	}
sl@0: 
sl@0: static void int_thread_del_item(const ERR_STATE *d)
sl@0: 	{
sl@0: 	ERR_STATE *p;
sl@0: 	LHASH *hash;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	hash = ERRFN(thread_get)(0);
sl@0: 	if (!hash)
sl@0: 		return;
sl@0: 
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	p = (ERR_STATE *)lh_delete(hash, d);
sl@0: 	/* make sure we don't leak memory */
sl@0: 	if (int_thread_hash_references == 1
sl@0: 		&& int_thread_hash && (lh_num_items(int_thread_hash) == 0))
sl@0: 		{
sl@0: 		lh_free(int_thread_hash);
sl@0: 		int_thread_hash = NULL;
sl@0: 		}
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 
sl@0: 	ERRFN(thread_release)(&hash);
sl@0: 	if (p)
sl@0: 		ERR_STATE_free(p);
sl@0: 	}
sl@0: 
sl@0: static int int_err_get_next_lib(void)
sl@0: 	{
sl@0: 	int ret;
sl@0: 
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	ret = int_err_library_number++;
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: #ifndef OPENSSL_NO_ERR
sl@0: #define NUM_SYS_STR_REASONS 127
sl@0: #define LEN_SYS_STR_REASON 32
sl@0: 
sl@0: #ifndef EMULATOR
sl@0: static ERR_STRING_DATA SYS_str_reasons[NUM_SYS_STR_REASONS + 1];
sl@0: #endif
sl@0: /* SYS_str_reasons is filled with copies of strerror() results at
sl@0:  * initialization.
sl@0:  * 'errno' values up to 127 should cover all usual errors,
sl@0:  * others will be displayed numerically by ERR_error_string.
sl@0:  * It is crucial that we have something for each reason code
sl@0:  * that occurs in ERR_str_reasons, or bogus reason strings
sl@0:  * will be returned for SYSerr(), which always gets an errno
sl@0:  * value and never one of those 'standard' reason codes. */
sl@0: #ifdef EMULATOR
sl@0:   GET_STATIC_VAR_FROM_TLS(init,err,int)
sl@0:   #define init (*GET_WSD_VAR_NAME(init,err, s)())
sl@0:   GET_STATIC_ARRAY_FROM_TLS(SYS_str_reasons,err,ERR_STRING_DATA)
sl@0:   #define SYS_str_reasons (GET_WSD_VAR_NAME(SYS_str_reasons,err, s)())
sl@0:   
sl@0:   
sl@0:   //GET_STATIC_ARRAY_FROM_TLS(&strerror_tab,err,char)
sl@0:   #define strerror_tab libcrypto_ImpurePtr()->strerror_tab
sl@0: #endif 
sl@0: 
sl@0: static void build_SYS_str_reasons(void)
sl@0: 	{
sl@0: 	/* OPENSSL_malloc cannot be used here, use static storage instead */
sl@0: #ifndef EMULATOR		
sl@0: 	static char strerror_tab[NUM_SYS_STR_REASONS][LEN_SYS_STR_REASON];
sl@0: #endif	
sl@0: 	int i;
sl@0: #ifndef EMULATOR	
sl@0: 	static int init = 1;
sl@0: #endif	
sl@0: 
sl@0: 	CRYPTO_r_lock(CRYPTO_LOCK_ERR);
sl@0: 	if (!init)
sl@0: 		{
sl@0: 		CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
sl@0: 		return;
sl@0: 		}
sl@0: 	
sl@0: 	CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
sl@0: 	CRYPTO_w_lock(CRYPTO_LOCK_ERR);
sl@0: 	if (!init)
sl@0: 		{
sl@0: 		CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 		return;
sl@0: 		}
sl@0: 
sl@0: 	for (i = 1; i <= NUM_SYS_STR_REASONS; i++)
sl@0: 		{
sl@0: 		ERR_STRING_DATA *str = &SYS_str_reasons[i - 1];
sl@0: 
sl@0: 		str->error = (unsigned long)i;
sl@0: 		if (str->string == NULL)
sl@0: 			{
sl@0: 			char (*dest)[LEN_SYS_STR_REASON] = &(strerror_tab[i - 1]);
sl@0: 			char *src = strerror(i);
sl@0: 			if (src != NULL)
sl@0: 				{
sl@0: 				strncpy(*dest, src, sizeof *dest);
sl@0: 				(*dest)[sizeof *dest - 1] = '\0';
sl@0: 				str->string = *dest;
sl@0: 				}
sl@0: 			}
sl@0: 		if (str->string == NULL)
sl@0: 			str->string = "unknown";
sl@0: 		}
sl@0: 
sl@0: 	/* Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL},
sl@0: 	 * as required by ERR_load_strings. */
sl@0: 
sl@0: 	init = 0;
sl@0: 	
sl@0: 	CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
sl@0: 	}
sl@0: #endif
sl@0: 
sl@0: #define err_clear_data(p,i) \
sl@0: 	do { \
sl@0: 	if (((p)->err_data[i] != NULL) && \
sl@0: 		(p)->err_data_flags[i] & ERR_TXT_MALLOCED) \
sl@0: 		{  \
sl@0: 		OPENSSL_free((p)->err_data[i]); \
sl@0: 		(p)->err_data[i]=NULL; \
sl@0: 		} \
sl@0: 	(p)->err_data_flags[i]=0; \
sl@0: 	} while(0)
sl@0: 
sl@0: #define err_clear(p,i) \
sl@0: 	do { \
sl@0: 	(p)->err_flags[i]=0; \
sl@0: 	(p)->err_buffer[i]=0; \
sl@0: 	err_clear_data(p,i); \
sl@0: 	(p)->err_file[i]=NULL; \
sl@0: 	(p)->err_line[i]= -1; \
sl@0: 	} while(0)
sl@0: 
sl@0: static void ERR_STATE_free(ERR_STATE *s)
sl@0: 	{
sl@0: 	int i;
sl@0: 
sl@0: 	if (s == NULL)
sl@0: 	    return;
sl@0: 
sl@0: 	for (i=0; i<ERR_NUM_ERRORS; i++)
sl@0: 		{
sl@0: 		err_clear_data(s,i);
sl@0: 		}
sl@0: 	OPENSSL_free(s);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_load_ERR_strings(void)
sl@0: 	{
sl@0: 	err_fns_check();
sl@0: #ifndef OPENSSL_NO_ERR
sl@0: 	err_load_strings(0,ERR_str_libraries);
sl@0: 	err_load_strings(0,ERR_str_reasons);
sl@0: 	err_load_strings(ERR_LIB_SYS,ERR_str_functs);
sl@0: 	build_SYS_str_reasons();
sl@0: 	err_load_strings(ERR_LIB_SYS,SYS_str_reasons);
sl@0: #endif
sl@0: 	}
sl@0: 
sl@0: static void err_load_strings(int lib, ERR_STRING_DATA *str)
sl@0: 	{
sl@0: 	while (str->error)
sl@0: 		{
sl@0: 		if (lib)
sl@0: 			str->error|=ERR_PACK(lib,0,0);
sl@0: 		ERRFN(err_set_item)(str);
sl@0: 		str++;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_load_strings(int lib, ERR_STRING_DATA *str)
sl@0: 	{
sl@0: 	ERR_load_ERR_strings();
sl@0: 	err_load_strings(lib, str);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_unload_strings(int lib, ERR_STRING_DATA *str)
sl@0: 	{
sl@0: 	while (str->error)
sl@0: 		{
sl@0: 		if (lib)
sl@0: 			str->error|=ERR_PACK(lib,0,0);
sl@0: 		ERRFN(err_del_item)(str);
sl@0: 		str++;
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_free_strings(void)
sl@0: 	{
sl@0: 	err_fns_check();
sl@0: 	ERRFN(err_del)();
sl@0: 	}
sl@0: 
sl@0: /********************************************************/
sl@0: 
sl@0: EXPORT_C void ERR_put_error(int lib, int func, int reason, const char *file,
sl@0: 	     int line)
sl@0: 	{
sl@0: 	ERR_STATE *es;
sl@0: 
sl@0: #ifdef _OSD_POSIX
sl@0: 	/* In the BS2000-OSD POSIX subsystem, the compiler generates
sl@0: 	 * path names in the form "*POSIX(/etc/passwd)".
sl@0: 	 * This dirty hack strips them to something sensible.
sl@0: 	 * @@@ We shouldn't modify a const string, though.
sl@0: 	 */
sl@0: 	if (strncmp(file,"*POSIX(", sizeof("*POSIX(")-1) == 0) {
sl@0: 		char *end;
sl@0: 
sl@0: 		/* Skip the "*POSIX(" prefix */
sl@0: 		file += sizeof("*POSIX(")-1;
sl@0: 		end = &file[strlen(file)-1];
sl@0: 		if (*end == ')')
sl@0: 			*end = '\0';
sl@0: 		/* Optional: use the basename of the path only. */
sl@0: 		if ((end = strrchr(file, '/')) != NULL)
sl@0: 			file = &end[1];
sl@0: 	}
sl@0: #endif
sl@0: 	es=ERR_get_state();
sl@0: 
sl@0: 	es->top=(es->top+1)%ERR_NUM_ERRORS;
sl@0: 	if (es->top == es->bottom)
sl@0: 		es->bottom=(es->bottom+1)%ERR_NUM_ERRORS;
sl@0: 	es->err_flags[es->top]=0;
sl@0: 	es->err_buffer[es->top]=ERR_PACK(lib,func,reason);
sl@0: 	es->err_file[es->top]=file;
sl@0: 	es->err_line[es->top]=line;
sl@0: 	err_clear_data(es,es->top);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_clear_error(void)
sl@0: 	{
sl@0: 	int i;
sl@0: 	ERR_STATE *es;
sl@0: 
sl@0: 	es=ERR_get_state();
sl@0: 
sl@0: 	for (i=0; i<ERR_NUM_ERRORS; i++)
sl@0: 		{
sl@0: 		err_clear(es,i);
sl@0: 		}
sl@0: 	es->top=es->bottom=0;
sl@0: 	}
sl@0: 
sl@0: 
sl@0: EXPORT_C unsigned long ERR_get_error(void)
sl@0: 	{ return(get_error_values(1,0,NULL,NULL,NULL,NULL)); }
sl@0: 
sl@0: EXPORT_C unsigned long ERR_get_error_line(const char **file,
sl@0: 	     int *line)
sl@0: 	{ return(get_error_values(1,0,file,line,NULL,NULL)); }
sl@0: 
sl@0: EXPORT_C unsigned long ERR_get_error_line_data(const char **file, int *line,
sl@0: 	     const char **data, int *flags)
sl@0: 	{ return(get_error_values(1,0,file,line,data,flags)); }
sl@0: 
sl@0: 
sl@0: EXPORT_C unsigned long ERR_peek_error(void)
sl@0: 	{ return(get_error_values(0,0,NULL,NULL,NULL,NULL)); }
sl@0: 
sl@0: EXPORT_C unsigned long ERR_peek_error_line(const char **file, int *line)
sl@0: 	{ return(get_error_values(0,0,file,line,NULL,NULL)); }
sl@0: 
sl@0: EXPORT_C unsigned long ERR_peek_error_line_data(const char **file, int *line,
sl@0: 	     const char **data, int *flags)
sl@0: 	{ return(get_error_values(0,0,file,line,data,flags)); }
sl@0: 
sl@0: 
sl@0: EXPORT_C unsigned long ERR_peek_last_error(void)
sl@0: 	{ return(get_error_values(0,1,NULL,NULL,NULL,NULL)); }
sl@0: 
sl@0: EXPORT_C unsigned long ERR_peek_last_error_line(const char **file, int *line)
sl@0: 	{ return(get_error_values(0,1,file,line,NULL,NULL)); }
sl@0: 
sl@0: EXPORT_C unsigned long ERR_peek_last_error_line_data(const char **file, int *line,
sl@0: 	     const char **data, int *flags)
sl@0: 	{ return(get_error_values(0,1,file,line,data,flags)); }
sl@0: 
sl@0: 
sl@0: static unsigned long get_error_values(int inc, int top, const char **file, int *line,
sl@0: 	     const char **data, int *flags)
sl@0: 	{	
sl@0: 	int i=0;
sl@0: 	ERR_STATE *es;
sl@0: 	unsigned long ret;
sl@0: 
sl@0: 	es=ERR_get_state();
sl@0: 
sl@0: 	if (inc && top)
sl@0: 		{
sl@0: 		if (file) *file = "";
sl@0: 		if (line) *line = 0;
sl@0: 		if (data) *data = "";
sl@0: 		if (flags) *flags = 0;
sl@0: 			
sl@0: 		return ERR_R_INTERNAL_ERROR;
sl@0: 		}
sl@0: 
sl@0: 	if (es->bottom == es->top) return 0;
sl@0: 	if (top)
sl@0: 		i=es->top;			 /* last error */
sl@0: 	else
sl@0: 		i=(es->bottom+1)%ERR_NUM_ERRORS; /* first error */
sl@0: 
sl@0: 	ret=es->err_buffer[i];
sl@0: 	if (inc)
sl@0: 		{
sl@0: 		es->bottom=i;
sl@0: 		es->err_buffer[i]=0;
sl@0: 		}
sl@0: 
sl@0: 	if ((file != NULL) && (line != NULL))
sl@0: 		{
sl@0: 		if (es->err_file[i] == NULL)
sl@0: 			{
sl@0: 			*file="NA";
sl@0: 			if (line != NULL) *line=0;
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			*file=es->err_file[i];
sl@0: 			if (line != NULL) *line=es->err_line[i];
sl@0: 			}
sl@0: 		}
sl@0: 
sl@0: 	if (data == NULL)
sl@0: 		{
sl@0: 		if (inc)
sl@0: 			{
sl@0: 			err_clear_data(es, i);
sl@0: 			}
sl@0: 		}
sl@0: 	else
sl@0: 		{
sl@0: 		if (es->err_data[i] == NULL)
sl@0: 			{
sl@0: 			*data="";
sl@0: 			if (flags != NULL) *flags=0;
sl@0: 			}
sl@0: 		else
sl@0: 			{
sl@0: 			*data=es->err_data[i];
sl@0: 			if (flags != NULL) *flags=es->err_data_flags[i];
sl@0: 			}
sl@0: 		}
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_error_string_n(unsigned long e, char *buf, size_t len)
sl@0: 	{
sl@0: 	char lsbuf[64], fsbuf[64], rsbuf[64];
sl@0: 	const char *ls,*fs,*rs;
sl@0: 	unsigned long l,f,r;
sl@0: 
sl@0: 	l=ERR_GET_LIB(e);
sl@0: 	f=ERR_GET_FUNC(e);
sl@0: 	r=ERR_GET_REASON(e);
sl@0: 
sl@0: 	ls=ERR_lib_error_string(e);
sl@0: 	fs=ERR_func_error_string(e);
sl@0: 	rs=ERR_reason_error_string(e);
sl@0: 
sl@0: 	if (ls == NULL) 
sl@0: 		BIO_snprintf(lsbuf, sizeof(lsbuf), "lib(%lu)", l);
sl@0: 	if (fs == NULL)
sl@0: 		BIO_snprintf(fsbuf, sizeof(fsbuf), "func(%lu)", f);
sl@0: 	if (rs == NULL)
sl@0: 		BIO_snprintf(rsbuf, sizeof(rsbuf), "reason(%lu)", r);
sl@0: 
sl@0: 	BIO_snprintf(buf, len,"error:%08lX:%s:%s:%s", e, ls?ls:lsbuf, 
sl@0: 		fs?fs:fsbuf, rs?rs:rsbuf);
sl@0: 	if (strlen(buf) == len-1)
sl@0: 		{
sl@0: 		/* output may be truncated; make sure we always have 5 
sl@0: 		 * colon-separated fields, i.e. 4 colons ... */
sl@0: #define NUM_COLONS 4
sl@0: 		if (len > NUM_COLONS) /* ... if possible */
sl@0: 			{
sl@0: 			int i;
sl@0: 			char *s = buf;
sl@0: 			
sl@0: 			for (i = 0; i < NUM_COLONS; i++)
sl@0: 				{
sl@0: 				char *colon = strchr(s, ':');
sl@0: 				if (colon == NULL || colon > &buf[len-1] - NUM_COLONS + i)
sl@0: 					{
sl@0: 					/* set colon no. i at last possible position
sl@0: 					 * (buf[len-1] is the terminating 0)*/
sl@0: 					colon = &buf[len-1] - NUM_COLONS + i;
sl@0: 					*colon = ':';
sl@0: 					}
sl@0: 				s = colon + 1;
sl@0: 				}
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: #ifdef EMULATOR	
sl@0: GET_STATIC_ARRAY_FROM_TLS(buf,err,char)
sl@0: #define buf (GET_WSD_VAR_NAME(buf,err, s)())
sl@0: #endif	
sl@0: 
sl@0: /* BAD for multi-threading: uses a local buffer if ret == NULL */
sl@0: /* ERR_error_string_n should be used instead for ret != NULL
sl@0:  * as ERR_error_string cannot know how large the buffer is */
sl@0: EXPORT_C char *ERR_error_string(unsigned long e, char *ret)
sl@0: 	{
sl@0: #ifndef EMULATOR	
sl@0: 	static char buf[256];
sl@0: #endif	
sl@0: 
sl@0: 	if (ret == NULL) ret=buf;
sl@0: 	ERR_error_string_n(e, ret, 256);
sl@0: 
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C LHASH *ERR_get_string_table(void)
sl@0: 	{
sl@0: 	err_fns_check();
sl@0: 	return ERRFN(err_get)(0);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C LHASH *ERR_get_err_state_table(void)
sl@0: 	{
sl@0: 	err_fns_check();
sl@0: 	return ERRFN(thread_get)(0);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_release_err_state_table(LHASH **hash)
sl@0: 	{
sl@0: 	err_fns_check();
sl@0: 	ERRFN(thread_release)(hash);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C const char *ERR_lib_error_string(unsigned long e)
sl@0: 	{
sl@0: 	ERR_STRING_DATA d,*p;
sl@0: 	unsigned long l;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	l=ERR_GET_LIB(e);
sl@0: 	d.error=ERR_PACK(l,0,0);
sl@0: 	p=ERRFN(err_get_item)(&d);
sl@0: 	return((p == NULL)?NULL:p->string);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C const char *ERR_func_error_string(unsigned long e)
sl@0: 	{
sl@0: 	ERR_STRING_DATA d,*p;
sl@0: 	unsigned long l,f;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	l=ERR_GET_LIB(e);
sl@0: 	f=ERR_GET_FUNC(e);
sl@0: 	d.error=ERR_PACK(l,f,0);
sl@0: 	p=ERRFN(err_get_item)(&d);
sl@0: 	return((p == NULL)?NULL:p->string);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C const char *ERR_reason_error_string(unsigned long e)
sl@0: 	{
sl@0: 	ERR_STRING_DATA d,*p=NULL;
sl@0: 	unsigned long l,r;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	l=ERR_GET_LIB(e);
sl@0: 	r=ERR_GET_REASON(e);
sl@0: 	d.error=ERR_PACK(l,0,r);
sl@0: 	p=ERRFN(err_get_item)(&d);
sl@0: 	if (!p)
sl@0: 		{
sl@0: 		d.error=ERR_PACK(0,0,r);
sl@0: 		p=ERRFN(err_get_item)(&d);
sl@0: 		}
sl@0: 	return((p == NULL)?NULL:p->string);
sl@0: 	}
sl@0: 
sl@0: /* static unsigned long err_hash(ERR_STRING_DATA *a) */
sl@0: static unsigned long err_hash(const void *a_void)
sl@0: 	{
sl@0: 	unsigned long ret,l;
sl@0: 
sl@0: 	l=((const ERR_STRING_DATA *)a_void)->error;
sl@0: 	ret=l^ERR_GET_LIB(l)^ERR_GET_FUNC(l);
sl@0: 	return(ret^ret%19*13);
sl@0: 	}
sl@0: 
sl@0: /* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b) */
sl@0: static int err_cmp(const void *a_void, const void *b_void)
sl@0: 	{
sl@0: 	return((int)(((const ERR_STRING_DATA *)a_void)->error -
sl@0: 			((const ERR_STRING_DATA *)b_void)->error));
sl@0: 	}
sl@0: 
sl@0: /* static unsigned long pid_hash(ERR_STATE *a) */
sl@0: static unsigned long pid_hash(const void *a_void)
sl@0: 	{
sl@0: 	return(((const ERR_STATE *)a_void)->pid*13);
sl@0: 	}
sl@0: 
sl@0: /* static int pid_cmp(ERR_STATE *a, ERR_STATE *b) */
sl@0: static int pid_cmp(const void *a_void, const void *b_void)
sl@0: 	{
sl@0: 	return((int)((long)((const ERR_STATE *)a_void)->pid -
sl@0: 			(long)((const ERR_STATE *)b_void)->pid));
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_remove_state(unsigned long pid)
sl@0: 	{
sl@0: 	ERR_STATE tmp;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	if (pid == 0)
sl@0: 		pid=(unsigned long)CRYPTO_thread_id();
sl@0: 	tmp.pid=pid;
sl@0: 	/* thread_del_item automatically destroys the LHASH if the number of
sl@0: 	 * items reaches zero. */
sl@0: 	ERRFN(thread_del_item)(&tmp);
sl@0: 	}
sl@0: #ifdef EMULATOR
sl@0: GET_STATIC_VAR_FROM_TLS(fallback,err,ERR_STATE)
sl@0: #define fallback (*GET_WSD_VAR_NAME(fallback,err, s)())
sl@0: #endif
sl@0: EXPORT_C ERR_STATE *ERR_get_state(void)
sl@0: 	{
sl@0: #ifndef EMULATOR	
sl@0: 	static ERR_STATE fallback;
sl@0: #endif	
sl@0: 	ERR_STATE *ret,tmp,*tmpp=NULL;
sl@0: 	int i;
sl@0: 	unsigned long pid;
sl@0: 
sl@0: 	err_fns_check();
sl@0: 	pid=(unsigned long)CRYPTO_thread_id();
sl@0: 	tmp.pid=pid;
sl@0: 	ret=ERRFN(thread_get_item)(&tmp);
sl@0: 
sl@0: 	/* ret == the error state, if NULL, make a new one */
sl@0: 	if (ret == NULL)
sl@0: 		{
sl@0: 		ret=(ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE));
sl@0: 		if (ret == NULL) return(&fallback);
sl@0: 		ret->pid=pid;
sl@0: 		ret->top=0;
sl@0: 		ret->bottom=0;
sl@0: 		for (i=0; i<ERR_NUM_ERRORS; i++)
sl@0: 			{
sl@0: 			ret->err_data[i]=NULL;
sl@0: 			ret->err_data_flags[i]=0;
sl@0: 			}
sl@0: 		tmpp = ERRFN(thread_set_item)(ret);
sl@0: 		/* To check if insertion failed, do a get. */
sl@0: 		if (ERRFN(thread_get_item)(ret) != ret)
sl@0: 			{
sl@0: 			ERR_STATE_free(ret); /* could not insert it */
sl@0: 			return(&fallback);
sl@0: 			}
sl@0: 		/* If a race occured in this function and we came second, tmpp
sl@0: 		 * is the first one that we just replaced. */
sl@0: 		if (tmpp)
sl@0: 			ERR_STATE_free(tmpp);
sl@0: 		}
sl@0: 	return ret;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C int ERR_get_next_error_library(void)
sl@0: 	{
sl@0: 	err_fns_check();
sl@0: 	return ERRFN(get_next_lib)();
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_set_error_data(char *data, int flags)
sl@0: 	{
sl@0: 	ERR_STATE *es;
sl@0: 	int i;
sl@0: 
sl@0: 	es=ERR_get_state();
sl@0: 
sl@0: 	i=es->top;
sl@0: 	if (i == 0)
sl@0: 		i=ERR_NUM_ERRORS-1;
sl@0: 
sl@0: 	err_clear_data(es,i);
sl@0: 	es->err_data[i]=data;
sl@0: 	es->err_data_flags[i]=flags;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C void ERR_add_error_data(int num, ...)
sl@0: 	{
sl@0: 	va_list args;
sl@0: 	int i,n,s;
sl@0: 	char *str,*p,*a;
sl@0: 
sl@0: 	s=80;
sl@0: 	str=OPENSSL_malloc(s+1);
sl@0: 	if (str == NULL) return;
sl@0: 	str[0]='\0';
sl@0: 
sl@0: 	va_start(args, num);
sl@0: 	n=0;
sl@0: 	for (i=0; i<num; i++)
sl@0: 		{
sl@0: 		a=va_arg(args, char*);
sl@0: 		/* ignore NULLs, thanks to Bob Beck <beck@obtuse.com> */
sl@0: 		if (a != NULL)
sl@0: 			{
sl@0: 			n+=strlen(a);
sl@0: 			if (n > s)
sl@0: 				{
sl@0: 				s=n+20;
sl@0: 				p=OPENSSL_realloc(str,s+1);
sl@0: 				if (p == NULL)
sl@0: 					{
sl@0: 					OPENSSL_free(str);
sl@0: 					goto err;
sl@0: 					}
sl@0: 				else
sl@0: 					str=p;
sl@0: 				}
sl@0: 			BUF_strlcat(str,a,(size_t)s+1);
sl@0: 			}
sl@0: 		}
sl@0: 	ERR_set_error_data(str,ERR_TXT_MALLOCED|ERR_TXT_STRING);
sl@0: 
sl@0: err:
sl@0: 	va_end(args);
sl@0: 	}
sl@0: 
sl@0: EXPORT_C int ERR_set_mark(void)
sl@0: 	{
sl@0: 	ERR_STATE *es;
sl@0: 
sl@0: 	es=ERR_get_state();
sl@0: 
sl@0: 	if (es->bottom == es->top) return 0;
sl@0: 	es->err_flags[es->top]|=ERR_FLAG_MARK;
sl@0: 	return 1;
sl@0: 	}
sl@0: 
sl@0: EXPORT_C int ERR_pop_to_mark(void)
sl@0: 	{
sl@0: 	ERR_STATE *es;
sl@0: 
sl@0: 	es=ERR_get_state();
sl@0: 
sl@0: 	while(es->bottom != es->top
sl@0: 		&& (es->err_flags[es->top] & ERR_FLAG_MARK) == 0)
sl@0: 		{
sl@0: 		err_clear(es,es->top);
sl@0: 		es->top-=1;
sl@0: 		if (es->top == -1) es->top=ERR_NUM_ERRORS;
sl@0: 		}
sl@0: 		
sl@0: 	if (es->bottom == es->top) return 0;
sl@0: 	es->err_flags[es->top]&=~ERR_FLAG_MARK;
sl@0: 	return 1;
sl@0: 	}