o_names.c revision 296465
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5#include <openssl/err.h> 6#include <openssl/lhash.h> 7#include <openssl/objects.h> 8#include <openssl/safestack.h> 9#include <openssl/e_os2.h> 10 11/* 12 * Later versions of DEC C has started to add lnkage information to certain 13 * functions, which makes it tricky to use them as values to regular function 14 * pointers. One way is to define a macro that takes care of casting them 15 * correctly. 16 */ 17#ifdef OPENSSL_SYS_VMS_DECC 18# define OPENSSL_strcmp (int (*)(const char *,const char *))strcmp 19#else 20# define OPENSSL_strcmp strcmp 21#endif 22 23/* 24 * I use the ex_data stuff to manage the identifiers for the obj_name_types 25 * that applications may define. I only really use the free function field. 26 */ 27static LHASH *names_lh = NULL; 28static int names_type_num = OBJ_NAME_TYPE_NUM; 29 30typedef struct name_funcs_st { 31 unsigned long (*hash_func) (const char *name); 32 int (*cmp_func) (const char *a, const char *b); 33 void (*free_func) (const char *, int, const char *); 34} NAME_FUNCS; 35 36DECLARE_STACK_OF(NAME_FUNCS) 37IMPLEMENT_STACK_OF(NAME_FUNCS) 38 39static STACK_OF(NAME_FUNCS) *name_funcs_stack; 40 41/* 42 * The LHASH callbacks now use the raw "void *" prototypes and do 43 * per-variable casting in the functions. This prevents function pointer 44 * casting without the need for macro-generated wrapper functions. 45 */ 46 47/* static unsigned long obj_name_hash(OBJ_NAME *a); */ 48static unsigned long obj_name_hash(const void *a_void); 49/* static int obj_name_cmp(OBJ_NAME *a,OBJ_NAME *b); */ 50static int obj_name_cmp(const void *a_void, const void *b_void); 51 52int OBJ_NAME_init(void) 53{ 54 if (names_lh != NULL) 55 return (1); 56 MemCheck_off(); 57 names_lh = lh_new(obj_name_hash, obj_name_cmp); 58 MemCheck_on(); 59 return (names_lh != NULL); 60} 61 62int OBJ_NAME_new_index(unsigned long (*hash_func) (const char *), 63 int (*cmp_func) (const char *, const char *), 64 void (*free_func) (const char *, int, const char *)) 65{ 66 int ret; 67 int i; 68 NAME_FUNCS *name_funcs; 69 70 if (name_funcs_stack == NULL) { 71 MemCheck_off(); 72 name_funcs_stack = sk_NAME_FUNCS_new_null(); 73 MemCheck_on(); 74 } 75 if ((name_funcs_stack == NULL)) { 76 /* ERROR */ 77 return (0); 78 } 79 ret = names_type_num; 80 names_type_num++; 81 for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) { 82 MemCheck_off(); 83 name_funcs = OPENSSL_malloc(sizeof(NAME_FUNCS)); 84 MemCheck_on(); 85 if (!name_funcs) { 86 OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE); 87 return (0); 88 } 89 name_funcs->hash_func = lh_strhash; 90 name_funcs->cmp_func = OPENSSL_strcmp; 91 name_funcs->free_func = 0; /* NULL is often declared to * ((void 92 * *)0), which according * to Compaq C is 93 * not really * compatible with a function 94 * * pointer. -- Richard Levitte */ 95 MemCheck_off(); 96 sk_NAME_FUNCS_push(name_funcs_stack, name_funcs); 97 MemCheck_on(); 98 } 99 name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret); 100 if (hash_func != NULL) 101 name_funcs->hash_func = hash_func; 102 if (cmp_func != NULL) 103 name_funcs->cmp_func = cmp_func; 104 if (free_func != NULL) 105 name_funcs->free_func = free_func; 106 return (ret); 107} 108 109/* static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b) */ 110static int obj_name_cmp(const void *a_void, const void *b_void) 111{ 112 int ret; 113 const OBJ_NAME *a = (const OBJ_NAME *)a_void; 114 const OBJ_NAME *b = (const OBJ_NAME *)b_void; 115 116 ret = a->type - b->type; 117 if (ret == 0) { 118 if ((name_funcs_stack != NULL) 119 && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) { 120 ret = sk_NAME_FUNCS_value(name_funcs_stack, 121 a->type)->cmp_func(a->name, b->name); 122 } else 123 ret = strcmp(a->name, b->name); 124 } 125 return (ret); 126} 127 128/* static unsigned long obj_name_hash(OBJ_NAME *a) */ 129static unsigned long obj_name_hash(const void *a_void) 130{ 131 unsigned long ret; 132 const OBJ_NAME *a = (const OBJ_NAME *)a_void; 133 134 if ((name_funcs_stack != NULL) 135 && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) { 136 ret = 137 sk_NAME_FUNCS_value(name_funcs_stack, 138 a->type)->hash_func(a->name); 139 } else { 140 ret = lh_strhash(a->name); 141 } 142 ret ^= a->type; 143 return (ret); 144} 145 146const char *OBJ_NAME_get(const char *name, int type) 147{ 148 OBJ_NAME on, *ret; 149 int num = 0, alias; 150 151 if (name == NULL) 152 return (NULL); 153 if ((names_lh == NULL) && !OBJ_NAME_init()) 154 return (NULL); 155 156 alias = type & OBJ_NAME_ALIAS; 157 type &= ~OBJ_NAME_ALIAS; 158 159 on.name = name; 160 on.type = type; 161 162 for (;;) { 163 ret = (OBJ_NAME *)lh_retrieve(names_lh, &on); 164 if (ret == NULL) 165 return (NULL); 166 if ((ret->alias) && !alias) { 167 if (++num > 10) 168 return (NULL); 169 on.name = ret->data; 170 } else { 171 return (ret->data); 172 } 173 } 174} 175 176int OBJ_NAME_add(const char *name, int type, const char *data) 177{ 178 OBJ_NAME *onp, *ret; 179 int alias; 180 181 if ((names_lh == NULL) && !OBJ_NAME_init()) 182 return (0); 183 184 alias = type & OBJ_NAME_ALIAS; 185 type &= ~OBJ_NAME_ALIAS; 186 187 onp = (OBJ_NAME *)OPENSSL_malloc(sizeof(OBJ_NAME)); 188 if (onp == NULL) { 189 /* ERROR */ 190 return (0); 191 } 192 193 onp->name = name; 194 onp->alias = alias; 195 onp->type = type; 196 onp->data = data; 197 198 ret = (OBJ_NAME *)lh_insert(names_lh, onp); 199 if (ret != NULL) { 200 /* free things */ 201 if ((name_funcs_stack != NULL) 202 && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) { 203 /* 204 * XXX: I'm not sure I understand why the free function should 205 * get three arguments... -- Richard Levitte 206 */ 207 sk_NAME_FUNCS_value(name_funcs_stack, 208 ret->type)->free_func(ret->name, ret->type, 209 ret->data); 210 } 211 OPENSSL_free(ret); 212 } else { 213 if (lh_error(names_lh)) { 214 /* ERROR */ 215 return (0); 216 } 217 } 218 return (1); 219} 220 221int OBJ_NAME_remove(const char *name, int type) 222{ 223 OBJ_NAME on, *ret; 224 225 if (names_lh == NULL) 226 return (0); 227 228 type &= ~OBJ_NAME_ALIAS; 229 on.name = name; 230 on.type = type; 231 ret = (OBJ_NAME *)lh_delete(names_lh, &on); 232 if (ret != NULL) { 233 /* free things */ 234 if ((name_funcs_stack != NULL) 235 && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) { 236 /* 237 * XXX: I'm not sure I understand why the free function should 238 * get three arguments... -- Richard Levitte 239 */ 240 sk_NAME_FUNCS_value(name_funcs_stack, 241 ret->type)->free_func(ret->name, ret->type, 242 ret->data); 243 } 244 OPENSSL_free(ret); 245 return (1); 246 } else 247 return (0); 248} 249 250struct doall { 251 int type; 252 void (*fn) (const OBJ_NAME *, void *arg); 253 void *arg; 254}; 255 256static void do_all_fn(const OBJ_NAME *name, struct doall *d) 257{ 258 if (name->type == d->type) 259 d->fn(name, d->arg); 260} 261 262static IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME *, 263 struct doall *) 264 265void OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg), 266 void *arg) 267{ 268 struct doall d; 269 270 d.type = type; 271 d.fn = fn; 272 d.arg = arg; 273 274 lh_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn), &d); 275} 276 277struct doall_sorted { 278 int type; 279 int n; 280 const OBJ_NAME **names; 281}; 282 283static void do_all_sorted_fn(const OBJ_NAME *name, void *d_) 284{ 285 struct doall_sorted *d = d_; 286 287 if (name->type != d->type) 288 return; 289 290 d->names[d->n++] = name; 291} 292 293static int do_all_sorted_cmp(const void *n1_, const void *n2_) 294{ 295 const OBJ_NAME *const *n1 = n1_; 296 const OBJ_NAME *const *n2 = n2_; 297 298 return strcmp((*n1)->name, (*n2)->name); 299} 300 301void OBJ_NAME_do_all_sorted(int type, 302 void (*fn) (const OBJ_NAME *, void *arg), 303 void *arg) 304{ 305 struct doall_sorted d; 306 int n; 307 308 d.type = type; 309 d.names = OPENSSL_malloc(lh_num_items(names_lh) * sizeof *d.names); 310 d.n = 0; 311 OBJ_NAME_do_all(type, do_all_sorted_fn, &d); 312 313 qsort((void *)d.names, d.n, sizeof *d.names, do_all_sorted_cmp); 314 315 for (n = 0; n < d.n; ++n) 316 fn(d.names[n], arg); 317 318 OPENSSL_free((void *)d.names); 319} 320 321static int free_type; 322 323static void names_lh_free(OBJ_NAME *onp) 324{ 325 if (onp == NULL) 326 return; 327 328 if ((free_type < 0) || (free_type == onp->type)) { 329 OBJ_NAME_remove(onp->name, onp->type); 330 } 331} 332 333static IMPLEMENT_LHASH_DOALL_FN(names_lh_free, OBJ_NAME *) 334 335static void name_funcs_free(NAME_FUNCS *ptr) 336{ 337 OPENSSL_free(ptr); 338} 339 340void OBJ_NAME_cleanup(int type) 341{ 342 unsigned long down_load; 343 344 if (names_lh == NULL) 345 return; 346 347 free_type = type; 348 down_load = names_lh->down_load; 349 names_lh->down_load = 0; 350 351 lh_doall(names_lh, LHASH_DOALL_FN(names_lh_free)); 352 if (type < 0) { 353 lh_free(names_lh); 354 sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free); 355 names_lh = NULL; 356 name_funcs_stack = NULL; 357 } else 358 names_lh->down_load = down_load; 359} 360