ex_data.c 15.1 KB
Newer Older
1 2 3 4 5 6
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 * All rights reserved.
 *
 * This package is an SSL implementation written
 * by Eric Young (eay@cryptsoft.com).
 * The implementation was written so as to conform with Netscapes SSL.
7
 *
8 9 10 11 12 13
 * This library is free for commercial and non-commercial use as long as
 * the following conditions are aheared to.  The following conditions
 * apply to all code found in this distribution, be it the RC4, RSA,
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 * included with this distribution is covered by the same copyright terms
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14
 *
15 16 17 18 19 20
 * Copyright remains Eric Young's, and as such any Copyright notices in
 * the code are not to be removed.
 * If this package is used in a product, Eric Young should be given attribution
 * as the author of the parts of the library used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
21
 *
22 23 24 25 26 27 28 29 30 31 32 33 34 35
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    "This product includes cryptographic software written by
 *     Eric Young (eay@cryptsoft.com)"
 *    The word 'cryptographic' can be left out if the rouines from the library
 *    being used are not cryptographic related :-).
36
 * 4. If you include any Windows specific code (or a derivative thereof) from
37 38
 *    the apps directory (application code) you must include an acknowledgement:
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39
 *
40 41 42 43 44 45 46 47 48 49 50
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
51
 *
52 53 54 55 56
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */
B
Bodo Möller 已提交
57 58 59 60 61 62 63 64
/* ====================================================================
 * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
65
 *    notice, this list of conditions and the following disclaimer.
B
Bodo Möller 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */
110

111
#include "internal/cryptlib_int.h"
112
#include "internal/threads.h"
113
#include <openssl/lhash.h>
114

115 116 117 118
/*
 * Each structure type (sometimes called a class), that supports
 * exdata has a stack of callbacks for each instance.
 */
119
struct ex_callback_st {
F
FdaSilvaYY 已提交
120 121
    long argl;                  /* Arbitrary long */
    void *argp;                 /* Arbitrary void * */
R
Rich Salz 已提交
122 123 124
    CRYPTO_EX_new *new_func;
    CRYPTO_EX_free *free_func;
    CRYPTO_EX_dup *dup_func;
125
};
126 127

/*
128 129
 * The state for each class.  This could just be a typedef, but
 * a structure allows future changes.
130
 */
131 132 133
typedef struct ex_callbacks_st {
    STACK_OF(EX_CALLBACK) *meth;
} EX_CALLBACKS;
134

135
static EX_CALLBACKS ex_data[CRYPTO_EX_INDEX__COUNT];
136

137 138 139 140 141 142
static CRYPTO_RWLOCK *ex_data_lock;
static CRYPTO_ONCE ex_data_init = CRYPTO_ONCE_STATIC_INIT;

static void do_ex_data_init(void)
{
    ex_data_lock = CRYPTO_THREAD_lock_new();
143 144 145 146 147 148
}

void ex_data_cleanup(void)
{
    CRYPTO_THREAD_lock_free(ex_data_lock);
    ex_data_lock = NULL;
149 150
}

151
/*
152
 * Return the EX_CALLBACKS from the |ex_data| array that corresponds to
R
Rich Salz 已提交
153
 * a given class.  On success, *holds the lock.*
154
 */
155
static EX_CALLBACKS *get_and_lock(int class_index)
156
{
157
    EX_CALLBACKS *ip;
R
Rich Salz 已提交
158 159

    if (class_index < 0 || class_index >= CRYPTO_EX_INDEX__COUNT) {
F
FdaSilvaYY 已提交
160
        CRYPTOerr(CRYPTO_F_GET_AND_LOCK, ERR_R_PASSED_INVALID_ARGUMENT);
R
Rich Salz 已提交
161 162 163
        return NULL;
    }

164 165
    CRYPTO_THREAD_run_once(&ex_data_init, do_ex_data_init);

R
Rich Salz 已提交
166
    ip = &ex_data[class_index];
167
    CRYPTO_THREAD_write_lock(ex_data_lock);
R
Rich Salz 已提交
168
    return ip;
169 170
}

171
static void cleanup_cb(EX_CALLBACK *funcs)
172 173 174
{
    OPENSSL_free(funcs);
}
175

176
/*
R
Rich Salz 已提交
177 178 179 180
 * Release all "ex_data" state to prevent memory leaks. This can't be made
 * thread-safe without overhauling a lot of stuff, and shouldn't really be
 * called under potential race-conditions anyway (it's for program shutdown
 * after all).
181
 */
182
void crypto_cleanup_all_ex_data_int(void)
183
{
R
Rich Salz 已提交
184
    int i;
185

R
Rich Salz 已提交
186
    for (i = 0; i < CRYPTO_EX_INDEX__COUNT; ++i) {
187
        EX_CALLBACKS *ip = &ex_data[i];
R
Rich Salz 已提交
188

189
        sk_EX_CALLBACK_pop_free(ip->meth, cleanup_cb);
R
Rich Salz 已提交
190
        ip->meth = NULL;
191 192 193
    }
}

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233

/*
 * Unregister a new index by replacing the callbacks with no-ops.
 * Any in-use instances are leaked.
 */
static void dummy_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
                     long argl, void *argp)
{
}

static void dummy_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
                       long argl, void *argp)
{
}

static int dummy_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from,
                     void *from_d, int idx,
                     long argl, void *argp)
{
    return 0;
}

int CRYPTO_free_ex_index(int class_index, int idx)
{
    EX_CALLBACKS *ip = get_and_lock(class_index);
    EX_CALLBACK *a;
    int toret = 0;

    if (ip == NULL)
        return 0;
    if (idx < 0 || idx >= sk_EX_CALLBACK_num(ip->meth))
        goto err;
    a = sk_EX_CALLBACK_value(ip->meth, idx);
    if (a == NULL)
        goto err;
    a->new_func = dummy_new;
    a->dup_func = dummy_dup;
    a->free_func = dummy_free;
    toret = 1;
err:
234
    CRYPTO_THREAD_unlock(ex_data_lock);
235 236 237
    return toret;
}

238
/*
239
 * Register a new index.
240
 */
R
Rich Salz 已提交
241 242 243
int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
                            CRYPTO_EX_free *free_func)
244 245
{
    int toret = -1;
246 247
    EX_CALLBACK *a;
    EX_CALLBACKS *ip = get_and_lock(class_index);
R
Rich Salz 已提交
248

249
    if (ip == NULL)
250
        return -1;
251 252 253 254 255 256 257

    if (ip->meth == NULL) {
        ip->meth = sk_EX_CALLBACK_new_null();
        /* We push an initial value on the stack because the SSL
         * "app_data" routines use ex_data index zero.  See RT 3710. */
        if (ip->meth == NULL
            || !sk_EX_CALLBACK_push(ip->meth, NULL)) {
258
            CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
259 260 261 262
            goto err;
        }
    }

263
    a = (EX_CALLBACK *)OPENSSL_malloc(sizeof(*a));
264
    if (a == NULL) {
R
Rich Salz 已提交
265 266
        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
        goto err;
267 268 269 270 271 272
    }
    a->argl = argl;
    a->argp = argp;
    a->new_func = new_func;
    a->dup_func = dup_func;
    a->free_func = free_func;
273

274
    if (!sk_EX_CALLBACK_push(ip->meth, NULL)) {
R
Rich Salz 已提交
275 276 277 278
        CRYPTOerr(CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX, ERR_R_MALLOC_FAILURE);
        OPENSSL_free(a);
        goto err;
    }
279 280
    toret = sk_EX_CALLBACK_num(ip->meth) - 1;
    (void)sk_EX_CALLBACK_set(ip->meth, toret, a);
281

R
Rich Salz 已提交
282
 err:
283
    CRYPTO_THREAD_unlock(ex_data_lock);
284 285
    return toret;
}
286

287
/*
R
Rich Salz 已提交
288 289
 * Initialise a new CRYPTO_EX_DATA for use in a particular class - including
 * calling new() callbacks for each index in the class used by this variable
290
 * Thread-safe by copying a class's array of "EX_CALLBACK" entries
R
Rich Salz 已提交
291 292
 * in the lock, then using them outside the lock. Note this only applies
 * to the global "ex_data" state (ie. class definitions), not 'ad' itself.
293
 */
R
Rich Salz 已提交
294
int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
295 296 297
{
    int mx, i;
    void *ptr;
298 299 300
    EX_CALLBACK **storage = NULL;
    EX_CALLBACK *stack[10];
    EX_CALLBACKS *ip = get_and_lock(class_index);
R
Rich Salz 已提交
301

302
    if (ip == NULL)
303
        return 0;
R
Rich Salz 已提交
304

305
    ad->sk = NULL;
R
Rich Salz 已提交
306

307
    mx = sk_EX_CALLBACK_num(ip->meth);
308
    if (mx > 0) {
R
Rich Salz 已提交
309 310 311 312
        if (mx < (int)OSSL_NELEM(stack))
            storage = stack;
        else
            storage = OPENSSL_malloc(sizeof(*storage) * mx);
313
        if (storage != NULL)
R
Rich Salz 已提交
314
            for (i = 0; i < mx; i++)
315
                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
316
    }
317
    CRYPTO_THREAD_unlock(ex_data_lock);
R
Rich Salz 已提交
318 319 320

    if (mx > 0 && storage == NULL) {
        CRYPTOerr(CRYPTO_F_CRYPTO_NEW_EX_DATA, ERR_R_MALLOC_FAILURE);
321 322 323 324 325 326 327 328 329
        return 0;
    }
    for (i = 0; i < mx; i++) {
        if (storage[i] && storage[i]->new_func) {
            ptr = CRYPTO_get_ex_data(ad, i);
            storage[i]->new_func(obj, ptr, ad, i,
                                 storage[i]->argl, storage[i]->argp);
        }
    }
R
Rich Salz 已提交
330 331
    if (storage != stack)
        OPENSSL_free(storage);
332 333
    return 1;
}
334

R
Rich Salz 已提交
335 336 337 338 339 340
/*
 * Duplicate a CRYPTO_EX_DATA variable - including calling dup() callbacks
 * for each index in the class used by this variable
 */
int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
                       CRYPTO_EX_DATA *from)
341 342 343
{
    int mx, j, i;
    char *ptr;
344 345 346
    EX_CALLBACK *stack[10];
    EX_CALLBACK **storage = NULL;
    EX_CALLBACKS *ip;
R
Rich Salz 已提交
347 348 349

    if (from->sk == NULL)
        /* Nothing to copy over */
350
        return 1;
351
    if ((ip = get_and_lock(class_index)) == NULL)
352
        return 0;
R
Rich Salz 已提交
353

354
    mx = sk_EX_CALLBACK_num(ip->meth);
355 356 357 358
    j = sk_void_num(from->sk);
    if (j < mx)
        mx = j;
    if (mx > 0) {
R
Rich Salz 已提交
359 360 361 362
        if (mx < (int)OSSL_NELEM(stack))
            storage = stack;
        else
            storage = OPENSSL_malloc(sizeof(*storage) * mx);
363
        if (storage != NULL)
R
Rich Salz 已提交
364
            for (i = 0; i < mx; i++)
365
                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
366
    }
367
    CRYPTO_THREAD_unlock(ex_data_lock);
R
Rich Salz 已提交
368 369 370

    if (mx > 0 && storage == NULL) {
        CRYPTOerr(CRYPTO_F_CRYPTO_DUP_EX_DATA, ERR_R_MALLOC_FAILURE);
371 372
        return 0;
    }
R
Rich Salz 已提交
373

374 375 376 377 378 379 380
    for (i = 0; i < mx; i++) {
        ptr = CRYPTO_get_ex_data(from, i);
        if (storage[i] && storage[i]->dup_func)
            storage[i]->dup_func(to, from, &ptr, i,
                                 storage[i]->argl, storage[i]->argp);
        CRYPTO_set_ex_data(to, i, ptr);
    }
R
Rich Salz 已提交
381 382
    if (storage != stack)
        OPENSSL_free(storage);
383 384
    return 1;
}
385

R
Rich Salz 已提交
386 387 388 389 390 391

/*
 * Cleanup a CRYPTO_EX_DATA variable - including calling free() callbacks for
 * each index in the class used by this variable
 */
void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad)
392 393
{
    int mx, i;
394
    EX_CALLBACKS *ip;
395
    void *ptr;
396 397
    EX_CALLBACK *stack[10];
    EX_CALLBACK **storage = NULL;
R
Rich Salz 已提交
398

399
    if ((ip = get_and_lock(class_index)) == NULL)
400
        return;
R
Rich Salz 已提交
401

402
    mx = sk_EX_CALLBACK_num(ip->meth);
403
    if (mx > 0) {
R
Rich Salz 已提交
404 405 406 407
        if (mx < (int)OSSL_NELEM(stack))
            storage = stack;
        else
            storage = OPENSSL_malloc(sizeof(*storage) * mx);
408
        if (storage != NULL)
R
Rich Salz 已提交
409
            for (i = 0; i < mx; i++)
410
                storage[i] = sk_EX_CALLBACK_value(ip->meth, i);
411
    }
412
    CRYPTO_THREAD_unlock(ex_data_lock);
R
Rich Salz 已提交
413 414 415

    if (mx > 0 && storage == NULL) {
        CRYPTOerr(CRYPTO_F_CRYPTO_FREE_EX_DATA, ERR_R_MALLOC_FAILURE);
416 417 418 419 420 421 422 423 424
        return;
    }
    for (i = 0; i < mx; i++) {
        if (storage[i] && storage[i]->free_func) {
            ptr = CRYPTO_get_ex_data(ad, i);
            storage[i]->free_func(obj, ptr, ad, i,
                                  storage[i]->argl, storage[i]->argp);
        }
    }
R
Rich Salz 已提交
425 426 427

    if (storage != stack)
        OPENSSL_free(storage);
R
Rich Salz 已提交
428 429
    sk_void_free(ad->sk);
    ad->sk = NULL;
430
}
431

432 433 434 435
/*
 * For a given CRYPTO_EX_DATA variable, set the value corresponding to a
 * particular index in the class used by this variable
 */
D
 
Dr. Stephen Henson 已提交
436
int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val)
437 438 439 440 441 442
{
    int i;

    if (ad->sk == NULL) {
        if ((ad->sk = sk_void_new_null()) == NULL) {
            CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
R
Rich Salz 已提交
443
            return 0;
444 445 446
        }
    }

R
Rich Salz 已提交
447
    for (i = sk_void_num(ad->sk); i <= idx; ++i) {
448 449
        if (!sk_void_push(ad->sk, NULL)) {
            CRYPTOerr(CRYPTO_F_CRYPTO_SET_EX_DATA, ERR_R_MALLOC_FAILURE);
R
Rich Salz 已提交
450
            return 0;
451 452 453
        }
    }
    sk_void_set(ad->sk, idx, val);
R
Rich Salz 已提交
454
    return 1;
455 456 457 458 459 460
}

/*
 * For a given CRYPTO_EX_DATA_ variable, get the value corresponding to a
 * particular index in the class used by this variable
 */
461
void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx)
462
{
R
Rich Salz 已提交
463 464 465
    if (ad->sk == NULL || idx >= sk_void_num(ad->sk))
        return NULL;
    return sk_void_value(ad->sk, idx);
466
}