Coverage Report

Created: 2018-08-29 13:53

/src/openssl/crypto/objects/o_names.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright 1998-2018 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the OpenSSL license (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
#include <stdio.h>
11
#include <stdlib.h>
12
#include <string.h>
13
14
#include <openssl/err.h>
15
#include <openssl/lhash.h>
16
#include <openssl/objects.h>
17
#include <openssl/safestack.h>
18
#include <openssl/e_os2.h>
19
#include "internal/thread_once.h"
20
#include "obj_lcl.h"
21
22
/*
23
 * We define this wrapper for two reasons. Firstly, later versions of
24
 * DEC C add linkage information to certain functions, which makes it
25
 * tricky to use them as values to regular function pointers.
26
 * Secondly, in the EDK2 build environment, the strcmp function is
27
 * actually an external function (AsciiStrCmp) with the Microsoft ABI,
28
 * so we can't transparently assign function pointers to it.
29
 * Arguably the latter is a stupidity of the UEFI environment, but
30
 * since the wrapper solves the DEC C issue too, let's just use the
31
 * same solution.
32
 */
33
#if defined(OPENSSL_SYS_VMS_DECC) || defined(OPENSSL_SYS_UEFI)
34
static int obj_strcmp(const char *a, const char *b)
35
{
36
    return strcmp(a, b);
37
}
38
#else
39
0
#define obj_strcmp strcmp
40
#endif
41
42
/*
43
 * I use the ex_data stuff to manage the identifiers for the obj_name_types
44
 * that applications may define.  I only really use the free function field.
45
 */
46
static LHASH_OF(OBJ_NAME) *names_lh = NULL;
47
static int names_type_num = OBJ_NAME_TYPE_NUM;
48
static CRYPTO_RWLOCK *obj_lock = NULL;
49
50
struct name_funcs_st {
51
    unsigned long (*hash_func) (const char *name);
52
    int (*cmp_func) (const char *a, const char *b);
53
    void (*free_func) (const char *, int, const char *);
54
};
55
56
static STACK_OF(NAME_FUNCS) *name_funcs_stack;
57
58
/*
59
 * The LHASH callbacks now use the raw "void *" prototypes and do
60
 * per-variable casting in the functions. This prevents function pointer
61
 * casting without the need for macro-generated wrapper functions.
62
 */
63
64
static unsigned long obj_name_hash(const OBJ_NAME *a);
65
static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b);
66
67
static CRYPTO_ONCE init = CRYPTO_ONCE_STATIC_INIT;
68
DEFINE_RUN_ONCE_STATIC(o_names_init)
69
8
{
70
8
    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
71
8
    names_lh = lh_OBJ_NAME_new(obj_name_hash, obj_name_cmp);
72
8
    obj_lock = CRYPTO_THREAD_lock_new();
73
8
    CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
74
8
    return names_lh != NULL && obj_lock != NULL;
75
8
}
76
77
int OBJ_NAME_init(void)
78
9.56k
{
79
9.56k
    return RUN_ONCE(&init, o_names_init);
80
9.56k
}
81
82
int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *),
83
                       int (*cmp_func) (const char *, const char *),
84
                       void (*free_func) (const char *, int, const char *))
85
0
{
86
0
    int ret = 0, i, push;
87
0
    NAME_FUNCS *name_funcs;
88
0
89
0
    if (!OBJ_NAME_init())
90
0
        return 0;
91
0
92
0
    CRYPTO_THREAD_write_lock(obj_lock);
93
0
94
0
    if (name_funcs_stack == NULL) {
95
0
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
96
0
        name_funcs_stack = sk_NAME_FUNCS_new_null();
97
0
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
98
0
    }
99
0
    if (name_funcs_stack == NULL) {
100
0
        /* ERROR */
101
0
        goto out;
102
0
    }
103
0
    ret = names_type_num;
104
0
    names_type_num++;
105
0
    for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) {
106
0
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
107
0
        name_funcs = OPENSSL_zalloc(sizeof(*name_funcs));
108
0
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
109
0
        if (name_funcs == NULL) {
110
0
            OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
111
0
            ret = 0;
112
0
            goto out;
113
0
        }
114
0
        name_funcs->hash_func = OPENSSL_LH_strhash;
115
0
        name_funcs->cmp_func = obj_strcmp;
116
0
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
117
0
118
0
        push = sk_NAME_FUNCS_push(name_funcs_stack, name_funcs);
119
0
        CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
120
0
121
0
        if (!push) {
122
0
            OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE);
123
0
            OPENSSL_free(name_funcs);
124
0
            ret = 0;
125
0
            goto out;
126
0
        }
127
0
    }
128
0
    name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret);
129
0
    if (hash_func != NULL)
130
0
        name_funcs->hash_func = hash_func;
131
0
    if (cmp_func != NULL)
132
0
        name_funcs->cmp_func = cmp_func;
133
0
    if (free_func != NULL)
134
0
        name_funcs->free_func = free_func;
135
0
136
0
out:
137
0
    CRYPTO_THREAD_unlock(obj_lock);
138
0
    return ret;
139
0
}
140
141
static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b)
142
7.65k
{
143
7.65k
    int ret;
144
7.65k
145
7.65k
    ret = a->type - b->type;
146
7.65k
    if (ret == 0) {
147
7.65k
        if ((name_funcs_stack != NULL)
148
7.65k
            && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
149
0
            ret = sk_NAME_FUNCS_value(name_funcs_stack,
150
0
                                      a->type)->cmp_func(a->name, b->name);
151
0
        } else
152
7.65k
            ret = strcmp(a->name, b->name);
153
7.65k
    }
154
7.65k
    return ret;
155
7.65k
}
156
157
static unsigned long obj_name_hash(const OBJ_NAME *a)
158
11.7k
{
159
11.7k
    unsigned long ret;
160
11.7k
161
11.7k
    if ((name_funcs_stack != NULL)
162
11.7k
        && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) {
163
0
        ret =
164
0
            sk_NAME_FUNCS_value(name_funcs_stack,
165
0
                                a->type)->hash_func(a->name);
166
11.7k
    } else {
167
11.7k
        ret = OPENSSL_LH_strhash(a->name);
168
11.7k
    }
169
11.7k
    ret ^= a->type;
170
11.7k
    return ret;
171
11.7k
}
172
173
const char *OBJ_NAME_get(const char *name, int type)
174
4.17k
{
175
4.17k
    OBJ_NAME on, *ret;
176
4.17k
    int num = 0, alias;
177
4.17k
    const char *value = NULL;
178
4.17k
179
4.17k
    if (name == NULL)
180
4.17k
        return NULL;
181
4.17k
    if (!OBJ_NAME_init())
182
0
        return NULL;
183
4.17k
    CRYPTO_THREAD_read_lock(obj_lock);
184
4.17k
185
4.17k
    alias = type & OBJ_NAME_ALIAS;
186
4.17k
    type &= ~OBJ_NAME_ALIAS;
187
4.17k
188
4.17k
    on.name = name;
189
4.17k
    on.type = type;
190
4.17k
191
6.36k
    for (;;) {
192
6.36k
        ret = lh_OBJ_NAME_retrieve(names_lh, &on);
193
6.36k
        if (ret == NULL)
194
6.36k
            break;
195
4.92k
        if ((ret->alias) && !alias) {
196
2.18k
            if (++num > 10)
197
0
                break;
198
2.18k
            on.name = ret->data;
199
2.73k
        } else {
200
2.73k
            value = ret->data;
201
2.73k
            break;
202
2.73k
        }
203
4.92k
    }
204
4.17k
205
4.17k
    CRYPTO_THREAD_unlock(obj_lock);
206
4.17k
    return value;
207
4.17k
}
208
209
int OBJ_NAME_add(const char *name, int type, const char *data)
210
2.72k
{
211
2.72k
    OBJ_NAME *onp, *ret;
212
2.72k
    int alias, ok = 0;
213
2.72k
214
2.72k
    if (!OBJ_NAME_init())
215
0
        return 0;
216
2.72k
217
2.72k
    CRYPTO_THREAD_write_lock(obj_lock);
218
2.72k
219
2.72k
    alias = type & OBJ_NAME_ALIAS;
220
2.72k
    type &= ~OBJ_NAME_ALIAS;
221
2.72k
222
2.72k
    onp = OPENSSL_malloc(sizeof(*onp));
223
2.72k
    if (onp == NULL) {
224
0
        /* ERROR */
225
0
        goto unlock;
226
0
    }
227
2.72k
228
2.72k
    onp->name = name;
229
2.72k
    onp->alias = alias;
230
2.72k
    onp->type = type;
231
2.72k
    onp->data = data;
232
2.72k
233
2.72k
    ret = lh_OBJ_NAME_insert(names_lh, onp);
234
2.72k
    if (ret != NULL) {
235
56
        /* free things */
236
56
        if ((name_funcs_stack != NULL)
237
56
            && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
238
0
            /*
239
0
             * XXX: I'm not sure I understand why the free function should
240
0
             * get three arguments... -- Richard Levitte
241
0
             */
242
0
            sk_NAME_FUNCS_value(name_funcs_stack,
243
0
                                ret->type)->free_func(ret->name, ret->type,
244
0
                                                      ret->data);
245
0
        }
246
56
        OPENSSL_free(ret);
247
2.66k
    } else {
248
2.66k
        if (lh_OBJ_NAME_error(names_lh)) {
249
0
            /* ERROR */
250
0
            OPENSSL_free(onp);
251
0
            goto unlock;
252
0
        }
253
2.72k
    }
254
2.72k
255
2.72k
    ok = 1;
256
2.72k
257
2.72k
unlock:
258
2.72k
    CRYPTO_THREAD_unlock(obj_lock);
259
2.72k
    return ok;
260
2.72k
}
261
262
int OBJ_NAME_remove(const char *name, int type)
263
2.66k
{
264
2.66k
    OBJ_NAME on, *ret;
265
2.66k
    int ok = 0;
266
2.66k
267
2.66k
    if (!OBJ_NAME_init())
268
0
        return 0;
269
2.66k
270
2.66k
    CRYPTO_THREAD_write_lock(obj_lock);
271
2.66k
272
2.66k
    type &= ~OBJ_NAME_ALIAS;
273
2.66k
    on.name = name;
274
2.66k
    on.type = type;
275
2.66k
    ret = lh_OBJ_NAME_delete(names_lh, &on);
276
2.66k
    if (ret != NULL) {
277
2.66k
        /* free things */
278
2.66k
        if ((name_funcs_stack != NULL)
279
2.66k
            && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) {
280
0
            /*
281
0
             * XXX: I'm not sure I understand why the free function should
282
0
             * get three arguments... -- Richard Levitte
283
0
             */
284
0
            sk_NAME_FUNCS_value(name_funcs_stack,
285
0
                                ret->type)->free_func(ret->name, ret->type,
286
0
                                                      ret->data);
287
0
        }
288
2.66k
        OPENSSL_free(ret);
289
2.66k
        ok = 1;
290
2.66k
    }
291
2.66k
292
2.66k
    CRYPTO_THREAD_unlock(obj_lock);
293
2.66k
    return ok;
294
2.66k
}
295
296
typedef struct {
297
    int type;
298
    void (*fn) (const OBJ_NAME *, void *arg);
299
    void *arg;
300
} OBJ_DOALL;
301
302
static void do_all_fn(const OBJ_NAME *name, OBJ_DOALL *d)
303
0
{
304
0
    if (name->type == d->type)
305
0
        d->fn(name, d->arg);
306
0
}
307
308
IMPLEMENT_LHASH_DOALL_ARG_CONST(OBJ_NAME, OBJ_DOALL);
309
310
void OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg),
311
                     void *arg)
312
0
{
313
0
    OBJ_DOALL d;
314
0
315
0
    d.type = type;
316
0
    d.fn = fn;
317
0
    d.arg = arg;
318
0
319
0
    lh_OBJ_NAME_doall_OBJ_DOALL(names_lh, do_all_fn, &d);
320
0
}
321
322
struct doall_sorted {
323
    int type;
324
    int n;
325
    const OBJ_NAME **names;
326
};
327
328
static void do_all_sorted_fn(const OBJ_NAME *name, void *d_)
329
0
{
330
0
    struct doall_sorted *d = d_;
331
0
332
0
    if (name->type != d->type)
333
0
        return;
334
0
335
0
    d->names[d->n++] = name;
336
0
}
337
338
static int do_all_sorted_cmp(const void *n1_, const void *n2_)
339
0
{
340
0
    const OBJ_NAME *const *n1 = n1_;
341
0
    const OBJ_NAME *const *n2 = n2_;
342
0
343
0
    return strcmp((*n1)->name, (*n2)->name);
344
0
}
345
346
void OBJ_NAME_do_all_sorted(int type,
347
                            void (*fn) (const OBJ_NAME *, void *arg),
348
                            void *arg)
349
0
{
350
0
    struct doall_sorted d;
351
0
    int n;
352
0
353
0
    d.type = type;
354
0
    d.names =
355
0
        OPENSSL_malloc(sizeof(*d.names) * lh_OBJ_NAME_num_items(names_lh));
356
0
    /* Really should return an error if !d.names...but its a void function! */
357
0
    if (d.names != NULL) {
358
0
        d.n = 0;
359
0
        OBJ_NAME_do_all(type, do_all_sorted_fn, &d);
360
0
361
0
        qsort((void *)d.names, d.n, sizeof(*d.names), do_all_sorted_cmp);
362
0
363
0
        for (n = 0; n < d.n; ++n)
364
0
            fn(d.names[n], arg);
365
0
366
0
        OPENSSL_free((void *)d.names);
367
0
    }
368
0
}
369
370
static int free_type;
371
372
static void names_lh_free_doall(OBJ_NAME *onp)
373
2.66k
{
374
2.66k
    if (onp == NULL)
375
2.66k
        return;
376
2.66k
377
2.66k
    if (free_type < 0 || free_type == onp->type)
378
2.66k
        OBJ_NAME_remove(onp->name, onp->type);
379
2.66k
}
380
381
static void name_funcs_free(NAME_FUNCS *ptr)
382
0
{
383
0
    OPENSSL_free(ptr);
384
0
}
385
386
void OBJ_NAME_cleanup(int type)
387
24
{
388
24
    unsigned long down_load;
389
24
390
24
    if (names_lh == NULL)
391
24
        return;
392
24
393
24
    free_type = type;
394
24
    down_load = lh_OBJ_NAME_get_down_load(names_lh);
395
24
    lh_OBJ_NAME_set_down_load(names_lh, 0);
396
24
397
24
    lh_OBJ_NAME_doall(names_lh, names_lh_free_doall);
398
24
    if (type < 0) {
399
8
        lh_OBJ_NAME_free(names_lh);
400
8
        sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free);
401
8
        CRYPTO_THREAD_lock_free(obj_lock);
402
8
        names_lh = NULL;
403
8
        name_funcs_stack = NULL;
404
8
        obj_lock = NULL;
405
8
    } else
406
16
        lh_OBJ_NAME_set_down_load(names_lh, down_load);
407
24
}