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