1*0Sstevel@tonic-gate /* crypto/ex_data.c */ 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gate /* 4*0Sstevel@tonic-gate * Overhaul notes; 5*0Sstevel@tonic-gate * 6*0Sstevel@tonic-gate * This code is now *mostly* thread-safe. It is now easier to understand in what 7*0Sstevel@tonic-gate * ways it is safe and in what ways it is not, which is an improvement. Firstly, 8*0Sstevel@tonic-gate * all per-class stacks and index-counters for ex_data are stored in the same 9*0Sstevel@tonic-gate * global LHASH table (keyed by class). This hash table uses locking for all 10*0Sstevel@tonic-gate * access with the exception of CRYPTO_cleanup_all_ex_data(), which must only be 11*0Sstevel@tonic-gate * called when no other threads can possibly race against it (even if it was 12*0Sstevel@tonic-gate * locked, the race would mean it's possible the hash table might have been 13*0Sstevel@tonic-gate * recreated after the cleanup). As classes can only be added to the hash table, 14*0Sstevel@tonic-gate * and within each class, the stack of methods can only be incremented, the 15*0Sstevel@tonic-gate * locking mechanics are simpler than they would otherwise be. For example, the 16*0Sstevel@tonic-gate * new/dup/free ex_data functions will lock the hash table, copy the method 17*0Sstevel@tonic-gate * pointers it needs from the relevant class, then unlock the hash table before 18*0Sstevel@tonic-gate * actually applying those method pointers to the task of the new/dup/free 19*0Sstevel@tonic-gate * operations. As they can't be removed from the method-stack, only 20*0Sstevel@tonic-gate * supplemented, there's no race conditions associated with using them outside 21*0Sstevel@tonic-gate * the lock. The get/set_ex_data functions are not locked because they do not 22*0Sstevel@tonic-gate * involve this global state at all - they operate directly with a previously 23*0Sstevel@tonic-gate * obtained per-class method index and a particular "ex_data" variable. These 24*0Sstevel@tonic-gate * variables are usually instantiated per-context (eg. each RSA structure has 25*0Sstevel@tonic-gate * one) so locking on read/write access to that variable can be locked locally 26*0Sstevel@tonic-gate * if required (eg. using the "RSA" lock to synchronise access to a 27*0Sstevel@tonic-gate * per-RSA-structure ex_data variable if required). 28*0Sstevel@tonic-gate * [Geoff] 29*0Sstevel@tonic-gate */ 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 32*0Sstevel@tonic-gate * All rights reserved. 33*0Sstevel@tonic-gate * 34*0Sstevel@tonic-gate * This package is an SSL implementation written 35*0Sstevel@tonic-gate * by Eric Young (eay@cryptsoft.com). 36*0Sstevel@tonic-gate * The implementation was written so as to conform with Netscapes SSL. 37*0Sstevel@tonic-gate * 38*0Sstevel@tonic-gate * This library is free for commercial and non-commercial use as long as 39*0Sstevel@tonic-gate * the following conditions are aheared to. The following conditions 40*0Sstevel@tonic-gate * apply to all code found in this distribution, be it the RC4, RSA, 41*0Sstevel@tonic-gate * lhash, DES, etc., code; not just the SSL code. The SSL documentation 42*0Sstevel@tonic-gate * included with this distribution is covered by the same copyright terms 43*0Sstevel@tonic-gate * except that the holder is Tim Hudson (tjh@cryptsoft.com). 44*0Sstevel@tonic-gate * 45*0Sstevel@tonic-gate * Copyright remains Eric Young's, and as such any Copyright notices in 46*0Sstevel@tonic-gate * the code are not to be removed. 47*0Sstevel@tonic-gate * If this package is used in a product, Eric Young should be given attribution 48*0Sstevel@tonic-gate * as the author of the parts of the library used. 49*0Sstevel@tonic-gate * This can be in the form of a textual message at program startup or 50*0Sstevel@tonic-gate * in documentation (online or textual) provided with the package. 51*0Sstevel@tonic-gate * 52*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 53*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 54*0Sstevel@tonic-gate * are met: 55*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the copyright 56*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 57*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 58*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 59*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 60*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software 61*0Sstevel@tonic-gate * must display the following acknowledgement: 62*0Sstevel@tonic-gate * "This product includes cryptographic software written by 63*0Sstevel@tonic-gate * Eric Young (eay@cryptsoft.com)" 64*0Sstevel@tonic-gate * The word 'cryptographic' can be left out if the rouines from the library 65*0Sstevel@tonic-gate * being used are not cryptographic related :-). 66*0Sstevel@tonic-gate * 4. If you include any Windows specific code (or a derivative thereof) from 67*0Sstevel@tonic-gate * the apps directory (application code) you must include an acknowledgement: 68*0Sstevel@tonic-gate * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 69*0Sstevel@tonic-gate * 70*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 71*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 72*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 73*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 74*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 75*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 76*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 77*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 78*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 79*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 80*0Sstevel@tonic-gate * SUCH DAMAGE. 81*0Sstevel@tonic-gate * 82*0Sstevel@tonic-gate * The licence and distribution terms for any publically available version or 83*0Sstevel@tonic-gate * derivative of this code cannot be changed. i.e. this code cannot simply be 84*0Sstevel@tonic-gate * copied and put under another distribution licence 85*0Sstevel@tonic-gate * [including the GNU Public Licence.] 86*0Sstevel@tonic-gate */ 87*0Sstevel@tonic-gate /* ==================================================================== 88*0Sstevel@tonic-gate * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. 89*0Sstevel@tonic-gate * 90*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 91*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 92*0Sstevel@tonic-gate * are met: 93*0Sstevel@tonic-gate * 94*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 95*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 96*0Sstevel@tonic-gate * 97*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 98*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in 99*0Sstevel@tonic-gate * the documentation and/or other materials provided with the 100*0Sstevel@tonic-gate * distribution. 101*0Sstevel@tonic-gate * 102*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this 103*0Sstevel@tonic-gate * software must display the following acknowledgment: 104*0Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project 105*0Sstevel@tonic-gate * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 106*0Sstevel@tonic-gate * 107*0Sstevel@tonic-gate * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 108*0Sstevel@tonic-gate * endorse or promote products derived from this software without 109*0Sstevel@tonic-gate * prior written permission. For written permission, please contact 110*0Sstevel@tonic-gate * openssl-core@openssl.org. 111*0Sstevel@tonic-gate * 112*0Sstevel@tonic-gate * 5. Products derived from this software may not be called "OpenSSL" 113*0Sstevel@tonic-gate * nor may "OpenSSL" appear in their names without prior written 114*0Sstevel@tonic-gate * permission of the OpenSSL Project. 115*0Sstevel@tonic-gate * 116*0Sstevel@tonic-gate * 6. Redistributions of any form whatsoever must retain the following 117*0Sstevel@tonic-gate * acknowledgment: 118*0Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project 119*0Sstevel@tonic-gate * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 120*0Sstevel@tonic-gate * 121*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 122*0Sstevel@tonic-gate * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 123*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 124*0Sstevel@tonic-gate * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 125*0Sstevel@tonic-gate * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 126*0Sstevel@tonic-gate * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 127*0Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 128*0Sstevel@tonic-gate * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 129*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 130*0Sstevel@tonic-gate * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 131*0Sstevel@tonic-gate * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 132*0Sstevel@tonic-gate * OF THE POSSIBILITY OF SUCH DAMAGE. 133*0Sstevel@tonic-gate * ==================================================================== 134*0Sstevel@tonic-gate * 135*0Sstevel@tonic-gate * This product includes cryptographic software written by Eric Young 136*0Sstevel@tonic-gate * (eay@cryptsoft.com). This product includes software written by Tim 137*0Sstevel@tonic-gate * Hudson (tjh@cryptsoft.com). 138*0Sstevel@tonic-gate * 139*0Sstevel@tonic-gate */ 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate #include <stdio.h> 142*0Sstevel@tonic-gate #include <stdlib.h> 143*0Sstevel@tonic-gate #include <openssl/buffer.h> 144*0Sstevel@tonic-gate #include <openssl/bio.h> 145*0Sstevel@tonic-gate #include <openssl/lhash.h> 146*0Sstevel@tonic-gate #include "cryptlib.h" 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate /* What an "implementation of ex_data functionality" looks like */ 149*0Sstevel@tonic-gate struct st_CRYPTO_EX_DATA_IMPL 150*0Sstevel@tonic-gate { 151*0Sstevel@tonic-gate /*********************/ 152*0Sstevel@tonic-gate /* GLOBAL OPERATIONS */ 153*0Sstevel@tonic-gate /* Return a new class index */ 154*0Sstevel@tonic-gate int (*cb_new_class)(void); 155*0Sstevel@tonic-gate /* Cleanup all state used by the implementation */ 156*0Sstevel@tonic-gate void (*cb_cleanup)(void); 157*0Sstevel@tonic-gate /************************/ 158*0Sstevel@tonic-gate /* PER-CLASS OPERATIONS */ 159*0Sstevel@tonic-gate /* Get a new method index within a class */ 160*0Sstevel@tonic-gate int (*cb_get_new_index)(int class_index, long argl, void *argp, 161*0Sstevel@tonic-gate CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 162*0Sstevel@tonic-gate CRYPTO_EX_free *free_func); 163*0Sstevel@tonic-gate /* Initialise a new CRYPTO_EX_DATA of a given class */ 164*0Sstevel@tonic-gate int (*cb_new_ex_data)(int class_index, void *obj, 165*0Sstevel@tonic-gate CRYPTO_EX_DATA *ad); 166*0Sstevel@tonic-gate /* Duplicate a CRYPTO_EX_DATA of a given class onto a copy */ 167*0Sstevel@tonic-gate int (*cb_dup_ex_data)(int class_index, CRYPTO_EX_DATA *to, 168*0Sstevel@tonic-gate CRYPTO_EX_DATA *from); 169*0Sstevel@tonic-gate /* Cleanup a CRYPTO_EX_DATA of a given class */ 170*0Sstevel@tonic-gate void (*cb_free_ex_data)(int class_index, void *obj, 171*0Sstevel@tonic-gate CRYPTO_EX_DATA *ad); 172*0Sstevel@tonic-gate }; 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate /* The implementation we use at run-time */ 175*0Sstevel@tonic-gate static const CRYPTO_EX_DATA_IMPL *impl = NULL; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate /* To call "impl" functions, use this macro rather than referring to 'impl' directly, eg. 178*0Sstevel@tonic-gate * EX_IMPL(get_new_index)(...); */ 179*0Sstevel@tonic-gate #define EX_IMPL(a) impl->cb_##a 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate /* Predeclare the "default" ex_data implementation */ 182*0Sstevel@tonic-gate static int int_new_class(void); 183*0Sstevel@tonic-gate static void int_cleanup(void); 184*0Sstevel@tonic-gate static int int_get_new_index(int class_index, long argl, void *argp, 185*0Sstevel@tonic-gate CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 186*0Sstevel@tonic-gate CRYPTO_EX_free *free_func); 187*0Sstevel@tonic-gate static int int_new_ex_data(int class_index, void *obj, 188*0Sstevel@tonic-gate CRYPTO_EX_DATA *ad); 189*0Sstevel@tonic-gate static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, 190*0Sstevel@tonic-gate CRYPTO_EX_DATA *from); 191*0Sstevel@tonic-gate static void int_free_ex_data(int class_index, void *obj, 192*0Sstevel@tonic-gate CRYPTO_EX_DATA *ad); 193*0Sstevel@tonic-gate static CRYPTO_EX_DATA_IMPL impl_default = 194*0Sstevel@tonic-gate { 195*0Sstevel@tonic-gate int_new_class, 196*0Sstevel@tonic-gate int_cleanup, 197*0Sstevel@tonic-gate int_get_new_index, 198*0Sstevel@tonic-gate int_new_ex_data, 199*0Sstevel@tonic-gate int_dup_ex_data, 200*0Sstevel@tonic-gate int_free_ex_data 201*0Sstevel@tonic-gate }; 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate /* Internal function that checks whether "impl" is set and if not, sets it to 204*0Sstevel@tonic-gate * the default. */ 205*0Sstevel@tonic-gate static void impl_check(void) 206*0Sstevel@tonic-gate { 207*0Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 208*0Sstevel@tonic-gate if(!impl) 209*0Sstevel@tonic-gate impl = &impl_default; 210*0Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate /* A macro wrapper for impl_check that first uses a non-locked test before 213*0Sstevel@tonic-gate * invoking the function (which checks again inside a lock). */ 214*0Sstevel@tonic-gate #define IMPL_CHECK if(!impl) impl_check(); 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* API functions to get/set the "ex_data" implementation */ 217*0Sstevel@tonic-gate const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void) 218*0Sstevel@tonic-gate { 219*0Sstevel@tonic-gate IMPL_CHECK 220*0Sstevel@tonic-gate return impl; 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i) 223*0Sstevel@tonic-gate { 224*0Sstevel@tonic-gate int toret = 0; 225*0Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 226*0Sstevel@tonic-gate if(!impl) 227*0Sstevel@tonic-gate { 228*0Sstevel@tonic-gate impl = i; 229*0Sstevel@tonic-gate toret = 1; 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 232*0Sstevel@tonic-gate return toret; 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate /****************************************************************************/ 236*0Sstevel@tonic-gate /* Interal (default) implementation of "ex_data" support. API functions are 237*0Sstevel@tonic-gate * further down. */ 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate /* The type that represents what each "class" used to implement locally. A STACK 240*0Sstevel@tonic-gate * of CRYPTO_EX_DATA_FUNCS plus a index-counter. The 'class_index' is the global 241*0Sstevel@tonic-gate * value representing the class that is used to distinguish these items. */ 242*0Sstevel@tonic-gate typedef struct st_ex_class_item { 243*0Sstevel@tonic-gate int class_index; 244*0Sstevel@tonic-gate STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth; 245*0Sstevel@tonic-gate int meth_num; 246*0Sstevel@tonic-gate } EX_CLASS_ITEM; 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate /* When assigning new class indexes, this is our counter */ 249*0Sstevel@tonic-gate static int ex_class = CRYPTO_EX_INDEX_USER; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate /* The global hash table of EX_CLASS_ITEM items */ 252*0Sstevel@tonic-gate static LHASH *ex_data = NULL; 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate /* The callbacks required in the "ex_data" hash table */ 255*0Sstevel@tonic-gate static unsigned long ex_hash_cb(const void *a_void) 256*0Sstevel@tonic-gate { 257*0Sstevel@tonic-gate return ((const EX_CLASS_ITEM *)a_void)->class_index; 258*0Sstevel@tonic-gate } 259*0Sstevel@tonic-gate static int ex_cmp_cb(const void *a_void, const void *b_void) 260*0Sstevel@tonic-gate { 261*0Sstevel@tonic-gate return (((const EX_CLASS_ITEM *)a_void)->class_index - 262*0Sstevel@tonic-gate ((const EX_CLASS_ITEM *)b_void)->class_index); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* Internal functions used by the "impl_default" implementation to access the 266*0Sstevel@tonic-gate * state */ 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate static int ex_data_check(void) 269*0Sstevel@tonic-gate { 270*0Sstevel@tonic-gate int toret = 1; 271*0Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 272*0Sstevel@tonic-gate if(!ex_data && ((ex_data = lh_new(ex_hash_cb, ex_cmp_cb)) == NULL)) 273*0Sstevel@tonic-gate toret = 0; 274*0Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 275*0Sstevel@tonic-gate return toret; 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate /* This macros helps reduce the locking from repeated checks because the 278*0Sstevel@tonic-gate * ex_data_check() function checks ex_data again inside a lock. */ 279*0Sstevel@tonic-gate #define EX_DATA_CHECK(iffail) if(!ex_data && !ex_data_check()) {iffail} 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate /* This "inner" callback is used by the callback function that follows it */ 282*0Sstevel@tonic-gate static void def_cleanup_util_cb(CRYPTO_EX_DATA_FUNCS *funcs) 283*0Sstevel@tonic-gate { 284*0Sstevel@tonic-gate OPENSSL_free(funcs); 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* This callback is used in lh_doall to destroy all EX_CLASS_ITEM values from 288*0Sstevel@tonic-gate * "ex_data" prior to the ex_data hash table being itself destroyed. Doesn't do 289*0Sstevel@tonic-gate * any locking. */ 290*0Sstevel@tonic-gate static void def_cleanup_cb(const void *a_void) 291*0Sstevel@tonic-gate { 292*0Sstevel@tonic-gate EX_CLASS_ITEM *item = (EX_CLASS_ITEM *)a_void; 293*0Sstevel@tonic-gate sk_CRYPTO_EX_DATA_FUNCS_pop_free(item->meth, def_cleanup_util_cb); 294*0Sstevel@tonic-gate OPENSSL_free(item); 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate /* Return the EX_CLASS_ITEM from the "ex_data" hash table that corresponds to a 298*0Sstevel@tonic-gate * given class. Handles locking. */ 299*0Sstevel@tonic-gate static EX_CLASS_ITEM *def_get_class(int class_index) 300*0Sstevel@tonic-gate { 301*0Sstevel@tonic-gate EX_CLASS_ITEM d, *p, *gen; 302*0Sstevel@tonic-gate EX_DATA_CHECK(return NULL;) 303*0Sstevel@tonic-gate d.class_index = class_index; 304*0Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 305*0Sstevel@tonic-gate p = lh_retrieve(ex_data, &d); 306*0Sstevel@tonic-gate if(!p) 307*0Sstevel@tonic-gate { 308*0Sstevel@tonic-gate gen = OPENSSL_malloc(sizeof(EX_CLASS_ITEM)); 309*0Sstevel@tonic-gate if(gen) 310*0Sstevel@tonic-gate { 311*0Sstevel@tonic-gate gen->class_index = class_index; 312*0Sstevel@tonic-gate gen->meth_num = 0; 313*0Sstevel@tonic-gate gen->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null(); 314*0Sstevel@tonic-gate if(!gen->meth) 315*0Sstevel@tonic-gate OPENSSL_free(gen); 316*0Sstevel@tonic-gate else 317*0Sstevel@tonic-gate { 318*0Sstevel@tonic-gate /* Because we're inside the ex_data lock, the 319*0Sstevel@tonic-gate * return value from the insert will be NULL */ 320*0Sstevel@tonic-gate lh_insert(ex_data, gen); 321*0Sstevel@tonic-gate p = gen; 322*0Sstevel@tonic-gate } 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 326*0Sstevel@tonic-gate if(!p) 327*0Sstevel@tonic-gate CRYPTOerr(CRYPTO_F_DEF_GET_CLASS,ERR_R_MALLOC_FAILURE); 328*0Sstevel@tonic-gate return p; 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate /* Add a new method to the given EX_CLASS_ITEM and return the corresponding 332*0Sstevel@tonic-gate * index (or -1 for error). Handles locking. */ 333*0Sstevel@tonic-gate static int def_add_index(EX_CLASS_ITEM *item, long argl, void *argp, 334*0Sstevel@tonic-gate CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 335*0Sstevel@tonic-gate CRYPTO_EX_free *free_func) 336*0Sstevel@tonic-gate { 337*0Sstevel@tonic-gate int toret = -1; 338*0Sstevel@tonic-gate CRYPTO_EX_DATA_FUNCS *a = (CRYPTO_EX_DATA_FUNCS *)OPENSSL_malloc( 339*0Sstevel@tonic-gate sizeof(CRYPTO_EX_DATA_FUNCS)); 340*0Sstevel@tonic-gate if(!a) 341*0Sstevel@tonic-gate { 342*0Sstevel@tonic-gate CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX,ERR_R_MALLOC_FAILURE); 343*0Sstevel@tonic-gate return -1; 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate a->argl=argl; 346*0Sstevel@tonic-gate a->argp=argp; 347*0Sstevel@tonic-gate a->new_func=new_func; 348*0Sstevel@tonic-gate a->dup_func=dup_func; 349*0Sstevel@tonic-gate a->free_func=free_func; 350*0Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 351*0Sstevel@tonic-gate while (sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) <= item->meth_num) 352*0Sstevel@tonic-gate { 353*0Sstevel@tonic-gate if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, NULL)) 354*0Sstevel@tonic-gate { 355*0Sstevel@tonic-gate CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX,ERR_R_MALLOC_FAILURE); 356*0Sstevel@tonic-gate OPENSSL_free(a); 357*0Sstevel@tonic-gate goto err; 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate toret = item->meth_num++; 361*0Sstevel@tonic-gate sk_CRYPTO_EX_DATA_FUNCS_set(item->meth, toret, a); 362*0Sstevel@tonic-gate err: 363*0Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 364*0Sstevel@tonic-gate return toret; 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate /**************************************************************/ 368*0Sstevel@tonic-gate /* The functions in the default CRYPTO_EX_DATA_IMPL structure */ 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate static int int_new_class(void) 371*0Sstevel@tonic-gate { 372*0Sstevel@tonic-gate int toret; 373*0Sstevel@tonic-gate CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); 374*0Sstevel@tonic-gate toret = ex_class++; 375*0Sstevel@tonic-gate CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); 376*0Sstevel@tonic-gate return toret; 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate static void int_cleanup(void) 380*0Sstevel@tonic-gate { 381*0Sstevel@tonic-gate EX_DATA_CHECK(return;) 382*0Sstevel@tonic-gate lh_doall(ex_data, def_cleanup_cb); 383*0Sstevel@tonic-gate lh_free(ex_data); 384*0Sstevel@tonic-gate ex_data = NULL; 385*0Sstevel@tonic-gate impl = NULL; 386*0Sstevel@tonic-gate } 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate static int int_get_new_index(int class_index, long argl, void *argp, 389*0Sstevel@tonic-gate CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 390*0Sstevel@tonic-gate CRYPTO_EX_free *free_func) 391*0Sstevel@tonic-gate { 392*0Sstevel@tonic-gate EX_CLASS_ITEM *item = def_get_class(class_index); 393*0Sstevel@tonic-gate if(!item) 394*0Sstevel@tonic-gate return -1; 395*0Sstevel@tonic-gate return def_add_index(item, argl, argp, new_func, dup_func, free_func); 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate /* Thread-safe by copying a class's array of "CRYPTO_EX_DATA_FUNCS" entries in 399*0Sstevel@tonic-gate * the lock, then using them outside the lock. NB: Thread-safety only applies to 400*0Sstevel@tonic-gate * the global "ex_data" state (ie. class definitions), not thread-safe on 'ad' 401*0Sstevel@tonic-gate * itself. */ 402*0Sstevel@tonic-gate static int int_new_ex_data(int class_index, void *obj, 403*0Sstevel@tonic-gate CRYPTO_EX_DATA *ad) 404*0Sstevel@tonic-gate { 405*0Sstevel@tonic-gate int mx,i; 406*0Sstevel@tonic-gate void *ptr; 407*0Sstevel@tonic-gate CRYPTO_EX_DATA_FUNCS **storage = NULL; 408*0Sstevel@tonic-gate EX_CLASS_ITEM *item = def_get_class(class_index); 409*0Sstevel@tonic-gate if(!item) 410*0Sstevel@tonic-gate /* error is already set */ 411*0Sstevel@tonic-gate return 0; 412*0Sstevel@tonic-gate ad->sk = NULL; 413*0Sstevel@tonic-gate CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); 414*0Sstevel@tonic-gate mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); 415*0Sstevel@tonic-gate if(mx > 0) 416*0Sstevel@tonic-gate { 417*0Sstevel@tonic-gate storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS*)); 418*0Sstevel@tonic-gate if(!storage) 419*0Sstevel@tonic-gate goto skip; 420*0Sstevel@tonic-gate for(i = 0; i < mx; i++) 421*0Sstevel@tonic-gate storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth,i); 422*0Sstevel@tonic-gate } 423*0Sstevel@tonic-gate skip: 424*0Sstevel@tonic-gate CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); 425*0Sstevel@tonic-gate if((mx > 0) && !storage) 426*0Sstevel@tonic-gate { 427*0Sstevel@tonic-gate CRYPTOerr(CRYPTO_F_INT_NEW_EX_DATA,ERR_R_MALLOC_FAILURE); 428*0Sstevel@tonic-gate return 0; 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate for(i = 0; i < mx; i++) 431*0Sstevel@tonic-gate { 432*0Sstevel@tonic-gate if(storage[i] && storage[i]->new_func) 433*0Sstevel@tonic-gate { 434*0Sstevel@tonic-gate ptr = CRYPTO_get_ex_data(ad, i); 435*0Sstevel@tonic-gate storage[i]->new_func(obj,ptr,ad,i, 436*0Sstevel@tonic-gate storage[i]->argl,storage[i]->argp); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate if(storage) 440*0Sstevel@tonic-gate OPENSSL_free(storage); 441*0Sstevel@tonic-gate return 1; 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate /* Same thread-safety notes as for "int_new_ex_data" */ 445*0Sstevel@tonic-gate static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, 446*0Sstevel@tonic-gate CRYPTO_EX_DATA *from) 447*0Sstevel@tonic-gate { 448*0Sstevel@tonic-gate int mx, j, i; 449*0Sstevel@tonic-gate char *ptr; 450*0Sstevel@tonic-gate CRYPTO_EX_DATA_FUNCS **storage = NULL; 451*0Sstevel@tonic-gate EX_CLASS_ITEM *item; 452*0Sstevel@tonic-gate if(!from->sk) 453*0Sstevel@tonic-gate /* 'to' should be "blank" which *is* just like 'from' */ 454*0Sstevel@tonic-gate return 1; 455*0Sstevel@tonic-gate if((item = def_get_class(class_index)) == NULL) 456*0Sstevel@tonic-gate return 0; 457*0Sstevel@tonic-gate CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); 458*0Sstevel@tonic-gate mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); 459*0Sstevel@tonic-gate j = sk_num(from->sk); 460*0Sstevel@tonic-gate if(j < mx) 461*0Sstevel@tonic-gate mx = j; 462*0Sstevel@tonic-gate if(mx > 0) 463*0Sstevel@tonic-gate { 464*0Sstevel@tonic-gate storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS*)); 465*0Sstevel@tonic-gate if(!storage) 466*0Sstevel@tonic-gate goto skip; 467*0Sstevel@tonic-gate for(i = 0; i < mx; i++) 468*0Sstevel@tonic-gate storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth,i); 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate skip: 471*0Sstevel@tonic-gate CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); 472*0Sstevel@tonic-gate if((mx > 0) && !storage) 473*0Sstevel@tonic-gate { 474*0Sstevel@tonic-gate CRYPTOerr(CRYPTO_F_INT_DUP_EX_DATA,ERR_R_MALLOC_FAILURE); 475*0Sstevel@tonic-gate return 0; 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate for(i = 0; i < mx; i++) 478*0Sstevel@tonic-gate { 479*0Sstevel@tonic-gate ptr = CRYPTO_get_ex_data(from, i); 480*0Sstevel@tonic-gate if(storage[i] && storage[i]->dup_func) 481*0Sstevel@tonic-gate storage[i]->dup_func(to,from,&ptr,i, 482*0Sstevel@tonic-gate storage[i]->argl,storage[i]->argp); 483*0Sstevel@tonic-gate CRYPTO_set_ex_data(to,i,ptr); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate if(storage) 486*0Sstevel@tonic-gate OPENSSL_free(storage); 487*0Sstevel@tonic-gate return 1; 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate /* Same thread-safety notes as for "int_new_ex_data" */ 491*0Sstevel@tonic-gate static void int_free_ex_data(int class_index, void *obj, 492*0Sstevel@tonic-gate CRYPTO_EX_DATA *ad) 493*0Sstevel@tonic-gate { 494*0Sstevel@tonic-gate int mx,i; 495*0Sstevel@tonic-gate EX_CLASS_ITEM *item; 496*0Sstevel@tonic-gate void *ptr; 497*0Sstevel@tonic-gate CRYPTO_EX_DATA_FUNCS **storage = NULL; 498*0Sstevel@tonic-gate if((item = def_get_class(class_index)) == NULL) 499*0Sstevel@tonic-gate return; 500*0Sstevel@tonic-gate CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); 501*0Sstevel@tonic-gate mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); 502*0Sstevel@tonic-gate if(mx > 0) 503*0Sstevel@tonic-gate { 504*0Sstevel@tonic-gate storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS*)); 505*0Sstevel@tonic-gate if(!storage) 506*0Sstevel@tonic-gate goto skip; 507*0Sstevel@tonic-gate for(i = 0; i < mx; i++) 508*0Sstevel@tonic-gate storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth,i); 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate skip: 511*0Sstevel@tonic-gate CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); 512*0Sstevel@tonic-gate if((mx > 0) && !storage) 513*0Sstevel@tonic-gate { 514*0Sstevel@tonic-gate CRYPTOerr(CRYPTO_F_INT_FREE_EX_DATA,ERR_R_MALLOC_FAILURE); 515*0Sstevel@tonic-gate return; 516*0Sstevel@tonic-gate } 517*0Sstevel@tonic-gate for(i = 0; i < mx; i++) 518*0Sstevel@tonic-gate { 519*0Sstevel@tonic-gate if(storage[i] && storage[i]->free_func) 520*0Sstevel@tonic-gate { 521*0Sstevel@tonic-gate ptr = CRYPTO_get_ex_data(ad,i); 522*0Sstevel@tonic-gate storage[i]->free_func(obj,ptr,ad,i, 523*0Sstevel@tonic-gate storage[i]->argl,storage[i]->argp); 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate if(storage) 527*0Sstevel@tonic-gate OPENSSL_free(storage); 528*0Sstevel@tonic-gate if(ad->sk) 529*0Sstevel@tonic-gate { 530*0Sstevel@tonic-gate sk_free(ad->sk); 531*0Sstevel@tonic-gate ad->sk=NULL; 532*0Sstevel@tonic-gate } 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /********************************************************************/ 536*0Sstevel@tonic-gate /* API functions that defer all "state" operations to the "ex_data" 537*0Sstevel@tonic-gate * implementation we have set. */ 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate /* Obtain an index for a new class (not the same as getting a new index within 540*0Sstevel@tonic-gate * an existing class - this is actually getting a new *class*) */ 541*0Sstevel@tonic-gate int CRYPTO_ex_data_new_class(void) 542*0Sstevel@tonic-gate { 543*0Sstevel@tonic-gate IMPL_CHECK 544*0Sstevel@tonic-gate return EX_IMPL(new_class)(); 545*0Sstevel@tonic-gate } 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate /* Release all "ex_data" state to prevent memory leaks. This can't be made 548*0Sstevel@tonic-gate * thread-safe without overhauling a lot of stuff, and shouldn't really be 549*0Sstevel@tonic-gate * called under potential race-conditions anyway (it's for program shutdown 550*0Sstevel@tonic-gate * after all). */ 551*0Sstevel@tonic-gate void CRYPTO_cleanup_all_ex_data(void) 552*0Sstevel@tonic-gate { 553*0Sstevel@tonic-gate IMPL_CHECK 554*0Sstevel@tonic-gate EX_IMPL(cleanup)(); 555*0Sstevel@tonic-gate } 556*0Sstevel@tonic-gate 557*0Sstevel@tonic-gate /* Inside an existing class, get/register a new index. */ 558*0Sstevel@tonic-gate int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, 559*0Sstevel@tonic-gate CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, 560*0Sstevel@tonic-gate CRYPTO_EX_free *free_func) 561*0Sstevel@tonic-gate { 562*0Sstevel@tonic-gate int ret = -1; 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate IMPL_CHECK 565*0Sstevel@tonic-gate ret = EX_IMPL(get_new_index)(class_index, 566*0Sstevel@tonic-gate argl, argp, new_func, dup_func, free_func); 567*0Sstevel@tonic-gate return ret; 568*0Sstevel@tonic-gate } 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate /* Initialise a new CRYPTO_EX_DATA for use in a particular class - including 571*0Sstevel@tonic-gate * calling new() callbacks for each index in the class used by this variable */ 572*0Sstevel@tonic-gate int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 573*0Sstevel@tonic-gate { 574*0Sstevel@tonic-gate IMPL_CHECK 575*0Sstevel@tonic-gate return EX_IMPL(new_ex_data)(class_index, obj, ad); 576*0Sstevel@tonic-gate } 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate /* Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks for 579*0Sstevel@tonic-gate * each index in the class used by this variable */ 580*0Sstevel@tonic-gate int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, 581*0Sstevel@tonic-gate CRYPTO_EX_DATA *from) 582*0Sstevel@tonic-gate { 583*0Sstevel@tonic-gate IMPL_CHECK 584*0Sstevel@tonic-gate return EX_IMPL(dup_ex_data)(class_index, to, from); 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate /* Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for 588*0Sstevel@tonic-gate * each index in the class used by this variable */ 589*0Sstevel@tonic-gate void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) 590*0Sstevel@tonic-gate { 591*0Sstevel@tonic-gate IMPL_CHECK 592*0Sstevel@tonic-gate EX_IMPL(free_ex_data)(class_index, obj, ad); 593*0Sstevel@tonic-gate } 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate /* For a given CRYPTO_EX_DATA variable, set the value corresponding to a 596*0Sstevel@tonic-gate * particular index in the class used by this variable */ 597*0Sstevel@tonic-gate int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val) 598*0Sstevel@tonic-gate { 599*0Sstevel@tonic-gate int i; 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate if (ad->sk == NULL) 602*0Sstevel@tonic-gate { 603*0Sstevel@tonic-gate if ((ad->sk=sk_new_null()) == NULL) 604*0Sstevel@tonic-gate { 605*0Sstevel@tonic-gate CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA,ERR_R_MALLOC_FAILURE); 606*0Sstevel@tonic-gate return(0); 607*0Sstevel@tonic-gate } 608*0Sstevel@tonic-gate } 609*0Sstevel@tonic-gate i=sk_num(ad->sk); 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate while (i <= idx) 612*0Sstevel@tonic-gate { 613*0Sstevel@tonic-gate if (!sk_push(ad->sk,NULL)) 614*0Sstevel@tonic-gate { 615*0Sstevel@tonic-gate CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA,ERR_R_MALLOC_FAILURE); 616*0Sstevel@tonic-gate return(0); 617*0Sstevel@tonic-gate } 618*0Sstevel@tonic-gate i++; 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate sk_set(ad->sk,idx,val); 621*0Sstevel@tonic-gate return(1); 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate /* For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a 625*0Sstevel@tonic-gate * particular index in the class used by this variable */ 626*0Sstevel@tonic-gate void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx) 627*0Sstevel@tonic-gate { 628*0Sstevel@tonic-gate if (ad->sk == NULL) 629*0Sstevel@tonic-gate return(0); 630*0Sstevel@tonic-gate else if (idx >= sk_num(ad->sk)) 631*0Sstevel@tonic-gate return(0); 632*0Sstevel@tonic-gate else 633*0Sstevel@tonic-gate return(sk_value(ad->sk,idx)); 634*0Sstevel@tonic-gate } 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate IMPLEMENT_STACK_OF(CRYPTO_EX_DATA_FUNCS) 637