1/* 2 * Copyright 1998-2021 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) 33static int obj_strcasecmp(const char *a, const char *b) 34{ 35 return strcasecmp(a, b); 36} 37#else 38#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 */ 45static LHASH_OF(OBJ_NAME) *names_lh = NULL; 46static int names_type_num = OBJ_NAME_TYPE_NUM; 47static CRYPTO_RWLOCK *obj_lock = NULL; 48 49struct 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 55static 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 63static unsigned long obj_name_hash(const OBJ_NAME *a); 64static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b); 65 66static CRYPTO_ONCE init = CRYPTO_ONCE_STATIC_INIT; 67DEFINE_RUN_ONCE_STATIC(o_names_init) 68{ 69 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); 70 names_lh = NULL; 71 obj_lock = CRYPTO_THREAD_lock_new(); 72 if (obj_lock != NULL) 73 names_lh = lh_OBJ_NAME_new(obj_name_hash, obj_name_cmp); 74 if (names_lh == NULL) { 75 CRYPTO_THREAD_lock_free(obj_lock); 76 obj_lock = NULL; 77 } 78 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); 79 return names_lh != NULL && obj_lock != NULL; 80} 81 82int OBJ_NAME_init(void) 83{ 84 return RUN_ONCE(&init, o_names_init); 85} 86 87int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *), 88 int (*cmp_func) (const char *, const char *), 89 void (*free_func) (const char *, int, const char *)) 90{ 91 int ret = 0, i, push; 92 NAME_FUNCS *name_funcs; 93 94 if (!OBJ_NAME_init()) 95 return 0; 96 97 CRYPTO_THREAD_write_lock(obj_lock); 98 99 if (name_funcs_stack == NULL) { 100 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); 101 name_funcs_stack = sk_NAME_FUNCS_new_null(); 102 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); 103 } 104 if (name_funcs_stack == NULL) { 105 /* ERROR */ 106 goto out; 107 } 108 ret = names_type_num; 109 names_type_num++; 110 for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) { 111 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); 112 name_funcs = OPENSSL_zalloc(sizeof(*name_funcs)); 113 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); 114 if (name_funcs == NULL) { 115 OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE); 116 ret = 0; 117 goto out; 118 } 119 name_funcs->hash_func = openssl_lh_strcasehash; 120 name_funcs->cmp_func = obj_strcasecmp; 121 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE); 122 123 push = sk_NAME_FUNCS_push(name_funcs_stack, name_funcs); 124 CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE); 125 126 if (!push) { 127 OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE); 128 OPENSSL_free(name_funcs); 129 ret = 0; 130 goto out; 131 } 132 } 133 name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret); 134 if (hash_func != NULL) 135 name_funcs->hash_func = hash_func; 136 if (cmp_func != NULL) 137 name_funcs->cmp_func = cmp_func; 138 if (free_func != NULL) 139 name_funcs->free_func = free_func; 140 141out: 142 CRYPTO_THREAD_unlock(obj_lock); 143 return ret; 144} 145 146static int obj_name_cmp(const OBJ_NAME *a, const OBJ_NAME *b) 147{ 148 int ret; 149 150 ret = a->type - b->type; 151 if (ret == 0) { 152 if ((name_funcs_stack != NULL) 153 && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) { 154 ret = sk_NAME_FUNCS_value(name_funcs_stack, 155 a->type)->cmp_func(a->name, b->name); 156 } else 157 ret = strcasecmp(a->name, b->name); 158 } 159 return ret; 160} 161 162static unsigned long obj_name_hash(const OBJ_NAME *a) 163{ 164 unsigned long ret; 165 166 if ((name_funcs_stack != NULL) 167 && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) { 168 ret = 169 sk_NAME_FUNCS_value(name_funcs_stack, 170 a->type)->hash_func(a->name); 171 } else { 172 ret = openssl_lh_strcasehash(a->name); 173 } 174 ret ^= a->type; 175 return ret; 176} 177 178const char *OBJ_NAME_get(const char *name, int type) 179{ 180 OBJ_NAME on, *ret; 181 int num = 0, alias; 182 const char *value = NULL; 183 184 if (name == NULL) 185 return NULL; 186 if (!OBJ_NAME_init()) 187 return NULL; 188 CRYPTO_THREAD_read_lock(obj_lock); 189 190 alias = type & OBJ_NAME_ALIAS; 191 type &= ~OBJ_NAME_ALIAS; 192 193 on.name = name; 194 on.type = type; 195 196 for (;;) { 197 ret = lh_OBJ_NAME_retrieve(names_lh, &on); 198 if (ret == NULL) 199 break; 200 if ((ret->alias) && !alias) { 201 if (++num > 10) 202 break; 203 on.name = ret->data; 204 } else { 205 value = ret->data; 206 break; 207 } 208 } 209 210 CRYPTO_THREAD_unlock(obj_lock); 211 return value; 212} 213 214int OBJ_NAME_add(const char *name, int type, const char *data) 215{ 216 OBJ_NAME *onp, *ret; 217 int alias, ok = 0; 218 219 if (!OBJ_NAME_init()) 220 return 0; 221 222 alias = type & OBJ_NAME_ALIAS; 223 type &= ~OBJ_NAME_ALIAS; 224 225 onp = OPENSSL_malloc(sizeof(*onp)); 226 if (onp == NULL) 227 return 0; 228 229 onp->name = name; 230 onp->alias = alias; 231 onp->type = type; 232 onp->data = data; 233 234 CRYPTO_THREAD_write_lock(obj_lock); 235 236 ret = lh_OBJ_NAME_insert(names_lh, onp); 237 if (ret != NULL) { 238 /* free things */ 239 if ((name_funcs_stack != NULL) 240 && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) { 241 /* 242 * XXX: I'm not sure I understand why the free function should 243 * get three arguments... -- Richard Levitte 244 */ 245 sk_NAME_FUNCS_value(name_funcs_stack, 246 ret->type)->free_func(ret->name, ret->type, 247 ret->data); 248 } 249 OPENSSL_free(ret); 250 } else { 251 if (lh_OBJ_NAME_error(names_lh)) { 252 /* ERROR */ 253 OPENSSL_free(onp); 254 goto unlock; 255 } 256 } 257 258 ok = 1; 259 260unlock: 261 CRYPTO_THREAD_unlock(obj_lock); 262 return ok; 263} 264 265int OBJ_NAME_remove(const char *name, int type) 266{ 267 OBJ_NAME on, *ret; 268 int ok = 0; 269 270 if (!OBJ_NAME_init()) 271 return 0; 272 273 CRYPTO_THREAD_write_lock(obj_lock); 274 275 type &= ~OBJ_NAME_ALIAS; 276 on.name = name; 277 on.type = type; 278 ret = lh_OBJ_NAME_delete(names_lh, &on); 279 if (ret != NULL) { 280 /* free things */ 281 if ((name_funcs_stack != NULL) 282 && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) { 283 /* 284 * XXX: I'm not sure I understand why the free function should 285 * get three arguments... -- Richard Levitte 286 */ 287 sk_NAME_FUNCS_value(name_funcs_stack, 288 ret->type)->free_func(ret->name, ret->type, 289 ret->data); 290 } 291 OPENSSL_free(ret); 292 ok = 1; 293 } 294 295 CRYPTO_THREAD_unlock(obj_lock); 296 return ok; 297} 298 299typedef struct { 300 int type; 301 void (*fn) (const OBJ_NAME *, void *arg); 302 void *arg; 303} OBJ_DOALL; 304 305static void do_all_fn(const OBJ_NAME *name, OBJ_DOALL *d) 306{ 307 if (name->type == d->type) 308 d->fn(name, d->arg); 309} 310 311IMPLEMENT_LHASH_DOALL_ARG_CONST(OBJ_NAME, OBJ_DOALL); 312 313void OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg), 314 void *arg) 315{ 316 OBJ_DOALL d; 317 318 d.type = type; 319 d.fn = fn; 320 d.arg = arg; 321 322 lh_OBJ_NAME_doall_OBJ_DOALL(names_lh, do_all_fn, &d); 323} 324 325struct doall_sorted { 326 int type; 327 int n; 328 const OBJ_NAME **names; 329}; 330 331static void do_all_sorted_fn(const OBJ_NAME *name, void *d_) 332{ 333 struct doall_sorted *d = d_; 334 335 if (name->type != d->type) 336 return; 337 338 d->names[d->n++] = name; 339} 340 341static int do_all_sorted_cmp(const void *n1_, const void *n2_) 342{ 343 const OBJ_NAME *const *n1 = n1_; 344 const OBJ_NAME *const *n2 = n2_; 345 346 return strcmp((*n1)->name, (*n2)->name); 347} 348 349void OBJ_NAME_do_all_sorted(int type, 350 void (*fn) (const OBJ_NAME *, void *arg), 351 void *arg) 352{ 353 struct doall_sorted d; 354 int n; 355 356 d.type = type; 357 d.names = 358 OPENSSL_malloc(sizeof(*d.names) * lh_OBJ_NAME_num_items(names_lh)); 359 /* Really should return an error if !d.names...but its a void function! */ 360 if (d.names != NULL) { 361 d.n = 0; 362 OBJ_NAME_do_all(type, do_all_sorted_fn, &d); 363 364 qsort((void *)d.names, d.n, sizeof(*d.names), do_all_sorted_cmp); 365 366 for (n = 0; n < d.n; ++n) 367 fn(d.names[n], arg); 368 369 OPENSSL_free((void *)d.names); 370 } 371} 372 373static int free_type; 374 375static void names_lh_free_doall(OBJ_NAME *onp) 376{ 377 if (onp == NULL) 378 return; 379 380 if (free_type < 0 || free_type == onp->type) 381 OBJ_NAME_remove(onp->name, onp->type); 382} 383 384static void name_funcs_free(NAME_FUNCS *ptr) 385{ 386 OPENSSL_free(ptr); 387} 388 389void OBJ_NAME_cleanup(int type) 390{ 391 unsigned long down_load; 392 393 if (names_lh == NULL) 394 return; 395 396 free_type = type; 397 down_load = lh_OBJ_NAME_get_down_load(names_lh); 398 lh_OBJ_NAME_set_down_load(names_lh, 0); 399 400 lh_OBJ_NAME_doall(names_lh, names_lh_free_doall); 401 if (type < 0) { 402 lh_OBJ_NAME_free(names_lh); 403 sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free); 404 CRYPTO_THREAD_lock_free(obj_lock); 405 names_lh = NULL; 406 name_funcs_stack = NULL; 407 obj_lock = NULL; 408 } else 409 lh_OBJ_NAME_set_down_load(names_lh, down_load); 410} 411