/src/openssl/crypto/ex_data.c
Line | Count | Source (jump to first uncovered line) |
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 | 325k | #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 | | static void impl_check(void) |
200 | 19 | { |
201 | 19 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
202 | 19 | if (!impl) |
203 | 19 | impl = &impl_default; |
204 | 19 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
205 | 19 | } |
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 | 325k | #define IMPL_CHECK if(!impl) impl_check(); |
212 | | |
213 | | /* API functions to get/set the "ex_data" implementation */ |
214 | | const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void) |
215 | 0 | { |
216 | 0 | IMPL_CHECK return impl; |
217 | 0 | } |
218 | | |
219 | | int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i) |
220 | 0 | { |
221 | 0 | int toret = 0; |
222 | 0 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
223 | 0 | if (!impl) { |
224 | 0 | impl = i; |
225 | 0 | toret = 1; |
226 | 0 | } |
227 | 0 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
228 | 0 | return toret; |
229 | 0 | } |
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 | 326k | { |
259 | 326k | return a->class_index; |
260 | 326k | } |
261 | | |
262 | | 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 | 325k | { |
266 | 325k | return a->class_index - b->class_index; |
267 | 325k | } |
268 | | |
269 | | 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 | | static int ex_data_check(void) |
276 | 19 | { |
277 | 19 | int toret = 1; |
278 | 19 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
279 | 19 | if (!ex_data && (ex_data = lh_EX_CLASS_ITEM_new()) == NULL) |
280 | 0 | toret = 0; |
281 | 19 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
282 | 19 | return toret; |
283 | 19 | } |
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 | 325k | #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 | | static void def_cleanup_util_cb(CRYPTO_EX_DATA_FUNCS *funcs) |
293 | 0 | { |
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 | | static void def_cleanup_cb(void *a_void) |
303 | 0 | { |
304 | 0 | 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 | | static EX_CLASS_ITEM *def_get_class(int class_index) |
314 | 325k | { |
315 | 325k | EX_CLASS_ITEM d, *p, *gen; |
316 | 325k | EX_DATA_CHECK(return NULL;) |
317 | 325k | d.class_index = class_index; |
318 | 325k | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
319 | 325k | p = lh_EX_CLASS_ITEM_retrieve(ex_data, &d); |
320 | 325k | if (!p) { |
321 | 78 | gen = OPENSSL_malloc(sizeof(EX_CLASS_ITEM)); |
322 | 78 | if (gen) { |
323 | 78 | gen->class_index = class_index; |
324 | 78 | gen->meth_num = 0; |
325 | 78 | gen->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null(); |
326 | 78 | if (!gen->meth) |
327 | 0 | OPENSSL_free(gen); |
328 | 78 | else { |
329 | | /* |
330 | | * Because we're inside the ex_data lock, the return value |
331 | | * from the insert will be NULL |
332 | | */ |
333 | 78 | (void)lh_EX_CLASS_ITEM_insert(ex_data, gen); |
334 | 78 | p = lh_EX_CLASS_ITEM_retrieve(ex_data, &d); |
335 | 78 | if (p != gen) { |
336 | 0 | sk_CRYPTO_EX_DATA_FUNCS_free(gen->meth); |
337 | 0 | OPENSSL_free(gen); |
338 | 0 | } |
339 | 78 | } |
340 | 78 | } |
341 | 78 | } |
342 | 325k | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
343 | 325k | if (!p) |
344 | 325k | CRYPTOerr(CRYPTO_F_DEF_GET_CLASS, ERR_R_MALLOC_FAILURE); |
345 | 325k | return p; |
346 | 325k | } |
347 | | |
348 | | /* |
349 | | * Add a new method to the given EX_CLASS_ITEM and return the corresponding |
350 | | * index (or -1 for error). Handles locking. |
351 | | */ |
352 | | static int def_add_index(EX_CLASS_ITEM *item, long argl, void *argp, |
353 | | CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, |
354 | | CRYPTO_EX_free *free_func) |
355 | 84 | { |
356 | 84 | int toret = -1; |
357 | 84 | CRYPTO_EX_DATA_FUNCS *a = |
358 | 84 | (CRYPTO_EX_DATA_FUNCS *)OPENSSL_malloc(sizeof(CRYPTO_EX_DATA_FUNCS)); |
359 | 84 | if (!a) { |
360 | 0 | CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX, ERR_R_MALLOC_FAILURE); |
361 | 0 | return -1; |
362 | 0 | } |
363 | 84 | a->argl = argl; |
364 | 84 | a->argp = argp; |
365 | 84 | a->new_func = new_func; |
366 | 84 | a->dup_func = dup_func; |
367 | 84 | a->free_func = free_func; |
368 | 84 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
369 | 168 | while (sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) <= item->meth_num) { |
370 | 84 | if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, NULL)) { |
371 | 0 | CRYPTOerr(CRYPTO_F_DEF_ADD_INDEX, ERR_R_MALLOC_FAILURE); |
372 | 0 | OPENSSL_free(a); |
373 | 0 | goto err; |
374 | 0 | } |
375 | 84 | } |
376 | 84 | toret = item->meth_num++; |
377 | 84 | (void)sk_CRYPTO_EX_DATA_FUNCS_set(item->meth, toret, a); |
378 | 84 | err: |
379 | 84 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
380 | 84 | return toret; |
381 | 84 | } |
382 | | |
383 | | /**************************************************************/ |
384 | | /* The functions in the default CRYPTO_EX_DATA_IMPL structure */ |
385 | | |
386 | | static int int_new_class(void) |
387 | 0 | { |
388 | 0 | int toret; |
389 | 0 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
390 | 0 | toret = ex_class++; |
391 | 0 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
392 | 0 | return toret; |
393 | 0 | } |
394 | | |
395 | | static void int_cleanup(void) |
396 | 0 | { |
397 | 0 | EX_DATA_CHECK(return;) |
398 | 0 | lh_EX_CLASS_ITEM_doall(ex_data, def_cleanup_cb); |
399 | 0 | lh_EX_CLASS_ITEM_free(ex_data); |
400 | 0 | ex_data = NULL; |
401 | 0 | impl = NULL; |
402 | 0 | } |
403 | | |
404 | | static int int_get_new_index(int class_index, long argl, void *argp, |
405 | | CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, |
406 | | CRYPTO_EX_free *free_func) |
407 | 84 | { |
408 | 84 | EX_CLASS_ITEM *item = def_get_class(class_index); |
409 | 84 | if (!item) |
410 | 0 | return -1; |
411 | 84 | return def_add_index(item, argl, argp, new_func, dup_func, free_func); |
412 | 84 | } |
413 | | |
414 | | /* |
415 | | * Thread-safe by copying a class's array of "CRYPTO_EX_DATA_FUNCS" entries |
416 | | * in the lock, then using them outside the lock. NB: Thread-safety only |
417 | | * applies to the global "ex_data" state (ie. class definitions), not |
418 | | * thread-safe on 'ad' itself. |
419 | | */ |
420 | | static int int_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) |
421 | 163k | { |
422 | 163k | int mx, i; |
423 | 163k | void *ptr; |
424 | 163k | CRYPTO_EX_DATA_FUNCS **storage = NULL; |
425 | 163k | EX_CLASS_ITEM *item = def_get_class(class_index); |
426 | 163k | if (!item) |
427 | | /* error is already set */ |
428 | 0 | return 0; |
429 | 163k | ad->sk = NULL; |
430 | 163k | CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); |
431 | 163k | mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); |
432 | 163k | if (mx > 0) { |
433 | 0 | storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *)); |
434 | 0 | if (!storage) |
435 | 0 | goto skip; |
436 | 0 | for (i = 0; i < mx; i++) |
437 | 0 | storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); |
438 | 0 | } |
439 | 163k | skip: |
440 | 163k | CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); |
441 | 163k | if ((mx > 0) && !storage) { |
442 | 0 | CRYPTOerr(CRYPTO_F_INT_NEW_EX_DATA, ERR_R_MALLOC_FAILURE); |
443 | 0 | return 0; |
444 | 0 | } |
445 | 163k | for (i = 0; i < mx; i++) { |
446 | 0 | if (storage[i] && storage[i]->new_func) { |
447 | 0 | ptr = CRYPTO_get_ex_data(ad, i); |
448 | 0 | storage[i]->new_func(obj, ptr, ad, i, |
449 | 0 | storage[i]->argl, storage[i]->argp); |
450 | 0 | } |
451 | 0 | } |
452 | 163k | if (storage) |
453 | 0 | OPENSSL_free(storage); |
454 | 163k | return 1; |
455 | 163k | } |
456 | | |
457 | | /* Same thread-safety notes as for "int_new_ex_data" */ |
458 | | static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, |
459 | | CRYPTO_EX_DATA *from) |
460 | 0 | { |
461 | 0 | int mx, j, i; |
462 | 0 | void *ptr; |
463 | 0 | CRYPTO_EX_DATA_FUNCS **storage = NULL; |
464 | 0 | EX_CLASS_ITEM *item; |
465 | 0 | if (!from->sk) |
466 | | /* 'to' should be "blank" which *is* just like 'from' */ |
467 | 0 | return 1; |
468 | 0 | if ((item = def_get_class(class_index)) == NULL) |
469 | 0 | return 0; |
470 | 0 | CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); |
471 | 0 | mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); |
472 | 0 | j = sk_void_num(from->sk); |
473 | 0 | if (j < mx) |
474 | 0 | mx = j; |
475 | 0 | if (mx > 0) { |
476 | | /* |
477 | | * Make sure the ex_data stack is at least |mx| elements long to avoid |
478 | | * issues in the for loop that follows; so go get the |mx|'th element |
479 | | * (if it does not exist CRYPTO_get_ex_data() returns NULL), and assign |
480 | | * to itself. This is normally a no-op; but ensures the stack is the |
481 | | * proper size |
482 | | */ |
483 | 0 | if (!CRYPTO_set_ex_data(to, mx - 1, CRYPTO_get_ex_data(to, mx - 1))) |
484 | 0 | goto skip; |
485 | 0 | storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *)); |
486 | 0 | if (!storage) |
487 | 0 | goto skip; |
488 | 0 | for (i = 0; i < mx; i++) |
489 | 0 | storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); |
490 | 0 | } |
491 | 0 | skip: |
492 | 0 | CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); |
493 | 0 | if ((mx > 0) && !storage) { |
494 | 0 | CRYPTOerr(CRYPTO_F_INT_DUP_EX_DATA, ERR_R_MALLOC_FAILURE); |
495 | 0 | return 0; |
496 | 0 | } |
497 | 0 | for (i = 0; i < mx; i++) { |
498 | 0 | ptr = CRYPTO_get_ex_data(from, i); |
499 | 0 | if (storage[i] && storage[i]->dup_func) |
500 | 0 | storage[i]->dup_func(to, from, &ptr, i, |
501 | 0 | storage[i]->argl, storage[i]->argp); |
502 | 0 | CRYPTO_set_ex_data(to, i, ptr); |
503 | 0 | } |
504 | 0 | if (storage) |
505 | 0 | OPENSSL_free(storage); |
506 | 0 | return 1; |
507 | 0 | } |
508 | | |
509 | | /* Same thread-safety notes as for "int_new_ex_data" */ |
510 | | static void int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) |
511 | 162k | { |
512 | 162k | int mx, i; |
513 | 162k | EX_CLASS_ITEM *item; |
514 | 162k | void *ptr; |
515 | 162k | CRYPTO_EX_DATA_FUNCS *f; |
516 | 162k | CRYPTO_EX_DATA_FUNCS **storage = NULL; |
517 | 162k | if (ex_data == NULL) |
518 | 0 | goto err; |
519 | 162k | if ((item = def_get_class(class_index)) == NULL) |
520 | 0 | goto err; |
521 | 162k | CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); |
522 | 162k | mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); |
523 | 162k | if (mx > 0) { |
524 | 0 | storage = OPENSSL_malloc(mx * sizeof(CRYPTO_EX_DATA_FUNCS *)); |
525 | 0 | if (!storage) |
526 | 0 | goto skip; |
527 | 0 | for (i = 0; i < mx; i++) |
528 | 0 | storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); |
529 | 0 | } |
530 | 162k | skip: |
531 | 162k | CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); |
532 | 162k | for (i = 0; i < mx; i++) { |
533 | 0 | if (storage != NULL) |
534 | 0 | f = storage[i]; |
535 | 0 | else { |
536 | 0 | CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); |
537 | 0 | f = sk_CRYPTO_EX_DATA_FUNCS_value(item->meth, i); |
538 | 0 | CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); |
539 | 0 | } |
540 | 0 | if (f != NULL && f->free_func != NULL) { |
541 | 0 | ptr = CRYPTO_get_ex_data(ad, i); |
542 | 0 | f->free_func(obj, ptr, ad, i, f->argl, f->argp); |
543 | 0 | } |
544 | 0 | } |
545 | 162k | OPENSSL_free(storage); |
546 | 162k | err: |
547 | 162k | sk_void_free(ad->sk); |
548 | 162k | ad->sk = NULL; |
549 | 162k | } |
550 | | |
551 | | /********************************************************************/ |
552 | | /* |
553 | | * API functions that defer all "state" operations to the "ex_data" |
554 | | * implementation we have set. |
555 | | */ |
556 | | |
557 | | /* |
558 | | * Obtain an index for a new class (not the same as getting a new index |
559 | | * within an existing class - this is actually getting a new *class*) |
560 | | */ |
561 | | int CRYPTO_ex_data_new_class(void) |
562 | 0 | { |
563 | 0 | IMPL_CHECK return EX_IMPL(new_class) (); |
564 | 0 | } |
565 | | |
566 | | /* |
567 | | * Release all "ex_data" state to prevent memory leaks. This can't be made |
568 | | * thread-safe without overhauling a lot of stuff, and shouldn't really be |
569 | | * called under potential race-conditions anyway (it's for program shutdown |
570 | | * after all). |
571 | | */ |
572 | | void CRYPTO_cleanup_all_ex_data(void) |
573 | 0 | { |
574 | 0 | IMPL_CHECK EX_IMPL(cleanup) (); |
575 | 0 | } |
576 | | |
577 | | /* Inside an existing class, get/register a new index. */ |
578 | | int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, |
579 | | CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, |
580 | | CRYPTO_EX_free *free_func) |
581 | 84 | { |
582 | 84 | int ret = -1; |
583 | | |
584 | 84 | IMPL_CHECK |
585 | 84 | ret = EX_IMPL(get_new_index) (class_index, |
586 | 84 | argl, argp, new_func, dup_func, |
587 | 84 | free_func); |
588 | 84 | return ret; |
589 | 84 | } |
590 | | |
591 | | /* |
592 | | * Initialise a new CRYPTO_EX_DATA for use in a particular class - including |
593 | | * calling new() callbacks for each index in the class used by this variable |
594 | | */ |
595 | | int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) |
596 | 163k | { |
597 | 163k | IMPL_CHECK return EX_IMPL(new_ex_data) (class_index, obj, ad); |
598 | 163k | } |
599 | | |
600 | | /* |
601 | | * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks |
602 | | * for each index in the class used by this variable |
603 | | */ |
604 | | int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, |
605 | | CRYPTO_EX_DATA *from) |
606 | 0 | { |
607 | 0 | IMPL_CHECK return EX_IMPL(dup_ex_data) (class_index, to, from); |
608 | 0 | } |
609 | | |
610 | | /* |
611 | | * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for |
612 | | * each index in the class used by this variable |
613 | | */ |
614 | | void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) |
615 | 162k | { |
616 | 162k | IMPL_CHECK EX_IMPL(free_ex_data) (class_index, obj, ad); |
617 | 162k | } |
618 | | |
619 | | /* |
620 | | * For a given CRYPTO_EX_DATA variable, set the value corresponding to a |
621 | | * particular index in the class used by this variable |
622 | | */ |
623 | | int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val) |
624 | 0 | { |
625 | 0 | int i; |
626 | |
|
627 | 0 | if (ad->sk == NULL) { |
628 | 0 | if ((ad->sk = sk_void_new_null()) == NULL) { |
629 | 0 | CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE); |
630 | 0 | return (0); |
631 | 0 | } |
632 | 0 | } |
633 | 0 | i = sk_void_num(ad->sk); |
634 | |
|
635 | 0 | while (i <= idx) { |
636 | 0 | if (!sk_void_push(ad->sk, NULL)) { |
637 | 0 | CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE); |
638 | 0 | return (0); |
639 | 0 | } |
640 | 0 | i++; |
641 | 0 | } |
642 | 0 | sk_void_set(ad->sk, idx, val); |
643 | 0 | return (1); |
644 | 0 | } |
645 | | |
646 | | /* |
647 | | * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a |
648 | | * particular index in the class used by this variable |
649 | | */ |
650 | | void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx) |
651 | 0 | { |
652 | 0 | if (ad->sk == NULL) |
653 | 0 | return (0); |
654 | 0 | else if (idx >= sk_void_num(ad->sk)) |
655 | 0 | return (0); |
656 | 0 | else |
657 | 0 | return (sk_void_value(ad->sk, idx)); |
658 | 0 | } |
659 | | |
660 | | IMPLEMENT_STACK_OF(CRYPTO_EX_DATA_FUNCS) |