/src/libressl/crypto/ex_data.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: ex_data.c,v 1.20 2018/03/17 16:20:01 beck Exp $ */ |
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 <openssl/err.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, |
160 | | CRYPTO_EX_DATA *ad); |
161 | | /* Duplicate a CRYPTO_EX_DATA of a given class onto a copy */ |
162 | | int (*cb_dup_ex_data)(int class_index, CRYPTO_EX_DATA *to, |
163 | | CRYPTO_EX_DATA *from); |
164 | | /* Cleanup a CRYPTO_EX_DATA of a given class */ |
165 | | void (*cb_free_ex_data)(int class_index, void *obj, |
166 | | CRYPTO_EX_DATA *ad); |
167 | | }; |
168 | | |
169 | | /* The implementation we use at run-time */ |
170 | | static const CRYPTO_EX_DATA_IMPL *impl = NULL; |
171 | | |
172 | | /* To call "impl" functions, use this macro rather than referring to 'impl' directly, eg. |
173 | | * EX_IMPL(get_new_index)(...); |
174 | | */ |
175 | 117k | #define EX_IMPL(a) impl->cb_##a |
176 | | |
177 | | /* Predeclare the "default" ex_data implementation */ |
178 | | static int int_new_class(void); |
179 | | static void int_cleanup(void); |
180 | | static int int_get_new_index(int class_index, long argl, void *argp, |
181 | | CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, |
182 | | CRYPTO_EX_free *free_func); |
183 | | static int int_new_ex_data(int class_index, void *obj, |
184 | | CRYPTO_EX_DATA *ad); |
185 | | static int int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, |
186 | | CRYPTO_EX_DATA *from); |
187 | | static void int_free_ex_data(int class_index, void *obj, |
188 | | CRYPTO_EX_DATA *ad); |
189 | | |
190 | | static CRYPTO_EX_DATA_IMPL impl_default = { |
191 | | int_new_class, |
192 | | int_cleanup, |
193 | | int_get_new_index, |
194 | | int_new_ex_data, |
195 | | int_dup_ex_data, |
196 | | int_free_ex_data |
197 | | }; |
198 | | |
199 | | /* Internal function that checks whether "impl" is set and if not, sets it to |
200 | | * the default. */ |
201 | | static void |
202 | | impl_check(void) |
203 | 2 | { |
204 | 2 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
205 | 2 | if (!impl) |
206 | 2 | impl = &impl_default; |
207 | 2 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
208 | 2 | } |
209 | | /* A macro wrapper for impl_check that first uses a non-locked test before |
210 | | * invoking the function (which checks again inside a lock). */ |
211 | 117k | #define IMPL_CHECK if(!impl) impl_check(); |
212 | | |
213 | | /* API functions to get/set the "ex_data" implementation */ |
214 | | const CRYPTO_EX_DATA_IMPL * |
215 | | CRYPTO_get_ex_data_implementation(void) |
216 | 0 | { |
217 | 0 | IMPL_CHECK |
218 | 0 | return impl; |
219 | 0 | } |
220 | | |
221 | | int |
222 | | CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i) |
223 | 0 | { |
224 | 0 | int toret = 0; |
225 | 0 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
226 | 0 | if (!impl) { |
227 | 0 | impl = i; |
228 | 0 | toret = 1; |
229 | 0 | } |
230 | 0 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
231 | 0 | return toret; |
232 | 0 | } |
233 | | |
234 | | /****************************************************************************/ |
235 | | /* Interal (default) implementation of "ex_data" support. API functions are |
236 | | * further down. */ |
237 | | |
238 | | /* The type that represents what each "class" used to implement locally. A STACK |
239 | | * of CRYPTO_EX_DATA_FUNCS plus a index-counter. The 'class_index' is the global |
240 | | * value representing the class that is used to distinguish these items. */ |
241 | | typedef struct st_ex_class_item { |
242 | | int class_index; |
243 | | STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth; |
244 | | int meth_num; |
245 | | } EX_CLASS_ITEM; |
246 | | |
247 | | /* When assigning new class indexes, this is our counter */ |
248 | | static int ex_class = CRYPTO_EX_INDEX_USER; |
249 | | |
250 | | /* The global hash table of EX_CLASS_ITEM items */ |
251 | | DECLARE_LHASH_OF(EX_CLASS_ITEM); |
252 | | static LHASH_OF(EX_CLASS_ITEM) *ex_data = NULL; |
253 | | |
254 | | /* The callbacks required in the "ex_data" hash table */ |
255 | | static unsigned long |
256 | | ex_class_item_hash(const EX_CLASS_ITEM *a) |
257 | 117k | { |
258 | 117k | return a->class_index; |
259 | 117k | } |
260 | | |
261 | | static IMPLEMENT_LHASH_HASH_FN(ex_class_item, EX_CLASS_ITEM) |
262 | | |
263 | | static int |
264 | | ex_class_item_cmp(const EX_CLASS_ITEM *a, const EX_CLASS_ITEM *b) |
265 | 117k | { |
266 | 117k | return a->class_index - b->class_index; |
267 | 117k | } |
268 | | |
269 | | static IMPLEMENT_LHASH_COMP_FN(ex_class_item, EX_CLASS_ITEM) |
270 | | |
271 | | /* Internal functions used by the "impl_default" implementation to access the |
272 | | * state */ |
273 | | |
274 | | static int |
275 | | ex_data_check(void) |
276 | 2 | { |
277 | 2 | int toret = 1; |
278 | 2 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
279 | 2 | if (!ex_data && |
280 | 2 | (ex_data = lh_EX_CLASS_ITEM_new()) == NULL) |
281 | 0 | toret = 0; |
282 | 2 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
283 | 2 | return toret; |
284 | 2 | } |
285 | | /* This macros helps reduce the locking from repeated checks because the |
286 | | * ex_data_check() function checks ex_data again inside a lock. */ |
287 | 117k | #define EX_DATA_CHECK(iffail) if(!ex_data && !ex_data_check()) {iffail} |
288 | | |
289 | | /* This "inner" callback is used by the callback function that follows it */ |
290 | | static void |
291 | | def_cleanup_util_cb(CRYPTO_EX_DATA_FUNCS *funcs) |
292 | 0 | { |
293 | 0 | free(funcs); |
294 | 0 | } |
295 | | |
296 | | /* This callback is used in lh_doall to destroy all EX_CLASS_ITEM values from |
297 | | * "ex_data" prior to the ex_data hash table being itself destroyed. Doesn't do |
298 | | * any locking. */ |
299 | | static void |
300 | | def_cleanup_cb(void *a_void) |
301 | 0 | { |
302 | 0 | EX_CLASS_ITEM *item = (EX_CLASS_ITEM *)a_void; |
303 | 0 | sk_CRYPTO_EX_DATA_FUNCS_pop_free(item->meth, def_cleanup_util_cb); |
304 | 0 | free(item); |
305 | 0 | } |
306 | | |
307 | | /* Return the EX_CLASS_ITEM from the "ex_data" hash table that corresponds to a |
308 | | * given class. Handles locking. */ |
309 | | static EX_CLASS_ITEM * |
310 | | def_get_class(int class_index) |
311 | 117k | { |
312 | 117k | EX_CLASS_ITEM d, *p, *gen; |
313 | 117k | EX_DATA_CHECK(return NULL;) |
314 | 117k | d.class_index = class_index; |
315 | 117k | if (!OPENSSL_init_crypto(0, NULL)) |
316 | 0 | return NULL; |
317 | 117k | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
318 | 117k | p = lh_EX_CLASS_ITEM_retrieve(ex_data, &d); |
319 | 117k | if (!p) { |
320 | 14 | gen = malloc(sizeof(EX_CLASS_ITEM)); |
321 | 14 | if (gen) { |
322 | 14 | gen->class_index = class_index; |
323 | 14 | gen->meth_num = 0; |
324 | 14 | gen->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null(); |
325 | 14 | if (!gen->meth) |
326 | 0 | free(gen); |
327 | 14 | else { |
328 | | /* Because we're inside the ex_data lock, the |
329 | | * return value from the insert will be NULL */ |
330 | 14 | (void)lh_EX_CLASS_ITEM_insert(ex_data, gen); |
331 | 14 | p = gen; |
332 | 14 | } |
333 | 14 | } |
334 | 14 | } |
335 | 117k | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
336 | 117k | if (!p) |
337 | 117k | CRYPTOerror(ERR_R_MALLOC_FAILURE); |
338 | 117k | return p; |
339 | 117k | } |
340 | | |
341 | | /* Add a new method to the given EX_CLASS_ITEM and return the corresponding |
342 | | * index (or -1 for error). Handles locking. */ |
343 | | static int |
344 | | def_add_index(EX_CLASS_ITEM *item, long argl, void *argp, |
345 | | CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) |
346 | 2 | { |
347 | 2 | int toret = -1; |
348 | 2 | CRYPTO_EX_DATA_FUNCS *a = malloc(sizeof(CRYPTO_EX_DATA_FUNCS)); |
349 | | |
350 | 2 | if (!a) { |
351 | 0 | CRYPTOerror(ERR_R_MALLOC_FAILURE); |
352 | 0 | return -1; |
353 | 0 | } |
354 | 2 | a->argl = argl; |
355 | 2 | a->argp = argp; |
356 | 2 | a->new_func = new_func; |
357 | 2 | a->dup_func = dup_func; |
358 | 2 | a->free_func = free_func; |
359 | 2 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
360 | 4 | while (sk_CRYPTO_EX_DATA_FUNCS_num(item->meth) <= item->meth_num) { |
361 | 2 | if (!sk_CRYPTO_EX_DATA_FUNCS_push(item->meth, NULL)) { |
362 | 0 | CRYPTOerror(ERR_R_MALLOC_FAILURE); |
363 | 0 | free(a); |
364 | 0 | goto err; |
365 | 0 | } |
366 | 2 | } |
367 | 2 | toret = item->meth_num++; |
368 | 2 | (void)sk_CRYPTO_EX_DATA_FUNCS_set(item->meth, toret, a); |
369 | 2 | err: |
370 | 2 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
371 | 2 | return toret; |
372 | 2 | } |
373 | | |
374 | | /**************************************************************/ |
375 | | /* The functions in the default CRYPTO_EX_DATA_IMPL structure */ |
376 | | |
377 | | static int |
378 | | int_new_class(void) |
379 | 0 | { |
380 | 0 | int toret; |
381 | |
|
382 | 0 | CRYPTO_w_lock(CRYPTO_LOCK_EX_DATA); |
383 | 0 | toret = ex_class++; |
384 | 0 | CRYPTO_w_unlock(CRYPTO_LOCK_EX_DATA); |
385 | 0 | return toret; |
386 | 0 | } |
387 | | |
388 | | static void |
389 | | int_cleanup(void) |
390 | 0 | { |
391 | 0 | EX_DATA_CHECK(return;) |
392 | 0 | lh_EX_CLASS_ITEM_doall(ex_data, def_cleanup_cb); |
393 | 0 | lh_EX_CLASS_ITEM_free(ex_data); |
394 | 0 | ex_data = NULL; |
395 | 0 | impl = NULL; |
396 | 0 | } |
397 | | |
398 | | static int |
399 | | int_get_new_index(int class_index, long argl, void *argp, |
400 | | CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, |
401 | | CRYPTO_EX_free *free_func) |
402 | 2 | { |
403 | 2 | EX_CLASS_ITEM *item = def_get_class(class_index); |
404 | | |
405 | 2 | if (!item) |
406 | 0 | return -1; |
407 | 2 | return def_add_index(item, argl, argp, new_func, dup_func, free_func); |
408 | 2 | } |
409 | | |
410 | | /* Thread-safe by copying a class's array of "CRYPTO_EX_DATA_FUNCS" entries in |
411 | | * the lock, then using them outside the lock. NB: Thread-safety only applies to |
412 | | * the global "ex_data" state (ie. class definitions), not thread-safe on 'ad' |
413 | | * itself. */ |
414 | | static int |
415 | | int_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) |
416 | 58.7k | { |
417 | 58.7k | int mx, i; |
418 | 58.7k | void *ptr; |
419 | 58.7k | CRYPTO_EX_DATA_FUNCS **storage = NULL; |
420 | 58.7k | EX_CLASS_ITEM *item = def_get_class(class_index); |
421 | | |
422 | 58.7k | if (!item) |
423 | | /* error is already set */ |
424 | 0 | return 0; |
425 | 58.7k | ad->sk = NULL; |
426 | 58.7k | CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); |
427 | 58.7k | mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); |
428 | 58.7k | if (mx > 0) { |
429 | 893 | storage = reallocarray(NULL, mx, sizeof(CRYPTO_EX_DATA_FUNCS*)); |
430 | 893 | if (!storage) |
431 | 0 | goto skip; |
432 | 1.78k | for (i = 0; i < mx; i++) |
433 | 893 | storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value( |
434 | 893 | item->meth, i); |
435 | 893 | } |
436 | 58.7k | skip: |
437 | 58.7k | CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); |
438 | 58.7k | if ((mx > 0) && !storage) { |
439 | 0 | CRYPTOerror(ERR_R_MALLOC_FAILURE); |
440 | 0 | return 0; |
441 | 0 | } |
442 | 59.6k | for (i = 0; i < mx; i++) { |
443 | 893 | if (storage[i] && storage[i]->new_func) { |
444 | 0 | ptr = CRYPTO_get_ex_data(ad, i); |
445 | 0 | storage[i]->new_func(obj, ptr, ad, i, |
446 | 0 | storage[i]->argl, storage[i]->argp); |
447 | 0 | } |
448 | 893 | } |
449 | 58.7k | free(storage); |
450 | 58.7k | return 1; |
451 | 58.7k | } |
452 | | |
453 | | /* Same thread-safety notes as for "int_new_ex_data" */ |
454 | | static int |
455 | | int_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from) |
456 | 0 | { |
457 | 0 | int mx, j, i; |
458 | 0 | char *ptr; |
459 | 0 | CRYPTO_EX_DATA_FUNCS **storage = NULL; |
460 | 0 | EX_CLASS_ITEM *item; |
461 | |
|
462 | 0 | if (!from->sk) |
463 | | /* 'to' should be "blank" which *is* just like 'from' */ |
464 | 0 | return 1; |
465 | 0 | if ((item = def_get_class(class_index)) == NULL) |
466 | 0 | return 0; |
467 | 0 | CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); |
468 | 0 | mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); |
469 | 0 | j = sk_void_num(from->sk); |
470 | 0 | if (j < mx) |
471 | 0 | mx = j; |
472 | 0 | if (mx > 0) { |
473 | 0 | storage = reallocarray(NULL, mx, sizeof(CRYPTO_EX_DATA_FUNCS*)); |
474 | 0 | if (!storage) |
475 | 0 | goto skip; |
476 | 0 | for (i = 0; i < mx; i++) |
477 | 0 | storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value( |
478 | 0 | item->meth, i); |
479 | 0 | } |
480 | 0 | skip: |
481 | 0 | CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); |
482 | 0 | if ((mx > 0) && !storage) { |
483 | 0 | CRYPTOerror(ERR_R_MALLOC_FAILURE); |
484 | 0 | return 0; |
485 | 0 | } |
486 | 0 | for (i = 0; i < mx; i++) { |
487 | 0 | ptr = CRYPTO_get_ex_data(from, i); |
488 | 0 | if (storage[i] && storage[i]->dup_func) |
489 | 0 | storage[i]->dup_func(to, from, &ptr, i, |
490 | 0 | storage[i]->argl, storage[i]->argp); |
491 | 0 | CRYPTO_set_ex_data(to, i, ptr); |
492 | 0 | } |
493 | 0 | free(storage); |
494 | 0 | return 1; |
495 | 0 | } |
496 | | |
497 | | /* Same thread-safety notes as for "int_new_ex_data" */ |
498 | | static void |
499 | | int_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) |
500 | 58.7k | { |
501 | 58.7k | int mx, i; |
502 | 58.7k | EX_CLASS_ITEM *item; |
503 | 58.7k | void *ptr; |
504 | 58.7k | CRYPTO_EX_DATA_FUNCS **storage = NULL; |
505 | | |
506 | 58.7k | if ((item = def_get_class(class_index)) == NULL) |
507 | 0 | return; |
508 | 58.7k | CRYPTO_r_lock(CRYPTO_LOCK_EX_DATA); |
509 | 58.7k | mx = sk_CRYPTO_EX_DATA_FUNCS_num(item->meth); |
510 | 58.7k | if (mx > 0) { |
511 | 893 | storage = reallocarray(NULL, mx, sizeof(CRYPTO_EX_DATA_FUNCS*)); |
512 | 893 | if (!storage) |
513 | 0 | goto skip; |
514 | 1.78k | for (i = 0; i < mx; i++) |
515 | 893 | storage[i] = sk_CRYPTO_EX_DATA_FUNCS_value( |
516 | 893 | item->meth, i); |
517 | 893 | } |
518 | 58.7k | skip: |
519 | 58.7k | CRYPTO_r_unlock(CRYPTO_LOCK_EX_DATA); |
520 | 58.7k | if ((mx > 0) && !storage) { |
521 | 0 | CRYPTOerror(ERR_R_MALLOC_FAILURE); |
522 | 0 | return; |
523 | 0 | } |
524 | 59.6k | for (i = 0; i < mx; i++) { |
525 | 893 | if (storage[i] && storage[i]->free_func) { |
526 | 0 | ptr = CRYPTO_get_ex_data(ad, i); |
527 | 0 | storage[i]->free_func(obj, ptr, ad, i, |
528 | 0 | storage[i]->argl, storage[i]->argp); |
529 | 0 | } |
530 | 893 | } |
531 | 58.7k | free(storage); |
532 | 58.7k | if (ad->sk) { |
533 | 893 | sk_void_free(ad->sk); |
534 | 893 | ad->sk = NULL; |
535 | 893 | } |
536 | 58.7k | } |
537 | | |
538 | | /********************************************************************/ |
539 | | /* API functions that defer all "state" operations to the "ex_data" |
540 | | * implementation we have set. */ |
541 | | |
542 | | /* Obtain an index for a new class (not the same as getting a new index within |
543 | | * an existing class - this is actually getting a new *class*) */ |
544 | | int |
545 | | CRYPTO_ex_data_new_class(void) |
546 | 0 | { |
547 | 0 | IMPL_CHECK |
548 | 0 | return EX_IMPL(new_class)(); |
549 | 0 | } |
550 | | |
551 | | /* Release all "ex_data" state to prevent memory leaks. This can't be made |
552 | | * thread-safe without overhauling a lot of stuff, and shouldn't really be |
553 | | * called under potential race-conditions anyway (it's for program shutdown |
554 | | * after all). */ |
555 | | void |
556 | | CRYPTO_cleanup_all_ex_data(void) |
557 | 0 | { |
558 | 0 | IMPL_CHECK |
559 | 0 | EX_IMPL(cleanup)(); |
560 | 0 | } |
561 | | |
562 | | /* Inside an existing class, get/register a new index. */ |
563 | | int |
564 | | CRYPTO_get_ex_new_index(int class_index, long argl, void *argp, |
565 | | CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) |
566 | 2 | { |
567 | 2 | int ret = -1; |
568 | | |
569 | 2 | IMPL_CHECK |
570 | 2 | ret = EX_IMPL(get_new_index)(class_index, |
571 | 2 | argl, argp, new_func, dup_func, free_func); |
572 | 2 | return ret; |
573 | 2 | } |
574 | | |
575 | | /* Initialise a new CRYPTO_EX_DATA for use in a particular class - including |
576 | | * calling new() callbacks for each index in the class used by this variable */ |
577 | | int |
578 | | CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) |
579 | 58.7k | { |
580 | 58.7k | IMPL_CHECK |
581 | 58.7k | return EX_IMPL(new_ex_data)(class_index, obj, ad); |
582 | 58.7k | } |
583 | | |
584 | | /* Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks for |
585 | | * each index in the class used by this variable */ |
586 | | int |
587 | | CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from) |
588 | 0 | { |
589 | 0 | IMPL_CHECK |
590 | 0 | return EX_IMPL(dup_ex_data)(class_index, to, from); |
591 | 0 | } |
592 | | |
593 | | /* Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for |
594 | | * each index in the class used by this variable */ |
595 | | void |
596 | | CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad) |
597 | 58.7k | { |
598 | 58.7k | IMPL_CHECK |
599 | 58.7k | EX_IMPL(free_ex_data)(class_index, obj, ad); |
600 | 58.7k | } |
601 | | |
602 | | /* For a given CRYPTO_EX_DATA variable, set the value corresponding to a |
603 | | * particular index in the class used by this variable */ |
604 | | int |
605 | | CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val) |
606 | 893 | { |
607 | 893 | int i; |
608 | | |
609 | 893 | if (ad->sk == NULL) { |
610 | 893 | if ((ad->sk = sk_void_new_null()) == NULL) { |
611 | 0 | CRYPTOerror(ERR_R_MALLOC_FAILURE); |
612 | 0 | return (0); |
613 | 0 | } |
614 | 893 | } |
615 | 893 | i = sk_void_num(ad->sk); |
616 | | |
617 | 1.78k | while (i <= idx) { |
618 | 893 | if (!sk_void_push(ad->sk, NULL)) { |
619 | 0 | CRYPTOerror(ERR_R_MALLOC_FAILURE); |
620 | 0 | return (0); |
621 | 0 | } |
622 | 893 | i++; |
623 | 893 | } |
624 | 893 | sk_void_set(ad->sk, idx, val); |
625 | 893 | return (1); |
626 | 893 | } |
627 | | |
628 | | /* For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a |
629 | | * particular index in the class used by this variable */ |
630 | | void * |
631 | | CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx) |
632 | 0 | { |
633 | 0 | if (ad->sk == NULL) |
634 | 0 | return (0); |
635 | 0 | else if (idx >= sk_void_num(ad->sk)) |
636 | 0 | return (0); |
637 | 0 | else |
638 | 0 | return (sk_void_value(ad->sk, idx)); |
639 | 0 | } |