1193645Ssimon/* crypto/err/err_def.c */
2193645Ssimon/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3193645Ssimon * All rights reserved.
4193645Ssimon *
5193645Ssimon * This package is an SSL implementation written
6193645Ssimon * by Eric Young (eay@cryptsoft.com).
7193645Ssimon * The implementation was written so as to conform with Netscapes SSL.
8296465Sdelphij *
9193645Ssimon * This library is free for commercial and non-commercial use as long as
10193645Ssimon * the following conditions are aheared to.  The following conditions
11193645Ssimon * apply to all code found in this distribution, be it the RC4, RSA,
12193645Ssimon * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13193645Ssimon * included with this distribution is covered by the same copyright terms
14193645Ssimon * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15296465Sdelphij *
16193645Ssimon * Copyright remains Eric Young's, and as such any Copyright notices in
17193645Ssimon * the code are not to be removed.
18193645Ssimon * If this package is used in a product, Eric Young should be given attribution
19193645Ssimon * as the author of the parts of the library used.
20193645Ssimon * This can be in the form of a textual message at program startup or
21193645Ssimon * in documentation (online or textual) provided with the package.
22296465Sdelphij *
23193645Ssimon * Redistribution and use in source and binary forms, with or without
24193645Ssimon * modification, are permitted provided that the following conditions
25193645Ssimon * are met:
26193645Ssimon * 1. Redistributions of source code must retain the copyright
27193645Ssimon *    notice, this list of conditions and the following disclaimer.
28193645Ssimon * 2. Redistributions in binary form must reproduce the above copyright
29193645Ssimon *    notice, this list of conditions and the following disclaimer in the
30193645Ssimon *    documentation and/or other materials provided with the distribution.
31193645Ssimon * 3. All advertising materials mentioning features or use of this software
32193645Ssimon *    must display the following acknowledgement:
33193645Ssimon *    "This product includes cryptographic software written by
34193645Ssimon *     Eric Young (eay@cryptsoft.com)"
35193645Ssimon *    The word 'cryptographic' can be left out if the rouines from the library
36193645Ssimon *    being used are not cryptographic related :-).
37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from
38193645Ssimon *    the apps directory (application code) you must include an acknowledgement:
39193645Ssimon *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40296465Sdelphij *
41193645Ssimon * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42193645Ssimon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43193645Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44193645Ssimon * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45193645Ssimon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46193645Ssimon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47193645Ssimon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48193645Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49193645Ssimon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50193645Ssimon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51193645Ssimon * SUCH DAMAGE.
52296465Sdelphij *
53193645Ssimon * The licence and distribution terms for any publically available version or
54193645Ssimon * derivative of this code cannot be changed.  i.e. this code cannot simply be
55193645Ssimon * copied and put under another distribution licence
56193645Ssimon * [including the GNU Public Licence.]
57193645Ssimon */
58193645Ssimon/* ====================================================================
59193645Ssimon * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
60193645Ssimon *
61193645Ssimon * Redistribution and use in source and binary forms, with or without
62193645Ssimon * modification, are permitted provided that the following conditions
63193645Ssimon * are met:
64193645Ssimon *
65193645Ssimon * 1. Redistributions of source code must retain the above copyright
66296465Sdelphij *    notice, this list of conditions and the following disclaimer.
67193645Ssimon *
68193645Ssimon * 2. Redistributions in binary form must reproduce the above copyright
69193645Ssimon *    notice, this list of conditions and the following disclaimer in
70193645Ssimon *    the documentation and/or other materials provided with the
71193645Ssimon *    distribution.
72193645Ssimon *
73193645Ssimon * 3. All advertising materials mentioning features or use of this
74193645Ssimon *    software must display the following acknowledgment:
75193645Ssimon *    "This product includes software developed by the OpenSSL Project
76193645Ssimon *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
77193645Ssimon *
78193645Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
79193645Ssimon *    endorse or promote products derived from this software without
80193645Ssimon *    prior written permission. For written permission, please contact
81193645Ssimon *    openssl-core@openssl.org.
82193645Ssimon *
83193645Ssimon * 5. Products derived from this software may not be called "OpenSSL"
84193645Ssimon *    nor may "OpenSSL" appear in their names without prior written
85193645Ssimon *    permission of the OpenSSL Project.
86193645Ssimon *
87193645Ssimon * 6. Redistributions of any form whatsoever must retain the following
88193645Ssimon *    acknowledgment:
89193645Ssimon *    "This product includes software developed by the OpenSSL Project
90193645Ssimon *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
91193645Ssimon *
92193645Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
93193645Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94193645Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
95193645Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
96193645Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
97193645Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
98193645Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
99193645Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
100193645Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
101193645Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
102193645Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
103193645Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
104193645Ssimon * ====================================================================
105193645Ssimon *
106193645Ssimon * This product includes cryptographic software written by Eric Young
107193645Ssimon * (eay@cryptsoft.com).  This product includes software written by Tim
108193645Ssimon * Hudson (tjh@cryptsoft.com).
109193645Ssimon *
110193645Ssimon */
111193645Ssimon
112193645Ssimon#include <stdio.h>
113193645Ssimon#include <stdarg.h>
114193645Ssimon#include <string.h>
115193645Ssimon#include "cryptlib.h"
116193645Ssimon#include <openssl/lhash.h>
117193645Ssimon#include <openssl/crypto.h>
118193645Ssimon#include <openssl/buffer.h>
119193645Ssimon#include <openssl/bio.h>
120193645Ssimon#include <openssl/err.h>
121193645Ssimon
122193645Ssimon#define err_clear_data(p,i) \
123296465Sdelphij        do { \
124296465Sdelphij        if (((p)->err_data[i] != NULL) && \
125296465Sdelphij                (p)->err_data_flags[i] & ERR_TXT_MALLOCED) \
126296465Sdelphij                {  \
127296465Sdelphij                OPENSSL_free((p)->err_data[i]); \
128296465Sdelphij                (p)->err_data[i]=NULL; \
129296465Sdelphij                } \
130296465Sdelphij        (p)->err_data_flags[i]=0; \
131296465Sdelphij        } while(0)
132193645Ssimon
133193645Ssimon#define err_clear(p,i) \
134296465Sdelphij        do { \
135296465Sdelphij        (p)->err_flags[i]=0; \
136296465Sdelphij        (p)->err_buffer[i]=0; \
137296465Sdelphij        err_clear_data(p,i); \
138296465Sdelphij        (p)->err_file[i]=NULL; \
139296465Sdelphij        (p)->err_line[i]= -1; \
140296465Sdelphij        } while(0)
141193645Ssimon
142193645Ssimonstatic void err_load_strings(int lib, ERR_STRING_DATA *str);
143193645Ssimon
144193645Ssimonstatic void ERR_STATE_free(ERR_STATE *s);
145193645Ssimon
146193645Ssimon/* Define the predeclared (but externally opaque) "ERR_FNS" type */
147296465Sdelphijstruct st_ERR_FNS {
148296465Sdelphij    /* Works on the "error_hash" string table */
149296465Sdelphij    LHASH *(*cb_err_get) (int create);
150296465Sdelphij    void (*cb_err_del) (void);
151296465Sdelphij    ERR_STRING_DATA *(*cb_err_get_item) (const ERR_STRING_DATA *);
152296465Sdelphij    ERR_STRING_DATA *(*cb_err_set_item) (ERR_STRING_DATA *);
153296465Sdelphij    ERR_STRING_DATA *(*cb_err_del_item) (ERR_STRING_DATA *);
154296465Sdelphij    /* Works on the "thread_hash" error-state table */
155296465Sdelphij    LHASH *(*cb_thread_get) (int create);
156296465Sdelphij    void (*cb_thread_release) (LHASH **hash);
157296465Sdelphij    ERR_STATE *(*cb_thread_get_item) (const ERR_STATE *);
158296465Sdelphij    ERR_STATE *(*cb_thread_set_item) (ERR_STATE *);
159296465Sdelphij    void (*cb_thread_del_item) (const ERR_STATE *);
160296465Sdelphij    /* Returns the next available error "library" numbers */
161296465Sdelphij    int (*cb_get_next_lib) (void);
162296465Sdelphij};
163193645Ssimon
164193645Ssimon/* Predeclarations of the "err_defaults" functions */
165193645Ssimonstatic LHASH *int_err_get(int create);
166193645Ssimonstatic void int_err_del(void);
167193645Ssimonstatic ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *);
168193645Ssimonstatic ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *);
169193645Ssimonstatic ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *);
170193645Ssimonstatic LHASH *int_thread_get(int create);
171193645Ssimonstatic void int_thread_release(LHASH **hash);
172193645Ssimonstatic ERR_STATE *int_thread_get_item(const ERR_STATE *);
173193645Ssimonstatic ERR_STATE *int_thread_set_item(ERR_STATE *);
174193645Ssimonstatic void int_thread_del_item(const ERR_STATE *);
175193645Ssimonstatic int int_err_get_next_lib(void);
176193645Ssimon/* The static ERR_FNS table using these defaults functions */
177296465Sdelphijstatic const ERR_FNS err_defaults = {
178296465Sdelphij    int_err_get,
179296465Sdelphij    int_err_del,
180296465Sdelphij    int_err_get_item,
181296465Sdelphij    int_err_set_item,
182296465Sdelphij    int_err_del_item,
183296465Sdelphij    int_thread_get,
184296465Sdelphij    int_thread_release,
185296465Sdelphij    int_thread_get_item,
186296465Sdelphij    int_thread_set_item,
187296465Sdelphij    int_thread_del_item,
188296465Sdelphij    int_err_get_next_lib
189296465Sdelphij};
190193645Ssimon
191193645Ssimon/* The replacable table of ERR_FNS functions we use at run-time */
192193645Ssimonstatic const ERR_FNS *err_fns = NULL;
193193645Ssimon
194193645Ssimon/* Eg. rather than using "err_get()", use "ERRFN(err_get)()". */
195193645Ssimon#define ERRFN(a) err_fns->cb_##a
196193645Ssimon
197296465Sdelphij/*
198296465Sdelphij * The internal state used by "err_defaults" - as such, the setting, reading,
199193645Ssimon * creating, and deleting of this data should only be permitted via the
200296465Sdelphij * "err_defaults" functions. This way, a linked module can completely defer
201296465Sdelphij * all ERR state operation (together with requisite locking) to the
202296465Sdelphij * implementations and state in the loading application.
203296465Sdelphij */
204193645Ssimonstatic LHASH *int_error_hash = NULL;
205193645Ssimonstatic LHASH *int_thread_hash = NULL;
206193645Ssimonstatic int int_thread_hash_references = 0;
207296465Sdelphijstatic int int_err_library_number = ERR_LIB_USER;
208193645Ssimon
209296465Sdelphij/*
210296465Sdelphij * Internal function that checks whether "err_fns" is set and if not, sets it
211296465Sdelphij * to the defaults.
212296465Sdelphij */
213193645Ssimonstatic void err_fns_check(void)
214296465Sdelphij{
215296465Sdelphij    if (err_fns)
216296465Sdelphij        return;
217193645Ssimon
218296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
219296465Sdelphij    if (!err_fns)
220296465Sdelphij        err_fns = &err_defaults;
221296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
222296465Sdelphij}
223296465Sdelphij
224193645Ssimon/* API functions to get or set the underlying ERR functions. */
225193645Ssimon
226193645Ssimonconst ERR_FNS *ERR_get_implementation(void)
227296465Sdelphij{
228296465Sdelphij    err_fns_check();
229296465Sdelphij    return err_fns;
230296465Sdelphij}
231193645Ssimon
232193645Ssimonint ERR_set_implementation(const ERR_FNS *fns)
233296465Sdelphij{
234296465Sdelphij    int ret = 0;
235193645Ssimon
236296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
237296465Sdelphij    /*
238296465Sdelphij     * It's too late if 'err_fns' is non-NULL. BTW: not much point setting an
239296465Sdelphij     * error is there?!
240296465Sdelphij     */
241296465Sdelphij    if (!err_fns) {
242296465Sdelphij        err_fns = fns;
243296465Sdelphij        ret = 1;
244296465Sdelphij    }
245296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
246296465Sdelphij    return ret;
247296465Sdelphij}
248193645Ssimon
249296465Sdelphij/*
250296465Sdelphij * These are the callbacks provided to "lh_new()" when creating the LHASH
251296465Sdelphij * tables internal to the "err_defaults" implementation.
252296465Sdelphij */
253193645Ssimon
254193645Ssimon/* static unsigned long err_hash(ERR_STRING_DATA *a); */
255193645Ssimonstatic unsigned long err_hash(const void *a_void);
256193645Ssimon/* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b); */
257193645Ssimonstatic int err_cmp(const void *a_void, const void *b_void);
258193645Ssimon/* static unsigned long pid_hash(ERR_STATE *pid); */
259193645Ssimonstatic unsigned long pid_hash(const void *pid_void);
260193645Ssimon/* static int pid_cmp(ERR_STATE *a,ERR_STATE *pid); */
261296465Sdelphijstatic int pid_cmp(const void *a_void, const void *pid_void);
262193645Ssimon
263193645Ssimon/* The internal functions used in the "err_defaults" implementation */
264193645Ssimon
265193645Ssimonstatic LHASH *int_err_get(int create)
266296465Sdelphij{
267296465Sdelphij    LHASH *ret = NULL;
268193645Ssimon
269296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
270296465Sdelphij    if (!int_error_hash && create) {
271296465Sdelphij        CRYPTO_push_info("int_err_get (err.c)");
272296465Sdelphij        int_error_hash = lh_new(err_hash, err_cmp);
273296465Sdelphij        CRYPTO_pop_info();
274296465Sdelphij    }
275296465Sdelphij    if (int_error_hash)
276296465Sdelphij        ret = int_error_hash;
277296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
278193645Ssimon
279296465Sdelphij    return ret;
280296465Sdelphij}
281193645Ssimon
282193645Ssimonstatic void int_err_del(void)
283296465Sdelphij{
284296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
285296465Sdelphij    if (int_error_hash) {
286296465Sdelphij        lh_free(int_error_hash);
287296465Sdelphij        int_error_hash = NULL;
288296465Sdelphij    }
289296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
290296465Sdelphij}
291193645Ssimon
292193645Ssimonstatic ERR_STRING_DATA *int_err_get_item(const ERR_STRING_DATA *d)
293296465Sdelphij{
294296465Sdelphij    ERR_STRING_DATA *p;
295296465Sdelphij    LHASH *hash;
296193645Ssimon
297296465Sdelphij    err_fns_check();
298296465Sdelphij    hash = ERRFN(err_get) (0);
299296465Sdelphij    if (!hash)
300296465Sdelphij        return NULL;
301193645Ssimon
302296465Sdelphij    CRYPTO_r_lock(CRYPTO_LOCK_ERR);
303296465Sdelphij    p = (ERR_STRING_DATA *)lh_retrieve(hash, d);
304296465Sdelphij    CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
305193645Ssimon
306296465Sdelphij    return p;
307296465Sdelphij}
308193645Ssimon
309193645Ssimonstatic ERR_STRING_DATA *int_err_set_item(ERR_STRING_DATA *d)
310296465Sdelphij{
311296465Sdelphij    ERR_STRING_DATA *p;
312296465Sdelphij    LHASH *hash;
313193645Ssimon
314296465Sdelphij    err_fns_check();
315296465Sdelphij    hash = ERRFN(err_get) (1);
316296465Sdelphij    if (!hash)
317296465Sdelphij        return NULL;
318193645Ssimon
319296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
320296465Sdelphij    p = (ERR_STRING_DATA *)lh_insert(hash, d);
321296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
322193645Ssimon
323296465Sdelphij    return p;
324296465Sdelphij}
325193645Ssimon
326193645Ssimonstatic ERR_STRING_DATA *int_err_del_item(ERR_STRING_DATA *d)
327296465Sdelphij{
328296465Sdelphij    ERR_STRING_DATA *p;
329296465Sdelphij    LHASH *hash;
330193645Ssimon
331296465Sdelphij    err_fns_check();
332296465Sdelphij    hash = ERRFN(err_get) (0);
333296465Sdelphij    if (!hash)
334296465Sdelphij        return NULL;
335193645Ssimon
336296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
337296465Sdelphij    p = (ERR_STRING_DATA *)lh_delete(hash, d);
338296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
339193645Ssimon
340296465Sdelphij    return p;
341296465Sdelphij}
342193645Ssimon
343193645Ssimonstatic LHASH *int_thread_get(int create)
344296465Sdelphij{
345296465Sdelphij    LHASH *ret = NULL;
346193645Ssimon
347296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
348296465Sdelphij    if (!int_thread_hash && create) {
349296465Sdelphij        CRYPTO_push_info("int_thread_get (err.c)");
350296465Sdelphij        int_thread_hash = lh_new(pid_hash, pid_cmp);
351296465Sdelphij        CRYPTO_pop_info();
352296465Sdelphij    }
353296465Sdelphij    if (int_thread_hash) {
354296465Sdelphij        int_thread_hash_references++;
355296465Sdelphij        ret = int_thread_hash;
356296465Sdelphij    }
357296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
358296465Sdelphij    return ret;
359296465Sdelphij}
360193645Ssimon
361193645Ssimonstatic void int_thread_release(LHASH **hash)
362296465Sdelphij{
363296465Sdelphij    int i;
364193645Ssimon
365296465Sdelphij    if (hash == NULL || *hash == NULL)
366296465Sdelphij        return;
367193645Ssimon
368296465Sdelphij    i = CRYPTO_add(&int_thread_hash_references, -1, CRYPTO_LOCK_ERR);
369193645Ssimon
370193645Ssimon#ifdef REF_PRINT
371296465Sdelphij    fprintf(stderr, "%4d:%s\n", int_thread_hash_references, "ERR");
372193645Ssimon#endif
373296465Sdelphij    if (i > 0)
374296465Sdelphij        return;
375193645Ssimon#ifdef REF_CHECK
376296465Sdelphij    if (i < 0) {
377296465Sdelphij        fprintf(stderr, "int_thread_release, bad reference count\n");
378296465Sdelphij        abort();                /* ok */
379296465Sdelphij    }
380193645Ssimon#endif
381296465Sdelphij    *hash = NULL;
382296465Sdelphij}
383193645Ssimon
384193645Ssimonstatic ERR_STATE *int_thread_get_item(const ERR_STATE *d)
385296465Sdelphij{
386296465Sdelphij    ERR_STATE *p;
387296465Sdelphij    LHASH *hash;
388193645Ssimon
389296465Sdelphij    err_fns_check();
390296465Sdelphij    hash = ERRFN(thread_get) (0);
391296465Sdelphij    if (!hash)
392296465Sdelphij        return NULL;
393193645Ssimon
394296465Sdelphij    CRYPTO_r_lock(CRYPTO_LOCK_ERR);
395296465Sdelphij    p = (ERR_STATE *)lh_retrieve(hash, d);
396296465Sdelphij    CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
397193645Ssimon
398296465Sdelphij    ERRFN(thread_release) (&hash);
399296465Sdelphij    return p;
400296465Sdelphij}
401193645Ssimon
402193645Ssimonstatic ERR_STATE *int_thread_set_item(ERR_STATE *d)
403296465Sdelphij{
404296465Sdelphij    ERR_STATE *p;
405296465Sdelphij    LHASH *hash;
406193645Ssimon
407296465Sdelphij    err_fns_check();
408296465Sdelphij    hash = ERRFN(thread_get) (1);
409296465Sdelphij    if (!hash)
410296465Sdelphij        return NULL;
411193645Ssimon
412296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
413296465Sdelphij    p = (ERR_STATE *)lh_insert(hash, d);
414296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
415193645Ssimon
416296465Sdelphij    ERRFN(thread_release) (&hash);
417296465Sdelphij    return p;
418296465Sdelphij}
419193645Ssimon
420193645Ssimonstatic void int_thread_del_item(const ERR_STATE *d)
421296465Sdelphij{
422296465Sdelphij    ERR_STATE *p;
423296465Sdelphij    LHASH *hash;
424193645Ssimon
425296465Sdelphij    err_fns_check();
426296465Sdelphij    hash = ERRFN(thread_get) (0);
427296465Sdelphij    if (!hash)
428296465Sdelphij        return;
429193645Ssimon
430296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
431296465Sdelphij    p = (ERR_STATE *)lh_delete(hash, d);
432296465Sdelphij    /* make sure we don't leak memory */
433296465Sdelphij    if (int_thread_hash_references == 1
434296465Sdelphij        && int_thread_hash && (lh_num_items(int_thread_hash) == 0)) {
435296465Sdelphij        lh_free(int_thread_hash);
436296465Sdelphij        int_thread_hash = NULL;
437296465Sdelphij    }
438296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
439193645Ssimon
440296465Sdelphij    ERRFN(thread_release) (&hash);
441296465Sdelphij    if (p)
442296465Sdelphij        ERR_STATE_free(p);
443296465Sdelphij}
444193645Ssimon
445193645Ssimonstatic int int_err_get_next_lib(void)
446296465Sdelphij{
447296465Sdelphij    int ret;
448193645Ssimon
449296465Sdelphij    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
450296465Sdelphij    ret = int_err_library_number++;
451296465Sdelphij    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
452193645Ssimon
453296465Sdelphij    return ret;
454296465Sdelphij}
455193645Ssimon
456193645Ssimonstatic void ERR_STATE_free(ERR_STATE *s)
457296465Sdelphij{
458296465Sdelphij    int i;
459193645Ssimon
460296465Sdelphij    if (s == NULL)
461296465Sdelphij        return;
462193645Ssimon
463296465Sdelphij    for (i = 0; i < ERR_NUM_ERRORS; i++) {
464296465Sdelphij        err_clear_data(s, i);
465296465Sdelphij    }
466296465Sdelphij    OPENSSL_free(s);
467296465Sdelphij}
468193645Ssimon
469193645Ssimonstatic void err_load_strings(int lib, ERR_STRING_DATA *str)
470296465Sdelphij{
471296465Sdelphij    while (str->error) {
472296465Sdelphij        if (lib)
473296465Sdelphij            str->error |= ERR_PACK(lib, 0, 0);
474296465Sdelphij        ERRFN(err_set_item) (str);
475296465Sdelphij        str++;
476296465Sdelphij    }
477296465Sdelphij}
478193645Ssimon
479193645Ssimonvoid ERR_load_strings(int lib, ERR_STRING_DATA *str)
480296465Sdelphij{
481296465Sdelphij    err_fns_check();
482296465Sdelphij    err_load_strings(lib, str);
483296465Sdelphij}
484193645Ssimon
485193645Ssimonvoid ERR_unload_strings(int lib, ERR_STRING_DATA *str)
486296465Sdelphij{
487296465Sdelphij    while (str->error) {
488296465Sdelphij        if (lib)
489296465Sdelphij            str->error |= ERR_PACK(lib, 0, 0);
490296465Sdelphij        ERRFN(err_del_item) (str);
491296465Sdelphij        str++;
492296465Sdelphij    }
493296465Sdelphij}
494193645Ssimon
495193645Ssimonvoid ERR_free_strings(void)
496296465Sdelphij{
497296465Sdelphij    err_fns_check();
498296465Sdelphij    ERRFN(err_del) ();
499296465Sdelphij}
500193645Ssimon
501193645SsimonLHASH *ERR_get_string_table(void)
502296465Sdelphij{
503296465Sdelphij    err_fns_check();
504296465Sdelphij    return ERRFN(err_get) (0);
505296465Sdelphij}
506193645Ssimon
507193645SsimonLHASH *ERR_get_err_state_table(void)
508296465Sdelphij{
509296465Sdelphij    err_fns_check();
510296465Sdelphij    return ERRFN(thread_get) (0);
511296465Sdelphij}
512193645Ssimon
513193645Ssimonvoid ERR_release_err_state_table(LHASH **hash)
514296465Sdelphij{
515296465Sdelphij    err_fns_check();
516296465Sdelphij    ERRFN(thread_release) (hash);
517296465Sdelphij}
518193645Ssimon
519193645Ssimonconst char *ERR_lib_error_string(unsigned long e)
520296465Sdelphij{
521296465Sdelphij    ERR_STRING_DATA d, *p;
522296465Sdelphij    unsigned long l;
523193645Ssimon
524296465Sdelphij    err_fns_check();
525296465Sdelphij    l = ERR_GET_LIB(e);
526296465Sdelphij    d.error = ERR_PACK(l, 0, 0);
527296465Sdelphij    p = ERRFN(err_get_item) (&d);
528296465Sdelphij    return ((p == NULL) ? NULL : p->string);
529296465Sdelphij}
530193645Ssimon
531193645Ssimonconst char *ERR_func_error_string(unsigned long e)
532296465Sdelphij{
533296465Sdelphij    ERR_STRING_DATA d, *p;
534296465Sdelphij    unsigned long l, f;
535193645Ssimon
536296465Sdelphij    err_fns_check();
537296465Sdelphij    l = ERR_GET_LIB(e);
538296465Sdelphij    f = ERR_GET_FUNC(e);
539296465Sdelphij    d.error = ERR_PACK(l, f, 0);
540296465Sdelphij    p = ERRFN(err_get_item) (&d);
541296465Sdelphij    return ((p == NULL) ? NULL : p->string);
542296465Sdelphij}
543193645Ssimon
544193645Ssimonconst char *ERR_reason_error_string(unsigned long e)
545296465Sdelphij{
546296465Sdelphij    ERR_STRING_DATA d, *p = NULL;
547296465Sdelphij    unsigned long l, r;
548193645Ssimon
549296465Sdelphij    err_fns_check();
550296465Sdelphij    l = ERR_GET_LIB(e);
551296465Sdelphij    r = ERR_GET_REASON(e);
552296465Sdelphij    d.error = ERR_PACK(l, 0, r);
553296465Sdelphij    p = ERRFN(err_get_item) (&d);
554296465Sdelphij    if (!p) {
555296465Sdelphij        d.error = ERR_PACK(0, 0, r);
556296465Sdelphij        p = ERRFN(err_get_item) (&d);
557296465Sdelphij    }
558296465Sdelphij    return ((p == NULL) ? NULL : p->string);
559296465Sdelphij}
560193645Ssimon
561193645Ssimon/* static unsigned long err_hash(ERR_STRING_DATA *a) */
562193645Ssimonstatic unsigned long err_hash(const void *a_void)
563296465Sdelphij{
564296465Sdelphij    unsigned long ret, l;
565193645Ssimon
566296465Sdelphij    l = ((const ERR_STRING_DATA *)a_void)->error;
567296465Sdelphij    ret = l ^ ERR_GET_LIB(l) ^ ERR_GET_FUNC(l);
568296465Sdelphij    return (ret ^ ret % 19 * 13);
569296465Sdelphij}
570193645Ssimon
571193645Ssimon/* static int err_cmp(ERR_STRING_DATA *a, ERR_STRING_DATA *b) */
572193645Ssimonstatic int err_cmp(const void *a_void, const void *b_void)
573296465Sdelphij{
574296465Sdelphij    return ((int)(((const ERR_STRING_DATA *)a_void)->error -
575296465Sdelphij                  ((const ERR_STRING_DATA *)b_void)->error));
576296465Sdelphij}
577193645Ssimon
578193645Ssimon/* static unsigned long pid_hash(ERR_STATE *a) */
579193645Ssimonstatic unsigned long pid_hash(const void *a_void)
580296465Sdelphij{
581296465Sdelphij    return (((const ERR_STATE *)a_void)->pid * 13);
582296465Sdelphij}
583193645Ssimon
584193645Ssimon/* static int pid_cmp(ERR_STATE *a, ERR_STATE *b) */
585193645Ssimonstatic int pid_cmp(const void *a_void, const void *b_void)
586296465Sdelphij{
587296465Sdelphij    return ((int)((long)((const ERR_STATE *)a_void)->pid -
588296465Sdelphij                  (long)((const ERR_STATE *)b_void)->pid));
589296465Sdelphij}
590296465Sdelphij
591193645Ssimon#ifdef OPENSSL_FIPS
592193645Ssimonstatic void int_err_remove_state(unsigned long pid)
593193645Ssimon#else
594193645Ssimonvoid ERR_remove_state(unsigned long pid)
595193645Ssimon#endif
596296465Sdelphij{
597296465Sdelphij    ERR_STATE tmp;
598193645Ssimon
599296465Sdelphij    err_fns_check();
600296465Sdelphij    if (pid == 0)
601296465Sdelphij        pid = (unsigned long)CRYPTO_thread_id();
602296465Sdelphij    tmp.pid = pid;
603296465Sdelphij    /*
604296465Sdelphij     * thread_del_item automatically destroys the LHASH if the number of
605296465Sdelphij     * items reaches zero.
606296465Sdelphij     */
607296465Sdelphij    ERRFN(thread_del_item) (&tmp);
608296465Sdelphij}
609193645Ssimon
610193645Ssimon#ifdef OPENSSL_FIPS
611296465Sdelphijstatic ERR_STATE *int_err_get_state(void)
612193645Ssimon#else
613193645SsimonERR_STATE *ERR_get_state(void)
614193645Ssimon#endif
615296465Sdelphij{
616296465Sdelphij    static ERR_STATE fallback;
617296465Sdelphij    ERR_STATE *ret, tmp, *tmpp = NULL;
618296465Sdelphij    int i;
619296465Sdelphij    unsigned long pid;
620193645Ssimon
621296465Sdelphij    err_fns_check();
622296465Sdelphij    pid = (unsigned long)CRYPTO_thread_id();
623296465Sdelphij    tmp.pid = pid;
624296465Sdelphij    ret = ERRFN(thread_get_item) (&tmp);
625193645Ssimon
626296465Sdelphij    /* ret == the error state, if NULL, make a new one */
627296465Sdelphij    if (ret == NULL) {
628296465Sdelphij        ret = (ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE));
629296465Sdelphij        if (ret == NULL)
630296465Sdelphij            return (&fallback);
631296465Sdelphij        ret->pid = pid;
632296465Sdelphij        ret->top = 0;
633296465Sdelphij        ret->bottom = 0;
634296465Sdelphij        for (i = 0; i < ERR_NUM_ERRORS; i++) {
635296465Sdelphij            ret->err_data[i] = NULL;
636296465Sdelphij            ret->err_data_flags[i] = 0;
637296465Sdelphij        }
638296465Sdelphij        tmpp = ERRFN(thread_set_item) (ret);
639296465Sdelphij        /* To check if insertion failed, do a get. */
640296465Sdelphij        if (ERRFN(thread_get_item) (ret) != ret) {
641296465Sdelphij            ERR_STATE_free(ret); /* could not insert it */
642296465Sdelphij            return (&fallback);
643296465Sdelphij        }
644296465Sdelphij        /*
645296465Sdelphij         * If a race occured in this function and we came second, tmpp is the
646296465Sdelphij         * first one that we just replaced.
647296465Sdelphij         */
648296465Sdelphij        if (tmpp)
649296465Sdelphij            ERR_STATE_free(tmpp);
650296465Sdelphij    }
651296465Sdelphij    return ret;
652296465Sdelphij}
653193645Ssimon
654193645Ssimon#ifdef OPENSSL_FIPS
655193645Ssimonvoid int_ERR_lib_init(void)
656296465Sdelphij{
657296465Sdelphij    int_ERR_set_state_func(int_err_get_state, int_err_remove_state);
658296465Sdelphij}
659193645Ssimon#endif
660193645Ssimon
661193645Ssimonint ERR_get_next_error_library(void)
662296465Sdelphij{
663296465Sdelphij    err_fns_check();
664296465Sdelphij    return ERRFN(get_next_lib) ();
665296465Sdelphij}
666