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. 37296341Sdelphij * 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). 44296341Sdelphij * 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. 51296341Sdelphij * 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 :-). 66296341Sdelphij * 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)" 69296341Sdelphij * 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. 81296341Sdelphij * 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 95296341Sdelphij * 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 */ 145296341Sdelphijstruct st_CRYPTO_EX_DATA_IMPL { 146296341Sdelphij /*********************/ 147296341Sdelphij /* GLOBAL OPERATIONS */ 148296341Sdelphij /* Return a new class index */ 149296341Sdelphij int (*cb_new_class) (void); 150296341Sdelphij /* Cleanup all state used by the implementation */ 151296341Sdelphij void (*cb_cleanup) (void); 152296341Sdelphij /************************/ 153296341Sdelphij /* PER-CLASS OPERATIONS */ 154296341Sdelphij /* Get a new method index within a class */ 155296341Sdelphij int (*cb_get_new_index) (int class_index, long argl, void *argp, 156296341Sdelphij CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 157296341Sdelphij CRYPTO_EX_free *free_func); 158296341Sdelphij /* Initialise a new CRYPTO_EX_DATA of a given class */ 159296341Sdelphij int (*cb_new_ex_data) (int class_index, void *obj, CRYPTO_EX_DATA *ad); 160296341Sdelphij /* Duplicate a CRYPTO_EX_DATA of a given class onto a copy */ 161296341Sdelphij int (*cb_dup_ex_data) (int class_index, CRYPTO_EX_DATA *to, 162296341Sdelphij CRYPTO_EX_DATA *from); 163296341Sdelphij /* Cleanup a CRYPTO_EX_DATA of a given class */ 164296341Sdelphij void (*cb_free_ex_data) (int class_index, void *obj, CRYPTO_EX_DATA *ad); 165296341Sdelphij}; 16655714Skris 167109998Smarkm/* The implementation we use at run-time */ 168109998Smarkmstatic const CRYPTO_EX_DATA_IMPL *impl = NULL; 169109998Smarkm 170296341Sdelphij/* 171296341Sdelphij * To call "impl" functions, use this macro rather than referring to 'impl' 172296341Sdelphij * directly, eg. EX_IMPL(get_new_index)(...); 173296341Sdelphij */ 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, 180296341Sdelphij CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 181296341Sdelphij CRYPTO_EX_free *free_func); 182296341Sdelphijstatic 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, 184296341Sdelphij CRYPTO_EX_DATA *from); 185296341Sdelphijstatic void int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad); 186296341Sdelphijstatic CRYPTO_EX_DATA_IMPL impl_default = { 187296341Sdelphij int_new_class, 188296341Sdelphij int_cleanup, 189296341Sdelphij int_get_new_index, 190296341Sdelphij int_new_ex_data, 191296341Sdelphij int_dup_ex_data, 192296341Sdelphij int_free_ex_data 193296341Sdelphij}; 194109998Smarkm 195296341Sdelphij/* 196296341Sdelphij * Internal function that checks whether "impl" is set and if not, sets it to 197296341Sdelphij * the default. 198296341Sdelphij */ 199109998Smarkmstatic void impl_check(void) 200296341Sdelphij{ 201296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 202296341Sdelphij if (!impl) 203296341Sdelphij impl = &impl_default; 204296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 205296341Sdelphij} 206296341Sdelphij 207296341Sdelphij/* 208296341Sdelphij * A macro wrapper for impl_check that first uses a non-locked test before 209296341Sdelphij * invoking the function (which checks again inside a lock). 210296341Sdelphij */ 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) 215296341Sdelphij{ 216296341Sdelphij IMPL_CHECK return impl; 217296341Sdelphij} 218296341Sdelphij 219109998Smarkmint CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i) 220296341Sdelphij{ 221296341Sdelphij int toret = 0; 222296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 223296341Sdelphij if (!impl) { 224296341Sdelphij impl = i; 225296341Sdelphij toret = 1; 226296341Sdelphij } 227296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 228296341Sdelphij return toret; 229296341Sdelphij} 230109998Smarkm 231109998Smarkm/****************************************************************************/ 232296341Sdelphij/* 233296341Sdelphij * Interal (default) implementation of "ex_data" support. API functions are 234296341Sdelphij * further down. 235296341Sdelphij */ 236109998Smarkm 237296341Sdelphij/* 238296341Sdelphij * The type that represents what each "class" used to implement locally. A 239296341Sdelphij * STACK of CRYPTO_EX_DATA_FUNCS plus a index-counter. The 'class_index' is 240296341Sdelphij * the global value representing the class that is used to distinguish these 241296341Sdelphij * items. 242296341Sdelphij */ 243109998Smarkmtypedef struct st_ex_class_item { 244296341Sdelphij int class_index; 245296341Sdelphij STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth; 246296341Sdelphij 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) 258296341Sdelphij{ 259296341Sdelphij return a->class_index; 260296341Sdelphij} 261296341Sdelphij 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) 265296341Sdelphij{ 266296341Sdelphij return a->class_index - b->class_index; 267296341Sdelphij} 268296341Sdelphij 269238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(ex_class_item, EX_CLASS_ITEM) 270109998Smarkm 271296341Sdelphij/* 272296341Sdelphij * Internal functions used by the "impl_default" implementation to access the 273296341Sdelphij * state 274296341Sdelphij */ 275296341Sdelphijstatic int ex_data_check(void) 276296341Sdelphij{ 277296341Sdelphij int toret = 1; 278296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 279296341Sdelphij if (!ex_data && (ex_data = lh_EX_CLASS_ITEM_new()) == NULL) 280296341Sdelphij toret = 0; 281296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 282296341Sdelphij return toret; 283296341Sdelphij} 284109998Smarkm 285296341Sdelphij/* 286296341Sdelphij * This macros helps reduce the locking from repeated checks because the 287296341Sdelphij * ex_data_check() function checks ex_data again inside a lock. 288296341Sdelphij */ 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) 293296341Sdelphij{ 294296341Sdelphij OPENSSL_free(funcs); 295296341Sdelphij} 296109998Smarkm 297296341Sdelphij/* 298296341Sdelphij * This callback is used in lh_doall to destroy all EX_CLASS_ITEM values from 299296341Sdelphij * "ex_data" prior to the ex_data hash table being itself destroyed. Doesn't 300296341Sdelphij * do any locking. 301296341Sdelphij */ 302160814Ssimonstatic void def_cleanup_cb(void *a_void) 303296341Sdelphij{ 304296341Sdelphij EX_CLASS_ITEM *item = (EX_CLASS_ITEM *)a_void; 305296341Sdelphij sk_CRYPTO_EX_DATA_FUNCS_pop_free(item->meth, def_cleanup_util_cb); 306296341Sdelphij OPENSSL_free(item); 307296341Sdelphij} 308109998Smarkm 309296341Sdelphij/* 310296341Sdelphij * Return the EX_CLASS_ITEM from the "ex_data" hash table that corresponds to 311296341Sdelphij * a given class. Handles locking. 312296341Sdelphij */ 313109998Smarkmstatic EX_CLASS_ITEM *def_get_class(int class_index) 314296341Sdelphij{ 315296341Sdelphij EX_CLASS_ITEM d, *p, *gen; 316296341Sdelphij EX_DATA_CHECK(return NULL;) 317296341Sdelphij d.class_index = class_index; 318296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 319296341Sdelphij p = lh_EX_CLASS_ITEM_retrieve(ex_data, &d); 320296341Sdelphij if (!p) { 321296341Sdelphij gen = OPENSSL_malloc(sizeof(EX_CLASS_ITEM)); 322296341Sdelphij if (gen) { 323296341Sdelphij gen->class_index = class_index; 324296341Sdelphij gen->meth_num = 0; 325296341Sdelphij gen->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null(); 326296341Sdelphij if (!gen->meth) 327296341Sdelphij OPENSSL_free(gen); 328296341Sdelphij else { 329296341Sdelphij /* 330296341Sdelphij * Because we're inside the ex_data lock, the return value 331296341Sdelphij * from the insert will be NULL 332296341Sdelphij */ 333296341Sdelphij (void)lh_EX_CLASS_ITEM_insert(ex_data, gen); 334296341Sdelphij p = gen; 335296341Sdelphij } 336296341Sdelphij } 337296341Sdelphij } 338296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 339296341Sdelphij if (!p) 340296341Sdelphij CRYPTOerr(CRYPTO_F_DEF_GET_CLASS, ERR_R_MALLOC_FAILURE); 341296341Sdelphij return p; 342296341Sdelphij} 343109998Smarkm 344296341Sdelphij/* 345296341Sdelphij * Add a new method to the given EX_CLASS_ITEM and return the corresponding 346296341Sdelphij * index (or -1 for error). Handles locking. 347296341Sdelphij */ 348109998Smarkmstatic int def_add_index(EX_CLASS_ITEM *item, long argl, void *argp, 349296341Sdelphij CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 350296341Sdelphij CRYPTO_EX_free *free_func) 351296341Sdelphij{ 352296341Sdelphij int toret = -1; 353296341Sdelphij CRYPTO_EX_DATA_FUNCS *a = 354296341Sdelphij (CRYPTO_EX_DATA_FUNCS *)OPENSSL_malloc(sizeof(CRYPTO_EX_DATA_FUNCS)); 355296341Sdelphij if (!a) { 356296341Sdelphij CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX, ERR_R_MALLOC_FAILURE); 357296341Sdelphij return -1; 358296341Sdelphij } 359296341Sdelphij a->argl = argl; 360296341Sdelphij a->argp = argp; 361296341Sdelphij a->new_func = new_func; 362296341Sdelphij a->dup_func = dup_func; 363296341Sdelphij a->free_func = free_func; 364296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 365296341Sdelphij while (sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) <= item->meth_num) { 366296341Sdelphij if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, NULL)) { 367296341Sdelphij CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX, ERR_R_MALLOC_FAILURE); 368296341Sdelphij OPENSSL_free(a); 369296341Sdelphij goto err; 370296341Sdelphij } 371296341Sdelphij } 372296341Sdelphij toret = item->meth_num++; 373296341Sdelphij (void)sk_CRYPTO_EX_DATA_FUNCS_set(item->meth, toret, a); 374296341Sdelphij err: 375296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 376296341Sdelphij return toret; 377296341Sdelphij} 37855714Skris 379109998Smarkm/**************************************************************/ 380109998Smarkm/* The functions in the default CRYPTO_EX_DATA_IMPL structure */ 381109998Smarkm 382109998Smarkmstatic int int_new_class(void) 383296341Sdelphij{ 384296341Sdelphij int toret; 385296341Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 386296341Sdelphij toret = ex_class++; 387296341Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 388296341Sdelphij return toret; 389296341Sdelphij} 390109998Smarkm 391109998Smarkmstatic void int_cleanup(void) 392296341Sdelphij{ 393296341Sdelphij EX_DATA_CHECK(return;) 394296341Sdelphij lh_EX_CLASS_ITEM_doall(ex_data, def_cleanup_cb); 395296341Sdelphij lh_EX_CLASS_ITEM_free(ex_data); 396296341Sdelphij ex_data = NULL; 397296341Sdelphij impl = NULL; 398296341Sdelphij} 399109998Smarkm 400109998Smarkmstatic int int_get_new_index(int class_index, long argl, void *argp, 401296341Sdelphij CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 402296341Sdelphij CRYPTO_EX_free *free_func) 403296341Sdelphij{ 404296341Sdelphij EX_CLASS_ITEM *item = def_get_class(class_index); 405296341Sdelphij if (!item) 406296341Sdelphij return -1; 407296341Sdelphij return def_add_index(item, argl, argp, new_func, dup_func, free_func); 408296341Sdelphij} 409109998Smarkm 410296341Sdelphij/* 411296341Sdelphij * Thread-safe by copying a class's array of "CRYPTO_EX_DATA_FUNCS" entries 412296341Sdelphij * in the lock, then using them outside the lock. NB: Thread-safety only 413296341Sdelphij * applies to the global "ex_data" state (ie. class definitions), not 414296341Sdelphij * thread-safe on 'ad' itself. 415296341Sdelphij */ 416296341Sdelphijstatic int int_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 417296341Sdelphij{ 418296341Sdelphij int mx, i; 419296341Sdelphij void *ptr; 420296341Sdelphij CRYPTO_EX_DATA_FUNCS **storage = NULL; 421296341Sdelphij EX_CLASS_ITEM *item = def_get_class(class_index); 422296341Sdelphij if (!item) 423296341Sdelphij /* error is already set */ 424296341Sdelphij return 0; 425296341Sdelphij ad->sk = NULL; 426296341Sdelphij CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); 427296341Sdelphij mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); 428296341Sdelphij if (mx > 0) { 429296341Sdelphij storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *)); 430296341Sdelphij if (!storage) 431296341Sdelphij goto skip; 432296341Sdelphij for (i = 0; i < mx; i++) 433296341Sdelphij storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); 434296341Sdelphij } 435296341Sdelphij skip: 436296341Sdelphij CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); 437296341Sdelphij if ((mx > 0) && !storage) { 438296341Sdelphij CRYPTOerr(CRYPTO_F_INT_NEW_EX_DATA, ERR_R_MALLOC_FAILURE); 439296341Sdelphij return 0; 440296341Sdelphij } 441296341Sdelphij for (i = 0; i < mx; i++) { 442296341Sdelphij if (storage[i] && storage[i]->new_func) { 443296341Sdelphij ptr = CRYPTO_get_ex_data(ad, i); 444296341Sdelphij storage[i]->new_func(obj, ptr, ad, i, 445296341Sdelphij storage[i]->argl, storage[i]->argp); 446296341Sdelphij } 447296341Sdelphij } 448296341Sdelphij if (storage) 449296341Sdelphij OPENSSL_free(storage); 450296341Sdelphij return 1; 451296341Sdelphij} 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, 455296341Sdelphij CRYPTO_EX_DATA *from) 456296341Sdelphij{ 457296341Sdelphij int mx, j, i; 458296341Sdelphij char *ptr; 459296341Sdelphij CRYPTO_EX_DATA_FUNCS **storage = NULL; 460296341Sdelphij EX_CLASS_ITEM *item; 461296341Sdelphij if (!from->sk) 462296341Sdelphij /* 'to' should be "blank" which *is* just like 'from' */ 463296341Sdelphij return 1; 464296341Sdelphij if ((item = def_get_class(class_index)) == NULL) 465296341Sdelphij return 0; 466296341Sdelphij CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); 467296341Sdelphij mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); 468296341Sdelphij j = sk_void_num(from->sk); 469296341Sdelphij if (j < mx) 470296341Sdelphij mx = j; 471296341Sdelphij if (mx > 0) { 472296341Sdelphij storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *)); 473296341Sdelphij if (!storage) 474296341Sdelphij goto skip; 475296341Sdelphij for (i = 0; i < mx; i++) 476296341Sdelphij storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); 477296341Sdelphij } 478296341Sdelphij skip: 479296341Sdelphij CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); 480296341Sdelphij if ((mx > 0) && !storage) { 481296341Sdelphij CRYPTOerr(CRYPTO_F_INT_DUP_EX_DATA, ERR_R_MALLOC_FAILURE); 482296341Sdelphij return 0; 483296341Sdelphij } 484296341Sdelphij for (i = 0; i < mx; i++) { 485296341Sdelphij ptr = CRYPTO_get_ex_data(from, i); 486296341Sdelphij if (storage[i] && storage[i]->dup_func) 487296341Sdelphij storage[i]->dup_func(to, from, &ptr, i, 488296341Sdelphij storage[i]->argl, storage[i]->argp); 489296341Sdelphij CRYPTO_set_ex_data(to, i, ptr); 490296341Sdelphij } 491296341Sdelphij if (storage) 492296341Sdelphij OPENSSL_free(storage); 493296341Sdelphij return 1; 494296341Sdelphij} 495109998Smarkm 496109998Smarkm/* Same thread-safety notes as for "int_new_ex_data" */ 497296341Sdelphijstatic void int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 498296341Sdelphij{ 499296341Sdelphij int mx, i; 500296341Sdelphij EX_CLASS_ITEM *item; 501296341Sdelphij void *ptr; 502296341Sdelphij CRYPTO_EX_DATA_FUNCS **storage = NULL; 503296341Sdelphij if (ex_data == NULL) 504296341Sdelphij return; 505296341Sdelphij if ((item = def_get_class(class_index)) == NULL) 506296341Sdelphij return; 507296341Sdelphij CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); 508296341Sdelphij mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); 509296341Sdelphij if (mx > 0) { 510296341Sdelphij storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *)); 511296341Sdelphij if (!storage) 512296341Sdelphij goto skip; 513296341Sdelphij for (i = 0; i < mx; i++) 514296341Sdelphij storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); 515296341Sdelphij } 516296341Sdelphij skip: 517296341Sdelphij CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); 518296341Sdelphij if ((mx > 0) && !storage) { 519296341Sdelphij CRYPTOerr(CRYPTO_F_INT_FREE_EX_DATA, ERR_R_MALLOC_FAILURE); 520296341Sdelphij return; 521296341Sdelphij } 522296341Sdelphij for (i = 0; i < mx; i++) { 523296341Sdelphij if (storage[i] && storage[i]->free_func) { 524296341Sdelphij ptr = CRYPTO_get_ex_data(ad, i); 525296341Sdelphij storage[i]->free_func(obj, ptr, ad, i, 526296341Sdelphij storage[i]->argl, storage[i]->argp); 527296341Sdelphij } 528296341Sdelphij } 529296341Sdelphij if (storage) 530296341Sdelphij OPENSSL_free(storage); 531296341Sdelphij if (ad->sk) { 532296341Sdelphij sk_void_free(ad->sk); 533296341Sdelphij ad->sk = NULL; 534296341Sdelphij } 535296341Sdelphij} 536109998Smarkm 537109998Smarkm/********************************************************************/ 538296341Sdelphij/* 539296341Sdelphij * API functions that defer all "state" operations to the "ex_data" 540296341Sdelphij * implementation we have set. 541296341Sdelphij */ 542109998Smarkm 543296341Sdelphij/* 544296341Sdelphij * Obtain an index for a new class (not the same as getting a new index 545296341Sdelphij * within an existing class - this is actually getting a new *class*) 546296341Sdelphij */ 547109998Smarkmint CRYPTO_ex_data_new_class(void) 548296341Sdelphij{ 549296341Sdelphij IMPL_CHECK return EX_IMPL(new_class) (); 550296341Sdelphij} 551109998Smarkm 552296341Sdelphij/* 553296341Sdelphij * 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 556296341Sdelphij * after all). 557296341Sdelphij */ 558109998Smarkmvoid CRYPTO_cleanup_all_ex_data(void) 559296341Sdelphij{ 560296341Sdelphij IMPL_CHECK EX_IMPL(cleanup) (); 561296341Sdelphij} 562109998Smarkm 563109998Smarkm/* Inside an existing class, get/register a new index. */ 564109998Smarkmint CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, 565296341Sdelphij CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 566296341Sdelphij CRYPTO_EX_free *free_func) 567296341Sdelphij{ 568296341Sdelphij int ret = -1; 569109998Smarkm 570296341Sdelphij IMPL_CHECK 571296341Sdelphij ret = EX_IMPL(get_new_index) (class_index, 572296341Sdelphij argl, argp, new_func, dup_func, 573296341Sdelphij free_func); 574296341Sdelphij return ret; 575296341Sdelphij} 576109998Smarkm 577296341Sdelphij/* 578296341Sdelphij * Initialise a new CRYPTO_EX_DATA for use in a particular class - including 579296341Sdelphij * calling new() callbacks for each index in the class used by this variable 580296341Sdelphij */ 581109998Smarkmint CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 582296341Sdelphij{ 583296341Sdelphij IMPL_CHECK return EX_IMPL(new_ex_data) (class_index, obj, ad); 584296341Sdelphij} 585109998Smarkm 586296341Sdelphij/* 587296341Sdelphij * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks 588296341Sdelphij * for each index in the class used by this variable 589296341Sdelphij */ 590109998Smarkmint CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, 591296341Sdelphij CRYPTO_EX_DATA *from) 592296341Sdelphij{ 593296341Sdelphij IMPL_CHECK return EX_IMPL(dup_ex_data) (class_index, to, from); 594296341Sdelphij} 595109998Smarkm 596296341Sdelphij/* 597296341Sdelphij * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for 598296341Sdelphij * each index in the class used by this variable 599296341Sdelphij */ 600109998Smarkmvoid CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 601296341Sdelphij{ 602296341Sdelphij IMPL_CHECK EX_IMPL(free_ex_data) (class_index, obj, ad); 603296341Sdelphij} 604109998Smarkm 605296341Sdelphij/* 606296341Sdelphij * For a given CRYPTO_EX_DATA variable, set the value corresponding to a 607296341Sdelphij * particular index in the class used by this variable 608296341Sdelphij */ 60959191Skrisint CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val) 610296341Sdelphij{ 611296341Sdelphij int i; 61255714Skris 613296341Sdelphij if (ad->sk == NULL) { 614296341Sdelphij if ((ad->sk = sk_void_new_null()) == NULL) { 615296341Sdelphij CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE); 616296341Sdelphij return (0); 617296341Sdelphij } 618296341Sdelphij } 619296341Sdelphij i = sk_void_num(ad->sk); 62055714Skris 621296341Sdelphij while (i <= idx) { 622296341Sdelphij if (!sk_void_push(ad->sk, NULL)) { 623296341Sdelphij CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE); 624296341Sdelphij return (0); 625296341Sdelphij } 626296341Sdelphij i++; 627296341Sdelphij } 628296341Sdelphij sk_void_set(ad->sk, idx, val); 629296341Sdelphij return (1); 630296341Sdelphij} 63155714Skris 632296341Sdelphij/* 633296341Sdelphij * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a 634296341Sdelphij * particular index in the class used by this variable 635296341Sdelphij */ 636109998Smarkmvoid *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx) 637296341Sdelphij{ 638296341Sdelphij if (ad->sk == NULL) 639296341Sdelphij return (0); 640296341Sdelphij else if (idx >= sk_void_num(ad->sk)) 641296341Sdelphij return (0); 642296341Sdelphij else 643296341Sdelphij return (sk_void_value(ad->sk, idx)); 644296341Sdelphij} 64555714Skris 64659191SkrisIMPLEMENT_STACK_OF(CRYPTO_EX_DATA_FUNCS) 647