155714Skris#include <stdio.h> 255714Skris#include <stdlib.h> 355714Skris#include <string.h> 455714Skris 5160814Ssimon#include <openssl/err.h> 655714Skris#include <openssl/lhash.h> 755714Skris#include <openssl/objects.h> 859191Skris#include <openssl/safestack.h> 9109998Smarkm#include <openssl/e_os2.h> 1055714Skris 11280304Sjkim/* 12280304Sjkim * Later versions of DEC C has started to add lnkage information to certain 13109998Smarkm * functions, which makes it tricky to use them as values to regular function 14109998Smarkm * pointers. One way is to define a macro that takes care of casting them 15109998Smarkm * correctly. 16109998Smarkm */ 17109998Smarkm#ifdef OPENSSL_SYS_VMS_DECC 18109998Smarkm# define OPENSSL_strcmp (int (*)(const char *,const char *))strcmp 19109998Smarkm#else 20109998Smarkm# define OPENSSL_strcmp strcmp 21109998Smarkm#endif 22109998Smarkm 23280304Sjkim/* 24280304Sjkim * I use the ex_data stuff to manage the identifiers for the obj_name_types 2555714Skris * that applications may define. I only really use the free function field. 2655714Skris */ 27238405SjkimDECLARE_LHASH_OF(OBJ_NAME); 28280304Sjkimstatic LHASH_OF(OBJ_NAME) *names_lh = NULL; 29280304Sjkimstatic int names_type_num = OBJ_NAME_TYPE_NUM; 3055714Skris 31280304Sjkimtypedef struct name_funcs_st { 32280304Sjkim unsigned long (*hash_func) (const char *name); 33280304Sjkim int (*cmp_func) (const char *a, const char *b); 34280304Sjkim void (*free_func) (const char *, int, const char *); 35280304Sjkim} NAME_FUNCS; 3659191Skris 3759191SkrisDECLARE_STACK_OF(NAME_FUNCS) 3859191SkrisIMPLEMENT_STACK_OF(NAME_FUNCS) 3959191Skris 4059191Skrisstatic STACK_OF(NAME_FUNCS) *name_funcs_stack; 4159191Skris 42280304Sjkim/* 43280304Sjkim * The LHASH callbacks now use the raw "void *" prototypes and do 44280304Sjkim * per-variable casting in the functions. This prevents function pointer 45280304Sjkim * casting without the need for macro-generated wrapper functions. 46280304Sjkim */ 4755714Skris 48109998Smarkm/* static unsigned long obj_name_hash(OBJ_NAME *a); */ 49109998Smarkmstatic unsigned long obj_name_hash(const void *a_void); 50109998Smarkm/* static int obj_name_cmp(OBJ_NAME *a,OBJ_NAME *b); */ 51280304Sjkimstatic int obj_name_cmp(const void *a_void, const void *b_void); 52109998Smarkm 53238405Sjkimstatic IMPLEMENT_LHASH_HASH_FN(obj_name, OBJ_NAME) 54238405Sjkimstatic IMPLEMENT_LHASH_COMP_FN(obj_name, OBJ_NAME) 55238405Sjkim 5655714Skrisint OBJ_NAME_init(void) 57280304Sjkim{ 58280304Sjkim if (names_lh != NULL) 59280304Sjkim return (1); 60280304Sjkim MemCheck_off(); 61280304Sjkim names_lh = lh_OBJ_NAME_new(); 62280304Sjkim MemCheck_on(); 63280304Sjkim return (names_lh != NULL); 64280304Sjkim} 6555714Skris 66280304Sjkimint OBJ_NAME_new_index(unsigned long (*hash_func) (const char *), 67280304Sjkim int (*cmp_func) (const char *, const char *), 68280304Sjkim void (*free_func) (const char *, int, const char *)) 69280304Sjkim{ 70280304Sjkim int ret; 71280304Sjkim int i; 72280304Sjkim NAME_FUNCS *name_funcs; 7355714Skris 74280304Sjkim if (name_funcs_stack == NULL) { 75280304Sjkim MemCheck_off(); 76280304Sjkim name_funcs_stack = sk_NAME_FUNCS_new_null(); 77280304Sjkim MemCheck_on(); 78280304Sjkim } 79280304Sjkim if (name_funcs_stack == NULL) { 80280304Sjkim /* ERROR */ 81280304Sjkim return (0); 82280304Sjkim } 83280304Sjkim ret = names_type_num; 84280304Sjkim names_type_num++; 85280304Sjkim for (i = sk_NAME_FUNCS_num(name_funcs_stack); i < names_type_num; i++) { 86280304Sjkim MemCheck_off(); 87280304Sjkim name_funcs = OPENSSL_malloc(sizeof(NAME_FUNCS)); 88280304Sjkim MemCheck_on(); 89280304Sjkim if (!name_funcs) { 90280304Sjkim OBJerr(OBJ_F_OBJ_NAME_NEW_INDEX, ERR_R_MALLOC_FAILURE); 91280304Sjkim return (0); 92280304Sjkim } 93280304Sjkim name_funcs->hash_func = lh_strhash; 94280304Sjkim name_funcs->cmp_func = OPENSSL_strcmp; 95280304Sjkim name_funcs->free_func = 0; /* NULL is often declared to * ((void 96280304Sjkim * *)0), which according * to Compaq C is 97280304Sjkim * not really * compatible with a function 98280304Sjkim * * pointer. -- Richard Levitte */ 99280304Sjkim MemCheck_off(); 100280304Sjkim sk_NAME_FUNCS_push(name_funcs_stack, name_funcs); 101280304Sjkim MemCheck_on(); 102280304Sjkim } 103280304Sjkim name_funcs = sk_NAME_FUNCS_value(name_funcs_stack, ret); 104280304Sjkim if (hash_func != NULL) 105280304Sjkim name_funcs->hash_func = hash_func; 106280304Sjkim if (cmp_func != NULL) 107280304Sjkim name_funcs->cmp_func = cmp_func; 108280304Sjkim if (free_func != NULL) 109280304Sjkim name_funcs->free_func = free_func; 110280304Sjkim return (ret); 111280304Sjkim} 11255714Skris 113109998Smarkm/* static int obj_name_cmp(OBJ_NAME *a, OBJ_NAME *b) */ 114109998Smarkmstatic int obj_name_cmp(const void *a_void, const void *b_void) 115280304Sjkim{ 116280304Sjkim int ret; 117280304Sjkim const OBJ_NAME *a = (const OBJ_NAME *)a_void; 118280304Sjkim const OBJ_NAME *b = (const OBJ_NAME *)b_void; 11955714Skris 120280304Sjkim ret = a->type - b->type; 121280304Sjkim if (ret == 0) { 122280304Sjkim if ((name_funcs_stack != NULL) 123280304Sjkim && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) { 124280304Sjkim ret = sk_NAME_FUNCS_value(name_funcs_stack, 125280304Sjkim a->type)->cmp_func(a->name, b->name); 126280304Sjkim } else 127280304Sjkim ret = strcmp(a->name, b->name); 128280304Sjkim } 129280304Sjkim return (ret); 130280304Sjkim} 13155714Skris 132109998Smarkm/* static unsigned long obj_name_hash(OBJ_NAME *a) */ 133109998Smarkmstatic unsigned long obj_name_hash(const void *a_void) 134280304Sjkim{ 135280304Sjkim unsigned long ret; 136280304Sjkim const OBJ_NAME *a = (const OBJ_NAME *)a_void; 13755714Skris 138280304Sjkim if ((name_funcs_stack != NULL) 139280304Sjkim && (sk_NAME_FUNCS_num(name_funcs_stack) > a->type)) { 140280304Sjkim ret = 141280304Sjkim sk_NAME_FUNCS_value(name_funcs_stack, 142280304Sjkim a->type)->hash_func(a->name); 143280304Sjkim } else { 144280304Sjkim ret = lh_strhash(a->name); 145280304Sjkim } 146280304Sjkim ret ^= a->type; 147280304Sjkim return (ret); 148280304Sjkim} 14955714Skris 15055714Skrisconst char *OBJ_NAME_get(const char *name, int type) 151280304Sjkim{ 152280304Sjkim OBJ_NAME on, *ret; 153280304Sjkim int num = 0, alias; 15455714Skris 155280304Sjkim if (name == NULL) 156280304Sjkim return (NULL); 157280304Sjkim if ((names_lh == NULL) && !OBJ_NAME_init()) 158280304Sjkim return (NULL); 15955714Skris 160280304Sjkim alias = type & OBJ_NAME_ALIAS; 161280304Sjkim type &= ~OBJ_NAME_ALIAS; 16255714Skris 163280304Sjkim on.name = name; 164280304Sjkim on.type = type; 16555714Skris 166280304Sjkim for (;;) { 167280304Sjkim ret = lh_OBJ_NAME_retrieve(names_lh, &on); 168280304Sjkim if (ret == NULL) 169280304Sjkim return (NULL); 170280304Sjkim if ((ret->alias) && !alias) { 171280304Sjkim if (++num > 10) 172280304Sjkim return (NULL); 173280304Sjkim on.name = ret->data; 174280304Sjkim } else { 175280304Sjkim return (ret->data); 176280304Sjkim } 177280304Sjkim } 178280304Sjkim} 17955714Skris 18055714Skrisint OBJ_NAME_add(const char *name, int type, const char *data) 181280304Sjkim{ 182280304Sjkim OBJ_NAME *onp, *ret; 183280304Sjkim int alias; 18455714Skris 185280304Sjkim if ((names_lh == NULL) && !OBJ_NAME_init()) 186280304Sjkim return (0); 18755714Skris 188280304Sjkim alias = type & OBJ_NAME_ALIAS; 189280304Sjkim type &= ~OBJ_NAME_ALIAS; 19055714Skris 191280304Sjkim onp = (OBJ_NAME *)OPENSSL_malloc(sizeof(OBJ_NAME)); 192280304Sjkim if (onp == NULL) { 193280304Sjkim /* ERROR */ 194280304Sjkim return (0); 195280304Sjkim } 19655714Skris 197280304Sjkim onp->name = name; 198280304Sjkim onp->alias = alias; 199280304Sjkim onp->type = type; 200280304Sjkim onp->data = data; 20155714Skris 202280304Sjkim ret = lh_OBJ_NAME_insert(names_lh, onp); 203280304Sjkim if (ret != NULL) { 204280304Sjkim /* free things */ 205280304Sjkim if ((name_funcs_stack != NULL) 206280304Sjkim && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) { 207280304Sjkim /* 208280304Sjkim * XXX: I'm not sure I understand why the free function should 209280304Sjkim * get three arguments... -- Richard Levitte 210280304Sjkim */ 211280304Sjkim sk_NAME_FUNCS_value(name_funcs_stack, 212280304Sjkim ret->type)->free_func(ret->name, ret->type, 213280304Sjkim ret->data); 214280304Sjkim } 215280304Sjkim OPENSSL_free(ret); 216280304Sjkim } else { 217280304Sjkim if (lh_OBJ_NAME_error(names_lh)) { 218280304Sjkim /* ERROR */ 219280304Sjkim return (0); 220280304Sjkim } 221280304Sjkim } 222280304Sjkim return (1); 223280304Sjkim} 22455714Skris 22555714Skrisint OBJ_NAME_remove(const char *name, int type) 226280304Sjkim{ 227280304Sjkim OBJ_NAME on, *ret; 22855714Skris 229280304Sjkim if (names_lh == NULL) 230280304Sjkim return (0); 23155714Skris 232280304Sjkim type &= ~OBJ_NAME_ALIAS; 233280304Sjkim on.name = name; 234280304Sjkim on.type = type; 235280304Sjkim ret = lh_OBJ_NAME_delete(names_lh, &on); 236280304Sjkim if (ret != NULL) { 237280304Sjkim /* free things */ 238280304Sjkim if ((name_funcs_stack != NULL) 239280304Sjkim && (sk_NAME_FUNCS_num(name_funcs_stack) > ret->type)) { 240280304Sjkim /* 241280304Sjkim * XXX: I'm not sure I understand why the free function should 242280304Sjkim * get three arguments... -- Richard Levitte 243280304Sjkim */ 244280304Sjkim sk_NAME_FUNCS_value(name_funcs_stack, 245280304Sjkim ret->type)->free_func(ret->name, ret->type, 246280304Sjkim ret->data); 247280304Sjkim } 248280304Sjkim OPENSSL_free(ret); 249280304Sjkim return (1); 250280304Sjkim } else 251280304Sjkim return (0); 252280304Sjkim} 25355714Skris 254280304Sjkimstruct doall { 255280304Sjkim int type; 256280304Sjkim void (*fn) (const OBJ_NAME *, void *arg); 257280304Sjkim void *arg; 258280304Sjkim}; 259109998Smarkm 260280304Sjkimstatic void do_all_fn_doall_arg(const OBJ_NAME *name, struct doall *d) 261280304Sjkim{ 262280304Sjkim if (name->type == d->type) 263280304Sjkim d->fn(name, d->arg); 264280304Sjkim} 265109998Smarkm 266238405Sjkimstatic IMPLEMENT_LHASH_DOALL_ARG_FN(do_all_fn, const OBJ_NAME, struct doall) 267109998Smarkm 268280304Sjkimvoid OBJ_NAME_do_all(int type, void (*fn) (const OBJ_NAME *, void *arg), 269280304Sjkim void *arg) 270280304Sjkim{ 271280304Sjkim struct doall d; 272109998Smarkm 273280304Sjkim d.type = type; 274280304Sjkim d.fn = fn; 275280304Sjkim d.arg = arg; 276109998Smarkm 277280304Sjkim lh_OBJ_NAME_doall_arg(names_lh, LHASH_DOALL_ARG_FN(do_all_fn), 278280304Sjkim struct doall, &d); 279280304Sjkim} 280109998Smarkm 281280304Sjkimstruct doall_sorted { 282280304Sjkim int type; 283280304Sjkim int n; 284280304Sjkim const OBJ_NAME **names; 285280304Sjkim}; 286109998Smarkm 287280304Sjkimstatic void do_all_sorted_fn(const OBJ_NAME *name, void *d_) 288280304Sjkim{ 289280304Sjkim struct doall_sorted *d = d_; 290109998Smarkm 291280304Sjkim if (name->type != d->type) 292280304Sjkim return; 293109998Smarkm 294280304Sjkim d->names[d->n++] = name; 295280304Sjkim} 296109998Smarkm 297280304Sjkimstatic int do_all_sorted_cmp(const void *n1_, const void *n2_) 298280304Sjkim{ 299280304Sjkim const OBJ_NAME *const *n1 = n1_; 300280304Sjkim const OBJ_NAME *const *n2 = n2_; 301109998Smarkm 302280304Sjkim return strcmp((*n1)->name, (*n2)->name); 303280304Sjkim} 304109998Smarkm 305280304Sjkimvoid OBJ_NAME_do_all_sorted(int type, 306280304Sjkim void (*fn) (const OBJ_NAME *, void *arg), 307280304Sjkim void *arg) 308280304Sjkim{ 309280304Sjkim struct doall_sorted d; 310280304Sjkim int n; 311109998Smarkm 312280304Sjkim d.type = type; 313280304Sjkim d.names = 314280304Sjkim OPENSSL_malloc(lh_OBJ_NAME_num_items(names_lh) * sizeof *d.names); 315280304Sjkim /* Really should return an error if !d.names...but its a void function! */ 316284285Sjkim if (d.names) { 317280304Sjkim d.n = 0; 318280304Sjkim OBJ_NAME_do_all(type, do_all_sorted_fn, &d); 319109998Smarkm 320280304Sjkim qsort((void *)d.names, d.n, sizeof *d.names, do_all_sorted_cmp); 321109998Smarkm 322280304Sjkim for (n = 0; n < d.n; ++n) 323280304Sjkim fn(d.names[n], arg); 324109998Smarkm 325280304Sjkim OPENSSL_free((void *)d.names); 326280304Sjkim } 327280304Sjkim} 328109998Smarkm 32955714Skrisstatic int free_type; 33055714Skris 331238405Sjkimstatic void names_lh_free_doall(OBJ_NAME *onp) 332280304Sjkim{ 333280304Sjkim if (onp == NULL) 334280304Sjkim return; 33555714Skris 336280304Sjkim if (free_type < 0 || free_type == onp->type) 337280304Sjkim OBJ_NAME_remove(onp->name, onp->type); 338280304Sjkim} 33955714Skris 340238405Sjkimstatic IMPLEMENT_LHASH_DOALL_FN(names_lh_free, OBJ_NAME) 341109998Smarkm 34259191Skrisstatic void name_funcs_free(NAME_FUNCS *ptr) 343280304Sjkim{ 344280304Sjkim OPENSSL_free(ptr); 345280304Sjkim} 34659191Skris 34755714Skrisvoid OBJ_NAME_cleanup(int type) 348280304Sjkim{ 349280304Sjkim unsigned long down_load; 35055714Skris 351280304Sjkim if (names_lh == NULL) 352280304Sjkim return; 35355714Skris 354280304Sjkim free_type = type; 355280304Sjkim down_load = lh_OBJ_NAME_down_load(names_lh); 356280304Sjkim lh_OBJ_NAME_down_load(names_lh) = 0; 35755714Skris 358280304Sjkim lh_OBJ_NAME_doall(names_lh, LHASH_DOALL_FN(names_lh_free)); 359280304Sjkim if (type < 0) { 360280304Sjkim lh_OBJ_NAME_free(names_lh); 361280304Sjkim sk_NAME_FUNCS_pop_free(name_funcs_stack, name_funcs_free); 362280304Sjkim names_lh = NULL; 363280304Sjkim name_funcs_stack = NULL; 364280304Sjkim } else 365280304Sjkim lh_OBJ_NAME_down_load(names_lh) = down_load; 366280304Sjkim} 367