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