Coverage Report

Created: 2026-01-17 07:10

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