195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * All rights reserved.
395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * This package is an SSL implementation written
595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * by Eric Young (eay@cryptsoft.com).
695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * The implementation was written so as to conform with Netscapes SSL.
795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * This library is free for commercial and non-commercial use as long as
995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * the following conditions are aheared to.  The following conditions
1095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * apply to all code found in this distribution, be it the RC4, RSA,
1195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * included with this distribution is covered by the same copyright terms
1395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
1595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Copyright remains Eric Young's, and as such any Copyright notices in
1695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * the code are not to be removed.
1795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * If this package is used in a product, Eric Young should be given attribution
1895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * as the author of the parts of the library used.
1995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * This can be in the form of a textual message at program startup or
2095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * in documentation (online or textual) provided with the package.
2195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
2295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Redistribution and use in source and binary forms, with or without
2395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * modification, are permitted provided that the following conditions
2495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * are met:
2595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 1. Redistributions of source code must retain the copyright
2695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    notice, this list of conditions and the following disclaimer.
2795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 2. Redistributions in binary form must reproduce the above copyright
2895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    notice, this list of conditions and the following disclaimer in the
2995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    documentation and/or other materials provided with the distribution.
3095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 3. All advertising materials mentioning features or use of this software
3195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    must display the following acknowledgement:
3295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    "This product includes cryptographic software written by
3395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *     Eric Young (eay@cryptsoft.com)"
3495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    The word 'cryptographic' can be left out if the rouines from the library
3595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    being used are not cryptographic related :-).
3695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 4. If you include any Windows specific code (or a derivative thereof) from
3795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    the apps directory (application code) you must include an acknowledgement:
3895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
3995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
4095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * SUCH DAMAGE.
5195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
5295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * The licence and distribution terms for any publically available version or
5395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * derivative of this code cannot be changed.  i.e. this code cannot simply be
5495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * copied and put under another distribution licence
5595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * [including the GNU Public Licence.]
5695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley */
5795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* ====================================================================
5895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Copyright (c) 1998-2006 The OpenSSL Project.  All rights reserved.
5995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
6095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Redistribution and use in source and binary forms, with or without
6195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * modification, are permitted provided that the following conditions
6295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * are met:
6395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
6495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 1. Redistributions of source code must retain the above copyright
6595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    notice, this list of conditions and the following disclaimer.
6695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
6795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 2. Redistributions in binary form must reproduce the above copyright
6895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    notice, this list of conditions and the following disclaimer in
6995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    the documentation and/or other materials provided with the
7095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    distribution.
7195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
7295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 3. All advertising materials mentioning features or use of this
7395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    software must display the following acknowledgment:
7495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    "This product includes software developed by the OpenSSL Project
7595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
7695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
7795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
7895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    endorse or promote products derived from this software without
7995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    prior written permission. For written permission, please contact
8095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    openssl-core@openssl.org.
8195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
8295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 5. Products derived from this software may not be called "OpenSSL"
8395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    nor may "OpenSSL" appear in their names without prior written
8495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    permission of the OpenSSL Project.
8595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
8695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * 6. Redistributions of any form whatsoever must retain the following
8795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    acknowledgment:
8895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    "This product includes software developed by the OpenSSL Project
8995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
9095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
9195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
9295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
9395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
9495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
9595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
9795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
9895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
10095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
10195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
10295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * OF THE POSSIBILITY OF SUCH DAMAGE.
10395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * ====================================================================
10495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley *
10595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * This product includes cryptographic software written by Eric Young
10695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * (eay@cryptsoft.com).  This product includes software written by Tim
10795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * Hudson (tjh@cryptsoft.com). */
10895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
10995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/err.h>
11095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <assert.h>
11295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/lhash.h>
11495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <openssl/mem.h>
11595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11795c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyDEFINE_LHASH_OF(ERR_STATE);
11895c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyDEFINE_LHASH_OF(ERR_STRING_DATA);
11995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
12095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* state_hash is a map from thread ID to ERR_STATE. It works like thread-local
12195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * storage. */
12295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic LHASH_OF(ERR_STATE) *state_hash = NULL;
12395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
12495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* error_hash maps from a packed error to the string for that library /
12595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * function / reason. */
12695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic LHASH_OF(ERR_STRING_DATA) *error_hash = NULL;
12795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
1284042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley/* global_next_library contains the next custom library value to return. */
1294042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langleystatic int global_next_library = ERR_NUM_LIBS;
1304042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley
13195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* err_string_data_hash is an lhash hash function for ERR_STRING_DATA. */
13295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic uint32_t err_string_data_hash(const ERR_STRING_DATA *a) {
13395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return OPENSSL_hash32(&a->error, sizeof(a->error));
13495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
13595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
13695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* err_string_data_cmp is an lhash compare function for ERR_STRING_DATA. */
13795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int err_string_data_cmp(const ERR_STRING_DATA *a,
13895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                               const ERR_STRING_DATA *b) {
13995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return ((int)a->error) - ((int)b->error);
14095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
14195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
14295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* error_hash_get_write_locked returns the hash that maps from packed error to
14395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * error string and creates it if need be. The caller must hold a write lock on
14495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * LOCK_ERR. */
14595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic LHASH_OF(ERR_STRING_DATA) * error_hash_get_write_locked(void) {
14695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!error_hash) {
14795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    error_hash = lh_ERR_STRING_DATA_new(err_string_data_hash, err_string_data_cmp);
14895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
14995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
15095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return error_hash;
15195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
15295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
15395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* err_get_item returns an ERR_STRING_DATA with an |error| member that
15495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * equals |packed_error|, or NULL if none can be found. */
15595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic ERR_STRING_DATA *err_get_item(uint32_t packed_error) {
15695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ERR_STRING_DATA *ret = NULL, pattern;
15795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
15895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pattern.error = packed_error;
15995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
16095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_r_lock(CRYPTO_LOCK_ERR);
16195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (error_hash) {
16295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    ret = lh_ERR_STRING_DATA_retrieve(error_hash, &pattern);
16395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
16495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
16595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
16695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return ret;
16795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
16895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
16995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* err_set_item adds an ERR_STRING_DATA to the global hash of error strings and
17095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * returns the previous entry with the same |err->error| value, if any. */
17195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic ERR_STRING_DATA *err_set_item(const ERR_STRING_DATA *err) {
17295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ERR_STRING_DATA *old_item = NULL;
17395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  LHASH_OF(ERR_STRING_DATA) *hash;
17495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
17595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_w_lock(CRYPTO_LOCK_ERR);
17695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  hash = error_hash_get_write_locked();
17795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (hash) {
17895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    lh_ERR_STRING_DATA_insert(hash, &old_item, (ERR_STRING_DATA*) err);
17995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
18095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
18195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
18295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return old_item;
18395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
18495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
18595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* err_set_item removes an item from the global hash of error strings for
18695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley * |packed_error| and returns the removed entry, if any. */
18795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic ERR_STRING_DATA *err_del_item(uint32_t packed_error) {
18895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ERR_STRING_DATA *old_item = NULL, pattern;
18995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  pattern.error = packed_error;
19195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_w_lock(CRYPTO_LOCK_ERR);
19395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (error_hash) {
19495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    old_item = lh_ERR_STRING_DATA_delete(error_hash, &pattern);
19595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
19695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
19795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return old_item;
19995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
20095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* err_state_hash is an lhash hash function for ERR_STATE. */
20395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic uint32_t err_state_hash(const ERR_STATE *a) {
20495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return CRYPTO_THREADID_hash(&a->tid);
20595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
20695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley/* err_state_cmp is an lhash compare function for ERR_STATE. */
20895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic int err_state_cmp(const ERR_STATE *a, const ERR_STATE *b) {
20995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return CRYPTO_THREADID_cmp(&a->tid, &b->tid);
21095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
21195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic ERR_STATE *err_get_state(void) {
21495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_THREADID tid;
21595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ERR_STATE pattern, *state, *race_state;
21695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int insert_result;
21795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  static ERR_STATE fallback;
21895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_THREADID_current(&tid);
22095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  memset(&pattern, 0, sizeof(pattern));
22195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_THREADID_cpy(&pattern.tid, &tid);
22295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_r_lock(CRYPTO_LOCK_ERR);
22495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (state_hash == NULL) {
22595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
22695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    CRYPTO_w_lock(CRYPTO_LOCK_ERR);
22795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (state_hash == NULL) {
22895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      state_hash = lh_ERR_STATE_new(err_state_hash, err_state_cmp);
22995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
23095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
23195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    CRYPTO_r_lock(CRYPTO_LOCK_ERR);
23295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
23395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  state = lh_ERR_STATE_retrieve(state_hash, &pattern);
23595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
23695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (state != NULL) {
23795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return state;
23895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
23995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  state = OPENSSL_malloc(sizeof(ERR_STATE));
24195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (state == NULL) {
24295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
24395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    /* The other error functions don't cope with a failure to get the error
24495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley     * state, so we return a dummy value. */
24595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return &fallback;
24695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
24795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  memset(state, 0, sizeof(ERR_STATE));
24995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_THREADID_cpy(&state->tid, &tid);
25095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_w_lock(CRYPTO_LOCK_ERR);
25295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  insert_result = lh_ERR_STATE_insert(state_hash, &race_state, state);
25395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
25495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (!insert_result) {
25695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    /* Insertion failed because of malloc failure. */
25795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    OPENSSL_free(state);
25895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return &fallback;
25995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
26095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
26195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  /* We cannot have raced with another thread to insert an ERR_STATE because no
26295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley   * other thread should be inserting values for this thread. */
26395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  assert(race_state == NULL);
26495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
26595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  return state;
26695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
26795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
26803d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langleystatic ERR_STATE *err_release_state(const CRYPTO_THREADID *tid) {
26903d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley  ERR_STATE pattern, *state;
27003d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley
27103d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley  CRYPTO_THREADID_cpy(&pattern.tid, tid);
27203d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley
27303d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley  CRYPTO_r_lock(CRYPTO_LOCK_ERR);
27403d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley  if (state_hash == NULL) {
27503d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley    CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
27603d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley    return NULL;
27703d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley  }
27803d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley
27903d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley  state = lh_ERR_STATE_delete(state_hash, &pattern);
28003d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley  CRYPTO_r_unlock(CRYPTO_LOCK_ERR);
28103d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley
28203d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley  return state;
28303d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley}
28403d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley
28595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleystatic void err_shutdown(void) {
28695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_w_lock(CRYPTO_LOCK_ERR);
28795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  if (error_hash) {
28895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    lh_ERR_STRING_DATA_free(error_hash);
28995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    error_hash = NULL;
29095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
29195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
29295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
29395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
2944042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langleystatic int err_get_next_library(void) {
2954042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley  int ret;
2964042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley
2974042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley  CRYPTO_w_lock(CRYPTO_LOCK_ERR);
2984042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley  ret = global_next_library++;
2994042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley  CRYPTO_w_unlock(CRYPTO_LOCK_ERR);
3004042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley
3014042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley  return ret;
3024042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley}
3034042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley
30495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyconst struct ERR_FNS_st openssl_err_default_impl = {
30595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  err_shutdown,
30695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  err_get_item,
30795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  err_set_item,
30895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  err_del_item,
30995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  err_get_state,
31003d31ed3e49a71e9ea09232d817cb1200b7a9149Adam Langley  err_release_state,
3114042667eb90b5619e6ba2d8f6f407cb55f71c05aAdam Langley  err_get_next_library,
31295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
313