os/ossrv/ssl/libcrypto/src/crypto/ex_data.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/ssl/libcrypto/src/crypto/ex_data.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,669 @@
     1.4 +/* crypto/ex_data.c */
     1.5 +
     1.6 +/*
     1.7 + * Overhaul notes;
     1.8 + *
     1.9 + * This code is now *mostly* thread-safe. It is now easier to understand in what
    1.10 + * ways it is safe and in what ways it is not, which is an improvement. Firstly,
    1.11 + * all per-class stacks and index-counters for ex_data are stored in the same
    1.12 + * global LHASH table (keyed by class). This hash table uses locking for all
    1.13 + * access with the exception of CRYPTO_cleanup_all_ex_data(), which must only be
    1.14 + * called when no other threads can possibly race against it (even if it was
    1.15 + * locked, the race would mean it's possible the hash table might have been
    1.16 + * recreated after the cleanup). As classes can only be added to the hash table,
    1.17 + * and within each class, the stack of methods can only be incremented, the
    1.18 + * locking mechanics are simpler than they would otherwise be. For example, the
    1.19 + * new/dup/free ex_data functions will lock the hash table, copy the method
    1.20 + * pointers it needs from the relevant class, then unlock the hash table before
    1.21 + * actually applying those method pointers to the task of the new/dup/free
    1.22 + * operations. As they can't be removed from the method-stack, only
    1.23 + * supplemented, there's no race conditions associated with using them outside
    1.24 + * the lock. The get/set_ex_data functions are not locked because they do not
    1.25 + * involve this global state at all - they operate directly with a previously
    1.26 + * obtained per-class method index and a particular "ex_data" variable. These
    1.27 + * variables are usually instantiated per-context (eg. each RSA structure has
    1.28 + * one) so locking on read/write access to that variable can be locked locally
    1.29 + * if required (eg. using the "RSA" lock to synchronise access to a
    1.30 + * per-RSA-structure ex_data variable if required).
    1.31 + * [Geoff]
    1.32 + */
    1.33 +
    1.34 +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
    1.35 + * All rights reserved.
    1.36 + *
    1.37 + * This package is an SSL implementation written
    1.38 + * by Eric Young (eay@cryptsoft.com).
    1.39 + * The implementation was written so as to conform with Netscapes SSL.
    1.40 + * 
    1.41 + * This library is free for commercial and non-commercial use as long as
    1.42 + * the following conditions are aheared to.  The following conditions
    1.43 + * apply to all code found in this distribution, be it the RC4, RSA,
    1.44 + * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
    1.45 + * included with this distribution is covered by the same copyright terms
    1.46 + * except that the holder is Tim Hudson (tjh@cryptsoft.com).
    1.47 + * 
    1.48 + * Copyright remains Eric Young's, and as such any Copyright notices in
    1.49 + * the code are not to be removed.
    1.50 + * If this package is used in a product, Eric Young should be given attribution
    1.51 + * as the author of the parts of the library used.
    1.52 + * This can be in the form of a textual message at program startup or
    1.53 + * in documentation (online or textual) provided with the package.
    1.54 + * 
    1.55 + * Redistribution and use in source and binary forms, with or without
    1.56 + * modification, are permitted provided that the following conditions
    1.57 + * are met:
    1.58 + * 1. Redistributions of source code must retain the copyright
    1.59 + *    notice, this list of conditions and the following disclaimer.
    1.60 + * 2. Redistributions in binary form must reproduce the above copyright
    1.61 + *    notice, this list of conditions and the following disclaimer in the
    1.62 + *    documentation and/or other materials provided with the distribution.
    1.63 + * 3. All advertising materials mentioning features or use of this software
    1.64 + *    must display the following acknowledgement:
    1.65 + *    "This product includes cryptographic software written by
    1.66 + *     Eric Young (eay@cryptsoft.com)"
    1.67 + *    The word 'cryptographic' can be left out if the rouines from the library
    1.68 + *    being used are not cryptographic related :-).
    1.69 + * 4. If you include any Windows specific code (or a derivative thereof) from 
    1.70 + *    the apps directory (application code) you must include an acknowledgement:
    1.71 + *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
    1.72 + * 
    1.73 + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
    1.74 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    1.75 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.76 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    1.77 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    1.78 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    1.79 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    1.80 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    1.81 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    1.82 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    1.83 + * SUCH DAMAGE.
    1.84 + * 
    1.85 + * The licence and distribution terms for any publically available version or
    1.86 + * derivative of this code cannot be changed.  i.e. this code cannot simply be
    1.87 + * copied and put under another distribution licence
    1.88 + * [including the GNU Public Licence.]
    1.89 + */
    1.90 +/* ====================================================================
    1.91 + * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
    1.92 + *
    1.93 + * Redistribution and use in source and binary forms, with or without
    1.94 + * modification, are permitted provided that the following conditions
    1.95 + * are met:
    1.96 + *
    1.97 + * 1. Redistributions of source code must retain the above copyright
    1.98 + *    notice, this list of conditions and the following disclaimer. 
    1.99 + *
   1.100 + * 2. Redistributions in binary form must reproduce the above copyright
   1.101 + *    notice, this list of conditions and the following disclaimer in
   1.102 + *    the documentation and/or other materials provided with the
   1.103 + *    distribution.
   1.104 + *
   1.105 + * 3. All advertising materials mentioning features or use of this
   1.106 + *    software must display the following acknowledgment:
   1.107 + *    "This product includes software developed by the OpenSSL Project
   1.108 + *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
   1.109 + *
   1.110 + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
   1.111 + *    endorse or promote products derived from this software without
   1.112 + *    prior written permission. For written permission, please contact
   1.113 + *    openssl-core@openssl.org.
   1.114 + *
   1.115 + * 5. Products derived from this software may not be called "OpenSSL"
   1.116 + *    nor may "OpenSSL" appear in their names without prior written
   1.117 + *    permission of the OpenSSL Project.
   1.118 + *
   1.119 + * 6. Redistributions of any form whatsoever must retain the following
   1.120 + *    acknowledgment:
   1.121 + *    "This product includes software developed by the OpenSSL Project
   1.122 + *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
   1.123 + *
   1.124 + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
   1.125 + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   1.126 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   1.127 + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
   1.128 + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   1.129 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   1.130 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   1.131 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   1.132 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   1.133 + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   1.134 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   1.135 + * OF THE POSSIBILITY OF SUCH DAMAGE.
   1.136 + * ====================================================================
   1.137 + *
   1.138 + * This product includes cryptographic software written by Eric Young
   1.139 + * (eay@cryptsoft.com).  This product includes software written by Tim
   1.140 + * Hudson (tjh@cryptsoft.com).
   1.141 + *
   1.142 + */
   1.143 + /*
   1.144 + © Portions copyright (c) 2006 Nokia Corporation.  All rights reserved.
   1.145 + */
   1.146 +
   1.147 +#include "cryptlib.h"
   1.148 +#include <openssl/lhash.h>
   1.149 +#if (defined(SYMBIAN) && (defined(__WINSCW__) || defined(__WINS__)))
   1.150 +#include "libcrypto_wsd_macros.h"
   1.151 +#include "libcrypto_wsd.h"
   1.152 +#endif
   1.153 +
   1.154 +#ifndef EMULATOR
   1.155 +/* What an "implementation of ex_data functionality" looks like */
   1.156 +struct st_CRYPTO_EX_DATA_IMPL
   1.157 +	{
   1.158 +	/*********************/
   1.159 +	/* GLOBAL OPERATIONS */
   1.160 +	/* Return a new class index */
   1.161 +	int (*cb_new_class)(void);
   1.162 +	/* Cleanup all state used by the implementation */
   1.163 +	void (*cb_cleanup)(void);
   1.164 +	/************************/
   1.165 +	/* PER-CLASS OPERATIONS */
   1.166 +	/* Get a new method index within a class */
   1.167 +	int (*cb_get_new_index)(int class_index, long argl, void *argp,
   1.168 +			CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
   1.169 +			CRYPTO_EX_free *free_func);
   1.170 +	/* Initialise a new CRYPTO_EX_DATA of a given class */
   1.171 +	int (*cb_new_ex_data)(int class_index, void *obj,
   1.172 +			CRYPTO_EX_DATA *ad);
   1.173 +	/* Duplicate a CRYPTO_EX_DATA of a given class onto a copy */
   1.174 +	int (*cb_dup_ex_data)(int class_index, CRYPTO_EX_DATA *to,
   1.175 +			CRYPTO_EX_DATA *from);
   1.176 +	/* Cleanup a CRYPTO_EX_DATA of a given class */
   1.177 +	void (*cb_free_ex_data)(int class_index, void *obj,
   1.178 +			CRYPTO_EX_DATA *ad);
   1.179 +	};
   1.180 +#endif
   1.181 +#ifndef EMULATOR
   1.182 +/* The implementation we use at run-time */
   1.183 +static const CRYPTO_EX_DATA_IMPL *impl = NULL;
   1.184 +#else
   1.185 + GET_STATIC_VAR_FROM_TLS(impl ,ex_data,CRYPTO_EX_DATA_IMPL *)
   1.186 + #define impl  (*GET_WSD_VAR_NAME(impl,ex_data,s)())
   1.187 +#endif
   1.188 +
   1.189 +/* To call "impl" functions, use this macro rather than referring to 'impl' directly, eg.
   1.190 + * EX_IMPL(get_new_index)(...); */
   1.191 +#define EX_IMPL(a) impl->cb_##a
   1.192 +
   1.193 +/* Predeclare the "default" ex_data implementation */
   1.194 +static int int_new_class(void);
   1.195 +static void int_cleanup(void);
   1.196 +static int int_get_new_index(int class_index, long argl, void *argp,
   1.197 +		CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
   1.198 +		CRYPTO_EX_free *free_func);
   1.199 +static int int_new_ex_data(int class_index, void *obj,
   1.200 +		CRYPTO_EX_DATA *ad);
   1.201 +static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
   1.202 +		CRYPTO_EX_DATA *from);
   1.203 +static void int_free_ex_data(int class_index, void *obj,
   1.204 +		CRYPTO_EX_DATA *ad);
   1.205 +		
   1.206 +		
   1.207 +#ifndef EMULATOR		
   1.208 +static CRYPTO_EX_DATA_IMPL impl_default =
   1.209 +	{
   1.210 +	int_new_class,
   1.211 +	int_cleanup,
   1.212 +	int_get_new_index,
   1.213 +	int_new_ex_data,
   1.214 +	int_dup_ex_data,
   1.215 +	int_free_ex_data
   1.216 +	};
   1.217 +#else	
   1.218 +  GET_STATIC_VAR_FROM_TLS(impl_default,ex_data,CRYPTO_EX_DATA_IMPL)
   1.219 +  #define impl_default (*GET_WSD_VAR_NAME(impl_default,ex_data, s)())
   1.220 +  const CRYPTO_EX_DATA_IMPL temp_s_impl_default =
   1.221 +	{
   1.222 +	int_new_class,
   1.223 +	int_cleanup,
   1.224 +	int_get_new_index,
   1.225 +	int_new_ex_data,
   1.226 +	int_dup_ex_data,
   1.227 +	int_free_ex_data
   1.228 +	};
   1.229 +#endif
   1.230 +
   1.231 +/* Internal function that checks whether "impl" is set and if not, sets it to
   1.232 + * the default. */
   1.233 +static void impl_check(void)
   1.234 +	{
   1.235 +	CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
   1.236 +	if(!impl)
   1.237 +		impl = &impl_default;
   1.238 +	CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
   1.239 +	}
   1.240 +/* A macro wrapper for impl_check that first uses a non-locked test before
   1.241 + * invoking the function (which checks again inside a lock). */
   1.242 +#define IMPL_CHECK if(!impl) impl_check();
   1.243 +
   1.244 +/* API functions to get/set the "ex_data" implementation */
   1.245 +EXPORT_C const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void)
   1.246 +	{
   1.247 +	IMPL_CHECK
   1.248 +	return impl;
   1.249 +	}
   1.250 +EXPORT_C int CRYPTO_set_ex_data_implementation(CRYPTO_EX_DATA_IMPL *i)
   1.251 +	{
   1.252 +	int toret = 0;
   1.253 +	CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
   1.254 +	if(!impl)
   1.255 +		{
   1.256 +		impl = i;
   1.257 +		toret = 1;
   1.258 +		}
   1.259 +	CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
   1.260 +	return toret;
   1.261 +	}
   1.262 +
   1.263 +/****************************************************************************/
   1.264 +/* Interal (default) implementation of "ex_data" support. API functions are
   1.265 + * further down. */
   1.266 +
   1.267 +/* The type that represents what each "class" used to implement locally. A STACK
   1.268 + * of CRYPTO_EX_DATA_FUNCS plus a index-counter. The 'class_index' is the global
   1.269 + * value representing the class that is used to distinguish these items. */
   1.270 +typedef struct st_ex_class_item {
   1.271 +	int class_index;
   1.272 +	STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth;
   1.273 +	int meth_num;
   1.274 +} EX_CLASS_ITEM;
   1.275 +
   1.276 +#ifndef EMULATOR
   1.277 +/* When assigning new class indexes, this is our counter */
   1.278 +static int ex_class = CRYPTO_EX_INDEX_USER;
   1.279 +
   1.280 +/* The global hash table of EX_CLASS_ITEM items */
   1.281 +static LHASH *ex_data = NULL;
   1.282 +#else
   1.283 + GET_STATIC_VAR_FROM_TLS(ex_class ,ex_data,int)
   1.284 + #define ex_class (*GET_WSD_VAR_NAME(ex_class ,ex_data,s)())
   1.285 + GET_STATIC_VAR_FROM_TLS(ex_data ,ex_data,LHASH *)
   1.286 + #define ex_data (*GET_WSD_VAR_NAME(ex_data ,ex_data,s)())
   1.287 +
   1.288 +#endif
   1.289 +
   1.290 +/* The callbacks required in the "ex_data" hash table */
   1.291 +static unsigned long ex_hash_cb(const void *a_void)
   1.292 +	{
   1.293 +	return ((const EX_CLASS_ITEM *)a_void)->class_index;
   1.294 +	}
   1.295 +static int ex_cmp_cb(const void *a_void, const void *b_void)
   1.296 +	{
   1.297 +	return (((const EX_CLASS_ITEM *)a_void)->class_index -
   1.298 +		((const EX_CLASS_ITEM *)b_void)->class_index);
   1.299 +	}
   1.300 +
   1.301 +/* Internal functions used by the "impl_default" implementation to access the
   1.302 + * state */
   1.303 +
   1.304 +static int ex_data_check(void)
   1.305 +	{
   1.306 +	int toret = 1;
   1.307 +	CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
   1.308 +	if(!ex_data && ((ex_data = lh_new(ex_hash_cb, ex_cmp_cb)) == NULL))
   1.309 +		toret = 0;
   1.310 +	CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
   1.311 +	return toret;
   1.312 +	}
   1.313 +/* This macros helps reduce the locking from repeated checks because the
   1.314 + * ex_data_check() function checks ex_data again inside a lock. */
   1.315 +#define EX_DATA_CHECK(iffail) if(!ex_data && !ex_data_check()) {iffail}
   1.316 +
   1.317 +/* This "inner" callback is used by the callback function that follows it */
   1.318 +static void def_cleanup_util_cb(CRYPTO_EX_DATA_FUNCS *funcs)
   1.319 +	{
   1.320 +	OPENSSL_free(funcs);
   1.321 +	}
   1.322 +
   1.323 +/* This callback is used in lh_doall to destroy all EX_CLASS_ITEM values from
   1.324 + * "ex_data" prior to the ex_data hash table being itself destroyed. Doesn't do
   1.325 + * any locking. */
   1.326 +static void def_cleanup_cb(void *a_void)
   1.327 +	{
   1.328 +	EX_CLASS_ITEM *item = (EX_CLASS_ITEM *)a_void;
   1.329 +	sk_CRYPTO_EX_DATA_FUNCS_pop_free(item->meth, def_cleanup_util_cb);
   1.330 +	OPENSSL_free(item);
   1.331 +	}
   1.332 +
   1.333 +/* Return the EX_CLASS_ITEM from the "ex_data" hash table that corresponds to a
   1.334 + * given class. Handles locking. */
   1.335 +static EX_CLASS_ITEM *def_get_class(int class_index)
   1.336 +	{
   1.337 +	EX_CLASS_ITEM d, *p, *gen;
   1.338 +	EX_DATA_CHECK(return NULL;)
   1.339 +	d.class_index = class_index;
   1.340 +	CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
   1.341 +	p = lh_retrieve(ex_data, &d);
   1.342 +	if(!p)
   1.343 +		{
   1.344 +		gen = OPENSSL_malloc(sizeof(EX_CLASS_ITEM));
   1.345 +		if(gen)
   1.346 +			{
   1.347 +			gen->class_index = class_index;
   1.348 +			gen->meth_num = 0;
   1.349 +			gen->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null();
   1.350 +			if(!gen->meth)
   1.351 +				OPENSSL_free(gen);
   1.352 +			else
   1.353 +				{
   1.354 +				/* Because we're inside the ex_data lock, the
   1.355 +				 * return value from the insert will be NULL */
   1.356 +				lh_insert(ex_data, gen);
   1.357 +				p = gen;
   1.358 +				}
   1.359 +			}
   1.360 +		}
   1.361 +	CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
   1.362 +	if(!p)
   1.363 +		CRYPTOerr(CRYPTO_F_DEF_GET_CLASS,ERR_R_MALLOC_FAILURE);
   1.364 +	return p;
   1.365 +	}
   1.366 +
   1.367 +/* Add a new method to the given EX_CLASS_ITEM and return the corresponding
   1.368 + * index (or -1 for error). Handles locking. */
   1.369 +static int def_add_index(EX_CLASS_ITEM *item, long argl, void *argp,
   1.370 +		CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
   1.371 +		CRYPTO_EX_free *free_func)
   1.372 +	{
   1.373 +	int toret = -1;
   1.374 +	CRYPTO_EX_DATA_FUNCS *a = (CRYPTO_EX_DATA_FUNCS *)OPENSSL_malloc(
   1.375 +					sizeof(CRYPTO_EX_DATA_FUNCS));
   1.376 +	if(!a)
   1.377 +		{
   1.378 +		CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX,ERR_R_MALLOC_FAILURE);
   1.379 +		return -1;
   1.380 +		}
   1.381 +	a->argl=argl;
   1.382 +	a->argp=argp;
   1.383 +	a->new_func=new_func;
   1.384 +	a->dup_func=dup_func;
   1.385 +	a->free_func=free_func;
   1.386 +	CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
   1.387 +	while (sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) <= item->meth_num)
   1.388 +		{
   1.389 +		if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, NULL))
   1.390 +			{
   1.391 +			CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX,ERR_R_MALLOC_FAILURE);
   1.392 +			OPENSSL_free(a);
   1.393 +			goto err;
   1.394 +			}
   1.395 +		}
   1.396 +	toret = item->meth_num++;
   1.397 +	(void)sk_CRYPTO_EX_DATA_FUNCS_set(item->meth, toret, a);
   1.398 +err:
   1.399 +	CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
   1.400 +	return toret;
   1.401 +	}
   1.402 +
   1.403 +/**************************************************************/
   1.404 +/* The functions in the default CRYPTO_EX_DATA_IMPL structure */
   1.405 +
   1.406 +static int int_new_class(void)
   1.407 +	{
   1.408 +	int toret;
   1.409 +	CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA);
   1.410 +	toret = ex_class++;
   1.411 +	CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA);
   1.412 +	return toret;
   1.413 +	}
   1.414 +
   1.415 +static void int_cleanup(void)
   1.416 +	{
   1.417 +	EX_DATA_CHECK(return;)
   1.418 +	lh_doall(ex_data, def_cleanup_cb);
   1.419 +	lh_free(ex_data);
   1.420 +	ex_data = NULL;
   1.421 +	impl = NULL;
   1.422 +	}
   1.423 +
   1.424 +static int int_get_new_index(int class_index, long argl, void *argp,
   1.425 +		CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
   1.426 +		CRYPTO_EX_free *free_func)
   1.427 +	{
   1.428 +	EX_CLASS_ITEM *item = def_get_class(class_index);
   1.429 +	if(!item)
   1.430 +		return -1;
   1.431 +	return def_add_index(item, argl, argp, new_func, dup_func, free_func);
   1.432 +	}
   1.433 +
   1.434 +/* Thread-safe by copying a class's array of "CRYPTO_EX_DATA_FUNCS" entries in
   1.435 + * the lock, then using them outside the lock. NB: Thread-safety only applies to
   1.436 + * the global "ex_data" state (ie. class definitions), not thread-safe on 'ad'
   1.437 + * itself. */
   1.438 +static int int_new_ex_data(int class_index, void *obj,
   1.439 +		CRYPTO_EX_DATA *ad)
   1.440 +	{
   1.441 +	int mx,i;
   1.442 +	void *ptr;
   1.443 +	CRYPTO_EX_DATA_FUNCS **storage = NULL;
   1.444 +	EX_CLASS_ITEM *item = def_get_class(class_index);
   1.445 +	if(!item)
   1.446 +		/* error is already set */
   1.447 +		return 0;
   1.448 +	ad->sk = NULL;
   1.449 +	CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
   1.450 +	mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
   1.451 +	if(mx > 0)
   1.452 +		{
   1.453 +		storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS*));
   1.454 +		if(!storage)
   1.455 +			goto skip;
   1.456 +		for(i = 0; i < mx; i++)
   1.457 +			storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth,i);
   1.458 +		}
   1.459 +skip:
   1.460 +	CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
   1.461 +	if((mx > 0) && !storage)
   1.462 +		{
   1.463 +		CRYPTOerr(CRYPTO_F_INT_NEW_EX_DATA,ERR_R_MALLOC_FAILURE);
   1.464 +		return 0;
   1.465 +		}
   1.466 +	for(i = 0; i < mx; i++)
   1.467 +		{
   1.468 +		if(storage[i] && storage[i]->new_func)
   1.469 +			{
   1.470 +			ptr = CRYPTO_get_ex_data(ad, i);
   1.471 +			storage[i]->new_func(obj,ptr,ad,i,
   1.472 +				storage[i]->argl,storage[i]->argp);
   1.473 +			}
   1.474 +		}
   1.475 +	if(storage)
   1.476 +		OPENSSL_free(storage);
   1.477 +	return 1;
   1.478 +	}
   1.479 +
   1.480 +/* Same thread-safety notes as for "int_new_ex_data" */
   1.481 +static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
   1.482 +		CRYPTO_EX_DATA *from)
   1.483 +	{
   1.484 +	int mx, j, i;
   1.485 +	char *ptr;
   1.486 +	CRYPTO_EX_DATA_FUNCS **storage = NULL;
   1.487 +	EX_CLASS_ITEM *item;
   1.488 +	if(!from->sk)
   1.489 +		/* 'to' should be "blank" which *is* just like 'from' */
   1.490 +		return 1;
   1.491 +	if((item = def_get_class(class_index)) == NULL)
   1.492 +		return 0;
   1.493 +	CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
   1.494 +	mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
   1.495 +	j = sk_num(from->sk);
   1.496 +	if(j < mx)
   1.497 +		mx = j;
   1.498 +	if(mx > 0)
   1.499 +		{
   1.500 +		storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS*));
   1.501 +		if(!storage)
   1.502 +			goto skip;
   1.503 +		for(i = 0; i < mx; i++)
   1.504 +			storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth,i);
   1.505 +		}
   1.506 +skip:
   1.507 +	CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
   1.508 +	if((mx > 0) && !storage)
   1.509 +		{
   1.510 +		CRYPTOerr(CRYPTO_F_INT_DUP_EX_DATA,ERR_R_MALLOC_FAILURE);
   1.511 +		return 0;
   1.512 +		}
   1.513 +	for(i = 0; i < mx; i++)
   1.514 +		{
   1.515 +		ptr = CRYPTO_get_ex_data(from, i);
   1.516 +		if(storage[i] && storage[i]->dup_func)
   1.517 +			storage[i]->dup_func(to,from,&ptr,i,
   1.518 +				storage[i]->argl,storage[i]->argp);
   1.519 +		CRYPTO_set_ex_data(to,i,ptr);
   1.520 +		}
   1.521 +	if(storage)
   1.522 +		OPENSSL_free(storage);
   1.523 +	return 1;
   1.524 +	}
   1.525 +
   1.526 +/* Same thread-safety notes as for "int_new_ex_data" */
   1.527 +static void int_free_ex_data(int class_index, void *obj,
   1.528 +		CRYPTO_EX_DATA *ad)
   1.529 +	{
   1.530 +	int mx,i;
   1.531 +	EX_CLASS_ITEM *item;
   1.532 +	void *ptr;
   1.533 +	CRYPTO_EX_DATA_FUNCS **storage = NULL;
   1.534 +	if((item = def_get_class(class_index)) == NULL)
   1.535 +		return;
   1.536 +	CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA);
   1.537 +	mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth);
   1.538 +	if(mx > 0)
   1.539 +		{
   1.540 +		storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS*));
   1.541 +		if(!storage)
   1.542 +			goto skip;
   1.543 +		for(i = 0; i < mx; i++)
   1.544 +			storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth,i);
   1.545 +		}
   1.546 +skip:
   1.547 +	CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA);
   1.548 +	if((mx > 0) && !storage)
   1.549 +		{
   1.550 +		CRYPTOerr(CRYPTO_F_INT_FREE_EX_DATA,ERR_R_MALLOC_FAILURE);
   1.551 +		return;
   1.552 +		}
   1.553 +	for(i = 0; i < mx; i++)
   1.554 +		{
   1.555 +		if(storage[i] && storage[i]->free_func)
   1.556 +			{
   1.557 +			ptr = CRYPTO_get_ex_data(ad,i);
   1.558 +			storage[i]->free_func(obj,ptr,ad,i,
   1.559 +				storage[i]->argl,storage[i]->argp);
   1.560 +			}
   1.561 +		}
   1.562 +	if(storage)
   1.563 +		OPENSSL_free(storage);
   1.564 +	if(ad->sk)
   1.565 +		{
   1.566 +		sk_free(ad->sk);
   1.567 +		ad->sk=NULL;
   1.568 +		}
   1.569 +	}
   1.570 +
   1.571 +/********************************************************************/
   1.572 +/* API functions that defer all "state" operations to the "ex_data"
   1.573 + * implementation we have set. */
   1.574 +
   1.575 +/* Obtain an index for a new class (not the same as getting a new index within
   1.576 + * an existing class - this is actually getting a new *class*) */
   1.577 +EXPORT_C int CRYPTO_ex_data_new_class(void)
   1.578 +	{
   1.579 +	IMPL_CHECK
   1.580 +	return EX_IMPL(new_class)();
   1.581 +	}
   1.582 +
   1.583 +/* Release all "ex_data" state to prevent memory leaks. This can't be made
   1.584 + * thread-safe without overhauling a lot of stuff, and shouldn't really be
   1.585 + * called under potential race-conditions anyway (it's for program shutdown
   1.586 + * after all). */
   1.587 +EXPORT_C void CRYPTO_cleanup_all_ex_data(void)
   1.588 +	{
   1.589 +	IMPL_CHECK
   1.590 +	EX_IMPL(cleanup)();
   1.591 +	}
   1.592 +
   1.593 +/* Inside an existing class, get/register a new index. */
   1.594 +EXPORT_C int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
   1.595 +		CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
   1.596 +		CRYPTO_EX_free *free_func)
   1.597 +	{
   1.598 +	int ret = -1;
   1.599 +
   1.600 +	IMPL_CHECK
   1.601 +	ret = EX_IMPL(get_new_index)(class_index,
   1.602 +			argl, argp, new_func, dup_func, free_func);
   1.603 +	return ret;
   1.604 +	}
   1.605 +
   1.606 +/* Initialise a new CRYPTO_EX_DATA for use in a particular class - including
   1.607 + * calling new() callbacks for each index in the class used by this variable */
   1.608 +EXPORT_C int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
   1.609 +	{
   1.610 +	IMPL_CHECK
   1.611 +	return EX_IMPL(new_ex_data)(class_index, obj, ad);
   1.612 +	}
   1.613 +
   1.614 +/* Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks for
   1.615 + * each index in the class used by this variable */
   1.616 +EXPORT_C int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
   1.617 +	     CRYPTO_EX_DATA *from)
   1.618 +	{
   1.619 +	IMPL_CHECK
   1.620 +	return EX_IMPL(dup_ex_data)(class_index, to, from);
   1.621 +	}
   1.622 +
   1.623 +/* Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
   1.624 + * each index in the class used by this variable */
   1.625 +EXPORT_C void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
   1.626 +	{
   1.627 +	IMPL_CHECK
   1.628 +	EX_IMPL(free_ex_data)(class_index, obj, ad);
   1.629 +	}
   1.630 +
   1.631 +/* For a given CRYPTO_EX_DATA variable, set the value corresponding to a
   1.632 + * particular index in the class used by this variable */
   1.633 +EXPORT_C int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
   1.634 +	{
   1.635 +	int i;
   1.636 +
   1.637 +	if (ad->sk == NULL)
   1.638 +		{
   1.639 +		if ((ad->sk=sk_new_null()) == NULL)
   1.640 +			{
   1.641 +			CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA,ERR_R_MALLOC_FAILURE);
   1.642 +			return(0);
   1.643 +			}
   1.644 +		}
   1.645 +	i=sk_num(ad->sk);
   1.646 +
   1.647 +	while (i <= idx)
   1.648 +		{
   1.649 +		if (!sk_push(ad->sk,NULL))
   1.650 +			{
   1.651 +			CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA,ERR_R_MALLOC_FAILURE);
   1.652 +			return(0);
   1.653 +			}
   1.654 +		i++;
   1.655 +		}
   1.656 +	sk_set(ad->sk,idx,val);
   1.657 +	return(1);
   1.658 +	}
   1.659 +
   1.660 +/* For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
   1.661 + * particular index in the class used by this variable */
   1.662 +EXPORT_C void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
   1.663 +	{
   1.664 +	if (ad->sk == NULL)
   1.665 +		return(0);
   1.666 +	else if (idx >= sk_num(ad->sk))
   1.667 +		return(0);
   1.668 +	else
   1.669 +		return(sk_value(ad->sk,idx));
   1.670 +	}
   1.671 +
   1.672 +IMPLEMENT_STACK_OF(CRYPTO_EX_DATA_FUNCS)