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