155714Skris/* crypto/ex_data.c */ 2109998Smarkm 3109998Smarkm/* 4109998Smarkm * Overhaul notes; 5109998Smarkm * 6109998Smarkm * This code is now *mostly* thread-safe. It is now easier to understand in what 7109998Smarkm * ways it is safe and in what ways it is not, which is an improvement. Firstly, 8109998Smarkm * all per-class stacks and index-counters for ex_data are stored in the same 9109998Smarkm * global LHASH table (keyed by class). This hash table uses locking for all 10109998Smarkm * access with the exception of CRYPTO_cleanup_all_ex_data(), which must only be 11109998Smarkm * called when no other threads can possibly race against it (even if it was 12109998Smarkm * locked, the race would mean it's possible the hash table might have been 13109998Smarkm * recreated after the cleanup). As classes can only be added to the hash table, 14109998Smarkm * and within each class, the stack of methods can only be incremented, the 15109998Smarkm * locking mechanics are simpler than they would otherwise be. For example, the 16109998Smarkm * new/dup/free ex_data functions will lock the hash table, copy the method 17109998Smarkm * pointers it needs from the relevant class, then unlock the hash table before 18109998Smarkm * actually applying those method pointers to the task of the new/dup/free 19109998Smarkm * operations. As they can't be removed from the method-stack, only 20109998Smarkm * supplemented, there's no race conditions associated with using them outside 21109998Smarkm * the lock. The get/set_ex_data functions are not locked because they do not 22109998Smarkm * involve this global state at all - they operate directly with a previously 23109998Smarkm * obtained per-class method index and a particular "ex_data" variable. These 24109998Smarkm * variables are usually instantiated per-context (eg. each RSA structure has 25109998Smarkm * one) so locking on read/write access to that variable can be locked locally 26109998Smarkm * if required (eg. using the "RSA" lock to synchronise access to a 27109998Smarkm * per-RSA-structure ex_data variable if required). 28109998Smarkm * [Geoff] 29109998Smarkm */ 30109998Smarkm 3155714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3255714Skris * All rights reserved. 3355714Skris * 3455714Skris * This package is an SSL implementation written 3555714Skris * by Eric Young (eay@cryptsoft.com). 3655714Skris * The implementation was written so as to conform with Netscapes SSL. 37280304Sjkim * 3855714Skris * This library is free for commercial and non-commercial use as long as 3955714Skris * the following conditions are aheared to. The following conditions 4055714Skris * apply to all code found in this distribution, be it the RC4, RSA, 4155714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 4255714Skris * included with this distribution is covered by the same copyright terms 4355714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 44280304Sjkim * 4555714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 4655714Skris * the code are not to be removed. 4755714Skris * If this package is used in a product, Eric Young should be given attribution 4855714Skris * as the author of the parts of the library used. 4955714Skris * This can be in the form of a textual message at program startup or 5055714Skris * in documentation (online or textual) provided with the package. 51280304Sjkim * 5255714Skris * Redistribution and use in source and binary forms, with or without 5355714Skris * modification, are permitted provided that the following conditions 5455714Skris * are met: 5555714Skris * 1. Redistributions of source code must retain the copyright 5655714Skris * notice, this list of conditions and the following disclaimer. 5755714Skris * 2. Redistributions in binary form must reproduce the above copyright 5855714Skris * notice, this list of conditions and the following disclaimer in the 5955714Skris * documentation and/or other materials provided with the distribution. 6055714Skris * 3. All advertising materials mentioning features or use of this software 6155714Skris * must display the following acknowledgement: 6255714Skris * "This product includes cryptographic software written by 6355714Skris * Eric Young (eay@cryptsoft.com)" 6455714Skris * The word 'cryptographic' can be left out if the rouines from the library 6555714Skris * being used are not cryptographic related :-). 66280304Sjkim * 4. If you include any Windows specific code (or a derivative thereof) from 6755714Skris * the apps directory (application code) you must include an acknowledgement: 6855714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 69280304Sjkim * 7055714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 7155714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 7255714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 7355714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 7455714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 7555714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 7655714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 7755714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 7855714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 7955714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 8055714Skris * SUCH DAMAGE. 81280304Sjkim * 8255714Skris * The licence and distribution terms for any publically available version or 8355714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 8455714Skris * copied and put under another distribution licence 8555714Skris * [including the GNU Public Licence.] 8655714Skris */ 87109998Smarkm/* ==================================================================== 88109998Smarkm * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. 89109998Smarkm * 90109998Smarkm * Redistribution and use in source and binary forms, with or without 91109998Smarkm * modification, are permitted provided that the following conditions 92109998Smarkm * are met: 93109998Smarkm * 94109998Smarkm * 1. Redistributions of source code must retain the above copyright 95280304Sjkim * notice, this list of conditions and the following disclaimer. 96109998Smarkm * 97109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 98109998Smarkm * notice, this list of conditions and the following disclaimer in 99109998Smarkm * the documentation and/or other materials provided with the 100109998Smarkm * distribution. 101109998Smarkm * 102109998Smarkm * 3. All advertising materials mentioning features or use of this 103109998Smarkm * software must display the following acknowledgment: 104109998Smarkm * "This product includes software developed by the OpenSSL Project 105109998Smarkm * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 106109998Smarkm * 107109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 108109998Smarkm * endorse or promote products derived from this software without 109109998Smarkm * prior written permission. For written permission, please contact 110109998Smarkm * openssl-core@openssl.org. 111109998Smarkm * 112109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 113109998Smarkm * nor may "OpenSSL" appear in their names without prior written 114109998Smarkm * permission of the OpenSSL Project. 115109998Smarkm * 116109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 117109998Smarkm * acknowledgment: 118109998Smarkm * "This product includes software developed by the OpenSSL Project 119109998Smarkm * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 120109998Smarkm * 121109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 122109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 123109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 124109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 125109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 126109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 127109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 128109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 129109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 130109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 131109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 132109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 133109998Smarkm * ==================================================================== 134109998Smarkm * 135109998Smarkm * This product includes cryptographic software written by Eric Young 136109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 137109998Smarkm * Hudson (tjh@cryptsoft.com). 138109998Smarkm * 139109998Smarkm */ 14055714Skris 141160814Ssimon#include "cryptlib.h" 14255714Skris#include <openssl/lhash.h> 14355714Skris 144109998Smarkm/* What an "implementation of ex_data functionality" looks like */ 145280304Sjkimstruct st_CRYPTO_EX_DATA_IMPL { 146280304Sjkim /*********************/ 147280304Sjkim /* GLOBAL OPERATIONS */ 148280304Sjkim /* Return a new class index */ 149280304Sjkim int (*cb_new_class) (void); 150280304Sjkim /* Cleanup all state used by the implementation */ 151280304Sjkim void (*cb_cleanup) (void); 152280304Sjkim /************************/ 153280304Sjkim /* PER-CLASS OPERATIONS */ 154280304Sjkim /* Get a new method index within a class */ 155280304Sjkim int (*cb_get_new_index) (int class_index, long argl, void *argp, 156280304Sjkim CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 157280304Sjkim CRYPTO_EX_free *free_func); 158280304Sjkim /* Initialise a new CRYPTO_EX_DATA of a given class */ 159280304Sjkim int (*cb_new_ex_data) (int class_index, void *obj, CRYPTO_EX_DATA *ad); 160280304Sjkim /* Duplicate a CRYPTO_EX_DATA of a given class onto a copy */ 161280304Sjkim int (*cb_dup_ex_data) (int class_index, CRYPTO_EX_DATA *to, 162280304Sjkim CRYPTO_EX_DATA *from); 163280304Sjkim /* Cleanup a CRYPTO_EX_DATA of a given class */ 164280304Sjkim void (*cb_free_ex_data) (int class_index, void *obj, CRYPTO_EX_DATA *ad); 165280304Sjkim}; 16655714Skris 167109998Smarkm/* The implementation we use at run-time */ 168109998Smarkmstatic const CRYPTO_EX_DATA_IMPL *impl = NULL; 169109998Smarkm 170280304Sjkim/* 171280304Sjkim * To call "impl" functions, use this macro rather than referring to 'impl' 172280304Sjkim * directly, eg. EX_IMPL(get_new_index)(...); 173280304Sjkim */ 174109998Smarkm#define EX_IMPL(a) impl->cb_##a 175109998Smarkm 176109998Smarkm/* Predeclare the "default" ex_data implementation */ 177109998Smarkmstatic int int_new_class(void); 178109998Smarkmstatic void int_cleanup(void); 179109998Smarkmstatic int int_get_new_index(int class_index, long argl, void *argp, 180280304Sjkim CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 181280304Sjkim CRYPTO_EX_free *free_func); 182280304Sjkimstatic int int_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad); 183109998Smarkmstatic int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, 184280304Sjkim CRYPTO_EX_DATA *from); 185280304Sjkimstatic void int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad); 186280304Sjkimstatic CRYPTO_EX_DATA_IMPL impl_default = { 187280304Sjkim int_new_class, 188280304Sjkim int_cleanup, 189280304Sjkim int_get_new_index, 190280304Sjkim int_new_ex_data, 191280304Sjkim int_dup_ex_data, 192280304Sjkim int_free_ex_data 193280304Sjkim}; 194109998Smarkm 195280304Sjkim/* 196280304Sjkim * Internal function that checks whether "impl" is set and if not, sets it to 197280304Sjkim * the default. 198280304Sjkim */ 199109998Smarkmstatic void impl_check(void) 200280304Sjkim{ 201280304Sjkim CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 202280304Sjkim if (!impl) 203280304Sjkim impl = &impl_default; 204280304Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 205280304Sjkim} 206280304Sjkim 207280304Sjkim/* 208280304Sjkim * A macro wrapper for impl_check that first uses a non-locked test before 209280304Sjkim * invoking the function (which checks again inside a lock). 210280304Sjkim */ 211109998Smarkm#define IMPL_CHECK if(!impl) impl_check(); 212109998Smarkm 213109998Smarkm/* API functions to get/set the "ex_data" implementation */ 214109998Smarkmconst CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void) 215280304Sjkim{ 216280304Sjkim IMPL_CHECK return impl; 217280304Sjkim} 218280304Sjkim 219109998Smarkmint CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i) 220280304Sjkim{ 221280304Sjkim int toret = 0; 222280304Sjkim CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 223280304Sjkim if (!impl) { 224280304Sjkim impl = i; 225280304Sjkim toret = 1; 226280304Sjkim } 227280304Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 228280304Sjkim return toret; 229280304Sjkim} 230109998Smarkm 231109998Smarkm/****************************************************************************/ 232280304Sjkim/* 233280304Sjkim * Interal (default) implementation of "ex_data" support. API functions are 234280304Sjkim * further down. 235280304Sjkim */ 236109998Smarkm 237280304Sjkim/* 238280304Sjkim * The type that represents what each "class" used to implement locally. A 239280304Sjkim * STACK of CRYPTO_EX_DATA_FUNCS plus a index-counter. The 'class_index' is 240280304Sjkim * the global value representing the class that is used to distinguish these 241280304Sjkim * items. 242280304Sjkim */ 243109998Smarkmtypedef struct st_ex_class_item { 244280304Sjkim int class_index; 245280304Sjkim STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth; 246280304Sjkim int meth_num; 247109998Smarkm} EX_CLASS_ITEM; 248109998Smarkm 249109998Smarkm/* When assigning new class indexes, this is our counter */ 250109998Smarkmstatic int ex_class = CRYPTO_EX_INDEX_USER; 251109998Smarkm 252109998Smarkm/* The global hash table of EX_CLASS_ITEM items */ 253238405SjkimDECLARE_LHASH_OF(EX_CLASS_ITEM); 254238405Sjkimstatic LHASH_OF(EX_CLASS_ITEM) *ex_data = NULL; 255109998Smarkm 256109998Smarkm/* The callbacks required in the "ex_data" hash table */ 257238405Sjkimstatic unsigned long ex_class_item_hash(const EX_CLASS_ITEM *a) 258280304Sjkim{ 259280304Sjkim return a->class_index; 260280304Sjkim} 261280304Sjkim 262238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(ex_class_item, EX_CLASS_ITEM) 263238405Sjkim 264238405Sjkimstatic int ex_class_item_cmp(const EX_CLASS_ITEM *a, const EX_CLASS_ITEM *b) 265280304Sjkim{ 266280304Sjkim return a->class_index - b->class_index; 267280304Sjkim} 268280304Sjkim 269238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(ex_class_item, EX_CLASS_ITEM) 270109998Smarkm 271280304Sjkim/* 272280304Sjkim * Internal functions used by the "impl_default" implementation to access the 273280304Sjkim * state 274280304Sjkim */ 275280304Sjkimstatic int ex_data_check(void) 276280304Sjkim{ 277280304Sjkim int toret = 1; 278280304Sjkim CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 279280304Sjkim if (!ex_data && (ex_data = lh_EX_CLASS_ITEM_new()) == NULL) 280280304Sjkim toret = 0; 281280304Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 282280304Sjkim return toret; 283280304Sjkim} 284109998Smarkm 285280304Sjkim/* 286280304Sjkim * This macros helps reduce the locking from repeated checks because the 287280304Sjkim * ex_data_check() function checks ex_data again inside a lock. 288280304Sjkim */ 289109998Smarkm#define EX_DATA_CHECK(iffail) if(!ex_data && !ex_data_check()) {iffail} 290109998Smarkm 291109998Smarkm/* This "inner" callback is used by the callback function that follows it */ 292109998Smarkmstatic void def_cleanup_util_cb(CRYPTO_EX_DATA_FUNCS *funcs) 293280304Sjkim{ 294280304Sjkim OPENSSL_free(funcs); 295280304Sjkim} 296109998Smarkm 297280304Sjkim/* 298280304Sjkim * This callback is used in lh_doall to destroy all EX_CLASS_ITEM values from 299280304Sjkim * "ex_data" prior to the ex_data hash table being itself destroyed. Doesn't 300280304Sjkim * do any locking. 301280304Sjkim */ 302160814Ssimonstatic void def_cleanup_cb(void *a_void) 303280304Sjkim{ 304280304Sjkim EX_CLASS_ITEM *item = (EX_CLASS_ITEM *)a_void; 305280304Sjkim sk_CRYPTO_EX_DATA_FUNCS_pop_free(item->meth, def_cleanup_util_cb); 306280304Sjkim OPENSSL_free(item); 307280304Sjkim} 308109998Smarkm 309280304Sjkim/* 310280304Sjkim * Return the EX_CLASS_ITEM from the "ex_data" hash table that corresponds to 311280304Sjkim * a given class. Handles locking. 312280304Sjkim */ 313109998Smarkmstatic EX_CLASS_ITEM *def_get_class(int class_index) 314280304Sjkim{ 315280304Sjkim EX_CLASS_ITEM d, *p, *gen; 316280304Sjkim EX_DATA_CHECK(return NULL;) 317280304Sjkim d.class_index = class_index; 318280304Sjkim CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 319280304Sjkim p = lh_EX_CLASS_ITEM_retrieve(ex_data, &d); 320280304Sjkim if (!p) { 321280304Sjkim gen = OPENSSL_malloc(sizeof(EX_CLASS_ITEM)); 322280304Sjkim if (gen) { 323280304Sjkim gen->class_index = class_index; 324280304Sjkim gen->meth_num = 0; 325280304Sjkim gen->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null(); 326280304Sjkim if (!gen->meth) 327280304Sjkim OPENSSL_free(gen); 328280304Sjkim else { 329280304Sjkim /* 330280304Sjkim * Because we're inside the ex_data lock, the return value 331280304Sjkim * from the insert will be NULL 332280304Sjkim */ 333280304Sjkim (void)lh_EX_CLASS_ITEM_insert(ex_data, gen); 334280304Sjkim p = gen; 335280304Sjkim } 336280304Sjkim } 337280304Sjkim } 338280304Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 339280304Sjkim if (!p) 340280304Sjkim CRYPTOerr(CRYPTO_F_DEF_GET_CLASS, ERR_R_MALLOC_FAILURE); 341280304Sjkim return p; 342280304Sjkim} 343109998Smarkm 344280304Sjkim/* 345280304Sjkim * Add a new method to the given EX_CLASS_ITEM and return the corresponding 346280304Sjkim * index (or -1 for error). Handles locking. 347280304Sjkim */ 348109998Smarkmstatic int def_add_index(EX_CLASS_ITEM *item, long argl, void *argp, 349280304Sjkim CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 350280304Sjkim CRYPTO_EX_free *free_func) 351280304Sjkim{ 352280304Sjkim int toret = -1; 353280304Sjkim CRYPTO_EX_DATA_FUNCS *a = 354280304Sjkim (CRYPTO_EX_DATA_FUNCS *)OPENSSL_malloc(sizeof(CRYPTO_EX_DATA_FUNCS)); 355280304Sjkim if (!a) { 356280304Sjkim CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX, ERR_R_MALLOC_FAILURE); 357280304Sjkim return -1; 358280304Sjkim } 359280304Sjkim a->argl = argl; 360280304Sjkim a->argp = argp; 361280304Sjkim a->new_func = new_func; 362280304Sjkim a->dup_func = dup_func; 363280304Sjkim a->free_func = free_func; 364280304Sjkim CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 365280304Sjkim while (sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) <= item->meth_num) { 366280304Sjkim if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, NULL)) { 367280304Sjkim CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX, ERR_R_MALLOC_FAILURE); 368280304Sjkim OPENSSL_free(a); 369280304Sjkim goto err; 370280304Sjkim } 371280304Sjkim } 372280304Sjkim toret = item->meth_num++; 373280304Sjkim (void)sk_CRYPTO_EX_DATA_FUNCS_set(item->meth, toret, a); 374280304Sjkim err: 375280304Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 376280304Sjkim return toret; 377280304Sjkim} 37855714Skris 379109998Smarkm/**************************************************************/ 380109998Smarkm/* The functions in the default CRYPTO_EX_DATA_IMPL structure */ 381109998Smarkm 382109998Smarkmstatic int int_new_class(void) 383280304Sjkim{ 384280304Sjkim int toret; 385280304Sjkim CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 386280304Sjkim toret = ex_class++; 387280304Sjkim CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 388280304Sjkim return toret; 389280304Sjkim} 390109998Smarkm 391109998Smarkmstatic void int_cleanup(void) 392280304Sjkim{ 393280304Sjkim EX_DATA_CHECK(return;) 394280304Sjkim lh_EX_CLASS_ITEM_doall(ex_data, def_cleanup_cb); 395280304Sjkim lh_EX_CLASS_ITEM_free(ex_data); 396280304Sjkim ex_data = NULL; 397280304Sjkim impl = NULL; 398280304Sjkim} 399109998Smarkm 400109998Smarkmstatic int int_get_new_index(int class_index, long argl, void *argp, 401280304Sjkim CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 402280304Sjkim CRYPTO_EX_free *free_func) 403280304Sjkim{ 404280304Sjkim EX_CLASS_ITEM *item = def_get_class(class_index); 405280304Sjkim if (!item) 406280304Sjkim return -1; 407280304Sjkim return def_add_index(item, argl, argp, new_func, dup_func, free_func); 408280304Sjkim} 409109998Smarkm 410280304Sjkim/* 411280304Sjkim * Thread-safe by copying a class's array of "CRYPTO_EX_DATA_FUNCS" entries 412280304Sjkim * in the lock, then using them outside the lock. NB: Thread-safety only 413280304Sjkim * applies to the global "ex_data" state (ie. class definitions), not 414280304Sjkim * thread-safe on 'ad' itself. 415280304Sjkim */ 416280304Sjkimstatic int int_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 417280304Sjkim{ 418280304Sjkim int mx, i; 419280304Sjkim void *ptr; 420280304Sjkim CRYPTO_EX_DATA_FUNCS **storage = NULL; 421280304Sjkim EX_CLASS_ITEM *item = def_get_class(class_index); 422280304Sjkim if (!item) 423280304Sjkim /* error is already set */ 424280304Sjkim return 0; 425280304Sjkim ad->sk = NULL; 426280304Sjkim CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); 427280304Sjkim mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); 428280304Sjkim if (mx > 0) { 429280304Sjkim storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *)); 430280304Sjkim if (!storage) 431280304Sjkim goto skip; 432280304Sjkim for (i = 0; i < mx; i++) 433280304Sjkim storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); 434280304Sjkim } 435280304Sjkim skip: 436280304Sjkim CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); 437280304Sjkim if ((mx > 0) && !storage) { 438280304Sjkim CRYPTOerr(CRYPTO_F_INT_NEW_EX_DATA, ERR_R_MALLOC_FAILURE); 439280304Sjkim return 0; 440280304Sjkim } 441280304Sjkim for (i = 0; i < mx; i++) { 442280304Sjkim if (storage[i] && storage[i]->new_func) { 443280304Sjkim ptr = CRYPTO_get_ex_data(ad, i); 444280304Sjkim storage[i]->new_func(obj, ptr, ad, i, 445280304Sjkim storage[i]->argl, storage[i]->argp); 446280304Sjkim } 447280304Sjkim } 448280304Sjkim if (storage) 449280304Sjkim OPENSSL_free(storage); 450280304Sjkim return 1; 451280304Sjkim} 452109998Smarkm 453109998Smarkm/* Same thread-safety notes as for "int_new_ex_data" */ 454109998Smarkmstatic int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, 455280304Sjkim CRYPTO_EX_DATA *from) 456280304Sjkim{ 457280304Sjkim int mx, j, i; 458280304Sjkim char *ptr; 459280304Sjkim CRYPTO_EX_DATA_FUNCS **storage = NULL; 460280304Sjkim EX_CLASS_ITEM *item; 461280304Sjkim if (!from->sk) 462280304Sjkim /* 'to' should be "blank" which *is* just like 'from' */ 463280304Sjkim return 1; 464280304Sjkim if ((item = def_get_class(class_index)) == NULL) 465280304Sjkim return 0; 466280304Sjkim CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); 467280304Sjkim mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); 468280304Sjkim j = sk_void_num(from->sk); 469280304Sjkim if (j < mx) 470280304Sjkim mx = j; 471280304Sjkim if (mx > 0) { 472280304Sjkim storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *)); 473280304Sjkim if (!storage) 474280304Sjkim goto skip; 475280304Sjkim for (i = 0; i < mx; i++) 476280304Sjkim storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); 477280304Sjkim } 478280304Sjkim skip: 479280304Sjkim CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); 480280304Sjkim if ((mx > 0) && !storage) { 481280304Sjkim CRYPTOerr(CRYPTO_F_INT_DUP_EX_DATA, ERR_R_MALLOC_FAILURE); 482280304Sjkim return 0; 483280304Sjkim } 484280304Sjkim for (i = 0; i < mx; i++) { 485280304Sjkim ptr = CRYPTO_get_ex_data(from, i); 486280304Sjkim if (storage[i] && storage[i]->dup_func) 487280304Sjkim storage[i]->dup_func(to, from, &ptr, i, 488280304Sjkim storage[i]->argl, storage[i]->argp); 489280304Sjkim CRYPTO_set_ex_data(to, i, ptr); 490280304Sjkim } 491280304Sjkim if (storage) 492280304Sjkim OPENSSL_free(storage); 493280304Sjkim return 1; 494280304Sjkim} 495109998Smarkm 496109998Smarkm/* Same thread-safety notes as for "int_new_ex_data" */ 497280304Sjkimstatic void int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 498280304Sjkim{ 499280304Sjkim int mx, i; 500280304Sjkim EX_CLASS_ITEM *item; 501280304Sjkim void *ptr; 502280304Sjkim CRYPTO_EX_DATA_FUNCS **storage = NULL; 503280304Sjkim if (ex_data == NULL) 504280304Sjkim return; 505280304Sjkim if ((item = def_get_class(class_index)) == NULL) 506280304Sjkim return; 507280304Sjkim CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); 508280304Sjkim mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); 509280304Sjkim if (mx > 0) { 510280304Sjkim storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *)); 511280304Sjkim if (!storage) 512280304Sjkim goto skip; 513280304Sjkim for (i = 0; i < mx; i++) 514280304Sjkim storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); 515280304Sjkim } 516280304Sjkim skip: 517280304Sjkim CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); 518280304Sjkim if ((mx > 0) && !storage) { 519280304Sjkim CRYPTOerr(CRYPTO_F_INT_FREE_EX_DATA, ERR_R_MALLOC_FAILURE); 520280304Sjkim return; 521280304Sjkim } 522280304Sjkim for (i = 0; i < mx; i++) { 523280304Sjkim if (storage[i] && storage[i]->free_func) { 524280304Sjkim ptr = CRYPTO_get_ex_data(ad, i); 525280304Sjkim storage[i]->free_func(obj, ptr, ad, i, 526280304Sjkim storage[i]->argl, storage[i]->argp); 527280304Sjkim } 528280304Sjkim } 529280304Sjkim if (storage) 530280304Sjkim OPENSSL_free(storage); 531280304Sjkim if (ad->sk) { 532280304Sjkim sk_void_free(ad->sk); 533280304Sjkim ad->sk = NULL; 534280304Sjkim } 535280304Sjkim} 536109998Smarkm 537109998Smarkm/********************************************************************/ 538280304Sjkim/* 539280304Sjkim * API functions that defer all "state" operations to the "ex_data" 540280304Sjkim * implementation we have set. 541280304Sjkim */ 542109998Smarkm 543280304Sjkim/* 544280304Sjkim * Obtain an index for a new class (not the same as getting a new index 545280304Sjkim * within an existing class - this is actually getting a new *class*) 546280304Sjkim */ 547109998Smarkmint CRYPTO_ex_data_new_class(void) 548280304Sjkim{ 549280304Sjkim IMPL_CHECK return EX_IMPL(new_class) (); 550280304Sjkim} 551109998Smarkm 552280304Sjkim/* 553280304Sjkim * Release all "ex_data" state to prevent memory leaks. This can't be made 554109998Smarkm * thread-safe without overhauling a lot of stuff, and shouldn't really be 555109998Smarkm * called under potential race-conditions anyway (it's for program shutdown 556280304Sjkim * after all). 557280304Sjkim */ 558109998Smarkmvoid CRYPTO_cleanup_all_ex_data(void) 559280304Sjkim{ 560280304Sjkim IMPL_CHECK EX_IMPL(cleanup) (); 561280304Sjkim} 562109998Smarkm 563109998Smarkm/* Inside an existing class, get/register a new index. */ 564109998Smarkmint CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, 565280304Sjkim CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 566280304Sjkim CRYPTO_EX_free *free_func) 567280304Sjkim{ 568280304Sjkim int ret = -1; 569109998Smarkm 570280304Sjkim IMPL_CHECK 571280304Sjkim ret = EX_IMPL(get_new_index) (class_index, 572280304Sjkim argl, argp, new_func, dup_func, 573280304Sjkim free_func); 574280304Sjkim return ret; 575280304Sjkim} 576109998Smarkm 577280304Sjkim/* 578280304Sjkim * Initialise a new CRYPTO_EX_DATA for use in a particular class - including 579280304Sjkim * calling new() callbacks for each index in the class used by this variable 580280304Sjkim */ 581109998Smarkmint CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 582280304Sjkim{ 583280304Sjkim IMPL_CHECK return EX_IMPL(new_ex_data) (class_index, obj, ad); 584280304Sjkim} 585109998Smarkm 586280304Sjkim/* 587280304Sjkim * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks 588280304Sjkim * for each index in the class used by this variable 589280304Sjkim */ 590109998Smarkmint CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, 591280304Sjkim CRYPTO_EX_DATA *from) 592280304Sjkim{ 593280304Sjkim IMPL_CHECK return EX_IMPL(dup_ex_data) (class_index, to, from); 594280304Sjkim} 595109998Smarkm 596280304Sjkim/* 597280304Sjkim * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for 598280304Sjkim * each index in the class used by this variable 599280304Sjkim */ 600109998Smarkmvoid CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 601280304Sjkim{ 602280304Sjkim IMPL_CHECK EX_IMPL(free_ex_data) (class_index, obj, ad); 603280304Sjkim} 604109998Smarkm 605280304Sjkim/* 606280304Sjkim * For a given CRYPTO_EX_DATA variable, set the value corresponding to a 607280304Sjkim * particular index in the class used by this variable 608280304Sjkim */ 60959191Skrisint CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val) 610280304Sjkim{ 611280304Sjkim int i; 61255714Skris 613280304Sjkim if (ad->sk == NULL) { 614280304Sjkim if ((ad->sk = sk_void_new_null()) == NULL) { 615280304Sjkim CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE); 616280304Sjkim return (0); 617280304Sjkim } 618280304Sjkim } 619280304Sjkim i = sk_void_num(ad->sk); 62055714Skris 621280304Sjkim while (i <= idx) { 622280304Sjkim if (!sk_void_push(ad->sk, NULL)) { 623280304Sjkim CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE); 624280304Sjkim return (0); 625280304Sjkim } 626280304Sjkim i++; 627280304Sjkim } 628280304Sjkim sk_void_set(ad->sk, idx, val); 629280304Sjkim return (1); 630280304Sjkim} 63155714Skris 632280304Sjkim/* 633280304Sjkim * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a 634280304Sjkim * particular index in the class used by this variable 635280304Sjkim */ 636109998Smarkmvoid *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx) 637280304Sjkim{ 638280304Sjkim if (ad->sk == NULL) 639280304Sjkim return (0); 640280304Sjkim else if (idx >= sk_void_num(ad->sk)) 641280304Sjkim return (0); 642280304Sjkim else 643280304Sjkim return (sk_void_value(ad->sk, idx)); 644280304Sjkim} 64555714Skris 64659191SkrisIMPLEMENT_STACK_OF(CRYPTO_EX_DATA_FUNCS) 647