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