155714Skris/* crypto/err/err.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8280304Sjkim *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15280304Sjkim *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22280304Sjkim *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37280304Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40280304Sjkim *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52280304Sjkim *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5859191Skris/* ====================================================================
59238405Sjkim * Copyright (c) 1998-2006 The OpenSSL Project.  All rights reserved.
6059191Skris *
6159191Skris * Redistribution and use in source and binary forms, with or without
6259191Skris * modification, are permitted provided that the following conditions
6359191Skris * are met:
6459191Skris *
6559191Skris * 1. Redistributions of source code must retain the above copyright
66280304Sjkim *    notice, this list of conditions and the following disclaimer.
6759191Skris *
6859191Skris * 2. Redistributions in binary form must reproduce the above copyright
6959191Skris *    notice, this list of conditions and the following disclaimer in
7059191Skris *    the documentation and/or other materials provided with the
7159191Skris *    distribution.
7259191Skris *
7359191Skris * 3. All advertising materials mentioning features or use of this
7459191Skris *    software must display the following acknowledgment:
7559191Skris *    "This product includes software developed by the OpenSSL Project
7659191Skris *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
7759191Skris *
7859191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
7959191Skris *    endorse or promote products derived from this software without
8059191Skris *    prior written permission. For written permission, please contact
8159191Skris *    openssl-core@openssl.org.
8259191Skris *
8359191Skris * 5. Products derived from this software may not be called "OpenSSL"
8459191Skris *    nor may "OpenSSL" appear in their names without prior written
8559191Skris *    permission of the OpenSSL Project.
8659191Skris *
8759191Skris * 6. Redistributions of any form whatsoever must retain the following
8859191Skris *    acknowledgment:
8959191Skris *    "This product includes software developed by the OpenSSL Project
9059191Skris *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
9159191Skris *
9259191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
9359191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9459191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
9559191Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
9659191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9759191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
9859191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
9959191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
10059191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
10159191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
10259191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
10359191Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
10459191Skris * ====================================================================
10559191Skris *
10659191Skris * This product includes cryptographic software written by Eric Young
10759191Skris * (eay@cryptsoft.com).  This product includes software written by Tim
10859191Skris * Hudson (tjh@cryptsoft.com).
10959191Skris *
11059191Skris */
11155714Skris
11255714Skris#include <stdio.h>
11355714Skris#include <stdarg.h>
11459191Skris#include <string.h>
115160814Ssimon#include "cryptlib.h"
11655714Skris#include <openssl/lhash.h>
11755714Skris#include <openssl/crypto.h>
11855714Skris#include <openssl/buffer.h>
11968651Skris#include <openssl/bio.h>
12055714Skris#include <openssl/err.h>
12155714Skris
122238405SjkimDECLARE_LHASH_OF(ERR_STRING_DATA);
123238405SjkimDECLARE_LHASH_OF(ERR_STATE);
12455714Skris
125238405Sjkimstatic void err_load_strings(int lib, ERR_STRING_DATA *str);
126238405Sjkim
127238405Sjkimstatic void ERR_STATE_free(ERR_STATE *s);
128238405Sjkim#ifndef OPENSSL_NO_ERR
129280304Sjkimstatic ERR_STRING_DATA ERR_str_libraries[] = {
130280304Sjkim    {ERR_PACK(ERR_LIB_NONE, 0, 0), "unknown library"},
131280304Sjkim    {ERR_PACK(ERR_LIB_SYS, 0, 0), "system library"},
132280304Sjkim    {ERR_PACK(ERR_LIB_BN, 0, 0), "bignum routines"},
133280304Sjkim    {ERR_PACK(ERR_LIB_RSA, 0, 0), "rsa routines"},
134280304Sjkim    {ERR_PACK(ERR_LIB_DH, 0, 0), "Diffie-Hellman routines"},
135280304Sjkim    {ERR_PACK(ERR_LIB_EVP, 0, 0), "digital envelope routines"},
136280304Sjkim    {ERR_PACK(ERR_LIB_BUF, 0, 0), "memory buffer routines"},
137280304Sjkim    {ERR_PACK(ERR_LIB_OBJ, 0, 0), "object identifier routines"},
138280304Sjkim    {ERR_PACK(ERR_LIB_PEM, 0, 0), "PEM routines"},
139280304Sjkim    {ERR_PACK(ERR_LIB_DSA, 0, 0), "dsa routines"},
140280304Sjkim    {ERR_PACK(ERR_LIB_X509, 0, 0), "x509 certificate routines"},
141280304Sjkim    {ERR_PACK(ERR_LIB_ASN1, 0, 0), "asn1 encoding routines"},
142280304Sjkim    {ERR_PACK(ERR_LIB_CONF, 0, 0), "configuration file routines"},
143280304Sjkim    {ERR_PACK(ERR_LIB_CRYPTO, 0, 0), "common libcrypto routines"},
144280304Sjkim    {ERR_PACK(ERR_LIB_EC, 0, 0), "elliptic curve routines"},
145280304Sjkim    {ERR_PACK(ERR_LIB_SSL, 0, 0), "SSL routines"},
146280304Sjkim    {ERR_PACK(ERR_LIB_BIO, 0, 0), "BIO routines"},
147280304Sjkim    {ERR_PACK(ERR_LIB_PKCS7, 0, 0), "PKCS7 routines"},
148280304Sjkim    {ERR_PACK(ERR_LIB_X509V3, 0, 0), "X509 V3 routines"},
149280304Sjkim    {ERR_PACK(ERR_LIB_PKCS12, 0, 0), "PKCS12 routines"},
150280304Sjkim    {ERR_PACK(ERR_LIB_RAND, 0, 0), "random number generator"},
151280304Sjkim    {ERR_PACK(ERR_LIB_DSO, 0, 0), "DSO support routines"},
152280304Sjkim    {ERR_PACK(ERR_LIB_TS, 0, 0), "time stamp routines"},
153280304Sjkim    {ERR_PACK(ERR_LIB_ENGINE, 0, 0), "engine routines"},
154280304Sjkim    {ERR_PACK(ERR_LIB_OCSP, 0, 0), "OCSP routines"},
155280304Sjkim    {ERR_PACK(ERR_LIB_FIPS, 0, 0), "FIPS routines"},
156280304Sjkim    {ERR_PACK(ERR_LIB_CMS, 0, 0), "CMS routines"},
157280304Sjkim    {ERR_PACK(ERR_LIB_HMAC, 0, 0), "HMAC routines"},
158280304Sjkim    {0, NULL},
159280304Sjkim};
160238405Sjkim
161280304Sjkimstatic ERR_STRING_DATA ERR_str_functs[] = {
162280304Sjkim    {ERR_PACK(0, SYS_F_FOPEN, 0), "fopen"},
163280304Sjkim    {ERR_PACK(0, SYS_F_CONNECT, 0), "connect"},
164280304Sjkim    {ERR_PACK(0, SYS_F_GETSERVBYNAME, 0), "getservbyname"},
165280304Sjkim    {ERR_PACK(0, SYS_F_SOCKET, 0), "socket"},
166280304Sjkim    {ERR_PACK(0, SYS_F_IOCTLSOCKET, 0), "ioctlsocket"},
167280304Sjkim    {ERR_PACK(0, SYS_F_BIND, 0), "bind"},
168280304Sjkim    {ERR_PACK(0, SYS_F_LISTEN, 0), "listen"},
169280304Sjkim    {ERR_PACK(0, SYS_F_ACCEPT, 0), "accept"},
170280304Sjkim# ifdef OPENSSL_SYS_WINDOWS
171280304Sjkim    {ERR_PACK(0, SYS_F_WSASTARTUP, 0), "WSAstartup"},
172280304Sjkim# endif
173280304Sjkim    {ERR_PACK(0, SYS_F_OPENDIR, 0), "opendir"},
174280304Sjkim    {ERR_PACK(0, SYS_F_FREAD, 0), "fread"},
175280304Sjkim    {0, NULL},
176280304Sjkim};
177238405Sjkim
178280304Sjkimstatic ERR_STRING_DATA ERR_str_reasons[] = {
179280304Sjkim    {ERR_R_SYS_LIB, "system lib"},
180280304Sjkim    {ERR_R_BN_LIB, "BN lib"},
181280304Sjkim    {ERR_R_RSA_LIB, "RSA lib"},
182280304Sjkim    {ERR_R_DH_LIB, "DH lib"},
183280304Sjkim    {ERR_R_EVP_LIB, "EVP lib"},
184280304Sjkim    {ERR_R_BUF_LIB, "BUF lib"},
185280304Sjkim    {ERR_R_OBJ_LIB, "OBJ lib"},
186280304Sjkim    {ERR_R_PEM_LIB, "PEM lib"},
187280304Sjkim    {ERR_R_DSA_LIB, "DSA lib"},
188280304Sjkim    {ERR_R_X509_LIB, "X509 lib"},
189280304Sjkim    {ERR_R_ASN1_LIB, "ASN1 lib"},
190280304Sjkim    {ERR_R_CONF_LIB, "CONF lib"},
191280304Sjkim    {ERR_R_CRYPTO_LIB, "CRYPTO lib"},
192280304Sjkim    {ERR_R_EC_LIB, "EC lib"},
193280304Sjkim    {ERR_R_SSL_LIB, "SSL lib"},
194280304Sjkim    {ERR_R_BIO_LIB, "BIO lib"},
195280304Sjkim    {ERR_R_PKCS7_LIB, "PKCS7 lib"},
196280304Sjkim    {ERR_R_X509V3_LIB, "X509V3 lib"},
197280304Sjkim    {ERR_R_PKCS12_LIB, "PKCS12 lib"},
198280304Sjkim    {ERR_R_RAND_LIB, "RAND lib"},
199280304Sjkim    {ERR_R_DSO_LIB, "DSO lib"},
200280304Sjkim    {ERR_R_ENGINE_LIB, "ENGINE lib"},
201280304Sjkim    {ERR_R_OCSP_LIB, "OCSP lib"},
202280304Sjkim    {ERR_R_TS_LIB, "TS lib"},
203238405Sjkim
204280304Sjkim    {ERR_R_NESTED_ASN1_ERROR, "nested asn1 error"},
205280304Sjkim    {ERR_R_BAD_ASN1_OBJECT_HEADER, "bad asn1 object header"},
206280304Sjkim    {ERR_R_BAD_GET_ASN1_OBJECT_CALL, "bad get asn1 object call"},
207280304Sjkim    {ERR_R_EXPECTING_AN_ASN1_SEQUENCE, "expecting an asn1 sequence"},
208280304Sjkim    {ERR_R_ASN1_LENGTH_MISMATCH, "asn1 length mismatch"},
209280304Sjkim    {ERR_R_MISSING_ASN1_EOS, "missing asn1 eos"},
210238405Sjkim
211280304Sjkim    {ERR_R_FATAL, "fatal"},
212280304Sjkim    {ERR_R_MALLOC_FAILURE, "malloc failure"},
213280304Sjkim    {ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED,
214280304Sjkim     "called a function you should not call"},
215280304Sjkim    {ERR_R_PASSED_NULL_PARAMETER, "passed a null parameter"},
216280304Sjkim    {ERR_R_INTERNAL_ERROR, "internal error"},
217280304Sjkim    {ERR_R_DISABLED, "called a function that was disabled at compile-time"},
218238405Sjkim
219280304Sjkim    {0, NULL},
220280304Sjkim};
221238405Sjkim#endif
222238405Sjkim
223238405Sjkim/* Define the predeclared (but externally opaque) "ERR_FNS" type */
224280304Sjkimstruct st_ERR_FNS {
225280304Sjkim    /* Works on the "error_hash" string table */
226280304Sjkim    LHASH_OF(ERR_STRING_DATA) *(*cb_err_get) (int create);
227280304Sjkim    void (*cb_err_del) (void);
228280304Sjkim    ERR_STRING_DATA *(*cb_err_get_item) (const ERR_STRING_DATA *);
229280304Sjkim    ERR_STRING_DATA *(*cb_err_set_item) (ERR_STRING_DATA *);
230280304Sjkim    ERR_STRING_DATA *(*cb_err_del_item) (ERR_STRING_DATA *);
231280304Sjkim    /* Works on the "thread_hash" error-state table */
232280304Sjkim    LHASH_OF(ERR_STATE) *(*cb_thread_get) (int create);
233280304Sjkim    void (*cb_thread_release) (LHASH_OF(ERR_STATE) **hash);
234280304Sjkim    ERR_STATE *(*cb_thread_get_item) (const ERR_STATE *);
235280304Sjkim    ERR_STATE *(*cb_thread_set_item) (ERR_STATE *);
236280304Sjkim    void (*cb_thread_del_item) (const ERR_STATE *);
237280304Sjkim    /* Returns the next available error "library" numbers */
238280304Sjkim    int (*cb_get_next_lib) (void);
239280304Sjkim};
240238405Sjkim
241238405Sjkim/* Predeclarations of the "err_defaults" functions */
242238405Sjkimstatic LHASH_OF(ERR_STRING_DATA) *int_err_get(int create);
243238405Sjkimstatic void int_err_del(void);
244238405Sjkimstatic ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *);
245238405Sjkimstatic ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *);
246238405Sjkimstatic ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *);
247238405Sjkimstatic LHASH_OF(ERR_STATE) *int_thread_get(int create);
248238405Sjkimstatic void int_thread_release(LHASH_OF(ERR_STATE) **hash);
249238405Sjkimstatic ERR_STATE *int_thread_get_item(const ERR_STATE *);
250238405Sjkimstatic ERR_STATE *int_thread_set_item(ERR_STATE *);
251238405Sjkimstatic void int_thread_del_item(const ERR_STATE *);
252238405Sjkimstatic int int_err_get_next_lib(void);
253238405Sjkim/* The static ERR_FNS table using these defaults functions */
254280304Sjkimstatic const ERR_FNS err_defaults = {
255280304Sjkim    int_err_get,
256280304Sjkim    int_err_del,
257280304Sjkim    int_err_get_item,
258280304Sjkim    int_err_set_item,
259280304Sjkim    int_err_del_item,
260280304Sjkim    int_thread_get,
261280304Sjkim    int_thread_release,
262280304Sjkim    int_thread_get_item,
263280304Sjkim    int_thread_set_item,
264280304Sjkim    int_thread_del_item,
265280304Sjkim    int_err_get_next_lib
266280304Sjkim};
267238405Sjkim
268238405Sjkim/* The replacable table of ERR_FNS functions we use at run-time */
269238405Sjkimstatic const ERR_FNS *err_fns = NULL;
270238405Sjkim
271238405Sjkim/* Eg. rather than using "err_get()", use "ERRFN(err_get)()". */
272238405Sjkim#define ERRFN(a) err_fns->cb_##a
273238405Sjkim
274280304Sjkim/*
275280304Sjkim * The internal state used by "err_defaults" - as such, the setting, reading,
276238405Sjkim * creating, and deleting of this data should only be permitted via the
277280304Sjkim * "err_defaults" functions. This way, a linked module can completely defer
278280304Sjkim * all ERR state operation (together with requisite locking) to the
279280304Sjkim * implementations and state in the loading application.
280280304Sjkim */
281238405Sjkimstatic LHASH_OF(ERR_STRING_DATA) *int_error_hash = NULL;
282238405Sjkimstatic LHASH_OF(ERR_STATE) *int_thread_hash = NULL;
283238405Sjkimstatic int int_thread_hash_references = 0;
284280304Sjkimstatic int int_err_library_number = ERR_LIB_USER;
285238405Sjkim
286280304Sjkim/*
287280304Sjkim * Internal function that checks whether "err_fns" is set and if not, sets it
288280304Sjkim * to the defaults.
289280304Sjkim */
290238405Sjkimstatic void err_fns_check(void)
291280304Sjkim{
292280304Sjkim    if (err_fns)
293280304Sjkim        return;
294238405Sjkim
295280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
296280304Sjkim    if (!err_fns)
297280304Sjkim        err_fns = &err_defaults;
298280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
299280304Sjkim}
300280304Sjkim
301238405Sjkim/* API functions to get or set the underlying ERR functions. */
302238405Sjkim
303238405Sjkimconst ERR_FNS *ERR_get_implementation(void)
304280304Sjkim{
305280304Sjkim    err_fns_check();
306280304Sjkim    return err_fns;
307280304Sjkim}
308238405Sjkim
309238405Sjkimint ERR_set_implementation(const ERR_FNS *fns)
310280304Sjkim{
311280304Sjkim    int ret = 0;
312238405Sjkim
313280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
314280304Sjkim    /*
315280304Sjkim     * It's too late if 'err_fns' is non-NULL. BTW: not much point setting an
316280304Sjkim     * error is there?!
317280304Sjkim     */
318280304Sjkim    if (!err_fns) {
319280304Sjkim        err_fns = fns;
320280304Sjkim        ret = 1;
321280304Sjkim    }
322280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
323280304Sjkim    return ret;
324280304Sjkim}
325238405Sjkim
326280304Sjkim/*
327280304Sjkim * These are the callbacks provided to "lh_new()" when creating the LHASH
328280304Sjkim * tables internal to the "err_defaults" implementation.
329280304Sjkim */
330238405Sjkim
331280304Sjkimstatic unsigned long get_error_values(int inc, int top, const char **file,
332280304Sjkim                                      int *line, const char **data,
333280304Sjkim                                      int *flags);
334238405Sjkim
335238405Sjkim/* The internal functions used in the "err_defaults" implementation */
336238405Sjkim
337238405Sjkimstatic unsigned long err_string_data_hash(const ERR_STRING_DATA *a)
338280304Sjkim{
339280304Sjkim    unsigned long ret, l;
340238405Sjkim
341280304Sjkim    l = a->error;
342280304Sjkim    ret = l ^ ERR_GET_LIB(l) ^ ERR_GET_FUNC(l);
343280304Sjkim    return (ret ^ ret % 19 * 13);
344280304Sjkim}
345280304Sjkim
346238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(err_string_data, ERR_STRING_DATA)
347238405Sjkim
348238405Sjkimstatic int err_string_data_cmp(const ERR_STRING_DATA *a,
349280304Sjkim                               const ERR_STRING_DATA *b)
350280304Sjkim{
351280304Sjkim    return (int)(a->error - b->error);
352280304Sjkim}
353280304Sjkim
354238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(err_string_data, ERR_STRING_DATA)
355238405Sjkim
356238405Sjkimstatic LHASH_OF(ERR_STRING_DATA) *int_err_get(int create)
357280304Sjkim{
358280304Sjkim    LHASH_OF(ERR_STRING_DATA) *ret = NULL;
359238405Sjkim
360280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
361280304Sjkim    if (!int_error_hash && create) {
362280304Sjkim        CRYPTO_push_info("int_err_get (err.c)");
363280304Sjkim        int_error_hash = lh_ERR_STRING_DATA_new();
364280304Sjkim        CRYPTO_pop_info();
365280304Sjkim    }
366280304Sjkim    if (int_error_hash)
367280304Sjkim        ret = int_error_hash;
368280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
369238405Sjkim
370280304Sjkim    return ret;
371280304Sjkim}
372238405Sjkim
373238405Sjkimstatic void int_err_del(void)
374280304Sjkim{
375280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
376280304Sjkim    if (int_error_hash) {
377280304Sjkim        lh_ERR_STRING_DATA_free(int_error_hash);
378280304Sjkim        int_error_hash = NULL;
379280304Sjkim    }
380280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
381280304Sjkim}
382238405Sjkim
383238405Sjkimstatic ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d)
384280304Sjkim{
385280304Sjkim    ERR_STRING_DATA *p;
386280304Sjkim    LHASH_OF(ERR_STRING_DATA) *hash;
387238405Sjkim
388280304Sjkim    err_fns_check();
389280304Sjkim    hash = ERRFN(err_get) (0);
390280304Sjkim    if (!hash)
391280304Sjkim        return NULL;
392238405Sjkim
393280304Sjkim    CRYPTO_r_lock(CRYPTO_LOCK_ERR);
394280304Sjkim    p = lh_ERR_STRING_DATA_retrieve(hash, d);
395280304Sjkim    CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
396238405Sjkim
397280304Sjkim    return p;
398280304Sjkim}
399238405Sjkim
400238405Sjkimstatic ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *d)
401280304Sjkim{
402280304Sjkim    ERR_STRING_DATA *p;
403280304Sjkim    LHASH_OF(ERR_STRING_DATA) *hash;
404238405Sjkim
405280304Sjkim    err_fns_check();
406280304Sjkim    hash = ERRFN(err_get) (1);
407280304Sjkim    if (!hash)
408280304Sjkim        return NULL;
409238405Sjkim
410280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
411280304Sjkim    p = lh_ERR_STRING_DATA_insert(hash, d);
412280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
413238405Sjkim
414280304Sjkim    return p;
415280304Sjkim}
416238405Sjkim
417238405Sjkimstatic ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d)
418280304Sjkim{
419280304Sjkim    ERR_STRING_DATA *p;
420280304Sjkim    LHASH_OF(ERR_STRING_DATA) *hash;
421238405Sjkim
422280304Sjkim    err_fns_check();
423280304Sjkim    hash = ERRFN(err_get) (0);
424280304Sjkim    if (!hash)
425280304Sjkim        return NULL;
426238405Sjkim
427280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
428280304Sjkim    p = lh_ERR_STRING_DATA_delete(hash, d);
429280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
430238405Sjkim
431280304Sjkim    return p;
432280304Sjkim}
433238405Sjkim
434238405Sjkimstatic unsigned long err_state_hash(const ERR_STATE *a)
435280304Sjkim{
436280304Sjkim    return CRYPTO_THREADID_hash(&a->tid) * 13;
437280304Sjkim}
438280304Sjkim
439238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(err_state, ERR_STATE)
440238405Sjkim
441238405Sjkimstatic int err_state_cmp(const ERR_STATE *a, const ERR_STATE *b)
442280304Sjkim{
443280304Sjkim    return CRYPTO_THREADID_cmp(&a->tid, &b->tid);
444280304Sjkim}
445280304Sjkim
446238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(err_state, ERR_STATE)
447238405Sjkim
448238405Sjkimstatic LHASH_OF(ERR_STATE) *int_thread_get(int create)
449280304Sjkim{
450280304Sjkim    LHASH_OF(ERR_STATE) *ret = NULL;
451238405Sjkim
452280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
453280304Sjkim    if (!int_thread_hash && create) {
454280304Sjkim        CRYPTO_push_info("int_thread_get (err.c)");
455280304Sjkim        int_thread_hash = lh_ERR_STATE_new();
456280304Sjkim        CRYPTO_pop_info();
457280304Sjkim    }
458280304Sjkim    if (int_thread_hash) {
459280304Sjkim        int_thread_hash_references++;
460280304Sjkim        ret = int_thread_hash;
461280304Sjkim    }
462280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
463280304Sjkim    return ret;
464280304Sjkim}
465238405Sjkim
466238405Sjkimstatic void int_thread_release(LHASH_OF(ERR_STATE) **hash)
467280304Sjkim{
468280304Sjkim    int i;
469238405Sjkim
470280304Sjkim    if (hash == NULL || *hash == NULL)
471280304Sjkim        return;
472238405Sjkim
473280304Sjkim    i = CRYPTO_add(&int_thread_hash_references, -1, CRYPTO_LOCK_ERR);
474238405Sjkim
475238405Sjkim#ifdef REF_PRINT
476280304Sjkim    fprintf(stderr, "%4d:%s\n", int_thread_hash_references, "ERR");
477238405Sjkim#endif
478280304Sjkim    if (i > 0)
479280304Sjkim        return;
480238405Sjkim#ifdef REF_CHECK
481280304Sjkim    if (i < 0) {
482280304Sjkim        fprintf(stderr, "int_thread_release, bad reference count\n");
483280304Sjkim        abort();                /* ok */
484280304Sjkim    }
485238405Sjkim#endif
486280304Sjkim    *hash = NULL;
487280304Sjkim}
488238405Sjkim
489238405Sjkimstatic ERR_STATE *int_thread_get_item(const ERR_STATE *d)
490280304Sjkim{
491280304Sjkim    ERR_STATE *p;
492280304Sjkim    LHASH_OF(ERR_STATE) *hash;
493238405Sjkim
494280304Sjkim    err_fns_check();
495280304Sjkim    hash = ERRFN(thread_get) (0);
496280304Sjkim    if (!hash)
497280304Sjkim        return NULL;
498238405Sjkim
499280304Sjkim    CRYPTO_r_lock(CRYPTO_LOCK_ERR);
500280304Sjkim    p = lh_ERR_STATE_retrieve(hash, d);
501280304Sjkim    CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
502238405Sjkim
503280304Sjkim    ERRFN(thread_release) (&hash);
504280304Sjkim    return p;
505280304Sjkim}
506238405Sjkim
507238405Sjkimstatic ERR_STATE *int_thread_set_item(ERR_STATE *d)
508280304Sjkim{
509280304Sjkim    ERR_STATE *p;
510280304Sjkim    LHASH_OF(ERR_STATE) *hash;
511238405Sjkim
512280304Sjkim    err_fns_check();
513280304Sjkim    hash = ERRFN(thread_get) (1);
514280304Sjkim    if (!hash)
515280304Sjkim        return NULL;
516238405Sjkim
517280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
518280304Sjkim    p = lh_ERR_STATE_insert(hash, d);
519280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
520238405Sjkim
521280304Sjkim    ERRFN(thread_release) (&hash);
522280304Sjkim    return p;
523280304Sjkim}
524238405Sjkim
525238405Sjkimstatic void int_thread_del_item(const ERR_STATE *d)
526280304Sjkim{
527280304Sjkim    ERR_STATE *p;
528280304Sjkim    LHASH_OF(ERR_STATE) *hash;
529238405Sjkim
530280304Sjkim    err_fns_check();
531280304Sjkim    hash = ERRFN(thread_get) (0);
532280304Sjkim    if (!hash)
533280304Sjkim        return;
534238405Sjkim
535280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
536280304Sjkim    p = lh_ERR_STATE_delete(hash, d);
537280304Sjkim    /* make sure we don't leak memory */
538280304Sjkim    if (int_thread_hash_references == 1
539280304Sjkim        && int_thread_hash && lh_ERR_STATE_num_items(int_thread_hash) == 0) {
540280304Sjkim        lh_ERR_STATE_free(int_thread_hash);
541280304Sjkim        int_thread_hash = NULL;
542280304Sjkim    }
543280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
544238405Sjkim
545280304Sjkim    ERRFN(thread_release) (&hash);
546280304Sjkim    if (p)
547280304Sjkim        ERR_STATE_free(p);
548280304Sjkim}
549238405Sjkim
550238405Sjkimstatic int int_err_get_next_lib(void)
551280304Sjkim{
552280304Sjkim    int ret;
553238405Sjkim
554280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
555280304Sjkim    ret = int_err_library_number++;
556280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
557238405Sjkim
558280304Sjkim    return ret;
559280304Sjkim}
560238405Sjkim
561238405Sjkim#ifndef OPENSSL_NO_ERR
562280304Sjkim# define NUM_SYS_STR_REASONS 127
563280304Sjkim# define LEN_SYS_STR_REASON 32
564238405Sjkim
565238405Sjkimstatic ERR_STRING_DATA SYS_str_reasons[NUM_SYS_STR_REASONS + 1];
566280304Sjkim/*
567280304Sjkim * SYS_str_reasons is filled with copies of strerror() results at
568280304Sjkim * initialization. 'errno' values up to 127 should cover all usual errors,
569280304Sjkim * others will be displayed numerically by ERR_error_string. It is crucial
570280304Sjkim * that we have something for each reason code that occurs in
571280304Sjkim * ERR_str_reasons, or bogus reason strings will be returned for SYSerr(),
572280304Sjkim * which always gets an errno value and never one of those 'standard' reason
573280304Sjkim * codes.
574280304Sjkim */
575238405Sjkim
576238405Sjkimstatic void build_SYS_str_reasons(void)
577280304Sjkim{
578280304Sjkim    /* OPENSSL_malloc cannot be used here, use static storage instead */
579280304Sjkim    static char strerror_tab[NUM_SYS_STR_REASONS][LEN_SYS_STR_REASON];
580280304Sjkim    int i;
581280304Sjkim    static int init = 1;
582238405Sjkim
583280304Sjkim    CRYPTO_r_lock(CRYPTO_LOCK_ERR);
584280304Sjkim    if (!init) {
585280304Sjkim        CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
586280304Sjkim        return;
587280304Sjkim    }
588238405Sjkim
589280304Sjkim    CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
590280304Sjkim    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
591280304Sjkim    if (!init) {
592280304Sjkim        CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
593280304Sjkim        return;
594280304Sjkim    }
595238405Sjkim
596280304Sjkim    for (i = 1; i <= NUM_SYS_STR_REASONS; i++) {
597280304Sjkim        ERR_STRING_DATA *str = &SYS_str_reasons[i - 1];
598238405Sjkim
599280304Sjkim        str->error = (unsigned long)i;
600280304Sjkim        if (str->string == NULL) {
601280304Sjkim            char (*dest)[LEN_SYS_STR_REASON] = &(strerror_tab[i - 1]);
602280304Sjkim            char *src = strerror(i);
603280304Sjkim            if (src != NULL) {
604280304Sjkim                strncpy(*dest, src, sizeof *dest);
605280304Sjkim                (*dest)[sizeof *dest - 1] = '\0';
606280304Sjkim                str->string = *dest;
607280304Sjkim            }
608280304Sjkim        }
609280304Sjkim        if (str->string == NULL)
610280304Sjkim            str->string = "unknown";
611280304Sjkim    }
612238405Sjkim
613280304Sjkim    /*
614280304Sjkim     * Now we still have SYS_str_reasons[NUM_SYS_STR_REASONS] = {0, NULL}, as
615280304Sjkim     * required by ERR_load_strings.
616280304Sjkim     */
617280304Sjkim
618280304Sjkim    init = 0;
619280304Sjkim
620280304Sjkim    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
621280304Sjkim}
622238405Sjkim#endif
623238405Sjkim
62455714Skris#define err_clear_data(p,i) \
625280304Sjkim        do { \
626280304Sjkim        if (((p)->err_data[i] != NULL) && \
627280304Sjkim                (p)->err_data_flags[i] & ERR_TXT_MALLOCED) \
628280304Sjkim                {  \
629280304Sjkim                OPENSSL_free((p)->err_data[i]); \
630280304Sjkim                (p)->err_data[i]=NULL; \
631280304Sjkim                } \
632280304Sjkim        (p)->err_data_flags[i]=0; \
633280304Sjkim        } while(0)
63455714Skris
635160814Ssimon#define err_clear(p,i) \
636280304Sjkim        do { \
637280304Sjkim        (p)->err_flags[i]=0; \
638280304Sjkim        (p)->err_buffer[i]=0; \
639280304Sjkim        err_clear_data(p,i); \
640280304Sjkim        (p)->err_file[i]=NULL; \
641280304Sjkim        (p)->err_line[i]= -1; \
642280304Sjkim        } while(0)
643160814Ssimon
644238405Sjkimstatic void ERR_STATE_free(ERR_STATE *s)
645280304Sjkim{
646280304Sjkim    int i;
647238405Sjkim
648280304Sjkim    if (s == NULL)
649280304Sjkim        return;
650238405Sjkim
651280304Sjkim    for (i = 0; i < ERR_NUM_ERRORS; i++) {
652280304Sjkim        err_clear_data(s, i);
653280304Sjkim    }
654280304Sjkim    OPENSSL_free(s);
655280304Sjkim}
656238405Sjkim
657238405Sjkimvoid ERR_load_ERR_strings(void)
658280304Sjkim{
659280304Sjkim    err_fns_check();
660238405Sjkim#ifndef OPENSSL_NO_ERR
661280304Sjkim    err_load_strings(0, ERR_str_libraries);
662280304Sjkim    err_load_strings(0, ERR_str_reasons);
663280304Sjkim    err_load_strings(ERR_LIB_SYS, ERR_str_functs);
664280304Sjkim    build_SYS_str_reasons();
665280304Sjkim    err_load_strings(ERR_LIB_SYS, SYS_str_reasons);
666238405Sjkim#endif
667280304Sjkim}
668238405Sjkim
669238405Sjkimstatic void err_load_strings(int lib, ERR_STRING_DATA *str)
670280304Sjkim{
671280304Sjkim    while (str->error) {
672280304Sjkim        if (lib)
673280304Sjkim            str->error |= ERR_PACK(lib, 0, 0);
674280304Sjkim        ERRFN(err_set_item) (str);
675280304Sjkim        str++;
676280304Sjkim    }
677280304Sjkim}
678238405Sjkim
679238405Sjkimvoid ERR_load_strings(int lib, ERR_STRING_DATA *str)
680280304Sjkim{
681280304Sjkim    ERR_load_ERR_strings();
682280304Sjkim    err_load_strings(lib, str);
683280304Sjkim}
684238405Sjkim
685238405Sjkimvoid ERR_unload_strings(int lib, ERR_STRING_DATA *str)
686280304Sjkim{
687280304Sjkim    while (str->error) {
688280304Sjkim        if (lib)
689280304Sjkim            str->error |= ERR_PACK(lib, 0, 0);
690280304Sjkim        ERRFN(err_del_item) (str);
691280304Sjkim        str++;
692280304Sjkim    }
693280304Sjkim}
694238405Sjkim
695238405Sjkimvoid ERR_free_strings(void)
696280304Sjkim{
697280304Sjkim    err_fns_check();
698280304Sjkim    ERRFN(err_del) ();
699280304Sjkim}
700238405Sjkim
701238405Sjkim/********************************************************/
702238405Sjkim
703280304Sjkimvoid ERR_put_error(int lib, int func, int reason, const char *file, int line)
704280304Sjkim{
705280304Sjkim    ERR_STATE *es;
70655714Skris
70755714Skris#ifdef _OSD_POSIX
708280304Sjkim    /*
709280304Sjkim     * In the BS2000-OSD POSIX subsystem, the compiler generates path names
710280304Sjkim     * in the form "*POSIX(/etc/passwd)". This dirty hack strips them to
711280304Sjkim     * something sensible. @@@ We shouldn't modify a const string, though.
712280304Sjkim     */
713280304Sjkim    if (strncmp(file, "*POSIX(", sizeof("*POSIX(") - 1) == 0) {
714280304Sjkim        char *end;
71555714Skris
716280304Sjkim        /* Skip the "*POSIX(" prefix */
717280304Sjkim        file += sizeof("*POSIX(") - 1;
718280304Sjkim        end = &file[strlen(file) - 1];
719280304Sjkim        if (*end == ')')
720280304Sjkim            *end = '\0';
721280304Sjkim        /* Optional: use the basename of the path only. */
722280304Sjkim        if ((end = strrchr(file, '/')) != NULL)
723280304Sjkim            file = &end[1];
724280304Sjkim    }
72555714Skris#endif
726280304Sjkim    es = ERR_get_state();
72755714Skris
728280304Sjkim    es->top = (es->top + 1) % ERR_NUM_ERRORS;
729280304Sjkim    if (es->top == es->bottom)
730280304Sjkim        es->bottom = (es->bottom + 1) % ERR_NUM_ERRORS;
731280304Sjkim    es->err_flags[es->top] = 0;
732280304Sjkim    es->err_buffer[es->top] = ERR_PACK(lib, func, reason);
733280304Sjkim    es->err_file[es->top] = file;
734280304Sjkim    es->err_line[es->top] = line;
735280304Sjkim    err_clear_data(es, es->top);
736280304Sjkim}
73755714Skris
73855714Skrisvoid ERR_clear_error(void)
739280304Sjkim{
740280304Sjkim    int i;
741280304Sjkim    ERR_STATE *es;
74255714Skris
743280304Sjkim    es = ERR_get_state();
74455714Skris
745280304Sjkim    for (i = 0; i < ERR_NUM_ERRORS; i++) {
746280304Sjkim        err_clear(es, i);
747280304Sjkim    }
748280304Sjkim    es->top = es->bottom = 0;
749280304Sjkim}
75055714Skris
75155714Skrisunsigned long ERR_get_error(void)
752280304Sjkim{
753280304Sjkim    return (get_error_values(1, 0, NULL, NULL, NULL, NULL));
754280304Sjkim}
75555714Skris
756280304Sjkimunsigned long ERR_get_error_line(const char **file, int *line)
757280304Sjkim{
758280304Sjkim    return (get_error_values(1, 0, file, line, NULL, NULL));
759280304Sjkim}
76055714Skris
76155714Skrisunsigned long ERR_get_error_line_data(const char **file, int *line,
762280304Sjkim                                      const char **data, int *flags)
763280304Sjkim{
764280304Sjkim    return (get_error_values(1, 0, file, line, data, flags));
765280304Sjkim}
76655714Skris
76755714Skrisunsigned long ERR_peek_error(void)
768280304Sjkim{
769280304Sjkim    return (get_error_values(0, 0, NULL, NULL, NULL, NULL));
770280304Sjkim}
77155714Skris
772109998Smarkmunsigned long ERR_peek_error_line(const char **file, int *line)
773280304Sjkim{
774280304Sjkim    return (get_error_values(0, 0, file, line, NULL, NULL));
775280304Sjkim}
77655714Skris
77755714Skrisunsigned long ERR_peek_error_line_data(const char **file, int *line,
778280304Sjkim                                       const char **data, int *flags)
779280304Sjkim{
780280304Sjkim    return (get_error_values(0, 0, file, line, data, flags));
781280304Sjkim}
78255714Skris
783109998Smarkmunsigned long ERR_peek_last_error(void)
784280304Sjkim{
785280304Sjkim    return (get_error_values(0, 1, NULL, NULL, NULL, NULL));
786280304Sjkim}
787109998Smarkm
788109998Smarkmunsigned long ERR_peek_last_error_line(const char **file, int *line)
789280304Sjkim{
790280304Sjkim    return (get_error_values(0, 1, file, line, NULL, NULL));
791280304Sjkim}
792109998Smarkm
793109998Smarkmunsigned long ERR_peek_last_error_line_data(const char **file, int *line,
794280304Sjkim                                            const char **data, int *flags)
795280304Sjkim{
796280304Sjkim    return (get_error_values(0, 1, file, line, data, flags));
797280304Sjkim}
798109998Smarkm
799280304Sjkimstatic unsigned long get_error_values(int inc, int top, const char **file,
800280304Sjkim                                      int *line, const char **data,
801280304Sjkim                                      int *flags)
802280304Sjkim{
803280304Sjkim    int i = 0;
804280304Sjkim    ERR_STATE *es;
805280304Sjkim    unsigned long ret;
806109998Smarkm
807280304Sjkim    es = ERR_get_state();
80855714Skris
809280304Sjkim    if (inc && top) {
810280304Sjkim        if (file)
811280304Sjkim            *file = "";
812280304Sjkim        if (line)
813280304Sjkim            *line = 0;
814280304Sjkim        if (data)
815280304Sjkim            *data = "";
816280304Sjkim        if (flags)
817280304Sjkim            *flags = 0;
81855714Skris
819280304Sjkim        return ERR_R_INTERNAL_ERROR;
820280304Sjkim    }
82155714Skris
822280304Sjkim    if (es->bottom == es->top)
823280304Sjkim        return 0;
824280304Sjkim    if (top)
825280304Sjkim        i = es->top;            /* last error */
826280304Sjkim    else
827280304Sjkim        i = (es->bottom + 1) % ERR_NUM_ERRORS; /* first error */
828109998Smarkm
829280304Sjkim    ret = es->err_buffer[i];
830280304Sjkim    if (inc) {
831280304Sjkim        es->bottom = i;
832280304Sjkim        es->err_buffer[i] = 0;
833280304Sjkim    }
83455714Skris
835280304Sjkim    if ((file != NULL) && (line != NULL)) {
836280304Sjkim        if (es->err_file[i] == NULL) {
837280304Sjkim            *file = "NA";
838280304Sjkim            if (line != NULL)
839280304Sjkim                *line = 0;
840280304Sjkim        } else {
841280304Sjkim            *file = es->err_file[i];
842280304Sjkim            if (line != NULL)
843280304Sjkim                *line = es->err_line[i];
844280304Sjkim        }
845280304Sjkim    }
84655714Skris
847280304Sjkim    if (data == NULL) {
848280304Sjkim        if (inc) {
849280304Sjkim            err_clear_data(es, i);
850280304Sjkim        }
851280304Sjkim    } else {
852280304Sjkim        if (es->err_data[i] == NULL) {
853280304Sjkim            *data = "";
854280304Sjkim            if (flags != NULL)
855280304Sjkim                *flags = 0;
856280304Sjkim        } else {
857280304Sjkim            *data = es->err_data[i];
858280304Sjkim            if (flags != NULL)
859280304Sjkim                *flags = es->err_data_flags[i];
860280304Sjkim        }
861280304Sjkim    }
862280304Sjkim    return ret;
863280304Sjkim}
86455714Skris
865238405Sjkimvoid ERR_error_string_n(unsigned long e, char *buf, size_t len)
866280304Sjkim{
867280304Sjkim    char lsbuf[64], fsbuf[64], rsbuf[64];
868280304Sjkim    const char *ls, *fs, *rs;
869280304Sjkim    unsigned long l, f, r;
870238405Sjkim
871280304Sjkim    l = ERR_GET_LIB(e);
872280304Sjkim    f = ERR_GET_FUNC(e);
873280304Sjkim    r = ERR_GET_REASON(e);
874238405Sjkim
875280304Sjkim    ls = ERR_lib_error_string(e);
876280304Sjkim    fs = ERR_func_error_string(e);
877280304Sjkim    rs = ERR_reason_error_string(e);
878238405Sjkim
879280304Sjkim    if (ls == NULL)
880280304Sjkim        BIO_snprintf(lsbuf, sizeof(lsbuf), "lib(%lu)", l);
881280304Sjkim    if (fs == NULL)
882280304Sjkim        BIO_snprintf(fsbuf, sizeof(fsbuf), "func(%lu)", f);
883280304Sjkim    if (rs == NULL)
884280304Sjkim        BIO_snprintf(rsbuf, sizeof(rsbuf), "reason(%lu)", r);
885238405Sjkim
886280304Sjkim    BIO_snprintf(buf, len, "error:%08lX:%s:%s:%s", e, ls ? ls : lsbuf,
887280304Sjkim                 fs ? fs : fsbuf, rs ? rs : rsbuf);
888280304Sjkim    if (strlen(buf) == len - 1) {
889280304Sjkim        /*
890280304Sjkim         * output may be truncated; make sure we always have 5
891280304Sjkim         * colon-separated fields, i.e. 4 colons ...
892280304Sjkim         */
893238405Sjkim#define NUM_COLONS 4
894280304Sjkim        if (len > NUM_COLONS) { /* ... if possible */
895280304Sjkim            int i;
896280304Sjkim            char *s = buf;
897238405Sjkim
898280304Sjkim            for (i = 0; i < NUM_COLONS; i++) {
899280304Sjkim                char *colon = strchr(s, ':');
900280304Sjkim                if (colon == NULL || colon > &buf[len - 1] - NUM_COLONS + i) {
901280304Sjkim                    /*
902280304Sjkim                     * set colon no. i at last possible position (buf[len-1]
903280304Sjkim                     * is the terminating 0)
904280304Sjkim                     */
905280304Sjkim                    colon = &buf[len - 1] - NUM_COLONS + i;
906280304Sjkim                    *colon = ':';
907280304Sjkim                }
908280304Sjkim                s = colon + 1;
909280304Sjkim            }
910280304Sjkim        }
911280304Sjkim    }
912280304Sjkim}
913280304Sjkim
914238405Sjkim/* BAD for multi-threading: uses a local buffer if ret == NULL */
915280304Sjkim/*
916280304Sjkim * ERR_error_string_n should be used instead for ret != NULL as
917280304Sjkim * ERR_error_string cannot know how large the buffer is
918280304Sjkim */
919238405Sjkimchar *ERR_error_string(unsigned long e, char *ret)
920280304Sjkim{
921280304Sjkim    static char buf[256];
922238405Sjkim
923280304Sjkim    if (ret == NULL)
924280304Sjkim        ret = buf;
925280304Sjkim    ERR_error_string_n(e, ret, 256);
926238405Sjkim
927280304Sjkim    return ret;
928280304Sjkim}
929238405Sjkim
930238405SjkimLHASH_OF(ERR_STRING_DATA) *ERR_get_string_table(void)
931280304Sjkim{
932280304Sjkim    err_fns_check();
933280304Sjkim    return ERRFN(err_get) (0);
934280304Sjkim}
935238405Sjkim
936238405SjkimLHASH_OF(ERR_STATE) *ERR_get_err_state_table(void)
937280304Sjkim{
938280304Sjkim    err_fns_check();
939280304Sjkim    return ERRFN(thread_get) (0);
940280304Sjkim}
941238405Sjkim
942238405Sjkimvoid ERR_release_err_state_table(LHASH_OF(ERR_STATE) **hash)
943280304Sjkim{
944280304Sjkim    err_fns_check();
945280304Sjkim    ERRFN(thread_release) (hash);
946280304Sjkim}
947238405Sjkim
948238405Sjkimconst char *ERR_lib_error_string(unsigned long e)
949280304Sjkim{
950280304Sjkim    ERR_STRING_DATA d, *p;
951280304Sjkim    unsigned long l;
952238405Sjkim
953280304Sjkim    err_fns_check();
954280304Sjkim    l = ERR_GET_LIB(e);
955280304Sjkim    d.error = ERR_PACK(l, 0, 0);
956280304Sjkim    p = ERRFN(err_get_item) (&d);
957280304Sjkim    return ((p == NULL) ? NULL : p->string);
958280304Sjkim}
959238405Sjkim
960238405Sjkimconst char *ERR_func_error_string(unsigned long e)
961280304Sjkim{
962280304Sjkim    ERR_STRING_DATA d, *p;
963280304Sjkim    unsigned long l, f;
964238405Sjkim
965280304Sjkim    err_fns_check();
966280304Sjkim    l = ERR_GET_LIB(e);
967280304Sjkim    f = ERR_GET_FUNC(e);
968280304Sjkim    d.error = ERR_PACK(l, f, 0);
969280304Sjkim    p = ERRFN(err_get_item) (&d);
970280304Sjkim    return ((p == NULL) ? NULL : p->string);
971280304Sjkim}
972238405Sjkim
973238405Sjkimconst char *ERR_reason_error_string(unsigned long e)
974280304Sjkim{
975280304Sjkim    ERR_STRING_DATA d, *p = NULL;
976280304Sjkim    unsigned long l, r;
977238405Sjkim
978280304Sjkim    err_fns_check();
979280304Sjkim    l = ERR_GET_LIB(e);
980280304Sjkim    r = ERR_GET_REASON(e);
981280304Sjkim    d.error = ERR_PACK(l, 0, r);
982280304Sjkim    p = ERRFN(err_get_item) (&d);
983280304Sjkim    if (!p) {
984280304Sjkim        d.error = ERR_PACK(0, 0, r);
985280304Sjkim        p = ERRFN(err_get_item) (&d);
986280304Sjkim    }
987280304Sjkim    return ((p == NULL) ? NULL : p->string);
988280304Sjkim}
989238405Sjkim
990238405Sjkimvoid ERR_remove_thread_state(const CRYPTO_THREADID *id)
991280304Sjkim{
992280304Sjkim    ERR_STATE tmp;
993238405Sjkim
994280304Sjkim    if (id)
995280304Sjkim        CRYPTO_THREADID_cpy(&tmp.tid, id);
996280304Sjkim    else
997280304Sjkim        CRYPTO_THREADID_current(&tmp.tid);
998280304Sjkim    err_fns_check();
999280304Sjkim    /*
1000280304Sjkim     * thread_del_item automatically destroys the LHASH if the number of
1001280304Sjkim     * items reaches zero.
1002280304Sjkim     */
1003280304Sjkim    ERRFN(thread_del_item) (&tmp);
1004280304Sjkim}
1005238405Sjkim
1006238405Sjkim#ifndef OPENSSL_NO_DEPRECATED
1007238405Sjkimvoid ERR_remove_state(unsigned long pid)
1008280304Sjkim{
1009280304Sjkim    ERR_remove_thread_state(NULL);
1010280304Sjkim}
1011238405Sjkim#endif
1012238405Sjkim
1013238405SjkimERR_STATE *ERR_get_state(void)
1014280304Sjkim{
1015280304Sjkim    static ERR_STATE fallback;
1016280304Sjkim    ERR_STATE *ret, tmp, *tmpp = NULL;
1017280304Sjkim    int i;
1018280304Sjkim    CRYPTO_THREADID tid;
1019238405Sjkim
1020280304Sjkim    err_fns_check();
1021280304Sjkim    CRYPTO_THREADID_current(&tid);
1022280304Sjkim    CRYPTO_THREADID_cpy(&tmp.tid, &tid);
1023280304Sjkim    ret = ERRFN(thread_get_item) (&tmp);
1024238405Sjkim
1025280304Sjkim    /* ret == the error state, if NULL, make a new one */
1026280304Sjkim    if (ret == NULL) {
1027280304Sjkim        ret = (ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE));
1028280304Sjkim        if (ret == NULL)
1029280304Sjkim            return (&fallback);
1030280304Sjkim        CRYPTO_THREADID_cpy(&ret->tid, &tid);
1031280304Sjkim        ret->top = 0;
1032280304Sjkim        ret->bottom = 0;
1033280304Sjkim        for (i = 0; i < ERR_NUM_ERRORS; i++) {
1034280304Sjkim            ret->err_data[i] = NULL;
1035280304Sjkim            ret->err_data_flags[i] = 0;
1036280304Sjkim        }
1037280304Sjkim        tmpp = ERRFN(thread_set_item) (ret);
1038280304Sjkim        /* To check if insertion failed, do a get. */
1039280304Sjkim        if (ERRFN(thread_get_item) (ret) != ret) {
1040280304Sjkim            ERR_STATE_free(ret); /* could not insert it */
1041280304Sjkim            return (&fallback);
1042280304Sjkim        }
1043280304Sjkim        /*
1044280304Sjkim         * If a race occured in this function and we came second, tmpp is the
1045280304Sjkim         * first one that we just replaced.
1046280304Sjkim         */
1047280304Sjkim        if (tmpp)
1048280304Sjkim            ERR_STATE_free(tmpp);
1049280304Sjkim    }
1050280304Sjkim    return ret;
1051280304Sjkim}
1052238405Sjkim
1053238405Sjkimint ERR_get_next_error_library(void)
1054280304Sjkim{
1055280304Sjkim    err_fns_check();
1056280304Sjkim    return ERRFN(get_next_lib) ();
1057280304Sjkim}
1058238405Sjkim
105955714Skrisvoid ERR_set_error_data(char *data, int flags)
1060280304Sjkim{
1061280304Sjkim    ERR_STATE *es;
1062280304Sjkim    int i;
106355714Skris
1064280304Sjkim    es = ERR_get_state();
106555714Skris
1066280304Sjkim    i = es->top;
1067280304Sjkim    if (i == 0)
1068280304Sjkim        i = ERR_NUM_ERRORS - 1;
106955714Skris
1070280304Sjkim    err_clear_data(es, i);
1071280304Sjkim    es->err_data[i] = data;
1072280304Sjkim    es->err_data_flags[i] = flags;
1073280304Sjkim}
107455714Skris
107555714Skrisvoid ERR_add_error_data(int num, ...)
1076280304Sjkim{
1077280304Sjkim    va_list args;
1078280304Sjkim    va_start(args, num);
1079280304Sjkim    ERR_add_error_vdata(num, args);
1080280304Sjkim    va_end(args);
1081280304Sjkim}
1082238405Sjkim
1083238405Sjkimvoid ERR_add_error_vdata(int num, va_list args)
1084280304Sjkim{
1085280304Sjkim    int i, n, s;
1086280304Sjkim    char *str, *p, *a;
108755714Skris
1088280304Sjkim    s = 80;
1089280304Sjkim    str = OPENSSL_malloc(s + 1);
1090280304Sjkim    if (str == NULL)
1091280304Sjkim        return;
1092280304Sjkim    str[0] = '\0';
109355714Skris
1094280304Sjkim    n = 0;
1095280304Sjkim    for (i = 0; i < num; i++) {
1096280304Sjkim        a = va_arg(args, char *);
1097280304Sjkim        /* ignore NULLs, thanks to Bob Beck <beck@obtuse.com> */
1098280304Sjkim        if (a != NULL) {
1099280304Sjkim            n += strlen(a);
1100280304Sjkim            if (n > s) {
1101280304Sjkim                s = n + 20;
1102280304Sjkim                p = OPENSSL_realloc(str, s + 1);
1103280304Sjkim                if (p == NULL) {
1104280304Sjkim                    OPENSSL_free(str);
1105280304Sjkim                    return;
1106280304Sjkim                } else
1107280304Sjkim                    str = p;
1108280304Sjkim            }
1109280304Sjkim            BUF_strlcat(str, a, (size_t)s + 1);
1110280304Sjkim        }
1111280304Sjkim    }
1112280304Sjkim    ERR_set_error_data(str, ERR_TXT_MALLOCED | ERR_TXT_STRING);
1113280304Sjkim}
1114160814Ssimon
1115160814Ssimonint ERR_set_mark(void)
1116280304Sjkim{
1117280304Sjkim    ERR_STATE *es;
1118160814Ssimon
1119280304Sjkim    es = ERR_get_state();
1120160814Ssimon
1121280304Sjkim    if (es->bottom == es->top)
1122280304Sjkim        return 0;
1123280304Sjkim    es->err_flags[es->top] |= ERR_FLAG_MARK;
1124280304Sjkim    return 1;
1125280304Sjkim}
1126160814Ssimon
1127160814Ssimonint ERR_pop_to_mark(void)
1128280304Sjkim{
1129280304Sjkim    ERR_STATE *es;
1130160814Ssimon
1131280304Sjkim    es = ERR_get_state();
1132160814Ssimon
1133280304Sjkim    while (es->bottom != es->top
1134280304Sjkim           && (es->err_flags[es->top] & ERR_FLAG_MARK) == 0) {
1135280304Sjkim        err_clear(es, es->top);
1136280304Sjkim        es->top -= 1;
1137280304Sjkim        if (es->top == -1)
1138280304Sjkim            es->top = ERR_NUM_ERRORS - 1;
1139280304Sjkim    }
1140280304Sjkim
1141280304Sjkim    if (es->bottom == es->top)
1142280304Sjkim        return 0;
1143280304Sjkim    es->err_flags[es->top] &= ~ERR_FLAG_MARK;
1144280304Sjkim    return 1;
1145280304Sjkim}
1146